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