Clarify that scripts are called synchronously.
[tinc] / src / tincctl.c
1 /*
2     tincctl.c -- Controlling a running tincd
3     Copyright (C) 2007-2015 Guus Sliepen <guus@tinc-vpn.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "system.h"
21
22 #include <getopt.h>
23
24 #ifdef HAVE_READLINE
25 #include "readline/readline.h"
26 #include "readline/history.h"
27 #endif
28
29 #include "xalloc.h"
30 #include "protocol.h"
31 #include "control_common.h"
32 #include "crypto.h"
33 #include "ecdsagen.h"
34 #include "fsck.h"
35 #include "info.h"
36 #include "invitation.h"
37 #include "names.h"
38 #include "rsagen.h"
39 #include "utils.h"
40 #include "tincctl.h"
41 #include "top.h"
42 #include "version.h"
43
44 #ifndef MSG_NOSIGNAL
45 #define MSG_NOSIGNAL 0
46 #endif
47
48 static char **orig_argv;
49 static int orig_argc;
50
51 /* If nonzero, display usage information and exit. */
52 static bool show_help = false;
53
54 /* If nonzero, print the version on standard output and exit.  */
55 static bool show_version = false;
56
57 static char *name = NULL;
58 static char controlcookie[1025];
59 char *tinc_conf = NULL;
60 char *hosts_dir = NULL;
61 struct timeval now;
62
63 // Horrible global variables...
64 static int pid = 0;
65 int fd = -1;
66 char line[4096];
67 static int code;
68 static int req;
69 static int result;
70 bool force = false;
71 bool tty = true;
72 bool confbasegiven = false;
73 bool netnamegiven = false;
74 char *scriptinterpreter = NULL;
75 char *scriptextension = "";
76 static char *prompt;
77
78 static struct option const long_options[] = {
79         {"batch", no_argument, NULL, 'b'},
80         {"config", required_argument, NULL, 'c'},
81         {"net", required_argument, NULL, 'n'},
82         {"help", no_argument, NULL, 1},
83         {"version", no_argument, NULL, 2},
84         {"pidfile", required_argument, NULL, 3},
85         {"force", no_argument, NULL, 4},
86         {NULL, 0, NULL, 0}
87 };
88
89 static void version(void) {
90         printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
91                    BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
92         printf("Copyright (C) 1998-2015 Ivo Timmermans, Guus Sliepen and others.\n"
93                         "See the AUTHORS file for a complete list.\n\n"
94                         "tinc comes with ABSOLUTELY NO WARRANTY.  This is free software,\n"
95                         "and you are welcome to redistribute it under certain conditions;\n"
96                         "see the file COPYING for details.\n");
97 }
98
99 static void usage(bool status) {
100         if(status) {
101                 fprintf(stderr, "Try `%s --help\' for more information.\n", program_name);
102         } else {
103                 printf("Usage: %s [options] command\n\n", program_name);
104                 printf("Valid options are:\n"
105                                 "  -b, --batch             Don't ask for anything (non-interactive mode).\n"
106                                 "  -c, --config=DIR        Read configuration options from DIR.\n"
107                                 "  -n, --net=NETNAME       Connect to net NETNAME.\n"
108                                 "      --pidfile=FILENAME  Read control cookie from FILENAME.\n"
109                                 "      --force             Force some commands to work despite warnings.\n"
110                                 "      --help              Display this help and exit.\n"
111                                 "      --version           Output version information and exit.\n"
112                                 "\n"
113                                 "Valid commands are:\n"
114                                 "  init [name]                Create initial configuration files.\n"
115                                 "  get VARIABLE               Print current value of VARIABLE\n"
116                                 "  set VARIABLE VALUE         Set VARIABLE to VALUE\n"
117                                 "  add VARIABLE VALUE         Add VARIABLE with the given VALUE\n"
118                                 "  del VARIABLE [VALUE]       Remove VARIABLE [only ones with watching VALUE]\n"
119                                 "  start [tincd options]      Start tincd.\n"
120                                 "  stop                       Stop tincd.\n"
121                                 "  restart [tincd options]    Restart tincd.\n"
122                                 "  reload                     Partially reload configuration of running tincd.\n"
123                                 "  pid                        Show PID of currently running tincd.\n"
124 #ifdef DISABLE_LEGACY
125                                 "  generate-keys              Generate a new Ed25519 public/private keypair.\n"
126 #else
127                                 "  generate-keys [bits]       Generate new RSA and Ed25519 public/private keypairs.\n"
128                                 "  generate-rsa-keys [bits]   Generate a new RSA public/private keypair.\n"
129 #endif
130                                 "  generate-ed25519-keys      Generate a new Ed25519 public/private keypair.\n"
131                                 "  dump                       Dump a list of one of the following things:\n"
132                                 "    [reachable] nodes        - all known nodes in the VPN\n"
133                                 "    edges                    - all known connections in the VPN\n"
134                                 "    subnets                  - all known subnets in the VPN\n"
135                                 "    connections              - all meta connections with ourself\n"
136                                 "    [di]graph                - graph of the VPN in dotty format\n"
137                                 "    invitations              - outstanding invitations\n"
138                                 "  info NODE|SUBNET|ADDRESS   Give information about a particular NODE, SUBNET or ADDRESS.\n"
139                                 "  purge                      Purge unreachable nodes\n"
140                                 "  debug N                    Set debug level\n"
141                                 "  retry                      Retry all outgoing connections\n"
142                                 "  disconnect NODE            Close meta connection with NODE\n"
143 #ifdef HAVE_CURSES
144                                 "  top                        Show real-time statistics\n"
145 #endif
146                                 "  pcap [snaplen]             Dump traffic in pcap format [up to snaplen bytes per packet]\n"
147                                 "  log [level]                Dump log output [up to the specified level]\n"
148                                 "  export                     Export host configuration of local node to standard output\n"
149                                 "  export-all                 Export all host configuration files to standard output\n"
150                                 "  import                     Import host configuration file(s) from standard input\n"
151                                 "  exchange                   Same as export followed by import\n"
152                                 "  exchange-all               Same as export-all followed by import\n"
153                                 "  invite NODE [...]          Generate an invitation for NODE\n"
154                                 "  join INVITATION            Join a VPN using an INVITATION\n"
155                                 "  network [NETNAME]          List all known networks, or switch to the one named NETNAME.\n"
156                                 "  fsck                       Check the configuration files for problems.\n"
157                                 "  sign [FILE]                Generate a signed version of a file.\n"
158                                 "  verify NODE [FILE]         Verify that a file was signed by the given NODE.\n"
159                                 "\n");
160                 printf("Report bugs to tinc@tinc-vpn.org.\n");
161         }
162 }
163
164 static bool parse_options(int argc, char **argv) {
165         int r;
166         int option_index = 0;
167
168         while((r = getopt_long(argc, argv, "+c:n:", long_options, &option_index)) != EOF) {
169                 switch (r) {
170                         case 0:   /* long option */
171                                 break;
172
173                         case 'b':
174                                 tty = false;
175                                 break;
176
177                         case 'c': /* config file */
178                                 confbase = xstrdup(optarg);
179                                 confbasegiven = true;
180                                 break;
181
182                         case 'n': /* net name given */
183                                 netname = xstrdup(optarg);
184                                 break;
185
186                         case 1:   /* show help */
187                                 show_help = true;
188                                 break;
189
190                         case 2:   /* show version */
191                                 show_version = true;
192                                 break;
193
194                         case 3:   /* open control socket here */
195                                 pidfilename = xstrdup(optarg);
196                                 break;
197
198                         case 4:   /* force */
199                                 force = true;
200                                 break;
201
202                         case '?': /* wrong options */
203                                 usage(true);
204                                 return false;
205
206                         default:
207                                 break;
208                 }
209         }
210
211         if(!netname && (netname = getenv("NETNAME")))
212                 netname = xstrdup(netname);
213
214         /* netname "." is special: a "top-level name" */
215
216         if(netname && (!*netname || !strcmp(netname, "."))) {
217                 free(netname);
218                 netname = NULL;
219         }
220
221         if(netname && (strpbrk(netname, "\\/") || *netname == '.')) {
222                 fprintf(stderr, "Invalid character in netname!\n");
223                 return false;
224         }
225
226         return true;
227 }
228
229 /* Open a file with the desired permissions, minus the umask.
230    Also, if we want to create an executable file, we call fchmod()
231    to set the executable bits. */
232
233 FILE *fopenmask(const char *filename, const char *mode, mode_t perms) {
234         mode_t mask = umask(0);
235         perms &= ~mask;
236         umask(~perms);
237         FILE *f = fopen(filename, mode);
238
239         if(!f) {
240                 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
241                 return NULL;
242         }
243
244 #ifdef HAVE_FCHMOD
245         if((perms & 0444) && f)
246                 fchmod(fileno(f), perms);
247 #endif
248         umask(mask);
249         return f;
250 }
251
252 static void disable_old_keys(const char *filename, const char *what) {
253         char tmpfile[PATH_MAX] = "";
254         char buf[1024];
255         bool disabled = false;
256         bool block = false;
257         bool error = false;
258         FILE *r, *w;
259
260         r = fopen(filename, "r");
261         if(!r)
262                 return;
263
264         snprintf(tmpfile, sizeof tmpfile, "%s.tmp", filename);
265
266         struct stat st = {.st_mode = 0600};
267         fstat(fileno(r), &st);
268         w = fopenmask(tmpfile, "w", st.st_mode);
269
270         while(fgets(buf, sizeof buf, r)) {
271                 if(!block && !strncmp(buf, "-----BEGIN ", 11)) {
272                         if((strstr(buf, " ED25519 ") && strstr(what, "Ed25519")) || (strstr(buf, " RSA ") && strstr(what, "RSA"))) {
273                                 disabled = true;
274                                 block = true;
275                         }
276                 }
277
278                 bool ed25519pubkey = !strncasecmp(buf, "Ed25519PublicKey", 16) && strchr(" \t=", buf[16]) && strstr(what, "Ed25519");
279
280                 if(ed25519pubkey)
281                         disabled = true;
282
283                 if(w) {
284                         if(block || ed25519pubkey)
285                                 fputc('#', w);
286                         if(fputs(buf, w) < 0) {
287                                 error = true;
288                                 break;
289                         }
290                 }
291
292                 if(block && !strncmp(buf, "-----END ", 9))
293                         block = false;
294         }
295
296         if(w)
297                 if(fclose(w) < 0)
298                         error = true;
299         if(ferror(r) || fclose(r) < 0)
300                 error = true;
301
302         if(disabled) {
303                 if(!w || error) {
304                         fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
305                         if(w)
306                                 unlink(tmpfile);
307                         return;
308                 }
309
310 #ifdef HAVE_MINGW
311                 // We cannot atomically replace files on Windows.
312                 char bakfile[PATH_MAX] = "";
313                 snprintf(bakfile, sizeof bakfile, "%s.bak", filename);
314                 if(rename(filename, bakfile) || rename(tmpfile, filename)) {
315                         rename(bakfile, filename);
316 #else
317                 if(rename(tmpfile, filename)) {
318 #endif
319                         fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
320                 } else  {
321 #ifdef HAVE_MINGW
322                         unlink(bakfile);
323 #endif
324                         fprintf(stderr, "Warning: old key(s) found and disabled.\n");
325                 }
326         }
327
328         unlink(tmpfile);
329 }
330
331 static FILE *ask_and_open(const char *filename, const char *what, const char *mode, bool ask, mode_t perms) {
332         FILE *r;
333         char *directory;
334         char buf[PATH_MAX];
335         char buf2[PATH_MAX];
336
337         /* Check stdin and stdout */
338         if(ask && tty) {
339                 /* Ask for a file and/or directory name. */
340                 fprintf(stderr, "Please enter a file to save %s to [%s]: ", what, filename);
341
342                 if(fgets(buf, sizeof buf, stdin) == NULL) {
343                         fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
344                         return NULL;
345                 }
346
347                 size_t len = strlen(buf);
348                 if(len)
349                         buf[--len] = 0;
350
351                 if(len)
352                         filename = buf;
353         }
354
355 #ifdef HAVE_MINGW
356         if(filename[0] != '\\' && filename[0] != '/' && !strchr(filename, ':')) {
357 #else
358         if(filename[0] != '/') {
359 #endif
360                 /* The directory is a relative path or a filename. */
361                 directory = get_current_dir_name();
362                 snprintf(buf2, sizeof buf2, "%s" SLASH "%s", directory, filename);
363                 filename = buf2;
364         }
365
366         disable_old_keys(filename, what);
367
368         /* Open it first to keep the inode busy */
369
370         r = fopenmask(filename, mode, perms);
371
372         if(!r) {
373                 fprintf(stderr, "Error opening file `%s': %s\n", filename, strerror(errno));
374                 return NULL;
375         }
376
377         return r;
378 }
379
380 /*
381   Generate a public/private Ed25519 keypair, and ask for a file to store
382   them in.
383 */
384 static bool ed25519_keygen(bool ask) {
385         ecdsa_t *key;
386         FILE *f;
387         char fname[PATH_MAX];
388
389         fprintf(stderr, "Generating Ed25519 keypair:\n");
390
391         if(!(key = ecdsa_generate())) {
392                 fprintf(stderr, "Error during key generation!\n");
393                 return false;
394         } else
395                 fprintf(stderr, "Done.\n");
396
397         snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase);
398         f = ask_and_open(fname, "private Ed25519 key", "a", ask, 0600);
399
400         if(!f)
401                 goto error;
402
403         if(!ecdsa_write_pem_private_key(key, f)) {
404                 fprintf(stderr, "Error writing private key!\n");
405                 goto error;
406         }
407
408         fclose(f);
409
410         if(name)
411                 snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
412         else
413                 snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.pub", confbase);
414
415         f = ask_and_open(fname, "public Ed25519 key", "a", ask, 0666);
416
417         if(!f)
418                 return false;
419
420         char *pubkey = ecdsa_get_base64_public_key(key);
421         fprintf(f, "Ed25519PublicKey = %s\n", pubkey);
422         free(pubkey);
423
424         fclose(f);
425         ecdsa_free(key);
426
427         return true;
428
429 error:
430         if(f)
431                 fclose(f);
432         ecdsa_free(key);
433         return false;
434 }
435
436 #ifndef DISABLE_LEGACY
437 /*
438   Generate a public/private RSA keypair, and ask for a file to store
439   them in.
440 */
441 static bool rsa_keygen(int bits, bool ask) {
442         rsa_t *key;
443         FILE *f;
444         char fname[PATH_MAX];
445
446         // Make sure the key size is a multiple of 8 bits.
447         bits &= ~0x7;
448
449         // Force them to be between 1024 and 8192 bits long.
450         if(bits < 1024)
451                 bits = 1024;
452         if(bits > 8192)
453                 bits = 8192;
454
455         fprintf(stderr, "Generating %d bits keys:\n", bits);
456
457         if(!(key = rsa_generate(bits, 0x10001))) {
458                 fprintf(stderr, "Error during key generation!\n");
459                 return false;
460         } else
461                 fprintf(stderr, "Done.\n");
462
463         snprintf(fname, sizeof fname, "%s" SLASH "rsa_key.priv", confbase);
464         f = ask_and_open(fname, "private RSA key", "a", ask, 0600);
465
466         if(!f)
467                 goto error;
468
469         if(!rsa_write_pem_private_key(key, f)) {
470                 fprintf(stderr, "Error writing private key!\n");
471                 goto error;
472         }
473
474         fclose(f);
475
476         if(name)
477                 snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, name);
478         else
479                 snprintf(fname, sizeof fname, "%s" SLASH "rsa_key.pub", confbase);
480
481         f = ask_and_open(fname, "public RSA key", "a", ask, 0666);
482
483         if(!f)
484                 goto error;
485
486         if(!rsa_write_pem_public_key(key, f)) {
487                 fprintf(stderr, "Error writing public key!\n");
488                 goto error;
489         }
490
491         fclose(f);
492         rsa_free(key);
493
494         return true;
495
496 error:
497         if(f)
498                 fclose(f);
499         rsa_free(key);
500         return false;
501 }
502 #endif
503
504 char buffer[4096];
505 size_t blen = 0;
506
507 bool recvline(int fd, char *line, size_t len) {
508         char *newline = NULL;
509
510         if(!fd)
511                 abort();
512
513         while(!(newline = memchr(buffer, '\n', blen))) {
514                 int result = recv(fd, buffer + blen, sizeof buffer - blen, 0);
515                 if(result == -1 && sockerrno == EINTR)
516                         continue;
517                 else if(result <= 0)
518                         return false;
519                 blen += result;
520         }
521
522         if(newline - buffer >= len)
523                 return false;
524
525         len = newline - buffer;
526
527         memcpy(line, buffer, len);
528         line[len] = 0;
529         memmove(buffer, newline + 1, blen - len - 1);
530         blen -= len + 1;
531
532         return true;
533 }
534
535 bool recvdata(int fd, char *data, size_t len) {
536         if(len == -1)
537                 len = blen;
538
539         while(blen < len) {
540                 int result = recv(fd, buffer + blen, sizeof buffer - blen, 0);
541                 if(result == -1 && sockerrno == EINTR)
542                         continue;
543                 else if(result <= 0)
544                         return false;
545                 blen += result;
546         }
547
548         memcpy(data, buffer, len);
549         memmove(buffer, buffer + len, blen - len);
550         blen -= len;
551
552         return true;
553 }
554
555 bool sendline(int fd, char *format, ...) {
556         static char buffer[4096];
557         char *p = buffer;
558         int blen = 0;
559         va_list ap;
560
561         va_start(ap, format);
562         blen = vsnprintf(buffer, sizeof buffer, format, ap);
563         va_end(ap);
564
565         if(blen < 1 || blen >= sizeof buffer)
566                 return false;
567
568         buffer[blen] = '\n';
569         blen++;
570
571         while(blen) {
572                 int result = send(fd, p, blen, MSG_NOSIGNAL);
573                 if(result == -1 && sockerrno == EINTR)
574                         continue;
575                 else if(result <= 0)
576                         return false;
577                 p += result;
578                 blen -= result;
579         }
580
581         return true;
582 }
583
584 static void pcap(int fd, FILE *out, int snaplen) {
585         sendline(fd, "%d %d %d", CONTROL, REQ_PCAP, snaplen);
586         char data[9018];
587
588         struct {
589                 uint32_t magic;
590                 uint16_t major;
591                 uint16_t minor;
592                 uint32_t tz_offset;
593                 uint32_t tz_accuracy;
594                 uint32_t snaplen;
595                 uint32_t ll_type;
596         } header = {
597                 0xa1b2c3d4,
598                 2, 4,
599                 0, 0,
600                 snaplen ?: sizeof data,
601                 1,
602         };
603
604         struct {
605                 uint32_t tv_sec;
606                 uint32_t tv_usec;
607                 uint32_t len;
608                 uint32_t origlen;
609         } packet;
610
611         struct timeval tv;
612
613         fwrite(&header, sizeof header, 1, out);
614         fflush(out);
615
616         char line[32];
617         while(recvline(fd, line, sizeof line)) {
618                 int code, req, len;
619                 int n = sscanf(line, "%d %d %d", &code, &req, &len);
620                 gettimeofday(&tv, NULL);
621                 if(n != 3 || code != CONTROL || req != REQ_PCAP || len < 0 || len > sizeof data)
622                         break;
623                 if(!recvdata(fd, data, len))
624                         break;
625                 packet.tv_sec = tv.tv_sec;
626                 packet.tv_usec = tv.tv_usec;
627                 packet.len = len;
628                 packet.origlen = len;
629                 fwrite(&packet, sizeof packet, 1, out);
630                 fwrite(data, len, 1, out);
631                 fflush(out);
632         }
633 }
634
635 static void logcontrol(int fd, FILE *out, int level) {
636         sendline(fd, "%d %d %d", CONTROL, REQ_LOG, level);
637         char data[1024];
638         char line[32];
639
640         while(recvline(fd, line, sizeof line)) {
641                 int code, req, len;
642                 int n = sscanf(line, "%d %d %d", &code, &req, &len);
643                 if(n != 3 || code != CONTROL || req != REQ_LOG || len < 0 || len > sizeof data)
644                         break;
645                 if(!recvdata(fd, data, len))
646                         break;
647                 fwrite(data, len, 1, out);
648                 fputc('\n', out);
649                 fflush(out);
650         }
651 }
652
653 #ifdef HAVE_MINGW
654 static bool remove_service(void) {
655         SC_HANDLE manager = NULL;
656         SC_HANDLE service = NULL;
657         SERVICE_STATUS status = {0};
658
659         manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
660         if(!manager) {
661                 fprintf(stderr, "Could not open service manager: %s\n", winerror(GetLastError()));
662                 return false;
663         }
664
665         service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
666
667         if(!service) {
668                 fprintf(stderr, "Could not open %s service: %s\n", identname, winerror(GetLastError()));
669                 return false;
670         }
671
672         if(!ControlService(service, SERVICE_CONTROL_STOP, &status))
673                 fprintf(stderr, "Could not stop %s service: %s\n", identname, winerror(GetLastError()));
674         else
675                 fprintf(stderr, "%s service stopped\n", identname);
676
677         if(!DeleteService(service)) {
678                 fprintf(stderr, "Could not remove %s service: %s\n", identname, winerror(GetLastError()));
679                 return false;
680         }
681
682         fprintf(stderr, "%s service removed\n", identname);
683
684         return true;
685 }
686 #endif
687
688 bool connect_tincd(bool verbose) {
689         if(fd >= 0) {
690                 fd_set r;
691                 FD_ZERO(&r);
692                 FD_SET(fd, &r);
693                 struct timeval tv = {0, 0};
694                 if(select(fd + 1, &r, NULL, NULL, &tv)) {
695                         fprintf(stderr, "Previous connection to tincd lost, reconnecting.\n");
696                         close(fd);
697                         fd = -1;
698                 } else {
699                         return true;
700                 }
701         }
702
703         FILE *f = fopen(pidfilename, "r");
704         if(!f) {
705                 if(verbose)
706                         fprintf(stderr, "Could not open pid file %s: %s\n", pidfilename, strerror(errno));
707                 return false;
708         }
709
710         char host[129];
711         char port[129];
712
713         if(fscanf(f, "%20d %1024s %128s port %128s", &pid, controlcookie, host, port) != 4) {
714                 if(verbose)
715                         fprintf(stderr, "Could not parse pid file %s\n", pidfilename);
716                 fclose(f);
717                 return false;
718         }
719
720         fclose(f);
721
722 #ifndef HAVE_MINGW
723         struct sockaddr_un sa;
724         sa.sun_family = AF_UNIX;
725         strncpy(sa.sun_path, unixsocketname, sizeof sa.sun_path);
726
727         fd = socket(AF_UNIX, SOCK_STREAM, 0);
728         if(fd < 0) {
729                 if(verbose)
730                         fprintf(stderr, "Cannot create UNIX socket: %s\n", sockstrerror(sockerrno));
731                 return false;
732         }
733
734         if(connect(fd, (struct sockaddr *)&sa, sizeof sa) < 0) {
735                 if(verbose)
736                         fprintf(stderr, "Cannot connect to UNIX socket %s: %s\n", unixsocketname, sockstrerror(sockerrno));
737                 close(fd);
738                 fd = -1;
739                 return false;
740         }
741 #else
742         struct addrinfo hints = {
743                 .ai_family = AF_UNSPEC,
744                 .ai_socktype = SOCK_STREAM,
745                 .ai_protocol = IPPROTO_TCP,
746                 .ai_flags = 0,
747         };
748
749         struct addrinfo *res = NULL;
750
751         if(getaddrinfo(host, port, &hints, &res) || !res) {
752                 if(verbose)
753                         fprintf(stderr, "Cannot resolve %s port %s: %s", host, port, sockstrerror(sockerrno));
754                 return false;
755         }
756
757         fd = socket(res->ai_family, SOCK_STREAM, IPPROTO_TCP);
758         if(fd < 0) {
759                 if(verbose)
760                         fprintf(stderr, "Cannot create TCP socket: %s\n", sockstrerror(sockerrno));
761                 return false;
762         }
763
764 #ifdef HAVE_MINGW
765         unsigned long arg = 0;
766
767         if(ioctlsocket(fd, FIONBIO, &arg) != 0) {
768                 if(verbose)
769                         fprintf(stderr, "ioctlsocket failed: %s", sockstrerror(sockerrno));
770         }
771 #endif
772
773         if(connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
774                 if(verbose)
775                         fprintf(stderr, "Cannot connect to %s port %s: %s\n", host, port, sockstrerror(sockerrno));
776                 close(fd);
777                 fd = -1;
778                 return false;
779         }
780
781         freeaddrinfo(res);
782 #endif
783
784 #ifdef SO_NOSIGPIPE
785         static const int one = 1;
786         setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&one, sizeof one);
787 #endif
788
789         char data[4096];
790         int version;
791
792         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %s %d", &code, data, &version) != 3 || code != 0) {
793                 if(verbose)
794                         fprintf(stderr, "Cannot read greeting from control socket: %s\n", sockstrerror(sockerrno));
795                 close(fd);
796                 fd = -1;
797                 return false;
798         }
799
800         sendline(fd, "%d ^%s %d", ID, controlcookie, TINC_CTL_VERSION_CURRENT);
801
802         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &version, &pid) != 3 || code != 4 || version != TINC_CTL_VERSION_CURRENT) {
803                 if(verbose)
804                         fprintf(stderr, "Could not fully establish control socket connection\n");
805                 close(fd);
806                 fd = -1;
807                 return false;
808         }
809
810         return true;
811 }
812
813
814 static int cmd_start(int argc, char *argv[]) {
815         if(connect_tincd(false)) {
816                 if(netname)
817                         fprintf(stderr, "A tincd is already running for net `%s' with pid %d.\n", netname, pid);
818                 else
819                         fprintf(stderr, "A tincd is already running with pid %d.\n", pid);
820                 return 0;
821         }
822
823         char *c;
824         char *slash = strrchr(program_name, '/');
825
826 #ifdef HAVE_MINGW
827         if ((c = strrchr(program_name, '\\')) > slash)
828                 slash = c;
829 #endif
830
831         if (slash++)
832                 xasprintf(&c, "%.*stincd", (int)(slash - program_name), program_name);
833         else
834                 c = "tincd";
835
836         int nargc = 0;
837         char **nargv = xzalloc((optind + argc) * sizeof *nargv);
838
839         char *arg0 = c;
840 #ifdef HAVE_MINGW
841         /*
842            Windows has no real concept of an "argv array". A command line is just one string.
843            The CRT of the new process will decode the command line string to generate argv before calling main(), and (by convention)
844            it uses quotes to handle spaces in arguments.
845            Therefore we need to quote all arguments that might contain spaces. No, execvp() won't do that for us (see MSDN).
846            If we don't do that, then execvp() will run fine but any spaces in the filename contained in arg0 will bleed
847            into the next arguments when the spawned process' CRT parses its command line, resulting in chaos.
848         */
849         xasprintf(&arg0, "\"%s\"", arg0);
850 #endif
851         nargv[nargc++] = arg0;
852         for(int i = 1; i < optind; i++)
853                 nargv[nargc++] = orig_argv[i];
854         for(int i = 1; i < argc; i++)
855                 nargv[nargc++] = argv[i];
856
857 #ifdef HAVE_MINGW
858         int status = spawnvp(_P_WAIT, c, nargv);
859         if (status == -1) {
860                 fprintf(stderr, "Error starting %s: %s\n", c, strerror(errno));
861                 return 1;
862         }
863         return status;
864 #else
865         int pfd[2] = {-1, -1};
866         if(socketpair(AF_UNIX, SOCK_STREAM, 0, pfd)) {
867                 fprintf(stderr, "Could not create umbilical socket: %s\n", strerror(errno));
868                 free(nargv);
869                 return 1;
870         }
871
872         pid_t pid = fork();
873         if(pid == -1) {
874                 fprintf(stderr, "Could not fork: %s\n", strerror(errno));
875                 free(nargv);
876                 return 1;
877         }
878
879         if(!pid) {
880                 close(pfd[0]);
881                 char buf[100] = "";
882                 snprintf(buf, sizeof buf, "%d", pfd[1]);
883                 setenv("TINC_UMBILICAL", buf, true);
884                 exit(execvp(c, nargv));
885         } else {
886                 close(pfd[1]);
887         }
888
889         free(nargv);
890
891         int status = -1, result;
892 #ifdef SIGINT
893         signal(SIGINT, SIG_IGN);
894 #endif
895
896         // Pass all log messages from the umbilical to stderr.
897         // A nul-byte right before closure means tincd started succesfully.
898         bool failure = true;
899         char buf[1024];
900         ssize_t len;
901
902         while((len = read(pfd[0], buf, sizeof buf)) > 0) {
903                 failure = buf[len - 1];
904                 if(!failure)
905                         len--;
906                 write(2, buf, len);
907         }
908
909         if(len)
910                 failure = true;
911
912         close(pfd[0]);
913
914         // Make sure the child process is really gone.
915         result = waitpid(pid, &status, 0);
916
917 #ifdef SIGINT
918         signal(SIGINT, SIG_DFL);
919 #endif
920
921         if(failure || result != pid || !WIFEXITED(status) || WEXITSTATUS(status)) {
922                 fprintf(stderr, "Error starting %s\n", c);
923                 return 1;
924         }
925
926         return 0;
927 #endif
928 }
929
930 static int cmd_stop(int argc, char *argv[]) {
931         if(argc > 1) {
932                 fprintf(stderr, "Too many arguments!\n");
933                 return 1;
934         }
935
936 #ifndef HAVE_MINGW
937         if(!connect_tincd(true)) {
938                 if(pid) {
939                         if(kill(pid, SIGTERM)) {
940                                 fprintf(stderr, "Could not send TERM signal to process with PID %u: %s\n", pid, strerror(errno));
941                                 return 1;
942                         }
943
944                         fprintf(stderr, "Sent TERM signal to process with PID %u.\n", pid);
945                         waitpid(pid, NULL, 0);
946                         return 0;
947                 }
948
949                 return 1;
950         }
951
952         sendline(fd, "%d %d", CONTROL, REQ_STOP);
953
954         while(recvline(fd, line, sizeof line)) {
955                 // Wait for tincd to close the connection...
956         }
957 #else
958         if(!remove_service())
959                 return 1;
960 #endif
961         close(fd);
962         pid = 0;
963         fd = -1;
964
965         return 0;
966 }
967
968 static int cmd_restart(int argc, char *argv[]) {
969         cmd_stop(1, argv);
970         return cmd_start(argc, argv);
971 }
972
973 static int cmd_reload(int argc, char *argv[]) {
974         if(argc > 1) {
975                 fprintf(stderr, "Too many arguments!\n");
976                 return 1;
977         }
978
979         if(!connect_tincd(true))
980                 return 1;
981
982         sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
983         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_RELOAD || result) {
984                 fprintf(stderr, "Could not reload configuration.\n");
985                 return 1;
986         }
987
988         return 0;
989
990 }
991
992 static int dump_invitations(void) {
993         char dname[PATH_MAX];
994         snprintf(dname, sizeof dname, "%s" SLASH "invitations", confbase);
995         DIR *dir = opendir(dname);
996         if(!dir) {
997                 if(errno == ENOENT) {
998                         fprintf(stderr, "No outstanding invitations.\n");
999                         return 0;
1000                 }
1001
1002                 fprintf(stderr, "Cannot not read directory %s: %s\n", dname, strerror(errno));
1003                 return 1;
1004         }
1005
1006         struct dirent *ent;
1007         bool found = false;
1008
1009         while((ent = readdir(dir))) {
1010                 char buf[MAX_STRING_SIZE];
1011                 if(b64decode(ent->d_name, buf, 24) != 18)
1012                         continue;
1013
1014                 char fname[PATH_MAX];
1015                 snprintf(fname, sizeof fname, "%s" SLASH "%s", dname, ent->d_name);
1016                 FILE *f = fopen(fname, "r");
1017                 if(!f) {
1018                         fprintf(stderr, "Cannot open %s: %s\n", fname, strerror(errno));
1019                         fclose(f);
1020                         continue;
1021                 }
1022
1023                 buf[0] = 0;
1024                 if(!fgets(buf, sizeof buf, f)) {
1025                         fprintf(stderr, "Invalid invitation file %s", fname);
1026                         fclose(f);
1027                         continue;
1028                 }
1029                 fclose(f);
1030
1031                 char *eol = buf + strlen(buf);
1032                 while(strchr("\t \r\n", *--eol))
1033                         *eol = 0;
1034                 if(strncmp(buf, "Name = ", 7) || !check_id(buf + 7)) {
1035                         fprintf(stderr, "Invalid invitation file %s", fname);
1036                         continue;
1037                 }
1038
1039                 found = true;
1040                 printf("%s %s\n", ent->d_name, buf + 7);
1041         }
1042
1043         closedir(dir);
1044
1045         if(!found)
1046                 fprintf(stderr, "No outstanding invitations.\n");
1047
1048         return 0;
1049 }
1050
1051 static int cmd_dump(int argc, char *argv[]) {
1052         bool only_reachable = false;
1053
1054         if(argc > 2 && !strcasecmp(argv[1], "reachable")) {
1055                 if(strcasecmp(argv[2], "nodes")) {
1056                         fprintf(stderr, "`reachable' only supported for nodes.\n");
1057                         usage(true);
1058                         return 1;
1059                 }
1060                 only_reachable = true;
1061                 argv++;
1062                 argc--;
1063         }
1064
1065         if(argc != 2) {
1066                 fprintf(stderr, "Invalid number of arguments.\n");
1067                 usage(true);
1068                 return 1;
1069         }
1070
1071         if(!strcasecmp(argv[1], "invitations"))
1072                 return dump_invitations();
1073
1074         if(!connect_tincd(true))
1075                 return 1;
1076
1077         int do_graph = 0;
1078
1079         if(!strcasecmp(argv[1], "nodes"))
1080                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
1081         else if(!strcasecmp(argv[1], "edges"))
1082                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_EDGES);
1083         else if(!strcasecmp(argv[1], "subnets"))
1084                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
1085         else if(!strcasecmp(argv[1], "connections"))
1086                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_CONNECTIONS);
1087         else if(!strcasecmp(argv[1], "graph")) {
1088                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
1089                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_EDGES);
1090                 do_graph = 1;
1091         } else if(!strcasecmp(argv[1], "digraph")) {
1092                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
1093                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_EDGES);
1094                 do_graph = 2;
1095         } else {
1096                 fprintf(stderr, "Unknown dump type '%s'.\n", argv[1]);
1097                 usage(true);
1098                 return 1;
1099         }
1100
1101         if(do_graph == 1)
1102                 printf("graph {\n");
1103         else if(do_graph == 2)
1104                 printf("digraph {\n");
1105
1106         while(recvline(fd, line, sizeof line)) {
1107                 char node1[4096], node2[4096];
1108                 int n = sscanf(line, "%d %d %s %s", &code, &req, node1, node2);
1109                 if(n == 2) {
1110                         if(do_graph && req == REQ_DUMP_NODES)
1111                                 continue;
1112                         else {
1113                                 if(do_graph)
1114                                         printf("}\n");
1115                                 return 0;
1116                         }
1117                 }
1118                 if(n < 2)
1119                         break;
1120
1121                 char node[4096];
1122                 char id[4096];
1123                 char from[4096];
1124                 char to[4096];
1125                 char subnet[4096];
1126                 char host[4096];
1127                 char port[4096];
1128                 char local_host[4096];
1129                 char local_port[4096];
1130                 char via[4096];
1131                 char nexthop[4096];
1132                 int cipher, digest, maclength, compression, distance, socket, weight;
1133                 short int pmtu, minmtu, maxmtu;
1134                 unsigned int options, status_int;
1135                 node_status_t status;
1136                 long int last_state_change;
1137
1138                 switch(req) {
1139                         case REQ_DUMP_NODES: {
1140                                 int n = sscanf(line, "%*d %*d %s %s %s port %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_int, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change);
1141                                 if(n != 17) {
1142                                         fprintf(stderr, "Unable to parse node dump from tincd: %s\n", line);
1143                                         return 1;
1144                                 }
1145
1146                                 memcpy(&status, &status_int, sizeof status);
1147
1148                                 if(do_graph) {
1149                                         const char *color = "black";
1150                                         if(!strcmp(host, "MYSELF"))
1151                                                 color = "green";
1152                                         else if(!status.reachable)
1153                                                 color = "red";
1154                                         else if(strcmp(via, node))
1155                                                 color = "orange";
1156                                         else if(!status.validkey)
1157                                                 color = "black";
1158                                         else if(minmtu > 0)
1159                                                 color = "green";
1160                                         printf(" %s [label = \"%s\", color = \"%s\"%s];\n", node, node, color, strcmp(host, "MYSELF") ? "" : ", style = \"filled\"");
1161                                 } else {
1162                                         if(only_reachable && !status.reachable)
1163                                                 continue;
1164                                         printf("%s id %s at %s port %s cipher %d digest %d maclength %d compression %d options %x status %04x nexthop %s via %s distance %d pmtu %hd (min %hd max %hd)\n",
1165                                                         node, id, host, port, cipher, digest, maclength, compression, options, status_int, nexthop, via, distance, pmtu, minmtu, maxmtu);
1166                                 }
1167                         } break;
1168
1169                         case REQ_DUMP_EDGES: {
1170                                 int n = sscanf(line, "%*d %*d %s %s %s port %s %s port %s %x %d", from, to, host, port, local_host, local_port, &options, &weight);
1171                                 if(n != 8) {
1172                                         fprintf(stderr, "Unable to parse edge dump from tincd.\n");
1173                                         return 1;
1174                                 }
1175
1176                                 if(do_graph) {
1177                                         float w = 1 + 65536.0 / weight;
1178                                         if(do_graph == 1 && strcmp(node1, node2) > 0)
1179                                                 printf(" %s -- %s [w = %f, weight = %f];\n", node1, node2, w, w);
1180                                         else if(do_graph == 2)
1181                                                 printf(" %s -> %s [w = %f, weight = %f];\n", node1, node2, w, w);
1182                                 } else {
1183                                         printf("%s to %s at %s port %s local %s port %s options %x weight %d\n", from, to, host, port, local_host, local_port, options, weight);
1184                                 }
1185                         } break;
1186
1187                         case REQ_DUMP_SUBNETS: {
1188                                 int n = sscanf(line, "%*d %*d %s %s", subnet, node);
1189                                 if(n != 2) {
1190                                         fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
1191                                         return 1;
1192                                 }
1193                                 printf("%s owner %s\n", strip_weight(subnet), node);
1194                         } break;
1195
1196                         case REQ_DUMP_CONNECTIONS: {
1197                                 int n = sscanf(line, "%*d %*d %s %s port %s %x %d %x", node, host, port, &options, &socket, &status_int);
1198                                 if(n != 6) {
1199                                         fprintf(stderr, "Unable to parse connection dump from tincd.\n");
1200                                         return 1;
1201                                 }
1202                                 printf("%s at %s port %s options %x socket %d status %x\n", node, host, port, options, socket, status_int);
1203                         } break;
1204
1205                         default:
1206                                 fprintf(stderr, "Unable to parse dump from tincd.\n");
1207                                 return 1;
1208                 }
1209         }
1210
1211         fprintf(stderr, "Error receiving dump.\n");
1212         return 1;
1213 }
1214
1215 static int cmd_purge(int argc, char *argv[]) {
1216         if(argc > 1) {
1217                 fprintf(stderr, "Too many arguments!\n");
1218                 return 1;
1219         }
1220
1221         if(!connect_tincd(true))
1222                 return 1;
1223
1224         sendline(fd, "%d %d", CONTROL, REQ_PURGE);
1225         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_PURGE || result) {
1226                 fprintf(stderr, "Could not purge old information.\n");
1227                 return 1;
1228         }
1229
1230         return 0;
1231 }
1232
1233 static int cmd_debug(int argc, char *argv[]) {
1234         if(argc != 2) {
1235                 fprintf(stderr, "Invalid number of arguments.\n");
1236                 return 1;
1237         }
1238
1239         if(!connect_tincd(true))
1240                 return 1;
1241
1242         int debuglevel = atoi(argv[1]);
1243         int origlevel;
1244
1245         sendline(fd, "%d %d %d", CONTROL, REQ_SET_DEBUG, debuglevel);
1246         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &origlevel) != 3 || code != CONTROL || req != REQ_SET_DEBUG) {
1247                 fprintf(stderr, "Could not set debug level.\n");
1248                 return 1;
1249         }
1250
1251         fprintf(stderr, "Old level %d, new level %d.\n", origlevel, debuglevel);
1252         return 0;
1253 }
1254
1255 static int cmd_retry(int argc, char *argv[]) {
1256         if(argc > 1) {
1257                 fprintf(stderr, "Too many arguments!\n");
1258                 return 1;
1259         }
1260
1261         if(!connect_tincd(true))
1262                 return 1;
1263
1264         sendline(fd, "%d %d", CONTROL, REQ_RETRY);
1265         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_RETRY || result) {
1266                 fprintf(stderr, "Could not retry outgoing connections.\n");
1267                 return 1;
1268         }
1269
1270         return 0;
1271 }
1272
1273 static int cmd_connect(int argc, char *argv[]) {
1274         if(argc != 2) {
1275                 fprintf(stderr, "Invalid number of arguments.\n");
1276                 return 1;
1277         }
1278
1279         if(!check_id(argv[1])) {
1280                 fprintf(stderr, "Invalid name for node.\n");
1281                 return 1;
1282         }
1283
1284         if(!connect_tincd(true))
1285                 return 1;
1286
1287         sendline(fd, "%d %d %s", CONTROL, REQ_CONNECT, argv[1]);
1288         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_CONNECT || result) {
1289                 fprintf(stderr, "Could not connect to %s.\n", argv[1]);
1290                 return 1;
1291         }
1292
1293         return 0;
1294 }
1295
1296 static int cmd_disconnect(int argc, char *argv[]) {
1297         if(argc != 2) {
1298                 fprintf(stderr, "Invalid number of arguments.\n");
1299                 return 1;
1300         }
1301
1302         if(!check_id(argv[1])) {
1303                 fprintf(stderr, "Invalid name for node.\n");
1304                 return 1;
1305         }
1306
1307         if(!connect_tincd(true))
1308                 return 1;
1309
1310         sendline(fd, "%d %d %s", CONTROL, REQ_DISCONNECT, argv[1]);
1311         if(!recvline(fd, line, sizeof line) || sscanf(line, "%d %d %d", &code, &req, &result) != 3 || code != CONTROL || req != REQ_DISCONNECT || result) {
1312                 fprintf(stderr, "Could not disconnect %s.\n", argv[1]);
1313                 return 1;
1314         }
1315
1316         return 0;
1317 }
1318
1319 static int cmd_top(int argc, char *argv[]) {
1320         if(argc > 1) {
1321                 fprintf(stderr, "Too many arguments!\n");
1322                 return 1;
1323         }
1324
1325 #ifdef HAVE_CURSES
1326         if(!connect_tincd(true))
1327                 return 1;
1328
1329         top(fd);
1330         return 0;
1331 #else
1332         fprintf(stderr, "This version of tinc was compiled without support for the curses library.\n");
1333         return 1;
1334 #endif
1335 }
1336
1337 static int cmd_pcap(int argc, char *argv[]) {
1338         if(argc > 2) {
1339                 fprintf(stderr, "Too many arguments!\n");
1340                 return 1;
1341         }
1342
1343         if(!connect_tincd(true))
1344                 return 1;
1345
1346         pcap(fd, stdout, argc > 1 ? atoi(argv[1]) : 0);
1347         return 0;
1348 }
1349
1350 #ifdef SIGINT
1351 static void sigint_handler(int sig) {
1352         fprintf(stderr, "\n");
1353         shutdown(fd, SHUT_RDWR);
1354 }
1355 #endif
1356
1357 static int cmd_log(int argc, char *argv[]) {
1358         if(argc > 2) {
1359                 fprintf(stderr, "Too many arguments!\n");
1360                 return 1;
1361         }
1362
1363         if(!connect_tincd(true))
1364                 return 1;
1365
1366 #ifdef SIGINT
1367         signal(SIGINT, sigint_handler);
1368 #endif
1369
1370         logcontrol(fd, stdout, argc > 1 ? atoi(argv[1]) : -1);
1371
1372 #ifdef SIGINT
1373         signal(SIGINT, SIG_DFL);
1374 #endif
1375
1376         close(fd);
1377         fd = -1;
1378         return 0;
1379 }
1380
1381 static int cmd_pid(int argc, char *argv[]) {
1382         if(argc > 1) {
1383                 fprintf(stderr, "Too many arguments!\n");
1384                 return 1;
1385         }
1386
1387         if(!connect_tincd(true) && !pid)
1388                 return 1;
1389
1390         printf("%d\n", pid);
1391         return 0;
1392 }
1393
1394 int rstrip(char *value) {
1395         int len = strlen(value);
1396         while(len && strchr("\t\r\n ", value[len - 1]))
1397                 value[--len] = 0;
1398         return len;
1399 }
1400
1401 char *get_my_name(bool verbose) {
1402         FILE *f = fopen(tinc_conf, "r");
1403         if(!f) {
1404                 if(verbose)
1405                         fprintf(stderr, "Could not open %s: %s\n", tinc_conf, strerror(errno));
1406                 return NULL;
1407         }
1408
1409         char buf[4096];
1410         char *value;
1411         while(fgets(buf, sizeof buf, f)) {
1412                 int len = strcspn(buf, "\t =");
1413                 value = buf + len;
1414                 value += strspn(value, "\t ");
1415                 if(*value == '=') {
1416                         value++;
1417                         value += strspn(value, "\t ");
1418                 }
1419                 if(!rstrip(value))
1420                         continue;
1421                 buf[len] = 0;
1422                 if(strcasecmp(buf, "Name"))
1423                         continue;
1424                 if(*value) {
1425                         fclose(f);
1426                         return replace_name(value);
1427                 }
1428         }
1429
1430         fclose(f);
1431         if(verbose)
1432                 fprintf(stderr, "Could not find Name in %s.\n", tinc_conf);
1433         return NULL;
1434 }
1435
1436 static ecdsa_t *get_pubkey(FILE *f) {
1437         char buf[4096];
1438         char *value;
1439         while(fgets(buf, sizeof buf, f)) {
1440                 int len = strcspn(buf, "\t =");
1441                 value = buf + len;
1442                 value += strspn(value, "\t ");
1443                 if(*value == '=') {
1444                         value++;
1445                         value += strspn(value, "\t ");
1446                 }
1447                 if(!rstrip(value))
1448                         continue;
1449                 buf[len] = 0;
1450                 if(strcasecmp(buf, "Ed25519PublicKey"))
1451                         continue;
1452                 if(*value)
1453                         return ecdsa_set_base64_public_key(value);
1454         }
1455
1456         return NULL;
1457 }
1458
1459 const var_t variables[] = {
1460         /* Server configuration */
1461         {"AddressFamily", VAR_SERVER},
1462         {"AutoConnect", VAR_SERVER | VAR_SAFE},
1463         {"BindToAddress", VAR_SERVER | VAR_MULTIPLE},
1464         {"BindToInterface", VAR_SERVER},
1465         {"Broadcast", VAR_SERVER | VAR_SAFE},
1466         {"BroadcastSubnet", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
1467         {"ConnectTo", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
1468         {"DecrementTTL", VAR_SERVER},
1469         {"Device", VAR_SERVER},
1470         {"DeviceStandby", VAR_SERVER},
1471         {"DeviceType", VAR_SERVER},
1472         {"DirectOnly", VAR_SERVER},
1473         {"Ed25519PrivateKeyFile", VAR_SERVER},
1474         {"ExperimentalProtocol", VAR_SERVER},
1475         {"Forwarding", VAR_SERVER},
1476         {"GraphDumpFile", VAR_SERVER | VAR_OBSOLETE},
1477         {"Hostnames", VAR_SERVER},
1478         {"IffOneQueue", VAR_SERVER},
1479         {"Interface", VAR_SERVER},
1480         {"KeyExpire", VAR_SERVER},
1481         {"ListenAddress", VAR_SERVER | VAR_MULTIPLE},
1482         {"LocalDiscovery", VAR_SERVER},
1483         {"MACExpire", VAR_SERVER},
1484         {"MaxConnectionBurst", VAR_SERVER},
1485         {"MaxOutputBufferSize", VAR_SERVER},
1486         {"MaxTimeout", VAR_SERVER},
1487         {"Mode", VAR_SERVER | VAR_SAFE},
1488         {"Name", VAR_SERVER},
1489         {"PingInterval", VAR_SERVER},
1490         {"PingTimeout", VAR_SERVER},
1491         {"PriorityInheritance", VAR_SERVER},
1492         {"PrivateKey", VAR_SERVER | VAR_OBSOLETE},
1493         {"PrivateKeyFile", VAR_SERVER},
1494         {"ProcessPriority", VAR_SERVER},
1495         {"Proxy", VAR_SERVER},
1496         {"ReplayWindow", VAR_SERVER},
1497         {"ScriptsExtension", VAR_SERVER},
1498         {"ScriptsInterpreter", VAR_SERVER},
1499         {"StrictSubnets", VAR_SERVER},
1500         {"TunnelServer", VAR_SERVER},
1501         {"UDPDiscovery", VAR_SERVER},
1502         {"UDPDiscoveryKeepaliveInterval", VAR_SERVER},
1503         {"UDPDiscoveryInterval", VAR_SERVER},
1504         {"UDPDiscoveryTimeout", VAR_SERVER},
1505         {"MTUInfoInterval", VAR_SERVER},
1506         {"UDPInfoInterval", VAR_SERVER},
1507         {"UDPRcvBuf", VAR_SERVER},
1508         {"UDPSndBuf", VAR_SERVER},
1509         {"UPnP", VAR_SERVER},
1510         {"UPnPDiscoverWait", VAR_SERVER},
1511         {"UPnPRefreshPeriod", VAR_SERVER},
1512         {"VDEGroup", VAR_SERVER},
1513         {"VDEPort", VAR_SERVER},
1514         /* Host configuration */
1515         {"Address", VAR_HOST | VAR_MULTIPLE},
1516         {"Cipher", VAR_SERVER | VAR_HOST},
1517         {"ClampMSS", VAR_SERVER | VAR_HOST},
1518         {"Compression", VAR_SERVER | VAR_HOST},
1519         {"Digest", VAR_SERVER | VAR_HOST},
1520         {"Ed25519PublicKey", VAR_HOST},
1521         {"Ed25519PublicKeyFile", VAR_SERVER | VAR_HOST},
1522         {"IndirectData", VAR_SERVER | VAR_HOST},
1523         {"MACLength", VAR_SERVER | VAR_HOST},
1524         {"PMTU", VAR_SERVER | VAR_HOST},
1525         {"PMTUDiscovery", VAR_SERVER | VAR_HOST},
1526         {"Port", VAR_HOST},
1527         {"PublicKey", VAR_HOST | VAR_OBSOLETE},
1528         {"PublicKeyFile", VAR_SERVER | VAR_HOST | VAR_OBSOLETE},
1529         {"Subnet", VAR_HOST | VAR_MULTIPLE | VAR_SAFE},
1530         {"TCPOnly", VAR_SERVER | VAR_HOST},
1531         {"Weight", VAR_HOST | VAR_SAFE},
1532         {NULL, 0}
1533 };
1534
1535 static int cmd_config(int argc, char *argv[]) {
1536         if(argc < 2) {
1537                 fprintf(stderr, "Invalid number of arguments.\n");
1538                 return 1;
1539         }
1540
1541         if(strcasecmp(argv[0], "config"))
1542                 argv--, argc++;
1543
1544         int action = -2;
1545         if(!strcasecmp(argv[1], "get")) {
1546                 argv++, argc--;
1547         } else if(!strcasecmp(argv[1], "add")) {
1548                 argv++, argc--, action = 1;
1549         } else if(!strcasecmp(argv[1], "del")) {
1550                 argv++, argc--, action = -1;
1551         } else if(!strcasecmp(argv[1], "replace") || !strcasecmp(argv[1], "set") || !strcasecmp(argv[1], "change")) {
1552                 argv++, argc--, action = 0;
1553         }
1554
1555         if(argc < 2) {
1556                 fprintf(stderr, "Invalid number of arguments.\n");
1557                 return 1;
1558         }
1559
1560         // Concatenate the rest of the command line
1561         strncpy(line, argv[1], sizeof line - 1);
1562         for(int i = 2; i < argc; i++) {
1563                 strncat(line, " ", sizeof line - 1 - strlen(line));
1564                 strncat(line, argv[i], sizeof line - 1 - strlen(line));
1565         }
1566
1567         // Liberal parsing into node name, variable name and value.
1568         char *node = NULL;
1569         char *variable;
1570         char *value;
1571         int len;
1572
1573         len = strcspn(line, "\t =");
1574         value = line + len;
1575         value += strspn(value, "\t ");
1576         if(*value == '=') {
1577                 value++;
1578                 value += strspn(value, "\t ");
1579         }
1580         line[len] = '\0';
1581         variable = strchr(line, '.');
1582         if(variable) {
1583                 node = line;
1584                 *variable++ = 0;
1585         } else {
1586                 variable = line;
1587         }
1588
1589         if(!*variable) {
1590                 fprintf(stderr, "No variable given.\n");
1591                 return 1;
1592         }
1593
1594         if(action >= 0 && !*value) {
1595                 fprintf(stderr, "No value for variable given.\n");
1596                 return 1;
1597         }
1598
1599         if(action < -1 && *value)
1600                 action = 0;
1601
1602         /* Some simple checks. */
1603         bool found = false;
1604         bool warnonremove = false;
1605
1606         for(int i = 0; variables[i].name; i++) {
1607                 if(strcasecmp(variables[i].name, variable))
1608                         continue;
1609
1610                 found = true;
1611                 variable = (char *)variables[i].name;
1612
1613                 /* Discourage use of obsolete variables. */
1614
1615                 if(variables[i].type & VAR_OBSOLETE && action >= 0) {
1616                         if(force) {
1617                                 fprintf(stderr, "Warning: %s is an obsolete variable!\n", variable);
1618                         } else {
1619                                 fprintf(stderr, "%s is an obsolete variable! Use --force to use it anyway.\n", variable);
1620                                 return 1;
1621                         }
1622                 }
1623
1624                 /* Don't put server variables in host config files */
1625
1626                 if(node && !(variables[i].type & VAR_HOST) && action >= 0) {
1627                         if(force) {
1628                                 fprintf(stderr, "Warning: %s is not a host configuration variable!\n", variable);
1629                         } else {
1630                                 fprintf(stderr, "%s is not a host configuration variable! Use --force to use it anyway.\n", variable);
1631                                 return 1;
1632                         }
1633                 }
1634
1635                 /* Should this go into our own host config file? */
1636
1637                 if(!node && !(variables[i].type & VAR_SERVER)) {
1638                         node = get_my_name(true);
1639                         if(!node)
1640                                 return 1;
1641                 }
1642
1643                 /* Change "add" into "set" for variables that do not allow multiple occurences.
1644                    Turn on warnings when it seems variables might be removed unintentionally. */
1645
1646                 if(action == 1 && !(variables[i].type & VAR_MULTIPLE)) {
1647                         warnonremove = true;
1648                         action = 0;
1649                 } else if(action == 0 && (variables[i].type & VAR_MULTIPLE)) {
1650                         warnonremove = true;
1651                 }
1652
1653                 break;
1654         }
1655
1656         if(node && !check_id(node)) {
1657                 fprintf(stderr, "Invalid name for node.\n");
1658                 return 1;
1659         }
1660
1661         if(!found) {
1662                 if(force || action < 0) {
1663                         fprintf(stderr, "Warning: %s is not a known configuration variable!\n", variable);
1664                 } else {
1665                         fprintf(stderr, "%s: is not a known configuration variable! Use --force to use it anyway.\n", variable);
1666                         return 1;
1667                 }
1668         }
1669
1670         // Open the right configuration file.
1671         char filename[PATH_MAX];
1672         if(node)
1673                 snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, node);
1674         else
1675                 snprintf(filename, sizeof filename, "%s", tinc_conf);
1676
1677         FILE *f = fopen(filename, "r");
1678         if(!f) {
1679                 fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
1680                 return 1;
1681         }
1682
1683         char tmpfile[PATH_MAX];
1684         FILE *tf = NULL;
1685
1686         if(action >= -1) {
1687                 snprintf(tmpfile, sizeof tmpfile, "%s.config.tmp", filename);
1688                 tf = fopen(tmpfile, "w");
1689                 if(!tf) {
1690                         fprintf(stderr, "Could not open temporary file %s: %s\n", tmpfile, strerror(errno));
1691                         fclose(f);
1692                         return 1;
1693                 }
1694         }
1695
1696         // Copy the file, making modifications on the fly, unless we are just getting a value.
1697         char buf1[4096];
1698         char buf2[4096];
1699         bool set = false;
1700         bool removed = false;
1701         found = false;
1702
1703         while(fgets(buf1, sizeof buf1, f)) {
1704                 buf1[sizeof buf1 - 1] = 0;
1705                 strncpy(buf2, buf1, sizeof buf2);
1706
1707                 // Parse line in a simple way
1708                 char *bvalue;
1709                 int len;
1710
1711                 len = strcspn(buf2, "\t =");
1712                 bvalue = buf2 + len;
1713                 bvalue += strspn(bvalue, "\t ");
1714                 if(*bvalue == '=') {
1715                         bvalue++;
1716                         bvalue += strspn(bvalue, "\t ");
1717                 }
1718                 rstrip(bvalue);
1719                 buf2[len] = '\0';
1720
1721                 // Did it match?
1722                 if(!strcasecmp(buf2, variable)) {
1723                         // Get
1724                         if(action < -1) {
1725                                 found = true;
1726                                 printf("%s\n", bvalue);
1727                         // Del
1728                         } else if(action == -1) {
1729                                 if(!*value || !strcasecmp(bvalue, value)) {
1730                                         removed = true;
1731                                         continue;
1732                                 }
1733                         // Set
1734                         } else if(action == 0) {
1735                                 // Warn if "set" was used for variables that can occur multiple times
1736                                 if(warnonremove && strcasecmp(bvalue, value))
1737                                         fprintf(stderr, "Warning: removing %s = %s\n", variable, bvalue);
1738
1739                                 // Already set? Delete the rest...
1740                                 if(set)
1741                                         continue;
1742
1743                                 // Otherwise, replace.
1744                                 if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
1745                                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1746                                         return 1;
1747                                 }
1748                                 set = true;
1749                                 continue;
1750                         // Add
1751                         } else if(action > 0) {
1752                                 // Check if we've already seen this variable with the same value
1753                                 if(!strcasecmp(bvalue, value))
1754                                         found = true;
1755                         }
1756                 }
1757
1758                 if(action >= -1) {
1759                         // Copy original line...
1760                         if(fputs(buf1, tf) < 0) {
1761                                 fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1762                                 return 1;
1763                         }
1764
1765                         // Add newline if it is missing...
1766                         if(*buf1 && buf1[strlen(buf1) - 1] != '\n') {
1767                                 if(fputc('\n', tf) < 0) {
1768                                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1769                                         return 1;
1770                                 }
1771                         }
1772                 }
1773         }
1774
1775         // Make sure we read everything...
1776         if(ferror(f) || !feof(f)) {
1777                 fprintf(stderr, "Error while reading from configuration file %s: %s\n", filename, strerror(errno));
1778                 return 1;
1779         }
1780
1781         if(fclose(f)) {
1782                 fprintf(stderr, "Error closing configuration file %s: %s\n", filename, strerror(errno));
1783                 return 1;
1784         }
1785
1786         // Add new variable if necessary.
1787         if((action > 0 && !found)|| (action == 0 && !set)) {
1788                 if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
1789                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1790                         return 1;
1791                 }
1792         }
1793
1794         if(action < -1) {
1795                 if(found) {
1796                         return 0;
1797                 } else {
1798                         fprintf(stderr, "No matching configuration variables found.\n");
1799                         return 1;
1800                 }
1801         }
1802
1803         // Make sure we wrote everything...
1804         if(fclose(tf)) {
1805                 fprintf(stderr, "Error closing temporary file %s: %s\n", tmpfile, strerror(errno));
1806                 return 1;
1807         }
1808
1809         // Could we find what we had to remove?
1810         if(action < 0 && !removed) {
1811                 remove(tmpfile);
1812                 fprintf(stderr, "No configuration variables deleted.\n");
1813                 return 1;
1814         }
1815
1816         // Replace the configuration file with the new one
1817 #ifdef HAVE_MINGW
1818         if(remove(filename)) {
1819                 fprintf(stderr, "Error replacing file %s: %s\n", filename, strerror(errno));
1820                 return 1;
1821         }
1822 #endif
1823         if(rename(tmpfile, filename)) {
1824                 fprintf(stderr, "Error renaming temporary file %s to configuration file %s: %s\n", tmpfile, filename, strerror(errno));
1825                 return 1;
1826         }
1827
1828         // Silently try notifying a running tincd of changes.
1829         if(connect_tincd(false))
1830                 sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
1831
1832         return 0;
1833 }
1834
1835 static bool try_bind(int port) {
1836         struct addrinfo *ai = NULL, *aip;
1837         struct addrinfo hint = {
1838                 .ai_flags = AI_PASSIVE,
1839                 .ai_family = AF_UNSPEC,
1840                 .ai_socktype = SOCK_STREAM,
1841                 .ai_protocol = IPPROTO_TCP,
1842         };
1843
1844         bool success = true;
1845         char portstr[16];
1846         snprintf(portstr, sizeof portstr, "%d", port);
1847
1848         if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai)
1849                 return false;
1850
1851         for(aip = ai; aip; aip = aip->ai_next) {
1852                 int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
1853                 if(!fd) {
1854                         success = false;
1855                         break;
1856                 }
1857
1858                 int result = bind(fd, ai->ai_addr, ai->ai_addrlen);
1859                 closesocket(fd);
1860                 if(result) {
1861                         success = false;
1862                         break;
1863                 }
1864         }
1865
1866         freeaddrinfo(ai);
1867         return success;
1868 }
1869
1870 int check_port(char *name) {
1871         if(try_bind(655))
1872                 return 655;
1873
1874         fprintf(stderr, "Warning: could not bind to port 655. ");
1875
1876         for(int i = 0; i < 100; i++) {
1877                 int port = 0x1000 + (rand() & 0x7fff);
1878                 if(try_bind(port)) {
1879                         char filename[PATH_MAX];
1880                         snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
1881                         FILE *f = fopen(filename, "a");
1882                         if(!f) {
1883                                 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
1884                                 fprintf(stderr, "Please change tinc's Port manually.\n");
1885                                 return 0;
1886                         }
1887
1888                         fprintf(f, "Port = %d\n", port);
1889                         fclose(f);
1890                         fprintf(stderr, "Tinc will instead listen on port %d.\n", port);
1891                         return port;
1892                 }
1893         }
1894
1895         fprintf(stderr, "Please change tinc's Port manually.\n");
1896         return 0;
1897 }
1898
1899 static int cmd_init(int argc, char *argv[]) {
1900         if(!access(tinc_conf, F_OK)) {
1901                 fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
1902                 return 1;
1903         }
1904
1905         if(argc > 2) {
1906                 fprintf(stderr, "Too many arguments!\n");
1907                 return 1;
1908         } else if(argc < 2) {
1909                 if(tty) {
1910                         char buf[1024];
1911                         fprintf(stderr, "Enter the Name you want your tinc node to have: ");
1912                         if(!fgets(buf, sizeof buf, stdin)) {
1913                                 fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
1914                                 return 1;
1915                         }
1916                         int len = rstrip(buf);
1917                         if(!len) {
1918                                 fprintf(stderr, "No name given!\n");
1919                                 return 1;
1920                         }
1921                         name = strdup(buf);
1922                 } else {
1923                         fprintf(stderr, "No Name given!\n");
1924                         return 1;
1925                 }
1926         } else {
1927                 name = strdup(argv[1]);
1928                 if(!*name) {
1929                         fprintf(stderr, "No Name given!\n");
1930                         return 1;
1931                 }
1932         }
1933
1934         if(!check_id(name)) {
1935                 fprintf(stderr, "Invalid Name! Only a-z, A-Z, 0-9 and _ are allowed characters.\n");
1936                 return 1;
1937         }
1938
1939         if(!confbase_given && mkdir(confdir, 0755) && errno != EEXIST) {
1940                 fprintf(stderr, "Could not create directory %s: %s\n", confdir, strerror(errno));
1941                 return 1;
1942         }
1943
1944         if(mkdir(confbase, 0777) && errno != EEXIST) {
1945                 fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno));
1946                 return 1;
1947         }
1948
1949         if(mkdir(hosts_dir, 0777) && errno != EEXIST) {
1950                 fprintf(stderr, "Could not create directory %s: %s\n", hosts_dir, strerror(errno));
1951                 return 1;
1952         }
1953
1954         FILE *f = fopen(tinc_conf, "w");
1955         if(!f) {
1956                 fprintf(stderr, "Could not create file %s: %s\n", tinc_conf, strerror(errno));
1957                 return 1;
1958         }
1959
1960         fprintf(f, "Name = %s\n", name);
1961         fclose(f);
1962
1963 #ifndef DISABLE_LEGACY
1964         if(!rsa_keygen(2048, false))
1965                 return 1;
1966 #endif
1967
1968         if(!ed25519_keygen(false))
1969                 return 1;
1970
1971         check_port(name);
1972
1973 #ifndef HAVE_MINGW
1974         char filename[PATH_MAX];
1975         snprintf(filename, sizeof filename, "%s" SLASH "tinc-up", confbase);
1976         if(access(filename, F_OK)) {
1977                 FILE *f = fopenmask(filename, "w", 0777);
1978                 if(!f) {
1979                         fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
1980                         return 1;
1981                 }
1982                 fprintf(f, "#!/bin/sh\n\necho 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
1983                 fclose(f);
1984         }
1985 #endif
1986
1987         return 0;
1988
1989 }
1990
1991 static int cmd_generate_keys(int argc, char *argv[]) {
1992 #ifdef DISABLE_LEGACY
1993         if(argc > 1) {
1994 #else
1995         if(argc > 2) {
1996 #endif
1997                 fprintf(stderr, "Too many arguments!\n");
1998                 return 1;
1999         }
2000
2001         if(!name)
2002                 name = get_my_name(false);
2003
2004 #ifndef DISABLE_LEGACY
2005         if(!rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true))
2006                 return 1;
2007 #endif
2008
2009         if(!ed25519_keygen(true))
2010                 return 1;
2011
2012         return 0;
2013 }
2014
2015 #ifndef DISABLE_LEGACY
2016 static int cmd_generate_rsa_keys(int argc, char *argv[]) {
2017         if(argc > 2) {
2018                 fprintf(stderr, "Too many arguments!\n");
2019                 return 1;
2020         }
2021
2022         if(!name)
2023                 name = get_my_name(false);
2024
2025         return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
2026 }
2027 #endif
2028
2029 static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
2030         if(argc > 1) {
2031                 fprintf(stderr, "Too many arguments!\n");
2032                 return 1;
2033         }
2034
2035         if(!name)
2036                 name = get_my_name(false);
2037
2038         return !ed25519_keygen(true);
2039 }
2040
2041 static int cmd_help(int argc, char *argv[]) {
2042         usage(false);
2043         return 0;
2044 }
2045
2046 static int cmd_version(int argc, char *argv[]) {
2047         if(argc > 1) {
2048                 fprintf(stderr, "Too many arguments!\n");
2049                 return 1;
2050         }
2051
2052         version();
2053         return 0;
2054 }
2055
2056 static int cmd_info(int argc, char *argv[]) {
2057         if(argc != 2) {
2058                 fprintf(stderr, "Invalid number of arguments.\n");
2059                 return 1;
2060         }
2061
2062         if(!connect_tincd(true))
2063                 return 1;
2064
2065         return info(fd, argv[1]);
2066 }
2067
2068 static const char *conffiles[] = {
2069         "tinc.conf",
2070         "tinc-up",
2071         "tinc-down",
2072         "subnet-up",
2073         "subnet-down",
2074         "host-up",
2075         "host-down",
2076         NULL,
2077 };
2078
2079 static int cmd_edit(int argc, char *argv[]) {
2080         if(argc != 2) {
2081                 fprintf(stderr, "Invalid number of arguments.\n");
2082                 return 1;
2083         }
2084
2085         char filename[PATH_MAX] = "";
2086
2087         if(strncmp(argv[1], "hosts" SLASH, 6)) {
2088                 for(int i = 0; conffiles[i]; i++) {
2089                         if(!strcmp(argv[1], conffiles[i])) {
2090                                 snprintf(filename, sizeof filename, "%s" SLASH "%s", confbase, argv[1]);
2091                                 break;
2092                         }
2093                 }
2094         } else {
2095                 argv[1] += 6;
2096         }
2097
2098         if(!*filename) {
2099                 snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, argv[1]);
2100                 char *dash = strchr(argv[1], '-');
2101                 if(dash) {
2102                         *dash++ = 0;
2103                         if((strcmp(dash, "up") && strcmp(dash, "down")) || !check_id(argv[1])) {
2104                                 fprintf(stderr, "Invalid configuration filename.\n");
2105                                 return 1;
2106                         }
2107                 }
2108         }
2109
2110         char *command;
2111 #ifndef HAVE_MINGW
2112         xasprintf(&command, "\"%s\" \"%s\"", getenv("VISUAL") ?: getenv("EDITOR") ?: "vi", filename);
2113 #else
2114         xasprintf(&command, "edit \"%s\"", filename);
2115 #endif
2116         int result = system(command);
2117         free(command);
2118         if(result)
2119                 return result;
2120
2121         // Silently try notifying a running tincd of changes.
2122         if(connect_tincd(false))
2123                 sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
2124
2125         return 0;
2126 }
2127
2128 static int export(const char *name, FILE *out) {
2129         char filename[PATH_MAX];
2130         snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name);
2131         FILE *in = fopen(filename, "r");
2132         if(!in) {
2133                 fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
2134                 return 1;
2135         }
2136
2137         fprintf(out, "Name = %s\n", name);
2138         char buf[4096];
2139         while(fgets(buf, sizeof buf, in)) {
2140                 if(strcspn(buf, "\t =") != 4 || strncasecmp(buf, "Name", 4))
2141                         fputs(buf, out);
2142         }
2143
2144         if(ferror(in)) {
2145                 fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno));
2146                 fclose(in);
2147                 return 1;
2148         }
2149
2150         fclose(in);
2151         return 0;
2152 }
2153
2154 static int cmd_export(int argc, char *argv[]) {
2155         if(argc > 1) {
2156                 fprintf(stderr, "Too many arguments!\n");
2157                 return 1;
2158         }
2159
2160         char *name = get_my_name(true);
2161         if(!name)
2162                 return 1;
2163
2164         int result = export(name, stdout);
2165         if(!tty)
2166                 fclose(stdout);
2167
2168         free(name);
2169         return result;
2170 }
2171
2172 static int cmd_export_all(int argc, char *argv[]) {
2173         if(argc > 1) {
2174                 fprintf(stderr, "Too many arguments!\n");
2175                 return 1;
2176         }
2177
2178         DIR *dir = opendir(hosts_dir);
2179         if(!dir) {
2180                 fprintf(stderr, "Could not open host configuration directory %s: %s\n", hosts_dir, strerror(errno));
2181                 return 1;
2182         }
2183
2184         bool first = true;
2185         int result = 0;
2186         struct dirent *ent;
2187
2188         while((ent = readdir(dir))) {
2189                 if(!check_id(ent->d_name))
2190                         continue;
2191
2192                 if(first)
2193                         first = false;
2194                 else
2195                         printf("#---------------------------------------------------------------#\n");
2196
2197                 result |= export(ent->d_name, stdout);
2198         }
2199
2200         closedir(dir);
2201         if(!tty)
2202                 fclose(stdout);
2203         return result;
2204 }
2205
2206 static int cmd_import(int argc, char *argv[]) {
2207         if(argc > 1) {
2208                 fprintf(stderr, "Too many arguments!\n");
2209                 return 1;
2210         }
2211
2212         FILE *in = stdin;
2213         FILE *out = NULL;
2214
2215         char buf[4096];
2216         char name[4096];
2217         char filename[PATH_MAX] = "";
2218         int count = 0;
2219         bool firstline = true;
2220
2221         while(fgets(buf, sizeof buf, in)) {
2222                 if(sscanf(buf, "Name = %s", name) == 1) {
2223                         firstline = false;
2224
2225                         if(!check_id(name)) {
2226                                 fprintf(stderr, "Invalid Name in input!\n");
2227                                 return 1;
2228                         }
2229
2230                         if(out)
2231                                 fclose(out);
2232
2233                         snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name);
2234
2235                         if(!force && !access(filename, F_OK)) {
2236                                 fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename);
2237                                 out = NULL;
2238                                 continue;
2239                         }
2240
2241                         out = fopen(filename, "w");
2242                         if(!out) {
2243                                 fprintf(stderr, "Error creating configuration file %s: %s\n", filename, strerror(errno));
2244                                 return 1;
2245                         }
2246
2247                         count++;
2248                         continue;
2249                 } else if(firstline) {
2250                         fprintf(stderr, "Junk at the beginning of the input, ignoring.\n");
2251                         firstline = false;
2252                 }
2253
2254
2255                 if(!strcmp(buf, "#---------------------------------------------------------------#\n"))
2256                         continue;
2257
2258                 if(out) {
2259                         if(fputs(buf, out) < 0) {
2260                                 fprintf(stderr, "Error writing to host configuration file %s: %s\n", filename, strerror(errno));
2261                                 return 1;
2262                         }
2263                 }
2264         }
2265
2266         if(out)
2267                 fclose(out);
2268
2269         if(count) {
2270                 fprintf(stderr, "Imported %d host configuration files.\n", count);
2271                 return 0;
2272         } else {
2273                 fprintf(stderr, "No host configuration files imported.\n");
2274                 return 1;
2275         }
2276 }
2277
2278 static int cmd_exchange(int argc, char *argv[]) {
2279         return cmd_export(argc, argv) ?: cmd_import(argc, argv);
2280 }
2281
2282 static int cmd_exchange_all(int argc, char *argv[]) {
2283         return cmd_export_all(argc, argv) ?: cmd_import(argc, argv);
2284 }
2285
2286 static int switch_network(char *name) {
2287         if(fd >= 0) {
2288                 close(fd);
2289                 fd = -1;
2290         }
2291
2292         free(confbase);
2293         confbase = NULL;
2294         free(pidfilename);
2295         pidfilename = NULL;
2296         free(logfilename);
2297         logfilename = NULL;
2298         free(unixsocketname);
2299         unixsocketname = NULL;
2300         free(tinc_conf);
2301         free(hosts_dir);
2302         free(prompt);
2303
2304         free(netname);
2305         netname = strcmp(name, ".") ? xstrdup(name) : NULL;
2306
2307         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
2308         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
2309         xasprintf(&prompt, "%s> ", identname);
2310
2311         return 0;
2312 }
2313
2314 static int cmd_network(int argc, char *argv[]) {
2315         if(argc > 2) {
2316                 fprintf(stderr, "Too many arguments!\n");
2317                 return 1;
2318         }
2319
2320         if(argc == 2)
2321                 return switch_network(argv[1]);
2322
2323         DIR *dir = opendir(confdir);
2324         if(!dir) {
2325                 fprintf(stderr, "Could not read directory %s: %s\n", confdir, strerror(errno));
2326                 return 1;
2327         }
2328
2329         struct dirent *ent;
2330         while((ent = readdir(dir))) {
2331                 if(*ent->d_name == '.')
2332                         continue;
2333
2334                 if(!strcmp(ent->d_name, "tinc.conf")) {
2335                         printf(".\n");
2336                         continue;
2337                 }
2338
2339                 char fname[PATH_MAX];
2340                 snprintf(fname, sizeof fname, "%s/%s/tinc.conf", confdir, ent->d_name);
2341                 if(!access(fname, R_OK))
2342                         printf("%s\n", ent->d_name);
2343         }
2344
2345         closedir(dir);
2346
2347         return 0;
2348 }
2349
2350 static int cmd_fsck(int argc, char *argv[]) {
2351         if(argc > 1) {
2352                 fprintf(stderr, "Too many arguments!\n");
2353                 return 1;
2354         }
2355
2356         return fsck(orig_argv[0]);
2357 }
2358
2359 static void *readfile(FILE *in, size_t *len) {
2360         size_t count = 0;
2361         size_t alloced = 4096;
2362         char *buf = xmalloc(alloced);
2363
2364         while(!feof(in)) {
2365                 size_t read = fread(buf + count, 1, alloced - count, in);
2366                 if(!read)
2367                         break;
2368                 count += read;
2369                 if(count >= alloced) {
2370                         alloced *= 2;
2371                         buf = xrealloc(buf, alloced);
2372                 }
2373         }
2374
2375         if(len)
2376                 *len = count;
2377
2378         return buf;
2379 }
2380
2381 static int cmd_sign(int argc, char *argv[]) {
2382         if(argc > 2) {
2383                 fprintf(stderr, "Too many arguments!\n");
2384                 return 1;
2385         }
2386
2387         if(!name) {
2388                 name = get_my_name(true);
2389                 if(!name)
2390                         return 1;
2391         }
2392
2393         char fname[PATH_MAX];
2394         snprintf(fname, sizeof fname, "%s" SLASH "ed25519_key.priv", confbase);
2395         FILE *fp = fopen(fname, "r");
2396         if(!fp) {
2397                 fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
2398                 return 1;
2399         }
2400
2401         ecdsa_t *key = ecdsa_read_pem_private_key(fp);
2402
2403         if(!key) {
2404                 fprintf(stderr, "Could not read private key from %s\n", fname);
2405                 fclose(fp);
2406                 return 1;
2407         }
2408
2409         fclose(fp);
2410
2411         FILE *in;
2412
2413         if(argc == 2) {
2414                 in = fopen(argv[1], "rb");
2415                 if(!in) {
2416                         fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
2417                         ecdsa_free(key);
2418                         return 1;
2419                 }
2420         } else {
2421                 in = stdin;
2422         }
2423
2424         size_t len;
2425         char *data = readfile(in, &len);
2426         if(in != stdin)
2427                 fclose(in);
2428         if(!data) {
2429                 fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
2430                 ecdsa_free(key);
2431                 return 1;
2432         }
2433
2434         // Ensure we sign our name and current time as well
2435         long t = time(NULL);
2436         char *trailer;
2437         xasprintf(&trailer, " %s %ld", name, t);
2438         int trailer_len = strlen(trailer);
2439
2440         data = xrealloc(data, len + trailer_len);
2441         memcpy(data + len, trailer, trailer_len);
2442         free(trailer);
2443
2444         char sig[87];
2445         if(!ecdsa_sign(key, data, len + trailer_len, sig)) {
2446                 fprintf(stderr, "Error generating signature\n");
2447                 free(data);
2448                 ecdsa_free(key);
2449                 return 1;
2450         }
2451         b64encode(sig, sig, 64);
2452         ecdsa_free(key);
2453
2454         fprintf(stdout, "Signature = %s %ld %s\n", name, t, sig);
2455         fwrite(data, len, 1, stdout);
2456
2457         free(data);
2458         return 0;
2459 }
2460
2461 static int cmd_verify(int argc, char *argv[]) {
2462         if(argc < 2) {
2463                 fprintf(stderr, "Not enough arguments!\n");
2464                 return 1;
2465         }
2466
2467         if(argc > 3) {
2468                 fprintf(stderr, "Too many arguments!\n");
2469                 return 1;
2470         }
2471
2472         char *node = argv[1];
2473         if(!strcmp(node, ".")) {
2474                 if(!name) {
2475                         name = get_my_name(true);
2476                         if(!name)
2477                                 return 1;
2478                 }
2479                 node = name;
2480         } else if(!strcmp(node, "*")) {
2481                 node = NULL;
2482         } else {
2483                 if(!check_id(node)) {
2484                         fprintf(stderr, "Invalid node name\n");
2485                         return 1;
2486                 }
2487         }
2488
2489         FILE *in;
2490
2491         if(argc == 3) {
2492                 in = fopen(argv[2], "rb");
2493                 if(!in) {
2494                         fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
2495                         return 1;
2496                 }
2497         } else {
2498                 in = stdin;
2499         }
2500
2501         size_t len;
2502         char *data = readfile(in, &len);
2503         if(in != stdin)
2504                 fclose(in);
2505         if(!data) {
2506                 fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
2507                 return 1;
2508         }
2509
2510         char *newline = memchr(data, '\n', len);
2511         if(!newline || (newline - data > MAX_STRING_SIZE - 1)) {
2512                 fprintf(stderr, "Invalid input\n");
2513                 return 1;
2514         }
2515
2516         *newline++ = '\0';
2517
2518         char signer[MAX_STRING_SIZE] = "";
2519         char sig[MAX_STRING_SIZE] = "";
2520         long t = 0;
2521
2522         if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) {
2523                 fprintf(stderr, "Invalid input\n");
2524                 return 1;
2525         }
2526
2527         if(node && strcmp(node, signer)) {
2528                 fprintf(stderr, "Signature is not made by %s\n", node);
2529                 return 1;
2530         }
2531
2532         if(!node)
2533                 node = signer;
2534
2535         char *trailer;
2536         xasprintf(&trailer, " %s %ld", signer, t);
2537         int trailer_len = strlen(trailer);
2538
2539         data = xrealloc(data, len + trailer_len);
2540         memcpy(data + len, trailer, trailer_len);
2541         free(trailer);
2542
2543         char fname[PATH_MAX];
2544         snprintf(fname, sizeof fname, "%s" SLASH "hosts" SLASH "%s", confbase, node);
2545         FILE *fp = fopen(fname, "r");
2546         if(!fp) {
2547                 fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
2548                 free(data);
2549                 return 1;
2550         }
2551
2552         ecdsa_t *key = get_pubkey(fp);
2553         if(!key) {
2554                 rewind(fp);
2555                 key = ecdsa_read_pem_public_key(fp);
2556         }
2557         if(!key) {
2558                 fprintf(stderr, "Could not read public key from %s\n", fname);
2559                 fclose(fp);
2560                 free(data);
2561                 return 1;
2562         }
2563
2564         fclose(fp);
2565
2566         if(b64decode(sig, sig, 86) != 64 || !ecdsa_verify(key, newline, len + trailer_len - (newline - data), sig)) {
2567                 fprintf(stderr, "Invalid signature\n");
2568                 free(data);
2569                 ecdsa_free(key);
2570                 return 1;
2571         }
2572
2573         ecdsa_free(key);
2574
2575         fwrite(newline, len - (newline - data), 1, stdout);
2576
2577         free(data);
2578         return 0;
2579 }
2580
2581 static const struct {
2582         const char *command;
2583         int (*function)(int argc, char *argv[]);
2584         bool hidden;
2585 } commands[] = {
2586         {"start", cmd_start},
2587         {"stop", cmd_stop},
2588         {"restart", cmd_restart},
2589         {"reload", cmd_reload},
2590         {"dump", cmd_dump},
2591         {"list", cmd_dump},
2592         {"purge", cmd_purge},
2593         {"debug", cmd_debug},
2594         {"retry", cmd_retry},
2595         {"connect", cmd_connect},
2596         {"disconnect", cmd_disconnect},
2597         {"top", cmd_top},
2598         {"pcap", cmd_pcap},
2599         {"log", cmd_log},
2600         {"pid", cmd_pid},
2601         {"config", cmd_config, true},
2602         {"add", cmd_config},
2603         {"del", cmd_config},
2604         {"get", cmd_config},
2605         {"set", cmd_config},
2606         {"init", cmd_init},
2607         {"generate-keys", cmd_generate_keys},
2608 #ifndef DISABLE_LEGACY
2609         {"generate-rsa-keys", cmd_generate_rsa_keys},
2610 #endif
2611         {"generate-ed25519-keys", cmd_generate_ed25519_keys},
2612         {"help", cmd_help},
2613         {"version", cmd_version},
2614         {"info", cmd_info},
2615         {"edit", cmd_edit},
2616         {"export", cmd_export},
2617         {"export-all", cmd_export_all},
2618         {"import", cmd_import},
2619         {"exchange", cmd_exchange},
2620         {"exchange-all", cmd_exchange_all},
2621         {"invite", cmd_invite},
2622         {"join", cmd_join},
2623         {"network", cmd_network},
2624         {"fsck", cmd_fsck},
2625         {"sign", cmd_sign},
2626         {"verify", cmd_verify},
2627         {NULL, NULL},
2628 };
2629
2630 #ifdef HAVE_READLINE
2631 static char *complete_command(const char *text, int state) {
2632         static int i;
2633
2634         if(!state)
2635                 i = 0;
2636         else
2637                 i++;
2638
2639         while(commands[i].command) {
2640                 if(!commands[i].hidden && !strncasecmp(commands[i].command, text, strlen(text)))
2641                         return xstrdup(commands[i].command);
2642                 i++;
2643         }
2644
2645         return NULL;
2646 }
2647
2648 static char *complete_dump(const char *text, int state) {
2649         const char *matches[] = {"reachable", "nodes", "edges", "subnets", "connections", "graph", NULL};
2650         static int i;
2651
2652         if(!state)
2653                 i = 0;
2654         else
2655                 i++;
2656
2657         while(matches[i]) {
2658                 if(!strncasecmp(matches[i], text, strlen(text)))
2659                         return xstrdup(matches[i]);
2660                 i++;
2661         }
2662
2663         return NULL;
2664 }
2665
2666 static char *complete_config(const char *text, int state) {
2667         static int i;
2668
2669         if(!state)
2670                 i = 0;
2671         else
2672                 i++;
2673
2674         while(variables[i].name) {
2675                 char *dot = strchr(text, '.');
2676                 if(dot) {
2677                         if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
2678                                 char *match;
2679                                 xasprintf(&match, "%.*s.%s", (int)(dot - text), text, variables[i].name);
2680                                 return match;
2681                         }
2682                 } else {
2683                         if(!strncasecmp(variables[i].name, text, strlen(text)))
2684                                 return xstrdup(variables[i].name);
2685                 }
2686                 i++;
2687         }
2688
2689         return NULL;
2690 }
2691
2692 static char *complete_info(const char *text, int state) {
2693         static int i;
2694         if(!state) {
2695                 i = 0;
2696                 if(!connect_tincd(false))
2697                         return NULL;
2698                 // Check the list of nodes
2699                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
2700                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
2701         }
2702
2703         while(recvline(fd, line, sizeof line)) {
2704                 char item[4096];
2705                 int n = sscanf(line, "%d %d %s", &code, &req, item);
2706                 if(n == 2) {
2707                         i++;
2708                         if(i >= 2)
2709                                 break;
2710                         else
2711                                 continue;
2712                 }
2713
2714                 if(n != 3) {
2715                         fprintf(stderr, "Unable to parse dump from tincd, n = %d, i = %d.\n", n, i);
2716                         break;
2717                 }
2718
2719                 if(!strncmp(item, text, strlen(text)))
2720                         return xstrdup(strip_weight(item));
2721         }
2722
2723         return NULL;
2724 }
2725
2726 static char *complete_nothing(const char *text, int state) {
2727         return NULL;
2728 }
2729
2730 static char **completion (const char *text, int start, int end) {
2731         char **matches = NULL;
2732
2733         if(!start)
2734                 matches = rl_completion_matches(text, complete_command);
2735         else if(!strncasecmp(rl_line_buffer, "dump ", 5))
2736                 matches = rl_completion_matches(text, complete_dump);
2737         else if(!strncasecmp(rl_line_buffer, "add ", 4))
2738                 matches = rl_completion_matches(text, complete_config);
2739         else if(!strncasecmp(rl_line_buffer, "del ", 4))
2740                 matches = rl_completion_matches(text, complete_config);
2741         else if(!strncasecmp(rl_line_buffer, "get ", 4))
2742                 matches = rl_completion_matches(text, complete_config);
2743         else if(!strncasecmp(rl_line_buffer, "set ", 4))
2744                 matches = rl_completion_matches(text, complete_config);
2745         else if(!strncasecmp(rl_line_buffer, "info ", 5))
2746                 matches = rl_completion_matches(text, complete_info);
2747
2748         return matches;
2749 }
2750 #endif
2751
2752 static int cmd_shell(int argc, char *argv[]) {
2753         xasprintf(&prompt, "%s> ", identname);
2754         int result = 0;
2755         char buf[4096];
2756         char *line = NULL;
2757         int maxargs = argc + 16;
2758         char **nargv = xmalloc(maxargs * sizeof *nargv);
2759
2760         for(int i = 0; i < argc; i++)
2761                 nargv[i] = argv[i];
2762
2763 #ifdef HAVE_READLINE
2764         rl_readline_name = "tinc";
2765         rl_completion_entry_function = complete_nothing;
2766         rl_attempted_completion_function = completion;
2767         rl_filename_completion_desired = 0;
2768         char *copy = NULL;
2769 #endif
2770
2771         while(true) {
2772 #ifdef HAVE_READLINE
2773                 if(tty) {
2774                         free(copy);
2775                         free(line);
2776                         rl_basic_word_break_characters = "\t\n ";
2777                         line = readline(prompt);
2778                         if(line)
2779                                 copy = xstrdup(line);
2780                 } else {
2781                         line = fgets(buf, sizeof buf, stdin);
2782                 }
2783 #else
2784                 if(tty)
2785                         fputs(prompt, stdout);
2786
2787                 line = fgets(buf, sizeof buf, stdin);
2788 #endif
2789
2790                 if(!line)
2791                         break;
2792
2793                 /* Ignore comments */
2794
2795                 if(*line == '#')
2796                         continue;
2797
2798                 /* Split */
2799
2800                 int nargc = argc;
2801                 char *p = line + strspn(line, " \t\n");
2802                 char *next = strtok(p, " \t\n");
2803
2804                 while(p && *p) {
2805                         if(nargc >= maxargs) {
2806                                 fprintf(stderr, "next %p '%s', p %p '%s'\n", next, next, p, p);
2807                                 abort();
2808                                 maxargs *= 2;
2809                                 nargv = xrealloc(nargv, maxargs * sizeof *nargv);
2810                         }
2811
2812                         nargv[nargc++] = p;
2813                         p = next;
2814                         next = strtok(NULL, " \t\n");
2815                 }
2816
2817                 if(nargc == argc)
2818                         continue;
2819
2820                 if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit"))
2821                         return result;
2822
2823                 bool found = false;
2824
2825                 for(int i = 0; commands[i].command; i++) {
2826                         if(!strcasecmp(nargv[argc], commands[i].command)) {
2827                                 result |= commands[i].function(nargc - argc - 1, nargv + argc + 1);
2828                                 found = true;
2829                                 break;
2830                         }
2831                 }
2832
2833 #ifdef HAVE_READLINE
2834                 if(tty && found)
2835                         add_history(copy);
2836 #endif
2837
2838                 if(!found) {
2839                         fprintf(stderr, "Unknown command `%s'.\n", nargv[argc]);
2840                         result |= 1;
2841                 }
2842         }
2843
2844         free(nargv);
2845
2846         if(tty)
2847                 printf("\n");
2848         return result;
2849 }
2850
2851
2852 int main(int argc, char *argv[]) {
2853         program_name = argv[0];
2854         orig_argv = argv;
2855         orig_argc = argc;
2856         tty = isatty(0) && isatty(1);
2857
2858         if(!parse_options(argc, argv))
2859                 return 1;
2860
2861         make_names(false);
2862         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
2863         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
2864
2865         if(show_version) {
2866                 version();
2867                 return 0;
2868         }
2869
2870         if(show_help) {
2871                 usage(false);
2872                 return 0;
2873         }
2874
2875 #ifdef HAVE_MINGW
2876         static struct WSAData wsa_state;
2877
2878         if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
2879                 fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
2880                 return false;
2881         }
2882 #endif
2883
2884         srand(time(NULL));
2885         crypto_init();
2886
2887         if(optind >= argc)
2888                 return cmd_shell(argc, argv);
2889
2890         for(int i = 0; commands[i].command; i++) {
2891                 if(!strcasecmp(argv[optind], commands[i].command))
2892                         return commands[i].function(argc - optind, argv + optind);
2893         }
2894
2895         fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
2896         usage(true);
2897         return 1;
2898 }