s3:lib: extend interpret_interface() to optionally read speed, caps, and index from...
[samba.git] / source3 / lib / interface.c
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
25 static struct iface_struct *probed_ifaces;
26 static int total_probed;
27
28 static struct interface *local_interfaces;
29
30 /****************************************************************************
31  Check if an IP is one of mine.
32 **************************************************************************/
33
34 bool 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
45 bool 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
56 static 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
82 bool 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)
94 void 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
112 bool 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
124 int 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
139 int 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
160 const 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
182 struct 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
200 const 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
218 const 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
236 const 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
254 const 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
273 const 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
295 bool 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
304 static 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
355 static 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
419 static 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
603 void 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
657 void 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
673 bool 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 }