s4: lsa-server: fix crash bugs related to [out,ref] ** changes
[Samba/nascimento.git] / source3 / lib / interface.c
blobf533ec92c780bd1ae8f0039ff0fb4eff5c9813cd
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 *ip)
34 struct interface *i;
35 for (i=local_interfaces;i;i=i->next) {
36 if (addr_equal((struct sockaddr *)&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((struct sockaddr *)&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 *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, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
66 return i;
68 } else if (addr_equal((struct sockaddr *)&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 *from)
82 struct interface *i;
83 for (i=local_interfaces;i;i=i->next) {
84 if (same_net(from, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
85 return true;
88 return false;
91 #if defined(HAVE_IPV6)
92 void setup_linklocal_scope_id(struct sockaddr *pss)
94 struct interface *i;
95 for (i=local_interfaces;i;i=i->next) {
96 if (addr_equal((struct sockaddr *)&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((struct sockaddr *)&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((struct sockaddr *)&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.
155 **************************************************************************/
157 const struct in_addr *first_ipv4_iface(void)
159 struct interface *i;
161 for (i=local_interfaces;i ;i=i->next) {
162 if (i->ip.ss_family == AF_INET) {
163 break;
167 if (!i) {
168 return NULL;
170 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
173 /****************************************************************************
174 Return the Nth interface.
175 **************************************************************************/
177 struct interface *get_interface(int n)
179 struct interface *i;
181 for (i=local_interfaces;i && n;i=i->next) {
182 n--;
185 if (i) {
186 return i;
188 return NULL;
191 /****************************************************************************
192 Return IP sockaddr_storage of the Nth interface.
193 **************************************************************************/
195 const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
197 struct interface *i;
199 for (i=local_interfaces;i && n;i=i->next) {
200 n--;
203 if (i) {
204 return &i->ip;
206 return NULL;
209 /****************************************************************************
210 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
211 **************************************************************************/
213 const struct in_addr *iface_n_ip_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->ip)->sin_addr;
224 return NULL;
227 /****************************************************************************
228 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
229 **************************************************************************/
231 const struct in_addr *iface_n_bcast_v4(int n)
233 struct interface *i;
235 for (i=local_interfaces;i && n;i=i->next) {
236 n--;
239 if (i && i->ip.ss_family == AF_INET) {
240 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
242 return NULL;
245 /****************************************************************************
246 Return bcast of the Nth interface.
247 **************************************************************************/
249 const struct sockaddr_storage *iface_n_bcast(int n)
251 struct interface *i;
253 for (i=local_interfaces;i && n;i=i->next) {
254 n--;
257 if (i) {
258 return &i->bcast;
260 return NULL;
263 /* these 3 functions return the ip/bcast/nmask for the interface
264 most appropriate for the given ip address. If they can't find
265 an appropriate interface they return the requested field of the
266 first known interface. */
268 const struct sockaddr_storage *iface_ip(const struct sockaddr *ip)
270 struct interface *i = iface_find(ip, true);
271 if (i) {
272 return &i->ip;
275 /* Search for the first interface with
276 * matching address family. */
278 for (i=local_interfaces;i;i=i->next) {
279 if (i->ip.ss_family == ip->sa_family) {
280 return &i->ip;
283 return NULL;
287 return True if a IP is directly reachable on one of our interfaces
290 bool iface_local(const struct sockaddr *ip)
292 return iface_find(ip, true) ? true : false;
295 /****************************************************************************
296 Add an interface to the linked list of interfaces.
297 ****************************************************************************/
299 static void add_interface(const struct iface_struct *ifs)
301 char addr[INET6_ADDRSTRLEN];
302 struct interface *iface;
304 if (iface_find((struct sockaddr *)&ifs->ip, False)) {
305 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
306 print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
307 return;
310 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
311 DEBUG(3,("not adding non-broadcast interface %s\n",
312 ifs->name ));
313 return;
316 iface = SMB_MALLOC_P(struct interface);
317 if (!iface) {
318 return;
321 ZERO_STRUCTPN(iface);
323 iface->name = SMB_STRDUP(ifs->name);
324 if (!iface->name) {
325 SAFE_FREE(iface);
326 return;
328 iface->flags = ifs->flags;
329 iface->ip = ifs->ip;
330 iface->netmask = ifs->netmask;
331 iface->bcast = ifs->bcast;
333 DLIST_ADD(local_interfaces, iface);
335 DEBUG(2,("added interface %s ip=%s ",
336 iface->name,
337 print_sockaddr(addr, sizeof(addr), &iface->ip) ));
338 DEBUG(2,("bcast=%s ",
339 print_sockaddr(addr, sizeof(addr),
340 &iface->bcast) ));
341 DEBUG(2,("netmask=%s\n",
342 print_sockaddr(addr, sizeof(addr),
343 &iface->netmask) ));
346 /****************************************************************************
347 Interpret a single element from a interfaces= config line.
349 This handles the following different forms:
351 1) wildcard interface name
352 2) DNS name
353 3) IP/masklen
354 4) ip/mask
355 5) bcast/mask
356 ****************************************************************************/
358 static void interpret_interface(char *token)
360 struct sockaddr_storage ss;
361 struct sockaddr_storage ss_mask;
362 struct sockaddr_storage ss_net;
363 struct sockaddr_storage ss_bcast;
364 struct iface_struct ifs;
365 char *p;
366 int i;
367 bool added=false;
368 bool goodaddr = false;
370 /* first check if it is an interface name */
371 for (i=0;i<total_probed;i++) {
372 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
373 add_interface(&probed_ifaces[i]);
374 added = true;
377 if (added) {
378 return;
381 /* maybe it is a DNS name */
382 p = strchr_m(token,'/');
383 if (p == NULL) {
384 if (!interpret_string_addr(&ss, token, 0)) {
385 DEBUG(2, ("interpret_interface: Can't find address "
386 "for %s\n", token));
387 return;
390 for (i=0;i<total_probed;i++) {
391 if (addr_equal((struct sockaddr *)&ss, (struct sockaddr *)&probed_ifaces[i].ip)) {
392 add_interface(&probed_ifaces[i]);
393 return;
396 DEBUG(2,("interpret_interface: "
397 "can't determine interface for %s\n",
398 token));
399 return;
402 /* parse it into an IP address/netmasklength pair */
403 *p = 0;
404 goodaddr = interpret_string_addr(&ss, token, 0);
405 *p++ = '/';
407 if (!goodaddr) {
408 DEBUG(2,("interpret_interface: "
409 "can't determine interface for %s\n",
410 token));
411 return;
414 if (strlen(p) > 2) {
415 goodaddr = interpret_string_addr(&ss_mask, p, 0);
416 if (!goodaddr) {
417 DEBUG(2,("interpret_interface: "
418 "can't determine netmask from %s\n",
419 p));
420 return;
422 } else {
423 char *endp = NULL;
424 unsigned long val = strtoul(p, &endp, 0);
425 if (p == endp || (endp && *endp != '\0')) {
426 DEBUG(2,("interpret_interface: "
427 "can't determine netmask value from %s\n",
428 p));
429 return;
431 if (!make_netmask(&ss_mask, &ss, val)) {
432 DEBUG(2,("interpret_interface: "
433 "can't apply netmask value %lu from %s\n",
434 val,
435 p));
436 return;
440 make_bcast(&ss_bcast, &ss, &ss_mask);
441 make_net(&ss_net, &ss, &ss_mask);
443 /* Maybe the first component was a broadcast address. */
444 if (addr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) ||
445 addr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) {
446 for (i=0;i<total_probed;i++) {
447 if (same_net((struct sockaddr *)&ss,
448 (struct sockaddr *)&probed_ifaces[i].ip,
449 (struct sockaddr *)&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;