s3: Implement wbcGetpwsid
[ira/wip.git] / source3 / lib / interfaces.c
1 /*
2    Unix SMB/CIFS implementation.
3    return a list of network interfaces
4    Copyright (C) Andrew Tridgell 1998
5    Copyright (C) Jeremy Allison 2007
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21
22 /* working out the interfaces for a OS is an incredibly non-portable
23    thing. We have several possible implementations below, and autoconf
24    tries each of them to see what works
25
26    Note that this file does _not_ include includes.h. That is so this code
27    can be called directly from the autoconf tests. That also means
28    this code cannot use any of the normal Samba debug stuff or defines.
29    This is standalone code.
30
31 */
32
33 #ifndef AUTOCONF_TEST
34 #include "config.h"
35 #endif
36
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <sys/types.h>
40 #include <netdb.h>
41 #include <sys/ioctl.h>
42 #include <netdb.h>
43 #include <sys/ioctl.h>
44 #include <sys/time.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48
49 #ifdef HAVE_IFADDRS_H
50 #include <ifaddrs.h>
51 #endif
52
53 #ifdef HAVE_SYS_TIME_H
54 #include <sys/time.h>
55 #endif
56
57 #ifndef SIOCGIFCONF
58 #ifdef HAVE_SYS_SOCKIO_H
59 #include <sys/sockio.h>
60 #endif
61 #endif
62
63 #ifdef HAVE_STDLIB_H
64 #include <stdlib.h>
65 #endif
66
67 #ifdef HAVE_STRING_H
68 #include <string.h>
69 #endif
70
71 #ifdef HAVE_STRINGS_H
72 #include <strings.h>
73 #endif
74
75 #ifdef __COMPAR_FN_T
76 #define QSORT_CAST (__compar_fn_t)
77 #endif
78
79 #ifndef QSORT_CAST
80 #define QSORT_CAST (int (*)(const void *, const void *))
81 #endif
82
83 #ifdef HAVE_NET_IF_H
84 #include <net/if.h>
85 #endif
86
87 #define SOCKET_WRAPPER_NOT_REPLACE
88 #include "interfaces.h"
89 #include "../replace/replace.h"
90
91 /****************************************************************************
92  Utility functions.
93 ****************************************************************************/
94
95 /****************************************************************************
96  Create a struct sockaddr_storage with the netmask bits set to 1.
97 ****************************************************************************/
98
99 bool make_netmask(struct sockaddr_storage *pss_out,
100                         const struct sockaddr_storage *pss_in,
101                         unsigned long masklen)
102 {
103         *pss_out = *pss_in;
104         /* Now apply masklen bits of mask. */
105 #if defined(HAVE_IPV6)
106         if (pss_in->ss_family == AF_INET6) {
107                 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
108                 unsigned int i;
109
110                 if (masklen > 128) {
111                         return false;
112                 }
113                 for (i = 0; masklen >= 8; masklen -= 8, i++) {
114                         *p++ = 0xff;
115                 }
116                 /* Deal with the partial byte. */
117                 *p++ &= (0xff & ~(0xff>>masklen));
118                 i++;
119                 for (;i < sizeof(struct in6_addr); i++) {
120                         *p++ = '\0';
121                 }
122                 return true;
123         }
124 #endif
125         if (pss_in->ss_family == AF_INET) {
126                 if (masklen > 32) {
127                         return false;
128                 }
129                 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
130                         htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
131                 return true;
132         }
133         return false;
134 }
135
136 /****************************************************************************
137  Create a struct sockaddr_storage set to the broadcast or network adress from
138  an incoming sockaddr_storage.
139 ****************************************************************************/
140
141 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
142                         const struct sockaddr_storage *pss_in,
143                         const struct sockaddr_storage *nmask,
144                         bool make_bcast_p)
145 {
146         unsigned int i = 0, len = 0;
147         char *pmask = NULL;
148         char *p = NULL;
149         *pss_out = *pss_in;
150
151         /* Set all zero netmask bits to 1. */
152 #if defined(HAVE_IPV6)
153         if (pss_in->ss_family == AF_INET6) {
154                 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
155                 pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
156                 len = 16;
157         }
158 #endif
159         if (pss_in->ss_family == AF_INET) {
160                 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
161                 pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
162                 len = 4;
163         }
164
165         for (i = 0; i < len; i++, p++, pmask++) {
166                 if (make_bcast_p) {
167                         *p = (*p & *pmask) | (*pmask ^ 0xff);
168                 } else {
169                         /* make_net */
170                         *p = (*p & *pmask);
171                 }
172         }
173 }
174
175 void make_bcast(struct sockaddr_storage *pss_out,
176                         const struct sockaddr_storage *pss_in,
177                         const struct sockaddr_storage *nmask)
178 {
179         make_bcast_or_net(pss_out, pss_in, nmask, true);
180 }
181
182 void make_net(struct sockaddr_storage *pss_out,
183                         const struct sockaddr_storage *pss_in,
184                         const struct sockaddr_storage *nmask)
185 {
186         make_bcast_or_net(pss_out, pss_in, nmask, false);
187 }
188
189 /****************************************************************************
190  Try the "standard" getifaddrs/freeifaddrs interfaces.
191  Also gets IPv6 interfaces.
192 ****************************************************************************/
193
194 /****************************************************************************
195  Get the netmask address for a local interface.
196 ****************************************************************************/
197
198 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
199 {
200         struct ifaddrs *iflist = NULL;
201         struct ifaddrs *ifptr = NULL;
202         int total = 0;
203         size_t copy_size;
204
205         if (getifaddrs(&iflist) < 0) {
206                 return -1;
207         }
208
209         /* Loop through interfaces, looking for given IP address */
210         for (ifptr = iflist, total = 0;
211                         ifptr != NULL && total < max_interfaces;
212                         ifptr = ifptr->ifa_next) {
213
214                 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
215
216                 copy_size = sizeof(struct sockaddr_in);
217
218                 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
219                         continue;
220                 }
221
222                 ifaces[total].flags = ifptr->ifa_flags;
223
224                 /* Check the interface is up. */
225                 if (!(ifaces[total].flags & IFF_UP)) {
226                         continue;
227                 }
228
229 #if defined(HAVE_IPV6)
230                 if (ifptr->ifa_addr->sa_family == AF_INET6) {
231                         copy_size = sizeof(struct sockaddr_in6);
232                 }
233 #endif
234
235                 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
236                 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
237
238                 if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
239                         make_bcast(&ifaces[total].bcast,
240                                 &ifaces[total].ip,
241                                 &ifaces[total].netmask);
242                 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
243                                ifptr->ifa_dstaddr ) {
244                         memcpy(&ifaces[total].bcast,
245                                 ifptr->ifa_dstaddr,
246                                 copy_size);
247                 } else {
248                         continue;
249                 }
250
251                 strlcpy(ifaces[total].name, ifptr->ifa_name,
252                         sizeof(ifaces[total].name));
253                 total++;
254         }
255
256         freeifaddrs(iflist);
257
258         return total;
259 }
260
261 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
262 {
263         int r;
264
265 #if defined(HAVE_IPV6)
266         /*
267          * If we have IPv6 - sort these interfaces lower
268          * than any IPv4 ones.
269          */
270         if (i1->ip.ss_family == AF_INET6 &&
271                         i2->ip.ss_family == AF_INET) {
272                 return -1;
273         } else if (i1->ip.ss_family == AF_INET &&
274                         i2->ip.ss_family == AF_INET6) {
275                 return 1;
276         }
277
278         if (i1->ip.ss_family == AF_INET6) {
279                 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
280                 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
281
282                 r = memcmp(&s1->sin6_addr,
283                                 &s2->sin6_addr,
284                                 sizeof(struct in6_addr));
285                 if (r) {
286                         return r;
287                 }
288
289                 s1 = (struct sockaddr_in6 *)&i1->netmask;
290                 s2 = (struct sockaddr_in6 *)&i2->netmask;
291
292                 r = memcmp(&s1->sin6_addr,
293                                 &s2->sin6_addr,
294                                 sizeof(struct in6_addr));
295                 if (r) {
296                         return r;
297                 }
298         }
299 #endif
300
301         /* AIX uses __ss_family instead of ss_family inside of
302            sockaddr_storage. Instead of trying to figure out which field to
303            use, we can just cast it to a sockaddr.
304          */
305
306         if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
307                 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
308                 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
309
310                 r = ntohl(s1->sin_addr.s_addr) -
311                         ntohl(s2->sin_addr.s_addr);
312                 if (r) {
313                         return r;
314                 }
315
316                 s1 = (struct sockaddr_in *)&i1->netmask;
317                 s2 = (struct sockaddr_in *)&i2->netmask;
318
319                 return ntohl(s1->sin_addr.s_addr) -
320                         ntohl(s2->sin_addr.s_addr);
321         }
322         return 0;
323 }
324
325 int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
326 /* this wrapper is used to remove duplicates from the interface list generated
327    above */
328 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
329 {
330         int total, i, j;
331
332         total = _get_interfaces(ifaces, max_interfaces);
333         if (total <= 0) return total;
334
335         /* now we need to remove duplicates */
336         qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
337
338         for (i=1;i<total;) {
339                 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
340                         for (j=i-1;j<total-1;j++) {
341                                 ifaces[j] = ifaces[j+1];
342                         }
343                         total--;
344                 } else {
345                         i++;
346                 }
347         }
348
349         return total;
350 }
351