source: vendor/current/source3/lib/interface.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 16.4 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#include "lib/socket/interfaces.h"
23#include "librpc/gen_ndr/ioctl.h"
24
25static struct iface_struct *probed_ifaces;
26static int total_probed;
27
28static struct interface *local_interfaces;
29
30/****************************************************************************
31 Check if an IP is one of mine.
32**************************************************************************/
33
34bool ismyaddr(const struct sockaddr *ip)
35{
36 struct interface *i;
37 for (i=local_interfaces;i;i=i->next) {
38 if (sockaddr_equal((struct sockaddr *)&i->ip,ip)) {
39 return true;
40 }
41 }
42 return false;
43}
44
45bool ismyip_v4(struct in_addr ip)
46{
47 struct sockaddr_storage ss;
48 in_addr_to_sockaddr_storage(&ss, ip);
49 return ismyaddr((struct sockaddr *)&ss);
50}
51
52/****************************************************************************
53 Try and find an interface that matches an ip. If we cannot, return NULL.
54**************************************************************************/
55
56static struct interface *iface_find(const struct sockaddr *ip,
57 bool check_mask)
58{
59 struct interface *i;
60
61 if (is_address_any(ip)) {
62 return local_interfaces;
63 }
64
65 for (i=local_interfaces;i;i=i->next) {
66 if (check_mask) {
67 if (same_net(ip, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
68 return i;
69 }
70 } else if (sockaddr_equal((struct sockaddr *)&i->ip, ip)) {
71 return i;
72 }
73 }
74
75 return NULL;
76}
77
78/****************************************************************************
79 Check if a packet is from a local (known) net.
80**************************************************************************/
81
82bool is_local_net(const struct sockaddr *from)
83{
84 struct interface *i;
85 for (i=local_interfaces;i;i=i->next) {
86 if (same_net(from, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
87 return true;
88 }
89 }
90 return false;
91}
92
93#if defined(HAVE_IPV6)
94void setup_linklocal_scope_id(struct sockaddr *pss)
95{
96 struct interface *i;
97 for (i=local_interfaces;i;i=i->next) {
98 if (sockaddr_equal((struct sockaddr *)&i->ip,pss)) {
99 struct sockaddr_in6 *psa6 =
100 (struct sockaddr_in6 *)pss;
101 psa6->sin6_scope_id = if_nametoindex(i->name);
102 return;
103 }
104 }
105}
106#endif
107
108/****************************************************************************
109 Check if a packet is from a local (known) net.
110**************************************************************************/
111
112bool is_local_net_v4(struct in_addr from)
113{
114 struct sockaddr_storage ss;
115
116 in_addr_to_sockaddr_storage(&ss, from);
117 return is_local_net((struct sockaddr *)&ss);
118}
119
120/****************************************************************************
121 How many interfaces do we have ?
122**************************************************************************/
123
124int iface_count(void)
125{
126 int ret = 0;
127 struct interface *i;
128
129 for (i=local_interfaces;i;i=i->next) {
130 ret++;
131 }
132 return ret;
133}
134
135/****************************************************************************
136 How many non-loopback IPv4 interfaces do we have ?
137**************************************************************************/
138
139int iface_count_v4_nl(void)
140{
141 int ret = 0;
142 struct interface *i;
143
144 for (i=local_interfaces;i;i=i->next) {
145 if (is_loopback_addr((struct sockaddr *)&i->ip)) {
146 continue;
147 }
148 if (i->ip.ss_family == AF_INET) {
149 ret++;
150 }
151 }
152 return ret;
153}
154
155/****************************************************************************
156 Return a pointer to the in_addr of the first IPv4 interface that's
157 not 0.0.0.0.
158**************************************************************************/
159
160const struct in_addr *first_ipv4_iface(void)
161{
162 struct interface *i;
163
164 for (i=local_interfaces;i ;i=i->next) {
165 if ((i->ip.ss_family == AF_INET) &&
166 (!is_zero_ip_v4(((struct sockaddr_in *)&i->ip)->sin_addr)))
167 {
168 break;
169 }
170 }
171
172 if (!i) {
173 return NULL;
174 }
175 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
176}
177
178/****************************************************************************
179 Return the Nth interface.
180**************************************************************************/
181
182struct interface *get_interface(int n)
183{
184 struct interface *i;
185
186 for (i=local_interfaces;i && n;i=i->next) {
187 n--;
188 }
189
190 if (i) {
191 return i;
192 }
193 return NULL;
194}
195
196/****************************************************************************
197 Return IP sockaddr_storage of the Nth interface.
198**************************************************************************/
199
200const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
201{
202 struct interface *i;
203
204 for (i=local_interfaces;i && n;i=i->next) {
205 n--;
206 }
207
208 if (i) {
209 return &i->ip;
210 }
211 return NULL;
212}
213
214/****************************************************************************
215 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
216**************************************************************************/
217
218const struct in_addr *iface_n_ip_v4(int n)
219{
220 struct interface *i;
221
222 for (i=local_interfaces;i && n;i=i->next) {
223 n--;
224 }
225
226 if (i && i->ip.ss_family == AF_INET) {
227 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
228 }
229 return NULL;
230}
231
232/****************************************************************************
233 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
234**************************************************************************/
235
236const struct in_addr *iface_n_bcast_v4(int n)
237{
238 struct interface *i;
239
240 for (i=local_interfaces;i && n;i=i->next) {
241 n--;
242 }
243
244 if (i && i->ip.ss_family == AF_INET) {
245 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
246 }
247 return NULL;
248}
249
250/****************************************************************************
251 Return bcast of the Nth interface.
252**************************************************************************/
253
254const struct sockaddr_storage *iface_n_bcast(int n)
255{
256 struct interface *i;
257
258 for (i=local_interfaces;i && n;i=i->next) {
259 n--;
260 }
261
262 if (i) {
263 return &i->bcast;
264 }
265 return NULL;
266}
267
268/* these 3 functions return the ip/bcast/nmask for the interface
269 most appropriate for the given ip address. If they can't find
270 an appropriate interface they return the requested field of the
271 first known interface. */
272
273const struct sockaddr_storage *iface_ip(const struct sockaddr *ip)
274{
275 struct interface *i = iface_find(ip, true);
276 if (i) {
277 return &i->ip;
278 }
279
280 /* Search for the first interface with
281 * matching address family. */
282
283 for (i=local_interfaces;i;i=i->next) {
284 if (i->ip.ss_family == ip->sa_family) {
285 return &i->ip;
286 }
287 }
288 return NULL;
289}
290
291/*
292 return True if a IP is directly reachable on one of our interfaces
293*/
294
295bool iface_local(const struct sockaddr *ip)
296{
297 return iface_find(ip, true) ? true : false;
298}
299
300/****************************************************************************
301 Add an interface to the linked list of interfaces.
302****************************************************************************/
303
304static void add_interface(const struct iface_struct *ifs)
305{
306 char addr[INET6_ADDRSTRLEN];
307 struct interface *iface;
308
309 if (iface_find((const struct sockaddr *)&ifs->ip, False)) {
310 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
311 print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
312 return;
313 }
314
315 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
316 DEBUG(3,("not adding non-broadcast interface %s\n",
317 ifs->name ));
318 return;
319 }
320
321 iface = SMB_MALLOC_P(struct interface);
322 if (!iface) {
323 return;
324 }
325
326 ZERO_STRUCTPN(iface);
327
328 iface->name = SMB_STRDUP(ifs->name);
329 if (!iface->name) {
330 SAFE_FREE(iface);
331 return;
332 }
333 iface->flags = ifs->flags;
334 iface->ip = ifs->ip;
335 iface->netmask = ifs->netmask;
336 iface->bcast = ifs->bcast;
337 iface->linkspeed = ifs->linkspeed;
338 iface->capability = ifs->capability;
339 iface->if_index = ifs->if_index;
340
341 DLIST_ADD(local_interfaces, iface);
342
343 DEBUG(2,("added interface %s ip=%s ",
344 iface->name,
345 print_sockaddr(addr, sizeof(addr), &iface->ip) ));
346 DEBUG(2,("bcast=%s ",
347 print_sockaddr(addr, sizeof(addr),
348 &iface->bcast) ));
349 DEBUG(2,("netmask=%s\n",
350 print_sockaddr(addr, sizeof(addr),
351 &iface->netmask) ));
352}
353
354
355static void parse_extra_info(char *key, uint64_t *speed, uint32_t *cap,
356 uint32_t *if_index)
357{
358 while (key != NULL && *key != '\0') {
359 char *next_key;
360 char *val;
361
362 next_key = strchr_m(key, ',');
363 if (next_key != NULL) {
364 *next_key++ = 0;
365 }
366
367 val = strchr_m(key, '=');
368 if (val != NULL) {
369 *val++ = 0;
370
371 if (strequal_m(key, "speed")) {
372 *speed = (uint64_t)strtoull(val, NULL, 0);
373 } else if (strequal_m(key, "capability")) {
374 if (strequal_m(val, "RSS")) {
375 *cap |= FSCTL_NET_IFACE_RSS_CAPABLE;
376 } else if (strequal(val, "RDMA")) {
377 *cap |= FSCTL_NET_IFACE_RDMA_CAPABLE;
378 } else {
379 DBG_WARNING("Capability unknown: "
380 "'%s'\n", val);
381 }
382 } else if (strequal_m(key, "if_index")) {
383 *if_index = (uint32_t)strtoul(val, NULL, 0);
384 } else {
385 DBG_DEBUG("Key unknown: '%s'\n", key);
386 }
387 }
388
389 key = next_key;
390 }
391}
392
393/****************************************************************************
394 Interpret a single element from a interfaces= config line.
395
396 This handles the following different forms:
397
398 1) wildcard interface name
399 2) DNS name
400 3) IP/masklen
401 4) ip/mask
402 5) bcast/mask
403
404 Additional information for an interface can be specified with
405 this extended syntax:
406
407 interface[;key1=value1[,key2=value2[...]]]
408
409 where
410 - keys known: 'speed', 'capability', 'if_index'
411 - speed is in bits per second
412 - capabilites known: 'RSS', 'RDMA'
413 - if_index should be used with care, because
414 these indexes should not conicide with indexes
415 the kernel sets...
416
417****************************************************************************/
418
419static void interpret_interface(char *token)
420{
421 struct sockaddr_storage ss;
422 struct sockaddr_storage ss_mask;
423 struct sockaddr_storage ss_net;
424 struct sockaddr_storage ss_bcast;
425 struct iface_struct ifs;
426 char *p;
427 int i;
428 bool added=false;
429 bool goodaddr = false;
430 uint64_t speed = 0;
431 uint32_t cap = FSCTL_NET_IFACE_NONE_CAPABLE;
432 uint32_t if_index = 0;
433 bool speed_set = false;
434 bool cap_set = false;
435 bool if_index_set = false;
436
437 /* first check if it is an interface name */
438 for (i=0;i<total_probed;i++) {
439 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
440 add_interface(&probed_ifaces[i]);
441 added = true;
442 }
443 }
444 if (added) {
445 return;
446 }
447
448 /*
449 * extract speed / capability information if present
450 */
451 p = strchr_m(token, ';');
452 if (p != NULL) {
453 *p++ = 0;
454 parse_extra_info(p, &speed, &cap, &if_index);
455 if (speed != 0) {
456 speed_set = true;
457 }
458 if (cap != FSCTL_NET_IFACE_NONE_CAPABLE) {
459 cap_set = true;
460 }
461 if (if_index != 0) {
462 if_index_set = true;
463 }
464 }
465
466 p = strchr_m(token,'/');
467 if (p == NULL) {
468 if (!interpret_string_addr(&ss, token, 0)) {
469 DEBUG(2, ("interpret_interface: Can't find address "
470 "for %s\n", token));
471 return;
472 }
473
474 for (i=0;i<total_probed;i++) {
475 if (sockaddr_equal((struct sockaddr *)&ss,
476 (struct sockaddr *)&probed_ifaces[i].ip))
477 {
478 if (speed_set) {
479 probed_ifaces[i].linkspeed = speed;
480 }
481 if (cap_set) {
482 probed_ifaces[i].capability = cap;
483 }
484 if (if_index_set) {
485 probed_ifaces[i].if_index = if_index;
486 }
487 add_interface(&probed_ifaces[i]);
488 return;
489 }
490 }
491 DEBUG(2,("interpret_interface: "
492 "can't determine interface for %s\n",
493 token));
494 return;
495 }
496
497 /* parse it into an IP address/netmasklength pair */
498 *p = 0;
499 goodaddr = interpret_string_addr(&ss, token, 0);
500 *p++ = '/';
501
502 if (!goodaddr) {
503 DEBUG(2,("interpret_interface: "
504 "can't determine interface for %s\n",
505 token));
506 return;
507 }
508
509 if (strlen(p) > 2) {
510 goodaddr = interpret_string_addr(&ss_mask, p, 0);
511 if (!goodaddr) {
512 DEBUG(2,("interpret_interface: "
513 "can't determine netmask from %s\n",
514 p));
515 return;
516 }
517 } else {
518 char *endp = NULL;
519 unsigned long val = strtoul(p, &endp, 0);
520 if (p == endp || (endp && *endp != '\0')) {
521 DEBUG(2,("interpret_interface: "
522 "can't determine netmask value from %s\n",
523 p));
524 return;
525 }
526 if (!make_netmask(&ss_mask, &ss, val)) {
527 DEBUG(2,("interpret_interface: "
528 "can't apply netmask value %lu from %s\n",
529 val,
530 p));
531 return;
532 }
533 }
534
535 make_bcast(&ss_bcast, &ss, &ss_mask);
536 make_net(&ss_net, &ss, &ss_mask);
537
538 /* Maybe the first component was a broadcast address. */
539 if (sockaddr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) ||
540 sockaddr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) {
541 for (i=0;i<total_probed;i++) {
542 if (same_net((struct sockaddr *)&ss,
543 (struct sockaddr *)&probed_ifaces[i].ip,
544 (struct sockaddr *)&ss_mask)) {
545 /* Temporarily replace netmask on
546 * the detected interface - user knows
547 * best.... */
548 struct sockaddr_storage saved_mask =
549 probed_ifaces[i].netmask;
550 probed_ifaces[i].netmask = ss_mask;
551 DEBUG(2,("interpret_interface: "
552 "using netmask value %s from "
553 "config file on interface %s\n",
554 p,
555 probed_ifaces[i].name));
556 if (speed_set) {
557 probed_ifaces[i].linkspeed = speed;
558 }
559 if (cap_set) {
560 probed_ifaces[i].capability = cap;
561 }
562 if (if_index_set) {
563 probed_ifaces[i].if_index = if_index;
564 }
565 add_interface(&probed_ifaces[i]);
566 probed_ifaces[i].netmask = saved_mask;
567 return;
568 }
569 }
570 DEBUG(2,("interpret_interface: Can't determine ip for "
571 "broadcast address %s\n",
572 token));
573 return;
574 }
575
576 /* Just fake up the interface definition. User knows best. */
577
578 DEBUG(2,("interpret_interface: Adding interface %s\n",
579 token));
580
581 ZERO_STRUCT(ifs);
582 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
583 ifs.flags = IFF_BROADCAST;
584 ifs.ip = ss;
585 ifs.netmask = ss_mask;
586 ifs.bcast = ss_bcast;
587 if (if_index_set) {
588 probed_ifaces[i].if_index = if_index;
589 }
590 if (speed_set) {
591 ifs.linkspeed = speed;
592 } else {
593 ifs.linkspeed = 1000 * 1000 * 1000;
594 }
595 ifs.capability = cap;
596 add_interface(&ifs);
597}
598
599/****************************************************************************
600 Load the list of network interfaces.
601****************************************************************************/
602
603void load_interfaces(void)
604{
605 struct iface_struct *ifaces = NULL;
606 const char **ptr = lp_interfaces();
607 int i;
608
609 gfree_interfaces();
610
611 /* Probe the kernel for interfaces */
612 total_probed = get_interfaces(talloc_tos(), &ifaces);
613
614 if (total_probed > 0) {
615 probed_ifaces = (struct iface_struct *)smb_memdup(ifaces,
616 sizeof(ifaces[0])*total_probed);
617 if (!probed_ifaces) {
618 DEBUG(0,("ERROR: smb_memdup failed\n"));
619 exit(1);
620 }
621 }
622 TALLOC_FREE(ifaces);
623
624 /* if we don't have a interfaces line then use all broadcast capable
625 interfaces except loopback */
626 if (!ptr || !*ptr || !**ptr) {
627 if (total_probed <= 0) {
628 DEBUG(0,("ERROR: Could not determine network "
629 "interfaces, you must use a interfaces config line\n"));
630 exit(1);
631 }
632 for (i=0;i<total_probed;i++) {
633 if (probed_ifaces[i].flags & IFF_BROADCAST) {
634 add_interface(&probed_ifaces[i]);
635 }
636 }
637 return;
638 }
639
640 if (ptr) {
641 while (*ptr) {
642 char *ptr_cpy = SMB_STRDUP(*ptr);
643 if (ptr_cpy) {
644 interpret_interface(ptr_cpy);
645 free(ptr_cpy);
646 }
647 ptr++;
648 }
649 }
650
651 if (!local_interfaces) {
652 DEBUG(0,("WARNING: no network interfaces found\n"));
653 }
654}
655
656
657void gfree_interfaces(void)
658{
659 while (local_interfaces) {
660 struct interface *iface = local_interfaces;
661 DLIST_REMOVE(local_interfaces, local_interfaces);
662 SAFE_FREE(iface->name);
663 SAFE_FREE(iface);
664 }
665
666 SAFE_FREE(probed_ifaces);
667}
668
669/****************************************************************************
670 Return True if the list of probed interfaces has changed.
671****************************************************************************/
672
673bool interfaces_changed(void)
674{
675 bool ret = false;
676 int n;
677 struct iface_struct *ifaces = NULL;
678
679 n = get_interfaces(talloc_tos(), &ifaces);
680
681 if ((n > 0 )&& (n != total_probed ||
682 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
683 ret = true;
684 }
685
686 TALLOC_FREE(ifaces);
687 return ret;
688}
Note: See TracBrowser for help on using the repository browser.