dissector: icmpv6: Fix compiler warnings
[netsniff-ng.git] / curvetun.c
blobf44cb8069e3c21017f3c356686485fafa0495418
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 "die.h"
29 #include "str.h"
30 #include "sig.h"
31 #include "stun.h"
32 #include "cookie.h"
33 #include "ioexact.h"
34 #include "xmalloc.h"
35 #include "curvetun.h"
36 #include "curve.h"
37 #include "config.h"
38 #include "curvetun_mgmt.h"
39 #include "ioops.h"
40 #include "tprintf.h"
41 #include "crypto.h"
43 enum working_mode {
44 MODE_UNKNOW,
45 MODE_KEYGEN,
46 MODE_EXPORT,
47 MODE_DUMPC,
48 MODE_DUMPS,
49 MODE_CLIENT,
50 MODE_SERVER,
53 volatile sig_atomic_t sigint = 0;
55 static const char *short_options = "kxc::svhp:t:d:uCS46DN";
56 static const struct option long_options[] = {
57 {"client", optional_argument, NULL, 'c'},
58 {"dev", required_argument, NULL, 'd'},
59 {"port", required_argument, NULL, 'p'},
60 {"stun", required_argument, NULL, 't'},
61 {"keygen", no_argument, NULL, 'k'},
62 {"export", no_argument, NULL, 'x'},
63 {"dumpc", no_argument, NULL, 'C'},
64 {"dumps", no_argument, NULL, 'S'},
65 {"no-logging", no_argument, NULL, 'N'},
66 {"server", no_argument, NULL, 's'},
67 {"udp", no_argument, NULL, 'u'},
68 {"ipv4", no_argument, NULL, '4'},
69 {"ipv6", no_argument, NULL, '6'},
70 {"nofork", no_argument, NULL, 'D'},
71 {"version", no_argument, NULL, 'v'},
72 {"help", no_argument, NULL, 'h'},
73 {NULL, 0, NULL, 0}
76 static void signal_handler(int number)
78 switch (number) {
79 case SIGINT:
80 case SIGTERM:
81 sigint = 1;
82 break;
83 default:
84 break;
88 static void __noreturn help(void)
90 printf("\ncurvetun %s, lightweight curve25519-based IP tunnel\n", VERSION_STRING);
91 puts("http://www.netsniff-ng.org\n\n"
92 "Usage: curvetun [options]\n"
93 "Options, general:\n"
94 " -d|--dev <tun> Networking tunnel device, e.g. tun0\n"
95 " -p|--port <num> Server port number (mandatory)\n"
96 " -t|--stun <server> Show public IP/Port mapping via STUN\n"
97 " -c|--client[=alias] Client mode, server alias optional\n"
98 " -k|--keygen Generate public/private keypair\n"
99 " -x|--export Export your public data for remote servers\n"
100 " -C|--dumpc Dump parsed clients\n"
101 " -S|--dumps Dump parsed servers\n"
102 " -D|--nofork Do not daemonize\n"
103 " -s|--server Server mode, options follow below\n"
104 " -N|--no-logging Disable server logging (for better anonymity)\n"
105 " -u|--udp Use UDP as carrier instead of TCP\n"
106 " -4|--ipv4 Tunnel devices are IPv4\n"
107 " -6|--ipv6 Tunnel devices are IPv6\n"
108 " -v|--version Print version and exit\n"
109 " -h|--help Print this help and exit\n\n"
110 "Example:\n"
111 " See curvetun's man page for a configuration example.\n"
112 " curvetun --server -4 -u -N --port 6666 --stun stunserver.org\n"
113 " curvetun --client=ethz\n\n"
114 " curvetun --keygen\n"
115 " curvetun --export\n"
116 "Note:\n"
117 " There is no default port specified, so that you are forced\n"
118 " to select your own! For client/server status messages see syslog!\n"
119 " This software is an experimental prototype intended for researchers.\n\n"
120 "Secret ingredient: 7647-14-5\n\n"
121 "Please report bugs to <bugs@netsniff-ng.org>\n"
122 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
123 "Swiss federal institute of technology (ETH Zurich)\n"
124 "License: GNU GPL version 2.0\n"
125 "This is free software: you are free to change and redistribute it.\n"
126 "There is NO WARRANTY, to the extent permitted by law.\n");
127 die();
130 static void __noreturn version(void)
132 printf("\ncurvetun %s, Git id: %s\n", VERSION_LONG, GITVERSION);
133 puts("lightweight curve25519-based IP tunnel\n"
134 "Note: Einstein-Rosen bridge not yet supported\n"
135 "http://www.netsniff-ng.org\n\n"
136 "Please report bugs to <bugs@netsniff-ng.org>\n"
137 "Copyright (C) 2011-2013 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n"
138 "Swiss federal institute of technology (ETH Zurich)\n"
139 "License: GNU GPL version 2.0\n"
140 "This is free software: you are free to change and redistribute it.\n"
141 "There is NO WARRANTY, to the extent permitted by law.\n");
142 die();
145 static void check_file_or_die(char *home, char *file, int maybeempty)
147 char path[PATH_MAX];
148 struct stat st;
150 memset(path, 0, sizeof(path));
151 slprintf(path, sizeof(path), "%s/%s", home, file);
153 if (stat(path, &st))
154 panic("No such file %s! Type --help for further information\n",
155 path);
157 if (!S_ISREG(st.st_mode))
158 panic("%s is not a regular file!\n", path);
160 if ((st.st_mode & ~S_IFREG) != (S_IRUSR | S_IWUSR))
161 panic("You have set too many permissions on %s (%o)!\n",
162 path, st.st_mode);
164 if (maybeempty == 0 && st.st_size == 0)
165 panic("%s is empty!\n", path);
168 static void check_config_exists_or_die(char *home)
170 if (!home)
171 panic("No home dir specified!\n");
173 check_file_or_die(home, FILE_CLIENTS, 1);
174 check_file_or_die(home, FILE_SERVERS, 1);
175 check_file_or_die(home, FILE_PRIVKEY, 0);
176 check_file_or_die(home, FILE_PUBKEY, 0);
177 check_file_or_die(home, FILE_USERNAM, 0);
180 static char *fetch_home_dir(void)
182 char *home = getenv("HOME");
183 if (!home)
184 panic("No HOME defined!\n");
185 return home;
188 static void write_username(char *home)
190 int fd, ret;
191 char path[PATH_MAX];
192 char user[512];
194 memset(path, 0, sizeof(path));
195 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
197 printf("Username: [%s] ", getenv("USER"));
198 fflush(stdout);
200 memset(user, 0, sizeof(user));
201 if (fgets(user, sizeof(user), stdin) == NULL)
202 panic("Could not read from stdin!\n");
203 user[sizeof(user) - 1] = 0;
204 user[strlen(user) - 1] = 0; /* omit last \n */
205 if (strlen(user) == 0)
206 strlcpy(user, getenv("USER"), sizeof(user));
208 fd = open_or_die_m(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
210 ret = write(fd, user, strlen(user));
211 if (ret != strlen(user))
212 panic("Could not write username!\n");
214 close(fd);
216 printf("Username written to %s!\n", path);
219 static void create_curvedir(char *home)
221 int ret;
222 char path[PATH_MAX];
224 memset(path, 0, sizeof(path));
225 slprintf(path, sizeof(path), "%s/%s", home, ".curvetun/");
227 errno = 0;
229 ret = mkdir(path, S_IRWXU);
230 if (ret < 0 && errno != EEXIST)
231 panic("Cannot create curvetun dir!\n");
233 printf("curvetun directory %s created!\n", path);
234 /* We also create empty files for clients and servers! */
236 memset(path, 0, sizeof(path));
237 slprintf(path, sizeof(path), "%s/%s", home, FILE_CLIENTS);
239 create_or_die(path, S_IRUSR | S_IWUSR);
241 printf("Empty client file written to %s!\n", path);
243 memset(path, 0, sizeof(path));
244 slprintf(path, sizeof(path), "%s/%s", home, FILE_SERVERS);
246 create_or_die(path, S_IRUSR | S_IWUSR);
248 printf("Empty server file written to %s!\n", path);
251 static void create_keypair(char *home)
253 int fd, err = 0;
254 ssize_t ret;
255 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES] = { 0 };
256 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES] = { 0 };
257 char path[PATH_MAX];
258 const char * errstr = NULL;
260 printf("Reading from %s (this may take a while) ...\n", HIG_ENTROPY_SOURCE);
262 gen_key_bytes(secretkey, sizeof(secretkey));
263 crypto_scalarmult_curve25519_base(publickey, secretkey);
265 memset(path, 0, sizeof(path));
266 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
268 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
269 if (fd < 0) {
270 err = EIO;
271 errstr = "Cannot open pubkey file!\n";
272 goto out_noclose;
275 ret = write(fd, publickey, sizeof(publickey));
276 if (ret != sizeof(publickey)) {
277 err = EIO;
278 errstr = "Cannot write public key!\n";
279 goto out;
282 close(fd);
284 printf("Public key written to %s!\n", path);
286 memset(path, 0, sizeof(path));
287 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
289 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
290 if (fd < 0) {
291 err = EIO;
292 errstr = "Cannot open privkey file!\n";
293 goto out_noclose;
296 ret = write(fd, secretkey, sizeof(secretkey));
297 if (ret != sizeof(secretkey)) {
298 err = EIO;
299 errstr = "Cannot write private key!\n";
300 goto out;
302 out:
303 close(fd);
304 out_noclose:
305 xmemset(publickey, 0, sizeof(publickey));
306 xmemset(secretkey, 0, sizeof(secretkey));
308 if (err)
309 panic("%s: %s", errstr, strerror(errno));
310 else
311 printf("Private key written to %s!\n", path);
314 static void check_config_keypair_or_die(char *home)
316 int fd, err;
317 ssize_t ret;
318 const char * errstr = NULL;
319 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
320 unsigned char publicres[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
321 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES];
322 char path[PATH_MAX];
324 memset(path, 0, sizeof(path));
325 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
327 fd = open(path, O_RDONLY);
328 if (fd < 0) {
329 err = EIO;
330 errstr = "Cannot open privkey file!\n";
331 goto out;
334 ret = read(fd, secretkey, sizeof(secretkey));
335 if (ret != sizeof(secretkey)) {
336 err = EIO;
337 errstr = "Cannot read private key!\n";
338 goto out;
341 close(fd);
343 memset(path, 0, sizeof(path));
344 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
346 fd = open(path, O_RDONLY);
347 if (fd < 0) {
348 err = EIO;
349 errstr = "Cannot open pubkey file!\n";
350 goto out;
353 ret = read(fd, publickey, sizeof(publickey));
354 if (ret != sizeof(publickey)) {
355 err = EIO;
356 errstr = "Cannot read public key!\n";
357 goto out;
360 crypto_scalarmult_curve25519_base(publicres, secretkey);
362 err = crypto_verify_32(publicres, publickey);
363 if (err) {
364 err = EINVAL;
365 errstr = "WARNING: your keypair is corrupted!!! You need to "
366 "generate new keys!!!\n";
367 goto out;
369 out:
370 close(fd);
372 xmemset(publickey, 0, sizeof(publickey));
373 xmemset(publicres, 0, sizeof(publicres));
374 xmemset(secretkey, 0, sizeof(secretkey));
376 if (err)
377 panic("%s: %s\n", errstr, strerror(errno));
380 static int main_keygen(char *home)
382 create_curvedir(home);
383 write_username(home);
384 create_keypair(home);
385 check_config_keypair_or_die(home);
387 return 0;
390 static int main_export(char *home)
392 int fd, i;
393 ssize_t ret;
394 char path[PATH_MAX], tmp[64];
396 check_config_exists_or_die(home);
397 check_config_keypair_or_die(home);
399 printf("Your exported public information:\n\n");
401 memset(path, 0, sizeof(path));
402 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
404 fd = open_or_die(path, O_RDONLY);
406 while ((ret = read(fd, tmp, sizeof(tmp))) > 0) {
407 ret = write(STDOUT_FILENO, tmp, ret);
410 close(fd);
412 printf(";");
414 memset(path, 0, sizeof(path));
415 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
417 fd = open_or_die(path, O_RDONLY);
419 ret = read(fd, tmp, sizeof(tmp));
420 if (ret != crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)
421 panic("Cannot read public key!\n");
423 for (i = 0; i < ret; ++i)
424 if (i == ret - 1)
425 printf("%02x\n\n", (unsigned char) tmp[i]);
426 else
427 printf("%02x:", (unsigned char) tmp[i]);
429 close(fd);
430 fflush(stdout);
432 return 0;
435 static int main_dumpc(char *home)
437 check_config_exists_or_die(home);
438 check_config_keypair_or_die(home);
440 printf("Your clients:\n\n");
442 parse_userfile_and_generate_user_store_or_die(home);
444 dump_user_store();
446 destroy_user_store();
448 printf("\n");
449 die();
450 return 0;
453 static int main_dumps(char *home)
455 check_config_exists_or_die(home);
456 check_config_keypair_or_die(home);
458 printf("Your servers:\n\n");
460 parse_userfile_and_generate_serv_store_or_die(home);
462 dump_serv_store();
464 destroy_serv_store();
466 printf("\n");
467 die();
468 return 0;
471 static void daemonize(const char *lockfile)
473 char pidstr[8];
474 mode_t lperm = S_IRWXU | S_IRGRP | S_IXGRP; /* 0750 */
475 int lfp;
477 if (getppid() == 1)
478 return;
480 if (daemon(0, 1))
481 panic("Cannot daemonize: %s", strerror(errno));
483 to_std_log(&stdout);
484 to_std_log(&stderr);
486 umask(lperm);
487 if (lockfile) {
488 lfp = open(lockfile, O_RDWR | O_CREAT | O_EXCL,
489 S_IRUSR | S_IWUSR | S_IRGRP);
490 if (lfp < 0)
491 syslog_panic("Cannot create lockfile at %s! "
492 "curvetun server already running?\n",
493 lockfile);
495 slprintf(pidstr, sizeof(pidstr), "%u", getpid());
496 if (write(lfp, pidstr, strlen(pidstr)) <= 0)
497 syslog_panic("Could not write pid to pidfile %s",
498 lockfile);
500 close(lfp);
504 static int main_client(char *home, char *dev, char *alias, int daemon)
506 int ret, udp;
507 char *host, *port;
509 check_config_exists_or_die(home);
510 check_config_keypair_or_die(home);
512 parse_userfile_and_generate_serv_store_or_die(home);
514 get_serv_store_entry_by_alias(alias, alias ? strlen(alias) + 1 : 0,
515 &host, &port, &udp);
516 if (!host || !port || udp < 0)
517 panic("Did not find alias/entry in configuration!\n");
519 printf("Using [%s] -> %s:%s via %s as endpoint!\n",
520 alias ? : "default", host, port, udp ? "udp" : "tcp");
521 if (daemon)
522 daemonize(NULL);
524 ret = client_main(home, dev, host, port, udp);
526 destroy_serv_store();
528 return ret;
531 static int main_server(char *home, char *dev, char *port, int udp,
532 int ipv4, int daemon, int log)
534 int ret;
536 check_config_exists_or_die(home);
537 check_config_keypair_or_die(home);
539 if (daemon)
540 daemonize(LOCKFILE);
542 ret = server_main(home, dev, port, udp, ipv4, log);
544 unlink(LOCKFILE);
546 return ret;
549 int main(int argc, char **argv)
551 int ret = 0, c, opt_index, udp = 0, ipv4 = -1, daemon = 1, log = 1;
552 char *port = NULL, *stun = NULL, *dev = NULL, *home = NULL, *alias = NULL;
553 enum working_mode wmode = MODE_UNKNOW;
555 setfsuid(getuid());
556 setfsgid(getgid());
558 home = fetch_home_dir();
560 while ((c = getopt_long(argc, argv, short_options, long_options,
561 &opt_index)) != EOF) {
562 switch (c) {
563 case 'h':
564 help();
565 break;
566 case 'v':
567 version();
568 break;
569 case 'D':
570 daemon = 0;
571 break;
572 case 'N':
573 log = 0;
574 break;
575 case 'C':
576 wmode = MODE_DUMPC;
577 break;
578 case 'S':
579 wmode = MODE_DUMPS;
580 break;
581 case 'c':
582 wmode = MODE_CLIENT;
583 if (optarg) {
584 if (*optarg == '=')
585 optarg++;
586 alias = xstrdup(optarg);
588 break;
589 case 'd':
590 dev = xstrdup(optarg);
591 break;
592 case 'k':
593 wmode = MODE_KEYGEN;
594 break;
595 case '4':
596 ipv4 = 1;
597 break;
598 case '6':
599 ipv4 = 0;
600 break;
601 case 'x':
602 wmode = MODE_EXPORT;
603 break;
604 case 's':
605 wmode = MODE_SERVER;
606 break;
607 case 'u':
608 udp = 1;
609 break;
610 case 't':
611 stun = xstrdup(optarg);
612 break;
613 case 'p':
614 port = xstrdup(optarg);
615 break;
616 case '?':
617 switch (optopt) {
618 case 't':
619 case 'd':
620 case 'u':
621 case 'p':
622 panic("Option -%c requires an argument!\n",
623 optopt);
624 default:
625 if (isprint(optopt))
626 printf("Unknown option character `0x%X\'!\n", optopt);
627 die();
629 default:
630 break;
634 if (argc < 2)
635 help();
637 register_signal(SIGINT, signal_handler);
638 register_signal(SIGHUP, signal_handler);
639 register_signal(SIGTERM, signal_handler);
640 register_signal(SIGPIPE, signal_handler);
642 curve25519_selftest();
644 switch (wmode) {
645 case MODE_KEYGEN:
646 ret = main_keygen(home);
647 break;
648 case MODE_EXPORT:
649 ret = main_export(home);
650 break;
651 case MODE_DUMPC:
652 ret = main_dumpc(home);
653 break;
654 case MODE_DUMPS:
655 ret = main_dumps(home);
656 break;
657 case MODE_CLIENT:
658 ret = main_client(home, dev, alias, daemon);
659 break;
660 case MODE_SERVER:
661 if (!port)
662 panic("No port specified!\n");
663 if (stun)
664 print_stun_probe(stun, 3478, strtoul(port, NULL, 10));
665 ret = main_server(home, dev, port, udp, ipv4, daemon, log);
666 break;
667 default:
668 die();
671 free(dev);
672 free(stun);
673 free(port);
674 free(alias);
676 return ret;