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