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 #define MAX_INTERFACES 128
26 static struct iface_struct *probed_ifaces;
27 static int total_probed;
29 extern int DEBUGLEVEL;
31 struct in_addr ipzero;
32 struct in_addr allones_ip;
33 struct in_addr loopback_ip;
35 static struct interface *local_interfaces = NULL;
37 #define ALLONES ((uint32)0xFFFFFFFF)
38 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
39 #define MKNETADDR(_IP, _NM) (_IP & _NM)
41 /****************************************************************************
42 Try and find an interface that matches an ip. If we cannot, return NULL
43 **************************************************************************/
44 static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
47 if (zero_ip(ip)) return local_interfaces;
49 for (i=local_interfaces;i;i=i->next)
51 if (same_net(i->ip,ip,i->nmask)) return i;
52 } else if ((i->ip).s_addr == ip.s_addr) return i;
58 /****************************************************************************
59 add an interface to the linked list of interfaces
60 ****************************************************************************/
61 static void add_interface(struct in_addr ip, struct in_addr nmask)
63 struct interface *iface;
64 if (iface_find(ip, False)) {
65 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
69 if (ip_equal(nmask, allones_ip)) {
70 DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
74 iface = (struct interface *)malloc(sizeof(*iface));
81 iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
83 DLIST_ADD(local_interfaces, iface);
85 DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
86 DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
87 DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
92 /****************************************************************************
93 interpret a single element from a interfaces= config line
95 This handles the following different forms:
97 1) wildcard interface name
102 ****************************************************************************/
103 static void interpret_interface(char *token)
105 struct in_addr ip, nmask;
112 /* first check if it is an interface name */
113 for (i=0;i<total_probed;i++) {
114 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
115 add_interface(probed_ifaces[i].ip,
116 probed_ifaces[i].netmask);
122 /* maybe it is a DNS name */
123 p = strchr_m(token,'/');
125 ip = *interpret_addr2(token);
126 for (i=0;i<total_probed;i++) {
127 if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
128 !ip_equal(allones_ip, probed_ifaces[i].netmask)) {
129 add_interface(probed_ifaces[i].ip,
130 probed_ifaces[i].netmask);
134 DEBUG(2,("can't determine netmask for %s\n", token));
138 /* parse it into an IP address/netmasklength pair */
141 ip = *interpret_addr2(token);
144 nmask = *interpret_addr2(p);
146 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
149 /* maybe the first component was a broadcast address */
150 if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
151 ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
152 for (i=0;i<total_probed;i++) {
153 if (same_net(ip, probed_ifaces[i].ip, nmask)) {
154 add_interface(probed_ifaces[i].ip, nmask);
158 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
162 add_interface(ip, nmask);
166 /****************************************************************************
167 load the list of network interfaces
168 ****************************************************************************/
169 void load_interfaces(void)
173 struct iface_struct ifaces[MAX_INTERFACES];
175 ptr = lp_interfaces();
177 ipzero = *interpret_addr2("0.0.0.0");
178 allones_ip = *interpret_addr2("255.255.255.255");
179 loopback_ip = *interpret_addr2("127.0.0.1");
181 SAFE_FREE(probed_ifaces);
183 /* dump the current interfaces if any */
184 while (local_interfaces) {
185 struct interface *iface = local_interfaces;
186 DLIST_REMOVE(local_interfaces, local_interfaces);
187 ZERO_STRUCTPN(iface);
191 /* probe the kernel for interfaces */
192 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
194 if (total_probed > 0) {
195 probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
198 /* if we don't have a interfaces line then use all broadcast capable
199 interfaces except loopback */
200 if (!ptr || !*ptr || !**ptr) {
201 if (total_probed <= 0) {
202 DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
205 for (i=0;i<total_probed;i++) {
206 if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
207 probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
208 add_interface(probed_ifaces[i].ip,
209 probed_ifaces[i].netmask);
217 interpret_interface(*ptr);
222 if (!local_interfaces) {
223 DEBUG(0,("WARNING: no network interfaces found\n"));
228 /****************************************************************************
229 return True if the list of probed interfaces has changed
230 ****************************************************************************/
231 BOOL interfaces_changed(void)
234 struct iface_struct ifaces[MAX_INTERFACES];
236 n = get_interfaces(ifaces, MAX_INTERFACES);
238 if ((n > 0 )&& (n != total_probed ||
239 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
247 /****************************************************************************
248 check if an IP is one of mine
249 **************************************************************************/
250 BOOL ismyip(struct in_addr ip)
253 for (i=local_interfaces;i;i=i->next)
254 if (ip_equal(i->ip,ip)) return True;
258 /****************************************************************************
259 check if a packet is from a local (known) net
260 **************************************************************************/
261 BOOL is_local_net(struct in_addr from)
264 for (i=local_interfaces;i;i=i->next) {
265 if((from.s_addr & i->nmask.s_addr) ==
266 (i->ip.s_addr & i->nmask.s_addr))
272 /****************************************************************************
273 how many interfaces do we have
274 **************************************************************************/
275 int iface_count(void)
280 for (i=local_interfaces;i;i=i->next)
285 /****************************************************************************
286 True if we have two or more interfaces.
287 **************************************************************************/
288 BOOL we_are_multihomed(void)
290 static int multi = -1;
293 multi = (iface_count() > 1 ? True : False);
298 /****************************************************************************
299 return the Nth interface
300 **************************************************************************/
301 struct interface *get_interface(int n)
305 for (i=local_interfaces;i && n;i=i->next)
312 /****************************************************************************
313 return IP of the Nth interface
314 **************************************************************************/
315 struct in_addr *iface_n_ip(int n)
319 for (i=local_interfaces;i && n;i=i->next)
322 if (i) return &i->ip;
326 /****************************************************************************
327 return bcast of the Nth interface
328 **************************************************************************/
329 struct in_addr *iface_n_bcast(int n)
333 for (i=local_interfaces;i && n;i=i->next)
336 if (i) return &i->bcast;
341 /****************************************************************************
342 this function provides a simple hash of the configured interfaces. It is
343 used to detect a change in interfaces to tell us whether to discard
344 the current wins.dat file.
345 Note that the result is independent of the order of the interfaces
346 **************************************************************************/
347 unsigned iface_hash(void)
352 for (i=local_interfaces;i;i=i->next) {
353 unsigned x1 = (unsigned)str_checksum(inet_ntoa(i->ip));
354 unsigned x2 = (unsigned)str_checksum(inet_ntoa(i->nmask));
362 /* these 3 functions return the ip/bcast/nmask for the interface
363 most appropriate for the given ip address. If they can't find
364 an appropriate interface they return the requested field of the
365 first known interface. */
367 struct in_addr *iface_bcast(struct in_addr ip)
369 struct interface *i = iface_find(ip, True);
370 return(i ? &i->bcast : &local_interfaces->bcast);
373 struct in_addr *iface_ip(struct in_addr ip)
375 struct interface *i = iface_find(ip, True);
376 return(i ? &i->ip : &local_interfaces->ip);