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