diff -Nru openvpn-2.1~rc19/buffer.c openvpn-2.1.1/buffer.c --- openvpn-2.1~rc19/buffer.c 2009-05-30 23:34:11.000000000 +0200 +++ openvpn-2.1.1/buffer.c 2009-10-01 20:02:18.000000000 +0200 @@ -33,11 +33,11 @@ #include "memdbg.h" size_t -array_mult_safe (const size_t m1, const size_t m2) +array_mult_safe (const size_t m1, const size_t m2, const size_t extra) { const size_t limit = 0xFFFFFFFF; - unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2; - if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(res > (unsigned long long)limit)) + unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2 + (unsigned long long)extra; + if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(extra > limit) || unlikely(res > (unsigned long long)limit)) msg (M_FATAL, "attemped allocation of excessively large array"); return (size_t) res; } diff -Nru openvpn-2.1~rc19/buffer.h openvpn-2.1.1/buffer.h --- openvpn-2.1~rc19/buffer.h 2009-05-30 23:34:11.000000000 +0200 +++ openvpn-2.1.1/buffer.h 2009-10-01 20:02:18.000000000 +0200 @@ -88,7 +88,7 @@ void string_clear (char *str); int string_array_len (const char **array); -size_t array_mult_safe (const size_t m1, const size_t m2); +size_t array_mult_safe (const size_t m1, const size_t m2, const size_t extra); #define PA_BRACKET (1<<0) char *print_argv (const char **p, struct gc_arena *gc, const unsigned int flags); @@ -776,23 +776,28 @@ #define ALLOC_ARRAY(dptr, type, n) \ { \ - check_malloc_return ((dptr) = (type *) malloc (array_mult_safe (sizeof (type), (n)))); \ + check_malloc_return ((dptr) = (type *) malloc (array_mult_safe (sizeof (type), (n), 0))); \ } #define ALLOC_ARRAY_GC(dptr, type, n, gc) \ { \ - (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n)), false, (gc)); \ + (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n), 0), false, (gc)); \ } #define ALLOC_ARRAY_CLEAR(dptr, type, n) \ { \ ALLOC_ARRAY (dptr, type, n); \ - memset ((dptr), 0, (array_mult_safe (sizeof(type), (n)))); \ + memset ((dptr), 0, (array_mult_safe (sizeof(type), (n), 0))); \ } #define ALLOC_ARRAY_CLEAR_GC(dptr, type, n, gc) \ { \ - (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n)), true, (gc)); \ + (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n), 0), true, (gc)); \ +} + +#define ALLOC_VAR_ARRAY_CLEAR_GC(dptr, type, atype, n, gc) \ +{ \ + (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (atype), (n), sizeof (type)), true, (gc)); \ } #define ALLOC_OBJ_GC(dptr, type, gc) \ diff -Nru openvpn-2.1~rc19/ChangeLog openvpn-2.1.1/ChangeLog --- openvpn-2.1~rc19/ChangeLog 2009-07-16 11:13:14.000000000 +0200 +++ openvpn-2.1.1/ChangeLog 2009-12-12 00:42:25.000000000 +0100 @@ -1,6 +1,102 @@ OpenVPN Change Log Copyright (C) 2002-2009 OpenVPN Technologies, Inc. +2009.12.11 -- Version 2.1.1 + +* Fixed some breakage in openvpn.spec (which is required to build an + RPM distribution) where it was referencing a non-existent + subdirectory in the tarball, causing it to fail (patch from + David Sommerseth). + +2009.12.11 -- Version 2.1.0 + +* Fixed a couple issues in sample plugins auth-pam.c and down-root.c. + (1) Fail gracefully rather than segfault if calloc returns NULL. + (2) The openvpn_plugin_abort_v1 function can potentially be called + with handle == NULL. Add code to detect this case, and if so, avoid + dereferencing pointers derived from handle (Thanks to David + Sommerseth for finding this bug). + +* Documented "multihome" option in the man page. + +2009.11.20 -- Version 2.1_rc22 + +* Fixed a client-side bug on Windows that occurred when the + "dhcp-pre-release" or "dhcp-renew" options were combined with + "route-gateway dhcp". The release/renew would not occur + because the Windows DHCP renew function is blocking and + therefore must be called from another process or thread + so as not to stall the tunnel. + +* Added a hard failure when peer provides a certificate chain + with depth > 16. Previously, a warning was issued. + +2009.11.12 -- Version 2.1_rc21 + +* Rebuilt OpenVPN Windows installer with OpenSSL 0.9.8l to address + CVE-2009-3555. Note that OpenVPN has never relied on the session + renegotiation capabilities that are built into the SSL/TLS protocol, + therefore the fix in OpenSSL 0.9.8l (disable SSL/TLS renegotiation + completely) will not adversely affect OpenVPN mid-session SSL/TLS + renegotation or any other OpenVPN capabilities. + +* Added additional session renegotiation hardening. OpenVPN has always + required that mid-session renegotiations build up a new SSL/TLS + session from scratch. While the client certificate common name is + already locked against changes in mid-session TLS renegotiations, we + now extend this locking to the auth-user-pass username as well as all + certificate content in the full client certificate chain. + +2009.10.01 -- Version 2.1_rc20 + +* Fixed a bug introduced in 2.1_rc17 (svn r4436) where using the + redirect-gateway option by itself, without any extra parameters, + would cause the option to be ignored. + +* Fixed build problem when ./configure --disable-server is used. + +* Fixed ifconfig command for "topology subnet" on FreeBSD (Stefan Bethke). + +* Added --remote-random-hostname option. + +* Added "load-stats" management interface command to get global server + load statistics. + +* Added new ./configure flags: + + --disable-def-auth Disable deferred authentication + --disable-pf Disable internal packet filter + +* Added "setcon" directive for interoperability with SELinux (Sebastien + Raveau). + +* Optimized PUSH_REQUEST handshake sequence to shave several seconds + off of a typical client connection initiation. + +* The maximum number of "route" directives (specified in the config + file or pulled from a server) can now be configured via the new + "max-routes" directive. + +* Eliminated the limitation on the number of options that can be pushed + to clients, including routes. Previously, all pushed options needed + to fit within a 1024 byte options string. + +* Added --server-poll-timeout option : when polling possible remote + servers to connect to in a round-robin fashion, spend no more than + n seconds waiting for a response before trying the next server. + +* Added the ability for the server to provide a custom reason string + when an AUTH_FAILED message is returned to the client. This + string can be set by the server-side managment interface and read + by the client-side management interface. + +* client-kill management interface command, when issued on server, will + now send a RESTART message to client. + This feature is intended to make UDP clients respond the same as TCP + clients in the case where the server issues a RESTART message in + order to force the client to reconnect and pull a new options/route + list. + 2009.07.16 -- Version 2.1_rc19 * In Windows TAP driver, refactor DHCP/ARP packet injection code to diff -Nru openvpn-2.1~rc19/common.h openvpn-2.1.1/common.h --- openvpn-2.1~rc19/common.h 2009-05-30 23:34:11.000000000 +0200 +++ openvpn-2.1.1/common.h 2009-10-01 20:02:18.000000000 +0200 @@ -74,12 +74,10 @@ #define CCD_DEFAULT "DEFAULT" /* - * This parameter controls the TLS channel buffer size. Among - * other things, this buffer must be large enough to contain - * the full --push/--pull list. If you increase it, do so - * on both server and client. + * This parameter controls the TLS channel buffer size and the + * maximum size of a single TLS message (cleartext). */ -#define TLS_CHANNEL_BUF_SIZE 2048 +#define TLS_CHANNEL_BUF_SIZE 1024 /* * A sort of pseudo-filename for data provided inline within diff -Nru openvpn-2.1~rc19/config.h.in openvpn-2.1.1/config.h.in --- openvpn-2.1~rc19/config.h.in 2009-07-16 11:14:20.000000000 +0200 +++ openvpn-2.1.1/config.h.in 2009-12-12 00:27:04.000000000 +0100 @@ -1,5 +1,11 @@ /* config.h.in. Generated from configure.ac by autoheader. */ +/* Enable deferred authentication */ +#undef CONFIGURE_DEF_AUTH + +/* Enable internal packet filter */ +#undef CONFIGURE_PF + /* enable iproute2 support */ #undef CONFIG_FEATURE_IPROUTE @@ -279,6 +285,9 @@ /* Define to 1 if you have the `sendto' function. */ #undef HAVE_SENDTO +/* SELinux support */ +#undef HAVE_SETCON + /* Define to 1 if you have the `setgid' function. */ #undef HAVE_SETGID diff -Nru openvpn-2.1~rc19/configure openvpn-2.1.1/configure --- openvpn-2.1~rc19/configure 2009-07-16 11:14:20.000000000 +0200 +++ openvpn-2.1.1/configure 2009-12-12 00:27:03.000000000 +0100 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for OpenVPN 2.1_rc19. +# Generated by GNU Autoconf 2.61 for OpenVPN 2.1.1. # # Report bugs to . # @@ -574,8 +574,8 @@ # Identity of this package. PACKAGE_NAME='OpenVPN' PACKAGE_TARNAME='openvpn' -PACKAGE_VERSION='2.1_rc19' -PACKAGE_STRING='OpenVPN 2.1_rc19' +PACKAGE_VERSION='2.1.1' +PACKAGE_STRING='OpenVPN 2.1.1' PACKAGE_BUGREPORT='openvpn-users@lists.sourceforge.net' ac_unique_file="syshead.h" @@ -1233,7 +1233,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures OpenVPN 2.1_rc19 to adapt to many kinds of systems. +\`configure' configures OpenVPN 2.1.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1304,7 +1304,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of OpenVPN 2.1_rc19:";; + short | recursive ) echo "Configuration of OpenVPN 2.1.1:";; esac cat <<\_ACEOF @@ -1329,10 +1329,13 @@ --enable-pthread Enable pthread support (Experimental for OpenVPN 2.0) --enable-password-save Allow --askpass and --auth-user-pass passwords to be read from a file --enable-iproute2 Enable support for iproute2 + --disable-def-auth Disable deferred authentication + --disable-pf Disable internal packet filter --enable-strict Enable strict compiler warnings (debugging option) --enable-pedantic Enable pedantic compiler warnings, will not generate a working executable (debugging option) --enable-profiling Enable profiling (debugging option) --enable-strict-options Enable strict options check between peers (debugging option) + --disable-selinux Disable SELinux support --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors @@ -1426,7 +1429,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -OpenVPN configure 2.1_rc19 +OpenVPN configure 2.1.1 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1440,7 +1443,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by OpenVPN $as_me 2.1_rc19, which was +It was created by OpenVPN $as_me 2.1.1, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -2606,6 +2609,24 @@ fi +# Check whether --enable-def-auth was given. +if test "${enable_def_auth+set}" = set; then + enableval=$enable_def_auth; DEF_AUTH="$enableval" +else + DEF_AUTH="yes" + +fi + + +# Check whether --enable-pf was given. +if test "${enable_pf+set}" = set; then + enableval=$enable_pf; PF="$enableval" +else + PF="yes" + +fi + + # Check whether --enable-strict was given. if test "${enable_strict+set}" = set; then enableval=$enable_strict; STRICT="$enableval" @@ -2642,6 +2663,15 @@ fi +# Check whether --enable-selinux was given. +if test "${enable_selinux+set}" = set; then + enableval=$enable_selinux; SELINUX="$enableval" +else + SELINUX="yes" + +fi + + # Check whether --with-ssl-headers was given. if test "${with_ssl_headers+set}" = set; then @@ -12765,6 +12795,22 @@ fi +if test "$DEF_AUTH" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define CONFIGURE_DEF_AUTH 1 +_ACEOF + +fi + +if test "$PF" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define CONFIGURE_PF 1 +_ACEOF + +fi + if test "$STRICT" = "yes"; then CFLAGS="$CFLAGS -Wall -Wno-unused-parameter -Wno-unused-function" fi @@ -12793,6 +12839,227 @@ fi +if test "$SELINUX" = "yes"; then + { echo "$as_me:$LINENO: checking for libselinux Library and Header files..." >&5 +echo "$as_me: checking for libselinux Library and Header files..." >&6;} + if test "${ac_cv_header_selinux_selinux_h+set}" = set; then + { echo "$as_me:$LINENO: checking for selinux/selinux.h" >&5 +echo $ECHO_N "checking for selinux/selinux.h... $ECHO_C" >&6; } +if test "${ac_cv_header_selinux_selinux_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_selinux_selinux_h" >&5 +echo "${ECHO_T}$ac_cv_header_selinux_selinux_h" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking selinux/selinux.h usability" >&5 +echo $ECHO_N "checking selinux/selinux.h usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking selinux/selinux.h presence" >&5 +echo $ECHO_N "checking selinux/selinux.h presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: selinux/selinux.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: selinux/selinux.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: selinux/selinux.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: selinux/selinux.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: selinux/selinux.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: selinux/selinux.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: selinux/selinux.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: selinux/selinux.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: selinux/selinux.h: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## -------------------------------------------------- ## +## Report this to openvpn-users@lists.sourceforge.net ## +## -------------------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for selinux/selinux.h" >&5 +echo $ECHO_N "checking for selinux/selinux.h... $ECHO_C" >&6; } +if test "${ac_cv_header_selinux_selinux_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_selinux_selinux_h=$ac_header_preproc +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_selinux_selinux_h" >&5 +echo "${ECHO_T}$ac_cv_header_selinux_selinux_h" >&6; } + +fi +if test $ac_cv_header_selinux_selinux_h = yes; then + { echo "$as_me:$LINENO: checking for setcon in -lselinux" >&5 +echo $ECHO_N "checking for setcon in -lselinux... $ECHO_C" >&6; } +if test "${ac_cv_lib_selinux_setcon+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lselinux $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char setcon (); +int +main () +{ +return setcon (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_selinux_setcon=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_selinux_setcon=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_selinux_setcon" >&5 +echo "${ECHO_T}$ac_cv_lib_selinux_setcon" >&6; } +if test $ac_cv_lib_selinux_setcon = yes; then + + + LIBS="-lselinux $LIBS" + + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SETCON 1 +_ACEOF + + +else + { echo "$as_me:$LINENO: result: SELinux library not found." >&5 +echo "${ECHO_T}SELinux library not found." >&6; } + +fi + +else + { echo "$as_me:$LINENO: result: SELinux headers not found." >&5 +echo "${ECHO_T}SELinux headers not found." >&6; } + +fi + + +fi + TAP_ID="tap0901" TAP_WIN32_MIN_MAJOR="9" TAP_WIN32_MIN_MINOR="1" @@ -13256,7 +13523,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by OpenVPN $as_me 2.1_rc19, which was +This file was extended by OpenVPN $as_me 2.1.1, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -13309,7 +13576,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -OpenVPN config.status 2.1_rc19 +OpenVPN config.status 2.1.1 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" diff -Nru openvpn-2.1~rc19/configure.ac openvpn-2.1.1/configure.ac --- openvpn-2.1~rc19/configure.ac 2009-06-09 12:59:49.000000000 +0200 +++ openvpn-2.1.1/configure.ac 2009-10-01 20:02:18.000000000 +0200 @@ -170,6 +170,18 @@ test $enableval = "yes" && AC_DEFINE(CONFIG_FEATURE_IPROUTE, 1, [enable iproute2 support]) ) +AC_ARG_ENABLE(def-auth, + [ --disable-def-auth Disable deferred authentication], + [DEF_AUTH="$enableval"], + [DEF_AUTH="yes"] +) + +AC_ARG_ENABLE(pf, + [ --disable-pf Disable internal packet filter], + [PF="$enableval"], + [PF="yes"] +) + AC_ARG_ENABLE(strict, [ --enable-strict Enable strict compiler warnings (debugging option)], [STRICT="$enableval"], @@ -194,6 +206,12 @@ [STRICT_OPTIONS="no"] ) +AC_ARG_ENABLE(selinux, + [ --disable-selinux Disable SELinux support], + [SELINUX="$enableval"], + [SELINUX="yes"] +) + AC_ARG_WITH(ssl-headers, [ --with-ssl-headers=DIR Crypto/SSL Include files location], [CS_HDR_DIR="$withval"] @@ -816,6 +834,16 @@ AC_DEFINE(ENABLE_PORT_SHARE, 1, [Enable TCP Server port sharing]) fi +dnl enable deferred auth +if test "$DEF_AUTH" = "yes"; then + AC_DEFINE(CONFIGURE_DEF_AUTH, 1, [Enable deferred authentication]) +fi + +dnl enable internal packet filter +if test "$PF" = "yes"; then + AC_DEFINE(CONFIGURE_PF, 1, [Enable internal packet filter]) +fi + dnl enable strict compiler warnings if test "$STRICT" = "yes"; then CFLAGS="$CFLAGS -Wall -Wno-unused-parameter -Wno-unused-function" @@ -841,6 +869,23 @@ AC_DEFINE(ENABLE_PASSWORD_SAVE, 1, [Allow --askpass and --auth-user-pass passwords to be read from a file]) fi +dnl +dnl check for SELinux library and headers +dnl +if test "$SELINUX" = "yes"; then + AC_CHECKING([for libselinux Library and Header files]) + AC_CHECK_HEADER(selinux/selinux.h, + [AC_CHECK_LIB(selinux, setcon, + [ + OPENVPN_ADD_LIBS(-lselinux) + AC_DEFINE(HAVE_SETCON, 1, [SELinux support]) + ], + [AC_MSG_RESULT([SELinux library not found.])] + )], + [AC_MSG_RESULT([SELinux headers not found.])] + ) +fi + TAP_ID="PRODUCT_TAP_ID" TAP_WIN32_MIN_MAJOR="PRODUCT_TAP_WIN32_MIN_MAJOR" TAP_WIN32_MIN_MINOR="PRODUCT_TAP_WIN32_MIN_MINOR" diff -Nru openvpn-2.1~rc19/config-win32.h openvpn-2.1.1/config-win32.h --- openvpn-2.1~rc19/config-win32.h 2009-07-16 11:15:03.000000000 +0200 +++ openvpn-2.1.1/config-win32.h 2009-12-12 00:27:36.000000000 +0100 @@ -228,7 +228,7 @@ #define PACKAGE_TARNAME openvpn /* Define to the version of this package. */ -#define PACKAGE_VERSION 2.1_rc19 +#define PACKAGE_VERSION 2.1.1 /* Define to the full name and version of this package. */ #ifdef DEBUG_LABEL diff -Nru openvpn-2.1~rc19/COPYING openvpn-2.1.1/COPYING --- openvpn-2.1~rc19/COPYING 2009-05-30 23:34:11.000000000 +0200 +++ openvpn-2.1.1/COPYING 2009-12-11 05:43:07.000000000 +0100 @@ -53,10 +53,7 @@ The source and object code of the TAP-Win32/TAP-Win64 driver is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., and is released under - the GPL version 2 (see below), however due to the extra costs of - supporting Windows Vista, OpenVPN Technologies, Inc. reserves the right to - change the terms of the TAP-Win32/TAP-Win64 license for versions 9.1 - and higher prior to the official release of OpenVPN 2.1. + the GPL version 2. Windows DDK Samples: -------------------- diff -Nru openvpn-2.1~rc19/crypto.c openvpn-2.1.1/crypto.c --- openvpn-2.1~rc19/crypto.c 2009-05-30 23:34:11.000000000 +0200 +++ openvpn-2.1.1/crypto.c 2009-10-01 20:02:18.000000000 +0200 @@ -1796,4 +1796,49 @@ } #endif /* USE_SSL */ + +/* + * md5 functions + */ + +void +md5_state_init (struct md5_state *s) +{ + MD5_Init (&s->ctx); +} + +void +md5_state_update (struct md5_state *s, void *data, size_t len) +{ + MD5_Update (&s->ctx, data, len); +} + +void +md5_state_final (struct md5_state *s, struct md5_digest *out) +{ + MD5_Final (out->digest, &s->ctx); +} + +void +md5_digest_clear (struct md5_digest *digest) +{ + CLEAR (*digest); +} + +bool +md5_digest_defined (const struct md5_digest *digest) +{ + int i; + for (i = 0; i < MD5_DIGEST_LENGTH; ++i) + if (digest->digest[i]) + return true; + return false; +} + +bool +md5_digest_equal (const struct md5_digest *d1, const struct md5_digest *d2) +{ + return memcmp(d1->digest, d2->digest, MD5_DIGEST_LENGTH) == 0; +} + #endif /* USE_CRYPTO */ diff -Nru openvpn-2.1~rc19/crypto.h openvpn-2.1.1/crypto.h --- openvpn-2.1~rc19/crypto.h 2009-05-30 23:34:11.000000000 +0200 +++ openvpn-2.1.1/crypto.h 2009-10-01 20:02:18.000000000 +0200 @@ -398,5 +398,24 @@ return key->encrypt.cipher || key->encrypt.hmac || key->decrypt.cipher || key->decrypt.hmac; } +/* + * md5 functions + */ + +struct md5_state { + MD5_CTX ctx; +}; + +struct md5_digest { + uint8_t digest [MD5_DIGEST_LENGTH]; +}; + +void md5_state_init (struct md5_state *s); +void md5_state_update (struct md5_state *s, void *data, size_t len); +void md5_state_final (struct md5_state *s, struct md5_digest *out); +void md5_digest_clear (struct md5_digest *digest); +bool md5_digest_defined (const struct md5_digest *digest); +bool md5_digest_equal (const struct md5_digest *d1, const struct md5_digest *d2); + #endif /* USE_CRYPTO */ #endif /* CRYPTO_H */ diff -Nru openvpn-2.1~rc19/debian/changelog openvpn-2.1.1/debian/changelog --- openvpn-2.1~rc19/debian/changelog 2010-01-20 15:18:27.000000000 +0100 +++ openvpn-2.1.1/debian/changelog 2010-01-20 15:18:28.000000000 +0100 @@ -1,3 +1,12 @@ +openvpn (2.1.1-0ubuntu1) karmic; urgency=low + + * New upstream version (LP: #509078) + - removed redirect-gateway.patch, was a backport from rc20 + - updated manpage_dash_escaping.patch (submitted to upstream) + * Bumped Standards-Version to 3.8.3 + + -- Jan Brinkmann Wed, 20 Jan 2010 12:47:37 +0100 + openvpn (2.1~rc19-1ubuntu2) karmic; urgency=low * debian/patches/redirect-gateway.patch: Fix regression introduced in diff -Nru openvpn-2.1~rc19/debian/control openvpn-2.1.1/debian/control --- openvpn-2.1~rc19/debian/control 2010-01-20 15:18:27.000000000 +0100 +++ openvpn-2.1.1/debian/control 2010-01-20 15:18:28.000000000 +0100 @@ -4,7 +4,7 @@ Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Alberto Gonzalez Iniesta Build-Depends: debhelper (>= 7), libssl-dev (>> 0.9.8g-9), liblzo2-dev, libpam0g-dev, quilt, libpkcs11-helper1-dev -Standards-Version: 3.8.2 +Standards-Version: 3.8.3 Package: openvpn Architecture: any diff -Nru openvpn-2.1~rc19/debian/patches/manpage_dash_escaping.patch openvpn-2.1.1/debian/patches/manpage_dash_escaping.patch --- openvpn-2.1~rc19/debian/patches/manpage_dash_escaping.patch 2010-01-20 15:18:27.000000000 +0100 +++ openvpn-2.1.1/debian/patches/manpage_dash_escaping.patch 2010-01-20 15:18:28.000000000 +0100 @@ -1,7 +1,30 @@ -Index: openvpn-2.1_rc19/openvpn.8 +Index: openvpn-2.1.1/openvpn.8 =================================================================== ---- openvpn-2.1_rc19.orig/openvpn.8 2009-05-30 23:34:12.000000000 +0200 -+++ openvpn-2.1_rc19/openvpn.8 2009-07-21 18:54:23.679932251 +0200 +--- openvpn-2.1.1.orig/openvpn.8 2010-01-20 14:56:44.000000000 +0100 ++++ openvpn-2.1.1/openvpn.8 2010-01-20 14:56:52.000000000 +0100 +@@ -1,4 +1,4 @@ +-.\" OpenVPN -- An application to securely tunnel IP networks ++.\" OpenVPN \-\- An application to securely tunnel IP networks + .\" over a single TCP/UDP port, with support for SSL/TLS-based + .\" session authentication and key exchange, + .\" packet encryption, packet authentication, and +@@ -28,11 +28,11 @@ + .\" IP indented paragraph + .\" TP hanging label + .\ +-.\" .nf -- no formatting +-.\" .fi -- resume formatting +-.\" .ft 3 -- boldface +-.\" .ft -- normal face +-.\" .in +|-{n} -- indent ++.\" .nf \-\- no formatting ++.\" .fi \-\- resume formatting ++.\" .ft 3 \-\- boldface ++.\" .ft \-\- normal face ++.\" .in +|-{n} \-\- indent + .\" + .TH openvpn 8 "17 November 2008" + .\"********************************************************* @@ -97,25 +97,25 @@ .SH OPTIONS OpenVPN allows any option to be placed either on the command line @@ -637,9 +660,12 @@ otherwise 0. The default can be specified by leaving an option blank or setting -@@ -929,11 +929,11 @@ +@@ -927,37 +927,37 @@ + file resolvable name, or as one of three special keywords: + .B vpn_gateway - -- The remote VPN endpoint address +--- The remote VPN endpoint address ++\-\- The remote VPN endpoint address (derived either from -.B --route-gateway +.B \-\-route-gateway @@ -652,15 +678,27 @@ is specified). .B net_gateway -@@ -942,15 +942,15 @@ +--- The pre-existing IP default gateway, read from the routing ++\-\- The pre-existing IP default gateway, read from the routing + table (not supported on all OSes). .B remote_host - -- The +--- The -.B --remote ++\-\- The +.B \-\-remote address if OpenVPN is being run in client mode, and is undefined in server mode. .\"********************************************************* .TP +-.B --max-routes n ++.B \-\-max-routes n + Allow a maximum number of n +-.B --route ++.B \-\-route + options to be specified, either in the local configuration file, + or pulled from an OpenVPN server. By default, n=100. + .\"********************************************************* + .TP -.B --route-gateway gw|'dhcp' +.B \-\-route-gateway gw|'dhcp' Specify a default gateway @@ -671,7 +709,7 @@ If .B dhcp -@@ -959,14 +959,14 @@ +@@ -966,14 +966,14 @@ negotiation with the OpenVPN server-side LAN. .\"********************************************************* .TP @@ -689,7 +727,7 @@ Delay .B n seconds (default=0) after connection -@@ -974,16 +974,16 @@ +@@ -981,16 +981,16 @@ .B n is 0, routes will be added immediately upon connection establishment. If @@ -711,7 +749,7 @@ execution.) This option is designed to be useful in scenarios where DHCP is -@@ -992,18 +992,18 @@ +@@ -999,18 +999,18 @@ time to complete before routes are added. On Windows, @@ -733,7 +771,7 @@ See the "Environmental Variables" section below for additional parameters passed as environmental variables. -@@ -1013,17 +1013,17 @@ +@@ -1020,17 +1020,17 @@ can be a shell command with multiple arguments. .\"********************************************************* .TP @@ -756,7 +794,7 @@ accept options pushed by server EXCEPT for routes. When used on the client, this option effectively bars the -@@ -1032,16 +1032,16 @@ +@@ -1039,16 +1039,16 @@ to set the TCP/IP properties of the client's TUN/TAP interface. .\"********************************************************* .TP @@ -778,7 +816,7 @@ (Experimental) Automatically execute routing commands to cause all outgoing IP traffic to be redirected over the VPN. -@@ -1049,7 +1049,7 @@ +@@ -1056,7 +1056,7 @@ .B (1) Create a static route for the @@ -787,7 +825,7 @@ address which forwards to the pre-existing default gateway. This is done so that .B (3) -@@ -1060,11 +1060,11 @@ +@@ -1067,11 +1067,11 @@ .B (3) Set the new default gateway to be the VPN endpoint address (derived either from @@ -802,7 +840,7 @@ is specified). When the tunnel is torn down, all of the above steps are reversed so -@@ -1072,7 +1072,7 @@ +@@ -1079,7 +1079,7 @@ Option flags: @@ -811,7 +849,7 @@ Add the .B local flag if both OpenVPN servers are directly connected via a common subnet, -@@ -1082,19 +1082,19 @@ +@@ -1089,19 +1089,19 @@ .B 1 above to be omitted. @@ -834,7 +872,7 @@ Add a direct route to the DNS server(s) (if they are non-local) which bypasses the tunnel (Available on Windows clients, may not be available -@@ -1103,13 +1103,13 @@ +@@ -1110,13 +1110,13 @@ Using the def1 flag is highly recommended. .\"********************************************************* .TP @@ -850,7 +888,7 @@ Take the TUN device MTU to be .B n and derive the link MTU -@@ -1125,17 +1125,17 @@ +@@ -1132,17 +1132,17 @@ hang during periods of active usage. It's best to use the @@ -872,7 +910,7 @@ size on read. This parameter defaults to 0, which is sufficient for most TUN devices. TAP devices may introduce additional overhead in excess of the MTU size, and a setting of 32 is the default when TAP devices are used. -@@ -1143,34 +1143,34 @@ +@@ -1150,34 +1150,34 @@ so there is no transmission overhead associated with using a larger value. .\"********************************************************* .TP @@ -915,7 +953,7 @@ Enable internal datagram fragmentation so that no UDP datagrams are sent which are larger than -@@ -1180,24 +1180,24 @@ +@@ -1187,24 +1187,24 @@ The .B max parameter is interpreted in the same way as the @@ -946,7 +984,7 @@ It should also be noted that this option is not meant to replace UDP fragmentation at the IP stack level. It is only meant as a -@@ -1210,7 +1210,7 @@ +@@ -1217,7 +1217,7 @@ as tunneling a UDP multicast stream which requires fragmentation. .\"********************************************************* .TP @@ -955,7 +993,7 @@ Announce to TCP sessions running over the tunnel that they should limit their send packet sizes such that after OpenVPN has encapsulated them, the resulting UDP packet size that OpenVPN sends to its peer will not -@@ -1221,33 +1221,33 @@ +@@ -1228,33 +1228,33 @@ The .B max parameter is interpreted in the same way as the @@ -998,7 +1036,7 @@ are designed to work around cases where Path MTU discovery is broken on the network path between OpenVPN peers. -@@ -1256,35 +1256,35 @@ +@@ -1263,35 +1263,35 @@ during active usage. If @@ -1042,7 +1080,7 @@ Apply the given flags to the OpenVPN transport socket. Currently, only .B TCP_NODELAY -@@ -1301,12 +1301,12 @@ +@@ -1308,12 +1308,12 @@ on both client and server for maximum effect. .\"********************************************************* .TP @@ -1057,7 +1095,7 @@ Limit bandwidth of outgoing tunnel data to .B n bytes per second on the TCP/UDP port. -@@ -1342,7 +1342,7 @@ +@@ -1349,7 +1349,7 @@ to be between 100 bytes/sec and 100 Mbytes/sec. .\"********************************************************* .TP @@ -1066,7 +1104,7 @@ Causes OpenVPN to exit after .B n seconds of inactivity on the TUN/TAP device. The time length -@@ -1356,18 +1356,18 @@ +@@ -1363,18 +1363,18 @@ .B bytes. .\"********************************************************* .TP @@ -1089,7 +1127,7 @@ is specified), the ping packet will be cryptographically secure. -@@ -1380,33 +1380,33 @@ +@@ -1387,33 +1387,33 @@ (2) To provide a basis for the remote to test the existence of its peer using the @@ -1130,7 +1168,7 @@ but trigger a .B SIGUSR1 restart after -@@ -1425,13 +1425,13 @@ +@@ -1432,13 +1432,13 @@ If the peer cannot be reached, a restart will be triggered, causing the hostname used with @@ -1147,7 +1185,7 @@ or any other type of internally generated signal will always be applied to individual client instance objects, never to whole server itself. -@@ -1440,14 +1440,14 @@ +@@ -1447,14 +1447,14 @@ of the client instance object instead. In client mode, the @@ -1165,7 +1203,7 @@ on the client. See the signals section below for more information -@@ -1457,27 +1457,27 @@ +@@ -1464,27 +1464,27 @@ Note that the behavior of .B SIGUSR1 can be modified by the @@ -1201,7 +1239,7 @@ expands as follows: .nf -@@ -1496,24 +1496,24 @@ +@@ -1503,24 +1503,24 @@ .fi .\"********************************************************* .TP @@ -1232,7 +1270,7 @@ restarts. .B SIGUSR1 -@@ -1523,14 +1523,14 @@ +@@ -1530,14 +1530,14 @@ reset options. .\"********************************************************* .TP @@ -1250,7 +1288,7 @@ to allow restarts triggered by the .B SIGUSR1 signal. -@@ -1543,29 +1543,29 @@ +@@ -1550,29 +1550,29 @@ resets, so they don't need to be re-read. .\"********************************************************* .TP @@ -1286,7 +1324,7 @@ option). Using this option ensures that key material and tunnel -@@ -1577,33 +1577,33 @@ +@@ -1584,33 +1584,33 @@ recover previously used ephemeral keys, which are used for a period of time governed by the @@ -1326,7 +1364,7 @@ execute as: .B cmd tap_dev tap_mtu link_mtu ifconfig_local_ip ifconfig_netmask [ init | restart ] -@@ -1628,62 +1628,62 @@ +@@ -1635,62 +1635,62 @@ will be .I init. If the @@ -1405,7 +1443,7 @@ to allow connection initiation to be sensed in the absence of tunnel data, since UDP is a "connectionless" protocol. -@@ -1692,50 +1692,50 @@ +@@ -1699,50 +1699,50 @@ i.e. the receipt of the first authenticated packet from the peer. .\"********************************************************* .TP @@ -1471,7 +1509,7 @@ Relax config file syntax checking so that unknown directives will trigger a warning but not a fatal error, on the assumption that a given unknown directive might be valid -@@ -1748,7 +1748,7 @@ +@@ -1755,7 +1755,7 @@ older software versions. .\"********************************************************* .TP @@ -1480,7 +1518,7 @@ Set a custom environmental variable .B OPENVPN_name=value to pass to script. -@@ -1759,7 +1759,7 @@ +@@ -1766,23 +1766,23 @@ from a malicious or compromised server. .\"********************************************************* .TP @@ -1489,7 +1527,37 @@ This directive offers policy-level control over OpenVPN's usage of external programs and scripts. Lower .B level -@@ -1792,25 +1792,25 @@ + values are more restrictive, higher values are more permissive. Settings for + .B level: + +-.B 0 -- ++.B 0 \-\- + Strictly no calling of external programs. + .br +-.B 1 -- ++.B 1 \-\- + (Default) Only call built-in executables such as ifconfig, ip, route, or netsh. + .br +-.B 2 -- ++.B 2 \-\- + Allow calling of built-in executables and user-defined scripts. + .br +-.B 3 -- ++.B 3 \-\- + Allow passwords to be passed to scripts via environmental variables (potentially unsafe). + + The +@@ -1791,33 +1791,33 @@ + Settings for + .B method: + +-.B execve -- ++.B execve \-\- + (default) Use execve() function on Unix family OSes and CreateProcess() on Windows. + .br +-.B system -- ++.B system \-\- + Use system() function (deprecated and less safe since the external program command line is subject to shell expansion). The @@ -1521,7 +1589,7 @@ Change the user ID of the OpenVPN process to .B user after initialization, dropping privileges in the process. -@@ -1832,7 +1832,7 @@ +@@ -1839,7 +1839,7 @@ signal (for example in response to a DHCP reset), you should make use of one or more of the @@ -1530,7 +1598,7 @@ options to ensure that OpenVPN doesn't need to execute any privileged operations in order to restart (such as re-reading key files or running -@@ -1840,16 +1840,16 @@ +@@ -1847,16 +1847,16 @@ on the TUN device). .\"********************************************************* .TP @@ -1550,7 +1618,7 @@ Change directory to .B dir prior to reading any files such as -@@ -1861,16 +1861,16 @@ +@@ -1868,16 +1868,16 @@ This option is useful when you are running OpenVPN in @@ -1570,16 +1638,51 @@ essentially redefines .B dir as being the top -@@ -1889,7 +1889,7 @@ +@@ -1896,22 +1896,22 @@ are executed after the chroot operation. .\"********************************************************* .TP +-.B --setcon context ++.B \-\-setcon context + Apply SELinux + .B context + after initialization. This + essentially provides the ability to restrict OpenVPN's + rights to only network I/O operations, thanks to + SELinux. This goes further than +-.B --user ++.B \-\-user + and +-.B --chroot ++.B \-\-chroot + in that those two, while being great security features, + unfortunately do not protect against privilege escalation + by exploitation of a vulnerable system call. You can of + course combine all three, but please note that since + setcon requires access to /proc you will have to provide +-it inside the chroot directory (e.g. with mount --bind). ++it inside the chroot directory (e.g. with mount \-\-bind). + + Since the setcon operation is delayed until after + initialization, OpenVPN can be restricted to just +@@ -1923,13 +1923,13 @@ + Like with chroot, complications can result when scripts + or restarts are executed after the setcon operation, + which is why you should really consider using the +-.B --persist-key ++.B \-\-persist-key + and +-.B --persist-tun ++.B \-\-persist-tun + options. + .\"********************************************************* + .TP -.B --daemon [progname] +.B \-\-daemon [progname] Become a daemon after all initialization functions are completed. This option will cause all message and error output to be sent to the syslog file (such as /var/log/messages), -@@ -1898,10 +1898,10 @@ +@@ -1938,10 +1938,10 @@ which will go to /dev/null unless otherwise redirected. The syslog redirection occurs immediately at the point that @@ -1592,7 +1695,7 @@ options is present, it will supercede syslog redirection. -@@ -1917,7 +1917,7 @@ +@@ -1957,7 +1957,7 @@ defaults to "openvpn". When OpenVPN is run with the @@ -1601,7 +1704,7 @@ option, it will try to delay daemonization until the majority of initialization functions which are capable of generating fatal errors are complete. This means that initialization scripts can test the return status of the -@@ -1927,20 +1927,20 @@ +@@ -1967,20 +1967,20 @@ In OpenVPN, the vast majority of errors which occur after initialization are non-fatal. .\"********************************************************* .TP @@ -1626,7 +1729,7 @@ Use this option when OpenVPN is being run from the inetd or .BR xinetd(8) server. -@@ -1951,7 +1951,7 @@ +@@ -1991,7 +1991,7 @@ config file. The .B nowait mode can only be used with @@ -1635,7 +1738,7 @@ The default is .B wait. The -@@ -1963,16 +1963,16 @@ +@@ -2003,16 +2003,16 @@ .I http://openvpn.net/faq.html#oneport This option precludes the use of @@ -1656,7 +1759,7 @@ Also note that in .B wait -@@ -1982,7 +1982,7 @@ +@@ -2022,7 +2022,7 @@ .I http://openvpn.net/1xhowto.html .\"********************************************************* .TP @@ -1665,7 +1768,7 @@ Output logging messages to .B file, including output to stdout/stderr which -@@ -1993,44 +1993,44 @@ +@@ -2033,44 +2033,44 @@ This option takes effect immediately when it is parsed in the command line and will supercede syslog output if @@ -1718,7 +1821,7 @@ Change process priority after initialization ( .B n -@@ -2039,14 +2039,14 @@ +@@ -2079,14 +2079,14 @@ less than zero is higher priority). .\"********************************************************* .\".TP @@ -1736,7 +1839,7 @@ .\"specified). .\" .\"Using a TLS thread offloads the CPU-intensive process of SSL/TLS-based -@@ -2056,12 +2056,12 @@ +@@ -2096,12 +2096,12 @@ .\"The parameter .\".B n .\"is interpreted exactly as with the @@ -1751,7 +1854,7 @@ (Experimental) Optimize TUN/TAP/UDP I/O writes by avoiding a call to poll/epoll/select prior to the write operation. The purpose of such a call would normally be to block until the device -@@ -2072,13 +2072,13 @@ +@@ -2112,13 +2112,13 @@ by 5% to 10%. This option can only be used on non-Windows systems, when @@ -1763,12 +1866,29 @@ is NOT specified. .\"********************************************************* .TP +-.B --multihome ++.B \-\-multihome + Configure a multi-homed UDP server. This option can be used when + OpenVPN has been configured to listen on all interfaces, and will + attempt to bind client sessions to the interface on which packets +@@ -2127,13 +2127,13 @@ + UDP servers and currently is only implemented on Linux. + + Note: clients connecting to a +-.B --multihome ++.B \-\-multihome + server should always use the +-.B --nobind ++.B \-\-nobind + option. + .\"********************************************************* + .TP -.B --echo [parms...] +.B \-\-echo [parms...] Echo .B parms to log output. -@@ -2087,7 +2087,7 @@ +@@ -2142,7 +2142,7 @@ which is receiving the OpenVPN log output. .\"********************************************************* .TP @@ -1777,7 +1897,7 @@ Control whether internally or externally generated SIGUSR1 signals are remapped to SIGHUP (restart without persisting state) or -@@ -2098,20 +2098,20 @@ +@@ -2153,20 +2153,20 @@ occurs. .\"********************************************************* .TP @@ -1802,7 +1922,7 @@ Output .B R and -@@ -2119,12 +2119,12 @@ +@@ -2174,12 +2174,12 @@ characters to the console for each packet read and write, uppercase is used for TCP/UDP packets and lowercase is used for TUN/TAP packets. .br @@ -1817,7 +1937,7 @@ Write operational status to .B file every -@@ -2136,20 +2136,20 @@ +@@ -2191,21 +2191,21 @@ signal. .\"********************************************************* .TP @@ -1837,11 +1957,13 @@ .\"********************************************************* .TP -.B --comp-lzo [mode] +-Use fast LZO compression -- may add up to 1 byte per +.B \-\-comp-lzo [mode] - Use fast LZO compression -- may add up to 1 byte per ++Use fast LZO compression \-\- may add up to 1 byte per packet for incompressible data. .B mode -@@ -2160,16 +2160,16 @@ + may be "yes", "no", or "adaptive" (default). +@@ -2215,16 +2215,16 @@ First, make sure the client-side config file enables selective compression by having at least one @@ -1861,7 +1983,7 @@ file, specify the compression setting for the client, for example: -@@ -2188,12 +2188,12 @@ +@@ -2243,12 +2243,12 @@ side of the link, the second sets the client side. .\"********************************************************* .TP @@ -1877,7 +1999,7 @@ Adaptive compression tries to optimize the case where you have compression enabled, but you are sending predominantly uncompressible -@@ -2205,7 +2205,7 @@ +@@ -2260,7 +2260,7 @@ compression for a period of time until the next re-sample test. .\"********************************************************* .TP @@ -1886,7 +2008,7 @@ Enable a TCP server on .B IP:port to handle daemon management functions. -@@ -2224,9 +2224,9 @@ +@@ -2279,9 +2279,9 @@ .B port to 'unix'. While the default behavior is to create a unix domain socket that may be connected to by any process, the @@ -1898,7 +2020,7 @@ directives can be used to restrict access. The management interface provides a special mode where the TCP -@@ -2255,24 +2255,24 @@ +@@ -2310,24 +2310,24 @@ server to local clients. .\"********************************************************* .TP @@ -1928,7 +2050,7 @@ Start OpenVPN in a hibernating state, until a client of the management interface explicitly starts it with the -@@ -2280,45 +2280,45 @@ +@@ -2335,45 +2335,45 @@ command. .\"********************************************************* .TP @@ -1981,7 +2103,7 @@ Load plug-in module from the file .B module-pathname, passing -@@ -2354,7 +2354,7 @@ +@@ -2409,7 +2409,7 @@ .SS Server Mode Starting with OpenVPN 2.0, a multi-client TCP/UDP server mode is supported, and can be enabled with the @@ -1990,7 +2112,7 @@ option. In server mode, OpenVPN will listen on a single port for incoming client connections. All client connections will be routed through a single tun or tap -@@ -2364,7 +2364,7 @@ +@@ -2419,7 +2419,7 @@ be used in this mode. .\"********************************************************* .TP @@ -1999,7 +2121,7 @@ A helper directive designed to simplify the configuration of OpenVPN's server mode. This directive will set up an OpenVPN server which will allocate addresses to clients -@@ -2374,7 +2374,7 @@ +@@ -2429,7 +2429,7 @@ TUN/TAP interface. For example, @@ -2008,7 +2130,7 @@ expands as follows: .nf -@@ -2404,23 +2404,23 @@ +@@ -2459,23 +2459,23 @@ .fi Don't use @@ -2038,7 +2160,7 @@ is used without any parameters, it will enable a DHCP-proxy mode, where connecting OpenVPN clients will receive an IP address for their TAP adapter from the DHCP server running -@@ -2448,7 +2448,7 @@ +@@ -2503,7 +2503,7 @@ and .B netmask parameters to @@ -2047,7 +2169,7 @@ can be set to either the IP/netmask of the bridge interface, or the IP/netmask of the default gateway/router on the bridged -@@ -2480,7 +2480,7 @@ +@@ -2535,7 +2535,7 @@ .fi In another example, @@ -2056,7 +2178,7 @@ (without parameters) expands as follows: .nf -@@ -2495,7 +2495,7 @@ +@@ -2550,7 +2550,7 @@ .fi Or @@ -2065,7 +2187,7 @@ expands as follows: .nf -@@ -2508,13 +2508,13 @@ +@@ -2563,13 +2563,13 @@ .fi .\"********************************************************* .TP @@ -2081,7 +2203,7 @@ in its config file. The set of options which can be pushed is limited by both feasibility and security. Some options such as those which would execute scripts -@@ -2525,44 +2525,44 @@ +@@ -2580,44 +2580,44 @@ them before the connection to the server can be initiated. This is a partial list of options which can currently be pushed: @@ -2142,7 +2264,7 @@ Set aside a pool of subnets to be dynamically allocated to connecting clients, similar to a DHCP server. For tun-style -@@ -2575,7 +2575,7 @@ +@@ -2630,7 +2630,7 @@ .\"********************************************************* .TP @@ -2151,7 +2273,7 @@ Persist/unpersist ifconfig-pool data to .B file, -@@ -2590,7 +2590,7 @@ +@@ -2645,7 +2645,7 @@ Maintaining a long-term association is good for clients because it allows them to effectively use the @@ -2160,7 +2282,7 @@ option. .B file -@@ -2611,32 +2611,32 @@ +@@ -2666,32 +2666,32 @@ a common name and IP address. They do not guarantee that the given common name will always receive the given IP address. If you want guaranteed assignment, use @@ -2200,7 +2322,7 @@ directive which you want to execute on the client machine to configure the remote end of the tunnel. Note that the parameters .B local -@@ -2649,13 +2649,13 @@ +@@ -2704,13 +2704,13 @@ This option must be associated with a specific client instance, which means that it must be specified either in a client instance config file using @@ -2217,7 +2339,7 @@ directive in the main OpenVPN config file which encloses .B local, so that the kernel will know to route it -@@ -2665,23 +2665,23 @@ +@@ -2720,23 +2720,23 @@ follows: .B 1 @@ -2248,7 +2370,7 @@ Generate an internal route to a specific client. The .B netmask -@@ -2692,36 +2692,36 @@ +@@ -2747,36 +2747,36 @@ of where the client is connecting from. Remember that you must also add the route to the system routing table as well (such as by using the @@ -2295,7 +2417,7 @@ to effect this. In order for all clients to see A's subnet, OpenVPN must push this route to all clients EXCEPT for A, since the subnet is already owned by A. -@@ -2730,11 +2730,11 @@ +@@ -2785,11 +2785,11 @@ if it matches one of the client's iroutes. .\"********************************************************* .TP @@ -2309,7 +2431,7 @@ flag tells OpenVPN to internally route client-to-client traffic rather than pushing all client-originating traffic to the TUN/TAP interface. -@@ -2746,13 +2746,13 @@ +@@ -2801,13 +2801,13 @@ custom, per-client rules. .\"********************************************************* .TP @@ -2325,7 +2447,7 @@ Run .B script on client connection. The script is passed the common name -@@ -2768,7 +2768,7 @@ +@@ -2823,7 +2823,7 @@ it should write it to the file named by $1. See the @@ -2334,7 +2456,7 @@ option below for options which can be legally used in a dynamically generated config file. -@@ -2780,18 +2780,18 @@ +@@ -2835,18 +2835,18 @@ to be disconnected. .\"********************************************************* .TP @@ -2357,7 +2479,7 @@ script or plugins are cascaded, and at least one client-connect function succeeded, then ALL of the client-disconnect functions for scripts and plugins will be called on client instance object deletion, -@@ -2800,7 +2800,7 @@ +@@ -2855,7 +2855,7 @@ .B .\"********************************************************* .TP @@ -2366,7 +2488,7 @@ Specify a directory .B dir for custom client config files. After -@@ -2814,9 +2814,9 @@ +@@ -2869,9 +2869,9 @@ This file can specify a fixed IP address for a given client using @@ -2378,7 +2500,7 @@ One of the useful properties of this option is that it allows client configuration files to be conveniently -@@ -2825,28 +2825,28 @@ +@@ -2880,28 +2880,28 @@ The following options are legal in a client-specific context: @@ -2414,7 +2536,7 @@ Set the size of the real address hash table to .B r and the virtual address table to -@@ -2854,13 +2854,13 @@ +@@ -2909,13 +2909,13 @@ By default, both tables are sized at 256 buckets. .\"********************************************************* .TP @@ -2430,7 +2552,7 @@ Maximum number of output packets queued before TCP (default=64). When OpenVPN is tunneling data from a TUN/TAP device to a -@@ -2872,7 +2872,7 @@ +@@ -2927,7 +2927,7 @@ at this client. .\"********************************************************* .TP @@ -2439,7 +2561,7 @@ This macro sets the TCP_NODELAY socket flag on the server as well as pushes it to connecting clients. The TCP_NODELAY flag disables the Nagle algorithm on TCP sockets causing -@@ -2895,13 +2895,13 @@ +@@ -2950,13 +2950,13 @@ .fi .\"********************************************************* .TP @@ -2455,7 +2577,7 @@ Allow a maximum of .B n internal routes per client (default=256). -@@ -2911,9 +2911,9 @@ +@@ -2966,9 +2966,9 @@ forcing the server to deplete virtual memory as its internal routing table expands. This directive can be used in a @@ -2467,7 +2589,7 @@ script to override the global value for a particular client. Note that this -@@ -2921,7 +2921,7 @@ +@@ -2976,7 +2976,7 @@ kernel routing table. .\"********************************************************* .TP @@ -2476,7 +2598,7 @@ Allow a maximum of .B n new connections per -@@ -2935,12 +2935,12 @@ +@@ -2990,12 +2990,12 @@ For the best protection against DoS attacks in server mode, use @@ -2492,7 +2614,7 @@ Run script or shell command .B cmd to validate client virtual addresses or routes. -@@ -2948,19 +2948,19 @@ +@@ -3003,19 +3003,19 @@ .B cmd will be executed with 3 parameters: @@ -2516,7 +2638,7 @@ The common name on the certificate associated with the client linked to this address. Only present for "add" or "update" operations, not "delete". -@@ -2980,7 +2980,7 @@ +@@ -3035,7 +3035,7 @@ rather than the low level client virtual addresses. .\"********************************************************* .TP @@ -2525,7 +2647,7 @@ Require the client to provide a username/password (possibly in addition to a client certificate) for authentication. -@@ -3011,10 +3011,10 @@ +@@ -3066,10 +3066,10 @@ and the file will be automatically deleted by OpenVPN after the script returns. The location of the temporary file is controlled by the @@ -2538,7 +2660,7 @@ to a volatile storage medium such as .B /dev/shm (if available) to prevent the username/password file from touching the hard drive. -@@ -3046,7 +3046,7 @@ +@@ -3101,7 +3101,7 @@ in the OpenVPN source distribution. .\"********************************************************* .TP @@ -2547,7 +2669,7 @@ Clients that connect with options that are incompatible with those of the server will be disconnected. -@@ -3056,16 +3056,16 @@ +@@ -3111,16 +3111,16 @@ no-replay, no-iv, tls-auth, key-method, tls-server, and tls-client. This option requires that @@ -2568,7 +2690,7 @@ is specified (or an authentication plugin module), the OpenVPN server daemon will require connecting clients to specify a username and password. This option makes the submission of a username/password -@@ -3078,35 +3078,35 @@ +@@ -3133,35 +3133,35 @@ to detect this condition and respond accordingly. .\"********************************************************* .TP @@ -2611,7 +2733,7 @@ Allow Common Name, X509 Subject, and username strings to include any printable character including space, but excluding control characters such as tab, newline, and carriage-return. -@@ -3127,7 +3127,7 @@ +@@ -3182,7 +3182,7 @@ know what you are doing! .\"********************************************************* .TP @@ -2620,7 +2742,7 @@ When run in TCP server mode, share the OpenVPN port with another application, such as an HTTPS server. If OpenVPN senses a connection to its port which is using a non-OpenVPN -@@ -3142,13 +3142,13 @@ +@@ -3197,13 +3197,13 @@ .SS Client Mode Use client mode when connecting to an OpenVPN server which has @@ -2637,7 +2759,7 @@ A helper directive designed to simplify the configuration of OpenVPN's client mode. This directive is equivalent to: -@@ -3162,33 +3162,33 @@ +@@ -3217,33 +3217,33 @@ .fi .\"********************************************************* .TP @@ -2679,7 +2801,7 @@ by defining ENABLE_PASSWORD_SAVE in config-win32.h). If -@@ -3197,12 +3197,12 @@ +@@ -3252,12 +3252,12 @@ console. The server configuration must specify an @@ -2694,7 +2816,7 @@ Controls how OpenVPN responds to username/password verification errors such as the client-side response to an AUTH_FAILED message from the server or verification failure of the private key password. -@@ -3213,33 +3213,33 @@ +@@ -3268,40 +3268,40 @@ An AUTH_FAILED message is generated by the server if the client fails @@ -2731,12 +2853,20 @@ from the management interface. .\"********************************************************* .TP +-.B --server-poll-timeout n ++.B \-\-server-poll-timeout n + when polling possible remote servers to connect to + in a round-robin fashion, spend no more than + .B n + seconds waiting for a response before trying the next server. + .\"********************************************************* + .TP -.B --explicit-exit-notify [n] +.B \-\-explicit-exit-notify [n] In UDP client mode or point-to-point mode, send server/peer an exit notification if tunnel is restarted or OpenVPN process is exited. In client mode, on exit/restart, this -@@ -3254,12 +3254,12 @@ +@@ -3316,12 +3316,12 @@ (must be compatible between peers). .\"********************************************************* .TP @@ -2751,7 +2881,7 @@ The optional .B direction -@@ -3290,7 +3290,7 @@ +@@ -3352,7 +3352,7 @@ .B direction parameter, will also support 2048 bit key file generation using the @@ -2760,7 +2890,7 @@ option. Static key encryption mode has certain advantages, -@@ -3320,7 +3320,7 @@ +@@ -3382,7 +3382,7 @@ but random-looking data. .\"********************************************************* .TP @@ -2769,7 +2899,7 @@ Authenticate packets with HMAC using message digest algorithm .B alg. -@@ -3335,7 +3335,7 @@ +@@ -3397,7 +3397,7 @@ In static-key encryption mode, the HMAC key is included in the key file generated by @@ -2778,7 +2908,7 @@ In TLS mode, the HMAC key is dynamically generated and shared between peers via the TLS control channel. If OpenVPN receives a packet with a bad HMAC it will drop the packet. -@@ -3348,7 +3348,7 @@ +@@ -3410,7 +3410,7 @@ .I http://www.cs.ucsd.edu/users/mihir/papers/hmac.html .\"********************************************************* .TP @@ -2787,7 +2917,7 @@ Encrypt packets with cipher algorithm .B alg. The default is -@@ -3363,7 +3363,7 @@ +@@ -3425,7 +3425,7 @@ To see other ciphers that are available with OpenVPN, use the @@ -2796,7 +2926,7 @@ option. OpenVPN supports the CBC, CFB, and OFB cipher modes, -@@ -3375,10 +3375,10 @@ +@@ -3437,10 +3437,10 @@ to disable encryption. .\"********************************************************* .TP @@ -2809,7 +2939,7 @@ option (see below) shows all available OpenSSL ciphers, their default key sizes, and whether the key size can be changed. Use care in changing a cipher's default -@@ -3388,7 +3388,7 @@ +@@ -3450,7 +3450,7 @@ security, or may even reduce security. .\"********************************************************* .TP @@ -2818,7 +2948,7 @@ (Advanced) For PRNG (Pseudo-random number generator), use digest algorithm .B alg -@@ -3403,19 +3403,19 @@ +@@ -3465,19 +3465,19 @@ instead for all of OpenVPN's pseudo-random number needs. .\"********************************************************* .TP @@ -2841,7 +2971,7 @@ (Advanced) Disable OpenVPN's protection against replay attacks. Don't use this option unless you are prepared to make a tradeoff of greater efficiency in exchange for less -@@ -3459,7 +3459,7 @@ +@@ -3521,7 +3521,7 @@ by IPSec. .\"********************************************************* .TP @@ -2850,7 +2980,7 @@ Use a replay protection sliding-window of size .B n and a time window of -@@ -3474,9 +3474,9 @@ +@@ -3536,9 +3536,9 @@ This option is only relevant in UDP mode, i.e. when either @@ -2862,7 +2992,7 @@ option is specified. When OpenVPN tunnels IP packets over UDP, there is the possibility that -@@ -3488,7 +3488,7 @@ +@@ -3550,7 +3550,7 @@ .B (a) The packet cannot be a replay (unless @@ -2871,7 +3001,7 @@ is specified, which disables replay protection altogether). .B (b) -@@ -3510,7 +3510,7 @@ +@@ -3572,7 +3572,7 @@ Satellite links in particular often require this. If you run OpenVPN at @@ -2880,7 +3010,7 @@ you will see the message "Replay-window backtrack occurred [x]" every time the maximum sequence number backtrack seen thus far increases. This can be used to calibrate -@@ -3546,7 +3546,7 @@ +@@ -3608,7 +3608,7 @@ is easily fixed by simply using TCP as the VPN transport layer. .\"********************************************************* .TP @@ -2889,7 +3019,7 @@ Silence the output of replay warnings, which are a common false alarm on WiFi networks. This option preserves the security of the replay protection code without -@@ -3554,7 +3554,7 @@ +@@ -3616,7 +3616,7 @@ packets. .\"********************************************************* .TP @@ -2898,7 +3028,7 @@ Persist replay-protection state across sessions using .B file to save and reload the state. -@@ -3562,7 +3562,7 @@ +@@ -3624,7 +3624,7 @@ This option will strengthen protection against replay attacks, especially when you are using OpenVPN in a dynamic context (such as with @@ -2907,7 +3037,7 @@ when OpenVPN sessions are frequently started and stopped. This option will keep a disk copy of the current replay protection -@@ -3573,12 +3573,12 @@ +@@ -3635,12 +3635,12 @@ This option only makes sense when replay protection is enabled (the default) and you are using either @@ -2923,7 +3053,7 @@ (Advanced) Disable OpenVPN's use of IV (cipher initialization vector). Don't use this option unless you are prepared to make a tradeoff of greater efficiency in exchange for less -@@ -3599,24 +3599,24 @@ +@@ -3661,24 +3661,24 @@ datagram replay protection as the IV. .\"********************************************************* .TP @@ -2954,7 +3084,7 @@ This option is very useful to test OpenVPN after it has been ported to a new platform, or to isolate problems in the compiler, OpenSSL -@@ -3640,17 +3640,17 @@ +@@ -3702,17 +3702,17 @@ To use TLS mode, each peer that runs OpenVPN should have its own local certificate/key pair ( @@ -2976,7 +3106,7 @@ If that check on both peers succeeds, then the TLS negotiation will succeed, both OpenVPN -@@ -3667,18 +3667,18 @@ +@@ -3729,18 +3729,18 @@ .I http://openvpn.net/easyrsa.html .\"********************************************************* .TP @@ -2998,7 +3128,7 @@ Certificate authority (CA) file in .pem format, also referred to as the .I root certificate. This file can have multiple -@@ -3700,10 +3700,10 @@ +@@ -3762,10 +3762,10 @@ they are distributed with OpenVPN, they are totally insecure. .\"********************************************************* .TP @@ -3011,7 +3141,7 @@ only). Use .B openssl dhparam -out dh1024.pem 1024 -@@ -3713,15 +3713,15 @@ +@@ -3775,15 +3775,15 @@ may be considered public. .\"********************************************************* .TP @@ -3031,7 +3161,7 @@ certificate authority file. You can easily make your own certificate authority (see above) or pay money to use a commercial service such as thawte.com (in which case you will be -@@ -3746,7 +3746,7 @@ +@@ -3808,7 +3808,7 @@ command reads the location of the certificate authority key from its configuration file such as .B /usr/share/ssl/openssl.cnf @@ -3040,7 +3170,7 @@ that for certificate authority functions, you must set up the files .B index.txt (may be empty) and -@@ -3757,61 +3757,61 @@ +@@ -3819,90 +3819,90 @@ ). .\"********************************************************* .TP @@ -3116,7 +3246,26 @@ Specify which method to use in order to perform private key operations. A different mode can be specified for each provider. Mode is encoded as hex number, and can be a mask one of the following: -@@ -3833,14 +3833,14 @@ + + .B 0 +-(default) -- Try to determind automatically. ++(default) \-\- Try to determind automatically. + .br + .B 1 +--- Use sign. ++\-\- Use sign. + .br + .B 2 +--- Use sign recover. ++\-\- Use sign recover. + .br + .B 4 +--- Use decrypt. ++\-\- Use decrypt. + .br + .B 8 +--- Use unwrap. ++\-\- Use unwrap. .br .\"********************************************************* .TP @@ -3134,7 +3283,7 @@ This makes it possible to use any smart card, supported by Windows, but also any -@@ -3866,7 +3866,7 @@ +@@ -3928,7 +3928,7 @@ .\"********************************************************* .TP @@ -3143,7 +3292,7 @@ Use data channel key negotiation method .B m. The key method must match on both sides of the connection. -@@ -3894,16 +3894,16 @@ +@@ -3956,16 +3956,16 @@ of the connection producing certificates and verifying the certificate (or other authentication info provided) of the other side. The @@ -3163,7 +3312,7 @@ A list .B l of allowable TLS ciphers delimited by a colon (":"). -@@ -3913,11 +3913,11 @@ +@@ -3975,11 +3975,11 @@ to force two peers to negotiate to the lowest level of security they both support. Use @@ -3177,7 +3326,7 @@ Packet retransmit timeout on TLS control channel if no acknowledgment from remote within .B n -@@ -3934,7 +3934,7 @@ +@@ -3996,7 +3996,7 @@ such as TCP expect this role to be left to them. .\"********************************************************* .TP @@ -3186,7 +3335,7 @@ Renegotiate data channel key after .B n bytes sent or received (disabled by default). -@@ -3944,13 +3944,13 @@ +@@ -4006,13 +4006,13 @@ if any of these three criteria are met by either peer. .\"********************************************************* .TP @@ -3202,7 +3351,7 @@ Renegotiate data channel key after .B n seconds (default=3600). -@@ -3961,16 +3961,16 @@ +@@ -4023,16 +4023,16 @@ Also, keep in mind that this option can be used on both the client and server, and whichever uses the lower value will be the one to trigger the renegotiation. A common mistake is to set @@ -3223,7 +3372,7 @@ .B n seconds of handshake initiation by any peer (default = 60 seconds). -@@ -3978,47 +3978,47 @@ +@@ -4040,47 +4040,47 @@ we will attempt to reset our connection with our peer and try again. Even in the event of handshake failure we will still use our expiring key for up to @@ -3282,7 +3431,7 @@ enables a kind of "HMAC firewall" on OpenVPN's TCP/UDP port, where TLS control channel packets bearing an incorrect HMAC signature can be dropped immediately without -@@ -4029,7 +4029,7 @@ +@@ -4091,7 +4091,7 @@ .B (1) An OpenVPN static key file generated by @@ -3291,7 +3440,7 @@ (required if .B direction parameter is used). -@@ -4047,19 +4047,19 @@ +@@ -4109,19 +4109,19 @@ a static key file, format (2) will be used. See the @@ -3316,7 +3465,7 @@ The rationale for this feature is as follows. TLS requires a multi-packet exchange -@@ -4086,7 +4086,7 @@ +@@ -4148,7 +4148,7 @@ minimize the amount of resources a potential, but as yet unauthenticated, client is able to consume. @@ -3325,7 +3474,7 @@ does this by signing every TLS control channel packet with an HMAC signature, including packets which are sent before the TLS level has had a chance to authenticate the peer. -@@ -4094,20 +4094,20 @@ +@@ -4156,20 +4156,20 @@ the correct signature can be dropped immediately upon reception, before they have a chance to consume additional system resources such as by initiating a TLS handshake. @@ -3350,7 +3499,7 @@ Get certificate password from console or .B file before we daemonize. -@@ -4116,7 +4116,7 @@ +@@ -4178,7 +4178,7 @@ security conscious, it is possible to protect your private key with a password. Of course this means that every time the OpenVPN daemon is started you must be there to type the password. The @@ -3359,7 +3508,7 @@ option allows you to start OpenVPN from the command line. It will query you for a password before it daemonizes. To protect a private key with a password you should omit the -@@ -4133,15 +4133,15 @@ +@@ -4195,15 +4195,15 @@ to a certain extent invalidates the extra security provided by using an encrypted key (Note: OpenVPN will only read passwords from a file if it has been built @@ -3379,7 +3528,7 @@ username/passwords in virtual memory. If specified, this directive will cause OpenVPN to immediately -@@ -4151,19 +4151,19 @@ +@@ -4213,19 +4213,19 @@ OpenVPN session. This directive does not affect the @@ -3403,7 +3552,7 @@ test). .B cmd -@@ -4196,7 +4196,7 @@ +@@ -4258,7 +4258,7 @@ to build a command line which will be passed to the script. .\"********************************************************* .TP @@ -3412,7 +3561,7 @@ Accept connections only from a host with X509 name or common name equal to .B name. -@@ -4206,24 +4206,24 @@ +@@ -4268,24 +4268,24 @@ Name can also be a common name prefix, for example if you want a client to only accept connections to "Server-1", "Server-2", etc., you can simply use @@ -3443,7 +3592,7 @@ Require that peer certificate was signed with an explicit .B nsCertType designation of "client" or "server". -@@ -4238,19 +4238,19 @@ +@@ -4300,19 +4300,19 @@ If the server certificate's nsCertType field is set to "server", then the clients can verify this with @@ -3467,7 +3616,7 @@ Require that peer certificate was signed with an explicit .B key usage. -@@ -4261,7 +4261,7 @@ +@@ -4323,7 +4323,7 @@ usage can be specified. .\"********************************************************* .TP @@ -3476,7 +3625,7 @@ Require that peer certificate was signed with an explicit .B extended key usage. -@@ -4272,7 +4272,7 @@ +@@ -4334,7 +4334,7 @@ OpenSSL symbolic representation. .\"********************************************************* .TP @@ -3485,7 +3634,7 @@ Require that peer certificate was signed with an explicit .B key usage and -@@ -4283,18 +4283,18 @@ +@@ -4345,18 +4345,18 @@ the host they connect to is a designated server. The @@ -3508,7 +3657,7 @@ The key usage is digitalSignature and ( keyEncipherment or keyAgreement ). -@@ -4303,12 +4303,12 @@ +@@ -4365,12 +4365,12 @@ attempts to connect to another client by impersonating the server. The attack is easily prevented by having clients verify the server certificate using any one of @@ -3524,7 +3673,7 @@ Check peer certificate against the file .B crl in PEM format. -@@ -4328,28 +4328,28 @@ +@@ -4390,28 +4390,28 @@ .SS SSL Library information: .\"********************************************************* .TP @@ -3559,7 +3708,7 @@ (Standalone) Show currently available hardware-based crypto acceleration engines supported by the OpenSSL library. -@@ -4358,18 +4358,18 @@ +@@ -4420,18 +4420,18 @@ Used only for non-TLS static key encryption mode. .\"********************************************************* .TP @@ -3581,7 +3730,7 @@ Write key to .B file. .\"********************************************************* -@@ -4378,7 +4378,7 @@ +@@ -4440,7 +4440,7 @@ of OpenVPN which can be used to create and delete persistent tunnels. .\"********************************************************* .TP @@ -3590,7 +3739,7 @@ (Standalone) Create a persistent tunnel on platforms which support them such as Linux. Normally TUN/TAP tunnels exist only for -@@ -4389,9 +4389,9 @@ +@@ -4451,9 +4451,9 @@ One of the advantages of persistent tunnels is that they eliminate the need for separate @@ -3602,7 +3751,7 @@ scripts to run the appropriate .BR ifconfig (8) and -@@ -4403,40 +4403,40 @@ +@@ -4465,40 +4465,40 @@ will not be reset if the OpenVPN peer restarts. This can be useful to provide uninterrupted connectivity through the tunnel in the event of a DHCP reset of the peer's public IP address (see the @@ -3651,7 +3800,7 @@ Set the Windows system directory pathname to use when looking for system executables such as .B route.exe -@@ -4452,14 +4452,14 @@ +@@ -4514,23 +4514,23 @@ environmental variable. .\"********************************************************* .TP @@ -3667,9 +3816,20 @@ -.B --ifconfig. +.B \-\-ifconfig. - .B manual -- +-.B manual -- ++.B manual \-\- Don't set the IP address or netmask automatically. -@@ -4478,13 +4478,13 @@ + Instead output a message + to the console telling the user to configure the + adapter manually and indicating the IP/netmask which + OpenVPN expects the adapter to be set to. + +-.B dynamic [offset] [lease-time] -- ++.B dynamic [offset] [lease-time] \-\- + Automatically set the IP address and netmask by replying to + DHCP query messages generated by the kernel. This mode is + probably the "cleanest" solution +@@ -4540,13 +4540,13 @@ adapter must be set to "Obtain an IP address automatically," and (2) OpenVPN needs to claim an IP address in the subnet for use as the virtual DHCP server address. By default in @@ -3685,7 +3845,7 @@ mode, OpenVPN will cause the DHCP server to masquerade as if it were coming from the remote endpoint. The optional offset parameter is an integer which is > -256 and < 256 and which defaults to 0. -@@ -4506,13 +4506,13 @@ +@@ -4568,13 +4568,13 @@ being lost when the system goes to sleep. The default lease time is one year. @@ -3701,7 +3861,7 @@ Automatically set the IP address and netmask using the Windows IP Helper API. This approach does not have ideal semantics, though testing has indicated -@@ -4521,7 +4521,7 @@ +@@ -4583,7 +4583,7 @@ adapter in their default state, i.e. "Obtain an IP address automatically." @@ -3710,7 +3870,7 @@ (Default) Try .B dynamic method initially and fail over to -@@ -4551,55 +4551,55 @@ +@@ -4613,55 +4613,55 @@ to a DHCP configuration. .\"********************************************************* .TP @@ -3779,7 +3939,7 @@ Set NetBIOS over TCP/IP Node type. Possible options: .B 1 = b-node (broadcasts), -@@ -4612,7 +4612,7 @@ +@@ -4674,7 +4674,7 @@ .B 8 = h-node (query name server, then broadcast). @@ -3788,7 +3948,7 @@ Set NetBIOS over TCP/IP Scope. A NetBIOS Scope ID provides an extended naming service for the NetBIOS over TCP/IP (Known as NBT) module. The primary purpose of a NetBIOS scope ID is to isolate NetBIOS traffic on -@@ -4624,19 +4624,19 @@ +@@ -4686,19 +4686,19 @@ scope IDs. The Scope ID becomes a part of the NetBIOS name, making the name unique. (This description of NetBIOS scopes courtesy of NeonSurge@abyss.com) @@ -3812,7 +3972,7 @@ Cause OpenVPN to sleep for .B n seconds immediately after the TAP-Win32 adapter state -@@ -4644,21 +4644,21 @@ +@@ -4706,21 +4706,21 @@ This option is intended to be used to troubleshoot problems with the @@ -3838,7 +3998,7 @@ Ask Windows to renew the TAP adapter lease on startup. This option is normally unnecessary, as Windows automatically triggers a DHCP renegotiation on the TAP adapter when it -@@ -4667,21 +4667,21 @@ +@@ -4729,21 +4729,21 @@ flag. .\"********************************************************* .TP @@ -3864,7 +4024,7 @@ Should be used when OpenVPN is being automatically executed by another program in such a context that no interaction with the user via display or keyboard -@@ -4704,26 +4704,26 @@ +@@ -4766,26 +4766,26 @@ causing all such OpenVPN processes to exit. When executing an OpenVPN process using the @@ -3897,7 +4057,7 @@ (Standalone) Set .B TAP-adapter -@@ -4738,10 +4738,10 @@ +@@ -4800,10 +4800,10 @@ This directive can only be used by an administrator. .\"********************************************************* .TP @@ -3910,7 +4070,7 @@ emulation. Since the TAP-Win32 driver exports an ethernet interface to Windows, and since TUN devices are point-to-point in nature, it is necessary for the TAP-Win32 driver -@@ -4751,7 +4751,7 @@ +@@ -4813,7 +4813,7 @@ must be the middle two addresses of a /30 subnet (netmask 255.255.255.252). .\"********************************************************* .TP @@ -3919,7 +4079,7 @@ (Standalone) Show OpenVPN's view of the system routing table and network adapter list. -@@ -4759,12 +4759,12 @@ +@@ -4821,12 +4821,12 @@ .SS PKCS#11 Standalone Options: .\"********************************************************* .TP @@ -3934,7 +4094,7 @@ option can be used BEFORE this option to produce debugging information. .\"********************************************************* .SH SCRIPTING AND ENVIRONMENTAL VARIABLES -@@ -4774,52 +4774,52 @@ +@@ -4836,52 +4836,52 @@ .SS Script Order of Execution .\"********************************************************* .TP @@ -4001,7 +4161,7 @@ mode on new client connections, when the client is still untrusted. .\"********************************************************* -@@ -4843,7 +4843,7 @@ +@@ -4905,7 +4905,7 @@ .B A: Yes, by using the @@ -4010,7 +4170,7 @@ option, however this should be considered an advanced option. Here is a brief rundown of OpenVPN's current string types and the -@@ -4859,17 +4859,17 @@ +@@ -4921,17 +4921,17 @@ Alphanumeric, underbar ('_'), dash ('-'), dot ('.'), and at ('@'). @@ -4031,7 +4191,7 @@ Alphanumeric, underbar ('_'), dash ('-'), and dot ('.') except for "." or ".." as standalone strings. As of 2.0.1-rc6, the at ('@') character has been added as well for compatibility with the common name character class. -@@ -4899,45 +4899,45 @@ +@@ -4961,45 +4961,45 @@ .B bytes_received Total number of bytes received from client during VPN session. Set prior to execution of the @@ -4085,7 +4245,7 @@ directives are specified, or "0" otherwise. Set on program initiation and reset on SIGHUP. .\"********************************************************* -@@ -4946,30 +4946,30 @@ +@@ -5008,30 +5008,30 @@ The actual name of the TUN/TAP device, including a unit number if it exists. Set prior to @@ -4123,7 +4283,7 @@ is used. Set prior to OpenVPN calling the .I ifconfig -@@ -4977,13 +4977,13 @@ +@@ -5039,13 +5039,13 @@ .I netsh (windows version of ifconfig) commands which normally occurs prior to @@ -4139,7 +4299,7 @@ option (first parameter). Set prior to OpenVPN calling the .I ifconfig -@@ -4991,15 +4991,15 @@ +@@ -5053,15 +5053,15 @@ .I netsh (windows version of ifconfig) commands which normally occurs prior to @@ -4158,7 +4318,7 @@ is used. Set prior to OpenVPN calling the .I ifconfig -@@ -5007,16 +5007,16 @@ +@@ -5069,16 +5069,16 @@ .I netsh (windows version of ifconfig) commands which normally occurs prior to @@ -4178,7 +4338,7 @@ is being used. Set prior to OpenVPN calling the .I ifconfig -@@ -5024,61 +5024,61 @@ +@@ -5086,61 +5086,61 @@ .I netsh (windows version of ifconfig) commands which normally occurs prior to @@ -4255,7 +4415,7 @@ scripts. .\"********************************************************* .TP -@@ -5086,31 +5086,31 @@ +@@ -5148,31 +5148,31 @@ The maximum packet size (not including the IP header) of tunnel data in UDP tunnel transport mode. Set prior to @@ -4293,7 +4453,7 @@ script execution only when the .B via-env modifier is specified, and deleted from the environment -@@ -5119,23 +5119,23 @@ +@@ -5181,23 +5181,23 @@ .TP .B proto The @@ -4321,7 +4481,7 @@ Set on program initiation and reset on SIGHUP. .\"********************************************************* .TP -@@ -5143,29 +5143,29 @@ +@@ -5205,29 +5205,29 @@ The pre-existing default IP gateway in the system routing table. Set prior to @@ -4358,7 +4518,7 @@ script execution. .B parm -@@ -5184,7 +5184,7 @@ +@@ -5246,7 +5246,7 @@ Set to "init" or "restart" prior to up/down script execution. For more information, see documentation for @@ -4367,7 +4527,7 @@ .\"********************************************************* .TP .B script_type -@@ -5200,15 +5200,15 @@ +@@ -5262,15 +5262,15 @@ The reason for exit or restart. Can be one of .B sigusr1, sighup, sigterm, sigint, inactive (controlled by @@ -4386,7 +4546,7 @@ option), .B connection-reset (triggered on TCP connection reset), -@@ -5222,7 +5222,7 @@ +@@ -5284,7 +5284,7 @@ Client connection timestamp, formatted as a human-readable time string. Set prior to execution of the @@ -4395,7 +4555,7 @@ script. .\"********************************************************* .TP -@@ -5230,7 +5230,7 @@ +@@ -5292,7 +5292,7 @@ The duration (in seconds) of the client session which is now disconnecting. Set prior to execution of the @@ -4404,7 +4564,7 @@ script. .\"********************************************************* .TP -@@ -5238,7 +5238,7 @@ +@@ -5300,7 +5300,7 @@ Client connection timestamp, formatted as a unix integer date/time value. Set prior to execution of the @@ -4413,7 +4573,7 @@ script. .\"********************************************************* .TP -@@ -5248,7 +5248,7 @@ +@@ -5310,7 +5310,7 @@ .B n is the verification level. Only set for TLS connections. Set prior to execution of @@ -4422,7 +4582,7 @@ script. .\"********************************************************* .TP -@@ -5258,34 +5258,34 @@ +@@ -5320,34 +5320,34 @@ .B n is the verification level. Only set for TLS connections. Set prior to execution of @@ -4464,7 +4624,7 @@ scripts. .\"********************************************************* .TP -@@ -5294,12 +5294,12 @@ +@@ -5356,12 +5356,12 @@ yet. Sometimes used to .B nmap the connecting host in a @@ -4480,7 +4640,7 @@ scripts. .\"********************************************************* .TP -@@ -5307,16 +5307,16 @@ +@@ -5369,16 +5369,16 @@ Actual port number of connecting client or peer which has not been authenticated yet. Set prior to execution of @@ -4500,7 +4660,7 @@ script execution only when the .B via-env modifier is specified. -@@ -5328,7 +5328,7 @@ +@@ -5390,7 +5390,7 @@ .B n is the verification level. Only set for TLS connections. Set prior to execution of @@ -4509,7 +4669,7 @@ script. This variable is similar to .B tls_id_{n} except the component X509 subject fields are broken out, and -@@ -5372,30 +5372,30 @@ +@@ -5434,30 +5434,30 @@ except don't re-read configuration file, and possibly don't close and reopen TUN/TAP device, re-read key files, preserve local IP address/port, or preserve most recently authenticated remote IP address/port based on @@ -4546,7 +4706,7 @@ is used, or stdout otherwise). .\"********************************************************* .TP -@@ -5450,7 +5450,7 @@ +@@ -5512,7 +5512,7 @@ the two machines, they should be set to forward UDP port 1194 in both directions. If you do not have control over the firewalls between the two machines, you may still be able to use OpenVPN by adding @@ -4555,7 +4715,7 @@ to each of the .B openvpn commands used below in the examples (this will cause each peer to send out -@@ -5519,11 +5519,11 @@ +@@ -5581,11 +5581,11 @@ .LP On may: .IP @@ -4569,7 +4729,7 @@ .LP Now verify the tunnel is working by pinging across the tunnel. .LP -@@ -5536,17 +5536,17 @@ +@@ -5598,17 +5598,17 @@ .B ping 10.4.0.1 .LP The @@ -4590,7 +4750,7 @@ .LP This command will build a random key file called .B key -@@ -5560,11 +5560,11 @@ +@@ -5622,11 +5622,11 @@ .LP On may: .IP @@ -4604,7 +4764,7 @@ .LP Now verify the tunnel is working by pinging across the tunnel. .LP -@@ -5586,10 +5586,10 @@ +@@ -5648,10 +5648,10 @@ First, build a separate certificate/key pair for both may and june (see above where @@ -4617,7 +4777,7 @@ is discussed for more info). You can also use the included test files client.crt, client.key, server.crt, server.key and ca.crt. -@@ -5602,11 +5602,11 @@ +@@ -5664,11 +5664,11 @@ .LP On may: .IP @@ -4631,7 +4791,7 @@ .LP Now verify the tunnel is working by pinging across the tunnel. .LP -@@ -5619,16 +5619,16 @@ +@@ -5681,16 +5681,16 @@ .B ping 10.4.0.1 .LP Notice the @@ -4651,7 +4811,7 @@ option to use OpenVPN's default key renegotiation interval of one hour. .\"********************************************************* .SS Routing: -@@ -5664,7 +5664,7 @@ +@@ -5726,7 +5726,7 @@ In a production environment, you could put the route command(s) in a shell script and execute with the @@ -4660,7 +4820,7 @@ option. .\"********************************************************* .SH FIREWALLS -@@ -5672,7 +5672,7 @@ +@@ -5734,7 +5734,7 @@ You should add an entry to your firewall rules to allow incoming OpenVPN packets. On Linux 2.4+: .IP @@ -4669,7 +4829,7 @@ .LP This will allow incoming packets on UDP port 1194 (OpenVPN's default UDP port) from an OpenVPN peer at 1.2.3.4. -@@ -5683,7 +5683,7 @@ +@@ -5745,7 +5745,7 @@ is a much more secure method of verifying the authenticity of a packet source. In that case: .IP @@ -4678,7 +4838,7 @@ .LP would be adequate and would not render the host inflexible with respect to its peer having a dynamic IP address. -@@ -5692,7 +5692,7 @@ +@@ -5754,7 +5754,7 @@ not need to add any static rules to the firewall list if you are using a stateful firewall that knows how to track UDP connections. If you specify diff -Nru openvpn-2.1~rc19/debian/patches/redirect-gateway.patch openvpn-2.1.1/debian/patches/redirect-gateway.patch --- openvpn-2.1~rc19/debian/patches/redirect-gateway.patch 2010-01-20 15:18:27.000000000 +0100 +++ openvpn-2.1.1/debian/patches/redirect-gateway.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,17 +0,0 @@ -Index: openvpn-2.1~rc19/options.c -=================================================================== ---- openvpn-2.1~rc19.orig/options.c 2009-10-13 09:30:40.000000000 +0200 -+++ openvpn-2.1~rc19/options.c 2009-10-13 09:30:51.000000000 +0200 -@@ -4398,10 +4398,10 @@ - int j; - VERIFY_PERMISSION (OPT_P_ROUTE); - rol_check_alloc (options); -+ if (streq (p[0], "redirect-gateway")) -+ options->routes->flags |= RG_REROUTE_GW; - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) - { -- if (streq (p[0], "redirect-gateway")) -- options->routes->flags |= RG_REROUTE_GW; - if (streq (p[j], "local")) - options->routes->flags |= RG_LOCAL; - else if (streq (p[j], "autolocal")) diff -Nru openvpn-2.1~rc19/debian/patches/series openvpn-2.1.1/debian/patches/series --- openvpn-2.1~rc19/debian/patches/series 2010-01-20 15:18:27.000000000 +0100 +++ openvpn-2.1.1/debian/patches/series 2010-01-20 15:18:28.000000000 +0100 @@ -1,8 +1,7 @@ auth-pam_libpam_so_filename.patch close_socket_before_scripts.patch -manpage_dash_escaping.patch debian_nogroup_for_sample_files.patch debian_openssl_vulnkeys.patch attemping_typo openvpn-pkcs11warn.patch -redirect-gateway.patch +manpage_dash_escaping.patch diff -Nru openvpn-2.1~rc19/debug/valgrind-suppress openvpn-2.1.1/debug/valgrind-suppress --- openvpn-2.1~rc19/debug/valgrind-suppress 2008-10-09 11:45:48.000000000 +0200 +++ openvpn-2.1.1/debug/valgrind-suppress 2009-10-24 23:43:47.000000000 +0200 @@ -1169,3 +1169,14 @@ fun:main } +{ + + Memcheck:Cond + fun:BN_mod_inverse +} + +{ + + Memcheck:Cond + fun:BN_div +} diff -Nru openvpn-2.1~rc19/error.h openvpn-2.1.1/error.h --- openvpn-2.1~rc19/error.h 2009-05-30 23:34:11.000000000 +0200 +++ openvpn-2.1.1/error.h 2009-10-01 20:02:18.000000000 +0200 @@ -33,7 +33,7 @@ #ifdef ENABLE_PKCS11 #define ERR_BUF_SIZE 8192 #else -#define ERR_BUF_SIZE 1024 +#define ERR_BUF_SIZE 1280 #endif struct gc_arena; diff -Nru openvpn-2.1~rc19/forward.c openvpn-2.1.1/forward.c --- openvpn-2.1~rc19/forward.c 2009-05-30 23:34:11.000000000 +0200 +++ openvpn-2.1.1/forward.c 2009-11-20 14:09:14.000000000 +0100 @@ -32,6 +32,7 @@ #include "event.h" #include "ps.h" #include "dhcp.h" +#include "common.h" #include "memdbg.h" @@ -39,6 +40,9 @@ #include "occ-inline.h" #include "ping-inline.h" +counter_type link_read_bytes_global; /* GLOBAL */ +counter_type link_write_bytes_global; /* GLOBAL */ + /* show event wait debugging info */ #ifdef ENABLE_DEBUG @@ -153,6 +157,8 @@ receive_auth_failed (c, &buf); else if (buf_string_match_head_str (&buf, "PUSH_")) incoming_push_message (c, &buf); + else if (buf_string_match_head_str (&buf, "RESTART")) + server_pushed_restart (c, &buf); else msg (D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR (&buf)); } @@ -172,9 +178,12 @@ check_push_request_dowork (struct context *c) { send_push_request (c); + + /* if no response to first push_request, retry at 5 second intervals */ + event_timeout_modify_wakeup (&c->c2.push_request_interval, 5); } -#endif +#endif /* P2MP */ /* * Things that need to happen immediately after connection initiation should go here. @@ -200,10 +209,8 @@ 0); } #endif - send_push_request (c); - - /* if no reply, try again in 5 sec */ - event_timeout_init (&c->c2.push_request_interval, 5, now); + /* send push request in 1 sec */ + event_timeout_init (&c->c2.push_request_interval, 1, now); reset_coarse_timers (c); } else @@ -309,16 +316,30 @@ #if P2MP +void +check_server_poll_timeout_dowork (struct context *c) +{ + event_timeout_reset (&c->c2.server_poll_interval); + if (!tls_initial_packet_received (c->c2.tls_multi)) + { + msg (M_INFO, "Server poll timeout, restarting"); + c->sig->signal_received = SIGUSR1; + c->sig->signal_text = "server_poll"; + c->persist.restart_sleep_seconds = -1; + } +} + /* - * Schedule a SIGTERM n_seconds from now. + * Schedule a signal n_seconds from now. */ void -schedule_exit (struct context *c, const int n_seconds) +schedule_exit (struct context *c, const int n_seconds, const int signal) { tls_set_single_session (c->c2.tls_multi); update_time (); reset_coarse_timers (c); event_timeout_init (&c->c2.scheduled_exit, n_seconds, now); + c->c2.scheduled_exit_signal = signal; msg (D_SCHED_EXIT, "Delayed exit in %d seconds", n_seconds); } @@ -328,7 +349,7 @@ void check_scheduled_exit_dowork (struct context *c) { - c->sig->signal_received = SIGTERM; + c->sig->signal_received = c->c2.scheduled_exit_signal; c->sig->signal_text = "delayed-exit"; } @@ -511,6 +532,10 @@ return; #if P2MP + check_server_poll_timeout (c); + if (c->sig->signal_received) + return; + check_scheduled_exit (c); if (c->sig->signal_received) return; @@ -704,6 +729,7 @@ if (c->c2.buf.len > 0) { c->c2.link_read_bytes += c->c2.buf.len; + link_read_bytes_global += c->c2.buf.len; c->c2.original_recv_size = c->c2.buf.len; #ifdef ENABLE_MANAGEMENT if (management) @@ -1014,7 +1040,8 @@ if (flags & PIPV4_EXTRACT_DHCP_ROUTER) { const in_addr_t dhcp_router = dhcp_extract_router_msg (&ipbuf); - route_list_add_default_gateway (c->c1.route_list, c->c2.es, dhcp_router); + if (dhcp_router) + route_list_add_default_gateway (c->c1.route_list, c->c2.es, dhcp_router); } } } @@ -1103,6 +1130,7 @@ { c->c2.max_send_size_local = max_int (size, c->c2.max_send_size_local); c->c2.link_write_bytes += size; + link_write_bytes_global += size; #ifdef ENABLE_MANAGEMENT if (management) { diff -Nru openvpn-2.1~rc19/forward.h openvpn-2.1.1/forward.h --- openvpn-2.1~rc19/forward.h 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/forward.h 2009-10-01 21:35:38.000000000 +0200 @@ -80,7 +80,7 @@ void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf); #if P2MP -void schedule_exit (struct context *c, const int n_seconds); +void schedule_exit (struct context *c, const int n_seconds, const int signal); #endif #endif /* FORWARD_H */ diff -Nru openvpn-2.1~rc19/forward-inline.h openvpn-2.1.1/forward-inline.h --- openvpn-2.1~rc19/forward-inline.h 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/forward-inline.h 2009-10-01 20:02:18.000000000 +0200 @@ -119,6 +119,17 @@ } #if P2MP + +static inline void +check_server_poll_timeout (struct context *c) +{ + void check_server_poll_timeout_dowork (struct context *c); + + if (c->options.server_poll_timeout + && event_timeout_trigger (&c->c2.server_poll_interval, &c->c2.timeval, ETT_DEFAULT)) + check_server_poll_timeout_dowork (c); +} + /* * Scheduled exit? */ diff -Nru openvpn-2.1~rc19/init.c openvpn-2.1.1/init.c --- openvpn-2.1~rc19/init.c 2009-06-01 21:55:25.000000000 +0200 +++ openvpn-2.1.1/init.c 2009-10-01 20:02:18.000000000 +0200 @@ -667,7 +667,7 @@ } /* - * Actually do UID/GID downgrade, and chroot, if requested. + * Actually do UID/GID downgrade, chroot and SELinux context switching, if requested. */ static void do_uid_gid_chroot (struct context *c, bool no_delay) @@ -697,6 +697,26 @@ { msg (M_INFO, "NOTE: UID/GID downgrade %s", why_not); } + +#ifdef HAVE_SETCON + /* Apply a SELinux context in order to restrict what OpenVPN can do + * to _only_ what it is supposed to do after initialization is complete + * (basically just network I/O operations). Doing it after chroot + * requires /proc to be mounted in the chroot (which is annoying indeed + * but doing it before requires more complex SELinux policies. + */ + if (c->options.selinux_context) + { + if (no_delay) { + if (-1 == setcon (c->options.selinux_context)) + msg (M_ERR, "setcon to '%s' failed; is /proc accessible?", c->options.selinux_context); + else + msg (M_INFO, "setcon to '%s' succeeded", c->options.selinux_context); + } + else + msg (M_INFO, "NOTE: setcon %s", why_not); + } +#endif } } @@ -772,6 +792,11 @@ if (c->options.ping_rec_timeout) event_timeout_init (&c->c2.ping_rec_interval, c->options.ping_rec_timeout, now); +#if P2MP + if (c->options.server_poll_timeout) + event_timeout_init (&c->c2.server_poll_interval, c->options.server_poll_timeout, now); +#endif + if (!deferred) { /* initialize connection establishment timer */ @@ -827,7 +852,7 @@ do_alloc_route_list (struct context *c) { if (c->options.routes && !c->c1.route_list) - c->c1.route_list = new_route_list (&c->gc); + c->c1.route_list = new_route_list (c->options.max_routes, &c->gc); } @@ -972,15 +997,12 @@ */ #if P2MP static void -save_pulled_options_string (struct context *c, const char *newstring) +save_pulled_options_digest (struct context *c, const struct md5_digest *newdigest) { - if (c->c1.pulled_options_string_save) - free (c->c1.pulled_options_string_save); - - c->c1.pulled_options_string_save = NULL; - - if (newstring) - c->c1.pulled_options_string_save = string_alloc (newstring, NULL); + if (newdigest) + c->c1.pulled_options_digest_save = *newdigest; + else + md5_digest_clear (&c->c1.pulled_options_digest_save); } #endif @@ -1124,7 +1146,7 @@ c->c1.tuntap = NULL; c->c1.tuntap_owned = false; #if P2MP - save_pulled_options_string (c, NULL); /* delete C1-saved pulled_options_string */ + save_pulled_options_digest (c, NULL); /* delete C1-saved pulled_options_digest */ #endif } @@ -1224,8 +1246,8 @@ if (!c->c2.did_open_tun && PULL_DEFINED (&c->options) && c->c1.tuntap - && (!c->c1.pulled_options_string_save || !c->c2.pulled_options_string - || strcmp (c->c1.pulled_options_string_save, c->c2.pulled_options_string))) + && (!md5_digest_defined (&c->c1.pulled_options_digest_save) || !md5_digest_defined (&c->c2.pulled_options_digest) + || !md5_digest_equal (&c->c1.pulled_options_digest_save, &c->c2.pulled_options_digest))) { /* if so, close tun, delete routes, then reinitialize tun and add routes */ msg (M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device."); @@ -1240,7 +1262,7 @@ if (c->c2.did_open_tun) { #if P2MP - save_pulled_options_string (c, c->c2.pulled_options_string); + save_pulled_options_digest (c, &c->c2.pulled_options_digest); #endif /* if --route-delay was specified, start timer */ @@ -1427,10 +1449,15 @@ #if P2MP if (auth_retry_get () == AR_NOINTERACT) sec = 10; + + if (c->options.server_poll_timeout && sec > 1) + sec = 1; #endif if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec) sec = c->persist.restart_sleep_seconds; + else if (c->persist.restart_sleep_seconds == -1) + sec = 0; c->persist.restart_sleep_seconds = 0; /* do managment hold on context restart, i.e. second, third, fourth, etc. initialization */ @@ -1964,16 +1991,20 @@ if (o->ping_send_timeout && !o->ping_rec_timeout) msg (M_WARN, "WARNING: --ping should normally be used with --ping-restart or --ping-exit"); - if (o->username || o->groupname || o->chroot_dir) + if (o->username || o->groupname || o->chroot_dir +#ifdef HAVE_SETCON + || o->selinux_context +#endif + ) { if (!o->persist_tun) - msg (M_WARN, "WARNING: you are using user/group/chroot without persist-tun -- this may cause restarts to fail"); + msg (M_WARN, "WARNING: you are using user/group/chroot/setcon without persist-tun -- this may cause restarts to fail"); if (!o->persist_key #ifdef ENABLE_PKCS11 && !o->pkcs11_id #endif ) - msg (M_WARN, "WARNING: you are using user/group/chroot without persist-key -- this may cause restarts to fail"); + msg (M_WARN, "WARNING: you are using user/group/chroot/setcon without persist-key -- this may cause restarts to fail"); } if (o->chroot_dir && !(o->username && o->groupname)) diff -Nru openvpn-2.1~rc19/install-win32/openssl/.svn/all-wcprops openvpn-2.1.1/install-win32/openssl/.svn/all-wcprops --- openvpn-2.1~rc19/install-win32/openssl/.svn/all-wcprops 2009-05-16 10:16:16.000000000 +0200 +++ openvpn-2.1.1/install-win32/openssl/.svn/all-wcprops 1970-01-01 01:00:00.000000000 +0100 @@ -1,23 +0,0 @@ -K 25 -svn:wc:ra_dav:version-url -V 77 -/projects/openvpn/!svn/ver/4318/branches/BETA21/openvpn/install-win32/openssl -END -openssl097.patch -K 25 -svn:wc:ra_dav:version-url -V 94 -/projects/openvpn/!svn/ver/2982/branches/BETA21/openvpn/install-win32/openssl/openssl097.patch -END -openssl098.patch -K 25 -svn:wc:ra_dav:version-url -V 94 -/projects/openvpn/!svn/ver/3149/branches/BETA21/openvpn/install-win32/openssl/openssl098.patch -END -README.txt -K 25 -svn:wc:ra_dav:version-url -V 88 -/projects/openvpn/!svn/ver/4318/branches/BETA21/openvpn/install-win32/openssl/README.txt -END diff -Nru openvpn-2.1~rc19/install-win32/openssl/.svn/entries openvpn-2.1.1/install-win32/openssl/.svn/entries --- openvpn-2.1~rc19/install-win32/openssl/.svn/entries 2009-07-12 11:25:02.000000000 +0200 +++ openvpn-2.1.1/install-win32/openssl/.svn/entries 1970-01-01 01:00:00.000000000 +0100 @@ -1,64 +0,0 @@ -8 - -dir -4707 -https://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn/install-win32/openssl -https://svn.openvpn.net/projects/openvpn - - - -2009-05-13T13:36:23.481742Z -4318 -james - - -svn:special svn:externals svn:needs-lock - - - - - - - - - - - -e7ae566f-a301-0410-adde-c780ea21d3b5 - -openssl097.patch -file - - - - -2008-09-30T02:34:06.000000Z -686b9f53674fe4132af89cdc7aea5344 -2008-06-04T10:53:57.832544Z -2982 -james - -openssl098.patch -file - - - - -2008-09-30T02:34:06.000000Z -6f2e5ab0b37296726fbbd4dbc59df49c -2008-07-31T22:03:38.310201Z -3149 -james - -README.txt -file - - - - -2009-05-16T08:16:16.000000Z -fccb41da0fec42fe0b0cd08ce147510a -2009-05-13T13:36:23.481742Z -4318 -james - diff -Nru openvpn-2.1~rc19/install-win32/openssl/.svn/format openvpn-2.1.1/install-win32/openssl/.svn/format --- openvpn-2.1~rc19/install-win32/openssl/.svn/format 2008-09-30 04:34:06.000000000 +0200 +++ openvpn-2.1.1/install-win32/openssl/.svn/format 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -8 diff -Nru openvpn-2.1~rc19/install-win32/openssl/.svn/text-base/openssl097.patch.svn-base openvpn-2.1.1/install-win32/openssl/.svn/text-base/openssl097.patch.svn-base --- openvpn-2.1~rc19/install-win32/openssl/.svn/text-base/openssl097.patch.svn-base 2008-09-30 04:34:06.000000000 +0200 +++ openvpn-2.1.1/install-win32/openssl/.svn/text-base/openssl097.patch.svn-base 1970-01-01 01:00:00.000000000 +0100 @@ -1,68 +0,0 @@ -[in msys bash window] -cd /c/src/openssl-0.9.7m -patch -p1 <../21/install-win32/openssl.patch - -[open command prompt window] -cd \src\openssl-0.9.7m -ms\mw - -diff -wur openssl-0.9.7m.orig/ms/mw.bat openssl-0.9.7m/ms/mw.bat ---- openssl-0.9.7m.orig/ms/mw.bat Sat Feb 22 11:02:46 2003 -+++ openssl-0.9.7m/ms/mw.bat Mon Jan 21 23:12:34 2008 -@@ -1,17 +1,23 @@ - @rem OpenSSL with Mingw32 - @rem -------------------- - -+@rem Include MinGW, MSYS, and ActiveState Perl in path -+set PATH=c:\perl\bin;c:\MinGW\bin;c:\msys\1.0\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem -+ - @rem Makefile - perl util\mkfiles.pl >MINFO --perl util\mk1mf.pl Mingw32 >ms\mingw32.mak -+perl util\mk1mf.pl no-idea no-mdc2 no-rc5 Mingw32 >ms\mingw32.mak -+ - @rem DLL definition files --perl util\mkdef.pl 32 libeay >ms\libeay32.def -+perl util\mkdef.pl no-idea no-mdc2 no-rc5 32 libeay >ms\libeay32.def - if errorlevel 1 goto end --perl util\mkdef.pl 32 ssleay >ms\ssleay32.def -+perl util\mkdef.pl no-idea no-mdc2 no-rc5 32 ssleay >ms\ssleay32.def - if errorlevel 1 goto end - - @rem Build the libraries --make -f ms/mingw32.mak -+ -+@rem JY added --win32 flag -+make --win32 -f ms/mingw32.mak - if errorlevel 1 goto end - - @rem Generate the DLLs and input libraries -@@ -20,7 +26,9 @@ - dllwrap --dllname libssl32.dll --output-lib out/libssl32.a --def ms/ssleay32.def out/libssl.a out/libeay32.a - if errorlevel 1 goto end - -+@rem JY added openssl.exe linked to DLL -+gcc -o openssl tmp\verify.o tmp\asn1pars.o tmp\req.o tmp\dgst.o tmp\dh.o tmp\dhparam.o tmp\enc.o tmp\passwd.o tmp\gendh.o tmp\errstr.o tmp\ca.o tmp\pkcs7.o tmp\crl2p7.o tmp\crl.o tmp\rsa.o tmp\rsautl.o tmp\dsa.o tmp\dsaparam.o tmp\x509.o tmp\genrsa.o tmp\gendsa.o tmp\s_server.o tmp\s_client.o tmp\speed.o tmp\s_time.o tmp\apps.o tmp\s_cb.o tmp\s_socket.o tmp\app_rand.o tmp\version.o tmp\sess_id.o tmp\ciphers.o tmp\nseq.o tmp\pkcs12.o tmp\pkcs8.o tmp\spkac.o tmp\smime.o tmp\rand.o tmp\engine.o tmp\ocsp.o tmp\prime.o tmp\openssl.o -leay32 -lssl32 -L. -lwsock32 -lgdi32 -+ - echo Done compiling OpenSSL - - :end -- -diff -wur openssl-0.9.7m.orig/util/pl/Mingw32.pl openssl-0.9.7m/util/pl/Mingw32.pl ---- openssl-0.9.7m.orig/util/pl/Mingw32.pl Sun May 16 23:28:32 2004 -+++ openssl-0.9.7m/util/pl/Mingw32.pl Mon Jan 21 17:52:36 2008 -@@ -99,10 +99,10 @@ - $n=&bname($target); - $ret.="$target: $files $dep_libs\n"; - $ret.="\t\$(LINK) ${efile}$target \$(LFLAGS) $files $libs\n"; -- if (defined $sha1file) -- { -- $ret.="\t$openssl sha1 -hmac etaonrishdlcupfm -binary $target > $sha1file"; -- } -+# if (defined $sha1file) -+# { -+# $ret.="\t$openssl sha1 -hmac etaonrishdlcupfm -binary $target > $sha1file"; -+# } - $ret.="\n"; - return($ret); - } diff -Nru openvpn-2.1~rc19/install-win32/openssl/.svn/text-base/openssl098.patch.svn-base openvpn-2.1.1/install-win32/openssl/.svn/text-base/openssl098.patch.svn-base --- openvpn-2.1~rc19/install-win32/openssl/.svn/text-base/openssl098.patch.svn-base 2008-09-30 04:34:06.000000000 +0200 +++ openvpn-2.1.1/install-win32/openssl/.svn/text-base/openssl098.patch.svn-base 1970-01-01 01:00:00.000000000 +0100 @@ -1,56 +0,0 @@ -diff -urw tmp/openssl-0.9.8h/crypto/pqueue/pqueue.c openssl-0.9.8h/crypto/pqueue/pqueue.c ---- tmp/openssl-0.9.8h/crypto/pqueue/pqueue.c Tue Jun 28 06:53:34 2005 -+++ openssl-0.9.8h/crypto/pqueue/pqueue.c Wed Jun 4 02:52:42 2008 -@@ -199,10 +199,10 @@ - return found; - } - --#if PQ_64BIT_IS_INTEGER - void - pqueue_print(pqueue_s *pq) - { -+#if PQ_64BIT_IS_INTEGER - pitem *item = pq->items; - - while(item != NULL) -@@ -210,8 +210,8 @@ - printf("item\t" PQ_64BIT_PRINT "\n", item->priority); - item = item->next; - } -- } - #endif -+ } - - pitem * - pqueue_iterator(pqueue_s *pq) -diff -urw tmp/openssl-0.9.8h/ms/mw.bat openssl-0.9.8h/ms/mw.bat ---- tmp/openssl-0.9.8h/ms/mw.bat Sat Feb 22 11:00:10 2003 -+++ openssl-0.9.8h/ms/mw.bat Wed Jun 4 02:56:54 2008 -@@ -1,17 +1,23 @@ - @rem OpenSSL with Mingw32 - @rem -------------------- - -+@rem Include MinGW, MSYS, and ActiveState Perl in path -+set PATH=c:\bin;C:\Perl\bin\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;c:\MinGW\bin;c:\msys\1.0\bin -+ - @rem Makefile - perl util\mkfiles.pl >MINFO --perl util\mk1mf.pl Mingw32 >ms\mingw32.mak -+perl util\mk1mf.pl no-idea no-mdc2 no-rc5 Mingw32 >ms\mingw32.mak -+ - @rem DLL definition files --perl util\mkdef.pl 32 libeay >ms\libeay32.def -+perl util\mkdef.pl no-idea no-mdc2 no-rc5 32 libeay >ms\libeay32.def - if errorlevel 1 goto end --perl util\mkdef.pl 32 ssleay >ms\ssleay32.def -+perl util\mkdef.pl no-idea no-mdc2 no-rc5 32 ssleay >ms\ssleay32.def - if errorlevel 1 goto end - - @rem Build the libraries --make -f ms/mingw32.mak -+ -+@rem JY added --win32 -+make --win32 -f ms/mingw32.mak - if errorlevel 1 goto end - - @rem Generate the DLLs and input libraries diff -Nru openvpn-2.1~rc19/install-win32/openssl/.svn/text-base/README.txt.svn-base openvpn-2.1.1/install-win32/openssl/.svn/text-base/README.txt.svn-base --- openvpn-2.1~rc19/install-win32/openssl/.svn/text-base/README.txt.svn-base 2009-05-16 10:16:16.000000000 +0200 +++ openvpn-2.1.1/install-win32/openssl/.svn/text-base/README.txt.svn-base 1970-01-01 01:00:00.000000000 +0100 @@ -1,21 +0,0 @@ -Rebuild OpenSSL tarball without symbolic links, so -it can be extracted on Windows (run on Unix): - - [download tarball and .asc sig] - gpg --verify openssl-0.9.8k.tar.gz.asc - tar xfz openssl-0.9.8k.tar.gz - tar cfzh openssl-0.9.8k-nolinks.tar.gz openssl-0.9.8k - -To apply patch (in MSYS shell): - - cd /c/src/openssl-0.9.8k - patch -p1 <../21/install-win32/openssl/openssl098.patch - -To build OpenSSL, open a command prompt window, then: - - cd \src\openssl-0.9.8k - ms\mw - -To build a new patch (optional): - - diff -urw openssl-0.9.8k.orig openssl-0.9.8k | grep -v '^Only in' >openssl098.patch diff -Nru openvpn-2.1~rc19/install-win32/settings.in openvpn-2.1.1/install-win32/settings.in --- openvpn-2.1~rc19/install-win32/settings.in 2009-06-22 23:01:42.000000000 +0200 +++ openvpn-2.1.1/install-win32/settings.in 2009-11-12 09:32:52.000000000 +0100 @@ -22,7 +22,7 @@ ;!define OPENVPN_XGUI_DIR "../ovpnxml" # Prebuilt libraries. DMALLOC is optional. -!define OPENSSL_DIR "../openssl-0.9.8k" +!define OPENSSL_DIR "../openssl-0.9.8l" !define LZO_DIR "../lzo-2.02" !define PKCS11_HELPER_DIR "../pkcs11-helper" ;!define DMALLOC_DIR "../dmalloc-5.4.2" diff -Nru openvpn-2.1~rc19/interval.h openvpn-2.1.1/interval.h --- openvpn-2.1~rc19/interval.h 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/interval.h 2009-10-01 20:02:18.000000000 +0200 @@ -177,6 +177,14 @@ et->last = now; } +static inline void +event_timeout_modify_wakeup (struct event_timeout* et, interval_t n) +{ + /* note that you might need to call reset_coarse_timers after this */ + if (et->defined) + et->n = (n >= 0) ? n : 0; +} + /* * This is the principal function for testing and triggering recurring * timers and will return true on a timer signal event. diff -Nru openvpn-2.1~rc19/Makefile.am openvpn-2.1.1/Makefile.am --- openvpn-2.1~rc19/Makefile.am 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/Makefile.am 2009-10-07 13:11:01.000000000 +0200 @@ -123,6 +123,7 @@ ieproxy.h ieproxy.c \ ps.c ps.h \ push.c push.h \ + pushlist.h \ reliable.c reliable.h \ route.c route.h \ schedule.c schedule.h \ @@ -141,7 +142,7 @@ dist-hook: - cd $(distdir) && for i in $(EXTRA_DIST) ; do find $$i -name .svn -type d -prune -exec rm -rf '{}' ';' ; rm -f `find $$i -type f | grep -E '(^|\/)\.?\#|\~$$|\.s?o$$'` ; done + cd $(distdir) && for i in $(EXTRA_DIST) $(SUBDIRS) ; do find $$i -name .svn -type d -prune -exec rm -rf '{}' ';' ; rm -f `find $$i -type f | grep -E '(^|\/)\.?\#|\~$$|\.s?o$$'` ; done if WIN32 dist_noinst_DATA += openvpn.8 diff -Nru openvpn-2.1~rc19/Makefile.in openvpn-2.1.1/Makefile.in --- openvpn-2.1~rc19/Makefile.in 2009-07-16 11:14:23.000000000 +0200 +++ openvpn-2.1.1/Makefile.in 2009-12-12 00:27:05.000000000 +0100 @@ -353,6 +353,7 @@ ieproxy.h ieproxy.c \ ps.c ps.h \ push.c push.h \ + pushlist.h \ reliable.c reliable.h \ route.c route.h \ schedule.c schedule.h \ @@ -1075,7 +1076,7 @@ .PHONY: plugin dist-hook: - cd $(distdir) && for i in $(EXTRA_DIST) ; do find $$i -name .svn -type d -prune -exec rm -rf '{}' ';' ; rm -f `find $$i -type f | grep -E '(^|\/)\.?\#|\~$$|\.s?o$$'` ; done + cd $(distdir) && for i in $(EXTRA_DIST) $(SUBDIRS) ; do find $$i -name .svn -type d -prune -exec rm -rf '{}' ';' ; rm -f `find $$i -type f | grep -E '(^|\/)\.?\#|\~$$|\.s?o$$'` ; done @WIN32_TRUE@openvpn.8.html: $(srcdir)/openvpn.8 @WIN32_TRUE@ $(MAN2HTML) < $(srcdir)/openvpn.8 > openvpn.8.html # Tell versions [3.59,3.63) of GNU make to not export all variables. diff -Nru openvpn-2.1~rc19/manage.c openvpn-2.1.1/manage.c --- openvpn-2.1~rc19/manage.c 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/manage.c 2009-10-01 22:30:21.000000000 +0200 @@ -35,6 +35,7 @@ #include "integer.h" #include "misc.h" #include "ssl.h" +#include "common.h" #include "manage.h" #include "memdbg.h" @@ -75,6 +76,7 @@ msg (M_CLIENT, " release current hold and start tunnel."); msg (M_CLIENT, "kill cn : Kill the client instance(s) having common name cn."); msg (M_CLIENT, "kill IP:port : Kill the client instance connecting from IP:port."); + msg (M_CLIENT, "load-stats : Show global server load stats."); msg (M_CLIENT, "log [on|off] [N|all] : Turn on/off realtime log display"); msg (M_CLIENT, " + show last N lines or 'all' for entire history."); msg (M_CLIENT, "mute [n] : Set log mute level to n, or show level if n is absent."); @@ -92,7 +94,8 @@ #ifdef MANAGEMENT_DEF_AUTH msg (M_CLIENT, "client-auth CID KID : Authenticate client-id/key-id CID/KID (MULTILINE)"); msg (M_CLIENT, "client-auth-nt CID KID : Authenticate client-id/key-id CID/KID"); - msg (M_CLIENT, "client-deny CID KID R : Deny auth client-id/key-id CID/KID with reason text R"); + msg (M_CLIENT, "client-deny CID KID R [CR] : Deny auth client-id/key-id CID/KID with log reason"); + msg (M_CLIENT, " text R and optional client reason text CR"); msg (M_CLIENT, "client-kill CID : Kill client instance CID"); #ifdef MANAGEMENT_PF msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)"); @@ -799,6 +802,7 @@ man->connection.in_extra_kid, true, NULL, + NULL, man->connection.in_extra); man->connection.in_extra = NULL; if (status) @@ -860,7 +864,7 @@ } static void -man_client_deny (struct management *man, const char *cid_str, const char *kid_str, const char *reason) +man_client_deny (struct management *man, const char *cid_str, const char *kid_str, const char *reason, const char *client_reason) { unsigned long cid = 0; unsigned int kid = 0; @@ -874,6 +878,7 @@ kid, false, reason, + client_reason, NULL); if (status) { @@ -948,6 +953,21 @@ #endif #endif +static void +man_load_stats (struct management *man) +{ + extern counter_type link_read_bytes_global; + extern counter_type link_write_bytes_global; + int nclients = 0; + + if (man->persist.callback.n_clients) + nclients = (*man->persist.callback.n_clients) (man->persist.callback.arg); + msg (M_CLIENT, "SUCCESS: nclients=%d,bytesin=" counter_format ",bytesout=" counter_format, + nclients, + link_read_bytes_global, + link_write_bytes_global); +} + #define MN_AT_LEAST (1<<0) static bool @@ -995,15 +1015,21 @@ { msg (M_CLIENT, "SUCCESS: pid=%d", openvpn_getpid ()); } +#ifdef MANAGEMENT_DEF_AUTH else if (streq (p[0], "nclients")) { man_client_n_clients (man); } +#endif else if (streq (p[0], "signal")) { if (man_need (man, p, 1, 0)) man_signal (man, p[1]); } + else if (streq (p[0], "load-stats")) + { + man_load_stats (man); + } else if (streq (p[0], "status")) { int version = 0; @@ -1137,8 +1163,8 @@ } else if (streq (p[0], "client-deny")) { - if (man_need (man, p, 3, 0)) - man_client_deny (man, p[1], p[2], p[3]); + if (man_need (man, p, 3, MN_AT_LEAST)) + man_client_deny (man, p[1], p[2], p[3], p[4]); } else if (streq (p[0], "client-auth-nt")) { @@ -1575,7 +1601,7 @@ nparms = parse_line (line, parms, MAX_PARMS, "TCP", 0, M_CLIENT, &gc); if (parms[0] && streq (parms[0], "password")) msg (D_MANAGEMENT_DEBUG, "MANAGEMENT: CMD 'password [...]'"); - else + else if (!streq (line, "load-stats")) msg (D_MANAGEMENT_DEBUG, "MANAGEMENT: CMD '%s'", line); #if 0 diff -Nru openvpn-2.1~rc19/manage.h openvpn-2.1.1/manage.h --- openvpn-2.1~rc19/manage.h 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/manage.h 2009-10-01 20:02:18.000000000 +0200 @@ -162,6 +162,7 @@ const unsigned int mda_key_id, const bool auth, const char *reason, + const char *client_reason, struct buffer_list *cc_config); /* ownership transferred */ #endif #ifdef MANAGEMENT_PF diff -Nru openvpn-2.1~rc19/misc.c openvpn-2.1.1/misc.c --- openvpn-2.1~rc19/misc.c 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/misc.c 2009-10-01 20:02:18.000000000 +0200 @@ -1186,6 +1186,44 @@ return gen_path (directory, BSTR (&fname), gc); } +/* + * Add a random string to first DNS label of hostname to prevent DNS caching. + * For example, foo.bar.gov would be modified to .foo.bar.gov. + * Of course, this requires explicit support in the DNS server. + */ +const char * +hostname_randomize(const char *hostname, struct gc_arena *gc) +{ + const int n_rnd_bytes = 6; + + char *hst = string_alloc(hostname, gc); + char *dot = strchr(hst, '.'); + + if (dot) + { + uint8_t rnd_bytes[n_rnd_bytes]; + const char *rnd_str; + struct buffer hname = alloc_buf_gc (strlen(hostname)+sizeof(rnd_bytes)*2+4, gc); + + *dot++ = '\0'; + prng_bytes (rnd_bytes, sizeof (rnd_bytes)); + rnd_str = format_hex_ex (rnd_bytes, sizeof (rnd_bytes), 40, 0, NULL, gc); + buf_printf(&hname, "%s-0x%s.%s", hst, rnd_str, dot); + return BSTR(&hname); + } + else + return hostname; +} + +#else + +const char * +hostname_randomize(const char *hostname, struct gc_arena *gc) +{ + msg (M_WARN, "WARNING: hostname randomization disabled when crypto support is not compiled"); + return hostname; +} + #endif /* diff -Nru openvpn-2.1~rc19/misc.h openvpn-2.1.1/misc.h --- openvpn-2.1~rc19/misc.h 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/misc.h 2009-10-01 20:02:18.000000000 +0200 @@ -230,6 +230,9 @@ /* return true if pathname is absolute */ bool absolute_pathname (const char *pathname); +/* prepend a random prefix to hostname (need USE_CRYPTO) */ +const char *hostname_randomize(const char *hostname, struct gc_arena *gc); + /* * Get and store a username/password */ diff -Nru openvpn-2.1~rc19/multi.c openvpn-2.1.1/multi.c --- openvpn-2.1~rc19/multi.c 2009-06-29 06:40:11.000000000 +0200 +++ openvpn-2.1.1/multi.c 2009-10-25 01:17:29.000000000 +0200 @@ -1458,8 +1458,9 @@ ASSERT (mi->context.c1.tuntap); - /* lock down the common name so it can't change during future TLS renegotiations */ + /* lock down the common name and cert hashes so they can't change during future TLS renegotiations */ tls_lock_common_name (mi->context.c2.tls_multi); + tls_lock_cert_hash_set (mi->context.c2.tls_multi); /* generate a msg() prefix for this client instance */ generate_prefix (mi); @@ -2539,7 +2540,7 @@ struct multi_instance *mi = lookup_by_cid (m, cid); if (mi) { - multi_signal_instance (m, mi, SIGTERM); + send_restart (&mi->context); /* was: multi_signal_instance (m, mi, SIGTERM); */ return true; } else @@ -2552,6 +2553,7 @@ const unsigned int mda_key_id, const bool auth, const char *reason, + const char *client_reason, struct buffer_list *cc_config) /* ownership transferred */ { struct multi_context *m = (struct multi_context *) arg; @@ -2561,7 +2563,7 @@ if (mi) { - ret = tls_authenticate_key (mi->context.c2.tls_multi, mda_key_id, auth); + ret = tls_authenticate_key (mi->context.c2.tls_multi, mda_key_id, auth, client_reason); if (ret) { if (auth && !mi->connection_established_flag) @@ -2570,7 +2572,7 @@ cc_config_owned = false; } if (!auth && reason) - msg (D_MULTI_LOW, "MULTI: connection rejected: %s", reason); + msg (D_MULTI_LOW, "MULTI: connection rejected: %s, CLI:%s", reason, np(client_reason)); } } if (cc_config_owned && cc_config) diff -Nru openvpn-2.1~rc19/openvpn.8 openvpn-2.1.1/openvpn.8 --- openvpn-2.1~rc19/openvpn.8 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/openvpn.8 2009-12-11 09:04:24.000000000 +0100 @@ -946,6 +946,13 @@ address if OpenVPN is being run in client mode, and is undefined in server mode. .\"********************************************************* .TP +.B --max-routes n +Allow a maximum number of n +.B --route +options to be specified, either in the local configuration file, +or pulled from an OpenVPN server. By default, n=100. +.\"********************************************************* +.TP .B --route-gateway gw|'dhcp' Specify a default gateway .B gw @@ -1889,6 +1896,39 @@ are executed after the chroot operation. .\"********************************************************* .TP +.B --setcon context +Apply SELinux +.B context +after initialization. This +essentially provides the ability to restrict OpenVPN's +rights to only network I/O operations, thanks to +SELinux. This goes further than +.B --user +and +.B --chroot +in that those two, while being great security features, +unfortunately do not protect against privilege escalation +by exploitation of a vulnerable system call. You can of +course combine all three, but please note that since +setcon requires access to /proc you will have to provide +it inside the chroot directory (e.g. with mount --bind). + +Since the setcon operation is delayed until after +initialization, OpenVPN can be restricted to just +network-related system calls, whereas by applying the +context before startup (such as the OpenVPN one provided +in the SELinux Reference Policies) you will have to +allow many things required only during initialization. + +Like with chroot, complications can result when scripts +or restarts are executed after the setcon operation, +which is why you should really consider using the +.B --persist-key +and +.B --persist-tun +options. +.\"********************************************************* +.TP .B --daemon [progname] Become a daemon after all initialization functions are completed. This option will cause all message and error output to @@ -2078,6 +2118,21 @@ is NOT specified. .\"********************************************************* .TP +.B --multihome +Configure a multi-homed UDP server. This option can be used when +OpenVPN has been configured to listen on all interfaces, and will +attempt to bind client sessions to the interface on which packets +are being received, so that outgoing packets will be sent out +of the same interface. Note that this option is only relevant for +UDP servers and currently is only implemented on Linux. + +Note: clients connecting to a +.B --multihome +server should always use the +.B --nobind +option. +.\"********************************************************* +.TP .B --echo [parms...] Echo .B parms @@ -3239,6 +3294,13 @@ from the management interface. .\"********************************************************* .TP +.B --server-poll-timeout n +when polling possible remote servers to connect to +in a round-robin fashion, spend no more than +.B n +seconds waiting for a response before trying the next server. +.\"********************************************************* +.TP .B --explicit-exit-notify [n] In UDP client mode or point-to-point mode, send server/peer an exit notification if tunnel is restarted or OpenVPN process is exited. In client mode, on diff -Nru openvpn-2.1~rc19/openvpn.h openvpn-2.1.1/openvpn.h --- openvpn-2.1~rc19/openvpn.h 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/openvpn.h 2009-10-01 21:35:38.000000000 +0200 @@ -189,8 +189,8 @@ bool ifconfig_pool_persist_owned; #endif - /* if client mode, option strings we pulled from server */ - char *pulled_options_string_save; + /* if client mode, hash of option strings we pulled from server */ + struct md5_digest pulled_options_digest_save; /* save user/pass for authentication */ struct user_pass *auth_user_pass; @@ -427,9 +427,16 @@ #endif struct event_timeout push_request_interval; - const char *pulled_options_string; + bool did_pre_pull_restore; + + /* hash of pulled options, so we can compare when options change */ + struct md5_state pulled_options_state; + struct md5_digest pulled_options_digest; + + struct event_timeout server_poll_interval; struct event_timeout scheduled_exit; + int scheduled_exit_signal; #endif /* packet filter */ diff -Nru openvpn-2.1~rc19/openvpn.spec openvpn-2.1.1/openvpn.spec --- openvpn-2.1~rc19/openvpn.spec 2009-07-16 11:15:03.000000000 +0200 +++ openvpn-2.1.1/openvpn.spec 2009-12-12 00:27:36.000000000 +0100 @@ -16,7 +16,7 @@ Summary: OpenVPN is a robust and highly flexible VPN daemon by James Yonan. Name: openvpn -Version: 2.1_rc19 +Version: 2.1.1 Release: 1 URL: http://openvpn.net/ Source0: http://prdownloads.sourceforge.net/openvpn/%{name}-%{version}.tar.gz @@ -223,9 +223,12 @@ %endif # Install extra %doc stuff -%doc contrib/ easy-rsa/ management/ sample-*/ plugin/README.* +%doc contrib/ easy-rsa/ sample-*/ plugin/README.* %changelog +* Thu Jul 30 2009 David Sommerseth +- Removed management/ directory from %doc + * Thu Dec 14 2006 Alon Bar-Lev - Added with_pkcs11 diff -Nru openvpn-2.1~rc19/openvpn.spec.in openvpn-2.1.1/openvpn.spec.in --- openvpn-2.1~rc19/openvpn.spec.in 2008-09-30 04:34:10.000000000 +0200 +++ openvpn-2.1.1/openvpn.spec.in 2009-12-12 00:25:07.000000000 +0100 @@ -223,9 +223,12 @@ %endif # Install extra %doc stuff -%doc contrib/ easy-rsa/ management/ sample-*/ plugin/README.* +%doc contrib/ easy-rsa/ sample-*/ plugin/README.* %changelog +* Thu Jul 30 2009 David Sommerseth +- Removed management/ directory from %doc + * Thu Dec 14 2006 Alon Bar-Lev - Added with_pkcs11 diff -Nru openvpn-2.1~rc19/options.c openvpn-2.1.1/options.c --- openvpn-2.1~rc19/options.c 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/options.c 2009-12-11 09:09:39.000000000 +0100 @@ -90,6 +90,7 @@ "--local host : Local host name or ip address. Implies --bind.\n" "--remote host [port] : Remote host name or ip address.\n" "--remote-random : If multiple --remote options specified, choose one randomly.\n" + "--remote-random-hostname : Add a random string to remote DNS name.\n" "--mode m : Major mode, m = 'p2p' (default, point-to-point) or 'server'.\n" "--proto p : Use protocol p for communicating with peer.\n" " p = udp (default), tcp-server, or tcp-client\n" @@ -169,6 +170,8 @@ " netmask default: 255.255.255.255\n" " gateway default: taken from --route-gateway or --ifconfig\n" " Specify default by leaving blank or setting to \"nil\".\n" + "--max-routes n : Specify the maximum number of routes that may be defined\n" + " or pulled from a server.\n" "--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n" "--route-metric m : Specify a default metric for use with --route.\n" "--route-delay n [w] : Delay n seconds after connection initiation before\n" @@ -264,6 +267,9 @@ "--user user : Set UID to user after initialization.\n" "--group group : Set GID to group after initialization.\n" "--chroot dir : Chroot to this directory after initialization.\n" +#ifdef HAVE_SETCON + "--setcon context: Apply this SELinux context after initialization.\n" +#endif "--cd dir : Change to this directory before initialization.\n" "--daemon [name] : Become a daemon after initialization.\n" " The optional 'name' parameter will be passed\n" @@ -426,6 +432,9 @@ " when connecting to a '--mode server' remote host.\n" "--auth-retry t : How to handle auth failures. Set t to\n" " none (default), interact, or nointeract.\n" + "--server-poll-timeout n : when polling possible remote servers to connect to\n" + " in a round-robin fashion, spend no more than n seconds\n" + " waiting for a response before trying the next server.\n" #endif #ifdef ENABLE_OCC "--explicit-exit-notify [n] : On exit/restart, send exit signal to\n" @@ -676,6 +685,7 @@ o->mtu_discover_type = -1; o->mssfix = MSSFIX_DEFAULT; o->route_delay_window = 30; + o->max_routes = MAX_ROUTES_DEFAULT; o->resolve_retry_seconds = RESOLV_RETRY_INFINITE; #ifdef ENABLE_OCC o->occ = true; @@ -719,6 +729,7 @@ #endif #if P2MP o->scheduled_exit_interval = 5; + o->server_poll_timeout = 0; #endif #ifdef USE_CRYPTO o->ciphername = "BF-CBC"; @@ -953,11 +964,15 @@ msg (D_SHOW_PARMS, " server_bridge_netmask = %s", print_in_addr_t (o->server_bridge_netmask, 0, &gc)); msg (D_SHOW_PARMS, " server_bridge_pool_start = %s", print_in_addr_t (o->server_bridge_pool_start, 0, &gc)); msg (D_SHOW_PARMS, " server_bridge_pool_end = %s", print_in_addr_t (o->server_bridge_pool_end, 0, &gc)); - if (o->push_list) + if (o->push_list.head) { - const struct push_list *l = o->push_list; - const char *printable_push_list = l->options; - msg (D_SHOW_PARMS, " push_list = '%s'", printable_push_list); + const struct push_entry *e = o->push_list.head; + while (e) + { + if (e->enable) + msg (D_SHOW_PARMS, " push_entry = '%s'", e->option); + e = e->next; + } } SHOW_BOOL (ifconfig_pool_defined); msg (D_SHOW_PARMS, " ifconfig_pool_start = %s", print_in_addr_t (o->ifconfig_pool_start, 0, &gc)); @@ -1058,12 +1073,7 @@ gc_detach (&o->gc); o->routes = NULL; #if P2MP_SERVER - if (o->push_list) /* clone push_list */ - { - const struct push_list *old = o->push_list; - ALLOC_OBJ_GC (o->push_list, struct push_list, &o->gc); - strcpy (o->push_list->options, old->options); - } + clone_push_list(o); #endif } @@ -1071,7 +1081,7 @@ rol_check_alloc (struct options *options) { if (!options->routes) - options->routes = new_route_option_list (&options->gc); + options->routes = new_route_option_list (options->max_routes, &options->gc); } #ifdef ENABLE_DEBUG @@ -1215,6 +1225,9 @@ SHOW_STR (groupname); SHOW_STR (chroot_dir); SHOW_STR (cd_dir); +#ifdef HAVE_SETCON + SHOW_STR (selinux_context); +#endif SHOW_STR (writepid); SHOW_STR (up_script); SHOW_STR (down_script); @@ -1257,6 +1270,7 @@ SHOW_BOOL (route_delay_defined); SHOW_BOOL (route_nopull); SHOW_BOOL (route_gateway_via_dhcp); + SHOW_INT (max_routes); SHOW_BOOL (allow_pull_fqdn); if (o->routes) print_route_options (o->routes, D_SHOW_PARMS); @@ -2153,7 +2167,7 @@ o->pre_pull->foreign_option_index = o->foreign_option_index; if (o->routes) { - o->pre_pull->routes = *o->routes; + o->pre_pull->routes = clone_route_option_list(o->routes, &o->gc); o->pre_pull->routes_defined = true; } } @@ -2172,13 +2186,15 @@ if (pp->routes_defined) { rol_check_alloc (o); - *o->routes = pp->routes; + copy_route_option_list (o->routes, pp->routes); } else o->routes = NULL; o->foreign_option_index = pp->foreign_option_index; } + + o->push_continuation = 0; } #endif @@ -2728,7 +2744,7 @@ usage_version (void) { msg (M_INFO|M_NOPREFIX, "%s", title_string); - msg (M_INFO|M_NOPREFIX, "Developed by James Yonan"); + msg (M_INFO|M_NOPREFIX, "Originally developed by James Yonan"); msg (M_INFO|M_NOPREFIX, "Copyright (C) 2002-2009 OpenVPN Technologies, Inc. "); openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */ } @@ -2764,6 +2780,14 @@ return i < 0 ? 0 : i; } +static unsigned int +atou (const char *str) +{ + unsigned int val = 0; + sscanf (str, "%u", &val); + return val; +} + static inline bool space (unsigned char c) { @@ -3709,6 +3733,13 @@ } options->cd_dir = p[1]; } +#ifdef HAVE_SETCON + else if (streq (p[0], "setcon") && p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->selinux_context = p[1]; + } +#endif else if (streq (p[0], "writepid") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -4329,6 +4360,19 @@ } add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]); } + else if (streq (p[0], "max-routes") && p[1]) + { + int max_routes; + + VERIFY_PERMISSION (OPT_P_GENERAL); + max_routes = atoi (p[1]); + if (max_routes < 0 || max_routes > 100000000) + { + msg (msglevel, "--max-routes parameter is out of range"); + goto err; + } + options->max_routes = max_routes; + } else if (streq (p[0], "route-gateway") && p[1]) { VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); @@ -4398,10 +4442,10 @@ int j; VERIFY_PERMISSION (OPT_P_ROUTE); rol_check_alloc (options); + if (streq (p[0], "redirect-gateway")) + options->routes->flags |= RG_REROUTE_GW; for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) { - if (streq (p[0], "redirect-gateway")) - options->routes->flags |= RG_REROUTE_GW; if (streq (p[j], "local")) options->routes->flags |= RG_LOCAL; else if (streq (p[j], "autolocal")) @@ -4420,15 +4464,38 @@ } options->routes->flags |= RG_ENABLE; } + else if (streq (p[0], "remote-random-hostname")) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->sockflags |= SF_HOST_RANDOMIZE; + } else if (streq (p[0], "setenv") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], "FORWARD_COMPATIBLE") && p[2] && streq (p[2], "1")) + if (streq (p[1], "REMOTE_RANDOM_HOSTNAME")) + { + options->sockflags |= SF_HOST_RANDOMIZE; + } + else if (streq (p[1], "GENERIC_CONFIG")) + { + msg (msglevel, "this is a generic configuration and cannot directly be used"); + goto err; + } +#if P2MP + else if (streq (p[1], "SERVER_POLL_TIMEOUT") && p[2]) { - options->forward_compatible = true; - msglevel_fc = msglevel_forward_compatible (options, msglevel); + options->server_poll_timeout = positive_atoi(p[2]); + } +#endif + else + { + if (streq (p[1], "FORWARD_COMPATIBLE") && p[2] && streq (p[2], "1")) + { + options->forward_compatible = true; + msglevel_fc = msglevel_forward_compatible (options, msglevel); + } + setenv_str (es, p[1], p[2] ? p[2] : ""); } - setenv_str (es, p[1], p[2] ? p[2] : ""); } else if (streq (p[0], "setenv-safe") && p[1]) { @@ -4838,6 +4905,16 @@ VERIFY_PERMISSION (OPT_P_GENERAL); options->pull = true; } + else if (streq (p[0], "push-continuation") && p[1]) + { + VERIFY_PERMISSION (OPT_P_PULL_MODE); + options->push_continuation = atoi(p[1]); + } + else if (streq (p[0], "server-poll-timeout") && p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->server_poll_timeout = positive_atoi(p[1]); + } else if (streq (p[0], "auth-user-pass")) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -5028,6 +5105,19 @@ VERIFY_PERMISSION (OPT_P_IPWIN32); options->tuntap_options.dhcp_release = true; } + else if (streq (p[0], "dhcp-rr") && p[1]) /* standalone method for internal use */ + { + unsigned int adapter_index; + VERIFY_PERMISSION (OPT_P_GENERAL); + set_debug_level (options->verbosity, SDL_CONSTRAIN); + adapter_index = atou (p[1]); + sleep (options->tuntap_options.tap_sleep); + if (options->tuntap_options.dhcp_pre_release) + dhcp_release_by_adapter_index (adapter_index); + if (options->tuntap_options.dhcp_renew) + dhcp_renew_by_adapter_index (adapter_index); + openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */ + } else if (streq (p[0], "show-valid-subnets")) { VERIFY_PERMISSION (OPT_P_GENERAL); diff -Nru openvpn-2.1~rc19/options.h openvpn-2.1.1/options.h --- openvpn-2.1~rc19/options.h 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/options.h 2009-10-01 20:02:18.000000000 +0200 @@ -40,6 +40,7 @@ #include "manage.h" #include "proxy.h" #include "lzo.h" +#include "pushlist.h" /* * Maximum number of parameters associated with an option, @@ -57,17 +58,6 @@ #if P2MP -#if P2MP_SERVER -/* parameters to be pushed to peer */ - -#define MAX_PUSH_LIST_LEN TLS_CHANNEL_BUF_SIZE /* This parm is related to PLAINTEXT_BUFFER_SIZE in ssl.h */ - -struct push_list { - /* newline delimited options, like config file */ - char options[MAX_PUSH_LIST_LEN]; -}; -#endif - /* certain options are saved before --pull modifications are applied */ struct options_pre_pull { @@ -75,7 +65,7 @@ struct tuntap_options tuntap_options; bool routes_defined; - struct route_option_list routes; + struct route_option_list *routes; int foreign_option_index; }; @@ -253,6 +243,9 @@ const char *groupname; const char *chroot_dir; const char *cd_dir; +#ifdef HAVE_SETCON + char *selinux_context; +#endif const char *writepid; const char *up_script; const char *down_script; @@ -303,6 +296,7 @@ int route_delay; int route_delay_window; bool route_delay_defined; + int max_routes; struct route_option_list *routes; bool route_nopull; bool route_gateway_via_dhcp; @@ -358,7 +352,7 @@ in_addr_t server_bridge_pool_start; in_addr_t server_bridge_pool_end; - struct push_list *push_list; + struct push_list push_list; bool ifconfig_pool_defined; in_addr_t ifconfig_pool_start; in_addr_t ifconfig_pool_end; @@ -401,9 +395,12 @@ bool client; bool pull; /* client pull of config options from server */ + int push_continuation; const char *auth_user_pass_file; struct options_pre_pull *pre_pull; + int server_poll_timeout; + int scheduled_exit_interval; #endif diff -Nru openvpn-2.1~rc19/plugin/auth-pam/auth-pam.c openvpn-2.1.1/plugin/auth-pam/auth-pam.c --- openvpn-2.1~rc19/plugin/auth-pam/auth-pam.c 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/plugin/auth-pam/auth-pam.c 2009-12-11 00:35:04.000000000 +0100 @@ -305,6 +305,8 @@ * Allocate our context */ context = (struct auth_pam_context *) calloc (1, sizeof (struct auth_pam_context)); + if (!context) + goto error; context->foreground_fd = -1; /* @@ -492,7 +494,7 @@ struct auth_pam_context *context = (struct auth_pam_context *) handle; /* tell background process to exit */ - if (context->foreground_fd >= 0) + if (context && context->foreground_fd >= 0) { send_control (context->foreground_fd, COMMAND_EXIT); close (context->foreground_fd); diff -Nru openvpn-2.1~rc19/plugin/down-root/down-root.c openvpn-2.1.1/plugin/down-root/down-root.c --- openvpn-2.1~rc19/plugin/down-root/down-root.c 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/plugin/down-root/down-root.c 2009-12-11 00:35:04.000000000 +0100 @@ -274,6 +274,8 @@ * Allocate our context */ context = (struct down_root_context *) calloc (1, sizeof (struct down_root_context)); + if (!context) + goto error; context->foreground_fd = -1; /* @@ -434,7 +436,7 @@ { struct down_root_context *context = (struct down_root_context *) handle; - if (context->foreground_fd >= 0) + if (context && context->foreground_fd >= 0) { /* tell background process to exit */ send_control (context->foreground_fd, COMMAND_EXIT); diff -Nru openvpn-2.1~rc19/push.c openvpn-2.1.1/push.c --- openvpn-2.1~rc19/push.c 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/push.c 2009-10-01 21:35:38.000000000 +0200 @@ -61,21 +61,70 @@ c->sig->signal_text = "auth-failure"; #ifdef ENABLE_MANAGEMENT if (management) - management_auth_failure (management, UP_TYPE_AUTH); + { + const char *reason = UP_TYPE_AUTH; + struct buffer buf = *buffer; + if (buf_string_compare_advance (&buf, "AUTH_FAILED,") && BLEN (&buf)) + reason = BSTR (&buf); + management_auth_failure (management, reason); + } #endif } } +/* + * Act on received restart message from server + */ +void +server_pushed_restart (struct context *c, const struct buffer *buffer) +{ + if (c->options.pull) + { + msg (D_STREAM_ERRORS, "Connection reset command was pushed by server"); + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ + c->sig->signal_text = "server-pushed-connection-reset"; + } +} + #if P2MP_SERVER + /* * Send auth failed message from server to client. */ void -send_auth_failed (struct context *c) +send_auth_failed (struct context *c, const char *client_reason) { - schedule_exit (c, c->options.scheduled_exit_interval); - send_control_channel_string (c, "AUTH_FAILED", D_PUSH); + struct gc_arena gc = gc_new (); + static const char auth_failed[] = "AUTH_FAILED"; + size_t len; + + schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM); + + len = (client_reason ? strlen(client_reason)+1 : 0) + sizeof(auth_failed); + if (len > TLS_CHANNEL_BUF_SIZE) + len = TLS_CHANNEL_BUF_SIZE; + + { + struct buffer buf = alloc_buf_gc (len, &gc); + buf_printf (&buf, auth_failed); + if (client_reason) + buf_printf (&buf, ",%s", client_reason); + send_control_channel_string (c, BSTR (&buf), D_PUSH); + } + + gc_free (&gc); } + +/* + * Send restart message from server to client. + */ +void +send_restart (struct context *c) +{ + schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM); + send_control_channel_string (c, "RESTART", D_PUSH); +} + #endif /* @@ -99,9 +148,10 @@ if (status == PUSH_MSG_ERROR) msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", BSTR (buffer)); - else if (status == PUSH_MSG_REPLY) + else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) { - do_up (c, true, option_types_found); /* delay bringing tun/tap up until --push parms received from remote */ + if (status == PUSH_MSG_REPLY) + do_up (c, true, option_types_found); /* delay bringing tun/tap up until --push parms received from remote */ event_timeout_clear (&c->c2.push_request_interval); } @@ -115,60 +165,114 @@ } #if P2MP_SERVER + bool send_push_reply (struct context *c) { struct gc_arena gc = gc_new (); - struct buffer buf = alloc_buf_gc (MAX_PUSH_LIST_LEN + 256, &gc); - bool ret = false; + struct buffer buf = alloc_buf_gc (TLS_CHANNEL_BUF_SIZE, &gc); + struct push_entry *e = c->options.push_list.head; + bool multi_push = false; + static char cmd[] = "PUSH_REPLY"; + const int extra = 64; /* extra space for possible trailing ifconfig and push-continuation */ + const int safe_cap = BCAP (&buf) - extra; - buf_printf (&buf, "PUSH_REPLY"); + buf_printf (&buf, cmd); - if (c->options.push_list && strlen (c->options.push_list->options)) - buf_printf (&buf, ",%s", c->options.push_list->options); + while (e) + { + if (e->enable) + { + const int l = strlen (e->option); + if (BLEN (&buf) + l >= safe_cap) + { + buf_printf (&buf, ",push-continuation 2"); + { + const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH); + if (!status) + goto fail; + multi_push = true; + buf_reset_len (&buf); + buf_printf (&buf, cmd); + } + } + if (BLEN (&buf) + l >= safe_cap) + { + msg (M_WARN, "--push option is too long"); + goto fail; + } + buf_printf (&buf, ",%s", e->option); + } + e = e->next; + } if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask) buf_printf (&buf, ",ifconfig %s %s", print_in_addr_t (c->c2.push_ifconfig_local, 0, &gc), print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc)); + if (multi_push) + buf_printf (&buf, ",push-continuation 1"); - if (strlen (BSTR (&buf)) < MAX_PUSH_LIST_LEN) - ret = send_control_channel_string (c, BSTR (&buf), D_PUSH); - else - msg (M_WARN, "Maximum length of --push buffer (%d) has been exceeded", MAX_PUSH_LIST_LEN); + if (BLEN (&buf) > sizeof(cmd)-1) + { + const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH); + if (!status) + goto fail; + } gc_free (&gc); - return ret; + return true; + + fail: + gc_free (&gc); + return false; } -void -push_option (struct options *o, const char *opt, int msglevel) +static void +push_option_ex (struct options *o, const char *opt, bool enable, int msglevel) { - int len; - bool first = false; - if (!string_class (opt, CC_ANY, CC_COMMA)) { msg (msglevel, "PUSH OPTION FAILED (illegal comma (',') in string): '%s'", opt); } else { - if (!o->push_list) + struct push_entry *e; + ALLOC_OBJ_CLEAR_GC (e, struct push_entry, &o->gc); + e->enable = true; + e->option = opt; + if (o->push_list.head) { - ALLOC_OBJ_CLEAR_GC (o->push_list, struct push_list, &o->gc); - first = true; + ASSERT(o->push_list.tail); + o->push_list.tail->next = e; + o->push_list.tail = e; } - - len = strlen (o->push_list->options); - if (len + strlen (opt) + 2 >= MAX_PUSH_LIST_LEN) + else { - msg (msglevel, "Maximum length of --push buffer (%d) has been exceeded", MAX_PUSH_LIST_LEN); + ASSERT(!o->push_list.tail); + o->push_list.head = e; + o->push_list.tail = e; } - else + } +} + +void +push_option (struct options *o, const char *opt, int msglevel) +{ + push_option_ex (o, opt, true, msglevel); +} + +void +clone_push_list (struct options *o) +{ + if (o->push_list.head) + { + const struct push_entry *e = o->push_list.head; + push_reset (o); + while (e) { - if (!first) - strcat (o->push_list->options, ","); - strcat (o->push_list->options, opt); + push_option_ex (o, string_alloc (e->option, &o->gc), true, M_FATAL); + e = e->next; } } } @@ -184,7 +288,7 @@ void push_reset (struct options *o) { - o->push_list = NULL; + CLEAR (o->push_list); } #endif @@ -203,7 +307,8 @@ { if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED) { - send_auth_failed (c); + const char *client_reason = tls_client_reason (c->c2.tls_multi); + send_auth_failed (c, client_reason); ret = PUSH_MSG_AUTH_FAILURE; } else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) @@ -224,14 +329,31 @@ const uint8_t ch = buf_read_u8 (&buf); if (ch == ',') { - pre_pull_restore (&c->options); - c->c2.pulled_options_string = string_alloc (BSTR (&buf), &c->c2.gc); + struct buffer buf_orig = buf; + if (!c->c2.did_pre_pull_restore) + { + pre_pull_restore (&c->options); + md5_state_init (&c->c2.pulled_options_state); + c->c2.did_pre_pull_restore = true; + } if (apply_push_options (&c->options, &buf, permission_mask, option_types_found, c->c2.es)) - ret = PUSH_MSG_REPLY; + switch (c->options.push_continuation) + { + case 0: + case 1: + md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); + md5_state_final (&c->c2.pulled_options_state, &c->c2.pulled_options_digest); + ret = PUSH_MSG_REPLY; + break; + case 2: + md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); + ret = PUSH_MSG_CONTINUATION; + break; + } } else if (ch == '\0') { @@ -243,36 +365,27 @@ } #if P2MP_SERVER + /* * Remove iroutes from the push_list. */ void remove_iroutes_from_push_route_list (struct options *o) { - if (o && o->push_list && o->iroutes) + if (o && o->push_list.head && o->iroutes) { struct gc_arena gc = gc_new (); - struct push_list *pl; - struct buffer in, out; - char *line; - bool first = true; - - /* prepare input and output buffers */ - ALLOC_OBJ_CLEAR_GC (pl, struct push_list, &gc); - ALLOC_ARRAY_CLEAR_GC (line, char, MAX_PUSH_LIST_LEN, &gc); - - buf_set_read (&in, (const uint8_t*) o->push_list->options, strlen (o->push_list->options)); - buf_set_write (&out, (uint8_t*) pl->options, sizeof (pl->options)); + struct push_entry *e = o->push_list.head; /* cycle through the push list */ - while (buf_parse (&in, ',', line, MAX_PUSH_LIST_LEN)) + while (e) { char *p[MAX_PARMS]; - bool copy = true; + bool enable = true; /* parse the push item */ CLEAR (p); - if (parse_line (line, p, SIZE (p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc)) + if (parse_line (e->option, p, SIZE (p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc)) { /* is the push item a route directive? */ if (p[0] && !strcmp (p[0], "route") && !p[3]) @@ -292,7 +405,7 @@ { if (network == ir->network && netmask == netbits_to_netmask (ir->netbits >= 0 ? ir->netbits : 32)) { - copy = false; + enable = false; break; } } @@ -301,28 +414,17 @@ } /* should we copy the push item? */ - if (copy) - { - if (!first) - buf_printf (&out, ","); - buf_printf (&out, "%s", line); - first = false; - } - else - msg (D_PUSH, "REMOVE PUSH ROUTE: '%s'", line); - } + e->enable = enable; + if (!enable) + msg (D_PUSH, "REMOVE PUSH ROUTE: '%s'", e->option); -#if 0 - msg (M_INFO, "BEFORE: '%s'", o->push_list->options); - msg (M_INFO, "AFTER: '%s'", pl->options); -#endif - - /* copy new push list back to options */ - *o->push_list = *pl; + e = e->next; + } gc_free (&gc); } } + #endif #endif diff -Nru openvpn-2.1~rc19/push.h openvpn-2.1.1/push.h --- openvpn-2.1~rc19/push.h 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/push.h 2009-10-01 21:35:38.000000000 +0200 @@ -34,6 +34,7 @@ #define PUSH_MSG_REPLY 2 #define PUSH_MSG_REQUEST_DEFERRED 3 #define PUSH_MSG_AUTH_FAILURE 4 +#define PUSH_MSG_CONTINUATION 5 void incoming_push_message (struct context *c, const struct buffer *buffer); @@ -48,8 +49,12 @@ void receive_auth_failed (struct context *c, const struct buffer *buffer); +void server_pushed_restart (struct context *c, const struct buffer *buffer); + #if P2MP_SERVER +void clone_push_list (struct options *o); + void push_option (struct options *o, const char *opt, int msglevel); void push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc); @@ -59,7 +64,9 @@ void remove_iroutes_from_push_route_list (struct options *o); -void send_auth_failed (struct context *c); +void send_auth_failed (struct context *c, const char *client_reason); + +void send_restart (struct context *c); #endif #endif diff -Nru openvpn-2.1~rc19/pushlist.h openvpn-2.1.1/pushlist.h --- openvpn-2.1~rc19/pushlist.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/pushlist.h 2009-10-01 20:02:18.000000000 +0200 @@ -0,0 +1,42 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined(PUSHLIST_H) && P2MP && P2MP_SERVER +#define PUSHLIST_H + +/* parameters to be pushed to peer */ + +struct push_entry { + struct push_entry *next; + bool enable; + const char *option; +}; + +struct push_list { + struct push_entry *head; + struct push_entry *tail; +}; + + +#endif diff -Nru openvpn-2.1~rc19/route.c openvpn-2.1.1/route.c --- openvpn-2.1~rc19/route.c 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/route.c 2009-10-01 20:02:18.000000000 +0200 @@ -80,18 +80,38 @@ } struct route_option_list * -new_route_option_list (struct gc_arena *a) +new_route_option_list (const int max_routes, struct gc_arena *a) { struct route_option_list *ret; - ALLOC_OBJ_CLEAR_GC (ret, struct route_option_list, a); + ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_option_list, struct route_option, max_routes, a); + ret->capacity = max_routes; return ret; } +struct route_option_list * +clone_route_option_list (const struct route_option_list *src, struct gc_arena *a) +{ + const size_t rl_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list)); + struct route_option_list *ret = gc_malloc (rl_size, false, a); + memcpy (ret, src, rl_size); + return ret; +} + +void +copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src) +{ + const size_t src_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list)); + if (src->n > dest->capacity) + msg (M_FATAL, PACKAGE_NAME " ROUTE: (copy) number of route options in src (%d) is greater than route list capacity in dest (%d)", src->n, dest->capacity); + memcpy (dest, src, src_size); +} + struct route_list * -new_route_list (struct gc_arena *a) +new_route_list (const int max_routes, struct gc_arena *a) { struct route_list *ret; - ALLOC_OBJ_CLEAR_GC (ret, struct route_list, a); + ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route, max_routes, a); + ret->capacity = max_routes; return ret; } @@ -317,9 +337,9 @@ const char *metric) { struct route_option *ro; - if (l->n >= MAX_ROUTES) - msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d routes", - MAX_ROUTES); + if (l->n >= l->capacity) + msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d routes -- please increase the max-routes option in the client configuration file", + l->capacity); ro = &l->routes[l->n]; ro->network = network; ro->netmask = netmask; @@ -331,7 +351,10 @@ void clear_route_list (struct route_list *rl) { - CLEAR (*rl); + const int capacity = rl->capacity; + const size_t rl_size = array_mult_safe (sizeof(struct route), capacity, sizeof(struct route_list)); + memset(rl, 0, rl_size); + rl->capacity = capacity; } void @@ -415,7 +438,8 @@ else rl->spec.remote_endpoint_defined = false; - ASSERT (opt->n >= 0 && opt->n < MAX_ROUTES); + if (!(opt->n >= 0 && opt->n <= rl->capacity)) + msg (M_FATAL, PACKAGE_NAME " ROUTE: (init) number of route options (%d) is greater than route list capacity (%d)", opt->n, rl->capacity); /* parse the routes from opt to rl */ { @@ -716,7 +740,7 @@ } undo_redirect_default_route_to_vpn (rl, tt, flags, es); - CLEAR (*rl); + clear_route_list (rl); } #ifdef ENABLE_DEBUG @@ -2060,7 +2084,7 @@ #else bool -get_default_gateway (in_addr_t *ret, in_addr_t *netmask) +get_default_gateway (in_addr_t *ret, in_addr_t *netmask) /* PLATFORM-SPECIFIC */ { return false; } @@ -2156,7 +2180,7 @@ #else static void -get_bypass_addresses (struct route_bypass *rb, const unsigned int flags) +get_bypass_addresses (struct route_bypass *rb, const unsigned int flags) /* PLATFORM-SPECIFIC */ { } @@ -2303,7 +2327,7 @@ #else bool -get_default_gateway_mac_addr (unsigned char *macaddr) +get_default_gateway_mac_addr (unsigned char *macaddr) /* PLATFORM-SPECIFIC */ { return false; } @@ -2355,7 +2379,7 @@ int -test_local_addr (const in_addr_t addr) +test_local_addr (const in_addr_t addr) /* PLATFORM-SPECIFIC */ { return TLA_NOT_IMPLEMENTED; } diff -Nru openvpn-2.1~rc19/route.h openvpn-2.1.1/route.h --- openvpn-2.1~rc19/route.h 2009-05-30 23:34:12.000000000 +0200 +++ openvpn-2.1.1/route.h 2009-10-01 20:02:18.000000000 +0200 @@ -32,7 +32,7 @@ #include "tun.h" #include "misc.h" -#define MAX_ROUTES 100 +#define MAX_ROUTES_DEFAULT 100 #ifdef WIN32 /* @@ -86,9 +86,10 @@ #define RG_AUTO_LOCAL (1<<6) struct route_option_list { - int n; unsigned int flags; - struct route_option routes[MAX_ROUTES]; + int capacity; + int n; + struct route_option routes[EMPTY_ARRAY_SIZE]; }; struct route { @@ -107,8 +108,9 @@ unsigned int flags; bool did_redirect_default_gateway; bool did_local; + int capacity; int n; - struct route routes[MAX_ROUTES]; + struct route routes[EMPTY_ARRAY_SIZE]; }; #if P2MP @@ -120,9 +122,11 @@ }; #endif -struct route_option_list *new_route_option_list (struct gc_arena *a); +struct route_option_list *new_route_option_list (const int max_routes, struct gc_arena *a); +struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a); +void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src); -struct route_list *new_route_list (struct gc_arena *a); +struct route_list *new_route_list (const int max_routes, struct gc_arena *a); void add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); @@ -132,8 +136,6 @@ const char *gateway, const char *metric); -void clear_route_list (struct route_list *rl); - bool init_route_list (struct route_list *rl, const struct route_option_list *opt, const char *remote_endpoint, diff -Nru openvpn-2.1~rc19/sample-scripts/bs openvpn-2.1.1/sample-scripts/bs --- openvpn-2.1~rc19/sample-scripts/bs 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/sample-scripts/bs 2009-11-14 18:19:53.000000000 +0100 @@ -0,0 +1,39 @@ +#!/bin/bash + +################################# +# Set up Ethernet bridge on Linux +# Requires: bridge-utils +################################# + +# Define Bridge Interface +br="br0" + +# Define list of TAP interfaces to be bridged, +# for example tap="tap0 tap1 tap2". +tap="tap7" + +# Define physical ethernet interface to be bridged +# with TAP interface(s) above. +eth="eth0" +eth_ip="172.16.37.131" +eth_netmask="255.255.255.0" +eth_broadcast="172.16.37.255" + +for t in $tap; do + openvpn --mktun --dev $t --lladdr fe:ff:ff:ff:01:02 +done + +brctl addbr $br +brctl addif $br $eth + +for t in $tap; do + brctl addif $br $t +done + +for t in $tap; do + ifconfig $t 0.0.0.0 promisc up +done + +ifconfig $eth 0.0.0.0 promisc up + +ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast diff -Nru openvpn-2.1~rc19/socket.c openvpn-2.1.1/socket.c --- openvpn-2.1~rc19/socket.c 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/socket.c 2009-12-11 05:59:45.000000000 +0100 @@ -32,6 +32,7 @@ #include "plugin.h" #include "ps.h" #include "manage.h" +#include "misc.h" #include "memdbg.h" @@ -43,6 +44,19 @@ }; /* + * Convert sockflags/getaddr_flags into getaddr_flags + */ +static unsigned int +sf2gaf(const unsigned int getaddr_flags, + const unsigned int sockflags) +{ + if (sockflags & SF_HOST_RANDOMIZE) + return getaddr_flags | GETADDR_RANDOMIZE; + else + return getaddr_flags; +} + +/* * Functions related to the translation of DNS names to IP addresses. */ @@ -79,6 +93,10 @@ int status; int sigrec = 0; int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS; + struct gc_arena gc = gc_new (); + + if (flags & GETADDR_RANDOMIZE) + hostname = hostname_randomize(hostname, &gc); if (flags & GETADDR_MSG_VIRT_OUT) msglevel |= M_MSG_VIRT_OUT; @@ -225,6 +243,7 @@ msg (level, "RESOLVE: signal received during DNS resolution attempt"); } + gc_free (&gc); return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr; } @@ -359,12 +378,13 @@ static void update_remote (const char* host, struct openvpn_sockaddr *addr, - bool *changed) + bool *changed, + const unsigned int sockflags) { if (host && addr) { const in_addr_t new_addr = getaddr ( - GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, + sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), host, 1, NULL, @@ -728,7 +748,7 @@ if (socket_defined (new_sd)) { - update_remote (remote_dynamic, &remote_verify, remote_changed); + update_remote (remote_dynamic, &remote_verify, remote_changed, 0); if (addr_defined (&remote_verify) && !addr_match (&remote_verify, &act->dest)) { @@ -858,6 +878,7 @@ const int connect_retry_seconds, const int connect_timeout, const int connect_retry_max, + const unsigned int sockflags, volatile int *signal_received) { struct gc_arena gc = gc_new (); @@ -919,7 +940,7 @@ *sd = create_socket_tcp (); if (bind_local) socket_bind (*sd, local, "TCP Client"); - update_remote (remote_dynamic, remote, remote_changed); + update_remote (remote_dynamic, remote, remote_changed, sockflags); } msg (M_INFO, "TCP connection established with %s", @@ -1023,7 +1044,7 @@ if (sock->remote_host) { - unsigned int flags = GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE; + unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); int retry = 0; bool status = false; @@ -1384,6 +1405,7 @@ sock->connect_retry_seconds, sock->connect_timeout, sock->connect_retry_max, + sock->sockflags, signal_received); if (*signal_received) @@ -1432,6 +1454,7 @@ sock->connect_retry_seconds, sock->connect_timeout, sock->connect_retry_max, + sock->sockflags, signal_received); if (*signal_received) diff -Nru openvpn-2.1~rc19/socket.h openvpn-2.1.1/socket.h --- openvpn-2.1~rc19/socket.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/socket.h 2009-10-01 20:02:18.000000000 +0200 @@ -198,6 +198,7 @@ # define SF_USE_IP_PKTINFO (1<<0) # define SF_TCP_NODELAY (1<<1) # define SF_PORT_SHARE (1<<2) +# define SF_HOST_RANDOMIZE (1<<3) unsigned int sockflags; /* for stream sockets */ @@ -447,6 +448,7 @@ #define GETADDR_MSG_VIRT_OUT (1<<6) #define GETADDR_TRY_ONCE (1<<7) #define GETADDR_UPDATE_MANAGEMENT_STATE (1<<8) +#define GETADDR_RANDOMIZE (1<<9) in_addr_t getaddr (unsigned int flags, const char *hostname, diff -Nru openvpn-2.1~rc19/ssl.c openvpn-2.1.1/ssl.c --- openvpn-2.1~rc19/ssl.c 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/ssl.c 2009-11-12 21:30:36.000000000 +0100 @@ -340,6 +340,104 @@ } /* + * Cert hash functions + */ +static void +cert_hash_remember (struct tls_session *session, const int error_depth, const unsigned char *sha1_hash) +{ + if (error_depth >= 0 && error_depth < MAX_CERT_DEPTH) + { + if (!session->cert_hash_set) + ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set); + if (!session->cert_hash_set->ch[error_depth]) + ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash); + { + struct cert_hash *ch = session->cert_hash_set->ch[error_depth]; + memcpy (ch->sha1_hash, sha1_hash, SHA_DIGEST_LENGTH); + } + } +} + +#if 0 +static void +cert_hash_print (const struct cert_hash_set *chs, int msglevel) +{ + struct gc_arena gc = gc_new (); + msg (msglevel, "CERT_HASH"); + if (chs) + { + int i; + for (i = 0; i < MAX_CERT_DEPTH; ++i) + { + const struct cert_hash *ch = chs->ch[i]; + if (ch) + msg (msglevel, "%d:%s", i, format_hex(ch->sha1_hash, SHA_DIGEST_LENGTH, 0, &gc)); + } + } + gc_free (&gc); +} +#endif + +static void +cert_hash_free (struct cert_hash_set *chs) +{ + if (chs) + { + int i; + for (i = 0; i < MAX_CERT_DEPTH; ++i) + free (chs->ch[i]); + free (chs); + } +} + +static bool +cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set *chs2) +{ + if (chs1 && chs2) + { + int i; + for (i = 0; i < MAX_CERT_DEPTH; ++i) + { + const struct cert_hash *ch1 = chs1->ch[i]; + const struct cert_hash *ch2 = chs2->ch[i]; + + if (!ch1 && !ch2) + continue; + else if (ch1 && ch2 && !memcmp (ch1->sha1_hash, ch2->sha1_hash, SHA_DIGEST_LENGTH)) + continue; + else + return false; + } + return true; + } + else if (!chs1 && !chs2) + return true; + else + return false; +} + +static struct cert_hash_set * +cert_hash_copy (const struct cert_hash_set *chs) +{ + struct cert_hash_set *dest = NULL; + if (chs) + { + int i; + ALLOC_OBJ_CLEAR (dest, struct cert_hash_set); + for (i = 0; i < MAX_CERT_DEPTH; ++i) + { + const struct cert_hash *ch = chs->ch[i]; + if (ch) + { + ALLOC_OBJ (dest->ch[i], struct cert_hash); + memcpy (dest->ch[i]->sha1_hash, ch->sha1_hash, SHA_DIGEST_LENGTH); + } + } + } + return dest; +} + +/* * Extract a field from an X509 subject name. * * Example: @@ -603,7 +701,7 @@ SSL *ssl; struct tls_session *session; const struct tls_options *opt; - const int max_depth = 8; + const int max_depth = MAX_CERT_DEPTH; struct argv argv = argv_new (); /* get the tls_session pointer */ @@ -645,9 +743,16 @@ string_mod_sslname (common_name, COMMON_NAME_CHAR_CLASS, opt->ssl_flags); + cert_hash_remember (session, ctx->error_depth, ctx->current_cert->sha1_hash); + #if 0 /* print some debugging info */ - msg (D_LOW, "LOCAL OPT: %s", opt->local_options); - msg (D_LOW, "X509: %s", subject); + { + struct gc_arena gc = gc_new (); + msg (M_INFO, "LOCAL OPT[%d]: %s", ctx->error_depth, opt->local_options); + msg (M_INFO, "X509[%d]: %s", ctx->error_depth, subject); + msg (M_INFO, "SHA1[%d]: %s", ctx->error_depth, format_hex(ctx->current_cert->sha1_hash, SHA_DIGEST_LENGTH, 0, &gc)); + gc_free (&gc); + } #endif /* did peer present cert which was signed our root cert? */ @@ -661,7 +766,10 @@ /* warn if cert chain is too deep */ if (ctx->error_depth >= max_depth) - msg (M_WARN, "TLS Warning: Convoluted certificate chain detected with depth [%d] greater than %d", ctx->error_depth, max_depth); + { + msg (D_TLS_ERRORS, "TLS Error: Convoluted certificate chain detected with depth [%d] greater than %d", ctx->error_depth, max_depth); + goto err; /* Reject connection */ + } /* save common name in session object */ if (ctx->error_depth == 0) @@ -898,6 +1006,38 @@ multi->locked_cn = string_alloc (cn, NULL); } +void +tls_lock_cert_hash_set (struct tls_multi *multi) +{ + const struct cert_hash_set *chs = multi->session[TM_ACTIVE].cert_hash_set; + if (chs && !multi->locked_cert_hash_set) + multi->locked_cert_hash_set = cert_hash_copy (chs); +} + +static bool +tls_lock_username (struct tls_multi *multi, const char *username) +{ + if (multi->locked_username) + { + if (!username || strcmp (username, multi->locked_username)) + { + msg (D_TLS_ERRORS, "TLS Auth Error: username attempted to change from '%s' to '%s' -- tunnel disabled", + multi->locked_username, + np(username)); + + /* disable the tunnel */ + tls_deauthenticate (multi); + return false; + } + } + else + { + if (username) + multi->locked_username = string_alloc (username, NULL); + } + return true; +} + #ifdef ENABLE_DEF_AUTH /* key_state_test_auth_control_file return values, NOTE: acf_merge indexing depends on these values */ @@ -908,6 +1048,18 @@ #endif #ifdef MANAGEMENT_DEF_AUTH +static void +man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason) +{ + if (multi->client_reason) + { + free (multi->client_reason); + multi->client_reason = NULL; + } + if (client_reason && strlen (client_reason)) + multi->client_reason = string_alloc (client_reason, NULL); +} + static inline unsigned int man_def_auth_test (const struct key_state *ks) { @@ -1077,12 +1229,13 @@ #ifdef MANAGEMENT_DEF_AUTH bool -tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth) +tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason) { bool ret = false; if (multi) { int i; + man_def_auth_set_client_reason (multi, client_reason); for (i = 0; i < KEY_SCAN_SIZE; ++i) { struct key_state *ks = multi->key_scan[i]; @@ -2069,8 +2222,8 @@ ALLOC_OBJ_CLEAR (ks->rec_ack, struct reliable_ack); /* allocate buffers */ - ks->plaintext_read_buf = alloc_buf (PLAINTEXT_BUFFER_SIZE); - ks->plaintext_write_buf = alloc_buf (PLAINTEXT_BUFFER_SIZE); + ks->plaintext_read_buf = alloc_buf (TLS_CHANNEL_BUF_SIZE); + ks->plaintext_write_buf = alloc_buf (TLS_CHANNEL_BUF_SIZE); ks->ack_write_buf = alloc_buf (BUF_SIZE (&session->opt->frame)); reliable_init (ks->send_reliable, BUF_SIZE (&session->opt->frame), FRAME_HEADROOM (&session->opt->frame), TLS_RELIABLE_N_SEND_BUFFERS, @@ -2214,6 +2367,8 @@ if (session->common_name) free (session->common_name); + cert_hash_free (session->cert_hash_set); + if (clear) CLEAR (*session); } @@ -2397,9 +2552,18 @@ ASSERT (multi); +#ifdef MANAGEMENT_DEF_AUTH + man_def_auth_set_client_reason(multi, NULL); +#endif + if (multi->locked_cn) free (multi->locked_cn); + if (multi->locked_username) + free (multi->locked_username); + + cert_hash_free (multi->locked_cert_hash_set); + for (i = 0; i < TM_SIZE; ++i) tls_session_free (&multi->session[i], false); @@ -3384,7 +3548,8 @@ #ifdef PLUGIN_DEF_AUTH || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED #endif - ) && s2 && man_def_auth != KMDA_ERROR) + ) && s2 && man_def_auth != KMDA_ERROR + && tls_lock_username (multi, up->username)) { ks->authenticated = true; #ifdef PLUGIN_DEF_AUTH @@ -3395,7 +3560,6 @@ if (man_def_auth != KMDA_UNDEF) ks->auth_deferred = true; #endif - if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)) set_common_name (session, up->username); #ifdef ENABLE_DEF_AUTH @@ -3448,6 +3612,20 @@ } } + /* Don't allow the cert hashes to change once they have been locked */ + if (ks->authenticated && multi->locked_cert_hash_set) + { + const struct cert_hash_set *chs = session->cert_hash_set; + if (chs && !cert_hash_compare (chs, multi->locked_cert_hash_set)) + { + msg (D_TLS_ERRORS, "TLS Auth Error: TLS object CN=%s client-provided SSL certs unexpectedly changed during mid-session reauth", + session->common_name); + + /* disable the tunnel */ + tls_deauthenticate (multi); + } + } + /* verify --client-config-dir based authentication */ if (ks->authenticated && session->opt->client_config_dir_exclusive) { @@ -3750,7 +3928,7 @@ int status; ASSERT (buf_init (buf, 0)); - status = key_state_read_plaintext (multi, ks, buf, PLAINTEXT_BUFFER_SIZE); + status = key_state_read_plaintext (multi, ks, buf, TLS_CHANNEL_BUF_SIZE); update_time (); if (status == -1) { diff -Nru openvpn-2.1~rc19/ssl.h openvpn-2.1.1/ssl.h --- openvpn-2.1~rc19/ssl.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/ssl.h 2009-11-12 13:04:18.000000000 +0100 @@ -278,8 +278,6 @@ * Buffer sizes (also see mtu.h). */ -#define PLAINTEXT_BUFFER_SIZE TLS_CHANNEL_BUF_SIZE - /* Maximum length of common name */ #define TLS_CN_LEN 64 @@ -305,6 +303,21 @@ /* #define MEASURE_TLS_HANDSHAKE_STATS */ /* + * Keep track of certificate hashes at various depths + */ + +/* Maximum certificate depth we will allow */ +#define MAX_CERT_DEPTH 16 + +struct cert_hash { + unsigned char sha1_hash[SHA_DIGEST_LENGTH]; +}; + +struct cert_hash_set { + struct cert_hash *ch[MAX_CERT_DEPTH]; +}; + +/* * Key material, used as source for PRF-based * key expansion. */ @@ -520,6 +533,8 @@ char *common_name; + struct cert_hash_set *cert_hash_set; + #ifdef ENABLE_PF uint32_t common_name_hashval; #endif @@ -591,11 +606,18 @@ int n_soft_errors; /* errors due to unrecognized or failed-to-authenticate incoming packets */ /* - * Our locked common name (cannot change during the life of this tls_multi object) + * Our locked common name, username, and cert hashes (cannot change during the life of this tls_multi object) */ char *locked_cn; + char *locked_username; + struct cert_hash_set *locked_cert_hash_set; #ifdef ENABLE_DEF_AUTH + /* + * An error message to send to client on AUTH_FAILED + */ + char *client_reason; + /* Time of last call to tls_authentication_status */ time_t tas_last; #endif @@ -688,6 +710,7 @@ const char *tls_common_name (const struct tls_multi* multi, const bool null); void tls_set_common_name (struct tls_multi *multi, const char *common_name); void tls_lock_common_name (struct tls_multi *multi); +void tls_lock_cert_hash_set (struct tls_multi *multi); #define TLS_AUTHENTICATION_SUCCEEDED 0 #define TLS_AUTHENTICATION_FAILED 1 @@ -697,7 +720,7 @@ void tls_deauthenticate (struct tls_multi *multi); #ifdef MANAGEMENT_DEF_AUTH -bool tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth); +bool tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason); #endif /* @@ -705,6 +728,12 @@ */ static inline bool +tls_initial_packet_received (const struct tls_multi *multi) +{ + return multi->n_sessions > 0; +} + +static inline bool tls_test_auth_deferred_interval (const struct tls_multi *multi) { if (multi) @@ -734,6 +763,16 @@ multi->opt.single_session = true; } +static inline const char * +tls_client_reason (struct tls_multi *multi) +{ +#ifdef ENABLE_DEF_AUTH + return multi->client_reason; +#else + return NULL; +#endif +} + #ifdef ENABLE_PF static inline bool diff -Nru openvpn-2.1~rc19/syshead.h openvpn-2.1.1/syshead.h --- openvpn-2.1~rc19/syshead.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/syshead.h 2009-10-01 20:02:18.000000000 +0200 @@ -180,6 +180,10 @@ #include #endif +#ifdef HAVE_SETCON +#include +#endif + #ifdef TARGET_SOLARIS #ifdef HAVE_STRINGS_H #include @@ -494,7 +498,6 @@ /* * Enable deferred authentication? */ -#define CONFIGURE_DEF_AUTH /* this should be set by autoconf and config.h */ #if defined(CONFIGURE_DEF_AUTH) && P2MP_SERVER && defined(ENABLE_PLUGIN) #define PLUGIN_DEF_AUTH #endif @@ -508,7 +511,6 @@ /* * Enable packet filter? */ -#define CONFIGURE_PF /* this should be set by autoconf and config.h */ #if defined(CONFIGURE_PF) && P2MP_SERVER && defined(ENABLE_PLUGIN) && defined(HAVE_STAT) #define PLUGIN_PF #endif diff -Nru openvpn-2.1~rc19/tap-win32/common.h openvpn-2.1.1/tap-win32/common.h --- openvpn-2.1~rc19/tap-win32/common.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/common.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/constants.h openvpn-2.1.1/tap-win32/constants.h --- openvpn-2.1~rc19/tap-win32/constants.h 2009-06-22 23:01:42.000000000 +0200 +++ openvpn-2.1.1/tap-win32/constants.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/dhcp.c openvpn-2.1.1/tap-win32/dhcp.c --- openvpn-2.1~rc19/tap-win32/dhcp.c 2009-06-22 23:01:42.000000000 +0200 +++ openvpn-2.1.1/tap-win32/dhcp.c 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/dhcp.h openvpn-2.1.1/tap-win32/dhcp.h --- openvpn-2.1~rc19/tap-win32/dhcp.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/dhcp.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/endian.h openvpn-2.1.1/tap-win32/endian.h --- openvpn-2.1~rc19/tap-win32/endian.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/endian.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/error.c openvpn-2.1.1/tap-win32/error.c --- openvpn-2.1~rc19/tap-win32/error.c 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/error.c 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/error.h openvpn-2.1.1/tap-win32/error.h --- openvpn-2.1~rc19/tap-win32/error.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/error.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/filt.py openvpn-2.1.1/tap-win32/filt.py --- openvpn-2.1~rc19/tap-win32/filt.py 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/filt.py 2009-12-11 06:04:40.000000000 +0100 @@ -0,0 +1,20 @@ +import sys +import re + +start_re = "(^.*released under the GPL version 2 \(see below\)).*however due" +skip = 0 +while True: + line = sys.stdin.readline() + if not line: + break + m = re.match (start_re, line) + if m: + g = m.groups() + print g[0] + '.' + skip = 5 + if skip > 0: + skip -= 1 + else: + print line, + +sys.exit(0) diff -Nru openvpn-2.1~rc19/tap-win32/hexdump.c openvpn-2.1.1/tap-win32/hexdump.c --- openvpn-2.1~rc19/tap-win32/hexdump.c 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/hexdump.c 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/hexdump.h openvpn-2.1.1/tap-win32/hexdump.h --- openvpn-2.1~rc19/tap-win32/hexdump.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/hexdump.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/instance.c openvpn-2.1.1/tap-win32/instance.c --- openvpn-2.1~rc19/tap-win32/instance.c 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/instance.c 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/lock.h openvpn-2.1.1/tap-win32/lock.h --- openvpn-2.1~rc19/tap-win32/lock.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/lock.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/macinfo.c openvpn-2.1.1/tap-win32/macinfo.c --- openvpn-2.1~rc19/tap-win32/macinfo.c 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/macinfo.c 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/macinfo.h openvpn-2.1.1/tap-win32/macinfo.h --- openvpn-2.1~rc19/tap-win32/macinfo.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/macinfo.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/mem.c openvpn-2.1.1/tap-win32/mem.c --- openvpn-2.1~rc19/tap-win32/mem.c 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/mem.c 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/proto.h openvpn-2.1.1/tap-win32/proto.h --- openvpn-2.1~rc19/tap-win32/proto.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tap-win32/proto.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/prototypes.h openvpn-2.1.1/tap-win32/prototypes.h --- openvpn-2.1~rc19/tap-win32/prototypes.h 2009-06-22 23:01:42.000000000 +0200 +++ openvpn-2.1.1/tap-win32/prototypes.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/tapdrvr.c openvpn-2.1.1/tap-win32/tapdrvr.c --- openvpn-2.1~rc19/tap-win32/tapdrvr.c 2009-06-22 23:01:42.000000000 +0200 +++ openvpn-2.1.1/tap-win32/tapdrvr.c 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tap-win32/tmp/common.h openvpn-2.1.1/tap-win32/tmp/common.h --- openvpn-2.1~rc19/tap-win32/tmp/common.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/common.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,92 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//=============================================== +// This file is included both by OpenVPN and +// the TAP-Win32 driver and contains definitions +// common to both. +//=============================================== + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#else +#if defined(_MSC_VER) && !defined(TAP_DRIVER_MAJOR_VERSION) +#include "config-win32.h" +#else +#include "../config.h" +#endif +#endif + +//============= +// TAP IOCTLs +//============= + +#define TAP_CONTROL_CODE(request,method) \ + CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) + +// Present in 8.1 + +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) +#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) +#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) +#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) +#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) +#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) + +// Added in 8.2 + +/* obsoletes TAP_IOCTL_CONFIG_POINT_TO_POINT */ +#define TAP_IOCTL_CONFIG_TUN TAP_CONTROL_CODE (10, METHOD_BUFFERED) + +//================= +// Registry keys +//================= + +#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +//====================== +// Filesystem prefixes +//====================== + +#define USERMODEDEVICEDIR "\\\\.\\Global\\" +#define SYSDEVICEDIR "\\Device\\" +#define USERDEVICEDIR "\\DosDevices\\Global\\" +#define TAPSUFFIX ".tap" + +//========================================================= +// TAP_COMPONENT_ID -- This string defines the TAP driver +// type -- different component IDs can reside in the system +// simultaneously. +//========================================================= + +#define TAP_COMPONENT_ID TAP_ID diff -Nru openvpn-2.1~rc19/tap-win32/tmp/constants.h openvpn-2.1.1/tap-win32/tmp/constants.h --- openvpn-2.1~rc19/tap-win32/tmp/constants.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/constants.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,56 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//==================================================================== +// Product and Version public settings +//==================================================================== + +#define PRODUCT_STRING PRODUCT_TAP_DEVICE_DESCRIPTION + +#define TAP_NDIS_MAJOR_VERSION 5 +#define TAP_NDIS_MINOR_VERSION 0 + +//=========================================================== +// Driver constants +//=========================================================== + +#define ETHERNET_HEADER_SIZE (sizeof (ETH_HEADER)) +#define ETHERNET_MTU 1500 +#define ETHERNET_PACKET_SIZE (ETHERNET_MTU + ETHERNET_HEADER_SIZE) +#define DEFAULT_PACKET_LOOKAHEAD (ETHERNET_PACKET_SIZE) + +#define NIC_MAX_MCAST_LIST 32 // Max length of multicast address list + +#define MINIMUM_MTU 576 // USE TCP Minimum MTU +#define MAXIMUM_MTU 65536 // IP maximum MTU + +#define PACKET_QUEUE_SIZE 64 // tap -> userspace queue size +#define IRP_QUEUE_SIZE 16 // max number of simultaneous i/o operations from userspace +#define INJECT_QUEUE_SIZE 16 // DHCP/ARP -> tap injection queue + +#define TAP_LITTLE_ENDIAN // affects ntohs, htonl, etc. functions diff -Nru openvpn-2.1~rc19/tap-win32/tmp/dhcp.c openvpn-2.1.1/tap-win32/tmp/dhcp.c --- openvpn-2.1~rc19/tap-win32/tmp/dhcp.c 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/dhcp.c 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,603 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//========================= +// Code to set DHCP options +//========================= + +VOID +SetDHCPOpt (DHCPMsg *m, void *data, unsigned int len) +{ + if (!m->overflow) + { + if (m->optlen + len <= DHCP_OPTIONS_BUFFER_SIZE) + { + if (len) + { + NdisMoveMemory (m->msg.options + m->optlen, data, len); + m->optlen += len; + } + } + else + { + m->overflow = TRUE; + } + } +} + +VOID +SetDHCPOpt0 (DHCPMsg *msg, int type) +{ + DHCPOPT0 opt; + opt.type = (UCHAR) type; + SetDHCPOpt (msg, &opt, sizeof (opt)); +} + +VOID +SetDHCPOpt8 (DHCPMsg *msg, int type, ULONG data) +{ + DHCPOPT8 opt; + opt.type = (UCHAR) type; + opt.len = sizeof (opt.data); + opt.data = (UCHAR) data; + SetDHCPOpt (msg, &opt, sizeof (opt)); +} + +VOID +SetDHCPOpt32 (DHCPMsg *msg, int type, ULONG data) +{ + DHCPOPT32 opt; + opt.type = (UCHAR) type; + opt.len = sizeof (opt.data); + opt.data = data; + SetDHCPOpt (msg, &opt, sizeof (opt)); +} + +//============== +// Checksum code +//============== + +USHORT +ip_checksum (const UCHAR *buf, const int len_ip_header) +{ + USHORT word16; + ULONG sum = 0; + int i; + + // make 16 bit words out of every two adjacent 8 bit words in the packet + // and add them up + for (i = 0; i < len_ip_header - 1; i += 2) { + word16 = ((buf[i] << 8) & 0xFF00) + (buf[i+1] & 0xFF); + sum += (ULONG) word16; + } + + // take only 16 bits out of the 32 bit sum and add up the carries + while (sum >> 16) + sum = (sum & 0xFFFF) + (sum >> 16); + + // one's complement the result + return ((USHORT) ~sum); +} + +USHORT +udp_checksum (const UCHAR *buf, + const int len_udp, + const UCHAR *src_addr, + const UCHAR *dest_addr) +{ + USHORT word16; + ULONG sum = 0; + int i; + + // make 16 bit words out of every two adjacent 8 bit words and + // calculate the sum of all 16 bit words + for (i = 0; i < len_udp; i += 2){ + word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0); + sum += word16; + } + + // add the UDP pseudo header which contains the IP source and destination addresses + for (i = 0; i < 4; i += 2){ + word16 =((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF); + sum += word16; + } + for (i = 0; i < 4; i += 2){ + word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF); + sum += word16; + } + + // the protocol number and the length of the UDP packet + sum += (USHORT) IPPROTO_UDP + (USHORT) len_udp; + + // keep only the last 16 bits of the 32 bit calculated sum and add the carries + while (sum >> 16) + sum = (sum & 0xFFFF) + (sum >> 16); + + // Take the one's complement of sum + return ((USHORT) ~sum); +} + +//================================ +// Set IP and UDP packet checksums +//================================ + +VOID +SetChecksumDHCPMsg (DHCPMsg *m) +{ + // Set IP checksum + m->msg.pre.ip.check = htons (ip_checksum ((UCHAR *) &m->msg.pre.ip, sizeof (IPHDR))); + + // Set UDP Checksum + m->msg.pre.udp.check = htons (udp_checksum ((UCHAR *) &m->msg.pre.udp, + sizeof (UDPHDR) + sizeof (DHCP) + m->optlen, + (UCHAR *)&m->msg.pre.ip.saddr, + (UCHAR *)&m->msg.pre.ip.daddr)); +} + +//=================== +// DHCP message tests +//=================== + +int +GetDHCPMessageType (const DHCP *dhcp, const int optlen) +{ + const UCHAR *p = (UCHAR *) (dhcp + 1); + int i; + + for (i = 0; i < optlen; ++i) + { + const UCHAR type = p[i]; + const int room = optlen - i - 1; + if (type == DHCP_END) // didn't find what we were looking for + return -1; + else if (type == DHCP_PAD) // no-operation + ; + else if (type == DHCP_MSG_TYPE) // what we are looking for + { + if (room >= 2) + { + if (p[i+1] == 1) // message length should be 1 + return p[i+2]; // return message type + } + return -1; + } + else // some other message + { + if (room >= 1) + { + const int len = p[i+1]; // get message length + i += (len + 1); // advance to next message + } + } + } + return -1; +} + +BOOLEAN +DHCPMessageOurs (const TapAdapterPointer p_Adapter, + const ETH_HEADER *eth, + const IPHDR *ip, + const UDPHDR *udp, + const DHCP *dhcp) +{ + // Must be UDPv4 protocol + if (!(eth->proto == htons (ETH_P_IP) && ip->protocol == IPPROTO_UDP)) + return FALSE; + + // Source MAC must be our adapter + if (!MAC_EQUAL (eth->src, p_Adapter->m_MAC)) + return FALSE; + + // Dest MAC must be either broadcast or our virtual DHCP server + if (!(MAC_EQUAL (eth->dest, p_Adapter->m_MAC_Broadcast) + || MAC_EQUAL (eth->dest, p_Adapter->m_dhcp_server_mac))) + return FALSE; + + // Port numbers must be correct + if (!(udp->dest == htons (BOOTPS_PORT) + && udp->source == htons (BOOTPC_PORT))) + return FALSE; + + // Hardware address must be MAC addr sized + if (!(dhcp->hlen == sizeof (MACADDR))) + return FALSE; + + // Hardware address must match our adapter + if (!MAC_EQUAL (eth->src, dhcp->chaddr)) + return FALSE; + + return TRUE; +} + + +//===================================================== +// Build all of DHCP packet except for DHCP options. +// Assume that *p has been zeroed before we are called. +//===================================================== + +VOID +BuildDHCPPre (const TapAdapterPointer a, + DHCPPre *p, + const ETH_HEADER *eth, + const IPHDR *ip, + const UDPHDR *udp, + const DHCP *dhcp, + const int optlen, + const int type) +{ + // Should we broadcast or direct to a specific MAC / IP address? + const BOOLEAN broadcast = (type == DHCPNAK + || MAC_EQUAL (eth->dest, a->m_MAC_Broadcast)); + // Build ethernet header + + COPY_MAC (p->eth.src, a->m_dhcp_server_mac); + + if (broadcast) + COPY_MAC (p->eth.dest, a->m_MAC_Broadcast); + else + COPY_MAC (p->eth.dest, eth->src); + + p->eth.proto = htons (ETH_P_IP); + + // Build IP header + + p->ip.version_len = (4 << 4) | (sizeof (IPHDR) >> 2); + p->ip.tos = 0; + p->ip.tot_len = htons (sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen); + p->ip.id = 0; + p->ip.frag_off = 0; + p->ip.ttl = 16; + p->ip.protocol = IPPROTO_UDP; + p->ip.check = 0; + p->ip.saddr = a->m_dhcp_server_ip; + + if (broadcast) + p->ip.daddr = ~0; + else + p->ip.daddr = a->m_dhcp_addr; + + // Build UDP header + + p->udp.source = htons (BOOTPS_PORT); + p->udp.dest = htons (BOOTPC_PORT); + p->udp.len = htons (sizeof (UDPHDR) + sizeof (DHCP) + optlen); + p->udp.check = 0; + + // Build DHCP response + + p->dhcp.op = BOOTREPLY; + p->dhcp.htype = 1; + p->dhcp.hlen = sizeof (MACADDR); + p->dhcp.hops = 0; + p->dhcp.xid = dhcp->xid; + p->dhcp.secs = 0; + p->dhcp.flags = 0; + p->dhcp.ciaddr = 0; + + if (type == DHCPNAK) + p->dhcp.yiaddr = 0; + else + p->dhcp.yiaddr = a->m_dhcp_addr; + + p->dhcp.siaddr = a->m_dhcp_server_ip; + p->dhcp.giaddr = 0; + COPY_MAC (p->dhcp.chaddr, eth->src); + p->dhcp.magic = htonl (0x63825363); +} +//============================= +// Build specific DHCP messages +//============================= + +VOID +SendDHCPMsg (const TapAdapterPointer a, + const int type, + const ETH_HEADER *eth, + const IPHDR *ip, + const UDPHDR *udp, + const DHCP *dhcp) +{ + DHCPMsg *pkt; + + if (!(type == DHCPOFFER || type == DHCPACK || type == DHCPNAK)) + { + DEBUGP (("[TAP] SendDHCPMsg: Bad DHCP type: %d\n", type)); + return; + } + + pkt = (DHCPMsg *) MemAlloc (sizeof (DHCPMsg), TRUE); + + if (pkt) + { + //----------------------- + // Build DHCP options + //----------------------- + + // Message Type + SetDHCPOpt8 (pkt, DHCP_MSG_TYPE, type); + + // Server ID + SetDHCPOpt32 (pkt, DHCP_SERVER_ID, a->m_dhcp_server_ip); + + if (type == DHCPOFFER || type == DHCPACK) + { + // Lease Time + SetDHCPOpt32 (pkt, DHCP_LEASE_TIME, htonl (a->m_dhcp_lease_time)); + + // Netmask + SetDHCPOpt32 (pkt, DHCP_NETMASK, a->m_dhcp_netmask); + + // Other user-defined options + SetDHCPOpt (pkt, + a->m_dhcp_user_supplied_options_buffer, + a->m_dhcp_user_supplied_options_buffer_len); + } + + // End + SetDHCPOpt0 (pkt, DHCP_END); + + if (!DHCPMSG_OVERFLOW (pkt)) + { + // The initial part of the DHCP message (not including options) gets built here + BuildDHCPPre (a, + &pkt->msg.pre, + eth, + ip, + udp, + dhcp, + DHCPMSG_LEN_OPT (pkt), + type); + + SetChecksumDHCPMsg (pkt); + + DUMP_PACKET ("DHCPMsg", + DHCPMSG_BUF (pkt), + DHCPMSG_LEN_FULL (pkt)); + + // Return DHCP response to kernel + InjectPacketDeferred (a, + DHCPMSG_BUF (pkt), + DHCPMSG_LEN_FULL (pkt)); + } + else + { + DEBUGP (("[TAP] SendDHCPMsg: DHCP buffer overflow\n")); + } + + MemFree (pkt, sizeof (DHCPMsg)); + } +} + +//=================================================================== +// Handle a BOOTPS packet produced by the local system to +// resolve the address/netmask of this adapter. +// If we are in TAP_IOCTL_CONFIG_DHCP_MASQ mode, reply +// to the message. Return TRUE if we processed the passed +// message, so that downstream stages can ignore it. +//=================================================================== + +BOOLEAN +ProcessDHCP (TapAdapterPointer p_Adapter, + const ETH_HEADER *eth, + const IPHDR *ip, + const UDPHDR *udp, + const DHCP *dhcp, + int optlen) +{ + int msg_type; + + // Sanity check IP header + if (!(ntohs (ip->tot_len) == sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen + && (ntohs (ip->frag_off) & IP_OFFMASK) == 0)) + return TRUE; + + // Does this message belong to us? + if (!DHCPMessageOurs (p_Adapter, eth, ip, udp, dhcp)) + return FALSE; + + msg_type = GetDHCPMessageType (dhcp, optlen); + + // Drop non-BOOTREQUEST messages + if (dhcp->op != BOOTREQUEST) + return TRUE; + + // Drop any messages except DHCPDISCOVER or DHCPREQUEST + if (!(msg_type == DHCPDISCOVER || msg_type == DHCPREQUEST)) + return TRUE; + + // Should we reply with DHCPOFFER, DHCPACK, or DHCPNAK? + if (msg_type == DHCPREQUEST + && ((dhcp->ciaddr && dhcp->ciaddr != p_Adapter->m_dhcp_addr) + || !p_Adapter->m_dhcp_received_discover + || p_Adapter->m_dhcp_bad_requests >= BAD_DHCPREQUEST_NAK_THRESHOLD)) + SendDHCPMsg (p_Adapter, + DHCPNAK, + eth, ip, udp, dhcp); + else + SendDHCPMsg (p_Adapter, + (msg_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK), + eth, ip, udp, dhcp); + + // Remember if we received a DHCPDISCOVER + if (msg_type == DHCPDISCOVER) + p_Adapter->m_dhcp_received_discover = TRUE; + + // Is this a bad DHCPREQUEST? + if (msg_type == DHCPREQUEST && dhcp->ciaddr != p_Adapter->m_dhcp_addr) + ++p_Adapter->m_dhcp_bad_requests; + + return TRUE; +} + +#if DBG + +const char * +message_op_text (int op) +{ + switch (op) + { + case BOOTREQUEST: + return "BOOTREQUEST"; + case BOOTREPLY: + return "BOOTREPLY"; + default: + return "???"; + } +} + +const char * +message_type_text (int type) +{ + switch (type) + { + case DHCPDISCOVER: + return "DHCPDISCOVER"; + case DHCPOFFER: + return "DHCPOFFER"; + case DHCPREQUEST: + return "DHCPREQUEST"; + case DHCPDECLINE: + return "DHCPDECLINE"; + case DHCPACK: + return "DHCPACK"; + case DHCPNAK: + return "DHCPNAK"; + case DHCPRELEASE: + return "DHCPRELEASE"; + case DHCPINFORM: + return "DHCPINFORM"; + default: + return "???"; + } +} + +const char * +port_name (int port) +{ + switch (port) + { + case BOOTPS_PORT: + return "BOOTPS"; + case BOOTPC_PORT: + return "BOOTPC"; + default: + return "unknown"; + } +} + +VOID +DumpDHCP (const ETH_HEADER *eth, + const IPHDR *ip, + const UDPHDR *udp, + const DHCP *dhcp, + const int optlen) +{ + DEBUGP ((" %s", message_op_text (dhcp->op))); + DEBUGP ((" %s ", message_type_text (GetDHCPMessageType (dhcp, optlen)))); + PrIP (ip->saddr); + DEBUGP ((":%s[", port_name (ntohs (udp->source)))); + PrMac (eth->src); + DEBUGP (("] -> ")); + PrIP (ip->daddr); + DEBUGP ((":%s[", port_name (ntohs (udp->dest)))); + PrMac (eth->dest); + DEBUGP (("]")); + if (dhcp->ciaddr) + { + DEBUGP ((" ci=")); + PrIP (dhcp->ciaddr); + } + if (dhcp->yiaddr) + { + DEBUGP ((" yi=")); + PrIP (dhcp->yiaddr); + } + if (dhcp->siaddr) + { + DEBUGP ((" si=")); + PrIP (dhcp->siaddr); + } + if (dhcp->hlen == sizeof (MACADDR)) + { + DEBUGP ((" ch=")); + PrMac (dhcp->chaddr); + } + + DEBUGP ((" xid=0x%08x", ntohl (dhcp->xid))); + + if (ntohl (dhcp->magic) != 0x63825363) + DEBUGP ((" ma=0x%08x", ntohl (dhcp->magic))); + if (dhcp->htype != 1) + DEBUGP ((" htype=%d", dhcp->htype)); + if (dhcp->hops) + DEBUGP ((" hops=%d", dhcp->hops)); + if (ntohs (dhcp->secs)) + DEBUGP ((" secs=%d", ntohs (dhcp->secs))); + if (ntohs (dhcp->flags)) + DEBUGP ((" flags=0x%04x", ntohs (dhcp->flags))); + + // extra stuff + + if (ip->version_len != 0x45) + DEBUGP ((" vl=0x%02x", ip->version_len)); + if (ntohs (ip->tot_len) != sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + optlen) + DEBUGP ((" tl=%d", ntohs (ip->tot_len))); + if (ntohs (udp->len) != sizeof (UDPHDR) + sizeof (DHCP) + optlen) + DEBUGP ((" ul=%d", ntohs (udp->len))); + + if (ip->tos) + DEBUGP ((" tos=0x%02x", ip->tos)); + if (ntohs (ip->id)) + DEBUGP ((" id=0x%04x", ntohs (ip->id))); + if (ntohs (ip->frag_off)) + DEBUGP ((" frag_off=0x%04x", ntohs (ip->frag_off))); + + DEBUGP ((" ttl=%d", ip->ttl)); + DEBUGP ((" ic=0x%04x [0x%04x]", ntohs (ip->check), + ip_checksum ((UCHAR*)ip, sizeof (IPHDR)))); + DEBUGP ((" uc=0x%04x [0x%04x/%d]", ntohs (udp->check), + udp_checksum ((UCHAR *) udp, + sizeof (UDPHDR) + sizeof (DHCP) + optlen, + (UCHAR *) &ip->saddr, + (UCHAR *) &ip->daddr), + optlen)); + + // Options + { + const UCHAR *opt = (UCHAR *) (dhcp + 1); + int i; + + DEBUGP ((" OPT")); + for (i = 0; i < optlen; ++i) + { + const UCHAR data = opt[i]; + DEBUGP ((".%d", data)); + } + } +} + +#endif /* DBG */ diff -Nru openvpn-2.1~rc19/tap-win32/tmp/dhcp.h openvpn-2.1.1/tap-win32/tmp/dhcp.h --- openvpn-2.1~rc19/tap-win32/tmp/dhcp.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/dhcp.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,168 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#pragma pack(1) + +//=================================================== +// How many bad DHCPREQUESTs do we receive before we +// return a NAK? +// +// A bad DHCPREQUEST is defined to be one where the +// requestor doesn't know its IP address. +//=================================================== + +#define BAD_DHCPREQUEST_NAK_THRESHOLD 3 + +//============================================== +// Maximum number of DHCP options bytes supplied +//============================================== + +#define DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE 256 +#define DHCP_OPTIONS_BUFFER_SIZE 256 + +//=================================== +// UDP port numbers of DHCP messages. +//=================================== + +#define BOOTPS_PORT 67 +#define BOOTPC_PORT 68 + +//=========================== +// The DHCP message structure +//=========================== + +typedef struct { +# define BOOTREQUEST 1 +# define BOOTREPLY 2 + UCHAR op; /* message op */ + + UCHAR htype; /* hardware address type (e.g. '1' = 10Mb Ethernet) */ + UCHAR hlen; /* hardware address length (e.g. '6' for 10Mb Ethernet) */ + UCHAR hops; /* client sets to 0, may be used by relay agents */ + ULONG xid; /* transaction ID, chosen by client */ + USHORT secs; /* seconds since request process began, set by client */ + USHORT flags; + ULONG ciaddr; /* client IP address, client sets if known */ + ULONG yiaddr; /* 'your' IP address -- server's response to client */ + ULONG siaddr; /* server IP address */ + ULONG giaddr; /* relay agent IP address */ + UCHAR chaddr[16]; /* client hardware address */ + UCHAR sname[64]; /* optional server host name */ + UCHAR file[128]; /* boot file name */ + ULONG magic; /* must be 0x63825363 (network order) */ +} DHCP; + +typedef struct { + ETH_HEADER eth; + IPHDR ip; + UDPHDR udp; + DHCP dhcp; +} DHCPPre; + +typedef struct { + DHCPPre pre; + UCHAR options[DHCP_OPTIONS_BUFFER_SIZE]; +} DHCPFull; + +typedef struct { + unsigned int optlen; + BOOLEAN overflow; + DHCPFull msg; +} DHCPMsg; + +//=================== +// Macros for DHCPMSG +//=================== + +#define DHCPMSG_LEN_BASE(p) (sizeof (DHCPPre)) +#define DHCPMSG_LEN_OPT(p) ((p)->optlen) +#define DHCPMSG_LEN_FULL(p) (DHCPMSG_LEN_BASE(p) + DHCPMSG_LEN_OPT(p)) +#define DHCPMSG_BUF(p) ((UCHAR*) &(p)->msg) +#define DHCPMSG_OVERFLOW(p) ((p)->overflow) + +//======================================== +// structs to hold individual DHCP options +//======================================== + +typedef struct { + UCHAR type; +} DHCPOPT0; + +typedef struct { + UCHAR type; + UCHAR len; + UCHAR data; +} DHCPOPT8; + +typedef struct { + UCHAR type; + UCHAR len; + ULONG data; +} DHCPOPT32; + +#pragma pack() + +//================== +// DHCP Option types +//================== + +#define DHCP_MSG_TYPE 53 /* message type (u8) */ +#define DHCP_PARM_REQ 55 /* parameter request list: c1 (u8), ... */ +#define DHCP_CLIENT_ID 61 /* client ID: type (u8), i1 (u8), ... */ +#define DHCP_IP 50 /* requested IP addr (u32) */ +#define DHCP_NETMASK 1 /* subnet mask (u32) */ +#define DHCP_LEASE_TIME 51 /* lease time sec (u32) */ +#define DHCP_RENEW_TIME 58 /* renewal time sec (u32) */ +#define DHCP_REBIND_TIME 59 /* rebind time sec (u32) */ +#define DHCP_SERVER_ID 54 /* server ID: IP addr (u32) */ +#define DHCP_PAD 0 +#define DHCP_END 255 + +//==================== +// DHCP Messages types +//==================== + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +#if DBG + +VOID +DumpDHCP (const ETH_HEADER *eth, + const IPHDR *ip, + const UDPHDR *udp, + const DHCP *dhcp, + const int optlen); + +#endif diff -Nru openvpn-2.1~rc19/tap-win32/tmp/endian.h openvpn-2.1.1/tap-win32/tmp/endian.h --- openvpn-2.1~rc19/tap-win32/tmp/endian.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/endian.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,39 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef TAP_LITTLE_ENDIAN +#define ntohs(x) RtlUshortByteSwap(x) +#define htons(x) RtlUshortByteSwap(x) +#define ntohl(x) RtlUlongByteSwap(x) +#define htonl(x) RtlUlongByteSwap(x) +#else +#define ntohs(x) ((USHORT)(x)) +#define htons(x) ((USHORT)(x)) +#define ntohl(x) ((ULONG)(x)) +#define htonl(x) ((ULONG)(x)) +#endif diff -Nru openvpn-2.1~rc19/tap-win32/tmp/error.c openvpn-2.1.1/tap-win32/tmp/error.c --- openvpn-2.1~rc19/tap-win32/tmp/error.c 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/error.c 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,382 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//----------------- +// DEBUGGING OUTPUT +//----------------- + +const char *g_LastErrorFilename; +int g_LastErrorLineNumber; + +#if DBG + +DebugOutput g_Debug; + +BOOLEAN +NewlineExists (const char *str, int len) +{ + while (len-- > 0) + { + const char c = *str++; + if (c == '\n') + return TRUE; + else if (c == '\0') + break; + } + return FALSE; +} + +VOID +MyDebugInit (unsigned int bufsiz) +{ + NdisZeroMemory (&g_Debug, sizeof (g_Debug)); + g_Debug.text = (char *) MemAlloc (bufsiz, FALSE); + if (g_Debug.text) + g_Debug.capacity = bufsiz; +} + +VOID +MyDebugFree () +{ + if (g_Debug.text) + MemFree (g_Debug.text, g_Debug.capacity); + NdisZeroMemory (&g_Debug, sizeof (g_Debug)); +} + +VOID +MyDebugPrint (const unsigned char* format, ...) +{ + if (g_Debug.text && g_Debug.capacity > 0 && CAN_WE_PRINT) + { + BOOLEAN owned; + ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned); + if (owned) + { + const int remaining = (int)g_Debug.capacity - (int)g_Debug.out; + + if (remaining > 0) + { + va_list args; + NTSTATUS status; + char *end; + + va_start (args, format); + status = RtlStringCchVPrintfExA (g_Debug.text + g_Debug.out, + remaining, + &end, + NULL, + STRSAFE_NO_TRUNCATION | STRSAFE_IGNORE_NULLS, + format, + args); + va_end (args); + + if (status == STATUS_SUCCESS) + g_Debug.out = (unsigned int) (end - g_Debug.text); + else + g_Debug.error = TRUE; + } + else + g_Debug.error = TRUE; + + RELEASE_MUTEX (&g_Debug.lock); + } + else + g_Debug.error = TRUE; + } +} + +BOOLEAN +GetDebugLine (char *buf, const int len) +{ + static const char *truncated = "[OUTPUT TRUNCATED]\n"; + BOOLEAN ret = FALSE; + + NdisZeroMemory (buf, len); + + if (g_Debug.text && g_Debug.capacity > 0) + { + BOOLEAN owned; + ACQUIRE_MUTEX_ADAPTIVE (&g_Debug.lock, owned); + if (owned) + { + int i = 0; + + if (g_Debug.error || NewlineExists (g_Debug.text + g_Debug.in, (int)g_Debug.out - (int)g_Debug.in)) + { + while (i < (len - 1) && g_Debug.in < g_Debug.out) + { + const char c = g_Debug.text[g_Debug.in++]; + if (c == '\n') + break; + buf[i++] = c; + } + if (i < len) + buf[i] = '\0'; + } + + if (!i) + { + if (g_Debug.in == g_Debug.out) + { + g_Debug.in = g_Debug.out = 0; + if (g_Debug.error) + { + const unsigned int tlen = strlen (truncated); + if (tlen < g_Debug.capacity) + { + NdisMoveMemory (g_Debug.text, truncated, tlen+1); + g_Debug.out = tlen; + } + g_Debug.error = FALSE; + } + } + } + else + ret = TRUE; + + RELEASE_MUTEX (&g_Debug.lock); + } + } + return ret; +} + +VOID +MyAssert (const unsigned char *file, int line) +{ + DEBUGP (("MYASSERT failed %s/%d\n", file, line)); + KeBugCheckEx (0x0F00BABA, + (ULONG_PTR) line, + (ULONG_PTR) 0, + (ULONG_PTR) 0, + (ULONG_PTR) 0); +} + +VOID +PrMac (const MACADDR mac) +{ + DEBUGP (("%x:%x:%x:%x:%x:%x", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5])); +} + +VOID +PrIP (IPADDR ip_addr) +{ + const unsigned char *ip = (const unsigned char *) &ip_addr; + + DEBUGP (("%d.%d.%d.%d", + ip[0], ip[1], ip[2], ip[3])); +} + +const char * +PrIPProto (int proto) +{ + switch (proto) + { + case IPPROTO_UDP: + return "UDP"; + case IPPROTO_TCP: + return "TCP"; + case IPPROTO_ICMP: + return "ICMP"; + case IPPROTO_IGMP: + return "IGMP"; + default: + return "???"; + } +} + +VOID +DumpARP (const char *prefix, const ARP_PACKET *arp) +{ + DEBUGP (("%s ARP src=", prefix)); + PrMac (arp->m_MAC_Source); + DEBUGP ((" dest=")); + PrMac (arp->m_MAC_Destination); + DEBUGP ((" OP=0x%04x", + (int)ntohs(arp->m_ARP_Operation))); + DEBUGP ((" M=0x%04x(%d)", + (int)ntohs(arp->m_MAC_AddressType), + (int)arp->m_MAC_AddressSize)); + DEBUGP ((" P=0x%04x(%d)", + (int)ntohs(arp->m_PROTO_AddressType), + (int)arp->m_PROTO_AddressSize)); + + DEBUGP ((" MacSrc=")); + PrMac (arp->m_ARP_MAC_Source); + DEBUGP ((" MacDest=")); + PrMac (arp->m_ARP_MAC_Destination); + + DEBUGP ((" IPSrc=")); + PrIP (arp->m_ARP_IP_Source); + DEBUGP ((" IPDest=")); + PrIP (arp->m_ARP_IP_Destination); + + DEBUGP (("\n")); +} + +struct ethpayload { + ETH_HEADER eth; + UCHAR payload[DEFAULT_PACKET_LOOKAHEAD]; +}; + +VOID +DumpPacket2 (const char *prefix, + const ETH_HEADER *eth, + const unsigned char *data, + unsigned int len) +{ + struct ethpayload *ep = (struct ethpayload *) MemAlloc (sizeof (struct ethpayload), TRUE); + if (ep) + { + if (len > DEFAULT_PACKET_LOOKAHEAD) + len = DEFAULT_PACKET_LOOKAHEAD; + ep->eth = *eth; + NdisMoveMemory (ep->payload, data, len); + DumpPacket (prefix, (unsigned char *) ep, sizeof (ETH_HEADER) + len); + MemFree (ep, sizeof (struct ethpayload)); + } +} + +VOID +DumpPacket (const char *prefix, + const unsigned char *data, + unsigned int len) +{ + const ETH_HEADER *eth = (const ETH_HEADER *) data; + const IPHDR *ip = (const IPHDR *) (data + sizeof (ETH_HEADER)); + + if (len < sizeof (ETH_HEADER)) + { + DEBUGP (("%s TRUNCATED PACKET LEN=%d\n", prefix, len)); + return; + } + + // ARP Packet? + if (len >= sizeof (ARP_PACKET) && eth->proto == htons (ETH_P_ARP)) + { + DumpARP (prefix, (const ARP_PACKET *) data); + return; + } + + // IPv4 packet? + if (len >= (sizeof (IPHDR) + sizeof (ETH_HEADER)) + && eth->proto == htons (ETH_P_IP) + && IPH_GET_VER (ip->version_len) == 4) + { + const int hlen = IPH_GET_LEN (ip->version_len); + const int blen = len - sizeof (ETH_HEADER); + BOOLEAN did = FALSE; + + DEBUGP (("%s IPv4 %s[%d]", prefix, PrIPProto (ip->protocol), len)); + + if (!(ntohs (ip->tot_len) == blen && hlen <= blen)) + { + DEBUGP ((" XXX")); + return; + } + + // TCP packet? + if (ip->protocol == IPPROTO_TCP + && blen - hlen >= (sizeof (TCPHDR))) + { + const TCPHDR *tcp = (TCPHDR *) (data + sizeof (ETH_HEADER) + hlen); + DEBUGP ((" ")); + PrIP (ip->saddr); + DEBUGP ((":%d", ntohs (tcp->source))); + DEBUGP ((" -> ")); + PrIP (ip->daddr); + DEBUGP ((":%d", ntohs (tcp->dest))); + did = TRUE; + } + + // UDP packet? + else if ((ntohs (ip->frag_off) & IP_OFFMASK) == 0 + && ip->protocol == IPPROTO_UDP + && blen - hlen >= (sizeof (UDPHDR))) + { + const UDPHDR *udp = (UDPHDR *) (data + sizeof (ETH_HEADER) + hlen); + + // DHCP packet? + if ((udp->dest == htons (BOOTPC_PORT) || udp->dest == htons (BOOTPS_PORT)) + && blen - hlen >= (sizeof (UDPHDR) + sizeof (DHCP))) + { + const DHCP *dhcp = (DHCP *) (data + + hlen + + sizeof (ETH_HEADER) + + sizeof (UDPHDR)); + + int optlen = len + - sizeof (ETH_HEADER) + - hlen + - sizeof (UDPHDR) + - sizeof (DHCP); + + if (optlen < 0) + optlen = 0; + + DumpDHCP (eth, ip, udp, dhcp, optlen); + did = TRUE; + } + + if (!did) + { + DEBUGP ((" ")); + PrIP (ip->saddr); + DEBUGP ((":%d", ntohs (udp->source))); + DEBUGP ((" -> ")); + PrIP (ip->daddr); + DEBUGP ((":%d", ntohs (udp->dest))); + did = TRUE; + } + } + + if (!did) + { + DEBUGP ((" ipproto=%d ", ip->protocol)); + PrIP (ip->saddr); + DEBUGP ((" -> ")); + PrIP (ip->daddr); + } + + DEBUGP (("\n")); + return; + } + + { + DEBUGP (("%s ??? src=", prefix)); + PrMac (eth->src); + DEBUGP ((" dest=")); + PrMac (eth->dest); + DEBUGP ((" proto=0x%04x len=%d\n", + (int) ntohs(eth->proto), + len)); + } +} + +#endif diff -Nru openvpn-2.1~rc19/tap-win32/tmp/error.h openvpn-2.1.1/tap-win32/tmp/error.h --- openvpn-2.1~rc19/tap-win32/tmp/error.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/error.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,92 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//----------------- +// DEBUGGING OUTPUT +//----------------- + +#define NOTE_ERROR() \ +{ \ + g_LastErrorFilename = __FILE__; \ + g_LastErrorLineNumber = __LINE__; \ +} + +#if DBG + +typedef struct { + unsigned int in; + unsigned int out; + unsigned int capacity; + char *text; + BOOLEAN error; + MUTEX lock; +} DebugOutput; + +VOID MyDebugPrint (const unsigned char* format, ...); + +VOID MyAssert (const unsigned char *file, int line); + +VOID DumpPacket (const char *prefix, + const unsigned char *data, + unsigned int len); + +VOID DumpPacket2 (const char *prefix, + const ETH_HEADER *eth, + const unsigned char *data, + unsigned int len); + +#define CAN_WE_PRINT (DEBUGP_AT_DISPATCH || KeGetCurrentIrql () < DISPATCH_LEVEL) + +#if ALSO_DBGPRINT +#define DEBUGP(fmt) { MyDebugPrint fmt; if (CAN_WE_PRINT) DbgPrint fmt; } +#else +#define DEBUGP(fmt) { MyDebugPrint fmt; } +#endif + +#define MYASSERT(exp) \ +{ \ + if (!(exp)) \ + { \ + MyAssert(__FILE__, __LINE__); \ + } \ +} + +#define DUMP_PACKET(prefix, data, len) \ + DumpPacket (prefix, data, len) + +#define DUMP_PACKET2(prefix, eth, data, len) \ + DumpPacket2 (prefix, eth, data, len) + +#else + +#define DEBUGP(fmt) +#define MYASSERT(exp) +#define DUMP_PACKET(prefix, data, len) +#define DUMP_PACKET2(prefix, eth, data, len) + +#endif diff -Nru openvpn-2.1~rc19/tap-win32/tmp/hexdump.c openvpn-2.1.1/tap-win32/tmp/hexdump.c --- openvpn-2.1~rc19/tap-win32/tmp/hexdump.c 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/hexdump.c 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,73 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hexdump.h" + +#ifndef NDIS_MINIPORT_DRIVER + +VOID (*DbgMessage)(char *p_Format, ...) = DisplayDebugString; + +VOID DisplayDebugString (char *p_Format, ...) + { + static char l_Buffer [4096]; + + va_list l_ArgumentList; + va_start (l_ArgumentList, p_Format); + vsprintf (l_Buffer, p_Format, l_ArgumentList); + va_end (l_ArgumentList); + + OutputDebugStringA (l_Buffer); + } + +#endif + +VOID HexDump (unsigned char *p_Buffer, unsigned long p_Size) + { + unsigned long l_Index, l_Idx; + unsigned char l_Row [17]; + + for (l_Index = l_Row [16] = 0; l_Index < p_Size || l_Index % 16; ++l_Index) + { + if (l_Index % 16 == 0) + DEBUGP (("%05x ", l_Index)); + DEBUGP (("%02x ", l_Row [l_Index % 16] = (l_Index < p_Size ? p_Buffer [l_Index] : 0))); + l_Row [l_Index % 16] = IfPrint (l_Row [l_Index % 16]); + if ((l_Index + 1) % 16 == 0) + DEBUGP ((" %s\n", l_Row)); + } + + DEBUGP (("\n")); + } + +#ifdef __cplusplus +} +#endif diff -Nru openvpn-2.1~rc19/tap-win32/tmp/hexdump.h openvpn-2.1.1/tap-win32/tmp/hexdump.h --- openvpn-2.1~rc19/tap-win32/tmp/hexdump.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/hexdump.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,67 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HEXDUMP_DEFINED +#define HEXDUMP_DEFINED + +#ifdef __cplusplus +extern "C" { +#endif + +//===================================================================================== +// Debug Routines +//===================================================================================== + +#ifndef NDIS_MINIPORT_DRIVER +# include +# include +# include +# include +# include + +# ifndef DEBUGP +# define DEBUGP(fmt) { DbgMessage fmt; } +# endif + + extern VOID (*DbgMessage)(char *p_Format, ...); + + VOID DisplayDebugString (char *p_Format, ...); +#endif + +//=================================================================================== +// Reporting / Debugging +//=================================================================================== +#define IfPrint(c) (c >= 32 && c < 127 ? c : '.') + +VOID HexDump (unsigned char *p_Buffer, unsigned long p_Size); + +#ifdef __cplusplus +} +#endif + +#endif diff -Nru openvpn-2.1~rc19/tap-win32/tmp/instance.c openvpn-2.1.1/tap-win32/tmp/instance.c --- openvpn-2.1~rc19/tap-win32/tmp/instance.c 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/instance.c 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,245 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define INSTANCE_KEY(a) ((PVOID)((a)->m_Extension.m_TapDevice)) + +#define N_INSTANCE_BUCKETS 256 + +typedef struct _INSTANCE { + struct _INSTANCE *next; + TapAdapterPointer m_Adapter; +} INSTANCE; + +typedef struct { + INSTANCE *list; + MUTEX lock; +} INSTANCE_BUCKET; + +typedef struct { + INSTANCE_BUCKET buckets[N_INSTANCE_BUCKETS]; +} INSTANCE_HASH; + +INSTANCE_HASH *g_InstanceHash = NULL; + +// must return a hash >= 0 and < N_INSTANCE_BUCKETS +int +InstanceHashValue (PVOID addr) +{ + UCHAR *p = (UCHAR *) &addr; + + if (sizeof (addr) == 4) + return p[0] ^ p[1] ^ p[2] ^ p[3]; + else if (sizeof (addr) == 8) + return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4] ^ p[5] ^ p[6] ^ p[7]; + else + { + MYASSERT (0); + } +} + +BOOLEAN +InitInstanceList (VOID) +{ + MYASSERT (g_InstanceHash == NULL); + g_InstanceHash = MemAlloc (sizeof (INSTANCE_HASH), TRUE); + if (g_InstanceHash) + { + int i; + for (i = 0; i < N_INSTANCE_BUCKETS; ++i) + INIT_MUTEX (&g_InstanceHash->buckets[i].lock); + return TRUE; + } + else + return FALSE; +} + +int +NInstances (VOID) +{ + int i, n = 0; + + if (g_InstanceHash) + { + for (i = 0; i < N_INSTANCE_BUCKETS; ++i) + { + BOOLEAN got_lock; + INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i]; + ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock); + + if (got_lock) + { + INSTANCE *current; + for (current = ib->list; current != NULL; current = current->next) + ++n; + RELEASE_MUTEX (&ib->lock); + } + else + return -1; + } + } + + return n; +} + +int +InstanceMaxBucketSize (VOID) +{ + int i, n = 0; + + if (g_InstanceHash) + { + for (i = 0; i < N_INSTANCE_BUCKETS; ++i) + { + BOOLEAN got_lock; + int bucket_size = 0; + INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i]; + ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock); + + if (got_lock) + { + INSTANCE *current; + for (current = ib->list; current != NULL; current = current->next) + ++bucket_size; + if (bucket_size > n) + n = bucket_size; + RELEASE_MUTEX (&ib->lock); + } + else + return -1; + } + } + + return n; +} + +VOID +FreeInstanceList (VOID) +{ + if (g_InstanceHash) + { + MYASSERT (NInstances() == 0); + MemFree (g_InstanceHash, sizeof (INSTANCE_HASH)); + g_InstanceHash = NULL; + } +} + +BOOLEAN +AddAdapterToInstanceList (TapAdapterPointer p_Adapter) +{ + BOOLEAN got_lock; + BOOLEAN ret = FALSE; + const int hash = InstanceHashValue(INSTANCE_KEY(p_Adapter)); + INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[hash]; + + DEBUGP (("[TAP] AddAdapterToInstanceList hash=%d\n", hash)); + + ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock); + + if (got_lock) + { + INSTANCE *i = MemAlloc (sizeof (INSTANCE), FALSE); + if (i) + { + MYASSERT (p_Adapter); + i->m_Adapter = p_Adapter; + i->next = ib->list; + ib->list = i; + ret = TRUE; + } + RELEASE_MUTEX (&ib->lock); + } + + return ret; +} + +BOOLEAN +RemoveAdapterFromInstanceList (TapAdapterPointer p_Adapter) +{ + BOOLEAN got_lock; + BOOLEAN ret = FALSE; + INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue(INSTANCE_KEY(p_Adapter))]; + + ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock); + + if (got_lock) + { + INSTANCE *current, *prev=NULL; + for (current = ib->list; current != NULL; current = current->next) + { + if (current->m_Adapter == p_Adapter) // found match + { + if (prev) + prev->next = current->next; + else + ib->list = current->next; + MemFree (current->m_Adapter, sizeof (TapAdapter)); + MemFree (current, sizeof (INSTANCE)); + ret = TRUE; + break; + } + prev = current; + } + RELEASE_MUTEX (&ib->lock); + } + + return ret; +} + +TapAdapterPointer +LookupAdapterInInstanceList (PDEVICE_OBJECT p_DeviceObject) +{ + BOOLEAN got_lock; + TapAdapterPointer ret = NULL; + INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue((PVOID)p_DeviceObject)]; + + ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock); + + if (got_lock) + { + INSTANCE *current, *prev=NULL; + for (current = ib->list; current != NULL; current = current->next) + { + if (p_DeviceObject == INSTANCE_KEY (current->m_Adapter)) // found match + { + // move it to head of list + if (prev) + { + prev->next = current->next; + current->next = ib->list; + ib->list = current; + } + ret = ib->list->m_Adapter; + break; + } + prev = current; + } + RELEASE_MUTEX (&ib->lock); + } + + return ret; +} diff -Nru openvpn-2.1~rc19/tap-win32/tmp/lock.h openvpn-2.1.1/tap-win32/tmp/lock.h --- openvpn-2.1~rc19/tap-win32/tmp/lock.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/lock.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,79 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +typedef struct +{ + volatile long count; +} MUTEX; + +#define MUTEX_SLEEP_TIME 10000 // microseconds + +#define INIT_MUTEX(m) { (m)->count = 0; } + +#define ACQUIRE_MUTEX_BLOCKING(m) \ +{ \ + while (NdisInterlockedIncrement (&((m)->count)) != 1) \ + { \ + NdisInterlockedDecrement(&((m)->count)); \ + NdisMSleep(MUTEX_SLEEP_TIME); \ + } \ +} + +#define RELEASE_MUTEX(m) \ +{ \ + NdisInterlockedDecrement(&((m)->count)); \ +} + +#define ACQUIRE_MUTEX_NONBLOCKING(m, result) \ +{ \ + if (NdisInterlockedIncrement (&((m)->count)) != 1) \ + { \ + NdisInterlockedDecrement(&((m)->count)); \ + result = FALSE; \ + } \ + else \ + { \ + result = TRUE; \ + } \ +} + +#define ACQUIRE_MUTEX_ADAPTIVE(m, result) \ +{ \ + result = TRUE; \ + while (NdisInterlockedIncrement (&((m)->count)) != 1) \ + { \ + NdisInterlockedDecrement(&((m)->count)); \ + if (KeGetCurrentIrql () < DISPATCH_LEVEL) \ + NdisMSleep(MUTEX_SLEEP_TIME); \ + else \ + { \ + result = FALSE; \ + break; \ + } \ + } \ +} diff -Nru openvpn-2.1~rc19/tap-win32/tmp/macinfo.c openvpn-2.1.1/tap-win32/tmp/macinfo.c --- openvpn-2.1~rc19/tap-win32/tmp/macinfo.c 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/macinfo.c 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,158 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "macinfo.h" + +int +HexStringToDecimalInt (const int p_Character) +{ + int l_Value = 0; + + if (p_Character >= 'A' && p_Character <= 'F') + l_Value = (p_Character - 'A') + 10; + else if (p_Character >= 'a' && p_Character <= 'f') + l_Value = (p_Character - 'a') + 10; + else if (p_Character >= '0' && p_Character <= '9') + l_Value = p_Character - '0'; + + return l_Value; +} + +BOOLEAN +ParseMAC (MACADDR dest, const char *src) +{ + int c; + int mac_index = 0; + BOOLEAN high_digit = FALSE; + int delim_action = 1; + + MYASSERT (src); + MYASSERT (dest); + + CLEAR_MAC (dest); + + while (c = *src++) + { + if (IsMacDelimiter (c)) + { + mac_index += delim_action; + high_digit = FALSE; + delim_action = 1; + } + else if (IsHexDigit (c)) + { + const int digit = HexStringToDecimalInt (c); + if (mac_index < sizeof (MACADDR)) + { + if (!high_digit) + { + dest[mac_index] = (char)(digit); + high_digit = TRUE; + delim_action = 1; + } + else + { + dest[mac_index] = (char)(dest[mac_index] * 16 + digit); + ++mac_index; + high_digit = FALSE; + delim_action = 0; + } + } + else + return FALSE; + } + else + return FALSE; + } + + return (mac_index + delim_action) >= sizeof (MACADDR); +} + +/* + * Generate a MAC using the GUID in the adapter name. + * + * The mac is constructed as 00:FF:xx:xx:xx:xx where + * the Xs are taken from the first 32 bits of the GUID in the + * adapter name. This is similar to the Linux 2.4 tap MAC + * generator, except linux uses 32 random bits for the Xs. + * + * In general, this solution is reasonable for most + * applications except for very large bridged TAP networks, + * where the probability of address collisions becomes more + * than infintesimal. + * + * Using the well-known "birthday paradox", on a 1000 node + * network the probability of collision would be + * 0.000116292153. On a 10,000 node network, the probability + * of collision would be 0.01157288998621678766. + */ + +VOID GenerateRandomMac (MACADDR mac, const unsigned char *adapter_name) +{ + unsigned const char *cp = adapter_name; + unsigned char c; + unsigned int i = 2; + unsigned int byte = 0; + int brace = 0; + int state = 0; + + CLEAR_MAC (mac); + + mac[0] = 0x00; + mac[1] = 0xFF; + + while (c = *cp++) + { + if (i >= sizeof (MACADDR)) + break; + if (c == '{') + brace = 1; + if (IsHexDigit (c) && brace) + { + const unsigned int digit = HexStringToDecimalInt (c); + if (state) + { + byte <<= 4; + byte |= digit; + mac[i++] = (unsigned char) byte; + state = 0; + } + else + { + byte = digit; + state = 1; + } + } + } +} + +VOID GenerateRelatedMAC (MACADDR dest, const MACADDR src, const int delta) +{ + COPY_MAC (dest, src); + dest[2] += (UCHAR) delta; +} diff -Nru openvpn-2.1~rc19/tap-win32/tmp/macinfo.h openvpn-2.1.1/tap-win32/tmp/macinfo.h --- openvpn-2.1~rc19/tap-win32/tmp/macinfo.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/macinfo.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,42 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MacInfoDefined +#define MacInfoDefined + +//=================================================================================== +// Macros +//=================================================================================== +#define IsMacDelimiter(a) (a == ':' || a == '-' || a == '.') +#define IsHexDigit(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) + +#define COPY_MAC(dest, src) NdisMoveMemory ((dest), (src), sizeof (MACADDR)) +#define CLEAR_MAC(dest) NdisZeroMemory ((dest), sizeof (MACADDR)) +#define MAC_EQUAL(a,b) (memcmp ((a), (b), sizeof (MACADDR)) == 0) + +#endif diff -Nru openvpn-2.1~rc19/tap-win32/tmp/mem.c openvpn-2.1.1/tap-win32/tmp/mem.c --- openvpn-2.1~rc19/tap-win32/tmp/mem.c 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/mem.c 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,190 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//------------------ +// Memory Management +//------------------ + +PVOID +MemAlloc (ULONG p_Size, BOOLEAN zero) +{ + PVOID l_Return = NULL; + + if (p_Size) + { + __try + { + if (NdisAllocateMemoryWithTag (&l_Return, p_Size, 'APAT') + == NDIS_STATUS_SUCCESS) + { + if (zero) + NdisZeroMemory (l_Return, p_Size); + } + else + l_Return = NULL; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + l_Return = NULL; + } + } + + return l_Return; +} + +VOID +MemFree (PVOID p_Addr, ULONG p_Size) +{ + if (p_Addr && p_Size) + { + __try + { +#if DBG + NdisZeroMemory (p_Addr, p_Size); +#endif + NdisFreeMemory (p_Addr, p_Size, 0); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + } +} + +/* + * Circular queue management routines. + */ + +#define QUEUE_BYTE_ALLOCATION(size) \ + (sizeof (Queue) + (size * sizeof (PVOID))) + +#define QUEUE_ADD_INDEX(var, inc) \ +{ \ + var += inc; \ + if (var >= q->capacity) \ + var -= q->capacity; \ + MYASSERT (var < q->capacity); \ +} + +#define QUEUE_SANITY_CHECK() \ + MYASSERT (q != NULL && q->base < q->capacity && q->size <= q->capacity) + +#define QueueCount(q) (q->size) + +#define UPDATE_MAX_SIZE() \ +{ \ + if (q->size > q->max_size) \ + q->max_size = q->size; \ +} + +Queue * +QueueInit (ULONG capacity) +{ + Queue *q; + + MYASSERT (capacity > 0); + q = (Queue *) MemAlloc (QUEUE_BYTE_ALLOCATION (capacity), TRUE); + if (!q) + return NULL; + + q->base = q->size = 0; + q->capacity = capacity; + q->max_size = 0; + return q; +} + +VOID +QueueFree (Queue *q) +{ + if (q) + { + QUEUE_SANITY_CHECK (); + MemFree (q, QUEUE_BYTE_ALLOCATION (q->capacity)); + } +} + +PVOID +QueuePush (Queue *q, PVOID item) +{ + ULONG dest; + QUEUE_SANITY_CHECK (); + if (q->size == q->capacity) + return NULL; + dest = q->base; + QUEUE_ADD_INDEX (dest, q->size); + q->data[dest] = item; + ++q->size; + UPDATE_MAX_SIZE(); + return item; +} + +PVOID +QueuePop (Queue *q) +{ + ULONG oldbase; + QUEUE_SANITY_CHECK (); + if (!q->size) + return NULL; + oldbase = q->base; + QUEUE_ADD_INDEX (q->base, 1); + --q->size; + UPDATE_MAX_SIZE(); + return q->data[oldbase]; +} + +PVOID +QueueExtract (Queue *q, PVOID item) +{ + ULONG src, dest, count, n; + QUEUE_SANITY_CHECK (); + n = 0; + src = dest = q->base; + count = q->size; + while (count--) + { + if (item == q->data[src]) + { + ++n; + --q->size; + } + else + { + q->data[dest] = q->data[src]; + QUEUE_ADD_INDEX (dest, 1); + } + QUEUE_ADD_INDEX (src, 1); + } + if (n) + return item; + else + return NULL; +} + +#undef QUEUE_BYTE_ALLOCATION +#undef QUEUE_ADD_INDEX +#undef QUEUE_SANITY_CHECK +#undef UPDATE_MAX_SIZE diff -Nru openvpn-2.1~rc19/tap-win32/tmp/proto.h openvpn-2.1.1/tap-win32/tmp/proto.h --- openvpn-2.1~rc19/tap-win32/tmp/proto.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/proto.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,168 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//============================================================ +// MAC address, Ethernet header, and ARP +//============================================================ + +#pragma pack(1) + +#define IP_HEADER_SIZE 20 + +typedef unsigned char MACADDR [6]; +typedef unsigned long IPADDR; + +//----------------- +// Ethernet address +//----------------- + +typedef struct { + MACADDR addr; +} ETH_ADDR; + +typedef struct { + ETH_ADDR list[NIC_MAX_MCAST_LIST]; +} MC_LIST; + +//---------------- +// Ethernet header +//---------------- + +typedef struct +{ + MACADDR dest; /* destination eth addr */ + MACADDR src; /* source ether addr */ + +# define ETH_P_IP 0x0800 /* IPv4 protocol */ +# define ETH_P_ARP 0x0806 /* ARP protocol */ + USHORT proto; /* packet type ID field */ +} ETH_HEADER, *PETH_HEADER; + +//---------------- +// ARP packet +//---------------- + +typedef struct + { + MACADDR m_MAC_Destination; // Reverse these two + MACADDR m_MAC_Source; // to answer ARP requests + USHORT m_Proto; // 0x0806 + +# define MAC_ADDR_TYPE 0x0001 + USHORT m_MAC_AddressType; // 0x0001 + + USHORT m_PROTO_AddressType; // 0x0800 + UCHAR m_MAC_AddressSize; // 0x06 + UCHAR m_PROTO_AddressSize; // 0x04 + +# define ARP_REQUEST 0x0001 +# define ARP_REPLY 0x0002 + USHORT m_ARP_Operation; // 0x0001 for ARP request, 0x0002 for ARP reply + + MACADDR m_ARP_MAC_Source; + IPADDR m_ARP_IP_Source; + MACADDR m_ARP_MAC_Destination; + IPADDR m_ARP_IP_Destination; + } +ARP_PACKET, *PARP_PACKET; + +//---------- +// IP Header +//---------- + +typedef struct { +# define IPH_GET_VER(v) (((v) >> 4) & 0x0F) +# define IPH_GET_LEN(v) (((v) & 0x0F) << 2) + UCHAR version_len; + + UCHAR tos; + USHORT tot_len; + USHORT id; + +# define IP_OFFMASK 0x1fff + USHORT frag_off; + + UCHAR ttl; + +# define IPPROTO_UDP 17 /* UDP protocol */ +# define IPPROTO_TCP 6 /* TCP protocol */ +# define IPPROTO_ICMP 1 /* ICMP protocol */ +# define IPPROTO_IGMP 2 /* IGMP protocol */ + UCHAR protocol; + + USHORT check; + ULONG saddr; + ULONG daddr; + /* The options start here. */ +} IPHDR; + +//----------- +// UDP header +//----------- + +typedef struct { + USHORT source; + USHORT dest; + USHORT len; + USHORT check; +} UDPHDR; + +//-------------------------- +// TCP header, per RFC 793. +//-------------------------- + +typedef struct { + USHORT source; /* source port */ + USHORT dest; /* destination port */ + ULONG seq; /* sequence number */ + ULONG ack_seq; /* acknowledgement number */ + +# define TCPH_GET_DOFF(d) (((d) & 0xF0) >> 2) + UCHAR doff_res; + +# define TCPH_FIN_MASK (1<<0) +# define TCPH_SYN_MASK (1<<1) +# define TCPH_RST_MASK (1<<2) +# define TCPH_PSH_MASK (1<<3) +# define TCPH_ACK_MASK (1<<4) +# define TCPH_URG_MASK (1<<5) +# define TCPH_ECE_MASK (1<<6) +# define TCPH_CWR_MASK (1<<7) + UCHAR flags; + + USHORT window; + USHORT check; + USHORT urg_ptr; +} TCPHDR; + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOLEN_MAXSEG 4 + +#pragma pack() diff -Nru openvpn-2.1~rc19/tap-win32/tmp/prototypes.h openvpn-2.1.1/tap-win32/tmp/prototypes.h --- openvpn-2.1~rc19/tap-win32/tmp/prototypes.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/prototypes.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,264 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TAP_PROTOTYPES_DEFINED +#define TAP_PROTOTYPES_DEFINED + +NTSTATUS DriverEntry + ( + IN PDRIVER_OBJECT p_DriverObject, + IN PUNICODE_STRING p_RegistryPath + ); + +VOID TapDriverUnload + ( + IN PDRIVER_OBJECT p_DriverObject + ); + +NDIS_STATUS AdapterCreate + ( + OUT PNDIS_STATUS p_ErrorStatus, + OUT PUINT p_MediaIndex, + IN PNDIS_MEDIUM p_Media, + IN UINT p_MediaCount, + IN NDIS_HANDLE p_AdapterHandle, + IN NDIS_HANDLE p_ConfigurationHandle + ); + +VOID AdapterHalt + ( + IN NDIS_HANDLE p_AdapterContext + ); + +VOID AdapterFreeResources + ( + TapAdapterPointer p_Adapter + ); + +NDIS_STATUS AdapterReset + ( + OUT PBOOLEAN p_AddressingReset, + IN NDIS_HANDLE p_AdapterContext + ); + +NDIS_STATUS AdapterQuery + ( + IN NDIS_HANDLE p_AdapterContext, + IN NDIS_OID p_OID, + IN PVOID p_Buffer, + IN ULONG p_BufferLength, + OUT PULONG p_BytesWritten, + OUT PULONG p_BytesNeeded + ); + +NDIS_STATUS AdapterModify + ( + IN NDIS_HANDLE p_AdapterContext, + IN NDIS_OID p_OID, + IN PVOID p_Buffer, + IN ULONG p_BufferLength, + OUT PULONG p_BytesRead, + OUT PULONG p_BytesNeeded + ); + +NDIS_STATUS AdapterTransmit + ( + IN NDIS_HANDLE p_AdapterContext, + IN PNDIS_PACKET p_Packet, + IN UINT p_Flags + ); + +NDIS_STATUS AdapterReceive + ( + OUT PNDIS_PACKET p_Packet, + OUT PUINT p_Transferred, + IN NDIS_HANDLE p_AdapterContext, + IN NDIS_HANDLE p_ReceiveContext, + IN UINT p_Offset, + IN UINT p_ToTransfer + ); + +NTSTATUS TapDeviceHook + ( + IN PDEVICE_OBJECT p_DeviceObject, + IN PIRP p_IRP + ); + +NDIS_STATUS CreateTapDevice + ( + TapExtensionPointer p_Extension, + const char *p_Name + ); + +VOID DestroyTapDevice + ( + TapExtensionPointer p_Extension + ); + +VOID TapDeviceFreeResources + ( + TapExtensionPointer p_Extension + ); + +NTSTATUS CompleteIRP + ( + IN PIRP p_IRP, + IN TapPacketPointer p_PacketBuffer, + IN CCHAR PriorityBoost + ); + +VOID CancelIRPCallback + ( + IN PDEVICE_OBJECT p_DeviceObject, + IN PIRP p_IRP + ); + +VOID CancelIRP + ( + TapExtensionPointer p_Extension, + IN PIRP p_IRP, + BOOLEAN callback + ); + +VOID FlushQueues + ( + TapExtensionPointer p_Extension + ); + +VOID ResetTapAdapterState + ( + TapAdapterPointer p_Adapter + ); + +BOOLEAN ProcessARP + ( + TapAdapterPointer p_Adapter, + const PARP_PACKET src, + const IPADDR adapter_ip, + const IPADDR ip_network, + const IPADDR ip_netmask, + const MACADDR mac + ); + +VOID SetMediaStatus + ( + TapAdapterPointer p_Adapter, + BOOLEAN state + ); + +VOID InjectPacketDeferred + ( + TapAdapterPointer p_Adapter, + UCHAR *packet, + const unsigned int len + ); + +VOID InjectPacketNow + ( + TapAdapterPointer p_Adapter, + UCHAR *packet, + const unsigned int len + ); + +// for KDEFERRED_ROUTINE and Static Driver Verifier +//#include +//KDEFERRED_ROUTINE InjectPacketDpc; + +VOID InjectPacketDpc + ( + KDPC *Dpc, + PVOID DeferredContext, + PVOID SystemArgument1, + PVOID SystemArgument2 + ); + +VOID CheckIfDhcpAndTunMode + ( + TapAdapterPointer p_Adapter + ); + +VOID HookDispatchFunctions(); + +#if ENABLE_NONADMIN + +#if DDKVER_MAJOR < 5600 +/* + * Better solution for use on Vista DDK, but possibly not compatible with + * earlier DDKs: + * + * Eliminate the definition of SECURITY_DESCRIPTOR (and even ZwSetSecurityObject), + * and at the top of tapdrv.c change: + * + * #include + * #include + * #include + * + * To + * + * #include + * #include + * #include + */ +typedef struct _SECURITY_DESCRIPTOR { + unsigned char opaque[64]; +} SECURITY_DESCRIPTOR; + +NTSYSAPI +NTSTATUS +NTAPI +ZwSetSecurityObject ( + IN HANDLE Handle, + IN SECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR SecurityDescriptor); + +#endif + +VOID AllowNonAdmin (TapExtensionPointer p_Extension); + +#endif + +struct WIN2K_NDIS_MINIPORT_BLOCK +{ + unsigned char opaque[16]; + UNICODE_STRING MiniportName; // how mini-port refers to us +}; + +#if PACKET_TRUNCATION_CHECK + +VOID IPv4PacketSizeVerify + ( + const UCHAR *data, + ULONG length, + BOOLEAN tun, + const char *prefix, + LONG *counter + ); + +#endif + +#endif diff -Nru openvpn-2.1~rc19/tap-win32/tmp/tapdrvr.c openvpn-2.1.1/tap-win32/tmp/tapdrvr.c --- openvpn-2.1~rc19/tap-win32/tmp/tapdrvr.c 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/tapdrvr.c 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,2959 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +//====================================================== +// This driver is designed to work on Win 2000 or higher +// versions of Windows. +// +// It is SMP-safe and handles NDIS 5 power management. +// +// By default we operate as a "tap" virtual ethernet +// 802.3 interface, but we can emulate a "tun" +// interface (point-to-point IPv4) through the +// TAP_IOCTL_CONFIG_POINT_TO_POINT or +// TAP_IOCTL_CONFIG_TUN ioctl. +//====================================================== + +#include "../../autodefs/defs.h" +#ifndef DDKVER_MAJOR +#error DDKVER_MAJOR must be defined as the major number of the DDK Version +#endif + +#define NDIS_MINIPORT_DRIVER +#define BINARY_COMPATIBLE 0 +#define NDIS50_MINIPORT 1 +#define NDIS_WDM 0 +#define NDIS50 1 +#define NTSTRSAFE_LIB + +// Debug info output +#define ALSO_DBGPRINT 1 +#define DEBUGP_AT_DISPATCH 0 + +//======================================================== +// Check for truncated IPv4 packets, log errors if found. +//======================================================== +#define PACKET_TRUNCATION_CHECK 0 + +//======================================================== +// EXPERIMENTAL -- Configure TAP device object to be +// accessible from non-administrative accounts, based +// on an advanced properties setting. +// +// Duplicates the functionality of OpenVPN's +// --allow-nonadmin directive. +//======================================================== +#define ENABLE_NONADMIN 1 + +#if DDKVER_MAJOR < 5600 +#include +#include +#include +#else +#include +#include +#include +#endif + +#include "lock.h" +#include "constants.h" +#include "common.h" +#include "proto.h" +#include "error.h" +#include "endian.h" +#include "dhcp.h" +#include "types.h" +#include "prototypes.h" + +#include "mem.c" +#include "macinfo.c" +#include "error.c" +#include "dhcp.c" +#include "instance.c" + +#define IS_UP(ta) \ + ((ta)->m_InterfaceIsRunning && (ta)->m_Extension.m_TapIsRunning) + +#define INCREMENT_STAT(s) ++(s) + +#define NAME_BUFFER_SIZE 80 + +//======================================================== +// Globals +//======================================================== + +NDIS_HANDLE g_NdisWrapperHandle; + +const UINT g_SupportedOIDList[] = { + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAC_OPTIONS, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_DRIVER_VERSION, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_GEN_RCV_NO_BUFFER, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_PROTOCOL_OPTIONS, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_VENDOR_DRIVER_VERSION, + OID_GEN_MAXIMUM_SEND_PACKETS, + OID_GEN_MEDIA_CONNECT_STATUS, + OID_GEN_SUPPORTED_LIST +}; + +//============================================================ +// Driver Entry +//============================================================ +#pragma NDIS_INIT_FUNCTION (DriverEntry) + +NTSTATUS +DriverEntry (IN PDRIVER_OBJECT p_DriverObject, + IN PUNICODE_STRING p_RegistryPath) +{ + NDIS_STATUS l_Status = NDIS_STATUS_FAILURE; + NDIS_MINIPORT_CHARACTERISTICS *l_Properties = NULL; + + //======================================================== + // Notify NDIS that a new miniport driver is initializing. + //======================================================== + + NdisMInitializeWrapper (&g_NdisWrapperHandle, + p_DriverObject, + p_RegistryPath, NULL); + + //====================== + // Global initialization + //====================== + +#if DBG + MyDebugInit (10000); // Allocate debugging text space +#endif + + if (!InitInstanceList ()) + { + DEBUGP (("[TAP] Allocation failed for adapter instance list\n")); + goto cleanup; + } + + //======================================= + // Set and register miniport entry points + //======================================= + + l_Properties = MemAlloc (sizeof (NDIS_MINIPORT_CHARACTERISTICS), TRUE); + + if (l_Properties == NULL) + { + DEBUGP (("[TAP] Allocation failed for miniport entry points\n")); + goto cleanup; + } + + l_Properties->MajorNdisVersion = TAP_NDIS_MAJOR_VERSION; + l_Properties->MinorNdisVersion = TAP_NDIS_MINOR_VERSION; + l_Properties->InitializeHandler = AdapterCreate; + l_Properties->HaltHandler = AdapterHalt; + l_Properties->ResetHandler = AdapterReset; /* DISPATCH_LEVEL */ + l_Properties->TransferDataHandler = AdapterReceive; /* DISPATCH_LEVEL */ + l_Properties->SendHandler = AdapterTransmit; /* DISPATCH_LEVEL */ + l_Properties->QueryInformationHandler = AdapterQuery; /* DISPATCH_LEVEL */ + l_Properties->SetInformationHandler = AdapterModify; /* DISPATCH_LEVEL */ + + switch (l_Status = + NdisMRegisterMiniport (g_NdisWrapperHandle, l_Properties, + sizeof (NDIS_MINIPORT_CHARACTERISTICS))) + { + case NDIS_STATUS_SUCCESS: + { + DEBUGP (("[TAP] version [%d.%d] %s %s registered miniport successfully\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, + __DATE__, + __TIME__)); + DEBUGP (("Registry Path: '%S'\n", p_RegistryPath->Buffer)); + break; + } + + case NDIS_STATUS_BAD_CHARACTERISTICS: + { + DEBUGP (("[TAP] Miniport characteristics were badly defined\n")); + NdisTerminateWrapper (g_NdisWrapperHandle, NULL); + break; + } + + case NDIS_STATUS_BAD_VERSION: + { + DEBUGP + (("[TAP] NDIS Version is wrong for the given characteristics\n")); + NdisTerminateWrapper (g_NdisWrapperHandle, NULL); + break; + } + + case NDIS_STATUS_RESOURCES: + { + DEBUGP (("[TAP] Insufficient resources\n")); + NdisTerminateWrapper (g_NdisWrapperHandle, NULL); + break; + } + + default: + case NDIS_STATUS_FAILURE: + { + DEBUGP (("[TAP] Unknown fatal registration error\n")); + NdisTerminateWrapper (g_NdisWrapperHandle, NULL); + break; + } + } + + cleanup: + if (l_Properties) + MemFree (l_Properties, sizeof (NDIS_MINIPORT_CHARACTERISTICS)); + + if (l_Status == NDIS_STATUS_SUCCESS) + NdisMRegisterUnloadHandler (g_NdisWrapperHandle, TapDriverUnload); + else + TapDriverUnload (p_DriverObject); + + return l_Status; +} + +//============================================================ +// Driver Unload +//============================================================ +VOID +TapDriverUnload (IN PDRIVER_OBJECT p_DriverObject) +{ + DEBUGP (("[TAP] version [%d.%d] %s %s unloaded, instances=%d, imbs=%d\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, + __DATE__, + __TIME__, + NInstances(), + InstanceMaxBucketSize())); + + FreeInstanceList (); + + //============================== + // Free debugging text space + //============================== +#if DBG + MyDebugFree (); +#endif +} + +//========================================================== +// Adapter Initialization +//========================================================== +NDIS_STATUS AdapterCreate +(OUT PNDIS_STATUS p_ErrorStatus, + OUT PUINT p_MediaIndex, + IN PNDIS_MEDIUM p_Media, + IN UINT p_MediaCount, + IN NDIS_HANDLE p_AdapterHandle, + IN NDIS_HANDLE p_ConfigurationHandle) +{ + TapAdapterPointer l_Adapter = NULL; + + NDIS_MEDIUM l_PreferredMedium = NdisMedium802_3; // Ethernet + BOOLEAN l_MacFromRegistry = FALSE; + UINT l_Index; + NDIS_STATUS status; + +#if ENABLE_NONADMIN + BOOLEAN enable_non_admin = FALSE; +#endif + + DEBUGP (("[TAP] AdapterCreate called\n")); + + //==================================== + // Make sure adapter type is supported + //==================================== + + for (l_Index = 0; + l_Index < p_MediaCount && p_Media[l_Index] != l_PreferredMedium; + ++l_Index); + + if (l_Index == p_MediaCount) + { + DEBUGP (("[TAP] Unsupported adapter type [wanted: %d]\n", + l_PreferredMedium)); + return NDIS_STATUS_UNSUPPORTED_MEDIA; + } + + *p_MediaIndex = l_Index; + + //========================================= + // Allocate memory for TapAdapter structure + //========================================= + + l_Adapter = MemAlloc (sizeof (TapAdapter), TRUE); + + if (l_Adapter == NULL) + { + DEBUGP (("[TAP] Couldn't allocate adapter memory\n")); + return NDIS_STATUS_RESOURCES; + } + + //========================================== + // Inform the NDIS library about significant + // features of our virtual NIC. + //========================================== + + NdisMSetAttributesEx + (p_AdapterHandle, + (NDIS_HANDLE) l_Adapter, + 16, + NDIS_ATTRIBUTE_DESERIALIZE + | NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT + | NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT + | NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND, + NdisInterfaceInternal); + + //===================================== + // Initialize simple Adapter parameters + //===================================== + + l_Adapter->m_Lookahead = DEFAULT_PACKET_LOOKAHEAD; + l_Adapter->m_Medium = l_PreferredMedium; + l_Adapter->m_DeviceState = '?'; + l_Adapter->m_MiniportAdapterHandle = p_AdapterHandle; + + //================================== + // Allocate spinlock for controlling + // access to multicast address list. + //================================== + NdisAllocateSpinLock (&l_Adapter->m_MCLock); + l_Adapter->m_MCLockAllocated = TRUE; + + //==================================================== + // Register a shutdown handler which will be called + // on system restart/shutdown to halt our virtual NIC. + //==================================================== + + NdisMRegisterAdapterShutdownHandler (p_AdapterHandle, l_Adapter, + AdapterHalt); + l_Adapter->m_RegisteredAdapterShutdownHandler = TRUE; + + //============================================ + // Get parameters from registry which were set + // in the adapter advanced properties dialog. + //============================================ + { + NDIS_STATUS status; + NDIS_HANDLE configHandle; + NDIS_CONFIGURATION_PARAMETER *parm; + + // set defaults in case our registry query fails + l_Adapter->m_MTU = ETHERNET_MTU; + l_Adapter->m_MediaStateAlwaysConnected = FALSE; + l_Adapter->m_MediaState = FALSE; + + NdisOpenConfiguration (&status, &configHandle, p_ConfigurationHandle); + if (status != NDIS_STATUS_SUCCESS) + { + DEBUGP (("[TAP] Couldn't open adapter registry\n")); + AdapterFreeResources (l_Adapter); + return status; + } + + //==================================== + // Allocate and construct adapter name + //==================================== + { + + NDIS_STRING mkey = NDIS_STRING_CONST("MiniportName"); + NDIS_STRING vkey = NDIS_STRING_CONST("NdisVersion"); + NDIS_STATUS vstatus; + NDIS_CONFIGURATION_PARAMETER *vparm; + + NdisReadConfiguration (&vstatus, &vparm, configHandle, &vkey, NdisParameterInteger); + if (vstatus == NDIS_STATUS_SUCCESS) + DEBUGP (("[TAP] NdisReadConfiguration NdisVersion=%X\n", vparm->ParameterData.IntegerData)); + + NdisReadConfiguration (&status, &parm, configHandle, &mkey, NdisParameterString); + if (status == NDIS_STATUS_SUCCESS) + { + if (parm->ParameterType == NdisParameterString) + { + DEBUGP (("[TAP] NdisReadConfiguration (MiniportName=%S)\n", parm->ParameterData.StringData.Buffer)); + + if (RtlUnicodeStringToAnsiString ( + &l_Adapter->m_NameAnsi, + &parm->ParameterData.StringData, + TRUE) != STATUS_SUCCESS) + { + DEBUGP (("[TAP] MiniportName failed\n")); + status = NDIS_STATUS_RESOURCES; + } + } + } + else + { + /* "MiniportName" is available only XP and above. Not on Windows 2000. */ + if (vstatus == NDIS_STATUS_SUCCESS && vparm->ParameterData.IntegerData == 0x50000) + { + /* Fallback for Windows 2000 with NDIS version 5.00.00 + Don't use this on Vista, 'NDIS_MINIPORT_BLOCK' was changed! */ + if (RtlUnicodeStringToAnsiString (&l_Adapter->m_NameAnsi, + &((struct WIN2K_NDIS_MINIPORT_BLOCK *) p_AdapterHandle)->MiniportName, + TRUE) != STATUS_SUCCESS) + { + DEBUGP (("[TAP] MiniportName (W2K) failed\n")); + status = NDIS_STATUS_RESOURCES; + } + else + { + DEBUGP (("[TAP] MiniportName (W2K) succeeded: %s\n", l_Adapter->m_NameAnsi.Buffer)); + status = NDIS_STATUS_SUCCESS; + } + } + } + } + + /* Can't continue without name (see macro 'NAME') */ + if (status != NDIS_STATUS_SUCCESS || !l_Adapter->m_NameAnsi.Buffer) + { + NdisCloseConfiguration (configHandle); + AdapterFreeResources (l_Adapter); + DEBUGP (("[TAP] failed to get miniport name\n")); + return NDIS_STATUS_RESOURCES; + } + + /* Read MTU setting from registry */ + { + NDIS_STRING key = NDIS_STRING_CONST("MTU"); + NdisReadConfiguration (&status, &parm, configHandle, + &key, NdisParameterInteger); + if (status == NDIS_STATUS_SUCCESS) + { + if (parm->ParameterType == NdisParameterInteger) + { + int mtu = parm->ParameterData.IntegerData; + if (mtu < MINIMUM_MTU) + mtu = MINIMUM_MTU; + if (mtu > MAXIMUM_MTU) + mtu = MAXIMUM_MTU; + l_Adapter->m_MTU = mtu; + } + } + } + + /* Read Media Status setting from registry */ + { + NDIS_STRING key = NDIS_STRING_CONST("MediaStatus"); + NdisReadConfiguration (&status, &parm, configHandle, + &key, NdisParameterInteger); + if (status == NDIS_STATUS_SUCCESS) + { + if (parm->ParameterType == NdisParameterInteger) + { + if (parm->ParameterData.IntegerData) + { + l_Adapter->m_MediaStateAlwaysConnected = TRUE; + l_Adapter->m_MediaState = TRUE; + } + } + } + } + +#if ENABLE_NONADMIN + /* Read AllowNonAdmin setting from registry */ + { + NDIS_STRING key = NDIS_STRING_CONST("AllowNonAdmin"); + NdisReadConfiguration (&status, &parm, configHandle, + &key, NdisParameterInteger); + if (status == NDIS_STATUS_SUCCESS) + { + if (parm->ParameterType == NdisParameterInteger) + { + if (parm->ParameterData.IntegerData) + { + enable_non_admin = TRUE; + } + } + } + } +#endif + + /* Read optional MAC setting from registry */ + { + NDIS_STRING key = NDIS_STRING_CONST("MAC"); + ANSI_STRING mac_string; + NdisReadConfiguration (&status, &parm, configHandle, + &key, NdisParameterString); + if (status == NDIS_STATUS_SUCCESS) + { + if (parm->ParameterType == NdisParameterString) + { + if (RtlUnicodeStringToAnsiString (&mac_string, &parm->ParameterData.StringData, TRUE) == STATUS_SUCCESS) + { + l_MacFromRegistry = ParseMAC (l_Adapter->m_MAC, mac_string.Buffer); + RtlFreeAnsiString (&mac_string); + } + } + } + } + + NdisCloseConfiguration (configHandle); + + DEBUGP (("[%s] MTU=%d\n", NAME (l_Adapter), l_Adapter->m_MTU)); + } + + //================================== + // Store and update MAC address info + //================================== + + if (!l_MacFromRegistry) + GenerateRandomMac (l_Adapter->m_MAC, NAME (l_Adapter)); + + DEBUGP (("[%s] Using MAC %x:%x:%x:%x:%x:%x\n", + NAME (l_Adapter), + l_Adapter->m_MAC[0], l_Adapter->m_MAC[1], l_Adapter->m_MAC[2], + l_Adapter->m_MAC[3], l_Adapter->m_MAC[4], l_Adapter->m_MAC[5])); + + //================== + // Set broadcast MAC + //================== + { + int i; + for (i = 0; i < sizeof (MACADDR); ++i) + l_Adapter->m_MAC_Broadcast[i] = 0xFF; + } + + //==================================== + // Initialize TAP device + //==================================== + { + NDIS_STATUS tap_status; + tap_status = CreateTapDevice (&l_Adapter->m_Extension, NAME (l_Adapter)); + if (tap_status != NDIS_STATUS_SUCCESS) + { + AdapterFreeResources (l_Adapter); + DEBUGP (("[TAP] CreateTapDevice failed\n")); + return tap_status; + } + } + + if (!AddAdapterToInstanceList (l_Adapter)) + { + NOTE_ERROR (); + TapDeviceFreeResources (&l_Adapter->m_Extension); + AdapterFreeResources (l_Adapter); + DEBUGP (("[TAP] AddAdapterToInstanceList failed\n")); + return NDIS_STATUS_RESOURCES; + } + + l_Adapter->m_InterfaceIsRunning = TRUE; + +#if ENABLE_NONADMIN + if (enable_non_admin) + AllowNonAdmin (&l_Adapter->m_Extension); +#endif + + return NDIS_STATUS_SUCCESS; +} + +VOID +AdapterHalt (IN NDIS_HANDLE p_AdapterContext) +{ + BOOLEAN status; + + TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext; + + NOTE_ERROR (); + + l_Adapter->m_InterfaceIsRunning = FALSE; + + DEBUGP (("[%s] is being halted\n", NAME (l_Adapter))); + + DestroyTapDevice (&l_Adapter->m_Extension); + + // Free resources + DEBUGP (("[%s] Freeing Resources\n", NAME (l_Adapter))); + AdapterFreeResources (l_Adapter); + + status = RemoveAdapterFromInstanceList (l_Adapter); + DEBUGP (("[TAP] RemoveAdapterFromInstanceList returned %d\n", (int) status)); + + DEBUGP (("[TAP] version [%d.%d] %s %s AdapterHalt returning\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, + __DATE__, + __TIME__)); +} + +VOID +AdapterFreeResources (TapAdapterPointer p_Adapter) +{ + MYASSERT (!p_Adapter->m_CalledAdapterFreeResources); + p_Adapter->m_CalledAdapterFreeResources = TRUE; + + if (p_Adapter->m_NameAnsi.Buffer) + RtlFreeAnsiString (&p_Adapter->m_NameAnsi); + + if (p_Adapter->m_RegisteredAdapterShutdownHandler) + NdisMDeregisterAdapterShutdownHandler (p_Adapter->m_MiniportAdapterHandle); + + if (p_Adapter->m_MCLockAllocated) + NdisFreeSpinLock (&p_Adapter->m_MCLock); +} + +VOID +DestroyTapDevice (TapExtensionPointer p_Extension) +{ + DEBUGP (("[%s] Destroying tap device\n", p_Extension->m_TapName)); + + //====================================== + // Let clients know we are shutting down + //====================================== + p_Extension->m_TapIsRunning = FALSE; + p_Extension->m_TapOpens = 0; + p_Extension->m_Halt = TRUE; + + //===================================== + // If we are concurrently executing in + // TapDeviceHook or AdapterTransmit, + // give those calls time to finish. + // Note that we must be running at IRQL + // < DISPATCH_LEVEL in order to call + // NdisMSleep. + //===================================== + NdisMSleep (500000); + + //=========================================================== + // Exhaust IRP and packet queues. Any pending IRPs will + // be cancelled, causing user-space to get this error + // on overlapped reads: + // The I/O operation has been aborted because of either a + // thread exit or an application request. (code=995) + // It's important that user-space close the device handle + // when this code is returned, so that when we finally + // do a NdisMDeregisterDevice, the device reference count + // is 0. Otherwise the driver will not unload even if the + // the last adapter has been halted. + //=========================================================== + FlushQueues (p_Extension); + NdisMSleep (500000); // give user space time to respond to IRP cancel + + TapDeviceFreeResources (p_Extension); +} + +VOID +TapDeviceFreeResources (TapExtensionPointer p_Extension) +{ + MYASSERT (p_Extension); + MYASSERT (!p_Extension->m_CalledTapDeviceFreeResources); + p_Extension->m_CalledTapDeviceFreeResources = TRUE; + + if (p_Extension->m_PacketQueue) + QueueFree (p_Extension->m_PacketQueue); + if (p_Extension->m_IrpQueue) + QueueFree (p_Extension->m_IrpQueue); + if (p_Extension->m_InjectQueue) + QueueFree (p_Extension->m_InjectQueue); + + if (p_Extension->m_CreatedUnicodeLinkName) + RtlFreeUnicodeString (&p_Extension->m_UnicodeLinkName); + + //========================================================== + // According to DDK docs, the device is not actually deleted + // until its reference count falls to zero. That means we + // still need to gracefully fail TapDeviceHook requests + // after this point, otherwise ugly things would happen if + // the device was disabled (e.g. in the network connections + // control panel) while a userspace app still held an open + // file handle to it. + //========================================================== + + if (p_Extension->m_TapDevice) + { + BOOLEAN status; + status = (NdisMDeregisterDevice (p_Extension->m_TapDeviceHandle) + == NDIS_STATUS_SUCCESS); + DEBUGP (("[TAP] Deregistering TAP device, status=%d\n", (int)status)); + } + + if (p_Extension->m_TapName) + MemFree (p_Extension->m_TapName, NAME_BUFFER_SIZE); + + if (p_Extension->m_InjectDpcInitialized) + KeRemoveQueueDpc (&p_Extension->m_InjectDpc); + + if (p_Extension->m_AllocatedSpinlocks) + { + NdisFreeSpinLock (&p_Extension->m_QueueLock); + NdisFreeSpinLock (&p_Extension->m_InjectLock); + } +} + +//======================================================================== +// Tap Device Initialization +//======================================================================== + +NDIS_STATUS +CreateTapDevice (TapExtensionPointer p_Extension, const char *p_Name) +{ +# define SIZEOF_DISPATCH (sizeof(PDRIVER_DISPATCH) * (IRP_MJ_MAXIMUM_FUNCTION + 1)) + PDRIVER_DISPATCH *l_Dispatch = NULL; + ANSI_STRING l_TapString, l_LinkString; + UNICODE_STRING l_TapUnicode; + BOOLEAN l_FreeTapUnicode = FALSE; + NTSTATUS l_Status, l_Return = NDIS_STATUS_SUCCESS; + const char *l_UsableName; + + DEBUGP (("[TAP] version [%d.%d] creating tap device: %s\n", + TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, + p_Name)); + + NdisZeroMemory (p_Extension, sizeof (TapExtension)); + + INIT_MUTEX (&p_Extension->m_OpenCloseMutex); + + l_LinkString.Buffer = NULL; + l_TapString.Buffer = NULL; + + l_TapString.MaximumLength = l_LinkString.MaximumLength = NAME_BUFFER_SIZE; + + //======================================= + // Set TAP device entry points + //======================================= + + if ((l_Dispatch = MemAlloc (SIZEOF_DISPATCH, TRUE)) == NULL) + { + DEBUGP (("[%s] couldn't alloc TAP dispatch table\n", p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + + l_Dispatch[IRP_MJ_DEVICE_CONTROL] = TapDeviceHook; + l_Dispatch[IRP_MJ_READ] = TapDeviceHook; + l_Dispatch[IRP_MJ_WRITE] = TapDeviceHook; + l_Dispatch[IRP_MJ_CREATE] = TapDeviceHook; + l_Dispatch[IRP_MJ_CLOSE] = TapDeviceHook; + + //================================== + // Find the beginning of the GUID + //================================== + l_UsableName = p_Name; + while (*l_UsableName != '{') + { + if (*l_UsableName == '\0') + { + DEBUGP (("[%s] couldn't find leading '{' in name\n", p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + ++l_UsableName; + } + + //================================== + // Allocate pool for TAP device name + //================================== + + if ((p_Extension->m_TapName = l_TapString.Buffer = + MemAlloc (NAME_BUFFER_SIZE, TRUE)) == NULL) + { + DEBUGP (("[%s] couldn't alloc TAP name buffer\n", p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + + //================================================ + // Allocate pool for TAP symbolic link name buffer + //================================================ + + if ((l_LinkString.Buffer = + MemAlloc (NAME_BUFFER_SIZE, TRUE)) == NULL) + { + DEBUGP (("[%s] couldn't alloc TAP symbolic link name buffer\n", + p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + + //======================================================= + // Set TAP device name + //======================================================= + + l_Status = RtlStringCchPrintfExA + (l_TapString.Buffer, + l_TapString.MaximumLength, + NULL, + NULL, + STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS, + "%s%s%s", + SYSDEVICEDIR, + l_UsableName, + TAPSUFFIX); + + if (l_Status != STATUS_SUCCESS) + { + DEBUGP (("[%s] couldn't format TAP device name\n", + p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + l_TapString.Length = (USHORT) strlen (l_TapString.Buffer); + + DEBUGP (("TAP DEV NAME: '%s'\n", l_TapString.Buffer)); + + //======================================================= + // Set TAP link name + //======================================================= + + l_Status = RtlStringCchPrintfExA + (l_LinkString.Buffer, + l_LinkString.MaximumLength, + NULL, + NULL, + STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS, + "%s%s%s", + USERDEVICEDIR, + l_UsableName, + TAPSUFFIX); + + if (l_Status != STATUS_SUCCESS) + { + DEBUGP (("[%s] couldn't format TAP device symbolic link\n", + p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + l_LinkString.Length = (USHORT) strlen (l_LinkString.Buffer); + + DEBUGP (("TAP LINK NAME: '%s'\n", l_LinkString.Buffer)); + + //================================================== + // Convert strings to unicode + //================================================== + if (RtlAnsiStringToUnicodeString (&l_TapUnicode, &l_TapString, TRUE) != + STATUS_SUCCESS) + { + DEBUGP (("[%s] couldn't alloc TAP unicode name buffer\n", + p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + l_FreeTapUnicode = TRUE; + + if (RtlAnsiStringToUnicodeString + (&p_Extension->m_UnicodeLinkName, &l_LinkString, TRUE) + != STATUS_SUCCESS) + { + DEBUGP + (("[%s] Couldn't allocate unicode string for symbolic link name\n", + p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + p_Extension->m_CreatedUnicodeLinkName = TRUE; + + //================================================== + // Create new TAP device with symbolic + // link and associate with adapter. + //================================================== + + l_Status = NdisMRegisterDevice + (g_NdisWrapperHandle, + &l_TapUnicode, + &p_Extension->m_UnicodeLinkName, + l_Dispatch, + &p_Extension->m_TapDevice, + &p_Extension->m_TapDeviceHandle + ); + + if (l_Status != STATUS_SUCCESS) + { + DEBUGP (("[%s] couldn't be created\n", p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + + /* Set TAP device flags */ + p_Extension->m_TapDevice->Flags |= DO_DIRECT_IO; + + //======================================================== + // Initialize Packet and IRP queues. + // + // The packet queue is used to buffer data which has been + // "transmitted" by the virtual NIC, before user space + // has had a chance to read it. + // + // The IRP queue is used to buffer pending I/O requests + // from userspace, i.e. read requests on the TAP device + // waiting for the system to "transmit" something through + // the virtual NIC. + // + // Basically, packets in the packet queue are used + // to satisfy IRP requests in the IRP queue. + // + // QueueLock is used to lock the packet queue used + // for the TAP-Win32 NIC -> User Space packet flow direction. + // + // All accesses to packet or IRP queues should be + // bracketed by the QueueLock spinlock, + // in order to be SMP-safe. + //======================================================== + + NdisAllocateSpinLock (&p_Extension->m_QueueLock); + NdisAllocateSpinLock (&p_Extension->m_InjectLock); + p_Extension->m_AllocatedSpinlocks = TRUE; + + p_Extension->m_PacketQueue = QueueInit (PACKET_QUEUE_SIZE); + p_Extension->m_IrpQueue = QueueInit (IRP_QUEUE_SIZE); + p_Extension->m_InjectQueue = QueueInit (INJECT_QUEUE_SIZE); + if (!p_Extension->m_PacketQueue + || !p_Extension->m_IrpQueue + || !p_Extension->m_InjectQueue) + { + DEBUGP (("[%s] couldn't alloc TAP queues\n", p_Name)); + l_Return = NDIS_STATUS_RESOURCES; + goto cleanup; + } + + //================================================================= + // Initialize deferred procedure call for DHCP/ARP packet injection + //================================================================= + + KeInitializeDpc (&p_Extension->m_InjectDpc, InjectPacketDpc, NULL); + p_Extension->m_InjectDpcInitialized = TRUE; + + //======================== + // Finalize initialization + //======================== + + p_Extension->m_TapIsRunning = TRUE; + + DEBUGP (("[%s] successfully created TAP device [%s]\n", p_Name, + p_Extension->m_TapName)); + + cleanup: + if (l_FreeTapUnicode) + RtlFreeUnicodeString (&l_TapUnicode); + if (l_LinkString.Buffer) + MemFree (l_LinkString.Buffer, NAME_BUFFER_SIZE); + if (l_Dispatch) + MemFree (l_Dispatch, SIZEOF_DISPATCH); + + if (l_Return != NDIS_STATUS_SUCCESS) + TapDeviceFreeResources (p_Extension); + + return l_Return; +} +#undef SIZEOF_DISPATCH + +//======================================================== +// Adapter Control +//======================================================== +NDIS_STATUS +AdapterReset (OUT PBOOLEAN p_AddressingReset, IN NDIS_HANDLE p_AdapterContext) +{ + TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext; + DEBUGP (("[%s] is resetting\n", NAME (l_Adapter))); + return NDIS_STATUS_SUCCESS; +} + +NDIS_STATUS AdapterReceive + (OUT PNDIS_PACKET p_Packet, + OUT PUINT p_Transferred, + IN NDIS_HANDLE p_AdapterContext, + IN NDIS_HANDLE p_ReceiveContext, + IN UINT p_Offset, + IN UINT p_ToTransfer) +{ + return NDIS_STATUS_SUCCESS; +} + +//============================================================== +// Adapter Option Query/Modification +//============================================================== +NDIS_STATUS AdapterQuery +(IN NDIS_HANDLE p_AdapterContext, + IN NDIS_OID p_OID, + IN PVOID p_Buffer, + IN ULONG p_BufferLength, + OUT PULONG p_BytesWritten, OUT PULONG p_BytesNeeded) +{ + TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext; + TapAdapterQuery l_Query, *l_QueryPtr = &l_Query; + NDIS_STATUS l_Status = NDIS_STATUS_SUCCESS; + UINT l_QueryLength = 4; + BOOLEAN lock_succeeded; + + NdisZeroMemory (&l_Query, sizeof (l_Query)); + + switch (p_OID) + { + //=================================================================== + // Vendor & Driver version Info + //=================================================================== + case OID_GEN_VENDOR_DESCRIPTION: + l_QueryPtr = (TapAdapterQueryPointer) PRODUCT_STRING; + l_QueryLength = strlen (PRODUCT_STRING) + 1; + break; + + case OID_GEN_VENDOR_ID: + l_Query.m_Long = 0xffffff; + break; + + case OID_GEN_DRIVER_VERSION: + l_Query.m_Short = + (((USHORT) TAP_NDIS_MAJOR_VERSION) << 8 | (USHORT) + TAP_NDIS_MINOR_VERSION); + l_QueryLength = sizeof (unsigned short); + break; + + case OID_GEN_VENDOR_DRIVER_VERSION: + l_Query.m_Long = + (((USHORT) TAP_DRIVER_MAJOR_VERSION) << 8 | (USHORT) + TAP_DRIVER_MINOR_VERSION); + break; + + //================================================================= + // Statistics + //================================================================= + case OID_GEN_RCV_NO_BUFFER: + l_Query.m_Long = 0; + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + l_Query.m_Long = 0; + break; + + case OID_802_3_XMIT_ONE_COLLISION: + l_Query.m_Long = 0; + break; + + case OID_802_3_XMIT_MORE_COLLISIONS: + l_Query.m_Long = 0; + break; + + case OID_GEN_XMIT_OK: + l_Query.m_Long = l_Adapter->m_Tx; + break; + + case OID_GEN_RCV_OK: + l_Query.m_Long = l_Adapter->m_Rx; + break; + + case OID_GEN_XMIT_ERROR: + l_Query.m_Long = l_Adapter->m_TxErr; + break; + + case OID_GEN_RCV_ERROR: + l_Query.m_Long = l_Adapter->m_RxErr; + break; + + //=================================================================== + // Device & Protocol Options + //=================================================================== + case OID_GEN_SUPPORTED_LIST: + l_QueryPtr = (TapAdapterQueryPointer) g_SupportedOIDList; + l_QueryLength = sizeof (g_SupportedOIDList); + break; + + case OID_GEN_MAC_OPTIONS: + // This MUST be here !!! + l_Query.m_Long = (NDIS_MAC_OPTION_RECEIVE_SERIALIZED + | NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA + | NDIS_MAC_OPTION_NO_LOOPBACK + | NDIS_MAC_OPTION_TRANSFERS_NOT_PEND); + + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + l_Query.m_Long = + (NDIS_PACKET_TYPE_ALL_LOCAL | + NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_DIRECTED | NDIS_PACKET_TYPE_ALL_FUNCTIONAL); + + break; + + case OID_GEN_PROTOCOL_OPTIONS: + l_Query.m_Long = 0; + break; + + //================================================================== + // Device Info + //================================================================== + case OID_GEN_MEDIA_CONNECT_STATUS: + l_Query.m_Long = l_Adapter->m_MediaState + ? NdisMediaStateConnected : NdisMediaStateDisconnected; + break; + + case OID_GEN_HARDWARE_STATUS: + l_Query.m_HardwareStatus = NdisHardwareStatusReady; + l_QueryLength = sizeof (NDIS_HARDWARE_STATUS); + break; + + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + l_Query.m_Medium = l_Adapter->m_Medium; + l_QueryLength = sizeof (NDIS_MEDIUM); + break; + + case OID_GEN_PHYSICAL_MEDIUM: + l_Query.m_PhysicalMedium = NdisPhysicalMediumUnspecified; + l_QueryLength = sizeof (NDIS_PHYSICAL_MEDIUM); + break; + + case OID_GEN_LINK_SPEED: + l_Query.m_Long = 100000; // rate / 100 bps + break; + + case OID_802_3_PERMANENT_ADDRESS: + case OID_802_3_CURRENT_ADDRESS: + COPY_MAC (l_Query.m_MacAddress, l_Adapter->m_MAC); + l_QueryLength = sizeof (MACADDR); + break; + + //================================================================== + // Limits + //================================================================== + + case OID_GEN_MAXIMUM_SEND_PACKETS: + l_Query.m_Long = 1; + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + l_Query.m_Long = NIC_MAX_MCAST_LIST; + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + l_Query.m_Long = l_Adapter->m_Lookahead; + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_MAXIMUM_TOTAL_SIZE: + case OID_GEN_RECEIVE_BUFFER_SPACE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + l_Query.m_Long = DEFAULT_PACKET_LOOKAHEAD; + break; + + case OID_GEN_MAXIMUM_FRAME_SIZE: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_TRANSMIT_BUFFER_SPACE: + l_Query.m_Long = l_Adapter->m_MTU; + break; + + case OID_PNP_CAPABILITIES: + do + { + PNDIS_PNP_CAPABILITIES pPNPCapabilities; + PNDIS_PM_WAKE_UP_CAPABILITIES pPMstruct; + + if (p_BufferLength >= sizeof (NDIS_PNP_CAPABILITIES)) + { + pPNPCapabilities = (PNDIS_PNP_CAPABILITIES) (p_Buffer); + + // + // Setting up the buffer to be returned + // to the Protocol above the Passthru miniport + // + pPMstruct = &pPNPCapabilities->WakeUpCapabilities; + pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified; + pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified; + pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified; + } + l_QueryLength = sizeof (NDIS_PNP_CAPABILITIES); + } + while (FALSE); + break; + case OID_PNP_QUERY_POWER: + break; + + // Required OIDs that we don't support + + case OID_GEN_SUPPORTED_GUIDS: + case OID_GEN_MEDIA_CAPABILITIES: + case OID_TCP_TASK_OFFLOAD: + case OID_FFP_SUPPORT: + l_Status = NDIS_STATUS_INVALID_OID; + break; + + // Optional stats OIDs + + case OID_GEN_DIRECTED_BYTES_XMIT: + case OID_GEN_DIRECTED_FRAMES_XMIT: + case OID_GEN_MULTICAST_BYTES_XMIT: + case OID_GEN_MULTICAST_FRAMES_XMIT: + case OID_GEN_BROADCAST_BYTES_XMIT: + case OID_GEN_BROADCAST_FRAMES_XMIT: + case OID_GEN_DIRECTED_BYTES_RCV: + case OID_GEN_DIRECTED_FRAMES_RCV: + case OID_GEN_MULTICAST_BYTES_RCV: + case OID_GEN_MULTICAST_FRAMES_RCV: + case OID_GEN_BROADCAST_BYTES_RCV: + case OID_GEN_BROADCAST_FRAMES_RCV: + l_Status = NDIS_STATUS_INVALID_OID; + break; + + //=================================================================== + // Not Handled + //=================================================================== + default: + DEBUGP (("[%s] Unhandled OID %lx\n", NAME (l_Adapter), p_OID)); + l_Status = NDIS_STATUS_INVALID_OID; + break; + } + + if (l_Status != NDIS_STATUS_SUCCESS) + ; + else if (l_QueryLength > p_BufferLength) + { + l_Status = NDIS_STATUS_INVALID_LENGTH; + *p_BytesNeeded = l_QueryLength; + } + else + NdisMoveMemory (p_Buffer, (PVOID) l_QueryPtr, + (*p_BytesWritten = l_QueryLength)); + + return l_Status; +} + +NDIS_STATUS AdapterModify +(IN NDIS_HANDLE p_AdapterContext, + IN NDIS_OID p_OID, + IN PVOID p_Buffer, + IN ULONG p_BufferLength, + OUT PULONG p_BytesRead, + OUT PULONG p_BytesNeeded) +{ + TapAdapterQueryPointer l_Query = (TapAdapterQueryPointer) p_Buffer; + TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext; + NDIS_STATUS l_Status = NDIS_STATUS_INVALID_OID; + ULONG l_Long; + + switch (p_OID) + { + //================================================================== + // Device Info + //================================================================== + case OID_802_3_MULTICAST_LIST: + DEBUGP (("[%s] Setting [OID_802_3_MULTICAST_LIST]\n", + NAME (l_Adapter))); + + *p_BytesNeeded = sizeof (ETH_ADDR); + *p_BytesRead = p_BufferLength; + + if (p_BufferLength % sizeof (ETH_ADDR)) + l_Status = NDIS_STATUS_INVALID_LENGTH; + else if (p_BufferLength > sizeof (MC_LIST)) + { + l_Status = NDIS_STATUS_MULTICAST_FULL; + *p_BytesNeeded = sizeof (MC_LIST); + } + else + { + NdisAcquireSpinLock (&l_Adapter->m_MCLock); + + NdisZeroMemory(&l_Adapter->m_MCList, sizeof (MC_LIST)); + + NdisMoveMemory(&l_Adapter->m_MCList, + p_Buffer, + p_BufferLength); + + l_Adapter->m_MCListSize = p_BufferLength / sizeof (ETH_ADDR); + + NdisReleaseSpinLock (&l_Adapter->m_MCLock); + + l_Status = NDIS_STATUS_SUCCESS; + } + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + l_Status = NDIS_STATUS_INVALID_LENGTH; + *p_BytesNeeded = 4; + + if (p_BufferLength >= sizeof (ULONG)) + { + DEBUGP + (("[%s] Setting [OID_GEN_CURRENT_PACKET_FILTER] to [0x%02lx]\n", + NAME (l_Adapter), l_Query->m_Long)); + l_Status = NDIS_STATUS_SUCCESS; + *p_BytesRead = sizeof (ULONG); + } + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + if (p_BufferLength < sizeof (ULONG)) + { + l_Status = NDIS_STATUS_INVALID_LENGTH; + *p_BytesNeeded = 4; + } + else if (l_Query->m_Long > DEFAULT_PACKET_LOOKAHEAD + || l_Query->m_Long <= 0) + { + l_Status = NDIS_STATUS_INVALID_DATA; + } + else + { + DEBUGP (("[%s] Setting [OID_GEN_CURRENT_LOOKAHEAD] to [%d]\n", + NAME (l_Adapter), l_Query->m_Long)); + l_Adapter->m_Lookahead = l_Query->m_Long; + l_Status = NDIS_STATUS_SUCCESS; + *p_BytesRead = sizeof (ULONG); + } + break; + + case OID_GEN_NETWORK_LAYER_ADDRESSES: + l_Status = NDIS_STATUS_SUCCESS; + *p_BytesRead = *p_BytesNeeded = 0; + break; + + case OID_GEN_TRANSPORT_HEADER_OFFSET: + l_Status = NDIS_STATUS_SUCCESS; + *p_BytesRead = *p_BytesNeeded = 0; + break; + + case OID_PNP_SET_POWER: + do + { + NDIS_DEVICE_POWER_STATE NewDeviceState; + + NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE) p_Buffer); + + switch (NewDeviceState) + { + case NdisDeviceStateD0: + l_Adapter->m_DeviceState = '0'; + break; + case NdisDeviceStateD1: + l_Adapter->m_DeviceState = '1'; + break; + case NdisDeviceStateD2: + l_Adapter->m_DeviceState = '2'; + break; + case NdisDeviceStateD3: + l_Adapter->m_DeviceState = '3'; + break; + default: + l_Adapter->m_DeviceState = '?'; + break; + } + + l_Status = NDIS_STATUS_FAILURE; + + // + // Check for invalid length + // + if (p_BufferLength < sizeof (NDIS_DEVICE_POWER_STATE)) + { + l_Status = NDIS_STATUS_INVALID_LENGTH; + break; + } + + if (NewDeviceState > NdisDeviceStateD0) + { + l_Adapter->m_InterfaceIsRunning = FALSE; + DEBUGP (("[%s] Power management device state OFF\n", + NAME (l_Adapter))); + } + else + { + l_Adapter->m_InterfaceIsRunning = TRUE; + DEBUGP (("[%s] Power management device state ON\n", + NAME (l_Adapter))); + } + + l_Status = NDIS_STATUS_SUCCESS; + } + while (FALSE); + + if (l_Status == NDIS_STATUS_SUCCESS) + { + *p_BytesRead = sizeof (NDIS_DEVICE_POWER_STATE); + *p_BytesNeeded = 0; + } + else + { + *p_BytesRead = 0; + *p_BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE); + } + break; + + case OID_PNP_REMOVE_WAKE_UP_PATTERN: + case OID_PNP_ADD_WAKE_UP_PATTERN: + l_Status = NDIS_STATUS_SUCCESS; + *p_BytesRead = *p_BytesNeeded = 0; + break; + + default: + DEBUGP (("[%s] Can't set value for OID %lx\n", NAME (l_Adapter), + p_OID)); + l_Status = NDIS_STATUS_INVALID_OID; + *p_BytesRead = *p_BytesNeeded = 0; + break; + } + + return l_Status; +} + +//==================================================================== +// Adapter Transmission +//==================================================================== +NDIS_STATUS +AdapterTransmit (IN NDIS_HANDLE p_AdapterContext, + IN PNDIS_PACKET p_Packet, + IN UINT p_Flags) +{ + TapAdapterPointer l_Adapter = (TapAdapterPointer) p_AdapterContext; + ULONG l_Index = 0, l_PacketLength = 0; + UINT l_BufferLength = 0; + PIRP l_IRP; + TapPacketPointer l_PacketBuffer; + PNDIS_BUFFER l_NDIS_Buffer; + PUCHAR l_Buffer; + PVOID result; + + NdisQueryPacket (p_Packet, NULL, NULL, &l_NDIS_Buffer, &l_PacketLength); + + //==================================================== + // Here we abandon the transmission attempt if any of + // the parameters is wrong or memory allocation fails + // but we do not indicate failure. The packet is + // silently dropped. + //==================================================== + + if (l_PacketLength < ETHERNET_HEADER_SIZE || l_PacketLength > 65535) + goto exit_fail; + else if (!l_Adapter->m_Extension.m_TapOpens || !l_Adapter->m_MediaState) + goto exit_success; // Nothing is bound to the TAP device + + if (NdisAllocateMemoryWithTag (&l_PacketBuffer, + TAP_PACKET_SIZE (l_PacketLength), + '5PAT') != NDIS_STATUS_SUCCESS) + goto exit_no_resources; + + if (l_PacketBuffer == NULL) + goto exit_no_resources; + + l_PacketBuffer->m_SizeFlags = (l_PacketLength & TP_SIZE_MASK); + + //=========================== + // Reassemble packet contents + //=========================== + + __try + { + l_Index = 0; + while (l_NDIS_Buffer && l_Index < l_PacketLength) + { + ULONG newlen; + NdisQueryBuffer (l_NDIS_Buffer, (PVOID *) & l_Buffer, + &l_BufferLength); + newlen = l_Index + l_BufferLength; + if (newlen > l_PacketLength) + { + NOTE_ERROR (); + goto no_queue; /* overflow */ + } + NdisMoveMemory (l_PacketBuffer->m_Data + l_Index, l_Buffer, + l_BufferLength); + l_Index = newlen; + NdisGetNextBuffer (l_NDIS_Buffer, &l_NDIS_Buffer); + } + if (l_Index != l_PacketLength) + { + NOTE_ERROR (); + goto no_queue; /* underflow */ + } + + DUMP_PACKET ("AdapterTransmit", l_PacketBuffer->m_Data, l_PacketLength); + + //===================================================== + // If IPv4 packet, check whether or not packet + // was truncated. + //===================================================== +#if PACKET_TRUNCATION_CHECK + IPv4PacketSizeVerify (l_PacketBuffer->m_Data, l_PacketLength, FALSE, "TX", &l_Adapter->m_TxTrunc); +#endif + + //===================================================== + // Are we running in DHCP server masquerade mode? + // + // If so, catch both DHCP requests and ARP queries + // to resolve the address of our virtual DHCP server. + //===================================================== + if (l_Adapter->m_dhcp_enabled) + { + const ETH_HEADER *eth = (ETH_HEADER *) l_PacketBuffer->m_Data; + const IPHDR *ip = (IPHDR *) (l_PacketBuffer->m_Data + sizeof (ETH_HEADER)); + const UDPHDR *udp = (UDPHDR *) (l_PacketBuffer->m_Data + sizeof (ETH_HEADER) + sizeof (IPHDR)); + + // ARP packet? + if (l_PacketLength == sizeof (ARP_PACKET) + && eth->proto == htons (ETH_P_ARP) + && l_Adapter->m_dhcp_server_arp) + { + if (ProcessARP (l_Adapter, + (PARP_PACKET) l_PacketBuffer->m_Data, + l_Adapter->m_dhcp_addr, + l_Adapter->m_dhcp_server_ip, + ~0, + l_Adapter->m_dhcp_server_mac)) + goto no_queue; + } + + // DHCP packet? + else if (l_PacketLength >= sizeof (ETH_HEADER) + sizeof (IPHDR) + sizeof (UDPHDR) + sizeof (DHCP) + && eth->proto == htons (ETH_P_IP) + && ip->version_len == 0x45 // IPv4, 20 byte header + && ip->protocol == IPPROTO_UDP + && udp->dest == htons (BOOTPS_PORT)) + { + const DHCP *dhcp = (DHCP *) (l_PacketBuffer->m_Data + + sizeof (ETH_HEADER) + + sizeof (IPHDR) + + sizeof (UDPHDR)); + + const int optlen = l_PacketLength + - sizeof (ETH_HEADER) + - sizeof (IPHDR) + - sizeof (UDPHDR) + - sizeof (DHCP); + + if (optlen > 0) // we must have at least one DHCP option + { + if (ProcessDHCP (l_Adapter, eth, ip, udp, dhcp, optlen)) + goto no_queue; + } + else + goto no_queue; + } + } + + //=============================================== + // In Point-To-Point mode, check to see whether + // packet is ARP or IPv4 (if neither, then drop). + //=============================================== + if (l_Adapter->m_tun) + { + ETH_HEADER *e; + + if (l_PacketLength < ETHERNET_HEADER_SIZE) + goto no_queue; + + e = (ETH_HEADER *) l_PacketBuffer->m_Data; + + switch (ntohs (e->proto)) + { + case ETH_P_ARP: + + // Make sure that packet is the + // right size for ARP. + if (l_PacketLength != sizeof (ARP_PACKET)) + goto no_queue; + + ProcessARP (l_Adapter, + (PARP_PACKET) l_PacketBuffer->m_Data, + l_Adapter->m_localIP, + l_Adapter->m_remoteNetwork, + l_Adapter->m_remoteNetmask, + l_Adapter->m_TapToUser.dest); + + default: + goto no_queue; + + case ETH_P_IP: + + // Make sure that packet is large + // enough to be IPv4. + if (l_PacketLength + < ETHERNET_HEADER_SIZE + IP_HEADER_SIZE) + goto no_queue; + + // Only accept directed packets, + // not broadcasts. + if (memcmp (e, &l_Adapter->m_TapToUser, ETHERNET_HEADER_SIZE)) + goto no_queue; + + // Packet looks like IPv4, queue it. + l_PacketBuffer->m_SizeFlags |= TP_TUN; + } + } + + //=============================================== + // Push packet onto queue to wait for read from + // userspace. + //=============================================== + + NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock); + + result = NULL; + if (IS_UP (l_Adapter)) + result = QueuePush (l_Adapter->m_Extension.m_PacketQueue, l_PacketBuffer); + + NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock); + + if ((TapPacketPointer) result != l_PacketBuffer) + { + // adapter receive overrun + INCREMENT_STAT (l_Adapter->m_TxErr); + goto no_queue; + } + else + { + INCREMENT_STAT (l_Adapter->m_Tx); + } + + //============================================================ + // Cycle through IRPs and packets, try to satisfy each pending + // IRP with a queued packet. + //============================================================ + while (TRUE) + { + l_IRP = NULL; + l_PacketBuffer = NULL; + + NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock); + + if (IS_UP (l_Adapter) + && QueueCount (l_Adapter->m_Extension.m_PacketQueue) + && QueueCount (l_Adapter->m_Extension.m_IrpQueue)) + { + l_IRP = (PIRP) QueuePop (l_Adapter->m_Extension.m_IrpQueue); + l_PacketBuffer = (TapPacketPointer) + QueuePop (l_Adapter->m_Extension.m_PacketQueue); + } + + NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock); + + MYASSERT ((l_IRP != NULL) + (l_PacketBuffer != NULL) != 1); + + if (l_IRP && l_PacketBuffer) + { + CompleteIRP (l_IRP, + l_PacketBuffer, + IO_NETWORK_INCREMENT); + } + else + break; + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + + return NDIS_STATUS_SUCCESS; + + no_queue: + NdisFreeMemory (l_PacketBuffer, + TAP_PACKET_SIZE (l_PacketLength), + 0); + + exit_success: + return NDIS_STATUS_SUCCESS; + + exit_fail: + return NDIS_STATUS_FAILURE; + + exit_no_resources: + return NDIS_STATUS_RESOURCES; +} + +//====================================================================== +// Hooks for catching TAP device IRP's. +//====================================================================== + +NTSTATUS +TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP) +{ + TapAdapterPointer l_Adapter = LookupAdapterInInstanceList (p_DeviceObject); + PIO_STACK_LOCATION l_IrpSp; + NTSTATUS l_Status = STATUS_SUCCESS; + BOOLEAN accessible; + + l_IrpSp = IoGetCurrentIrpStackLocation (p_IRP); + + p_IRP->IoStatus.Status = STATUS_SUCCESS; + p_IRP->IoStatus.Information = 0; + + if (!l_Adapter || l_Adapter->m_Extension.m_Halt) + { + DEBUGP (("TapDeviceHook called when TAP device is halted, MajorFunction=%d\n", + (int)l_IrpSp->MajorFunction)); + + if (l_IrpSp->MajorFunction == IRP_MJ_CLOSE) + { + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + return STATUS_SUCCESS; + } + else + { + p_IRP->IoStatus.Status = STATUS_NO_SUCH_DEVICE; + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + return STATUS_NO_SUCH_DEVICE; + } + } + + switch (l_IrpSp->MajorFunction) + { + //=========================================================== + // Ioctl call handlers + //=========================================================== + case IRP_MJ_DEVICE_CONTROL: + { + switch (l_IrpSp->Parameters.DeviceIoControl.IoControlCode) + { + case TAP_IOCTL_GET_MAC: + { + if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength + >= sizeof (MACADDR)) + { + COPY_MAC (p_IRP->AssociatedIrp.SystemBuffer, + l_Adapter->m_MAC); + p_IRP->IoStatus.Information = sizeof (MACADDR); + } + else + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + case TAP_IOCTL_GET_VERSION: + { + const ULONG size = sizeof (ULONG) * 3; + if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength + >= size) + { + ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0] + = TAP_DRIVER_MAJOR_VERSION; + ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[1] + = TAP_DRIVER_MINOR_VERSION; + ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[2] +#if DBG + = 1; +#else + = 0; +#endif + p_IRP->IoStatus.Information = size; + } + else + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL; + } + + break; + } + case TAP_IOCTL_GET_MTU: + { + const ULONG size = sizeof (ULONG) * 1; + if (l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength + >= size) + { + ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0] + = l_Adapter->m_MTU; + p_IRP->IoStatus.Information = size; + } + else + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL; + } + + break; + } + case TAP_IOCTL_GET_INFO: + { + char state[16]; + if (l_Adapter->m_InterfaceIsRunning) + state[0] = 'A'; + else + state[0] = 'a'; + if (l_Adapter->m_Extension.m_TapIsRunning) + state[1] = 'T'; + else + state[1] = 't'; + state[2] = l_Adapter->m_DeviceState; + if (l_Adapter->m_MediaStateAlwaysConnected) + state[3] = 'C'; + else + state[3] = 'c'; + state[4] = '\0'; + + p_IRP->IoStatus.Status = l_Status = RtlStringCchPrintfExA ( + ((LPTSTR) (p_IRP->AssociatedIrp.SystemBuffer)), + l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength, + NULL, + NULL, + STRSAFE_FILL_BEHIND_NULL | STRSAFE_IGNORE_NULLS, +#if PACKET_TRUNCATION_CHECK + "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d,%d] Rx=[%d,%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]", +#else + "State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%d,%d,%d] InjQ=[%d,%d,%d]", +#endif + state, + g_LastErrorFilename, + g_LastErrorLineNumber, + (int)l_Adapter->m_Extension.m_NumTapOpens, + (int)l_Adapter->m_Tx, + (int)l_Adapter->m_TxErr, +#if PACKET_TRUNCATION_CHECK + (int)l_Adapter->m_TxTrunc, +#endif + (int)l_Adapter->m_Rx, + (int)l_Adapter->m_RxErr, +#if PACKET_TRUNCATION_CHECK + (int)l_Adapter->m_RxTrunc, +#endif + (int)l_Adapter->m_Extension.m_IrpQueue->size, + (int)l_Adapter->m_Extension.m_IrpQueue->max_size, + (int)IRP_QUEUE_SIZE, + (int)l_Adapter->m_Extension.m_PacketQueue->size, + (int)l_Adapter->m_Extension.m_PacketQueue->max_size, + (int)PACKET_QUEUE_SIZE, + (int)l_Adapter->m_Extension.m_InjectQueue->size, + (int)l_Adapter->m_Extension.m_InjectQueue->max_size, + (int)INJECT_QUEUE_SIZE + ); + + p_IRP->IoStatus.Information + = l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + + break; + } + +#if DBG + case TAP_IOCTL_GET_LOG_LINE: + { + if (GetDebugLine ((LPTSTR)p_IRP->AssociatedIrp.SystemBuffer, + l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength)) + p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS; + else + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + + p_IRP->IoStatus.Information + = l_IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + + break; + } +#endif + + case TAP_IOCTL_CONFIG_TUN: + { + if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >= + (sizeof (IPADDR) * 3)) + { + MACADDR dest; + + l_Adapter->m_tun = FALSE; + + GenerateRelatedMAC (dest, l_Adapter->m_MAC, 1); + + l_Adapter->m_localIP = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0]; + l_Adapter->m_remoteNetwork = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1]; + l_Adapter->m_remoteNetmask = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[2]; + + // sanity check on network/netmask + if ((l_Adapter->m_remoteNetwork & l_Adapter->m_remoteNetmask) != l_Adapter->m_remoteNetwork) + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER; + break; + } + + COPY_MAC (l_Adapter->m_TapToUser.src, l_Adapter->m_MAC); + COPY_MAC (l_Adapter->m_TapToUser.dest, dest); + COPY_MAC (l_Adapter->m_UserToTap.src, dest); + COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC); + + l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP); + + l_Adapter->m_tun = TRUE; + + CheckIfDhcpAndTunMode (l_Adapter); + + p_IRP->IoStatus.Information = 1; // Simple boolean value + } + else + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER; + } + + break; + } + + case TAP_IOCTL_CONFIG_POINT_TO_POINT: // Obsoleted by TAP_IOCTL_CONFIG_TUN + { + if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >= + (sizeof (IPADDR) * 2)) + { + MACADDR dest; + + l_Adapter->m_tun = FALSE; + + GenerateRelatedMAC (dest, l_Adapter->m_MAC, 1); + + l_Adapter->m_localIP = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0]; + l_Adapter->m_remoteNetwork = ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1]; + l_Adapter->m_remoteNetmask = ~0; + + COPY_MAC (l_Adapter->m_TapToUser.src, l_Adapter->m_MAC); + COPY_MAC (l_Adapter->m_TapToUser.dest, dest); + COPY_MAC (l_Adapter->m_UserToTap.src, dest); + COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC); + + l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP); + + l_Adapter->m_tun = TRUE; + + CheckIfDhcpAndTunMode (l_Adapter); + + p_IRP->IoStatus.Information = 1; // Simple boolean value + } + else + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER; + } + + break; + } + + case TAP_IOCTL_SET_MEDIA_STATUS: + { + if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >= + (sizeof (ULONG) * 1)) + { + ULONG parm = ((PULONG) (p_IRP->AssociatedIrp.SystemBuffer))[0]; + SetMediaStatus (l_Adapter, (BOOLEAN) parm); + p_IRP->IoStatus.Information = 1; + } + else + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER; + } + break; + } + + case TAP_IOCTL_CONFIG_DHCP_MASQ: + { + if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength >= + (sizeof (IPADDR) * 4)) + { + l_Adapter->m_dhcp_enabled = FALSE; + l_Adapter->m_dhcp_server_arp = FALSE; + l_Adapter->m_dhcp_user_supplied_options_buffer_len = 0; + + // Adapter IP addr / netmask + l_Adapter->m_dhcp_addr = + ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[0]; + l_Adapter->m_dhcp_netmask = + ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[1]; + + // IP addr of DHCP masq server + l_Adapter->m_dhcp_server_ip = + ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[2]; + + // Lease time in seconds + l_Adapter->m_dhcp_lease_time = + ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[3]; + + GenerateRelatedMAC (l_Adapter->m_dhcp_server_mac, l_Adapter->m_MAC, 2); + + l_Adapter->m_dhcp_enabled = TRUE; + l_Adapter->m_dhcp_server_arp = TRUE; + + CheckIfDhcpAndTunMode (l_Adapter); + + p_IRP->IoStatus.Information = 1; // Simple boolean value + } + else + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER; + } + + break; + } + + case TAP_IOCTL_CONFIG_DHCP_SET_OPT: + { + if (l_IrpSp->Parameters.DeviceIoControl.InputBufferLength <= + DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE + && l_Adapter->m_dhcp_enabled) + { + l_Adapter->m_dhcp_user_supplied_options_buffer_len = 0; + + NdisMoveMemory (l_Adapter->m_dhcp_user_supplied_options_buffer, + p_IRP->AssociatedIrp.SystemBuffer, + l_IrpSp->Parameters.DeviceIoControl.InputBufferLength); + + l_Adapter->m_dhcp_user_supplied_options_buffer_len = + l_IrpSp->Parameters.DeviceIoControl.InputBufferLength; + + p_IRP->IoStatus.Information = 1; // Simple boolean value + } + else + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER; + } + + break; + } + + default: + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER; + break; + } + } + + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + break; + } + + //=========================================================== + // User mode thread issued a read request on the tap device + // If there are packets waiting to be read, then the request + // will be satisfied here. If not, then the request will be + // queued and satisfied by any packet that is not used to + // satisfy requests ahead of it. + //=========================================================== + case IRP_MJ_READ: + { + TapPacketPointer l_PacketBuffer; + BOOLEAN pending = FALSE; + + // Save IRP-accessible copy of buffer length + p_IRP->IoStatus.Information = l_IrpSp->Parameters.Read.Length; + + if (p_IRP->MdlAddress == NULL) + { + DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_READ\n", + NAME (l_Adapter))); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER; + p_IRP->IoStatus.Information = 0; + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + break; + } + else if ((p_IRP->AssociatedIrp.SystemBuffer = + MmGetSystemAddressForMdlSafe + (p_IRP->MdlAddress, NormalPagePriority)) == NULL) + { + DEBUGP (("[%s] Could not map address in IRP_MJ_READ\n", + NAME (l_Adapter))); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INSUFFICIENT_RESOURCES; + p_IRP->IoStatus.Information = 0; + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + break; + } + else if (!l_Adapter->m_InterfaceIsRunning) + { + DEBUGP (("[%s] Interface is down in IRP_MJ_READ\n", + NAME (l_Adapter))); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + p_IRP->IoStatus.Information = 0; + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + break; + } + + //================================== + // Can we provide immediate service? + //================================== + + l_PacketBuffer = NULL; + + NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock); + + if (IS_UP (l_Adapter) + && QueueCount (l_Adapter->m_Extension.m_PacketQueue) + && QueueCount (l_Adapter->m_Extension.m_IrpQueue) == 0) + { + l_PacketBuffer = (TapPacketPointer) + QueuePop (l_Adapter->m_Extension.m_PacketQueue); + } + + NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock); + + if (l_PacketBuffer) + { + l_Status = CompleteIRP (p_IRP, + l_PacketBuffer, + IO_NO_INCREMENT); + break; + } + + //============================= + // Attempt to pend read request + //============================= + + NdisAcquireSpinLock (&l_Adapter->m_Extension.m_QueueLock); + + if (IS_UP (l_Adapter) + && QueuePush (l_Adapter->m_Extension.m_IrpQueue, p_IRP) == (PIRP) p_IRP) + { + IoSetCancelRoutine (p_IRP, CancelIRPCallback); + l_Status = STATUS_PENDING; + IoMarkIrpPending (p_IRP); + pending = TRUE; + } + + NdisReleaseSpinLock (&l_Adapter->m_Extension.m_QueueLock); + + if (pending) + break; + + // Can't queue anymore IRP's + DEBUGP (("[%s] TAP [%s] read IRP overrun\n", + NAME (l_Adapter), l_Adapter->m_Extension.m_TapName)); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + p_IRP->IoStatus.Information = 0; + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + break; + } + + //============================================================== + // User mode issued a WriteFile request on the TAP file handle. + // The request will always get satisfied here. The call may + // fail if there are too many pending packets (queue full). + //============================================================== + case IRP_MJ_WRITE: + { + if (p_IRP->MdlAddress == NULL) + { + DEBUGP (("[%s] MdlAddress is NULL for IRP_MJ_WRITE\n", + NAME (l_Adapter))); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INVALID_PARAMETER; + p_IRP->IoStatus.Information = 0; + } + else if ((p_IRP->AssociatedIrp.SystemBuffer = + MmGetSystemAddressForMdlSafe + (p_IRP->MdlAddress, NormalPagePriority)) == NULL) + { + DEBUGP (("[%s] Could not map address in IRP_MJ_WRITE\n", + NAME (l_Adapter))); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_INSUFFICIENT_RESOURCES; + p_IRP->IoStatus.Information = 0; + } + else if (!l_Adapter->m_InterfaceIsRunning) + { + DEBUGP (("[%s] Interface is down in IRP_MJ_WRITE\n", + NAME (l_Adapter))); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + p_IRP->IoStatus.Information = 0; + } + else if (!l_Adapter->m_tun && ((l_IrpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE)) + { + __try + { + p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length; + + DUMP_PACKET ("IRP_MJ_WRITE ETH", + (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer, + l_IrpSp->Parameters.Write.Length); + + //===================================================== + // If IPv4 packet, check whether or not packet + // was truncated. + //===================================================== +#if PACKET_TRUNCATION_CHECK + IPv4PacketSizeVerify ((unsigned char *) p_IRP->AssociatedIrp.SystemBuffer, + l_IrpSp->Parameters.Write.Length, + FALSE, + "RX", + &l_Adapter->m_RxTrunc); +#endif + + NdisMEthIndicateReceive + (l_Adapter->m_MiniportAdapterHandle, + (NDIS_HANDLE) l_Adapter, + (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer, + ETHERNET_HEADER_SIZE, + (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer + ETHERNET_HEADER_SIZE, + l_IrpSp->Parameters.Write.Length - ETHERNET_HEADER_SIZE, + l_IrpSp->Parameters.Write.Length - ETHERNET_HEADER_SIZE); + + NdisMEthIndicateReceiveComplete (l_Adapter->m_MiniportAdapterHandle); + + p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE\n", + NAME (l_Adapter))); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + p_IRP->IoStatus.Information = 0; + } + } + else if (l_Adapter->m_tun && ((l_IrpSp->Parameters.Write.Length) >= IP_HEADER_SIZE)) + { + __try + { + p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length; + + DUMP_PACKET2 ("IRP_MJ_WRITE P2P", + &l_Adapter->m_UserToTap, + (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer, + l_IrpSp->Parameters.Write.Length); + + //===================================================== + // If IPv4 packet, check whether or not packet + // was truncated. + //===================================================== +#if PACKET_TRUNCATION_CHECK + IPv4PacketSizeVerify ((unsigned char *) p_IRP->AssociatedIrp.SystemBuffer, + l_IrpSp->Parameters.Write.Length, + TRUE, + "RX", + &l_Adapter->m_RxTrunc); +#endif + + NdisMEthIndicateReceive + (l_Adapter->m_MiniportAdapterHandle, + (NDIS_HANDLE) l_Adapter, + (unsigned char *) &l_Adapter->m_UserToTap, + sizeof (l_Adapter->m_UserToTap), + (unsigned char *) p_IRP->AssociatedIrp.SystemBuffer, + l_IrpSp->Parameters.Write.Length, + l_IrpSp->Parameters.Write.Length); + + NdisMEthIndicateReceiveComplete (l_Adapter->m_MiniportAdapterHandle); + + p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + DEBUGP (("[%s] NdisMEthIndicateReceive failed in IRP_MJ_WRITE (P2P)\n", + NAME (l_Adapter))); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + p_IRP->IoStatus.Information = 0; + } + } + else + { + DEBUGP (("[%s] Bad buffer size in IRP_MJ_WRITE, len=%d\n", + NAME (l_Adapter), + l_IrpSp->Parameters.Write.Length)); + NOTE_ERROR (); + p_IRP->IoStatus.Information = 0; // ETHERNET_HEADER_SIZE; + p_IRP->IoStatus.Status = l_Status = STATUS_BUFFER_TOO_SMALL; + } + + if (l_Status == STATUS_SUCCESS) + INCREMENT_STAT (l_Adapter->m_Rx); + else + INCREMENT_STAT (l_Adapter->m_RxErr); + + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + break; + } + + //-------------------------------------------------------------- + // User mode thread has called CreateFile() on the tap device + //-------------------------------------------------------------- + case IRP_MJ_CREATE: + { + BOOLEAN succeeded = FALSE; + BOOLEAN mutex_succeeded; + + DEBUGP + (("[%s] [TAP] release [%d.%d] open request (m_TapOpens=%d)\n", + NAME (l_Adapter), TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION, l_Adapter->m_Extension.m_TapOpens)); + + ACQUIRE_MUTEX_ADAPTIVE (&l_Adapter->m_Extension.m_OpenCloseMutex, mutex_succeeded); + if (mutex_succeeded) + { + if (l_Adapter->m_Extension.m_TapIsRunning && !l_Adapter->m_Extension.m_TapOpens) + { + ResetTapAdapterState (l_Adapter); + l_Adapter->m_Extension.m_TapOpens = 1; + succeeded = TRUE; + } + + if (succeeded) + { + INCREMENT_STAT (l_Adapter->m_Extension.m_NumTapOpens); + p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS; + p_IRP->IoStatus.Information = 0; + } + else + { + DEBUGP (("[%s] TAP is presently unavailable (m_TapOpens=%d)\n", + NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens)); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + p_IRP->IoStatus.Information = 0; + } + + RELEASE_MUTEX (&l_Adapter->m_Extension.m_OpenCloseMutex); + } + else + { + DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n", + NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens)); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + p_IRP->IoStatus.Information = 0; + } + + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + break; + } + + //----------------------------------------------------------- + // User mode thread called CloseHandle() on the tap device + //----------------------------------------------------------- + case IRP_MJ_CLOSE: + { + BOOLEAN mutex_succeeded; + + DEBUGP (("[%s] [TAP] release [%d.%d] close/cleanup request\n", + NAME (l_Adapter), TAP_DRIVER_MAJOR_VERSION, + TAP_DRIVER_MINOR_VERSION)); + + ACQUIRE_MUTEX_ADAPTIVE (&l_Adapter->m_Extension.m_OpenCloseMutex, mutex_succeeded); + if (mutex_succeeded) + { + l_Adapter->m_Extension.m_TapOpens = 0; + ResetTapAdapterState (l_Adapter); + FlushQueues (&l_Adapter->m_Extension); + SetMediaStatus (l_Adapter, FALSE); + RELEASE_MUTEX (&l_Adapter->m_Extension.m_OpenCloseMutex); + } + else + { + DEBUGP (("[%s] TAP is presently locked (m_TapOpens=%d)\n", + NAME (l_Adapter), l_Adapter->m_Extension.m_TapOpens)); + NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + p_IRP->IoStatus.Information = 0; + } + + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + break; + } + + //------------------ + // Strange Request + //------------------ + default: + { + //NOTE_ERROR (); + p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL; + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + break; + } + } + + return l_Status; +} + +//============================================================= +// CompleteIRP is normally called with an adapter -> userspace +// network packet and an IRP (Pending I/O request) from userspace. +// +// The IRP will normally represent a queued overlapped read +// operation from userspace that is in a wait state. +// +// Use the ethernet packet to satisfy the IRP. +//============================================================= + +NTSTATUS +CompleteIRP (IN PIRP p_IRP, + IN TapPacketPointer p_PacketBuffer, + IN CCHAR PriorityBoost) +{ + NTSTATUS l_Status = STATUS_UNSUCCESSFUL; + + int offset; + int len; + + MYASSERT (p_IRP); + MYASSERT (p_PacketBuffer); + + IoSetCancelRoutine (p_IRP, NULL); // Disable cancel routine + + //------------------------------------------- + // While p_PacketBuffer always contains a + // full ethernet packet, including the + // ethernet header, in point-to-point mode, + // we only want to return the IPv4 + // component. + //------------------------------------------- + + if (p_PacketBuffer->m_SizeFlags & TP_TUN) + { + offset = ETHERNET_HEADER_SIZE; + len = (int) (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE; + } + else + { + offset = 0; + len = (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK); + } + + if (len < 0 || (int) p_IRP->IoStatus.Information < len) + { + p_IRP->IoStatus.Information = 0; + p_IRP->IoStatus.Status = STATUS_BUFFER_OVERFLOW; + NOTE_ERROR (); + } + else + { + p_IRP->IoStatus.Information = len; + p_IRP->IoStatus.Status = l_Status = STATUS_SUCCESS; + + __try + { + NdisMoveMemory (p_IRP->AssociatedIrp.SystemBuffer, + p_PacketBuffer->m_Data + offset, + len); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + NOTE_ERROR (); + p_IRP->IoStatus.Status = STATUS_UNSUCCESSFUL; + p_IRP->IoStatus.Information = 0; + } + } + + __try + { + NdisFreeMemory (p_PacketBuffer, + TAP_PACKET_SIZE (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK), + 0); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } + + if (l_Status == STATUS_SUCCESS) + { + IoCompleteRequest (p_IRP, PriorityBoost); + } + else + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); + + return l_Status; +} + +//============================================== +// IRPs get cancelled for a number of reasons. +// +// The TAP device could be closed by userspace +// when there are still pending read operations. +// +// The user could disable the TAP adapter in the +// network connections control panel, while the +// device is still open by a process. +//============================================== +VOID +CancelIRPCallback (IN PDEVICE_OBJECT p_DeviceObject, + IN PIRP p_IRP) +{ + TapAdapterPointer l_Adapter = LookupAdapterInInstanceList (p_DeviceObject); + CancelIRP (l_Adapter ? &l_Adapter->m_Extension : NULL, p_IRP, TRUE); +} + +VOID +CancelIRP (TapExtensionPointer p_Extension, + IN PIRP p_IRP, + BOOLEAN callback) +{ + BOOLEAN exists = FALSE; + + MYASSERT (p_IRP); + + if (p_Extension) + { + NdisAcquireSpinLock (&p_Extension->m_QueueLock); + exists = (QueueExtract (p_Extension->m_IrpQueue, p_IRP) == p_IRP); + NdisReleaseSpinLock (&p_Extension->m_QueueLock); + } + else + exists = TRUE; + + if (exists) + { + IoSetCancelRoutine (p_IRP, NULL); + p_IRP->IoStatus.Status = STATUS_CANCELLED; + p_IRP->IoStatus.Information = 0; + } + + if (callback) + IoReleaseCancelSpinLock (p_IRP->CancelIrql); + + if (exists) + IoCompleteRequest (p_IRP, IO_NO_INCREMENT); +} + +//=========================================== +// Exhaust packet, IRP, and injection queues. +//=========================================== +VOID +FlushQueues (TapExtensionPointer p_Extension) +{ + PIRP l_IRP; + TapPacketPointer l_PacketBuffer; + InjectPacketPointer l_InjectBuffer; + int n_IRP=0, n_Packet=0, n_Inject=0; + + MYASSERT (p_Extension); + MYASSERT (p_Extension->m_TapDevice); + + while (TRUE) + { + NdisAcquireSpinLock (&p_Extension->m_QueueLock); + l_IRP = QueuePop (p_Extension->m_IrpQueue); + NdisReleaseSpinLock (&p_Extension->m_QueueLock); + if (l_IRP) + { + ++n_IRP; + CancelIRP (NULL, l_IRP, FALSE); + } + else + break; + } + + while (TRUE) + { + NdisAcquireSpinLock (&p_Extension->m_QueueLock); + l_PacketBuffer = QueuePop (p_Extension->m_PacketQueue); + NdisReleaseSpinLock (&p_Extension->m_QueueLock); + if (l_PacketBuffer) + { + ++n_Packet; + MemFree (l_PacketBuffer, TAP_PACKET_SIZE (l_PacketBuffer->m_SizeFlags & TP_SIZE_MASK)); + } + else + break; + } + + while (TRUE) + { + NdisAcquireSpinLock (&p_Extension->m_InjectLock); + l_InjectBuffer = QueuePop (p_Extension->m_InjectQueue); + NdisReleaseSpinLock (&p_Extension->m_InjectLock); + if (l_InjectBuffer) + { + ++n_Inject; + INJECT_PACKET_FREE(l_InjectBuffer); + } + else + break; + } + + DEBUGP (( + "[%s] [TAP] FlushQueues n_IRP=[%d,%d,%d] n_Packet=[%d,%d,%d] n_Inject=[%d,%d,%d]\n", + p_Extension->m_TapName, + n_IRP, + p_Extension->m_IrpQueue->max_size, + IRP_QUEUE_SIZE, + n_Packet, + p_Extension->m_PacketQueue->max_size, + PACKET_QUEUE_SIZE, + n_Inject, + p_Extension->m_InjectQueue->max_size, + INJECT_QUEUE_SIZE + )); +} + +//=================================================== +// Tell Windows whether the TAP device should be +// considered "connected" or "disconnected". +//=================================================== +VOID +SetMediaStatus (TapAdapterPointer p_Adapter, BOOLEAN state) +{ + if (p_Adapter->m_MediaState != state && !p_Adapter->m_MediaStateAlwaysConnected) + { + if (state) + NdisMIndicateStatus (p_Adapter->m_MiniportAdapterHandle, + NDIS_STATUS_MEDIA_CONNECT, NULL, 0); + else + NdisMIndicateStatus (p_Adapter->m_MiniportAdapterHandle, + NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0); + + NdisMIndicateStatusComplete (p_Adapter->m_MiniportAdapterHandle); + p_Adapter->m_MediaState = state; + } +} + + +//====================================================== +// If DHCP mode is used together with tun +// mode, consider the fact that the P2P remote subnet +// might enclose the DHCP masq server address. +//====================================================== +VOID +CheckIfDhcpAndTunMode (TapAdapterPointer p_Adapter) +{ + if (p_Adapter->m_tun && p_Adapter->m_dhcp_enabled) + { + if ((p_Adapter->m_dhcp_server_ip & p_Adapter->m_remoteNetmask) == p_Adapter->m_remoteNetwork) + { + COPY_MAC (p_Adapter->m_dhcp_server_mac, p_Adapter->m_TapToUser.dest); + p_Adapter->m_dhcp_server_arp = FALSE; + } + } +} + +//=================================================== +// Generate an ARP reply message for specific kinds +// ARP queries. +//=================================================== +BOOLEAN +ProcessARP (TapAdapterPointer p_Adapter, + const PARP_PACKET src, + const IPADDR adapter_ip, + const IPADDR ip_network, + const IPADDR ip_netmask, + const MACADDR mac) +{ + //----------------------------------------------- + // Is this the kind of packet we are looking for? + //----------------------------------------------- + if (src->m_Proto == htons (ETH_P_ARP) + && MAC_EQUAL (src->m_MAC_Source, p_Adapter->m_MAC) + && MAC_EQUAL (src->m_ARP_MAC_Source, p_Adapter->m_MAC) + && MAC_EQUAL (src->m_MAC_Destination, p_Adapter->m_MAC_Broadcast) + && src->m_ARP_Operation == htons (ARP_REQUEST) + && src->m_MAC_AddressType == htons (MAC_ADDR_TYPE) + && src->m_MAC_AddressSize == sizeof (MACADDR) + && src->m_PROTO_AddressType == htons (ETH_P_IP) + && src->m_PROTO_AddressSize == sizeof (IPADDR) + && src->m_ARP_IP_Source == adapter_ip + && (src->m_ARP_IP_Destination & ip_netmask) == ip_network + && src->m_ARP_IP_Destination != adapter_ip) + { + ARP_PACKET *arp = (ARP_PACKET *) MemAlloc (sizeof (ARP_PACKET), TRUE); + if (arp) + { + //---------------------------------------------- + // Initialize ARP reply fields + //---------------------------------------------- + arp->m_Proto = htons (ETH_P_ARP); + arp->m_MAC_AddressType = htons (MAC_ADDR_TYPE); + arp->m_PROTO_AddressType = htons (ETH_P_IP); + arp->m_MAC_AddressSize = sizeof (MACADDR); + arp->m_PROTO_AddressSize = sizeof (IPADDR); + arp->m_ARP_Operation = htons (ARP_REPLY); + + //---------------------------------------------- + // ARP addresses + //---------------------------------------------- + COPY_MAC (arp->m_MAC_Source, mac); + COPY_MAC (arp->m_MAC_Destination, p_Adapter->m_MAC); + COPY_MAC (arp->m_ARP_MAC_Source, mac); + COPY_MAC (arp->m_ARP_MAC_Destination, p_Adapter->m_MAC); + arp->m_ARP_IP_Source = src->m_ARP_IP_Destination; + arp->m_ARP_IP_Destination = adapter_ip; + + DUMP_PACKET ("ProcessARP", + (unsigned char *) arp, + sizeof (ARP_PACKET)); + + InjectPacketDeferred (p_Adapter, (UCHAR *) arp, sizeof (ARP_PACKET)); + + MemFree (arp, sizeof (ARP_PACKET)); + } + + return TRUE; + } + else + return FALSE; +} + +//=============================================================== +// Used in cases where internally generated packets such as +// ARP or DHCP replies must be returned to the kernel, to be +// seen as an incoming packet "arriving" on the interface. +//=============================================================== + +// Defer packet injection till IRQL < DISPATCH_LEVEL +VOID +InjectPacketDeferred (TapAdapterPointer p_Adapter, + UCHAR *packet, + const unsigned int len) +{ + InjectPacketPointer l_InjectBuffer; + PVOID result; + + if (NdisAllocateMemoryWithTag (&l_InjectBuffer, + INJECT_PACKET_SIZE (len), + 'IPAT') == NDIS_STATUS_SUCCESS) + { + l_InjectBuffer->m_Size = len; + NdisMoveMemory (l_InjectBuffer->m_Data, packet, len); + NdisAcquireSpinLock (&p_Adapter->m_Extension.m_InjectLock); + result = QueuePush (p_Adapter->m_Extension.m_InjectQueue, l_InjectBuffer); + NdisReleaseSpinLock (&p_Adapter->m_Extension.m_InjectLock); + if (result) + KeInsertQueueDpc (&p_Adapter->m_Extension.m_InjectDpc, p_Adapter, NULL); + else + INJECT_PACKET_FREE(l_InjectBuffer); + } +} + +// Handle the injection of previously deferred packets +VOID +InjectPacketDpc(KDPC *Dpc, + PVOID DeferredContext, + PVOID SystemArgument1, + PVOID SystemArgument2) +{ + InjectPacketPointer l_InjectBuffer; + TapAdapterPointer l_Adapter = (TapAdapterPointer)SystemArgument1; + while (TRUE) + { + NdisAcquireSpinLock (&l_Adapter->m_Extension.m_InjectLock); + l_InjectBuffer = QueuePop (l_Adapter->m_Extension.m_InjectQueue); + NdisReleaseSpinLock (&l_Adapter->m_Extension.m_InjectLock); + if (l_InjectBuffer) + { + InjectPacketNow(l_Adapter, l_InjectBuffer->m_Data, l_InjectBuffer->m_Size); + INJECT_PACKET_FREE(l_InjectBuffer); + } + else + break; + } +} + +// Do packet injection now +VOID +InjectPacketNow (TapAdapterPointer p_Adapter, + UCHAR *packet, + const unsigned int len) +{ + MYASSERT (len >= ETHERNET_HEADER_SIZE); + + __try + { + //------------------------------------------------------------ + // NdisMEthIndicateReceive and NdisMEthIndicateReceiveComplete + // could potentially be called reentrantly both here and in + // TapDeviceHook/IRP_MJ_WRITE. + // + // The DDK docs imply that this is okay. + // + // Note that reentrant behavior could only occur if the + // non-deferred version of InjectPacket is used. + //------------------------------------------------------------ + NdisMEthIndicateReceive + (p_Adapter->m_MiniportAdapterHandle, + (NDIS_HANDLE) p_Adapter, + packet, + ETHERNET_HEADER_SIZE, + packet + ETHERNET_HEADER_SIZE, + len - ETHERNET_HEADER_SIZE, + len - ETHERNET_HEADER_SIZE); + + NdisMEthIndicateReceiveComplete (p_Adapter->m_MiniportAdapterHandle); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + DEBUGP (("[%s] NdisMEthIndicateReceive failed in InjectPacketNow\n", + NAME (p_Adapter))); + NOTE_ERROR (); + } +} + +//=================================================================== +// Go back to default TAP mode from Point-To-Point mode. +// Also reset (i.e. disable) DHCP Masq mode. +//=================================================================== +VOID ResetTapAdapterState (TapAdapterPointer p_Adapter) +{ + // Point-To-Point + p_Adapter->m_tun = FALSE; + p_Adapter->m_localIP = 0; + p_Adapter->m_remoteNetwork = 0; + p_Adapter->m_remoteNetmask = 0; + NdisZeroMemory (&p_Adapter->m_TapToUser, sizeof (p_Adapter->m_TapToUser)); + NdisZeroMemory (&p_Adapter->m_UserToTap, sizeof (p_Adapter->m_UserToTap)); + + // DHCP Masq + p_Adapter->m_dhcp_enabled = FALSE; + p_Adapter->m_dhcp_server_arp = FALSE; + p_Adapter->m_dhcp_user_supplied_options_buffer_len = 0; + p_Adapter->m_dhcp_addr = 0; + p_Adapter->m_dhcp_netmask = 0; + p_Adapter->m_dhcp_server_ip = 0; + p_Adapter->m_dhcp_lease_time = 0; + p_Adapter->m_dhcp_received_discover = FALSE; + p_Adapter->m_dhcp_bad_requests = 0; + NdisZeroMemory (p_Adapter->m_dhcp_server_mac, sizeof (MACADDR)); +} + +#if ENABLE_NONADMIN + +//=================================================================== +// Set TAP device handle to be accessible without admin privileges. +//=================================================================== +VOID AllowNonAdmin (TapExtensionPointer p_Extension) +{ + NTSTATUS stat; + SECURITY_DESCRIPTOR sd; + OBJECT_ATTRIBUTES oa; + IO_STATUS_BLOCK isb; + HANDLE hand = NULL; + + NdisZeroMemory (&sd, sizeof (sd)); + NdisZeroMemory (&oa, sizeof (oa)); + NdisZeroMemory (&isb, sizeof (isb)); + + if (!p_Extension->m_CreatedUnicodeLinkName) + { + DEBUGP (("[TAP] AllowNonAdmin: UnicodeLinkName is uninitialized\n")); + NOTE_ERROR (); + return; + } + + stat = RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION); + if (stat != STATUS_SUCCESS) + { + DEBUGP (("[TAP] AllowNonAdmin: RtlCreateSecurityDescriptor failed\n")); + NOTE_ERROR (); + return; + } + + InitializeObjectAttributes ( + &oa, + &p_Extension->m_UnicodeLinkName, + OBJ_KERNEL_HANDLE, + NULL, + NULL + ); + + stat = ZwOpenFile ( + &hand, + WRITE_DAC, + &oa, + &isb, + 0, + 0 + ); + if (stat != STATUS_SUCCESS) + { + DEBUGP (("[TAP] AllowNonAdmin: ZwOpenFile failed, status=0x%08x\n", (unsigned int)stat)); + NOTE_ERROR (); + return; + } + + stat = ZwSetSecurityObject (hand, DACL_SECURITY_INFORMATION, &sd); + if (stat != STATUS_SUCCESS) + { + DEBUGP (("[TAP] AllowNonAdmin: ZwSetSecurityObject failed\n")); + NOTE_ERROR (); + return; + } + + stat = ZwClose (hand); + if (stat != STATUS_SUCCESS) + { + DEBUGP (("[TAP] AllowNonAdmin: ZwClose failed\n")); + NOTE_ERROR (); + return; + } + + DEBUGP (("[TAP] AllowNonAdmin: SUCCEEDED\n")); +} + +#endif + +#if PACKET_TRUNCATION_CHECK + +VOID +IPv4PacketSizeVerify (const UCHAR *data, ULONG length, BOOLEAN tun, const char *prefix, LONG *counter) +{ + const IPHDR *ip; + int len = length; + + if (tun) + { + ip = (IPHDR *) data; + } + else + { + if (length >= sizeof (ETH_HEADER)) + { + const ETH_HEADER *eth = (ETH_HEADER *) data; + + if (eth->proto != htons (ETH_P_IP)) + return; + + ip = (IPHDR *) (data + sizeof (ETH_HEADER)); + len -= sizeof (ETH_HEADER); + } + else + return; + } + + if (len >= sizeof (IPHDR)) + { + const int totlen = ntohs (ip->tot_len); + + DEBUGP (("[TAP] IPv4PacketSizeVerify %s len=%d totlen=%d\n", prefix, len, totlen)); + + if (len != totlen) + ++(*counter); + } +} + +#endif + +//====================================================================== +// End of Source +//====================================================================== diff -Nru openvpn-2.1~rc19/tap-win32/tmp/types.h openvpn-2.1.1/tap-win32/tmp/types.h --- openvpn-2.1~rc19/tap-win32/tmp/types.h 1970-01-01 01:00:00.000000000 +0100 +++ openvpn-2.1.1/tap-win32/tmp/types.h 2009-12-11 06:00:45.000000000 +0100 @@ -0,0 +1,181 @@ +/* + * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap + * device functionality on Windows. + * + * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. + * + * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., + * and is released under the GPL version 2 (see below), however due + * to the extra costs of supporting Windows Vista, OpenVPN Solutions + * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 + * license for versions 9.1 and higher prior to the official release of + * OpenVPN 2.1. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TAP_TYPES_DEFINED +#define TAP_TYPES_DEFINED + +typedef struct _Queue +{ + ULONG base; + ULONG size; + ULONG capacity; + ULONG max_size; + PVOID data[]; +} Queue; + +typedef struct _TapAdapter; +typedef struct _TapPacket; + +typedef union _TapAdapterQuery +{ + NDIS_HARDWARE_STATUS m_HardwareStatus; + NDIS_MEDIUM m_Medium; + NDIS_PHYSICAL_MEDIUM m_PhysicalMedium; + UCHAR m_MacAddress [6]; + UCHAR m_Buffer [256]; + ULONG m_Long; + USHORT m_Short; + UCHAR m_Byte; +} +TapAdapterQuery, *TapAdapterQueryPointer; + +typedef struct _TapExtension +{ + // TAP device object and packet queues + Queue *m_PacketQueue, *m_IrpQueue; + PDEVICE_OBJECT m_TapDevice; + NDIS_HANDLE m_TapDeviceHandle; + ULONG m_TapOpens; + + // Used to lock packet queues + NDIS_SPIN_LOCK m_QueueLock; + BOOLEAN m_AllocatedSpinlocks; + + // Used to bracket open/close + // state changes. + MUTEX m_OpenCloseMutex; + + // True if device has been permanently halted + BOOLEAN m_Halt; + + // TAP device name + unsigned char *m_TapName; + UNICODE_STRING m_UnicodeLinkName; + BOOLEAN m_CreatedUnicodeLinkName; + + // Used for device status ioctl only + const char *m_LastErrorFilename; + int m_LastErrorLineNumber; + LONG m_NumTapOpens; + + // Flags + BOOLEAN m_TapIsRunning; + BOOLEAN m_CalledTapDeviceFreeResources; + + // DPC queue for deferred packet injection + BOOLEAN m_InjectDpcInitialized; + KDPC m_InjectDpc; + NDIS_SPIN_LOCK m_InjectLock; + Queue *m_InjectQueue; +} +TapExtension, *TapExtensionPointer; + +typedef struct _TapPacket + { +# define TAP_PACKET_SIZE(data_size) (sizeof (TapPacket) + (data_size)) +# define TP_TUN 0x80000000 +# define TP_SIZE_MASK (~TP_TUN) + ULONG m_SizeFlags; + UCHAR m_Data []; // m_Data must be the last struct member + } +TapPacket, *TapPacketPointer; + +typedef struct _InjectPacket + { +# define INJECT_PACKET_SIZE(data_size) (sizeof (InjectPacket) + (data_size)) +# define INJECT_PACKET_FREE(ib) NdisFreeMemory ((ib), INJECT_PACKET_SIZE ((ib)->m_Size), 0) + ULONG m_Size; + UCHAR m_Data []; // m_Data must be the last struct member + } +InjectPacket, *InjectPacketPointer; + +typedef struct _TapAdapter +{ +# define NAME(a) ((a)->m_NameAnsi.Buffer) + ANSI_STRING m_NameAnsi; + MACADDR m_MAC; + BOOLEAN m_InterfaceIsRunning; + NDIS_HANDLE m_MiniportAdapterHandle; + LONG m_Rx, m_Tx, m_RxErr, m_TxErr; +#if PACKET_TRUNCATION_CHECK + LONG m_RxTrunc, m_TxTrunc; +#endif + NDIS_MEDIUM m_Medium; + ULONG m_Lookahead; + ULONG m_MTU; + + // TRUE if adapter should always be + // "connected" even when device node + // is not open by a userspace process. + BOOLEAN m_MediaStateAlwaysConnected; + + // TRUE if device is "connected" + BOOLEAN m_MediaState; + + // Adapter power state + char m_DeviceState; + + // Info for point-to-point mode + BOOLEAN m_tun; + IPADDR m_localIP; + IPADDR m_remoteNetwork; + IPADDR m_remoteNetmask; + ETH_HEADER m_TapToUser; + ETH_HEADER m_UserToTap; + MACADDR m_MAC_Broadcast; + + // Used for DHCP server masquerade + BOOLEAN m_dhcp_enabled; + IPADDR m_dhcp_addr; + ULONG m_dhcp_netmask; + IPADDR m_dhcp_server_ip; + BOOLEAN m_dhcp_server_arp; + MACADDR m_dhcp_server_mac; + ULONG m_dhcp_lease_time; + UCHAR m_dhcp_user_supplied_options_buffer[DHCP_USER_SUPPLIED_OPTIONS_BUFFER_SIZE]; + ULONG m_dhcp_user_supplied_options_buffer_len; + BOOLEAN m_dhcp_received_discover; + ULONG m_dhcp_bad_requests; + + // Help to tear down the adapter by keeping + // some state information on allocated + // resources. + BOOLEAN m_CalledAdapterFreeResources; + BOOLEAN m_RegisteredAdapterShutdownHandler; + + // Multicast list info + NDIS_SPIN_LOCK m_MCLock; + BOOLEAN m_MCLockAllocated; + ULONG m_MCListSize; + MC_LIST m_MCList; + + // Information on the TAP device + TapExtension m_Extension; +} TapAdapter, *TapAdapterPointer; + +#endif diff -Nru openvpn-2.1~rc19/tap-win32/types.h openvpn-2.1.1/tap-win32/types.h --- openvpn-2.1~rc19/tap-win32/types.h 2009-06-22 23:01:42.000000000 +0200 +++ openvpn-2.1.1/tap-win32/types.h 2009-12-11 06:05:15.000000000 +0100 @@ -5,11 +5,7 @@ * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson. * * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc., - * and is released under the GPL version 2 (see below), however due - * to the extra costs of supporting Windows Vista, OpenVPN Solutions - * LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64 - * license for versions 9.1 and higher prior to the official release of - * OpenVPN 2.1. + * and is released under the GPL version 2 (see below). * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff -Nru openvpn-2.1~rc19/tun.c openvpn-2.1.1/tun.c --- openvpn-2.1~rc19/tun.c 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tun.c 2009-11-20 14:09:14.000000000 +0100 @@ -863,11 +863,10 @@ else { if (tt->topology == TOP_SUBNET) argv_printf (&argv, - "%s %s %s %s netmask %s mtu %d up", + "%s %s %s netmask %s mtu %d up", IFCONFIG_PATH, actual, ifconfig_local, - ifconfig_local, ifconfig_remote_netmask, tun_mtu ); @@ -1745,14 +1744,19 @@ { open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); - if (tt->fd >= 0) + if (tt->fd >= 0 && tt->type == DEV_TYPE_TUN) { int i = 0; - /* Disable extended modes */ - ioctl (tt->fd, TUNSLMODE, &i); + i = tt->topology == TOP_SUBNET ? IFF_BROADCAST : IFF_POINTOPOINT; + i |= IFF_MULTICAST; + if (ioctl (tt->fd, TUNSIFMODE, &i) < 0) { + msg (M_WARN | M_ERRNO, "ioctl(TUNSIFMODE): %s", strerror(errno)); + } i = 1; - ioctl (tt->fd, TUNSIFHEAD, &i); + if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0) { + msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); + } } } @@ -3288,59 +3292,73 @@ /* * DHCP release/renewal */ - bool -dhcp_release (const struct tuntap *tt) +dhcp_release_by_adapter_index(const DWORD adapter_index) { struct gc_arena gc = gc_new (); bool ret = false; - if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0) + const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc); + + if (inter) { - const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (tt->adapter_index, &gc); - if (inter) + DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter); + if (status == NO_ERROR) { - DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter); - if (status == NO_ERROR) - { - msg (D_TUNTAP_INFO, "TAP: DHCP address released"); - ret = true; - } - else - msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)", - strerror_win32 (status, &gc), - (unsigned int)status); + msg (D_TUNTAP_INFO, "TAP: DHCP address released"); + ret = true; } + else + msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Win32 adapter failed: %s (code=%u)", + strerror_win32 (status, &gc), + (unsigned int)status); } + gc_free (&gc); return ret; } +static bool +dhcp_release (const struct tuntap *tt) +{ + if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0) + return dhcp_release_by_adapter_index (tt->adapter_index); + else + return false; +} + bool -dhcp_renew (const struct tuntap *tt) +dhcp_renew_by_adapter_index (const DWORD adapter_index) { struct gc_arena gc = gc_new (); bool ret = false; - if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0) + const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc); + + if (inter) { - const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (tt->adapter_index, &gc); - if (inter) + DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter); + if (status == NO_ERROR) { - DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter); - if (status == NO_ERROR) - { - msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded"); - ret = true; - } - else - msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)", - strerror_win32 (status, &gc), - (unsigned int)status); + msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded"); + ret = true; } + else + msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Win32 adapter: %s (code=%u)", + strerror_win32 (status, &gc), + (unsigned int)status); } gc_free (&gc); return ret; } +static bool +dhcp_renew (const struct tuntap *tt) +{ + if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != ~0) + return dhcp_renew_by_adapter_index (tt->adapter_index); + else + return false; +} + /* * netsh functions */ @@ -3784,6 +3802,28 @@ return !error; } +static void +fork_dhcp_action (struct tuntap *tt) +{ + if (tt->options.dhcp_pre_release || tt->options.dhcp_renew) + { + struct gc_arena gc = gc_new (); + struct buffer cmd = alloc_buf_gc (256, &gc); + const int verb = 3; + const int pre_sleep = 1; + + buf_printf (&cmd, "openvpn --verb %d --tap-sleep %d", verb, pre_sleep); + if (tt->options.dhcp_pre_release) + buf_printf (&cmd, " --dhcp-pre-release"); + if (tt->options.dhcp_renew) + buf_printf (&cmd, " --dhcp-renew"); + buf_printf (&cmd, " --dhcp-rr %u", (unsigned int)tt->adapter_index); + + fork_to_self (BSTR (&cmd)); + gc_free (&gc); + } +} + void open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) { @@ -4148,6 +4188,8 @@ if (tt->options.dhcp_renew) dhcp_renew (tt); } + else + fork_dhcp_action (tt); if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_IPAPI) { diff -Nru openvpn-2.1~rc19/tun.h openvpn-2.1.1/tun.h --- openvpn-2.1~rc19/tun.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/tun.h 2009-11-20 14:09:14.000000000 +0100 @@ -332,8 +332,8 @@ const char *tap_win32_getinfo (const struct tuntap *tt, struct gc_arena *gc); void tun_show_debug (struct tuntap *tt); -bool dhcp_release (const struct tuntap *tt); -bool dhcp_renew (const struct tuntap *tt); +bool dhcp_release_by_adapter_index(const DWORD adapter_index); +bool dhcp_renew_by_adapter_index (const DWORD adapter_index); void tun_standby_init (struct tuntap *tt); bool tun_standby (struct tuntap *tt); diff -Nru openvpn-2.1~rc19/version.m4 openvpn-2.1.1/version.m4 --- openvpn-2.1~rc19/version.m4 2009-07-16 11:13:42.000000000 +0200 +++ openvpn-2.1.1/version.m4 2009-12-11 22:47:19.000000000 +0100 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1_rc19]) +define(PRODUCT_VERSION,[2.1.1]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) diff -Nru openvpn-2.1~rc19/win32.c openvpn-2.1.1/win32.c --- openvpn-2.1~rc19/win32.c 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/win32.c 2009-11-20 14:09:14.000000000 +0100 @@ -1016,6 +1016,51 @@ return ret; } +/* + * call ourself in another process + */ +void +fork_to_self (const char *cmdline) +{ + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + char self_exe[256]; + char *cl = string_alloc (cmdline, NULL); + DWORD status; + + CLEAR (start_info); + CLEAR (proc_info); + CLEAR (self_exe); + + status = GetModuleFileName (NULL, self_exe, sizeof(self_exe)); + if (status == 0 || status == sizeof(self_exe)) + { + msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: cannot get module name via GetModuleFileName"); + goto done; + } + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + start_info.wShowWindow = SW_HIDE; + start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE); + + if (CreateProcess (self_exe, cl, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info)) + { + CloseHandle (proc_info.hThread); + CloseHandle (proc_info.hProcess); + } + else + { + msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: %s", cmdline); + } + + done: + free (cl); +} + char * get_win_sys_path (void) { diff -Nru openvpn-2.1~rc19/win32.h openvpn-2.1.1/win32.h --- openvpn-2.1~rc19/win32.h 2009-05-30 23:34:13.000000000 +0200 +++ openvpn-2.1.1/win32.h 2009-11-20 14:09:14.000000000 +0100 @@ -265,5 +265,8 @@ void set_win_sys_path_via_env (struct env_set *es); char *get_win_sys_path (void); +/* call self in a subprocess */ +void fork_to_self (const char *cmdline); + #endif #endif