aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml21
-rw-r--r--.travis.yml35
-rw-r--r--PKGBUILD4
-rw-r--r--README2
-rw-r--r--README.md3
-rw-r--r--configure.ac13
-rw-r--r--src/Makefile.am11
-rw-r--r--src/challenge.c51
-rw-r--r--src/challenge.h41
-rw-r--r--src/options.c55
-rw-r--r--src/options.h10
-rw-r--r--src/pconfig.h2
-rw-r--r--src/pkt.c33
-rw-r--r--src/pkt.h3
-rw-r--r--src/ptunnel.c40
-rw-r--r--src/utils.c2
16 files changed, 236 insertions, 90 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8b29b77..7c51609 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -12,12 +12,15 @@ before_script:
- test ! -r /etc/arch-release || pacman -Sy archlinux-keyring --noconfirm
- test ! -r /etc/arch-release || pacman -Syu --noconfirm
- test ! -r /etc/arch-release || pacman -S --noconfirm binutils gcc base-devel git
+ - mkdir -p ./deploy/gcc ./deploy/i686-w64-mingw32-winpcap ./deploy/i686-w64-mingw32-npcap ./deploy/clang ./deploy/android28-clang
build:
script:
- autoreconf -fi
- - ./configure --prefix=/
- - make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy)" V=s
+ - ./configure --enable-option-checking=fatal --prefix=/
+ - make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/gcc)" V=s
+ - make dist
+ - cp ptunnel-ng-*.tar.gz ./deploy/
stage: build
artifacts:
paths:
@@ -47,8 +50,10 @@ build-archlinux:
build-mingw:
script:
- autoreconf -fi
- - ./configure --prefix=/ --host=i686-w64-mingw32
- - make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy)" V=s
+ - ./configure --enable-option-checking=fatal --prefix=/ --host=i686-w64-mingw32
+ - make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/i686-w64-mingw32-winpcap)" V=s
+ - ./configure --enable-option-checking=fatal --prefix=/ --host=i686-w64-mingw32 --enable-npcap
+ - make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/i686-w64-mingw32-npcap)" V=s
stage: build
artifacts:
paths:
@@ -59,8 +64,8 @@ build-mingw:
build-clang:
script:
- autoreconf -fi
- - CC=clang ./configure --prefix=/
- - make install CFLAGS='-Werror -Wno-error=for-loop-analysis' DESTDIR="$(realpath ./deploy)" V=s
+ - CC=clang ./configure --enable-option-checking=fatal --prefix=/
+ - make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/clang)" V=s
stage: build
artifacts:
paths:
@@ -79,8 +84,8 @@ build-android:
- test -d 'android-ndk-r19' || unzip -q 'android-ndk-r19-linux-x86_64.zip'
- cd ..
- autoreconf -fi
- - CC=aarch64-linux-android28-clang PATH="${PATH}:$(realpath ./vendor/android-ndk-r19/toolchains/llvm/prebuilt/linux-x86_64/bin)" ./configure --host=aarch64-linux-android
- - PATH="${PATH}:$(realpath ./vendor/android-ndk-r19/toolchains/llvm/prebuilt/linux-x86_64/bin)" make install CFLAGS='-Werror -Wno-error=for-loop-analysis' DESTDIR="$(realpath ./deploy)" V=s
+ - CC=aarch64-linux-android28-clang PATH="${PATH}:$(realpath ./vendor/android-ndk-r19/toolchains/llvm/prebuilt/linux-x86_64/bin)" ./configure --enable-option-checking=fatal --host=aarch64-linux-android
+ - PATH="${PATH}:$(realpath ./vendor/android-ndk-r19/toolchains/llvm/prebuilt/linux-x86_64/bin)" make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/android28-clang)" V=s
stage: build
artifacts:
paths:
diff --git a/.travis.yml b/.travis.yml
index 20c9c90..630d2bb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,34 +4,47 @@ before_install:
- sudo apt-get install -y git debhelper dpkg-dev build-essential fakeroot flawfinder wget unzip realpath
- sudo apt-get install -y libpcap-dev libselinux1-dev
- sudo apt-get install -y binutils-mingw-w64-i686 gcc-mingw-w64 mingw-w64-i686-dev mingw-w64-common clang
+- sudo apt-get install -y binutils-mingw-w64-x86-64 mingw-w64-x86-64-dev
- sudo apt-get install -y autoconf automake dh-autoreconf
after_failure:
- cat config.log
script:
-- mkdir -p ./deploy
+- mkdir -p ./deploy ./deploy/gcc ./deploy/mingw-w64-i386-winpcap ./deploy/mingw-w64-i386-npcap ./deploy/mingw-w64-x86_64-winpcap ./deploy/mingw-w64-x86_64-npcap ./deploy/clang ./deploy/android28-clang
# default gcc build
- autoreconf -fi
-- ./configure --prefix=/
-- make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy)" V=s
+- ./configure --enable-option-checking=fatal --prefix=/
+- make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/gcc)" V=s
- make clean
# debian build
- dpkg-buildpackage -b -us -uc
- make clean
-# mingw-w64 build
-- CC=i686-w64-mingw32-gcc ./configure --prefix=/ --host=i686-w64-mingw32
-- make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy)" V=s
+# mingw-w64-i386 build (WinPcap)
+- CC=i686-w64-mingw32-gcc ./configure --enable-option-checking=fatal --prefix=/ --host=i686-w64-mingw32
+- make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/mingw-w64-i386-winpcap)" V=s
+- make clean
+# mingw-w64-i386 build (Npcap)
+- CC=i686-w64-mingw32-gcc ./configure --enable-option-checking=fatal --prefix=/ --host=i686-w64-mingw32 --enable-npcap
+- make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/mingw-w64-i386-npcap)" V=s
+- make clean
+# mingw-w64-x86_64 build (WinPcap)
+- CC=x86_64-w64-mingw32-gcc ./configure --enable-option-checking=fatal --prefix=/ --host=x86_64-w64-mingw32
+- make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/mingw-w64-x86_64-winpcap)" V=s
+- make clean
+# mingw-w64-x86_64 build (Npcap)
+- CC=x86_64-w64-mingw32-gcc ./configure --enable-option-checking=fatal --prefix=/ --host=x86_64-w64-mingw32 --enable-npcap
+- make install CFLAGS='-Werror' DESTDIR="$(realpath ./deploy/mingw-w64-x86_64-npcap)" V=s
- make clean
# clang build
-- CC=clang ./configure --prefix=/
-- make install CFLAGS='-Werror -Wno-error=for-loop-analysis' DESTDIR="$(realpath ./deploy)" V=s
+- CC=clang ./configure --enable-option-checking=fatal --prefix=/
+- make install CFLAGS='-Werror -Wno-error=for-loop-analysis' DESTDIR="$(realpath ./deploy/clang)" V=s
- make clean
# android build
- mkdir -p vendor && cd vendor
- test -r 'android-ndk-r19-linux-x86_64.zip' || wget --progress=dot:mega 'https://dl.google.com/android/repository/android-ndk-r19-linux-x86_64.zip'
- test -d 'android-ndk-r19' || unzip -q 'android-ndk-r19-linux-x86_64.zip'
- cd ..
-- CC=aarch64-linux-android28-clang PATH="${PATH}:$(realpath ./vendor/android-ndk-r19/toolchains/llvm/prebuilt/linux-x86_64/bin)" ./configure --host=aarch64-linux-android
-- PATH="${PATH}:$(realpath ./vendor/android-ndk-r19/toolchains/llvm/prebuilt/linux-x86_64/bin)" make install CFLAGS='-Werror -Wno-error=for-loop-analysis' DESTDIR="$(realpath ./deploy)" V=s
+- CC=aarch64-linux-android28-clang PATH="${PATH}:$(realpath ./vendor/android-ndk-r19/toolchains/llvm/prebuilt/linux-x86_64/bin)" ./configure --enable-option-checking=fatal --host=aarch64-linux-android
+- PATH="${PATH}:$(realpath ./vendor/android-ndk-r19/toolchains/llvm/prebuilt/linux-x86_64/bin)" make install CFLAGS='-Werror -Wno-error=for-loop-analysis' DESTDIR="$(realpath ./deploy/android28-clang)" V=s
# archlinux build
# see: https://wiki.archlinux.org/index.php/Install_from_existing_Linux#Method_A:_Using_the_bootstrap_image_(recommended)
#- wget --progress=dot:mega 'https://ftp.fau.de/archlinux/iso/2019.02.01/archlinux-bootstrap-2019.02.01-x86_64.tar.gz'
@@ -58,6 +71,6 @@ addons:
project:
name: lnslbrty/ptunnel-ng
notification_email: matzeton@googlemail.com
- build_command_prepend: autoreconf -i && ./configure
+ build_command_prepend: autoreconf -i && ./configure --enable-option-checking=fatal
build_command: make
branch_pattern: coverity_scan
diff --git a/PKGBUILD b/PKGBUILD
index 5279f40..74bf25b 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -1,5 +1,5 @@
pkgname="ptunnel-ng"
-pkgver=1.32
+pkgver=1.42
pkgrel=1
pkgdesc="A TCP forwarder and proxy used for ICMP/UDP tunneling without creating tun devices. (Ping Tunnel, ICMP Echo Tunnel, UDP Tunnel)"
arch=('i686' 'x86_64')
@@ -8,7 +8,7 @@ license=('BSD-3')
makedepends=('git')
provides=("ptunnel-ng=${pkgver}")
source=("https://github.com/lnslbrty/ptunnel-ng/archive/v${pkgver}.tar.gz")
-md5sums=('cbb9a17ed0ac728170e03f4fa618a617')
+md5sums=('b7741527a7833bc06130ea67502ae21a')
build() {
cd "${srcdir}/${pkgname}-${pkgver}"
diff --git a/README b/README
index 6092f15..c11df67 100644
--- a/README
+++ b/README
@@ -123,7 +123,7 @@ installed.
TODOs
-----
-- challenge response: switch from md5 to sha-512
+- challenge response: switch from md5 to sha-512 (WiP)
- packet obfuscation
- encryption (metadata + payload)
diff --git a/README.md b/README.md
index 5e79e4f..a3314ea 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
[![Travis Build Status](https://travis-ci.org/lnslbrty/ptunnel-ng.svg?branch=coverity_scan)](https://travis-ci.org/lnslbrty/ptunnel-ng)
[![Gitlab Build Status](https://gitlab.com/lnslbrty/ptunnel-ng/badges/coverity_scan/build.svg)](https://gitlab.com/lnslbrty/ptunnel-ng)
[![Coverity Status](https://scan.coverity.com/projects/14737/badge.svg?flat=1)](https://scan.coverity.com/projects/14737)
+[![Total alerts](https://img.shields.io/lgtm/alerts/g/lnslbrty/ptunnel-ng.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/lnslbrty/ptunnel-ng/alerts/)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/021aa1d88dd7486db83df3ff96f9eff8)](https://www.codacy.com/app/lnslbrty/ptunnel-ng?utm_source=github.com&utm_medium=referral&utm_content=lnslbrty/ptunnel-ng&utm_campaign=Badge_Grade)
[![GitHub issues](https://img.shields.io/github/issues/lnslbrty/ptunnel-ng.svg)](https://github.com/lnslbrty/ptunnel-ng/issues)
[![GitHub license](https://img.shields.io/github/license/lnslbrty/ptunnel-ng.svg)](https://github.com/lnslbrty/ptunnel-ng/blob/master/COPYING)
@@ -140,7 +141,7 @@ installed.
## TODOs
```
-- challenge response: switch from md5 to sha-512
+- challenge response: switch from md5 to sha-512 (WiP)
- packet obfuscation
- encryption (metadata + payload)
```
diff --git a/configure.ac b/configure.ac
index 5a6af52..457497f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ(2.69)
-AC_INIT([ptunnel-ng], [1.41], [], [], [])
+AC_INIT([ptunnel-ng], [1.42], [], [], [])
AC_CONFIG_SRCDIR([src/config.h.in])
AC_CONFIG_FILES([Makefile src/Makefile])
@@ -128,6 +128,16 @@ case ${pcap_enabled} in
*) AC_MSG_ERROR([Unknown option \`${pcap_enabled}\` for --disable-pcap]) ;;
esac
+dnl `--enable-npcap`: Enable npcap interface (Windows only!)
+AC_ARG_ENABLE([npcap],
+ [AS_HELP_STRING([--enable-npcap], [Enable npcap support. (Windows only; default: disabled)])],[npcap_enabled=yes],)
+npcap_enabled=$(echo ${npcap_enabled})
+case ${npcap_enabled} in
+ 1|y|yes) pcap_enabled=yes ;;
+ ''|0|n|no) pcap_enabled= ;;
+ *) AC_MSG_ERROR([Unknown option \`${npcap_enabled}\` for --enable-npcap]) ;;
+esac
+
dnl `--disable-selinux`: Enabled if found.
AC_ARG_ENABLE([selinux],
[AS_HELP_STRING([--disable-selinux], [Disable SELINUX support. (default: enabled if found)])],,[selinux_enabled=yes])
@@ -203,6 +213,7 @@ AC_SEARCH_LIBS([__android_log_vprint], [log],,,)
dnl Set automake conf vars
AM_CONDITIONAL([HAVE_PCAP], [test x"${pcap_enabled}" = xyes])
+AM_CONDITIONAL([HAVE_NPCAP], [test x"${npcap_enabled}" = xyes])
AM_CONDITIONAL([HAVE_SELINUX], [test x"${selinux_enabled}" = xyes])
AM_CONDITIONAL([IS_WINDOWS], [test x"${use_msw}" = xyes])
AM_CONDITIONAL([HAVE_ICMPFILTER], [test x"${with_icmp_filter}" = xyes])
diff --git a/src/Makefile.am b/src/Makefile.am
index 8d4787a..552c894 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,14 +36,17 @@ ptunnel_ng_SOURCES = \
ptunnel.c
if IS_WINDOWS
-wpcap_DEF = $(abs_srcdir)/win32/WPCAP.DEF
-wpcap_IMP = $(abs_srcdir)/win32/libwpcap_implib.a
-ptunnel_ng_CFLAGS += -I$(abs_srcdir)/win32/includes
+wpcap_DEF = $(srcdir)/win32/WPCAP.DEF
+wpcap_IMP = $(srcdir)/win32/libwpcap_implib.a
+ptunnel_ng_CFLAGS += -I$(srcdir)/win32/includes -DHAVE_PCAP=1
+if HAVE_NPCAP
+ptunnel_ng_CFLAGS += -DHAVE_NPCAP=1
+endif
ptunnel_ng_LDADD += $(wpcap_IMP)
ptunnel_ng_SOURCES += $(wpcap_DEF)
$(wpcap_IMP):
- @DLLTOOL@ -k -l $(wpcap_IMP) --def $(wpcap_DEF)
+ @DLLTOOL@ -k -y $(wpcap_IMP) --def $(wpcap_DEF)
CLEANFILES += $(wpcap_IMP)
EXTTRA_DIST += $(wpcap_DEF)
diff --git a/src/challenge.c b/src/challenge.c
index f269313..f0b02ad 100644
--- a/src/challenge.c
+++ b/src/challenge.c
@@ -46,6 +46,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
+#include <assert.h>
#include "challenge.h"
#include "options.h"
@@ -55,48 +56,66 @@
/* generate_challenge: Generates a random challenge, incorporating the current
* local timestamp to avoid replay attacks.
*/
-challenge_t* generate_challenge(void) {
+challenge_t *generate_challenge(void) {
struct timeval tt;
challenge_t *c;
int i;
c = (challenge_t *) calloc(1, sizeof(challenge_t));
+ assert(c != NULL);
gettimeofday(&tt, 0);
- c->sec = tt.tv_sec;
- c->usec_rnd = tt.tv_usec + pt_random();
+ c->plain.sec = tt.tv_sec;
+ c->plain.usec_rnd = tt.tv_usec + pt_random();
for (i=0;i<6;i++)
- c->random[i] = pt_random();
+ c->plain.random[i] = pt_random();
return c;
}
-/* generate_response: Generates a response to the given challenge. The response
+/* generate_response_md5: Generates a response to the given challenge. The response
* is generated by combining the concatenating the challenge data with the
* md5 digest of the password, and then calculating the MD5 digest of the
* entire buffer. The result is stored in the passed-in challenge, overwriting
* the challenge data.
*/
-void generate_response(challenge_t *challenge) {
- md5_byte_t buf[sizeof(challenge_t)+kMD5_digest_size];
+void generate_response_md5(challenge_plain_t *plain, challenge_digest_t *digest) {
+ md5_byte_t buf[sizeof(*plain) + kMD5_digest_size];
md5_state_t state;
- memcpy(buf, challenge, sizeof(challenge_t));
- memcpy(&buf[sizeof(challenge_t)], opts.password_digest, kMD5_digest_size);
- memset(challenge, 0, sizeof(challenge_t));
+ digest->hash_type = HT_MD5;
+ memcpy(buf, plain, sizeof(*plain));
+ memcpy(&buf[sizeof(*plain)], opts.md5_password_digest, kMD5_digest_size);
+ memset(plain, 0, sizeof(*plain));
+
md5_init(&state);
- md5_append(&state, buf, sizeof(challenge_t)+kMD5_digest_size);
- md5_finish(&state, (md5_byte_t*)challenge);
+ md5_append(&state, buf, sizeof(*plain) + kMD5_digest_size);
+ md5_finish(&state, (md5_byte_t *) &digest->md5[0]);
}
-/* validate_challenge: Checks whether a given response matches the expected
+/* validate_challenge_md5: Checks whether a given response matches the expected
* response, returning 1 if validation succeeded, and 0 otherwise. Note that
* overwriting the local challenge with the challenge result is not a problem,
* as the data will not be used again anyway (authentication either succeeds,
* or the connection is closed down).
*/
-int validate_challenge(challenge_t *local, challenge_t *remote) {
- generate_response(local);
- if (memcmp(local, remote, sizeof(challenge_t)) == 0)
+int validate_challenge_md5(challenge_t *local, challenge_digest_t *remote) {
+ generate_response_md5(&local->plain, &local->digest);
+ if (remote->hash_type == HT_MD5 &&
+ memcmp(&local->digest.md5[0], &remote->md5[0], sizeof(local->digest.md5)) == 0)
+ {
return 1;
+ }
return 0;
}
+
+#ifdef ENABLE_SHA512
+void generate_response_sha512(challenge_t *challenge)
+{
+ /* TODO: Implement me! */
+}
+
+int validate_challenge_sha512(challenge_t *local, challenge_t *remote)
+{
+ /* TODO: Implement me! */
+}
+#endif /* ENABLE_SHA512 */
diff --git a/src/challenge.h b/src/challenge.h
index 18495cf..203e420 100644
--- a/src/challenge.h
+++ b/src/challenge.h
@@ -46,23 +46,50 @@
#ifndef CHALLENGE_H
#define CHALLENGE_H 1
+#include "pconfig.h"
+
#include <stdint.h>
+#ifdef ENABLE_SHA512
+#include <openssl/sha.h>
+#endif
-/** challenge_t: This structure contains the pseudo-random challenge used for
- * authentication.
- */
-typedef struct challenge_t {
+#define HT_MD5 0x1
+#define HT_SHA512 0x2
+
+
+typedef struct challenge_plain_t {
/** tv_sec as returned by gettimeofday */
uint32_t sec;
/** tv_usec as returned by gettimeofday + random value */
uint32_t usec_rnd;
/** random values */
uint32_t random[6];
+} __attribute__ ((packed)) challenge_plain_t;
+
+typedef struct challenge_digest_t {
+ uint8_t hash_type;
+ union {
+ unsigned char md5[kMD5_digest_size];
+ unsigned char sha512[kSHA512_digest_size];
+ };
+} __attribute__ ((packed)) challenge_digest_t;
+
+/** challenge_t: This structure contains the pseudo-random challenge used for
+ * authentication. If OpenSSL is available SHA512 will be used per default.
+ */
+typedef struct challenge_t {
+ challenge_plain_t plain;
+ challenge_digest_t digest;
} __attribute__ ((packed)) challenge_t;
+challenge_t *generate_challenge(void);
+
+void generate_response_md5(challenge_plain_t *plain, challenge_digest_t *digest);
+int validate_challenge_md5(challenge_t *local, challenge_digest_t *remote);
-challenge_t* generate_challenge(void);
-void generate_response(challenge_t *challenge);
-int validate_challenge(challenge_t *local, challenge_t *remote);
+#ifdef ENABLE_SHA512
+void generate_response_sha512(challenge_plain_t *plain, challenge_digest_t *digest);
+int validate_challenge_sha512(challenge_t *local, challenge_digest_t *remote);
+#endif
#endif
diff --git a/src/options.c b/src/options.c
index ffb5339..10838ad 100644
--- a/src/options.c
+++ b/src/options.c
@@ -41,6 +41,9 @@
#ifdef WIN32
#include <ws2tcpip.h>
#endif
+#ifdef ENABLE_SHA512
+#include <openssl/sha.h>
+#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
@@ -107,7 +110,7 @@ static const struct option_usage usage[] = {
"The special level 5 (or higher) includes xfer logging (lots of output)\n"
},
/** --libpcap */
- {"interface", 0, OPT_STR, {.str = "eth0"},
+ {"interface", 0, OPT_STR, {.str = NULL},
#ifndef HAVE_PCAP
"(Not available on this platform.)\n"
#endif
@@ -169,6 +172,22 @@ static const struct option_usage usage[] = {
"Tune the number of empty pings to send with each explicit acknowledgement.\n"
"Empty pings can compensate for ICMP sequence number inspection.\n"
},
+ /** --force-md5 */
+ {"force-md5", 0, OPT_BOOL, {.num = 0},
+ "Force MD5 as challenge response checksum generator.\n"
+#ifndef ENABLE_SHA512
+ "This is the default for this configuration.\n"
+#endif
+ },
+ /** --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
@@ -237,6 +256,8 @@ static struct option long_options[] = {
{"resend-interval", required_argument, 0, 't'},
{"payload-size", required_argument, 0, 'y'},
{"empty-pings", required_argument, 0, 'E'},
+ {"force-md5", no_argument, &opts.force_md5, 1},
+ {"force-sha512", no_argument, &opts.force_sha512, 1},
{"daemon", optional_argument, 0, 'd'},
{"syslog", no_argument, 0, 'S'},
{"user", optional_argument, 0, 'u'},
@@ -250,8 +271,11 @@ static struct option long_options[] = {
static const void *get_default_optval(enum option_type opttype, const char *optname) {
for (unsigned i = 0; i < ARRAY_SIZE(long_options); ++i) {
- if (strncmp(long_options[i].name, optname, BUFSIZ /* not optimal */) == 0) {
- assert(usage[i].otype == opttype);
+ 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;
}
}
@@ -274,9 +298,6 @@ static void set_options_defaults(void) {
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");
-#ifdef HAVE_PCAP
- opts.pcap_device = strdup(*(char **)get_default_optval(OPT_STR, "libpcap"));
-#endif
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");
@@ -421,7 +442,7 @@ int parse_options(int argc, char **argv) {
* 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::w:a:t:y:E:h", &long_options[0], &oidx);
+ c = getopt_long(argc, argv, "m:p:l:r::R::c:v:L:o::sP:d::Su::g::C::e::w:a:t:y:E:h", &long_options[0], &oidx);
if (c == -1) break;
switch (c) {
@@ -498,13 +519,17 @@ int parse_options(int argc, char **argv) {
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
+ 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.password_digest[0]);
+ md5_finish(&state, &opts.md5_password_digest[0]);
// Hide the password in process listing
memset(optarg, '*', strnlen(optarg, BUFSIZ /* not optimal */));
+#ifdef ENABLE_SHA512
+ pt_log(kLog_debug, "%s\n", "Password set - sha512 authentication enabled.");
+ SHA512(optarg, strnlen(opts.password, BUFSIZ /* not optimal */), &opts.sha512_password_digest[0]);
+#endif
break;
#ifndef WIN32
case 'd':
@@ -609,6 +634,16 @@ int parse_options(int argc, char **argv) {
exit(1);
}
+#if ENABLE_SHA512
+ if (opts.force_md5) {
+ pt_log(kLog_error, "%s\n", "You are forcing md5 but sha512 is available.");
+ }
+#else
+ if (opts.force_sha512) {
+ pt_log(kLog_error, "%s\n", "You are forcing sha512 but it isn't available.");
+ }
+#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",
diff --git a/src/options.h b/src/options.h
index 9c2ca3f..5551426 100644
--- a/src/options.h
+++ b/src/options.h
@@ -75,6 +75,10 @@ struct options {
/** Device to capture packets from */
char *pcap_device;
#endif
+ /** Force MD5 based challenge response. */
+ int force_md5;
+ /** Force SHA512 based challenge response. */
+ int force_sha512;
/** List all available pcap devices and exit */
int list_pcap_devices;
/** Usually stdout, but can be altered by the user */
@@ -84,8 +88,10 @@ struct options {
int print_stats;
/** Password (must be the same on proxy and client for authentica tion to succeed) */
char *password;
- /** MD5 digest of challenge+password */
- md5_byte_t password_digest[kMD5_digest_size];
+ /** MD5 digest of password */
+ md5_byte_t md5_password_digest[kMD5_digest_size];
+ /** SHA512 digest of password */
+ unsigned char sha512_password_digest[kSHA512_digest_size];
/** use UDP instead of ICMP */
int udp;
/** unpriviledged mode */
diff --git a/src/pconfig.h b/src/pconfig.h
index e13f7ee..5c642ee 100644
--- a/src/pconfig.h
+++ b/src/pconfig.h
@@ -88,6 +88,8 @@ enum {
kAutomatic_close_timeout = 60, // Seconds!
/** size of md5 digest in bytes */
kMD5_digest_size = 16,
+ /** size of sha512 digest in bytes */
+ kSHA512_digest_size = 64,
/** These constants are used to indicate the protocol state. The protocol
* works as follows:
* - The identifier is used by both the proxy and the forwarder
diff --git a/src/pkt.c b/src/pkt.c
index f1e134b..473737e 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -76,7 +76,7 @@ void handle_packet(char *buf, unsigned bytes, int is_pcap, struct sockaddr_in *a
if (bytes < sizeof(icmp_echo_packet_t)+sizeof(ping_tunnel_pkt_t))
pt_log(kLog_verbose, "Skipping this packet - too short. "
- "Expect: %d+%d = %d ; Got: %d\n",
+ "Expect: %lu+%lu = %lu ; Got: %u\n",
sizeof(icmp_echo_packet_t),
sizeof(ping_tunnel_pkt_t),
sizeof(icmp_echo_packet_t) +
@@ -176,9 +176,9 @@ void handle_packet(char *buf, unsigned bytes, int is_pcap, struct sockaddr_in *a
init_state = kProto_data;
cur = (proxy_desc_t *) create_and_insert_proxy_desc(pt_pkt->id_no, pkt->identifier, 0,
- addr, pt_pkt->dst_ip,
- ntohl(pt_pkt->dst_port),
- init_state, kProxy_flag);
+ addr, pt_pkt->dst_ip,
+ ntohl(pt_pkt->dst_port),
+ init_state, kProxy_flag);
if (!cur) {
/* if failed, abort. Logging is done in create_insert_proxy_desc */
pt_log(kLog_error, "Failed to create proxy descriptor!\n");
@@ -236,7 +236,7 @@ void handle_packet(char *buf, unsigned bytes, int is_pcap, struct sockaddr_in *a
return;
}
pt_log(kLog_debug, "Got authentication challenge - sending response\n");
- generate_response(challenge);
+ generate_response_md5(&challenge->plain, &challenge->digest);
queue_packet(icmp_sock, cur->pkt_type, (char*)challenge,
sizeof(challenge_t), cur->id_no, cur->icmp_id,
&cur->my_seq, cur->send_ring, &cur->send_idx,
@@ -254,8 +254,8 @@ void handle_packet(char *buf, unsigned bytes, int is_pcap, struct sockaddr_in *a
/* If proxy: Handle client's response to challenge */
else if (type_flag == proxy_flag) {
pt_log(kLog_debug, "Received remote challenge response.\n");
- if (validate_challenge(cur->challenge, challenge) ||
- cur->authenticated)
+ if (validate_challenge_md5(cur->challenge, &challenge->digest) ||
+ cur->authenticated)
{
pt_log(kLog_verbose, "Remote end authenticated successfully.\n");
handle_extended_options(cur);
@@ -432,14 +432,13 @@ void handle_data(icmp_echo_packet_t *pkt, int total_len, forward_desc_t *ring[],
}
}
-void handle_extended_options(void *vcur)
+void handle_extended_options(proxy_desc_t *cur)
{
- proxy_desc_t *cur = (proxy_desc_t *)vcur;
if (cur->extended_options[0] > 0) {
if (cur->extended_options[0] > cur->window_size) {
size_t extend = cur->extended_options[0] - cur->window_size;
- cur->send_ring = realloc(cur->send_ring, cur->extended_options[0] * sizeof(icmp_desc_t));
- cur->recv_ring = realloc(cur->recv_ring, cur->extended_options[0] * sizeof(forward_desc_t *));
+ cur->send_ring = (icmp_desc_t *) realloc(cur->send_ring, cur->extended_options[0] * sizeof(icmp_desc_t));
+ cur->recv_ring = (forward_desc_t **) realloc(cur->recv_ring, cur->extended_options[0] * sizeof(forward_desc_t *));
memset(cur->send_ring + cur->window_size, 0, extend * sizeof(icmp_desc_t));
memset(cur->recv_ring + cur->window_size, 0, extend * sizeof(forward_desc_t *));
}
@@ -474,14 +473,14 @@ void handle_ack(uint16_t seq_no, icmp_desc_t ring[], int *packets_awaiting_ack,
pt_log(kLog_debug, "Received ack for only seq %d\n", seq_no);
pt_pkt = (ping_tunnel_pkt_t*)ring[i].pkt->data;
/* WARNING: We make the dangerous assumption here that packets arrive in order! */
- *remote_ack = (uint16_t)ntohl(pt_pkt->ack);
+ *remote_ack = (uint16_t) ntohl(pt_pkt->ack);
free(ring[i].pkt);
ring[i].pkt = 0;
ring[i].pkt_len = 0;
(*packets_awaiting_ack)--;
if (i == *first_ack) {
- for (j=1;j<window_size;j++) {
- k = (i+j)%window_size;
+ for (j = 1; j < window_size; j += 2) {
+ k = (i + j) % window_size;
if (ring[k].pkt) {
*first_ack = k;
break;
@@ -489,7 +488,6 @@ void handle_ack(uint16_t seq_no, icmp_desc_t ring[], int *packets_awaiting_ack,
/* we have looped through everything */
if (k == i)
*first_ack = insert_idx;
- j++;
}
}
return;
@@ -525,7 +523,6 @@ void handle_ack(uint16_t seq_no, icmp_desc_t ring[], int *packets_awaiting_ack,
}
}
}
-/* else
- * pt_log(kLog_verbose, "Dropping superfluous acknowledgement (no outstanding packets needing ack.)\n");
- */
+ else
+ pt_log(kLog_verbose, "Dropping superfluous acknowledgement (no outstanding packets needing ack.)\n");
}
diff --git a/src/pkt.h b/src/pkt.h
index 8002f78..3953adb 100644
--- a/src/pkt.h
+++ b/src/pkt.h
@@ -133,6 +133,7 @@ typedef struct {
typedef struct forward_desc_t forward_desc_t;
typedef struct icmp_desc_t icmp_desc_t;
+typedef struct proxy_desc_t proxy_desc_t;
void handle_packet(char *buf, unsigned bytes, int is_pcap, struct sockaddr_in *addr, int icmp_sock);
@@ -140,7 +141,7 @@ void handle_packet(char *buf, unsigned bytes, int is_pcap, struct sockaddr_in *a
void handle_data(icmp_echo_packet_t *pkt, int total_len, forward_desc_t **ring,
int *await_send, int *insert_idx, uint16_t *next_expected_seq, void *vcur, uint16_t window_size);
-void handle_extended_options(void *vcur);
+void handle_extended_options(proxy_desc_t *cur);
void handle_ack(uint16_t seq_no, icmp_desc_t *ring, int *packets_awaiting_ack,
int one_ack_only, int insert_idx, int *first_ack,
diff --git a/src/ptunnel.c b/src/ptunnel.c
index d70edce..9af8db7 100644
--- a/src/ptunnel.c
+++ b/src/ptunnel.c
@@ -54,6 +54,7 @@
#endif
#ifdef WIN32
+#include <tchar.h>
#include <winsock2.h>
/* Map errno (which Winsock doesn't use) to GetLastError; include the code in the strerror */
#ifdef errno
@@ -75,6 +76,25 @@ static char * print_last_windows_error() {
#define strerror(x) print_last_windows_error()
#endif /* WIN32 */
+#ifdef HAVE_NPCAP
+static BOOL LoadNpcapDlls()
+{
+ TCHAR npcap_dir[512];
+ UINT len;
+ len = GetSystemDirectory(npcap_dir, 480);
+ if (!len) {
+ pt_log(kLog_error, "Error in GetSystemDirectory: %x", GetLastError());
+ return FALSE;
+ }
+ _tcscat_s(npcap_dir, 512, _T("\\Npcap"));
+ if (SetDllDirectory(npcap_dir) == 0) {
+ pt_log(kLog_error, "Error in SetDllDirectory: %x", GetLastError());
+ return FALSE;
+ }
+ return TRUE;
+}
+#endif
+
/* globals */
/** Lock protecting the chain of connections */
pthread_mutex_t chain_lock;
@@ -150,7 +170,13 @@ int main(int argc, char *argv[]) {
}
#endif /* WIN32 */
- memset(opts.password_digest, 0, kMD5_digest_size);
+#ifdef HAVE_NPCAP
+ if (!LoadNpcapDlls())
+ return -1;
+#endif
+
+ memset(opts.md5_password_digest, 0, kMD5_digest_size);
+ memset(opts.sha512_password_digest, 0, kSHA512_digest_size);
/* The seq_expiry_tbl is used to prevent the remote ends from prematurely
* re-using a sequence number.
@@ -181,9 +207,9 @@ int main(int argc, char *argv[]) {
}
#ifdef WIN32
if (!opts.pcap && !opts.udp) {
- pt_log(kLog_info, "Running ptunnel-ng on Windows in ICMP mode without WinPcap enabled is not supported and may not work!\n");
- pt_log(kLog_info, "If you encounter problems, install WinPCAP from:\n");
- pt_log(kLog_info, "https://www.winpcap.org/install/default.htm or for WIN10: https://nmap.org/npcap/windows-10.html\n");
+ pt_log(kLog_info, "Running ptunnel-ng on Windows in ICMP mode without WinPcap/Npcap enabled is not supported and may not work!\n");
+ pt_log(kLog_info, "If you encounter problems, install WinPCAP/Npcap from:\n");
+ pt_log(kLog_info, "https://www.winpcap.org/install/default.htm or Npcap for WIN10: https://nmap.org/npcap/windows-10.html\n");
pt_log(kLog_info, "After WinPCAP is installed, you can list pcap devices with: --list-pcap-devices\n");
}
#endif
@@ -252,8 +278,8 @@ int main(int argc, char *argv[]) {
}
#endif /* !WIN32 */
- pthread_mutex_init(&chain_lock, 0);
- pthread_mutex_init(&num_threads_lock, 0);
+ pthread_mutex_init(&chain_lock, 0);
+ pthread_mutex_init(&num_threads_lock, 0);
// Check mode, validate arguments and start either client or proxy.
if (opts.mode == kMode_forward) {
@@ -676,7 +702,7 @@ void* pt_proxy(void *args) {
for (cur = chain; cur; cur = cur->next) {
in_addr.s_addr = cur->dst_ip;
if (cur->last_activity + kAutomatic_close_timeout < now) {
- pt_log(kLog_info, "Dropping tunnel to %s:%d due to inactivity.\n", inet_ntoa(in_addr), cur->dst_port, cur->id_no);
+ pt_log(kLog_info, "Dropping tunnel %u to %s:%u due to inactivity.\n", cur->id_no, inet_ntoa(in_addr), cur->dst_port);
cur->should_remove = 1;
continue;
}
diff --git a/src/utils.c b/src/utils.c
index a65f947..8e340d4 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -160,7 +160,7 @@ int pt_random(void) {
#ifdef HAVE_ARC4RANDOM
return arc4random();
#else
-#if defined(USE_CUSTOMRNG) && !defined(_WIN32)
+#if defined(RNGDEV) && !defined(_WIN32)
static int rng_fd = -1;
ssize_t bytes_read;
int rnd_val;