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

Last change on this file since 201 was 141, checked in by Paul Smedley, 17 years ago

Update trunk to 3.2.1

File size: 14.1 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 interfaces do we have (v4 only) ?
135**************************************************************************/
136
137int iface_count_v4(void)
138{
139 int ret = 0;
140 struct interface *i;
141
142 for (i=local_interfaces;i;i=i->next) {
143 if (i->ip.ss_family == AF_INET) {
144 ret++;
145 }
146 }
147 return ret;
148}
149
150/****************************************************************************
151 Return a pointer to the in_addr of the first IPv4 interface.
152**************************************************************************/
153
154const struct in_addr *first_ipv4_iface(void)
155{
156 struct interface *i;
157
158 for (i=local_interfaces;i ;i=i->next) {
159 if (i->ip.ss_family == AF_INET) {
160 break;
161 }
162 }
163
164 if (!i) {
165 return NULL;
166 }
167 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
168}
169
170/****************************************************************************
171 Return the Nth interface.
172**************************************************************************/
173
174struct interface *get_interface(int n)
175{
176 struct interface *i;
177
178 for (i=local_interfaces;i && n;i=i->next) {
179 n--;
180 }
181
182 if (i) {
183 return i;
184 }
185 return NULL;
186}
187
188/****************************************************************************
189 Return IP sockaddr_storage of the Nth interface.
190**************************************************************************/
191
192const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
193{
194 struct interface *i;
195
196 for (i=local_interfaces;i && n;i=i->next) {
197 n--;
198 }
199
200 if (i) {
201 return &i->ip;
202 }
203 return NULL;
204}
205
206/****************************************************************************
207 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
208**************************************************************************/
209
210const struct in_addr *iface_n_ip_v4(int n)
211{
212 struct interface *i;
213
214 for (i=local_interfaces;i && n;i=i->next) {
215 n--;
216 }
217
218 if (i && i->ip.ss_family == AF_INET) {
219 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
220 }
221 return NULL;
222}
223
224/****************************************************************************
225 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
226**************************************************************************/
227
228const struct in_addr *iface_n_bcast_v4(int n)
229{
230 struct interface *i;
231
232 for (i=local_interfaces;i && n;i=i->next) {
233 n--;
234 }
235
236 if (i && i->ip.ss_family == AF_INET) {
237 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
238 }
239 return NULL;
240}
241
242/****************************************************************************
243 Return bcast of the Nth interface.
244**************************************************************************/
245
246const struct sockaddr_storage *iface_n_bcast(int n)
247{
248 struct interface *i;
249
250 for (i=local_interfaces;i && n;i=i->next) {
251 n--;
252 }
253
254 if (i) {
255 return &i->bcast;
256 }
257 return NULL;
258}
259
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. */
264
265const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip)
266{
267 struct interface *i = iface_find(ip, true);
268 if (i) {
269 return &i->ip;
270 }
271
272 /* Search for the first interface with
273 * matching address family. */
274
275 for (i=local_interfaces;i;i=i->next) {
276 if (i->ip.ss_family == ip->ss_family) {
277 return &i->ip;
278 }
279 }
280 return NULL;
281}
282
283/*
284 return True if a IP is directly reachable on one of our interfaces
285*/
286
287bool iface_local(const struct sockaddr_storage *ip)
288{
289 return iface_find(ip, True) ? true : false;
290}
291
292/****************************************************************************
293 Add an interface to the linked list of interfaces.
294****************************************************************************/
295
296static void add_interface(const struct iface_struct *ifs)
297{
298 char addr[INET6_ADDRSTRLEN];
299 struct interface *iface;
300
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;
305 }
306
307 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
308 DEBUG(3,("not adding non-broadcast interface %s\n",
309 ifs->name ));
310 return;
311 }
312
313 iface = SMB_MALLOC_P(struct interface);
314 if (!iface) {
315 return;
316 }
317
318 ZERO_STRUCTPN(iface);
319
320 iface->name = SMB_STRDUP(ifs->name);
321 if (!iface->name) {
322 SAFE_FREE(iface);
323 return;
324 }
325 iface->flags = ifs->flags;
326 iface->ip = ifs->ip;
327 iface->netmask = ifs->netmask;
328 iface->bcast = ifs->bcast;
329
330 DLIST_ADD(local_interfaces, iface);
331
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) ));
341}
342
343/****************************************************************************
344 Interpret a single element from a interfaces= config line.
345
346 This handles the following different forms:
347
348 1) wildcard interface name
349 2) DNS name
350 3) IP/masklen
351 4) ip/mask
352 5) bcast/mask
353****************************************************************************/
354
355static void interpret_interface(char *token)
356{
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;
366
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;
372 }
373 }
374 if (added) {
375 return;
376 }
377
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;
385 }
386
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;
391 }
392 }
393 DEBUG(2,("interpret_interface: "
394 "can't determine interface for %s\n",
395 token));
396 return;
397 }
398
399 /* parse it into an IP address/netmasklength pair */
400 *p = 0;
401 goodaddr = interpret_string_addr(&ss, token, 0);
402 *p++ = '/';
403
404 if (!goodaddr) {
405 DEBUG(2,("interpret_interface: "
406 "can't determine interface for %s\n",
407 token));
408 return;
409 }
410
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;
418 }
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;
427 }
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;
434 }
435 }
436
437 make_bcast(&ss_bcast, &ss, &ss_mask);
438 make_net(&ss_net, &ss, &ss_mask);
439
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",
453 p,
454 probed_ifaces[i].name));
455 add_interface(&probed_ifaces[i]);
456 probed_ifaces[i].netmask = saved_mask;
457 return;
458 }
459 }
460 DEBUG(2,("interpret_interface: Can't determine ip for "
461 "broadcast address %s\n",
462 token));
463 return;
464 }
465
466 /* Just fake up the interface definition. User knows best. */
467
468 DEBUG(2,("interpret_interface: Adding interface %s\n",
469 token));
470
471 ZERO_STRUCT(ifs);
472 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
473 ifs.flags = IFF_BROADCAST;
474 ifs.ip = ss;
475 ifs.netmask = ss_mask;
476 ifs.bcast = ss_bcast;
477 add_interface(&ifs);
478}
479
480/****************************************************************************
481 Load the list of network interfaces.
482****************************************************************************/
483
484void load_interfaces(void)
485{
486 struct iface_struct ifaces[MAX_INTERFACES];
487 const char **ptr = lp_interfaces();
488 int i;
489
490 SAFE_FREE(probed_ifaces);
491
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);
498 }
499
500 /* Probe the kernel for interfaces */
501 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
502
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);
509 }
510 }
511
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);
519 }
520 for (i=0;i<total_probed;i++) {
521 if (probed_ifaces[i].flags & IFF_BROADCAST) {
522 add_interface(&probed_ifaces[i]);
523 }
524 }
525 return;
526 }
527
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);
534 }
535 ptr++;
536 }
537 }
538
539 if (!local_interfaces) {
540 DEBUG(0,("WARNING: no network interfaces found\n"));
541 }
542}
543
544
545void gfree_interfaces(void)
546{
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);
552 }
553
554 SAFE_FREE(probed_ifaces);
555}
556
557/****************************************************************************
558 Return True if the list of probed interfaces has changed.
559****************************************************************************/
560
561bool interfaces_changed(void)
562{
563 int n;
564 struct iface_struct ifaces[MAX_INTERFACES];
565
566 n = get_interfaces(ifaces, MAX_INTERFACES);
567
568 if ((n > 0 )&& (n != total_probed ||
569 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
570 return true;
571 }
572
573 return false;
574}
Note: See TracBrowser for help on using the repository browser.