3a91bb40d2ac44c87b8ff1885d8ca0be22b23f5b
[ira/wip.git] / lib / replace / getifaddrs.c
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
7    
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.
12    
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.
17    
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/>.
20 */
21
22 #define SOCKET_WRAPPER_NOT_REPLACE
23
24 #include "replace.h"
25 #include "system/network.h"
26
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <sys/types.h>
30
31 #ifdef HAVE_SYS_TIME_H
32 #include <sys/time.h>
33 #endif
34
35 #ifndef SIOCGIFCONF
36 #ifdef HAVE_SYS_SOCKIO_H
37 #include <sys/sockio.h>
38 #endif
39 #endif
40
41 #ifdef HAVE_IFACE_GETIFADDRS
42 #define _FOUND_IFACE_ANY
43 #else
44
45 void rep_freeifaddrs(struct ifaddrs *ifp)
46 {
47         if (ifp != NULL) {
48                 free(ifp->ifa_name);
49                 free(ifp->ifa_addr);
50                 free(ifp->ifa_netmask);
51                 free(ifp->ifa_dstaddr);
52                 freeifaddrs(ifp->ifa_next);
53                 free(ifp);
54         }
55 }
56
57 static struct sockaddr *sockaddr_dup(struct sockaddr *sa)
58 {
59         struct sockaddr *ret;
60         socklen_t socklen;
61 #ifdef HAVE_SOCKADDR_SA_LEN
62         socklen = sa->sa_len;
63 #else
64         socklen = sizeof(struct sockaddr_storage);
65 #endif
66         ret = calloc(1, socklen);
67         if (ret == NULL)
68                 return NULL;
69         memcpy(ret, sa, socklen);
70         return ret;
71 }
72 #endif
73
74 #if HAVE_IFACE_IFCONF
75
76 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
77    V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
78
79    It probably also works on any BSD style system.  */
80
81 int rep_getifaddrs(struct ifaddrs **ifap)
82 {
83         struct ifconf ifc;
84         char buff[8192];
85         int fd, i, n;
86         struct ifreq *ifr=NULL;
87         struct ifaddrs *curif;
88         struct ifaddrs *lastif = NULL;
89
90         *ifap = NULL;
91
92         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
93                 return -1;
94         }
95   
96         ifc.ifc_len = sizeof(buff);
97         ifc.ifc_buf = buff;
98
99         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
100                 close(fd);
101                 return -1;
102         } 
103
104         ifr = ifc.ifc_req;
105   
106         n = ifc.ifc_len / sizeof(struct ifreq);
107
108         /* Loop through interfaces, looking for given IP address */
109         for (i=n-1; i>=0; i--) {
110                 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) {
111                         freeifaddrs(*ifap);
112                         return -1;
113                 }
114
115                 curif = calloc(1, sizeof(struct ifaddrs));
116                 curif->ifa_name = strdup(ifr[i].ifr_name);
117                 curif->ifa_flags = ifr[i].ifr_flags;
118                 curif->ifa_dstaddr = NULL;
119                 curif->ifa_data = NULL;
120                 curif->ifa_next = NULL;
121
122                 curif->ifa_addr = NULL;
123                 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) {
124                         curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
125                 }
126
127                 curif->ifa_netmask = NULL;
128                 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) {
129                         curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
130                 }
131
132                 if (lastif == NULL) {
133                         *ifap = curif;
134                 } else {
135                         lastif->ifa_next = curif;
136                 }
137                 lastif = curif;
138         }
139
140         close(fd);
141
142         return 0;
143 }  
144
145 #define _FOUND_IFACE_ANY
146 #endif /* HAVE_IFACE_IFCONF */
147 #ifdef HAVE_IFACE_IFREQ
148
149 #ifndef I_STR
150 #include <sys/stropts.h>
151 #endif
152
153 /****************************************************************************
154 this should cover most of the streams based systems
155 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
156 ****************************************************************************/
157 int rep_getifaddrs(struct ifaddrs **ifap)
158 {
159         struct ifreq ifreq;
160         struct strioctl strioctl;
161         char buff[8192];
162         int fd, i, n;
163         struct ifreq *ifr=NULL;
164         struct ifaddrs *curif;
165         struct ifaddrs *lastif = NULL;
166
167         *ifap = NULL;
168
169         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
170                 return -1;
171         }
172   
173         strioctl.ic_cmd = SIOCGIFCONF;
174         strioctl.ic_dp  = buff;
175         strioctl.ic_len = sizeof(buff);
176         if (ioctl(fd, I_STR, &strioctl) < 0) {
177                 close(fd);
178                 return -1;
179         } 
180
181         /* we can ignore the possible sizeof(int) here as the resulting
182            number of interface structures won't change */
183         n = strioctl.ic_len / sizeof(struct ifreq);
184
185         /* we will assume that the kernel returns the length as an int
186            at the start of the buffer if the offered size is a
187            multiple of the structure size plus an int */
188         if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
189                 ifr = (struct ifreq *)(buff + sizeof(int));  
190         } else {
191                 ifr = (struct ifreq *)buff;  
192         }
193
194         /* Loop through interfaces */
195
196         for (i = 0; i<n; i++) {
197                 ifreq = ifr[i];
198   
199                 curif = calloc(1, sizeof(struct ifaddrs));
200                 if (lastif == NULL) {
201                         *ifap = curif;
202                 } else {
203                         lastif->ifa_next = curif;
204                 }
205
206                 strioctl.ic_cmd = SIOCGIFFLAGS;
207                 strioctl.ic_dp  = (char *)&ifreq;
208                 strioctl.ic_len = sizeof(struct ifreq);
209                 if (ioctl(fd, I_STR, &strioctl) != 0) {
210                         freeifaddrs(*ifap);
211                         return -1;
212                 }
213
214                 curif->ifa_flags = ifreq.ifr_flags;
215                 
216                 strioctl.ic_cmd = SIOCGIFADDR;
217                 strioctl.ic_dp  = (char *)&ifreq;
218                 strioctl.ic_len = sizeof(struct ifreq);
219                 if (ioctl(fd, I_STR, &strioctl) != 0) {
220                         freeifaddrs(*ifap);
221                         return -1;
222                 }
223
224                 curif->ifa_name = strdup(ifreq.ifr_name);
225                 curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
226                 curif->ifa_dstaddr = NULL;
227                 curif->ifa_data = NULL;
228                 curif->ifa_next = NULL;
229                 curif->ifa_netmask = NULL;
230
231                 strioctl.ic_cmd = SIOCGIFNETMASK;
232                 strioctl.ic_dp  = (char *)&ifreq;
233                 strioctl.ic_len = sizeof(struct ifreq);
234                 if (ioctl(fd, I_STR, &strioctl) != 0) {
235                         freeifaddrs(*ifap);
236                         return -1;
237                 }
238
239                 curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
240
241                 lastif = curif;
242         }
243
244         close(fd);
245
246         return 0;
247 }
248
249 #define _FOUND_IFACE_ANY
250 #endif /* HAVE_IFACE_IFREQ */
251 #ifdef HAVE_IFACE_AIX
252
253 /****************************************************************************
254 this one is for AIX (tested on 4.2)
255 ****************************************************************************/
256 int rep_getifaddrs(struct ifaddrs **ifap)
257 {
258         char buff[8192];
259         int fd, i;
260         struct ifconf ifc;
261         struct ifreq *ifr=NULL;
262         struct ifaddrs *curif;
263         struct ifaddrs *lastif = NULL;
264
265         *ifap = NULL;
266
267         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
268                 return -1;
269         }
270
271         ifc.ifc_len = sizeof(buff);
272         ifc.ifc_buf = buff;
273
274         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
275                 close(fd);
276                 return -1;
277         }
278
279         ifr = ifc.ifc_req;
280
281         /* Loop through interfaces */
282         i = ifc.ifc_len;
283
284         while (i > 0) {
285                 uint_t inc;
286
287                 inc = ifr->ifr_addr.sa_len;
288
289                 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
290                         freeaddrinfo(*ifap);
291                         return -1;
292                 }
293
294                 curif = calloc(1, sizeof(struct ifaddrs));
295                 if (lastif == NULL) {
296                         *ifap = curif;
297                 } else {
298                         lastif->ifa_next = curif;
299                 }
300
301                 curif->ifa_name = strdup(ifr->ifr_name);
302                 curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
303                 curif->ifa_dstaddr = NULL;
304                 curif->ifa_data = NULL;
305                 curif->ifa_netmask = NULL;
306                 curif->ifa_next = NULL;
307
308                 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
309                         freeaddrinfo(*ifap);
310                         return -1;
311                 }
312
313                 curif->ifa_flags = ifr->ifr_flags;
314
315                 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
316                         freeaddrinfo(*ifap);
317                         return -1;
318                 }
319
320                 curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
321
322                 lastif = curif;
323
324         next:
325                 /*
326                  * Patch from Archie Cobbs (archie@whistle.com).  The
327                  * addresses in the SIOCGIFCONF interface list have a
328                  * minimum size. Usually this doesn't matter, but if
329                  * your machine has tunnel interfaces, etc. that have
330                  * a zero length "link address", this does matter.  */
331
332                 if (inc < sizeof(ifr->ifr_addr))
333                         inc = sizeof(ifr->ifr_addr);
334                 inc += IFNAMSIZ;
335
336                 ifr = (struct ifreq*) (((char*) ifr) + inc);
337                 i -= inc;
338         }
339
340         close(fd);
341         return 0;
342 }
343
344 #define _FOUND_IFACE_ANY
345 #endif /* HAVE_IFACE_AIX */
346 #ifndef _FOUND_IFACE_ANY
347 int rep_getifaddrs(struct ifaddrs **ifap)
348 {
349         errno = ENOSYS;
350         return -1;
351 }
352 #endif