pyldb: Modernize test suite
[Samba.git] / source3 / lib / interface.c
blobadf8b429eb2c73303e020d64ef1b08aa3a8a95b7
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"
22 #include "lib/socket/interfaces.h"
24 static struct iface_struct *probed_ifaces;
25 static int total_probed;
27 static struct interface *local_interfaces;
29 /****************************************************************************
30 Check if an IP is one of mine.
31 **************************************************************************/
33 bool ismyaddr(const struct sockaddr *ip)
35 struct interface *i;
36 for (i=local_interfaces;i;i=i->next) {
37 if (sockaddr_equal((struct sockaddr *)&i->ip,ip)) {
38 return true;
41 return false;
44 bool ismyip_v4(struct in_addr ip)
46 struct sockaddr_storage ss;
47 in_addr_to_sockaddr_storage(&ss, ip);
48 return ismyaddr((struct sockaddr *)&ss);
51 /****************************************************************************
52 Try and find an interface that matches an ip. If we cannot, return NULL.
53 **************************************************************************/
55 static struct interface *iface_find(const struct sockaddr *ip,
56 bool check_mask)
58 struct interface *i;
60 if (is_address_any(ip)) {
61 return local_interfaces;
64 for (i=local_interfaces;i;i=i->next) {
65 if (check_mask) {
66 if (same_net(ip, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
67 return i;
69 } else if (sockaddr_equal((struct sockaddr *)&i->ip, ip)) {
70 return i;
74 return NULL;
77 /****************************************************************************
78 Check if a packet is from a local (known) net.
79 **************************************************************************/
81 bool is_local_net(const struct sockaddr *from)
83 struct interface *i;
84 for (i=local_interfaces;i;i=i->next) {
85 if (same_net(from, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
86 return true;
89 return false;
92 #if defined(HAVE_IPV6)
93 void setup_linklocal_scope_id(struct sockaddr *pss)
95 struct interface *i;
96 for (i=local_interfaces;i;i=i->next) {
97 if (sockaddr_equal((struct sockaddr *)&i->ip,pss)) {
98 struct sockaddr_in6 *psa6 =
99 (struct sockaddr_in6 *)pss;
100 psa6->sin6_scope_id = if_nametoindex(i->name);
101 return;
105 #endif
107 /****************************************************************************
108 Check if a packet is from a local (known) net.
109 **************************************************************************/
111 bool is_local_net_v4(struct in_addr from)
113 struct sockaddr_storage ss;
115 in_addr_to_sockaddr_storage(&ss, from);
116 return is_local_net((struct sockaddr *)&ss);
119 /****************************************************************************
120 How many interfaces do we have ?
121 **************************************************************************/
123 int iface_count(void)
125 int ret = 0;
126 struct interface *i;
128 for (i=local_interfaces;i;i=i->next) {
129 ret++;
131 return ret;
134 /****************************************************************************
135 How many non-loopback IPv4 interfaces do we have ?
136 **************************************************************************/
138 int iface_count_v4_nl(void)
140 int ret = 0;
141 struct interface *i;
143 for (i=local_interfaces;i;i=i->next) {
144 if (is_loopback_addr((struct sockaddr *)&i->ip)) {
145 continue;
147 if (i->ip.ss_family == AF_INET) {
148 ret++;
151 return ret;
154 /****************************************************************************
155 Return a pointer to the in_addr of the first IPv4 interface that's
156 not 0.0.0.0.
157 **************************************************************************/
159 const struct in_addr *first_ipv4_iface(void)
161 struct interface *i;
163 for (i=local_interfaces;i ;i=i->next) {
164 if ((i->ip.ss_family == AF_INET) &&
165 (!is_zero_ip_v4(((struct sockaddr_in *)&i->ip)->sin_addr)))
167 break;
171 if (!i) {
172 return NULL;
174 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
177 /****************************************************************************
178 Return the Nth interface.
179 **************************************************************************/
181 struct interface *get_interface(int n)
183 struct interface *i;
185 for (i=local_interfaces;i && n;i=i->next) {
186 n--;
189 if (i) {
190 return i;
192 return NULL;
195 /****************************************************************************
196 Return IP sockaddr_storage of the Nth interface.
197 **************************************************************************/
199 const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
201 struct interface *i;
203 for (i=local_interfaces;i && n;i=i->next) {
204 n--;
207 if (i) {
208 return &i->ip;
210 return NULL;
213 /****************************************************************************
214 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
215 **************************************************************************/
217 const struct in_addr *iface_n_ip_v4(int n)
219 struct interface *i;
221 for (i=local_interfaces;i && n;i=i->next) {
222 n--;
225 if (i && i->ip.ss_family == AF_INET) {
226 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
228 return NULL;
231 /****************************************************************************
232 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
233 **************************************************************************/
235 const struct in_addr *iface_n_bcast_v4(int n)
237 struct interface *i;
239 for (i=local_interfaces;i && n;i=i->next) {
240 n--;
243 if (i && i->ip.ss_family == AF_INET) {
244 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
246 return NULL;
249 /****************************************************************************
250 Return bcast of the Nth interface.
251 **************************************************************************/
253 const struct sockaddr_storage *iface_n_bcast(int n)
255 struct interface *i;
257 for (i=local_interfaces;i && n;i=i->next) {
258 n--;
261 if (i) {
262 return &i->bcast;
264 return NULL;
267 /* these 3 functions return the ip/bcast/nmask for the interface
268 most appropriate for the given ip address. If they can't find
269 an appropriate interface they return the requested field of the
270 first known interface. */
272 const struct sockaddr_storage *iface_ip(const struct sockaddr *ip)
274 struct interface *i = iface_find(ip, true);
275 if (i) {
276 return &i->ip;
279 /* Search for the first interface with
280 * matching address family. */
282 for (i=local_interfaces;i;i=i->next) {
283 if (i->ip.ss_family == ip->sa_family) {
284 return &i->ip;
287 return NULL;
291 return True if a IP is directly reachable on one of our interfaces
294 bool iface_local(const struct sockaddr *ip)
296 return iface_find(ip, true) ? true : false;
299 /****************************************************************************
300 Add an interface to the linked list of interfaces.
301 ****************************************************************************/
303 static void add_interface(const struct iface_struct *ifs)
305 char addr[INET6_ADDRSTRLEN];
306 struct interface *iface;
308 if (iface_find((const struct sockaddr *)&ifs->ip, False)) {
309 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
310 print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
311 return;
314 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
315 DEBUG(3,("not adding non-broadcast interface %s\n",
316 ifs->name ));
317 return;
320 iface = SMB_MALLOC_P(struct interface);
321 if (!iface) {
322 return;
325 ZERO_STRUCTPN(iface);
327 iface->name = SMB_STRDUP(ifs->name);
328 if (!iface->name) {
329 SAFE_FREE(iface);
330 return;
332 iface->flags = ifs->flags;
333 iface->ip = ifs->ip;
334 iface->netmask = ifs->netmask;
335 iface->bcast = ifs->bcast;
337 DLIST_ADD(local_interfaces, iface);
339 DEBUG(2,("added interface %s ip=%s ",
340 iface->name,
341 print_sockaddr(addr, sizeof(addr), &iface->ip) ));
342 DEBUG(2,("bcast=%s ",
343 print_sockaddr(addr, sizeof(addr),
344 &iface->bcast) ));
345 DEBUG(2,("netmask=%s\n",
346 print_sockaddr(addr, sizeof(addr),
347 &iface->netmask) ));
350 /****************************************************************************
351 Interpret a single element from a interfaces= config line.
353 This handles the following different forms:
355 1) wildcard interface name
356 2) DNS name
357 3) IP/masklen
358 4) ip/mask
359 5) bcast/mask
360 ****************************************************************************/
362 static void interpret_interface(char *token)
364 struct sockaddr_storage ss;
365 struct sockaddr_storage ss_mask;
366 struct sockaddr_storage ss_net;
367 struct sockaddr_storage ss_bcast;
368 struct iface_struct ifs;
369 char *p;
370 int i;
371 bool added=false;
372 bool goodaddr = false;
374 /* first check if it is an interface name */
375 for (i=0;i<total_probed;i++) {
376 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
377 add_interface(&probed_ifaces[i]);
378 added = true;
381 if (added) {
382 return;
385 /* maybe it is a DNS name */
386 p = strchr_m(token,'/');
387 if (p == NULL) {
388 if (!interpret_string_addr(&ss, token, 0)) {
389 DEBUG(2, ("interpret_interface: Can't find address "
390 "for %s\n", token));
391 return;
394 for (i=0;i<total_probed;i++) {
395 if (sockaddr_equal((struct sockaddr *)&ss,
396 (struct sockaddr *)&probed_ifaces[i].ip))
398 add_interface(&probed_ifaces[i]);
399 return;
402 DEBUG(2,("interpret_interface: "
403 "can't determine interface for %s\n",
404 token));
405 return;
408 /* parse it into an IP address/netmasklength pair */
409 *p = 0;
410 goodaddr = interpret_string_addr(&ss, token, 0);
411 *p++ = '/';
413 if (!goodaddr) {
414 DEBUG(2,("interpret_interface: "
415 "can't determine interface for %s\n",
416 token));
417 return;
420 if (strlen(p) > 2) {
421 goodaddr = interpret_string_addr(&ss_mask, p, 0);
422 if (!goodaddr) {
423 DEBUG(2,("interpret_interface: "
424 "can't determine netmask from %s\n",
425 p));
426 return;
428 } else {
429 char *endp = NULL;
430 unsigned long val = strtoul(p, &endp, 0);
431 if (p == endp || (endp && *endp != '\0')) {
432 DEBUG(2,("interpret_interface: "
433 "can't determine netmask value from %s\n",
434 p));
435 return;
437 if (!make_netmask(&ss_mask, &ss, val)) {
438 DEBUG(2,("interpret_interface: "
439 "can't apply netmask value %lu from %s\n",
440 val,
441 p));
442 return;
446 make_bcast(&ss_bcast, &ss, &ss_mask);
447 make_net(&ss_net, &ss, &ss_mask);
449 /* Maybe the first component was a broadcast address. */
450 if (sockaddr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) ||
451 sockaddr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) {
452 for (i=0;i<total_probed;i++) {
453 if (same_net((struct sockaddr *)&ss,
454 (struct sockaddr *)&probed_ifaces[i].ip,
455 (struct sockaddr *)&ss_mask)) {
456 /* Temporarily replace netmask on
457 * the detected interface - user knows
458 * best.... */
459 struct sockaddr_storage saved_mask =
460 probed_ifaces[i].netmask;
461 probed_ifaces[i].netmask = ss_mask;
462 DEBUG(2,("interpret_interface: "
463 "using netmask value %s from "
464 "config file on interface %s\n",
466 probed_ifaces[i].name));
467 add_interface(&probed_ifaces[i]);
468 probed_ifaces[i].netmask = saved_mask;
469 return;
472 DEBUG(2,("interpret_interface: Can't determine ip for "
473 "broadcast address %s\n",
474 token));
475 return;
478 /* Just fake up the interface definition. User knows best. */
480 DEBUG(2,("interpret_interface: Adding interface %s\n",
481 token));
483 ZERO_STRUCT(ifs);
484 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
485 ifs.flags = IFF_BROADCAST;
486 ifs.ip = ss;
487 ifs.netmask = ss_mask;
488 ifs.bcast = ss_bcast;
489 add_interface(&ifs);
492 /****************************************************************************
493 Load the list of network interfaces.
494 ****************************************************************************/
496 void load_interfaces(void)
498 struct iface_struct *ifaces = NULL;
499 const char **ptr = lp_interfaces();
500 int i;
502 gfree_interfaces();
504 /* Probe the kernel for interfaces */
505 total_probed = get_interfaces(talloc_tos(), &ifaces);
507 if (total_probed > 0) {
508 probed_ifaces = (struct iface_struct *)smb_memdup(ifaces,
509 sizeof(ifaces[0])*total_probed);
510 if (!probed_ifaces) {
511 DEBUG(0,("ERROR: smb_memdup failed\n"));
512 exit(1);
515 TALLOC_FREE(ifaces);
517 /* if we don't have a interfaces line then use all broadcast capable
518 interfaces except loopback */
519 if (!ptr || !*ptr || !**ptr) {
520 if (total_probed <= 0) {
521 DEBUG(0,("ERROR: Could not determine network "
522 "interfaces, you must use a interfaces config line\n"));
523 exit(1);
525 for (i=0;i<total_probed;i++) {
526 if (probed_ifaces[i].flags & IFF_BROADCAST) {
527 add_interface(&probed_ifaces[i]);
530 return;
533 if (ptr) {
534 while (*ptr) {
535 char *ptr_cpy = SMB_STRDUP(*ptr);
536 if (ptr_cpy) {
537 interpret_interface(ptr_cpy);
538 free(ptr_cpy);
540 ptr++;
544 if (!local_interfaces) {
545 DEBUG(0,("WARNING: no network interfaces found\n"));
550 void gfree_interfaces(void)
552 while (local_interfaces) {
553 struct interface *iface = local_interfaces;
554 DLIST_REMOVE(local_interfaces, local_interfaces);
555 SAFE_FREE(iface->name);
556 SAFE_FREE(iface);
559 SAFE_FREE(probed_ifaces);
562 /****************************************************************************
563 Return True if the list of probed interfaces has changed.
564 ****************************************************************************/
566 bool interfaces_changed(void)
568 bool ret = false;
569 int n;
570 struct iface_struct *ifaces = NULL;
572 n = get_interfaces(talloc_tos(), &ifaces);
574 if ((n > 0 )&& (n != total_probed ||
575 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
576 ret = true;
579 TALLOC_FREE(ifaces);
580 return ret;