Add test for "struct in6_addr" to the HAVE_IPV6 configure test.
[Samba/gebeck_regimport.git] / source3 / lib / interface.c
blob0696329fd66afd8e4140877cdcc3df7a6aadcc66
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 (addr_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 (addr_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 /****************************************************************************
92 Check if a packet is from a local (known) net.
93 **************************************************************************/
95 bool is_local_net_v4(struct in_addr from)
97 struct sockaddr_storage ss;
99 in_addr_to_sockaddr_storage(&ss, from);
100 return is_local_net(&ss);
103 /****************************************************************************
104 How many interfaces do we have ?
105 **************************************************************************/
107 int iface_count(void)
109 int ret = 0;
110 struct interface *i;
112 for (i=local_interfaces;i;i=i->next) {
113 ret++;
115 return ret;
118 /****************************************************************************
119 How many interfaces do we have (v4 only) ?
120 **************************************************************************/
122 int iface_count_v4(void)
124 int ret = 0;
125 struct interface *i;
127 for (i=local_interfaces;i;i=i->next) {
128 if (i->ip.ss_family == AF_INET) {
129 ret++;
132 return ret;
135 /****************************************************************************
136 Return a pointer to the in_addr of the first IPv4 interface.
137 **************************************************************************/
139 const struct in_addr *first_ipv4_iface(void)
141 struct interface *i;
143 for (i=local_interfaces;i ;i=i->next) {
144 if (i->ip.ss_family == AF_INET) {
145 break;
149 if (!i) {
150 return NULL;
152 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
155 /****************************************************************************
156 Return the Nth interface.
157 **************************************************************************/
159 struct interface *get_interface(int n)
161 struct interface *i;
163 for (i=local_interfaces;i && n;i=i->next) {
164 n--;
167 if (i) {
168 return i;
170 return NULL;
173 /****************************************************************************
174 Return IP sockaddr_storage of the Nth interface.
175 **************************************************************************/
177 const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
179 struct interface *i;
181 for (i=local_interfaces;i && n;i=i->next) {
182 n--;
185 if (i) {
186 return &i->ip;
188 return NULL;
191 /****************************************************************************
192 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
193 **************************************************************************/
195 const struct in_addr *iface_n_ip_v4(int n)
197 struct interface *i;
199 for (i=local_interfaces;i && n;i=i->next) {
200 n--;
203 if (i && i->ip.ss_family == AF_INET) {
204 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
206 return NULL;
209 /****************************************************************************
210 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
211 **************************************************************************/
213 const struct in_addr *iface_n_bcast_v4(int n)
215 struct interface *i;
217 for (i=local_interfaces;i && n;i=i->next) {
218 n--;
221 if (i && i->ip.ss_family == AF_INET) {
222 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
224 return NULL;
227 /****************************************************************************
228 Return bcast of the Nth interface.
229 **************************************************************************/
231 const struct sockaddr_storage *iface_n_bcast(int n)
233 struct interface *i;
235 for (i=local_interfaces;i && n;i=i->next) {
236 n--;
239 if (i) {
240 return &i->bcast;
242 return NULL;
245 /* these 3 functions return the ip/bcast/nmask for the interface
246 most appropriate for the given ip address. If they can't find
247 an appropriate interface they return the requested field of the
248 first known interface. */
250 const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip)
252 struct interface *i = iface_find(ip, true);
253 if (i) {
254 return &i->ip;
257 /* Search for the first interface with
258 * matching address family. */
260 for (i=local_interfaces;i;i=i->next) {
261 if (i->ip.ss_family == ip->ss_family) {
262 return &i->ip;
265 return NULL;
269 return True if a IP is directly reachable on one of our interfaces
272 bool iface_local(struct sockaddr_storage *ip)
274 return iface_find(ip, True) ? true : false;
277 /****************************************************************************
278 Add an interface to the linked list of interfaces.
279 ****************************************************************************/
281 static void add_interface(const struct iface_struct *ifs)
283 char addr[INET6_ADDRSTRLEN];
284 struct interface *iface;
286 if (iface_find(&ifs->ip, False)) {
287 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
288 print_sockaddr(addr, sizeof(addr),
289 &ifs->ip, sizeof(struct sockaddr_storage)) ));
290 return;
293 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
294 DEBUG(3,("not adding non-broadcast interface %s\n",
295 ifs->name ));
296 return;
299 iface = SMB_MALLOC_P(struct interface);
300 if (!iface) {
301 return;
304 ZERO_STRUCTPN(iface);
306 iface->name = SMB_STRDUP(ifs->name);
307 if (!iface->name) {
308 SAFE_FREE(iface);
309 return;
311 iface->flags = ifs->flags;
312 iface->ip = ifs->ip;
313 iface->netmask = ifs->netmask;
314 iface->bcast = ifs->bcast;
316 DLIST_ADD(local_interfaces, iface);
318 DEBUG(2,("added interface %s ip=%s ",
319 iface->name,
320 print_sockaddr(addr, sizeof(addr),
321 &iface->ip, sizeof(struct sockaddr_storage)) ));
322 DEBUG(2,("bcast=%s ",
323 print_sockaddr(addr, sizeof(addr),
324 &iface->bcast,
325 sizeof(struct sockaddr_storage)) ));
326 DEBUG(2,("netmask=%s\n",
327 print_sockaddr(addr, sizeof(addr),
328 &iface->netmask,
329 sizeof(struct sockaddr_storage)) ));
332 /****************************************************************************
333 Create a struct sockaddr_storage with the netmask bits set to 1.
334 ****************************************************************************/
336 bool make_netmask(struct sockaddr_storage *pss_out,
337 const struct sockaddr_storage *pss_in,
338 unsigned long masklen)
340 *pss_out = *pss_in;
341 /* Now apply masklen bits of mask. */
342 #if defined(HAVE_IPV6)
343 if (pss_in->ss_family == AF_INET6) {
344 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
345 unsigned int i;
347 if (masklen > 128) {
348 return false;
350 for (i = 0; masklen >= 8; masklen -= 8, i++) {
351 *p++ = 0xff;
353 /* Deal with the partial byte. */
354 *p++ &= (0xff & ~(0xff>>masklen));
355 i++;
356 for (;i < sizeof(struct in6_addr); i++) {
357 *p++ = '\0';
359 return true;
361 #endif
362 if (pss_in->ss_family == AF_INET) {
363 if (masklen > 32) {
364 return false;
366 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
367 htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
368 return true;
370 return false;
373 /****************************************************************************
374 Create a struct sockaddr_storage set to the broadcast or network adress from
375 an incoming sockaddr_storage.
376 ****************************************************************************/
378 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
379 const struct sockaddr_storage *pss_in,
380 const struct sockaddr_storage *nmask,
381 bool make_bcast)
383 unsigned int i = 0, len = 0;
384 char *pmask = NULL;
385 char *p = NULL;
386 *pss_out = *pss_in;
388 /* Set all zero netmask bits to 1. */
389 #if defined(HAVE_IPV6)
390 if (pss_in->ss_family == AF_INET6) {
391 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
392 pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
393 len = 16;
395 #endif
396 if (pss_in->ss_family == AF_INET) {
397 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
398 pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
399 len = 4;
402 for (i = 0; i < len; i++, p++, pmask++) {
403 if (make_bcast) {
404 *p = (*p & *pmask) | (*pmask ^ 0xff);
405 } else {
406 /* make_net */
407 *p = (*p & *pmask);
412 static void make_bcast(struct sockaddr_storage *pss_out,
413 const struct sockaddr_storage *pss_in,
414 const struct sockaddr_storage *nmask)
416 make_bcast_or_net(pss_out, pss_in, nmask, true);
419 static void make_net(struct sockaddr_storage *pss_out,
420 const struct sockaddr_storage *pss_in,
421 const struct sockaddr_storage *nmask)
423 make_bcast_or_net(pss_out, pss_in, nmask, false);
426 /****************************************************************************
427 Interpret a single element from a interfaces= config line.
429 This handles the following different forms:
431 1) wildcard interface name
432 2) DNS name
433 3) IP/masklen
434 4) ip/mask
435 5) bcast/mask
436 ****************************************************************************/
438 static void interpret_interface(char *token)
440 struct sockaddr_storage ss;
441 struct sockaddr_storage ss_mask;
442 struct sockaddr_storage ss_net;
443 struct sockaddr_storage ss_bcast;
444 struct iface_struct ifs;
445 char *p;
446 int i;
447 bool added=false;
448 bool goodaddr = false;
450 /* first check if it is an interface name */
451 for (i=0;i<total_probed;i++) {
452 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
453 add_interface(&probed_ifaces[i]);
454 added = true;
457 if (added) {
458 return;
461 /* maybe it is a DNS name */
462 p = strchr_m(token,'/');
463 if (p == NULL) {
464 if (!interpret_string_addr(&ss, token, 0)) {
465 DEBUG(2, ("interpret_interface: Can't find address "
466 "for %s\n", token));
467 return;
470 for (i=0;i<total_probed;i++) {
471 if (addr_equal(&ss, &probed_ifaces[i].ip)) {
472 add_interface(&probed_ifaces[i]);
473 return;
476 DEBUG(2,("interpret_interface: "
477 "can't determine interface for %s\n",
478 token));
479 return;
482 /* parse it into an IP address/netmasklength pair */
483 *p = 0;
484 goodaddr = interpret_string_addr(&ss, token, 0);
485 *p++ = '/';
487 if (!goodaddr) {
488 DEBUG(2,("interpret_interface: "
489 "can't determine interface for %s\n",
490 token));
491 return;
494 if (strlen(p) > 2) {
495 goodaddr = interpret_string_addr(&ss_mask, p, 0);
496 if (!goodaddr) {
497 DEBUG(2,("interpret_interface: "
498 "can't determine netmask from %s\n",
499 p));
500 return;
502 } else {
503 char *endp = NULL;
504 unsigned long val = strtoul(p, &endp, 0);
505 if (p == endp || (endp && *endp != '\0')) {
506 DEBUG(2,("interpret_interface: "
507 "can't determine netmask value from %s\n",
508 p));
509 return;
511 if (!make_netmask(&ss_mask, &ss, val)) {
512 DEBUG(2,("interpret_interface: "
513 "can't apply netmask value %lu from %s\n",
514 val,
515 p));
516 return;
520 make_bcast(&ss_bcast, &ss, &ss_mask);
521 make_net(&ss_net, &ss, &ss_mask);
523 /* Maybe the first component was a broadcast address. */
524 if (addr_equal(&ss_bcast, &ss) || addr_equal(&ss_net, &ss)) {
525 for (i=0;i<total_probed;i++) {
526 if (same_net(&ss, &probed_ifaces[i].ip, &ss_mask)) {
527 /* Temporarily replace netmask on
528 * the detected interface - user knows
529 * best.... */
530 struct sockaddr_storage saved_mask =
531 probed_ifaces[i].netmask;
532 probed_ifaces[i].netmask = ss_mask;
533 DEBUG(2,("interpret_interface: "
534 "using netmask value %s from "
535 "config file on interface %s\n",
537 probed_ifaces[i].name));
538 add_interface(&probed_ifaces[i]);
539 probed_ifaces[i].netmask = saved_mask;
540 return;
543 DEBUG(2,("interpret_interface: Can't determine ip for "
544 "broadcast address %s\n",
545 token));
546 return;
549 /* Just fake up the interface definition. User knows best. */
551 DEBUG(2,("interpret_interface: Adding interface %s\n",
552 token));
554 ZERO_STRUCT(ifs);
555 safe_strcpy(ifs.name, token, sizeof(ifs.name)-1);
556 ifs.flags = IFF_BROADCAST;
557 ifs.ip = ss;
558 ifs.netmask = ss_mask;
559 ifs.bcast = ss_bcast;
560 add_interface(&ifs);
563 /****************************************************************************
564 Load the list of network interfaces.
565 ****************************************************************************/
567 void load_interfaces(void)
569 struct iface_struct ifaces[MAX_INTERFACES];
570 const char **ptr = lp_interfaces();
571 int i;
573 SAFE_FREE(probed_ifaces);
575 /* dump the current interfaces if any */
576 while (local_interfaces) {
577 struct interface *iface = local_interfaces;
578 DLIST_REMOVE(local_interfaces, local_interfaces);
579 SAFE_FREE(iface->name);
580 SAFE_FREE(iface);
583 /* Probe the kernel for interfaces */
584 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
586 if (total_probed > 0) {
587 probed_ifaces = (struct iface_struct *)memdup(ifaces,
588 sizeof(ifaces[0])*total_probed);
589 if (!probed_ifaces) {
590 DEBUG(0,("ERROR: memdup failed\n"));
591 exit(1);
595 /* if we don't have a interfaces line then use all broadcast capable
596 interfaces except loopback */
597 if (!ptr || !*ptr || !**ptr) {
598 if (total_probed <= 0) {
599 DEBUG(0,("ERROR: Could not determine network "
600 "interfaces, you must use a interfaces config line\n"));
601 exit(1);
603 for (i=0;i<total_probed;i++) {
604 if (probed_ifaces[i].flags & IFF_BROADCAST) {
605 add_interface(&probed_ifaces[i]);
608 return;
611 if (ptr) {
612 while (*ptr) {
613 char *ptr_cpy = SMB_STRDUP(*ptr);
614 if (ptr_cpy) {
615 interpret_interface(ptr_cpy);
616 free(ptr_cpy);
618 ptr++;
622 if (!local_interfaces) {
623 DEBUG(0,("WARNING: no network interfaces found\n"));
628 void gfree_interfaces(void)
630 while (local_interfaces) {
631 struct interface *iface = local_interfaces;
632 DLIST_REMOVE(local_interfaces, local_interfaces);
633 SAFE_FREE(iface->name);
634 SAFE_FREE(iface);
637 SAFE_FREE(probed_ifaces);
640 /****************************************************************************
641 Return True if the list of probed interfaces has changed.
642 ****************************************************************************/
644 bool interfaces_changed(void)
646 int n;
647 struct iface_struct ifaces[MAX_INTERFACES];
649 n = get_interfaces(ifaces, MAX_INTERFACES);
651 if ((n > 0 )&& (n != total_probed ||
652 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
653 return true;
656 return false;