Add basic pledge/unveil sandbox on OpenBSD
[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         fprintf(stderr, "\n");
1523         shutdown(fd, SHUT_RDWR);
1524 }
1525 #endif
1526
1527 static int cmd_log(int argc, char *argv[]) {
1528         if(argc > 2) {
1529                 fprintf(stderr, "Too many arguments!\n");
1530                 return 1;
1531         }
1532
1533         if(!connect_tincd(true)) {
1534                 return 1;
1535         }
1536
1537 #ifdef SIGINT
1538         signal(SIGINT, sigint_handler);
1539 #endif
1540
1541         bool use_color = use_ansi_escapes(stdout);
1542         log_control(fd, stdout, argc > 1 ? atoi(argv[1]) : DEBUG_UNSET, use_color);
1543
1544 #ifdef SIGINT
1545         signal(SIGINT, SIG_DFL);
1546 #endif
1547
1548         closesocket(fd);
1549         fd = -1;
1550         return 0;
1551 }
1552
1553 static int cmd_pid(int argc, char *argv[]) {
1554         (void)argv;
1555
1556         if(argc > 1) {
1557                 fprintf(stderr, "Too many arguments!\n");
1558                 return 1;
1559         }
1560
1561         if(!connect_tincd(true) || !pid) {
1562                 return 1;
1563         }
1564
1565         printf("%d\n", pid);
1566         return 0;
1567 }
1568
1569 size_t rstrip(char *value) {
1570         size_t len = strlen(value);
1571
1572         while(len && strchr("\t\r\n ", value[len - 1])) {
1573                 value[--len] = 0;
1574         }
1575
1576         return len;
1577 }
1578
1579 char *get_my_name(bool verbose) {
1580         FILE *f = fopen(tinc_conf, "r");
1581
1582         if(!f) {
1583                 if(verbose) {
1584                         fprintf(stderr, "Could not open %s: %s\n", tinc_conf, strerror(errno));
1585                 }
1586
1587                 return NULL;
1588         }
1589
1590         char buf[4096];
1591         char *value;
1592
1593         while(fgets(buf, sizeof(buf), f)) {
1594                 size_t len = strcspn(buf, "\t =");
1595                 value = buf + len;
1596                 value += strspn(value, "\t ");
1597
1598                 if(*value == '=') {
1599                         value++;
1600                         value += strspn(value, "\t ");
1601                 }
1602
1603                 if(!rstrip(value)) {
1604                         continue;
1605                 }
1606
1607                 buf[len] = 0;
1608
1609                 if(strcasecmp(buf, "Name")) {
1610                         continue;
1611                 }
1612
1613                 if(*value) {
1614                         fclose(f);
1615                         return replace_name(value);
1616                 }
1617         }
1618
1619         fclose(f);
1620
1621         if(verbose) {
1622                 fprintf(stderr, "Could not find Name in %s.\n", tinc_conf);
1623         }
1624
1625         return NULL;
1626 }
1627
1628 static ecdsa_t *get_pubkey(FILE *f) ATTR_MALLOC ATTR_DEALLOCATOR(ecdsa_free);
1629 static ecdsa_t *get_pubkey(FILE *f) {
1630         char buf[4096];
1631         char *value;
1632
1633         while(fgets(buf, sizeof(buf), f)) {
1634                 size_t len = strcspn(buf, "\t =");
1635                 value = buf + len;
1636                 value += strspn(value, "\t ");
1637
1638                 if(*value == '=') {
1639                         value++;
1640                         value += strspn(value, "\t ");
1641                 }
1642
1643                 if(!rstrip(value)) {
1644                         continue;
1645                 }
1646
1647                 buf[len] = 0;
1648
1649                 if(strcasecmp(buf, "Ed25519PublicKey")) {
1650                         continue;
1651                 }
1652
1653                 if(*value) {
1654                         return ecdsa_set_base64_public_key(value);
1655                 }
1656         }
1657
1658         return NULL;
1659 }
1660
1661 const var_t variables[] = {
1662         /* Server configuration */
1663         {"AddressFamily", VAR_SERVER | VAR_SAFE},
1664         {"AutoConnect", VAR_SERVER | VAR_SAFE},
1665         {"BindToAddress", VAR_SERVER | VAR_MULTIPLE},
1666         {"BindToInterface", VAR_SERVER},
1667         {"Broadcast", VAR_SERVER | VAR_SAFE},
1668         {"BroadcastSubnet", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
1669         {"ConnectTo", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE},
1670         {"DecrementTTL", VAR_SERVER | VAR_SAFE},
1671         {"Device", VAR_SERVER},
1672         {"DeviceStandby", VAR_SERVER},
1673         {"DeviceType", VAR_SERVER},
1674         {"DirectOnly", VAR_SERVER | VAR_SAFE},
1675         {"Ed25519PrivateKeyFile", VAR_SERVER},
1676         {"ExperimentalProtocol", VAR_SERVER},
1677         {"Forwarding", VAR_SERVER},
1678         {"FWMark", VAR_SERVER},
1679         {"GraphDumpFile", VAR_SERVER | VAR_OBSOLETE},
1680         {"Hostnames", VAR_SERVER},
1681         {"IffOneQueue", VAR_SERVER},
1682         {"Interface", VAR_SERVER},
1683         {"InvitationExpire", VAR_SERVER},
1684         {"KeyExpire", VAR_SERVER | VAR_SAFE},
1685         {"ListenAddress", VAR_SERVER | VAR_MULTIPLE},
1686         {"LocalDiscovery", VAR_SERVER | VAR_SAFE},
1687         {"LogLevel", VAR_SERVER},
1688         {"MACExpire", VAR_SERVER | VAR_SAFE},
1689         {"MaxConnectionBurst", VAR_SERVER | VAR_SAFE},
1690         {"MaxOutputBufferSize", VAR_SERVER | VAR_SAFE},
1691         {"MaxTimeout", VAR_SERVER | VAR_SAFE},
1692         {"Mode", VAR_SERVER | VAR_SAFE},
1693         {"Name", VAR_SERVER},
1694         {"PingInterval", VAR_SERVER | VAR_SAFE},
1695         {"PingTimeout", VAR_SERVER | VAR_SAFE},
1696         {"PriorityInheritance", VAR_SERVER},
1697         {"PrivateKey", VAR_SERVER | VAR_OBSOLETE},
1698         {"PrivateKeyFile", VAR_SERVER},
1699         {"ProcessPriority", VAR_SERVER},
1700         {"Proxy", VAR_SERVER},
1701         {"ReplayWindow", VAR_SERVER | VAR_SAFE},
1702         {"Sandbox", VAR_SERVER},
1703         {"ScriptsExtension", VAR_SERVER},
1704         {"ScriptsInterpreter", VAR_SERVER},
1705         {"StrictSubnets", VAR_SERVER | VAR_SAFE},
1706         {"TunnelServer", VAR_SERVER | VAR_SAFE},
1707         {"UDPDiscovery", VAR_SERVER | VAR_SAFE},
1708         {"UDPDiscoveryKeepaliveInterval", VAR_SERVER | VAR_SAFE},
1709         {"UDPDiscoveryInterval", VAR_SERVER | VAR_SAFE},
1710         {"UDPDiscoveryTimeout", VAR_SERVER | VAR_SAFE},
1711         {"MTUInfoInterval", VAR_SERVER | VAR_SAFE},
1712         {"UDPInfoInterval", VAR_SERVER | VAR_SAFE},
1713         {"UDPRcvBuf", VAR_SERVER},
1714         {"UDPSndBuf", VAR_SERVER},
1715         {"UPnP", VAR_SERVER},
1716         {"UPnPDiscoverWait", VAR_SERVER},
1717         {"UPnPRefreshPeriod", VAR_SERVER},
1718         {"VDEGroup", VAR_SERVER},
1719         {"VDEPort", VAR_SERVER},
1720         /* Host configuration */
1721         {"Address", VAR_HOST | VAR_MULTIPLE},
1722         {"Cipher", VAR_SERVER | VAR_HOST},
1723         {"ClampMSS", VAR_SERVER | VAR_HOST | VAR_SAFE},
1724         {"Compression", VAR_SERVER | VAR_HOST | VAR_SAFE},
1725         {"Digest", VAR_SERVER | VAR_HOST},
1726         {"Ed25519PublicKey", VAR_HOST},
1727         {"Ed25519PublicKeyFile", VAR_SERVER | VAR_HOST},
1728         {"IndirectData", VAR_SERVER | VAR_HOST | VAR_SAFE},
1729         {"MACLength", VAR_SERVER | VAR_HOST},
1730         {"PMTU", VAR_SERVER | VAR_HOST},
1731         {"PMTUDiscovery", VAR_SERVER | VAR_HOST},
1732         {"Port", VAR_HOST},
1733         {"PublicKey", VAR_HOST | VAR_OBSOLETE},
1734         {"PublicKeyFile", VAR_SERVER | VAR_HOST | VAR_OBSOLETE},
1735         {"Subnet", VAR_HOST | VAR_MULTIPLE | VAR_SAFE},
1736         {"TCPOnly", VAR_SERVER | VAR_HOST | VAR_SAFE},
1737         {"Weight", VAR_HOST | VAR_SAFE},
1738         {NULL, 0}
1739 };
1740
1741 // Request actual port from tincd
1742 static bool read_actual_port(void) {
1743         pidfile_t *pidfile = read_pidfile();
1744
1745         if(pidfile) {
1746                 printf("%s\n", pidfile->port);
1747                 free(pidfile);
1748                 return true;
1749         } else {
1750                 fprintf(stderr, "Could not get port from the pidfile.\n");
1751                 return false;
1752         }
1753 }
1754
1755 static int cmd_config(int argc, char *argv[]) {
1756         if(argc < 2) {
1757                 fprintf(stderr, "Invalid number of arguments.\n");
1758                 return 1;
1759         }
1760
1761         if(strcasecmp(argv[0], "config")) {
1762                 argv--, argc++;
1763         }
1764
1765         typedef enum { GET, DEL, SET, ADD } action_t;
1766         action_t action = GET;
1767
1768         if(!strcasecmp(argv[1], "get")) {
1769                 argv++, argc--;
1770         } else if(!strcasecmp(argv[1], "add")) {
1771                 argv++, argc--, action = ADD;
1772         } else if(!strcasecmp(argv[1], "del")) {
1773                 argv++, argc--, action = DEL;
1774         } else if(!strcasecmp(argv[1], "replace") || !strcasecmp(argv[1], "set") || !strcasecmp(argv[1], "change")) {
1775                 argv++, argc--, action = SET;
1776         }
1777
1778         if(argc < 2) {
1779                 fprintf(stderr, "Invalid number of arguments.\n");
1780                 return 1;
1781         }
1782
1783         // Concatenate the rest of the command line
1784         strncpy(line, argv[1], sizeof(line) - 1);
1785
1786         for(int i = 2; i < argc; i++) {
1787                 strncat(line, " ", sizeof(line) - 1 - strlen(line));
1788                 strncat(line, argv[i], sizeof(line) - 1 - strlen(line));
1789         }
1790
1791         // Liberal parsing into node name, variable name and value.
1792         char *node = NULL;
1793         char *variable;
1794         char *value;
1795         size_t len;
1796
1797         len = strcspn(line, "\t =");
1798         value = line + len;
1799         value += strspn(value, "\t ");
1800
1801         if(*value == '=') {
1802                 value++;
1803                 value += strspn(value, "\t ");
1804         }
1805
1806         line[len] = '\0';
1807         variable = strchr(line, '.');
1808
1809         if(variable) {
1810                 node = line;
1811                 *variable++ = 0;
1812         } else {
1813                 variable = line;
1814         }
1815
1816         if(!*variable) {
1817                 fprintf(stderr, "No variable given.\n");
1818                 return 1;
1819         }
1820
1821         if((action == SET || action == ADD) && !*value) {
1822                 fprintf(stderr, "No value for variable given.\n");
1823                 return 1;
1824         }
1825
1826         if(action == GET && *value) {
1827                 action = SET;
1828         }
1829
1830         // If port is requested, try reading it from the pidfile and fall back to configs if that fails
1831         if(action == GET && !strcasecmp(variable, "Port") && read_actual_port()) {
1832                 return 0;
1833         }
1834
1835         /* Some simple checks. */
1836         bool found = false;
1837         bool warnonremove = false;
1838
1839         for(int i = 0; variables[i].name; i++) {
1840                 if(strcasecmp(variables[i].name, variable)) {
1841                         continue;
1842                 }
1843
1844                 found = true;
1845                 variable = (char *)variables[i].name;
1846
1847                 if(!strcasecmp(variable, "Subnet") && *value) {
1848                         subnet_t s = {0};
1849
1850                         if(!str2net(&s, value)) {
1851                                 fprintf(stderr, "Malformed subnet definition %s\n", value);
1852                                 return 1;
1853                         }
1854
1855                         if(!subnetcheck(s)) {
1856                                 fprintf(stderr, "Network address and prefix length do not match: %s\n", value);
1857                                 return 1;
1858                         }
1859                 }
1860
1861                 /* Discourage use of obsolete variables. */
1862
1863                 if(variables[i].type & VAR_OBSOLETE && (action == SET || action == ADD)) {
1864                         if(force) {
1865                                 fprintf(stderr, "Warning: %s is an obsolete variable!\n", variable);
1866                         } else {
1867                                 fprintf(stderr, "%s is an obsolete variable! Use --force to use it anyway.\n", variable);
1868                                 return 1;
1869                         }
1870                 }
1871
1872                 /* Don't put server variables in host config files */
1873
1874                 if(node && !(variables[i].type & VAR_HOST) && (action == SET || action == ADD)) {
1875                         if(force) {
1876                                 fprintf(stderr, "Warning: %s is not a host configuration variable!\n", variable);
1877                         } else {
1878                                 fprintf(stderr, "%s is not a host configuration variable! Use --force to use it anyway.\n", variable);
1879                                 return 1;
1880                         }
1881                 }
1882
1883                 /* Should this go into our own host config file? */
1884
1885                 if(!node && !(variables[i].type & VAR_SERVER)) {
1886                         node = get_my_name(true);
1887
1888                         if(!node) {
1889                                 return 1;
1890                         }
1891                 }
1892
1893                 /* Change "add" into "set" for variables that do not allow multiple occurrences.
1894                    Turn on warnings when it seems variables might be removed unintentionally. */
1895
1896                 if(action == ADD && !(variables[i].type & VAR_MULTIPLE)) {
1897                         warnonremove = true;
1898                         action = SET;
1899                 } else if(action == SET && (variables[i].type & VAR_MULTIPLE)) {
1900                         warnonremove = true;
1901                 }
1902
1903                 break;
1904         }
1905
1906         if(node && !check_id(node)) {
1907                 fprintf(stderr, "Invalid name for node.\n");
1908
1909                 if(node != line) {
1910                         free(node);
1911                 }
1912
1913                 return 1;
1914         }
1915
1916         if(!found) {
1917                 if(force || action == GET || action == DEL) {
1918                         fprintf(stderr, "Warning: %s is not a known configuration variable!\n", variable);
1919                 } else {
1920                         fprintf(stderr, "%s: is not a known configuration variable! Use --force to use it anyway.\n", variable);
1921
1922                         if(node && node != line) {
1923                                 free(node);
1924                         }
1925
1926                         return 1;
1927                 }
1928         }
1929
1930         // Open the right configuration file.
1931         char filename[PATH_MAX];
1932
1933         if(node) {
1934                 if((size_t)snprintf(filename, sizeof(filename), "%s" SLASH "%s", hosts_dir, node) >= sizeof(filename)) {
1935                         fprintf(stderr, "Filename too long: %s" SLASH "%s\n", hosts_dir, node);
1936                         free(node);
1937                         return 1;
1938                 }
1939
1940                 if(node != line) {
1941                         free(node);
1942                         node = NULL;
1943                 }
1944         } else {
1945                 snprintf(filename, sizeof(filename), "%s", tinc_conf);
1946         }
1947
1948         FILE *f = fopen(filename, "r");
1949
1950         if(!f) {
1951                 fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
1952                 return 1;
1953         }
1954
1955         char tmpfile[PATH_MAX];
1956         FILE *tf = NULL;
1957
1958         if(action != GET) {
1959                 if((size_t)snprintf(tmpfile, sizeof(tmpfile), "%s.config.tmp", filename) >= sizeof(tmpfile)) {
1960                         fprintf(stderr, "Filename too long: %s.config.tmp\n", filename);
1961                         return 1;
1962                 }
1963
1964                 tf = fopen(tmpfile, "w");
1965
1966                 if(!tf) {
1967                         fprintf(stderr, "Could not open temporary file %s: %s\n", tmpfile, strerror(errno));
1968                         fclose(f);
1969                         return 1;
1970                 }
1971         }
1972
1973         // Copy the file, making modifications on the fly, unless we are just getting a value.
1974         char buf1[4096];
1975         char buf2[4096];
1976         bool set = false;
1977         bool removed = false;
1978         found = false;
1979
1980         while(fgets(buf1, sizeof(buf1), f)) {
1981                 buf1[sizeof(buf1) - 1] = 0;
1982                 strncpy(buf2, buf1, sizeof(buf2));
1983
1984                 // Parse line in a simple way
1985                 char *bvalue;
1986
1987                 size_t len = strcspn(buf2, "\t =");
1988                 bvalue = buf2 + len;
1989                 bvalue += strspn(bvalue, "\t ");
1990
1991                 if(*bvalue == '=') {
1992                         bvalue++;
1993                         bvalue += strspn(bvalue, "\t ");
1994                 }
1995
1996                 rstrip(bvalue);
1997                 buf2[len] = '\0';
1998
1999                 // Did it match?
2000                 if(!strcasecmp(buf2, variable)) {
2001                         if(action == GET) {
2002                                 found = true;
2003                                 printf("%s\n", bvalue);
2004                         } else if(action == DEL) {
2005                                 if(!*value || !strcasecmp(bvalue, value)) {
2006                                         removed = true;
2007                                         continue;
2008                                 }
2009                         } else if(action == SET) {
2010                                 // Warn if "set" was used for variables that can occur multiple times
2011                                 if(warnonremove && strcasecmp(bvalue, value)) {
2012                                         fprintf(stderr, "Warning: removing %s = %s\n", variable, bvalue);
2013                                 }
2014
2015                                 // Already set? Delete the rest...
2016                                 if(set) {
2017                                         continue;
2018                                 }
2019
2020                                 // Otherwise, replace.
2021                                 if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
2022                                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
2023                                         return 1;
2024                                 }
2025
2026                                 set = true;
2027                                 continue;
2028                         } else if(action == ADD) {
2029                                 // Check if we've already seen this variable with the same value
2030                                 if(!strcasecmp(bvalue, value)) {
2031                                         found = true;
2032                                 }
2033                         }
2034                 }
2035
2036                 if(action != GET) {
2037                         // Copy original line...
2038                         if(fputs(buf1, tf) < 0) {
2039                                 fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
2040                                 return 1;
2041                         }
2042
2043                         // Add newline if it is missing...
2044                         if(*buf1 && buf1[strlen(buf1) - 1] != '\n') {
2045                                 if(fputc('\n', tf) < 0) {
2046                                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
2047                                         return 1;
2048                                 }
2049                         }
2050                 }
2051         }
2052
2053         // Make sure we read everything...
2054         if(ferror(f) || !feof(f)) {
2055                 fprintf(stderr, "Error while reading from configuration file %s: %s\n", filename, strerror(errno));
2056                 return 1;
2057         }
2058
2059         if(fclose(f)) {
2060                 fprintf(stderr, "Error closing configuration file %s: %s\n", filename, strerror(errno));
2061                 return 1;
2062         }
2063
2064         // Add new variable if necessary.
2065         if((action == ADD && !found) || (action == SET && !set)) {
2066                 if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
2067                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
2068                         return 1;
2069                 }
2070         }
2071
2072         if(action == GET) {
2073                 if(found) {
2074                         return 0;
2075                 } else {
2076                         fprintf(stderr, "No matching configuration variables found.\n");
2077                         return 1;
2078                 }
2079         }
2080
2081         // Make sure we wrote everything...
2082         if(fclose(tf)) {
2083                 fprintf(stderr, "Error closing temporary file %s: %s\n", tmpfile, strerror(errno));
2084                 return 1;
2085         }
2086
2087         // Could we find what we had to remove?
2088         if((action == GET || action == DEL) && !removed) {
2089                 remove(tmpfile);
2090                 fprintf(stderr, "No configuration variables deleted.\n");
2091                 return 1;
2092         }
2093
2094         // Replace the configuration file with the new one
2095 #ifdef HAVE_WINDOWS
2096
2097         if(remove(filename)) {
2098                 fprintf(stderr, "Error replacing file %s: %s\n", filename, strerror(errno));
2099                 return 1;
2100         }
2101
2102 #endif
2103
2104         if(rename(tmpfile, filename)) {
2105                 fprintf(stderr, "Error renaming temporary file %s to configuration file %s: %s\n", tmpfile, filename, strerror(errno));
2106                 return 1;
2107         }
2108
2109         // Silently try notifying a running tincd of changes.
2110         if(connect_tincd(false)) {
2111                 sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
2112         }
2113
2114         return 0;
2115 }
2116
2117 static bool try_bind(int port) {
2118         struct addrinfo *ai = NULL, *aip;
2119         struct addrinfo hint = {
2120                 .ai_flags = AI_PASSIVE,
2121                 .ai_family = AF_UNSPEC,
2122                 .ai_socktype = SOCK_STREAM,
2123                 .ai_protocol = IPPROTO_TCP,
2124         };
2125
2126         bool success = true;
2127         char portstr[16];
2128         snprintf(portstr, sizeof(portstr), "%d", port);
2129
2130         if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai) {
2131                 return false;
2132         }
2133
2134         for(aip = ai; aip; aip = aip->ai_next) {
2135                 int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
2136
2137                 if(!fd) {
2138                         success = false;
2139                         break;
2140                 }
2141
2142                 int result = bind(fd, ai->ai_addr, ai->ai_addrlen);
2143                 closesocket(fd);
2144
2145                 if(result) {
2146                         success = false;
2147                         break;
2148                 }
2149         }
2150
2151         freeaddrinfo(ai);
2152         return success;
2153 }
2154
2155 int check_port(const char *name) {
2156         if(try_bind(655)) {
2157                 return 655;
2158         }
2159
2160         fprintf(stderr, "Warning: could not bind to port 655. ");
2161
2162         for(int i = 0; i < 100; i++) {
2163                 uint16_t port = 0x1000 + prng(0x8000);
2164
2165                 if(try_bind(port)) {
2166                         char filename[PATH_MAX];
2167                         snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", confbase, name);
2168                         FILE *f = fopen(filename, "a");
2169
2170                         if(!f) {
2171                                 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
2172                                 fprintf(stderr, "Please change tinc's Port manually.\n");
2173                                 return 0;
2174                         }
2175
2176                         fprintf(f, "Port = %d\n", port);
2177                         fclose(f);
2178                         fprintf(stderr, "Tinc will instead listen on port %d.\n", port);
2179                         return port;
2180                 }
2181         }
2182
2183         fprintf(stderr, "Please change tinc's Port manually.\n");
2184         return 0;
2185 }
2186
2187 static int cmd_init(int argc, char *argv[]) {
2188         if(!access(tinc_conf, F_OK)) {
2189                 fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
2190                 return 1;
2191         }
2192
2193         if(argc > 2) {
2194                 fprintf(stderr, "Too many arguments!\n");
2195                 return 1;
2196         } else if(argc < 2) {
2197                 if(tty) {
2198                         char buf[1024];
2199                         fprintf(stderr, "Enter the Name you want your tinc node to have: ");
2200
2201                         if(!fgets(buf, sizeof(buf), stdin)) {
2202                                 fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
2203                                 return 1;
2204                         }
2205
2206                         size_t len = rstrip(buf);
2207
2208                         if(!len) {
2209                                 fprintf(stderr, "No name given!\n");
2210                                 return 1;
2211                         }
2212
2213                         name = strdup(buf);
2214                 } else {
2215                         fprintf(stderr, "No Name given!\n");
2216                         return 1;
2217                 }
2218         } else {
2219                 name = strdup(argv[1]);
2220
2221                 if(!*name) {
2222                         fprintf(stderr, "No Name given!\n");
2223                         return 1;
2224                 }
2225         }
2226
2227         if(!check_id(name)) {
2228                 fprintf(stderr, "Invalid Name! Only a-z, A-Z, 0-9 and _ are allowed characters.\n");
2229                 return 1;
2230         }
2231
2232         if(!confbase_given && mkdir(confdir, 0755) && errno != EEXIST) {
2233                 fprintf(stderr, "Could not create directory %s: %s\n", confdir, strerror(errno));
2234                 return 1;
2235         }
2236
2237         if(mkdir(confbase, 0777) && errno != EEXIST) {
2238                 fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno));
2239                 return 1;
2240         }
2241
2242         if(mkdir(hosts_dir, 0777) && errno != EEXIST) {
2243                 fprintf(stderr, "Could not create directory %s: %s\n", hosts_dir, strerror(errno));
2244                 return 1;
2245         }
2246
2247         FILE *f = fopen(tinc_conf, "w");
2248
2249         if(!f) {
2250                 fprintf(stderr, "Could not create file %s: %s\n", tinc_conf, strerror(errno));
2251                 return 1;
2252         }
2253
2254         fprintf(f, "Name = %s\n", name);
2255         fclose(f);
2256
2257 #ifndef DISABLE_LEGACY
2258
2259         if(!rsa_keygen(2048, false)) {
2260                 return 1;
2261         }
2262
2263 #endif
2264
2265         if(!ed25519_keygen(false)) {
2266                 return 1;
2267         }
2268
2269         check_port(name);
2270
2271 #ifndef HAVE_WINDOWS
2272         char filename[PATH_MAX];
2273         snprintf(filename, sizeof(filename), "%s" SLASH "tinc-up", confbase);
2274
2275         if(access(filename, F_OK)) {
2276                 FILE *f = fopenmask(filename, "w", 0777);
2277
2278                 if(!f) {
2279                         fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
2280                         return 1;
2281                 }
2282
2283                 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");
2284                 fclose(f);
2285         }
2286
2287 #endif
2288
2289         return 0;
2290
2291 }
2292
2293 static int cmd_generate_keys(int argc, char *argv[]) {
2294 #ifdef DISABLE_LEGACY
2295         (void)argv;
2296
2297         if(argc > 1) {
2298 #else
2299
2300         if(argc > 2) {
2301 #endif
2302                 fprintf(stderr, "Too many arguments!\n");
2303                 return 1;
2304         }
2305
2306         if(!name) {
2307                 name = get_my_name(false);
2308         }
2309
2310 #ifndef DISABLE_LEGACY
2311
2312         if(!rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true)) {
2313                 return 1;
2314         }
2315
2316 #endif
2317
2318         if(!ed25519_keygen(true)) {
2319                 return 1;
2320         }
2321
2322         return 0;
2323 }
2324
2325 #ifndef DISABLE_LEGACY
2326 static int cmd_generate_rsa_keys(int argc, char *argv[]) {
2327         if(argc > 2) {
2328                 fprintf(stderr, "Too many arguments!\n");
2329                 return 1;
2330         }
2331
2332         if(!name) {
2333                 name = get_my_name(false);
2334         }
2335
2336         return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
2337 }
2338 #endif
2339
2340 static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
2341         (void)argv;
2342
2343         if(argc > 1) {
2344                 fprintf(stderr, "Too many arguments!\n");
2345                 return 1;
2346         }
2347
2348         if(!name) {
2349                 name = get_my_name(false);
2350         }
2351
2352         return !ed25519_keygen(true);
2353 }
2354
2355 static int cmd_help(int argc, char *argv[]) {
2356         (void)argc;
2357         (void)argv;
2358
2359         usage(false);
2360         return 0;
2361 }
2362
2363 static int cmd_version(int argc, char *argv[]) {
2364         (void)argv;
2365
2366         if(argc > 1) {
2367                 fprintf(stderr, "Too many arguments!\n");
2368                 return 1;
2369         }
2370
2371         version();
2372         return 0;
2373 }
2374
2375 static int cmd_info(int argc, char *argv[]) {
2376         if(argc != 2) {
2377                 fprintf(stderr, "Invalid number of arguments.\n");
2378                 return 1;
2379         }
2380
2381         if(!connect_tincd(true)) {
2382                 return 1;
2383         }
2384
2385         return info(fd, argv[1]);
2386 }
2387
2388 static const char *conffiles[] = {
2389         "tinc.conf",
2390         "tinc-up",
2391         "tinc-down",
2392         "subnet-up",
2393         "subnet-down",
2394         "host-up",
2395         "host-down",
2396         NULL,
2397 };
2398
2399 static int cmd_edit(int argc, char *argv[]) {
2400         if(argc != 2) {
2401                 fprintf(stderr, "Invalid number of arguments.\n");
2402                 return 1;
2403         }
2404
2405         char filename[PATH_MAX] = "";
2406
2407         if(strncmp(argv[1], "hosts" SLASH, 6)) {
2408                 for(int i = 0; conffiles[i]; i++) {
2409                         if(!strcmp(argv[1], conffiles[i])) {
2410                                 snprintf(filename, sizeof(filename), "%s" SLASH "%s", confbase, argv[1]);
2411                                 break;
2412                         }
2413                 }
2414         } else {
2415                 argv[1] += 6;
2416         }
2417
2418         if(!*filename) {
2419                 snprintf(filename, sizeof(filename), "%s" SLASH "%s", hosts_dir, argv[1]);
2420                 char *dash = strchr(argv[1], '-');
2421
2422                 if(dash) {
2423                         *dash++ = 0;
2424
2425                         if((strcmp(dash, "up") && strcmp(dash, "down")) || !check_id(argv[1])) {
2426                                 fprintf(stderr, "Invalid configuration filename.\n");
2427                                 return 1;
2428                         }
2429                 }
2430         }
2431
2432         char *command;
2433 #ifndef HAVE_WINDOWS
2434         const char *editor = getenv("VISUAL");
2435
2436         if(!editor) {
2437                 editor = getenv("EDITOR");
2438         }
2439
2440         if(!editor) {
2441                 editor = "vi";
2442         }
2443
2444         xasprintf(&command, "\"%s\" \"%s\"", editor, filename);
2445 #else
2446         xasprintf(&command, "edit \"%s\"", filename);
2447 #endif
2448         int result = system(command);
2449         free(command);
2450
2451         if(result) {
2452                 return result;
2453         }
2454
2455         // Silently try notifying a running tincd of changes.
2456         if(connect_tincd(false)) {
2457                 sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
2458         }
2459
2460         return 0;
2461 }
2462
2463 static int export(const char *name, FILE *out) {
2464         char filename[PATH_MAX];
2465         snprintf(filename, sizeof(filename), "%s" SLASH "%s", hosts_dir, name);
2466         FILE *in = fopen(filename, "r");
2467
2468         if(!in) {
2469                 fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
2470                 return 1;
2471         }
2472
2473         fprintf(out, "Name = %s\n", name);
2474         char buf[4096];
2475
2476         while(fgets(buf, sizeof(buf), in)) {
2477                 if(strcspn(buf, "\t =") != 4 || strncasecmp(buf, "Name", 4)) {
2478                         fputs(buf, out);
2479                 }
2480         }
2481
2482         if(ferror(in)) {
2483                 fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno));
2484                 fclose(in);
2485                 return 1;
2486         }
2487
2488         fclose(in);
2489         return 0;
2490 }
2491
2492 static int cmd_export(int argc, char *argv[]) {
2493         (void)argv;
2494
2495         if(argc > 1) {
2496                 fprintf(stderr, "Too many arguments!\n");
2497                 return 1;
2498         }
2499
2500         char *name = get_my_name(true);
2501
2502         if(!name) {
2503                 return 1;
2504         }
2505
2506         int result = export(name, stdout);
2507
2508         if(!tty) {
2509                 fclose(stdout);
2510         }
2511
2512         free(name);
2513         return result;
2514 }
2515
2516 static int cmd_export_all(int argc, char *argv[]) {
2517         (void)argv;
2518
2519         if(argc > 1) {
2520                 fprintf(stderr, "Too many arguments!\n");
2521                 return 1;
2522         }
2523
2524         DIR *dir = opendir(hosts_dir);
2525
2526         if(!dir) {
2527                 fprintf(stderr, "Could not open host configuration directory %s: %s\n", hosts_dir, strerror(errno));
2528                 return 1;
2529         }
2530
2531         bool first = true;
2532         int result = 0;
2533         struct dirent *ent;
2534
2535         while((ent = readdir(dir))) {
2536                 if(!check_id(ent->d_name)) {
2537                         continue;
2538                 }
2539
2540                 if(first) {
2541                         first = false;
2542                 } else {
2543                         printf("#---------------------------------------------------------------#\n");
2544                 }
2545
2546                 result |= export(ent->d_name, stdout);
2547         }
2548
2549         closedir(dir);
2550
2551         if(!tty) {
2552                 fclose(stdout);
2553         }
2554
2555         return result;
2556 }
2557
2558 static int cmd_import(int argc, char *argv[]) {
2559         (void)argv;
2560
2561         if(argc > 1) {
2562                 fprintf(stderr, "Too many arguments!\n");
2563                 return 1;
2564         }
2565
2566         FILE *in = stdin;
2567         FILE *out = NULL;
2568
2569         char buf[4096];
2570         char name[4096];
2571         char filename[PATH_MAX] = "";
2572         int count = 0;
2573         bool firstline = true;
2574
2575         while(fgets(buf, sizeof(buf), in)) {
2576                 if(sscanf(buf, "Name = %4095s", name) == 1) {
2577                         firstline = false;
2578
2579                         if(!check_id(name)) {
2580                                 fprintf(stderr, "Invalid Name in input!\n");
2581                                 return 1;
2582                         }
2583
2584                         if(out) {
2585                                 fclose(out);
2586                         }
2587
2588                         if((size_t)snprintf(filename, sizeof(filename), "%s" SLASH "%s", hosts_dir, name) >= sizeof(filename)) {
2589                                 fprintf(stderr, "Filename too long: %s" SLASH "%s\n", hosts_dir, name);
2590                                 return 1;
2591                         }
2592
2593                         if(!force && !access(filename, F_OK)) {
2594                                 fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename);
2595                                 out = NULL;
2596                                 continue;
2597                         }
2598
2599                         out = fopen(filename, "w");
2600
2601                         if(!out) {
2602                                 fprintf(stderr, "Error creating configuration file %s: %s\n", filename, strerror(errno));
2603                                 return 1;
2604                         }
2605
2606                         count++;
2607                         continue;
2608                 } else if(firstline) {
2609                         fprintf(stderr, "Junk at the beginning of the input, ignoring.\n");
2610                         firstline = false;
2611                 }
2612
2613
2614                 if(!strcmp(buf, "#---------------------------------------------------------------#\n")) {
2615                         continue;
2616                 }
2617
2618                 if(out) {
2619                         if(fputs(buf, out) < 0) {
2620                                 fprintf(stderr, "Error writing to host configuration file %s: %s\n", filename, strerror(errno));
2621                                 return 1;
2622                         }
2623                 }
2624         }
2625
2626         if(out) {
2627                 fclose(out);
2628         }
2629
2630         if(count) {
2631                 fprintf(stderr, "Imported %d host configuration files.\n", count);
2632                 return 0;
2633         } else {
2634                 fprintf(stderr, "No host configuration files imported.\n");
2635                 return 1;
2636         }
2637 }
2638
2639 static int cmd_exchange(int argc, char *argv[]) {
2640         return cmd_export(argc, argv) ? 1 : cmd_import(argc, argv);
2641 }
2642
2643 static int cmd_exchange_all(int argc, char *argv[]) {
2644         return cmd_export_all(argc, argv) ? 1 : cmd_import(argc, argv);
2645 }
2646
2647 static int switch_network(char *name) {
2648         if(strcmp(name, ".")) {
2649                 if(!check_netname(name, false)) {
2650                         fprintf(stderr, "Invalid character in netname!\n");
2651                         return 1;
2652                 }
2653
2654                 if(!check_netname(name, true)) {
2655                         fprintf(stderr, "Warning: unsafe character in netname!\n");
2656                 }
2657         }
2658
2659         if(fd >= 0) {
2660                 closesocket(fd);
2661                 fd = -1;
2662         }
2663
2664         free_names();
2665         netname = strcmp(name, ".") ? xstrdup(name) : NULL;
2666         make_names(false);
2667
2668         free(tinc_conf);
2669         free(hosts_dir);
2670         free(prompt);
2671
2672         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
2673         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
2674         xasprintf(&prompt, "%s> ", identname);
2675
2676         return 0;
2677 }
2678
2679 static int cmd_network(int argc, char *argv[]) {
2680         if(argc > 2) {
2681                 fprintf(stderr, "Too many arguments!\n");
2682                 return 1;
2683         }
2684
2685         if(argc == 2) {
2686                 return switch_network(argv[1]);
2687         }
2688
2689         DIR *dir = opendir(confdir);
2690
2691         if(!dir) {
2692                 fprintf(stderr, "Could not read directory %s: %s\n", confdir, strerror(errno));
2693                 return 1;
2694         }
2695
2696         struct dirent *ent;
2697
2698         while((ent = readdir(dir))) {
2699                 if(*ent->d_name == '.') {
2700                         continue;
2701                 }
2702
2703                 if(!strcmp(ent->d_name, "tinc.conf")) {
2704                         printf(".\n");
2705                         continue;
2706                 }
2707
2708                 char fname[PATH_MAX];
2709                 snprintf(fname, sizeof(fname), "%s/%s/tinc.conf", confdir, ent->d_name);
2710
2711                 if(!access(fname, R_OK)) {
2712                         printf("%s\n", ent->d_name);
2713                 }
2714         }
2715
2716         closedir(dir);
2717
2718         return 0;
2719 }
2720
2721 static int cmd_fsck(int argc, char *argv[]) {
2722         (void)argv;
2723
2724         if(argc > 1) {
2725                 fprintf(stderr, "Too many arguments!\n");
2726                 return 1;
2727         }
2728
2729         return fsck(orig_argv[0]);
2730 }
2731
2732 static void *readfile(FILE *in, size_t *len) {
2733         size_t count = 0;
2734         size_t bufsize = 4096;
2735         char *buf = xmalloc(bufsize);
2736
2737         while(!feof(in)) {
2738                 size_t read = fread(buf + count, 1, bufsize - count, in);
2739
2740                 if(!read) {
2741                         break;
2742                 }
2743
2744                 count += read;
2745
2746                 if(count >= bufsize) {
2747                         bufsize *= 2;
2748                         buf = xrealloc(buf, bufsize);
2749                 }
2750         }
2751
2752         if(len) {
2753                 *len = count;
2754         }
2755
2756         return buf;
2757 }
2758
2759 static int cmd_sign(int argc, char *argv[]) {
2760         if(argc > 2) {
2761                 fprintf(stderr, "Too many arguments!\n");
2762                 return 1;
2763         }
2764
2765         if(!name) {
2766                 name = get_my_name(true);
2767
2768                 if(!name) {
2769                         return 1;
2770                 }
2771         }
2772
2773         char fname[PATH_MAX];
2774         snprintf(fname, sizeof(fname), "%s" SLASH "ed25519_key.priv", confbase);
2775         FILE *fp = fopen(fname, "r");
2776
2777         if(!fp) {
2778                 fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
2779                 return 1;
2780         }
2781
2782         ecdsa_t *key = ecdsa_read_pem_private_key(fp);
2783
2784         if(!key) {
2785                 fprintf(stderr, "Could not read private key from %s\n", fname);
2786                 fclose(fp);
2787                 return 1;
2788         }
2789
2790         fclose(fp);
2791
2792         FILE *in;
2793
2794         if(argc == 2) {
2795                 in = fopen(argv[1], "rb");
2796
2797                 if(!in) {
2798                         fprintf(stderr, "Could not open %s: %s\n", argv[1], strerror(errno));
2799                         ecdsa_free(key);
2800                         return 1;
2801                 }
2802         } else {
2803                 in = stdin;
2804         }
2805
2806         size_t len;
2807         char *data = readfile(in, &len);
2808
2809         if(in != stdin) {
2810                 fclose(in);
2811         }
2812
2813         if(!data) {
2814                 fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
2815                 ecdsa_free(key);
2816                 return 1;
2817         }
2818
2819         // Ensure we sign our name and current time as well
2820         long t = time(NULL);
2821         char *trailer;
2822         xasprintf(&trailer, " %s %ld", name, t);
2823         size_t trailer_len = strlen(trailer);
2824
2825         data = xrealloc(data, len + trailer_len);
2826         memcpy(data + len, trailer, trailer_len);
2827         free(trailer);
2828
2829         char sig[87];
2830
2831         if(!ecdsa_sign(key, data, len + trailer_len, sig)) {
2832                 fprintf(stderr, "Error generating signature\n");
2833                 free(data);
2834                 ecdsa_free(key);
2835                 return 1;
2836         }
2837
2838         b64encode_tinc(sig, sig, 64);
2839         ecdsa_free(key);
2840
2841         fprintf(stdout, "Signature = %s %ld %s\n", name, t, sig);
2842         fwrite(data, len, 1, stdout);
2843
2844         free(data);
2845         return 0;
2846 }
2847
2848 static int cmd_verify(int argc, char *argv[]) {
2849         if(argc < 2) {
2850                 fprintf(stderr, "Not enough arguments!\n");
2851                 return 1;
2852         }
2853
2854         if(argc > 3) {
2855                 fprintf(stderr, "Too many arguments!\n");
2856                 return 1;
2857         }
2858
2859         char *node = argv[1];
2860
2861         if(!strcmp(node, ".")) {
2862                 if(!name) {
2863                         name = get_my_name(true);
2864
2865                         if(!name) {
2866                                 return 1;
2867                         }
2868                 }
2869
2870                 node = name;
2871         } else if(!strcmp(node, "*")) {
2872                 node = NULL;
2873         } else {
2874                 if(!check_id(node)) {
2875                         fprintf(stderr, "Invalid node name\n");
2876                         return 1;
2877                 }
2878         }
2879
2880         FILE *in;
2881
2882         if(argc == 3) {
2883                 in = fopen(argv[2], "rb");
2884
2885                 if(!in) {
2886                         fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
2887                         return 1;
2888                 }
2889         } else {
2890                 in = stdin;
2891         }
2892
2893         size_t len;
2894         char *data = readfile(in, &len);
2895
2896         if(in != stdin) {
2897                 fclose(in);
2898         }
2899
2900         if(!data) {
2901                 fprintf(stderr, "Error reading %s: %s\n", argv[1], strerror(errno));
2902                 return 1;
2903         }
2904
2905         char *newline = memchr(data, '\n', len);
2906
2907         if(!newline || (newline - data > MAX_STRING_SIZE - 1)) {
2908                 fprintf(stderr, "Invalid input\n");
2909                 free(data);
2910                 return 1;
2911         }
2912
2913         *newline++ = '\0';
2914         size_t skip = newline - data;
2915
2916         char signer[MAX_STRING_SIZE] = "";
2917         char sig[MAX_STRING_SIZE] = "";
2918         long t = 0;
2919
2920         if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) {
2921                 fprintf(stderr, "Invalid input\n");
2922                 free(data);
2923                 return 1;
2924         }
2925
2926         if(node && strcmp(node, signer)) {
2927                 fprintf(stderr, "Signature is not made by %s\n", node);
2928                 free(data);
2929                 return 1;
2930         }
2931
2932         if(!node) {
2933                 node = signer;
2934         }
2935
2936         char *trailer;
2937         xasprintf(&trailer, " %s %ld", signer, t);
2938         size_t trailer_len = strlen(trailer);
2939
2940         data = xrealloc(data, len + trailer_len);
2941         memcpy(data + len, trailer, trailer_len);
2942         free(trailer);
2943
2944         newline = data + skip;
2945
2946         char fname[PATH_MAX];
2947         snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, node);
2948         FILE *fp = fopen(fname, "r");
2949
2950         if(!fp) {
2951                 fprintf(stderr, "Could not open %s: %s\n", fname, strerror(errno));
2952                 free(data);
2953                 return 1;
2954         }
2955
2956         ecdsa_t *key = get_pubkey(fp);
2957
2958         if(!key) {
2959                 rewind(fp);
2960                 key = ecdsa_read_pem_public_key(fp);
2961         }
2962
2963         if(!key) {
2964                 fprintf(stderr, "Could not read public key from %s\n", fname);
2965                 fclose(fp);
2966                 free(data);
2967                 return 1;
2968         }
2969
2970         fclose(fp);
2971
2972         if(b64decode_tinc(sig, sig, 86) != 64 || !ecdsa_verify(key, newline, len + trailer_len - (newline - data), sig)) {
2973                 fprintf(stderr, "Invalid signature\n");
2974                 free(data);
2975                 ecdsa_free(key);
2976                 return 1;
2977         }
2978
2979         ecdsa_free(key);
2980
2981         fwrite(newline, len - (newline - data), 1, stdout);
2982
2983         free(data);
2984         return 0;
2985 }
2986
2987 static const struct {
2988         const char *command;
2989         int (*function)(int argc, char *argv[]);
2990         bool hidden;
2991 } commands[] = {
2992         {"start", cmd_start, false},
2993         {"stop", cmd_stop, false},
2994         {"restart", cmd_restart, false},
2995         {"reload", cmd_reload, false},
2996         {"dump", cmd_dump, false},
2997         {"list", cmd_dump, false},
2998         {"purge", cmd_purge, false},
2999         {"debug", cmd_debug, false},
3000         {"retry", cmd_retry, false},
3001         {"connect", cmd_connect, false},
3002         {"disconnect", cmd_disconnect, false},
3003         {"top", cmd_top, false},
3004         {"pcap", cmd_pcap, false},
3005         {"log", cmd_log, false},
3006         {"pid", cmd_pid, false},
3007         {"config", cmd_config, true},
3008         {"add", cmd_config, false},
3009         {"del", cmd_config, false},
3010         {"get", cmd_config, false},
3011         {"set", cmd_config, false},
3012         {"init", cmd_init, false},
3013         {"generate-keys", cmd_generate_keys, false},
3014 #ifndef DISABLE_LEGACY
3015         {"generate-rsa-keys", cmd_generate_rsa_keys, false},
3016 #endif
3017         {"generate-ed25519-keys", cmd_generate_ed25519_keys, false},
3018         {"help", cmd_help, false},
3019         {"version", cmd_version, false},
3020         {"info", cmd_info, false},
3021         {"edit", cmd_edit, false},
3022         {"export", cmd_export, false},
3023         {"export-all", cmd_export_all, false},
3024         {"import", cmd_import, false},
3025         {"exchange", cmd_exchange, false},
3026         {"exchange-all", cmd_exchange_all, false},
3027         {"invite", cmd_invite, false},
3028         {"join", cmd_join, false},
3029         {"network", cmd_network, false},
3030         {"fsck", cmd_fsck, false},
3031         {"sign", cmd_sign, false},
3032         {"verify", cmd_verify, false},
3033         {NULL, NULL, false},
3034 };
3035
3036 #ifdef HAVE_READLINE
3037 static char *complete_command(const char *text, int state) {
3038         static int i;
3039
3040         if(!state) {
3041                 i = 0;
3042         } else {
3043                 i++;
3044         }
3045
3046         while(commands[i].command) {
3047                 if(!commands[i].hidden && !strncasecmp(commands[i].command, text, strlen(text))) {
3048                         return xstrdup(commands[i].command);
3049                 }
3050
3051                 i++;
3052         }
3053
3054         return NULL;
3055 }
3056
3057 static char *complete_dump(const char *text, int state) {
3058         const char *matches[] = {"reachable", "nodes", "edges", "subnets", "connections", "graph", NULL};
3059         static int i;
3060
3061         if(!state) {
3062                 i = 0;
3063         } else {
3064                 i++;
3065         }
3066
3067         while(matches[i]) {
3068                 if(!strncasecmp(matches[i], text, strlen(text))) {
3069                         return xstrdup(matches[i]);
3070                 }
3071
3072                 i++;
3073         }
3074
3075         return NULL;
3076 }
3077
3078 static char *complete_config(const char *text, int state) {
3079         static int i;
3080
3081         if(!state) {
3082                 i = 0;
3083         } else {
3084                 i++;
3085         }
3086
3087         while(variables[i].name) {
3088                 char *dot = strchr(text, '.');
3089
3090                 if(dot) {
3091                         if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
3092                                 char *match;
3093                                 xasprintf(&match, "%.*s.%s", (int)(dot - text), text, variables[i].name);
3094                                 return match;
3095                         }
3096                 } else {
3097                         if(!strncasecmp(variables[i].name, text, strlen(text))) {
3098                                 return xstrdup(variables[i].name);
3099                         }
3100                 }
3101
3102                 i++;
3103         }
3104
3105         return NULL;
3106 }
3107
3108 static char *complete_info(const char *text, int state) {
3109         static int i;
3110
3111         if(!state) {
3112                 i = 0;
3113
3114                 if(!connect_tincd(false)) {
3115                         return NULL;
3116                 }
3117
3118                 // Check the list of nodes
3119                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
3120                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
3121         }
3122
3123         while(recvline(fd, line, sizeof(line))) {
3124                 char item[4096];
3125                 int n = sscanf(line, "%d %d %4095s", &code, &req, item);
3126
3127                 if(n == 2) {
3128                         i++;
3129
3130                         if(i >= 2) {
3131                                 break;
3132                         } else {
3133                                 continue;
3134                         }
3135                 }
3136
3137                 if(n != 3) {
3138                         fprintf(stderr, "Unable to parse dump from tincd, n = %d, i = %d.\n", n, i);
3139                         break;
3140                 }
3141
3142                 if(!strncmp(item, text, strlen(text))) {
3143                         return xstrdup(strip_weight(item));
3144                 }
3145         }
3146
3147         return NULL;
3148 }
3149
3150 static char *complete_nothing(const char *text, int state) {
3151         (void)text;
3152         (void)state;
3153         return NULL;
3154 }
3155
3156 static char **completion(const char *text, int start, int end) {
3157         (void)end;
3158         char **matches = NULL;
3159
3160         if(!start) {
3161                 matches = rl_completion_matches(text, complete_command);
3162         } else if(!strncasecmp(rl_line_buffer, "dump ", 5)) {
3163                 matches = rl_completion_matches(text, complete_dump);
3164         } else if(!strncasecmp(rl_line_buffer, "add ", 4)) {
3165                 matches = rl_completion_matches(text, complete_config);
3166         } else if(!strncasecmp(rl_line_buffer, "del ", 4)) {
3167                 matches = rl_completion_matches(text, complete_config);
3168         } else if(!strncasecmp(rl_line_buffer, "get ", 4)) {
3169                 matches = rl_completion_matches(text, complete_config);
3170         } else if(!strncasecmp(rl_line_buffer, "set ", 4)) {
3171                 matches = rl_completion_matches(text, complete_config);
3172         } else if(!strncasecmp(rl_line_buffer, "info ", 5)) {
3173                 matches = rl_completion_matches(text, complete_info);
3174         }
3175
3176         return matches;
3177 }
3178 #endif
3179
3180 static int cmd_shell(int argc, char *argv[]) {
3181         xasprintf(&prompt, "%s> ", identname);
3182         int result = 0;
3183         char buf[4096];
3184         char *line = NULL;
3185         int maxargs = argc + 16;
3186         char **nargv = xmalloc(maxargs * sizeof(*nargv));
3187
3188         for(int i = 0; i < argc; i++) {
3189                 nargv[i] = argv[i];
3190         }
3191
3192 #ifdef HAVE_READLINE
3193         rl_readline_name = "tinc";
3194         rl_basic_word_break_characters = "\t\n ";
3195         rl_completion_entry_function = complete_nothing;
3196         rl_attempted_completion_function = completion;
3197         rl_filename_completion_desired = 0;
3198         char *copy = NULL;
3199 #endif
3200
3201         while(true) {
3202 #ifdef HAVE_READLINE
3203
3204                 if(tty) {
3205                         free(copy);
3206                         free(line);
3207                         line = readline(prompt);
3208                         copy = line ? xstrdup(line) : NULL;
3209                 } else {
3210                         line = fgets(buf, sizeof(buf), stdin);
3211                 }
3212
3213 #else
3214
3215                 if(tty) {
3216                         fputs(prompt, stdout);
3217                 }
3218
3219                 line = fgets(buf, sizeof(buf), stdin);
3220 #endif
3221
3222                 if(!line) {
3223                         break;
3224                 }
3225
3226                 /* Ignore comments */
3227
3228                 if(*line == '#') {
3229                         continue;
3230                 }
3231
3232                 /* Split */
3233
3234                 int nargc = argc;
3235                 char *p = line + strspn(line, " \t\n");
3236                 char *next = strtok(p, " \t\n");
3237
3238                 while(p && *p) {
3239                         if(nargc >= maxargs) {
3240                                 maxargs *= 2;
3241                                 nargv = xrealloc(nargv, maxargs * sizeof(*nargv));
3242                         }
3243
3244                         nargv[nargc++] = p;
3245                         p = next;
3246                         next = strtok(NULL, " \t\n");
3247                 }
3248
3249                 if(nargc == argc) {
3250                         continue;
3251                 }
3252
3253                 if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit")) {
3254 #ifdef HAVE_READLINE
3255                         free(copy);
3256 #endif
3257                         free(nargv);
3258                         return result;
3259                 }
3260
3261                 bool found = false;
3262
3263                 for(int i = 0; commands[i].command; i++) {
3264                         if(!strcasecmp(nargv[argc], commands[i].command)) {
3265                                 result |= commands[i].function(nargc - argc - 1, nargv + argc + 1);
3266                                 found = true;
3267                                 break;
3268                         }
3269                 }
3270
3271 #ifdef HAVE_READLINE
3272
3273                 if(tty && found) {
3274                         add_history(copy);
3275                 }
3276
3277 #endif
3278
3279                 if(!found) {
3280                         fprintf(stderr, "Unknown command `%s'.\n", nargv[argc]);
3281                         result |= 1;
3282                 }
3283         }
3284
3285 #ifdef HAVE_READLINE
3286         free(copy);
3287 #endif
3288         free(nargv);
3289
3290         if(tty) {
3291                 printf("\n");
3292         }
3293
3294         return result;
3295 }
3296
3297 static void cleanup(void) {
3298         free(tinc_conf);
3299         free(hosts_dir);
3300         free_names();
3301 }
3302
3303 static int run_command(int argc, char *argv[]) {
3304         if(optind >= argc) {
3305                 return cmd_shell(argc, argv);
3306         }
3307
3308         for(int i = 0; commands[i].command; i++) {
3309                 if(!strcasecmp(argv[optind], commands[i].command)) {
3310                         return commands[i].function(argc - optind, argv + optind);
3311                 }
3312         }
3313
3314         fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
3315         usage(true);
3316         return 1;
3317 }
3318
3319 int main(int argc, char *argv[]) {
3320         program_name = argv[0];
3321         orig_argv = argv;
3322         tty = isatty(0) && isatty(1);
3323
3324         if(!parse_options(argc, argv)) {
3325                 return 1;
3326         }
3327
3328         make_names(false);
3329         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
3330         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
3331         atexit(cleanup);
3332
3333         if(show_version) {
3334                 version();
3335                 return 0;
3336         }
3337
3338         if(show_help) {
3339                 usage(false);
3340                 return 0;
3341         }
3342
3343 #ifdef HAVE_WINDOWS
3344         static struct WSAData wsa_state;
3345
3346         if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
3347                 fprintf(stderr, "System call `%s' failed: %s\n", "WSAStartup", winerror(GetLastError()));
3348                 return false;
3349         }
3350
3351 #endif
3352
3353         gettimeofday(&now, NULL);
3354         random_init();
3355         crypto_init();
3356         prng_init();
3357
3358         sandbox_set_level(SANDBOX_NORMAL);
3359         sandbox_enter();
3360
3361         int result = run_command(argc, argv);
3362
3363         random_exit();
3364
3365         return result;
3366 }