]> git.meshlink.io Git - meshlink/blob - src/meshlink.c
Moved 12 static variables to the meshlink_handle_t handle. Correctly passing the...
[meshlink] / src / meshlink.c
1 /*
2     meshlink.c -- Implementation of the MeshLink API.
3     Copyright (C) 2014 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 #define VAR_SERVER 1    /* Should be in tinc.conf */
20 #define VAR_HOST 2      /* Can be in host config file */
21 #define VAR_MULTIPLE 4  /* Multiple statements allowed */
22 #define VAR_OBSOLETE 8  /* Should not be used anymore */
23 #define VAR_SAFE 16     /* Variable is safe when accepting invitations */
24 typedef struct {
25         const char *name;
26         int type;
27 } var_t;
28
29 #include "system.h"
30 #include <pthread.h>
31
32 #include "crypto.h"
33 #include "ecdsagen.h"
34 #include "meshlink_internal.h"
35 #include "node.h"
36 #include "protocol.h"
37 #include "route.h"
38 #include "xalloc.h"
39 #include "ed25519/sha512.h"
40
41
42 //TODO: this can go away completely
43 const var_t variables[] = {
44         /* Server configuration */
45         {"AddressFamily", VAR_SERVER},
46         {"AutoConnect", VAR_SERVER | VAR_SAFE},
47         {"BindToAddress", VAR_SERVER | VAR_MULTIPLE},
48         {"BindToInterface", VAR_SERVER},
49         {"Broadcast", VAR_SERVER | VAR_SAFE},
50         {"ConnectTo", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
51         {"DecrementTTL", VAR_SERVER},
52         {"Device", VAR_SERVER},
53         {"DeviceType", VAR_SERVER},
54         {"DirectOnly", VAR_SERVER},
55         {"ECDSAPrivateKeyFile", VAR_SERVER},
56         {"ExperimentalProtocol", VAR_SERVER},
57         {"Forwarding", VAR_SERVER},
58         {"GraphDumpFile", VAR_SERVER | VAR_OBSOLETE},
59         {"Hostnames", VAR_SERVER},
60         {"IffOneQueue", VAR_SERVER},
61         {"Interface", VAR_SERVER},
62         {"KeyExpire", VAR_SERVER},
63         {"ListenAddress", VAR_SERVER | VAR_MULTIPLE},
64         {"LocalDiscovery", VAR_SERVER},
65         {"MACExpire", VAR_SERVER},
66         {"MaxConnectionBurst", VAR_SERVER},
67         {"MaxOutputBufferSize", VAR_SERVER},
68         {"MaxTimeout", VAR_SERVER},
69         {"Mode", VAR_SERVER | VAR_SAFE},
70         {"Name", VAR_SERVER},
71         {"PingInterval", VAR_SERVER},
72         {"PingTimeout", VAR_SERVER},
73         {"PriorityInheritance", VAR_SERVER},
74         {"PrivateKey", VAR_SERVER | VAR_OBSOLETE},
75         {"PrivateKeyFile", VAR_SERVER},
76         {"ProcessPriority", VAR_SERVER},
77         {"Proxy", VAR_SERVER},
78         {"ReplayWindow", VAR_SERVER},
79         {"ScriptsExtension", VAR_SERVER},
80         {"ScriptsInterpreter", VAR_SERVER},
81         {"StrictSubnets", VAR_SERVER},
82         {"TunnelServer", VAR_SERVER},
83         {"VDEGroup", VAR_SERVER},
84         {"VDEPort", VAR_SERVER},
85         /* Host configuration */
86         {"Address", VAR_HOST | VAR_MULTIPLE},
87         {"Cipher", VAR_SERVER | VAR_HOST},
88         {"ClampMSS", VAR_SERVER | VAR_HOST},
89         {"Compression", VAR_SERVER | VAR_HOST},
90         {"Digest", VAR_SERVER | VAR_HOST},
91         {"ECDSAPublicKey", VAR_HOST},
92         {"ECDSAPublicKeyFile", VAR_SERVER | VAR_HOST},
93         {"IndirectData", VAR_SERVER | VAR_HOST},
94         {"MACLength", VAR_SERVER | VAR_HOST},
95         {"PMTU", VAR_SERVER | VAR_HOST},
96         {"PMTUDiscovery", VAR_SERVER | VAR_HOST},
97         {"Port", VAR_HOST},
98         {"PublicKey", VAR_HOST | VAR_OBSOLETE},
99         {"PublicKeyFile", VAR_SERVER | VAR_HOST | VAR_OBSOLETE},
100         {"Subnet", VAR_HOST | VAR_MULTIPLE | VAR_SAFE},
101         {"TCPOnly", VAR_SERVER | VAR_HOST},
102         {"Weight", VAR_HOST | VAR_SAFE},
103         {NULL, 0}
104 };
105
106 static char *get_line(const char **data) {
107         if(!data || !*data)
108                 return NULL;
109
110         if(!**data) {
111                 *data = NULL;
112                 return NULL;
113         }
114
115         static char line[1024];
116         const char *end = strchr(*data, '\n');
117         size_t len = end ? end - *data : strlen(*data);
118         if(len >= sizeof line) {
119                 fprintf(stderr, "Maximum line length exceeded!\n");
120                 return NULL;
121         }
122         if(len && !isprint(**data))
123                 abort();
124
125         memcpy(line, *data, len);
126         line[len] = 0;
127
128         if(end)
129                 *data = end + 1;
130         else
131                 *data = NULL;
132
133         return line;
134 }
135
136 static char *get_value(const char *data, const char *var) {
137         char *line = get_line(&data);
138         if(!line)
139                 return NULL;
140
141         char *sep = line + strcspn(line, " \t=");
142         char *val = sep + strspn(sep, " \t");
143         if(*val == '=')
144                 val += 1 + strspn(val + 1, " \t");
145         *sep = 0;
146         if(strcasecmp(line, var))
147                 return NULL;
148         return val;
149 }
150 static FILE *fopenmask(const char *filename, const char *mode, mode_t perms) {
151         mode_t mask = umask(0);
152         perms &= ~mask;
153         umask(~perms);
154         FILE *f = fopen(filename, mode);
155 #ifdef HAVE_FCHMOD
156         if((perms & 0444) && f)
157                 fchmod(fileno(f), perms);
158 #endif
159         umask(mask);
160         return f;
161 }
162
163 static bool finalize_join(meshlink_handle_t *mesh) {
164         char *name = xstrdup(get_value(mesh->data, "Name"));
165         if(!name) {
166                 fprintf(stderr, "No Name found in invitation!\n");
167                 return false;
168         }
169
170         if(!check_id(name)) {
171                 fprintf(stderr, "Invalid Name found in invitation: %s!\n", name);
172                 return false;
173         }
174
175         if(mkdir(mesh->confbase, 0777) && errno != EEXIST) {
176                 fprintf(stderr, "Could not create directory %s: %s\n", mesh->confbase, strerror(errno));
177                 return false;
178         }
179
180         if(mkdir(mesh->hosts_dir, 0777) && errno != EEXIST) {
181                 fprintf(stderr, "Could not create directory %s: %s\n", mesh->hosts_dir, strerror(errno));
182                 return false;
183         }
184
185         FILE *f = fopen(mesh->meshlink_conf, "w");
186         if(!f) {
187                 fprintf(stderr, "Could not create file %s: %s\n", mesh->meshlink_conf, strerror(errno));
188                 return false;
189         }
190
191         fprintf(f, "Name = %s\n", name);
192
193         char filename[PATH_MAX];
194         snprintf(filename,PATH_MAX, "%s" SLASH "%s", mesh->hosts_dir, name);
195         FILE *fh = fopen(filename, "w");
196         if(!fh) {
197                 fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
198                 return false;
199         }
200
201         // Filter first chunk on approved keywords, split between tinc.conf and hosts/Name
202         // Other chunks go unfiltered to their respective host config files
203         const char *p = mesh->data;
204         char *l, *value;
205
206         while((l = get_line(&p))) {
207                 // Ignore comments
208                 if(*l == '#')
209                         continue;
210
211                 // Split line into variable and value
212                 int len = strcspn(l, "\t =");
213                 value = l + len;
214                 value += strspn(value, "\t ");
215                 if(*value == '=') {
216                         value++;
217                         value += strspn(value, "\t ");
218                 }
219                 l[len] = 0;
220
221                 // Is it a Name?
222                 if(!strcasecmp(l, "Name"))
223                         if(strcmp(value, name))
224                                 break;
225                         else
226                                 continue;
227                 else if(!strcasecmp(l, "NetName"))
228                         continue;
229
230                 // Check the list of known variables //TODO: most variables will not be available in meshlink, only name and key will be absolutely necessary
231                 bool found = false;
232                 int i;
233                 for(i = 0; variables[i].name; i++) {
234                         if(strcasecmp(l, variables[i].name))
235                                 continue;
236                         found = true;
237                         break;
238                 }
239
240                 // Ignore unknown and unsafe variables
241                 if(!found) {
242                         fprintf(stderr, "Ignoring unknown variable '%s' in invitation.\n", l);
243                         continue;
244                 } else if(!(variables[i].type & VAR_SAFE)) {
245                         fprintf(stderr, "Ignoring unsafe variable '%s' in invitation.\n", l);
246                         continue;
247                 }
248
249                 // Copy the safe variable to the right config file
250                 fprintf(variables[i].type & VAR_HOST ? fh : f, "%s = %s\n", l, value);
251         }
252
253         fclose(f);
254
255         while(l && !strcasecmp(l, "Name")) {
256                 if(!check_id(value)) {
257                         fprintf(stderr, "Invalid Name found in invitation.\n");
258                         return false;
259                 }
260
261                 if(!strcmp(value, name)) {
262                         fprintf(stderr, "Secondary chunk would overwrite our own host config file.\n");
263                         return false;
264                 }
265
266                 snprintf(filename,PATH_MAX, "%s" SLASH "%s", mesh->hosts_dir, value);
267                 f = fopen(filename, "w");
268
269                 if(!f) {
270                         fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
271                         return false;
272                 }
273
274                 while((l = get_line(&p))) {
275                         if(!strcmp(l, "#---------------------------------------------------------------#"))
276                                 continue;
277                         int len = strcspn(l, "\t =");
278                         if(len == 4 && !strncasecmp(l, "Name", 4)) {
279                                 value = l + len;
280                                 value += strspn(value, "\t ");
281                                 if(*value == '=') {
282                                         value++;
283                                         value += strspn(value, "\t ");
284                                 }
285                                 l[len] = 0;
286                                 break;
287                         }
288
289                         fputs(l, f);
290                         fputc('\n', f);
291                 }
292
293                 fclose(f);
294         }
295
296         // Generate our key and send a copy to the server
297         ecdsa_t *key = ecdsa_generate();
298         if(!key)
299                 return false;
300
301         char *b64key = ecdsa_get_base64_public_key(key);
302         if(!b64key)
303                 return false;
304
305         snprintf(filename,PATH_MAX, "%s" SLASH "ecdsa_key.priv", mesh->confbase);
306         f = fopenmask(filename, "w", 0600);
307
308         if(!ecdsa_write_pem_private_key(key, f)) {
309                 fprintf(stderr, "Error writing private key!\n");
310                 ecdsa_free(key);
311                 fclose(f);
312                 return false;
313         }
314
315         fclose(f);
316
317         fprintf(fh, "ECDSAPublicKey = %s\n", b64key);
318
319         sptps_send_record(&(mesh->sptps), 1, b64key, strlen(b64key));
320         free(b64key);
321
322         ecdsa_free(key);
323
324         check_port(name);
325
326         fprintf(stderr, "Configuration stored in: %s\n", mesh->confbase);
327
328         return true;
329 }
330
331 static bool invitation_send(void *handle, uint8_t type, const char *data, size_t len) {
332         meshlink_handle_t* mesh = handle;
333         while(len) {
334                 int result = send(mesh->sock, data, len, 0);
335                 if(result == -1 && errno == EINTR)
336                         continue;
337                 else if(result <= 0)
338                         return false;
339                 data += result;
340                 len -= result;
341         }
342         return true;
343 }
344
345 static bool invitation_receive(void *handle, uint8_t type, const char *msg, uint16_t len) {
346         meshlink_handle_t* mesh = handle;
347         switch(type) {
348                 case SPTPS_HANDSHAKE:
349                         return sptps_send_record(&(mesh->sptps), 0, mesh->cookie, sizeof mesh->cookie);
350
351                 case 0:
352                         mesh->data = xrealloc(mesh->data, mesh->thedatalen + len + 1);
353                         memcpy(mesh->data + mesh->thedatalen, msg, len);
354                         mesh->thedatalen += len;
355                         mesh->data[mesh->thedatalen] = 0;
356                         break;
357
358                 case 1:
359                         return finalize_join(mesh);
360
361                 case 2:
362                         fprintf(stderr, "Invitation succesfully accepted.\n");
363                         shutdown(mesh->sock, SHUT_RDWR);
364                         mesh->success = true;
365                         break;
366
367                 default:
368                         return false;
369         }
370
371         return true;
372 }
373
374 static bool recvline(meshlink_handle_t* mesh, size_t len) {
375         char *newline = NULL;
376
377         if(!mesh->sock)
378                 abort();
379
380         while(!(newline = memchr(mesh->buffer, '\n', mesh->blen))) {
381                 int result = recv(mesh->sock, mesh->buffer + mesh->blen, sizeof mesh->buffer - mesh->blen, 0);
382                 if(result == -1 && errno == EINTR)
383                         continue;
384                 else if(result <= 0)
385                         return false;
386                 mesh->blen += result;
387         }
388
389         if(newline - mesh->buffer >= len)
390                 return false;
391
392         len = newline - mesh->buffer;
393
394         memcpy(mesh->line, mesh->buffer, len);
395         mesh->line[len] = 0;
396         memmove(mesh->buffer, newline + 1, mesh->blen - len - 1);
397         mesh->blen -= len + 1;
398
399         return true;
400 }
401 static bool sendline(int fd, char *format, ...) {
402         static char buffer[4096];
403         char *p = buffer;
404         int blen = 0;
405         va_list ap;
406
407         va_start(ap, format);
408         blen = vsnprintf(buffer, sizeof buffer, format, ap);
409         va_end(ap);
410
411         if(blen < 1 || blen >= sizeof buffer)
412                 return false;
413
414         buffer[blen] = '\n';
415         blen++;
416
417         while(blen) {
418                 int result = send(fd, p, blen, MSG_NOSIGNAL);
419                 if(result == -1 && errno == EINTR)
420                         continue;
421                 else if(result <= 0)
422                         return false;
423                 p += result;
424                 blen -= result;
425         }
426
427         return true;
428 }
429 int rstrip(char *value) {
430         int len = strlen(value);
431         while(len && strchr("\t\r\n ", value[len - 1]))
432                 value[--len] = 0;
433         return len;
434 }
435
436
437 static const char *errstr[] = {
438         [MESHLINK_OK] = "No error",
439         [MESHLINK_ENOMEM] = "Out of memory",
440         [MESHLINK_ENOENT] = "No such node",
441 };
442
443 const char *meshlink_strerror(meshlink_errno_t errno) {
444         return errstr[errno];
445 }
446
447 static bool ecdsa_keygen(meshlink_handle_t *mesh) {
448         ecdsa_t *key;
449         FILE *f;
450         char pubname[PATH_MAX], privname[PATH_MAX];
451
452         fprintf(stderr, "Generating ECDSA keypair:\n");
453
454         if(!(key = ecdsa_generate())) {
455                 fprintf(stderr, "Error during key generation!\n");
456                 return false;
457         } else
458                 fprintf(stderr, "Done.\n");
459
460         snprintf(privname, sizeof privname, "%s" SLASH "ecdsa_key.priv", mesh->confbase);
461         f = fopen(privname, "w");
462
463         if(!f)
464                 return false;
465
466 #ifdef HAVE_FCHMOD
467         fchmod(fileno(f), 0600);
468 #endif
469
470         if(!ecdsa_write_pem_private_key(key, f)) {
471                 fprintf(stderr, "Error writing private key!\n");
472                 ecdsa_free(key);
473                 fclose(f);
474                 return false;
475         }
476
477         fclose(f);
478
479
480         snprintf(pubname, sizeof pubname, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, mesh->name);
481         f = fopen(pubname, "a");
482
483         if(!f)
484                 return false;
485
486         char *pubkey = ecdsa_get_base64_public_key(key);
487         fprintf(f, "ECDSAPublicKey = %s\n", pubkey);
488         free(pubkey);
489
490         fclose(f);
491         ecdsa_free(key);
492
493         return true;
494 }
495
496 static bool try_bind(int port) {
497         struct addrinfo *ai = NULL;
498         struct addrinfo hint = {
499                 .ai_flags = AI_PASSIVE,
500                 .ai_family = AF_UNSPEC,
501                 .ai_socktype = SOCK_STREAM,
502                 .ai_protocol = IPPROTO_TCP,
503         };
504
505         char portstr[16];
506         snprintf(portstr, sizeof portstr, "%d", port);
507
508         if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai)
509                 return false;
510
511         while(ai) {
512                 int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
513                 if(!fd)
514                         return false;
515                 int result = bind(fd, ai->ai_addr, ai->ai_addrlen);
516                 closesocket(fd);
517                 if(result)
518                         return false;
519                 ai = ai->ai_next;
520         }
521
522         return true;
523 }
524
525 int check_port(meshlink_handle_t *mesh) {
526         if(try_bind(655))
527                 return 655;
528
529         fprintf(stderr, "Warning: could not bind to port 655.\n");
530
531         for(int i = 0; i < 100; i++) {
532                 int port = 0x1000 + (rand() & 0x7fff);
533                 if(try_bind(port)) {
534                         char filename[PATH_MAX];
535                         snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", mesh->confbase, mesh->name);
536                         FILE *f = fopen(filename, "a");
537                         if(!f) {
538                                 fprintf(stderr, "Please change MeshLink's Port manually.\n");
539                                 return 0;
540                         }
541
542                         fprintf(f, "Port = %d\n", port);
543                         fclose(f);
544                         fprintf(stderr, "MeshLink will instead listen on port %d.\n", port);
545                         return port;
546                 }
547         }
548
549         fprintf(stderr, "Please change MeshLink's Port manually.\n");
550         return 0;
551 }
552
553 static bool meshlink_setup(meshlink_handle_t *mesh) {
554
555         if(mkdir(mesh->confbase, 0777) && errno != EEXIST) {
556                 fprintf(stderr, "Could not create directory %s: %s\n", mesh->confbase, strerror(errno));
557                 return false;
558         }
559
560         snprintf(mesh->hosts_dir, sizeof mesh->hosts_dir, "%s" SLASH "hosts", mesh->confbase);
561
562         if(mkdir(mesh->hosts_dir, 0777) && errno != EEXIST) {
563                 fprintf(stderr, "Could not create directory %s: %s\n", mesh->hosts_dir, strerror(errno));
564                 return false;
565         }
566
567         snprintf(mesh->meshlink_conf, sizeof mesh->meshlink_conf, "%s" SLASH "meshlink.conf", mesh->confbase);
568
569         if(!access(mesh->meshlink_conf, F_OK)) {
570                 fprintf(stderr, "Configuration file %s already exists!\n", mesh->meshlink_conf);
571                 return false;
572         }
573
574         FILE *f = fopen(mesh->meshlink_conf, "w");
575         if(!f) {
576                 fprintf(stderr, "Could not create file %s: %s\n", mesh->meshlink_conf, strerror(errno));
577                 return 1;
578         }
579
580         fprintf(f, "Name = %s\n", mesh->name);
581         fclose(f);
582
583         if(!ecdsa_keygen(mesh))
584                 return false;
585
586         check_port(mesh);
587
588         return true;
589 }
590
591 meshlink_handle_t *meshlink_open(const char *confbase, const char *name) {
592         // Validate arguments provided by the application
593
594         if(!confbase || !*confbase) {
595                 fprintf(stderr, "No confbase given!\n");
596                 return NULL;
597         }
598
599         if(!name || !*name) {
600                 fprintf(stderr, "No name given!\n");
601                 return NULL;
602         }
603
604         if(!check_id(name)) {
605                 fprintf(stderr, "Invalid name given!\n");
606                 return NULL;
607         }
608
609         meshlink_handle_t *mesh = xzalloc(sizeof *mesh);
610         mesh->confbase = xstrdup(confbase);
611         mesh->name = xstrdup(name);
612         event_loop_init(&mesh->loop);
613         mesh->loop.data = mesh;
614
615         // TODO: should be set by a function.
616         mesh->debug_level = 5;
617
618         // Check whether meshlink.conf already exists
619
620         char filename[PATH_MAX];
621         snprintf(filename, sizeof filename, "%s" SLASH "meshlink.conf", confbase);
622
623         if(access(filename, R_OK)) {
624                 if(errno == ENOENT) {
625                         // If not, create it
626                         meshlink_setup(mesh);
627                 } else {
628                         fprintf(stderr, "Cannot not read from %s: %s\n", filename, strerror(errno));
629                         return meshlink_close(mesh), NULL;
630                 }
631         }
632
633         // Read the configuration
634
635         init_configuration(&mesh->config);
636
637         if(!read_server_config(mesh))
638                 return meshlink_close(mesh), NULL;
639
640         // Setup up everything
641         // TODO: we should not open listening sockets yet
642
643         if(!setup_network(mesh))
644                 return meshlink_close(mesh), NULL;
645
646         return mesh;
647 }
648
649 void *meshlink_main_loop(void *arg) {
650         meshlink_handle_t *mesh = arg;
651
652         try_outgoing_connections(mesh);
653
654         main_loop(mesh);
655
656         return NULL;
657 }
658
659 bool meshlink_start(meshlink_handle_t *mesh) {
660         // TODO: open listening sockets first
661
662         // Start the main thread
663
664         if(pthread_create(&mesh->thread, NULL, meshlink_main_loop, mesh) != 0) {
665                 fprintf(stderr, "Could not start thread: %s\n", strerror(errno));
666                 memset(&mesh->thread, 0, sizeof mesh->thread);
667                 return false;
668         }
669
670         return true;
671 }
672
673 void meshlink_stop(meshlink_handle_t *mesh) {
674         // TODO: close the listening sockets to signal the main thread to shut down
675
676         // Wait for the main thread to finish
677
678         pthread_join(mesh->thread, NULL);
679 }
680
681 void meshlink_close(meshlink_handle_t *mesh) {
682         // Close and free all resources used.
683
684         close_network_connections(mesh);
685
686         logger(DEBUG_ALWAYS, LOG_NOTICE, "Terminating");
687
688         exit_configuration(&mesh->config);
689         event_loop_exit(&mesh->loop);
690 }
691
692 void meshlink_set_receive_cb(meshlink_handle_t *mesh, meshlink_receive_cb_t cb) {
693         mesh->receive_cb = cb;
694 }
695
696 void meshlink_set_node_status_cb(meshlink_handle_t *mesh, meshlink_node_status_cb_t cb) {
697         mesh->node_status_cb = cb;
698 }
699
700 void meshlink_set_log_cb(meshlink_handle_t *mesh, meshlink_log_level_t level, meshlink_log_cb_t cb) {
701         mesh->log_cb = cb;
702         mesh->log_level = level;
703 }
704
705 bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, unsigned int len) {
706         vpn_packet_t packet;
707         meshlink_packethdr_t *hdr = (meshlink_packethdr_t *)packet.data;
708         if (sizeof(meshlink_packethdr_t) + len > MAXSIZE) {
709                 //log something
710                 return false;
711         }
712
713         packet.probe = false;
714         memset(hdr, 0, sizeof *hdr);
715         memcpy(hdr->destination, destination->name, sizeof hdr->destination);
716         memcpy(hdr->source, mesh->self->name, sizeof hdr->source);
717
718         packet.len = sizeof *hdr + len;
719         memcpy(packet.data + sizeof *hdr, data, len);
720
721         mesh->self->in_packets++;
722         mesh->self->in_bytes += packet.len;
723         route(mesh, mesh->self, &packet);
724         return false;
725 }
726
727 meshlink_node_t *meshlink_get_node(meshlink_handle_t *mesh, const char *name) {
728         return (meshlink_node_t *)lookup_node(mesh, name);
729         return NULL;
730 }
731
732 size_t meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, size_t nmemb) {
733         return 0;
734 }
735
736 char *meshlink_sign(meshlink_handle_t *mesh, const char *data, size_t len) {
737         return NULL;
738 }
739
740 bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, const char *data, size_t len, const char *signature) {
741         return false;
742 }
743
744 char *meshlink_invite(meshlink_handle_t *mesh, const char *name) {
745         return NULL;
746 }
747
748 bool meshlink_join(meshlink_handle_t *mesh, const char *invitation) {
749
750
751         // Make sure confbase exists and is accessible.
752         if(mkdir(mesh->confbase, 0777) && errno != EEXIST) {
753                 fprintf(stderr, "Could not create directory %s: %s\n", mesh->confbase, strerror(errno));
754                 return 1;
755         }
756
757         if(access(mesh->confbase, R_OK | W_OK | X_OK)) {
758                 fprintf(stderr, "No permission to write in directory %s: %s\n", mesh->confbase, strerror(errno));
759                 return 1;
760         }
761
762         // TODO: Either remove or reintroduce netname in meshlink
763         // If a netname or explicit configuration directory is specified, check for an existing meshlink.conf.
764         //if((mesh->netname || confbasegiven) && !access(meshlink_conf, F_OK)) {
765         //      fprintf(stderr, "Configuration file %s already exists!\n", meshlink_conf);
766         //      return 1;
767         //}
768
769         char *slash = strchr(invitation, '/');
770         if(!slash)
771                 goto invalid;
772
773         *slash++ = 0;
774
775         if(strlen(slash) != 48)
776                 goto invalid;
777
778         char *address = invitation;
779         char *port = NULL;
780         if(*address == '[') {
781                 address++;
782                 char *bracket = strchr(address, ']');
783                 if(!bracket)
784                         goto invalid;
785                 *bracket = 0;
786                 if(bracket[1] == ':')
787                         port = bracket + 2;
788         } else {
789                 port = strchr(address, ':');
790                 if(port)
791                         *port++ = 0;
792         }
793
794         if(!mesh->myport || !*port)
795                 port = "655";
796
797         if(!b64decode(slash, mesh->hash, 18) || !b64decode(slash + 24, mesh->cookie, 18))
798                 goto invalid;
799
800         // Generate a throw-away key for the invitation.
801         ecdsa_t *key = ecdsa_generate();
802         if(!key)
803                 return 1;
804
805         char *b64key = ecdsa_get_base64_public_key(key);
806
807         // Connect to the meshlink daemon mentioned in the URL.
808         struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM);
809         if(!ai)
810                 return 1;
811
812         mesh->sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
813         if(mesh->sock <= 0) {
814                 fprintf(stderr, "Could not open socket: %s\n", strerror(errno));
815                 return 1;
816         }
817
818         if(connect(mesh->sock, ai->ai_addr, ai->ai_addrlen)) {
819                 fprintf(stderr, "Could not connect to %s port %s: %s\n", address, port, strerror(errno));
820                 closesocket(mesh->sock);
821                 return 1;
822         }
823
824         fprintf(stderr, "Connected to %s port %s...\n", address, port);
825
826         // Tell him we have an invitation, and give him our throw-away key.
827         int len = snprintf(invitation, sizeof invitation, "0 ?%s %d.%d\n", b64key, PROT_MAJOR, PROT_MINOR);
828         if(len <= 0 || len >= sizeof invitation)
829                 abort();
830
831         if(!sendline(mesh->sock, "0 ?%s %d.%d", b64key, PROT_MAJOR, 1)) {
832                 fprintf(stderr, "Error sending request to %s port %s: %s\n", address, port, strerror(errno));
833                 closesocket(mesh->sock);
834                 return 1;
835         }
836
837         char hisname[4096] = "";
838         int code, hismajor, hisminor = 0;
839
840         if(!recvline(mesh, sizeof mesh->line) || sscanf(mesh->line, "%d %s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(mesh, sizeof mesh->line) || !rstrip(mesh->line) || sscanf(mesh->line, "%d ", &code) != 1 || code != ACK || strlen(mesh->line) < 3) {
841                 fprintf(stderr, "Cannot read greeting from peer\n");
842                 closesocket(mesh->sock);
843                 return 1;
844         }
845
846         // Check if the hash of the key he gave us matches the hash in the URL.
847         char *fingerprint = mesh->line + 2;
848         char hishash[64];
849         if(!sha512(fingerprint, strlen(fingerprint), hishash)) {
850                 fprintf(stderr, "Could not create hash\n%s\n", mesh->line + 2);
851                 return 1;
852         }
853         if(memcmp(hishash, mesh->hash, 18)) {
854                 fprintf(stderr, "Peer has an invalid key!\n%s\n", mesh->line + 2);
855                 return 1;
856
857         }
858
859         ecdsa_t *hiskey = ecdsa_set_base64_public_key(fingerprint);
860         if(!hiskey)
861                 return 1;
862
863         // Start an SPTPS session
864         if(!sptps_start(&mesh->sptps, mesh, true, false, key, hiskey, "meshlink invitation", 15, invitation_send, invitation_receive))
865                 return 1;
866
867         // Feed rest of input buffer to SPTPS
868         if(!sptps_receive_data(&mesh->sptps, mesh->buffer, mesh->blen))
869                 return 1;
870
871         while((len = recv(mesh->sock, mesh->line, sizeof mesh->line, 0))) {
872                 if(len < 0) {
873                         if(errno == EINTR)
874                                 continue;
875                         fprintf(stderr, "Error reading data from %s port %s: %s\n", address, port, strerror(errno));
876                         return 1;
877                 }
878
879                 if(!sptps_receive_data(&mesh->sptps, mesh->line, len))
880                         return 1;
881         }
882
883         sptps_stop(&mesh->sptps);
884         ecdsa_free(hiskey);
885         ecdsa_free(key);
886         closesocket(mesh->sock);
887
888         if(!mesh->success) {
889                 fprintf(stderr, "Connection closed by peer, invitation cancelled.\n");
890                 return false;
891         }
892
893         return true;
894
895 invalid:
896         fprintf(stderr, "Invalid invitation URL.\n");
897         return false;
898 }
899
900 char *meshlink_export(meshlink_handle_t *mesh) {
901         return NULL;
902 }
903
904 bool meshlink_import(meshlink_handle_t *mesh, const char *data) {
905         return false;
906 }
907
908 void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) {
909 }
910
911 static void __attribute__((constructor)) meshlink_init(void) {
912         crypto_init();
913 }
914
915 static void __attribute__((destructor)) meshlink_exit(void) {
916         crypto_exit();
917 }