Changes from APPLIANCE_HEAD:
[ira/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)
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 (same_net(i->ip,ip,i->nmask)) 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)) {
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 (ms_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(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         fstring token;
171         int i;
172         struct iface_struct ifaces[MAX_INTERFACES];
173
174         ptr = lp_interfaces();
175
176         ipzero = *interpret_addr2("0.0.0.0");
177         allones_ip = *interpret_addr2("255.255.255.255");
178         loopback_ip = *interpret_addr2("127.0.0.1");
179
180         if (probed_ifaces) {
181                 free(probed_ifaces);
182                 probed_ifaces = NULL;
183         }
184
185         /* dump the current interfaces if any */
186         while (local_interfaces) {
187                 struct interface *iface = local_interfaces;
188                 DLIST_REMOVE(local_interfaces, local_interfaces);
189                 ZERO_STRUCTPN(iface);
190                 free(iface);
191         }
192
193         /* probe the kernel for interfaces */
194         total_probed = get_interfaces(ifaces, MAX_INTERFACES);
195
196         if (total_probed > 0) {
197                 probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
198         }
199
200         /* if we don't have a interfaces line then use all broadcast capable 
201            interfaces except loopback */
202         if (!ptr || !*ptr) {
203                 if (total_probed <= 0) {
204                         DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
205                         exit(1);
206                 }
207                 for (i=0;i<total_probed;i++) {
208                         if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
209                             probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
210                                 add_interface(probed_ifaces[i].ip, 
211                                               probed_ifaces[i].netmask);
212                         }
213                 }
214                 return;
215         }
216
217         while (next_token(&ptr,token,NULL,sizeof(token))) {
218                 interpret_interface(token);
219         }
220
221         if (!local_interfaces) {
222                 DEBUG(0,("WARNING: no network interfaces found\n"));
223         }
224 }
225
226
227 /****************************************************************************
228 return True if the list of probed interfaces has changed
229 ****************************************************************************/
230 BOOL interfaces_changed(void)
231 {
232         int n;
233         struct iface_struct ifaces[MAX_INTERFACES];
234
235         n = get_interfaces(ifaces, MAX_INTERFACES);
236
237         if ((n > 0 )&& (n != total_probed ||
238             memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
239                 return True;
240         }
241         
242         return False;
243 }
244
245
246 /****************************************************************************
247   check if an IP is one of mine
248   **************************************************************************/
249 BOOL ismyip(struct in_addr ip)
250 {
251         struct interface *i;
252         for (i=local_interfaces;i;i=i->next)
253                 if (ip_equal(i->ip,ip)) return True;
254         return False;
255 }
256
257 /****************************************************************************
258   check if a packet is from a local (known) net
259   **************************************************************************/
260 BOOL is_local_net(struct in_addr from)
261 {
262         struct interface *i;
263         for (i=local_interfaces;i;i=i->next) {
264                 if((from.s_addr & i->nmask.s_addr) == 
265                    (i->ip.s_addr & i->nmask.s_addr))
266                         return True;
267         }
268         return False;
269 }
270
271 /****************************************************************************
272   how many interfaces do we have
273   **************************************************************************/
274 int iface_count(void)
275 {
276         int ret = 0;
277         struct interface *i;
278
279         for (i=local_interfaces;i;i=i->next)
280                 ret++;
281         return ret;
282 }
283
284 /****************************************************************************
285  True if we have two or more interfaces.
286   **************************************************************************/
287 BOOL we_are_multihomed(void)
288 {
289         static int multi = -1;
290
291         if(multi == -1)
292                 multi = (iface_count() > 1 ? True : False);
293         
294         return multi;
295 }
296
297 /****************************************************************************
298   return the Nth interface
299   **************************************************************************/
300 struct interface *get_interface(int n)
301
302         struct interface *i;
303   
304         for (i=local_interfaces;i && n;i=i->next)
305                 n--;
306
307         if (i) return i;
308         return NULL;
309 }
310
311 /****************************************************************************
312   return IP of the Nth interface
313   **************************************************************************/
314 struct in_addr *iface_n_ip(int n)
315 {
316         struct interface *i;
317   
318         for (i=local_interfaces;i && n;i=i->next)
319                 n--;
320
321         if (i) return &i->ip;
322         return NULL;
323 }
324
325 /****************************************************************************
326   return bcast of the Nth interface
327   **************************************************************************/
328 struct in_addr *iface_n_bcast(int n)
329 {
330         struct interface *i;
331   
332         for (i=local_interfaces;i && n;i=i->next)
333                 n--;
334
335         if (i) return &i->bcast;
336         return NULL;
337 }
338
339
340 /****************************************************************************
341 this function provides a simple hash of the configured interfaces. It is
342 used to detect a change in interfaces to tell us whether to discard
343 the current wins.dat file.
344 Note that the result is independent of the order of the interfaces
345   **************************************************************************/
346 unsigned iface_hash(void)
347 {
348         unsigned ret = 0;
349         struct interface *i;
350
351         for (i=local_interfaces;i;i=i->next) {
352                 unsigned x1 = (unsigned)str_checksum(inet_ntoa(i->ip));
353                 unsigned x2 = (unsigned)str_checksum(inet_ntoa(i->nmask));
354                 ret ^= (x1 ^ x2);
355         }
356
357         return ret;
358 }
359
360
361 /* these 3 functions return the ip/bcast/nmask for the interface
362    most appropriate for the given ip address. If they can't find
363    an appropriate interface they return the requested field of the
364    first known interface. */
365
366 struct in_addr *iface_bcast(struct in_addr ip)
367 {
368         struct interface *i = iface_find(ip);
369         return(i ? &i->bcast : &local_interfaces->bcast);
370 }
371
372 struct in_addr *iface_ip(struct in_addr ip)
373 {
374         struct interface *i = iface_find(ip);
375         return(i ? &i->ip : &local_interfaces->ip);
376 }