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
23static struct iface_struct *probed_ifaces;
24static int total_probed;
25
26struct in_addr allones_ip;
27struct in_addr loopback_ip;
28
29static 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/****************************************************************************
36Try and find an interface that matches an ip. If we cannot, return NULL
37  **************************************************************************/
38static 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/****************************************************************************
53add an interface to the linked list of interfaces
54****************************************************************************/
55static 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 !defined(__s390__)
64	if (ip_equal(nmask, allones_ip)) {
65		DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
66		return;
67	}
68#endif
69
70	iface = SMB_MALLOC_P(struct interface);
71	if (!iface) return;
72
73	ZERO_STRUCTPN(iface);
74
75	iface->ip = ip;
76	iface->nmask = nmask;
77	iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
78
79	DLIST_ADD(local_interfaces, iface);
80
81	DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
82	DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
83	DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
84}
85
86
87
88/****************************************************************************
89interpret a single element from a interfaces= config line
90
91This handles the following different forms:
92
931) wildcard interface name
942) DNS name
953) IP/masklen
964) ip/mask
975) bcast/mask
98****************************************************************************/
99static void interpret_interface(char *token)
100{
101	struct in_addr ip, nmask;
102	char *p;
103	int i, added=0;
104
105        zero_ip(&ip);
106        zero_ip(&nmask);
107
108	/* first check if it is an interface name */
109	for (i=0;i<total_probed;i++) {
110		if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
111			add_interface(probed_ifaces[i].ip,
112				      probed_ifaces[i].netmask);
113			added = 1;
114		}
115	}
116	if (added) return;
117
118	/* maybe it is a DNS name */
119	p = strchr_m(token,'/');
120	if (!p) {
121		ip = *interpret_addr2(token);
122		for (i=0;i<total_probed;i++) {
123			if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
124			    !ip_equal(allones_ip, probed_ifaces[i].netmask)) {
125				add_interface(probed_ifaces[i].ip,
126					      probed_ifaces[i].netmask);
127				return;
128			}
129		}
130		DEBUG(2,("can't determine netmask for %s\n", token));
131		return;
132	}
133
134	/* parse it into an IP address/netmasklength pair */
135	*p = 0;
136	ip = *interpret_addr2(token);
137	*p++ = '/';
138
139	if (strlen(p) > 2) {
140		nmask = *interpret_addr2(p);
141	} else {
142		nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
143	}
144
145	/* maybe the first component was a broadcast address */
146	if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
147	    ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
148		for (i=0;i<total_probed;i++) {
149			if (same_net(ip, probed_ifaces[i].ip, nmask)) {
150				add_interface(probed_ifaces[i].ip, nmask);
151				return;
152			}
153		}
154		DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
155		return;
156	}
157
158	add_interface(ip, nmask);
159}
160
161
162/****************************************************************************
163load the list of network interfaces
164****************************************************************************/
165void load_interfaces(void)
166{
167	const char **ptr;
168	int i;
169	struct iface_struct ifaces[MAX_INTERFACES];
170
171	ptr = lp_interfaces();
172
173	allones_ip = *interpret_addr2("255.255.255.255");
174	loopback_ip = *interpret_addr2("127.0.0.1");
175
176	SAFE_FREE(probed_ifaces);
177
178	/* dump the current interfaces if any */
179	while (local_interfaces) {
180		struct interface *iface = local_interfaces;
181		DLIST_REMOVE(local_interfaces, local_interfaces);
182		ZERO_STRUCTPN(iface);
183		SAFE_FREE(iface);
184	}
185
186	/* probe the kernel for interfaces */
187	total_probed = get_interfaces(ifaces, MAX_INTERFACES);
188
189	if (total_probed > 0) {
190		probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
191	}
192
193	/* if we don't have a interfaces line then use all broadcast capable
194	   interfaces except loopback */
195	if (!ptr || !*ptr || !**ptr) {
196		if (total_probed <= 0) {
197			DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
198			exit(1);
199		}
200		for (i=0;i<total_probed;i++) {
201			if (
202#if !defined(__s390__)
203			    probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
204#endif
205			    probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
206				add_interface(probed_ifaces[i].ip,
207					      probed_ifaces[i].netmask);
208			}
209		}
210		return;
211	}
212
213	if (ptr) {
214		while (*ptr) {
215			char *ptr_cpy = SMB_STRDUP(*ptr);
216			if (ptr_cpy) {
217				interpret_interface(ptr_cpy);
218				free(ptr_cpy);
219			}
220			ptr++;
221		}
222	}
223
224	if (!local_interfaces) {
225		DEBUG(0,("WARNING: no network interfaces found\n"));
226	}
227}
228
229
230/****************************************************************************
231return True if the list of probed interfaces has changed
232****************************************************************************/
233BOOL interfaces_changed(void)
234{
235	int n;
236	struct iface_struct ifaces[MAX_INTERFACES];
237
238	n = get_interfaces(ifaces, MAX_INTERFACES);
239
240	if ((n > 0 )&& (n != total_probed ||
241	    memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
242		return True;
243	}
244
245	return False;
246}
247
248
249/****************************************************************************
250  check if an IP is one of mine
251  **************************************************************************/
252BOOL ismyip(struct in_addr ip)
253{
254	struct interface *i;
255	for (i=local_interfaces;i;i=i->next)
256		if (ip_equal(i->ip,ip)) return True;
257	return False;
258}
259
260/****************************************************************************
261  check if a packet is from a local (known) net
262  **************************************************************************/
263BOOL is_local_net(struct in_addr from)
264{
265	struct interface *i;
266	for (i=local_interfaces;i;i=i->next) {
267		if((from.s_addr & i->nmask.s_addr) ==
268		   (i->ip.s_addr & i->nmask.s_addr))
269			return True;
270	}
271	return False;
272}
273
274/****************************************************************************
275  how many interfaces do we have
276  **************************************************************************/
277int iface_count(void)
278{
279	int ret = 0;
280	struct interface *i;
281
282	for (i=local_interfaces;i;i=i->next)
283		ret++;
284	return ret;
285}
286
287/****************************************************************************
288  return the Nth interface
289  **************************************************************************/
290struct interface *get_interface(int n)
291{
292	struct interface *i;
293
294	for (i=local_interfaces;i && n;i=i->next)
295		n--;
296
297	if (i) return i;
298	return NULL;
299}
300
301/****************************************************************************
302  return IP of the Nth interface
303  **************************************************************************/
304struct in_addr *iface_n_ip(int n)
305{
306	struct interface *i;
307
308	for (i=local_interfaces;i && n;i=i->next)
309		n--;
310
311	if (i) return &i->ip;
312	return NULL;
313}
314
315/****************************************************************************
316  return bcast of the Nth interface
317  **************************************************************************/
318struct in_addr *iface_n_bcast(int n)
319{
320	struct interface *i;
321
322	for (i=local_interfaces;i && n;i=i->next)
323		n--;
324
325	if (i) return &i->bcast;
326	return NULL;
327}
328
329
330/* these 3 functions return the ip/bcast/nmask for the interface
331   most appropriate for the given ip address. If they can't find
332   an appropriate interface they return the requested field of the
333   first known interface. */
334
335struct in_addr *iface_ip(struct in_addr ip)
336{
337	struct interface *i = iface_find(ip, True);
338	return(i ? &i->ip : &local_interfaces->ip);
339}
340
341/*
342  return True if a IP is directly reachable on one of our interfaces
343*/
344BOOL iface_local(struct in_addr ip)
345{
346	return iface_find(ip, True) ? True : False;
347}
348