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