r25398: Parse loadparm context to all lp_*() functions.
[ira/wip.git] / source4 / lib / socket / 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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/network.h"
24 #include "lib/socket/netif.h"
25 #include "lib/util/dlinklist.h"
26 #include "param/param.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
79         if (iface_find(ip, false)) {
80                 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
81                 return;
82         }
83
84         iface = talloc(local_interfaces == NULL ? talloc_autofree_context() : local_interfaces, struct interface);
85         if (!iface) return;
86         
87         ZERO_STRUCTPN(iface);
88
89         iface->ip = tov4(ip);
90         iface->nmask = tov4(nmask);
91         bcast.addr = MKBCADDR(iface->ip.addr, iface->nmask.addr);
92
93         /* keep string versions too, to avoid people tripping over the implied
94            static in sys_inet_ntoa() */
95         iface->ip_s = talloc_strdup(iface, sys_inet_ntoa(iface->ip));
96         iface->nmask_s = talloc_strdup(iface, sys_inet_ntoa(iface->nmask));
97         
98         if (nmask.s_addr != ~0) {
99                 iface->bcast_s = talloc_strdup(iface, sys_inet_ntoa(bcast));
100         }
101
102         DLIST_ADD_END(local_interfaces, iface, struct interface *);
103
104         DEBUG(2,("added interface ip=%s nmask=%s\n", iface->ip_s, iface->nmask_s));
105 }
106
107
108
109 /**
110 interpret a single element from a interfaces= config line 
111
112 This handles the following different forms:
113
114 1) wildcard interface name
115 2) DNS name
116 3) IP/masklen
117 4) ip/mask
118 5) bcast/mask
119 **/
120 static void interpret_interface(const char *token, 
121                                 struct iface_struct *probed_ifaces, 
122                                 int total_probed)
123 {
124         struct in_addr ip, nmask;
125         char *p;
126         int i, added=0;
127
128         ip.s_addr = 0;
129         nmask.s_addr = 0;
130         
131         /* first check if it is an interface name */
132         for (i=0;i<total_probed;i++) {
133                 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
134                         add_interface(probed_ifaces[i].ip,
135                                       probed_ifaces[i].netmask);
136                         added = 1;
137                 }
138         }
139         if (added) return;
140
141         /* maybe it is a DNS name */
142         p = strchr_m(token,'/');
143         if (!p) {
144                 /* don't try to do dns lookups on wildcard names */
145                 if (strpbrk(token, "*?") != NULL) {
146                         return;
147                 }
148                 ip.s_addr = interpret_addr2(token).addr;
149                 for (i=0;i<total_probed;i++) {
150                         if (ip.s_addr == probed_ifaces[i].ip.s_addr) {
151                                 add_interface(probed_ifaces[i].ip,
152                                               probed_ifaces[i].netmask);
153                                 return;
154                         }
155                 }
156                 DEBUG(2,("can't determine netmask for %s\n", token));
157                 return;
158         }
159
160         /* parse it into an IP address/netmasklength pair */
161         *p++ = 0;
162
163         ip.s_addr = interpret_addr2(token).addr;
164
165         if (strlen(p) > 2) {
166                 nmask.s_addr = interpret_addr2(p).addr;
167         } else {
168                 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
169         }
170
171         /* maybe the first component was a broadcast address */
172         if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
173             ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
174                 for (i=0;i<total_probed;i++) {
175                         if (same_net(tov4(ip), tov4(probed_ifaces[i].ip), tov4(nmask))) {
176                                 add_interface(probed_ifaces[i].ip, nmask);
177                                 return;
178                         }
179                 }
180                 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
181                 return;
182         }
183
184         add_interface(ip, nmask);
185 }
186
187
188 /**
189 load the list of network interfaces
190 **/
191 static void load_interfaces(void)
192 {
193         const char **ptr;
194         int i;
195         struct iface_struct ifaces[MAX_INTERFACES];
196         struct ipv4_addr loopback_ip;
197         int total_probed;
198
199         if (local_interfaces != NULL) {
200                 return;
201         }
202
203         ptr = lp_interfaces(global_loadparm);
204         loopback_ip = interpret_addr2("127.0.0.1");
205
206         /* probe the kernel for interfaces */
207         total_probed = get_interfaces(ifaces, MAX_INTERFACES);
208
209         /* if we don't have a interfaces line then use all interfaces
210            except loopback */
211         if (!ptr || !*ptr || !**ptr) {
212                 if (total_probed <= 0) {
213                         DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
214                 }
215                 for (i=0;i<total_probed;i++) {
216                         if (ifaces[i].ip.s_addr != loopback_ip.addr) {
217                                 add_interface(ifaces[i].ip, 
218                                               ifaces[i].netmask);
219                         }
220                 }
221         }
222
223         while (ptr && *ptr) {
224                 interpret_interface(*ptr, ifaces, total_probed);
225                 ptr++;
226         }
227
228         if (!local_interfaces) {
229                 DEBUG(0,("WARNING: no network interfaces found\n"));
230         }
231 }
232
233
234 /**
235   unload the interfaces list, so it can be reloaded when needed
236 */
237 void unload_interfaces(void)
238 {
239         talloc_free(local_interfaces);
240         local_interfaces = NULL;
241 }
242
243 /**
244   how many interfaces do we have
245   **/
246 int iface_count(void)
247 {
248         int ret = 0;
249         struct interface *i;
250
251         load_interfaces();
252
253         for (i=local_interfaces;i;i=i->next)
254                 ret++;
255         return ret;
256 }
257
258 /**
259   return IP of the Nth interface
260   **/
261 const char *iface_n_ip(int n)
262 {
263         struct interface *i;
264   
265         load_interfaces();
266
267         for (i=local_interfaces;i && n;i=i->next)
268                 n--;
269
270         if (i) {
271                 return i->ip_s;
272         }
273         return NULL;
274 }
275
276 /**
277   return bcast of the Nth interface
278   **/
279 const char *iface_n_bcast(int n)
280 {
281         struct interface *i;
282   
283         load_interfaces();
284
285         for (i=local_interfaces;i && n;i=i->next)
286                 n--;
287
288         if (i) {
289                 return i->bcast_s;
290         }
291         return NULL;
292 }
293
294 /**
295   return netmask of the Nth interface
296   **/
297 const char *iface_n_netmask(int n)
298 {
299         struct interface *i;
300   
301         load_interfaces();
302
303         for (i=local_interfaces;i && n;i=i->next)
304                 n--;
305
306         if (i) {
307                 return i->nmask_s;
308         }
309         return NULL;
310 }
311
312 /**
313   return the local IP address that best matches a destination IP, or
314   our first interface if none match
315 */
316 const char *iface_best_ip(const char *dest)
317 {
318         struct interface *iface;
319         struct in_addr ip;
320
321         load_interfaces();
322
323         ip.s_addr = interpret_addr(dest);
324         iface = iface_find(ip, True);
325         if (iface) {
326                 return iface->ip_s;
327         }
328         return iface_n_ip(0);
329 }
330
331 /**
332   return True if an IP is one one of our local networks
333 */
334 BOOL iface_is_local(const char *dest)
335 {
336         struct in_addr ip;
337
338         load_interfaces();
339
340         ip.s_addr = interpret_addr(dest);
341         if (iface_find(ip, True)) {
342                 return True;
343         }
344         return False;
345 }
346
347 /**
348   return True if a IP matches a IP/netmask pair
349 */
350 BOOL iface_same_net(const char *ip1, const char *ip2, const char *netmask)
351 {
352         return same_net(interpret_addr2(ip1),
353                         interpret_addr2(ip2),
354                         interpret_addr2(netmask));
355 }