curvetun: Added graceful handling of SIGTERM signal
[netsniff-ng.git] / curvetun.c
blob451cd504fdb446e603cef56715167d6233ac2dcd
1 /*
2 * curvetun - the cipherspace wormhole creator
3 * Part of the netsniff-ng project
4 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Copyright 2011 Emmanuel Roullit.
6 * Subject to the GPL, version 2.
8 * He used often to say there was only one Road; that it was like a great
9 * river: it's springs were at every doorstep and every path was it's
10 * tributary. "It's a dangerous business, Frodo, going out of your door,"
11 * he used to say. "You step into the Road, and if you don't keep your
12 * feet, there is no telling where you might be swept off to."
14 * -- The Lord of the Rings, Frodo about his uncle Bilbo Baggins,
15 * Chapter 'Three is Company'.
18 #define _GNU_SOURCE
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <getopt.h>
25 #include <errno.h>
26 #include <stdbool.h>
27 #include <limits.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/socket.h>
31 #include <sys/ptrace.h>
32 #include <sys/fsuid.h>
33 #include <netinet/in.h>
34 #include <unistd.h>
35 #include <signal.h>
37 #include "xutils.h"
38 #include "die.h"
39 #include "xmalloc.h"
40 #include "curvetun.h"
41 #include "curve.h"
42 #include "ct_usermgmt.h"
43 #include "ct_servmgmt.h"
44 #include "xio.h"
45 #include "tprintf.h"
46 #include "crypto_verify_32.h"
47 #include "crypto_box_curve25519xsalsa20poly1305.h"
48 #include "crypto_scalarmult_curve25519.h"
49 #include "crypto_auth_hmacsha512256.h"
51 #define CURVETUN_ENTROPY_SOURCE "/dev/random"
53 extern void print_stun_probe(char *server, uint16_t sport, uint16_t tunport);
55 enum working_mode {
56 MODE_UNKNOW,
57 MODE_KEYGEN,
58 MODE_EXPORT,
59 MODE_DUMPC,
60 MODE_DUMPS,
61 MODE_CLIENT,
62 MODE_SERVER,
65 volatile sig_atomic_t sigint = 0;
67 static const char *short_options = "kxc::svhp:t:d:uCS46DN";
68 static const struct option long_options[] = {
69 {"client", optional_argument, NULL, 'c'},
70 {"dev", required_argument, NULL, 'd'},
71 {"port", required_argument, NULL, 'p'},
72 {"stun", required_argument, NULL, 't'},
73 {"keygen", no_argument, NULL, 'k'},
74 {"export", no_argument, NULL, 'x'},
75 {"dumpc", no_argument, NULL, 'C'},
76 {"dumps", no_argument, NULL, 'S'},
77 {"no-logging", no_argument, NULL, 'N'},
78 {"server", no_argument, NULL, 's'},
79 {"udp", no_argument, NULL, 'u'},
80 {"ipv4", no_argument, NULL, '4'},
81 {"ipv6", no_argument, NULL, '6'},
82 {"nofork", no_argument, NULL, 'D'},
83 {"version", no_argument, NULL, 'v'},
84 {"help", no_argument, NULL, 'h'},
85 {NULL, 0, NULL, 0}
88 static void signal_handler(int number)
90 switch (number) {
91 case SIGINT:
92 sigint = 1;
93 break;
94 case SIGTERM:
95 sigint = 1;
96 break;
97 default:
98 break;
102 static void help(void)
104 printf("\ncurvetun %s, lightweight curve25519-based VPN/IP tunnel\n", VERSION_STRING);
105 puts("http://www.netsniff-ng.org\n\n"
106 "Usage: curvetun [options]\n"
107 "Options, general:\n"
108 " -d|--dev <tun> Networking tunnel device, e.g. tun0\n"
109 " -p|--port <num> Server port number (mandatory)\n"
110 " -t|--stun <server> Show public IP/Port mapping via STUN\n"
111 " -c|--client[=alias] Client mode, server alias optional\n"
112 " -k|--keygen Generate public/private keypair\n"
113 " -x|--export Export your public data for remote servers\n"
114 " -C|--dumpc Dump parsed clients\n"
115 " -S|--dumps Dump parsed servers\n"
116 " -D|--nofork Do not daemonize\n"
117 " -s|--server Server mode, options follow below\n"
118 " -N|--no-logging Disable server logging (for better anonymity)\n"
119 " -u|--udp Use UDP as carrier instead of TCP\n"
120 " -4|--ipv4 Tunnel devices are IPv4\n"
121 " -6|--ipv6 Tunnel devices are IPv6\n"
122 " -v|--version Print version\n"
123 " -h|--help Print this help\n\n"
124 "Example:\n"
125 " See Documentation/Curvetun for a configuration example.\n"
126 " curvetun --server -4 -u -N --port 6666 --stun stunserver.org\n"
127 " curvetun --client=ethz\n\n"
128 " curvetun --keygen\n"
129 " curvetun --export\n"
130 "Note:\n"
131 " There is no default port specified, so that you are forced\n"
132 " to select your own! For client/server status messages see syslog!\n"
133 " This software is an experimental prototype intended for researchers.\n\n"
134 "Secret ingredient: 7647-14-5\n\n"
135 "Please report bugs to <bugs@netsniff-ng.org>\n"
136 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
137 "Swiss federal institute of technology (ETH Zurich)\n"
138 "License: GNU GPL version 2.0\n"
139 "This is free software: you are free to change and redistribute it.\n"
140 "There is NO WARRANTY, to the extent permitted by law.\n");
141 die();
144 static void version(void)
146 printf("\ncurvetun %s, lightweight curve25519-based VPN/IP tunnel\n", VERSION_STRING);
147 puts("http://www.netsniff-ng.org\n\n"
148 "Please report bugs to <bugs@netsniff-ng.org>\n"
149 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
150 "Swiss federal institute of technology (ETH Zurich)\n"
151 "License: GNU GPL version 2.0\n"
152 "This is free software: you are free to change and redistribute it.\n"
153 "There is NO WARRANTY, to the extent permitted by law.\n");
154 die();
157 static void check_file_or_die(char *home, char *file, int maybeempty)
159 char path[PATH_MAX];
160 struct stat st;
162 memset(path, 0, sizeof(path));
163 slprintf(path, sizeof(path), "%s/%s", home, file);
165 if (stat(path, &st))
166 panic("No such file %s! Type --help for further information\n",
167 path);
169 if (!S_ISREG(st.st_mode))
170 panic("%s is not a regular file!\n", path);
172 if ((st.st_mode & ~S_IFREG) != (S_IRUSR | S_IWUSR))
173 panic("You have set too many permissions on %s (%o)!\n",
174 path, st.st_mode);
176 if (maybeempty == 0 && st.st_size == 0)
177 panic("%s is empty!\n", path);
180 static void check_config_exists_or_die(char *home)
182 if (!home)
183 panic("No home dir specified!\n");
185 check_file_or_die(home, FILE_CLIENTS, 1);
186 check_file_or_die(home, FILE_SERVERS, 1);
187 check_file_or_die(home, FILE_PRIVKEY, 0);
188 check_file_or_die(home, FILE_PUBKEY, 0);
189 check_file_or_die(home, FILE_USERNAM, 0);
192 static char *fetch_home_dir(void)
194 char *home = getenv("HOME");
195 if (!home)
196 panic("No HOME defined!\n");
197 return home;
200 static void write_username(char *home)
202 int fd, ret;
203 char path[PATH_MAX];
204 char user[512];
206 memset(path, 0, sizeof(path));
207 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
209 printf("Username: [%s] ", getenv("USER"));
210 fflush(stdout);
212 memset(user, 0, sizeof(user));
213 if (fgets(user, sizeof(user), stdin) == NULL)
214 panic("Could not read from stdin!\n");
215 user[sizeof(user) - 1] = 0;
216 user[strlen(user) - 1] = 0; /* omit last \n */
217 if (strlen(user) == 0)
218 strlcpy(user, getenv("USER"), sizeof(user));
220 fd = open_or_die_m(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
222 ret = write(fd, user, strlen(user));
223 if (ret != strlen(user))
224 panic("Could not write username!\n");
226 close(fd);
228 printf("Username written to %s!\n", path);
231 static void create_curvedir(char *home)
233 int ret;
234 char path[PATH_MAX];
236 memset(path, 0, sizeof(path));
237 slprintf(path, sizeof(path), "%s/%s", home, ".curvetun/");
239 errno = 0;
241 ret = mkdir(path, S_IRWXU);
242 if (ret < 0 && errno != EEXIST)
243 panic("Cannot create curvetun dir!\n");
245 printf("curvetun directory %s created!\n", path);
246 /* We also create empty files for clients and servers! */
248 memset(path, 0, sizeof(path));
249 slprintf(path, sizeof(path), "%s/%s", home, FILE_CLIENTS);
251 create_or_die(path, S_IRUSR | S_IWUSR);
253 printf("Empty client file written to %s!\n", path);
255 memset(path, 0, sizeof(path));
256 slprintf(path, sizeof(path), "%s/%s", home, FILE_SERVERS);
258 create_or_die(path, S_IRUSR | S_IWUSR);
260 printf("Empty server file written to %s!\n", path);
263 static void create_keypair(char *home)
265 int fd, err = 0;
266 ssize_t ret;
267 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES] = { 0 };
268 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES] = { 0 };
269 char path[PATH_MAX];
270 const char * errstr = NULL;
272 printf("Reading from %s (this may take a while) ...\n", CURVETUN_ENTROPY_SOURCE);
274 fd = open_or_die(CURVETUN_ENTROPY_SOURCE, O_RDONLY);
276 ret = read_exact(fd, secretkey, sizeof(secretkey), 0);
277 if (ret != sizeof(secretkey)) {
278 err = EIO;
279 errstr = "Cannot read from "CURVETUN_ENTROPY_SOURCE"!\n";
280 goto out;
283 close(fd);
285 crypto_scalarmult_curve25519_base(publickey, secretkey);
287 memset(path, 0, sizeof(path));
288 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
290 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
291 if (fd < 0) {
292 err = EIO;
293 errstr = "Cannot open pubkey file!\n";
294 goto out;
297 ret = write(fd, publickey, sizeof(publickey));
298 if (ret != sizeof(publickey)) {
299 err = EIO;
300 errstr = "Cannot write public key!\n";
301 goto out;
304 close(fd);
306 printf("Public key written to %s!\n", path);
308 memset(path, 0, sizeof(path));
309 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
311 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
312 if (fd < 0) {
313 err = EIO;
314 errstr = "Cannot open privkey file!\n";
315 goto out;
318 ret = write(fd, secretkey, sizeof(secretkey));
319 if (ret != sizeof(secretkey)) {
320 err = EIO;
321 errstr = "Cannot write private key!\n";
322 goto out;
324 out:
325 close(fd);
327 xmemset(publickey, 0, sizeof(publickey));
328 xmemset(secretkey, 0, sizeof(secretkey));
330 if (err)
331 panic("%s: %s", errstr, strerror(errno));
332 else
333 printf("Private key written to %s!\n", path);
336 static void check_config_keypair_or_die(char *home)
338 int fd, err;
339 ssize_t ret;
340 const char * errstr = NULL;
341 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
342 unsigned char publicres[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
343 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES];
344 char path[PATH_MAX];
346 memset(path, 0, sizeof(path));
347 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
349 fd = open(path, O_RDONLY);
350 if (fd < 0) {
351 err = EIO;
352 errstr = "Cannot open privkey file!\n";
353 goto out;
356 ret = read(fd, secretkey, sizeof(secretkey));
357 if (ret != sizeof(secretkey)) {
358 err = EIO;
359 errstr = "Cannot read private key!\n";
360 goto out;
363 close(fd);
365 memset(path, 0, sizeof(path));
366 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
368 fd = open(path, O_RDONLY);
369 if (fd < 0) {
370 err = EIO;
371 errstr = "Cannot open pubkey file!\n";
372 goto out;
375 ret = read(fd, publickey, sizeof(publickey));
376 if (ret != sizeof(publickey)) {
377 err = EIO;
378 errstr = "Cannot read public key!\n";
379 goto out;
382 crypto_scalarmult_curve25519_base(publicres, secretkey);
384 err = crypto_verify_32(publicres, publickey);
385 if (err) {
386 err = EINVAL;
387 errstr = "WARNING: your keypair is corrupted!!! You need to "
388 "generate new keys!!!\n";
389 goto out;
391 out:
392 close(fd);
394 xmemset(publickey, 0, sizeof(publickey));
395 xmemset(publicres, 0, sizeof(publicres));
396 xmemset(secretkey, 0, sizeof(secretkey));
398 if (err)
399 panic("%s: %s\n", errstr, strerror(errno));
402 static int main_keygen(char *home)
404 create_curvedir(home);
405 write_username(home);
406 create_keypair(home);
407 check_config_keypair_or_die(home);
409 return 0;
412 static int main_export(char *home)
414 int fd, i;
415 ssize_t ret;
416 char path[PATH_MAX], tmp[64];
418 check_config_exists_or_die(home);
419 check_config_keypair_or_die(home);
421 printf("Your exported public information:\n\n");
423 memset(path, 0, sizeof(path));
424 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
426 fd = open_or_die(path, O_RDONLY);
428 while ((ret = read(fd, tmp, sizeof(tmp))) > 0) {
429 ret = write(STDOUT_FILENO, tmp, ret);
432 close(fd);
434 printf(";");
436 memset(path, 0, sizeof(path));
437 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
439 fd = open_or_die(path, O_RDONLY);
441 ret = read(fd, tmp, sizeof(tmp));
442 if (ret != crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)
443 panic("Cannot read public key!\n");
445 for (i = 0; i < ret; ++i)
446 if (i == ret - 1)
447 printf("%02x\n\n", (unsigned char) tmp[i]);
448 else
449 printf("%02x:", (unsigned char) tmp[i]);
451 close(fd);
452 fflush(stdout);
454 return 0;
457 static int main_dumpc(char *home)
459 check_config_exists_or_die(home);
460 check_config_keypair_or_die(home);
462 printf("Your clients:\n\n");
464 parse_userfile_and_generate_user_store_or_die(home);
466 dump_user_store();
468 destroy_user_store();
470 printf("\n");
471 die();
472 return 0;
475 static int main_dumps(char *home)
477 check_config_exists_or_die(home);
478 check_config_keypair_or_die(home);
480 printf("Your servers:\n\n");
482 parse_userfile_and_generate_serv_store_or_die(home);
484 dump_serv_store();
486 destroy_serv_store();
488 printf("\n");
489 die();
490 return 0;
493 static void daemonize(const char *lockfile)
495 char pidstr[8];
496 mode_t lperm = S_IRWXU | S_IRGRP | S_IXGRP; /* 0750 */
497 int lfp;
499 if (getppid() == 1)
500 return;
502 if (daemon(0, 1))
503 panic("Cannot daemonize: %s", strerror(errno));
505 to_std_log(&stdout);
506 to_std_log(&stderr);
508 umask(lperm);
509 if (lockfile) {
510 lfp = open(lockfile, O_RDWR | O_CREAT | O_EXCL,
511 S_IRUSR | S_IWUSR | S_IRGRP);
512 if (lfp < 0)
513 syslog_panic("Cannot create lockfile at %s! "
514 "curvetun server already running?\n",
515 lockfile);
517 slprintf(pidstr, sizeof(pidstr), "%u", getpid());
518 if (write(lfp, pidstr, strlen(pidstr)) <= 0)
519 syslog_panic("Could not write pid to pidfile %s",
520 lockfile);
522 close(lfp);
526 static int main_client(char *home, char *dev, char *alias, int daemon)
528 int ret, udp;
529 char *host, *port;
531 check_config_exists_or_die(home);
532 check_config_keypair_or_die(home);
534 parse_userfile_and_generate_serv_store_or_die(home);
536 get_serv_store_entry_by_alias(alias, alias ? strlen(alias) + 1 : 0,
537 &host, &port, &udp);
538 if (!host || !port || udp < 0)
539 panic("Did not find alias/entry in configuration!\n");
541 printf("Using [%s] -> %s:%s via %s as endpoint!\n",
542 alias ? : "default", host, port, udp ? "udp" : "tcp");
543 if (daemon)
544 daemonize(NULL);
546 ret = client_main(home, dev, host, port, udp);
548 destroy_serv_store();
550 return ret;
553 static int main_server(char *home, char *dev, char *port, int udp,
554 int ipv4, int daemon, int log)
556 int ret;
558 check_config_exists_or_die(home);
559 check_config_keypair_or_die(home);
561 if (daemon)
562 daemonize(LOCKFILE);
564 ret = server_main(home, dev, port, udp, ipv4, log);
566 unlink(LOCKFILE);
568 return ret;
571 int main(int argc, char **argv)
573 int ret = 0, c, opt_index, udp = 0, ipv4 = -1, daemon = 1, log = 1;
574 char *port = NULL, *stun = NULL, *dev = NULL, *home = NULL, *alias = NULL;
575 enum working_mode wmode = MODE_UNKNOW;
577 setfsuid(getuid());
578 setfsgid(getgid());
580 home = fetch_home_dir();
582 while ((c = getopt_long(argc, argv, short_options, long_options,
583 &opt_index)) != EOF) {
584 switch (c) {
585 case 'h':
586 help();
587 break;
588 case 'v':
589 version();
590 break;
591 case 'D':
592 daemon = 0;
593 break;
594 case 'N':
595 log = 0;
596 break;
597 case 'C':
598 wmode = MODE_DUMPC;
599 break;
600 case 'S':
601 wmode = MODE_DUMPS;
602 break;
603 case 'c':
604 wmode = MODE_CLIENT;
605 if (optarg) {
606 if (*optarg == '=')
607 optarg++;
608 alias = xstrdup(optarg);
610 break;
611 case 'd':
612 dev = xstrdup(optarg);
613 break;
614 case 'k':
615 wmode = MODE_KEYGEN;
616 break;
617 case '4':
618 ipv4 = 1;
619 break;
620 case '6':
621 ipv4 = 0;
622 break;
623 case 'x':
624 wmode = MODE_EXPORT;
625 break;
626 case 's':
627 wmode = MODE_SERVER;
628 break;
629 case 'u':
630 udp = 1;
631 break;
632 case 't':
633 stun = xstrdup(optarg);
634 break;
635 case 'p':
636 port = xstrdup(optarg);
637 break;
638 case '?':
639 switch (optopt) {
640 case 't':
641 case 'd':
642 case 'u':
643 case 'p':
644 panic("Option -%c requires an argument!\n",
645 optopt);
646 default:
647 if (isprint(optopt))
648 printf("Unknown option character `0x%X\'!\n", optopt);
649 die();
651 default:
652 break;
656 if (argc < 2)
657 help();
659 register_signal(SIGINT, signal_handler);
660 register_signal(SIGHUP, signal_handler);
661 register_signal(SIGTERM, signal_handler);
662 register_signal(SIGPIPE, signal_handler);
664 curve25519_selftest();
666 switch (wmode) {
667 case MODE_KEYGEN:
668 ret = main_keygen(home);
669 break;
670 case MODE_EXPORT:
671 ret = main_export(home);
672 break;
673 case MODE_DUMPC:
674 ret = main_dumpc(home);
675 break;
676 case MODE_DUMPS:
677 ret = main_dumps(home);
678 break;
679 case MODE_CLIENT:
680 ret = main_client(home, dev, alias, daemon);
681 break;
682 case MODE_SERVER:
683 if (!port)
684 panic("No port specified!\n");
685 if (stun)
686 print_stun_probe(stun, 3478, strtoul(port, NULL, 10));
687 ret = main_server(home, dev, port, udp, ipv4, daemon, log);
688 break;
689 default:
690 die();
693 if (dev)
694 xfree(dev);
695 if (stun)
696 xfree(stun);
697 if (port)
698 xfree(port);
699 if (alias)
700 xfree(alias);
702 return ret;