]> git.meshlink.io Git - meshlink/blob - src/net_setup.c
Check the return value of check_port().
[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, hint = {};
277
278         hint.ai_family = addressfamily;
279
280         hint.ai_socktype = SOCK_STREAM;
281
282         hint.ai_protocol = IPPROTO_TCP;
283
284         hint.ai_flags = AI_PASSIVE;
285
286         int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
287
288         free(address);
289
290         if(err || !ai) {
291                 logger(mesh, MESHLINK_ERROR, "System call `%s' failed: %s", "getaddrinfo", err == EAI_SYSTEM ? strerror(err) : gai_strerror(err));
292                 return false;
293         }
294
295         bool success = false;
296
297         for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
298                 // Ignore duplicate addresses
299                 bool found = false;
300
301                 for(int i = 0; i < mesh->listen_sockets; i++)
302                         if(!memcmp(&mesh->listen_socket[i].sa, aip->ai_addr, aip->ai_addrlen)) {
303                                 found = true;
304                                 break;
305                         }
306
307                 if(found) {
308                         continue;
309                 }
310
311                 if(mesh->listen_sockets >= MAXSOCKETS) {
312                         logger(mesh, MESHLINK_ERROR, "Too many listening sockets");
313                         return false;
314                 }
315
316                 int tcp_fd = setup_listen_socket((sockaddr_t *) aip->ai_addr);
317
318                 if(tcp_fd < 0) {
319                         continue;
320                 }
321
322                 int udp_fd = setup_vpn_in_socket(mesh, (sockaddr_t *) aip->ai_addr);
323
324                 if(udp_fd < 0) {
325                         close(tcp_fd);
326                         continue;
327                 }
328
329                 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);
330                 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);
331
332                 if(mesh->log_level >= MESHLINK_INFO) {
333                         char *hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr);
334                         logger(mesh, MESHLINK_INFO, "Listening on %s", hostname);
335                         free(hostname);
336                 }
337
338                 mesh->listen_socket[mesh->listen_sockets].bindto = bindto;
339                 memcpy(&mesh->listen_socket[mesh->listen_sockets].sa, aip->ai_addr, aip->ai_addrlen);
340                 mesh->listen_sockets++;
341                 success = true;
342         }
343
344         freeaddrinfo(ai);
345         return success;
346 }
347
348 /*
349   Configure node_t mesh->self and set up the local sockets (listen only)
350 */
351 bool setup_myself(meshlink_handle_t *mesh) {
352         char *name;
353         char *address = NULL;
354
355         if(!(name = get_name(mesh))) {
356                 logger(mesh, MESHLINK_ERROR, "Name for MeshLink instance required!");
357                 return false;
358         }
359
360         mesh->self = new_node();
361         mesh->self->connection = new_connection();
362         mesh->self->name = name;
363         mesh->self->devclass = mesh->devclass;
364         mesh->self->connection->name = xstrdup(name);
365         read_host_config(mesh, mesh->config, name);
366
367         if(!get_config_string(lookup_config(mesh->config, "Port"), &mesh->myport)) {
368                 int port = check_port(mesh);
369                 if (port == 0)
370                         return false;
371                 xasprintf(&mesh->myport, "%d", port);
372         }
373
374         mesh->self->connection->options = 0;
375         mesh->self->connection->protocol_major = PROT_MAJOR;
376         mesh->self->connection->protocol_minor = PROT_MINOR;
377
378         mesh->self->options |= PROT_MINOR << 24;
379
380         if(!read_ecdsa_private_key(mesh)) {
381                 return false;
382         }
383
384         /* Ensure mesh->myport is numeric */
385
386         if(!atoi(mesh->myport)) {
387                 struct addrinfo *ai = str2addrinfo("localhost", mesh->myport, SOCK_DGRAM);
388                 sockaddr_t sa;
389
390                 if(!ai || !ai->ai_addr) {
391                         return false;
392                 }
393
394                 free(mesh->myport);
395                 memcpy(&sa, ai->ai_addr, ai->ai_addrlen);
396                 sockaddr2str(&sa, NULL, &mesh->myport);
397         }
398
399         /* Check some options */
400
401         if(!setup_myself_reloadable(mesh)) {
402                 return false;
403         }
404
405         /* Compression */
406
407         // TODO: drop compression in the packet layer?
408         mesh->self->incompression = 0;
409         mesh->self->connection->outcompression = 0;
410
411         /* Done */
412
413         mesh->self->nexthop = mesh->self;
414         mesh->self->via = mesh->self;
415         mesh->self->status.reachable = true;
416         mesh->self->last_state_change = mesh->loop.now.tv_sec;
417
418         node_write_devclass(mesh, mesh->self);
419         node_add(mesh, mesh->self);
420
421         graph(mesh);
422
423         load_all_nodes(mesh);
424
425         /* Open sockets */
426
427         mesh->listen_sockets = 0;
428
429         if(!add_listen_address(mesh, address, NULL)) {
430                 if(strcmp(mesh->myport, "0")) {
431                         logger(mesh, MESHLINK_INFO, "Could not bind to port %s, asking OS to choose one for us", mesh->myport);
432                         free(mesh->myport);
433                         mesh->myport = strdup("0");
434
435                         if(!mesh->myport) {
436                                 return false;
437                         }
438
439                         if(!add_listen_address(mesh, address, NULL)) {
440                                 return false;
441                         }
442                 } else {
443                         return false;
444                 }
445         }
446
447         if(!mesh->listen_sockets) {
448                 logger(mesh, MESHLINK_ERROR, "Unable to create any listening socket!");
449                 return false;
450         }
451
452         /* Done. */
453
454         mesh->last_config_check = mesh->loop.now.tv_sec;
455
456         return true;
457 }
458
459 /*
460   initialize network
461 */
462 bool setup_network(meshlink_handle_t *mesh) {
463         init_connections(mesh);
464         init_nodes(mesh);
465         init_edges(mesh);
466         init_requests(mesh);
467
468         mesh->pinginterval = 60;
469         mesh->pingtimeout = 5;
470         maxoutbufsize = 10 * MTU;
471
472         if(!setup_myself(mesh)) {
473                 return false;
474         }
475
476         return true;
477 }
478
479 /*
480   close all open network connections
481 */
482 void close_network_connections(meshlink_handle_t *mesh) {
483         if(mesh->connections) {
484                 for(list_node_t *node = mesh->connections->head, *next; node; node = next) {
485                         next = node->next;
486                         connection_t *c = node->data;
487                         c->outgoing = NULL;
488                         terminate_connection(mesh, c, false);
489                 }
490         }
491
492         if(mesh->outgoings) {
493                 list_delete_list(mesh->outgoings);
494         }
495
496         if(mesh->self && mesh->self->connection) {
497                 terminate_connection(mesh, mesh->self->connection, false);
498                 free_connection(mesh->self->connection);
499         }
500
501         for(int i = 0; i < mesh->listen_sockets; i++) {
502                 io_del(&mesh->loop, &mesh->listen_socket[i].tcp);
503                 io_del(&mesh->loop, &mesh->listen_socket[i].udp);
504                 close(mesh->listen_socket[i].tcp.fd);
505                 close(mesh->listen_socket[i].udp.fd);
506         }
507
508         exit_requests(mesh);
509         exit_edges(mesh);
510         exit_nodes(mesh);
511         exit_connections(mesh);
512
513         if(mesh->myport) {
514                 free(mesh->myport);
515         }
516
517         return;
518 }