xutils: remove unused declaration
[netsniff-ng.git] / curvetun.c
blobb2cc9b580a8f0ee82716a7c38af81825b854d77e
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.
7 */
9 #define _GNU_SOURCE
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <fcntl.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <getopt.h>
16 #include <errno.h>
17 #include <stdbool.h>
18 #include <limits.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #include <sys/ptrace.h>
23 #include <sys/fsuid.h>
24 #include <netinet/in.h>
25 #include <unistd.h>
26 #include <signal.h>
28 #include "xutils.h"
29 #include "die.h"
30 #include "str.h"
31 #include "xmalloc.h"
32 #include "curvetun.h"
33 #include "curve.h"
34 #include "ct_usermgmt.h"
35 #include "ct_servmgmt.h"
36 #include "xio.h"
37 #include "tprintf.h"
38 #include "crypto_verify_32.h"
39 #include "crypto_box_curve25519xsalsa20poly1305.h"
40 #include "crypto_scalarmult_curve25519.h"
41 #include "crypto_auth_hmacsha512256.h"
43 #define CURVETUN_ENTROPY_SOURCE "/dev/random"
45 extern void print_stun_probe(char *server, uint16_t sport, uint16_t tunport);
47 enum working_mode {
48 MODE_UNKNOW,
49 MODE_KEYGEN,
50 MODE_EXPORT,
51 MODE_DUMPC,
52 MODE_DUMPS,
53 MODE_CLIENT,
54 MODE_SERVER,
57 volatile sig_atomic_t sigint = 0;
59 static const char *short_options = "kxc::svhp:t:d:uCS46DN";
60 static const struct option long_options[] = {
61 {"client", optional_argument, NULL, 'c'},
62 {"dev", required_argument, NULL, 'd'},
63 {"port", required_argument, NULL, 'p'},
64 {"stun", required_argument, NULL, 't'},
65 {"keygen", no_argument, NULL, 'k'},
66 {"export", no_argument, NULL, 'x'},
67 {"dumpc", no_argument, NULL, 'C'},
68 {"dumps", no_argument, NULL, 'S'},
69 {"no-logging", no_argument, NULL, 'N'},
70 {"server", no_argument, NULL, 's'},
71 {"udp", no_argument, NULL, 'u'},
72 {"ipv4", no_argument, NULL, '4'},
73 {"ipv6", no_argument, NULL, '6'},
74 {"nofork", no_argument, NULL, 'D'},
75 {"version", no_argument, NULL, 'v'},
76 {"help", no_argument, NULL, 'h'},
77 {NULL, 0, NULL, 0}
80 static void signal_handler(int number)
82 switch (number) {
83 case SIGINT:
84 case SIGTERM:
85 sigint = 1;
86 break;
87 default:
88 break;
92 static void __noreturn help(void)
94 printf("\ncurvetun %s, lightweight curve25519-based VPN/IP tunnel\n", VERSION_STRING);
95 puts("http://www.netsniff-ng.org\n\n"
96 "Usage: curvetun [options]\n"
97 "Options, general:\n"
98 " -d|--dev <tun> Networking tunnel device, e.g. tun0\n"
99 " -p|--port <num> Server port number (mandatory)\n"
100 " -t|--stun <server> Show public IP/Port mapping via STUN\n"
101 " -c|--client[=alias] Client mode, server alias optional\n"
102 " -k|--keygen Generate public/private keypair\n"
103 " -x|--export Export your public data for remote servers\n"
104 " -C|--dumpc Dump parsed clients\n"
105 " -S|--dumps Dump parsed servers\n"
106 " -D|--nofork Do not daemonize\n"
107 " -s|--server Server mode, options follow below\n"
108 " -N|--no-logging Disable server logging (for better anonymity)\n"
109 " -u|--udp Use UDP as carrier instead of TCP\n"
110 " -4|--ipv4 Tunnel devices are IPv4\n"
111 " -6|--ipv6 Tunnel devices are IPv6\n"
112 " -v|--version Print version and exit\n"
113 " -h|--help Print this help and exit\n\n"
114 "Example:\n"
115 " See curvetun's man page for a configuration example.\n"
116 " curvetun --server -4 -u -N --port 6666 --stun stunserver.org\n"
117 " curvetun --client=ethz\n\n"
118 " curvetun --keygen\n"
119 " curvetun --export\n"
120 "Note:\n"
121 " There is no default port specified, so that you are forced\n"
122 " to select your own! For client/server status messages see syslog!\n"
123 " This software is an experimental prototype intended for researchers.\n\n"
124 "Secret ingredient: 7647-14-5\n\n"
125 "Please report bugs to <bugs@netsniff-ng.org>\n"
126 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
127 "Swiss federal institute of technology (ETH Zurich)\n"
128 "License: GNU GPL version 2.0\n"
129 "This is free software: you are free to change and redistribute it.\n"
130 "There is NO WARRANTY, to the extent permitted by law.\n");
131 die();
134 static void __noreturn version(void)
136 printf("\ncurvetun %s, lightweight curve25519-based VPN/IP tunnel\n", VERSION_LONG);
137 puts("http://www.netsniff-ng.org\n\n"
138 "Please report bugs to <bugs@netsniff-ng.org>\n"
139 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
140 "Swiss federal institute of technology (ETH Zurich)\n"
141 "License: GNU GPL version 2.0\n"
142 "This is free software: you are free to change and redistribute it.\n"
143 "There is NO WARRANTY, to the extent permitted by law.\n");
144 die();
147 static void check_file_or_die(char *home, char *file, int maybeempty)
149 char path[PATH_MAX];
150 struct stat st;
152 memset(path, 0, sizeof(path));
153 slprintf(path, sizeof(path), "%s/%s", home, file);
155 if (stat(path, &st))
156 panic("No such file %s! Type --help for further information\n",
157 path);
159 if (!S_ISREG(st.st_mode))
160 panic("%s is not a regular file!\n", path);
162 if ((st.st_mode & ~S_IFREG) != (S_IRUSR | S_IWUSR))
163 panic("You have set too many permissions on %s (%o)!\n",
164 path, st.st_mode);
166 if (maybeempty == 0 && st.st_size == 0)
167 panic("%s is empty!\n", path);
170 static void check_config_exists_or_die(char *home)
172 if (!home)
173 panic("No home dir specified!\n");
175 check_file_or_die(home, FILE_CLIENTS, 1);
176 check_file_or_die(home, FILE_SERVERS, 1);
177 check_file_or_die(home, FILE_PRIVKEY, 0);
178 check_file_or_die(home, FILE_PUBKEY, 0);
179 check_file_or_die(home, FILE_USERNAM, 0);
182 static char *fetch_home_dir(void)
184 char *home = getenv("HOME");
185 if (!home)
186 panic("No HOME defined!\n");
187 return home;
190 static void write_username(char *home)
192 int fd, ret;
193 char path[PATH_MAX];
194 char user[512];
196 memset(path, 0, sizeof(path));
197 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
199 printf("Username: [%s] ", getenv("USER"));
200 fflush(stdout);
202 memset(user, 0, sizeof(user));
203 if (fgets(user, sizeof(user), stdin) == NULL)
204 panic("Could not read from stdin!\n");
205 user[sizeof(user) - 1] = 0;
206 user[strlen(user) - 1] = 0; /* omit last \n */
207 if (strlen(user) == 0)
208 strlcpy(user, getenv("USER"), sizeof(user));
210 fd = open_or_die_m(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
212 ret = write(fd, user, strlen(user));
213 if (ret != strlen(user))
214 panic("Could not write username!\n");
216 close(fd);
218 printf("Username written to %s!\n", path);
221 static void create_curvedir(char *home)
223 int ret;
224 char path[PATH_MAX];
226 memset(path, 0, sizeof(path));
227 slprintf(path, sizeof(path), "%s/%s", home, ".curvetun/");
229 errno = 0;
231 ret = mkdir(path, S_IRWXU);
232 if (ret < 0 && errno != EEXIST)
233 panic("Cannot create curvetun dir!\n");
235 printf("curvetun directory %s created!\n", path);
236 /* We also create empty files for clients and servers! */
238 memset(path, 0, sizeof(path));
239 slprintf(path, sizeof(path), "%s/%s", home, FILE_CLIENTS);
241 create_or_die(path, S_IRUSR | S_IWUSR);
243 printf("Empty client file written to %s!\n", path);
245 memset(path, 0, sizeof(path));
246 slprintf(path, sizeof(path), "%s/%s", home, FILE_SERVERS);
248 create_or_die(path, S_IRUSR | S_IWUSR);
250 printf("Empty server file written to %s!\n", path);
253 static void create_keypair(char *home)
255 int fd, err = 0;
256 ssize_t ret;
257 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES] = { 0 };
258 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES] = { 0 };
259 char path[PATH_MAX];
260 const char * errstr = NULL;
262 printf("Reading from %s (this may take a while) ...\n", CURVETUN_ENTROPY_SOURCE);
264 fd = open_or_die(CURVETUN_ENTROPY_SOURCE, O_RDONLY);
266 ret = read_exact(fd, secretkey, sizeof(secretkey), 0);
267 if (ret != sizeof(secretkey)) {
268 err = EIO;
269 errstr = "Cannot read from "CURVETUN_ENTROPY_SOURCE"!\n";
270 goto out;
273 close(fd);
275 crypto_scalarmult_curve25519_base(publickey, secretkey);
277 memset(path, 0, sizeof(path));
278 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
280 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
281 if (fd < 0) {
282 err = EIO;
283 errstr = "Cannot open pubkey file!\n";
284 goto out_noclose;
287 ret = write(fd, publickey, sizeof(publickey));
288 if (ret != sizeof(publickey)) {
289 err = EIO;
290 errstr = "Cannot write public key!\n";
291 goto out;
294 close(fd);
296 printf("Public key written to %s!\n", path);
298 memset(path, 0, sizeof(path));
299 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
301 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
302 if (fd < 0) {
303 err = EIO;
304 errstr = "Cannot open privkey file!\n";
305 goto out_noclose;
308 ret = write(fd, secretkey, sizeof(secretkey));
309 if (ret != sizeof(secretkey)) {
310 err = EIO;
311 errstr = "Cannot write private key!\n";
312 goto out;
314 out:
315 close(fd);
316 out_noclose:
317 xmemset(publickey, 0, sizeof(publickey));
318 xmemset(secretkey, 0, sizeof(secretkey));
320 if (err)
321 panic("%s: %s", errstr, strerror(errno));
322 else
323 printf("Private key written to %s!\n", path);
326 static void check_config_keypair_or_die(char *home)
328 int fd, err;
329 ssize_t ret;
330 const char * errstr = NULL;
331 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
332 unsigned char publicres[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
333 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES];
334 char path[PATH_MAX];
336 memset(path, 0, sizeof(path));
337 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
339 fd = open(path, O_RDONLY);
340 if (fd < 0) {
341 err = EIO;
342 errstr = "Cannot open privkey file!\n";
343 goto out;
346 ret = read(fd, secretkey, sizeof(secretkey));
347 if (ret != sizeof(secretkey)) {
348 err = EIO;
349 errstr = "Cannot read private key!\n";
350 goto out;
353 close(fd);
355 memset(path, 0, sizeof(path));
356 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
358 fd = open(path, O_RDONLY);
359 if (fd < 0) {
360 err = EIO;
361 errstr = "Cannot open pubkey file!\n";
362 goto out;
365 ret = read(fd, publickey, sizeof(publickey));
366 if (ret != sizeof(publickey)) {
367 err = EIO;
368 errstr = "Cannot read public key!\n";
369 goto out;
372 crypto_scalarmult_curve25519_base(publicres, secretkey);
374 err = crypto_verify_32(publicres, publickey);
375 if (err) {
376 err = EINVAL;
377 errstr = "WARNING: your keypair is corrupted!!! You need to "
378 "generate new keys!!!\n";
379 goto out;
381 out:
382 close(fd);
384 xmemset(publickey, 0, sizeof(publickey));
385 xmemset(publicres, 0, sizeof(publicres));
386 xmemset(secretkey, 0, sizeof(secretkey));
388 if (err)
389 panic("%s: %s\n", errstr, strerror(errno));
392 static int main_keygen(char *home)
394 create_curvedir(home);
395 write_username(home);
396 create_keypair(home);
397 check_config_keypair_or_die(home);
399 return 0;
402 static int main_export(char *home)
404 int fd, i;
405 ssize_t ret;
406 char path[PATH_MAX], tmp[64];
408 check_config_exists_or_die(home);
409 check_config_keypair_or_die(home);
411 printf("Your exported public information:\n\n");
413 memset(path, 0, sizeof(path));
414 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
416 fd = open_or_die(path, O_RDONLY);
418 while ((ret = read(fd, tmp, sizeof(tmp))) > 0) {
419 ret = write(STDOUT_FILENO, tmp, ret);
422 close(fd);
424 printf(";");
426 memset(path, 0, sizeof(path));
427 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
429 fd = open_or_die(path, O_RDONLY);
431 ret = read(fd, tmp, sizeof(tmp));
432 if (ret != crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)
433 panic("Cannot read public key!\n");
435 for (i = 0; i < ret; ++i)
436 if (i == ret - 1)
437 printf("%02x\n\n", (unsigned char) tmp[i]);
438 else
439 printf("%02x:", (unsigned char) tmp[i]);
441 close(fd);
442 fflush(stdout);
444 return 0;
447 static int main_dumpc(char *home)
449 check_config_exists_or_die(home);
450 check_config_keypair_or_die(home);
452 printf("Your clients:\n\n");
454 parse_userfile_and_generate_user_store_or_die(home);
456 dump_user_store();
458 destroy_user_store();
460 printf("\n");
461 die();
462 return 0;
465 static int main_dumps(char *home)
467 check_config_exists_or_die(home);
468 check_config_keypair_or_die(home);
470 printf("Your servers:\n\n");
472 parse_userfile_and_generate_serv_store_or_die(home);
474 dump_serv_store();
476 destroy_serv_store();
478 printf("\n");
479 die();
480 return 0;
483 static void daemonize(const char *lockfile)
485 char pidstr[8];
486 mode_t lperm = S_IRWXU | S_IRGRP | S_IXGRP; /* 0750 */
487 int lfp;
489 if (getppid() == 1)
490 return;
492 if (daemon(0, 1))
493 panic("Cannot daemonize: %s", strerror(errno));
495 to_std_log(&stdout);
496 to_std_log(&stderr);
498 umask(lperm);
499 if (lockfile) {
500 lfp = open(lockfile, O_RDWR | O_CREAT | O_EXCL,
501 S_IRUSR | S_IWUSR | S_IRGRP);
502 if (lfp < 0)
503 syslog_panic("Cannot create lockfile at %s! "
504 "curvetun server already running?\n",
505 lockfile);
507 slprintf(pidstr, sizeof(pidstr), "%u", getpid());
508 if (write(lfp, pidstr, strlen(pidstr)) <= 0)
509 syslog_panic("Could not write pid to pidfile %s",
510 lockfile);
512 close(lfp);
516 static int main_client(char *home, char *dev, char *alias, int daemon)
518 int ret, udp;
519 char *host, *port;
521 check_config_exists_or_die(home);
522 check_config_keypair_or_die(home);
524 parse_userfile_and_generate_serv_store_or_die(home);
526 get_serv_store_entry_by_alias(alias, alias ? strlen(alias) + 1 : 0,
527 &host, &port, &udp);
528 if (!host || !port || udp < 0)
529 panic("Did not find alias/entry in configuration!\n");
531 printf("Using [%s] -> %s:%s via %s as endpoint!\n",
532 alias ? : "default", host, port, udp ? "udp" : "tcp");
533 if (daemon)
534 daemonize(NULL);
536 ret = client_main(home, dev, host, port, udp);
538 destroy_serv_store();
540 return ret;
543 static int main_server(char *home, char *dev, char *port, int udp,
544 int ipv4, int daemon, int log)
546 int ret;
548 check_config_exists_or_die(home);
549 check_config_keypair_or_die(home);
551 if (daemon)
552 daemonize(LOCKFILE);
554 ret = server_main(home, dev, port, udp, ipv4, log);
556 unlink(LOCKFILE);
558 return ret;
561 int main(int argc, char **argv)
563 int ret = 0, c, opt_index, udp = 0, ipv4 = -1, daemon = 1, log = 1;
564 char *port = NULL, *stun = NULL, *dev = NULL, *home = NULL, *alias = NULL;
565 enum working_mode wmode = MODE_UNKNOW;
567 setfsuid(getuid());
568 setfsgid(getgid());
570 home = fetch_home_dir();
572 while ((c = getopt_long(argc, argv, short_options, long_options,
573 &opt_index)) != EOF) {
574 switch (c) {
575 case 'h':
576 help();
577 break;
578 case 'v':
579 version();
580 break;
581 case 'D':
582 daemon = 0;
583 break;
584 case 'N':
585 log = 0;
586 break;
587 case 'C':
588 wmode = MODE_DUMPC;
589 break;
590 case 'S':
591 wmode = MODE_DUMPS;
592 break;
593 case 'c':
594 wmode = MODE_CLIENT;
595 if (optarg) {
596 if (*optarg == '=')
597 optarg++;
598 alias = xstrdup(optarg);
600 break;
601 case 'd':
602 dev = xstrdup(optarg);
603 break;
604 case 'k':
605 wmode = MODE_KEYGEN;
606 break;
607 case '4':
608 ipv4 = 1;
609 break;
610 case '6':
611 ipv4 = 0;
612 break;
613 case 'x':
614 wmode = MODE_EXPORT;
615 break;
616 case 's':
617 wmode = MODE_SERVER;
618 break;
619 case 'u':
620 udp = 1;
621 break;
622 case 't':
623 stun = xstrdup(optarg);
624 break;
625 case 'p':
626 port = xstrdup(optarg);
627 break;
628 case '?':
629 switch (optopt) {
630 case 't':
631 case 'd':
632 case 'u':
633 case 'p':
634 panic("Option -%c requires an argument!\n",
635 optopt);
636 default:
637 if (isprint(optopt))
638 printf("Unknown option character `0x%X\'!\n", optopt);
639 die();
641 default:
642 break;
646 if (argc < 2)
647 help();
649 register_signal(SIGINT, signal_handler);
650 register_signal(SIGHUP, signal_handler);
651 register_signal(SIGTERM, signal_handler);
652 register_signal(SIGPIPE, signal_handler);
654 curve25519_selftest();
656 switch (wmode) {
657 case MODE_KEYGEN:
658 ret = main_keygen(home);
659 break;
660 case MODE_EXPORT:
661 ret = main_export(home);
662 break;
663 case MODE_DUMPC:
664 ret = main_dumpc(home);
665 break;
666 case MODE_DUMPS:
667 ret = main_dumps(home);
668 break;
669 case MODE_CLIENT:
670 ret = main_client(home, dev, alias, daemon);
671 break;
672 case MODE_SERVER:
673 if (!port)
674 panic("No port specified!\n");
675 if (stun)
676 print_stun_probe(stun, 3478, strtoul(port, NULL, 10));
677 ret = main_server(home, dev, port, udp, ipv4, daemon, log);
678 break;
679 default:
680 die();
683 free(dev);
684 free(stun);
685 free(port);
686 free(alias);
688 return ret;