2 Unix SMB/Netbios implementation.
4 multiple interface handling
5 Copyright (C) Andrew Tridgell 1992-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 static struct iface_struct *probed_ifaces;
25 static int total_probed;
27 struct in_addr allones_ip;
28 struct in_addr loopback_ip;
30 static struct interface *local_interfaces;
32 #define ALLONES ((uint32)0xFFFFFFFF)
33 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
34 #define MKNETADDR(_IP, _NM) (_IP & _NM)
36 /****************************************************************************
37 Try and find an interface that matches an ip. If we cannot, return NULL
38 **************************************************************************/
39 static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
42 if (is_zero_ip(ip)) return local_interfaces;
44 for (i=local_interfaces;i;i=i->next)
46 if (same_net(i->ip,ip,i->nmask)) return i;
47 } else if ((i->ip).s_addr == ip.s_addr) return i;
53 /****************************************************************************
54 add an interface to the linked list of interfaces
55 ****************************************************************************/
56 static void add_interface(struct in_addr ip, struct in_addr nmask)
58 struct interface *iface;
59 if (iface_find(ip, False)) {
60 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
64 if (ip_equal(nmask, allones_ip)) {
65 DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
69 iface = (struct interface *)malloc(sizeof(*iface));
76 iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
78 DLIST_ADD(local_interfaces, iface);
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)));
87 /****************************************************************************
88 interpret a single element from a interfaces= config line
90 This handles the following different forms:
92 1) wildcard interface name
97 ****************************************************************************/
98 static void interpret_interface(char *token)
100 struct in_addr ip, nmask;
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);
117 /* maybe it is a DNS name */
118 p = strchr_m(token,'/');
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);
129 DEBUG(2,("can't determine netmask for %s\n", token));
133 /* parse it into an IP address/netmasklength pair */
136 ip = *interpret_addr2(token);
139 nmask = *interpret_addr2(p);
141 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
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);
153 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
157 add_interface(ip, nmask);
161 /****************************************************************************
162 load the list of network interfaces
163 ****************************************************************************/
164 void load_interfaces(void)
168 struct iface_struct ifaces[MAX_INTERFACES];
170 ptr = lp_interfaces();
172 allones_ip = *interpret_addr2("255.255.255.255");
173 loopback_ip = *interpret_addr2("127.0.0.1");
175 SAFE_FREE(probed_ifaces);
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);
185 /* probe the kernel for interfaces */
186 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
188 if (total_probed > 0) {
189 probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
192 /* if we don't have a interfaces line then use all broadcast capable
193 interfaces except loopback */
194 if (!ptr || !*ptr || !**ptr) {
195 if (total_probed <= 0) {
196 DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
199 for (i=0;i<total_probed;i++) {
200 if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
201 probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
202 add_interface(probed_ifaces[i].ip,
203 probed_ifaces[i].netmask);
211 interpret_interface(*ptr);
216 if (!local_interfaces) {
217 DEBUG(0,("WARNING: no network interfaces found\n"));
222 /****************************************************************************
223 return True if the list of probed interfaces has changed
224 ****************************************************************************/
225 BOOL interfaces_changed(void)
228 struct iface_struct ifaces[MAX_INTERFACES];
230 n = get_interfaces(ifaces, MAX_INTERFACES);
232 if ((n > 0 )&& (n != total_probed ||
233 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
241 /****************************************************************************
242 check if an IP is one of mine
243 **************************************************************************/
244 BOOL ismyip(struct in_addr ip)
247 for (i=local_interfaces;i;i=i->next)
248 if (ip_equal(i->ip,ip)) return True;
252 /****************************************************************************
253 check if a packet is from a local (known) net
254 **************************************************************************/
255 BOOL is_local_net(struct in_addr from)
258 for (i=local_interfaces;i;i=i->next) {
259 if((from.s_addr & i->nmask.s_addr) ==
260 (i->ip.s_addr & i->nmask.s_addr))
266 /****************************************************************************
267 how many interfaces do we have
268 **************************************************************************/
269 int iface_count(void)
274 for (i=local_interfaces;i;i=i->next)
279 /****************************************************************************
280 True if we have two or more interfaces.
281 **************************************************************************/
282 BOOL we_are_multihomed(void)
284 static int multi = -1;
287 multi = (iface_count() > 1 ? True : False);
292 /****************************************************************************
293 return the Nth interface
294 **************************************************************************/
295 struct interface *get_interface(int n)
299 for (i=local_interfaces;i && n;i=i->next)
306 /****************************************************************************
307 return IP of the Nth interface
308 **************************************************************************/
309 struct in_addr *iface_n_ip(int n)
313 for (i=local_interfaces;i && n;i=i->next)
316 if (i) return &i->ip;
320 /****************************************************************************
321 return bcast of the Nth interface
322 **************************************************************************/
323 struct in_addr *iface_n_bcast(int n)
327 for (i=local_interfaces;i && n;i=i->next)
330 if (i) return &i->bcast;
335 /****************************************************************************
336 this function provides a simple hash of the configured interfaces. It is
337 used to detect a change in interfaces to tell us whether to discard
338 the current wins.dat file.
339 Note that the result is independent of the order of the interfaces
340 **************************************************************************/
341 unsigned iface_hash(void)
346 for (i=local_interfaces;i;i=i->next) {
347 unsigned x1 = (unsigned)str_checksum(inet_ntoa(i->ip));
348 unsigned x2 = (unsigned)str_checksum(inet_ntoa(i->nmask));
356 /* these 3 functions return the ip/bcast/nmask for the interface
357 most appropriate for the given ip address. If they can't find
358 an appropriate interface they return the requested field of the
359 first known interface. */
361 struct in_addr *iface_bcast(struct in_addr ip)
363 struct interface *i = iface_find(ip, True);
364 return(i ? &i->bcast : &local_interfaces->bcast);
367 struct in_addr *iface_ip(struct in_addr ip)
369 struct interface *i = iface_find(ip, True);
370 return(i ? &i->ip : &local_interfaces->ip);