source: branches/samba-3.5.x/source3/lib/interface.c@ 742

Last change on this file since 742 was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 13.9 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 multiple interface handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Jeremy Allison 2007
6
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.
11
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.
16
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/>.
19*/
20
21#include "includes.h"
22
23static struct iface_struct *probed_ifaces;
24static int total_probed;
25
26static struct interface *local_interfaces;
27
28/****************************************************************************
29 Check if an IP is one of mine.
30**************************************************************************/
31
32bool ismyaddr(const struct sockaddr *ip)
33{
34 struct interface *i;
35 for (i=local_interfaces;i;i=i->next) {
36 if (sockaddr_equal((struct sockaddr *)&i->ip,ip)) {
37 return true;
38 }
39 }
40 return false;
41}
42
43bool ismyip_v4(struct in_addr ip)
44{
45 struct sockaddr_storage ss;
46 in_addr_to_sockaddr_storage(&ss, ip);
47 return ismyaddr((struct sockaddr *)&ss);
48}
49
50/****************************************************************************
51 Try and find an interface that matches an ip. If we cannot, return NULL.
52**************************************************************************/
53
54static struct interface *iface_find(const struct sockaddr *ip,
55 bool check_mask)
56{
57 struct interface *i;
58
59 if (is_address_any(ip)) {
60 return local_interfaces;
61 }
62
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;
67 }
68 } else if (sockaddr_equal((struct sockaddr *)&i->ip, ip)) {
69 return i;
70 }
71 }
72
73 return NULL;
74}
75
76/****************************************************************************
77 Check if a packet is from a local (known) net.
78**************************************************************************/
79
80bool is_local_net(const struct sockaddr *from)
81{
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;
86 }
87 }
88 return false;
89}
90
91#if defined(HAVE_IPV6)
92void setup_linklocal_scope_id(struct sockaddr *pss)
93{
94 struct interface *i;
95 for (i=local_interfaces;i;i=i->next) {
96 if (sockaddr_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;
101 }
102 }
103}
104#endif
105
106/****************************************************************************
107 Check if a packet is from a local (known) net.
108**************************************************************************/
109
110bool is_local_net_v4(struct in_addr from)
111{
112 struct sockaddr_storage ss;
113
114 in_addr_to_sockaddr_storage(&ss, from);
115 return is_local_net((struct sockaddr *)&ss);
116}
117
118/****************************************************************************
119 How many interfaces do we have ?
120**************************************************************************/
121
122int iface_count(void)
123{
124 int ret = 0;
125 struct interface *i;
126
127 for (i=local_interfaces;i;i=i->next) {
128 ret++;
129 }
130 return ret;
131}
132
133/****************************************************************************
134 How many non-loopback IPv4 interfaces do we have ?
135**************************************************************************/
136
137int iface_count_v4_nl(void)
138{
139 int ret = 0;
140 struct interface *i;
141
142 for (i=local_interfaces;i;i=i->next) {
143 if (is_loopback_addr((struct sockaddr *)&i->ip)) {
144 continue;
145 }
146 if (i->ip.ss_family == AF_INET) {
147 ret++;
148 }
149 }
150 return ret;
151}
152
153/****************************************************************************
154 Return a pointer to the in_addr of the first IPv4 interface that's
155 not 0.0.0.0.
156**************************************************************************/
157
158const struct in_addr *first_ipv4_iface(void)
159{
160 struct interface *i;
161
162 for (i=local_interfaces;i ;i=i->next) {
163 if ((i->ip.ss_family == AF_INET) &&
164 (!is_zero_ip_v4(((struct sockaddr_in *)&i->ip)->sin_addr)))
165 {
166 break;
167 }
168 }
169
170 if (!i) {
171 return NULL;
172 }
173 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
174}
175
176/****************************************************************************
177 Return the Nth interface.
178**************************************************************************/
179
180struct interface *get_interface(int n)
181{
182 struct interface *i;
183
184 for (i=local_interfaces;i && n;i=i->next) {
185 n--;
186 }
187
188 if (i) {
189 return i;
190 }
191 return NULL;
192}
193
194/****************************************************************************
195 Return IP sockaddr_storage of the Nth interface.
196**************************************************************************/
197
198const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
199{
200 struct interface *i;
201
202 for (i=local_interfaces;i && n;i=i->next) {
203 n--;
204 }
205
206 if (i) {
207 return &i->ip;
208 }
209 return NULL;
210}
211
212/****************************************************************************
213 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
214**************************************************************************/
215
216const struct in_addr *iface_n_ip_v4(int n)
217{
218 struct interface *i;
219
220 for (i=local_interfaces;i && n;i=i->next) {
221 n--;
222 }
223
224 if (i && i->ip.ss_family == AF_INET) {
225 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
226 }
227 return NULL;
228}
229
230/****************************************************************************
231 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
232**************************************************************************/
233
234const struct in_addr *iface_n_bcast_v4(int n)
235{
236 struct interface *i;
237
238 for (i=local_interfaces;i && n;i=i->next) {
239 n--;
240 }
241
242 if (i && i->ip.ss_family == AF_INET) {
243 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
244 }
245 return NULL;
246}
247
248/****************************************************************************
249 Return bcast of the Nth interface.
250**************************************************************************/
251
252const struct sockaddr_storage *iface_n_bcast(int n)
253{
254 struct interface *i;
255
256 for (i=local_interfaces;i && n;i=i->next) {
257 n--;
258 }
259
260 if (i) {
261 return &i->bcast;
262 }
263 return NULL;
264}
265
266/* these 3 functions return the ip/bcast/nmask for the interface
267 most appropriate for the given ip address. If they can't find
268 an appropriate interface they return the requested field of the
269 first known interface. */
270
271const struct sockaddr_storage *iface_ip(const struct sockaddr *ip)
272{
273 struct interface *i = iface_find(ip, true);
274 if (i) {
275 return &i->ip;
276 }
277
278 /* Search for the first interface with
279 * matching address family. */
280
281 for (i=local_interfaces;i;i=i->next) {
282 if (i->ip.ss_family == ip->sa_family) {
283 return &i->ip;
284 }
285 }
286 return NULL;
287}
288
289/*
290 return True if a IP is directly reachable on one of our interfaces
291*/
292
293bool iface_local(const struct sockaddr *ip)
294{
295 return iface_find(ip, true) ? true : false;
296}
297
298/****************************************************************************
299 Add an interface to the linked list of interfaces.
300****************************************************************************/
301
302static void add_interface(const struct iface_struct *ifs)
303{
304 char addr[INET6_ADDRSTRLEN];
305 struct interface *iface;
306
307 if (iface_find((struct sockaddr *)&ifs->ip, False)) {
308 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
309 print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
310 return;
311 }
312
313 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
314 DEBUG(3,("not adding non-broadcast interface %s\n",
315 ifs->name ));
316 return;
317 }
318
319 iface = SMB_MALLOC_P(struct interface);
320 if (!iface) {
321 return;
322 }
323
324 ZERO_STRUCTPN(iface);
325
326 iface->name = SMB_STRDUP(ifs->name);
327 if (!iface->name) {
328 SAFE_FREE(iface);
329 return;
330 }
331 iface->flags = ifs->flags;
332 iface->ip = ifs->ip;
333 iface->netmask = ifs->netmask;
334 iface->bcast = ifs->bcast;
335
336 DLIST_ADD(local_interfaces, iface);
337
338 DEBUG(2,("added interface %s ip=%s ",
339 iface->name,
340 print_sockaddr(addr, sizeof(addr), &iface->ip) ));
341 DEBUG(2,("bcast=%s ",
342 print_sockaddr(addr, sizeof(addr),
343 &iface->bcast) ));
344 DEBUG(2,("netmask=%s\n",
345 print_sockaddr(addr, sizeof(addr),
346 &iface->netmask) ));
347}
348
349/****************************************************************************
350 Interpret a single element from a interfaces= config line.
351
352 This handles the following different forms:
353
354 1) wildcard interface name
355 2) DNS name
356 3) IP/masklen
357 4) ip/mask
358 5) bcast/mask
359****************************************************************************/
360
361static void interpret_interface(char *token)
362{
363 struct sockaddr_storage ss;
364 struct sockaddr_storage ss_mask;
365 struct sockaddr_storage ss_net;
366 struct sockaddr_storage ss_bcast;
367 struct iface_struct ifs;
368 char *p;
369 int i;
370 bool added=false;
371 bool goodaddr = false;
372
373 /* first check if it is an interface name */
374 for (i=0;i<total_probed;i++) {
375 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
376 add_interface(&probed_ifaces[i]);
377 added = true;
378 }
379 }
380 if (added) {
381 return;
382 }
383
384 /* maybe it is a DNS name */
385 p = strchr_m(token,'/');
386 if (p == NULL) {
387 if (!interpret_string_addr(&ss, token, 0)) {
388 DEBUG(2, ("interpret_interface: Can't find address "
389 "for %s\n", token));
390 return;
391 }
392
393 for (i=0;i<total_probed;i++) {
394 if (sockaddr_equal((struct sockaddr *)&ss, (struct sockaddr *)&probed_ifaces[i].ip)) {
395 add_interface(&probed_ifaces[i]);
396 return;
397 }
398 }
399 DEBUG(2,("interpret_interface: "
400 "can't determine interface for %s\n",
401 token));
402 return;
403 }
404
405 /* parse it into an IP address/netmasklength pair */
406 *p = 0;
407 goodaddr = interpret_string_addr(&ss, token, 0);
408 *p++ = '/';
409
410 if (!goodaddr) {
411 DEBUG(2,("interpret_interface: "
412 "can't determine interface for %s\n",
413 token));
414 return;
415 }
416
417 if (strlen(p) > 2) {
418 goodaddr = interpret_string_addr(&ss_mask, p, 0);
419 if (!goodaddr) {
420 DEBUG(2,("interpret_interface: "
421 "can't determine netmask from %s\n",
422 p));
423 return;
424 }
425 } else {
426 char *endp = NULL;
427 unsigned long val = strtoul(p, &endp, 0);
428 if (p == endp || (endp && *endp != '\0')) {
429 DEBUG(2,("interpret_interface: "
430 "can't determine netmask value from %s\n",
431 p));
432 return;
433 }
434 if (!make_netmask(&ss_mask, &ss, val)) {
435 DEBUG(2,("interpret_interface: "
436 "can't apply netmask value %lu from %s\n",
437 val,
438 p));
439 return;
440 }
441 }
442
443 make_bcast(&ss_bcast, &ss, &ss_mask);
444 make_net(&ss_net, &ss, &ss_mask);
445
446 /* Maybe the first component was a broadcast address. */
447 if (sockaddr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) ||
448 sockaddr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) {
449 for (i=0;i<total_probed;i++) {
450 if (same_net((struct sockaddr *)&ss,
451 (struct sockaddr *)&probed_ifaces[i].ip,
452 (struct sockaddr *)&ss_mask)) {
453 /* Temporarily replace netmask on
454 * the detected interface - user knows
455 * best.... */
456 struct sockaddr_storage saved_mask =
457 probed_ifaces[i].netmask;
458 probed_ifaces[i].netmask = ss_mask;
459 DEBUG(2,("interpret_interface: "
460 "using netmask value %s from "
461 "config file on interface %s\n",
462 p,
463 probed_ifaces[i].name));
464 add_interface(&probed_ifaces[i]);
465 probed_ifaces[i].netmask = saved_mask;
466 return;
467 }
468 }
469 DEBUG(2,("interpret_interface: Can't determine ip for "
470 "broadcast address %s\n",
471 token));
472 return;
473 }
474
475 /* Just fake up the interface definition. User knows best. */
476
477 DEBUG(2,("interpret_interface: Adding interface %s\n",
478 token));
479
480 ZERO_STRUCT(ifs);
481 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
482 ifs.flags = IFF_BROADCAST;
483 ifs.ip = ss;
484 ifs.netmask = ss_mask;
485 ifs.bcast = ss_bcast;
486 add_interface(&ifs);
487}
488
489/****************************************************************************
490 Load the list of network interfaces.
491****************************************************************************/
492
493void load_interfaces(void)
494{
495 struct iface_struct *ifaces = NULL;
496 const char **ptr = lp_interfaces();
497 int i;
498
499 gfree_interfaces();
500
501 /* Probe the kernel for interfaces */
502 total_probed = get_interfaces(talloc_tos(), &ifaces);
503
504 if (total_probed > 0) {
505 probed_ifaces = (struct iface_struct *)memdup(ifaces,
506 sizeof(ifaces[0])*total_probed);
507 if (!probed_ifaces) {
508 DEBUG(0,("ERROR: memdup failed\n"));
509 exit(1);
510 }
511 }
512 TALLOC_FREE(ifaces);
513
514 /* if we don't have a interfaces line then use all broadcast capable
515 interfaces except loopback */
516 if (!ptr || !*ptr || !**ptr) {
517 if (total_probed <= 0) {
518 DEBUG(0,("ERROR: Could not determine network "
519 "interfaces, you must use a interfaces config line\n"));
520 exit(1);
521 }
522 for (i=0;i<total_probed;i++) {
523 if (probed_ifaces[i].flags & IFF_BROADCAST) {
524 add_interface(&probed_ifaces[i]);
525 }
526 }
527 return;
528 }
529
530 if (ptr) {
531 while (*ptr) {
532 char *ptr_cpy = SMB_STRDUP(*ptr);
533 if (ptr_cpy) {
534 interpret_interface(ptr_cpy);
535 free(ptr_cpy);
536 }
537 ptr++;
538 }
539 }
540
541 if (!local_interfaces) {
542 DEBUG(0,("WARNING: no network interfaces found\n"));
543 }
544}
545
546
547void gfree_interfaces(void)
548{
549 while (local_interfaces) {
550 struct interface *iface = local_interfaces;
551 DLIST_REMOVE(local_interfaces, local_interfaces);
552 SAFE_FREE(iface->name);
553 SAFE_FREE(iface);
554 }
555
556 SAFE_FREE(probed_ifaces);
557}
558
559/****************************************************************************
560 Return True if the list of probed interfaces has changed.
561****************************************************************************/
562
563bool interfaces_changed(void)
564{
565 bool ret = false;
566 int n;
567 struct iface_struct *ifaces = NULL;
568
569 n = get_interfaces(talloc_tos(), &ifaces);
570
571 if ((n > 0 )&& (n != total_probed ||
572 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
573 ret = true;
574 }
575
576 TALLOC_FREE(ifaces);
577 return ret;
578}
Note: See TracBrowser for help on using the repository browser.