]> git.meshlink.io Git - meshlink-tiny/blob - src/protocol_auth.c
943040e9fd528d4c6894ce135997564ff28cd18b
[meshlink-tiny] / src / protocol_auth.c
1 /*
2     protocol_auth.c -- handle the meta-protocol, authentication
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 "devtools.h"
25 #include "ecdsa.h"
26 #include "edge.h"
27 #include "graph.h"
28 #include "logger.h"
29 #include "meshlink_internal.h"
30 #include "meta.h"
31 #include "net.h"
32 #include "netutl.h"
33 #include "node.h"
34 #include "packmsg.h"
35 #include "prf.h"
36 #include "protocol.h"
37 #include "sptps.h"
38 #include "utils.h"
39 #include "xalloc.h"
40 #include "ed25519/sha512.h"
41
42 #include <assert.h>
43
44 extern bool node_write_devclass(meshlink_handle_t *mesh, node_t *n);
45
46 bool send_id(meshlink_handle_t *mesh, connection_t *c) {
47         return send_request(mesh, c, NULL, "%d %s %d.%d %s", ID, mesh->self->name, PROT_MAJOR, PROT_MINOR, mesh->appname);
48 }
49
50 bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
51         assert(request);
52         assert(*request);
53
54         char name[MAX_STRING_SIZE];
55
56         if(sscanf(request, "%*d " MAX_STRING " %d.%d", name, &c->protocol_major, &c->protocol_minor) < 2) {
57                 logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "ID", c->name);
58                 return false;
59         }
60
61         /* Check if identity is a valid name */
62
63         if(!check_id(name)) {
64                 logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ID", c->name, "invalid name");
65                 return false;
66         }
67
68         /* If this is an outgoing connection, make sure we are connected to the right host */
69
70         if(c->outgoing) {
71                 if(strcmp(c->name, name)) {
72                         logger(mesh, MESHLINK_ERROR, "Peer is %s instead of %s", name, c->name);
73                         return false;
74                 }
75         } else {
76                 if(c->name) {
77                         free(c->name);
78                 }
79
80                 c->name = xstrdup(name);
81         }
82
83         /* Check if version matches */
84
85         if(c->protocol_major != PROT_MAJOR) {
86                 logger(mesh, MESHLINK_ERROR, "Peer %s uses incompatible version %d.%d",
87                        c->name, c->protocol_major, c->protocol_minor);
88                 return false;
89         }
90
91         /* Check if we know this node */
92
93         node_t *n = lookup_node(mesh, c->name);
94
95         if(!n) {
96                 logger(mesh, MESHLINK_ERROR, "Peer %s has unknown identity", c->name);
97                 return false;
98         }
99
100         if(!node_read_public_key(mesh, n)) {
101                 logger(mesh, MESHLINK_ERROR, "No key known for peer %s", c->name);
102
103                 if(n->status.reachable && !n->status.waitingforkey) {
104                         logger(mesh, MESHLINK_INFO, "Requesting key from peer %s", c->name);
105                         send_req_key(mesh, n);
106                 }
107
108                 return false;
109         }
110
111         /* Forbid version rollback for nodes whose ECDSA key we know */
112
113         if(ecdsa_active(c->ecdsa) && c->protocol_minor < 2) {
114                 logger(mesh, MESHLINK_ERROR, "Peer %s tries to roll back protocol version to %d.%d",
115                        c->name, c->protocol_major, c->protocol_minor);
116                 return false;
117         }
118
119         c->allow_request = ACK;
120         c->last_ping_time = mesh->loop.now.tv_sec;
121         char label[sizeof(meshlink_tcp_label) + strlen(mesh->self->name) + strlen(c->name) + 2];
122
123         if(c->outgoing) {
124                 snprintf(label, sizeof(label), "%s %s %s", meshlink_tcp_label, mesh->self->name, c->name);
125         } else {
126                 snprintf(label, sizeof(label), "%s %s %s", meshlink_tcp_label, c->name, mesh->self->name);
127         }
128
129         if(mesh->log_level <= MESHLINK_DEBUG) {
130                 char buf1[1024], buf2[1024];
131                 bin2hex((uint8_t *)mesh->private_key + 64, buf1, 32);
132                 bin2hex((uint8_t *)n->ecdsa + 64, buf2, 32);
133                 logger(mesh, MESHLINK_DEBUG, "Connection to %s mykey %s hiskey %s", c->name, buf1, buf2);
134         }
135
136         return sptps_start(&c->sptps, c, c->outgoing, false, mesh->private_key, n->ecdsa, label, sizeof(label) - 1, send_meta_sptps, receive_meta_sptps);
137 }
138
139 bool send_ack(meshlink_handle_t *mesh, connection_t *c) {
140         node_t *n = lookup_node(mesh, c->name);
141
142         if(n && n->status.blacklisted) {
143                 logger(mesh, MESHLINK_WARNING, "Peer %s is blacklisted", c->name);
144                 return send_error(mesh, c, BLACKLISTED, "blacklisted");
145         }
146
147         c->last_ping_time = mesh->loop.now.tv_sec;
148         return send_request(mesh, c, NULL, "%d %s %d %x", ACK, mesh->myport, mesh->devclass, OPTION_PMTU_DISCOVERY | (PROT_MINOR << 24));
149 }
150
151 static void send_everything(meshlink_handle_t *mesh, connection_t *c) {
152         /* Send all known subnets and edges */
153
154         for splay_each(node_t, n, mesh->nodes) {
155                 for inner_splay_each(edge_t, e, n->edge_tree) {
156                         send_add_edge(mesh, c, e, 0);
157                 }
158         }
159 }
160
161 bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
162         assert(request);
163         assert(*request);
164
165         char hisport[MAX_STRING_SIZE];
166         int devclass;
167         uint32_t options;
168         node_t *n;
169
170         if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &devclass, &options) != 3) {
171                 logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "ACK", c->name);
172                 return false;
173         }
174
175         if(devclass < 0 || devclass >= DEV_CLASS_COUNT) {
176                 logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ACK", c->name, "devclass invalid");
177                 return false;
178         }
179
180         /* Check if we already have a node_t for him */
181
182         n = lookup_node(mesh, c->name);
183
184         if(!n) {
185                 n = new_node();
186                 n->name = xstrdup(c->name);
187                 node_add(mesh, n);
188         } else {
189                 if(n->connection) {
190                         /* Oh dear, we already have a connection to this node. */
191                         logger(mesh, MESHLINK_INFO, "Established a second connection with %s, closing old connection", n->connection->name);
192
193                         if(n->connection->outgoing) {
194                                 if(c->outgoing) {
195                                         logger(mesh, MESHLINK_WARNING, "Two outgoing connections to the same node!");
196                                 } else {
197                                         c->outgoing = n->connection->outgoing;
198                                 }
199
200                                 n->connection->outgoing = NULL;
201                         }
202
203                         /* Remove the edge before terminating the connection, to prevent a graph update. */
204                         edge_del(mesh, n->connection->edge);
205                         n->connection->edge = NULL;
206
207                         terminate_connection(mesh, n->connection, false);
208                 }
209         }
210
211         n->devclass = devclass;
212         n->status.dirty = true;
213
214         n->last_successfull_connection = mesh->loop.now.tv_sec;
215
216         n->connection = c;
217         n->nexthop = n;
218         c->node = n;
219
220         /* Activate this connection */
221
222         c->allow_request = ALL;
223         c->last_key_renewal = mesh->loop.now.tv_sec;
224         c->status.active = true;
225
226         logger(mesh, MESHLINK_INFO, "Connection with %s activated", c->name);
227
228         if(mesh->meta_status_cb) {
229                 mesh->meta_status_cb(mesh, (meshlink_node_t *)n, true);
230         }
231
232         /*  Terminate any connections to this node that are not activated yet */
233
234         for list_each(connection_t, other, mesh->connections) {
235                 if(!other->status.active && !strcmp(other->name, c->name)) {
236                         if(other->outgoing) {
237                                 if(c->outgoing) {
238                                         logger(mesh, MESHLINK_WARNING, "Two outgoing connections to the same node!");
239                                 } else {
240                                         c->outgoing = other->outgoing;
241                                 }
242
243                                 other->outgoing = NULL;
244                         }
245
246                         logger(mesh, MESHLINK_DEBUG, "Terminating pending second connection with %s", n->name);
247                         terminate_connection(mesh, other, false);
248                 }
249         }
250
251         /* Send him everything we know */
252
253         send_everything(mesh, c);
254
255         /* Create an edge_t for this connection */
256
257         assert(devclass >= 0 && devclass < DEV_CLASS_COUNT);
258
259         c->edge = new_edge();
260         c->edge->from = mesh->self;
261         c->edge->to = n;
262         sockaddrcpy_setport(&c->edge->address, &c->address, atoi(hisport));
263         c->edge->weight = mesh->dev_class_traits[devclass].edge_weight;
264         c->edge->connection = c;
265
266         node_add_recent_address(mesh, n, &c->address);
267         edge_add(mesh, c->edge);
268
269         /* Notify everyone of the new edge */
270
271         send_add_edge(mesh, mesh->everyone, c->edge, 0);
272
273         /* Run MST and SSSP algorithms */
274
275         graph(mesh);
276
277         /* Request a session key to jump start UDP traffic */
278
279         if(c->status.initiator) {
280                 send_req_key(mesh, n);
281         }
282
283         return true;
284 }