regedit: improvements for hexedit
[Samba.git] / source3 / lib / interface.c
blob3edeae5742b7ab0b165d160776164c545e59b2c2
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, (struct sockaddr *)&probed_ifaces[i].ip)) {
396 add_interface(&probed_ifaces[i]);
397 return;
400 DEBUG(2,("interpret_interface: "
401 "can't determine interface for %s\n",
402 token));
403 return;
406 /* parse it into an IP address/netmasklength pair */
407 *p = 0;
408 goodaddr = interpret_string_addr(&ss, token, 0);
409 *p++ = '/';
411 if (!goodaddr) {
412 DEBUG(2,("interpret_interface: "
413 "can't determine interface for %s\n",
414 token));
415 return;
418 if (strlen(p) > 2) {
419 goodaddr = interpret_string_addr(&ss_mask, p, 0);
420 if (!goodaddr) {
421 DEBUG(2,("interpret_interface: "
422 "can't determine netmask from %s\n",
423 p));
424 return;
426 } else {
427 char *endp = NULL;
428 unsigned long val = strtoul(p, &endp, 0);
429 if (p == endp || (endp && *endp != '\0')) {
430 DEBUG(2,("interpret_interface: "
431 "can't determine netmask value from %s\n",
432 p));
433 return;
435 if (!make_netmask(&ss_mask, &ss, val)) {
436 DEBUG(2,("interpret_interface: "
437 "can't apply netmask value %lu from %s\n",
438 val,
439 p));
440 return;
444 make_bcast(&ss_bcast, &ss, &ss_mask);
445 make_net(&ss_net, &ss, &ss_mask);
447 /* Maybe the first component was a broadcast address. */
448 if (sockaddr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) ||
449 sockaddr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) {
450 for (i=0;i<total_probed;i++) {
451 if (same_net((struct sockaddr *)&ss,
452 (struct sockaddr *)&probed_ifaces[i].ip,
453 (struct sockaddr *)&ss_mask)) {
454 /* Temporarily replace netmask on
455 * the detected interface - user knows
456 * best.... */
457 struct sockaddr_storage saved_mask =
458 probed_ifaces[i].netmask;
459 probed_ifaces[i].netmask = ss_mask;
460 DEBUG(2,("interpret_interface: "
461 "using netmask value %s from "
462 "config file on interface %s\n",
464 probed_ifaces[i].name));
465 add_interface(&probed_ifaces[i]);
466 probed_ifaces[i].netmask = saved_mask;
467 return;
470 DEBUG(2,("interpret_interface: Can't determine ip for "
471 "broadcast address %s\n",
472 token));
473 return;
476 /* Just fake up the interface definition. User knows best. */
478 DEBUG(2,("interpret_interface: Adding interface %s\n",
479 token));
481 ZERO_STRUCT(ifs);
482 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
483 ifs.flags = IFF_BROADCAST;
484 ifs.ip = ss;
485 ifs.netmask = ss_mask;
486 ifs.bcast = ss_bcast;
487 add_interface(&ifs);
490 /****************************************************************************
491 Load the list of network interfaces.
492 ****************************************************************************/
494 void load_interfaces(void)
496 struct iface_struct *ifaces = NULL;
497 const char **ptr = lp_interfaces();
498 int i;
500 gfree_interfaces();
502 /* Probe the kernel for interfaces */
503 total_probed = get_interfaces(talloc_tos(), &ifaces);
505 if (total_probed > 0) {
506 probed_ifaces = (struct iface_struct *)smb_memdup(ifaces,
507 sizeof(ifaces[0])*total_probed);
508 if (!probed_ifaces) {
509 DEBUG(0,("ERROR: smb_memdup failed\n"));
510 exit(1);
513 TALLOC_FREE(ifaces);
515 /* if we don't have a interfaces line then use all broadcast capable
516 interfaces except loopback */
517 if (!ptr || !*ptr || !**ptr) {
518 if (total_probed <= 0) {
519 DEBUG(0,("ERROR: Could not determine network "
520 "interfaces, you must use a interfaces config line\n"));
521 exit(1);
523 for (i=0;i<total_probed;i++) {
524 if (probed_ifaces[i].flags & IFF_BROADCAST) {
525 add_interface(&probed_ifaces[i]);
528 return;
531 if (ptr) {
532 while (*ptr) {
533 char *ptr_cpy = SMB_STRDUP(*ptr);
534 if (ptr_cpy) {
535 interpret_interface(ptr_cpy);
536 free(ptr_cpy);
538 ptr++;
542 if (!local_interfaces) {
543 DEBUG(0,("WARNING: no network interfaces found\n"));
548 void gfree_interfaces(void)
550 while (local_interfaces) {
551 struct interface *iface = local_interfaces;
552 DLIST_REMOVE(local_interfaces, local_interfaces);
553 SAFE_FREE(iface->name);
554 SAFE_FREE(iface);
557 SAFE_FREE(probed_ifaces);
560 /****************************************************************************
561 Return True if the list of probed interfaces has changed.
562 ****************************************************************************/
564 bool interfaces_changed(void)
566 bool ret = false;
567 int n;
568 struct iface_struct *ifaces = NULL;
570 n = get_interfaces(talloc_tos(), &ifaces);
572 if ((n > 0 )&& (n != total_probed ||
573 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
574 ret = true;
577 TALLOC_FREE(ifaces);
578 return ret;