]> git.meshlink.io Git - meshlink-tiny/blob - src/net_setup.c
Add a metering test.
[meshlink-tiny] / 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 "logger.h"
26 #include "meshlink_internal.h"
27 #include "net.h"
28 #include "netutl.h"
29 #include "packmsg.h"
30 #include "protocol.h"
31 #include "utils.h"
32 #include "xalloc.h"
33
34 /// Helper function to start parsing a host config file
35 static bool node_get_config(meshlink_handle_t *mesh, node_t *n, config_t *config, packmsg_input_t *in) {
36         if(!config_read(mesh, "current", n->name, config, mesh->config_key)) {
37                 return false;
38         }
39
40         in->ptr = config->buf;
41         in->len = config->len;
42
43         uint32_t version = packmsg_get_uint32(in);
44
45         if(version != MESHLINK_CONFIG_VERSION) {
46                 logger(mesh, MESHLINK_ERROR, "Invalid config file for node %s", n->name);
47                 config_free(config);
48                 return false;
49         }
50
51         const char *name;
52         uint32_t len = packmsg_get_str_raw(in, &name);
53
54         if(len != strlen(n->name) || !name || strncmp(name, n->name, len)) {
55                 logger(mesh, MESHLINK_ERROR, "Invalid config file for node %s", n->name);
56                 config_free(config);
57                 return false;
58         }
59
60         return true;
61 }
62
63 /// Read the public key from a host config file. Used whenever we need to start an SPTPS session.
64 bool node_read_public_key(meshlink_handle_t *mesh, node_t *n) {
65         if(ecdsa_active(n->ecdsa)) {
66                 return true;
67         }
68
69         config_t config;
70         packmsg_input_t in;
71
72         if(!node_get_config(mesh, n, &config, &in)) {
73                 return false;
74         }
75
76         packmsg_skip_element(&in); /* submesh */
77         packmsg_get_int32(&in); /* devclass */
78         packmsg_get_bool(&in); /* blacklisted */
79
80         const void *key;
81         uint32_t len = packmsg_get_bin_raw(&in, &key);
82
83         if(len != 32) {
84                 config_free(&config);
85                 return false;
86         }
87
88         n->ecdsa = ecdsa_set_public_key(key);
89
90         // While we are at it, read known address information
91         if(!n->canonical_address) {
92                 n->canonical_address = packmsg_get_str_dup(&in);
93
94                 if(!*n->canonical_address) {
95                         free(n->canonical_address);
96                         n->canonical_address = NULL;
97                 }
98         } else {
99                 packmsg_skip_element(&in);
100         }
101
102         // Append any known addresses in the config file to the list we currently have
103         uint32_t known_count = 0;
104
105         for(uint32_t i = 0; i < MAX_RECENT; i++) {
106                 if(n->recent[i].sa.sa_family) {
107                         known_count++;
108                 }
109         }
110
111         uint32_t count = packmsg_get_array(&in);
112
113         for(uint32_t i = 0; i < count; i++) {
114                 if(i < MAX_RECENT - known_count) {
115                         n->recent[i + known_count] = packmsg_get_sockaddr(&in);
116                 } else {
117                         packmsg_skip_element(&in);
118                 }
119         }
120
121         packmsg_skip_element(&in); // last_reachable
122         packmsg_skip_element(&in); // last_unreachable
123
124         config_free(&config);
125         return true;
126 }
127
128 /// Fill in node details from a config blob.
129 bool node_read_from_config(meshlink_handle_t *mesh, node_t *n, const config_t *config) {
130         (void)mesh;
131
132         if(n->canonical_address) {
133                 return true;
134         }
135
136         packmsg_input_t in = {config->buf, config->len};
137         uint32_t version = packmsg_get_uint32(&in);
138
139         if(version != MESHLINK_CONFIG_VERSION) {
140                 return false;
141         }
142
143         char *name = packmsg_get_str_dup(&in);
144
145         if(!name) {
146                 return false;
147         }
148
149         if(n->name) {
150                 if(strcmp(n->name, name)) {
151                         free(name);
152                         return false;
153                 }
154
155                 free(name);
156         } else {
157                 n->name = name;
158         }
159
160         packmsg_skip_element(&in); // submesh_name
161
162         n->devclass = packmsg_get_int32(&in);
163         n->status.blacklisted = packmsg_get_bool(&in);
164         const void *key;
165         uint32_t len = packmsg_get_bin_raw(&in, &key);
166
167         if(len) {
168                 if(len != 32) {
169                         return false;
170                 }
171
172                 if(!ecdsa_active(n->ecdsa)) {
173                         n->ecdsa = ecdsa_set_public_key(key);
174                 }
175         }
176
177         n->canonical_address = packmsg_get_str_dup(&in);
178
179         if(!*n->canonical_address) {
180                 free(n->canonical_address);
181                 n->canonical_address = NULL;
182         }
183
184         uint32_t count = packmsg_get_array(&in);
185
186         for(uint32_t i = 0; i < count; i++) {
187                 if(i < MAX_RECENT) {
188                         n->recent[i] = packmsg_get_sockaddr(&in);
189                 } else {
190                         packmsg_skip_element(&in);
191                 }
192         }
193
194         packmsg_skip_element(&in); // last_reachable
195         packmsg_skip_element(&in); // last_unreachable
196
197         return packmsg_done(&in);
198 }
199
200 bool node_write_config(meshlink_handle_t *mesh, node_t *n, bool new_key) {
201         if(!mesh->confbase) {
202                 return true;
203         }
204
205         switch(mesh->storage_policy) {
206         case MESHLINK_STORAGE_KEYS_ONLY:
207                 if(!new_key) {
208                         return true;
209                 }
210
211                 break;
212
213         case MESHLINK_STORAGE_DISABLED:
214                 return true;
215
216         default:
217                 break;
218         }
219
220         uint8_t buf[4096];
221         packmsg_output_t out = {buf, sizeof(buf)};
222
223         packmsg_add_uint32(&out, MESHLINK_CONFIG_VERSION);
224         packmsg_add_str(&out, n->name);
225         packmsg_add_str(&out, CORE_MESH);
226         packmsg_add_int32(&out, n->devclass);
227         packmsg_add_bool(&out, n->status.blacklisted);
228
229         if(ecdsa_active(n->ecdsa)) {
230                 packmsg_add_bin(&out, ecdsa_get_public_key(n->ecdsa), 32);
231         } else {
232                 packmsg_add_bin(&out, "", 0);
233         }
234
235         packmsg_add_str(&out, n->canonical_address ? n->canonical_address : "");
236
237         uint32_t count = 0;
238
239         for(uint32_t i = 0; i < MAX_RECENT; i++) {
240                 if(n->recent[i].sa.sa_family) {
241                         count++;
242                 } else {
243                         break;
244                 }
245         }
246
247         packmsg_add_array(&out, count);
248
249         for(uint32_t i = 0; i < count; i++) {
250                 packmsg_add_sockaddr(&out, &n->recent[i]);
251         }
252
253         packmsg_add_int64(&out, 0); // last_reachable
254         packmsg_add_int64(&out, 0); // last_unreachable
255
256         if(!packmsg_output_ok(&out)) {
257                 meshlink_errno = MESHLINK_EINTERNAL;
258                 return false;
259         }
260
261         config_t config = {buf, packmsg_output_size(&out, buf)};
262
263         if(!config_write(mesh, "current", n->name, &config, mesh->config_key)) {
264                 call_error_cb(mesh, MESHLINK_ESTORAGE);
265                 return false;
266         }
267
268         n->status.dirty = false;
269         return true;
270 }
271
272 static bool load_node(meshlink_handle_t *mesh, const char *name, void *priv) {
273         (void)priv;
274
275         if(!check_id(name)) {
276                 // Check if this is a temporary file, if so remove it
277                 const char *suffix = strstr(name, ".tmp");
278
279                 if(suffix && !suffix[4]) {
280                         char filename[PATH_MAX];
281                         snprintf(filename, sizeof(filename), "%s" SLASH "current" SLASH "hosts", mesh->confbase);
282                         unlink(filename);
283                 }
284
285                 return true;
286         }
287
288         node_t *n = lookup_node(mesh, name);
289
290         if(n) {
291                 return true;
292         }
293
294         n = new_node();
295         n->name = xstrdup(name);
296
297         config_t config;
298         packmsg_input_t in;
299
300         if(!node_get_config(mesh, n, &config, &in)) {
301                 free_node(n);
302                 return false;
303         }
304
305         if(!node_read_from_config(mesh, n, &config)) {
306                 logger(mesh, MESHLINK_ERROR, "Invalid config file for node %s", n->name);
307                 config_free(&config);
308                 free_node(n);
309                 return false;
310         }
311
312         config_free(&config);
313
314         node_add(mesh, n);
315
316         return true;
317 }
318
319 /*
320   Configure node_t mesh->self and set up the local sockets (listen only)
321 */
322 static bool setup_myself(meshlink_handle_t *mesh) {
323         mesh->self->nexthop = mesh->self;
324
325         node_add(mesh, mesh->self);
326
327         if(!config_scan_all(mesh, "current", "hosts", load_node, NULL)) {
328                 logger(mesh, MESHLINK_WARNING, "Could not scan all host config files");
329         }
330
331         /* Done. */
332
333         mesh->last_unreachable = mesh->loop.now.tv_sec;
334
335         return true;
336 }
337
338 /*
339   initialize network
340 */
341 bool setup_network(meshlink_handle_t *mesh) {
342         init_connections(mesh);
343         init_nodes(mesh);
344
345         if(!setup_myself(mesh)) {
346                 return false;
347         }
348
349         return true;
350 }
351
352 /*
353   close all open network connections
354 */
355 void close_network_connections(meshlink_handle_t *mesh) {
356         if(mesh->connection) {
357                 mesh->connection->outgoing = NULL;
358                 terminate_connection(mesh, mesh->connection, false);
359         }
360
361         exit_nodes(mesh);
362         exit_connections(mesh);
363
364         free(mesh->myport);
365         mesh->myport = NULL;
366         mesh->self = NULL;
367 }