aboutsummaryrefslogtreecommitdiff
path: root/src/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/options.c')
-rw-r--r--src/options.c613
1 files changed, 0 insertions, 613 deletions
diff --git a/src/options.c b/src/options.c
deleted file mode 100644
index 84227ae..0000000
--- a/src/options.c
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
- * options.c
- * ptunnel is licensed under the BSD license:
- *
- * Copyright (c) 2017-2019, Toni Uhlig <matzeton@googlemail.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the Yellow Lemon Software nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <string.h>
-#include <getopt.h>
-#include <ctype.h>
-#include <assert.h>
-#ifdef WIN32
-#include <ws2tcpip.h>
-#endif
-#ifdef ENABLE_SHA512
-#include <openssl/sha.h>
-#endif
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "options.h"
-#include "utils.h"
-#include "ptunnel.h"
-#include "md5.h"
-
-
-struct options opts;
-
-enum option_type {
- OPT_BOOL, OPT_DEC32, OPT_HEX32, OPT_STR
-};
-
-struct option_usage {
- const char *short_help;
- int required;
- enum option_type otype;
- union {
- int32_t num;
- uint32_t unum;
- const char *str;
- };
- const char *long_help;
-};
-
-static const struct option_usage usage[] = {
- /** --magic */
- {"magic", 0, OPT_HEX32, {.unum = 0xdeadc0de},
- "Set ptunnel magic hexadecimal number. (32-bit unsigned)\n"
- "It is an identifier for all ICMP/UDP packets\n"
- "and can be used to bypass Cisco IPS fingerprint scan.\n"
- "This value has to be the same on the server and client!\n"
- },
- /** --proxy */
- {"address", 1, OPT_STR, {.str = NULL},
- "Set address of peer running packet forwarder. This causes\n"
- "ptunnel to operate in forwarding mode (Client) - the absence of this\n"
- "option causes ptunnel to operate in proxy mode (Server).\n"
- },
- /** --listen */
- {"port", 0, OPT_DEC32, {.unum = 2222},
- "Set TCP listening port (only used when operating in forward mode)\n"
- },
- /** --remote-addr */
- {"address", 1, OPT_STR, {.str = "127.0.0.1"},
- "Set remote proxy destination address if client\n"
- "Restrict to only this destination address if server\n"
- },
- /** --remote-port */
- {"port", 1, OPT_DEC32, {.unum = 22},
- "Set remote proxy destination port if client\n"
- "Restrict to only this destination port if server\n"
- },
- /** --connections */
- {"connections", 0, OPT_DEC32, {.unum = kMax_tunnels},
- "Set maximum number of concurrent tunnels\n"
- },
- /** --verbosity */
- {"level", 0, OPT_DEC32, {.num = kLog_event},
- "Verbosity level (-1 to 4, where -1 is no output, and 4 is all output)\n"
- "The special level 5 (or higher) includes xfer logging (lots of output)\n"
- },
- /** --libpcap */
- {"interface", 0, OPT_STR, {.str = NULL},
-#ifndef HAVE_PCAP
- "(Not available on this platform.)\n"
-#endif
- "Enable libpcap on the given device.\n"
- },
- /** --list-libpcap-devices */
- {NULL, 0, OPT_BOOL, {.num = 0},
-#ifndef HAVE_PCAP
- "(Not available on this platform.)\n"
-#endif
- "List all available pcap devices.\n"
- },
- /** --logfile */
- {"file", 0, OPT_STR, {.str = "/var/log/ptunnel.log"},
- "Specify a file to log to, rather than printing to standard out.\n"
- },
- /** --statistics */
- {NULL, 0, OPT_BOOL, {.num = 0},
- "Client only. Enables continuous output of statistics (packet loss, etc.)\n"
- },
- /** --passwd */
- {"password", 0, OPT_STR, {.str = NULL},
- "Set a password (must be same on client and proxy)\n"
- "DEPRECATED: Will be removed/replaced soon!\n"
- },
- /** --udp */
- {NULL, 0, OPT_BOOL, {.num = 0},
- "Toggle use of UDP instead of ICMP. Proxy will listen on port 53 (must be root).\n"
- },
- /** --unprivileged */
- {NULL, 0, OPT_BOOL, {.num = 0},
- "Run proxy in unprivileged mode. This causes the proxy to forward\n"
- "packets using standard echo requests, instead of crafting custom echo replies.\n"
- "Unprivileged mode will only work on some systems, and is in general less reliable\n"
- "than running in privileged mode.\n"
- },
- /** --force-sha512 */
- {"force-sha512", 0, OPT_BOOL, {.num = 0},
- "Force SHA512 as challenge response checksum generator.\n"
-#ifdef ENABLE_SHA512
- "This is the default for this configuration.\n"
-#else
- "SHA512 is not available for this configuration.\n"
-#endif
- },
- /** --daemon */
- {"pidfile", 0, OPT_STR, {.str = "/run/ptunnel.pid"},
-#ifdef WIN32
- "(Not available on this platform.)\n"
-#endif
- "Run in background, the PID will be written in the file supplied as argument\n"
- },
- /** --syslog */
- {NULL, 0, OPT_BOOL, {.num = 0},
-#ifdef WIN32
- "(Not available on this platform.)\n"
-#endif
- "Output debug to syslog instead of standard out.\n"
- },
- /** --user */
- {"user", 0, OPT_STR, {.str = "nobody"},
-#ifdef WIN32
- "(Not available on this platform.)\n"
-#endif
- "When started in privileged mode, drop down to user's rights as soon as possible\n"
- },
- /** --group */
- {"group", 0, OPT_STR, {.str = "nogroup"},
-#ifdef WIN32
- "(Not available on this platform.)\n"
-#endif
- "When started in privileged mode, drop down to group's rights as soon as possible\n"
- },
- /** --chroot */
- {"directory", 0, OPT_STR, {.str = "/var/lib/ptunnel"},
-#ifdef WIN32
- "(Not available on this platform.)\n"
-#endif
- "When started in privileged mode, restrict file access to the specified directory\n"
- },
- /** --setcon */
- {"context", 0, OPT_STR, {.str = "ptunnel"},
-#ifndef HAVE_SELINUX
- "(Not available on this platform.)\n"
-#endif
- "Set SELinux context when all there is left to do are network I/O operations\n"
- "To combine with --chroot you will have to `mount --bind /proc /chrootdir/proc`\n"
- },
- /** --help */
- {NULL, 0, OPT_STR, {.str = NULL}, "this\n"},
- {NULL,0,OPT_BOOL,{.unum=0},NULL}
-};
-
-static struct option long_options[] = {
- {"magic", required_argument, 0, 'm'},
- {"proxy", required_argument, 0, 'p'},
- {"listen", required_argument, 0, 'l'},
- {"remote-addr", optional_argument, 0, 'r'},
- {"remote-port", optional_argument, 0, 'R'},
- {"connections", required_argument, 0, 'c'},
- {"verbosity", required_argument, 0, 'v'},
- {"libpcap", required_argument, 0, 'L'},
- {"list-libpcap-devices", no_argument, &opts.list_pcap_devices, 1},
- {"logfile", optional_argument, 0, 'o'},
- {"statistics", no_argument, 0, 's'},
- {"passwd", required_argument, 0, 'P'},
- {"udp", no_argument, &opts.udp, 1},
- {"unprivileged", no_argument, &opts.unprivileged, 1},
- {"force-sha512", no_argument, &opts.force_sha512, 1},
- {"daemon", optional_argument, 0, 'd'},
- {"syslog", no_argument, 0, 'S'},
- {"user", optional_argument, 0, 'u'},
- {"group", optional_argument, 0, 'g'},
- {"chroot", optional_argument, 0, 'C'},
- {"setcon", optional_argument, 0, 'e'},
- {"help", no_argument, 0, 'h'},
- {NULL,0,0,0}
-};
-
-
-static const void *get_default_optval(enum option_type opttype, const char *optname) {
- (void) opttype;
-
- for (unsigned i = 0; i < ARRAY_SIZE(long_options); ++i) {
- if (strncmp(long_options[i].name, optname, BUFSIZ /* not optimal */) == 0 &&
- strlen(long_options[i].name) == strlen(optname))
- {
- assert(usage[i].otype == opttype &&
- (usage[i].otype != OPT_STR || usage[i].str));
- return &usage[i].str;
- }
- }
- assert(NULL);
- return NULL;
-}
-
-static void set_options_defaults(void) {
-#ifndef WIN32
- char *tmp;
- struct passwd *pwnam;
- struct group *grnam;
-#endif
-
- memset(&opts, 0, sizeof(opts));
- opts.magic = *(uint32_t *) get_default_optval(OPT_HEX32, "magic");
- opts.mode = kMode_proxy;
- opts.tcp_listen_port = *(uint32_t *) get_default_optval(OPT_DEC32, "listen");
- opts.given_dst_hostname = strdup(*(char **) get_default_optval(OPT_STR, "remote-addr"));
- opts.given_dst_port = *(uint32_t *) get_default_optval(OPT_DEC32, "remote-port");
- opts.max_tunnels = *(uint32_t *) get_default_optval(OPT_DEC32, "connections");
- opts.log_level = *(int *) get_default_optval(OPT_DEC32, "verbosity");
- opts.log_path = strdup(*(char **)get_default_optval(OPT_STR, "logfile"));
- opts.log_file = stdout;
- opts.print_stats = *(int *) get_default_optval(OPT_BOOL, "statistics");
-#ifndef WIN32
- opts.pid_path = strdup(*(char **)get_default_optval(OPT_STR, "daemon"));
-
- errno = 0;
- tmp = *(char **) get_default_optval(OPT_STR, "user");
- if (NULL == (pwnam = getpwnam(tmp)))
- pt_log(kLog_error, "%s: %s\n", tmp, errno ? strerror(errno) : "unknown user");
- else {
- opts.uid = pwnam->pw_uid;
- if (!opts.gid)
- opts.gid = pwnam->pw_gid;
- }
-
- errno = 0;
- tmp = *(char **) get_default_optval(OPT_STR, "group");
- if (NULL != (grnam = getgrnam(tmp)))
- opts.gid = grnam->gr_gid;
-
- opts.root_dir = strdup(*(char **)get_default_optval(OPT_STR, "chroot"));
-#endif
-#ifdef HAVE_SELINUX
- opts.selinux_context = strdup(*(char **)get_default_optval(OPT_STR, "setcon"));
-#endif
-}
-
-static void print_multiline(const char *prefix, const char *multiline) {
- const char sep[] = "\n";
- const char *start, *end;
-
- start = multiline;
- end = NULL;
- do {
- if (start) {
- end = strstr(start, sep);
- if (end && *end != '\0') {
- printf("%s%.*s\n", prefix, (int)(end-start), start);
- start = end + strnlen(sep, BUFSIZ /* not optimal */);
- }
- }
- } while (start && end);
-}
-
-static void print_long_help(unsigned index, int required_state) {
- const char spaces[] = " ";
-
- if (usage[index].required != required_state)
- return;
- if (!long_options[index].name)
- return;
-
- if (isalpha(long_options[index].val)) {
- printf("%.*s-%c --%s\n", 4, spaces, long_options[index].val, long_options[index].name);
- } else {
- printf("%.*s--%s\n", 4, spaces, long_options[index].name);
- }
-
- if (usage[index].long_help) {
- print_multiline(&spaces[4], usage[index].long_help);
- }
-
- switch (usage[index].otype) {
- case OPT_BOOL:
- break;
- case OPT_DEC32:
- printf("%s(default: %d)\n", spaces, usage[index].num);
- break;
- case OPT_HEX32:
- printf("%s(default: 0x%X)\n", spaces, usage[index].unum);
- break;
- case OPT_STR:
- if (usage[index].str)
- printf("%s(default: %s)\n", spaces, usage[index].str);
- break;
- }
-}
-
-static void print_short_help(unsigned index, int required_state) {
- const char *ob = (required_state == 0 ? "[" : "");
- const char *cb = (required_state == 0 ? "]" : "");
- const char *ov = (long_options[index].has_arg != optional_argument ? " " : "");
-
- if (usage[index].required != required_state)
- return;
- if (!long_options[index].name)
- return;
-
- if (!usage[index].short_help && isalpha(long_options[index].val)) {
- printf(" %s-%c%s", ob, long_options[index].val, cb);
- }
- else if (!usage[index].short_help) {
- printf(" %s--%s%s", ob, long_options[index].name, cb);
- }
- else if (isalpha(long_options[index].val)) {
- printf(" %s-%c%s<%s>%s", ob, long_options[index].val, ov, usage[index].short_help, cb);
- }
- else {
- printf(" %s--%s <%s>%s", ob, long_options[index].name, usage[index].short_help, cb);
- }
-}
-
-void print_usage(const char *arg0) {
- unsigned i;
-
- printf("%s\n\nUsage: %s", PACKAGE_STRING, arg0);
- /* print (short)help argument line */
- for (i = 0; i < ARRAY_SIZE(usage); ++i) {
- print_short_help(i, 1);
- }
- for (i = 0; i < ARRAY_SIZE(usage); ++i) {
- print_short_help(i, 0);
- }
-
- printf("%s", "\n\n");
- /* print (long)help lines */
- for (i = 0; i < ARRAY_SIZE(usage); ++i) {
- print_long_help(i, 1);
- }
- for (i = 0; i < ARRAY_SIZE(usage); ++i) {
- print_long_help(i, 0);
- }
-}
-
-int parse_options(int argc, char **argv) {
- int c = 0, oidx = -1, has_logfile = 0, ret;
- md5_state_t state;
-#ifndef WIN32
- struct passwd *pwnam;
- struct group *grnam;
-#endif
- FILE *tmp_log;
-
- assert( ARRAY_SIZE(long_options) == ARRAY_SIZE(usage) );
-
- /* set defaults */
- set_options_defaults();
-
- /* parse command line arguments */
- while (1) {
- /* FIXME: We are using '::' (optional argument values). This is not optimal
- * since you have to pass long options as '--option=value'. Commonly used
- * '--option value' is *NOT* allowed for some libc implementations.
- */
- c = getopt_long(argc, argv, "m:p:l:r::R::c:v:L:o::sP:d::Su::g::C::e::h", &long_options[0], &oidx);
- if (c == -1) break;
-
- switch (c) {
- case 'm':
- if (!optarg)
- break;
- opts.magic = strtoul(optarg, NULL, 16);
- break;
- case 'p':
- if (!optarg)
- break;
- opts.mode = kMode_forward;
- if (opts.given_proxy_hostname)
- free(opts.given_proxy_hostname);
- opts.given_proxy_hostname = strdup(optarg);
- break;
- case 'l':
- if (!optarg)
- break;
- opts.tcp_listen_port = strtoul(optarg, NULL, 10);
- break;
- case 'r':
- opts.restrict_dst_ip = 1;
- if (!optarg)
- break;
- if (opts.given_dst_hostname)
- free(opts.given_dst_hostname);
- opts.given_dst_hostname = strdup(optarg);
- break;
- case 'R':
- opts.restrict_dst_port = 1;
- if (optarg)
- opts.given_dst_port = strtoul(optarg, NULL, 10);
- break;
- case 'c':
- if (!optarg)
- break;
- opts.max_tunnels = strtoul(optarg, NULL,10);
- if (opts.max_tunnels > kMax_tunnels)
- opts.max_tunnels = kMax_tunnels;
- break;
- case 'v':
- if (!optarg)
- break;
- opts.log_level = strtol(optarg, NULL, 10);
- break;
- case 'L':
-#ifdef HAVE_PCAP
- opts.pcap = 1;
- if (!optarg)
- break;
- if (opts.pcap_device)
- free(opts.pcap_device);
- opts.pcap_device = strdup(optarg);
- break;
-#else
- pt_log(kLog_error, "pcap: %s\n", "feature not supported");
- exit(1);
-#endif
- case 'o':
- has_logfile = 1;
- if (!optarg)
- break;
- if (opts.log_path)
- free(opts.log_path);
- opts.log_path = strdup(optarg);
- break;
- case 's':
- opts.print_stats = !opts.print_stats;
- break;
- case 'P':
- if (!optarg)
- break;
- if (opts.password)
- free(opts.password);
- opts.password = strdup(optarg);
- pt_log(kLog_debug, "%s\n", "Password set - unauthenicated connections will be refused.");
- /* Compute the md5 password digest */
- md5_init(&state);
- md5_append(&state, (md5_byte_t *)optarg, strnlen(opts.password, BUFSIZ /* not optimal */));
- md5_finish(&state, &opts.md5_password_digest[0]);
-#ifdef ENABLE_SHA512
- pt_log(kLog_debug, "%s\n", "Password set - sha512 authentication enabled.");
- SHA512((const unsigned char *)optarg, strnlen(opts.password, BUFSIZ /* not optimal */), &opts.sha512_password_digest[0]);
-#endif
- // Hide the password in process listing
- memset(optarg, '*', strnlen(optarg, BUFSIZ /* not optimal */));
- break;
-#ifndef WIN32
- case 'd':
- opts.daemonize = true;
- if (!optarg)
- break;
- if (opts.pid_path)
- free(opts.pid_path);
- opts.pid_path = strdup(optarg);
- break;
- case 'S':
- opts.use_syslog = 1;
- break;
- case 'u':
- if (!optarg)
- break;
- errno = 0;
- if (NULL == (pwnam = getpwnam(optarg))) {
- pt_log(kLog_error, "%s: %s\n", optarg, errno ? strerror(errno) : "unknown user");
- exit(1);
- }
- opts.uid = pwnam->pw_uid;
- if (!opts.gid)
- opts.gid = pwnam->pw_gid;
- break;
- case 'g':
- if (!optarg)
- break;
- errno = 0;
- if (NULL == (grnam = getgrnam(optarg))) {
- pt_log(kLog_error, "%s: %s\n", optarg, errno ? strerror(errno) : "unknown group");
- exit(1);
- }
- opts.gid = grnam->gr_gid;
- break;
- case 'C':
- opts.chroot = 1;
- if (!optarg)
- break;
- if (opts.root_dir)
- free(opts.root_dir);
- opts.root_dir = strdup(optarg);
- break;
-#else
- case 'd':
- case 'S':
- case 'u':
- case 'g':
- case 'C':
- pt_log(kLog_error, "-%c: %s\n", c, "feature not supported");
- exit(1);
-#endif
- case 'e':
-#ifdef HAVE_SELINUX
- opts.selinux = 1;
- if (!optarg)
- break;
- if (opts.selinux_context)
- free(opts.selinux_context);
- opts.selinux_context = strdup(optarg);
- break;
-#else
- pt_log(kLog_error, "SeLinux: %s\n", "feature not supported");
- exit(1);
-#endif
- case 'h':
- print_usage(argv[0]);
- exit(EXIT_SUCCESS);
- case 0: /* long opt only */
- default:
- break;
- }
- }
-
- if (optind != argc) {
- pt_log(kLog_error, "Unknown argument: '%s'\n", argv[optind]);
- exit(1);
- }
-
-#ifndef ENABLE_SHA512
- if (opts.force_sha512) {
- pt_log(kLog_error, "%s\n", "You are forcing sha512 but it isn't available.");
- return 1;
- }
-#endif
-
- if (opts.given_proxy_hostname) {
- if ((ret = host_to_addr(opts.given_proxy_hostname, &opts.given_proxy_ip)) != 0) {
- pt_log(kLog_error, "Failed to look up %s as destination address: %s\n",
- opts.given_proxy_hostname, gai_strerror(ret));
- return 1;
- }
- }
-
- if ((ret = host_to_addr(opts.given_dst_hostname, &opts.given_dst_ip)) != 0) {
- pt_log(kLog_error, "Failed to look up %s as destination address: %s\n",
- opts.given_dst_hostname, gai_strerror(ret));
- return 1;
- }
-
-#ifndef WIN32
- if (NULL == (opts.pid_file = fopen(opts.pid_path, "w")))
- pt_log(kLog_error, "Failed to open pidfile: \"%s\", Cause: %s\n", opts.pid_path, strerror(errno));
-#endif
-
- if (has_logfile && opts.log_path) {
- pt_log(kLog_info, "Open Logfile: \"%s\"\n", opts.log_path);
- tmp_log = fopen(opts.log_path, "a");
- if (!tmp_log) {
- pt_log(kLog_error, "Failed to open log file: \"%s\", Cause: %s\n", opts.log_path, strerror(errno));
- pt_log(kLog_error, "Reverting log to standard out.\n");
- } else opts.log_file = tmp_log;
- }
-
- return 0;
-}