summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2017-12-12 00:17:40 +0100
committerToni Uhlig <matzeton@googlemail.com>2017-12-12 00:17:40 +0100
commit8cb97f22fec130583b245326faee023fc4cfcd8f (patch)
tree5c7f4633039d1ae81344048bb69acd7dd25170ad
parent2c5bf52173f92ce1f7cad8ba793290dc9dfa0bdd (diff)
ptunnel-ng:
* options parsing
-rw-r--r--options.c109
-rw-r--r--options.h9
-rw-r--r--ptunnel.c76
3 files changed, 119 insertions, 75 deletions
diff --git a/options.c b/options.c
index 6a47098..bc15e76 100644
--- a/options.c
+++ b/options.c
@@ -31,51 +31,64 @@ struct option_usage {
};
static const struct option_usage usage[] = {
+ /** --magic */
{"magic", 0, OPT_HEX32, {.unum = 0xdeadc0de},
"Set ptunnel magic hexadecimal number. (32-bit unsigned)\n"
- "This will be prefixed in all ICMP packets\n"
- "and can be used to bypass Cisco IPS\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"
},
- {"address", 1, OPT_DEC32, {.unum = 0},
+ /** --proxy */
+ {"address", 1, OPT_DEC32, {.unum = 0},
"Set address of peer running packet forwarder. This causes\n"
"ptunnel to operate in forwarding mode - the absence of this\n"
"option causes ptunnel to operate in proxy mode.\n"
},
+ /** --listen */
{"port", 1, OPT_DEC32, {.unum = 2222},
"Set TCP listening port (only used when operating in forward mode)\n"
},
+ /** --remote-adr */
{"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"
},
- {"interface", 0, OPT_STR, {.str = "eth0"},
+ /** --libpcap */
+ {"interface", 0, OPT_STR, {.str = "eth0"},
"Enable libpcap on the given device.\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 password (must be same on client and proxy)\n"
"If no password is set, you will be asked during runtime.\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"
@@ -83,28 +96,35 @@ static const struct option_usage usage[] = {
"than running in privileged mode.\n"
},
#ifndef WIN32
- {NULL, 0, OPT_BOOL, {.num = 0},
+ /** --daemon */
+ {"pidfile", 0, OPT_STR, {.str = "/run/ptunnel.pid"},
"Run in background, the PID will be written in the file supplied as argument\n"
},
+ /** --syslog */
{NULL, 0, OPT_BOOL, {.num = 0},
"Output debug to syslog instead of standard out.\n"
},
+ /** --user */
{"user", 0, OPT_STR, {.str = "nobody"},
"When started in privileged mode, drop down to user's rights as soon as possible\n"
},
+ /** --group */
{"group", 0, OPT_STR, {.str = "nogroup"},
"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"},
"When started in privileged mode, restrict file access to the specified directory\n"
},
#endif
#ifdef HAVE_SELINUX
- {NULL, 0, OPT_BOOL, {.num = 0},
+ /** --setcon */
+ {NULL, 0, OPT_STR, {.num = 0},
"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"
},
#endif
+ /** --help */
{"help", 0, OPT_STR, {.str = NULL}, "this\n"},
{NULL,0,OPT_BOOL,{.unum=0},NULL}
};
@@ -124,11 +144,11 @@ static struct option long_options[] = {
{"udp", no_argument, &opts.udp, 1 },
{"unprivileged", no_argument, &opts.unprivileged, 1 },
#ifndef WIN32
- {"daemon", no_argument, 0, 'd'},
+ {"daemon", optional_argument, 0, 'd'},
{"syslog", no_argument, 0, 'S'},
- {"user", required_argument, 0, 'u'},
- {"group", required_argument, 0, 'g'},
- {"chroot", required_argument, 0, 't'},
+ {"user", optional_argument, 0, 'u'},
+ {"group", optional_argument, 0, 'g'},
+ {"chroot", optional_argument, 0, 'C'},
#endif
#ifdef HAVE_SELINUX
{"setcon", no_argument, 0, 'e'},
@@ -172,6 +192,8 @@ static void set_options_defaults(void) {
opts.udp = *(int *) get_default_optval(OPT_BOOL, "udp");
opts.unprivileged = *(int *) get_default_optval(OPT_BOOL, "unprivileged");
#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)))
@@ -188,6 +210,8 @@ static void set_options_defaults(void) {
pt_log(kLog_error, "%s: %s\n", tmp, errno ? strerror(errno) : "unknown group");
else
opts.gid = grnam->gr_gid;
+
+ opts.root_dir = strdup(*(char **)get_default_optval(OPT_STR, "chroot"));
#endif
}
@@ -303,7 +327,7 @@ int parse_options(int argc, char **argv) {
/* parse command line arguments */
while (1) {
- c = getopt_long(argc, argv, "m:p:l::r::R::c:v:a:o::sdSx:u::g::t:eh", &long_options[0], &optind);
+ c = getopt_long(argc, argv, "m:p:l::r::R::c:v:a::o::sd::Sx:u::g::C::eh", &long_options[0], &optind);
if (c == -1) break;
switch (c) {
@@ -312,19 +336,20 @@ int parse_options(int argc, char **argv) {
break;
case 'p':
opts.mode = kMode_forward;
- if (NULL == (host_ent = gethostbyname(optarg))) {
- pt_log(kLog_error, "Failed to look up %s as proxy address\n", optarg);
- return 1;
- }
- opts.given_proxy_ip = *(uint32_t*)host_ent->h_addr_list[0];
+ if (opts.given_proxy_hostname)
+ free(opts.given_proxy_hostname);
+ opts.given_proxy_hostname = strdup(optarg);
break;
case 'l':
if (optarg)
opts.tcp_listen_port = strtoul(optarg, NULL, 10);
break;
case 'r':
- if (optarg)
- opts.given_dst_hostname = strdup(optarg);
+ if (!optarg)
+ break;
+ if (opts.given_dst_hostname)
+ free(opts.given_dst_hostname);
+ opts.given_dst_hostname = strdup(optarg);
break;
case 'R':
if (optarg)
@@ -339,22 +364,27 @@ int parse_options(int argc, char **argv) {
opts.log_level = strtol(optarg, NULL, 10);
break;
case 'a':
+ opts.pcap = 1;
+ if (!optarg)
+ break;
if (opts.pcap_device)
free(opts.pcap_device);
opts.pcap_device = strdup(optarg);
break;
case 'o':
- if (optarg) {
- if (opts.log_path)
- free(opts.log_path);
- opts.log_path = strdup(optarg);
- }
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 'x':
+ if (opts.password)
+ free(opts.password);
opts.password = strdup(optarg);
pt_log(kLog_debug, "Password set - unauthenicated connections will be refused.\n");
// Compute the password digest
@@ -367,8 +397,11 @@ int parse_options(int argc, char **argv) {
#ifndef WIN32
case 'd':
opts.daemonize = true;
- if (NULL == (opts.pid_file = fopen(optarg, "w")))
- pt_log(kLog_error, "%s: %s\n", optarg, strerror(errno));
+ if (!optarg)
+ break;
+ if (opts.pid_path)
+ free(opts.pid_path);
+ opts.pid_path = strdup(optarg);
break;
case 'S':
opts.use_syslog = 1;
@@ -395,7 +428,12 @@ int parse_options(int argc, char **argv) {
}
opts.gid = grnam->gr_gid;
break;
- case 't':
+ case 'C':
+ opts.chroot = 1;
+ if (!optarg)
+ break;
+ if (opts.root_dir)
+ free(opts.root_dir);
opts.root_dir = strdup(optarg);
break;
#else
@@ -404,34 +442,45 @@ int parse_options(int argc, char **argv) {
case 'u':
case 'g':
case 't':
- pt_log(kLog_error, "%s: feature not supported\n", optarg);
+ pt_log(kLog_error, "%s: feature not supported\n", argv[optind - 1]);
exit(1);
#endif
case 'e':
#ifdef HAVE_SELINUX
+ if (opts.selinux_context)
+ free(opts.selinux_context);
opts.selinux_context = strdup(optarg);
break;
#else
- pt_log(kLog_error, "%s: feature not supported\n", optarg);
+ pt_log(kLog_error, "%s: feature not supported\n", argv[optind - 1]);
exit(1);
#endif
case 'h':
print_usage(argv[0]);
_exit(EXIT_SUCCESS);
case 0: /* long opt only */
- break;
default:
- pt_log(kLog_error, "\"%s\": option unknown\n", argv[optind - 1]);
break;
}
}
+ if (opts.given_proxy_hostname) {
+ if (NULL == (host_ent = gethostbyname(opts.given_proxy_hostname))) {
+ pt_log(kLog_error, "Failed to look up %s as proxy address\n", opts.given_proxy_hostname);
+ return 1;
+ }
+ opts.given_proxy_ip = *(uint32_t*)host_ent->h_addr_list[0];
+ }
+
if (NULL == (host_ent = gethostbyname(opts.given_dst_hostname))) {
pt_log(kLog_error, "Failed to look up %s as destination address\n", opts.given_dst_hostname);
return 1;
}
opts.given_dst_ip = *(uint32_t*)host_ent->h_addr_list[0];
+ 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));
+
if (has_logfile && opts.log_path) {
pt_log(kLog_info, "Open Logfile: \"%s\"\n", opts.log_path);
tmp_log = fopen(opts.log_path, "a");
diff --git a/options.h b/options.h
index 564f1a9..34dfe9b 100644
--- a/options.h
+++ b/options.h
@@ -20,6 +20,7 @@ struct options {
/** proxy or forwarder? */
int mode;
/** Proxy's internet address */
+ char *given_proxy_hostname;
uint32_t given_proxy_ip;
/** Port the client listens on */
uint32_t tcp_listen_port;
@@ -32,6 +33,8 @@ struct options {
uint32_t max_tunnels;
/** Default log level */
int log_level;
+ /** Non zero value if user wants packet capturing */
+ int pcap;
/** Device to capture packets from */
char *pcap_device;
/** Usually stdout, but can be altered by the user */
@@ -51,6 +54,9 @@ struct options {
#ifndef WIN32
/** run as daemon if non zero value */
int daemonize;
+ /** PIDFILE if running as daemon */
+ char *pid_path;
+ FILE *pid_file;
/** log to syslog if non zero value */
int use_syslog;
/** UID of the running process */
@@ -58,9 +64,8 @@ struct options {
/** GID of the running process */
gid_t gid;
/** CHROOT dir */
+ int chroot;
char *root_dir;
- /** PIDFILE */
- FILE *pid_file;
#endif
#ifdef HAVE_SELINUX
diff --git a/ptunnel.c b/ptunnel.c
index f377306..7bbc9f3 100644
--- a/ptunnel.c
+++ b/ptunnel.c
@@ -43,6 +43,9 @@
#include "ptunnel.h"
#include "options.h"
#include "md5.h"
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
#ifdef WIN32
/* pthread porting to windows */
@@ -69,13 +72,6 @@
}
#define strerror(x) print_last_windows_error()
#else
-#ifdef HAVE_SELINUX
- #include <selinux/selinux.h>
- static char *selinux_context = NULL;
-#endif
- static char *root_dir = NULL;
- static bool daemonize = false;
- static FILE *pid_file = NULL;
#endif /* WIN32 */
@@ -83,15 +79,11 @@
pthread_mutex_t
chain_lock, // Lock protecting the chain of connections
num_threads_lock; // Lock protecting the num_threads variable
-bool
- pcap = false; // True if user wants packet capturing
int
num_threads = 0, // Current thread count
num_tunnels = 0; // Current tunnel count
uint32_t
*seq_expiry_tbl = 0; // Table indicating when a connection ID is allowable (used by proxy)
-char
- *pcap_device = 0; // Device to capture packets from
// Some buffer constants
const int
@@ -139,11 +131,12 @@ int main(int argc, char *argv[]) {
seq_expiry_tbl = calloc(65536, sizeof(uint32_t));
// Parse options
- parse_options(argc, argv);
+ if (parse_options(argc, argv))
+ return -1;
- if (pcap && opts.udp) {
+ if (opts.pcap && opts.udp) {
pt_log(kLog_error, "Packet capture is not supported (or needed) when using UDP for transport.\n");
- pcap = 0;
+ opts.pcap = 0;
}
pt_log(kLog_info, "Starting ptunnel v %d.%.2d.\n", kMajor_version, kMinor_version);
pt_log(kLog_info, "(c) 2004-2011 Daniel Stoedle, <daniels@cs.uit.no>\n");
@@ -169,14 +162,14 @@ int main(int argc, char *argv[]) {
}
openlog("ptunnel", LOG_PID, LOG_USER);
}
- if (NULL != root_dir) {
- pt_log(kLog_info, "Restricting file access to %s\n", root_dir);
- if (-1 == chdir(root_dir) || -1 == chroot(root_dir)) {
- pt_log(kLog_error, "%s: %s\n", root_dir, strerror(errno));
+ if (opts.chroot) {
+ pt_log(kLog_info, "Restricting file access to %s\n", opts.root_dir);
+ if (-1 == chdir(opts.root_dir) || -1 == chroot(opts.root_dir)) {
+ pt_log(kLog_error, "%s: %s\n", opts.root_dir, strerror(errno));
exit(1);
}
}
- if (daemonize) {
+ if (opts.daemonize) {
pt_log(kLog_info, "Going to the background.\n");
if (0 < (pid = fork()))
exit(0);
@@ -191,9 +184,9 @@ int main(int argc, char *argv[]) {
if (0 > pid)
pt_log(kLog_error, "fork: %s\n", strerror(errno));
else {
- if (NULL != pid_file) {
- fprintf(pid_file, "%d\n", getpid());
- fclose(pid_file);
+ if (NULL != opts.pid_file) {
+ fprintf(opts.pid_file, "%d\n", getpid());
+ fclose(opts.pid_file);
}
if (! freopen("/dev/null", "r", stdin) ||
! freopen("/dev/null", "w", stdout) ||
@@ -237,18 +230,14 @@ int main(int argc, char *argv[]) {
else
pt_proxy(0);
- // Clean up
- if (opts.log_file != stdout)
- fclose(opts.log_file);
-
#ifdef WIN32
WSACleanup();
#else
- if (NULL != root_dir)
- free(root_dir);
+ if (opts.root_dir)
+ free(opts.root_dir);
#ifdef HAVE_SELINUX
- if (NULL != selinux_context)
- free(selinux_context);
+ if (NULL != opts.selinux_context)
+ free(opts.selinux_context);
#endif
#endif /* WIN32 */
@@ -426,45 +415,46 @@ void* pt_proxy(void *args) {
}
}
max_sock = fwd_sock+1;
- if (pcap) {
+ if (opts.pcap) {
if (opts.udp) {
pt_log(kLog_error, "Packet capture is not useful with UDP [should not get here!]!\n");
close(fwd_sock);
return 0;
}
if (!opts.unprivileged) {
+ memset(&pc, 0, sizeof(pc));
pt_log(kLog_info, "Initializing pcap.\n");
pc.pcap_err_buf = malloc(PCAP_ERRBUF_SIZE);
pc.pcap_data_buf = malloc(pcap_buf_size);
- pc.pcap_desc = pcap_open_live(pcap_device, pcap_buf_size, 0 /* promiscous */, 50 /* ms */, pc.pcap_err_buf);
+ pc.pcap_desc = pcap_open_live(opts.pcap_device, pcap_buf_size, 0 /* promiscous */, 50 /* ms */, pc.pcap_err_buf);
if (pc.pcap_desc) {
- if (pcap_lookupnet(pcap_device, &pc.netp, &pc.netmask, pc.pcap_err_buf) == -1) {
+ if (pcap_lookupnet(opts.pcap_device, &pc.netp, &pc.netmask, pc.pcap_err_buf) == -1) {
pt_log(kLog_error, "pcap error: %s\n", pc.pcap_err_buf);
- pcap = 0;
+ opts.pcap = 0;
}
pt_log(kLog_verbose, "Network: %s\n", inet_ntoa(*(struct in_addr*)&pc.netp));
pt_log(kLog_verbose, "Netmask: %s\n", inet_ntoa(*(struct in_addr*)&pc.netmask));
if (pcap_compile(pc.pcap_desc, &pc.fp, pcap_filter_program, 0, pc.netp) == -1) {
pt_log(kLog_error, "Failed to compile pcap filter program.\n");
pcap_close(pc.pcap_desc);
- pcap = 0;
+ opts.pcap = 0;
}
else if (pcap_setfilter(pc.pcap_desc, &pc.fp) == -1) {
pt_log(kLog_error, "Failed to set pcap filter program.\n");
pcap_close(pc.pcap_desc);
- pcap = 0;
+ opts.pcap = 0;
}
}
else {
pt_log(kLog_error, "pcap error: %s\n", pc.pcap_err_buf);
- pcap = 0;
+ opts.pcap = 0;
}
pc.pkt_q.head = 0;
pc.pkt_q.tail = 0;
pc.pkt_q.elems = 0;
// Check if we have succeeded, and free stuff if not
- if (!pcap) {
+ if (!opts.pcap) {
pt_log(kLog_error, "There were errors enabling pcap - pcap has been disabled.\n");
free(pc.pcap_err_buf);
free(pc.pcap_data_buf);
@@ -487,7 +477,7 @@ void* pt_proxy(void *args) {
#ifndef WIN32
#ifdef HAVE_SELINUX
- if (opts.uid || opts.gid || selinux_context)
+ if (opts.uid || opts.gid || opts.selinux_context)
#else
if (opts.uid || opts.gid)
#endif
@@ -497,8 +487,8 @@ void* pt_proxy(void *args) {
if (opts.uid && -1 == setuid(opts.uid))
pt_log(kLog_error, "setuid(%d): %s\n", opts.uid, strerror(errno));
#ifdef HAVE_SELINUX
- if (NULL != selinux_context && -1 == setcon(selinux_context))
- pt_log(kLog_error, "setcon(%s) failed: %s\n", selinux_context, strerror(errno));
+ if (NULL != opts.selinux_context && -1 == setcon(opts.selinux_context))
+ pt_log(kLog_error, "setcon(%s) failed: %s\n", opts.selinux_context, strerror(errno));
#endif
#endif
@@ -607,7 +597,7 @@ void* pt_proxy(void *args) {
}
}
pthread_mutex_unlock(&chain_lock);
- if (pcap) {
+ if (opts.pcap) {
if (pcap_dispatch(pc.pcap_desc, 32, pcap_packet_handler, (u_char*)&pc.pkt_q) > 0) {
pqueue_elem_t *cur;
//pt_log(kLog_verbose, "pcap captured %d packets - handling them..\n", pc.pkt_q.elems);
@@ -640,7 +630,7 @@ void* pt_proxy(void *args) {
xfer.icmp_resent += cur->xfer.icmp_resent;
}
pthread_mutex_unlock(&chain_lock);
- print_statistics(&xfer, (opts.log_level > kLog_verbose ? 0 : 1));
+ print_statistics(&xfer, (opts.log_level >= kLog_verbose ? 0 : 1));
last_status_update = now;
}
}