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

Last change on this file was 133, checked in by Paul Smedley, 17 years ago

Update trunk to 3.2.0pre3

File size: 7.9 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 in_addr ipaddr;
88 struct in_addr nmask;
89 char *iname;
90 struct ifaddrs *curif;
91 struct ifaddrs *lastif = NULL;
92
93 *ifap = NULL;
94
95 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
96 return -1;
97 }
98
99 ifc.ifc_len = sizeof(buff);
100 ifc.ifc_buf = buff;
101
102 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
103 close(fd);
104 return -1;
105 }
106
107 ifr = ifc.ifc_req;
108
109 n = ifc.ifc_len / sizeof(struct ifreq);
110
111 /* Loop through interfaces, looking for given IP address */
112 for (i=n-1; i>=0; i--) {
113 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) {
114 freeifaddrs(*ifap);
115 return -1;
116 }
117
118 curif = calloc(1, sizeof(struct ifaddrs));
119 curif->ifa_name = strdup(ifr[i].ifr_name);
120 curif->ifa_flags = ifr[i].ifr_flags;
121 curif->ifa_dstaddr = NULL;
122 curif->ifa_data = NULL;
123 curif->ifa_next = NULL;
124
125 curif->ifa_addr = NULL;
126 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) {
127 curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
128 }
129
130 curif->ifa_netmask = NULL;
131 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) {
132 curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
133 }
134
135 if (lastif == NULL) {
136 *ifap = curif;
137 } else {
138 lastif->ifa_next = curif;
139 }
140 lastif = curif;
141 }
142
143 close(fd);
144
145 return 0;
146}
147
148#define _FOUND_IFACE_ANY
149#endif /* HAVE_IFACE_IFCONF */
150#ifdef HAVE_IFACE_IFREQ
151
152#ifndef I_STR
153#include <sys/stropts.h>
154#endif
155
156/****************************************************************************
157this should cover most of the streams based systems
158Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
159****************************************************************************/
160int rep_getifaddrs(struct ifaddrs **ifap)
161{
162 struct ifreq ifreq;
163 struct strioctl strioctl;
164 char buff[8192];
165 int fd, i, n;
166 struct ifreq *ifr=NULL;
167 struct in_addr ipaddr;
168 struct in_addr nmask;
169 char *iname;
170 struct ifaddrs *curif;
171 struct ifaddrs *lastif = NULL;
172
173 *ifap = NULL;
174
175 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
176 return -1;
177 }
178
179 strioctl.ic_cmd = SIOCGIFCONF;
180 strioctl.ic_dp = buff;
181 strioctl.ic_len = sizeof(buff);
182 if (ioctl(fd, I_STR, &strioctl) < 0) {
183 close(fd);
184 return -1;
185 }
186
187 /* we can ignore the possible sizeof(int) here as the resulting
188 number of interface structures won't change */
189 n = strioctl.ic_len / sizeof(struct ifreq);
190
191 /* we will assume that the kernel returns the length as an int
192 at the start of the buffer if the offered size is a
193 multiple of the structure size plus an int */
194 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
195 ifr = (struct ifreq *)(buff + sizeof(int));
196 } else {
197 ifr = (struct ifreq *)buff;
198 }
199
200 /* Loop through interfaces */
201
202 for (i = 0; i<n; i++) {
203 ifreq = ifr[i];
204
205 curif = calloc(1, sizeof(struct ifaddrs));
206 if (lastif == NULL) {
207 *ifap = curif;
208 } else {
209 lastif->ifa_next = curif;
210 }
211
212 strioctl.ic_cmd = SIOCGIFFLAGS;
213 strioctl.ic_dp = (char *)&ifreq;
214 strioctl.ic_len = sizeof(struct ifreq);
215 if (ioctl(fd, I_STR, &strioctl) != 0) {
216 freeifaddrs(*ifap);
217 return -1;
218 }
219
220 curif->ifa_flags = ifreq.ifr_flags;
221
222 strioctl.ic_cmd = SIOCGIFADDR;
223 strioctl.ic_dp = (char *)&ifreq;
224 strioctl.ic_len = sizeof(struct ifreq);
225 if (ioctl(fd, I_STR, &strioctl) != 0) {
226 freeifaddrs(*ifap);
227 return -1;
228 }
229
230 curif->ifa_name = strdup(ifreq.ifr_name);
231 curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
232 curif->ifa_dstaddr = NULL;
233 curif->ifa_data = NULL;
234 curif->ifa_next = NULL;
235 curif->ifa_netmask = NULL;
236
237 strioctl.ic_cmd = SIOCGIFNETMASK;
238 strioctl.ic_dp = (char *)&ifreq;
239 strioctl.ic_len = sizeof(struct ifreq);
240 if (ioctl(fd, I_STR, &strioctl) != 0) {
241 freeifaddrs(*ifap);
242 return -1;
243 }
244
245 curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
246
247 lastif = curif;
248 }
249
250 close(fd);
251
252 return 0;
253}
254
255#define _FOUND_IFACE_ANY
256#endif /* HAVE_IFACE_IFREQ */
257#if defined(HAVE_IFACE_AIX) || defined(__OS2__)
258
259/****************************************************************************
260this one is for AIX (tested on 4.2)
261****************************************************************************/
262int rep_getifaddrs(struct ifaddrs **ifap)
263{
264 char buff[8192];
265 int fd, i;
266 struct ifconf ifc;
267 struct ifreq *ifr=NULL;
268 struct in_addr ipaddr;
269 struct in_addr nmask;
270 char *iname;
271 struct ifaddrs *curif;
272 struct ifaddrs *lastif = NULL;
273
274 *ifap = NULL;
275
276 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
277 return -1;
278 }
279
280 ifc.ifc_len = sizeof(buff);
281 ifc.ifc_buf = buff;
282
283 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
284 close(fd);
285 return -1;
286 }
287
288 ifr = ifc.ifc_req;
289
290 /* Loop through interfaces */
291 i = ifc.ifc_len;
292
293 while (i > 0) {
294 uint_t inc;
295
296 inc = ifr->ifr_addr.sa_len;
297
298 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
299#ifndef __OS2__
300 freeaddrinfo(*ifap);
301 return -1;
302#else
303 goto next;
304#endif
305 }
306
307 curif = calloc(1, sizeof(struct ifaddrs));
308 if (lastif == NULL) {
309 *ifap = curif;
310 } else {
311 lastif->ifa_next = curif;
312 }
313
314 curif->ifa_name = strdup(ifr->ifr_name);
315 curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
316 curif->ifa_dstaddr = NULL;
317 curif->ifa_data = NULL;
318 curif->ifa_netmask = NULL;
319 curif->ifa_next = NULL;
320
321 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
322 freeaddrinfo(*ifap);
323 return -1;
324 }
325
326 curif->ifa_flags = ifr->ifr_flags;
327
328 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
329 freeaddrinfo(*ifap);
330 return -1;
331 }
332
333 curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
334
335 lastif = curif;
336
337 next:
338 /*
339 * Patch from Archie Cobbs (archie@whistle.com). The
340 * addresses in the SIOCGIFCONF interface list have a
341 * minimum size. Usually this doesn't matter, but if
342 * your machine has tunnel interfaces, etc. that have
343 * a zero length "link address", this does matter. */
344
345 if (inc < sizeof(ifr->ifr_addr))
346 inc = sizeof(ifr->ifr_addr);
347 inc += IFNAMSIZ;
348
349 ifr = (struct ifreq*) (((char*) ifr) + inc);
350 i -= inc;
351 }
352
353 close(fd);
354 return 0;
355}
356
357#define _FOUND_IFACE_ANY
358#endif /* HAVE_IFACE_AIX */
359#ifndef _FOUND_IFACE_ANY
360int rep_getifaddrs(struct ifaddrs **ifap)
361{
362 errno = ENOSYS;
363 return -1;
364}
365#endif
Note: See TracBrowser for help on using the repository browser.