154fd8048b16285ff79c8d8b3665ff72a5f84db4
[tinc] / src / subnet.c
1 /*
2     subnet.c -- handle subnet lookups and lists
3     Copyright (C) 2000-2019 Guus Sliepen <guus@tinc-vpn.org>,
4                   2000-2005 Ivo Timmermans
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "system.h"
22
23 #include "avl_tree.h"
24 #include "device.h"
25 #include "logger.h"
26 #include "net.h"
27 #include "netutl.h"
28 #include "node.h"
29 #include "process.h"
30 #include "subnet.h"
31 #include "utils.h"
32 #include "xalloc.h"
33
34 /* lists type of subnet */
35
36 avl_tree_t *subnet_tree;
37
38 /* Subnet lookup cache */
39
40 static ipv4_t cache_ipv4_address[2];
41 static subnet_t *cache_ipv4_subnet[2];
42 static bool cache_ipv4_valid[2];
43 static int cache_ipv4_slot;
44
45 static ipv6_t cache_ipv6_address[2];
46 static subnet_t *cache_ipv6_subnet[2];
47 static bool cache_ipv6_valid[2];
48 static int cache_ipv6_slot;
49
50 static mac_t cache_mac_address[2];
51 static subnet_t *cache_mac_subnet[2];
52 static bool cache_mac_valid[2];
53 static int cache_mac_slot;
54
55 void subnet_cache_flush(void) {
56         cache_ipv4_valid[0] = cache_ipv4_valid[1] = false;
57         cache_ipv6_valid[0] = cache_ipv6_valid[1] = false;
58         cache_mac_valid[0] = cache_mac_valid[1] = false;
59 }
60
61 /* Subnet comparison */
62
63 static int subnet_compare_mac(const subnet_t *a, const subnet_t *b) {
64         int result;
65
66         result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
67
68         if(result) {
69                 return result;
70         }
71
72         result = a->weight - b->weight;
73
74         if(result || !a->owner || !b->owner) {
75                 return result;
76         }
77
78         return strcmp(a->owner->name, b->owner->name);
79 }
80
81 static int subnet_compare_ipv4(const subnet_t *a, const subnet_t *b) {
82         int result;
83
84         result = b->net.ipv4.prefixlength - a->net.ipv4.prefixlength;
85
86         if(result) {
87                 return result;
88         }
89
90         result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t));
91
92         if(result) {
93                 return result;
94         }
95
96         result = a->weight - b->weight;
97
98         if(result || !a->owner || !b->owner) {
99                 return result;
100         }
101
102         return strcmp(a->owner->name, b->owner->name);
103 }
104
105 static int subnet_compare_ipv6(const subnet_t *a, const subnet_t *b) {
106         int result;
107
108         result = b->net.ipv6.prefixlength - a->net.ipv6.prefixlength;
109
110         if(result) {
111                 return result;
112         }
113
114         result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t));
115
116         if(result) {
117                 return result;
118         }
119
120         result = a->weight - b->weight;
121
122         if(result || !a->owner || !b->owner) {
123                 return result;
124         }
125
126         return strcmp(a->owner->name, b->owner->name);
127 }
128
129 int subnet_compare(const subnet_t *a, const subnet_t *b) {
130         int result;
131
132         result = a->type - b->type;
133
134         if(result) {
135                 return result;
136         }
137
138         switch(a->type) {
139         case SUBNET_MAC:
140                 return subnet_compare_mac(a, b);
141
142         case SUBNET_IPV4:
143                 return subnet_compare_ipv4(a, b);
144
145         case SUBNET_IPV6:
146                 return subnet_compare_ipv6(a, b);
147
148         default:
149                 logger(LOG_ERR, "subnet_compare() was called with unknown subnet type %d, exitting!",
150                        a->type);
151                 exit(0);
152         }
153
154         return 0;
155 }
156
157 /* Initialising trees */
158
159 void init_subnets(void) {
160         subnet_tree = avl_alloc_tree((avl_compare_t) subnet_compare, (avl_action_t) free_subnet);
161
162         subnet_cache_flush();
163 }
164
165 void exit_subnets(void) {
166         avl_delete_tree(subnet_tree);
167 }
168
169 avl_tree_t *new_subnet_tree(void) {
170         return avl_alloc_tree((avl_compare_t) subnet_compare, NULL);
171 }
172
173 void free_subnet_tree(avl_tree_t *subnet_tree) {
174         avl_delete_tree(subnet_tree);
175 }
176
177 /* Allocating and freeing space for subnets */
178
179 subnet_t *new_subnet(void) {
180         return xmalloc_and_zero(sizeof(subnet_t));
181 }
182
183 void free_subnet(subnet_t *subnet) {
184         free(subnet);
185 }
186
187 /* Adding and removing subnets */
188
189 void subnet_add(node_t *n, subnet_t *subnet) {
190         subnet->owner = n;
191
192         avl_insert(subnet_tree, subnet);
193         avl_insert(n->subnet_tree, subnet);
194
195         subnet_cache_flush();
196 }
197
198 void subnet_del(node_t *n, subnet_t *subnet) {
199         avl_delete(n->subnet_tree, subnet);
200         avl_delete(subnet_tree, subnet);
201
202         subnet_cache_flush();
203 }
204
205 /* Ascii representation of subnets */
206
207 bool str2net(subnet_t *subnet, const char *subnetstr) {
208         char str[1024];
209         strncpy(str, subnetstr, sizeof(str));
210         str[sizeof(str) - 1] = 0;
211         int consumed;
212
213         int weight = 10;
214         char *weight_separator = strchr(str, '#');
215
216         if(weight_separator) {
217                 char *weight_str = weight_separator + 1;
218
219                 if(sscanf(weight_str, "%d%n", &weight, &consumed) < 1) {
220                         return false;
221                 }
222
223                 if(weight_str[consumed]) {
224                         return false;
225                 }
226
227                 *weight_separator = 0;
228         }
229
230         int prefixlength = -1;
231         char *prefixlength_separator = strchr(str, '/');
232
233         if(prefixlength_separator) {
234                 char *prefixlength_str = prefixlength_separator + 1;
235
236                 if(sscanf(prefixlength_str, "%d%n", &prefixlength, &consumed) < 1) {
237                         return false;
238                 }
239
240                 if(prefixlength_str[consumed]) {
241                         return false;
242                 }
243
244                 *prefixlength_separator = 0;
245
246                 if(prefixlength < 0) {
247                         return false;
248                 }
249         }
250
251         uint16_t x[8];
252
253         if(sscanf(str, "%hx:%hx:%hx:%hx:%hx:%hx%n", &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &consumed) >= 6 && !str[consumed]) {
254                 /*
255                    Normally we should check that each part has two digits to prevent ambiguities.
256                    However, in old tinc versions net2str() will aggressively return MAC addresses with one-digit parts,
257                    so we have to accept them otherwise we would be unable to parse ADD_SUBNET messages.
258                 */
259                 if(prefixlength >= 0) {
260                         return false;
261                 }
262
263                 subnet->type = SUBNET_MAC;
264                 subnet->weight = weight;
265
266                 for(int i = 0; i < 6; i++) {
267                         subnet->net.mac.address.x[i] = x[i];
268                 }
269
270                 return true;
271         }
272
273         if(sscanf(str, "%hu.%hu.%hu.%hu%n", &x[0], &x[1], &x[2], &x[3], &consumed) >= 4 && !str[consumed]) {
274                 if(prefixlength == -1) {
275                         prefixlength = 32;
276                 }
277
278                 if(prefixlength > 32) {
279                         return false;
280                 }
281
282                 subnet->type = SUBNET_IPV4;
283                 subnet->net.ipv4.prefixlength = prefixlength;
284                 subnet->weight = weight;
285
286                 for(int i = 0; i < 4; i++) {
287                         if(x[i] > 255) {
288                                 return false;
289                         }
290
291                         subnet->net.ipv4.address.x[i] = x[i];
292                 }
293
294                 return true;
295         }
296
297         /* IPv6 */
298
299         char *last_colon = strrchr(str, ':');
300
301         if(last_colon && sscanf(last_colon, ":%hu.%hu.%hu.%hu%n", &x[0], &x[1], &x[2], &x[3], &consumed) >= 4 && !last_colon[consumed]) {
302                 /* Dotted quad suffix notation, convert to standard IPv6 notation */
303                 for(int i = 0; i < 4; i++)
304                         if(x[i] > 255) {
305                                 return false;
306                         }
307
308                 snprintf(last_colon, sizeof(str) - (last_colon - str), ":%02x%02x:%02x%02x", x[0], x[1], x[2], x[3]);
309         }
310
311         char *double_colon = strstr(str, "::");
312
313         if(double_colon) {
314                 /* Figure out how many zero groups we need to expand */
315                 int zero_group_count = 8;
316
317                 for(const char *cur = str; *cur; cur++)
318                         if(*cur != ':') {
319                                 zero_group_count--;
320
321                                 while(cur[1] && cur[1] != ':') {
322                                         cur++;
323                                 }
324                         }
325
326                 if(zero_group_count < 1) {
327                         return false;
328                 }
329
330                 /* Split the double colon in the middle to make room for zero groups */
331                 double_colon++;
332                 memmove(double_colon + (zero_group_count * 2 - 1), double_colon, strlen(double_colon) + 1);
333
334                 /* Write zero groups in the resulting gap, overwriting the second colon */
335                 for(int i = 0; i < zero_group_count; i++) {
336                         memcpy(&double_colon[i * 2], "0:", 2);
337                 }
338
339                 /* Remove any leading or trailing colons */
340                 if(str[0] == ':') {
341                         memmove(&str[0], &str[1], strlen(&str[1]) + 1);
342                 }
343
344                 if(str[strlen(str) - 1] == ':') {
345                         str[strlen(str) - 1] = 0;
346                 }
347         }
348
349         if(sscanf(str, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx%n",
350                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &consumed) >= 8 && !str[consumed]) {
351                 if(prefixlength == -1) {
352                         prefixlength = 128;
353                 }
354
355                 if(prefixlength > 128) {
356                         return false;
357                 }
358
359                 subnet->type = SUBNET_IPV6;
360                 subnet->net.ipv6.prefixlength = prefixlength;
361                 subnet->weight = weight;
362
363                 for(int i = 0; i < 8; i++) {
364                         subnet->net.ipv6.address.x[i] = htons(x[i]);
365                 }
366
367                 return true;
368         }
369
370         return false;
371 }
372
373 bool net2str(char *netstr, int len, const subnet_t *subnet) {
374         if(!netstr || !subnet) {
375                 logger(LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!", (void *)netstr, (void *)subnet);
376                 return false;
377         }
378
379         switch(subnet->type) {
380         case SUBNET_MAC:
381                 snprintf(netstr, len, "%x:%x:%x:%x:%x:%x#%d",
382                          subnet->net.mac.address.x[0],
383                          subnet->net.mac.address.x[1],
384                          subnet->net.mac.address.x[2],
385                          subnet->net.mac.address.x[3],
386                          subnet->net.mac.address.x[4],
387                          subnet->net.mac.address.x[5],
388                          subnet->weight);
389                 break;
390
391         case SUBNET_IPV4:
392                 snprintf(netstr, len, "%u.%u.%u.%u/%d#%d",
393                          subnet->net.ipv4.address.x[0],
394                          subnet->net.ipv4.address.x[1],
395                          subnet->net.ipv4.address.x[2],
396                          subnet->net.ipv4.address.x[3],
397                          subnet->net.ipv4.prefixlength,
398                          subnet->weight);
399                 break;
400
401         case SUBNET_IPV6:
402                 snprintf(netstr, len, "%x:%x:%x:%x:%x:%x:%x:%x/%d#%d",
403                          ntohs(subnet->net.ipv6.address.x[0]),
404                          ntohs(subnet->net.ipv6.address.x[1]),
405                          ntohs(subnet->net.ipv6.address.x[2]),
406                          ntohs(subnet->net.ipv6.address.x[3]),
407                          ntohs(subnet->net.ipv6.address.x[4]),
408                          ntohs(subnet->net.ipv6.address.x[5]),
409                          ntohs(subnet->net.ipv6.address.x[6]),
410                          ntohs(subnet->net.ipv6.address.x[7]),
411                          subnet->net.ipv6.prefixlength,
412                          subnet->weight);
413                 break;
414
415         default:
416                 logger(LOG_ERR,
417                        "net2str() was called with unknown subnet type %d, exiting!",
418                        subnet->type);
419                 exit(0);
420         }
421
422         return true;
423 }
424
425 /* Subnet lookup routines */
426
427 subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) {
428         return avl_search(owner->subnet_tree, subnet);
429 }
430
431 subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
432         subnet_t *p, *r = NULL;
433         avl_node_t *n;
434         int i;
435
436         // Check if this address is cached
437
438         for(i = 0; i < 2; i++) {
439                 if(!cache_mac_valid[i]) {
440                         continue;
441                 }
442
443                 if(owner && cache_mac_subnet[i] && cache_mac_subnet[i]->owner != owner) {
444                         continue;
445                 }
446
447                 if(!memcmp(address, &cache_mac_address[i], sizeof(*address))) {
448                         return cache_mac_subnet[i];
449                 }
450         }
451
452         // Search all subnets for a matching one
453
454         for(n = owner ? owner->subnet_tree->head : subnet_tree->head; n; n = n->next) {
455                 p = n->data;
456
457                 if(!p || p->type != SUBNET_MAC) {
458                         continue;
459                 }
460
461                 if(!memcmp(address, &p->net.mac.address, sizeof(*address))) {
462                         r = p;
463
464                         if(p->owner->status.reachable) {
465                                 break;
466                         }
467                 }
468         }
469
470         // Cache the result
471
472         cache_mac_slot = !cache_mac_slot;
473         memcpy(&cache_mac_address[cache_mac_slot], address, sizeof(*address));
474         cache_mac_subnet[cache_mac_slot] = r;
475         cache_mac_valid[cache_mac_slot] = true;
476
477         return r;
478 }
479
480 subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
481         subnet_t *p, *r = NULL;
482         avl_node_t *n;
483         int i;
484
485         // Check if this address is cached
486
487         for(i = 0; i < 2; i++) {
488                 if(!cache_ipv4_valid[i]) {
489                         continue;
490                 }
491
492                 if(!memcmp(address, &cache_ipv4_address[i], sizeof(*address))) {
493                         return cache_ipv4_subnet[i];
494                 }
495         }
496
497         // Search all subnets for a matching one
498
499         for(n = subnet_tree->head; n; n = n->next) {
500                 p = n->data;
501
502                 if(!p || p->type != SUBNET_IPV4) {
503                         continue;
504                 }
505
506                 if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) {
507                         r = p;
508
509                         if(p->owner->status.reachable) {
510                                 break;
511                         }
512                 }
513         }
514
515         // Cache the result
516
517         cache_ipv4_slot = !cache_ipv4_slot;
518         memcpy(&cache_ipv4_address[cache_ipv4_slot], address, sizeof(*address));
519         cache_ipv4_subnet[cache_ipv4_slot] = r;
520         cache_ipv4_valid[cache_ipv4_slot] = true;
521
522         return r;
523 }
524
525 subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
526         subnet_t *p, *r = NULL;
527         avl_node_t *n;
528         int i;
529
530         // Check if this address is cached
531
532         for(i = 0; i < 2; i++) {
533                 if(!cache_ipv6_valid[i]) {
534                         continue;
535                 }
536
537                 if(!memcmp(address, &cache_ipv6_address[i], sizeof(*address))) {
538                         return cache_ipv6_subnet[i];
539                 }
540         }
541
542         // Search all subnets for a matching one
543
544         for(n = subnet_tree->head; n; n = n->next) {
545                 p = n->data;
546
547                 if(!p || p->type != SUBNET_IPV6) {
548                         continue;
549                 }
550
551                 if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) {
552                         r = p;
553
554                         if(p->owner->status.reachable) {
555                                 break;
556                         }
557                 }
558         }
559
560         // Cache the result
561
562         cache_ipv6_slot = !cache_ipv6_slot;
563         memcpy(&cache_ipv6_address[cache_ipv6_slot], address, sizeof(*address));
564         cache_ipv6_subnet[cache_ipv6_slot] = r;
565         cache_ipv6_valid[cache_ipv6_slot] = true;
566
567         return r;
568 }
569
570 void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
571         avl_node_t *node;
572         int i;
573         char *envp[10] = {NULL};
574         char netstr[MAXNETSTR];
575         char *name, *address, *port;
576         char empty[] = "";
577
578         // Prepare environment variables to be passed to the script
579
580         xasprintf(&envp[0], "NETNAME=%s", netname ? netname : "");
581         xasprintf(&envp[1], "DEVICE=%s", device ? device : "");
582         xasprintf(&envp[2], "INTERFACE=%s", iface ? iface : "");
583         xasprintf(&envp[3], "NODE=%s", owner->name);
584         xasprintf(&envp[4], "NAME=%s", myself->name);
585
586         if(owner != myself) {
587                 sockaddr2str(&owner->address, &address, &port);
588                 // 5 and 6 are reserved for SUBNET and WEIGHT
589                 xasprintf(&envp[7], "REMOTEADDRESS=%s", address);
590                 xasprintf(&envp[8], "REMOTEPORT=%s", port);
591                 free(port);
592                 free(address);
593         }
594
595         name = up ? "subnet-up" : "subnet-down";
596
597         if(!subnet) {
598                 for(node = owner->subnet_tree->head; node; node = node->next) {
599                         subnet = node->data;
600
601                         if(!net2str(netstr, sizeof(netstr), subnet)) {
602                                 continue;
603                         }
604
605                         // Strip the weight from the subnet, and put it in its own environment variable
606                         char *weight = strchr(netstr, '#');
607
608                         if(weight) {
609                                 *weight++ = 0;
610                         } else {
611                                 weight = empty;
612                         }
613
614                         // Prepare the SUBNET and WEIGHT variables
615                         free(envp[5]);
616                         free(envp[6]);
617
618                         xasprintf(&envp[5], "SUBNET=%s", netstr);
619                         xasprintf(&envp[6], "WEIGHT=%s", weight);
620
621                         execute_script(name, envp);
622                 }
623         } else {
624                 if(net2str(netstr, sizeof(netstr), subnet)) {
625                         // Strip the weight from the subnet, and put it in its own environment variable
626                         char *weight = strchr(netstr, '#');
627
628                         if(weight) {
629                                 *weight++ = 0;
630                         } else {
631                                 weight = empty;
632                         }
633
634                         // Prepare the SUBNET and WEIGHT variables
635                         xasprintf(&envp[5], "SUBNET=%s", netstr);
636                         xasprintf(&envp[6], "WEIGHT=%s", weight);
637
638                         execute_script(name, envp);
639                 }
640         }
641
642         for(i = 0; i < 9; i++) {
643                 free(envp[i]);
644         }
645 }
646
647 void dump_subnets(void) {
648         char netstr[MAXNETSTR];
649         subnet_t *subnet;
650         avl_node_t *node;
651
652         logger(LOG_DEBUG, "Subnet list:");
653
654         for(node = subnet_tree->head; node; node = node->next) {
655                 subnet = node->data;
656
657                 if(!net2str(netstr, sizeof(netstr), subnet)) {
658                         continue;
659                 }
660
661                 logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name);
662         }
663
664         logger(LOG_DEBUG, "End of subnet list.");
665 }