Removed 'extern int DEBUGLEVEL' as it is now in the smb.h header.
[kai/samba.git] / source3 / lib / interface.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    multiple interface handling
5    Copyright (C) Andrew Tridgell 1992-1998
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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 #define MAX_INTERFACES 128
25
26 static struct iface_struct *probed_ifaces;
27 static int total_probed;
28
29 struct in_addr ipzero;
30 struct in_addr allones_ip;
31 struct in_addr loopback_ip;
32
33 static struct interface *local_interfaces  = NULL;
34
35 #define ALLONES  ((uint32)0xFFFFFFFF)
36 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
37 #define MKNETADDR(_IP, _NM) (_IP & _NM)
38
39 /****************************************************************************
40 Try and find an interface that matches an ip. If we cannot, return NULL
41   **************************************************************************/
42 static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
43 {
44         struct interface *i;
45         if (zero_ip(ip)) return local_interfaces;
46
47         for (i=local_interfaces;i;i=i->next)
48                 if (CheckMask) {
49                         if (same_net(i->ip,ip,i->nmask)) return i;
50                 } else if ((i->ip).s_addr == ip.s_addr) return i;
51
52         return NULL;
53 }
54
55
56 /****************************************************************************
57 add an interface to the linked list of interfaces
58 ****************************************************************************/
59 static void add_interface(struct in_addr ip, struct in_addr nmask)
60 {
61         struct interface *iface;
62         if (iface_find(ip, False)) {
63                 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
64                 return;
65         }
66
67         if (ip_equal(nmask, allones_ip)) {
68                 DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
69                 return;
70         }
71
72         iface = (struct interface *)malloc(sizeof(*iface));
73         if (!iface) return;
74         
75         ZERO_STRUCTPN(iface);
76
77         iface->ip = ip;
78         iface->nmask = nmask;
79         iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
80
81         DLIST_ADD(local_interfaces, iface);
82
83         DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
84         DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
85         DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));             
86 }
87
88
89
90 /****************************************************************************
91 interpret a single element from a interfaces= config line 
92
93 This handles the following different forms:
94
95 1) wildcard interface name
96 2) DNS name
97 3) IP/masklen
98 4) ip/mask
99 5) bcast/mask
100 ****************************************************************************/
101 static void interpret_interface(char *token)
102 {
103         struct in_addr ip, nmask;
104         char *p;
105         int i, added=0;
106
107         ip = ipzero;
108         nmask = ipzero;
109         
110         /* first check if it is an interface name */
111         for (i=0;i<total_probed;i++) {
112                 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
113                         add_interface(probed_ifaces[i].ip,
114                                       probed_ifaces[i].netmask);
115                         added = 1;
116                 }
117         }
118         if (added) return;
119
120         /* maybe it is a DNS name */
121         p = strchr_m(token,'/');
122         if (!p) {
123                 ip = *interpret_addr2(token);
124                 for (i=0;i<total_probed;i++) {
125                         if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
126                             !ip_equal(allones_ip, probed_ifaces[i].netmask)) {
127                                 add_interface(probed_ifaces[i].ip,
128                                               probed_ifaces[i].netmask);
129                                 return;
130                         }
131                 }
132                 DEBUG(2,("can't determine netmask for %s\n", token));
133                 return;
134         }
135
136         /* parse it into an IP address/netmasklength pair */
137         *p++ = 0;
138
139         ip = *interpret_addr2(token);
140
141         if (strlen(p) > 2) {
142                 nmask = *interpret_addr2(p);
143         } else {
144                 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
145         }
146
147         /* maybe the first component was a broadcast address */
148         if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
149             ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
150                 for (i=0;i<total_probed;i++) {
151                         if (same_net(ip, probed_ifaces[i].ip, nmask)) {
152                                 add_interface(probed_ifaces[i].ip, nmask);
153                                 return;
154                         }
155                 }
156                 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
157                 return;
158         }
159
160         add_interface(ip, nmask);
161 }
162
163
164 /****************************************************************************
165 load the list of network interfaces
166 ****************************************************************************/
167 void load_interfaces(void)
168 {
169         char **ptr;
170         int i;
171         struct iface_struct ifaces[MAX_INTERFACES];
172
173         ptr = lp_interfaces();
174
175         ipzero = *interpret_addr2("0.0.0.0");
176         allones_ip = *interpret_addr2("255.255.255.255");
177         loopback_ip = *interpret_addr2("127.0.0.1");
178
179         SAFE_FREE(probed_ifaces);
180
181         /* dump the current interfaces if any */
182         while (local_interfaces) {
183                 struct interface *iface = local_interfaces;
184                 DLIST_REMOVE(local_interfaces, local_interfaces);
185                 ZERO_STRUCTPN(iface);
186                 SAFE_FREE(iface);
187         }
188
189         /* probe the kernel for interfaces */
190         total_probed = get_interfaces(ifaces, MAX_INTERFACES);
191
192         if (total_probed > 0) {
193                 probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
194         }
195
196         /* if we don't have a interfaces line then use all broadcast capable 
197            interfaces except loopback */
198         if (!ptr || !*ptr || !**ptr) {
199                 if (total_probed <= 0) {
200                         DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
201                         exit(1);
202                 }
203                 for (i=0;i<total_probed;i++) {
204                         if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
205                             probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
206                                 add_interface(probed_ifaces[i].ip, 
207                                               probed_ifaces[i].netmask);
208                         }
209                 }
210                 return;
211         }
212
213         if (ptr) {
214                 while (*ptr) {
215                         interpret_interface(*ptr);
216                         ptr++;
217                 }
218         }
219
220         if (!local_interfaces) {
221                 DEBUG(0,("WARNING: no network interfaces found\n"));
222         }
223 }
224
225
226 /****************************************************************************
227 return True if the list of probed interfaces has changed
228 ****************************************************************************/
229 BOOL interfaces_changed(void)
230 {
231         int n;
232         struct iface_struct ifaces[MAX_INTERFACES];
233
234         n = get_interfaces(ifaces, MAX_INTERFACES);
235
236         if ((n > 0 )&& (n != total_probed ||
237             memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
238                 return True;
239         }
240         
241         return False;
242 }
243
244
245 /****************************************************************************
246   check if an IP is one of mine
247   **************************************************************************/
248 BOOL ismyip(struct in_addr ip)
249 {
250         struct interface *i;
251         for (i=local_interfaces;i;i=i->next)
252                 if (ip_equal(i->ip,ip)) return True;
253         return False;
254 }
255
256 /****************************************************************************
257   check if a packet is from a local (known) net
258   **************************************************************************/
259 BOOL is_local_net(struct in_addr from)
260 {
261         struct interface *i;
262         for (i=local_interfaces;i;i=i->next) {
263                 if((from.s_addr & i->nmask.s_addr) == 
264                    (i->ip.s_addr & i->nmask.s_addr))
265                         return True;
266         }
267         return False;
268 }
269
270 /****************************************************************************
271   how many interfaces do we have
272   **************************************************************************/
273 int iface_count(void)
274 {
275         int ret = 0;
276         struct interface *i;
277
278         for (i=local_interfaces;i;i=i->next)
279                 ret++;
280         return ret;
281 }
282
283 /****************************************************************************
284  True if we have two or more interfaces.
285   **************************************************************************/
286 BOOL we_are_multihomed(void)
287 {
288         static int multi = -1;
289
290         if(multi == -1)
291                 multi = (iface_count() > 1 ? True : False);
292         
293         return multi;
294 }
295
296 /****************************************************************************
297   return the Nth interface
298   **************************************************************************/
299 struct interface *get_interface(int n)
300
301         struct interface *i;
302   
303         for (i=local_interfaces;i && n;i=i->next)
304                 n--;
305
306         if (i) return i;
307         return NULL;
308 }
309
310 /****************************************************************************
311   return IP of the Nth interface
312   **************************************************************************/
313 struct in_addr *iface_n_ip(int n)
314 {
315         struct interface *i;
316   
317         for (i=local_interfaces;i && n;i=i->next)
318                 n--;
319
320         if (i) return &i->ip;
321         return NULL;
322 }
323
324 /****************************************************************************
325   return bcast of the Nth interface
326   **************************************************************************/
327 struct in_addr *iface_n_bcast(int n)
328 {
329         struct interface *i;
330   
331         for (i=local_interfaces;i && n;i=i->next)
332                 n--;
333
334         if (i) return &i->bcast;
335         return NULL;
336 }
337
338
339 /****************************************************************************
340 this function provides a simple hash of the configured interfaces. It is
341 used to detect a change in interfaces to tell us whether to discard
342 the current wins.dat file.
343 Note that the result is independent of the order of the interfaces
344   **************************************************************************/
345 unsigned iface_hash(void)
346 {
347         unsigned ret = 0;
348         struct interface *i;
349
350         for (i=local_interfaces;i;i=i->next) {
351                 unsigned x1 = (unsigned)str_checksum(inet_ntoa(i->ip));
352                 unsigned x2 = (unsigned)str_checksum(inet_ntoa(i->nmask));
353                 ret ^= (x1 ^ x2);
354         }
355
356         return ret;
357 }
358
359
360 /* these 3 functions return the ip/bcast/nmask for the interface
361    most appropriate for the given ip address. If they can't find
362    an appropriate interface they return the requested field of the
363    first known interface. */
364
365 struct in_addr *iface_bcast(struct in_addr ip)
366 {
367         struct interface *i = iface_find(ip, True);
368         return(i ? &i->bcast : &local_interfaces->bcast);
369 }
370
371 struct in_addr *iface_ip(struct in_addr ip)
372 {
373         struct interface *i = iface_find(ip, True);
374         return(i ? &i->ip : &local_interfaces->ip);
375 }