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