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