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