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