updated the 3.0 branch from the head branch - ready for alpha18
[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   return the Nth interface
280   **************************************************************************/
281 struct interface *get_interface(int n)
282
283         struct interface *i;
284   
285         for (i=local_interfaces;i && n;i=i->next)
286                 n--;
287
288         if (i) return i;
289         return NULL;
290 }
291
292 /****************************************************************************
293   return IP of the Nth interface
294   **************************************************************************/
295 struct in_addr *iface_n_ip(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->ip;
303         return NULL;
304 }
305
306 /****************************************************************************
307   return bcast of the Nth interface
308   **************************************************************************/
309 struct in_addr *iface_n_bcast(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->bcast;
317         return NULL;
318 }
319
320
321 /* these 3 functions return the ip/bcast/nmask for the interface
322    most appropriate for the given ip address. If they can't find
323    an appropriate interface they return the requested field of the
324    first known interface. */
325
326 struct in_addr *iface_ip(struct in_addr ip)
327 {
328         struct interface *i = iface_find(ip, True);
329         return(i ? &i->ip : &local_interfaces->ip);
330 }
331
332 /*
333   return True if a IP is directly reachable on one of our interfaces
334 */
335 BOOL iface_local(struct in_addr ip)
336 {
337         return iface_find(ip, True) ? True : False;
338 }