]> git.meshlink.io Git - meshlink/blob - src/net_setup.c
Add channel disconnection fix when node blacklisted
[meshlink] / src / net_setup.c
1 /*
2     net_setup.c -- Setup.
3     Copyright (C) 2014-2017 Guus Sliepen <guus@meshlink.io>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include "conf.h"
23 #include "connection.h"
24 #include "ecdsa.h"
25 #include "graph.h"
26 #include "logger.h"
27 #include "meshlink_internal.h"
28 #include "net.h"
29 #include "netutl.h"
30 #include "protocol.h"
31 #include "route.h"
32 #include "utils.h"
33 #include "xalloc.h"
34 #include "submesh.h"
35
36 bool node_read_ecdsa_public_key(meshlink_handle_t *mesh, node_t *n) {
37         if(ecdsa_active(n->ecdsa)) {
38                 return true;
39         }
40
41         splay_tree_t *config_tree;
42         char *p;
43
44         init_configuration(&config_tree);
45
46         if(!read_host_config(mesh, config_tree, n->name)) {
47                 goto exit;
48         }
49
50         /* First, check for simple ECDSAPublicKey statement */
51
52         if(get_config_string(lookup_config(config_tree, "ECDSAPublicKey"), &p)) {
53                 n->ecdsa = ecdsa_set_base64_public_key(p);
54                 free(p);
55         }
56
57 exit:
58         exit_configuration(&config_tree);
59         return n->ecdsa;
60 }
61
62 bool read_ecdsa_public_key(meshlink_handle_t *mesh, connection_t *c) {
63         if(ecdsa_active(c->ecdsa)) {
64                 return true;
65         }
66
67         char *p;
68
69         if(!c->config_tree) {
70                 init_configuration(&c->config_tree);
71
72                 if(!read_host_config(mesh, c->config_tree, c->name)) {
73                         return false;
74                 }
75         }
76
77         /* First, check for simple ECDSAPublicKey statement */
78
79         if(get_config_string(lookup_config(c->config_tree, "ECDSAPublicKey"), &p)) {
80                 c->ecdsa = ecdsa_set_base64_public_key(p);
81                 free(p);
82                 return c->ecdsa;
83         }
84
85         return false;
86 }
87
88 bool read_ecdsa_private_key(meshlink_handle_t *mesh) {
89         FILE *fp;
90         char filename[PATH_MAX];
91
92         snprintf(filename, PATH_MAX, "%s" SLASH "ecdsa_key.priv", mesh->confbase);
93         fp = fopen(filename, "rb");
94
95         if(!fp) {
96                 logger(mesh, MESHLINK_ERROR, "Error reading ECDSA private key file: %s", strerror(errno));
97                 return false;
98         }
99
100         mesh->self->connection->ecdsa = ecdsa_read_pem_private_key(fp);
101         fclose(fp);
102
103         if(!mesh->self->connection->ecdsa) {
104                 logger(mesh, MESHLINK_ERROR, "Reading ECDSA private key file failed: %s", strerror(errno));
105         }
106
107         return mesh->self->connection->ecdsa;
108 }
109
110 static bool read_invitation_key(meshlink_handle_t *mesh) {
111         FILE *fp;
112         char filename[PATH_MAX];
113
114         if(mesh->invitation_key) {
115                 ecdsa_free(mesh->invitation_key);
116                 mesh->invitation_key = NULL;
117         }
118
119         snprintf(filename, PATH_MAX, "%s" SLASH "invitations" SLASH "ecdsa_key.priv", mesh->confbase);
120
121         fp = fopen(filename, "rb");
122
123         if(fp) {
124                 mesh->invitation_key = ecdsa_read_pem_private_key(fp);
125                 fclose(fp);
126
127                 if(!mesh->invitation_key) {
128                         logger(mesh, MESHLINK_ERROR, "Reading ECDSA private key file `%s' failed: %s", filename, strerror(errno));
129                 }
130         }
131
132         return mesh->invitation_key;
133 }
134
135 bool node_read_devclass(meshlink_handle_t *mesh, node_t *n) {
136
137         splay_tree_t *config_tree;
138         char *p;
139
140         init_configuration(&config_tree);
141
142         if(!read_host_config(mesh, config_tree, n->name)) {
143                 goto exit;
144         }
145
146         if(get_config_string(lookup_config(config_tree, "DeviceClass"), &p)) {
147                 n->devclass = atoi(p);
148                 free(p);
149         }
150
151         if((int)n->devclass < 0 || n->devclass > _DEV_CLASS_MAX) {
152                 n->devclass = _DEV_CLASS_MAX;
153         }
154
155 exit:
156         exit_configuration(&config_tree);
157         return n->devclass != 0;
158 }
159
160 bool node_read_submesh(meshlink_handle_t *mesh, node_t *n) {
161
162         splay_tree_t *config_tree;
163         char *p;
164
165         init_configuration(&config_tree);
166
167         if(!read_host_config(mesh, config_tree, n->name)) {
168                 goto exit;
169         }
170
171         if(get_config_string(lookup_config(config_tree, "SubMesh"), &p)) {
172                 n->submesh = NULL;
173
174                 for list_each(submesh_t, s, mesh->submeshes) {
175                         if(!strcmp(p, s->name)) {
176                                 n->submesh = s;
177                                 break;
178                         }
179                 }
180
181                 if(!n->submesh) {
182                         n->submesh = (submesh_t *)meshlink_submesh_open(mesh, p);
183                 }
184
185                 free(p);
186         }
187
188 exit:
189         exit_configuration(&config_tree);
190         return n->submesh != NULL;
191 }
192
193 bool node_read_blacklist_status(meshlink_handle_t *mesh, node_t *n) {
194
195         splay_tree_t *config_tree;
196         bool blacklist_status;
197
198         init_configuration(&config_tree);
199
200         if(!read_host_config(mesh, config_tree, n->name)) {
201                 goto exit;
202         }
203
204         if(get_config_bool(lookup_config(config_tree, "blacklisted"), &blacklist_status)) {
205                 n->status.blacklisted = blacklist_status;
206         }
207
208 exit:
209         exit_configuration(&config_tree);
210         return n->status.blacklisted;
211 }
212
213 bool node_write_devclass(meshlink_handle_t *mesh, node_t *n) {
214
215         if((int)n->devclass < 0 || n->devclass > _DEV_CLASS_MAX) {
216                 return false;
217         }
218
219         bool result = false;
220
221         splay_tree_t *config_tree;
222         init_configuration(&config_tree);
223
224         // ignore read errors; in case the file does not exist we will create it
225         read_host_config(mesh, config_tree, n->name);
226
227         config_t *cnf = lookup_config(config_tree, "DeviceClass");
228
229         if(!cnf) {
230                 cnf = new_config();
231                 cnf->variable = xstrdup("DeviceClass");
232                 config_add(config_tree, cnf);
233         }
234
235         set_config_int(cnf, n->devclass);
236
237         if(!write_host_config(mesh, config_tree, n->name)) {
238                 goto fail;
239         }
240
241         result = true;
242
243 fail:
244         exit_configuration(&config_tree);
245         return result;
246 }
247
248 bool node_write_submesh(meshlink_handle_t *mesh, node_t *n) {
249
250         if(!n->submesh) {
251                 return false;
252         }
253
254         bool result = false;
255
256         splay_tree_t *config_tree;
257         init_configuration(&config_tree);
258
259         // ignore read errors; in case the file does not exist we will create it
260         read_host_config(mesh, config_tree, n->name);
261
262         config_t *cnf = lookup_config(config_tree, "SubMesh");
263
264         if(!cnf) {
265                 cnf = new_config();
266                 cnf->variable = xstrdup("SubMesh");
267                 config_add(config_tree, cnf);
268         }
269
270         set_config_string(cnf, n->submesh->name);
271
272         if(!write_host_config(mesh, config_tree, n->name)) {
273                 goto fail;
274         }
275
276         result = true;
277
278 fail:
279         exit_configuration(&config_tree);
280         return result;
281 }
282
283 void load_all_nodes(meshlink_handle_t *mesh) {
284         DIR *dir;
285         struct dirent *ent;
286         char dname[PATH_MAX];
287
288         snprintf(dname, PATH_MAX, "%s" SLASH "hosts", mesh->confbase);
289         dir = opendir(dname);
290
291         if(!dir) {
292                 logger(mesh, MESHLINK_ERROR, "Could not open %s: %s", dname, strerror(errno));
293                 return;
294         }
295
296         while((ent = readdir(dir))) {
297                 if(!check_id(ent->d_name)) {
298                         continue;
299                 }
300
301                 node_t *n = lookup_node(mesh, ent->d_name);
302
303                 if(n) {
304                         if(n == mesh->self && !n->submesh) {
305                                 node_read_submesh(mesh, n);
306                         }
307
308                         continue;
309                 }
310
311                 n = new_node();
312                 n->name = xstrdup(ent->d_name);
313                 node_read_devclass(mesh, n);
314                 node_read_submesh(mesh, n);
315                 node_read_blacklist_status(mesh, n);
316                 node_add(mesh, n);
317         }
318
319         closedir(dir);
320 }
321
322
323 char *get_name(meshlink_handle_t *mesh) {
324         char *name = NULL;
325
326         get_config_string(lookup_config(mesh->config, "Name"), &name);
327
328         if(!name) {
329                 return NULL;
330         }
331
332         if(!check_id(name)) {
333                 logger(mesh, MESHLINK_ERROR, "Invalid name for mesh->self!");
334                 free(name);
335                 return NULL;
336         }
337
338         return name;
339 }
340
341 bool setup_myself_reloadable(meshlink_handle_t *mesh) {
342         mesh->localdiscovery = true;
343         keylifetime = 3600; // TODO: check if this can be removed as well
344         mesh->maxtimeout = 900;
345         mesh->self->options |= OPTION_PMTU_DISCOVERY;
346
347         read_invitation_key(mesh);
348
349         return true;
350 }
351
352 /*
353   Add listening sockets.
354 */
355 static bool add_listen_address(meshlink_handle_t *mesh, char *address, bool bindto) {
356         char *port = mesh->myport;
357
358         if(address) {
359                 char *space = strchr(address, ' ');
360
361                 if(space) {
362                         *space++ = 0;
363                         port = space;
364                 }
365
366                 if(!strcmp(address, "*")) {
367                         *address = 0;
368                 }
369         }
370
371         struct addrinfo *ai;
372
373         struct addrinfo hint = {
374                 .ai_family = addressfamily,
375                 .ai_socktype = SOCK_STREAM,
376                 .ai_protocol = IPPROTO_TCP,
377                 .ai_flags = AI_PASSIVE,
378         };
379
380         int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
381
382         free(address);
383
384         if(err || !ai) {
385                 logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "getaddrinfo", err == EAI_SYSTEM ? strerror(err) : gai_strerror(err));
386                 return false;
387         }
388
389         bool success = false;
390
391         for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
392                 // Ignore duplicate addresses
393                 bool found = false;
394
395                 for(int i = 0; i < mesh->listen_sockets; i++)
396                         if(!memcmp(&mesh->listen_socket[i].sa, aip->ai_addr, aip->ai_addrlen)) {
397                                 found = true;
398                                 break;
399                         }
400
401                 if(found) {
402                         continue;
403                 }
404
405                 if(mesh->listen_sockets >= MAXSOCKETS) {
406                         logger(mesh, MESHLINK_ERROR, "Too many listening sockets");
407                         return false;
408                 }
409
410                 int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr);
411
412                 if(tcp_fd < 0) {
413                         continue;
414                 }
415
416                 int udp_fd = setup_vpn_in_socket(mesh, (sockaddr_t *) aip->ai_addr);
417
418                 if(udp_fd < 0) {
419                         close(tcp_fd);
420                         continue;
421                 }
422
423                 io_add(&mesh->loop, &mesh->listen_socket[mesh->listen_sockets].tcp, handle_new_meta_connection, &mesh->listen_socket[mesh->listen_sockets], tcp_fd, IO_READ);
424                 io_add(&mesh->loop, &mesh->listen_socket[mesh->listen_sockets].udp, handle_incoming_vpn_data, &mesh->listen_socket[mesh->listen_sockets], udp_fd, IO_READ);
425
426                 if(mesh->log_level >= MESHLINK_INFO) {
427                         char *hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
428                         logger(mesh, MESHLINK_INFO, "Listening on %s", hostname);
429                         free(hostname);
430                 }
431
432                 mesh->listen_socket[mesh->listen_sockets].bindto = bindto;
433                 memcpy(&mesh->listen_socket[mesh->listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
434                 mesh->listen_sockets++;
435                 success = true;
436         }
437
438         freeaddrinfo(ai);
439         return success;
440 }
441
442 /*
443   Configure node_t mesh->self and set up the local sockets (listen only)
444 */
445 bool setup_myself(meshlink_handle_t *mesh) {
446         char *name;
447         char *address = NULL;
448
449         if(!(name = get_name(mesh))) {
450                 logger(mesh, MESHLINK_ERROR, "Name for MeshLink instance required!");
451                 return false;
452         }
453
454         mesh->self = new_node();
455         mesh->self->connection = new_connection();
456         mesh->self->name = name;
457         mesh->self->devclass = mesh->devclass;
458         mesh->self->connection->name = xstrdup(name);
459         read_host_config(mesh, mesh->config, name);
460
461         if(!get_config_string(lookup_config(mesh->config, "Port"), &mesh->myport)) {
462                 int port = check_port(mesh);
463
464                 if(port == 0) {
465                         return false;
466                 }
467
468                 xasprintf(&mesh->myport, "%d", port);
469         }
470
471         mesh->self->connection->options = 0;
472         mesh->self->connection->protocol_major = PROT_MAJOR;
473         mesh->self->connection->protocol_minor = PROT_MINOR;
474
475         mesh->self->options |= PROT_MINOR << 24;
476
477         if(!read_ecdsa_private_key(mesh)) {
478                 return false;
479         }
480
481         /* Ensure mesh->myport is numeric */
482
483         if(!atoi(mesh->myport)) {
484                 struct addrinfo *ai = str2addrinfo("localhost", mesh->myport, SOCK_DGRAM);
485                 sockaddr_t sa;
486
487                 if(!ai || !ai->ai_addr) {
488                         return false;
489                 }
490
491                 free(mesh->myport);
492                 memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
493                 sockaddr2str(&sa, NULL, &mesh->myport);
494         }
495
496         /* Check some options */
497
498         if(!setup_myself_reloadable(mesh)) {
499                 return false;
500         }
501
502         /* Compression */
503
504         // TODO: drop compression in the packet layer?
505         mesh->self->incompression = 0;
506         mesh->self->connection->outcompression = 0;
507
508         /* Done */
509
510         mesh->self->nexthop = mesh->self;
511         mesh->self->via = mesh->self;
512         mesh->self->status.reachable = true;
513         mesh->self->last_state_change = mesh->loop.now.tv_sec;
514
515         node_write_devclass(mesh, mesh->self);
516         node_add(mesh, mesh->self);
517
518         graph(mesh);
519
520         load_all_nodes(mesh);
521
522         /* Open sockets */
523
524         mesh->listen_sockets = 0;
525
526         if(!add_listen_address(mesh, address, NULL)) {
527                 if(strcmp(mesh->myport, "0")) {
528                         logger(mesh, MESHLINK_INFO, "Could not bind to port %s, asking OS to choose one for us", mesh->myport);
529                         free(mesh->myport);
530                         mesh->myport = strdup("0");
531
532                         if(!mesh->myport) {
533                                 return false;
534                         }
535
536                         if(!add_listen_address(mesh, address, NULL)) {
537                                 return false;
538                         }
539                 } else {
540                         return false;
541                 }
542         }
543
544         if(!mesh->listen_sockets) {
545                 logger(mesh, MESHLINK_ERROR, "Unable to create any listening socket!");
546                 return false;
547         }
548
549         /* Done. */
550
551         mesh->last_config_check = mesh->loop.now.tv_sec;
552
553         return true;
554 }
555
556 /*
557   initialize network
558 */
559 bool setup_network(meshlink_handle_t *mesh) {
560         init_connections(mesh);
561         init_submeshes(mesh);
562         init_nodes(mesh);
563         init_edges(mesh);
564         init_requests(mesh);
565
566         mesh->pinginterval = 60;
567         mesh->pingtimeout = 5;
568         maxoutbufsize = 10 * MTU;
569
570         if(!setup_myself(mesh)) {
571                 return false;
572         }
573
574         return true;
575 }
576
577 /*
578   close all open network connections
579 */
580 void close_network_connections(meshlink_handle_t *mesh) {
581         if(mesh->connections) {
582                 for(list_node_t *node = mesh->connections->head, *next; node; node = next) {
583                         next = node->next;
584                         connection_t *c = node->data;
585                         c->outgoing = NULL;
586                         terminate_connection(mesh, c, false);
587                 }
588         }
589
590         if(mesh->outgoings) {
591                 list_delete_list(mesh->outgoings);
592         }
593
594         if(mesh->self && mesh->self->connection) {
595                 terminate_connection(mesh, mesh->self->connection, false);
596                 free_connection(mesh->self->connection);
597         }
598
599         for(int i = 0; i < mesh->listen_sockets; i++) {
600                 io_del(&mesh->loop, &mesh->listen_socket[i].tcp);
601                 io_del(&mesh->loop, &mesh->listen_socket[i].udp);
602                 close(mesh->listen_socket[i].tcp.fd);
603                 close(mesh->listen_socket[i].udp.fd);
604         }
605
606         exit_requests(mesh);
607         exit_edges(mesh);
608         exit_nodes(mesh);
609         exit_connections(mesh);
610
611         if(mesh->myport) {
612                 free(mesh->myport);
613         }
614
615         return;
616 }