r13924: Split more prototypes out of include/proto.h + initial work on header
[bbaumbach/samba-autobuild/.git] / source4 / lib / netif / interface.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    multiple interface handling
5
6    Copyright (C) Andrew Tridgell 1992-2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "system/network.h"
25 #include "lib/netif/netif.h"
26 #include "dlinklist.h"
27
28 /** used for network interfaces */
29 struct interface {
30         struct interface *next, *prev;
31         struct ipv4_addr ip;
32         struct ipv4_addr nmask;
33         const char *ip_s;
34         const char *bcast_s;
35         const char *nmask_s;
36 };
37
38 static struct interface *local_interfaces;
39
40 #define ALLONES  ((uint32_t)0xFFFFFFFF)
41 /*
42   address construction based on a patch from fred@datalync.com
43 */
44 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
45 #define MKNETADDR(_IP, _NM) (_IP & _NM)
46
47 static struct ipv4_addr tov4(struct in_addr in)
48 {
49         struct ipv4_addr in2;
50         in2.addr = in.s_addr;
51         return in2;
52 }
53
54 /****************************************************************************
55 Try and find an interface that matches an ip. If we cannot, return NULL
56   **************************************************************************/
57 static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
58 {
59         struct interface *i;
60         if (is_zero_ip(tov4(ip))) return local_interfaces;
61
62         for (i=local_interfaces;i;i=i->next)
63                 if (CheckMask) {
64                         if (same_net(i->ip,tov4(ip),i->nmask)) return i;
65                 } else if (i->ip.addr == ip.s_addr) return i;
66
67         return NULL;
68 }
69
70
71 /****************************************************************************
72 add an interface to the linked list of interfaces
73 ****************************************************************************/
74 static void add_interface(struct in_addr ip, struct in_addr nmask)
75 {
76         struct interface *iface;
77         struct ipv4_addr bcast;
78         if (iface_find(ip, False)) {
79                 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
80                 return;
81         }
82
83         iface = talloc(local_interfaces, struct interface);
84         if (!iface) return;
85         
86         ZERO_STRUCTPN(iface);
87
88         iface->ip = tov4(ip);
89         iface->nmask = tov4(nmask);
90         bcast.addr = MKBCADDR(iface->ip.addr, iface->nmask.addr);
91
92         /* keep string versions too, to avoid people tripping over the implied
93            static in sys_inet_ntoa() */
94         iface->ip_s = talloc_strdup(iface, sys_inet_ntoa(iface->ip));
95         iface->nmask_s = talloc_strdup(iface, sys_inet_ntoa(iface->nmask));
96         
97         if (nmask.s_addr != ~0) {
98                 iface->bcast_s = talloc_strdup(iface, sys_inet_ntoa(bcast));
99         }
100
101         DLIST_ADD_END(local_interfaces, iface, struct interface *);
102
103         DEBUG(2,("added interface ip=%s nmask=%s\n", iface->ip_s, iface->nmask_s));
104 }
105
106
107
108 /**
109 interpret a single element from a interfaces= config line 
110
111 This handles the following different forms:
112
113 1) wildcard interface name
114 2) DNS name
115 3) IP/masklen
116 4) ip/mask
117 5) bcast/mask
118 **/
119 static void interpret_interface(const char *token, 
120                                 struct iface_struct *probed_ifaces, 
121                                 int total_probed)
122 {
123         struct in_addr ip, nmask;
124         char *p;
125         int i, added=0;
126
127         ip.s_addr = 0;
128         nmask.s_addr = 0;
129         
130         /* first check if it is an interface name */
131         for (i=0;i<total_probed;i++) {
132                 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
133                         add_interface(probed_ifaces[i].ip,
134                                       probed_ifaces[i].netmask);
135                         added = 1;
136                 }
137         }
138         if (added) return;
139
140         /* maybe it is a DNS name */
141         p = strchr_m(token,'/');
142         if (!p) {
143                 /* don't try to do dns lookups on wildcard names */
144                 if (strpbrk(token, "*?") != NULL) {
145                         return;
146                 }
147                 ip.s_addr = interpret_addr2(token).addr;
148                 for (i=0;i<total_probed;i++) {
149                         if (ip.s_addr == probed_ifaces[i].ip.s_addr) {
150                                 add_interface(probed_ifaces[i].ip,
151                                               probed_ifaces[i].netmask);
152                                 return;
153                         }
154                 }
155                 DEBUG(2,("can't determine netmask for %s\n", token));
156                 return;
157         }
158
159         /* parse it into an IP address/netmasklength pair */
160         *p++ = 0;
161
162         ip.s_addr = interpret_addr2(token).addr;
163
164         if (strlen(p) > 2) {
165                 nmask.s_addr = interpret_addr2(p).addr;
166         } else {
167                 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
168         }
169
170         /* maybe the first component was a broadcast address */
171         if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
172             ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
173                 for (i=0;i<total_probed;i++) {
174                         if (same_net(tov4(ip), tov4(probed_ifaces[i].ip), tov4(nmask))) {
175                                 add_interface(probed_ifaces[i].ip, nmask);
176                                 return;
177                         }
178                 }
179                 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
180                 return;
181         }
182
183         add_interface(ip, nmask);
184 }
185
186
187 /**
188 load the list of network interfaces
189 **/
190 static void load_interfaces(void)
191 {
192         const char **ptr;
193         int i;
194         struct iface_struct ifaces[MAX_INTERFACES];
195         struct ipv4_addr loopback_ip;
196         int total_probed;
197
198         if (local_interfaces != NULL) {
199                 return;
200         }
201
202         ptr = lp_interfaces();
203         loopback_ip = interpret_addr2("127.0.0.1");
204
205         /* probe the kernel for interfaces */
206         total_probed = get_interfaces(ifaces, MAX_INTERFACES);
207
208         /* if we don't have a interfaces line then use all interfaces
209            except loopback */
210         if (!ptr || !*ptr || !**ptr) {
211                 if (total_probed <= 0) {
212                         DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
213                 }
214                 for (i=0;i<total_probed;i++) {
215                         if (ifaces[i].ip.s_addr != loopback_ip.addr) {
216                                 add_interface(ifaces[i].ip, 
217                                               ifaces[i].netmask);
218                         }
219                 }
220         }
221
222         while (ptr && *ptr) {
223                 interpret_interface(*ptr, ifaces, total_probed);
224                 ptr++;
225         }
226
227         if (!local_interfaces) {
228                 DEBUG(0,("WARNING: no network interfaces found\n"));
229         }
230 }
231
232
233 /**
234   unload the interfaces list, so it can be reloaded when needed
235 */
236 void unload_interfaces(void)
237 {
238         talloc_free(local_interfaces);
239         local_interfaces = NULL;
240 }
241
242 /**
243   how many interfaces do we have
244   **/
245 int iface_count(void)
246 {
247         int ret = 0;
248         struct interface *i;
249
250         load_interfaces();
251
252         for (i=local_interfaces;i;i=i->next)
253                 ret++;
254         return ret;
255 }
256
257 /**
258   return IP of the Nth interface
259   **/
260 const char *iface_n_ip(int n)
261 {
262         struct interface *i;
263   
264         load_interfaces();
265
266         for (i=local_interfaces;i && n;i=i->next)
267                 n--;
268
269         if (i) {
270                 return i->ip_s;
271         }
272         return NULL;
273 }
274
275 /**
276   return bcast of the Nth interface
277   **/
278 const char *iface_n_bcast(int n)
279 {
280         struct interface *i;
281   
282         load_interfaces();
283
284         for (i=local_interfaces;i && n;i=i->next)
285                 n--;
286
287         if (i) {
288                 return i->bcast_s;
289         }
290         return NULL;
291 }
292
293 /**
294   return netmask of the Nth interface
295   **/
296 const char *iface_n_netmask(int n)
297 {
298         struct interface *i;
299   
300         load_interfaces();
301
302         for (i=local_interfaces;i && n;i=i->next)
303                 n--;
304
305         if (i) {
306                 return i->nmask_s;
307         }
308         return NULL;
309 }
310
311 /**
312   return the local IP address that best matches a destination IP, or
313   our first interface if none match
314 */
315 const char *iface_best_ip(const char *dest)
316 {
317         struct interface *iface;
318         struct in_addr ip;
319
320         load_interfaces();
321
322         ip.s_addr = interpret_addr(dest);
323         iface = iface_find(ip, True);
324         if (iface) {
325                 return iface->ip_s;
326         }
327         return iface_n_ip(0);
328 }
329
330 /**
331   return True if an IP is one one of our local networks
332 */
333 BOOL iface_is_local(const char *dest)
334 {
335         struct in_addr ip;
336
337         load_interfaces();
338
339         ip.s_addr = interpret_addr(dest);
340         if (iface_find(ip, True)) {
341                 return True;
342         }
343         return False;
344 }
345
346 /**
347   return True if a IP matches a IP/netmask pair
348 */
349 BOOL iface_same_net(const char *ip1, const char *ip2, const char *netmask)
350 {
351         return same_net(interpret_addr2(ip1),
352                         interpret_addr2(ip2),
353                         interpret_addr2(netmask));
354 }