46073b3aaad7db9651c077a7dbc5734caaa47d9d
[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 bool makedir(const char *path, mode_t mode) {
2193         if(mkdir(path, mode) && errno != EEXIST) {
2194                 fprintf(stderr, "Could not create directory %s: %s\n", path, strerror(errno));
2195                 return false;
2196         }
2197
2198         return true;
2199 }
2200
2201 bool makedirs(tincd_dir_t dirs) {
2202         if(dirs & DIR_CONFBASE && !makedir(confbase, 0777)) {
2203                 return false;
2204         }
2205
2206         if(dirs & DIR_CONFDIR && !confbase_given && !makedir(confdir, 0755)) {
2207                 return false;
2208         }
2209
2210         if(dirs & DIR_HOSTS && !makedir(hosts_dir, 0777)) {
2211                 return false;
2212         }
2213
2214         char path[PATH_MAX];
2215
2216         if(dirs & DIR_INVITATIONS) {
2217                 snprintf(path, sizeof(path), "%s" SLASH "invitations", confbase);
2218
2219                 if(!makedir(path, 0700)) {
2220                         return false;
2221                 }
2222         }
2223
2224         if(dirs & DIR_CACHE) {
2225                 snprintf(path, sizeof(path), "%s" SLASH "%s", confbase, "cache");
2226
2227                 if(!makedir(path, 0755)) {
2228                         return false;
2229                 }
2230         }
2231
2232         return true;
2233 }
2234
2235 static int cmd_init(int argc, char *argv[]) {
2236         if(!access(tinc_conf, F_OK)) {
2237                 fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
2238                 return 1;
2239         }
2240
2241         if(argc > 2) {
2242                 fprintf(stderr, "Too many arguments!\n");
2243                 return 1;
2244         } else if(argc < 2) {
2245                 if(tty) {
2246                         char buf[1024];
2247                         fprintf(stderr, "Enter the Name you want your tinc node to have: ");
2248
2249                         if(!fgets(buf, sizeof(buf), stdin)) {
2250                                 fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
2251                                 return 1;
2252                         }
2253
2254                         size_t len = rstrip(buf);
2255
2256                         if(!len) {
2257                                 fprintf(stderr, "No name given!\n");
2258                                 return 1;
2259                         }
2260
2261                         name = strdup(buf);
2262                 } else {
2263                         fprintf(stderr, "No Name given!\n");
2264                         return 1;
2265                 }
2266         } else {
2267                 name = strdup(argv[1]);
2268
2269                 if(!*name) {
2270                         fprintf(stderr, "No Name given!\n");
2271                         return 1;
2272                 }
2273         }
2274
2275         if(!check_id(name)) {
2276                 fprintf(stderr, "Invalid Name! Only a-z, A-Z, 0-9 and _ are allowed characters.\n");
2277                 return 1;
2278         }
2279
2280         if(!makedirs(DIR_HOSTS | DIR_CONFBASE | DIR_CONFDIR | DIR_CACHE)) {
2281                 return false;
2282         }
2283
2284         FILE *f = fopen(tinc_conf, "w");
2285
2286         if(!f) {
2287                 fprintf(stderr, "Could not create file %s: %s\n", tinc_conf, strerror(errno));
2288                 return 1;
2289         }
2290
2291         fprintf(f, "Name = %s\n", name);
2292         fclose(f);
2293
2294 #ifndef DISABLE_LEGACY
2295
2296         if(!rsa_keygen(2048, false)) {
2297                 return 1;
2298         }
2299
2300 #endif
2301
2302         if(!ed25519_keygen(false)) {
2303                 return 1;
2304         }
2305
2306         check_port(name);
2307
2308 #ifndef HAVE_WINDOWS
2309         char filename[PATH_MAX];
2310         snprintf(filename, sizeof(filename), "%s" SLASH "tinc-up", confbase);
2311
2312         if(access(filename, F_OK)) {
2313                 FILE *f = fopenmask(filename, "w", 0777);
2314
2315                 if(!f) {
2316                         fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
2317                         return 1;
2318                 }
2319
2320                 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");
2321                 fclose(f);
2322         }
2323
2324 #endif
2325
2326         return 0;
2327
2328 }
2329
2330 static int cmd_generate_keys(int argc, char *argv[]) {
2331 #ifdef DISABLE_LEGACY
2332         (void)argv;
2333
2334         if(argc > 1) {
2335 #else
2336
2337         if(argc > 2) {
2338 #endif
2339                 fprintf(stderr, "Too many arguments!\n");
2340                 return 1;
2341         }
2342
2343         if(!name) {
2344                 name = get_my_name(false);
2345         }
2346
2347 #ifndef DISABLE_LEGACY
2348
2349         if(!rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true)) {
2350                 return 1;
2351         }
2352
2353 #endif
2354
2355         if(!ed25519_keygen(true)) {
2356                 return 1;
2357         }
2358
2359         return 0;
2360 }
2361
2362 #ifndef DISABLE_LEGACY
2363 static int cmd_generate_rsa_keys(int argc, char *argv[]) {
2364         if(argc > 2) {
2365                 fprintf(stderr, "Too many arguments!\n");
2366                 return 1;
2367         }
2368
2369         if(!name) {
2370                 name = get_my_name(false);
2371         }
2372
2373         return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
2374 }
2375 #endif
2376
2377 static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
2378         (void)argv;
2379
2380         if(argc > 1) {
2381                 fprintf(stderr, "Too many arguments!\n");
2382                 return 1;
2383         }
2384
2385         if(!name) {
2386                 name = get_my_name(false);
2387         }
2388
2389         return !ed25519_keygen(true);
2390 }
2391
2392 static int cmd_help(int argc, char *argv[]) {
2393         (void)argc;
2394         (void)argv;
2395
2396         usage(false);
2397         return 0;
2398 }
2399
2400 static int cmd_version(int argc, char *argv[]) {
2401         (void)argv;
2402
2403         if(argc > 1) {
2404                 fprintf(stderr, "Too many arguments!\n");
2405                 return 1;
2406         }
2407
2408         version();
2409         return 0;
2410 }
2411
2412 static int cmd_info(int argc, char *argv[]) {
2413         if(argc != 2) {
2414                 fprintf(stderr, "Invalid number of arguments.\n");
2415                 return 1;
2416         }
2417
2418         if(!connect_tincd(true)) {
2419                 return 1;
2420         }
2421
2422         return info(fd, argv[1]);
2423 }
2424
2425 static const char *conffiles[] = {
2426         "tinc.conf",
2427         "tinc-up",
2428         "tinc-down",
2429         "subnet-up",
2430         "subnet-down",
2431         "host-up",
2432         "host-down",
2433         NULL,
2434 };
2435
2436 static int cmd_edit(int argc, char *argv[]) {
2437         if(argc != 2) {
2438                 fprintf(stderr, "Invalid number of arguments.\n");
2439                 return 1;
2440         }
2441
2442         char filename[PATH_MAX] = "";
2443
2444         if(strncmp(argv[1], "hosts" SLASH, 6)) {
2445                 for(int i = 0; conffiles[i]; i++) {
2446                         if(!strcmp(argv[1], conffiles[i])) {
2447                                 snprintf(filename, sizeof(filename), "%s" SLASH "%s", confbase, argv[1]);
2448                                 break;
2449                         }
2450                 }
2451         } else {
2452                 argv[1] += 6;
2453         }
2454
2455         if(!*filename) {
2456                 snprintf(filename, sizeof(filename), "%s" SLASH "%s", hosts_dir, argv[1]);
2457                 char *dash = strchr(argv[1], '-');
2458
2459                 if(dash) {
2460                         *dash++ = 0;
2461
2462                         if((strcmp(dash, "up") && strcmp(dash, "down")) || !check_id(argv[1])) {
2463                                 fprintf(stderr, "Invalid configuration filename.\n");
2464                                 return 1;
2465                         }
2466                 }
2467         }
2468
2469         char *command;
2470 #ifndef HAVE_WINDOWS
2471         const char *editor = getenv("VISUAL");
2472
2473         if(!editor) {
2474                 editor = getenv("EDITOR");
2475         }
2476
2477         if(!editor) {
2478                 editor = "vi";
2479         }
2480
2481         xasprintf(&command, "\"%s\" \"%s\"", editor, filename);
2482 #else
2483         xasprintf(&command, "edit \"%s\"", filename);
2484 #endif
2485         int result = system(command);
2486         free(command);
2487
2488         if(result) {
2489                 return result;
2490         }
2491
2492         // Silently try notifying a running tincd of changes.
2493         if(connect_tincd(false)) {
2494                 sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
2495         }
2496
2497         return 0;
2498 }
2499
2500 static int export(const char *name, FILE *out) {
2501         char filename[PATH_MAX];
2502         snprintf(filename, sizeof(filename), "%s" SLASH "%s", hosts_dir, name);
2503         FILE *in = fopen(filename, "r");
2504
2505         if(!in) {
2506                 fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
2507                 return 1;
2508         }
2509
2510         fprintf(out, "Name = %s\n", name);
2511         char buf[4096];
2512
2513         while(fgets(buf, sizeof(buf), in)) {
2514                 if(strcspn(buf, "\t =") != 4 || strncasecmp(buf, "Name", 4)) {
2515                         fputs(buf, out);
2516                 }
2517         }
2518
2519         if(ferror(in)) {
2520                 fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno));
2521                 fclose(in);
2522                 return 1;
2523         }
2524
2525         fclose(in);
2526         return 0;
2527 }
2528
2529 static int cmd_export(int argc, char *argv[]) {
2530         (void)argv;
2531
2532         if(argc > 1) {
2533                 fprintf(stderr, "Too many arguments!\n");
2534                 return 1;
2535         }
2536
2537         char *name = get_my_name(true);
2538
2539         if(!name) {
2540                 return 1;
2541         }
2542
2543         int result = export(name, stdout);
2544
2545         if(!tty) {
2546                 fclose(stdout);
2547         }
2548
2549         free(name);
2550         return result;
2551 }
2552
2553 static int cmd_export_all(int argc, char *argv[]) {
2554         (void)argv;
2555
2556         if(argc > 1) {
2557                 fprintf(stderr, "Too many arguments!\n");
2558                 return 1;
2559         }
2560
2561         DIR *dir = opendir(hosts_dir);
2562
2563         if(!dir) {
2564                 fprintf(stderr, "Could not open host configuration directory %s: %s\n", hosts_dir, strerror(errno));
2565                 return 1;
2566         }
2567
2568         bool first = true;
2569         int result = 0;
2570         struct dirent *ent;
2571
2572         while((ent = readdir(dir))) {
2573                 if(!check_id(ent->d_name)) {
2574                         continue;
2575                 }
2576
2577                 if(first) {
2578                         first = false;
2579                 } else {
2580                         printf("\n#---------------------------------------------------------------#\n");
2581                 }
2582
2583                 result |= export(ent->d_name, stdout);
2584         }
2585
2586         closedir(dir);
2587
2588         if(!tty) {
2589                 fclose(stdout);
2590         }
2591
2592         return result;
2593 }
2594
2595 static int cmd_import(int argc, char *argv[]) {
2596         (void)argv;
2597
2598         if(argc > 1) {
2599                 fprintf(stderr, "Too many arguments!\n");
2600                 return 1;
2601         }
2602
2603         FILE *in = stdin;
2604         FILE *out = NULL;
2605
2606         char buf[4096];
2607         char name[4096];
2608         char filename[PATH_MAX] = "";
2609         int count = 0;
2610         bool firstline = true;
2611
2612         while(fgets(buf, sizeof(buf), in)) {
2613                 if(sscanf(buf, "Name = %4095s", name) == 1) {
2614                         firstline = false;
2615
2616                         if(!check_id(name)) {
2617                                 fprintf(stderr, "Invalid Name in input!\n");
2618                                 return 1;
2619                         }
2620
2621                         if(out) {
2622                                 fclose(out);
2623                         }
2624
2625                         if((size_t)snprintf(filename, sizeof(filename), "%s" SLASH "%s", hosts_dir, name) >= sizeof(filename)) {
2626                                 fprintf(stderr, "Filename too long: %s" SLASH "%s\n", hosts_dir, name);
2627                                 return 1;
2628                         }
2629
2630                         if(!force && !access(filename, F_OK)) {
2631                                 fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename);
2632                                 out = NULL;
2633                                 continue;
2634                         }
2635
2636                         out = fopen(filename, "w");
2637
2638                         if(!out) {
2639                                 fprintf(stderr, "Error creating configuration file %s: %s\n", filename, strerror(errno));
2640                                 return 1;
2641                         }
2642
2643                         count++;
2644                         continue;
2645                 } else if(firstline) {
2646                         fprintf(stderr, "Junk at the beginning of the input, ignoring.\n");
2647                         firstline = false;
2648                 }
2649
2650
2651                 if(!strcmp(buf, "#---------------------------------------------------------------#\n")) {
2652                         continue;
2653                 }
2654
2655                 if(out) {
2656                         if(fputs(buf, out) < 0) {
2657                                 fprintf(stderr, "Error writing to host configuration file %s: %s\n", filename, strerror(errno));
2658                                 return 1;
2659                         }
2660                 }
2661         }
2662
2663         if(out) {
2664                 fclose(out);
2665         }
2666
2667         if(count) {
2668                 fprintf(stderr, "Imported %d host configuration files.\n", count);
2669                 return 0;
2670         } else {
2671                 fprintf(stderr, "No host configuration files imported.\n");
2672                 return 1;
2673         }
2674 }
2675
2676 static int cmd_exchange(int argc, char *argv[]) {
2677         return cmd_export(argc, argv) ? 1 : cmd_import(argc, argv);
2678 }
2679
2680 static int cmd_exchange_all(int argc, char *argv[]) {
2681         return cmd_export_all(argc, argv) ? 1 : cmd_import(argc, argv);
2682 }
2683
2684 static int switch_network(char *name) {
2685         if(strcmp(name, ".")) {
2686                 if(!check_netname(name, false)) {
2687                         fprintf(stderr, "Invalid character in netname!\n");
2688                         return 1;
2689                 }
2690
2691                 if(!check_netname(name, true)) {
2692                         fprintf(stderr, "Warning: unsafe character in netname!\n");
2693                 }
2694         }
2695
2696         if(fd >= 0) {
2697                 closesocket(fd);
2698                 fd = -1;
2699         }
2700
2701         free_names();
2702         netname = strcmp(name, ".") ? xstrdup(name) : NULL;
2703         make_names(false);
2704
2705         free(tinc_conf);
2706         free(hosts_dir);
2707         free(prompt);
2708
2709         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
2710         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
2711         xasprintf(&prompt, "%s> ", identname);
2712
2713         return 0;
2714 }
2715
2716 static int cmd_network(int argc, char *argv[]) {
2717         if(argc > 2) {
2718                 fprintf(stderr, "Too many arguments!\n");
2719                 return 1;
2720         }
2721
2722         if(argc == 2) {
2723                 return switch_network(argv[1]);
2724         }
2725
2726         DIR *dir = opendir(confdir);
2727
2728         if(!dir) {
2729                 fprintf(stderr, "Could not read directory %s: %s\n", confdir, strerror(errno));
2730                 return 1;
2731         }
2732
2733         struct dirent *ent;
2734
2735         while((ent = readdir(dir))) {
2736                 if(*ent->d_name == '.') {
2737                         continue;
2738                 }
2739
2740                 if(!strcmp(ent->d_name, "tinc.conf")) {
2741                         printf(".\n");
2742                         continue;
2743                 }
2744
2745                 char fname[PATH_MAX];
2746                 snprintf(fname, sizeof(fname), "%s/%s/tinc.conf", confdir, ent->d_name);
2747
2748                 if(!access(fname, R_OK)) {
2749                         printf("%s\n", ent->d_name);
2750                 }
2751         }
2752
2753         closedir(dir);
2754
2755         return 0;
2756 }
2757
2758 static int cmd_fsck(int argc, char *argv[]) {
2759         (void)argv;
2760
2761         if(argc > 1) {
2762                 fprintf(stderr, "Too many arguments!\n");
2763                 return 1;
2764         }
2765
2766         return fsck(orig_argv[0]);
2767 }
2768
2769 static void *readfile(FILE *in, size_t *len) {
2770         size_t count = 0;
2771         size_t bufsize = 4096;
2772         char *buf = xmalloc(bufsize);
2773
2774         while(!feof(in)) {
2775                 size_t read = fread(buf + count, 1, bufsize - count, in);
2776
2777                 if(!read) {
2778                         break;
2779                 }
2780
2781                 count += read;
2782
2783                 if(count >= bufsize) {
2784                         bufsize *= 2;
2785                         buf = xrealloc(buf, bufsize);
2786                 }
2787         }
2788
2789         if(len) {
2790                 *len = count;
2791         }
2792
2793         return buf;
2794 }
2795
2796 static int cmd_sign(int argc, char *argv[]) {
2797         if(argc > 2) {
2798                 fprintf(stderr, "Too many arguments!\n");
2799                 return 1;
2800         }
2801
2802         if(!name) {
2803                 name = get_my_name(true);
2804
2805                 if(!name) {
2806                         return 1;
2807                 }
2808         }
2809
2810         char fname[PATH_MAX];
2811         snprintf(fname, sizeof(fname), "%s" SLASH "ed25519_key.priv", confbase);
2812         FILE *fp = fopen(fname, "r");
2813
2814         if(!fp) {
2815                 fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
2816                 return 1;
2817         }
2818
2819         ecdsa_t *key = ecdsa_read_pem_private_key(fp);
2820
2821         if(!key) {
2822                 fprintf(stderr, "Could not read private key from %s\n", fname);
2823                 fclose(fp);
2824                 return 1;
2825         }
2826
2827         fclose(fp);
2828
2829         FILE *in;
2830
2831         if(argc == 2) {
2832                 in = fopen(argv[1], "rb");
2833
2834                 if(!in) {
2835                         fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
2836                         ecdsa_free(key);
2837                         return 1;
2838                 }
2839         } else {
2840                 in = stdin;
2841         }
2842
2843         size_t len;
2844         char *data = readfile(in, &len);
2845
2846         if(in != stdin) {
2847                 fclose(in);
2848         }
2849
2850         if(!data) {
2851                 fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
2852                 ecdsa_free(key);
2853                 return 1;
2854         }
2855
2856         // Ensure we sign our name and current time as well
2857         long t = time(NULL);
2858         char *trailer;
2859         xasprintf(&trailer, " %s %ld", name, t);
2860         size_t trailer_len = strlen(trailer);
2861
2862         data = xrealloc(data, len + trailer_len);
2863         memcpy(data + len, trailer, trailer_len);
2864         free(trailer);
2865
2866         char sig[87];
2867
2868         if(!ecdsa_sign(key, data, len + trailer_len, sig)) {
2869                 fprintf(stderr, "Error generating signature\n");
2870                 free(data);
2871                 ecdsa_free(key);
2872                 return 1;
2873         }
2874
2875         b64encode_tinc(sig, sig, 64);
2876         ecdsa_free(key);
2877
2878         fprintf(stdout, "Signature = %s %ld %s\n", name, t, sig);
2879         fwrite(data, len, 1, stdout);
2880
2881         free(data);
2882         return 0;
2883 }
2884
2885 static int cmd_verify(int argc, char *argv[]) {
2886         if(argc < 2) {
2887                 fprintf(stderr, "Not enough arguments!\n");
2888                 return 1;
2889         }
2890
2891         if(argc > 3) {
2892                 fprintf(stderr, "Too many arguments!\n");
2893                 return 1;
2894         }
2895
2896         char *node = argv[1];
2897
2898         if(!strcmp(node, ".")) {
2899                 if(!name) {
2900                         name = get_my_name(true);
2901
2902                         if(!name) {
2903                                 return 1;
2904                         }
2905                 }
2906
2907                 node = name;
2908         } else if(!strcmp(node, "*")) {
2909                 node = NULL;
2910         } else {
2911                 if(!check_id(node)) {
2912                         fprintf(stderr, "Invalid node name\n");
2913                         return 1;
2914                 }
2915         }
2916
2917         FILE *in;
2918
2919         if(argc == 3) {
2920                 in = fopen(argv[2], "rb");
2921
2922                 if(!in) {
2923                         fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
2924                         return 1;
2925                 }
2926         } else {
2927                 in = stdin;
2928         }
2929
2930         size_t len;
2931         char *data = readfile(in, &len);
2932
2933         if(in != stdin) {
2934                 fclose(in);
2935         }
2936
2937         if(!data) {
2938                 fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
2939                 return 1;
2940         }
2941
2942         char *newline = memchr(data, '\n', len);
2943
2944         if(!newline || (newline - data > MAX_STRING_SIZE - 1)) {
2945                 fprintf(stderr, "Invalid input\n");
2946                 free(data);
2947                 return 1;
2948         }
2949
2950         *newline++ = '\0';
2951         size_t skip = newline - data;
2952
2953         char signer[MAX_STRING_SIZE] = "";
2954         char sig[MAX_STRING_SIZE] = "";
2955         long t = 0;
2956
2957         if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) {
2958                 fprintf(stderr, "Invalid input\n");
2959                 free(data);
2960                 return 1;
2961         }
2962
2963         if(node && strcmp(node, signer)) {
2964                 fprintf(stderr, "Signature is not made by %s\n", node);
2965                 free(data);
2966                 return 1;
2967         }
2968
2969         if(!node) {
2970                 node = signer;
2971         }
2972
2973         char *trailer;
2974         xasprintf(&trailer, " %s %ld", signer, t);
2975         size_t trailer_len = strlen(trailer);
2976
2977         data = xrealloc(data, len + trailer_len);
2978         memcpy(data + len, trailer, trailer_len);
2979         free(trailer);
2980
2981         newline = data + skip;
2982
2983         char fname[PATH_MAX];
2984         snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, node);
2985         FILE *fp = fopen(fname, "r");
2986
2987         if(!fp) {
2988                 fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
2989                 free(data);
2990                 return 1;
2991         }
2992
2993         ecdsa_t *key = get_pubkey(fp);
2994
2995         if(!key) {
2996                 rewind(fp);
2997                 key = ecdsa_read_pem_public_key(fp);
2998         }
2999
3000         if(!key) {
3001                 fprintf(stderr, "Could not read public key from %s\n", fname);
3002                 fclose(fp);
3003                 free(data);
3004                 return 1;
3005         }
3006
3007         fclose(fp);
3008
3009         if(b64decode_tinc(sig, sig, 86) != 64 || !ecdsa_verify(key, newline, len + trailer_len - (newline - data), sig)) {
3010                 fprintf(stderr, "Invalid signature\n");
3011                 free(data);
3012                 ecdsa_free(key);
3013                 return 1;
3014         }
3015
3016         ecdsa_free(key);
3017
3018         fwrite(newline, len - (newline - data), 1, stdout);
3019
3020         free(data);
3021         return 0;
3022 }
3023
3024 static const struct {
3025         const char *command;
3026         int (*function)(int argc, char *argv[]);
3027         bool hidden;
3028 } commands[] = {
3029         {"start", cmd_start, false},
3030         {"stop", cmd_stop, false},
3031         {"restart", cmd_restart, false},
3032         {"reload", cmd_reload, false},
3033         {"dump", cmd_dump, false},
3034         {"list", cmd_dump, false},
3035         {"purge", cmd_purge, false},
3036         {"debug", cmd_debug, false},
3037         {"retry", cmd_retry, false},
3038         {"connect", cmd_connect, false},
3039         {"disconnect", cmd_disconnect, false},
3040         {"top", cmd_top, false},
3041         {"pcap", cmd_pcap, false},
3042         {"log", cmd_log, false},
3043         {"pid", cmd_pid, false},
3044         {"config", cmd_config, true},
3045         {"add", cmd_config, false},
3046         {"del", cmd_config, false},
3047         {"get", cmd_config, false},
3048         {"set", cmd_config, false},
3049         {"init", cmd_init, false},
3050         {"generate-keys", cmd_generate_keys, false},
3051 #ifndef DISABLE_LEGACY
3052         {"generate-rsa-keys", cmd_generate_rsa_keys, false},
3053 #endif
3054         {"generate-ed25519-keys", cmd_generate_ed25519_keys, false},
3055         {"help", cmd_help, false},
3056         {"version", cmd_version, false},
3057         {"info", cmd_info, false},
3058         {"edit", cmd_edit, false},
3059         {"export", cmd_export, false},
3060         {"export-all", cmd_export_all, false},
3061         {"import", cmd_import, false},
3062         {"exchange", cmd_exchange, false},
3063         {"exchange-all", cmd_exchange_all, false},
3064         {"invite", cmd_invite, false},
3065         {"join", cmd_join, false},
3066         {"network", cmd_network, false},
3067         {"fsck", cmd_fsck, false},
3068         {"sign", cmd_sign, false},
3069         {"verify", cmd_verify, false},
3070         {NULL, NULL, false},
3071 };
3072
3073 #ifdef HAVE_READLINE
3074 static char *complete_command(const char *text, int state) {
3075         static int i;
3076
3077         if(!state) {
3078                 i = 0;
3079         } else {
3080                 i++;
3081         }
3082
3083         while(commands[i].command) {
3084                 if(!commands[i].hidden && !strncasecmp(commands[i].command, text, strlen(text))) {
3085                         return xstrdup(commands[i].command);
3086                 }
3087
3088                 i++;
3089         }
3090
3091         return NULL;
3092 }
3093
3094 static char *complete_dump(const char *text, int state) {
3095         const char *matches[] = {"reachable", "nodes", "edges", "subnets", "connections", "graph", NULL};
3096         static int i;
3097
3098         if(!state) {
3099                 i = 0;
3100         } else {
3101                 i++;
3102         }
3103
3104         while(matches[i]) {
3105                 if(!strncasecmp(matches[i], text, strlen(text))) {
3106                         return xstrdup(matches[i]);
3107                 }
3108
3109                 i++;
3110         }
3111
3112         return NULL;
3113 }
3114
3115 static char *complete_config(const char *text, int state) {
3116         static int i;
3117
3118         if(!state) {
3119                 i = 0;
3120         } else {
3121                 i++;
3122         }
3123
3124         while(variables[i].name) {
3125                 char *dot = strchr(text, '.');
3126
3127                 if(dot) {
3128                         if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
3129                                 char *match;
3130                                 xasprintf(&match, "%.*s.%s", (int)(dot - text), text, variables[i].name);
3131                                 return match;
3132                         }
3133                 } else {
3134                         if(!strncasecmp(variables[i].name, text, strlen(text))) {
3135                                 return xstrdup(variables[i].name);
3136                         }
3137                 }
3138
3139                 i++;
3140         }
3141
3142         return NULL;
3143 }
3144
3145 static char *complete_info(const char *text, int state) {
3146         static int i;
3147
3148         if(!state) {
3149                 i = 0;
3150
3151                 if(!connect_tincd(false)) {
3152                         return NULL;
3153                 }
3154
3155                 // Check the list of nodes
3156                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
3157                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
3158         }
3159
3160         while(recvline(fd, line, sizeof(line))) {
3161                 char item[4096];
3162                 int n = sscanf(line, "%d %d %4095s", &code, &req, item);
3163
3164                 if(n == 2) {
3165                         i++;
3166
3167                         if(i >= 2) {
3168                                 break;
3169                         } else {
3170                                 continue;
3171                         }
3172                 }
3173
3174                 if(n != 3) {
3175                         fprintf(stderr, "Unable to parse dump from tincd, n = %d, i = %d.\n", n, i);
3176                         break;
3177                 }
3178
3179                 if(!strncmp(item, text, strlen(text))) {
3180                         return xstrdup(strip_weight(item));
3181                 }
3182         }
3183
3184         return NULL;
3185 }
3186
3187 static char *complete_nothing(const char *text, int state) {
3188         (void)text;
3189         (void)state;
3190         return NULL;
3191 }
3192
3193 static char **completion(const char *text, int start, int end) {
3194         (void)end;
3195         char **matches = NULL;
3196
3197         if(!start) {
3198                 matches = rl_completion_matches(text, complete_command);
3199         } else if(!strncasecmp(rl_line_buffer, "dump ", 5)) {
3200                 matches = rl_completion_matches(text, complete_dump);
3201         } else if(!strncasecmp(rl_line_buffer, "add ", 4)) {
3202                 matches = rl_completion_matches(text, complete_config);
3203         } else if(!strncasecmp(rl_line_buffer, "del ", 4)) {
3204                 matches = rl_completion_matches(text, complete_config);
3205         } else if(!strncasecmp(rl_line_buffer, "get ", 4)) {
3206                 matches = rl_completion_matches(text, complete_config);
3207         } else if(!strncasecmp(rl_line_buffer, "set ", 4)) {
3208                 matches = rl_completion_matches(text, complete_config);
3209         } else if(!strncasecmp(rl_line_buffer, "info ", 5)) {
3210                 matches = rl_completion_matches(text, complete_info);
3211         }
3212
3213         return matches;
3214 }
3215 #endif
3216
3217 static int cmd_shell(int argc, char *argv[]) {
3218         xasprintf(&prompt, "%s> ", identname);
3219         int result = 0;
3220         char buf[4096];
3221         char *line = NULL;
3222         int maxargs = argc + 16;
3223         char **nargv = xmalloc(maxargs * sizeof(*nargv));
3224
3225         for(int i = 0; i < argc; i++) {
3226                 nargv[i] = argv[i];
3227         }
3228
3229 #ifdef HAVE_READLINE
3230         rl_readline_name = "tinc";
3231         rl_basic_word_break_characters = "\t\n ";
3232         rl_completion_entry_function = complete_nothing;
3233         rl_attempted_completion_function = completion;
3234         rl_filename_completion_desired = 0;
3235         char *copy = NULL;
3236 #endif
3237
3238         while(true) {
3239 #ifdef HAVE_READLINE
3240
3241                 if(tty) {
3242                         free(copy);
3243                         free(line);
3244                         line = readline(prompt);
3245                         copy = line ? xstrdup(line) : NULL;
3246                 } else {
3247                         line = fgets(buf, sizeof(buf), stdin);
3248                 }
3249
3250 #else
3251
3252                 if(tty) {
3253                         fputs(prompt, stdout);
3254                 }
3255
3256                 line = fgets(buf, sizeof(buf), stdin);
3257 #endif
3258
3259                 if(!line) {
3260                         break;
3261                 }
3262
3263                 /* Ignore comments */
3264
3265                 if(*line == '#') {
3266                         continue;
3267                 }
3268
3269                 /* Split */
3270
3271                 int nargc = argc;
3272                 char *p = line + strspn(line, " \t\n");
3273                 char *next = strtok(p, " \t\n");
3274
3275                 while(p && *p) {
3276                         if(nargc >= maxargs) {
3277                                 maxargs *= 2;
3278                                 nargv = xrealloc(nargv, maxargs * sizeof(*nargv));
3279                         }
3280
3281                         nargv[nargc++] = p;
3282                         p = next;
3283                         next = strtok(NULL, " \t\n");
3284                 }
3285
3286                 if(nargc == argc) {
3287                         continue;
3288                 }
3289
3290                 if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit")) {
3291 #ifdef HAVE_READLINE
3292                         free(copy);
3293 #endif
3294                         free(nargv);
3295                         return result;
3296                 }
3297
3298                 bool found = false;
3299
3300                 for(int i = 0; commands[i].command; i++) {
3301                         if(!strcasecmp(nargv[argc], commands[i].command)) {
3302                                 result |= commands[i].function(nargc - argc - 1, nargv + argc + 1);
3303                                 found = true;
3304                                 break;
3305                         }
3306                 }
3307
3308 #ifdef HAVE_READLINE
3309
3310                 if(tty && found) {
3311                         add_history(copy);
3312                 }
3313
3314 #endif
3315
3316                 if(!found) {
3317                         fprintf(stderr, "Unknown command `%s'.\n", nargv[argc]);
3318                         result |= 1;
3319                 }
3320         }
3321
3322 #ifdef HAVE_READLINE
3323         free(copy);
3324 #endif
3325         free(nargv);
3326
3327         if(tty) {
3328                 printf("\n");
3329         }
3330
3331         return result;
3332 }
3333
3334 static void cleanup(void) {
3335         free(tinc_conf);
3336         free(hosts_dir);
3337         free_names();
3338 }
3339
3340 static int run_command(int argc, char *argv[]) {
3341         if(optind >= argc) {
3342                 return cmd_shell(argc, argv);
3343         }
3344
3345         for(int i = 0; commands[i].command; i++) {
3346                 if(!strcasecmp(argv[optind], commands[i].command)) {
3347                         return commands[i].function(argc - optind, argv + optind);
3348                 }
3349         }
3350
3351         fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
3352         usage(true);
3353         return 1;
3354 }
3355
3356 int main(int argc, char *argv[]) {
3357         program_name = argv[0];
3358         orig_argv = argv;
3359         tty = isatty(0) && isatty(1);
3360
3361         if(!parse_options(argc, argv)) {
3362                 return 1;
3363         }
3364
3365         make_names(false);
3366         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
3367         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
3368         atexit(cleanup);
3369
3370         if(show_version) {
3371                 version();
3372                 return 0;
3373         }
3374
3375         if(show_help) {
3376                 usage(false);
3377                 return 0;
3378         }
3379
3380 #ifdef HAVE_WINDOWS
3381         static struct WSAData wsa_state;
3382
3383         if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
3384                 fprintf(stderr, "System call `%s' failed: %s\n", "WSAStartup", winerror(GetLastError()));
3385                 return false;
3386         }
3387
3388 #endif
3389
3390         gettimeofday(&now, NULL);
3391         random_init();
3392         crypto_init();
3393         prng_init();
3394
3395         sandbox_set_level(SANDBOX_NORMAL);
3396         sandbox_enter();
3397
3398         int result = run_command(argc, argv);
3399
3400         random_exit();
3401
3402         return result;
3403 }