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