Add comment explaining the previous fix.
[Samba.git] / source / lib / interface.c
blobcc8fb371d4ee17d9e5a3f0d10946bb891b43c8f7
1 /*
2 Unix SMB/CIFS implementation.
3 multiple interface handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007
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 3 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, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
23 static struct iface_struct *probed_ifaces;
24 static int total_probed;
26 static struct interface *local_interfaces;
28 /****************************************************************************
29 Check if an IP is one of mine.
30 **************************************************************************/
32 bool ismyaddr(const struct sockaddr_storage *ip)
34 struct interface *i;
35 for (i=local_interfaces;i;i=i->next) {
36 if (sockaddr_equal(&i->ip,ip)) {
37 return true;
40 return false;
43 bool ismyip_v4(struct in_addr ip)
45 struct sockaddr_storage ss;
46 in_addr_to_sockaddr_storage(&ss, ip);
47 return ismyaddr(&ss);
50 /****************************************************************************
51 Try and find an interface that matches an ip. If we cannot, return NULL.
52 **************************************************************************/
54 static struct interface *iface_find(const struct sockaddr_storage *ip,
55 bool check_mask)
57 struct interface *i;
59 if (is_address_any(ip)) {
60 return local_interfaces;
63 for (i=local_interfaces;i;i=i->next) {
64 if (check_mask) {
65 if (same_net(ip, &i->ip, &i->netmask)) {
66 return i;
68 } else if (sockaddr_equal(&i->ip, ip)) {
69 return i;
73 return NULL;
76 /****************************************************************************
77 Check if a packet is from a local (known) net.
78 **************************************************************************/
80 bool is_local_net(const struct sockaddr_storage *from)
82 struct interface *i;
83 for (i=local_interfaces;i;i=i->next) {
84 if (same_net(from, &i->ip, &i->netmask)) {
85 return true;
88 return false;
91 #if defined(HAVE_IPV6)
92 void setup_linklocal_scope_id(struct sockaddr_storage *pss)
94 struct interface *i;
95 for (i=local_interfaces;i;i=i->next) {
96 if (sockaddr_equal(&i->ip,pss)) {
97 struct sockaddr_in6 *psa6 =
98 (struct sockaddr_in6 *)pss;
99 psa6->sin6_scope_id = if_nametoindex(i->name);
100 return;
104 #endif
106 /****************************************************************************
107 Check if a packet is from a local (known) net.
108 **************************************************************************/
110 bool is_local_net_v4(struct in_addr from)
112 struct sockaddr_storage ss;
114 in_addr_to_sockaddr_storage(&ss, from);
115 return is_local_net(&ss);
118 /****************************************************************************
119 How many interfaces do we have ?
120 **************************************************************************/
122 int iface_count(void)
124 int ret = 0;
125 struct interface *i;
127 for (i=local_interfaces;i;i=i->next) {
128 ret++;
130 return ret;
133 /****************************************************************************
134 How many non-loopback IPv4 interfaces do we have ?
135 **************************************************************************/
137 int iface_count_v4_nl(void)
139 int ret = 0;
140 struct interface *i;
142 for (i=local_interfaces;i;i=i->next) {
143 if (is_loopback_addr(&i->ip)) {
144 continue;
146 if (i->ip.ss_family == AF_INET) {
147 ret++;
150 return ret;
153 /****************************************************************************
154 Return a pointer to the in_addr of the first IPv4 interface that's
155 not 0.0.0.0.
156 **************************************************************************/
158 const struct in_addr *first_ipv4_iface(void)
160 struct interface *i;
162 for (i=local_interfaces;i ;i=i->next) {
163 if ((i->ip.ss_family == AF_INET) &&
164 (!is_zero_ip_v4(((struct sockaddr_in *)&i->ip)->sin_addr)))
166 break;
170 if (!i) {
171 return NULL;
173 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
176 /****************************************************************************
177 Return the Nth interface.
178 **************************************************************************/
180 struct interface *get_interface(int n)
182 struct interface *i;
184 for (i=local_interfaces;i && n;i=i->next) {
185 n--;
188 if (i) {
189 return i;
191 return NULL;
194 /****************************************************************************
195 Return IP sockaddr_storage of the Nth interface.
196 **************************************************************************/
198 const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
200 struct interface *i;
202 for (i=local_interfaces;i && n;i=i->next) {
203 n--;
206 if (i) {
207 return &i->ip;
209 return NULL;
212 /****************************************************************************
213 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
214 **************************************************************************/
216 const struct in_addr *iface_n_ip_v4(int n)
218 struct interface *i;
220 for (i=local_interfaces;i && n;i=i->next) {
221 n--;
224 if (i && i->ip.ss_family == AF_INET) {
225 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
227 return NULL;
230 /****************************************************************************
231 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
232 **************************************************************************/
234 const struct in_addr *iface_n_bcast_v4(int n)
236 struct interface *i;
238 for (i=local_interfaces;i && n;i=i->next) {
239 n--;
242 if (i && i->ip.ss_family == AF_INET) {
243 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
245 return NULL;
248 /****************************************************************************
249 Return bcast of the Nth interface.
250 **************************************************************************/
252 const struct sockaddr_storage *iface_n_bcast(int n)
254 struct interface *i;
256 for (i=local_interfaces;i && n;i=i->next) {
257 n--;
260 if (i) {
261 return &i->bcast;
263 return NULL;
266 /* these 3 functions return the ip/bcast/nmask for the interface
267 most appropriate for the given ip address. If they can't find
268 an appropriate interface they return the requested field of the
269 first known interface. */
271 const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip)
273 struct interface *i = iface_find(ip, true);
274 if (i) {
275 return &i->ip;
278 /* Search for the first interface with
279 * matching address family. */
281 for (i=local_interfaces;i;i=i->next) {
282 if (i->ip.ss_family == ip->ss_family) {
283 return &i->ip;
286 return NULL;
290 return True if a IP is directly reachable on one of our interfaces
293 bool iface_local(const struct sockaddr_storage *ip)
295 return iface_find(ip, True) ? true : false;
298 /****************************************************************************
299 Add an interface to the linked list of interfaces.
300 ****************************************************************************/
302 static void add_interface(const struct iface_struct *ifs)
304 char addr[INET6_ADDRSTRLEN];
305 struct interface *iface;
307 if (iface_find(&ifs->ip, False)) {
308 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
309 print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
310 return;
313 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
314 DEBUG(3,("not adding non-broadcast interface %s\n",
315 ifs->name ));
316 return;
319 iface = SMB_MALLOC_P(struct interface);
320 if (!iface) {
321 return;
324 ZERO_STRUCTPN(iface);
326 iface->name = SMB_STRDUP(ifs->name);
327 if (!iface->name) {
328 SAFE_FREE(iface);
329 return;
331 iface->flags = ifs->flags;
332 iface->ip = ifs->ip;
333 iface->netmask = ifs->netmask;
334 iface->bcast = ifs->bcast;
336 DLIST_ADD(local_interfaces, iface);
338 DEBUG(2,("added interface %s ip=%s ",
339 iface->name,
340 print_sockaddr(addr, sizeof(addr), &iface->ip) ));
341 DEBUG(2,("bcast=%s ",
342 print_sockaddr(addr, sizeof(addr),
343 &iface->bcast) ));
344 DEBUG(2,("netmask=%s\n",
345 print_sockaddr(addr, sizeof(addr),
346 &iface->netmask) ));
349 /****************************************************************************
350 Interpret a single element from a interfaces= config line.
352 This handles the following different forms:
354 1) wildcard interface name
355 2) DNS name
356 3) IP/masklen
357 4) ip/mask
358 5) bcast/mask
359 ****************************************************************************/
361 static void interpret_interface(char *token)
363 struct sockaddr_storage ss;
364 struct sockaddr_storage ss_mask;
365 struct sockaddr_storage ss_net;
366 struct sockaddr_storage ss_bcast;
367 struct iface_struct ifs;
368 char *p;
369 int i;
370 bool added=false;
371 bool goodaddr = false;
373 /* first check if it is an interface name */
374 for (i=0;i<total_probed;i++) {
375 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
376 add_interface(&probed_ifaces[i]);
377 added = true;
380 if (added) {
381 return;
384 /* maybe it is a DNS name */
385 p = strchr_m(token,'/');
386 if (p == NULL) {
387 if (!interpret_string_addr(&ss, token, 0)) {
388 DEBUG(2, ("interpret_interface: Can't find address "
389 "for %s\n", token));
390 return;
393 for (i=0;i<total_probed;i++) {
394 if (sockaddr_equal(&ss, &probed_ifaces[i].ip)) {
395 add_interface(&probed_ifaces[i]);
396 return;
399 DEBUG(2,("interpret_interface: "
400 "can't determine interface for %s\n",
401 token));
402 return;
405 /* parse it into an IP address/netmasklength pair */
406 *p = 0;
407 goodaddr = interpret_string_addr(&ss, token, 0);
408 *p++ = '/';
410 if (!goodaddr) {
411 DEBUG(2,("interpret_interface: "
412 "can't determine interface for %s\n",
413 token));
414 return;
417 if (strlen(p) > 2) {
418 goodaddr = interpret_string_addr(&ss_mask, p, 0);
419 if (!goodaddr) {
420 DEBUG(2,("interpret_interface: "
421 "can't determine netmask from %s\n",
422 p));
423 return;
425 } else {
426 char *endp = NULL;
427 unsigned long val = strtoul(p, &endp, 0);
428 if (p == endp || (endp && *endp != '\0')) {
429 DEBUG(2,("interpret_interface: "
430 "can't determine netmask value from %s\n",
431 p));
432 return;
434 if (!make_netmask(&ss_mask, &ss, val)) {
435 DEBUG(2,("interpret_interface: "
436 "can't apply netmask value %lu from %s\n",
437 val,
438 p));
439 return;
443 make_bcast(&ss_bcast, &ss, &ss_mask);
444 make_net(&ss_net, &ss, &ss_mask);
446 /* Maybe the first component was a broadcast address. */
447 if (sockaddr_equal(&ss_bcast, &ss) || sockaddr_equal(&ss_net, &ss)) {
448 for (i=0;i<total_probed;i++) {
449 if (same_net(&ss, &probed_ifaces[i].ip, &ss_mask)) {
450 /* Temporarily replace netmask on
451 * the detected interface - user knows
452 * best.... */
453 struct sockaddr_storage saved_mask =
454 probed_ifaces[i].netmask;
455 probed_ifaces[i].netmask = ss_mask;
456 DEBUG(2,("interpret_interface: "
457 "using netmask value %s from "
458 "config file on interface %s\n",
460 probed_ifaces[i].name));
461 add_interface(&probed_ifaces[i]);
462 probed_ifaces[i].netmask = saved_mask;
463 return;
466 DEBUG(2,("interpret_interface: Can't determine ip for "
467 "broadcast address %s\n",
468 token));
469 return;
472 /* Just fake up the interface definition. User knows best. */
474 DEBUG(2,("interpret_interface: Adding interface %s\n",
475 token));
477 ZERO_STRUCT(ifs);
478 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
479 ifs.flags = IFF_BROADCAST;
480 ifs.ip = ss;
481 ifs.netmask = ss_mask;
482 ifs.bcast = ss_bcast;
483 add_interface(&ifs);
486 /****************************************************************************
487 Load the list of network interfaces.
488 ****************************************************************************/
490 void load_interfaces(void)
492 struct iface_struct ifaces[MAX_INTERFACES];
493 const char **ptr = lp_interfaces();
494 int i;
496 SAFE_FREE(probed_ifaces);
498 /* dump the current interfaces if any */
499 while (local_interfaces) {
500 struct interface *iface = local_interfaces;
501 DLIST_REMOVE(local_interfaces, local_interfaces);
502 SAFE_FREE(iface->name);
503 SAFE_FREE(iface);
506 /* Probe the kernel for interfaces */
507 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
509 if (total_probed > 0) {
510 probed_ifaces = (struct iface_struct *)memdup(ifaces,
511 sizeof(ifaces[0])*total_probed);
512 if (!probed_ifaces) {
513 DEBUG(0,("ERROR: memdup failed\n"));
514 exit(1);
518 /* if we don't have a interfaces line then use all broadcast capable
519 interfaces except loopback */
520 if (!ptr || !*ptr || !**ptr) {
521 if (total_probed <= 0) {
522 DEBUG(0,("ERROR: Could not determine network "
523 "interfaces, you must use a interfaces config line\n"));
524 exit(1);
526 for (i=0;i<total_probed;i++) {
527 if (probed_ifaces[i].flags & IFF_BROADCAST) {
528 add_interface(&probed_ifaces[i]);
531 return;
534 if (ptr) {
535 while (*ptr) {
536 char *ptr_cpy = SMB_STRDUP(*ptr);
537 if (ptr_cpy) {
538 interpret_interface(ptr_cpy);
539 free(ptr_cpy);
541 ptr++;
545 if (!local_interfaces) {
546 DEBUG(0,("WARNING: no network interfaces found\n"));
551 void gfree_interfaces(void)
553 while (local_interfaces) {
554 struct interface *iface = local_interfaces;
555 DLIST_REMOVE(local_interfaces, local_interfaces);
556 SAFE_FREE(iface->name);
557 SAFE_FREE(iface);
560 SAFE_FREE(probed_ifaces);
563 /****************************************************************************
564 Return True if the list of probed interfaces has changed.
565 ****************************************************************************/
567 bool interfaces_changed(void)
569 int n;
570 struct iface_struct ifaces[MAX_INTERFACES];
572 n = get_interfaces(ifaces, MAX_INTERFACES);
574 if ((n > 0 )&& (n != total_probed ||
575 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
576 return true;
579 return false;