r4088: Get medieval on our ass about malloc.... :-). Take control of all our allocation
[tprouty/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 = SMB_MALLOC_P(struct interface);
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         ip = *interpret_addr2(token);
135         *p++ = '/';
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         const 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                         char *ptr_cpy = SMB_STRDUP(*ptr);
211                         if (ptr_cpy) {
212                                 interpret_interface(ptr_cpy);
213                                 free(ptr_cpy);
214                         }
215                         ptr++;
216                 }
217         }
218
219         if (!local_interfaces) {
220                 DEBUG(0,("WARNING: no network interfaces found\n"));
221         }
222 }
223
224
225 /****************************************************************************
226 return True if the list of probed interfaces has changed
227 ****************************************************************************/
228 BOOL interfaces_changed(void)
229 {
230         int n;
231         struct iface_struct ifaces[MAX_INTERFACES];
232
233         n = get_interfaces(ifaces, MAX_INTERFACES);
234
235         if ((n > 0 )&& (n != total_probed ||
236             memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
237                 return True;
238         }
239         
240         return False;
241 }
242
243
244 /****************************************************************************
245   check if an IP is one of mine
246   **************************************************************************/
247 BOOL ismyip(struct in_addr ip)
248 {
249         struct interface *i;
250         for (i=local_interfaces;i;i=i->next)
251                 if (ip_equal(i->ip,ip)) return True;
252         return False;
253 }
254
255 /****************************************************************************
256   check if a packet is from a local (known) net
257   **************************************************************************/
258 BOOL is_local_net(struct in_addr from)
259 {
260         struct interface *i;
261         for (i=local_interfaces;i;i=i->next) {
262                 if((from.s_addr & i->nmask.s_addr) == 
263                    (i->ip.s_addr & i->nmask.s_addr))
264                         return True;
265         }
266         return False;
267 }
268
269 /****************************************************************************
270   how many interfaces do we have
271   **************************************************************************/
272 int iface_count(void)
273 {
274         int ret = 0;
275         struct interface *i;
276
277         for (i=local_interfaces;i;i=i->next)
278                 ret++;
279         return ret;
280 }
281
282 /****************************************************************************
283   return the Nth interface
284   **************************************************************************/
285 struct interface *get_interface(int n)
286
287         struct interface *i;
288   
289         for (i=local_interfaces;i && n;i=i->next)
290                 n--;
291
292         if (i) return i;
293         return NULL;
294 }
295
296 /****************************************************************************
297   return IP of the Nth interface
298   **************************************************************************/
299 struct in_addr *iface_n_ip(int n)
300 {
301         struct interface *i;
302   
303         for (i=local_interfaces;i && n;i=i->next)
304                 n--;
305
306         if (i) return &i->ip;
307         return NULL;
308 }
309
310 /****************************************************************************
311   return bcast of the Nth interface
312   **************************************************************************/
313 struct in_addr *iface_n_bcast(int n)
314 {
315         struct interface *i;
316   
317         for (i=local_interfaces;i && n;i=i->next)
318                 n--;
319
320         if (i) return &i->bcast;
321         return NULL;
322 }
323
324
325 /* these 3 functions return the ip/bcast/nmask for the interface
326    most appropriate for the given ip address. If they can't find
327    an appropriate interface they return the requested field of the
328    first known interface. */
329
330 struct in_addr *iface_ip(struct in_addr ip)
331 {
332         struct interface *i = iface_find(ip, True);
333         return(i ? &i->ip : &local_interfaces->ip);
334 }
335
336 /*
337   return True if a IP is directly reachable on one of our interfaces
338 */
339 BOOL iface_local(struct in_addr ip)
340 {
341         return iface_find(ip, True) ? True : False;
342 }