if_ioctl.c 11 KB

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