2 Unix SMB/CIFS implementation.
3 multiple interface handling
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
23 static struct iface_struct *probed_ifaces;
24 static int total_probed;
26 static struct in_addr allones_ip;
27 struct in_addr loopback_ip;
29 static struct interface *local_interfaces;
31 #define ALLONES ((uint32_t)0xFFFFFFFF)
32 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
33 #define MKNETADDR(_IP, _NM) (_IP & _NM)
35 /****************************************************************************
36 Try and find an interface that matches an ip. If we cannot, return NULL
37 **************************************************************************/
38 static struct interface *iface_find(struct in_addr ip, BOOL CheckMask)
41 if (is_zero_ip(ip)) return local_interfaces;
43 for (i=local_interfaces;i;i=i->next)
45 if (same_net(i->ip,ip,i->nmask)) return i;
46 } else if ((i->ip).s_addr == ip.s_addr) return i;
52 /****************************************************************************
53 add an interface to the linked list of interfaces
54 ****************************************************************************/
55 static void add_interface(struct in_addr ip, struct in_addr nmask)
57 struct interface *iface;
58 if (iface_find(ip, False)) {
59 DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
63 if (ip_equal(nmask, allones_ip)) {
64 DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip)));
68 iface = (struct interface *)malloc(sizeof(*iface));
75 iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
77 DLIST_ADD(local_interfaces, iface);
79 DEBUG(2,("added interface ip=%s ",inet_ntoa(iface->ip)));
80 DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
81 DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));
86 /****************************************************************************
87 interpret a single element from a interfaces= config line
89 This handles the following different forms:
91 1) wildcard interface name
96 ****************************************************************************/
97 static void interpret_interface(TALLOC_CTX *mem_ctx, const char *token)
99 struct in_addr ip, nmask;
106 /* first check if it is an interface name */
107 for (i=0;i<total_probed;i++) {
108 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
109 add_interface(probed_ifaces[i].ip,
110 probed_ifaces[i].netmask);
116 /* maybe it is a DNS name */
117 p = strchr_m(token,'/');
119 ip = *interpret_addr2(mem_ctx, token);
120 for (i=0;i<total_probed;i++) {
121 if (ip.s_addr == probed_ifaces[i].ip.s_addr &&
122 !ip_equal(allones_ip, probed_ifaces[i].netmask)) {
123 add_interface(probed_ifaces[i].ip,
124 probed_ifaces[i].netmask);
128 DEBUG(2,("can't determine netmask for %s\n", token));
132 /* parse it into an IP address/netmasklength pair */
135 ip = *interpret_addr2(mem_ctx, token);
138 nmask = *interpret_addr2(mem_ctx, p);
140 nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
143 /* maybe the first component was a broadcast address */
144 if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
145 ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
146 for (i=0;i<total_probed;i++) {
147 if (same_net(ip, probed_ifaces[i].ip, nmask)) {
148 add_interface(probed_ifaces[i].ip, nmask);
152 DEBUG(2,("Can't determine ip for broadcast address %s\n", token));
156 add_interface(ip, nmask);
160 /****************************************************************************
161 load the list of network interfaces
162 ****************************************************************************/
163 void load_interfaces(void)
167 struct iface_struct ifaces[MAX_INTERFACES];
170 ptr = lp_interfaces();
171 mem_ctx = talloc_init("load_interfaces");
173 DEBUG(2,("no memory to load interfaces \n"));
177 allones_ip = *interpret_addr2(mem_ctx, "255.255.255.255");
178 loopback_ip = *interpret_addr2(mem_ctx, "127.0.0.1");
180 SAFE_FREE(probed_ifaces);
182 /* dump the current interfaces if any */
183 while (local_interfaces) {
184 struct interface *iface = local_interfaces;
185 DLIST_REMOVE(local_interfaces, local_interfaces);
186 ZERO_STRUCTPN(iface);
190 /* probe the kernel for interfaces */
191 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
193 if (total_probed > 0) {
194 probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed);
197 /* if we don't have a interfaces line then use all broadcast capable
198 interfaces except loopback */
199 if (!ptr || !*ptr || !**ptr) {
200 if (total_probed <= 0) {
201 DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
204 for (i=0;i<total_probed;i++) {
205 if (probed_ifaces[i].netmask.s_addr != allones_ip.s_addr &&
206 probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) {
207 add_interface(probed_ifaces[i].ip,
208 probed_ifaces[i].netmask);
216 interpret_interface(mem_ctx, *ptr);
221 if (!local_interfaces) {
222 DEBUG(0,("WARNING: no network interfaces found\n"));
226 talloc_destroy(mem_ctx);
230 /****************************************************************************
231 return True if the list of probed interfaces has changed
232 ****************************************************************************/
233 BOOL interfaces_changed(void)
236 struct iface_struct ifaces[MAX_INTERFACES];
238 n = get_interfaces(ifaces, MAX_INTERFACES);
240 if ((n > 0 )&& (n != total_probed ||
241 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
249 /****************************************************************************
250 check if an IP is one of mine
251 **************************************************************************/
252 BOOL ismyip(struct in_addr ip)
255 for (i=local_interfaces;i;i=i->next)
256 if (ip_equal(i->ip,ip)) return True;
260 /****************************************************************************
261 check if a packet is from a local (known) net
262 **************************************************************************/
263 BOOL is_local_net(struct in_addr from)
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))
274 /****************************************************************************
275 how many interfaces do we have
276 **************************************************************************/
277 int iface_count(void)
282 for (i=local_interfaces;i;i=i->next)
287 /****************************************************************************
288 return IP of the Nth interface
289 **************************************************************************/
290 struct in_addr *iface_n_ip(int n)
294 for (i=local_interfaces;i && n;i=i->next)
297 if (i) return &i->ip;
301 /****************************************************************************
302 return bcast of the Nth interface
303 **************************************************************************/
304 struct in_addr *iface_n_bcast(int n)
308 for (i=local_interfaces;i && n;i=i->next)
311 if (i) return &i->bcast;
316 /* these 3 functions return the ip/bcast/nmask for the interface
317 most appropriate for the given ip address. If they can't find
318 an appropriate interface they return the requested field of the
319 first known interface. */
321 struct in_addr *iface_ip(struct in_addr ip)
323 struct interface *i = iface_find(ip, True);
324 return(i ? &i->ip : &local_interfaces->ip);
328 return True if a IP is directly reachable on one of our interfaces
330 BOOL iface_local(struct in_addr ip)
332 return iface_find(ip, True) ? True : False;