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 (ms_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");
183 probed_ifaces = NULL;
186 /* dump the current interfaces if any */
187 while (local_interfaces) {
188 struct interface *iface = local_interfaces;
189 DLIST_REMOVE(local_interfaces, local_interfaces);
190 ZERO_STRUCTPN(iface);
194 /* probe the kernel for interfaces */
195 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
197 if (total_probed > 0) {
198 probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
201 /* if we don't have a interfaces line then use all broadcast capable
202 interfaces except loopback */
203 if (!ptr || !*ptr || !**ptr) {
204 if (total_probed <= 0) {
205 DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
208 for (i=0;i<total_probed;i++) {
209 if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
210 probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
211 add_interface(probed_ifaces[i].ip,
212 probed_ifaces[i].netmask);
220 interpret_interface(*ptr);
225 if (!local_interfaces) {
226 DEBUG(0,("WARNING: no network interfaces found\n"));
231 /****************************************************************************
232 return True if the list of probed interfaces has changed
233 ****************************************************************************/
234 BOOL interfaces_changed(void)
237 struct iface_struct ifaces[MAX_INTERFACES];
239 n = get_interfaces(ifaces, MAX_INTERFACES);
241 if ((n > 0 )&& (n != total_probed ||
242 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
250 /****************************************************************************
251 check if an IP is one of mine
252 **************************************************************************/
253 BOOL ismyip(struct in_addr ip)
256 for (i=local_interfaces;i;i=i->next)
257 if (ip_equal(i->ip,ip)) return True;
261 /****************************************************************************
262 check if a packet is from a local (known) net
263 **************************************************************************/
264 BOOL is_local_net(struct in_addr from)
267 for (i=local_interfaces;i;i=i->next) {
268 if((from.s_addr & i->nmask.s_addr) ==
269 (i->ip.s_addr & i->nmask.s_addr))
275 /****************************************************************************
276 how many interfaces do we have
277 **************************************************************************/
278 int iface_count(void)
283 for (i=local_interfaces;i;i=i->next)
288 /****************************************************************************
289 True if we have two or more interfaces.
290 **************************************************************************/
291 BOOL we_are_multihomed(void)
293 static int multi = -1;
296 multi = (iface_count() > 1 ? True : False);
301 /****************************************************************************
302 return the Nth interface
303 **************************************************************************/
304 struct interface *get_interface(int n)
308 for (i=local_interfaces;i && n;i=i->next)
315 /****************************************************************************
316 return IP of the Nth interface
317 **************************************************************************/
318 struct in_addr *iface_n_ip(int n)
322 for (i=local_interfaces;i && n;i=i->next)
325 if (i) return &i->ip;
329 /****************************************************************************
330 return bcast of the Nth interface
331 **************************************************************************/
332 struct in_addr *iface_n_bcast(int n)
336 for (i=local_interfaces;i && n;i=i->next)
339 if (i) return &i->bcast;
344 /****************************************************************************
345 this function provides a simple hash of the configured interfaces. It is
346 used to detect a change in interfaces to tell us whether to discard
347 the current wins.dat file.
348 Note that the result is independent of the order of the interfaces
349 **************************************************************************/
350 unsigned iface_hash(void)
355 for (i=local_interfaces;i;i=i->next) {
356 unsigned x1 = (unsigned)str_checksum(inet_ntoa(i->ip));
357 unsigned x2 = (unsigned)str_checksum(inet_ntoa(i->nmask));
365 /* these 3 functions return the ip/bcast/nmask for the interface
366 most appropriate for the given ip address. If they can't find
367 an appropriate interface they return the requested field of the
368 first known interface. */
370 struct in_addr *iface_bcast(struct in_addr ip)
372 struct interface *i = iface_find(ip, True);
373 return(i ? &i->bcast : &local_interfaces->bcast);
376 struct in_addr *iface_ip(struct in_addr ip)
378 struct interface *i = iface_find(ip, True);
379 return(i ? &i->ip : &local_interfaces->ip);