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