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