if_ioctl.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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. int
  33. interface_list_ioctl ()
  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. 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. 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. int
  186. if_getaddrs ()
  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. ifp = if_lookup_by_name (ifap->ifa_name);
  202. if (ifp == NULL)
  203. {
  204. zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
  205. ifap->ifa_name);
  206. continue;
  207. }
  208. if (ifap->ifa_addr->sa_family == AF_INET)
  209. {
  210. struct sockaddr_in *addr;
  211. struct sockaddr_in *mask;
  212. struct sockaddr_in *dest;
  213. struct in_addr *dest_pnt;
  214. addr = (struct sockaddr_in *) ifap->ifa_addr;
  215. mask = (struct sockaddr_in *) ifap->ifa_netmask;
  216. prefixlen = ip_masklen (mask->sin_addr);
  217. dest_pnt = NULL;
  218. if (ifap->ifa_flags & IFF_POINTOPOINT)
  219. {
  220. dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
  221. dest_pnt = &dest->sin_addr;
  222. }
  223. if (ifap->ifa_flags & IFF_BROADCAST)
  224. {
  225. dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
  226. dest_pnt = &dest->sin_addr;
  227. }
  228. connected_add_ipv4 (ifp, 0, &addr->sin_addr,
  229. prefixlen, dest_pnt, NULL);
  230. }
  231. #ifdef HAVE_IPV6
  232. if (ifap->ifa_addr->sa_family == AF_INET6)
  233. {
  234. struct sockaddr_in6 *addr;
  235. struct sockaddr_in6 *mask;
  236. struct sockaddr_in6 *dest;
  237. struct in6_addr *dest_pnt;
  238. addr = (struct sockaddr_in6 *) ifap->ifa_addr;
  239. mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
  240. prefixlen = ip6_masklen (mask->sin6_addr);
  241. dest_pnt = NULL;
  242. if (ifap->ifa_flags & IFF_POINTOPOINT)
  243. {
  244. if (ifap->ifa_dstaddr)
  245. {
  246. dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
  247. dest_pnt = &dest->sin6_addr;
  248. }
  249. }
  250. if (ifap->ifa_flags & IFF_BROADCAST)
  251. {
  252. if (ifap->ifa_broadaddr)
  253. {
  254. dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
  255. dest_pnt = &dest->sin6_addr;
  256. }
  257. }
  258. #if defined(KAME)
  259. if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
  260. {
  261. addr->sin6_scope_id =
  262. ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
  263. addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
  264. }
  265. #endif
  266. connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt);
  267. }
  268. #endif /* HAVE_IPV6 */
  269. }
  270. freeifaddrs (ifapfree);
  271. return 0;
  272. }
  273. #else /* HAVE_GETIFADDRS */
  274. /* Interface address lookup by ioctl. This function only looks up
  275. IPv4 address. */
  276. int
  277. if_get_addr (struct interface *ifp)
  278. {
  279. int ret;
  280. struct ifreq ifreq;
  281. struct sockaddr_in addr;
  282. struct sockaddr_in mask;
  283. struct sockaddr_in dest;
  284. struct in_addr *dest_pnt;
  285. u_char prefixlen;
  286. /* Interface's name and address family. */
  287. strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
  288. ifreq.ifr_addr.sa_family = AF_INET;
  289. /* Interface's address. */
  290. ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
  291. if (ret < 0)
  292. {
  293. if (errno != EADDRNOTAVAIL)
  294. {
  295. zlog_warn ("SIOCGIFADDR fail: %s", safe_strerror (errno));
  296. return ret;
  297. }
  298. return 0;
  299. }
  300. memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
  301. /* Interface's network mask. */
  302. ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
  303. if (ret < 0)
  304. {
  305. if (errno != EADDRNOTAVAIL)
  306. {
  307. zlog_warn ("SIOCGIFNETMASK fail: %s", safe_strerror (errno));
  308. return ret;
  309. }
  310. return 0;
  311. }
  312. #ifdef ifr_netmask
  313. memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
  314. #else
  315. memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
  316. #endif /* ifr_netmask */
  317. prefixlen = ip_masklen (mask.sin_addr);
  318. /* Point to point or borad cast address pointer init. */
  319. dest_pnt = NULL;
  320. if (ifp->flags & IFF_POINTOPOINT)
  321. {
  322. ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
  323. if (ret < 0)
  324. {
  325. if (errno != EADDRNOTAVAIL)
  326. {
  327. zlog_warn ("SIOCGIFDSTADDR fail: %s", safe_strerror (errno));
  328. return ret;
  329. }
  330. return 0;
  331. }
  332. memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
  333. dest_pnt = &dest.sin_addr;
  334. }
  335. if (ifp->flags & IFF_BROADCAST)
  336. {
  337. ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
  338. if (ret < 0)
  339. {
  340. if (errno != EADDRNOTAVAIL)
  341. {
  342. zlog_warn ("SIOCGIFBRDADDR fail: %s", safe_strerror (errno));
  343. return ret;
  344. }
  345. return 0;
  346. }
  347. memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
  348. dest_pnt = &dest.sin_addr;
  349. }
  350. /* Set address to the interface. */
  351. connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL);
  352. return 0;
  353. }
  354. #endif /* HAVE_GETIFADDRS */
  355. /* Fetch interface information via ioctl(). */
  356. static void
  357. interface_info_ioctl ()
  358. {
  359. struct listnode *node;
  360. struct interface *ifp;
  361. LIST_LOOP (iflist, ifp, node)
  362. {
  363. ifp = getdata (node);
  364. if_get_index (ifp);
  365. #ifdef SIOCGIFHWADDR
  366. if_get_hwaddr (ifp);
  367. #endif /* SIOCGIFHWADDR */
  368. if_get_flags (ifp);
  369. #ifndef HAVE_GETIFADDRS
  370. if_get_addr (ifp);
  371. #endif /* ! HAVE_GETIFADDRS */
  372. if_get_mtu (ifp);
  373. if_get_metric (ifp);
  374. }
  375. }
  376. /* Lookup all interface information. */
  377. void
  378. interface_list ()
  379. {
  380. /* Linux can do both proc & ioctl, ioctl is the only way to get
  381. interface aliases in 2.2 series kernels. */
  382. #ifdef HAVE_PROC_NET_DEV
  383. interface_list_proc ();
  384. #endif /* HAVE_PROC_NET_DEV */
  385. interface_list_ioctl ();
  386. /* After listing is done, get index, address, flags and other
  387. interface's information. */
  388. interface_info_ioctl ();
  389. #ifdef HAVE_GETIFADDRS
  390. if_getaddrs ();
  391. #endif /* HAVE_GETIFADDRS */
  392. #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
  393. /* Linux provides interface's IPv6 address via
  394. /proc/net/if_inet6. */
  395. ifaddr_proc_ipv6 ();
  396. #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
  397. }