]> git.meshlink.io Git - meshlink/blob - src/net_setup.c
Modified meshlink_invite to generate invites for submesh
[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_write_devclass(meshlink_handle_t *mesh, node_t *n) {
194
195         if((int)n->devclass < 0 || n->devclass > _DEV_CLASS_MAX) {
196                 return false;
197         }
198
199         bool result = false;
200
201         splay_tree_t *config_tree;
202         init_configuration(&config_tree);
203
204         // ignore read errors; in case the file does not exist we will create it
205         read_host_config(mesh, config_tree, n->name);
206
207         config_t *cnf = lookup_config(config_tree, "DeviceClass");
208
209         if(!cnf) {
210                 cnf = new_config();
211                 cnf->variable = xstrdup("DeviceClass");
212                 config_add(config_tree, cnf);
213         }
214
215         set_config_int(cnf, n->devclass);
216
217         if(!write_host_config(mesh, config_tree, n->name)) {
218                 goto fail;
219         }
220
221         result = true;
222
223 fail:
224         exit_configuration(&config_tree);
225         return result;
226 }
227
228 bool node_write_submesh(meshlink_handle_t *mesh, node_t *n) {
229
230         if(!n->submesh) {
231                 return false;
232         }
233
234         bool result = false;
235
236         splay_tree_t *config_tree;
237         init_configuration(&config_tree);
238
239         // ignore read errors; in case the file does not exist we will create it
240         read_host_config(mesh, config_tree, n->name);
241
242         config_t *cnf = lookup_config(config_tree, "SubMesh");
243
244         if(!cnf) {
245                 cnf = new_config();
246                 cnf->variable = xstrdup("SubMesh");
247                 config_add(config_tree, cnf);
248         }
249
250         set_config_string(cnf, n->submesh->name);
251
252         if(!write_host_config(mesh, config_tree, n->name)) {
253                 goto fail;
254         }
255
256         result = true;
257
258 fail:
259         exit_configuration(&config_tree);
260         return result;
261 }
262
263 void load_all_nodes(meshlink_handle_t *mesh) {
264         DIR *dir;
265         struct dirent *ent;
266         char dname[PATH_MAX];
267
268         snprintf(dname, PATH_MAX, "%s" SLASH "hosts", mesh->confbase);
269         dir = opendir(dname);
270
271         if(!dir) {
272                 logger(mesh, MESHLINK_ERROR, "Could not open %s: %s", dname, strerror(errno));
273                 return;
274         }
275
276         while((ent = readdir(dir))) {
277                 if(!check_id(ent->d_name)) {
278                         continue;
279                 }
280
281                 node_t *n = lookup_node(mesh, ent->d_name);
282
283                 if(n) {
284                         if(n == mesh->self && !n->submesh) {
285                                 node_read_submesh(mesh, n);
286                         }
287
288                         continue;
289                 }
290
291                 n = new_node();
292                 n->name = xstrdup(ent->d_name);
293                 node_read_devclass(mesh, n);
294                 node_read_submesh(mesh, n);
295                 node_add(mesh, n);
296         }
297
298         closedir(dir);
299 }
300
301
302 char *get_name(meshlink_handle_t *mesh) {
303         char *name = NULL;
304
305         get_config_string(lookup_config(mesh->config, "Name"), &name);
306
307         if(!name) {
308                 return NULL;
309         }
310
311         if(!check_id(name)) {
312                 logger(mesh, MESHLINK_ERROR, "Invalid name for mesh->self!");
313                 free(name);
314                 return NULL;
315         }
316
317         return name;
318 }
319
320 bool setup_myself_reloadable(meshlink_handle_t *mesh) {
321         mesh->localdiscovery = true;
322         keylifetime = 3600; // TODO: check if this can be removed as well
323         mesh->maxtimeout = 900;
324         mesh->self->options |= OPTION_PMTU_DISCOVERY;
325
326         read_invitation_key(mesh);
327
328         return true;
329 }
330
331 /*
332   Add listening sockets.
333 */
334 static bool add_listen_address(meshlink_handle_t *mesh, char *address, bool bindto) {
335         char *port = mesh->myport;
336
337         if(address) {
338                 char *space = strchr(address, ' ');
339
340                 if(space) {
341                         *space++ = 0;
342                         port = space;
343                 }
344
345                 if(!strcmp(address, "*")) {
346                         *address = 0;
347                 }
348         }
349
350         struct addrinfo *ai;
351
352         struct addrinfo hint = {
353                 .ai_family = addressfamily,
354                 .ai_socktype = SOCK_STREAM,
355                 .ai_protocol = IPPROTO_TCP,
356                 .ai_flags = AI_PASSIVE,
357         };
358
359         int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
360
361         free(address);
362
363         if(err || !ai) {
364                 logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "getaddrinfo", err == EAI_SYSTEM ? strerror(err) : gai_strerror(err));
365                 return false;
366         }
367
368         bool success = false;
369
370         for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
371                 // Ignore duplicate addresses
372                 bool found = false;
373
374                 for(int i = 0; i < mesh->listen_sockets; i++)
375                         if(!memcmp(&mesh->listen_socket[i].sa, aip->ai_addr, aip->ai_addrlen)) {
376                                 found = true;
377                                 break;
378                         }
379
380                 if(found) {
381                         continue;
382                 }
383
384                 if(mesh->listen_sockets >= MAXSOCKETS) {
385                         logger(mesh, MESHLINK_ERROR, "Too many listening sockets");
386                         return false;
387                 }
388
389                 int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr);
390
391                 if(tcp_fd < 0) {
392                         continue;
393                 }
394
395                 int udp_fd = setup_vpn_in_socket(mesh, (sockaddr_t *) aip->ai_addr);
396
397                 if(udp_fd < 0) {
398                         close(tcp_fd);
399                         continue;
400                 }
401
402                 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);
403                 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);
404
405                 if(mesh->log_level >= MESHLINK_INFO) {
406                         char *hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
407                         logger(mesh, MESHLINK_INFO, "Listening on %s", hostname);
408                         free(hostname);
409                 }
410
411                 mesh->listen_socket[mesh->listen_sockets].bindto = bindto;
412                 memcpy(&mesh->listen_socket[mesh->listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
413                 mesh->listen_sockets++;
414                 success = true;
415         }
416
417         freeaddrinfo(ai);
418         return success;
419 }
420
421 /*
422   Configure node_t mesh->self and set up the local sockets (listen only)
423 */
424 bool setup_myself(meshlink_handle_t *mesh) {
425         char *name;
426         char *address = NULL;
427
428         if(!(name = get_name(mesh))) {
429                 logger(mesh, MESHLINK_ERROR, "Name for MeshLink instance required!");
430                 return false;
431         }
432
433         mesh->self = new_node();
434         mesh->self->connection = new_connection();
435         mesh->self->name = name;
436         mesh->self->devclass = mesh->devclass;
437         mesh->self->connection->name = xstrdup(name);
438         read_host_config(mesh, mesh->config, name);
439
440         if(!get_config_string(lookup_config(mesh->config, "Port"), &mesh->myport)) {
441                 int port = check_port(mesh);
442
443                 if(port == 0) {
444                         return false;
445                 }
446
447                 xasprintf(&mesh->myport, "%d", port);
448         }
449
450         mesh->self->connection->options = 0;
451         mesh->self->connection->protocol_major = PROT_MAJOR;
452         mesh->self->connection->protocol_minor = PROT_MINOR;
453
454         mesh->self->options |= PROT_MINOR << 24;
455
456         if(!read_ecdsa_private_key(mesh)) {
457                 return false;
458         }
459
460         /* Ensure mesh->myport is numeric */
461
462         if(!atoi(mesh->myport)) {
463                 struct addrinfo *ai = str2addrinfo("localhost", mesh->myport, SOCK_DGRAM);
464                 sockaddr_t sa;
465
466                 if(!ai || !ai->ai_addr) {
467                         return false;
468                 }
469
470                 free(mesh->myport);
471                 memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
472                 sockaddr2str(&sa, NULL, &mesh->myport);
473         }
474
475         /* Check some options */
476
477         if(!setup_myself_reloadable(mesh)) {
478                 return false;
479         }
480
481         /* Compression */
482
483         // TODO: drop compression in the packet layer?
484         mesh->self->incompression = 0;
485         mesh->self->connection->outcompression = 0;
486
487         /* Done */
488
489         mesh->self->nexthop = mesh->self;
490         mesh->self->via = mesh->self;
491         mesh->self->status.reachable = true;
492         mesh->self->last_state_change = mesh->loop.now.tv_sec;
493
494         node_write_devclass(mesh, mesh->self);
495         node_add(mesh, mesh->self);
496
497         graph(mesh);
498
499         load_all_nodes(mesh);
500
501         /* Open sockets */
502
503         mesh->listen_sockets = 0;
504
505         if(!add_listen_address(mesh, address, NULL)) {
506                 if(strcmp(mesh->myport, "0")) {
507                         logger(mesh, MESHLINK_INFO, "Could not bind to port %s, asking OS to choose one for us", mesh->myport);
508                         free(mesh->myport);
509                         mesh->myport = strdup("0");
510
511                         if(!mesh->myport) {
512                                 return false;
513                         }
514
515                         if(!add_listen_address(mesh, address, NULL)) {
516                                 return false;
517                         }
518                 } else {
519                         return false;
520                 }
521         }
522
523         if(!mesh->listen_sockets) {
524                 logger(mesh, MESHLINK_ERROR, "Unable to create any listening socket!");
525                 return false;
526         }
527
528         /* Done. */
529
530         mesh->last_config_check = mesh->loop.now.tv_sec;
531
532         return true;
533 }
534
535 /*
536   initialize network
537 */
538 bool setup_network(meshlink_handle_t *mesh) {
539         init_connections(mesh);
540         init_submeshes(mesh);
541         init_nodes(mesh);
542         init_edges(mesh);
543         init_requests(mesh);
544
545         mesh->pinginterval = 60;
546         mesh->pingtimeout = 5;
547         maxoutbufsize = 10 * MTU;
548
549         if(!setup_myself(mesh)) {
550                 return false;
551         }
552
553         return true;
554 }
555
556 /*
557   close all open network connections
558 */
559 void close_network_connections(meshlink_handle_t *mesh) {
560         if(mesh->connections) {
561                 for(list_node_t *node = mesh->connections->head, *next; node; node = next) {
562                         next = node->next;
563                         connection_t *c = node->data;
564                         c->outgoing = NULL;
565                         terminate_connection(mesh, c, false);
566                 }
567         }
568
569         if(mesh->outgoings) {
570                 list_delete_list(mesh->outgoings);
571         }
572
573         if(mesh->self && mesh->self->connection) {
574                 terminate_connection(mesh, mesh->self->connection, false);
575                 free_connection(mesh->self->connection);
576         }
577
578         for(int i = 0; i < mesh->listen_sockets; i++) {
579                 io_del(&mesh->loop, &mesh->listen_socket[i].tcp);
580                 io_del(&mesh->loop, &mesh->listen_socket[i].udp);
581                 close(mesh->listen_socket[i].tcp.fd);
582                 close(mesh->listen_socket[i].udp.fd);
583         }
584
585         exit_requests(mesh);
586         exit_edges(mesh);
587         exit_nodes(mesh);
588         exit_connections(mesh);
589
590         if(mesh->myport) {
591                 free(mesh->myport);
592         }
593
594         return;
595 }