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