tinc-gui: Reformat codebase according to PEP8
[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         {"VDEGroup", VAR_SERVER},
1485         {"VDEPort", VAR_SERVER},
1486         /* Host configuration */
1487         {"Address", VAR_HOST | VAR_MULTIPLE},
1488         {"Cipher", VAR_SERVER | VAR_HOST},
1489         {"ClampMSS", VAR_SERVER | VAR_HOST},
1490         {"Compression", VAR_SERVER | VAR_HOST},
1491         {"Digest", VAR_SERVER | VAR_HOST},
1492         {"Ed25519PublicKey", VAR_HOST},
1493         {"Ed25519PublicKeyFile", VAR_SERVER | VAR_HOST},
1494         {"IndirectData", VAR_SERVER | VAR_HOST},
1495         {"MACLength", VAR_SERVER | VAR_HOST},
1496         {"PMTU", VAR_SERVER | VAR_HOST},
1497         {"PMTUDiscovery", VAR_SERVER | VAR_HOST},
1498         {"Port", VAR_HOST},
1499         {"PublicKey", VAR_HOST | VAR_OBSOLETE},
1500         {"PublicKeyFile", VAR_SERVER | VAR_HOST | VAR_OBSOLETE},
1501         {"Subnet", VAR_HOST | VAR_MULTIPLE | VAR_SAFE},
1502         {"TCPOnly", VAR_SERVER | VAR_HOST},
1503         {"Weight", VAR_HOST | VAR_SAFE},
1504         {NULL, 0}
1505 };
1506
1507 static int cmd_config(int argc, char *argv[]) {
1508         if(argc < 2) {
1509                 fprintf(stderr, "Invalid number of arguments.\n");
1510                 return 1;
1511         }
1512
1513         if(strcasecmp(argv[0], "config"))
1514                 argv--, argc++;
1515
1516         int action = -2;
1517         if(!strcasecmp(argv[1], "get")) {
1518                 argv++, argc--;
1519         } else if(!strcasecmp(argv[1], "add")) {
1520                 argv++, argc--, action = 1;
1521         } else if(!strcasecmp(argv[1], "del")) {
1522                 argv++, argc--, action = -1;
1523         } else if(!strcasecmp(argv[1], "replace") || !strcasecmp(argv[1], "set") || !strcasecmp(argv[1], "change")) {
1524                 argv++, argc--, action = 0;
1525         }
1526
1527         if(argc < 2) {
1528                 fprintf(stderr, "Invalid number of arguments.\n");
1529                 return 1;
1530         }
1531
1532         // Concatenate the rest of the command line
1533         strncpy(line, argv[1], sizeof line - 1);
1534         for(int i = 2; i < argc; i++) {
1535                 strncat(line, " ", sizeof line - 1 - strlen(line));
1536                 strncat(line, argv[i], sizeof line - 1 - strlen(line));
1537         }
1538
1539         // Liberal parsing into node name, variable name and value.
1540         char *node = NULL;
1541         char *variable;
1542         char *value;
1543         int len;
1544
1545         len = strcspn(line, "\t =");
1546         value = line + len;
1547         value += strspn(value, "\t ");
1548         if(*value == '=') {
1549                 value++;
1550                 value += strspn(value, "\t ");
1551         }
1552         line[len] = '\0';
1553         variable = strchr(line, '.');
1554         if(variable) {
1555                 node = line;
1556                 *variable++ = 0;
1557         } else {
1558                 variable = line;
1559         }
1560
1561         if(!*variable) {
1562                 fprintf(stderr, "No variable given.\n");
1563                 return 1;
1564         }
1565
1566         if(action >= 0 && !*value) {
1567                 fprintf(stderr, "No value for variable given.\n");
1568                 return 1;
1569         }
1570
1571         if(action < -1 && *value)
1572                 action = 0;
1573
1574         /* Some simple checks. */
1575         bool found = false;
1576         bool warnonremove = false;
1577
1578         for(int i = 0; variables[i].name; i++) {
1579                 if(strcasecmp(variables[i].name, variable))
1580                         continue;
1581
1582                 found = true;
1583                 variable = (char *)variables[i].name;
1584
1585                 /* Discourage use of obsolete variables. */
1586
1587                 if(variables[i].type & VAR_OBSOLETE && action >= 0) {
1588                         if(force) {
1589                                 fprintf(stderr, "Warning: %s is an obsolete variable!\n", variable);
1590                         } else {
1591                                 fprintf(stderr, "%s is an obsolete variable! Use --force to use it anyway.\n", variable);
1592                                 return 1;
1593                         }
1594                 }
1595
1596                 /* Don't put server variables in host config files */
1597
1598                 if(node && !(variables[i].type & VAR_HOST) && action >= 0) {
1599                         if(force) {
1600                                 fprintf(stderr, "Warning: %s is not a host configuration variable!\n", variable);
1601                         } else {
1602                                 fprintf(stderr, "%s is not a host configuration variable! Use --force to use it anyway.\n", variable);
1603                                 return 1;
1604                         }
1605                 }
1606
1607                 /* Should this go into our own host config file? */
1608
1609                 if(!node && !(variables[i].type & VAR_SERVER)) {
1610                         node = get_my_name(true);
1611                         if(!node)
1612                                 return 1;
1613                 }
1614
1615                 /* Change "add" into "set" for variables that do not allow multiple occurences.
1616                    Turn on warnings when it seems variables might be removed unintentionally. */
1617
1618                 if(action == 1 && !(variables[i].type & VAR_MULTIPLE)) {
1619                         warnonremove = true;
1620                         action = 0;
1621                 } else if(action == 0 && (variables[i].type & VAR_MULTIPLE)) {
1622                         warnonremove = true;
1623                 }
1624
1625                 break;
1626         }
1627
1628         if(node && !check_id(node)) {
1629                 fprintf(stderr, "Invalid name for node.\n");
1630                 return 1;
1631         }
1632
1633         if(!found) {
1634                 if(force || action < 0) {
1635                         fprintf(stderr, "Warning: %s is not a known configuration variable!\n", variable);
1636                 } else {
1637                         fprintf(stderr, "%s: is not a known configuration variable! Use --force to use it anyway.\n", variable);
1638                         return 1;
1639                 }
1640         }
1641
1642         // Open the right configuration file.
1643         char filename[PATH_MAX];
1644         if(node)
1645                 snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, node);
1646         else
1647                 snprintf(filename, sizeof filename, "%s", tinc_conf);
1648
1649         FILE *f = fopen(filename, "r");
1650         if(!f) {
1651                 fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
1652                 return 1;
1653         }
1654
1655         char tmpfile[PATH_MAX];
1656         FILE *tf = NULL;
1657
1658         if(action >= -1) {
1659                 snprintf(tmpfile, sizeof tmpfile, "%s.config.tmp", filename);
1660                 tf = fopen(tmpfile, "w");
1661                 if(!tf) {
1662                         fprintf(stderr, "Could not open temporary file %s: %s\n", tmpfile, strerror(errno));
1663                         fclose(f);
1664                         return 1;
1665                 }
1666         }
1667
1668         // Copy the file, making modifications on the fly, unless we are just getting a value.
1669         char buf1[4096];
1670         char buf2[4096];
1671         bool set = false;
1672         bool removed = false;
1673         found = false;
1674
1675         while(fgets(buf1, sizeof buf1, f)) {
1676                 buf1[sizeof buf1 - 1] = 0;
1677                 strncpy(buf2, buf1, sizeof buf2);
1678
1679                 // Parse line in a simple way
1680                 char *bvalue;
1681                 int len;
1682
1683                 len = strcspn(buf2, "\t =");
1684                 bvalue = buf2 + len;
1685                 bvalue += strspn(bvalue, "\t ");
1686                 if(*bvalue == '=') {
1687                         bvalue++;
1688                         bvalue += strspn(bvalue, "\t ");
1689                 }
1690                 rstrip(bvalue);
1691                 buf2[len] = '\0';
1692
1693                 // Did it match?
1694                 if(!strcasecmp(buf2, variable)) {
1695                         // Get
1696                         if(action < -1) {
1697                                 found = true;
1698                                 printf("%s\n", bvalue);
1699                         // Del
1700                         } else if(action == -1) {
1701                                 if(!*value || !strcasecmp(bvalue, value)) {
1702                                         removed = true;
1703                                         continue;
1704                                 }
1705                         // Set
1706                         } else if(action == 0) {
1707                                 // Warn if "set" was used for variables that can occur multiple times
1708                                 if(warnonremove && strcasecmp(bvalue, value))
1709                                         fprintf(stderr, "Warning: removing %s = %s\n", variable, bvalue);
1710
1711                                 // Already set? Delete the rest...
1712                                 if(set)
1713                                         continue;
1714
1715                                 // Otherwise, replace.
1716                                 if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
1717                                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1718                                         return 1;
1719                                 }
1720                                 set = true;
1721                                 continue;
1722                         // Add
1723                         } else if(action > 0) {
1724                                 // Check if we've already seen this variable with the same value
1725                                 if(!strcasecmp(bvalue, value))
1726                                         found = true;
1727                         }
1728                 }
1729
1730                 if(action >= -1) {
1731                         // Copy original line...
1732                         if(fputs(buf1, tf) < 0) {
1733                                 fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1734                                 return 1;
1735                         }
1736
1737                         // Add newline if it is missing...
1738                         if(*buf1 && buf1[strlen(buf1) - 1] != '\n') {
1739                                 if(fputc('\n', tf) < 0) {
1740                                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1741                                         return 1;
1742                                 }
1743                         }
1744                 }
1745         }
1746
1747         // Make sure we read everything...
1748         if(ferror(f) || !feof(f)) {
1749                 fprintf(stderr, "Error while reading from configuration file %s: %s\n", filename, strerror(errno));
1750                 return 1;
1751         }
1752
1753         if(fclose(f)) {
1754                 fprintf(stderr, "Error closing configuration file %s: %s\n", filename, strerror(errno));
1755                 return 1;
1756         }
1757
1758         // Add new variable if necessary.
1759         if((action > 0 && !found)|| (action == 0 && !set)) {
1760                 if(fprintf(tf, "%s = %s\n", variable, value) < 0) {
1761                         fprintf(stderr, "Error writing to temporary file %s: %s\n", tmpfile, strerror(errno));
1762                         return 1;
1763                 }
1764         }
1765
1766         if(action < -1) {
1767                 if(found) {
1768                         return 0;
1769                 } else {
1770                         fprintf(stderr, "No matching configuration variables found.\n");
1771                         return 1;
1772                 }
1773         }
1774
1775         // Make sure we wrote everything...
1776         if(fclose(tf)) {
1777                 fprintf(stderr, "Error closing temporary file %s: %s\n", tmpfile, strerror(errno));
1778                 return 1;
1779         }
1780
1781         // Could we find what we had to remove?
1782         if(action < 0 && !removed) {
1783                 remove(tmpfile);
1784                 fprintf(stderr, "No configuration variables deleted.\n");
1785                 return 1;
1786         }
1787
1788         // Replace the configuration file with the new one
1789 #ifdef HAVE_MINGW
1790         if(remove(filename)) {
1791                 fprintf(stderr, "Error replacing file %s: %s\n", filename, strerror(errno));
1792                 return 1;
1793         }
1794 #endif
1795         if(rename(tmpfile, filename)) {
1796                 fprintf(stderr, "Error renaming temporary file %s to configuration file %s: %s\n", tmpfile, filename, strerror(errno));
1797                 return 1;
1798         }
1799
1800         // Silently try notifying a running tincd of changes.
1801         if(connect_tincd(false))
1802                 sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
1803
1804         return 0;
1805 }
1806
1807 static bool try_bind(int port) {
1808         struct addrinfo *ai = NULL, *aip;
1809         struct addrinfo hint = {
1810                 .ai_flags = AI_PASSIVE,
1811                 .ai_family = AF_UNSPEC,
1812                 .ai_socktype = SOCK_STREAM,
1813                 .ai_protocol = IPPROTO_TCP,
1814         };
1815
1816         bool success = true;
1817         char portstr[16];
1818         snprintf(portstr, sizeof portstr, "%d", port);
1819
1820         if(getaddrinfo(NULL, portstr, &hint, &ai) || !ai)
1821                 return false;
1822
1823         for(aip = ai; aip; aip = aip->ai_next) {
1824                 int fd = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
1825                 if(!fd) {
1826                         success = false;
1827                         break;
1828                 }
1829
1830                 int result = bind(fd, ai->ai_addr, ai->ai_addrlen);
1831                 closesocket(fd);
1832                 if(result) {
1833                         success = false;
1834                         break;
1835                 }
1836         }
1837
1838         freeaddrinfo(ai);
1839         return success;
1840 }
1841
1842 int check_port(char *name) {
1843         if(try_bind(655))
1844                 return 655;
1845
1846         fprintf(stderr, "Warning: could not bind to port 655. ");
1847
1848         for(int i = 0; i < 100; i++) {
1849                 int port = 0x1000 + (rand() & 0x7fff);
1850                 if(try_bind(port)) {
1851                         char filename[PATH_MAX];
1852                         snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, name);
1853                         FILE *f = fopen(filename, "a");
1854                         if(!f) {
1855                                 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
1856                                 fprintf(stderr, "Please change tinc's Port manually.\n");
1857                                 return 0;
1858                         }
1859
1860                         fprintf(f, "Port = %d\n", port);
1861                         fclose(f);
1862                         fprintf(stderr, "Tinc will instead listen on port %d.\n", port);
1863                         return port;
1864                 }
1865         }
1866
1867         fprintf(stderr, "Please change tinc's Port manually.\n");
1868         return 0;
1869 }
1870
1871 static int cmd_init(int argc, char *argv[]) {
1872         if(!access(tinc_conf, F_OK)) {
1873                 fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf);
1874                 return 1;
1875         }
1876
1877         if(argc > 2) {
1878                 fprintf(stderr, "Too many arguments!\n");
1879                 return 1;
1880         } else if(argc < 2) {
1881                 if(tty) {
1882                         char buf[1024];
1883                         fprintf(stderr, "Enter the Name you want your tinc node to have: ");
1884                         if(!fgets(buf, sizeof buf, stdin)) {
1885                                 fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno));
1886                                 return 1;
1887                         }
1888                         int len = rstrip(buf);
1889                         if(!len) {
1890                                 fprintf(stderr, "No name given!\n");
1891                                 return 1;
1892                         }
1893                         name = strdup(buf);
1894                 } else {
1895                         fprintf(stderr, "No Name given!\n");
1896                         return 1;
1897                 }
1898         } else {
1899                 name = strdup(argv[1]);
1900                 if(!*name) {
1901                         fprintf(stderr, "No Name given!\n");
1902                         return 1;
1903                 }
1904         }
1905
1906         if(!check_id(name)) {
1907                 fprintf(stderr, "Invalid Name! Only a-z, A-Z, 0-9 and _ are allowed characters.\n");
1908                 return 1;
1909         }
1910
1911         if(!confbase_given && mkdir(confdir, 0755) && errno != EEXIST) {
1912                 fprintf(stderr, "Could not create directory %s: %s\n", confdir, strerror(errno));
1913                 return 1;
1914         }
1915
1916         if(mkdir(confbase, 0777) && errno != EEXIST) {
1917                 fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno));
1918                 return 1;
1919         }
1920
1921         if(mkdir(hosts_dir, 0777) && errno != EEXIST) {
1922                 fprintf(stderr, "Could not create directory %s: %s\n", hosts_dir, strerror(errno));
1923                 return 1;
1924         }
1925
1926         FILE *f = fopen(tinc_conf, "w");
1927         if(!f) {
1928                 fprintf(stderr, "Could not create file %s: %s\n", tinc_conf, strerror(errno));
1929                 return 1;
1930         }
1931
1932         fprintf(f, "Name = %s\n", name);
1933         fclose(f);
1934
1935 #ifndef DISABLE_LEGACY
1936         if(!rsa_keygen(2048, false))
1937                 return 1;
1938 #endif
1939
1940         if(!ed25519_keygen(false))
1941                 return 1;
1942
1943         check_port(name);
1944
1945 #ifndef HAVE_MINGW
1946         char filename[PATH_MAX];
1947         snprintf(filename, sizeof filename, "%s" SLASH "tinc-up", confbase);
1948         if(access(filename, F_OK)) {
1949                 FILE *f = fopenmask(filename, "w", 0777);
1950                 if(!f) {
1951                         fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno));
1952                         return 1;
1953                 }
1954                 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");
1955                 fclose(f);
1956         }
1957 #endif
1958
1959         return 0;
1960
1961 }
1962
1963 static int cmd_generate_keys(int argc, char *argv[]) {
1964 #ifdef DISABLE_LEGACY
1965         if(argc > 1) {
1966 #else
1967         if(argc > 2) {
1968 #endif
1969                 fprintf(stderr, "Too many arguments!\n");
1970                 return 1;
1971         }
1972
1973         if(!name)
1974                 name = get_my_name(false);
1975
1976 #ifndef DISABLE_LEGACY
1977         if(!rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true))
1978                 return 1;
1979 #endif
1980
1981         if(!ed25519_keygen(true))
1982                 return 1;
1983
1984         return 0;
1985 }
1986
1987 #ifndef DISABLE_LEGACY
1988 static int cmd_generate_rsa_keys(int argc, char *argv[]) {
1989         if(argc > 2) {
1990                 fprintf(stderr, "Too many arguments!\n");
1991                 return 1;
1992         }
1993
1994         if(!name)
1995                 name = get_my_name(false);
1996
1997         return !rsa_keygen(argc > 1 ? atoi(argv[1]) : 2048, true);
1998 }
1999 #endif
2000
2001 static int cmd_generate_ed25519_keys(int argc, char *argv[]) {
2002         if(argc > 1) {
2003                 fprintf(stderr, "Too many arguments!\n");
2004                 return 1;
2005         }
2006
2007         if(!name)
2008                 name = get_my_name(false);
2009
2010         return !ed25519_keygen(true);
2011 }
2012
2013 static int cmd_help(int argc, char *argv[]) {
2014         usage(false);
2015         return 0;
2016 }
2017
2018 static int cmd_version(int argc, char *argv[]) {
2019         if(argc > 1) {
2020                 fprintf(stderr, "Too many arguments!\n");
2021                 return 1;
2022         }
2023
2024         version();
2025         return 0;
2026 }
2027
2028 static int cmd_info(int argc, char *argv[]) {
2029         if(argc != 2) {
2030                 fprintf(stderr, "Invalid number of arguments.\n");
2031                 return 1;
2032         }
2033
2034         if(!connect_tincd(true))
2035                 return 1;
2036
2037         return info(fd, argv[1]);
2038 }
2039
2040 static const char *conffiles[] = {
2041         "tinc.conf",
2042         "tinc-up",
2043         "tinc-down",
2044         "subnet-up",
2045         "subnet-down",
2046         "host-up",
2047         "host-down",
2048         NULL,
2049 };
2050
2051 static int cmd_edit(int argc, char *argv[]) {
2052         if(argc != 2) {
2053                 fprintf(stderr, "Invalid number of arguments.\n");
2054                 return 1;
2055         }
2056
2057         char filename[PATH_MAX] = "";
2058
2059         if(strncmp(argv[1], "hosts" SLASH, 6)) {
2060                 for(int i = 0; conffiles[i]; i++) {
2061                         if(!strcmp(argv[1], conffiles[i])) {
2062                                 snprintf(filename, sizeof filename, "%s" SLASH "%s", confbase, argv[1]);
2063                                 break;
2064                         }
2065                 }
2066         } else {
2067                 argv[1] += 6;
2068         }
2069
2070         if(!*filename) {
2071                 snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, argv[1]);
2072                 char *dash = strchr(argv[1], '-');
2073                 if(dash) {
2074                         *dash++ = 0;
2075                         if((strcmp(dash, "up") && strcmp(dash, "down")) || !check_id(argv[1])) {
2076                                 fprintf(stderr, "Invalid configuration filename.\n");
2077                                 return 1;
2078                         }
2079                 }
2080         }
2081
2082         char *command;
2083 #ifndef HAVE_MINGW
2084         xasprintf(&command, "\"%s\" \"%s\"", getenv("VISUAL") ?: getenv("EDITOR") ?: "vi", filename);
2085 #else
2086         xasprintf(&command, "edit \"%s\"", filename);
2087 #endif
2088         int result = system(command);
2089         free(command);
2090         if(result)
2091                 return result;
2092
2093         // Silently try notifying a running tincd of changes.
2094         if(connect_tincd(false))
2095                 sendline(fd, "%d %d", CONTROL, REQ_RELOAD);
2096
2097         return 0;
2098 }
2099
2100 static int export(const char *name, FILE *out) {
2101         char filename[PATH_MAX];
2102         snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name);
2103         FILE *in = fopen(filename, "r");
2104         if(!in) {
2105                 fprintf(stderr, "Could not open configuration file %s: %s\n", filename, strerror(errno));
2106                 return 1;
2107         }
2108
2109         fprintf(out, "Name = %s\n", name);
2110         char buf[4096];
2111         while(fgets(buf, sizeof buf, in)) {
2112                 if(strcspn(buf, "\t =") != 4 || strncasecmp(buf, "Name", 4))
2113                         fputs(buf, out);
2114         }
2115
2116         if(ferror(in)) {
2117                 fprintf(stderr, "Error while reading configuration file %s: %s\n", filename, strerror(errno));
2118                 fclose(in);
2119                 return 1;
2120         }
2121
2122         fclose(in);
2123         return 0;
2124 }
2125
2126 static int cmd_export(int argc, char *argv[]) {
2127         if(argc > 1) {
2128                 fprintf(stderr, "Too many arguments!\n");
2129                 return 1;
2130         }
2131
2132         char *name = get_my_name(true);
2133         if(!name)
2134                 return 1;
2135
2136         int result = export(name, stdout);
2137         if(!tty)
2138                 fclose(stdout);
2139
2140         free(name);
2141         return result;
2142 }
2143
2144 static int cmd_export_all(int argc, char *argv[]) {
2145         if(argc > 1) {
2146                 fprintf(stderr, "Too many arguments!\n");
2147                 return 1;
2148         }
2149
2150         DIR *dir = opendir(hosts_dir);
2151         if(!dir) {
2152                 fprintf(stderr, "Could not open host configuration directory %s: %s\n", hosts_dir, strerror(errno));
2153                 return 1;
2154         }
2155
2156         bool first = true;
2157         int result = 0;
2158         struct dirent *ent;
2159
2160         while((ent = readdir(dir))) {
2161                 if(!check_id(ent->d_name))
2162                         continue;
2163
2164                 if(first)
2165                         first = false;
2166                 else
2167                         printf("#---------------------------------------------------------------#\n");
2168
2169                 result |= export(ent->d_name, stdout);
2170         }
2171
2172         closedir(dir);
2173         if(!tty)
2174                 fclose(stdout);
2175         return result;
2176 }
2177
2178 static int cmd_import(int argc, char *argv[]) {
2179         if(argc > 1) {
2180                 fprintf(stderr, "Too many arguments!\n");
2181                 return 1;
2182         }
2183
2184         FILE *in = stdin;
2185         FILE *out = NULL;
2186
2187         char buf[4096];
2188         char name[4096];
2189         char filename[PATH_MAX] = "";
2190         int count = 0;
2191         bool firstline = true;
2192
2193         while(fgets(buf, sizeof buf, in)) {
2194                 if(sscanf(buf, "Name = %s", name) == 1) {
2195                         firstline = false;
2196
2197                         if(!check_id(name)) {
2198                                 fprintf(stderr, "Invalid Name in input!\n");
2199                                 return 1;
2200                         }
2201
2202                         if(out)
2203                                 fclose(out);
2204
2205                         snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name);
2206
2207                         if(!force && !access(filename, F_OK)) {
2208                                 fprintf(stderr, "Host configuration file %s already exists, skipping.\n", filename);
2209                                 out = NULL;
2210                                 continue;
2211                         }
2212
2213                         out = fopen(filename, "w");
2214                         if(!out) {
2215                                 fprintf(stderr, "Error creating configuration file %s: %s\n", filename, strerror(errno));
2216                                 return 1;
2217                         }
2218
2219                         count++;
2220                         continue;
2221                 } else if(firstline) {
2222                         fprintf(stderr, "Junk at the beginning of the input, ignoring.\n");
2223                         firstline = false;
2224                 }
2225
2226
2227                 if(!strcmp(buf, "#---------------------------------------------------------------#\n"))
2228                         continue;
2229
2230                 if(out) {
2231                         if(fputs(buf, out) < 0) {
2232                                 fprintf(stderr, "Error writing to host configuration file %s: %s\n", filename, strerror(errno));
2233                                 return 1;
2234                         }
2235                 }
2236         }
2237
2238         if(out)
2239                 fclose(out);
2240
2241         if(count) {
2242                 fprintf(stderr, "Imported %d host configuration files.\n", count);
2243                 return 0;
2244         } else {
2245                 fprintf(stderr, "No host configuration files imported.\n");
2246                 return 1;
2247         }
2248 }
2249
2250 static int cmd_exchange(int argc, char *argv[]) {
2251         return cmd_export(argc, argv) ?: cmd_import(argc, argv);
2252 }
2253
2254 static int cmd_exchange_all(int argc, char *argv[]) {
2255         return cmd_export_all(argc, argv) ?: cmd_import(argc, argv);
2256 }
2257
2258 static int switch_network(char *name) {
2259         if(fd >= 0) {
2260                 close(fd);
2261                 fd = -1;
2262         }
2263
2264         free(confbase);
2265         confbase = NULL;
2266         free(pidfilename);
2267         pidfilename = NULL;
2268         free(logfilename);
2269         logfilename = NULL;
2270         free(unixsocketname);
2271         unixsocketname = NULL;
2272         free(tinc_conf);
2273         free(hosts_dir);
2274         free(prompt);
2275
2276         free(netname);
2277         netname = strcmp(name, ".") ? xstrdup(name) : NULL;
2278
2279         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
2280         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
2281         xasprintf(&prompt, "%s> ", identname);
2282
2283         return 0;
2284 }
2285
2286 static int cmd_network(int argc, char *argv[]) {
2287         if(argc > 2) {
2288                 fprintf(stderr, "Too many arguments!\n");
2289                 return 1;
2290         }
2291
2292         if(argc == 2)
2293                 return switch_network(argv[1]);
2294
2295         DIR *dir = opendir(confdir);
2296         if(!dir) {
2297                 fprintf(stderr, "Could not read directory %s: %s\n", confdir, strerror(errno));
2298                 return 1;
2299         }
2300
2301         struct dirent *ent;
2302         while((ent = readdir(dir))) {
2303                 if(*ent->d_name == '.')
2304                         continue;
2305
2306                 if(!strcmp(ent->d_name, "tinc.conf")) {
2307                         printf(".\n");
2308                         continue;
2309                 }
2310
2311                 char fname[PATH_MAX];
2312                 snprintf(fname, sizeof fname, "%s/%s/tinc.conf", confdir, ent->d_name);
2313                 if(!access(fname, R_OK))
2314                         printf("%s\n", ent->d_name);
2315         }
2316
2317         closedir(dir);
2318
2319         return 0;
2320 }
2321
2322 static int cmd_fsck(int argc, char *argv[]) {
2323         if(argc > 1) {
2324                 fprintf(stderr, "Too many arguments!\n");
2325                 return 1;
2326         }
2327
2328         return fsck(orig_argv[0]);
2329 }
2330
2331 static const struct {
2332         const char *command;
2333         int (*function)(int argc, char *argv[]);
2334         bool hidden;
2335 } commands[] = {
2336         {"start", cmd_start},
2337         {"stop", cmd_stop},
2338         {"restart", cmd_restart},
2339         {"reload", cmd_reload},
2340         {"dump", cmd_dump},
2341         {"list", cmd_dump},
2342         {"purge", cmd_purge},
2343         {"debug", cmd_debug},
2344         {"retry", cmd_retry},
2345         {"connect", cmd_connect},
2346         {"disconnect", cmd_disconnect},
2347         {"top", cmd_top},
2348         {"pcap", cmd_pcap},
2349         {"log", cmd_log},
2350         {"pid", cmd_pid},
2351         {"config", cmd_config, true},
2352         {"add", cmd_config},
2353         {"del", cmd_config},
2354         {"get", cmd_config},
2355         {"set", cmd_config},
2356         {"init", cmd_init},
2357         {"generate-keys", cmd_generate_keys},
2358 #ifndef DISABLE_LEGACY
2359         {"generate-rsa-keys", cmd_generate_rsa_keys},
2360 #endif
2361         {"generate-ed25519-keys", cmd_generate_ed25519_keys},
2362         {"help", cmd_help},
2363         {"version", cmd_version},
2364         {"info", cmd_info},
2365         {"edit", cmd_edit},
2366         {"export", cmd_export},
2367         {"export-all", cmd_export_all},
2368         {"import", cmd_import},
2369         {"exchange", cmd_exchange},
2370         {"exchange-all", cmd_exchange_all},
2371         {"invite", cmd_invite},
2372         {"join", cmd_join},
2373         {"network", cmd_network},
2374         {"fsck", cmd_fsck},
2375         {NULL, NULL},
2376 };
2377
2378 #ifdef HAVE_READLINE
2379 static char *complete_command(const char *text, int state) {
2380         static int i;
2381
2382         if(!state)
2383                 i = 0;
2384         else
2385                 i++;
2386
2387         while(commands[i].command) {
2388                 if(!commands[i].hidden && !strncasecmp(commands[i].command, text, strlen(text)))
2389                         return xstrdup(commands[i].command);
2390                 i++;
2391         }
2392
2393         return NULL;
2394 }
2395
2396 static char *complete_dump(const char *text, int state) {
2397         const char *matches[] = {"reachable", "nodes", "edges", "subnets", "connections", "graph", NULL};
2398         static int i;
2399
2400         if(!state)
2401                 i = 0;
2402         else
2403                 i++;
2404
2405         while(matches[i]) {
2406                 if(!strncasecmp(matches[i], text, strlen(text)))
2407                         return xstrdup(matches[i]);
2408                 i++;
2409         }
2410
2411         return NULL;
2412 }
2413
2414 static char *complete_config(const char *text, int state) {
2415         static int i;
2416
2417         if(!state)
2418                 i = 0;
2419         else
2420                 i++;
2421
2422         while(variables[i].name) {
2423                 char *dot = strchr(text, '.');
2424                 if(dot) {
2425                         if((variables[i].type & VAR_HOST) && !strncasecmp(variables[i].name, dot + 1, strlen(dot + 1))) {
2426                                 char *match;
2427                                 xasprintf(&match, "%.*s.%s", (int)(dot - text), text, variables[i].name);
2428                                 return match;
2429                         }
2430                 } else {
2431                         if(!strncasecmp(variables[i].name, text, strlen(text)))
2432                                 return xstrdup(variables[i].name);
2433                 }
2434                 i++;
2435         }
2436
2437         return NULL;
2438 }
2439
2440 static char *complete_info(const char *text, int state) {
2441         static int i;
2442         if(!state) {
2443                 i = 0;
2444                 if(!connect_tincd(false))
2445                         return NULL;
2446                 // Check the list of nodes
2447                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES);
2448                 sendline(fd, "%d %d", CONTROL, REQ_DUMP_SUBNETS);
2449         }
2450
2451         while(recvline(fd, line, sizeof line)) {
2452                 char item[4096];
2453                 int n = sscanf(line, "%d %d %s", &code, &req, item);
2454                 if(n == 2) {
2455                         i++;
2456                         if(i >= 2)
2457                                 break;
2458                         else
2459                                 continue;
2460                 }
2461
2462                 if(n != 3) {
2463                         fprintf(stderr, "Unable to parse dump from tincd, n = %d, i = %d.\n", n, i);
2464                         break;
2465                 }
2466
2467                 if(!strncmp(item, text, strlen(text)))
2468                         return xstrdup(strip_weight(item));
2469         }
2470
2471         return NULL;
2472 }
2473
2474 static char *complete_nothing(const char *text, int state) {
2475         return NULL;
2476 }
2477
2478 static char **completion (const char *text, int start, int end) {
2479         char **matches = NULL;
2480
2481         if(!start)
2482                 matches = rl_completion_matches(text, complete_command);
2483         else if(!strncasecmp(rl_line_buffer, "dump ", 5))
2484                 matches = rl_completion_matches(text, complete_dump);
2485         else if(!strncasecmp(rl_line_buffer, "add ", 4))
2486                 matches = rl_completion_matches(text, complete_config);
2487         else if(!strncasecmp(rl_line_buffer, "del ", 4))
2488                 matches = rl_completion_matches(text, complete_config);
2489         else if(!strncasecmp(rl_line_buffer, "get ", 4))
2490                 matches = rl_completion_matches(text, complete_config);
2491         else if(!strncasecmp(rl_line_buffer, "set ", 4))
2492                 matches = rl_completion_matches(text, complete_config);
2493         else if(!strncasecmp(rl_line_buffer, "info ", 5))
2494                 matches = rl_completion_matches(text, complete_info);
2495
2496         return matches;
2497 }
2498 #endif
2499
2500 static int cmd_shell(int argc, char *argv[]) {
2501         xasprintf(&prompt, "%s> ", identname);
2502         int result = 0;
2503         char buf[4096];
2504         char *line = NULL;
2505         int maxargs = argc + 16;
2506         char **nargv = xmalloc(maxargs * sizeof *nargv);
2507
2508         for(int i = 0; i < argc; i++)
2509                 nargv[i] = argv[i];
2510
2511 #ifdef HAVE_READLINE
2512         rl_readline_name = "tinc";
2513         rl_completion_entry_function = complete_nothing;
2514         rl_attempted_completion_function = completion;
2515         rl_filename_completion_desired = 0;
2516         char *copy = NULL;
2517 #endif
2518
2519         while(true) {
2520 #ifdef HAVE_READLINE
2521                 if(tty) {
2522                         free(copy);
2523                         free(line);
2524                         rl_basic_word_break_characters = "\t\n ";
2525                         line = readline(prompt);
2526                         if(line)
2527                                 copy = xstrdup(line);
2528                 } else {
2529                         line = fgets(buf, sizeof buf, stdin);
2530                 }
2531 #else
2532                 if(tty)
2533                         fputs(prompt, stdout);
2534
2535                 line = fgets(buf, sizeof buf, stdin);
2536 #endif
2537
2538                 if(!line)
2539                         break;
2540
2541                 /* Ignore comments */
2542
2543                 if(*line == '#')
2544                         continue;
2545
2546                 /* Split */
2547
2548                 int nargc = argc;
2549                 char *p = line + strspn(line, " \t\n");
2550                 char *next = strtok(p, " \t\n");
2551
2552                 while(p && *p) {
2553                         if(nargc >= maxargs) {
2554                                 fprintf(stderr, "next %p '%s', p %p '%s'\n", next, next, p, p);
2555                                 abort();
2556                                 maxargs *= 2;
2557                                 nargv = xrealloc(nargv, maxargs * sizeof *nargv);
2558                         }
2559
2560                         nargv[nargc++] = p;
2561                         p = next;
2562                         next = strtok(NULL, " \t\n");
2563                 }
2564
2565                 if(nargc == argc)
2566                         continue;
2567
2568                 if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit"))
2569                         return result;
2570
2571                 bool found = false;
2572
2573                 for(int i = 0; commands[i].command; i++) {
2574                         if(!strcasecmp(nargv[argc], commands[i].command)) {
2575                                 result |= commands[i].function(nargc - argc - 1, nargv + argc + 1);
2576                                 found = true;
2577                                 break;
2578                         }
2579                 }
2580
2581 #ifdef HAVE_READLINE
2582                 if(tty && found)
2583                         add_history(copy);
2584 #endif
2585
2586                 if(!found) {
2587                         fprintf(stderr, "Unknown command `%s'.\n", nargv[argc]);
2588                         result |= 1;
2589                 }
2590         }
2591
2592         free(nargv);
2593
2594         if(tty)
2595                 printf("\n");
2596         return result;
2597 }
2598
2599
2600 int main(int argc, char *argv[]) {
2601         program_name = argv[0];
2602         orig_argv = argv;
2603         orig_argc = argc;
2604         tty = isatty(0) && isatty(1);
2605
2606         if(!parse_options(argc, argv))
2607                 return 1;
2608
2609         make_names(false);
2610         xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase);
2611         xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase);
2612
2613         if(show_version) {
2614                 version();
2615                 return 0;
2616         }
2617
2618         if(show_help) {
2619                 usage(false);
2620                 return 0;
2621         }
2622
2623 #ifdef HAVE_MINGW
2624         static struct WSAData wsa_state;
2625
2626         if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
2627                 fprintf(stderr, "System call `%s' failed: %s", "WSAStartup", winerror(GetLastError()));
2628                 return false;
2629         }
2630 #endif
2631
2632         srand(time(NULL));
2633         crypto_init();
2634
2635         if(optind >= argc)
2636                 return cmd_shell(argc, argv);
2637
2638         for(int i = 0; commands[i].command; i++) {
2639                 if(!strcasecmp(argv[optind], commands[i].command))
2640                         return commands[i].function(argc - optind, argv + optind);
2641         }
2642
2643         fprintf(stderr, "Unknown command `%s'.\n", argv[optind]);
2644         usage(true);
2645         return 1;
2646 }