if_ioctl_solaris.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. * Interface looking up by ioctl () on Solaris.
  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 "privs.h"
  31. #include "zebra/interface.h"
  32. void lifreq_set_name (struct lifreq *, const char *);
  33. int if_get_flags_direct (const char *, uint64_t *, unsigned int af);
  34. static int if_get_addr (struct interface *, struct sockaddr *, const char *);
  35. static void interface_info_ioctl (struct interface *);
  36. extern struct zebra_privs_t zserv_privs;
  37. int
  38. interface_list_ioctl (int af)
  39. {
  40. int ret;
  41. int sock;
  42. #define IFNUM_BASE 32
  43. struct lifnum lifn;
  44. int ifnum;
  45. struct lifreq *lifreq;
  46. struct lifconf lifconf;
  47. struct interface *ifp;
  48. int n;
  49. int save_errno;
  50. size_t needed, lastneeded = 0;
  51. char *buf = NULL;
  52. if (zserv_privs.change(ZPRIVS_RAISE))
  53. zlog (NULL, LOG_ERR, "Can't raise privileges");
  54. sock = socket (af, SOCK_DGRAM, 0);
  55. if (sock < 0)
  56. {
  57. zlog_warn ("Can't make %s socket stream: %s",
  58. (af == AF_INET ? "AF_INET" : "AF_INET6"), safe_strerror (errno));
  59. if (zserv_privs.change(ZPRIVS_LOWER))
  60. zlog (NULL, LOG_ERR, "Can't lower privileges");
  61. return -1;
  62. }
  63. calculate_lifc_len: /* must hold privileges to enter here */
  64. lifn.lifn_family = af;
  65. lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
  66. ret = ioctl (sock, SIOCGLIFNUM, &lifn);
  67. save_errno = errno;
  68. if (zserv_privs.change(ZPRIVS_LOWER))
  69. zlog (NULL, LOG_ERR, "Can't lower privileges");
  70. if (ret < 0)
  71. {
  72. zlog_warn ("interface_list_ioctl: SIOCGLIFNUM failed %s",
  73. safe_strerror (save_errno));
  74. close (sock);
  75. return -1;
  76. }
  77. ifnum = lifn.lifn_count;
  78. /*
  79. * When calculating the buffer size needed, add a small number
  80. * of interfaces to those we counted. We do this to capture
  81. * the interface status of potential interfaces which may have
  82. * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
  83. */
  84. needed = (ifnum + 4) * sizeof (struct lifreq);
  85. if (needed > lastneeded || needed < lastneeded / 2)
  86. {
  87. if (buf != NULL)
  88. XFREE (MTYPE_TMP, buf);
  89. if ((buf = XMALLOC (MTYPE_TMP, needed)) == NULL)
  90. {
  91. zlog_warn ("interface_list_ioctl: malloc failed");
  92. close (sock);
  93. return -1;
  94. }
  95. }
  96. lastneeded = needed;
  97. lifconf.lifc_family = af;
  98. lifconf.lifc_flags = LIFC_NOXMIT;
  99. lifconf.lifc_len = needed;
  100. lifconf.lifc_buf = buf;
  101. if (zserv_privs.change(ZPRIVS_RAISE))
  102. zlog (NULL, LOG_ERR, "Can't raise privileges");
  103. ret = ioctl (sock, SIOCGLIFCONF, &lifconf);
  104. if (ret < 0)
  105. {
  106. if (errno == EINVAL)
  107. goto calculate_lifc_len; /* deliberately hold privileges */
  108. zlog_warn ("SIOCGLIFCONF: %s", safe_strerror (errno));
  109. if (zserv_privs.change(ZPRIVS_LOWER))
  110. zlog (NULL, LOG_ERR, "Can't lower privileges");
  111. goto end;
  112. }
  113. if (zserv_privs.change(ZPRIVS_LOWER))
  114. zlog (NULL, LOG_ERR, "Can't lower privileges");
  115. /* Allocate interface. */
  116. lifreq = lifconf.lifc_req;
  117. for (n = 0; n < lifconf.lifc_len; n += sizeof (struct lifreq))
  118. {
  119. /* we treat Solaris logical interfaces as addresses, because that is
  120. * how PF_ROUTE on Solaris treats them. Hence we can not directly use
  121. * the lifreq_name to get the ifp. We need to normalise the name
  122. * before attempting get.
  123. *
  124. * Solaris logical interface names are in the form of:
  125. * <interface name>:<logical interface id>
  126. */
  127. unsigned int normallen = 0;
  128. uint64_t lifflags;
  129. /* We should exclude ~IFF_UP interfaces, as we'll find out about them
  130. * coming up later through RTM_NEWADDR message on the route socket.
  131. */
  132. if (if_get_flags_direct (lifreq->lifr_name, &lifflags,
  133. lifreq->lifr_addr.ss_family)
  134. || !CHECK_FLAG (lifflags, IFF_UP))
  135. {
  136. lifreq++;
  137. continue;
  138. }
  139. /* Find the normalised name */
  140. while ( (normallen < sizeof(lifreq->lifr_name))
  141. && ( *(lifreq->lifr_name + normallen) != '\0')
  142. && ( *(lifreq->lifr_name + normallen) != ':') )
  143. normallen++;
  144. ifp = if_get_by_name_len(lifreq->lifr_name, normallen);
  145. if (lifreq->lifr_addr.ss_family == AF_INET)
  146. ifp->flags |= IFF_IPV4;
  147. if (lifreq->lifr_addr.ss_family == AF_INET6)
  148. {
  149. #ifdef HAVE_IPV6
  150. ifp->flags |= IFF_IPV6;
  151. #else
  152. lifreq++;
  153. continue;
  154. #endif /* HAVE_IPV6 */
  155. }
  156. if_add_update (ifp);
  157. interface_info_ioctl (ifp);
  158. /* If a logical interface pass the full name so it can be
  159. * as a label on the address
  160. */
  161. if ( *(lifreq->lifr_name + normallen) != '\0')
  162. if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr,
  163. lifreq->lifr_name);
  164. else
  165. if_get_addr (ifp, (struct sockaddr *) &lifreq->lifr_addr, NULL);
  166. /* Poke the interface flags. Lets IFF_UP mangling kick in */
  167. if_flags_update (ifp, ifp->flags);
  168. lifreq++;
  169. }
  170. end:
  171. close (sock);
  172. XFREE (MTYPE_TMP, lifconf.lifc_buf);
  173. return ret;
  174. }
  175. /* Get interface's index by ioctl. */
  176. int
  177. if_get_index (struct interface *ifp)
  178. {
  179. int ret;
  180. struct lifreq lifreq;
  181. lifreq_set_name (&lifreq, ifp);
  182. if (ifp->flags & IFF_IPV4)
  183. ret = AF_IOCTL (AF_INET, SIOCGLIFINDEX, (caddr_t) & lifreq);
  184. else if (ifp->flags & IFF_IPV6)
  185. ret = AF_IOCTL (AF_INET6, SIOCGLIFINDEX, (caddr_t) & lifreq);
  186. else
  187. ret = -1;
  188. if (ret < 0)
  189. {
  190. zlog_warn ("SIOCGLIFINDEX(%s) failed", ifp->name);
  191. return ret;
  192. }
  193. /* OK we got interface index. */
  194. #ifdef ifr_ifindex
  195. ifp->ifindex = lifreq.lifr_ifindex;
  196. #else
  197. ifp->ifindex = lifreq.lifr_index;
  198. #endif
  199. return ifp->ifindex;
  200. }
  201. /* Interface address lookup by ioctl. This function only looks up
  202. IPv4 address. */
  203. #define ADDRLEN(sa) (((sa)->sa_family == AF_INET ? \
  204. sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6)))
  205. #define SIN(s) ((struct sockaddr_in *)(s))
  206. #define SIN6(s) ((struct sockaddr_in6 *)(s))
  207. /* Retrieve address information for the given ifp */
  208. static int
  209. if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label)
  210. {
  211. int ret;
  212. struct lifreq lifreq;
  213. struct sockaddr_storage mask, dest;
  214. char *dest_pnt = NULL;
  215. u_char prefixlen = 0;
  216. afi_t af;
  217. int flags = 0;
  218. /* Interface's name and address family.
  219. * We need to use the logical interface name / label, if we've been
  220. * given one, in order to get the right address
  221. */
  222. strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ);
  223. /* Interface's address. */
  224. memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr));
  225. af = addr->sa_family;
  226. /* Point to point or broad cast address pointer init. */
  227. dest_pnt = NULL;
  228. if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0)
  229. {
  230. memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr));
  231. if (af == AF_INET)
  232. dest_pnt = (char *) &(SIN (&dest)->sin_addr);
  233. else
  234. dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr);
  235. flags = ZEBRA_IFA_PEER;
  236. }
  237. if (af == AF_INET)
  238. {
  239. ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq);
  240. if (ret < 0)
  241. {
  242. if (errno != EADDRNOTAVAIL)
  243. {
  244. zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name,
  245. safe_strerror (errno));
  246. return ret;
  247. }
  248. return 0;
  249. }
  250. memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr));
  251. prefixlen = ip_masklen (SIN (&mask)->sin_addr);
  252. if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0))
  253. {
  254. memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in));
  255. dest_pnt = (char *) &SIN (&dest)->sin_addr;
  256. }
  257. }
  258. #ifdef HAVE_IPV6
  259. else if (af == AF_INET6)
  260. {
  261. if (ifp->flags & IFF_POINTOPOINT)
  262. {
  263. prefixlen = IPV6_MAX_BITLEN;
  264. }
  265. else
  266. {
  267. ret = if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq);
  268. if (ret < 0)
  269. {
  270. zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s",
  271. ifp->name, safe_strerror (errno));
  272. }
  273. else
  274. {
  275. prefixlen = lifreq.lifr_addrlen;
  276. }
  277. }
  278. }
  279. #endif /* HAVE_IPV6 */
  280. /* Set address to the interface. */
  281. if (af == AF_INET)
  282. connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen,
  283. (struct in_addr *) dest_pnt, label);
  284. #ifdef HAVE_IPV6
  285. else if (af == AF_INET6)
  286. connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen,
  287. (struct in6_addr *) dest_pnt, label);
  288. #endif /* HAVE_IPV6 */
  289. return 0;
  290. }
  291. /* Fetch interface information via ioctl(). */
  292. static void
  293. interface_info_ioctl (struct interface *ifp)
  294. {
  295. if_get_index (ifp);
  296. if_get_flags (ifp);
  297. if_get_mtu (ifp);
  298. if_get_metric (ifp);
  299. }
  300. /* Lookup all interface information. */
  301. void
  302. interface_list ()
  303. {
  304. interface_list_ioctl (AF_INET);
  305. interface_list_ioctl (AF_INET6);
  306. interface_list_ioctl (AF_UNSPEC);
  307. }
  308. struct connected *
  309. if_lookup_linklocal (struct interface *ifp)
  310. {
  311. #ifdef HAVE_IPV6
  312. struct listnode *node;
  313. struct connected *ifc;
  314. if (ifp == NULL)
  315. return NULL;
  316. for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
  317. {
  318. if ((ifc->address->family == AF_INET6) &&
  319. (IN6_IS_ADDR_LINKLOCAL (&ifc->address->u.prefix6)))
  320. return ifc;
  321. }
  322. #endif /* HAVE_IPV6 */
  323. return NULL;
  324. }