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