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