xutils: break out promisc mode functions
[netsniff-ng.git] / curvetun.c
blob0e7bb83b9a48960891199ecbda57114dabc95e70
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 "cookie.h"
32 #include "ioexact.h"
33 #include "xmalloc.h"
34 #include "curvetun.h"
35 #include "curve.h"
36 #include "ct_usermgmt.h"
37 #include "ct_servmgmt.h"
38 #include "ioops.h"
39 #include "tprintf.h"
40 #include "crypto_verify_32.h"
41 #include "crypto_box_curve25519xsalsa20poly1305.h"
42 #include "crypto_scalarmult_curve25519.h"
43 #include "crypto_auth_hmacsha512256.h"
45 #define CURVETUN_ENTROPY_SOURCE "/dev/random"
47 extern void print_stun_probe(char *server, uint16_t sport, uint16_t tunport);
49 enum working_mode {
50 MODE_UNKNOW,
51 MODE_KEYGEN,
52 MODE_EXPORT,
53 MODE_DUMPC,
54 MODE_DUMPS,
55 MODE_CLIENT,
56 MODE_SERVER,
59 volatile sig_atomic_t sigint = 0;
61 static const char *short_options = "kxc::svhp:t:d:uCS46DN";
62 static const struct option long_options[] = {
63 {"client", optional_argument, NULL, 'c'},
64 {"dev", required_argument, NULL, 'd'},
65 {"port", required_argument, NULL, 'p'},
66 {"stun", required_argument, NULL, 't'},
67 {"keygen", no_argument, NULL, 'k'},
68 {"export", no_argument, NULL, 'x'},
69 {"dumpc", no_argument, NULL, 'C'},
70 {"dumps", no_argument, NULL, 'S'},
71 {"no-logging", no_argument, NULL, 'N'},
72 {"server", no_argument, NULL, 's'},
73 {"udp", no_argument, NULL, 'u'},
74 {"ipv4", no_argument, NULL, '4'},
75 {"ipv6", no_argument, NULL, '6'},
76 {"nofork", no_argument, NULL, 'D'},
77 {"version", no_argument, NULL, 'v'},
78 {"help", no_argument, NULL, 'h'},
79 {NULL, 0, NULL, 0}
82 static void signal_handler(int number)
84 switch (number) {
85 case SIGINT:
86 case SIGTERM:
87 sigint = 1;
88 break;
89 default:
90 break;
94 static void __noreturn help(void)
96 printf("\ncurvetun %s, lightweight curve25519-based VPN/IP tunnel\n", VERSION_STRING);
97 puts("http://www.netsniff-ng.org\n\n"
98 "Usage: curvetun [options]\n"
99 "Options, general:\n"
100 " -d|--dev <tun> Networking tunnel device, e.g. tun0\n"
101 " -p|--port <num> Server port number (mandatory)\n"
102 " -t|--stun <server> Show public IP/Port mapping via STUN\n"
103 " -c|--client[=alias] Client mode, server alias optional\n"
104 " -k|--keygen Generate public/private keypair\n"
105 " -x|--export Export your public data for remote servers\n"
106 " -C|--dumpc Dump parsed clients\n"
107 " -S|--dumps Dump parsed servers\n"
108 " -D|--nofork Do not daemonize\n"
109 " -s|--server Server mode, options follow below\n"
110 " -N|--no-logging Disable server logging (for better anonymity)\n"
111 " -u|--udp Use UDP as carrier instead of TCP\n"
112 " -4|--ipv4 Tunnel devices are IPv4\n"
113 " -6|--ipv6 Tunnel devices are IPv6\n"
114 " -v|--version Print version and exit\n"
115 " -h|--help Print this help and exit\n\n"
116 "Example:\n"
117 " See curvetun's man page for a configuration example.\n"
118 " curvetun --server -4 -u -N --port 6666 --stun stunserver.org\n"
119 " curvetun --client=ethz\n\n"
120 " curvetun --keygen\n"
121 " curvetun --export\n"
122 "Note:\n"
123 " There is no default port specified, so that you are forced\n"
124 " to select your own! For client/server status messages see syslog!\n"
125 " This software is an experimental prototype intended for researchers.\n\n"
126 "Secret ingredient: 7647-14-5\n\n"
127 "Please report bugs to <bugs@netsniff-ng.org>\n"
128 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
129 "Swiss federal institute of technology (ETH Zurich)\n"
130 "License: GNU GPL version 2.0\n"
131 "This is free software: you are free to change and redistribute it.\n"
132 "There is NO WARRANTY, to the extent permitted by law.\n");
133 die();
136 static void __noreturn version(void)
138 printf("\ncurvetun %s, lightweight curve25519-based VPN/IP tunnel\n", VERSION_LONG);
139 puts("http://www.netsniff-ng.org\n\n"
140 "Please report bugs to <bugs@netsniff-ng.org>\n"
141 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
142 "Swiss federal institute of technology (ETH Zurich)\n"
143 "License: GNU GPL version 2.0\n"
144 "This is free software: you are free to change and redistribute it.\n"
145 "There is NO WARRANTY, to the extent permitted by law.\n");
146 die();
149 static void check_file_or_die(char *home, char *file, int maybeempty)
151 char path[PATH_MAX];
152 struct stat st;
154 memset(path, 0, sizeof(path));
155 slprintf(path, sizeof(path), "%s/%s", home, file);
157 if (stat(path, &st))
158 panic("No such file %s! Type --help for further information\n",
159 path);
161 if (!S_ISREG(st.st_mode))
162 panic("%s is not a regular file!\n", path);
164 if ((st.st_mode & ~S_IFREG) != (S_IRUSR | S_IWUSR))
165 panic("You have set too many permissions on %s (%o)!\n",
166 path, st.st_mode);
168 if (maybeempty == 0 && st.st_size == 0)
169 panic("%s is empty!\n", path);
172 static void check_config_exists_or_die(char *home)
174 if (!home)
175 panic("No home dir specified!\n");
177 check_file_or_die(home, FILE_CLIENTS, 1);
178 check_file_or_die(home, FILE_SERVERS, 1);
179 check_file_or_die(home, FILE_PRIVKEY, 0);
180 check_file_or_die(home, FILE_PUBKEY, 0);
181 check_file_or_die(home, FILE_USERNAM, 0);
184 static char *fetch_home_dir(void)
186 char *home = getenv("HOME");
187 if (!home)
188 panic("No HOME defined!\n");
189 return home;
192 static void write_username(char *home)
194 int fd, ret;
195 char path[PATH_MAX];
196 char user[512];
198 memset(path, 0, sizeof(path));
199 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
201 printf("Username: [%s] ", getenv("USER"));
202 fflush(stdout);
204 memset(user, 0, sizeof(user));
205 if (fgets(user, sizeof(user), stdin) == NULL)
206 panic("Could not read from stdin!\n");
207 user[sizeof(user) - 1] = 0;
208 user[strlen(user) - 1] = 0; /* omit last \n */
209 if (strlen(user) == 0)
210 strlcpy(user, getenv("USER"), sizeof(user));
212 fd = open_or_die_m(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
214 ret = write(fd, user, strlen(user));
215 if (ret != strlen(user))
216 panic("Could not write username!\n");
218 close(fd);
220 printf("Username written to %s!\n", path);
223 static void create_curvedir(char *home)
225 int ret;
226 char path[PATH_MAX];
228 memset(path, 0, sizeof(path));
229 slprintf(path, sizeof(path), "%s/%s", home, ".curvetun/");
231 errno = 0;
233 ret = mkdir(path, S_IRWXU);
234 if (ret < 0 && errno != EEXIST)
235 panic("Cannot create curvetun dir!\n");
237 printf("curvetun directory %s created!\n", path);
238 /* We also create empty files for clients and servers! */
240 memset(path, 0, sizeof(path));
241 slprintf(path, sizeof(path), "%s/%s", home, FILE_CLIENTS);
243 create_or_die(path, S_IRUSR | S_IWUSR);
245 printf("Empty client file written to %s!\n", path);
247 memset(path, 0, sizeof(path));
248 slprintf(path, sizeof(path), "%s/%s", home, FILE_SERVERS);
250 create_or_die(path, S_IRUSR | S_IWUSR);
252 printf("Empty server file written to %s!\n", path);
255 static void create_keypair(char *home)
257 int fd, err = 0;
258 ssize_t ret;
259 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES] = { 0 };
260 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES] = { 0 };
261 char path[PATH_MAX];
262 const char * errstr = NULL;
264 printf("Reading from %s (this may take a while) ...\n", CURVETUN_ENTROPY_SOURCE);
266 fd = open_or_die(CURVETUN_ENTROPY_SOURCE, O_RDONLY);
268 ret = read_exact(fd, secretkey, sizeof(secretkey), 0);
269 if (ret != sizeof(secretkey)) {
270 err = EIO;
271 errstr = "Cannot read from "CURVETUN_ENTROPY_SOURCE"!\n";
272 goto out;
275 close(fd);
277 crypto_scalarmult_curve25519_base(publickey, secretkey);
279 memset(path, 0, sizeof(path));
280 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
282 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
283 if (fd < 0) {
284 err = EIO;
285 errstr = "Cannot open pubkey file!\n";
286 goto out_noclose;
289 ret = write(fd, publickey, sizeof(publickey));
290 if (ret != sizeof(publickey)) {
291 err = EIO;
292 errstr = "Cannot write public key!\n";
293 goto out;
296 close(fd);
298 printf("Public key written to %s!\n", path);
300 memset(path, 0, sizeof(path));
301 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
303 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
304 if (fd < 0) {
305 err = EIO;
306 errstr = "Cannot open privkey file!\n";
307 goto out_noclose;
310 ret = write(fd, secretkey, sizeof(secretkey));
311 if (ret != sizeof(secretkey)) {
312 err = EIO;
313 errstr = "Cannot write private key!\n";
314 goto out;
316 out:
317 close(fd);
318 out_noclose:
319 xmemset(publickey, 0, sizeof(publickey));
320 xmemset(secretkey, 0, sizeof(secretkey));
322 if (err)
323 panic("%s: %s", errstr, strerror(errno));
324 else
325 printf("Private key written to %s!\n", path);
328 static void check_config_keypair_or_die(char *home)
330 int fd, err;
331 ssize_t ret;
332 const char * errstr = NULL;
333 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
334 unsigned char publicres[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
335 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES];
336 char path[PATH_MAX];
338 memset(path, 0, sizeof(path));
339 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
341 fd = open(path, O_RDONLY);
342 if (fd < 0) {
343 err = EIO;
344 errstr = "Cannot open privkey file!\n";
345 goto out;
348 ret = read(fd, secretkey, sizeof(secretkey));
349 if (ret != sizeof(secretkey)) {
350 err = EIO;
351 errstr = "Cannot read private key!\n";
352 goto out;
355 close(fd);
357 memset(path, 0, sizeof(path));
358 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
360 fd = open(path, O_RDONLY);
361 if (fd < 0) {
362 err = EIO;
363 errstr = "Cannot open pubkey file!\n";
364 goto out;
367 ret = read(fd, publickey, sizeof(publickey));
368 if (ret != sizeof(publickey)) {
369 err = EIO;
370 errstr = "Cannot read public key!\n";
371 goto out;
374 crypto_scalarmult_curve25519_base(publicres, secretkey);
376 err = crypto_verify_32(publicres, publickey);
377 if (err) {
378 err = EINVAL;
379 errstr = "WARNING: your keypair is corrupted!!! You need to "
380 "generate new keys!!!\n";
381 goto out;
383 out:
384 close(fd);
386 xmemset(publickey, 0, sizeof(publickey));
387 xmemset(publicres, 0, sizeof(publicres));
388 xmemset(secretkey, 0, sizeof(secretkey));
390 if (err)
391 panic("%s: %s\n", errstr, strerror(errno));
394 static int main_keygen(char *home)
396 create_curvedir(home);
397 write_username(home);
398 create_keypair(home);
399 check_config_keypair_or_die(home);
401 return 0;
404 static int main_export(char *home)
406 int fd, i;
407 ssize_t ret;
408 char path[PATH_MAX], tmp[64];
410 check_config_exists_or_die(home);
411 check_config_keypair_or_die(home);
413 printf("Your exported public information:\n\n");
415 memset(path, 0, sizeof(path));
416 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
418 fd = open_or_die(path, O_RDONLY);
420 while ((ret = read(fd, tmp, sizeof(tmp))) > 0) {
421 ret = write(STDOUT_FILENO, tmp, ret);
424 close(fd);
426 printf(";");
428 memset(path, 0, sizeof(path));
429 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
431 fd = open_or_die(path, O_RDONLY);
433 ret = read(fd, tmp, sizeof(tmp));
434 if (ret != crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)
435 panic("Cannot read public key!\n");
437 for (i = 0; i < ret; ++i)
438 if (i == ret - 1)
439 printf("%02x\n\n", (unsigned char) tmp[i]);
440 else
441 printf("%02x:", (unsigned char) tmp[i]);
443 close(fd);
444 fflush(stdout);
446 return 0;
449 static int main_dumpc(char *home)
451 check_config_exists_or_die(home);
452 check_config_keypair_or_die(home);
454 printf("Your clients:\n\n");
456 parse_userfile_and_generate_user_store_or_die(home);
458 dump_user_store();
460 destroy_user_store();
462 printf("\n");
463 die();
464 return 0;
467 static int main_dumps(char *home)
469 check_config_exists_or_die(home);
470 check_config_keypair_or_die(home);
472 printf("Your servers:\n\n");
474 parse_userfile_and_generate_serv_store_or_die(home);
476 dump_serv_store();
478 destroy_serv_store();
480 printf("\n");
481 die();
482 return 0;
485 static void daemonize(const char *lockfile)
487 char pidstr[8];
488 mode_t lperm = S_IRWXU | S_IRGRP | S_IXGRP; /* 0750 */
489 int lfp;
491 if (getppid() == 1)
492 return;
494 if (daemon(0, 1))
495 panic("Cannot daemonize: %s", strerror(errno));
497 to_std_log(&stdout);
498 to_std_log(&stderr);
500 umask(lperm);
501 if (lockfile) {
502 lfp = open(lockfile, O_RDWR | O_CREAT | O_EXCL,
503 S_IRUSR | S_IWUSR | S_IRGRP);
504 if (lfp < 0)
505 syslog_panic("Cannot create lockfile at %s! "
506 "curvetun server already running?\n",
507 lockfile);
509 slprintf(pidstr, sizeof(pidstr), "%u", getpid());
510 if (write(lfp, pidstr, strlen(pidstr)) <= 0)
511 syslog_panic("Could not write pid to pidfile %s",
512 lockfile);
514 close(lfp);
518 static int main_client(char *home, char *dev, char *alias, int daemon)
520 int ret, udp;
521 char *host, *port;
523 check_config_exists_or_die(home);
524 check_config_keypair_or_die(home);
526 parse_userfile_and_generate_serv_store_or_die(home);
528 get_serv_store_entry_by_alias(alias, alias ? strlen(alias) + 1 : 0,
529 &host, &port, &udp);
530 if (!host || !port || udp < 0)
531 panic("Did not find alias/entry in configuration!\n");
533 printf("Using [%s] -> %s:%s via %s as endpoint!\n",
534 alias ? : "default", host, port, udp ? "udp" : "tcp");
535 if (daemon)
536 daemonize(NULL);
538 ret = client_main(home, dev, host, port, udp);
540 destroy_serv_store();
542 return ret;
545 static int main_server(char *home, char *dev, char *port, int udp,
546 int ipv4, int daemon, int log)
548 int ret;
550 check_config_exists_or_die(home);
551 check_config_keypair_or_die(home);
553 if (daemon)
554 daemonize(LOCKFILE);
556 ret = server_main(home, dev, port, udp, ipv4, log);
558 unlink(LOCKFILE);
560 return ret;
563 int main(int argc, char **argv)
565 int ret = 0, c, opt_index, udp = 0, ipv4 = -1, daemon = 1, log = 1;
566 char *port = NULL, *stun = NULL, *dev = NULL, *home = NULL, *alias = NULL;
567 enum working_mode wmode = MODE_UNKNOW;
569 setfsuid(getuid());
570 setfsgid(getgid());
572 home = fetch_home_dir();
574 while ((c = getopt_long(argc, argv, short_options, long_options,
575 &opt_index)) != EOF) {
576 switch (c) {
577 case 'h':
578 help();
579 break;
580 case 'v':
581 version();
582 break;
583 case 'D':
584 daemon = 0;
585 break;
586 case 'N':
587 log = 0;
588 break;
589 case 'C':
590 wmode = MODE_DUMPC;
591 break;
592 case 'S':
593 wmode = MODE_DUMPS;
594 break;
595 case 'c':
596 wmode = MODE_CLIENT;
597 if (optarg) {
598 if (*optarg == '=')
599 optarg++;
600 alias = xstrdup(optarg);
602 break;
603 case 'd':
604 dev = xstrdup(optarg);
605 break;
606 case 'k':
607 wmode = MODE_KEYGEN;
608 break;
609 case '4':
610 ipv4 = 1;
611 break;
612 case '6':
613 ipv4 = 0;
614 break;
615 case 'x':
616 wmode = MODE_EXPORT;
617 break;
618 case 's':
619 wmode = MODE_SERVER;
620 break;
621 case 'u':
622 udp = 1;
623 break;
624 case 't':
625 stun = xstrdup(optarg);
626 break;
627 case 'p':
628 port = xstrdup(optarg);
629 break;
630 case '?':
631 switch (optopt) {
632 case 't':
633 case 'd':
634 case 'u':
635 case 'p':
636 panic("Option -%c requires an argument!\n",
637 optopt);
638 default:
639 if (isprint(optopt))
640 printf("Unknown option character `0x%X\'!\n", optopt);
641 die();
643 default:
644 break;
648 if (argc < 2)
649 help();
651 register_signal(SIGINT, signal_handler);
652 register_signal(SIGHUP, signal_handler);
653 register_signal(SIGTERM, signal_handler);
654 register_signal(SIGPIPE, signal_handler);
656 curve25519_selftest();
658 switch (wmode) {
659 case MODE_KEYGEN:
660 ret = main_keygen(home);
661 break;
662 case MODE_EXPORT:
663 ret = main_export(home);
664 break;
665 case MODE_DUMPC:
666 ret = main_dumpc(home);
667 break;
668 case MODE_DUMPS:
669 ret = main_dumps(home);
670 break;
671 case MODE_CLIENT:
672 ret = main_client(home, dev, alias, daemon);
673 break;
674 case MODE_SERVER:
675 if (!port)
676 panic("No port specified!\n");
677 if (stun)
678 print_stun_probe(stun, 3478, strtoul(port, NULL, 10));
679 ret = main_server(home, dev, port, udp, ipv4, daemon, log);
680 break;
681 default:
682 die();
685 free(dev);
686 free(stun);
687 free(port);
688 free(alias);
690 return ret;