wins: fix null pointer crash in nss_wins module.
[Samba.git] / source / lib / interface.c
blob9627bf63dd8ea68ad84c5a6bdbc9113d3cb3b7e1
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 #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 (addr_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 interfaces do we have (v4 only) ?
135 **************************************************************************/
137 int iface_count_v4(void)
139 int ret = 0;
140 struct interface *i;
142 for (i=local_interfaces;i;i=i->next) {
143 if (i->ip.ss_family == AF_INET) {
144 ret++;
147 return ret;
150 /****************************************************************************
151 Return a pointer to the in_addr of the first IPv4 interface.
152 **************************************************************************/
154 const struct in_addr *first_ipv4_iface(void)
156 struct interface *i;
158 for (i=local_interfaces;i ;i=i->next) {
159 if (i->ip.ss_family == AF_INET) {
160 break;
164 if (!i) {
165 return NULL;
167 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
170 /****************************************************************************
171 Return the Nth interface.
172 **************************************************************************/
174 struct interface *get_interface(int n)
176 struct interface *i;
178 for (i=local_interfaces;i && n;i=i->next) {
179 n--;
182 if (i) {
183 return i;
185 return NULL;
188 /****************************************************************************
189 Return IP sockaddr_storage of the Nth interface.
190 **************************************************************************/
192 const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
194 struct interface *i;
196 for (i=local_interfaces;i && n;i=i->next) {
197 n--;
200 if (i) {
201 return &i->ip;
203 return NULL;
206 /****************************************************************************
207 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
208 **************************************************************************/
210 const struct in_addr *iface_n_ip_v4(int n)
212 struct interface *i;
214 for (i=local_interfaces;i && n;i=i->next) {
215 n--;
218 if (i && i->ip.ss_family == AF_INET) {
219 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
221 return NULL;
224 /****************************************************************************
225 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
226 **************************************************************************/
228 const struct in_addr *iface_n_bcast_v4(int n)
230 struct interface *i;
232 for (i=local_interfaces;i && n;i=i->next) {
233 n--;
236 if (i && i->ip.ss_family == AF_INET) {
237 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
239 return NULL;
242 /****************************************************************************
243 Return bcast of the Nth interface.
244 **************************************************************************/
246 const struct sockaddr_storage *iface_n_bcast(int n)
248 struct interface *i;
250 for (i=local_interfaces;i && n;i=i->next) {
251 n--;
254 if (i) {
255 return &i->bcast;
257 return NULL;
260 /* these 3 functions return the ip/bcast/nmask for the interface
261 most appropriate for the given ip address. If they can't find
262 an appropriate interface they return the requested field of the
263 first known interface. */
265 const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip)
267 struct interface *i = iface_find(ip, true);
268 if (i) {
269 return &i->ip;
272 /* Search for the first interface with
273 * matching address family. */
275 for (i=local_interfaces;i;i=i->next) {
276 if (i->ip.ss_family == ip->ss_family) {
277 return &i->ip;
280 return NULL;
284 return True if a IP is directly reachable on one of our interfaces
287 bool iface_local(const struct sockaddr_storage *ip)
289 return iface_find(ip, True) ? true : false;
292 /****************************************************************************
293 Add an interface to the linked list of interfaces.
294 ****************************************************************************/
296 static void add_interface(const struct iface_struct *ifs)
298 char addr[INET6_ADDRSTRLEN];
299 struct interface *iface;
301 if (iface_find(&ifs->ip, False)) {
302 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
303 print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
304 return;
307 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
308 DEBUG(3,("not adding non-broadcast interface %s\n",
309 ifs->name ));
310 return;
313 iface = SMB_MALLOC_P(struct interface);
314 if (!iface) {
315 return;
318 ZERO_STRUCTPN(iface);
320 iface->name = SMB_STRDUP(ifs->name);
321 if (!iface->name) {
322 SAFE_FREE(iface);
323 return;
325 iface->flags = ifs->flags;
326 iface->ip = ifs->ip;
327 iface->netmask = ifs->netmask;
328 iface->bcast = ifs->bcast;
330 DLIST_ADD(local_interfaces, iface);
332 DEBUG(2,("added interface %s ip=%s ",
333 iface->name,
334 print_sockaddr(addr, sizeof(addr), &iface->ip) ));
335 DEBUG(2,("bcast=%s ",
336 print_sockaddr(addr, sizeof(addr),
337 &iface->bcast) ));
338 DEBUG(2,("netmask=%s\n",
339 print_sockaddr(addr, sizeof(addr),
340 &iface->netmask) ));
343 /****************************************************************************
344 Interpret a single element from a interfaces= config line.
346 This handles the following different forms:
348 1) wildcard interface name
349 2) DNS name
350 3) IP/masklen
351 4) ip/mask
352 5) bcast/mask
353 ****************************************************************************/
355 static void interpret_interface(char *token)
357 struct sockaddr_storage ss;
358 struct sockaddr_storage ss_mask;
359 struct sockaddr_storage ss_net;
360 struct sockaddr_storage ss_bcast;
361 struct iface_struct ifs;
362 char *p;
363 int i;
364 bool added=false;
365 bool goodaddr = false;
367 /* first check if it is an interface name */
368 for (i=0;i<total_probed;i++) {
369 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
370 add_interface(&probed_ifaces[i]);
371 added = true;
374 if (added) {
375 return;
378 /* maybe it is a DNS name */
379 p = strchr_m(token,'/');
380 if (p == NULL) {
381 if (!interpret_string_addr(&ss, token, 0)) {
382 DEBUG(2, ("interpret_interface: Can't find address "
383 "for %s\n", token));
384 return;
387 for (i=0;i<total_probed;i++) {
388 if (addr_equal(&ss, &probed_ifaces[i].ip)) {
389 add_interface(&probed_ifaces[i]);
390 return;
393 DEBUG(2,("interpret_interface: "
394 "can't determine interface for %s\n",
395 token));
396 return;
399 /* parse it into an IP address/netmasklength pair */
400 *p = 0;
401 goodaddr = interpret_string_addr(&ss, token, 0);
402 *p++ = '/';
404 if (!goodaddr) {
405 DEBUG(2,("interpret_interface: "
406 "can't determine interface for %s\n",
407 token));
408 return;
411 if (strlen(p) > 2) {
412 goodaddr = interpret_string_addr(&ss_mask, p, 0);
413 if (!goodaddr) {
414 DEBUG(2,("interpret_interface: "
415 "can't determine netmask from %s\n",
416 p));
417 return;
419 } else {
420 char *endp = NULL;
421 unsigned long val = strtoul(p, &endp, 0);
422 if (p == endp || (endp && *endp != '\0')) {
423 DEBUG(2,("interpret_interface: "
424 "can't determine netmask value from %s\n",
425 p));
426 return;
428 if (!make_netmask(&ss_mask, &ss, val)) {
429 DEBUG(2,("interpret_interface: "
430 "can't apply netmask value %lu from %s\n",
431 val,
432 p));
433 return;
437 make_bcast(&ss_bcast, &ss, &ss_mask);
438 make_net(&ss_net, &ss, &ss_mask);
440 /* Maybe the first component was a broadcast address. */
441 if (addr_equal(&ss_bcast, &ss) || addr_equal(&ss_net, &ss)) {
442 for (i=0;i<total_probed;i++) {
443 if (same_net(&ss, &probed_ifaces[i].ip, &ss_mask)) {
444 /* Temporarily replace netmask on
445 * the detected interface - user knows
446 * best.... */
447 struct sockaddr_storage saved_mask =
448 probed_ifaces[i].netmask;
449 probed_ifaces[i].netmask = ss_mask;
450 DEBUG(2,("interpret_interface: "
451 "using netmask value %s from "
452 "config file on interface %s\n",
454 probed_ifaces[i].name));
455 add_interface(&probed_ifaces[i]);
456 probed_ifaces[i].netmask = saved_mask;
457 return;
460 DEBUG(2,("interpret_interface: Can't determine ip for "
461 "broadcast address %s\n",
462 token));
463 return;
466 /* Just fake up the interface definition. User knows best. */
468 DEBUG(2,("interpret_interface: Adding interface %s\n",
469 token));
471 ZERO_STRUCT(ifs);
472 safe_strcpy(ifs.name, token, sizeof(ifs.name)-1);
473 ifs.flags = IFF_BROADCAST;
474 ifs.ip = ss;
475 ifs.netmask = ss_mask;
476 ifs.bcast = ss_bcast;
477 add_interface(&ifs);
480 /****************************************************************************
481 Load the list of network interfaces.
482 ****************************************************************************/
484 void load_interfaces(void)
486 struct iface_struct ifaces[MAX_INTERFACES];
487 const char **ptr = lp_interfaces();
488 int i;
490 SAFE_FREE(probed_ifaces);
492 /* dump the current interfaces if any */
493 while (local_interfaces) {
494 struct interface *iface = local_interfaces;
495 DLIST_REMOVE(local_interfaces, local_interfaces);
496 SAFE_FREE(iface->name);
497 SAFE_FREE(iface);
500 /* Probe the kernel for interfaces */
501 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
503 if (total_probed > 0) {
504 probed_ifaces = (struct iface_struct *)memdup(ifaces,
505 sizeof(ifaces[0])*total_probed);
506 if (!probed_ifaces) {
507 DEBUG(0,("ERROR: memdup failed\n"));
508 exit(1);
512 /* if we don't have a interfaces line then use all broadcast capable
513 interfaces except loopback */
514 if (!ptr || !*ptr || !**ptr) {
515 if (total_probed <= 0) {
516 DEBUG(0,("ERROR: Could not determine network "
517 "interfaces, you must use a interfaces config line\n"));
518 exit(1);
520 for (i=0;i<total_probed;i++) {
521 if (probed_ifaces[i].flags & IFF_BROADCAST) {
522 add_interface(&probed_ifaces[i]);
525 return;
528 if (ptr) {
529 while (*ptr) {
530 char *ptr_cpy = SMB_STRDUP(*ptr);
531 if (ptr_cpy) {
532 interpret_interface(ptr_cpy);
533 free(ptr_cpy);
535 ptr++;
539 if (!local_interfaces) {
540 DEBUG(0,("WARNING: no network interfaces found\n"));
545 void gfree_interfaces(void)
547 while (local_interfaces) {
548 struct interface *iface = local_interfaces;
549 DLIST_REMOVE(local_interfaces, local_interfaces);
550 SAFE_FREE(iface->name);
551 SAFE_FREE(iface);
554 SAFE_FREE(probed_ifaces);
557 /****************************************************************************
558 Return True if the list of probed interfaces has changed.
559 ****************************************************************************/
561 bool interfaces_changed(void)
563 int n;
564 struct iface_struct ifaces[MAX_INTERFACES];
566 n = get_interfaces(ifaces, MAX_INTERFACES);
568 if ((n > 0 )&& (n != total_probed ||
569 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
570 return true;
573 return false;