r23779: Change from v2 or later to v3 or later.
[bbaumbach/samba-autobuild/.git] / source3 / 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 3 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 !defined(__s390__)
64         if (ip_equal(nmask, allones_ip)) {
65                 DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
66                 return;
67         }
68 #endif
69
70         iface = SMB_MALLOC_P(struct interface);
71         if (!iface) return;
72         
73         ZERO_STRUCTPN(iface);
74
75         iface->ip = ip;
76         iface->nmask = nmask;
77         iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
78
79         DLIST_ADD(local_interfaces, iface);
80
81         DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
82         DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
83         DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));             
84 }
85
86
87
88 /****************************************************************************
89 interpret a single element from a interfaces= config line 
90
91 This handles the following different forms:
92
93 1) wildcard interface name
94 2) DNS name
95 3) IP/masklen
96 4) ip/mask
97 5) bcast/mask
98 ****************************************************************************/
99 static void interpret_interface(char *token)
100 {
101         struct in_addr ip, nmask;
102         char *p;
103         int i, added=0;
104
105         zero_ip(&ip);
106         zero_ip(&nmask);
107         
108         /* first check if it is an interface name */
109         for (i=0;i<total_probed;i++) {
110                 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
111                         add_interface(probed_ifaces[i].ip,
112                                       probed_ifaces[i].netmask);
113                         added = 1;
114                 }
115         }
116         if (added) return;
117
118         /* maybe it is a DNS name */
119         p = strchr_m(token,'/');
120         if (!p) {
121                 ip = *interpret_addr2(token);
122                 for (i=0;i<total_probed;i++) {
123                         if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
124                             !ip_equal(allones_ip, probed_ifaces[i].netmask)) {
125                                 add_interface(probed_ifaces[i].ip,
126                                               probed_ifaces[i].netmask);
127                                 return;
128                         }
129                 }
130                 DEBUG(2,("can't determine netmask for %s\n", token));
131                 return;
132         }
133
134         /* parse it into an IP address/netmasklength pair */
135         *p = 0;
136         ip = *interpret_addr2(token);
137         *p++ = '/';
138
139         if (strlen(p) > 2) {
140                 nmask = *interpret_addr2(p);
141         } else {
142                 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
143         }
144
145         /* maybe the first component was a broadcast address */
146         if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
147             ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
148                 for (i=0;i<total_probed;i++) {
149                         if (same_net(ip, probed_ifaces[i].ip, nmask)) {
150                                 add_interface(probed_ifaces[i].ip, nmask);
151                                 return;
152                         }
153                 }
154                 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
155                 return;
156         }
157
158         add_interface(ip, nmask);
159 }
160
161
162 /****************************************************************************
163 load the list of network interfaces
164 ****************************************************************************/
165 void load_interfaces(void)
166 {
167         const char **ptr;
168         int i;
169         struct iface_struct ifaces[MAX_INTERFACES];
170
171         ptr = lp_interfaces();
172
173         allones_ip = *interpret_addr2("255.255.255.255");
174         loopback_ip = *interpret_addr2("127.0.0.1");
175
176         SAFE_FREE(probed_ifaces);
177
178         /* dump the current interfaces if any */
179         while (local_interfaces) {
180                 struct interface *iface = local_interfaces;
181                 DLIST_REMOVE(local_interfaces, local_interfaces);
182                 ZERO_STRUCTPN(iface);
183                 SAFE_FREE(iface);
184         }
185
186         /* probe the kernel for interfaces */
187         total_probed = get_interfaces(ifaces, MAX_INTERFACES);
188
189         if (total_probed > 0) {
190                 probed_ifaces = (struct iface_struct *)memdup(ifaces, sizeof(ifaces[0])*total_probed);
191                 if (!probed_ifaces) {
192                         DEBUG(0,("ERROR: memdup failed\n"));
193                         exit(1);
194                 }
195         }
196
197         /* if we don't have a interfaces line then use all broadcast capable 
198            interfaces except loopback */
199         if (!ptr || !*ptr || !**ptr) {
200                 if (total_probed <= 0) {
201                         DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
202                         exit(1);
203                 }
204                 for (i=0;i<total_probed;i++) {
205                         if (
206 #if !defined(__s390__)
207                             probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
208 #endif
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         if (ptr) {
218                 while (*ptr) {
219                         char *ptr_cpy = SMB_STRDUP(*ptr);
220                         if (ptr_cpy) {
221                                 interpret_interface(ptr_cpy);
222                                 free(ptr_cpy);
223                         }
224                         ptr++;
225                 }
226         }
227
228         if (!local_interfaces) {
229                 DEBUG(0,("WARNING: no network interfaces found\n"));
230         }
231 }
232
233
234 void gfree_interfaces(void)
235 {
236         while (local_interfaces) {
237                 struct interface *iface = local_interfaces;
238                 DLIST_REMOVE(local_interfaces, local_interfaces);
239                 ZERO_STRUCTPN(iface);
240                 SAFE_FREE(iface);
241         }
242
243         SAFE_FREE(probed_ifaces);
244 }
245
246 /****************************************************************************
247 return True if the list of probed interfaces has changed
248 ****************************************************************************/
249 BOOL interfaces_changed(void)
250 {
251         int n;
252         struct iface_struct ifaces[MAX_INTERFACES];
253
254         n = get_interfaces(ifaces, MAX_INTERFACES);
255
256         if ((n > 0 )&& (n != total_probed ||
257             memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
258                 return True;
259         }
260         
261         return False;
262 }
263
264
265 /****************************************************************************
266   check if an IP is one of mine
267   **************************************************************************/
268 BOOL ismyip(struct in_addr ip)
269 {
270         struct interface *i;
271         for (i=local_interfaces;i;i=i->next)
272                 if (ip_equal(i->ip,ip)) return True;
273         return False;
274 }
275
276 /****************************************************************************
277   check if a packet is from a local (known) net
278   **************************************************************************/
279 BOOL is_local_net(struct in_addr from)
280 {
281         struct interface *i;
282         for (i=local_interfaces;i;i=i->next) {
283                 if((from.s_addr & i->nmask.s_addr) == 
284                    (i->ip.s_addr & i->nmask.s_addr))
285                         return True;
286         }
287         return False;
288 }
289
290 /****************************************************************************
291   how many interfaces do we have
292   **************************************************************************/
293 int iface_count(void)
294 {
295         int ret = 0;
296         struct interface *i;
297
298         for (i=local_interfaces;i;i=i->next)
299                 ret++;
300         return ret;
301 }
302
303 /****************************************************************************
304   return the Nth interface
305   **************************************************************************/
306 struct interface *get_interface(int n)
307
308         struct interface *i;
309   
310         for (i=local_interfaces;i && n;i=i->next)
311                 n--;
312
313         if (i) return i;
314         return NULL;
315 }
316
317 /****************************************************************************
318   return IP of the Nth interface
319   **************************************************************************/
320 struct in_addr *iface_n_ip(int n)
321 {
322         struct interface *i;
323   
324         for (i=local_interfaces;i && n;i=i->next)
325                 n--;
326
327         if (i) return &i->ip;
328         return NULL;
329 }
330
331 /****************************************************************************
332   return bcast of the Nth interface
333   **************************************************************************/
334 struct in_addr *iface_n_bcast(int n)
335 {
336         struct interface *i;
337   
338         for (i=local_interfaces;i && n;i=i->next)
339                 n--;
340
341         if (i) return &i->bcast;
342         return NULL;
343 }
344
345
346 /* these 3 functions return the ip/bcast/nmask for the interface
347    most appropriate for the given ip address. If they can't find
348    an appropriate interface they return the requested field of the
349    first known interface. */
350
351 struct in_addr *iface_ip(struct in_addr ip)
352 {
353         struct interface *i = iface_find(ip, True);
354         return(i ? &i->ip : &local_interfaces->ip);
355 }
356
357 /*
358   return True if a IP is directly reachable on one of our interfaces
359 */
360 BOOL iface_local(struct in_addr ip)
361 {
362         return iface_find(ip, True) ? True : False;
363 }