4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2017 RackTop Systems.
28 #include <nss_dbdefs.h>
29 #include <netinet/in.h>
30 #include <sys/socket.h>
33 #include <sys/sockio.h>
34 #include <sys/types.h>
38 #include <libsocket_priv.h>
41 * Create a linked list of `struct ifaddrs' structures, one for each
42 * address that is UP. If successful, store the list in *ifap and
43 * return 0. On errors, return -1 and set `errno'.
45 * The storage returned in *ifap is allocated dynamically and can
46 * only be properly freed by passing it to `freeifaddrs'.
49 getifaddrs(struct ifaddrs
**ifap
)
60 err
= getallifaddrs(AF_UNSPEC
, ifap
, LIFC_ENABLED
);
62 for (curr
= *ifap
; curr
!= NULL
; curr
= curr
->ifa_next
) {
63 if ((cp
= strchr(curr
->ifa_name
, ':')) != NULL
)
71 freeifaddrs(struct ifaddrs
*ifa
)
80 free(curr
->ifa_netmask
);
81 free(curr
->ifa_dstaddr
);
87 * Returns all addresses configured on the system. If flags contain
88 * LIFC_ENABLED, only the addresses that are UP are returned.
89 * Address list that is returned by this function must be freed
90 * using freeifaddrs().
93 getallifaddrs(sa_family_t af
, struct ifaddrs
**ifap
, int64_t flags
)
95 struct lifreq
*buf
= NULL
;
100 struct ifaddrs
*curr
, *prev
;
107 * Initialize ifap to NULL so we can safely call freeifaddrs
108 * on it in case of error.
114 if ((sock4
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
116 if ((sock6
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
124 /* Get all interfaces from SIOCGLIFCONF */
125 ret
= getallifs(sock4
, af
, &buf
, &numifs
, (flags
& ~LIFC_ENABLED
));
130 * Loop through the interfaces obtained from SIOCGLIFCOMF
131 * and retrieve the addresses, netmask and flags.
135 for (n
= 0; n
< numifs
; n
++, lifrp
++) {
137 /* Prepare for the ioctl call */
138 (void) strncpy(lifrl
.lifr_name
, lifrp
->lifr_name
,
139 sizeof (lifrl
.lifr_name
));
140 lifr_af
= lifrp
->lifr_addr
.ss_family
;
141 if (af
!= AF_UNSPEC
&& lifr_af
!= af
)
144 s
= (lifr_af
== AF_INET
? sock4
: sock6
);
146 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifrl
) < 0)
148 if ((flags
& LIFC_ENABLED
) && !(lifrl
.lifr_flags
& IFF_UP
))
152 * Allocate the current list node. Each node contains data
153 * for one ifaddrs structure.
155 curr
= calloc(1, sizeof (struct ifaddrs
));
160 prev
->ifa_next
= curr
;
162 /* First node in the linked list */
167 curr
->ifa_flags
= lifrl
.lifr_flags
;
168 if ((curr
->ifa_name
= strdup(lifrp
->lifr_name
)) == NULL
)
171 curr
->ifa_addr
= malloc(sizeof (struct sockaddr_storage
));
172 if (curr
->ifa_addr
== NULL
)
174 (void) memcpy(curr
->ifa_addr
, &lifrp
->lifr_addr
,
175 sizeof (struct sockaddr_storage
));
177 /* Get the netmask */
178 if (ioctl(s
, SIOCGLIFNETMASK
, (caddr_t
)&lifrl
) < 0)
180 curr
->ifa_netmask
= malloc(sizeof (struct sockaddr_storage
));
181 if (curr
->ifa_netmask
== NULL
)
183 (void) memcpy(curr
->ifa_netmask
, &lifrl
.lifr_addr
,
184 sizeof (struct sockaddr_storage
));
186 /* Get the destination for a pt-pt interface */
187 if (curr
->ifa_flags
& IFF_POINTOPOINT
) {
188 if (ioctl(s
, SIOCGLIFDSTADDR
, (caddr_t
)&lifrl
) < 0)
190 curr
->ifa_dstaddr
= malloc(
191 sizeof (struct sockaddr_storage
));
192 if (curr
->ifa_dstaddr
== NULL
)
194 (void) memcpy(curr
->ifa_dstaddr
, &lifrl
.lifr_addr
,
195 sizeof (struct sockaddr_storage
));
196 } else if (curr
->ifa_flags
& IFF_BROADCAST
) {
197 if (ioctl(s
, SIOCGLIFBRDADDR
, (caddr_t
)&lifrl
) < 0)
199 curr
->ifa_broadaddr
= malloc(
200 sizeof (struct sockaddr_storage
));
201 if (curr
->ifa_broadaddr
== NULL
)
203 (void) memcpy(curr
->ifa_broadaddr
, &lifrl
.lifr_addr
,
204 sizeof (struct sockaddr_storage
));
226 * Do a SIOCGLIFCONF and store all the interfaces in `buf'.
229 getallifs(int s
, sa_family_t af
, struct lifreq
**lifr
, int *numifs
,
236 caddr_t
*buf
= (caddr_t
*)lifr
;
238 lifn
.lifn_family
= af
;
239 lifn
.lifn_flags
= lifc_flags
;
243 if (ioctl(s
, SIOCGLIFNUM
, &lifn
) < 0)
247 * When calculating the buffer size needed, add a small number
248 * of interfaces to those we counted. We do this to capture
249 * the interface status of potential interfaces which may have
250 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
252 bufsize
= (lifn
.lifn_count
+ 4) * sizeof (struct lifreq
);
254 if ((tmp
= realloc(*buf
, bufsize
)) == NULL
)
258 lifc
.lifc_family
= af
;
259 lifc
.lifc_flags
= lifc_flags
;
260 lifc
.lifc_len
= bufsize
;
261 lifc
.lifc_buf
= *buf
;
262 if (ioctl(s
, SIOCGLIFCONF
, (char *)&lifc
) < 0)
265 *numifs
= lifc
.lifc_len
/ sizeof (struct lifreq
);
266 if (*numifs
>= (lifn
.lifn_count
+ 4)) {
268 * If every entry was filled, there are probably
269 * more interfaces than (lifn.lifn_count + 4).
270 * Redo the ioctls SIOCGLIFNUM and SIOCGLIFCONF to
271 * get all the interfaces.