81dae5f3a6b6a0f257e3011036d01015915320ed
[oweals/tinc.git] / src / subnet.c
1 /*
2     subnet.c -- handle subnet lookups and lists
3     Copyright (C) 2000-2014 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         int i, l;
209         uint16_t x[8];
210         int weight = 10;
211
212         if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d#%d",
213                         &x[0], &x[1], &x[2], &x[3], &l, &weight) >= 5) {
214                 if(l < 0 || l > 32) {
215                         return false;
216                 }
217
218                 subnet->type = SUBNET_IPV4;
219                 subnet->net.ipv4.prefixlength = l;
220                 subnet->weight = weight;
221
222                 for(i = 0; i < 4; i++) {
223                         if(x[i] > 255) {
224                                 return false;
225                         }
226
227                         subnet->net.ipv4.address.x[i] = x[i];
228                 }
229
230                 return true;
231         }
232
233         if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d#%d",
234                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
235                         &l, &weight) >= 9) {
236                 if(l < 0 || l > 128) {
237                         return false;
238                 }
239
240                 subnet->type = SUBNET_IPV6;
241                 subnet->net.ipv6.prefixlength = l;
242                 subnet->weight = weight;
243
244                 for(i = 0; i < 8; i++) {
245                         subnet->net.ipv6.address.x[i] = htons(x[i]);
246                 }
247
248                 return true;
249         }
250
251         if(sscanf(subnetstr, "%hu.%hu.%hu.%hu#%d", &x[0], &x[1], &x[2], &x[3], &weight) >= 4) {
252                 subnet->type = SUBNET_IPV4;
253                 subnet->net.ipv4.prefixlength = 32;
254                 subnet->weight = weight;
255
256                 for(i = 0; i < 4; i++) {
257                         if(x[i] > 255) {
258                                 return false;
259                         }
260
261                         subnet->net.ipv4.address.x[i] = x[i];
262                 }
263
264                 return true;
265         }
266
267         if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx#%d",
268                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &weight) >= 8) {
269                 subnet->type = SUBNET_IPV6;
270                 subnet->net.ipv6.prefixlength = 128;
271                 subnet->weight = weight;
272
273                 for(i = 0; i < 8; i++) {
274                         subnet->net.ipv6.address.x[i] = htons(x[i]);
275                 }
276
277                 return true;
278         }
279
280         if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx#%d",
281                         &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &weight) >= 6) {
282                 subnet->type = SUBNET_MAC;
283                 subnet->weight = weight;
284
285                 for(i = 0; i < 6; i++) {
286                         subnet->net.mac.address.x[i] = x[i];
287                 }
288
289                 return true;
290         }
291
292         // IPv6 short form
293         if(strstr(subnetstr, "::")) {
294                 const char *p;
295                 char *q;
296                 int colons = 0;
297
298                 // Count number of colons
299                 for(p = subnetstr; *p; p++)
300                         if(*p == ':') {
301                                 colons++;
302                         }
303
304                 if(colons > 7) {
305                         return false;
306                 }
307
308                 // Scan numbers before the double colon
309                 p = subnetstr;
310
311                 for(i = 0; i < colons; i++) {
312                         if(*p == ':') {
313                                 break;
314                         }
315
316                         x[i] = strtoul(p, &q, 0x10);
317
318                         if(!q || p == q || *q != ':') {
319                                 return false;
320                         }
321
322                         p = ++q;
323                 }
324
325                 p++;
326                 colons -= i;
327
328                 if(!i) {
329                         p++;
330                         colons--;
331                 }
332
333                 if(!*p || *p == '/' || *p == '#') {
334                         colons--;
335                 }
336
337                 // Fill in the blanks
338                 for(; i < 8 - colons; i++) {
339                         x[i] = 0;
340                 }
341
342                 // Scan the remaining numbers
343                 for(; i < 8; i++) {
344                         x[i] = strtoul(p, &q, 0x10);
345
346                         if(!q || p == q) {
347                                 return false;
348                         }
349
350                         if(i == 7) {
351                                 p = q;
352                                 break;
353                         }
354
355                         if(*q != ':') {
356                                 return false;
357                         }
358
359                         p = ++q;
360                 }
361
362                 l = 128;
363
364                 if(*p == '/') {
365                         sscanf(p, "/%d#%d", &l, &weight);
366                 } else if(*p == '#') {
367                         sscanf(p, "#%d", &weight);
368                 }
369
370                 if(l < 0 || l > 128) {
371                         return false;
372                 }
373
374                 subnet->type = SUBNET_IPV6;
375                 subnet->net.ipv6.prefixlength = l;
376                 subnet->weight = weight;
377
378                 for(i = 0; i < 8; i++) {
379                         subnet->net.ipv6.address.x[i] = htons(x[i]);
380                 }
381
382                 return true;
383         }
384
385         return false;
386 }
387
388 bool net2str(char *netstr, int len, const subnet_t *subnet) {
389         if(!netstr || !subnet) {
390                 logger(LOG_ERR, "net2str() was called with netstr=%p, subnet=%p!", (void *)netstr, (void *)subnet);
391                 return false;
392         }
393
394         switch(subnet->type) {
395         case SUBNET_MAC:
396                 snprintf(netstr, len, "%x:%x:%x:%x:%x:%x#%d",
397                          subnet->net.mac.address.x[0],
398                          subnet->net.mac.address.x[1],
399                          subnet->net.mac.address.x[2],
400                          subnet->net.mac.address.x[3],
401                          subnet->net.mac.address.x[4],
402                          subnet->net.mac.address.x[5],
403                          subnet->weight);
404                 break;
405
406         case SUBNET_IPV4:
407                 snprintf(netstr, len, "%u.%u.%u.%u/%d#%d",
408                          subnet->net.ipv4.address.x[0],
409                          subnet->net.ipv4.address.x[1],
410                          subnet->net.ipv4.address.x[2],
411                          subnet->net.ipv4.address.x[3],
412                          subnet->net.ipv4.prefixlength,
413                          subnet->weight);
414                 break;
415
416         case SUBNET_IPV6:
417                 snprintf(netstr, len, "%x:%x:%x:%x:%x:%x:%x:%x/%d#%d",
418                          ntohs(subnet->net.ipv6.address.x[0]),
419                          ntohs(subnet->net.ipv6.address.x[1]),
420                          ntohs(subnet->net.ipv6.address.x[2]),
421                          ntohs(subnet->net.ipv6.address.x[3]),
422                          ntohs(subnet->net.ipv6.address.x[4]),
423                          ntohs(subnet->net.ipv6.address.x[5]),
424                          ntohs(subnet->net.ipv6.address.x[6]),
425                          ntohs(subnet->net.ipv6.address.x[7]),
426                          subnet->net.ipv6.prefixlength,
427                          subnet->weight);
428                 break;
429
430         default:
431                 logger(LOG_ERR,
432                        "net2str() was called with unknown subnet type %d, exiting!",
433                        subnet->type);
434                 exit(0);
435         }
436
437         return true;
438 }
439
440 /* Subnet lookup routines */
441
442 subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) {
443         return avl_search(owner->subnet_tree, subnet);
444 }
445
446 subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
447         subnet_t *p, *r = NULL;
448         avl_node_t *n;
449         int i;
450
451         // Check if this address is cached
452
453         for(i = 0; i < 2; i++) {
454                 if(!cache_mac_valid[i]) {
455                         continue;
456                 }
457
458                 if(owner && cache_mac_subnet[i] && cache_mac_subnet[i]->owner != owner) {
459                         continue;
460                 }
461
462                 if(!memcmp(address, &cache_mac_address[i], sizeof(*address))) {
463                         return cache_mac_subnet[i];
464                 }
465         }
466
467         // Search all subnets for a matching one
468
469         for(n = owner ? owner->subnet_tree->head : subnet_tree->head; n; n = n->next) {
470                 p = n->data;
471
472                 if(!p || p->type != SUBNET_MAC) {
473                         continue;
474                 }
475
476                 if(!memcmp(address, &p->net.mac.address, sizeof(*address))) {
477                         r = p;
478
479                         if(p->owner->status.reachable) {
480                                 break;
481                         }
482                 }
483         }
484
485         // Cache the result
486
487         cache_mac_slot = !cache_mac_slot;
488         memcpy(&cache_mac_address[cache_mac_slot], address, sizeof(*address));
489         cache_mac_subnet[cache_mac_slot] = r;
490         cache_mac_valid[cache_mac_slot] = true;
491
492         return r;
493 }
494
495 subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
496         subnet_t *p, *r = NULL;
497         avl_node_t *n;
498         int i;
499
500         // Check if this address is cached
501
502         for(i = 0; i < 2; i++) {
503                 if(!cache_ipv4_valid[i]) {
504                         continue;
505                 }
506
507                 if(!memcmp(address, &cache_ipv4_address[i], sizeof(*address))) {
508                         return cache_ipv4_subnet[i];
509                 }
510         }
511
512         // Search all subnets for a matching one
513
514         for(n = subnet_tree->head; n; n = n->next) {
515                 p = n->data;
516
517                 if(!p || p->type != SUBNET_IPV4) {
518                         continue;
519                 }
520
521                 if(!maskcmp(address, &p->net.ipv4.address, p->net.ipv4.prefixlength)) {
522                         r = p;
523
524                         if(p->owner->status.reachable) {
525                                 break;
526                         }
527                 }
528         }
529
530         // Cache the result
531
532         cache_ipv4_slot = !cache_ipv4_slot;
533         memcpy(&cache_ipv4_address[cache_ipv4_slot], address, sizeof(*address));
534         cache_ipv4_subnet[cache_ipv4_slot] = r;
535         cache_ipv4_valid[cache_ipv4_slot] = true;
536
537         return r;
538 }
539
540 subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
541         subnet_t *p, *r = NULL;
542         avl_node_t *n;
543         int i;
544
545         // Check if this address is cached
546
547         for(i = 0; i < 2; i++) {
548                 if(!cache_ipv6_valid[i]) {
549                         continue;
550                 }
551
552                 if(!memcmp(address, &cache_ipv6_address[i], sizeof(*address))) {
553                         return cache_ipv6_subnet[i];
554                 }
555         }
556
557         // Search all subnets for a matching one
558
559         for(n = subnet_tree->head; n; n = n->next) {
560                 p = n->data;
561
562                 if(!p || p->type != SUBNET_IPV6) {
563                         continue;
564                 }
565
566                 if(!maskcmp(address, &p->net.ipv6.address, p->net.ipv6.prefixlength)) {
567                         r = p;
568
569                         if(p->owner->status.reachable) {
570                                 break;
571                         }
572                 }
573         }
574
575         // Cache the result
576
577         cache_ipv6_slot = !cache_ipv6_slot;
578         memcpy(&cache_ipv6_address[cache_ipv6_slot], address, sizeof(*address));
579         cache_ipv6_subnet[cache_ipv6_slot] = r;
580         cache_ipv6_valid[cache_ipv6_slot] = true;
581
582         return r;
583 }
584
585 void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
586         avl_node_t *node;
587         int i;
588         char *envp[10] = {NULL};
589         char netstr[MAXNETSTR];
590         char *name, *address, *port;
591         char empty[] = "";
592
593         // Prepare environment variables to be passed to the script
594
595         xasprintf(&envp[0], "NETNAME=%s", netname ? netname : "");
596         xasprintf(&envp[1], "DEVICE=%s", device ? device : "");
597         xasprintf(&envp[2], "INTERFACE=%s", iface ? iface : "");
598         xasprintf(&envp[3], "NODE=%s", owner->name);
599         xasprintf(&envp[4], "NAME=%s", myself->name);
600
601         if(owner != myself) {
602                 sockaddr2str(&owner->address, &address, &port);
603                 // 5 and 6 are reserved for SUBNET and WEIGHT
604                 xasprintf(&envp[7], "REMOTEADDRESS=%s", address);
605                 xasprintf(&envp[8], "REMOTEPORT=%s", port);
606                 free(port);
607                 free(address);
608         }
609
610         name = up ? "subnet-up" : "subnet-down";
611
612         if(!subnet) {
613                 for(node = owner->subnet_tree->head; node; node = node->next) {
614                         subnet = node->data;
615
616                         if(!net2str(netstr, sizeof(netstr), subnet)) {
617                                 continue;
618                         }
619
620                         // Strip the weight from the subnet, and put it in its own environment variable
621                         char *weight = strchr(netstr, '#');
622
623                         if(weight) {
624                                 *weight++ = 0;
625                         } else {
626                                 weight = empty;
627                         }
628
629                         // Prepare the SUBNET and WEIGHT variables
630                         if(envp[5]) {
631                                 free(envp[5]);
632                         }
633
634                         if(envp[6]) {
635                                 free(envp[6]);
636                         }
637
638                         xasprintf(&envp[5], "SUBNET=%s", netstr);
639                         xasprintf(&envp[6], "WEIGHT=%s", weight);
640
641                         execute_script(name, envp);
642                 }
643         } else {
644                 if(net2str(netstr, sizeof(netstr), subnet)) {
645                         // Strip the weight from the subnet, and put it in its own environment variable
646                         char *weight = strchr(netstr, '#');
647
648                         if(weight) {
649                                 *weight++ = 0;
650                         } else {
651                                 weight = empty;
652                         }
653
654                         // Prepare the SUBNET and WEIGHT variables
655                         xasprintf(&envp[5], "SUBNET=%s", netstr);
656                         xasprintf(&envp[6], "WEIGHT=%s", weight);
657
658                         execute_script(name, envp);
659                 }
660         }
661
662         for(i = 0; envp[i] && i < 9; i++) {
663                 free(envp[i]);
664         }
665 }
666
667 void dump_subnets(void) {
668         char netstr[MAXNETSTR];
669         subnet_t *subnet;
670         avl_node_t *node;
671
672         logger(LOG_DEBUG, "Subnet list:");
673
674         for(node = subnet_tree->head; node; node = node->next) {
675                 subnet = node->data;
676
677                 if(!net2str(netstr, sizeof(netstr), subnet)) {
678                         continue;
679                 }
680
681                 logger(LOG_DEBUG, " %s owner %s", netstr, subnet->owner->name);
682         }
683
684         logger(LOG_DEBUG, "End of subnet list.");
685 }