if_ioctl.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /*
  2. * Interface looking up by ioctl ().
  3. * Copyright (C) 1997, 98 Kunihiro Ishiguro
  4. *
  5. * This file is part of GNU Zebra.
  6. *
  7. * GNU Zebra is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation; either version 2, or (at your option) any
  10. * later version.
  11. *
  12. * GNU Zebra is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with GNU Zebra; see the file COPYING. If not, write to the Free
  19. * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  20. * 02111-1307, USA.
  21. */
  22. #include <zebra.h>
  23. #include "if.h"
  24. #include "sockunion.h"
  25. #include "prefix.h"
  26. #include "ioctl.h"
  27. #include "connected.h"
  28. #include "memory.h"
  29. #include "log.h"
  30. #include "vrf.h"
  31. #include "zebra/interface.h"
  32. #include "zebra/rib.h"
  33. /* Interface looking up using infamous SIOCGIFCONF. */
  34. static int
  35. interface_list_ioctl (void)
  36. {
  37. int ret;
  38. int sock;
  39. #define IFNUM_BASE 32
  40. int ifnum;
  41. struct ifreq *ifreq;
  42. struct ifconf ifconf;
  43. struct interface *ifp;
  44. int n;
  45. int lastlen;
  46. /* Normally SIOCGIFCONF works with AF_INET socket. */
  47. sock = socket (AF_INET, SOCK_DGRAM, 0);
  48. if (sock < 0)
  49. {
  50. zlog_warn ("Can't make AF_INET socket stream: %s", safe_strerror (errno));
  51. return -1;
  52. }
  53. /* Set initial ifreq count. This will be double when SIOCGIFCONF
  54. fail. Solaris has SIOCGIFNUM. */
  55. #ifdef SIOCGIFNUM
  56. ret = ioctl (sock, SIOCGIFNUM, &ifnum);
  57. if (ret < 0)
  58. ifnum = IFNUM_BASE;
  59. else
  60. ifnum++;
  61. #else
  62. ifnum = IFNUM_BASE;
  63. #endif /* SIOCGIFNUM */
  64. ifconf.ifc_buf = NULL;
  65. lastlen = 0;
  66. /* Loop until SIOCGIFCONF success. */
  67. for (;;)
  68. {
  69. ifconf.ifc_len = sizeof (struct ifreq) * ifnum;
  70. ifconf.ifc_buf = XREALLOC(MTYPE_TMP, ifconf.ifc_buf, ifconf.ifc_len);
  71. ret = ioctl(sock, SIOCGIFCONF, &ifconf);
  72. if (ret < 0)
  73. {
  74. zlog_warn ("SIOCGIFCONF: %s", safe_strerror(errno));
  75. goto end;
  76. }
  77. /* Repeatedly get info til buffer fails to grow. */
  78. if (ifconf.ifc_len > lastlen)
  79. {
  80. lastlen = ifconf.ifc_len;
  81. ifnum += 10;
  82. continue;
  83. }
  84. /* Success. */
  85. break;
  86. }
  87. /* Allocate interface. */
  88. ifreq = ifconf.ifc_req;
  89. #ifdef OPEN_BSD
  90. for (n = 0; n < ifconf.ifc_len; )
  91. {
  92. int size;
  93. ifreq = (struct ifreq *)((caddr_t) ifconf.ifc_req + n);
  94. ifp = if_get_by_name_len(ifreq->ifr_name,
  95. strnlen(ifreq->ifr_name,
  96. sizeof(ifreq->ifr_name)));
  97. if_add_update (ifp);
  98. size = ifreq->ifr_addr.sa_len;
  99. if (size < sizeof (ifreq->ifr_addr))
  100. size = sizeof (ifreq->ifr_addr);
  101. size += sizeof (ifreq->ifr_name);
  102. n += size;
  103. }
  104. #else
  105. for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
  106. {
  107. ifp = if_get_by_name_len(ifreq->ifr_name,
  108. strnlen(ifreq->ifr_name,
  109. sizeof(ifreq->ifr_name)));
  110. if_add_update (ifp);
  111. ifreq++;
  112. }
  113. #endif /* OPEN_BSD */
  114. end:
  115. close (sock);
  116. XFREE (MTYPE_TMP, ifconf.ifc_buf);
  117. return ret;
  118. }
  119. /* Get interface's index by ioctl. */
  120. static int
  121. if_get_index (struct interface *ifp)
  122. {
  123. #if defined(HAVE_IF_NAMETOINDEX)
  124. /* Modern systems should have if_nametoindex(3). */
  125. ifp->ifindex = if_nametoindex(ifp->name);
  126. #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
  127. /* Fall-back for older linuxes. */
  128. int ret;
  129. struct ifreq ifreq;
  130. static int if_fake_index;
  131. ifreq_set_name (&ifreq, ifp);
  132. ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
  133. if (ret < 0)
  134. {
  135. /* Linux 2.0.X does not have interface index. */
  136. ifp->ifindex = if_fake_index++;
  137. return ifp->ifindex;
  138. }
  139. /* OK we got interface index. */
  140. #ifdef ifr_ifindex
  141. ifp->ifindex = ifreq.ifr_ifindex;
  142. #else
  143. ifp->ifindex = ifreq.ifr_index;
  144. #endif
  145. #else
  146. /* Linux 2.2.X does not provide individual interface index
  147. for aliases and we know it. For others issue a warning. */
  148. #if !defined(HAVE_BROKEN_ALIASES)
  149. #warning "Using if_fake_index. You may want to add appropriate"
  150. #warning "mapping from ifname to ifindex for your system..."
  151. #endif
  152. /* This branch probably won't provide usable results, but anyway... */
  153. static int if_fake_index = 1;
  154. ifp->ifindex = if_fake_index++;
  155. #endif
  156. return ifp->ifindex;
  157. }
  158. #ifdef SIOCGIFHWADDR
  159. static int
  160. if_get_hwaddr (struct interface *ifp)
  161. {
  162. int ret;
  163. struct ifreq ifreq;
  164. int i;
  165. strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
  166. ifreq.ifr_addr.sa_family = AF_INET;
  167. /* Fetch Hardware address if available. */
  168. ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
  169. if (ret < 0)
  170. ifp->hw_addr_len = 0;
  171. else
  172. {
  173. memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
  174. for (i = 0; i < 6; i++)
  175. if (ifp->hw_addr[i] != 0)
  176. break;
  177. if (i == 6)
  178. ifp->hw_addr_len = 0;
  179. else
  180. ifp->hw_addr_len = 6;
  181. }
  182. return 0;
  183. }
  184. #endif /* SIOCGIFHWADDR */
  185. #ifdef HAVE_GETIFADDRS
  186. #include <ifaddrs.h>
  187. static int
  188. if_getaddrs (void)
  189. {
  190. int ret;
  191. struct ifaddrs *ifap;
  192. struct ifaddrs *ifapfree;
  193. struct interface *ifp;
  194. int prefixlen;
  195. ret = getifaddrs (&ifap);
  196. if (ret != 0)
  197. {
  198. zlog_err ("getifaddrs(): %s", safe_strerror (errno));
  199. return -1;
  200. }
  201. for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
  202. {
  203. if (ifap->ifa_addr == NULL)
  204. {
  205. zlog_err ("%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
  206. __func__, (ifap->ifa_name ? ifap->ifa_name : "(null)"));
  207. continue;
  208. }
  209. ifp = if_lookup_by_name (ifap->ifa_name);
  210. if (ifp == NULL)
  211. {
  212. zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
  213. ifap->ifa_name);
  214. continue;
  215. }
  216. if (ifap->ifa_addr->sa_family == AF_INET)
  217. {
  218. struct sockaddr_in *addr;
  219. struct sockaddr_in *mask;
  220. struct sockaddr_in *dest;
  221. struct in_addr *dest_pnt;
  222. int flags = 0;
  223. addr = (struct sockaddr_in *) ifap->ifa_addr;
  224. mask = (struct sockaddr_in *) ifap->ifa_netmask;
  225. prefixlen = ip_masklen (mask->sin_addr);
  226. dest_pnt = NULL;
  227. if (ifap->ifa_dstaddr &&
  228. !IPV4_ADDR_SAME(&addr->sin_addr,
  229. &((struct sockaddr_in *)
  230. ifap->ifa_dstaddr)->sin_addr))
  231. {
  232. dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
  233. dest_pnt = &dest->sin_addr;
  234. flags = ZEBRA_IFA_PEER;
  235. }
  236. else if (ifap->ifa_broadaddr &&
  237. !IPV4_ADDR_SAME(&addr->sin_addr,
  238. &((struct sockaddr_in *)
  239. ifap->ifa_broadaddr)->sin_addr))
  240. {
  241. dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
  242. dest_pnt = &dest->sin_addr;
  243. }
  244. connected_add_ipv4 (ifp, flags, &addr->sin_addr,
  245. prefixlen, dest_pnt, NULL);
  246. }
  247. #ifdef HAVE_IPV6
  248. if (ifap->ifa_addr->sa_family == AF_INET6)
  249. {
  250. struct sockaddr_in6 *addr;
  251. struct sockaddr_in6 *mask;
  252. struct sockaddr_in6 *dest;
  253. struct in6_addr *dest_pnt;
  254. int flags = 0;
  255. addr = (struct sockaddr_in6 *) ifap->ifa_addr;
  256. mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
  257. prefixlen = ip6_masklen (mask->sin6_addr);
  258. dest_pnt = NULL;
  259. if (ifap->ifa_dstaddr &&
  260. !IPV6_ADDR_SAME(&addr->sin6_addr,
  261. &((struct sockaddr_in6 *)
  262. ifap->ifa_dstaddr)->sin6_addr))
  263. {
  264. dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
  265. dest_pnt = &dest->sin6_addr;
  266. flags = ZEBRA_IFA_PEER;
  267. }
  268. else if (ifap->ifa_broadaddr &&
  269. !IPV6_ADDR_SAME(&addr->sin6_addr,
  270. &((struct sockaddr_in6 *)
  271. ifap->ifa_broadaddr)->sin6_addr))
  272. {
  273. dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
  274. dest_pnt = &dest->sin6_addr;
  275. }
  276. #if defined(KAME)
  277. if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
  278. {
  279. addr->sin6_scope_id =
  280. ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
  281. addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
  282. }
  283. #endif
  284. connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen,
  285. dest_pnt, NULL);
  286. }
  287. #endif /* HAVE_IPV6 */
  288. }
  289. freeifaddrs (ifapfree);
  290. return 0;
  291. }
  292. #else /* HAVE_GETIFADDRS */
  293. /* Interface address lookup by ioctl. This function only looks up
  294. IPv4 address. */
  295. int
  296. if_get_addr (struct interface *ifp)
  297. {
  298. int ret;
  299. struct ifreq ifreq;
  300. struct sockaddr_in addr;
  301. struct sockaddr_in mask;
  302. struct sockaddr_in dest;
  303. struct in_addr *dest_pnt;
  304. u_char prefixlen;
  305. int flags = 0;
  306. /* Interface's name and address family. */
  307. strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
  308. ifreq.ifr_addr.sa_family = AF_INET;
  309. /* Interface's address. */
  310. ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
  311. if (ret < 0)
  312. {
  313. if (errno != EADDRNOTAVAIL)
  314. {
  315. zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno));
  316. return ret;
  317. }
  318. return 0;
  319. }
  320. memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
  321. /* Interface's network mask. */
  322. ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
  323. if (ret < 0)
  324. {
  325. if (errno != EADDRNOTAVAIL)
  326. {
  327. zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno));
  328. return ret;
  329. }
  330. return 0;
  331. }
  332. #ifdef ifr_netmask
  333. memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
  334. #else
  335. memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
  336. #endif /* ifr_netmask */
  337. prefixlen = ip_masklen (mask.sin_addr);
  338. /* Point to point or borad cast address pointer init. */
  339. dest_pnt = NULL;
  340. ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
  341. if (ret < 0)
  342. {
  343. if (errno != EADDRNOTAVAIL)
  344. zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno));
  345. }
  346. else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_dstaddr.sin_addr))
  347. {
  348. memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
  349. dest_pnt = &dest.sin_addr;
  350. flags = ZEBRA_IFA_PEER;
  351. }
  352. if (!dest_pnt)
  353. {
  354. ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
  355. if (ret < 0)
  356. {
  357. if (errno != EADDRNOTAVAIL)
  358. zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno));
  359. }
  360. else if (!IPV4_ADDR_SAME(&addr.sin_addr, &ifreq.ifr_broadaddr.sin_addr))
  361. {
  362. memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
  363. dest_pnt = &dest.sin_addr;
  364. }
  365. }
  366. /* Set address to the interface. */
  367. connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL);
  368. return 0;
  369. }
  370. #endif /* HAVE_GETIFADDRS */
  371. /* Fetch interface information via ioctl(). */
  372. static void
  373. interface_info_ioctl ()
  374. {
  375. struct listnode *node, *nnode;
  376. struct interface *ifp;
  377. for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
  378. {
  379. if_get_index (ifp);
  380. #ifdef SIOCGIFHWADDR
  381. if_get_hwaddr (ifp);
  382. #endif /* SIOCGIFHWADDR */
  383. if_get_flags (ifp);
  384. #ifndef HAVE_GETIFADDRS
  385. if_get_addr (ifp);
  386. #endif /* ! HAVE_GETIFADDRS */
  387. if_get_mtu (ifp);
  388. if_get_metric (ifp);
  389. }
  390. }
  391. /* Lookup all interface information. */
  392. void
  393. interface_list (struct zebra_vrf *zvrf)
  394. {
  395. if (zvrf->vrf_id != VRF_DEFAULT)
  396. {
  397. zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
  398. return;
  399. }
  400. /* Linux can do both proc & ioctl, ioctl is the only way to get
  401. interface aliases in 2.2 series kernels. */
  402. #ifdef HAVE_PROC_NET_DEV
  403. interface_list_proc ();
  404. #endif /* HAVE_PROC_NET_DEV */
  405. interface_list_ioctl ();
  406. /* After listing is done, get index, address, flags and other
  407. interface's information. */
  408. interface_info_ioctl ();
  409. #ifdef HAVE_GETIFADDRS
  410. if_getaddrs ();
  411. #endif /* HAVE_GETIFADDRS */
  412. #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
  413. /* Linux provides interface's IPv6 address via
  414. /proc/net/if_inet6. */
  415. ifaddr_proc_ipv6 ();
  416. #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
  417. }