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