r26469: Fix paths, only include IPv4 addresses for now.
[Samba.git] / source / lib / replace / getifaddrs.c
blobe04c023209baa11f148f192d6b8a920afc013bff
1 /*
2 Unix SMB/CIFS implementation.
3 Samba utility functions
4 Copyright (C) Andrew Tridgell 1998
5 Copyright (C) Jeremy Allison 2007
6 Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "replace.h"
23 #include "system/network.h"
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <sys/types.h>
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
33 #ifndef SIOCGIFCONF
34 #ifdef HAVE_SYS_SOCKIO_H
35 #include <sys/sockio.h>
36 #endif
37 #endif
39 #ifdef HAVE_IFACE_GETIFADDRS
40 #define _FOUND_IFACE_ANY
41 #else
43 void freeifaddrs(struct ifaddrs *ifp)
45 free(ifp->ifa_name);
46 free(ifp->ifa_addr);
47 free(ifp->ifa_netmask);
48 free(ifp->ifa_dstaddr);
49 if (ifp->ifa_next != NULL)
50 freeifaddrs(ifp->ifa_next);
51 free(ifp);
54 struct sockaddr *sockaddr_dup(struct sockaddr *sa)
56 struct sockaddr *ret = calloc(1, sa->sa_len);
57 if (ret == NULL)
58 return NULL;
59 memcpy(ret, sa, sa->sa_len);
60 return ret;
62 #endif
64 #if HAVE_IFACE_IFCONF
66 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
67 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
69 It probably also works on any BSD style system. */
71 int getifaddrs(struct ifaddrs **ifap)
73 struct ifconf ifc;
74 char buff[8192];
75 int fd, i, n;
76 struct ifreq *ifr=NULL;
77 int total = 0;
78 struct in_addr ipaddr;
79 struct in_addr nmask;
80 char *iname;
81 struct ifaddrs *curif, *lastif;
83 *ifap = NULL;
85 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
86 return -1;
89 ifc.ifc_len = sizeof(buff);
90 ifc.ifc_buf = buff;
92 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
93 close(fd);
94 return -1;
97 ifr = ifc.ifc_req;
99 n = ifc.ifc_len / sizeof(struct ifreq);
101 /* Loop through interfaces, looking for given IP address */
102 for (i=n-1;i>=0 && total < max_interfaces;i--) {
103 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
104 freeifaddrs(*ifap);
107 curif = calloc(1, sizeof(struct ifaddrs));
108 if (lastif == NULL) {
109 *ifap = curif;
110 } else {
111 lastif->ifa_next = (*ifap);
114 curif->ifa_name = strdup(ifr[i].ifr_name);
115 curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
116 curif->ifa_dstaddr = NULL;
117 curif->ifa_data = NULL;
118 curif->ifa_next = NULL;
119 curif->ifa_netmask = NULL;
121 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
122 freeifaddrs(*ifap);
123 return -1;
126 curif->ifa_flags = ifr[i].ifr_flags;
128 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
129 freeifaddrs(*ifap);
130 return -1;
133 curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
135 lastif = curif;
138 close(fd);
140 return 0;
143 #define _FOUND_IFACE_ANY
144 #endif /* HAVE_IFACE_IFCONF */
145 #ifdef HAVE_IFACE_IFREQ
147 #ifndef I_STR
148 #include <sys/stropts.h>
149 #endif
151 /****************************************************************************
152 this should cover most of the streams based systems
153 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
154 ****************************************************************************/
155 int getifaddrs(struct ifaddrs **ifap)
157 struct ifreq ifreq;
158 struct strioctl strioctl;
159 char buff[8192];
160 int fd, i, n;
161 struct ifreq *ifr=NULL;
162 int total = 0;
163 struct in_addr ipaddr;
164 struct in_addr nmask;
165 char *iname;
166 struct ifaddrs *curif;
168 *ifap = NULL;
170 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
171 return -1;
174 strioctl.ic_cmd = SIOCGIFCONF;
175 strioctl.ic_dp = buff;
176 strioctl.ic_len = sizeof(buff);
177 if (ioctl(fd, I_STR, &strioctl) < 0) {
178 close(fd);
179 return -1;
182 /* we can ignore the possible sizeof(int) here as the resulting
183 number of interface structures won't change */
184 n = strioctl.ic_len / sizeof(struct ifreq);
186 /* we will assume that the kernel returns the length as an int
187 at the start of the buffer if the offered size is a
188 multiple of the structure size plus an int */
189 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
190 ifr = (struct ifreq *)(buff + sizeof(int));
191 } else {
192 ifr = (struct ifreq *)buff;
195 /* Loop through interfaces */
197 for (i = 0; i<n && total < max_interfaces; i++) {
198 ifreq = ifr[i];
200 curif = calloc(1, sizeof(struct ifaddrs));
201 if (lastif == NULL) {
202 *ifap = curif;
203 } else {
204 lastif->ifa_next = (*ifap);
207 strioctl.ic_cmd = SIOCGIFFLAGS;
208 strioctl.ic_dp = (char *)&ifreq;
209 strioctl.ic_len = sizeof(struct ifreq);
210 if (ioctl(fd, I_STR, &strioctl) != 0) {
211 freeifaddrs(*ifap);
212 return -1;
215 curif->ifa_flags = ifreq.ifr_flags;
217 strioctl.ic_cmd = SIOCGIFADDR;
218 strioctl.ic_dp = (char *)&ifreq;
219 strioctl.ic_len = sizeof(struct ifreq);
220 if (ioctl(fd, I_STR, &strioctl) != 0) {
221 freeifaddrs(*ifap);
222 return -1;
225 curif->ifa_name = strdup(ifreq.ifr_name);
226 curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
227 curif->ifa_dstaddr = NULL;
228 curif->ifa_data = NULL;
229 curif->ifa_next = NULL;
230 curif->ifa_netmask = NULL;
232 strioctl.ic_cmd = SIOCGIFNETMASK;
233 strioctl.ic_dp = (char *)&ifreq;
234 strioctl.ic_len = sizeof(struct ifreq);
235 if (ioctl(fd, I_STR, &strioctl) != 0) {
236 freeifaddrs(*ifap);
237 return -1;
240 curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
242 lastif = curif;
245 close(fd);
247 return 0;
250 #define _FOUND_IFACE_ANY
251 #endif /* HAVE_IFACE_IFREQ */
252 #ifdef HAVE_IFACE_AIX
254 /****************************************************************************
255 this one is for AIX (tested on 4.2)
256 ****************************************************************************/
257 int getifaddrs(struct ifaddrs **ifap)
259 char buff[8192];
260 int fd, i;
261 struct ifconf ifc;
262 struct ifreq *ifr=NULL;
263 struct in_addr ipaddr;
264 struct in_addr nmask;
265 char *iname;
266 int total = 0;
267 struct ifaddrs *curif, *lastif;
269 *ifap = NULL;
271 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
272 return -1;
275 ifc.ifc_len = sizeof(buff);
276 ifc.ifc_buf = buff;
278 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
279 close(fd);
280 return -1;
283 ifr = ifc.ifc_req;
285 /* Loop through interfaces */
286 i = ifc.ifc_len;
288 while (i > 0) {
289 uint_t inc;
291 inc = ifr->ifr_addr.sa_len;
293 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
294 freeaddrinfo(*ifap);
295 return -1;
298 curif = calloc(1, sizeof(struct ifaddrs));
299 if (lastif == NULL) {
300 *ifap = curif;
301 } else {
302 lastif->ifa_next = (*ifap);
305 curif->ifa_name = strdup(ifr->ifr_name);
306 curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
307 curif->ifa_dstaddr = NULL;
308 curif->ifa_data = NULL;
309 curif->ifa_netmask = NULL;
310 curif->ifa_next = NULL;
312 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
313 freeaddrinfo(*ifap);
314 return -1;
317 curif->ifa_flags = ifr->ifr_flags;
319 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
320 freeaddrinfo(*ifap);
321 return -1;
324 curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
326 lastif = curif;
328 next:
330 * Patch from Archie Cobbs (archie@whistle.com). The
331 * addresses in the SIOCGIFCONF interface list have a
332 * minimum size. Usually this doesn't matter, but if
333 * your machine has tunnel interfaces, etc. that have
334 * a zero length "link address", this does matter. */
336 if (inc < sizeof(ifr->ifr_addr))
337 inc = sizeof(ifr->ifr_addr);
338 inc += IFNAMSIZ;
340 ifr = (struct ifreq*) (((char*) ifr) + inc);
341 i -= inc;
344 close(fd);
345 return 0;
348 #define _FOUND_IFACE_ANY
349 #endif /* HAVE_IFACE_AIX */
350 #ifndef _FOUND_IFACE_ANY
351 int getifaddrs(struct ifaddrs **ifap)
353 errno = ENOSYS;
354 return -1;
356 #endif
358 #ifdef AUTOCONF_TEST
359 /* this is the autoconf driver to test get_interfaces() */
361 int main()
363 struct ifaddrs *ifs = NULL;
364 int ret;
366 ret = getifaddrs(&ifs);
367 if (ret != 0) {
368 perror("getifaddrs() failed");
369 return 1;
372 while (ifs) {
373 printf("%-10s ", ifs->ifa_name);
374 if (ifs->ifa_addr != NULL &&
375 ifs->ifa_addr->sa_family == AF_INET) {
376 printf("IP=%s ", inet_ntoa(((struct sockaddr_in *)ifs->ifa_addr)->sin_addr));
377 if (ifs->ifa_netmask != NULL)
378 printf("NETMASK=%s", inet_ntoa(((struct sockaddr_in *)ifs->ifa_netmask)->sin_addr));
380 printf("\n");
381 ifs = ifs->ifa_next;
383 return 0;
385 #endif