debug: factor out a function that opens and closes the new and old logfile
[samba.git] / lib / replace / getifaddrs.c
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
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
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
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 ****************************************************************************/
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 ****************************************************************************/
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
378 int rep_getifaddrs(struct ifaddrs **ifap)
379 {
380         errno = ENOSYS;
381         return -1;
382 }
383 #endif