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