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