source: trunk/server/lib/replace/getifaddrs.c

Last change on this file was 862, checked in by Silvan Scherrer, 11 years ago

Samba Server: update trunk to 3.6.23

File size: 8.2 KB
Line 
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
49void 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
61static 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
85int 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/****************************************************************************
158this should cover most of the streams based systems
159Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
160****************************************************************************/
161int 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/****************************************************************************
258this one is for AIX (tested on 4.2)
259****************************************************************************/
260int 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#ifdef __OS2__
270 int total = 0;
271#endif
272 *ifap = NULL;
273
274 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
275 return -1;
276 }
277
278 ifc.ifc_len = sizeof(buff);
279 ifc.ifc_buf = buff;
280
281 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
282 close(fd);
283 return -1;
284 }
285
286 ifr = ifc.ifc_req;
287
288 /* Loop through interfaces */
289 i = ifc.ifc_len;
290
291 while (i > 0) {
292 unsigned int inc;
293
294 inc = ifr->ifr_addr.sa_len;
295
296 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
297#ifndef __OS2__
298 freeaddrinfo(*ifap);
299 return -1;
300#else
301 goto next;
302#endif
303 }
304
305 curif = calloc(1, sizeof(struct ifaddrs));
306 if (lastif == NULL) {
307 *ifap = curif;
308 } else {
309 lastif->ifa_next = curif;
310 }
311
312 curif->ifa_name = strdup(ifr->ifr_name);
313 curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
314 curif->ifa_dstaddr = NULL;
315 curif->ifa_data = NULL;
316 curif->ifa_netmask = NULL;
317 curif->ifa_next = NULL;
318
319 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
320#ifndef __OS2__
321 freeaddrinfo(*ifap);
322 return -1;
323#else
324 goto next;
325#endif
326 }
327
328 curif->ifa_flags = ifr->ifr_flags;
329
330 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
331#ifndef __OS2__
332 freeaddrinfo(*ifap);
333 return -1;
334#else
335 goto next;
336#endif
337 }
338
339 curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
340
341 lastif = curif;
342
343#ifdef __OS2__
344 total ++;
345#endif
346 next:
347 /*
348 * Patch from Archie Cobbs (archie@whistle.com). The
349 * addresses in the SIOCGIFCONF interface list have a
350 * minimum size. Usually this doesn't matter, but if
351 * your machine has tunnel interfaces, etc. that have
352 * a zero length "link address", this does matter. */
353
354 if (inc < sizeof(ifr->ifr_addr))
355 inc = sizeof(ifr->ifr_addr);
356 inc += IFNAMSIZ;
357
358 ifr = (struct ifreq*) (((char*) ifr) + inc);
359 i -= inc;
360 }
361
362 close(fd);
363#ifndef __OS2__
364 return 0;
365#else
366 if (total == 0) {
367 freeifaddrs(*ifap);
368 return -1;
369 }
370 return 0;
371#endif
372}
373
374#define _FOUND_IFACE_ANY
375#endif /* HAVE_IFACE_AIX */
376#ifndef _FOUND_IFACE_ANY
377int rep_getifaddrs(struct ifaddrs **ifap)
378{
379 errno = ENOSYS;
380 return -1;
381}
382#endif
Note: See TracBrowser for help on using the repository browser.