29ed15a0c265a8db324ea6db2335d601349673f6
[kai/samba.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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21
22 static struct iface_struct *probed_ifaces;
23 static int total_probed;
24
25 struct in_addr allones_ip;
26 struct in_addr loopback_ip;
27
28 static struct interface *local_interfaces;
29
30 #define ALLONES  ((uint32)0xFFFFFFFF)
31 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
32 #define MKNETADDR(_IP, _NM) (_IP & _NM)
33
34 /****************************************************************************
35 Try and find an interface that matches an ip. If we cannot, return NULL
36   **************************************************************************/
37 static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
38 {
39         struct interface *i;
40         if (is_zero_ip(ip)) return local_interfaces;
41
42         for (i=local_interfaces;i;i=i->next)
43                 if (CheckMask) {
44                         if (same_net(i->ip,ip,i->nmask)) return i;
45                 } else if ((i->ip).s_addr == ip.s_addr) return i;
46
47         return NULL;
48 }
49
50
51 /****************************************************************************
52 add an interface to the linked list of interfaces
53 ****************************************************************************/
54 static void add_interface(struct in_addr ip, struct in_addr nmask)
55 {
56         struct interface *iface;
57         if (iface_find(ip, False)) {
58                 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
59                 return;
60         }
61
62 #if !defined(__s390__)
63         if (ip_equal(nmask, allones_ip)) {
64                 DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
65                 return;
66         }
67 #endif
68
69         iface = SMB_MALLOC_P(struct interface);
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         ip = *interpret_addr2(token);
136         *p++ = '/';
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         const 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 = (struct iface_struct *)memdup(ifaces, sizeof(ifaces[0])*total_probed);
190                 if (!probed_ifaces) {
191                         DEBUG(0,("ERROR: memdup failed\n"));
192                         exit(1);
193                 }
194         }
195
196         /* if we don't have a interfaces line then use all broadcast capable 
197            interfaces except loopback */
198         if (!ptr || !*ptr || !**ptr) {
199                 if (total_probed <= 0) {
200                         DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
201                         exit(1);
202                 }
203                 for (i=0;i<total_probed;i++) {
204                         if (
205 #if !defined(__s390__)
206                             probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
207 #endif
208                             probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
209                                 add_interface(probed_ifaces[i].ip, 
210                                               probed_ifaces[i].netmask);
211                         }
212                 }
213                 return;
214         }
215
216         if (ptr) {
217                 while (*ptr) {
218                         char *ptr_cpy = SMB_STRDUP(*ptr);
219                         if (ptr_cpy) {
220                                 interpret_interface(ptr_cpy);
221                                 free(ptr_cpy);
222                         }
223                         ptr++;
224                 }
225         }
226
227         if (!local_interfaces) {
228                 DEBUG(0,("WARNING: no network interfaces found\n"));
229         }
230 }
231
232
233 void gfree_interfaces(void)
234 {
235         while (local_interfaces) {
236                 struct interface *iface = local_interfaces;
237                 DLIST_REMOVE(local_interfaces, local_interfaces);
238                 ZERO_STRUCTPN(iface);
239                 SAFE_FREE(iface);
240         }
241
242         SAFE_FREE(probed_ifaces);
243 }
244
245 /****************************************************************************
246 return True if the list of probed interfaces has changed
247 ****************************************************************************/
248 BOOL interfaces_changed(void)
249 {
250         int n;
251         struct iface_struct ifaces[MAX_INTERFACES];
252
253         n = get_interfaces(ifaces, MAX_INTERFACES);
254
255         if ((n > 0 )&& (n != total_probed ||
256             memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
257                 return True;
258         }
259         
260         return False;
261 }
262
263
264 /****************************************************************************
265   check if an IP is one of mine
266   **************************************************************************/
267 BOOL ismyip(struct in_addr ip)
268 {
269         struct interface *i;
270         for (i=local_interfaces;i;i=i->next)
271                 if (ip_equal(i->ip,ip)) return True;
272         return False;
273 }
274
275 /****************************************************************************
276   check if a packet is from a local (known) net
277   **************************************************************************/
278 BOOL is_local_net(struct in_addr from)
279 {
280         struct interface *i;
281         for (i=local_interfaces;i;i=i->next) {
282                 if((from.s_addr & i->nmask.s_addr) == 
283                    (i->ip.s_addr & i->nmask.s_addr))
284                         return True;
285         }
286         return False;
287 }
288
289 /****************************************************************************
290   how many interfaces do we have
291   **************************************************************************/
292 int iface_count(void)
293 {
294         int ret = 0;
295         struct interface *i;
296
297         for (i=local_interfaces;i;i=i->next)
298                 ret++;
299         return ret;
300 }
301
302 /****************************************************************************
303   return the Nth interface
304   **************************************************************************/
305 struct interface *get_interface(int n)
306
307         struct interface *i;
308   
309         for (i=local_interfaces;i && n;i=i->next)
310                 n--;
311
312         if (i) return i;
313         return NULL;
314 }
315
316 /****************************************************************************
317   return IP of the Nth interface
318   **************************************************************************/
319 struct in_addr *iface_n_ip(int n)
320 {
321         struct interface *i;
322   
323         for (i=local_interfaces;i && n;i=i->next)
324                 n--;
325
326         if (i) return &i->ip;
327         return NULL;
328 }
329
330 /****************************************************************************
331   return bcast of the Nth interface
332   **************************************************************************/
333 struct in_addr *iface_n_bcast(int n)
334 {
335         struct interface *i;
336   
337         for (i=local_interfaces;i && n;i=i->next)
338                 n--;
339
340         if (i) return &i->bcast;
341         return NULL;
342 }
343
344
345 /* these 3 functions return the ip/bcast/nmask for the interface
346    most appropriate for the given ip address. If they can't find
347    an appropriate interface they return the requested field of the
348    first known interface. */
349
350 struct in_addr *iface_ip(struct in_addr ip)
351 {
352         struct interface *i = iface_find(ip, True);
353         return(i ? &i->ip : &local_interfaces->ip);
354 }
355
356 /*
357   return True if a IP is directly reachable on one of our interfaces
358 */
359 BOOL iface_local(struct in_addr ip)
360 {
361         return iface_find(ip, True) ? True : False;
362 }