s3:libsmb: also remember the optional server name from the negprot response
[Samba/vl.git] / lib / replace / getifaddrs.c
blob84d790689dd7cb7484e0d20d9ad76e7b892a4aef
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 #define SOCKET_WRAPPER_NOT_REPLACE
24 #include "replace.h"
25 #include "system/network.h"
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <sys/types.h>
31 #ifdef HAVE_SYS_TIME_H
32 #include <sys/time.h>
33 #endif
35 #ifndef SIOCGIFCONF
36 #ifdef HAVE_SYS_SOCKIO_H
37 #include <sys/sockio.h>
38 #endif
39 #endif
41 #ifdef HAVE_IFACE_GETIFADDRS
42 #define _FOUND_IFACE_ANY
43 #else
45 void rep_freeifaddrs(struct ifaddrs *ifp)
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);
57 static struct sockaddr *sockaddr_dup(struct sockaddr *sa)
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;
72 #endif
74 #if HAVE_IFACE_IFCONF
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.
79 It probably also works on any BSD style system. */
81 int rep_getifaddrs(struct ifaddrs **ifap)
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;
90 *ifap = NULL;
92 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
93 return -1;
96 ifc.ifc_len = sizeof(buff);
97 ifc.ifc_buf = buff;
99 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
100 close(fd);
101 return -1;
104 ifr = ifc.ifc_req;
106 n = ifc.ifc_len / sizeof(struct ifreq);
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;
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;
122 curif->ifa_addr = NULL;
123 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) {
124 curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
127 curif->ifa_netmask = NULL;
128 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) {
129 curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
132 if (lastif == NULL) {
133 *ifap = curif;
134 } else {
135 lastif->ifa_next = curif;
137 lastif = curif;
140 close(fd);
142 return 0;
145 #define _FOUND_IFACE_ANY
146 #endif /* HAVE_IFACE_IFCONF */
147 #ifdef HAVE_IFACE_IFREQ
149 #ifndef I_STR
150 #include <sys/stropts.h>
151 #endif
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)
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;
167 *ifap = NULL;
169 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
170 return -1;
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;
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);
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;
194 /* Loop through interfaces */
196 for (i = 0; i<n; i++) {
197 ifreq = ifr[i];
199 curif = calloc(1, sizeof(struct ifaddrs));
200 if (lastif == NULL) {
201 *ifap = curif;
202 } else {
203 lastif->ifa_next = curif;
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;
214 curif->ifa_flags = ifreq.ifr_flags;
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;
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;
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;
239 curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
241 lastif = curif;
244 close(fd);
246 return 0;
249 #define _FOUND_IFACE_ANY
250 #endif /* HAVE_IFACE_IFREQ */
251 #ifdef HAVE_IFACE_AIX
253 /****************************************************************************
254 this one is for AIX (tested on 4.2)
255 ****************************************************************************/
256 int rep_getifaddrs(struct ifaddrs **ifap)
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;
265 *ifap = NULL;
267 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
268 return -1;
271 ifc.ifc_len = sizeof(buff);
272 ifc.ifc_buf = buff;
274 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
275 close(fd);
276 return -1;
279 ifr = ifc.ifc_req;
281 /* Loop through interfaces */
282 i = ifc.ifc_len;
284 while (i > 0) {
285 unsigned int inc;
287 inc = ifr->ifr_addr.sa_len;
289 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
290 freeaddrinfo(*ifap);
291 return -1;
294 curif = calloc(1, sizeof(struct ifaddrs));
295 if (lastif == NULL) {
296 *ifap = curif;
297 } else {
298 lastif->ifa_next = curif;
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;
308 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
309 freeaddrinfo(*ifap);
310 return -1;
313 curif->ifa_flags = ifr->ifr_flags;
315 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
316 freeaddrinfo(*ifap);
317 return -1;
320 curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
322 lastif = curif;
324 next:
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. */
332 if (inc < sizeof(ifr->ifr_addr))
333 inc = sizeof(ifr->ifr_addr);
334 inc += IFNAMSIZ;
336 ifr = (struct ifreq*) (((char*) ifr) + inc);
337 i -= inc;
340 close(fd);
341 return 0;
344 #define _FOUND_IFACE_ANY
345 #endif /* HAVE_IFACE_AIX */
346 #ifndef _FOUND_IFACE_ANY
347 int rep_getifaddrs(struct ifaddrs **ifap)
349 errno = ENOSYS;
350 return -1;
352 #endif