source: branches/samba-3.5.x/lib/replace/getifaddrs.c

Last change on this file was 664, checked in by Silvan Scherrer, 14 years ago

Samba Server 3.5: fixed a missing return, changed os2_socketpair to os2_pipe

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