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 #include "replace.h"
27 #include "system/network.h"
28
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <sys/types.h>
32
33 #ifdef HAVE_SYS_TIME_H
34 #include <sys/time.h>
35 #endif
36
37 #ifndef SIOCGIFCONF
38 #ifdef HAVE_SYS_SOCKIO_H
39 #include <sys/sockio.h>
40 #endif
41 #endif
42
43 #ifdef HAVE_IFACE_GETIFADDRS
44 #define _FOUND_IFACE_ANY
45 #else
46
rep_freeifaddrs(struct ifaddrs * ifp)47 void rep_freeifaddrs(struct ifaddrs *ifp)
48 {
49 if (ifp != NULL) {
50 free(ifp->ifa_name);
51 free(ifp->ifa_addr);
52 free(ifp->ifa_netmask);
53 free(ifp->ifa_dstaddr);
54 freeifaddrs(ifp->ifa_next);
55 free(ifp);
56 }
57 }
58
sockaddr_dup(struct sockaddr * sa)59 static struct sockaddr *sockaddr_dup(struct sockaddr *sa)
60 {
61 struct sockaddr *ret;
62 socklen_t socklen;
63 #ifdef HAVE_SOCKADDR_SA_LEN
64 socklen = sa->sa_len;
65 #else
66 socklen = sizeof(struct sockaddr_storage);
67 #endif
68 ret = calloc(1, socklen);
69 if (ret == NULL)
70 return NULL;
71 memcpy(ret, sa, socklen);
72 return ret;
73 }
74 #endif
75
76 #ifdef HAVE_IFACE_IFCONF
77
78 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
79 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
80
81 It probably also works on any BSD style system. */
82
rep_getifaddrs(struct ifaddrs ** ifap)83 int rep_getifaddrs(struct ifaddrs **ifap)
84 {
85 struct ifconf ifc;
86 char buff[8192];
87 int fd, i, n;
88 struct ifreq *ifr=NULL;
89 struct ifaddrs *curif;
90 struct ifaddrs *lastif = NULL;
91
92 *ifap = NULL;
93
94 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
95 return -1;
96 }
97
98 ifc.ifc_len = sizeof(buff);
99 ifc.ifc_buf = buff;
100
101 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
102 close(fd);
103 return -1;
104 }
105
106 ifr = ifc.ifc_req;
107
108 n = ifc.ifc_len / sizeof(struct ifreq);
109
110 /* Loop through interfaces, looking for given IP address */
111 for (i=n-1; i>=0; i--) {
112 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) {
113 freeifaddrs(*ifap);
114 close(fd);
115 return -1;
116 }
117
118 curif = calloc(1, sizeof(struct ifaddrs));
119 if (curif == NULL) {
120 freeifaddrs(*ifap);
121 close(fd);
122 return -1;
123 }
124 curif->ifa_name = strdup(ifr[i].ifr_name);
125 if (curif->ifa_name == NULL) {
126 free(curif);
127 freeifaddrs(*ifap);
128 close(fd);
129 return -1;
130 }
131 curif->ifa_flags = ifr[i].ifr_flags;
132 curif->ifa_dstaddr = NULL;
133 curif->ifa_data = NULL;
134 curif->ifa_next = NULL;
135
136 curif->ifa_addr = NULL;
137 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) {
138 curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr);
139 if (curif->ifa_addr == NULL) {
140 free(curif->ifa_name);
141 free(curif);
142 freeifaddrs(*ifap);
143 close(fd);
144 return -1;
145 }
146 }
147
148 curif->ifa_netmask = NULL;
149 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) {
150 curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr);
151 if (curif->ifa_netmask == NULL) {
152 if (curif->ifa_addr != NULL) {
153 free(curif->ifa_addr);
154 }
155 free(curif->ifa_name);
156 free(curif);
157 freeifaddrs(*ifap);
158 close(fd);
159 return -1;
160 }
161 }
162
163 if (lastif == NULL) {
164 *ifap = curif;
165 } else {
166 lastif->ifa_next = curif;
167 }
168 lastif = curif;
169 }
170
171 close(fd);
172
173 return 0;
174 }
175
176 #define _FOUND_IFACE_ANY
177 #endif /* HAVE_IFACE_IFCONF */
178 #ifdef HAVE_IFACE_IFREQ
179
180 #ifndef I_STR
181 #include <sys/stropts.h>
182 #endif
183
184 /****************************************************************************
185 this should cover most of the streams based systems
186 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
187 ****************************************************************************/
rep_getifaddrs(struct ifaddrs ** ifap)188 int rep_getifaddrs(struct ifaddrs **ifap)
189 {
190 struct ifreq ifreq;
191 struct strioctl strioctl;
192 char buff[8192];
193 int fd, i, n;
194 struct ifreq *ifr=NULL;
195 struct ifaddrs *curif;
196 struct ifaddrs *lastif = NULL;
197
198 *ifap = NULL;
199
200 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
201 return -1;
202 }
203
204 strioctl.ic_cmd = SIOCGIFCONF;
205 strioctl.ic_dp = buff;
206 strioctl.ic_len = sizeof(buff);
207 if (ioctl(fd, I_STR, &strioctl) < 0) {
208 close(fd);
209 return -1;
210 }
211
212 /* we can ignore the possible sizeof(int) here as the resulting
213 number of interface structures won't change */
214 n = strioctl.ic_len / sizeof(struct ifreq);
215
216 /* we will assume that the kernel returns the length as an int
217 at the start of the buffer if the offered size is a
218 multiple of the structure size plus an int */
219 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
220 ifr = (struct ifreq *)(buff + sizeof(int));
221 } else {
222 ifr = (struct ifreq *)buff;
223 }
224
225 /* Loop through interfaces */
226
227 for (i = 0; i<n; i++) {
228 ifreq = ifr[i];
229
230 curif = calloc(1, sizeof(struct ifaddrs));
231 if (lastif == NULL) {
232 *ifap = curif;
233 } else {
234 lastif->ifa_next = curif;
235 }
236
237 strioctl.ic_cmd = SIOCGIFFLAGS;
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_flags = ifreq.ifr_flags;
246
247 strioctl.ic_cmd = SIOCGIFADDR;
248 strioctl.ic_dp = (char *)&ifreq;
249 strioctl.ic_len = sizeof(struct ifreq);
250 if (ioctl(fd, I_STR, &strioctl) != 0) {
251 freeifaddrs(*ifap);
252 return -1;
253 }
254
255 curif->ifa_name = strdup(ifreq.ifr_name);
256 curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr);
257 curif->ifa_dstaddr = NULL;
258 curif->ifa_data = NULL;
259 curif->ifa_next = NULL;
260 curif->ifa_netmask = NULL;
261
262 strioctl.ic_cmd = SIOCGIFNETMASK;
263 strioctl.ic_dp = (char *)&ifreq;
264 strioctl.ic_len = sizeof(struct ifreq);
265 if (ioctl(fd, I_STR, &strioctl) != 0) {
266 freeifaddrs(*ifap);
267 return -1;
268 }
269
270 curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr);
271
272 lastif = curif;
273 }
274
275 close(fd);
276
277 return 0;
278 }
279
280 #define _FOUND_IFACE_ANY
281 #endif /* HAVE_IFACE_IFREQ */
282 #ifdef HAVE_IFACE_AIX
283
284 /****************************************************************************
285 this one is for AIX (tested on 4.2)
286 ****************************************************************************/
rep_getifaddrs(struct ifaddrs ** ifap)287 int rep_getifaddrs(struct ifaddrs **ifap)
288 {
289 char buff[8192];
290 int fd, i;
291 struct ifconf ifc;
292 struct ifreq *ifr=NULL;
293 struct ifaddrs *curif;
294 struct ifaddrs *lastif = NULL;
295
296 *ifap = NULL;
297
298 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
299 return -1;
300 }
301
302 ifc.ifc_len = sizeof(buff);
303 ifc.ifc_buf = buff;
304
305 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
306 close(fd);
307 return -1;
308 }
309
310 ifr = ifc.ifc_req;
311
312 /* Loop through interfaces */
313 i = ifc.ifc_len;
314
315 while (i > 0) {
316 unsigned int inc;
317
318 inc = ifr->ifr_addr.sa_len;
319
320 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
321 freeaddrinfo(*ifap);
322 return -1;
323 }
324
325 curif = calloc(1, sizeof(struct ifaddrs));
326 if (lastif == NULL) {
327 *ifap = curif;
328 } else {
329 lastif->ifa_next = curif;
330 }
331
332 curif->ifa_name = strdup(ifr->ifr_name);
333 curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr);
334 curif->ifa_dstaddr = NULL;
335 curif->ifa_data = NULL;
336 curif->ifa_netmask = NULL;
337 curif->ifa_next = NULL;
338
339 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
340 freeaddrinfo(*ifap);
341 return -1;
342 }
343
344 curif->ifa_flags = ifr->ifr_flags;
345
346 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
347 freeaddrinfo(*ifap);
348 return -1;
349 }
350
351 curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr);
352
353 lastif = curif;
354
355 next:
356 /*
357 * Patch from Archie Cobbs (archie@whistle.com). The
358 * addresses in the SIOCGIFCONF interface list have a
359 * minimum size. Usually this doesn't matter, but if
360 * your machine has tunnel interfaces, etc. that have
361 * a zero length "link address", this does matter. */
362
363 if (inc < sizeof(ifr->ifr_addr))
364 inc = sizeof(ifr->ifr_addr);
365 inc += IFNAMSIZ;
366
367 ifr = (struct ifreq*) (((char*) ifr) + inc);
368 i -= inc;
369 }
370
371 close(fd);
372 return 0;
373 }
374
375 #define _FOUND_IFACE_ANY
376 #endif /* HAVE_IFACE_AIX */
377 #ifndef _FOUND_IFACE_ANY
rep_getifaddrs(struct ifaddrs ** ifap)378 int rep_getifaddrs(struct ifaddrs **ifap)
379 {
380 errno = ENOSYS;
381 return -1;
382 }
383 #endif
384