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