all: minor: updated copyright year
[netsniff-ng.git] / src / curvetun.c
blob59359fe70272ef4c57c94c6a8de46a08f633076d
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'.
35 =head1 NAME
37 curvetun - lightweight curve25519-based multiuser IP tunnel
39 =head1 SYNOPSIS
41 curvetun [-d|--dev <tun>][-x|--export][-C|--dumpc][-S|--dumps]
42 [-k|--keygen][-c|--client [<alias>]][-s|--server][-N|--no-logging]
43 [-p|--port <num>][-t|--stun <server>][-4|--ipv4][-6|--ipv6]
44 [-v|--version][-h|--help]
46 =head1 DESCRIPTION
48 curvetun embeds a client and a server to build and manage multiuser
49 IP tunnels using Elliptic Curve Cryptography (ECC)
51 =head1 EXAMPLES
53 =over
55 =item curvetun --keygen
57 Generate public/private keypair. This needs to be done before
58 to get things started.
60 =item curvetun --export
62 Export public data to remote servers
64 =item curvetun --server -4 -u -N --port 6666 --stun stunserver.org
66 Start a UDP IPv4 curvetun server on port 6666.
67 Use stunserver.org as STUN server.
69 =item curvetun --client=ethz
71 Start curvetun client using the profile called 'ethz'
73 =back
75 =head1 OPTIONS
77 =over
79 =item -k|--keygen
81 Generate public/private keypair.
83 =item -x|--export
85 Export your public data for remote servers.
87 =item -C|--dumpc
89 Dump parsed clients.
91 =item -S|--dumps
93 Dump parsed servers.
95 =item -D|--nofork
97 Do not daemonize.
99 =item -d|--dev <tun>
101 Networking tunnel device, e.g. tun0.
103 =item -c|--client [<alias>]
105 Client mode, server alias optional.
107 =item -s|--server
109 Server mode.
111 =item -N|--no-logging
113 Disable server logging (for better anonymity).
115 =item -p|--port <num>
117 Port number (mandatory).
119 =item -t|--stun <server>
121 Show public IP/Port mapping via STUN.
123 =item -u|--udp
125 Use UDP as carrier instead of TCP.
127 =item -4|--ipv4
129 Tunnel devices are IPv4.
131 =item -6|--ipv6
133 Tunnel devices are IPv6.
135 =item -v|--version
137 Print version.
139 =item -h|--help
141 Print help text and lists all options.
143 =back
145 =head1 AUTHOR
147 Written by Daniel Borkmann <daniel@netsniff-ng.org> and Emmanuel Roullit <emmanuel@netsniff-ng.org>
149 =head1 DOCUMENTATION
151 Documentation by Emmanuel Roullit <emmanuel@netsniff-ng.org>
153 =head1 BUGS
155 Please report bugs to <bugs@netsniff-ng.org>
157 =cut
161 #define _GNU_SOURCE
162 #include <stdio.h>
163 #include <stdlib.h>
164 #include <fcntl.h>
165 #include <string.h>
166 #include <ctype.h>
167 #include <getopt.h>
168 #include <errno.h>
169 #include <stdbool.h>
170 #include <limits.h>
171 #include <sys/types.h>
172 #include <sys/stat.h>
173 #include <sys/socket.h>
174 #include <sys/ptrace.h>
175 #include <netinet/in.h>
176 #include <unistd.h>
177 #include <signal.h>
179 #include "xsys.h"
180 #include "stun.h"
181 #include "die.h"
182 #include "xmalloc.h"
183 #include "xstring.h"
184 #include "curvetun.h"
185 #include "curve.h"
186 #include "usermgmt.h"
187 #include "servmgmt.h"
188 #include "xio.h"
189 #include "crypto_verify_32.h"
190 #include "crypto_box_curve25519xsalsa20poly1305.h"
191 #include "crypto_scalarmult_curve25519.h"
192 #include "crypto_auth_hmacsha512256.h"
194 #define CURVETUN_ENTROPY_SOURCE "/dev/random"
196 enum working_mode {
197 MODE_UNKNOW,
198 MODE_KEYGEN,
199 MODE_EXPORT,
200 MODE_DUMPC,
201 MODE_DUMPS,
202 MODE_CLIENT,
203 MODE_SERVER,
206 volatile sig_atomic_t sigint = 0;
208 static const char *short_options = "kxc::svhp:t:d:uCS46DN";
210 static struct option long_options[] = {
211 {"client", optional_argument, 0, 'c'},
212 {"dev", required_argument, 0, 'd'},
213 {"port", required_argument, 0, 'p'},
214 {"stun", required_argument, 0, 't'},
215 {"keygen", no_argument, 0, 'k'},
216 {"export", no_argument, 0, 'x'},
217 {"dumpc", no_argument, 0, 'C'},
218 {"dumps", no_argument, 0, 'S'},
219 {"no-logging", no_argument, 0, 'N'},
220 {"server", no_argument, 0, 's'},
221 {"udp", no_argument, 0, 'u'},
222 {"ipv4", no_argument, 0, '4'},
223 {"ipv6", no_argument, 0, '6'},
224 {"nofork", no_argument, 0, 'D'},
225 {"version", no_argument, 0, 'v'},
226 {"help", no_argument, 0, 'h'},
227 {0, 0, 0, 0}
230 static void signal_handler(int number)
232 switch (number) {
233 case SIGINT:
234 sigint = 1;
235 break;
236 default:
237 break;
241 static void header(void)
243 printf("%s%s%s\n", colorize_start(bold), "curvetun "
244 VERSION_STRING, colorize_end());
247 static void help(void)
249 printf("\ncurvetun %s, lightweight curve25519-based multiuser IP tunnel\n",
250 VERSION_STRING);
251 printf("http://www.netsniff-ng.org\n\n");
252 printf("Usage: curvetun [options]\n");
253 printf("Options:\n");
254 printf(" -k|--keygen Generate public/private keypair\n");
255 printf(" -x|--export Export your public data for remote servers\n");
256 printf(" -C|--dumpc Dump parsed clients\n");
257 printf(" -S|--dumps Dump parsed servers\n");
258 printf(" -D|--nofork Do not daemonize\n");
259 printf(" -d|--dev <tun> Networking tunnel device, e.g. tun0\n");
260 printf(" -v|--version Print version\n");
261 printf(" -h|--help Print this help\n");
262 printf(" additional options for client:\n");
263 printf(" -c|--client[=alias] Client mode, server alias optional\n");
264 printf(" additional options for servers:\n");
265 printf(" -s|--server Server mode\n");
266 printf(" -N|--no-logging Disable server logging (for better anonymity)\n");
267 printf(" -p|--port <num> Port number (mandatory)\n");
268 printf(" -t|--stun <server> Show public IP/Port mapping via STUN\n");
269 printf(" -u|--udp Use UDP as carrier instead of TCP\n");
270 printf(" -4|--ipv4 Tunnel devices are IPv4\n");
271 printf(" -6|--ipv6 Tunnel devices are IPv6\n");
272 printf(" (default: same as carrier protocol)\n");
273 printf("\n");
274 printf("Example:\n");
275 printf(" See README.curvetun for a configuration example.\n");
276 printf(" curvetun --keygen\n");
277 printf(" curvetun --export\n");
278 printf(" curvetun --server -4 -u -N --port 6666 --stun stunserver.org\n");
279 printf(" curvetun --client=ethz\n");
280 printf("\n");
281 printf("Note:\n");
282 printf(" There is no default port specified, so that you are forced\n");
283 printf(" to select your own! For client/server status messages see syslog!\n");
284 printf(" This software is an experimental prototype intended for researchers.\n");
285 printf("\n");
286 printf("Secret ingredient: 7647-14-5\n");
287 printf("\n");
288 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
289 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
290 printf("License: GNU GPL version 2\n");
291 printf("This is free software: you are free to change and redistribute it.\n");
292 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
293 die();
296 static void version(void)
298 printf("\ncurvetun %s, lightweight curve25519-based multiuser IP tunnel\n",
299 VERSION_STRING);
300 printf("Build: %s\n", BUILD_STRING);
301 printf("http://www.netsniff-ng.org\n\n");
302 printf("Please report bugs to <bugs@netsniff-ng.org>\n");
303 printf("Copyright (C) 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,\n");
304 printf("License: GNU GPL version 2\n");
305 printf("This is free software: you are free to change and redistribute it.\n");
306 printf("There is NO WARRANTY, to the extent permitted by law.\n\n");
307 die();
310 static void check_file_or_die(char *home, char *file, int maybeempty)
312 char path[PATH_MAX];
313 struct stat st;
314 memset(path, 0, sizeof(path));
315 slprintf(path, sizeof(path), "%s/%s", home, file);
316 if (stat(path, &st))
317 panic("No such file %s! Type --help for further information\n",
318 path);
319 if (!S_ISREG(st.st_mode))
320 panic("%s is not a regular file!\n", path);
321 if ((st.st_mode & ~S_IFREG) != (S_IRUSR | S_IWUSR))
322 panic("You have set too many permissions on %s (%o)!\n",
323 path, st.st_mode);
324 if (maybeempty == 0 && st.st_size == 0)
325 panic("%s is empty!\n", path);
328 static void check_config_exists_or_die(char *home)
330 if (!home)
331 panic("No home dir specified!\n");
332 check_file_or_die(home, FILE_CLIENTS, 1);
333 check_file_or_die(home, FILE_SERVERS, 1);
334 check_file_or_die(home, FILE_PRIVKEY, 0);
335 check_file_or_die(home, FILE_PUBKEY, 0);
336 check_file_or_die(home, FILE_USERNAM, 0);
339 static char *fetch_home_dir(void)
341 char *home = getenv("HOME");
342 if (!home)
343 panic("No HOME defined!\n");
344 return home;
347 static void write_username(char *home)
349 int fd, ret;
350 char path[PATH_MAX], *eof;
351 char user[512];
352 memset(path, 0, sizeof(path));
353 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
354 printf("Username: [%s] ", getenv("USER"));
355 fflush(stdout);
356 memset(user, 0, sizeof(user));
357 eof = fgets(user, sizeof(user), stdin);
358 user[sizeof(user) - 1] = 0;
359 user[strlen(user) - 1] = 0; /* omit last \n */
360 if (strlen(user) == 0)
361 strlcpy(user, getenv("USER"), sizeof(user));
362 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
363 if (fd < 0)
364 panic("Cannot open your username file!\n");
365 ret = write(fd, user, strlen(user));
366 if (ret != strlen(user))
367 panic("Could not write username!\n");
368 close(fd);
369 printf("Username written to %s!\n", path);
372 static void create_curvedir(char *home)
374 int ret, fd;
375 char path[PATH_MAX];
376 memset(path, 0, sizeof(path));
377 slprintf(path, sizeof(path), "%s/%s", home, ".curvetun/");
378 errno = 0;
379 ret = mkdir(path, S_IRWXU);
380 if (ret < 0 && errno != EEXIST)
381 panic("Cannot create curvetun dir!\n");
382 printf("curvetun directory %s created!\n", path);
383 /* We also create empty files for clients and servers! */
384 memset(path, 0, sizeof(path));
385 slprintf(path, sizeof(path), "%s/%s", home, FILE_CLIENTS);
386 fd = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
387 if (fd < 0)
388 panic("Cannot open clients file!\n");
389 close(fd);
390 printf("Empty client file written to %s!\n", path);
391 memset(path, 0, sizeof(path));
392 slprintf(path, sizeof(path), "%s/%s", home, FILE_SERVERS);
393 fd = open(path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
394 if (fd < 0)
395 panic("Cannot open servers file!\n");
396 close(fd);
397 printf("Empty server file written to %s!\n", path);
400 static void create_keypair(char *home)
402 int fd, err = 0;
403 ssize_t ret;
404 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES] = { 0 };
405 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES] = { 0 };
406 char path[PATH_MAX];
407 const char * errstr = NULL;
408 printf("Reading from %s (this may take a while) ...\n", CURVETUN_ENTROPY_SOURCE);
409 fd = open_or_die(CURVETUN_ENTROPY_SOURCE, O_RDONLY);
410 ret = read_exact(fd, secretkey, sizeof(secretkey), 0);
411 if (ret != sizeof(secretkey)) {
412 err = EIO;
413 errstr = "Cannot read from "CURVETUN_ENTROPY_SOURCE"!\n";
414 goto out;
416 close(fd);
417 crypto_scalarmult_curve25519_base(publickey, secretkey);
418 memset(path, 0, sizeof(path));
419 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
420 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
421 if (fd < 0) {
422 err = EIO;
423 errstr = "Cannot open pubkey file!\n";
424 goto out;
426 ret = write(fd, publickey, sizeof(publickey));
427 if (ret != sizeof(publickey)) {
428 err = EIO;
429 errstr = "Cannot write public key!\n";
430 goto out;
432 close(fd);
433 printf("Public key written to %s!\n", path);
434 memset(path, 0, sizeof(path));
435 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
436 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
437 if (fd < 0) {
438 err = EIO;
439 errstr = "Cannot open privkey file!\n";
440 goto out;
442 ret = write(fd, secretkey, sizeof(secretkey));
443 if (ret != sizeof(secretkey)) {
444 err = EIO;
445 errstr = "Cannot write private key!\n";
446 goto out;
448 out:
449 close(fd);
450 xmemset(publickey, 0, sizeof(publickey));
451 xmemset(secretkey, 0, sizeof(secretkey));
452 if (err)
453 panic("%s: %s", errstr, strerror(errno));
454 else
455 printf("Private key written to %s!\n", path);
458 static void check_config_keypair_or_die(char *home)
460 int fd, err;
461 ssize_t ret;
462 const char * errstr = NULL;
463 unsigned char publickey[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
464 unsigned char publicres[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES];
465 unsigned char secretkey[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES];
466 char path[PATH_MAX];
467 memset(path, 0, sizeof(path));
468 slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY);
469 fd = open(path, O_RDONLY);
470 if (fd < 0) {
471 err = EIO;
472 errstr = "Cannot open privkey file!\n";
473 goto out;
475 ret = read(fd, secretkey, sizeof(secretkey));
476 if (ret != sizeof(secretkey)) {
477 err = EIO;
478 errstr = "Cannot read private key!\n";
479 goto out;
481 close(fd);
482 memset(path, 0, sizeof(path));
483 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
484 fd = open(path, O_RDONLY);
485 if (fd < 0) {
486 err = EIO;
487 errstr = "Cannot open pubkey file!\n";
488 goto out;
490 ret = read(fd, publickey, sizeof(publickey));
491 if (ret != sizeof(publickey)) {
492 err = EIO;
493 errstr = "Cannot read public key!\n";
494 goto out;
496 crypto_scalarmult_curve25519_base(publicres, secretkey);
497 err = crypto_verify_32(publicres, publickey);
498 if (err) {
499 err = EINVAL;
500 errstr = "WARNING: your keypair is corrupted!!! You need to "
501 "generate new keys!!!\n";
502 goto out;
504 out:
505 close(fd);
506 xmemset(publickey, 0, sizeof(publickey));
507 xmemset(publicres, 0, sizeof(publicres));
508 xmemset(secretkey, 0, sizeof(secretkey));
509 if (err)
510 panic("%s: %s\n", errstr, strerror(errno));
513 static int main_keygen(char *home)
515 create_curvedir(home);
516 write_username(home);
517 create_keypair(home);
518 check_config_keypair_or_die(home);
519 return 0;
522 static int main_export(char *home)
524 int fd, i;
525 ssize_t ret;
526 char path[PATH_MAX], tmp[64];
528 check_config_exists_or_die(home);
529 check_config_keypair_or_die(home);
530 printf("Your exported public information:\n\n");
531 memset(path, 0, sizeof(path));
532 slprintf(path, sizeof(path), "%s/%s", home, FILE_USERNAM);
533 fd = open_or_die(path, O_RDONLY);
534 while ((ret = read(fd, tmp, sizeof(tmp))) > 0) {
535 ret = write(STDOUT_FILENO, tmp, ret);
537 close(fd);
538 printf(";");
539 memset(path, 0, sizeof(path));
540 slprintf(path, sizeof(path), "%s/%s", home, FILE_PUBKEY);
541 fd = open_or_die(path, O_RDONLY);
542 ret = read(fd, tmp, sizeof(tmp));
543 if (ret != crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)
544 panic("Cannot read public key!\n");
545 for (i = 0; i < ret; ++i)
546 if (i == ret - 1)
547 printf("%02x\n\n", (unsigned char) tmp[i]);
548 else
549 printf("%02x:", (unsigned char) tmp[i]);
550 close(fd);
551 fflush(stdout);
552 return 0;
555 static int main_dumpc(char *home)
557 check_config_exists_or_die(home);
558 check_config_keypair_or_die(home);
559 printf("Your clients:\n\n");
560 parse_userfile_and_generate_user_store_or_die(home);
561 dump_user_store();
562 destroy_user_store();
563 printf("\n");
564 die();
565 return 0;
568 static int main_dumps(char *home)
570 check_config_exists_or_die(home);
571 check_config_keypair_or_die(home);
572 printf("Your servers:\n\n");
573 parse_userfile_and_generate_serv_store_or_die(home);
574 dump_serv_store();
575 destroy_serv_store();
576 printf("\n");
577 die();
578 return 0;
581 static void daemonize(const char *lockfile)
583 char pidstr[8];
584 mode_t lperm = S_IRWXU | S_IRGRP | S_IXGRP; /* 0750 */
585 int lfp;
586 if (getppid() == 1)
587 return;
588 if (daemon(0, 0))
589 panic("Cannot daemonize: %s", strerror(errno));
590 umask(lperm);
591 if (lockfile) {
592 lfp = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0640);
593 if (lfp < 0)
594 syslog_panic("Cannot create lockfile at %s! "
595 "curvetun server already running?\n",
596 lockfile);
597 slprintf(pidstr, sizeof(pidstr), "%u", getpid());
598 if (write(lfp, pidstr, strlen(pidstr)) <= 0)
599 syslog_panic("Could not write pid to pidfile %s",
600 lockfile);
601 close(lfp);
605 static int main_client(char *home, char *dev, char *alias, int daemon)
607 int ret, udp;
608 char *host, *port;
609 check_config_exists_or_die(home);
610 check_config_keypair_or_die(home);
611 parse_userfile_and_generate_serv_store_or_die(home);
612 get_serv_store_entry_by_alias(alias, alias ? strlen(alias) + 1 : 0,
613 &host, &port, &udp);
614 if (!host || !port || udp < 0)
615 panic("Did not find alias/entry in configuration!\n");
616 printf("Using [%s] -> %s:%s via %s as endpoint!\n",
617 alias ? : "default", host, port, udp ? "udp" : "tcp");
618 if (daemon)
619 daemonize(NULL);
620 ret = client_main(home, dev, host, port, udp);
621 destroy_serv_store();
622 return ret;
625 static int main_server(char *home, char *dev, char *port, int udp,
626 int ipv4, int daemon, int log)
628 int ret;
629 check_config_exists_or_die(home);
630 check_config_keypair_or_die(home);
631 if (daemon)
632 daemonize(LOCKFILE);
633 ret = server_main(home, dev, port, udp, ipv4, log);
634 unlink(LOCKFILE);
635 return ret;
638 int main(int argc, char **argv)
640 int ret = 0, c, opt_index, udp = 0, ipv4 = -1, daemon = 1, log = 1;
641 char *port = NULL, *stun = NULL, *dev = NULL, *home = NULL, *alias=NULL;
642 enum working_mode wmode = MODE_UNKNOW;
643 if (getuid() != geteuid())
644 seteuid(getuid());
645 if (getenv("LD_PRELOAD"))
646 panic("curvetun cannot be preloaded!\n");
647 if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0)
648 panic("curvetun cannot be ptraced!\n");
649 home = fetch_home_dir();
650 while ((c = getopt_long(argc, argv, short_options, long_options,
651 &opt_index)) != EOF) {
652 switch (c) {
653 case 'h':
654 help();
655 break;
656 case 'v':
657 version();
658 break;
659 case 'D':
660 daemon = 0;
661 break;
662 case 'N':
663 log = 0;
664 break;
665 case 'C':
666 wmode = MODE_DUMPC;
667 break;
668 case 'S':
669 wmode = MODE_DUMPS;
670 break;
671 case 'c':
672 wmode = MODE_CLIENT;
673 if (optarg) {
674 if (*optarg == '=')
675 optarg++;
676 alias = xstrdup(optarg);
678 break;
679 case 'd':
680 dev = xstrdup(optarg);
681 break;
682 case 'k':
683 wmode = MODE_KEYGEN;
684 break;
685 case '4':
686 ipv4 = 1;
687 break;
688 case '6':
689 ipv4 = 0;
690 break;
691 case 'x':
692 wmode = MODE_EXPORT;
693 break;
694 case 's':
695 wmode = MODE_SERVER;
696 break;
697 case 'u':
698 udp = 1;
699 break;
700 case 't':
701 stun = xstrdup(optarg);
702 break;
703 case 'p':
704 port = xstrdup(optarg);
705 break;
706 case '?':
707 switch (optopt) {
708 case 't':
709 case 'd':
710 case 'u':
711 case 'p':
712 panic("Option -%c requires an argument!\n",
713 optopt);
714 default:
715 if (isprint(optopt))
716 whine("Unknown option character "
717 "`0x%X\'!\n", optopt);
718 die();
720 default:
721 break;
725 if (argc < 2)
726 help();
727 register_signal(SIGINT, signal_handler);
728 register_signal(SIGHUP, signal_handler);
729 register_signal(SIGTERM, signal_handler);
730 register_signal(SIGPIPE, signal_handler);
731 header();
732 curve25519_selftest();
733 switch (wmode) {
734 case MODE_KEYGEN:
735 ret = main_keygen(home);
736 break;
737 case MODE_EXPORT:
738 ret = main_export(home);
739 break;
740 case MODE_DUMPC:
741 ret = main_dumpc(home);
742 break;
743 case MODE_DUMPS:
744 ret = main_dumps(home);
745 break;
746 case MODE_CLIENT:
747 ret = main_client(home, dev, alias, daemon);
748 break;
749 case MODE_SERVER:
750 if (!port)
751 panic("No port specified!\n");
752 if (stun)
753 print_stun_probe(stun, 3478, strtoul(port, NULL, 10));
754 ret = main_server(home, dev, port, udp, ipv4, daemon, log);
755 break;
756 default:
757 die();
759 if (dev)
760 xfree(dev);
761 if (stun)
762 xfree(stun);
763 if (port)
764 xfree(port);
765 if (alias)
766 xfree(alias);
767 return ret;