s3:winbind: remove the method SET_MAPPING from winbind's API
[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 #include "includes.h"
22
23 /****************************************************************************
24  Create a struct sockaddr_storage with the netmask bits set to 1.
25 ****************************************************************************/
26
27 bool make_netmask(struct sockaddr_storage *pss_out,
28                         const struct sockaddr_storage *pss_in,
29                         unsigned long masklen)
30 {
31         *pss_out = *pss_in;
32         /* Now apply masklen bits of mask. */
33 #if defined(HAVE_IPV6)
34         if (pss_in->ss_family == AF_INET6) {
35                 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
36                 unsigned int i;
37
38                 if (masklen > 128) {
39                         return false;
40                 }
41                 for (i = 0; masklen >= 8; masklen -= 8, i++) {
42                         *p++ = 0xff;
43                 }
44                 /* Deal with the partial byte. */
45                 *p++ &= (0xff & ~(0xff>>masklen));
46                 i++;
47                 for (;i < sizeof(struct in6_addr); i++) {
48                         *p++ = '\0';
49                 }
50                 return true;
51         }
52 #endif
53         if (pss_in->ss_family == AF_INET) {
54                 if (masklen > 32) {
55                         return false;
56                 }
57                 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
58                         htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
59                 return true;
60         }
61         return false;
62 }
63
64 /****************************************************************************
65  Create a struct sockaddr_storage set to the broadcast or network adress from
66  an incoming sockaddr_storage.
67 ****************************************************************************/
68
69 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
70                         const struct sockaddr_storage *pss_in,
71                         const struct sockaddr_storage *nmask,
72                         bool make_bcast_p)
73 {
74         unsigned int i = 0, len = 0;
75         char *pmask = NULL;
76         char *p = NULL;
77         *pss_out = *pss_in;
78
79         /* Set all zero netmask bits to 1. */
80 #if defined(HAVE_IPV6)
81         if (pss_in->ss_family == AF_INET6) {
82                 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
83                 pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
84                 len = 16;
85         }
86 #endif
87         if (pss_in->ss_family == AF_INET) {
88                 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
89                 pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
90                 len = 4;
91         }
92
93         for (i = 0; i < len; i++, p++, pmask++) {
94                 if (make_bcast_p) {
95                         *p = (*p & *pmask) | (*pmask ^ 0xff);
96                 } else {
97                         /* make_net */
98                         *p = (*p & *pmask);
99                 }
100         }
101 }
102
103 void make_bcast(struct sockaddr_storage *pss_out,
104                         const struct sockaddr_storage *pss_in,
105                         const struct sockaddr_storage *nmask)
106 {
107         make_bcast_or_net(pss_out, pss_in, nmask, true);
108 }
109
110 void make_net(struct sockaddr_storage *pss_out,
111                         const struct sockaddr_storage *pss_in,
112                         const struct sockaddr_storage *nmask)
113 {
114         make_bcast_or_net(pss_out, pss_in, nmask, false);
115 }
116
117 /****************************************************************************
118  Try the "standard" getifaddrs/freeifaddrs interfaces.
119  Also gets IPv6 interfaces.
120 ****************************************************************************/
121
122 /****************************************************************************
123  Get the netmask address for a local interface.
124 ****************************************************************************/
125
126 static int _get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
127 {
128         struct iface_struct *ifaces;
129         struct ifaddrs *iflist = NULL;
130         struct ifaddrs *ifptr = NULL;
131         int count;
132         int total = 0;
133         size_t copy_size;
134
135         if (getifaddrs(&iflist) < 0) {
136                 return -1;
137         }
138
139         count = 0;
140         for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
141                 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
142                         continue;
143                 }
144                 if (!(ifptr->ifa_flags & IFF_UP)) {
145                         continue;
146                 }
147                 count += 1;
148         }
149
150         ifaces = talloc_array(mem_ctx, struct iface_struct, count);
151         if (ifaces == NULL) {
152                 errno = ENOMEM;
153                 return -1;
154         }
155
156         /* Loop through interfaces, looking for given IP address */
157         for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
158
159                 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
160                         continue;
161                 }
162
163                 /* Check the interface is up. */
164                 if (!(ifptr->ifa_flags & IFF_UP)) {
165                         continue;
166                 }
167
168                 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
169
170                 copy_size = sizeof(struct sockaddr_in);
171
172                 ifaces[total].flags = ifptr->ifa_flags;
173
174 #if defined(HAVE_IPV6)
175                 if (ifptr->ifa_addr->sa_family == AF_INET6) {
176                         copy_size = sizeof(struct sockaddr_in6);
177                 }
178 #endif
179
180                 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
181                 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
182
183                 if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
184                         make_bcast(&ifaces[total].bcast,
185                                 &ifaces[total].ip,
186                                 &ifaces[total].netmask);
187                 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
188                                ifptr->ifa_dstaddr ) {
189                         memcpy(&ifaces[total].bcast,
190                                 ifptr->ifa_dstaddr,
191                                 copy_size);
192                 } else {
193                         continue;
194                 }
195
196                 strlcpy(ifaces[total].name, ifptr->ifa_name,
197                         sizeof(ifaces[total].name));
198                 total++;
199         }
200
201         freeifaddrs(iflist);
202
203         *pifaces = ifaces;
204         return total;
205 }
206
207 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
208 {
209         int r;
210
211 #if defined(HAVE_IPV6)
212         /*
213          * If we have IPv6 - sort these interfaces lower
214          * than any IPv4 ones.
215          */
216         if (i1->ip.ss_family == AF_INET6 &&
217                         i2->ip.ss_family == AF_INET) {
218                 return -1;
219         } else if (i1->ip.ss_family == AF_INET &&
220                         i2->ip.ss_family == AF_INET6) {
221                 return 1;
222         }
223
224         if (i1->ip.ss_family == AF_INET6) {
225                 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
226                 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
227
228                 r = memcmp(&s1->sin6_addr,
229                                 &s2->sin6_addr,
230                                 sizeof(struct in6_addr));
231                 if (r) {
232                         return r;
233                 }
234
235                 s1 = (struct sockaddr_in6 *)&i1->netmask;
236                 s2 = (struct sockaddr_in6 *)&i2->netmask;
237
238                 r = memcmp(&s1->sin6_addr,
239                                 &s2->sin6_addr,
240                                 sizeof(struct in6_addr));
241                 if (r) {
242                         return r;
243                 }
244         }
245 #endif
246
247         /* AIX uses __ss_family instead of ss_family inside of
248            sockaddr_storage. Instead of trying to figure out which field to
249            use, we can just cast it to a sockaddr.
250          */
251
252         if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
253                 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
254                 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
255
256                 r = ntohl(s1->sin_addr.s_addr) -
257                         ntohl(s2->sin_addr.s_addr);
258                 if (r) {
259                         return r;
260                 }
261
262                 s1 = (struct sockaddr_in *)&i1->netmask;
263                 s2 = (struct sockaddr_in *)&i2->netmask;
264
265                 return ntohl(s1->sin_addr.s_addr) -
266                         ntohl(s2->sin_addr.s_addr);
267         }
268         return 0;
269 }
270
271 /* this wrapper is used to remove duplicates from the interface list generated
272    above */
273 int get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
274 {
275         struct iface_struct *ifaces;
276         int total, i, j;
277
278         total = _get_interfaces(mem_ctx, &ifaces);
279         if (total <= 0) return total;
280
281         /* now we need to remove duplicates */
282         TYPESAFE_QSORT(ifaces, total, iface_comp);
283
284         for (i=1;i<total;) {
285                 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
286                         for (j=i-1;j<total-1;j++) {
287                                 ifaces[j] = ifaces[j+1];
288                         }
289                         total--;
290                 } else {
291                         i++;
292                 }
293         }
294
295         *pifaces = ifaces;
296         return total;
297 }
298