source: branches/samba-3.2.x/source/lib/interface.c@ 204

Last change on this file since 204 was 204, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 branch to 3.2.4

File size: 14.2 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_storage *ip)
33{
34 struct interface *i;
35 for (i=local_interfaces;i;i=i->next) {
36 if (addr_equal(&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(&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_storage *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, &i->ip, &i->netmask)) {
66 return i;
67 }
68 } else if (addr_equal(&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_storage *from)
81{
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;
86 }
87 }
88 return false;
89}
90
91#if defined(HAVE_IPV6)
92void setup_linklocal_scope_id(struct sockaddr_storage *pss)
93{
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;
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(&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(&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.
155**************************************************************************/
156
157const struct in_addr *first_ipv4_iface(void)
158{
159 struct interface *i;
160
161 for (i=local_interfaces;i ;i=i->next) {
162 if (i->ip.ss_family == AF_INET) {
163 break;
164 }
165 }
166
167 if (!i) {
168 return NULL;
169 }
170 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
171}
172
173/****************************************************************************
174 Return the Nth interface.
175**************************************************************************/
176
177struct interface *get_interface(int n)
178{
179 struct interface *i;
180
181 for (i=local_interfaces;i && n;i=i->next) {
182 n--;
183 }
184
185 if (i) {
186 return i;
187 }
188 return NULL;
189}
190
191/****************************************************************************
192 Return IP sockaddr_storage of the Nth interface.
193**************************************************************************/
194
195const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
196{
197 struct interface *i;
198
199 for (i=local_interfaces;i && n;i=i->next) {
200 n--;
201 }
202
203 if (i) {
204 return &i->ip;
205 }
206 return NULL;
207}
208
209/****************************************************************************
210 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
211**************************************************************************/
212
213const struct in_addr *iface_n_ip_v4(int n)
214{
215 struct interface *i;
216
217 for (i=local_interfaces;i && n;i=i->next) {
218 n--;
219 }
220
221 if (i && i->ip.ss_family == AF_INET) {
222 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
223 }
224 return NULL;
225}
226
227/****************************************************************************
228 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
229**************************************************************************/
230
231const struct in_addr *iface_n_bcast_v4(int n)
232{
233 struct interface *i;
234
235 for (i=local_interfaces;i && n;i=i->next) {
236 n--;
237 }
238
239 if (i && i->ip.ss_family == AF_INET) {
240 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
241 }
242 return NULL;
243}
244
245/****************************************************************************
246 Return bcast of the Nth interface.
247**************************************************************************/
248
249const struct sockaddr_storage *iface_n_bcast(int n)
250{
251 struct interface *i;
252
253 for (i=local_interfaces;i && n;i=i->next) {
254 n--;
255 }
256
257 if (i) {
258 return &i->bcast;
259 }
260 return NULL;
261}
262
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. */
267
268const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip)
269{
270 struct interface *i = iface_find(ip, true);
271 if (i) {
272 return &i->ip;
273 }
274
275 /* Search for the first interface with
276 * matching address family. */
277
278 for (i=local_interfaces;i;i=i->next) {
279 if (i->ip.ss_family == ip->ss_family) {
280 return &i->ip;
281 }
282 }
283 return NULL;
284}
285
286/*
287 return True if a IP is directly reachable on one of our interfaces
288*/
289
290bool iface_local(const struct sockaddr_storage *ip)
291{
292 return iface_find(ip, True) ? true : false;
293}
294
295/****************************************************************************
296 Add an interface to the linked list of interfaces.
297****************************************************************************/
298
299static void add_interface(const struct iface_struct *ifs)
300{
301 char addr[INET6_ADDRSTRLEN];
302 struct interface *iface;
303
304 if (iface_find(&ifs->ip, False)) {
305 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
306 print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
307 return;
308 }
309
310 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
311 DEBUG(3,("not adding non-broadcast interface %s\n",
312 ifs->name ));
313 return;
314 }
315
316 iface = SMB_MALLOC_P(struct interface);
317 if (!iface) {
318 return;
319 }
320
321 ZERO_STRUCTPN(iface);
322
323 iface->name = SMB_STRDUP(ifs->name);
324 if (!iface->name) {
325 SAFE_FREE(iface);
326 return;
327 }
328 iface->flags = ifs->flags;
329 iface->ip = ifs->ip;
330 iface->netmask = ifs->netmask;
331 iface->bcast = ifs->bcast;
332
333 DLIST_ADD(local_interfaces, iface);
334
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) ));
344}
345
346/****************************************************************************
347 Interpret a single element from a interfaces= config line.
348
349 This handles the following different forms:
350
351 1) wildcard interface name
352 2) DNS name
353 3) IP/masklen
354 4) ip/mask
355 5) bcast/mask
356****************************************************************************/
357
358static void interpret_interface(char *token)
359{
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;
369
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;
375 }
376 }
377 if (added) {
378 return;
379 }
380
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;
388 }
389
390 for (i=0;i<total_probed;i++) {
391 if (addr_equal(&ss, &probed_ifaces[i].ip)) {
392 add_interface(&probed_ifaces[i]);
393 return;
394 }
395 }
396 DEBUG(2,("interpret_interface: "
397 "can't determine interface for %s\n",
398 token));
399 return;
400 }
401
402 /* parse it into an IP address/netmasklength pair */
403 *p = 0;
404 goodaddr = interpret_string_addr(&ss, token, 0);
405 *p++ = '/';
406
407 if (!goodaddr) {
408 DEBUG(2,("interpret_interface: "
409 "can't determine interface for %s\n",
410 token));
411 return;
412 }
413
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;
421 }
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;
430 }
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;
437 }
438 }
439
440 make_bcast(&ss_bcast, &ss, &ss_mask);
441 make_net(&ss_net, &ss, &ss_mask);
442
443 /* Maybe the first component was a broadcast address. */
444 if (addr_equal(&ss_bcast, &ss) || addr_equal(&ss_net, &ss)) {
445 for (i=0;i<total_probed;i++) {
446 if (same_net(&ss, &probed_ifaces[i].ip, &ss_mask)) {
447 /* Temporarily replace netmask on
448 * the detected interface - user knows
449 * best.... */
450 struct sockaddr_storage saved_mask =
451 probed_ifaces[i].netmask;
452 probed_ifaces[i].netmask = ss_mask;
453 DEBUG(2,("interpret_interface: "
454 "using netmask value %s from "
455 "config file on interface %s\n",
456 p,
457 probed_ifaces[i].name));
458 add_interface(&probed_ifaces[i]);
459 probed_ifaces[i].netmask = saved_mask;
460 return;
461 }
462 }
463 DEBUG(2,("interpret_interface: Can't determine ip for "
464 "broadcast address %s\n",
465 token));
466 return;
467 }
468
469 /* Just fake up the interface definition. User knows best. */
470
471 DEBUG(2,("interpret_interface: Adding interface %s\n",
472 token));
473
474 ZERO_STRUCT(ifs);
475 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
476 ifs.flags = IFF_BROADCAST;
477 ifs.ip = ss;
478 ifs.netmask = ss_mask;
479 ifs.bcast = ss_bcast;
480 add_interface(&ifs);
481}
482
483/****************************************************************************
484 Load the list of network interfaces.
485****************************************************************************/
486
487void load_interfaces(void)
488{
489 struct iface_struct ifaces[MAX_INTERFACES];
490 const char **ptr = lp_interfaces();
491 int i;
492
493 SAFE_FREE(probed_ifaces);
494
495 /* dump the current interfaces if any */
496 while (local_interfaces) {
497 struct interface *iface = local_interfaces;
498 DLIST_REMOVE(local_interfaces, local_interfaces);
499 SAFE_FREE(iface->name);
500 SAFE_FREE(iface);
501 }
502
503 /* Probe the kernel for interfaces */
504 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
505
506 if (total_probed > 0) {
507 probed_ifaces = (struct iface_struct *)memdup(ifaces,
508 sizeof(ifaces[0])*total_probed);
509 if (!probed_ifaces) {
510 DEBUG(0,("ERROR: memdup failed\n"));
511 exit(1);
512 }
513 }
514
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);
522 }
523 for (i=0;i<total_probed;i++) {
524 if (probed_ifaces[i].flags & IFF_BROADCAST) {
525 add_interface(&probed_ifaces[i]);
526 }
527 }
528 return;
529 }
530
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);
537 }
538 ptr++;
539 }
540 }
541
542 if (!local_interfaces) {
543 DEBUG(0,("WARNING: no network interfaces found\n"));
544 }
545}
546
547
548void gfree_interfaces(void)
549{
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);
555 }
556
557 SAFE_FREE(probed_ifaces);
558}
559
560/****************************************************************************
561 Return True if the list of probed interfaces has changed.
562****************************************************************************/
563
564bool interfaces_changed(void)
565{
566 int n;
567 struct iface_struct ifaces[MAX_INTERFACES];
568
569 n = get_interfaces(ifaces, MAX_INTERFACES);
570
571 if ((n > 0 )&& (n != total_probed ||
572 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
573 return true;
574 }
575
576 return false;
577}
Note: See TracBrowser for help on using the repository browser.