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