]> git.meshlink.io Git - meshlink-tiny/blob - src/protocol_auth.c
Add a metering test.
[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 "logger.h"
27 #include "meshlink_internal.h"
28 #include "meta.h"
29 #include "net.h"
30 #include "netutl.h"
31 #include "node.h"
32 #include "packmsg.h"
33 #include "prf.h"
34 #include "protocol.h"
35 #include "sptps.h"
36 #include "utils.h"
37 #include "xalloc.h"
38 #include "ed25519/sha512.h"
39
40 #include <assert.h>
41
42 extern bool node_write_devclass(meshlink_handle_t *mesh, node_t *n);
43
44 bool send_id(meshlink_handle_t *mesh, connection_t *c) {
45         return send_request(mesh, c, "%d %s %d.%d %s %u", ID, mesh->self->name, PROT_MAJOR, PROT_MINOR, mesh->appname, PROTOCOL_TINY);
46 }
47
48 bool id_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
49         assert(request);
50         assert(*request);
51
52         char name[MAX_STRING_SIZE];
53         uint32_t flags;
54
55         if(sscanf(request, "%*d " MAX_STRING " %d.%d %*s %u", name, &c->protocol_major, &c->protocol_minor, &flags) < 4) {
56                 logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "ID", c->name);
57                 return false;
58         }
59
60         /* Check if identity is a valid name */
61
62         if(!check_id(name)) {
63                 logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ID", c->name, "invalid name");
64                 return false;
65         }
66
67         /* If this is an outgoing connection, make sure we are connected to the right host */
68
69         if(c->outgoing) {
70                 if(strcmp(c->name, name)) {
71                         logger(mesh, MESHLINK_ERROR, "Peer is %s instead of %s", name, c->name);
72                         return false;
73                 }
74         } else {
75                 if(c->name) {
76                         free(c->name);
77                 }
78
79                 c->name = xstrdup(name);
80         }
81
82         /* Check if version matches */
83
84         if(c->protocol_major != PROT_MAJOR) {
85                 logger(mesh, MESHLINK_ERROR, "Peer %s uses incompatible version %d.%d",
86                        c->name, c->protocol_major, c->protocol_minor);
87                 return false;
88         }
89
90         /* Check if we know this node */
91
92         node_t *n = lookup_node(mesh, c->name);
93
94         if(!n) {
95                 logger(mesh, MESHLINK_ERROR, "Peer %s has unknown identity", c->name);
96                 return false;
97         }
98
99         if(!node_read_public_key(mesh, n)) {
100                 logger(mesh, MESHLINK_ERROR, "No key known for peer %s", c->name);
101                 return false;
102         }
103
104         /* Forbid version rollback for nodes whose ECDSA key we know */
105
106         if(ecdsa_active(c->ecdsa) && c->protocol_minor < 2) {
107                 logger(mesh, MESHLINK_ERROR, "Peer %s tries to roll back protocol version to %d.%d",
108                        c->name, c->protocol_major, c->protocol_minor);
109                 return false;
110         }
111
112         c->allow_request = ACK;
113         c->last_ping_time = mesh->loop.now.tv_sec;
114         char label[sizeof(meshlink_tcp_label) + strlen(mesh->self->name) + strlen(c->name) + 2];
115
116         if(c->outgoing) {
117                 snprintf(label, sizeof(label), "%s %s %s", meshlink_tcp_label, mesh->self->name, c->name);
118         } else {
119                 snprintf(label, sizeof(label), "%s %s %s", meshlink_tcp_label, c->name, mesh->self->name);
120         }
121
122         if(mesh->log_level <= MESHLINK_DEBUG) {
123                 char buf1[1024], buf2[1024];
124                 bin2hex((uint8_t *)mesh->private_key + 64, buf1, 32);
125                 bin2hex((uint8_t *)n->ecdsa + 64, buf2, 32);
126                 logger(mesh, MESHLINK_DEBUG, "Connection to %s mykey %s hiskey %s", c->name, buf1, buf2);
127         }
128
129         return sptps_start(&c->sptps, c, c->outgoing, false, mesh->private_key, n->ecdsa, label, sizeof(label) - 1, send_meta_sptps, receive_meta_sptps);
130 }
131
132 bool send_ack(meshlink_handle_t *mesh, connection_t *c) {
133         node_t *n = lookup_node(mesh, c->name);
134
135         if(n && n->status.blacklisted) {
136                 logger(mesh, MESHLINK_WARNING, "Peer %s is blacklisted", c->name);
137                 return send_error(mesh, c, BLACKLISTED, "blacklisted");
138         }
139
140         c->last_ping_time = mesh->loop.now.tv_sec;
141         return send_request(mesh, c, "%d %s %d %x", ACK, mesh->myport, mesh->devclass, OPTION_PMTU_DISCOVERY | (PROT_MINOR << 24));
142 }
143
144 bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) {
145         assert(request);
146         assert(*request);
147
148         char hisport[MAX_STRING_SIZE];
149         int devclass;
150         uint32_t options;
151         node_t *n;
152
153         if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &devclass, &options) != 3) {
154                 logger(mesh, MESHLINK_ERROR, "Got bad %s from %s", "ACK", c->name);
155                 return false;
156         }
157
158         if(devclass < 0 || devclass >= DEV_CLASS_COUNT) {
159                 logger(mesh, MESHLINK_ERROR, "Got bad %s from %s: %s", "ACK", c->name, "devclass invalid");
160                 return false;
161         }
162
163         /* Check if we already have a node_t for him */
164
165         n = lookup_node(mesh, c->name);
166
167         if(!n) {
168                 n = new_node();
169                 n->name = xstrdup(c->name);
170                 node_add(mesh, n);
171         }
172
173         n->devclass = devclass;
174         n->status.dirty = true;
175
176         n->last_successfull_connection = mesh->loop.now.tv_sec;
177
178         n->connection = c;
179         n->nexthop = n;
180         c->node = n;
181
182         /* Activate this connection */
183
184         c->allow_request = ALL;
185         c->last_key_renewal = mesh->loop.now.tv_sec;
186         c->status.active = true;
187
188         logger(mesh, MESHLINK_INFO, "Connection with %s activated", c->name);
189
190         if(mesh->meta_status_cb) {
191                 mesh->meta_status_cb(mesh, (meshlink_node_t *)n, true);
192         }
193
194         send_add_edge(mesh, c, 0);
195         n->status.reachable = true;
196         update_node_status(mesh, c->node);
197
198         return true;
199 }