if_ioctl.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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", 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", 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 (ifreq->ifr_name);
  93. if_add_update (ifp);
  94. size = ifreq->ifr_addr.sa_len;
  95. if (size < sizeof (ifreq->ifr_addr))
  96. size = sizeof (ifreq->ifr_addr);
  97. size += sizeof (ifreq->ifr_name);
  98. n += size;
  99. }
  100. #else
  101. for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq))
  102. {
  103. ifp = if_get_by_name (ifreq->ifr_name);
  104. if_add_update (ifp);
  105. ifreq++;
  106. }
  107. #endif /* OPEN_BSD */
  108. end:
  109. close (sock);
  110. XFREE (MTYPE_TMP, ifconf.ifc_buf);
  111. return ret;
  112. }
  113. /* Get interface's index by ioctl. */
  114. int
  115. if_get_index (struct interface *ifp)
  116. {
  117. #if defined(HAVE_IF_NAMETOINDEX)
  118. /* Modern systems should have if_nametoindex(3). */
  119. ifp->ifindex = if_nametoindex(ifp->name);
  120. #elif defined(SIOCGIFINDEX) && !defined(HAVE_BROKEN_ALIASES)
  121. /* Fall-back for older linuxes. */
  122. int ret;
  123. struct ifreq ifreq;
  124. static int if_fake_index;
  125. ifreq_set_name (&ifreq, ifp);
  126. ret = if_ioctl (SIOCGIFINDEX, (caddr_t) &ifreq);
  127. if (ret < 0)
  128. {
  129. /* Linux 2.0.X does not have interface index. */
  130. ifp->ifindex = if_fake_index++;
  131. return ifp->ifindex;
  132. }
  133. /* OK we got interface index. */
  134. #ifdef ifr_ifindex
  135. ifp->ifindex = ifreq.ifr_ifindex;
  136. #else
  137. ifp->ifindex = ifreq.ifr_index;
  138. #endif
  139. #else
  140. /* Linux 2.2.X does not provide individual interface index
  141. for aliases and we know it. For others issue a warning. */
  142. #if !defined(HAVE_BROKEN_ALIASES)
  143. #warning "Using if_fake_index. You may want to add appropriate"
  144. #warning "mapping from ifname to ifindex for your system..."
  145. #endif
  146. /* This branch probably won't provide usable results, but anyway... */
  147. static int if_fake_index = 1;
  148. ifp->ifindex = if_fake_index++;
  149. #endif
  150. return ifp->ifindex;
  151. }
  152. #ifdef SIOCGIFHWADDR
  153. int
  154. if_get_hwaddr (struct interface *ifp)
  155. {
  156. int ret;
  157. struct ifreq ifreq;
  158. int i;
  159. strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
  160. ifreq.ifr_addr.sa_family = AF_INET;
  161. /* Fetch Hardware address if available. */
  162. ret = if_ioctl (SIOCGIFHWADDR, (caddr_t) &ifreq);
  163. if (ret < 0)
  164. ifp->hw_addr_len = 0;
  165. else
  166. {
  167. memcpy (ifp->hw_addr, ifreq.ifr_hwaddr.sa_data, 6);
  168. for (i = 0; i < 6; i++)
  169. if (ifp->hw_addr[i] != 0)
  170. break;
  171. if (i == 6)
  172. ifp->hw_addr_len = 0;
  173. else
  174. ifp->hw_addr_len = 6;
  175. }
  176. return 0;
  177. }
  178. #endif /* SIOCGIFHWADDR */
  179. #ifdef HAVE_GETIFADDRS
  180. #include <ifaddrs.h>
  181. int
  182. if_getaddrs ()
  183. {
  184. int ret;
  185. struct ifaddrs *ifap;
  186. struct ifaddrs *ifapfree;
  187. struct interface *ifp;
  188. int prefixlen;
  189. ret = getifaddrs (&ifap);
  190. if (ret != 0)
  191. {
  192. zlog_err ("getifaddrs(): %s", strerror (errno));
  193. return -1;
  194. }
  195. for (ifapfree = ifap; ifap; ifap = ifap->ifa_next)
  196. {
  197. ifp = if_lookup_by_name (ifap->ifa_name);
  198. if (ifp == NULL)
  199. {
  200. zlog_err ("if_getaddrs(): Can't lookup interface %s\n",
  201. ifap->ifa_name);
  202. continue;
  203. }
  204. if (ifap->ifa_addr->sa_family == AF_INET)
  205. {
  206. struct sockaddr_in *addr;
  207. struct sockaddr_in *mask;
  208. struct sockaddr_in *dest;
  209. struct in_addr *dest_pnt;
  210. addr = (struct sockaddr_in *) ifap->ifa_addr;
  211. mask = (struct sockaddr_in *) ifap->ifa_netmask;
  212. prefixlen = ip_masklen (mask->sin_addr);
  213. dest_pnt = NULL;
  214. if (ifap->ifa_flags & IFF_POINTOPOINT)
  215. {
  216. dest = (struct sockaddr_in *) ifap->ifa_dstaddr;
  217. dest_pnt = &dest->sin_addr;
  218. }
  219. if (ifap->ifa_flags & IFF_BROADCAST)
  220. {
  221. dest = (struct sockaddr_in *) ifap->ifa_broadaddr;
  222. dest_pnt = &dest->sin_addr;
  223. }
  224. connected_add_ipv4 (ifp, 0, &addr->sin_addr,
  225. prefixlen, dest_pnt, NULL);
  226. }
  227. #ifdef HAVE_IPV6
  228. if (ifap->ifa_addr->sa_family == AF_INET6)
  229. {
  230. struct sockaddr_in6 *addr;
  231. struct sockaddr_in6 *mask;
  232. struct sockaddr_in6 *dest;
  233. struct in6_addr *dest_pnt;
  234. addr = (struct sockaddr_in6 *) ifap->ifa_addr;
  235. mask = (struct sockaddr_in6 *) ifap->ifa_netmask;
  236. prefixlen = ip6_masklen (mask->sin6_addr);
  237. dest_pnt = NULL;
  238. if (ifap->ifa_flags & IFF_POINTOPOINT)
  239. {
  240. if (ifap->ifa_dstaddr)
  241. {
  242. dest = (struct sockaddr_in6 *) ifap->ifa_dstaddr;
  243. dest_pnt = &dest->sin6_addr;
  244. }
  245. }
  246. if (ifap->ifa_flags & IFF_BROADCAST)
  247. {
  248. if (ifap->ifa_broadaddr)
  249. {
  250. dest = (struct sockaddr_in6 *) ifap->ifa_broadaddr;
  251. dest_pnt = &dest->sin6_addr;
  252. }
  253. }
  254. #if defined(KAME)
  255. if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
  256. {
  257. addr->sin6_scope_id =
  258. ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]);
  259. addr->sin6_addr.s6_addr[2] = addr->sin6_addr.s6_addr[3] = 0;
  260. }
  261. #endif
  262. connected_add_ipv6 (ifp, &addr->sin6_addr, prefixlen, dest_pnt);
  263. }
  264. #endif /* HAVE_IPV6 */
  265. }
  266. freeifaddrs (ifapfree);
  267. return 0;
  268. }
  269. #else /* HAVE_GETIFADDRS */
  270. /* Interface address lookup by ioctl. This function only looks up
  271. IPv4 address. */
  272. int
  273. if_get_addr (struct interface *ifp)
  274. {
  275. int ret;
  276. struct ifreq ifreq;
  277. struct sockaddr_in addr;
  278. struct sockaddr_in mask;
  279. struct sockaddr_in dest;
  280. struct in_addr *dest_pnt;
  281. u_char prefixlen;
  282. /* Interface's name and address family. */
  283. strncpy (ifreq.ifr_name, ifp->name, IFNAMSIZ);
  284. ifreq.ifr_addr.sa_family = AF_INET;
  285. /* Interface's address. */
  286. ret = if_ioctl (SIOCGIFADDR, (caddr_t) &ifreq);
  287. if (ret < 0)
  288. {
  289. if (errno != EADDRNOTAVAIL)
  290. {
  291. zlog_warn ("SIOCGIFADDR fail: %s", strerror (errno));
  292. return ret;
  293. }
  294. return 0;
  295. }
  296. memcpy (&addr, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
  297. /* Interface's network mask. */
  298. ret = if_ioctl (SIOCGIFNETMASK, (caddr_t) &ifreq);
  299. if (ret < 0)
  300. {
  301. if (errno != EADDRNOTAVAIL)
  302. {
  303. zlog_warn ("SIOCGIFNETMASK fail: %s", strerror (errno));
  304. return ret;
  305. }
  306. return 0;
  307. }
  308. #ifdef ifr_netmask
  309. memcpy (&mask, &ifreq.ifr_netmask, sizeof (struct sockaddr_in));
  310. #else
  311. memcpy (&mask, &ifreq.ifr_addr, sizeof (struct sockaddr_in));
  312. #endif /* ifr_netmask */
  313. prefixlen = ip_masklen (mask.sin_addr);
  314. /* Point to point or borad cast address pointer init. */
  315. dest_pnt = NULL;
  316. if (ifp->flags & IFF_POINTOPOINT)
  317. {
  318. ret = if_ioctl (SIOCGIFDSTADDR, (caddr_t) &ifreq);
  319. if (ret < 0)
  320. {
  321. if (errno != EADDRNOTAVAIL)
  322. {
  323. zlog_warn ("SIOCGIFDSTADDR fail: %s", strerror (errno));
  324. return ret;
  325. }
  326. return 0;
  327. }
  328. memcpy (&dest, &ifreq.ifr_dstaddr, sizeof (struct sockaddr_in));
  329. dest_pnt = &dest.sin_addr;
  330. }
  331. if (ifp->flags & IFF_BROADCAST)
  332. {
  333. ret = if_ioctl (SIOCGIFBRDADDR, (caddr_t) &ifreq);
  334. if (ret < 0)
  335. {
  336. if (errno != EADDRNOTAVAIL)
  337. {
  338. zlog_warn ("SIOCGIFBRDADDR fail: %s", strerror (errno));
  339. return ret;
  340. }
  341. return 0;
  342. }
  343. memcpy (&dest, &ifreq.ifr_broadaddr, sizeof (struct sockaddr_in));
  344. dest_pnt = &dest.sin_addr;
  345. }
  346. /* Set address to the interface. */
  347. connected_add_ipv4 (ifp, 0, &addr.sin_addr, prefixlen, dest_pnt, NULL);
  348. return 0;
  349. }
  350. #endif /* HAVE_GETIFADDRS */
  351. /* Fetch interface information via ioctl(). */
  352. static void
  353. interface_info_ioctl ()
  354. {
  355. listnode node;
  356. struct interface *ifp;
  357. for (node = listhead (iflist); node; node = nextnode (node))
  358. {
  359. ifp = getdata (node);
  360. if_get_index (ifp);
  361. #ifdef SIOCGIFHWADDR
  362. if_get_hwaddr (ifp);
  363. #endif /* SIOCGIFHWADDR */
  364. if_get_flags (ifp);
  365. #ifndef HAVE_GETIFADDRS
  366. if_get_addr (ifp);
  367. #endif /* ! HAVE_GETIFADDRS */
  368. if_get_mtu (ifp);
  369. if_get_metric (ifp);
  370. }
  371. }
  372. /* Lookup all interface information. */
  373. void
  374. interface_list ()
  375. {
  376. /* Linux can do both proc & ioctl, ioctl is the only way to get
  377. interface aliases in 2.2 series kernels. */
  378. #ifdef HAVE_PROC_NET_DEV
  379. interface_list_proc ();
  380. #endif /* HAVE_PROC_NET_DEV */
  381. interface_list_ioctl ();
  382. /* After listing is done, get index, address, flags and other
  383. interface's information. */
  384. interface_info_ioctl ();
  385. #ifdef HAVE_GETIFADDRS
  386. if_getaddrs ();
  387. #endif /* HAVE_GETIFADDRS */
  388. #if defined(HAVE_IPV6) && defined(HAVE_PROC_NET_IF_INET6)
  389. /* Linux provides interface's IPv6 address via
  390. /proc/net/if_inet6. */
  391. ifaddr_proc_ipv6 ();
  392. #endif /* HAVE_IPV6 && HAVE_PROC_NET_IF_INET6 */
  393. }