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