]> git.meshlink.io Git - meshlink/blob - src/net_setup.c
10fb37b0005c5df5ae73b35bf33a66a9591796ac
[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
35 bool node_read_ecdsa_public_key(meshlink_handle_t *mesh, node_t *n) {
36         if(ecdsa_active(n->ecdsa)) {
37                 return true;
38         }
39
40         splay_tree_t *config_tree;
41         char *p;
42
43         init_configuration(&config_tree);
44
45         if(!read_host_config(mesh, config_tree, n->name)) {
46                 goto exit;
47         }
48
49         /* First, check for simple ECDSAPublicKey statement */
50
51         if(get_config_string(lookup_config(config_tree, "ECDSAPublicKey"), &p)) {
52                 n->ecdsa = ecdsa_set_base64_public_key(p);
53                 free(p);
54         }
55
56 exit:
57         exit_configuration(&config_tree);
58         return n->ecdsa;
59 }
60
61 bool read_ecdsa_public_key(meshlink_handle_t *mesh, connection_t *c) {
62         if(ecdsa_active(c->ecdsa)) {
63                 return true;
64         }
65
66         char *p;
67
68         if(!c->config_tree) {
69                 init_configuration(&c->config_tree);
70
71                 if(!read_host_config(mesh, c->config_tree, c->name)) {
72                         return false;
73                 }
74         }
75
76         /* First, check for simple ECDSAPublicKey statement */
77
78         if(get_config_string(lookup_config(c->config_tree, "ECDSAPublicKey"), &p)) {
79                 c->ecdsa = ecdsa_set_base64_public_key(p);
80                 free(p);
81                 return c->ecdsa;
82         }
83
84         return false;
85 }
86
87 bool read_ecdsa_private_key(meshlink_handle_t *mesh) {
88         FILE *fp;
89         char filename[PATH_MAX];
90
91         snprintf(filename, PATH_MAX, "%s" SLASH "ecdsa_key.priv", mesh->confbase);
92         fp = fopen(filename, "rb");
93
94         if(!fp) {
95                 logger(mesh, MESHLINK_ERROR, "Error reading ECDSA private key file: %s", strerror(errno));
96                 return false;
97         }
98
99         mesh->self->connection->ecdsa = ecdsa_read_pem_private_key(fp);
100         fclose(fp);
101
102         if(!mesh->self->connection->ecdsa) {
103                 logger(mesh, MESHLINK_ERROR, "Reading ECDSA private key file failed: %s", strerror(errno));
104         }
105
106         return mesh->self->connection->ecdsa;
107 }
108
109 static bool read_invitation_key(meshlink_handle_t *mesh) {
110         FILE *fp;
111         char filename[PATH_MAX];
112
113         if(mesh->invitation_key) {
114                 ecdsa_free(mesh->invitation_key);
115                 mesh->invitation_key = NULL;
116         }
117
118         snprintf(filename, PATH_MAX, "%s" SLASH "invitations" SLASH "ecdsa_key.priv", mesh->confbase);
119
120         fp = fopen(filename, "rb");
121
122         if(fp) {
123                 mesh->invitation_key = ecdsa_read_pem_private_key(fp);
124                 fclose(fp);
125
126                 if(!mesh->invitation_key) {
127                         logger(mesh, MESHLINK_ERROR, "Reading ECDSA private key file `%s' failed: %s", filename, strerror(errno));
128                 }
129         }
130
131         return mesh->invitation_key;
132 }
133
134 bool node_read_devclass(meshlink_handle_t *mesh, node_t *n) {
135
136         splay_tree_t *config_tree;
137         char *p;
138
139         init_configuration(&config_tree);
140
141         if(!read_host_config(mesh, config_tree, n->name)) {
142                 goto exit;
143         }
144
145         if(get_config_string(lookup_config(config_tree, "DeviceClass"), &p)) {
146                 n->devclass = atoi(p);
147                 free(p);
148         }
149
150         if((int)n->devclass < 0 || n->devclass > _DEV_CLASS_MAX) {
151                 n->devclass = _DEV_CLASS_MAX;
152         }
153
154 exit:
155         exit_configuration(&config_tree);
156         return n->devclass != 0;
157 }
158
159 bool node_write_devclass(meshlink_handle_t *mesh, node_t *n) {
160
161         if((int)n->devclass < 0 || n->devclass > _DEV_CLASS_MAX) {
162                 return false;
163         }
164
165         bool result = false;
166
167         splay_tree_t *config_tree;
168         init_configuration(&config_tree);
169
170         // ignore read errors; in case the file does not exist we will create it
171         read_host_config(mesh, config_tree, n->name);
172
173         config_t *cnf = lookup_config(config_tree, "DeviceClass");
174
175         if(!cnf) {
176                 cnf = new_config();
177                 cnf->variable = xstrdup("DeviceClass");
178                 config_add(config_tree, cnf);
179         }
180
181         set_config_int(cnf, n->devclass);
182
183         if(!write_host_config(mesh, config_tree, n->name)) {
184                 goto fail;
185         }
186
187         result = true;
188
189 fail:
190         exit_configuration(&config_tree);
191         return result;
192 }
193
194 void load_all_nodes(meshlink_handle_t *mesh) {
195         DIR *dir;
196         struct dirent *ent;
197         char dname[PATH_MAX];
198
199         snprintf(dname, PATH_MAX, "%s" SLASH "hosts", mesh->confbase);
200         dir = opendir(dname);
201
202         if(!dir) {
203                 logger(mesh, MESHLINK_ERROR, "Could not open %s: %s", dname, strerror(errno));
204                 return;
205         }
206
207         while((ent = readdir(dir))) {
208                 if(!check_id(ent->d_name)) {
209                         continue;
210                 }
211
212                 node_t *n = lookup_node(mesh, ent->d_name);
213
214                 if(n) {
215                         continue;
216                 }
217
218                 n = new_node();
219                 n->name = xstrdup(ent->d_name);
220                 node_read_devclass(mesh, n);
221                 node_add(mesh, n);
222         }
223
224         closedir(dir);
225 }
226
227
228 char *get_name(meshlink_handle_t *mesh) {
229         char *name = NULL;
230
231         get_config_string(lookup_config(mesh->config, "Name"), &name);
232
233         if(!name) {
234                 return NULL;
235         }
236
237         if(!check_id(name)) {
238                 logger(mesh, MESHLINK_ERROR, "Invalid name for mesh->self!");
239                 free(name);
240                 return NULL;
241         }
242
243         return name;
244 }
245
246 bool setup_myself_reloadable(meshlink_handle_t *mesh) {
247         mesh->localdiscovery = true;
248         keylifetime = 3600; // TODO: check if this can be removed as well
249         mesh->maxtimeout = 900;
250         mesh->self->options |= OPTION_PMTU_DISCOVERY;
251
252         read_invitation_key(mesh);
253
254         return true;
255 }
256
257 /*
258   Add listening sockets.
259 */
260 static bool add_listen_address(meshlink_handle_t *mesh, char *address, bool bindto) {
261         char *port = mesh->myport;
262
263         if(address) {
264                 char *space = strchr(address, ' ');
265
266                 if(space) {
267                         *space++ = 0;
268                         port = space;
269                 }
270
271                 if(!strcmp(address, "*")) {
272                         *address = 0;
273                 }
274         }
275
276         struct addrinfo *ai;
277
278         struct addrinfo hint = {
279                 .ai_family = addressfamily,
280                 .ai_socktype = SOCK_STREAM,
281                 .ai_protocol = IPPROTO_TCP,
282                 .ai_flags = AI_PASSIVE,
283         };
284
285         int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
286
287         free(address);
288
289         if(err || !ai) {
290                 logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "getaddrinfo", err == EAI_SYSTEM ? strerror(err) : gai_strerror(err));
291                 return false;
292         }
293
294         bool success = false;
295
296         for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
297                 // Ignore duplicate addresses
298                 bool found = false;
299
300                 for(int i = 0; i < mesh->listen_sockets; i++)
301                         if(!memcmp(&mesh->listen_socket[i].sa, aip->ai_addr, aip->ai_addrlen)) {
302                                 found = true;
303                                 break;
304                         }
305
306                 if(found) {
307                         continue;
308                 }
309
310                 if(mesh->listen_sockets >= MAXSOCKETS) {
311                         logger(mesh, MESHLINK_ERROR, "Too many listening sockets");
312                         return false;
313                 }
314
315                 int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr);
316
317                 if(tcp_fd < 0) {
318                         continue;
319                 }
320
321                 int udp_fd = setup_vpn_in_socket(mesh, (sockaddr_t *) aip->ai_addr);
322
323                 if(udp_fd < 0) {
324                         close(tcp_fd);
325                         continue;
326                 }
327
328                 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);
329                 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);
330
331                 if(mesh->log_level >= MESHLINK_INFO) {
332                         char *hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
333                         logger(mesh, MESHLINK_INFO, "Listening on %s", hostname);
334                         free(hostname);
335                 }
336
337                 mesh->listen_socket[mesh->listen_sockets].bindto = bindto;
338                 memcpy(&mesh->listen_socket[mesh->listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
339                 mesh->listen_sockets++;
340                 success = true;
341         }
342
343         freeaddrinfo(ai);
344         return success;
345 }
346
347 /*
348   Configure node_t mesh->self and set up the local sockets (listen only)
349 */
350 bool setup_myself(meshlink_handle_t *mesh) {
351         char *name;
352         char *address = NULL;
353
354         if(!(name = get_name(mesh))) {
355                 logger(mesh, MESHLINK_ERROR, "Name for MeshLink instance required!");
356                 return false;
357         }
358
359         mesh->self = new_node();
360         mesh->self->connection = new_connection();
361         mesh->self->name = name;
362         mesh->self->devclass = mesh->devclass;
363         mesh->self->connection->name = xstrdup(name);
364         read_host_config(mesh, mesh->config, name);
365
366         if(!get_config_string(lookup_config(mesh->config, "Port"), &mesh->myport)) {
367                 int port = check_port(mesh);
368
369                 if(port == 0) {
370                         return false;
371                 }
372
373                 xasprintf(&mesh->myport, "%d", port);
374         }
375
376         mesh->self->connection->options = 0;
377         mesh->self->connection->protocol_major = PROT_MAJOR;
378         mesh->self->connection->protocol_minor = PROT_MINOR;
379
380         mesh->self->options |= PROT_MINOR << 24;
381
382         if(!read_ecdsa_private_key(mesh)) {
383                 return false;
384         }
385
386         /* Ensure mesh->myport is numeric */
387
388         if(!atoi(mesh->myport)) {
389                 struct addrinfo *ai = str2addrinfo("localhost", mesh->myport, SOCK_DGRAM);
390                 sockaddr_t sa;
391
392                 if(!ai || !ai->ai_addr) {
393                         return false;
394                 }
395
396                 free(mesh->myport);
397                 memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
398                 sockaddr2str(&sa, NULL, &mesh->myport);
399         }
400
401         /* Check some options */
402
403         if(!setup_myself_reloadable(mesh)) {
404                 return false;
405         }
406
407         /* Compression */
408
409         // TODO: drop compression in the packet layer?
410         mesh->self->incompression = 0;
411         mesh->self->connection->outcompression = 0;
412
413         /* Done */
414
415         mesh->self->nexthop = mesh->self;
416         mesh->self->via = mesh->self;
417         mesh->self->status.reachable = true;
418         mesh->self->last_state_change = mesh->loop.now.tv_sec;
419
420         node_write_devclass(mesh, mesh->self);
421         node_add(mesh, mesh->self);
422
423         graph(mesh);
424
425         load_all_nodes(mesh);
426
427         /* Open sockets */
428
429         mesh->listen_sockets = 0;
430
431         if(!add_listen_address(mesh, address, NULL)) {
432                 if(strcmp(mesh->myport, "0")) {
433                         logger(mesh, MESHLINK_INFO, "Could not bind to port %s, asking OS to choose one for us", mesh->myport);
434                         free(mesh->myport);
435                         mesh->myport = strdup("0");
436
437                         if(!mesh->myport) {
438                                 return false;
439                         }
440
441                         if(!add_listen_address(mesh, address, NULL)) {
442                                 return false;
443                         }
444                 } else {
445                         return false;
446                 }
447         }
448
449         if(!mesh->listen_sockets) {
450                 logger(mesh, MESHLINK_ERROR, "Unable to create any listening socket!");
451                 return false;
452         }
453
454         /* Done. */
455
456         mesh->last_config_check = mesh->loop.now.tv_sec;
457
458         return true;
459 }
460
461 /*
462   initialize network
463 */
464 bool setup_network(meshlink_handle_t *mesh) {
465         init_connections(mesh);
466         init_nodes(mesh);
467         init_edges(mesh);
468         init_requests(mesh);
469
470         mesh->pinginterval = 60;
471         mesh->pingtimeout = 5;
472         maxoutbufsize = 10 * MTU;
473
474         if(!setup_myself(mesh)) {
475                 return false;
476         }
477
478         return true;
479 }
480
481 /*
482   close all open network connections
483 */
484 void close_network_connections(meshlink_handle_t *mesh) {
485         if(mesh->connections) {
486                 for(list_node_t *node = mesh->connections->head, *next; node; node = next) {
487                         next = node->next;
488                         connection_t *c = node->data;
489                         c->outgoing = NULL;
490                         terminate_connection(mesh, c, false);
491                 }
492         }
493
494         if(mesh->outgoings) {
495                 list_delete_list(mesh->outgoings);
496         }
497
498         if(mesh->self && mesh->self->connection) {
499                 terminate_connection(mesh, mesh->self->connection, false);
500                 free_connection(mesh->self->connection);
501         }
502
503         for(int i = 0; i < mesh->listen_sockets; i++) {
504                 io_del(&mesh->loop, &mesh->listen_socket[i].tcp);
505                 io_del(&mesh->loop, &mesh->listen_socket[i].udp);
506                 close(mesh->listen_socket[i].tcp.fd);
507                 close(mesh->listen_socket[i].udp.fd);
508         }
509
510         exit_requests(mesh);
511         exit_edges(mesh);
512         exit_nodes(mesh);
513         exit_connections(mesh);
514
515         if(mesh->myport) {
516                 free(mesh->myport);
517         }
518
519         return;
520 }