summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xmd5.h3
-rw-r--r--options.c151
-rw-r--r--options.h20
-rwxr-xr-xptunnel.c59
-rwxr-xr-xptunnel.h53
5 files changed, 186 insertions, 100 deletions
diff --git a/md5.h b/md5.h
index e2804fe..f9fdeb4 100755
--- a/md5.h
+++ b/md5.h
@@ -62,6 +62,7 @@
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
+#define MD5_LEN 16
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
@@ -82,7 +83,7 @@ void md5_init(md5_state_t *pms);
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
/* Finish the message and return the digest. */
-void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+void md5_finish(md5_state_t *pms, md5_byte_t digest[MD5_LEN]);
#ifdef __cplusplus
} /* end extern "C" */
diff --git a/options.c b/options.c
index ceee3c7..5bb5c99 100644
--- a/options.c
+++ b/options.c
@@ -8,6 +8,11 @@
#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
@@ -90,11 +95,14 @@ static const struct option_usage usage[] = {
{"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, {.unum = 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", 0, OPT_STR, {.str = NULL}, "this\n"},
{NULL,0,OPT_BOOL,{.unum=0},NULL}
};
@@ -105,23 +113,29 @@ static struct option long_options[] = {
{"remote", required_argument, 0, 'r'},
{"connections", required_argument, 0, 'c'},
{"verbosity", required_argument, 0, 'v'},
- {"libpcap", no_argument, 0, 0 },
+ {"libpcap", required_argument, 0, 'a'},
{"logfile", required_argument, 0, 'o'},
{"statistics", no_argument, 0, 's'},
#ifndef WIN32
{"daemon", no_argument, 0, 'd'},
- {"syslog", no_argument, 0, 0 },
+ {"syslog", no_argument, 0, 'S'},
#endif
- {"udp", no_argument, 0, 0 },
- {"passwd", optional_argument, 0, 'x'},
- {"unprivileged", no_argument, 0, 0 },
+ {"udp", no_argument, &opts.udp, 1 },
+ {"passwd", required_argument, 0, 'x'},
+ {"unprivileged", no_argument, &opts.unprivledged, 1 },
+#ifndef WIN32
{"user", required_argument, 0, 'u'},
{"group", required_argument, 0, 'g'},
- {"chroot", optional_argument, 0, 0 },
+ {"chroot", required_argument, 0, 't'},
+#endif
+#ifdef HAVE_SELINUX
{"setcon", no_argument, 0, 'e'},
+#endif
+ {"help", no_argument, 0, 'h'},
{NULL,0,0,0}
};
+
static void print_multiline(const char *prefix, const char *multiline) {
const char sep[] = "\n";
const char *start, *end;
@@ -200,7 +214,7 @@ void print_usage(const char *arg0) {
assert( ARRAY_SIZE(long_options) == ARRAY_SIZE(usage) );
- printf("ptunnel-ng v%d.%.2d.\n\nUsage: %s", 12, 22, arg0);
+ printf("ptunnel-ng v%d.%.2d\n\nUsage: %s", kMajor_version, kMinor_version, arg0);
/* print (short)help argument line */
for (i = 0; i < ARRAY_SIZE(usage); ++i) {
print_short_help(i, 1);
@@ -217,10 +231,129 @@ void print_usage(const char *arg0) {
for (i = 0; i < ARRAY_SIZE(usage); ++i) {
print_long_help(i, 0);
}
-
-_exit(0);
}
int parse_options(int argc, char **argv) {
+ int c = 0, optind = -1;
+ struct hostent *host_ent;
+ md5_state_t state;
+#ifndef WIN32
+ struct passwd *pwnam;
+ struct group *grnam;
+#endif
+
+ while (1) {
+ c = getopt_long(argc, argv, "m:p:l:r:c:v:a:o:sdSx:u:g:t:eh", &long_options[0], &optind);
+ if (c == -1) break;
+
+ switch (c) {
+ case 'm':
+ opts.magic = strtoul(optarg, NULL, 16);
+ break;
+ case 'p':
+ 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];
+ break;
+ case 'l':
+ opts.tcp_listen_port = strtoul(optarg, NULL, 10);
+ break;
+ case 'r':
+ if (NULL == (host_ent = gethostbyname(optarg))) {
+ pt_log(kLog_error, "Failed to look up %s as destination address\n", optarg);
+ return 1;
+ }
+ opts.given_dst_ip = *(uint32_t*)host_ent->h_addr_list[0];
+ break;
+ case 'c':
+ opts.max_tunnels = strtoul(optarg, NULL,10);
+ if (opts.max_tunnels > kMax_tunnels)
+ opts.max_tunnels = kMax_tunnels;
+ break;
+ case 'v':
+ opts.log_level = strtoul(optarg, NULL, 10);
+ break;
+ case 'a':
+ opts.pcap_device = strdup(optarg);
+ break;
+ case 'o':
+ opts.log_file = fopen(optarg, "a");
+ if (!opts.log_file) {
+ opts.log_file = stdout;
+ pt_log(kLog_error, "Failed to open log file: '%s'. Cause: % s\n", optarg, strerror(errno));
+ pt_log(kLog_error, "Reverting log to standard out.\n");
+ }
+ break;
+ case 's':
+ opts.print_stats = !opts.print_stats;
+ break;
+ case 'x':
+ opts.password_digest = (unsigned char *)calloc(MD5_LEN, sizeof(unsigned char));
+ pt_log(kLog_debug, "Password set - unauthenicated connections will be refused.\n");
+ // Compute the password digest
+ md5_init(&state);
+ md5_append(&state, (md5_byte_t*)optarg, strlen(optarg));
+ md5_finish(&state, opts.password_digest);
+ // Hide the password in process listing
+ memset(optarg, '*', strlen(optarg));
+ break;
+#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));
+ break;
+ case 'S':
+ opts.syslog = 1;
+ break;
+ case 'u':
+ 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':
+ 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 't':
+ opts.root_dir = strdup(optarg);
+ break;
+#else
+ case 'd':
+ case 'S':
+ case 'U':
+ case 'g':
+ case 't':
+ pt_log(kLog_error, "%s: feature not supported", optarg);
+ exit(1);
+#endif
+ case 'e':
+#ifdef HAVE_SELINUX
+ opts.selinux_context = strdup(optarg);
+ break;
+#else
+ pt_log(kLog_error, "%s: feature not supported", optarg);
+ exit(1);
+#endif
+ case 'h':
+ print_usage(argv[0]);
+ _exit(EXIT_SUCCESS);
+ default:
+ printf("Opt ERROR\n");
+ break;
+ }
+ }
+
return 0;
}
diff --git a/options.h b/options.h
index ad33e97..03b5e20 100644
--- a/options.h
+++ b/options.h
@@ -15,10 +15,10 @@ struct options {
uint32_t magic;
/** Proxy's internet address */
uint32_t given_proxy_ip;
- /** Password (must be the same on proxy and client for authentication to succeed) */
- char password;
+ /** Password-Digest (must be the same on proxy and client for authentication to succeed) */
+ unsigned char *password_digest;
/** Port the client listens on */
- int tcp_listen_port;
+ uint16_t tcp_listen_port;
/** Proxy's internet address */
uint32_t given_dst_ip;
/** Port to send data to from the proxy */
@@ -29,15 +29,19 @@ struct options {
int log_level;
/** Device to capture packets from */
char *pcap_device;
- /** True if user wants packet capturing */
- bool pcap;
/** Usually stdout, but can be altered by the user */
FILE *log_file;
+ /** Print more detailed traffic statistics if non zero value */
+ int print_stats;
+ /** use UDP instead of ICMP */
+ int udp;
+ /** unpriviledged mode */
+ int unprivledged;
-#ifndef WIN32
#ifdef HAVE_SELINUX
char *selinux_context;
#endif
+#ifndef WIN32
/** UID of the running process */
uid_t uid;
/** GID of the running process */
@@ -45,9 +49,11 @@ struct options {
/** CHROOT dir */
char *root_dir;
/** PIDFILE */
- char *pid_file;
+ FILE *pid_file;
/** run as daemon */
bool daemonize;
+ /** log to syslog if non zero value */
+ int syslog;
#endif
};
diff --git a/ptunnel.c b/ptunnel.c
index 8244a38..40ae9d2 100755
--- a/ptunnel.c
+++ b/ptunnel.c
@@ -165,6 +165,8 @@ int main(int argc, char *argv[]) {
log_file = stdout;
// Parse options
+ parse_options(argc, argv);
+
opt = kOpt_undefined;
mode = kMode_proxy;
for (i=1;i<argc;i++) {
@@ -303,14 +305,14 @@ int main(int argc, char *argv[]) {
break;
#endif /* !WIN32 */
case kOpt_undefined:
- usage(argv[0]);
+ print_usage(argv[0]);
return 1;
}
opt = kOpt_undefined;
}
}
if (opt != kOpt_undefined) {
- usage(argv[0]);
+ print_usage(argv[0]);
exit(1);
}
if (pcap && use_udp) {
@@ -398,7 +400,7 @@ int main(int argc, char *argv[]) {
if (mode == kMode_forward) {
if (!given_proxy_ip || !given_dst_ip || !tcp_port || !tcp_listen_port) {
printf("One of the options are missing or invalid.\n");
- usage(argv[0]);
+ print_usage(argv[0]);
return -1;
}
pt_forwarder();
@@ -425,57 +427,6 @@ int main(int argc, char *argv[]) {
return 0;
}
-
-void usage(char *exec_name) {
-print_usage(exec_name);
- printf("ptunnel v %d.%.2d.\n", kMajor_version, kMinor_version);
- printf("Usage: %s -p <addr> -lp <port> -da <dest_addr> -dp <dest_port> [-m max_tunnels] [-v verbosity] [-f logfile]\n", exec_name);
- printf(" %s [-m max_threads] [-v verbosity] [-c <device>]\n", exec_name);
- printf(" -a: Set ICMP Tunnel magic hexadecimal number e.g. %X\n", magic);
- printf(" -p: Set address of peer running packet forwarder. This causes\n");
- printf(" ptunnel to operate in forwarding mode - the absence of this\n");
- printf(" option causes ptunnel to operate in proxy mode.\n");
- printf(" -lp: Set TCP listening port (only used when operating in forward mode)\n");
- printf(" -da: Set remote proxy destination address if client\n");
- printf(" Restrict to only this destination address if server\n");
- printf(" -dp: Set remote proxy destionation port if client\n");
- printf(" Restrict to only this destination port if server\n");
- printf(" -m: Set maximum number of concurrent tunnels\n");
- printf(" -v: Verbosity level (-1 to 4, where -1 is no output, and 4 is all output)\n");
- printf(" -c: Enable libpcap on the given device.\n");
- printf(" -f: Specify a file to log to, rather than printing to standard out.\n");
- printf(" -s: Client only. Enables continuous output of statistics (packet loss, etc.)\n");
- #ifndef WIN32
- printf("-daemon: Run in background, the PID will be written in the file supplied as argument\n");
- printf("-syslog: Output debug to syslog instead of standard out.\n");
- #endif /* !WIN32 */
- printf(" -udp: Toggle use of UDP instead of ICMP. Proxy will listen on port 53 (must be root).\n\n");
-
- printf("Security features: [-x password] [-u] [-setuid user] [-setgid group] [-chroot dir]\n");
- printf(" -x: Set password (must be same on client and proxy)\n");
- printf(" -u: Run proxy in unprivileged mode. This causes the proxy to forward\n");
- printf(" packets using standard echo requests, instead of crafting custom echo replies.\n");
- printf(" Unprivileged mode will only work on some systems, and is in general less reliable\n");
- printf(" than running in privileged mode.\n");
- #ifndef WIN32
- printf(" Please consider combining the following three options instead:\n");
- printf("-setuid: When started in privileged mode, drop down to user's rights as soon as possible\n");
- printf("-setgid: When started in privileged mode, drop down to group's rights as soon as possible\n");
- printf("-chroot: When started in privileged mode, restrict file access to the specified directory\n");
- printf("-setcon: Set SELinux context when all there is left to do are network I/O operations\n");
- printf(" To combine with -chroot you will have to `mount --bind /proc /chrootdir/proc`\n");
- #endif /* !WIN32 */
-
- printf("\nStarting the proxy (needs to run as root):\n");
- printf(" [root #] %s\n", exec_name);
- printf("Starting a client (also needs root):\n");
- printf(" [root #] %s -p proxy.pingtunnel.com -lp 8000 -da login.domain.com -dp 22 -c eth0\n", exec_name);
- printf("And then using the tunnel to ssh to login.domain.com:\n");
- printf(" [user $] ssh -p 8000 localhost\n");
- printf("And that's it. Enjoy your tunnel!\n\n");
-}
-
-
/* pt_forwarder:
Sets up a listening TCP socket, and forwards incoming connections
over ping packets.
diff --git a/ptunnel.h b/ptunnel.h
index f6a2044..26dd36d 100755
--- a/ptunnel.h
+++ b/ptunnel.h
@@ -45,32 +45,33 @@
// Includes
#ifndef WIN32
-#include <sys/unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <pthread.h>
-#include <errno.h>
-#include <net/ethernet.h>
-#include <syslog.h>
-#include <pwd.h>
-#include <grp.h>
+#include <sys/unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <errno.h>
+#include <net/ethernet.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <grp.h>
#endif /* !WIN32 */
-#include <stdarg.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <sys/time.h>
-#include <signal.h>
-#include <stdint.h>
-#include <pcap.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <pcap.h>
#ifdef WIN32
-#include <winsock2.h>
+#include <winsock2.h>
typedef int socklen_t;
typedef uint32_t in_addr_t;
#define ETH_ALEN 6 /* Octets in one ethernet addr */
@@ -81,11 +82,6 @@ struct ether_header {
};
#endif /* WIN32 */
-// Constants
-#define false 0
-#define true 1
-#define bool char
-
enum {
kOpt_undefined = 0, // Constants for parsing options
kOpt_set_magic,
@@ -427,7 +423,6 @@ typedef struct {
// Prototypes (sorry about the long lines..)
- void usage(char *exec_name);
void* pt_proxy(void *args);
void pcap_packet_handler(u_char *refcon, const struct pcap_pkthdr *hdr, const u_char* pkt);
void handle_packet(char *buf, int bytes, int is_pcap, struct sockaddr_in *addr, int icmp_sock);