xsys: moved tty.h stuff into xsys, removed tty.h
[netsniff-ng.git] / src / curvetun.c
blob3bc12050b238149779843e309382cf8195e2337f
1 /*
2 * curvetun - the cipherspace wormhole creator
3 * Part of the netsniff-ng project
4 * By Daniel Borkmann <daniel@netsniff-ng.org>
5 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
6 * Copyright 2011 Emmanuel Roullit.
7 * Subject to the GPL, version 2.
9 * This is curvetun, a lightweight, high-speed ECDH multiuser IP tunnel for
10 * Linux that is based on epoll(2). curvetun uses the Linux TUN/TAP interface
11 * and supports {IPv4,IPv6} over {IPv4,IPv6} with UDP or TCP as carrier
12 * protocols. It has an integrated packet forwarding trie, thus multiple
13 * users with different IPs can be handled via a single tunnel device on the
14 * server side and flows are scheduled for processing in a CPU-local manner.
15 * For transmission, packets are being compressed and encrypted by both, the
16 * client and the server side. As an appropriate key management, public-key
17 * cryptography based on elliptic curves are being used and packets are
18 * encrypted by a symmetric stream cipher (Salsa20) and authenticated by a MAC
19 * (Poly1305), where keys have previously been computed with the ECDH key
20 * agreement protocol (Curve25519). Cryptography is based on Daniel J.
21 * Bernsteins Networking and Cryptography library (NaCl).
23 * He used often to say there was only one Road; that it was like a great
24 * river: it's springs were at every doorstep and every path was it's
25 * tributary. "It's a dangerous business, Frodo, going out of your door,"
26 * he used to say. "You step into the Road, and if you don't keep your
27 * feet, there is no telling where you might be swept off to."
29 * -- The Lord of the Rings, Frodo about his uncle Bilbo Baggins,
30 * Chapter 'Three is Company'.
33 #define _GNU_SOURCE
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <fcntl.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <getopt.h>
40 #include <errno.h>
41 #include <stdbool.h>
42 #include <limits.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/socket.h>
46 #include <sys/ptrace.h>
47 #include <netinet/in.h>
48 #include <unistd.h>
49 #include <signal.h>
51 #include "xsys.h"
52 #include "stun.h"
53 #include "die.h"
54 #include "xmalloc.h"
55 #include "strlcpy.h"
56 #include "curvetun.h"
57 #include "curve.h"
58 #include "usermgmt.h"
59 #include "servmgmt.h"
60 #include "xio.h"
61 #include "crypto_verify_32.h"
62 #include "crypto_box_curve25519xsalsa20poly1305.h"
63 #include "crypto_scalarmult_curve25519.h"
64 #include "crypto_auth_hmacsha512256.h"
66 #define CURVETUN_ENTROPY_SOURCE "/dev/random"
68 enum working_mode {
69 MODE_UNKNOW,
70 MODE_KEYGEN,
71 MODE_EXPORT,
72 MODE_DUMPC,
73 MODE_DUMPS,
74 MODE_CLIENT,
75 MODE_SERVER,
78 sig_atomic_t sigint = 0;
80 static const char *short_options = "kxc::svhp:t:d:uCS46DN";
82 static struct option long_options[] = {
83 {"client", optional_argument, 0, 'c'},
84 {"dev", required_argument, 0, 'd'},
85 {"port", required_argument, 0, 'p'},
86 {"stun", required_argument, 0, 't'},
87 {"keygen", no_argument, 0, 'k'},
88 {"export", no_argument, 0, 'x'},
89 {"dumpc", no_argument, 0, 'C'},
90 {"dumps", no_argument, 0, 'S'},
91 {"no-logging", no_argument, 0, 'N'},
92 {"server", no_argument, 0, 's'},
93 {"udp", no_argument, 0, 'u'},
94 {"ipv4", no_argument, 0, '4'},
95 {"ipv6", no_argument, 0, '6'},
96 {"nofork", no_argument, 0, 'D'},
97 {"version", no_argument, 0, 'v'},
98 {"help", no_argument, 0, 'h'},
99 {0, 0, 0, 0}
102 static void signal_handler(int number)
104 switch (number) {
105 case SIGINT:
106 sigint = 1;
107 break;
108 default:
109 break;
113 static void header(void)
115 printf("%s%s%s\n", colorize_start(bold), "curvetun "
116 VERSION_STRING, colorize_end());
119 static void help(void)
121 printf("\ncurvetun %s, lightweight curve25519-based multiuser IP tunnel\n",
122 VERSION_STRING);
123 printf("http://www.netsniff-ng.org\n\n");
124 printf("Usage: curvetun [options]\n");
125 printf("Options:\n");
126 printf(" -k|--keygen Generate public/private keypair\n");
127 printf(" -x|--export Export your public data for remote servers\n");
128 printf(" -C|--dumpc Dump parsed clients\n");
129 printf(" -S|--dumps Dump parsed servers\n");
130 printf(" -D|--nofork Do not daemonize\n");
131 printf(" -d|--dev <tun> Networking tunnel device, e.g. tun0\n");
132 printf(" -v|--version Print version\n");
133 printf(" -h|--help Print this help\n");
134 printf(" additional options for client:\n");
135 printf(" -c|--client[=alias] Client mode, server alias optional\n");
136 printf(" additional options for servers:\n");
137 printf(" -s|--server Server mode\n");
138 printf(" -N|--no-logging Disable server logging (for better anonymity)\n");
139 printf(" -p|--port <num> Port number (mandatory)\n");
140 printf(" -t|--stun <server> Show public IP/Port mapping via STUN\n");
141 printf(" -u|--udp Use UDP as carrier instead of TCP\n");
142 printf(" -4|--ipv4 Tunnel devices are IPv4\n");
143 printf(" -6|--ipv6 Tunnel devices are IPv6\n");
144 printf(" (default: same as carrier protocol)\n");
145 printf("\n");
146 printf("Example:\n");
147 printf(" See README.curvetun for a configuration example.\n");
148 printf(" curvetun --keygen\n");
149 printf(" curvetun --export\n");
150 printf(" curvetun --server -4 -u -N --port 6666 --stun stunserver.org\n");
151 printf(" curvetun --client=ethz\n");
152 printf("\n");
153 printf("Note:\n");
154 printf(" There is no default port specified, so that you are forced\n");
155 printf(" to select your own! For client/server status messages see syslog!\n");
156 printf("\n");
157 printf("Secret ingredient: 7647-14-5\n");
158 printf("\n");
159 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
160 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
161 printf("License: GNU GPL version 2\n");
162 printf("This is free software: you are free to change and redistribute it.\n");
163 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
164 die();
167 static void version(void)
169 printf("\ncurvetun %s, lightweight curve25519-based multiuser IP tunnel\n",
170 VERSION_STRING);
171 printf("Build: %s\n", BUILD_STRING);
172 printf("http://www.netsniff-ng.org\n\n");
173 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
174 printf("Copyright (C) 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
175 printf("License: GNU GPL version 2\n");
176 printf("This is free software: you are free to change and redistribute it.\n");
177 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
178 die();
181 static void check_file_or_die(char *home, char *file, int maybeempty)
183 char path[PATH_MAX];
184 struct stat st;
186 memset(path, 0, sizeof(path));
187 slprintf(path, sizeof(path), "%s/%s", home, file);
189 if (stat(path, &st))
190 panic("No such file %s! Type --help for further information\n",
191 path);
193 if (!S_ISREG(st.st_mode))
194 panic("%s is not a regular file!\n", path);
196 if ((st.st_mode & ~S_IFREG) != (S_IRUSR | S_IWUSR))
197 panic("You have set too many permissions on %s (%o)!\n",
198 path, st.st_mode);
200 if (maybeempty == 0 && st.st_size == 0)
201 panic("%s is empty!\n", path);
204 static void check_config_exists_or_die(char *home)
206 if (!home)
207 panic("No home dir specified!\n");
208 check_file_or_die(home, FILE_CLIENTS, 1);
209 check_file_or_die(home, FILE_SERVERS, 1);
210 check_file_or_die(home, FILE_PRIVKEY, 0);
211 check_file_or_die(home, FILE_PUBKEY, 0);
212 check_file_or_die(home, FILE_USERNAM, 0);
215 static char *fetch_home_dir(void)
217 char *home = getenv("HOME");
218 if (!home)
219 panic("No HOME defined!\n");
220 return home;
223 static void write_username(char *home)
225 int fd, ret;
226 char path[PATH_MAX], *eof;
227 char user[512];
229 memset(path, 0, sizeof(path));
230 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
232 printf("Username: [%s] ", getenv("USER"));
233 fflush(stdout);
235 memset(user, 0, sizeof(user));
236 eof = fgets(user, sizeof(user), stdin);
237 user[sizeof(user) - 1] = 0;
238 user[strlen(user) - 1] = 0; /* omit last \n */
240 if (strlen(user) == 0)
241 strlcpy(user, getenv("USER"), sizeof(user));
243 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
244 if (fd < 0)
245 panic("Cannot open your username file!\n");
246 ret = write(fd, user, strlen(user));
247 if (ret != strlen(user))
248 panic("Could not write username!\n");
249 close(fd);
251 info("Username written to %s!\n", path);
254 static void create_curvedir(char *home)
256 int ret, fd;
257 char path[PATH_MAX];
259 memset(path, 0, sizeof(path));
260 slprintf(path, sizeof(path), "%s/%s", home, ".curvetun/");
262 errno = 0;
263 ret = mkdir(path, S_IRWXU);
264 if (ret < 0 && errno != EEXIST)
265 panic("Cannot create curvetun dir!\n");
267 info("curvetun directory %s created!\n", path);
269 /* We also create empty files for clients and servers! */
270 memset(path, 0, sizeof(path));
271 slprintf(path, sizeof(path), "%s/%s", home, FILE_CLIENTS);
273 fd = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
274 if (fd < 0)
275 panic("Cannot open clients file!\n");
276 close(fd);
278 info("Empty client file written to %s!\n", path);
280 memset(path, 0, sizeof(path));
281 slprintf(path, sizeof(path), "%s/%s", home, FILE_SERVERS);
283 fd = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
284 if (fd < 0)
285 panic("Cannot open servers file!\n");
286 close(fd);
288 info("Empty server file written to %s!\n", path);
291 static void create_keypair(char *home)
293 int fd;
294 ssize_t ret;
295 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES] = { 0 };
296 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES] = { 0 };
297 char path[PATH_MAX];
298 const char * errstr = NULL;
299 int err = 0;
301 info("Reading from %s (this may take a while) ...\n", CURVETUN_ENTROPY_SOURCE);
303 fd = open_or_die(CURVETUN_ENTROPY_SOURCE, O_RDONLY);
304 ret = read_exact(fd, secretkey, sizeof(secretkey), 0);
305 if (ret != sizeof(secretkey)) {
306 err = EIO;
307 errstr = "Cannot read from "CURVETUN_ENTROPY_SOURCE"!\n";
308 goto out;
310 close(fd);
312 crypto_scalarmult_curve25519_base(publickey, secretkey);
314 memset(path, 0, sizeof(path));
315 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
317 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
318 if (fd < 0) {
319 err = EIO;
320 errstr = "Cannot open pubkey file!\n";
321 goto out;
323 ret = write(fd, publickey, sizeof(publickey));
324 if (ret != sizeof(publickey)) {
325 err = EIO;
326 errstr = "Cannot write public key!\n";
327 goto out;
329 close(fd);
331 info("Public key written to %s!\n", path);
333 memset(path, 0, sizeof(path));
334 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
336 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
337 if (fd < 0) {
338 err = EIO;
339 errstr = "Cannot open privkey file!\n";
340 goto out;
343 ret = write(fd, secretkey, sizeof(secretkey));
344 if (ret != sizeof(secretkey)) {
345 err = EIO;
346 errstr = "Cannot write private key!\n";
347 goto out;
349 out:
350 close(fd);
352 memset(publickey, 0, sizeof(publickey));
353 memset(secretkey, 0, sizeof(secretkey));
354 if (err)
355 panic("%s: %s", errstr, strerror(errno));
356 else
357 info("Private key written to %s!\n", path);
360 static void check_config_keypair_or_die(char *home)
362 int fd;
363 ssize_t ret;
364 int err;
365 const char * errstr = NULL;
366 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
367 unsigned char publicres[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
368 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES];
369 char path[PATH_MAX];
371 memset(path, 0, sizeof(path));
372 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
374 fd = open(path, O_RDONLY);
375 if (fd < 0) {
376 err = EIO;
377 errstr = "Cannot open privkey file!\n";
378 goto out;
380 ret = read(fd, secretkey, sizeof(secretkey));
381 if (ret != sizeof(secretkey)) {
382 err = EIO;
383 errstr = "Cannot read private key!\n";
384 goto out;
386 close(fd);
388 memset(path, 0, sizeof(path));
389 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
391 fd = open(path, O_RDONLY);
392 if (fd < 0) {
393 err = EIO;
394 errstr = "Cannot open pubkey file!\n";
395 goto out;
397 ret = read(fd, publickey, sizeof(publickey));
398 if (ret != sizeof(publickey)) {
399 err = EIO;
400 errstr = "Cannot read public key!\n";
401 goto out;
404 crypto_scalarmult_curve25519_base(publicres, secretkey);
405 err = crypto_verify_32(publicres, publickey);
406 if (err) {
407 err = EINVAL;
408 errstr = "WARNING: your keypair is corrupted!!! You need to "
409 "generate new keys!!!\n";
410 goto out;
412 out:
413 close(fd);
414 memset(publickey, 0, sizeof(publickey));
415 memset(publicres, 0, sizeof(publicres));
416 memset(secretkey, 0, sizeof(secretkey));
417 if (err)
418 panic("%s: %s\n", errstr, strerror(errno));
421 static int main_keygen(char *home)
423 create_curvedir(home);
424 write_username(home);
425 create_keypair(home);
426 check_config_keypair_or_die(home);
427 return 0;
430 static int main_export(char *home)
432 int fd, i;
433 ssize_t ret;
434 char path[PATH_MAX], tmp[64];
436 check_config_exists_or_die(home);
437 check_config_keypair_or_die(home);
439 printf("Your exported public information:\n\n");
441 memset(path, 0, sizeof(path));
442 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
444 fd = open_or_die(path, O_RDONLY);
445 while ((ret = read(fd, tmp, sizeof(tmp))) > 0) {
446 ret = write(STDOUT_FILENO, tmp, ret);
448 close(fd);
450 printf(";");
452 memset(path, 0, sizeof(path));
453 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
455 fd = open_or_die(path, O_RDONLY);
456 ret = read(fd, tmp, sizeof(tmp));
457 if (ret != crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)
458 panic("Cannot read public key!\n");
459 for (i = 0; i < ret; ++i)
460 if (i == ret - 1)
461 printf("%02x\n\n", (unsigned char) tmp[i]);
462 else
463 printf("%02x:", (unsigned char) tmp[i]);
464 close(fd);
465 fflush(stdout);
467 return 0;
470 static int main_dumpc(char *home)
472 check_config_exists_or_die(home);
473 check_config_keypair_or_die(home);
475 printf("Your clients:\n\n");
477 parse_userfile_and_generate_user_store_or_die(home);
478 dump_user_store();
479 destroy_user_store();
481 printf("\n");
482 die();
483 return 0;
486 static int main_dumps(char *home)
488 check_config_exists_or_die(home);
489 check_config_keypair_or_die(home);
491 printf("Your servers:\n\n");
493 parse_userfile_and_generate_serv_store_or_die(home);
494 dump_serv_store();
495 destroy_serv_store();
497 printf("\n");
498 die();
499 return 0;
502 static void daemonize(const char *lockfile)
504 char pidstr[8];
505 mode_t lperm = S_IRWXU | S_IRGRP | S_IXGRP; /* 0750 */
506 int lfp;
508 if (getppid() == 1)
509 return;
511 if (daemon(0, 0))
512 panic("Cannot daemonize: %s", strerror(errno));
514 umask(lperm);
516 if (lockfile) {
517 lfp = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0640);
518 if (lfp < 0)
519 syslog_panic("Cannot create lockfile at %s! "
520 "curvetun server already running?\n",
521 lockfile);
523 slprintf(pidstr, sizeof(pidstr), "%u", getpid());
524 if (write(lfp, pidstr, strlen(pidstr)) <= 0)
525 syslog_panic("Could not write pid to pidfile %s",
526 lockfile);
527 close(lfp);
531 static int main_client(char *home, char *dev, char *alias, int daemon)
533 int ret, udp;
534 char *host, *port;
536 check_config_exists_or_die(home);
537 check_config_keypair_or_die(home);
539 parse_userfile_and_generate_serv_store_or_die(home);
540 get_serv_store_entry_by_alias(alias, alias ? strlen(alias) + 1 : 0,
541 &host, &port, &udp);
542 if (!host || !port || udp < 0)
543 panic("Did not find alias/entry in configuration!\n");
544 printf("Using [%s] -> %s:%s via %s as endpoint!\n",
545 alias ? : "default", host, port, udp ? "udp" : "tcp");
547 if (daemon)
548 daemonize(NULL);
549 ret = client_main(home, dev, host, port, udp);
550 destroy_serv_store();
552 return ret;
555 static int main_server(char *home, char *dev, char *port, int udp,
556 int ipv4, int daemon, int log)
558 int ret;
560 check_config_exists_or_die(home);
561 check_config_keypair_or_die(home);
562 if (daemon)
563 daemonize(LOCKFILE);
564 ret = server_main(home, dev, port, udp, ipv4, log);
565 unlink(LOCKFILE);
567 return ret;
570 int main(int argc, char **argv)
572 int ret = 0, c, opt_index, udp = 0, ipv4 = -1, daemon = 1, log = 1;
573 char *port = NULL, *stun = NULL, *dev = NULL, *home = NULL, *alias=NULL;
574 enum working_mode wmode = MODE_UNKNOW;
576 if (getuid() != geteuid())
577 seteuid(getuid());
578 if (getenv("LD_PRELOAD"))
579 panic("curvetun cannot be preloaded!\n");
580 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0)
581 panic("curvetun cannot be ptraced!\n");
583 home = fetch_home_dir();
585 while ((c = getopt_long(argc, argv, short_options, long_options,
586 &opt_index)) != EOF) {
587 switch (c) {
588 case 'h':
589 help();
590 break;
591 case 'v':
592 version();
593 break;
594 case 'D':
595 daemon = 0;
596 break;
597 case 'N':
598 log = 0;
599 break;
600 case 'C':
601 wmode = MODE_DUMPC;
602 break;
603 case 'S':
604 wmode = MODE_DUMPS;
605 break;
606 case 'c':
607 wmode = MODE_CLIENT;
608 if (optarg) {
609 if (*optarg == '=')
610 optarg++;
611 alias = xstrdup(optarg);
613 break;
614 case 'd':
615 dev = xstrdup(optarg);
616 break;
617 case 'k':
618 wmode = MODE_KEYGEN;
619 break;
620 case '4':
621 ipv4 = 1;
622 break;
623 case '6':
624 ipv4 = 0;
625 break;
626 case 'x':
627 wmode = MODE_EXPORT;
628 break;
629 case 's':
630 wmode = MODE_SERVER;
631 break;
632 case 'u':
633 udp = 1;
634 break;
635 case 't':
636 stun = xstrdup(optarg);
637 break;
638 case 'p':
639 port = xstrdup(optarg);
640 break;
641 case '?':
642 switch (optopt) {
643 case 't':
644 case 'd':
645 case 'u':
646 case 'p':
647 panic("Option -%c requires an argument!\n",
648 optopt);
649 default:
650 if (isprint(optopt))
651 whine("Unknown option character "
652 "`0x%X\'!\n", optopt);
653 die();
655 default:
656 break;
660 if (argc < 2)
661 help();
663 register_signal(SIGINT, signal_handler);
664 register_signal(SIGHUP, signal_handler);
665 register_signal(SIGTERM, signal_handler);
666 register_signal(SIGPIPE, signal_handler);
668 header();
669 curve25519_selftest();
671 switch (wmode) {
672 case MODE_KEYGEN:
673 ret = main_keygen(home);
674 break;
675 case MODE_EXPORT:
676 ret = main_export(home);
677 break;
678 case MODE_DUMPC:
679 ret = main_dumpc(home);
680 break;
681 case MODE_DUMPS:
682 ret = main_dumps(home);
683 break;
684 case MODE_CLIENT:
685 ret = main_client(home, dev, alias, daemon);
686 break;
687 case MODE_SERVER:
688 if (!port)
689 panic("No port specified!\n");
690 if (stun)
691 print_stun_probe(stun, 3478, strtoul(port, NULL, 10));
692 ret = main_server(home, dev, port, udp, ipv4, daemon, log);
693 break;
694 default:
695 die();
698 if (dev)
699 xfree(dev);
700 if (stun)
701 xfree(stun);
702 if (port)
703 xfree(port);
704 if (alias)
705 xfree(alias);
706 return ret;