r23792: convert Samba4 to GPLv3
[abartlet/samba.git/.git] / source4 / lib / socket / interface.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    multiple interface handling
5
6    Copyright (C) Andrew Tridgell 1992-2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/network.h"
24 #include "lib/socket/netif.h"
25 #include "lib/util/dlinklist.h"
26
27 /** used for network interfaces */
28 struct interface {
29         struct interface *next, *prev;
30         struct ipv4_addr ip;
31         struct ipv4_addr nmask;
32         const char *ip_s;
33         const char *bcast_s;
34         const char *nmask_s;
35 };
36
37 static struct interface *local_interfaces;
38
39 #define ALLONES  ((uint32_t)0xFFFFFFFF)
40 /*
41   address construction based on a patch from fred@datalync.com
42 */
43 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
44 #define MKNETADDR(_IP, _NM) (_IP & _NM)
45
46 static struct ipv4_addr tov4(struct in_addr in)
47 {
48         struct ipv4_addr in2;
49         in2.addr = in.s_addr;
50         return in2;
51 }
52
53 /****************************************************************************
54 Try and find an interface that matches an ip. If we cannot, return NULL
55   **************************************************************************/
56 static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
57 {
58         struct interface *i;
59         if (is_zero_ip(tov4(ip))) return local_interfaces;
60
61         for (i=local_interfaces;i;i=i->next)
62                 if (CheckMask) {
63                         if (same_net(i->ip,tov4(ip),i->nmask)) return i;
64                 } else if (i->ip.addr == ip.s_addr) return i;
65
66         return NULL;
67 }
68
69
70 /****************************************************************************
71 add an interface to the linked list of interfaces
72 ****************************************************************************/
73 static void add_interface(struct in_addr ip, struct in_addr nmask)
74 {
75         struct interface *iface;
76         struct ipv4_addr bcast;
77         if (iface_find(ip, False)) {
78                 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
79                 return;
80         }
81
82         iface = talloc(local_interfaces, struct interface);
83         if (!iface) return;
84         
85         ZERO_STRUCTPN(iface);
86
87         iface->ip = tov4(ip);
88         iface->nmask = tov4(nmask);
89         bcast.addr = MKBCADDR(iface->ip.addr, iface->nmask.addr);
90
91         /* keep string versions too, to avoid people tripping over the implied
92            static in sys_inet_ntoa() */
93         iface->ip_s = talloc_strdup(iface, sys_inet_ntoa(iface->ip));
94         iface->nmask_s = talloc_strdup(iface, sys_inet_ntoa(iface->nmask));
95         
96         if (nmask.s_addr != ~0) {
97                 iface->bcast_s = talloc_strdup(iface, sys_inet_ntoa(bcast));
98         }
99
100         DLIST_ADD_END(local_interfaces, iface, struct interface *);
101
102         DEBUG(2,("added interface ip=%s nmask=%s\n", iface->ip_s, iface->nmask_s));
103 }
104
105
106
107 /**
108 interpret a single element from a interfaces= config line 
109
110 This handles the following different forms:
111
112 1) wildcard interface name
113 2) DNS name
114 3) IP/masklen
115 4) ip/mask
116 5) bcast/mask
117 **/
118 static void interpret_interface(const char *token, 
119                                 struct iface_struct *probed_ifaces, 
120                                 int total_probed)
121 {
122         struct in_addr ip, nmask;
123         char *p;
124         int i, added=0;
125
126         ip.s_addr = 0;
127         nmask.s_addr = 0;
128         
129         /* first check if it is an interface name */
130         for (i=0;i<total_probed;i++) {
131                 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
132                         add_interface(probed_ifaces[i].ip,
133                                       probed_ifaces[i].netmask);
134                         added = 1;
135                 }
136         }
137         if (added) return;
138
139         /* maybe it is a DNS name */
140         p = strchr_m(token,'/');
141         if (!p) {
142                 /* don't try to do dns lookups on wildcard names */
143                 if (strpbrk(token, "*?") != NULL) {
144                         return;
145                 }
146                 ip.s_addr = interpret_addr2(token).addr;
147                 for (i=0;i<total_probed;i++) {
148                         if (ip.s_addr == probed_ifaces[i].ip.s_addr) {
149                                 add_interface(probed_ifaces[i].ip,
150                                               probed_ifaces[i].netmask);
151                                 return;
152                         }
153                 }
154                 DEBUG(2,("can't determine netmask for %s\n", token));
155                 return;
156         }
157
158         /* parse it into an IP address/netmasklength pair */
159         *p++ = 0;
160
161         ip.s_addr = interpret_addr2(token).addr;
162
163         if (strlen(p) > 2) {
164                 nmask.s_addr = interpret_addr2(p).addr;
165         } else {
166                 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
167         }
168
169         /* maybe the first component was a broadcast address */
170         if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
171             ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
172                 for (i=0;i<total_probed;i++) {
173                         if (same_net(tov4(ip), tov4(probed_ifaces[i].ip), tov4(nmask))) {
174                                 add_interface(probed_ifaces[i].ip, nmask);
175                                 return;
176                         }
177                 }
178                 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
179                 return;
180         }
181
182         add_interface(ip, nmask);
183 }
184
185
186 /**
187 load the list of network interfaces
188 **/
189 static void load_interfaces(void)
190 {
191         const char **ptr;
192         int i;
193         struct iface_struct ifaces[MAX_INTERFACES];
194         struct ipv4_addr loopback_ip;
195         int total_probed;
196
197         if (local_interfaces != NULL) {
198                 return;
199         }
200
201         ptr = lp_interfaces();
202         loopback_ip = interpret_addr2("127.0.0.1");
203
204         /* probe the kernel for interfaces */
205         total_probed = get_interfaces(ifaces, MAX_INTERFACES);
206
207         /* if we don't have a interfaces line then use all interfaces
208            except loopback */
209         if (!ptr || !*ptr || !**ptr) {
210                 if (total_probed <= 0) {
211                         DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
212                 }
213                 for (i=0;i<total_probed;i++) {
214                         if (ifaces[i].ip.s_addr != loopback_ip.addr) {
215                                 add_interface(ifaces[i].ip, 
216                                               ifaces[i].netmask);
217                         }
218                 }
219         }
220
221         while (ptr && *ptr) {
222                 interpret_interface(*ptr, ifaces, total_probed);
223                 ptr++;
224         }
225
226         if (!local_interfaces) {
227                 DEBUG(0,("WARNING: no network interfaces found\n"));
228         }
229 }
230
231
232 /**
233   unload the interfaces list, so it can be reloaded when needed
234 */
235 void unload_interfaces(void)
236 {
237         talloc_free(local_interfaces);
238         local_interfaces = NULL;
239 }
240
241 /**
242   how many interfaces do we have
243   **/
244 int iface_count(void)
245 {
246         int ret = 0;
247         struct interface *i;
248
249         load_interfaces();
250
251         for (i=local_interfaces;i;i=i->next)
252                 ret++;
253         return ret;
254 }
255
256 /**
257   return IP of the Nth interface
258   **/
259 const char *iface_n_ip(int n)
260 {
261         struct interface *i;
262   
263         load_interfaces();
264
265         for (i=local_interfaces;i && n;i=i->next)
266                 n--;
267
268         if (i) {
269                 return i->ip_s;
270         }
271         return NULL;
272 }
273
274 /**
275   return bcast of the Nth interface
276   **/
277 const char *iface_n_bcast(int n)
278 {
279         struct interface *i;
280   
281         load_interfaces();
282
283         for (i=local_interfaces;i && n;i=i->next)
284                 n--;
285
286         if (i) {
287                 return i->bcast_s;
288         }
289         return NULL;
290 }
291
292 /**
293   return netmask of the Nth interface
294   **/
295 const char *iface_n_netmask(int n)
296 {
297         struct interface *i;
298   
299         load_interfaces();
300
301         for (i=local_interfaces;i && n;i=i->next)
302                 n--;
303
304         if (i) {
305                 return i->nmask_s;
306         }
307         return NULL;
308 }
309
310 /**
311   return the local IP address that best matches a destination IP, or
312   our first interface if none match
313 */
314 const char *iface_best_ip(const char *dest)
315 {
316         struct interface *iface;
317         struct in_addr ip;
318
319         load_interfaces();
320
321         ip.s_addr = interpret_addr(dest);
322         iface = iface_find(ip, True);
323         if (iface) {
324                 return iface->ip_s;
325         }
326         return iface_n_ip(0);
327 }
328
329 /**
330   return True if an IP is one one of our local networks
331 */
332 BOOL iface_is_local(const char *dest)
333 {
334         struct in_addr ip;
335
336         load_interfaces();
337
338         ip.s_addr = interpret_addr(dest);
339         if (iface_find(ip, True)) {
340                 return True;
341         }
342         return False;
343 }
344
345 /**
346   return True if a IP matches a IP/netmask pair
347 */
348 BOOL iface_same_net(const char *ip1, const char *ip2, const char *netmask)
349 {
350         return same_net(interpret_addr2(ip1),
351                         interpret_addr2(ip2),
352                         interpret_addr2(netmask));
353 }