1 #include "config.h"
2 #ifndef HAVE_GETIFADDRS
3 /*
4 * CDDL HEADER START
5 *
6 * The contents of this file are subject to the terms of the
7 * Common Development and Distribution License (the "License").
8 * You may not use this file except in compliance with the License.
9 *
10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11 * or http://www.opensolaris.org/os/licensing.
12 * See the License for the specific language governing permissions
13 * and limitations under the License.
14 *
15 * When distributing Covered Code, include this CDDL HEADER in each
16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17 * If applicable, add the following below this CDDL HEADER, with the
18 * fields enclosed by brackets "[]" replaced with your own identifying
19 * information: Portions Copyright [yyyy] [name of copyright owner]
20 *
21 * CDDL HEADER END
22 */
23
24 /*
25 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 */
27
28 #include <netdb.h>
29 #if !defined (_AIX)
30 #include <nss_dbdefs.h>
31 #endif
32
33 #include <netinet/in.h>
34 #include <sys/socket.h>
35 #if defined (_AIX)
36 #include <sys/errno.h>
37 #include <sys/ioctl.h>
38 #endif
39 #include <string.h>
40 #include <stdio.h>
41 #if defined (_AIX)
42 #include <netdb.h>
43 #endif
44 #if !defined (_AIX)
45 #include <sys/sockio.h>
46 #endif
47 #include <sys/types.h>
48 #include <stdlib.h>
49 #include <net/if.h>
50 #include <ifaddrs.h>
51 #if defined (_AIX)
52 #include <netinet/in6_var.h>
53 #endif
54
55 /* Normally this is defined in <net/if.h> but was new for Solaris 11 */
56 #ifndef LIFC_ENABLED
57 #define LIFC_ENABLED 0x20
58 #endif
59
60 #if defined (_AIX) /* Use ifaddrs_rsys instead of ifaddrs and ifreq instead of lifreq */
61 int getallifaddrs(sa_family_t af, struct ifaddrs_rsys **ifap, int64_t flags);
62 int getallifs(int s, sa_family_t af, struct ifreq **ifr, int *numifs,
63 int64_t ifc_flags);
64 #else
65 int getallifaddrs(sa_family_t af, struct ifaddrs **ifap, int64_t flags);
66 int getallifs(int s, sa_family_t af, struct lifreq **lifr, int *numifs,
67 int64_t lifc_flags);
68 #endif
69
70 /*
71 * Create a linked list of `struct ifaddrs_rsys' structures, one for each
72 * address that is UP. If successful, store the list in *ifap and
73 * return 0. On errors, return -1 and set `errno'.
74 *
75 * The storage returned in *ifap is allocated dynamically and can
76 * only be properly freed by passing it to `freeifaddrs'.
77 */
78 int
79 #if defined (_AIX)
getifaddrs(struct ifaddrs_rsys ** ifap)80 getifaddrs(struct ifaddrs_rsys **ifap)
81 #else
82 getifaddrs(struct ifaddrs **ifap)
83 #endif
84 {
85 int err;
86 char *cp;
87 #if defined (_AIX)
88 struct ifaddrs_rsys *curr;
89 #else
90 struct ifaddrs *curr;
91 #endif
92
93 if (ifap == NULL) {
94 errno = EINVAL;
95 return (-1);
96 }
97 *ifap = NULL;
98 err = getallifaddrs(AF_UNSPEC, ifap, LIFC_ENABLED);
99 if (err == 0) {
100 for (curr = *ifap; curr != NULL; curr = curr->ifa_next) {
101 if ((cp = strchr(curr->ifa_name, ':')) != NULL)
102 *cp = '\0';
103 }
104 }
105 return (err);
106 }
107
108 void
109 #if defined (_AIX)
freeifaddrs(struct ifaddrs_rsys * ifa)110 freeifaddrs(struct ifaddrs_rsys *ifa)
111 #else
112 freeifaddrs(struct ifaddrs *ifa)
113 #endif
114 {
115 #if defined (_AIX)
116 struct ifaddrs_rsys *curr;
117 #else
118 struct ifaddrs *curr;
119 #endif
120
121 while (ifa != NULL) {
122 curr = ifa;
123 ifa = ifa->ifa_next;
124 free(curr->ifa_name);
125 free(curr->ifa_addr);
126 free(curr->ifa_netmask);
127 free(curr->ifa_dstaddr);
128 free(curr);
129 }
130 }
131
132 /*
133 * Returns all addresses configured on the system. If flags contain
134 * LIFC_ENABLED, only the addresses that are UP are returned.
135 * Address list that is returned by this function must be freed
136 * using freeifaddrs().
137 */
138 #if defined (_AIX)
139 int
getallifaddrs(sa_family_t af,struct ifaddrs_rsys ** ifap,int64_t flags)140 getallifaddrs(sa_family_t af, struct ifaddrs_rsys **ifap, int64_t flags)
141 {
142 struct ifreq *buf = NULL;
143 struct ifreq *ifrp;
144 struct ifreq ifrl;
145 struct in6_ifreq ifrl6;
146 int ret;
147 int s, n, iflen;
148 struct ifaddrs_rsys *curr, *prev;
149 sa_family_t ifr_af;
150 int sock4;
151 int sock6;
152 int err;
153 int ifsize;
154 char *s_ifrp, *e_ifrp;
155 int flag;
156
157 if ((sock4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
158 return (-1);
159 if ((sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
160 err = errno;
161 close(sock4);
162 errno = err;
163 return (-1);
164 }
165
166 retry:
167 /* Get all interfaces from SIOCGIFCONF */
168 ret = getallifs(sock4, af, &buf, &iflen, (flags & ~LIFC_ENABLED));
169 if (ret != 0)
170 goto fail;
171
172 /*
173 * Loop through the interfaces obtained from SIOCGIFCOMF
174 * and retrieve the addresses, netmask and flags.
175 */
176 prev = NULL;
177 s_ifrp = (char *)buf;
178 e_ifrp = (char *)buf + iflen;
179 *ifap = NULL;
180 while (s_ifrp < e_ifrp)
181 {
182 ifrp = (struct ifreq *)s_ifrp;
183 ifsize = sizeof(struct ifreq);
184
185 if (ifrp->ifr_addr.sa_len > sizeof(ifrp->ifr_ifru)) {
186 ifsize += ifrp->ifr_addr.sa_len - sizeof(ifrp->ifr_ifru);
187 }
188
189 /* Prepare for the ioctl call */
190 (void) strncpy(ifrl.ifr_name, ifrp->ifr_name,
191 sizeof (ifrl.ifr_name));
192 (void) strncpy(ifrl6.ifr_name, ifrp->ifr_name,
193 sizeof (ifrl.ifr_name));
194 ifr_af = ifrp->ifr_addr.sa_family;
195
196 if (ifr_af != AF_INET && ifr_af != AF_INET6)
197 goto next;
198
199 s = (ifr_af == AF_INET ? sock4 : sock6);
200
201 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifrl) < 0)
202 goto fail;
203
204 if ((flags & LIFC_ENABLED) && !(ifrl.ifr_flags & IFF_UP)) {
205 goto next;
206 }
207
208 /*
209 * Allocate the current list node. Each node contains data
210 * for one ifaddrs structure.
211 */
212 curr = calloc(1, sizeof (struct ifaddrs_rsys));
213 if (curr == NULL)
214 goto fail;
215
216 if (prev != NULL) {
217 prev->ifa_next = curr;
218 } else {
219 /* First node in the linked list */
220 *ifap = curr;
221 }
222 prev = curr;
223
224 /* AIXPORT : ifreq field names used instead of linux lifreq field names */
225 curr->ifa_flags = ifrl.ifr_flags;
226 if ((curr->ifa_name = strdup(ifrp->ifr_name)) == NULL)
227 goto fail;
228
229 curr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
230 if (curr->ifa_addr == NULL)
231 goto fail;
232 (void) memcpy(curr->ifa_addr, &ifrp->ifr_addr,
233 sizeof (struct sockaddr_storage));
234
235 /* Get the netmask */
236 if (ifr_af == AF_INET) {
237 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifrl) < 0) {
238 goto fail;
239 }
240 curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
241 if (curr->ifa_netmask == NULL)
242 goto fail;
243 (void) memcpy(curr->ifa_netmask, &ifrl.ifr_addr,
244 sizeof (struct sockaddr_storage));
245 } else {
246 if (ioctl(s, SIOCGIFNETMASK6, (caddr_t)&ifrl6) < 0) {
247 goto fail;
248 }
249 curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
250 if (curr->ifa_netmask == NULL)
251 goto fail;
252 (void) memcpy(curr->ifa_netmask, &ifrl6.ifr_Addr,
253 sizeof (struct sockaddr_storage));
254 }
255
256 /* Get the destination for a pt-pt interface */
257 if (curr->ifa_flags & IFF_POINTOPOINT) {
258 if (ifr_af == AF_INET) {
259 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifrl) < 0)
260 goto fail;
261 curr->ifa_dstaddr = malloc(
262 sizeof (struct sockaddr_storage));
263 if (curr->ifa_dstaddr == NULL)
264 goto fail;
265 (void) memcpy(curr->ifa_dstaddr, &ifrl.ifr_addr,
266 sizeof (struct sockaddr_storage));
267 } else {
268 if (ioctl(s, SIOCGIFDSTADDR6, (caddr_t)&ifrl6) < 0)
269 goto fail;
270 curr->ifa_dstaddr = malloc(
271 sizeof (struct sockaddr_storage));
272 if (curr->ifa_dstaddr == NULL)
273 goto fail;
274 (void) memcpy(curr->ifa_dstaddr, &ifrl6.ifr_Addr,
275 sizeof (struct sockaddr_storage));
276 }
277 /* Do not get broadcast address for IPv6 */
278 } else if ((curr->ifa_flags & IFF_BROADCAST) && (ifr_af == AF_INET)) {
279 if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifrl) < 0)
280 goto fail;
281 curr->ifa_broadaddr = malloc(
282 sizeof (struct sockaddr_storage));
283 if (curr->ifa_broadaddr == NULL)
284 goto fail;
285 (void) memcpy(curr->ifa_broadaddr, &ifrl.ifr_addr,
286 sizeof (struct sockaddr_storage));
287 }
288 next:
289 s_ifrp += ifsize;
290 }
291 free(buf);
292 close(sock4);
293 close(sock6);
294 return (0);
295 fail:
296 err = errno;
297 free(buf);
298 freeifaddrs(*ifap);
299 *ifap = NULL;
300 if (err == ENXIO)
301 goto retry;
302 close(sock4);
303 close(sock6);
304 errno = err;
305 return (-1);
306 }
307
308 /*
309 * Do a SIOCGIFCONF and store all the interfaces in `buf'.
310 */
311 int
getallifs(int s,sa_family_t af,struct ifreq ** ifr,int * iflen,int64_t ifc_flags)312 getallifs(int s, sa_family_t af, struct ifreq **ifr, int *iflen,
313 int64_t ifc_flags)
314 {
315 int ifsize;
316 struct ifconf ifc;
317 size_t bufsize;
318 char *tmp;
319 caddr_t *buf = (caddr_t *)ifr;
320
321 *buf = NULL;
322 retry:
323 if (ioctl(s, SIOCGSIZIFCONF, &ifsize) < 0)
324 goto fail;
325
326 /*
327 * When calculating the buffer size needed, add a small number
328 * of interfaces to those we counted. We do this to capture
329 * the interface status of potential interfaces which may have
330 * been plumbed between the SIOCGSIZIFCONF and the SIOCGIFCONF.
331 */
332 bufsize = ifsize + (4 * sizeof (struct in6_ifreq));
333
334 if ((tmp = realloc(*buf, bufsize)) == NULL)
335 goto fail;
336
337 *buf = tmp;
338 ifc.ifc_buf = *buf;
339 ifc.ifc_len = bufsize;
340 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0)
341 goto fail;
342
343 *iflen = ifc.ifc_len;
344 if (*iflen >= bufsize) {
345 /*
346 * If every entry was filled, there are probably
347 * more interfaces than (ifn + 4)
348 * Redo the ioctls SIOCGSIZIFCONF and SIOCGIFCONF to
349 * get all the interfaces.
350 */
351 goto retry;
352 }
353 return (0);
354 fail:
355 free(*buf);
356 *buf = NULL;
357 return (-1);
358 }
359 #else /* _AIX */
360 int
getallifaddrs(sa_family_t af,struct ifaddrs ** ifap,int64_t flags)361 getallifaddrs(sa_family_t af, struct ifaddrs **ifap, int64_t flags)
362 {
363 struct lifreq *buf = NULL;
364 struct lifreq *lifrp;
365 struct lifreq lifrl;
366 int ret;
367 int s, n, numifs;
368 struct ifaddrs *curr, *prev;
369 sa_family_t lifr_af;
370 int sock4;
371 int sock6;
372 int err;
373
374 if ((sock4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
375 return (-1);
376 if ((sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
377 err = errno;
378 close(sock4);
379 errno = err;
380 return (-1);
381 }
382
383 retry:
384 /* Get all interfaces from SIOCGLIFCONF */
385 ret = getallifs(sock4, af, &buf, &numifs, (flags & ~LIFC_ENABLED));
386 if (ret != 0)
387 goto fail;
388
389 /*
390 * Loop through the interfaces obtained from SIOCGLIFCOMF
391 * and retrieve the addresses, netmask and flags.
392 */
393 prev = NULL;
394 lifrp = buf;
395 *ifap = NULL;
396 for (n = 0; n < numifs; n++, lifrp++) {
397
398 /* Prepare for the ioctl call */
399 (void) strncpy(lifrl.lifr_name, lifrp->lifr_name,
400 sizeof (lifrl.lifr_name));
401 lifr_af = lifrp->lifr_addr.ss_family;
402 if (af != AF_UNSPEC && lifr_af != af)
403 continue;
404
405 s = (lifr_af == AF_INET ? sock4 : sock6);
406
407 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
408 goto fail;
409 if ((flags & LIFC_ENABLED) && !(lifrl.lifr_flags & IFF_UP))
410 continue;
411
412 /*
413 * Allocate the current list node. Each node contains data
414 * for one ifaddrs structure.
415 */
416 curr = calloc(1, sizeof (struct ifaddrs));
417 if (curr == NULL)
418 goto fail;
419
420 if (prev != NULL) {
421 prev->ifa_next = curr;
422 } else {
423 /* First node in the linked list */
424 *ifap = curr;
425 }
426 prev = curr;
427
428 curr->ifa_flags = lifrl.lifr_flags;
429 if ((curr->ifa_name = strdup(lifrp->lifr_name)) == NULL)
430 goto fail;
431
432 curr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
433 if (curr->ifa_addr == NULL)
434 goto fail;
435 (void) memcpy(curr->ifa_addr, &lifrp->lifr_addr,
436 sizeof (struct sockaddr_storage));
437
438 /* Get the netmask */
439 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifrl) < 0)
440 goto fail;
441 curr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
442 if (curr->ifa_netmask == NULL)
443 goto fail;
444 (void) memcpy(curr->ifa_netmask, &lifrl.lifr_addr,
445 sizeof (struct sockaddr_storage));
446
447 /* Get the destination for a pt-pt interface */
448 if (curr->ifa_flags & IFF_POINTOPOINT) {
449 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifrl) < 0)
450 goto fail;
451 curr->ifa_dstaddr = malloc(
452 sizeof (struct sockaddr_storage));
453 if (curr->ifa_dstaddr == NULL)
454 goto fail;
455 (void) memcpy(curr->ifa_dstaddr, &lifrl.lifr_addr,
456 sizeof (struct sockaddr_storage));
457 } else if (curr->ifa_flags & IFF_BROADCAST) {
458 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifrl) < 0)
459 goto fail;
460 curr->ifa_broadaddr = malloc(
461 sizeof (struct sockaddr_storage));
462 if (curr->ifa_broadaddr == NULL)
463 goto fail;
464 (void) memcpy(curr->ifa_broadaddr, &lifrl.lifr_addr,
465 sizeof (struct sockaddr_storage));
466 }
467
468 }
469 free(buf);
470 close(sock4);
471 close(sock6);
472 return (0);
473 fail:
474 err = errno;
475 free(buf);
476 freeifaddrs(*ifap);
477 *ifap = NULL;
478 if (err == ENXIO)
479 goto retry;
480 close(sock4);
481 close(sock6);
482 errno = err;
483 return (-1);
484 }
485
486 /*
487 * Do a SIOCGLIFCONF and store all the interfaces in `buf'.
488 */
489 int
getallifs(int s,sa_family_t af,struct lifreq ** lifr,int * numifs,int64_t lifc_flags)490 getallifs(int s, sa_family_t af, struct lifreq **lifr, int *numifs,
491 int64_t lifc_flags)
492 {
493 struct lifnum lifn;
494 struct lifconf lifc;
495 size_t bufsize;
496 char *tmp;
497 caddr_t *buf = (caddr_t *)lifr;
498
499 lifn.lifn_family = af;
500 lifn.lifn_flags = lifc_flags;
501
502 *buf = NULL;
503 retry:
504 if (ioctl(s, SIOCGLIFNUM, &lifn) < 0)
505 goto fail;
506
507 /*
508 * When calculating the buffer size needed, add a small number
509 * of interfaces to those we counted. We do this to capture
510 * the interface status of potential interfaces which may have
511 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
512 */
513 bufsize = (lifn.lifn_count + 4) * sizeof (struct lifreq);
514
515 if ((tmp = realloc(*buf, bufsize)) == NULL)
516 goto fail;
517
518 *buf = tmp;
519 lifc.lifc_family = af;
520 lifc.lifc_flags = lifc_flags;
521 lifc.lifc_len = bufsize;
522 lifc.lifc_buf = *buf;
523 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0)
524 goto fail;
525
526 *numifs = lifc.lifc_len / sizeof (struct lifreq);
527 if (*numifs >= (lifn.lifn_count + 4)) {
528 /*
529 * If every entry was filled, there are probably
530 * more interfaces than (lifn.lifn_count + 4).
531 * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to
532 * get all the interfaces.
533 */
534 goto retry;
535 }
536 return (0);
537 fail:
538 free(*buf);
539 *buf = NULL;
540 return (-1);
541 }
542 #endif /* _AIX */
543 #endif /* HAVE_GETIFADDRS */
544