summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2005-09-26 07:40:02 +0000
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2005-09-26 07:40:02 +0000
commit3c7f2f553be4b3ba9412c1b3f64a258c469d78f4 (patch)
tree9d58836b0f1eade372de7ce15c41d6555d55ef21
parent6fbf66fad3367b24fd6743bcd50254902fd9c8d5 (diff)
downloadopenvpn-3c7f2f553be4b3ba9412c1b3f64a258c469d78f4.tar.gz
openvpn-3c7f2f553be4b3ba9412c1b3f64a258c469d78f4.tar.xz
openvpn-3c7f2f553be4b3ba9412c1b3f64a258c469d78f4.zip
version 2.1_beta1
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@581 e7ae566f-a301-0410-adde-c780ea21d3b5
-rw-r--r--ChangeLog43
-rw-r--r--config-win32.h.in3
-rw-r--r--configure.ac3
-rw-r--r--easy-rsa/1.0/README161
-rwxr-xr-xeasy-rsa/1.0/build-ca13
-rwxr-xr-xeasy-rsa/1.0/build-dh12
-rwxr-xr-xeasy-rsa/1.0/build-inter19
-rwxr-xr-xeasy-rsa/1.0/build-key20
-rwxr-xr-xeasy-rsa/1.0/build-key-pass20
-rwxr-xr-xeasy-rsa/1.0/build-key-pkcs1221
-rwxr-xr-xeasy-rsa/1.0/build-key-server22
-rwxr-xr-xeasy-rsa/1.0/build-req18
-rwxr-xr-xeasy-rsa/1.0/build-req-pass18
-rwxr-xr-xeasy-rsa/1.0/clean-all19
-rw-r--r--easy-rsa/1.0/list-crl18
-rw-r--r--easy-rsa/1.0/make-crl (renamed from easy-rsa/make-crl)0
-rw-r--r--easy-rsa/1.0/openssl.cnf255
-rw-r--r--easy-rsa/1.0/revoke-crt (renamed from easy-rsa/revoke-crt)0
-rwxr-xr-xeasy-rsa/1.0/revoke-full29
-rwxr-xr-xeasy-rsa/1.0/sign-req18
-rw-r--r--easy-rsa/1.0/vars49
-rw-r--r--easy-rsa/README193
-rwxr-xr-xeasy-rsa/build-ca11
-rwxr-xr-xeasy-rsa/build-dh9
-rwxr-xr-xeasy-rsa/build-inter18
-rwxr-xr-xeasy-rsa/build-key19
-rwxr-xr-xeasy-rsa/build-key-pass19
-rwxr-xr-xeasy-rsa/build-key-pkcs1219
-rwxr-xr-xeasy-rsa/build-key-server18
-rwxr-xr-xeasy-rsa/build-req17
-rwxr-xr-xeasy-rsa/build-req-pass17
-rwxr-xr-xeasy-rsa/clean-all21
-rwxr-xr-xeasy-rsa/inherit-inter39
-rwxr-xr-x[-rw-r--r--]easy-rsa/list-crl19
-rwxr-xr-x[-rw-r--r--]easy-rsa/openssl.cnf8
-rwxr-xr-xeasy-rsa/pkitool233
-rwxr-xr-xeasy-rsa/revoke-full44
-rwxr-xr-xeasy-rsa/sign-req17
-rwxr-xr-x[-rw-r--r--]easy-rsa/vars22
-rw-r--r--errlevel.h2
-rw-r--r--forward.c41
-rw-r--r--forward.h1
-rw-r--r--helper.c96
-rw-r--r--init.c132
-rw-r--r--init.h6
-rwxr-xr-xinstall-win32/openvpn.nsi.in2
-rw-r--r--manage.c20
-rw-r--r--manage.h5
-rw-r--r--misc.c2
-rw-r--r--multi.c197
-rw-r--r--openvpn-plugin.h129
-rw-r--r--openvpn.8110
-rw-r--r--openvpn.c6
-rw-r--r--openvpn.h14
-rw-r--r--options.c195
-rw-r--r--options.h32
-rw-r--r--otime.h2
-rw-r--r--plugin.c341
-rw-r--r--plugin.h87
-rw-r--r--proto.c54
-rw-r--r--proto.h17
-rw-r--r--push.c2
-rw-r--r--route.c253
-rw-r--r--route.h24
-rwxr-xr-xsample-scripts/ucn.pl11
-rwxr-xr-xservice-win32/mkpatch4
-rwxr-xr-xservice-win32/service.patch80
-rw-r--r--sig.c6
-rw-r--r--socket.c2
-rw-r--r--ssl.c4
-rwxr-xr-xtap-win32/SOURCES2
-rwxr-xr-xtap-win32/common.h7
-rwxr-xr-xtap-win32/i386/OemWin2k.inf43
-rwxr-xr-xtap-win32/prototypes.h36
-rwxr-xr-xtap-win32/tapdrvr.c331
-rwxr-xr-xtap-win32/types.h12
-rw-r--r--tun.c262
-rw-r--r--tun.h12
78 files changed, 3418 insertions, 668 deletions
diff --git a/ChangeLog b/ChangeLog
index f70ed1d..5b21470 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,49 @@ Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
$Id$
+2005.09.26 -- Version 2.1-beta1
+
+* Merged with 2.0.3-rc1
+* easy-rsa/2.0 moved to easy-rsa
+* old easy-rsa moved to easy-rsa/1.0
+
+2005.09.23 -- Version 2.0.2-TO4
+
+* Added feature to TAP-Win32 adapter to allow it to be
+ opened from non-administrator mode. This feature
+ is enabled by default, and can be enabled/disabled
+ in the adapter advanced properties dialog.
+* Added --allow-nonadmin standalone option for Windows to
+ set TAP adapter to allow non-admin access. This
+ is a user-mode version of the code, and duplicates
+ the same feature as the above entry.
+* Added fix that attempts to solve corner case of tunnel not
+ forwarding packets when system clock is reset to an earlier time.
+* Added --redirect-gateway bypass-dns option. (Developers:
+ To add bypass-dhcp or bypass-dns support to other OSes,
+ add a get_bypass_addresses function to route.c for
+ your OS.)
+* Added OPENVPN_PLUGIN_CLIENT_CONNECT_V2 plugin callback, which
+ allows a client-connect plugin to return configuration text
+ in memory, rather than via a file.
+* Fixed a bug where --mode server --proto tcp-server --cipher none
+ operation could cause tunnel packet truncation.
+* openvpn --version will show [LZO1] or [LZO2], depending on
+ version that was linked.
+
+2005.09.07 -- Version 2.0.2-TO1
+
+* Added --topology directive. See man page.
+* Added --redirect-gateway bypass-dhcp option to add a route
+ allowing DHCP packets to bypass the tunnel, when the
+ DHCP server is non-local. Currently only implemented
+ on Windows clients.
+* Modified OpenVPN Service on Windows to declare the DHCP
+ client service as a dependency.
+* Extended the plugin interface to allow plugins to declare
+ per-client constructor and destructor functions, to make
+ it simpler for plugins to maintain per-client state.
+
2005.09.25 -- Version 2.0.3-rc1
* openvpn_plugin_abort_v1 function wasn't being properly
diff --git a/config-win32.h.in b/config-win32.h.in
index 1a3ce9f..e58029c 100644
--- a/config-win32.h.in
+++ b/config-win32.h.in
@@ -260,6 +260,9 @@ typedef unsigned long in_addr_t;
/* Use LZO compression library */
#define USE_LZO 1
+/* LZO version number */
+#define LZO_VERSION_NUM "1"
+
/* Use OpenSSL SSL library */
#define USE_SSL 1
diff --git a/configure.ac b/configure.ac
index 2b09280..8df15eb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -25,7 +25,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.50)
-AC_INIT([OpenVPN], [2.0.3_rc1], [openvpn-users@lists.sourceforge.net], [openvpn])
+AC_INIT([OpenVPN], [2.1_beta1], [openvpn-users@lists.sourceforge.net], [openvpn])
AM_CONFIG_HEADER(config.h)
AC_CONFIG_SRCDIR(syshead.h)
@@ -489,6 +489,7 @@ if test "$LZO" = "yes"; then
[
OPENVPN_ADD_LIBS(-l$i)
AC_DEFINE(USE_LZO, 1, [Use LZO compression library])
+ AC_DEFINE_UNQUOTED(LZO_VERSION_NUM, "$LZO_H", [LZO version number])
havelzolib=1
]
)
diff --git a/easy-rsa/1.0/README b/easy-rsa/1.0/README
new file mode 100644
index 0000000..fd424ef
--- /dev/null
+++ b/easy-rsa/1.0/README
@@ -0,0 +1,161 @@
+This is a small RSA key management package,
+based on the openssl command line tool, that
+can be found in the easy-rsa subdirectory
+of the OpenVPN distribution.
+
+These are reference notes. For step
+by step instructions, see the HOWTO:
+
+http://openvpn.net/howto.html
+
+INSTALL
+
+1. Edit vars.
+2. Set KEY_CONFIG to point to the openssl.cnf file
+ included in this distribution.
+3. Set KEY_DIR to point to a directory which will
+ contain all keys, certificates, etc. This
+ directory need not exist, and if it does,
+ it will be deleted with rm -rf, so BE
+ CAREFUL how you set KEY_DIR.
+4. (Optional) Edit other fields in vars
+ per your site data. You may want to
+ increase KEY_SIZE to 2048 if you are
+ paranoid and don't mind slower key
+ processing, but certainly 1024 is
+ fine for testing purposes. KEY_SIZE
+ must be compatible across both peers
+ participating in a secure SSL/TLS
+ connection.
+5 . vars
+6. ./clean-all
+7. As you create certificates, keys, and
+ certificate signing requests, understand that
+ only .key files should be kept confidential.
+ .crt and .csr files can be sent over insecure
+ channels such as plaintext email.
+8. You should never need to copy a .key file
+ between computers. Normally each computer
+ will have its own certificate/key pair.
+
+BUILD YOUR OWN ROOT CERTIFICATE AUTHORITY (CA) CERTIFICATE/KEY
+
+1. ./build-ca
+2. ca.crt and ca.key will be built in your KEY_DIR
+ directory
+
+BUILD AN INTERMEDIATE CERTIFICATE AUTHORITY CERTIFICATE/KEY (optional)
+
+1. ./build-inter inter
+2. inter.crt and inter.key will be built in your KEY_DIR
+ directory and signed with your root certificate.
+
+BUILD DIFFIE-HELLMAN PARAMETERS (necessary for
+the server end of a SSL/TLS connection).
+
+1. ./build-dh
+
+BUILD A CERTIFICATE SIGNING REQUEST (If
+you want to sign your certificate with a root
+certificate controlled by another individual
+or organization, or residing on a different machine).
+
+1. Get ca.crt (the root certificate) from your
+ certificate authority. Though this
+ transfer can be over an insecure channel, to prevent
+ man-in-the-middle attacks you must confirm that
+ ca.crt was not tampered with. Large CAs solve this
+ problem by hardwiring their root certificates into
+ popular web browsers. A simple way to verify a root
+ CA is to call the issuer on the telephone and confirm
+ that the md5sum or sha1sum signatures on the ca.crt
+ files match (such as with the command: "md5sum ca.crt").
+2. Choose a name for your certificate such as your computer
+ name. In our example we will use "mycert".
+3. ./build-req mycert
+4. You can ignore most of the fields, but set
+ "Common Name" to something unique such as your
+ computer's host name. Leave all password
+ fields blank, unless you want your private key
+ to be protected by password. Using a password
+ is not required -- it will make your key more secure
+ but also more inconvenient to use, because you will
+ need to supply your password anytime the key is used.
+ NOTE: if you are using a password, use ./build-req-pass
+ instead of ./build-req
+5. Your key will be written to $KEY_DIR/mycert.key
+6. Your certificate signing request will be written to
+ to $KEY_DIR/mycert.csr
+7. Email mycert.csr to the individual or organization
+ which controls the root certificate. This can be
+ done over an insecure channel.
+8. After the .csr file is signed by the root certificate
+ authority, you will receive a file mycert.crt
+ (your certificate). Place mycert.crt in your
+ KEY_DIR directory.
+9. The combined files of mycert.crt, mycert.key,
+ and ca.crt can now be used to secure one end of
+ an SSL/TLS connection.
+
+SIGN A CERTIFICATE SIGNING REQUEST
+
+1. ./sign-req mycert
+2. mycert.crt will be built in your KEY_DIR
+ directory using mycert.csr and your root CA
+ file as input.
+
+BUILD AND SIGN A CERTIFICATE SIGNING REQUEST
+USING A LOCALLY INSTALLED ROOT CERTIFICATE/KEY -- this
+script generates and signs a certificate in one step,
+but it requires that the generated certificate and private
+key files be copied to the destination host over a
+secure channel.
+
+1. ./build-key mycert (no password protection)
+2. OR ./build-key-pass mycert (with password protection)
+3. OR ./build-key-pkcs12 mycert (PKCS #12 format)
+4. OR ./build-key-server mycert (with nsCertType=server)
+5. mycert.crt and mycert.key will be built in your
+ KEY_DIR directory, and mycert.crt will be signed
+ by your root CA. If ./build-key-pkcs12 was used a
+ mycert.p12 file will also be created including the
+ private key, certificate and the ca certificate.
+
+IMPORTANT
+
+To avoid a possible Man-in-the-Middle attack where an authorized
+client tries to connect to another client by impersonating the
+server, make sure to enforce some kind of server certificate
+verification by clients. There are currently four different ways
+of accomplishing this, listed in the order of preference:
+
+(1) Build your server certificates with the build-key-server
+ script. This will designate the certificate as a
+ server-only certificate by setting nsCertType=server.
+ Now add the following line to your client configuration:
+
+ ns-cert-type server
+
+ This will block clients from connecting to any
+ server which lacks the nsCertType=server designation
+ in its certificate, even if the certificate has been
+ signed by the CA which is cited in the OpenVPN configuration
+ file (--ca directive).
+
+(2) Use the --tls-remote directive on the client to
+ accept/reject the server connection based on the common
+ name of the server certificate.
+
+(3) Use a --tls-verify script or plugin to accept/reject the
+ server connection based on a custom test of the server
+ certificate's embedded X509 subject details.
+
+(4) Sign server certificates with one CA and client certificates
+ with a different CA. The client config "ca" directive should
+ reference the server-signing CA while the server config "ca"
+ directive should reference the client-signing CA.
+
+NOTES
+
+Show certificate fields:
+ openssl x509 -in cert.crt -text
diff --git a/easy-rsa/1.0/build-ca b/easy-rsa/1.0/build-ca
new file mode 100755
index 0000000..5ad59cc
--- /dev/null
+++ b/easy-rsa/1.0/build-ca
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+#
+# Build a root certificate
+#
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl req -days 3650 -nodes -new -x509 -keyout ca.key -out ca.crt -config $KEY_CONFIG && \
+ chmod 0600 ca.key
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/build-dh b/easy-rsa/1.0/build-dh
new file mode 100755
index 0000000..6de4baf
--- /dev/null
+++ b/easy-rsa/1.0/build-dh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+#
+# Build Diffie-Hellman parameters for the server side
+# of an SSL/TLS connection.
+#
+
+if test $KEY_DIR; then
+ openssl dhparam -out ${KEY_DIR}/dh${KEY_SIZE}.pem ${KEY_SIZE}
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/build-inter b/easy-rsa/1.0/build-inter
new file mode 100755
index 0000000..8b3a6b2
--- /dev/null
+++ b/easy-rsa/1.0/build-inter
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+#
+# Make an intermediate CA certificate/private key pair using a locally generated
+# root certificate.
+#
+
+if test $# -ne 1; then
+ echo "usage: build-inter <name>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
+ openssl ca -extensions v3_ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/build-key b/easy-rsa/1.0/build-key
new file mode 100755
index 0000000..3159d2b
--- /dev/null
+++ b/easy-rsa/1.0/build-key
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+#
+# Make a certificate/private key pair using a locally generated
+# root certificate.
+#
+
+if test $# -ne 1; then
+ echo "usage: build-key <name>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
+ openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG && \
+ chmod 0600 $1.key
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/build-key-pass b/easy-rsa/1.0/build-key-pass
new file mode 100755
index 0000000..03ab304
--- /dev/null
+++ b/easy-rsa/1.0/build-key-pass
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+#
+# Similar to build-key, but protect the private key
+# with a password.
+#
+
+if test $# -ne 1; then
+ echo "usage: build-key-pass <name>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl req -days 3650 -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
+ openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG && \
+ chmod 0600 $1.key
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/build-key-pkcs12 b/easy-rsa/1.0/build-key-pkcs12
new file mode 100755
index 0000000..f8a057b
--- /dev/null
+++ b/easy-rsa/1.0/build-key-pkcs12
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+#
+# Make a certificate/private key pair using a locally generated
+# root certificate and convert it to a PKCS #12 file including the
+# the CA certificate as well.
+
+if test $# -ne 1; then
+ echo "usage: build-key-pkcs12 <name>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
+ openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG && \
+ openssl pkcs12 -export -inkey $1.key -in $1.crt -certfile ca.crt -out $1.p12 && \
+ chmod 0600 $1.key $1.p12
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/build-key-server b/easy-rsa/1.0/build-key-server
new file mode 100755
index 0000000..30dc41e
--- /dev/null
+++ b/easy-rsa/1.0/build-key-server
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#
+# Make a certificate/private key pair using a locally generated
+# root certificate.
+#
+# Explicitly set nsCertType to server using the "server"
+# extension in the openssl.cnf file.
+
+if test $# -ne 1; then
+ echo "usage: build-key-server <name>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -extensions server -config $KEY_CONFIG && \
+ openssl ca -days 3650 -out $1.crt -in $1.csr -extensions server -config $KEY_CONFIG && \
+ chmod 0600 $1.key
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/build-req b/easy-rsa/1.0/build-req
new file mode 100755
index 0000000..30f62f5
--- /dev/null
+++ b/easy-rsa/1.0/build-req
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+#
+# Build a certificate signing request and private key. Use this
+# when your root certificate and key is not available locally.
+#
+
+if test $# -ne 1; then
+ echo "usage: build-req <name>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/build-req-pass b/easy-rsa/1.0/build-req-pass
new file mode 100755
index 0000000..829b286
--- /dev/null
+++ b/easy-rsa/1.0/build-req-pass
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+#
+# Like build-req, but protect your private key
+# with a password.
+#
+
+if test $# -ne 1; then
+ echo "usage: build-req-pass <name>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl req -days 3650 -new -keyout $1.key -out $1.csr -config $KEY_CONFIG
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/clean-all b/easy-rsa/1.0/clean-all
new file mode 100755
index 0000000..d10aef5
--- /dev/null
+++ b/easy-rsa/1.0/clean-all
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+#
+# Initialize the $KEY_DIR directory.
+# Note that this script does a
+# rm -rf on $KEY_DIR so be careful!
+#
+
+d=$KEY_DIR
+
+if test $d; then
+ rm -rf $d
+ mkdir $d && \
+ chmod go-rwx $d && \
+ touch $d/index.txt && \
+ echo 01 >$d/serial
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/list-crl b/easy-rsa/1.0/list-crl
new file mode 100644
index 0000000..b214dbd
--- /dev/null
+++ b/easy-rsa/1.0/list-crl
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+#
+# list revoked certificates
+#
+#
+
+if test $# -ne 1; then
+ echo "usage: list-crl <crlfile.pem>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl crl -text -noout -in $1
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/make-crl b/easy-rsa/1.0/make-crl
index 62fe6c1..62fe6c1 100644
--- a/easy-rsa/make-crl
+++ b/easy-rsa/1.0/make-crl
diff --git a/easy-rsa/1.0/openssl.cnf b/easy-rsa/1.0/openssl.cnf
new file mode 100644
index 0000000..270b069
--- /dev/null
+++ b/easy-rsa/1.0/openssl.cnf
@@ -0,0 +1,255 @@
+#
+# OpenSSL example configuration file.
+# This is mostly being used for generation of certificate requests.
+#
+
+# This definition stops the following lines choking if HOME isn't
+# defined.
+HOME = .
+RANDFILE = $ENV::HOME/.rnd
+
+# Extra OBJECT IDENTIFIER info:
+#oid_file = $ENV::HOME/.oid
+oid_section = new_oids
+
+# To use this configuration file with the "-extfile" option of the
+# "openssl x509" utility, name here the section containing the
+# X.509v3 extensions to use:
+# extensions =
+# (Alternatively, use a configuration file that has only
+# X.509v3 extensions in its main [= default] section.)
+
+[ new_oids ]
+
+# We can add new OIDs in here for use by 'ca' and 'req'.
+# Add a simple OID like this:
+# testoid1=1.2.3.4
+# Or use config file substitution like this:
+# testoid2=${testoid1}.5.6
+
+####################################################################
+[ ca ]
+default_ca = CA_default # The default ca section
+
+####################################################################
+[ CA_default ]
+
+dir = $ENV::KEY_DIR # Where everything is kept
+certs = $dir # Where the issued certs are kept
+crl_dir = $dir # Where the issued crl are kept
+database = $dir/index.txt # database index file.
+new_certs_dir = $dir # default place for new certs.
+
+certificate = $dir/ca.crt # The CA certificate
+serial = $dir/serial # The current serial number
+crl = $dir/crl.pem # The current CRL
+private_key = $dir/ca.key # The private key
+RANDFILE = $dir/.rand # private random number file
+
+x509_extensions = usr_cert # The extentions to add to the cert
+
+# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
+# so this is commented out by default to leave a V1 CRL.
+# crl_extensions = crl_ext
+
+default_days = 3650 # how long to certify for
+default_crl_days= 30 # how long before next CRL
+default_md = md5 # which md to use.
+preserve = no # keep passed DN ordering
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName = match
+stateOrProvinceName = match
+organizationName = match
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName = optional
+stateOrProvinceName = optional
+localityName = optional
+organizationName = optional
+organizationalUnitName = optional
+commonName = supplied
+emailAddress = optional
+
+####################################################################
+[ req ]
+default_bits = $ENV::KEY_SIZE
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+attributes = req_attributes
+x509_extensions = v3_ca # The extentions to add to the self signed cert
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options.
+# default: PrintableString, T61String, BMPString.
+# pkix : PrintableString, BMPString.
+# utf8only: only UTF8Strings.
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
+# so use this option with caution!
+string_mask = nombstr
+
+# req_extensions = v3_req # The extensions to add to a certificate request
+
+[ req_distinguished_name ]
+countryName = Country Name (2 letter code)
+countryName_default = $ENV::KEY_COUNTRY
+countryName_min = 2
+countryName_max = 2
+
+stateOrProvinceName = State or Province Name (full name)
+stateOrProvinceName_default = $ENV::KEY_PROVINCE
+
+localityName = Locality Name (eg, city)
+localityName_default = $ENV::KEY_CITY
+
+0.organizationName = Organization Name (eg, company)
+0.organizationName_default = $ENV::KEY_ORG
+
+# we can do this but it is not needed normally :-)
+#1.organizationName = Second Organization Name (eg, company)
+#1.organizationName_default = World Wide Web Pty Ltd
+
+organizationalUnitName = Organizational Unit Name (eg, section)
+#organizationalUnitName_default =
+
+commonName = Common Name (eg, your name or your server\'s hostname)
+commonName_max = 64
+
+emailAddress = Email Address
+emailAddress_default = $ENV::KEY_EMAIL
+emailAddress_max = 40
+
+# SET-ex3 = SET extension number 3
+
+[ req_attributes ]
+challengePassword = A challenge password
+challengePassword_min = 4
+challengePassword_max = 20
+
+unstructuredName = An optional company name
+
+[ usr_cert ]
+
+# These extensions are added when 'ca' signs a request.
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+
+# Here are some examples of the usage of nsCertType. If it is omitted
+# the certificate can be used for anything *except* object signing.
+
+# This is OK for an SSL server.
+# nsCertType = server
+
+# For an object signing certificate this would be used.
+# nsCertType = objsign
+
+# For normal client use this is typical
+# nsCertType = client, email
+
+# and for everything including object signing:
+# nsCertType = client, email, objsign
+
+# This is typical in keyUsage for a client certificate.
+# keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+# This will be displayed in Netscape's comment listbox.
+nsComment = "OpenSSL Generated Certificate"
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+
+# This stuff is for subjectAltName and issuerAltname.
+# Import the email address.
+# subjectAltName=email:copy
+
+# Copy subject details
+# issuerAltName=issuer:copy
+
+#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+[ server ]
+
+# JY ADDED -- Make a cert with nsCertType set to "server"
+basicConstraints=CA:FALSE
+nsCertType = server
+nsComment = "OpenSSL Generated Server Certificate"
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+
+
+# Extensions for a typical CA
+
+
+# PKIX recommendation.
+
+subjectKeyIdentifier=hash
+
+authorityKeyIdentifier=keyid:always,issuer:always
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+# Key usage: this is typical for a CA certificate. However since it will
+# prevent it being used as an test self-signed certificate it is best
+# left out by default.
+# keyUsage = cRLSign, keyCertSign
+
+# Some might want this also
+# nsCertType = sslCA, emailCA
+
+# Include email address in subject alt name: another PKIX recommendation
+# subjectAltName=email:copy
+# Copy issuer details
+# issuerAltName=issuer:copy
+
+# DER hex encoding of an extension: beware experts only!
+# obj=DER:02:03
+# Where 'obj' is a standard or added object
+# You can even override a supported extension:
+# basicConstraints= critical, DER:30:03:01:01:FF
+
+[ crl_ext ]
+
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always,issuer:always
diff --git a/easy-rsa/revoke-crt b/easy-rsa/1.0/revoke-crt
index 35b071a..35b071a 100644
--- a/easy-rsa/revoke-crt
+++ b/easy-rsa/1.0/revoke-crt
diff --git a/easy-rsa/1.0/revoke-full b/easy-rsa/1.0/revoke-full
new file mode 100755
index 0000000..66ea03f
--- /dev/null
+++ b/easy-rsa/1.0/revoke-full
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# revoke a certificate, regenerate CRL,
+# and verify revocation
+
+CRL=crl.pem
+RT=revoke-test.pem
+
+if test $# -ne 1; then
+ echo "usage: revoke-full <name>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR
+ rm -f $RT
+
+ # revoke key and generate a new CRL
+ openssl ca -revoke $1.crt -config $KEY_CONFIG
+
+ # generate a new CRL
+ openssl ca -gencrl -out $CRL -config $KEY_CONFIG
+ cat ca.crt $CRL >$RT
+
+ # verify the revocation
+ openssl verify -CAfile $RT -crl_check $1.crt
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/sign-req b/easy-rsa/1.0/sign-req
new file mode 100755
index 0000000..59edc42
--- /dev/null
+++ b/easy-rsa/1.0/sign-req
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+#
+# Sign a certificate signing request (a .csr file)
+# with a local root certificate and key.
+#
+
+if test $# -ne 1; then
+ echo "usage: sign-req <name>";
+ exit 1
+fi
+
+if test $KEY_DIR; then
+ cd $KEY_DIR && \
+ openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG
+else
+ echo you must define KEY_DIR
+fi
diff --git a/easy-rsa/1.0/vars b/easy-rsa/1.0/vars
new file mode 100644
index 0000000..da89cd2
--- /dev/null
+++ b/easy-rsa/1.0/vars
@@ -0,0 +1,49 @@
+# easy-rsa parameter settings
+
+# NOTE: If you installed from an RPM,
+# don't edit this file in place in
+# /usr/share/openvpn/easy-rsa --
+# instead, you should copy the whole
+# easy-rsa directory to another location
+# (such as /etc/openvpn) so that your
+# edits will not be wiped out by a future
+# OpenVPN package upgrade.
+
+# This variable should point to
+# the top level of the easy-rsa
+# tree.
+export D=`pwd`
+
+# This variable should point to
+# the openssl.cnf file included
+# with easy-rsa.
+export KEY_CONFIG=$D/openssl.cnf
+
+# Edit this variable to point to
+# your soon-to-be-created key
+# directory.
+#
+# WARNING: clean-all will do
+# a rm -rf on this directory
+# so make sure you define
+# it correctly!
+export KEY_DIR=$D/keys
+
+# Issue rm -rf warning
+echo NOTE: when you run ./clean-all, I will be doing a rm -rf on $KEY_DIR
+
+# Increase this to 2048 if you
+# are paranoid. This will slow
+# down TLS negotiation performance
+# as well as the one-time DH parms
+# generation process.
+export KEY_SIZE=1024
+
+# These are the default values for fields
+# which will be placed in the certificate.
+# Don't leave any of these fields blank.
+export KEY_COUNTRY=KG
+export KEY_PROVINCE=NA
+export KEY_CITY=BISHKEK
+export KEY_ORG="OpenVPN-TEST"
+export KEY_EMAIL="me@myhost.mydomain"
diff --git a/easy-rsa/README b/easy-rsa/README
index fd424ef..02800c2 100644
--- a/easy-rsa/README
+++ b/easy-rsa/README
@@ -1,14 +1,53 @@
-This is a small RSA key management package,
-based on the openssl command line tool, that
-can be found in the easy-rsa subdirectory
+EASY-RSA Version 2.0-rc1
+
+This is a small RSA key management package, based on the openssl
+command line tool, that can be found in the easy-rsa subdirectory
of the OpenVPN distribution.
-These are reference notes. For step
-by step instructions, see the HOWTO:
+These are reference notes. For step-by-step instructions, see the
+HOWTO:
http://openvpn.net/howto.html
-INSTALL
+This package is based on the ./pkitool script. Run ./pkitool
+without arguments for a detailed help message (which is also pasted
+below).
+
+Release Notes for easy-rsa-2.0
+
+* Most functionality has been consolidated into the pkitool
+ script. For compatibility, all previous scripts from 1.0 such
+ as build-key and build-key-server are provided as stubs
+ which call pkitool to do the real work.
+
+* pkitool has a --batch flag (enabled by default) which generates
+ keys/certs without needing any interactive input. pkitool
+ can still generate certs/keys using interactive prompting by
+ using the --interact flag.
+
+* The inherit-inter script has been provided for creating
+ a new PKI rooted on an intermediate certificate built within a
+ higher-level PKI. See comments in the inherit-inter script
+ for more info.
+
+* The openssl.cnf file has been modified. pkitool will not
+ work with the openssl.cnf file included with previous
+ easy-rsa releases.
+
+* The vars file has been modified -- the following extra
+ variables have been added: EASY_RSA, CA_EXPIRE,
+ KEY_EXPIRE.
+
+* The make-crl and revoke-crt scripts have been removed and
+ are replaced by the revoke-full script.
+
+* The "Organizational Unit" X509 field can be set using
+ the KEY_OU environmental variable before calling pkitool.
+
+* This release only affects the Linux/Unix version of easy-rsa.
+ The Windows version (written to use the Windows shell) is unchanged.
+
+INSTALL easy-rsa
1. Edit vars.
2. Set KEY_CONFIG to point to the openssl.cnf file
@@ -34,92 +73,6 @@ INSTALL
only .key files should be kept confidential.
.crt and .csr files can be sent over insecure
channels such as plaintext email.
-8. You should never need to copy a .key file
- between computers. Normally each computer
- will have its own certificate/key pair.
-
-BUILD YOUR OWN ROOT CERTIFICATE AUTHORITY (CA) CERTIFICATE/KEY
-
-1. ./build-ca
-2. ca.crt and ca.key will be built in your KEY_DIR
- directory
-
-BUILD AN INTERMEDIATE CERTIFICATE AUTHORITY CERTIFICATE/KEY (optional)
-
-1. ./build-inter inter
-2. inter.crt and inter.key will be built in your KEY_DIR
- directory and signed with your root certificate.
-
-BUILD DIFFIE-HELLMAN PARAMETERS (necessary for
-the server end of a SSL/TLS connection).
-
-1. ./build-dh
-
-BUILD A CERTIFICATE SIGNING REQUEST (If
-you want to sign your certificate with a root
-certificate controlled by another individual
-or organization, or residing on a different machine).
-
-1. Get ca.crt (the root certificate) from your
- certificate authority. Though this
- transfer can be over an insecure channel, to prevent
- man-in-the-middle attacks you must confirm that
- ca.crt was not tampered with. Large CAs solve this
- problem by hardwiring their root certificates into
- popular web browsers. A simple way to verify a root
- CA is to call the issuer on the telephone and confirm
- that the md5sum or sha1sum signatures on the ca.crt
- files match (such as with the command: "md5sum ca.crt").
-2. Choose a name for your certificate such as your computer
- name. In our example we will use "mycert".
-3. ./build-req mycert
-4. You can ignore most of the fields, but set
- "Common Name" to something unique such as your
- computer's host name. Leave all password
- fields blank, unless you want your private key
- to be protected by password. Using a password
- is not required -- it will make your key more secure
- but also more inconvenient to use, because you will
- need to supply your password anytime the key is used.
- NOTE: if you are using a password, use ./build-req-pass
- instead of ./build-req
-5. Your key will be written to $KEY_DIR/mycert.key
-6. Your certificate signing request will be written to
- to $KEY_DIR/mycert.csr
-7. Email mycert.csr to the individual or organization
- which controls the root certificate. This can be
- done over an insecure channel.
-8. After the .csr file is signed by the root certificate
- authority, you will receive a file mycert.crt
- (your certificate). Place mycert.crt in your
- KEY_DIR directory.
-9. The combined files of mycert.crt, mycert.key,
- and ca.crt can now be used to secure one end of
- an SSL/TLS connection.
-
-SIGN A CERTIFICATE SIGNING REQUEST
-
-1. ./sign-req mycert
-2. mycert.crt will be built in your KEY_DIR
- directory using mycert.csr and your root CA
- file as input.
-
-BUILD AND SIGN A CERTIFICATE SIGNING REQUEST
-USING A LOCALLY INSTALLED ROOT CERTIFICATE/KEY -- this
-script generates and signs a certificate in one step,
-but it requires that the generated certificate and private
-key files be copied to the destination host over a
-secure channel.
-
-1. ./build-key mycert (no password protection)
-2. OR ./build-key-pass mycert (with password protection)
-3. OR ./build-key-pkcs12 mycert (PKCS #12 format)
-4. OR ./build-key-server mycert (with nsCertType=server)
-5. mycert.crt and mycert.key will be built in your
- KEY_DIR directory, and mycert.crt will be signed
- by your root CA. If ./build-key-pkcs12 was used a
- mycert.p12 file will also be created including the
- private key, certificate and the ca certificate.
IMPORTANT
@@ -130,7 +83,8 @@ verification by clients. There are currently four different ways
of accomplishing this, listed in the order of preference:
(1) Build your server certificates with the build-key-server
- script. This will designate the certificate as a
+ script, or using the --server option to pkitool.
+ This will designate the certificate as a
server-only certificate by setting nsCertType=server.
Now add the following line to your client configuration:
@@ -159,3 +113,56 @@ NOTES
Show certificate fields:
openssl x509 -in cert.crt -text
+
+PKITOOL documentation
+
+pkitool 2.0
+Usage: pkitool [options...] [common-name]
+Options:
+ --batch : batch mode (default)
+ --interact : interactive mode
+ --server : build server cert
+ --initca : build root CA
+ --inter : build intermediate CA
+ --pass : encrypt private key with password
+ --csr : only generate a CSR, do not sign
+ --sign : sign an existing CSR
+ --pkcs12 : generate a combined pkcs12 file
+Notes:
+ Please edit the vars script to reflect your configuration,
+ then source it with "source ./vars".
+ Next, to start with a fresh PKI configuration and to delete any
+ previous certificates and keys, run "./clean-all".
+ Finally, you can run this tool (pkitool) to build certificates/keys.
+Generated files and corresponding OpenVPN directives:
+(Files will be placed in the $KEY_DIR directory, defined in ./vars)
+ ca.crt -> root certificate (--ca)
+ ca.key -> root key, keep secure (not directly used by OpenVPN)
+ .crt files -> client/server certificates (--cert)
+ .key files -> private keys, keep secure (--key)
+ .csr files -> certificate signing request (not directly used by OpenVPN)
+ dh1024.pem or dh2048.pem -> Diffie Hellman parameters (--dh)
+Examples:
+ pkitool --initca -> Build root certificate
+ pkitool --initca --pass -> Build root certificate with password-protected key
+ pkitool --server server1 -> Build "server1" certificate/key
+ pkitool client1 -> Build "client1" certificate/key
+ pkitool --pass client2 -> Build password-protected "client2" certificate/key
+ pkitool --pkcs12 client3 -> Build "client3" certificate/key in PKCS #12 format
+ pkitool --csr client4 -> Build "client4" CSR to be signed by another CA
+ pkitool --sign client4 -> Sign "client4" CSR
+ pkitool --inter interca -> Build an intermediate key-signing certificate/key
+ Also see ./inherit-inter script.
+Typical usage for initial PKI setup. Build myserver, client1, and client2 cert/keys.
+Protect client2 key with a password. Build DH parms. Generated files in ./keys :
+ [edit vars with your site-specific info]
+ source ./vars
+ ./clean-all
+ ./build-dh -> takes a long time, consider backgrounding
+ ./pkitool --initca
+ ./pkitool --server myserver
+ ./pkitool client1
+ ./pkitool --pass client2
+Typical usage for adding client cert to existing PKI:
+ source ./vars
+ ./pkitool client-new
diff --git a/easy-rsa/build-ca b/easy-rsa/build-ca
index 5ad59cc..fb1e2ca 100755
--- a/easy-rsa/build-ca
+++ b/easy-rsa/build-ca
@@ -1,13 +1,8 @@
-#!/bin/sh
+#!/bin/bash
#
# Build a root certificate
#
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl req -days 3650 -nodes -new -x509 -keyout ca.key -out ca.crt -config $KEY_CONFIG && \
- chmod 0600 ca.key
-else
- echo you must define KEY_DIR
-fi
+export EASY_RSA="${EASY_RSA:-.}"
+"$EASY_RSA/pkitool" --interact --initca $*
diff --git a/easy-rsa/build-dh b/easy-rsa/build-dh
index 6de4baf..ec7a805 100755
--- a/easy-rsa/build-dh
+++ b/easy-rsa/build-dh
@@ -1,12 +1,11 @@
-#!/bin/sh
+#!/bin/bash
-#
# Build Diffie-Hellman parameters for the server side
# of an SSL/TLS connection.
-#
-if test $KEY_DIR; then
+if [ -d $KEY_DIR ] && [ $KEY_SIZE ]; then
openssl dhparam -out ${KEY_DIR}/dh${KEY_SIZE}.pem ${KEY_SIZE}
else
- echo you must define KEY_DIR
+ echo 'Please source the vars script first (i.e. "source ./vars")'
+ echo 'Make sure you have edited it to reflect your configuration.'
fi
diff --git a/easy-rsa/build-inter b/easy-rsa/build-inter
index 8b3a6b2..f831d6f 100755
--- a/easy-rsa/build-inter
+++ b/easy-rsa/build-inter
@@ -1,19 +1,7 @@
-#!/bin/sh
+#!/bin/bash
-#
# Make an intermediate CA certificate/private key pair using a locally generated
# root certificate.
-#
-if test $# -ne 1; then
- echo "usage: build-inter <name>";
- exit 1
-fi
-
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
- openssl ca -extensions v3_ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG
-else
- echo you must define KEY_DIR
-fi
+export EASY_RSA="${EASY_RSA:-.}"
+"$EASY_RSA/pkitool" --interact --inter $*
diff --git a/easy-rsa/build-key b/easy-rsa/build-key
index 3159d2b..6196308 100755
--- a/easy-rsa/build-key
+++ b/easy-rsa/build-key
@@ -1,20 +1,7 @@
-#!/bin/sh
+#!/bin/bash
-#
# Make a certificate/private key pair using a locally generated
# root certificate.
-#
-if test $# -ne 1; then
- echo "usage: build-key <name>";
- exit 1
-fi
-
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
- openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG && \
- chmod 0600 $1.key
-else
- echo you must define KEY_DIR
-fi
+export EASY_RSA="${EASY_RSA:-.}"
+"$EASY_RSA/pkitool" --interact $*
diff --git a/easy-rsa/build-key-pass b/easy-rsa/build-key-pass
index 03ab304..35543e0 100755
--- a/easy-rsa/build-key-pass
+++ b/easy-rsa/build-key-pass
@@ -1,20 +1,7 @@
-#!/bin/sh
+#!/bin/bash
-#
# Similar to build-key, but protect the private key
# with a password.
-#
-if test $# -ne 1; then
- echo "usage: build-key-pass <name>";
- exit 1
-fi
-
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl req -days 3650 -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
- openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG && \
- chmod 0600 $1.key
-else
- echo you must define KEY_DIR
-fi
+export EASY_RSA="${EASY_RSA:-.}"
+"$EASY_RSA/pkitool" --interact --pass $*
diff --git a/easy-rsa/build-key-pkcs12 b/easy-rsa/build-key-pkcs12
index f8a057b..5ef064f 100755
--- a/easy-rsa/build-key-pkcs12
+++ b/easy-rsa/build-key-pkcs12
@@ -1,21 +1,8 @@
-#!/bin/sh
+#!/bin/bash
-#
# Make a certificate/private key pair using a locally generated
# root certificate and convert it to a PKCS #12 file including the
# the CA certificate as well.
-if test $# -ne 1; then
- echo "usage: build-key-pkcs12 <name>";
- exit 1
-fi
-
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG && \
- openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG && \
- openssl pkcs12 -export -inkey $1.key -in $1.crt -certfile ca.crt -out $1.p12 && \
- chmod 0600 $1.key $1.p12
-else
- echo you must define KEY_DIR
-fi
+export EASY_RSA="${EASY_RSA:-.}"
+"$EASY_RSA/pkitool" --interact --pkcs12 $*
diff --git a/easy-rsa/build-key-server b/easy-rsa/build-key-server
index 30dc41e..5502675 100755
--- a/easy-rsa/build-key-server
+++ b/easy-rsa/build-key-server
@@ -1,22 +1,10 @@
-#!/bin/sh
+#!/bin/bash
-#
# Make a certificate/private key pair using a locally generated
# root certificate.
#
# Explicitly set nsCertType to server using the "server"
# extension in the openssl.cnf file.
-if test $# -ne 1; then
- echo "usage: build-key-server <name>";
- exit 1
-fi
-
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -extensions server -config $KEY_CONFIG && \
- openssl ca -days 3650 -out $1.crt -in $1.csr -extensions server -config $KEY_CONFIG && \
- chmod 0600 $1.key
-else
- echo you must define KEY_DIR
-fi
+export EASY_RSA="${EASY_RSA:-.}"
+"$EASY_RSA/pkitool" --interact --server $*
diff --git a/easy-rsa/build-req b/easy-rsa/build-req
index 30f62f5..26587d1 100755
--- a/easy-rsa/build-req
+++ b/easy-rsa/build-req
@@ -1,18 +1,7 @@
-#!/bin/sh
+#!/bin/bash
-#
# Build a certificate signing request and private key. Use this
# when your root certificate and key is not available locally.
-#
-if test $# -ne 1; then
- echo "usage: build-req <name>";
- exit 1
-fi
-
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl req -days 3650 -nodes -new -keyout $1.key -out $1.csr -config $KEY_CONFIG
-else
- echo you must define KEY_DIR
-fi
+export EASY_RSA="${EASY_RSA:-.}"
+"$EASY_RSA/pkitool" --interact --csr $*
diff --git a/easy-rsa/build-req-pass b/easy-rsa/build-req-pass
index 829b286..6e6c863 100755
--- a/easy-rsa/build-req-pass
+++ b/easy-rsa/build-req-pass
@@ -1,18 +1,7 @@
-#!/bin/sh
+#!/bin/bash
-#
# Like build-req, but protect your private key
# with a password.
-#
-if test $# -ne 1; then
- echo "usage: build-req-pass <name>";
- exit 1
-fi
-
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl req -days 3650 -new -keyout $1.key -out $1.csr -config $KEY_CONFIG
-else
- echo you must define KEY_DIR
-fi
+export EASY_RSA="${EASY_RSA:-.}"
+"$EASY_RSA/pkitool" --interact --csr --pass $*
diff --git a/easy-rsa/clean-all b/easy-rsa/clean-all
index d10aef5..0576db5 100755
--- a/easy-rsa/clean-all
+++ b/easy-rsa/clean-all
@@ -1,19 +1,16 @@
-#!/bin/sh
+#!/bin/bash
-#
# Initialize the $KEY_DIR directory.
# Note that this script does a
# rm -rf on $KEY_DIR so be careful!
-#
-d=$KEY_DIR
-
-if test $d; then
- rm -rf $d
- mkdir $d && \
- chmod go-rwx $d && \
- touch $d/index.txt && \
- echo 01 >$d/serial
+if [ "$KEY_DIR" ]; then
+ rm -rf "$KEY_DIR"
+ mkdir "$KEY_DIR" && \
+ chmod go-rwx "$KEY_DIR" && \
+ touch "$KEY_DIR/index.txt" && \
+ echo 01 >"$KEY_DIR/serial"
else
- echo you must define KEY_DIR
+ echo 'Please source the vars script first (i.e. "source ./vars")'
+ echo 'Make sure you have edited it to reflect your configuration.'
fi
diff --git a/easy-rsa/inherit-inter b/easy-rsa/inherit-inter
new file mode 100755
index 0000000..2101951
--- /dev/null
+++ b/easy-rsa/inherit-inter
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# Build a new PKI which is rooted on an intermediate certificate generated
+# by ./build-inter or ./pkitool --inter from a parent PKI. The new PKI should
+# have independent vars settings, and must use a different KEY_DIR directory
+# from the parent. This tool can be used to generate arbitrary depth
+# certificate chains.
+#
+# To build an intermediate CA, follow the same steps for a regular PKI but
+# replace ./build-key or ./pkitool --initca with this script.
+
+# The EXPORT_CA file will contain the CA certificate chain and should be
+# referenced by the OpenVPN "ca" directive in config files. The ca.crt file
+# will only contain the local intermediate CA -- it's needed by the easy-rsa
+# scripts but not by OpenVPN directly.
+EXPORT_CA="export-ca.crt"
+
+if [ $# -ne 2 ]; then
+ echo "usage: $0 <parent-key-dir> <common-name>"
+ echo "parent-key-dir: the KEY_DIR directory of the parent PKI"
+ echo "common-name: the common name of the intermediate certificate in the parent PKI"
+ exit 1;
+fi
+
+if [ "$KEY_DIR" ]; then
+ cp "$1/$2.crt" "$KEY_DIR/ca.crt"
+ cp "$1/$2.key" "$KEY_DIR/ca.key"
+
+ if [ -e "$1/$EXPORT_CA" ]; then
+ PARENT_CA="$1/$EXPORT_CA"
+ else
+ PARENT_CA="$1/ca.crt"
+ fi
+ cp "$PARENT_CA" "$KEY_DIR/$EXPORT_CA"
+ cat "$KEY_DIR/ca.crt" >> "$KEY_DIR/$EXPORT_CA"
+else
+ echo 'Please source the vars script first (i.e. "source ./vars")'
+ echo 'Make sure you have edited it to reflect your configuration.'
+fi
diff --git a/easy-rsa/list-crl b/easy-rsa/list-crl
index b214dbd..7736fa8 100644..100755
--- a/easy-rsa/list-crl
+++ b/easy-rsa/list-crl
@@ -1,18 +1,13 @@
-#!/bin/sh
+#!/bin/bash
-#
# list revoked certificates
-#
-#
-if test $# -ne 1; then
- echo "usage: list-crl <crlfile.pem>";
- exit 1
-fi
+CRL="${1:-crl.pem}"
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl crl -text -noout -in $1
+if [ "$KEY_DIR" ]; then
+ cd "$KEY_DIR" && \
+ openssl crl -text -noout -in "$CRL"
else
- echo you must define KEY_DIR
+ echo 'Please source the vars script first (i.e. "source ./vars")'
+ echo 'Make sure you have edited it to reflect your configuration.'
fi
diff --git a/easy-rsa/openssl.cnf b/easy-rsa/openssl.cnf
index 270b069..7fedebe 100644..100755
--- a/easy-rsa/openssl.cnf
+++ b/easy-rsa/openssl.cnf
@@ -1,3 +1,5 @@
+# For use with easy-rsa version 2.0
+
#
# OpenSSL example configuration file.
# This is mostly being used for generation of certificate requests.
@@ -60,7 +62,7 @@ preserve = no # keep passed DN ordering
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
-policy = policy_match
+policy = policy_anything
# For the CA policy
[ policy_match ]
@@ -136,6 +138,10 @@ emailAddress = Email Address
emailAddress_default = $ENV::KEY_EMAIL
emailAddress_max = 40
+# JY -- added for batch mode
+organizationalUnitName_default = $ENV::KEY_OU
+commonName_default = $ENV::KEY_CN
+
# SET-ex3 = SET extension number 3
[ req_attributes ]
diff --git a/easy-rsa/pkitool b/easy-rsa/pkitool
new file mode 100755
index 0000000..2d2d764
--- /dev/null
+++ b/easy-rsa/pkitool
@@ -0,0 +1,233 @@
+#!/bin/sh
+
+# 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-2005 OpenVPN Solutions LLC <info@openvpn.net>
+#
+# 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
+
+# pkitool is a front-end for the openssl tool.
+
+# Calling scripts can set the certificate organizational
+# unit with the KEY_OU environmental variable.
+
+PROGNAME=pkitool
+VERSION=2.0
+DEBUG=0
+
+GREP=grep
+OPENSSL=openssl
+
+need_vars()
+{
+ echo ' Please edit the vars script to reflect your configuration,'
+ echo ' then source it with "source ./vars".'
+ echo ' Next, to start with a fresh PKI configuration and to delete any'
+ echo ' previous certificates and keys, run "./clean-all".'
+ echo " Finally, you can run this tool ($PROGNAME) to build certificates/keys."
+}
+
+usage()
+{
+ echo "$PROGNAME $VERSION"
+ echo "Usage: $PROGNAME [options...] [common-name]"
+ echo "Options:"
+ echo " --batch : batch mode (default)"
+ echo " --interact : interactive mode"
+ echo " --server : build server cert"
+ echo " --initca : build root CA"
+ echo " --inter : build intermediate CA"
+ echo " --pass : encrypt private key with password"
+ echo " --csr : only generate a CSR, do not sign"
+ echo " --sign : sign an existing CSR"
+ echo " --pkcs12 : generate a combined pkcs12 file"
+ echo "Notes:"
+ need_vars
+ echo "Generated files and corresponding OpenVPN directives:"
+ echo '(Files will be placed in the $KEY_DIR directory, defined in ./vars)'
+ echo " ca.crt -> root certificate (--ca)"
+ echo " ca.key -> root key, keep secure (not directly used by OpenVPN)"
+ echo " .crt files -> client/server certificates (--cert)"
+ echo " .key files -> private keys, keep secure (--key)"
+ echo " .csr files -> certificate signing request (not directly used by OpenVPN)"
+ echo " dh1024.pem or dh2048.pem -> Diffie Hellman parameters (--dh)"
+ echo "Examples:"
+ echo " $PROGNAME --initca -> Build root certificate"
+ echo " $PROGNAME --initca --pass -> Build root certificate with password-protected key"
+ echo " $PROGNAME --server server1 -> Build \"server1\" certificate/key"
+ echo " $PROGNAME client1 -> Build \"client1\" certificate/key"
+ echo " $PROGNAME --pass client2 -> Build password-protected \"client2\" certificate/key"
+ echo " $PROGNAME --pkcs12 client3 -> Build \"client3\" certificate/key in PKCS #12 format"
+ echo " $PROGNAME --csr client4 -> Build \"client4\" CSR to be signed by another CA"
+ echo " $PROGNAME --sign client4 -> Sign \"client4\" CSR"
+ echo " $PROGNAME --inter interca -> Build an intermediate key-signing certificate/key"
+ echo " Also see ./inherit-inter script."
+ echo "Typical usage for initial PKI setup. Build myserver, client1, and client2 cert/keys."
+ echo "Protect client2 key with a password. Build DH parms. Generated files in ./keys :"
+ echo " [edit vars with your site-specific info]"
+ echo " source ./vars"
+ echo " ./clean-all"
+ echo " ./build-dh -> takes a long time, consider backgrounding"
+ echo " ./$PROGNAME --initca"
+ echo " ./$PROGNAME --server myserver"
+ echo " ./$PROGNAME client1"
+ echo " ./$PROGNAME --pass client2"
+ echo "Typical usage for adding client cert to existing PKI:"
+ echo " source ./vars"
+ echo " ./$PROGNAME client-new"
+}
+
+# Set defaults
+DO_REQ="1"
+REQ_EXT=""
+DO_CA="1"
+CA_EXT=""
+DO_P12="0"
+DO_ROOT="0"
+NODES_REQ="-nodes"
+NODES_P12=""
+BATCH="-batch"
+CA="ca"
+
+# Process options
+while [ $# -gt 0 ]; do
+ case "$1" in
+ --server ) REQ_EXT="$REQ_EXT -extensions server"
+ CA_EXT="$CA_EXT -extensions server" ;;
+ --batch ) BATCH="-batch" ;;
+ --interact ) BATCH="" ;;
+ --inter ) CA_EXT="$CA_EXT -extensions v3_ca" ;;
+ --initca ) DO_ROOT="1" ;;
+ --pass ) NODES_REQ="" ;;
+ --csr ) DO_CA="0" ;;
+ --sign ) DO_REQ="0" ;;
+ --pkcs12 ) DO_P12="1" ;;
+ --* ) echo "$PROGNAME: unknown option: $1"
+ exit 1 ;;
+ * ) break ;;
+ esac
+ shift
+done
+
+# If we are generating pkcs12, only encrypt the final step
+if [ $DO_P12 -eq 1 ]; then
+ NODES_P12="$NODES_REQ"
+ NODES_REQ="-nodes"
+fi
+
+# If undefined, set default key expiration intervals
+if [ -z "$KEY_EXPIRE" ]; then
+ KEY_EXPIRE=3650
+fi
+if [ -z "$CA_EXPIRE" ]; then
+ CA_EXPIRE=3650
+fi
+
+# Set organizational unit to empty string if undefined
+if [ -z "$KEY_OU" ]; then
+ KEY_OU=""
+fi
+
+# Set KEY_CN
+if [ $DO_ROOT -eq 1 ]; then
+ if [ -z "$KEY_CN" ]; then
+ if [ "$1" ]; then
+ KEY_CN="$1"
+ elif [ "$KEY_ORG" ]; then
+ KEY_CN="$KEY_ORG CA"
+ fi
+ fi
+ if [ $BATCH ] && [ "$KEY_CN" ]; then
+ echo "Using CA Common Name:" $KEY_CN
+ fi
+elif [ $BATCH ] && [ "$KEY_CN" ] && [ $# -eq 0 ]; then
+ echo "Using Common Name:" $KEY_CN
+else
+ if [ $# -ne 1 ]; then
+ usage
+ exit 1
+ else
+ KEY_CN="$1"
+ fi
+fi
+export CA_EXPIRE KEY_EXPIRE KEY_OU KEY_CN
+
+# Show parameters (debugging)
+if [ $DEBUG -eq 1 ]; then
+ echo DO_REQ $DO_REQ
+ echo REQ_EXT $REQ_EXT
+ echo DO_CA $DO_CA
+ echo CA_EXT $CA_EXT
+ echo NODES_REQ $NODES_REQ
+ echo NODES_P12 $NODES_P12
+ echo DO_P12 $DO_P12
+ echo KEY_CN $KEY_CN
+ echo BATCH $BATCH
+ echo DO_ROOT $DO_ROOT
+ echo KEY_EXPIRE $KEY_EXPIRE
+ echo CA_EXPIRE $CA_EXPIRE
+ echo KEY_OU $KEY_OU
+fi
+
+# Make sure ./vars was sourced beforehand
+if [ -d "$KEY_DIR" ] && [ "$KEY_CONFIG" ]; then
+ cd "$KEY_DIR"
+
+ # Make sure $KEY_CONFIG points to the correct version
+ # of openssl.cnf
+ if $GREP -i 'easy-rsa version 2\.[0-9]' "$KEY_CONFIG" >/dev/null; then
+ :
+ else
+ echo "$PROGNAME: KEY_CONFIG (set by the ./vars script) is pointing to the wrong"
+ echo "version of openssl.cnf: $KEY_CONFIG"
+ echo "The correct version should have a comment that says: easy-rsa version 2.x";
+ exit 1;
+ fi
+
+ # Build root CA
+ if [ $DO_ROOT -eq 1 ]; then
+ $OPENSSL req $BATCH -days $CA_EXPIRE $NODES_REQ -new -x509 \
+ -keyout "$CA.key" -out "$CA.crt" -config "$KEY_CONFIG" && \
+ chmod 0600 "$CA.key"
+ else
+ # Make sure CA key/cert is available
+ if [ $DO_CA -eq 1 ] || [ $DO_P12 -eq 1 ]; then
+ if [ ! -r "$CA.crt" ] || [ ! -r "$CA.key" ]; then
+ echo "$PROGNAME: Need a readable $CA.crt and $CA.key in $KEY_DIR"
+ echo "Try $PROGNAME --initca to build a root certificate/key."
+ exit 1
+ fi
+ fi
+
+ # Build cert/key
+ ( [ $DO_REQ -eq 0 ] || $OPENSSL req $BATCH -days $KEY_EXPIRE $NODES_REQ -new \
+ -keyout "$KEY_CN.key" -out "$KEY_CN.csr" $REQ_EXT -config "$KEY_CONFIG" ) && \
+ ( [ $DO_CA -eq 0 ] || $OPENSSL ca $BATCH -days $KEY_EXPIRE -out "$KEY_CN.crt" \
+ -in "$KEY_CN.csr" $CA_EXT -config "$KEY_CONFIG" ) && \
+ ( [ $DO_P12 -eq 0 ] || $OPENSSL pkcs12 -export -inkey "$KEY_CN.key" \
+ -in "$KEY_CN.crt" -certfile "$CA.crt" -out "$KEY_CN.p12" $NODES_P12 ) && \
+ ( [ $DO_CA -eq 0 ] || chmod 0600 "$KEY_CN.key" ) && \
+ ( [ $DO_P12 -eq 0 ] || chmod 0600 "$KEY_CN.p12" )
+
+ fi
+
+# Need definitions
+else
+ need_vars
+fi
diff --git a/easy-rsa/revoke-full b/easy-rsa/revoke-full
index 66ea03f..9dc9b1e 100755
--- a/easy-rsa/revoke-full
+++ b/easy-rsa/revoke-full
@@ -1,29 +1,39 @@
-#!/bin/sh
+#!/bin/bash
# revoke a certificate, regenerate CRL,
# and verify revocation
-CRL=crl.pem
-RT=revoke-test.pem
+CRL="crl.pem"
+RT="revoke-test.pem"
-if test $# -ne 1; then
- echo "usage: revoke-full <name>";
- exit 1
+if [ $# -ne 1 ]; then
+ echo "usage: revoke-full <common-name>";
+ exit 1
fi
-if test $KEY_DIR; then
- cd $KEY_DIR
- rm -f $RT
+if [ "$KEY_DIR" ]; then
+ cd "$KEY_DIR"
+ rm -f "$RT"
- # revoke key and generate a new CRL
- openssl ca -revoke $1.crt -config $KEY_CONFIG
+ # set defaults
+ export KEY_CN=""
+ export KEY_OU=""
- # generate a new CRL
- openssl ca -gencrl -out $CRL -config $KEY_CONFIG
- cat ca.crt $CRL >$RT
+ # revoke key and generate a new CRL
+ openssl ca -revoke "$1.crt" -config "$KEY_CONFIG"
+
+ # generate a new CRL -- try to be compatible with
+ # intermediate PKIs
+ openssl ca -gencrl -out "$CRL" -config "$KEY_CONFIG"
+ if [ -e export-ca.crt ]; then
+ cat export-ca.crt "$CRL" >"$RT"
+ else
+ cat ca.crt "$CRL" >"$RT"
+ fi
- # verify the revocation
- openssl verify -CAfile $RT -crl_check $1.crt
+ # verify the revocation
+ openssl verify -CAfile "$RT" -crl_check "$1.crt"
else
- echo you must define KEY_DIR
+ echo 'Please source the vars script first (i.e. "source ./vars")'
+ echo 'Make sure you have edited it to reflect your configuration.'
fi
diff --git a/easy-rsa/sign-req b/easy-rsa/sign-req
index 59edc42..38655d3 100755
--- a/easy-rsa/sign-req
+++ b/easy-rsa/sign-req
@@ -1,18 +1,7 @@
-#!/bin/sh
+#!/bin/bash
-#
# Sign a certificate signing request (a .csr file)
# with a local root certificate and key.
-#
-if test $# -ne 1; then
- echo "usage: sign-req <name>";
- exit 1
-fi
-
-if test $KEY_DIR; then
- cd $KEY_DIR && \
- openssl ca -days 3650 -out $1.crt -in $1.csr -config $KEY_CONFIG
-else
- echo you must define KEY_DIR
-fi
+export EASY_RSA="${EASY_RSA:-.}"
+"$EASY_RSA/pkitool" --interact --sign $*
diff --git a/easy-rsa/vars b/easy-rsa/vars
index da89cd2..a4bd149 100644..100755
--- a/easy-rsa/vars
+++ b/easy-rsa/vars
@@ -12,12 +12,12 @@
# This variable should point to
# the top level of the easy-rsa
# tree.
-export D=`pwd`
+export EASY_RSA="`pwd`"
# This variable should point to
# the openssl.cnf file included
# with easy-rsa.
-export KEY_CONFIG=$D/openssl.cnf
+export KEY_CONFIG="$EASY_RSA/openssl.cnf"
# Edit this variable to point to
# your soon-to-be-created key
@@ -27,10 +27,10 @@ export KEY_CONFIG=$D/openssl.cnf
# a rm -rf on this directory
# so make sure you define
# it correctly!
-export KEY_DIR=$D/keys
+export KEY_DIR="$EASY_RSA/keys"
# Issue rm -rf warning
-echo NOTE: when you run ./clean-all, I will be doing a rm -rf on $KEY_DIR
+echo NOTE: If you run ./clean-all, I will be doing a rm -rf on $KEY_DIR
# Increase this to 2048 if you
# are paranoid. This will slow
@@ -39,11 +39,17 @@ echo NOTE: when you run ./clean-all, I will be doing a rm -rf on $KEY_DIR
# generation process.
export KEY_SIZE=1024
+# In how many days should the root CA key expire?
+export CA_EXPIRE=3650
+
+# In how many days should certificates expire?
+export KEY_EXPIRE=3650
+
# These are the default values for fields
# which will be placed in the certificate.
# Don't leave any of these fields blank.
-export KEY_COUNTRY=KG
-export KEY_PROVINCE=NA
-export KEY_CITY=BISHKEK
-export KEY_ORG="OpenVPN-TEST"
+export KEY_COUNTRY="US"
+export KEY_PROVINCE="CA"
+export KEY_CITY="SanFrancisco"
+export KEY_ORG="Fort-Funston"
export KEY_EMAIL="me@myhost.mydomain"
diff --git a/errlevel.h b/errlevel.h
index 225705f..83c5d25 100644
--- a/errlevel.h
+++ b/errlevel.h
@@ -99,6 +99,7 @@
#define D_DHCP_OPT LOGLEV(4, 53, 0) /* show DHCP options binary string */
#define D_OSBUF LOGLEV(4, 54, 0) /* show socket/tun/tap buffer sizes */
#define D_MBUF LOGLEV(4, 55, 0) /* mbuf.[ch] routines */
+#define D_PACKET_TRUNC_ERR LOGLEV(4, 56, 0) /* PACKET_TRUNCATION_CHECK */
#define D_LOG_RW LOGLEV(5, 0, 0) /* Print 'R' or 'W' to stdout for read/write */
@@ -127,6 +128,7 @@
#define D_PLUGIN_DEBUG LOGLEV(7, 70, M_DEBUG) /* show verbose plugin calls */
#define D_SOCKET_DEBUG LOGLEV(7, 70, M_DEBUG) /* show socket.[ch] debugging info */
#define D_ALIGN_DEBUG LOGLEV(7, 70, M_DEBUG) /* show verbose struct alignment info */
+#define D_PACKET_TRUNC_DEBUG LOGLEV(7, 70, M_DEBUG) /* PACKET_TRUNCATION_CHECK verbose */
#define D_HANDSHAKE_VERBOSE LOGLEV(8, 70, M_DEBUG) /* show detailed description of each handshake */
#define D_TLS_DEBUG_MED LOGLEV(8, 70, M_DEBUG) /* limited info from tls_session routines */
diff --git a/forward.c b/forward.c
index 4c0aff8..ccadff9 100644
--- a/forward.c
+++ b/forward.c
@@ -252,7 +252,7 @@ send_control_channel_string (struct context *c, const char *str, int msglevel)
static void
check_add_routes_action (struct context *c, const bool errors)
{
- do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->c1.plugins, c->c2.es);
+ do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es);
update_time ();
event_timeout_clear (&c->c2.route_wakeup);
event_timeout_clear (&c->c2.route_wakeup_expire);
@@ -615,6 +615,7 @@ read_incoming_link (struct context *c)
c->c2.buf = c->c2.buffers->read_link_buf;
ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM_ADJ (&c->c2.frame, FRAME_HEADROOM_MARKER_READ_LINK)));
+
status = link_socket_read (c->c2.link_socket, &c->c2.buf, MAX_RW_SIZE_LINK (&c->c2.frame), &c->c2.from);
if (socket_connection_reset (c->c2.link_socket, status))
@@ -766,6 +767,16 @@ process_incoming_link (struct context *c)
if (c->options.comp_lzo)
lzo_decompress (&c->c2.buf, c->c2.buffers->lzo_decompress_buf, &c->c2.lzo_compwork, &c->c2.frame);
#endif
+
+#ifdef PACKET_TRUNCATION_CHECK
+ //if (c->c2.buf.len > 1) --c->c2.buf.len; // JYFIXME
+ ipv4_packet_size_verify (BPTR (&c->c2.buf),
+ BLEN (&c->c2.buf),
+ TUNNEL_TYPE (c->c1.tuntap),
+ "POST_DECRYPT",
+ &c->c2.n_trunc_post_decrypt);
+#endif
+
/*
* Set our "official" outgoing address, since
* if buf.len is non-zero, we know the packet
@@ -840,6 +851,14 @@ read_incoming_tun (struct context *c)
c->c2.buf.len = read_tun (c->c1.tuntap, BPTR (&c->c2.buf), MAX_RW_SIZE_TUN (&c->c2.frame));
#endif
+#ifdef PACKET_TRUNCATION_CHECK
+ ipv4_packet_size_verify (BPTR (&c->c2.buf),
+ BLEN (&c->c2.buf),
+ TUNNEL_TYPE (c->c1.tuntap),
+ "READ_TUN",
+ &c->c2.n_trunc_tun_read);
+#endif
+
/* Was TUN/TAP interface stopped? */
if (tuntap_stop (c->c2.buf.len))
{
@@ -889,6 +908,16 @@ process_incoming_tun (struct context *c)
* us to examine the IPv4 header.
*/
process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX, &c->c2.buf);
+
+#ifdef PACKET_TRUNCATION_CHECK
+ //if (c->c2.buf.len > 1) --c->c2.buf.len; // JYFIXME
+ ipv4_packet_size_verify (BPTR (&c->c2.buf),
+ BLEN (&c->c2.buf),
+ TUNNEL_TYPE (c->c1.tuntap),
+ "PRE_ENCRYPT",
+ &c->c2.n_trunc_pre_encrypt);
+#endif
+
encrypt_sign (c, true);
}
else
@@ -1071,7 +1100,7 @@ process_outgoing_tun (struct context *c)
* The --mssfix option requires
* us to examine the IPv4 header.
*/
- process_ipv4_header (c, PIPV4_MSSFIX, &c->c2.to_tun);
+ process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_OUTGOING, &c->c2.to_tun);
if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame))
{
@@ -1089,6 +1118,14 @@ process_outgoing_tun (struct context *c)
format_hex (BPTR (&c->c2.to_tun), BLEN (&c->c2.to_tun), 80, &gc),
MD5SUM (BPTR (&c->c2.to_tun), BLEN (&c->c2.to_tun), &gc));
+#ifdef PACKET_TRUNCATION_CHECK
+ ipv4_packet_size_verify (BPTR (&c->c2.to_tun),
+ BLEN (&c->c2.to_tun),
+ TUNNEL_TYPE (c->c1.tuntap),
+ "WRITE_TUN",
+ &c->c2.n_trunc_tun_write);
+#endif
+
#ifdef TUN_PASS_BUFFER
size = write_tun_buffered (c->c1.tuntap, &c->c2.to_tun);
#else
diff --git a/forward.h b/forward.h
index 1d37aae..e745b9c 100644
--- a/forward.h
+++ b/forward.h
@@ -74,6 +74,7 @@ bool send_control_channel_string (struct context *c, const char *str, int msglev
#define PIPV4_PASSTOS (1<<0)
#define PIPV4_MSSFIX (1<<1)
+#define PIPV4_OUTGOING (1<<2)
void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf);
diff --git a/helper.c b/helper.c
index 1eb230b..9b0857e 100644
--- a/helper.c
+++ b/helper.c
@@ -77,6 +77,16 @@ print_opt_route (const in_addr_t network, const in_addr_t netmask, struct gc_are
}
static const char *
+print_opt_topology (const int topology, struct gc_arena *gc)
+{
+ struct buffer out = alloc_buf_gc (128, gc);
+
+ buf_printf (&out, "topology %s", print_topology (topology));
+
+ return BSTR (&out);
+}
+
+static const char *
print_str_int (const char *str, const int i, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (128, gc);
@@ -132,19 +142,23 @@ helper_client_server (struct options *o)
*
* mode server
* tls-server
+ * push "topology [topology]"
*
- * if tun:
- * ifconfig 10.8.0.1 10.8.0.2
- * ifconfig-pool 10.8.0.4 10.8.0.251
+ * if tun AND (topology == net30 OR topology == p2p):
+ * ifconfig 10.8.0.1 10.8.0.2
+ * if !nopool:
+ * ifconfig-pool 10.8.0.4 10.8.0.251
* route 10.8.0.0 255.255.255.0
* if client-to-client:
* push "route 10.8.0.0 255.255.255.0"
- * else if !linear-addr:
+ * else if topology == net30:
* push "route 10.8.0.1"
*
- * if tap:
+ * if tap OR (tun AND topology == subnet):
* ifconfig 10.8.0.1 255.255.255.0
- * ifconfig-pool 10.8.0.2 10.8.0.254 255.255.255.0
+ * ifconfig-pool-constraint 10.8.0.0 255.255.255.0
+ * if !nopool:
+ * ifconfig-pool 10.8.0.2 10.8.0.254 255.255.255.0
* push "route-gateway 10.8.0.1"
*/
@@ -152,6 +166,7 @@ helper_client_server (struct options *o)
* Get tun/tap/null device type
*/
const int dev = dev_type_enum (o->dev, o->dev_type);
+ const int topology = o->topology;
if (o->server_defined)
{
@@ -197,16 +212,44 @@ helper_client_server (struct options *o)
o->mode = MODE_SERVER;
o->tls_server = true;
- o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc);
- o->ifconfig_remote_netmask = print_in_addr_t (o->server_network + 2, 0, &o->gc);
- o->ifconfig_pool_defined = true;
- o->ifconfig_pool_start = o->server_network + 4;
- o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - pool_end_reserve;
- helper_add_route (o->server_network, o->server_netmask, o);
- if (o->enable_c2c)
- push_option (o, print_opt_route (o->server_network, o->server_netmask, &o->gc), M_USAGE);
- else if (!o->ifconfig_pool_linear)
- push_option (o, print_opt_route (o->server_network + 1, 0, &o->gc), M_USAGE);
+
+ if (topology == TOP_NET30 || topology == TOP_P2P)
+ {
+ o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc);
+ o->ifconfig_remote_netmask = print_in_addr_t (o->server_network + 2, 0, &o->gc);
+
+ if (!(o->server_flags & SF_NOPOOL))
+ {
+ o->ifconfig_pool_defined = true;
+ o->ifconfig_pool_start = o->server_network + 4;
+ o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - pool_end_reserve;
+ }
+
+ helper_add_route (o->server_network, o->server_netmask, o);
+ if (o->enable_c2c)
+ push_option (o, print_opt_route (o->server_network, o->server_netmask, &o->gc), M_USAGE);
+ else if (topology == TOP_NET30)
+ push_option (o, print_opt_route (o->server_network + 1, 0, &o->gc), M_USAGE);
+ }
+ else if (topology == TOP_SUBNET)
+ {
+ o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc);
+ o->ifconfig_remote_netmask = print_in_addr_t (o->server_netmask, 0, &o->gc);
+
+ if (!(o->server_flags & SF_NOPOOL))
+ {
+ o->ifconfig_pool_defined = true;
+ o->ifconfig_pool_start = o->server_network + 2;
+ o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 2;
+ o->ifconfig_pool_netmask = o->server_netmask;
+ }
+
+ push_option (o, print_opt_route_gateway (o->server_network + 1, &o->gc), M_USAGE);
+ }
+ else
+ ASSERT (0);
+
+ push_option (o, print_opt_topology (topology, &o->gc), M_USAGE);
}
else if (dev == DEV_TYPE_TAP)
{
@@ -218,10 +261,15 @@ helper_client_server (struct options *o)
o->tls_server = true;
o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc);
o->ifconfig_remote_netmask = print_in_addr_t (o->server_netmask, 0, &o->gc);
- o->ifconfig_pool_defined = true;
- o->ifconfig_pool_start = o->server_network + 2;
- o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1;
- o->ifconfig_pool_netmask = o->server_netmask;
+
+ if (!(o->server_flags & SF_NOPOOL))
+ {
+ o->ifconfig_pool_defined = true;
+ o->ifconfig_pool_start = o->server_network + 2;
+ o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1;
+ o->ifconfig_pool_netmask = o->server_netmask;
+ }
+
push_option (o, print_opt_route_gateway (o->server_network + 1, &o->gc), M_USAGE);
}
else
@@ -229,6 +277,14 @@ helper_client_server (struct options *o)
ASSERT (0);
}
+ /* set push-ifconfig-constraint directive */
+ if ((dev == DEV_TYPE_TAP || topology == TOP_SUBNET))
+ {
+ o->push_ifconfig_constraint_defined = true;
+ o->push_ifconfig_constraint_network = o->server_network;
+ o->push_ifconfig_constraint_netmask = o->server_netmask;
+ }
+
if (o->proto == PROTO_TCPv4)
o->proto = PROTO_TCPv4_SERVER;
}
diff --git a/init.c b/init.c
index 8a4c100..d0767f1 100644
--- a/init.c
+++ b/init.c
@@ -543,7 +543,7 @@ do_init_route_list (const struct options *options,
const char *gw = NULL;
int dev = dev_type_enum (options->dev, options->dev_type);
- if (dev == DEV_TYPE_TUN)
+ if (dev == DEV_TYPE_TUN && (options->topology == TOP_NET30 || options->topology == TOP_P2P))
gw = options->ifconfig_remote_netmask;
if (options->route_default_gateway)
gw = options->route_default_gateway;
@@ -626,7 +626,7 @@ do_route (const struct options *options,
if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP))
{
- if (plugin_call (plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, es))
+ if (plugin_call (plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, NULL, es))
msg (M_WARN, "WARNING: route-up plugin call failed");
}
@@ -676,6 +676,7 @@ do_init_tun (struct context *c)
{
c->c1.tuntap = init_tun (c->options.dev,
c->options.dev_type,
+ c->options.topology,
c->options.ifconfig_local,
c->options.ifconfig_remote_netmask,
addr_host (&c->c1.link_socket_addr.local),
@@ -712,7 +713,7 @@ do_open_tun (struct context *c)
do_alloc_route_list (c);
/* parse and resolve the route option list */
- if (c->c1.route_list && c->c2.link_socket)
+ if (c->options.routes && c->c1.route_list && c->c2.link_socket)
do_init_route_list (&c->options, c->c1.route_list, &c->c2.link_socket->info, false, c->c2.es);
/* do ifconfig */
@@ -741,7 +742,7 @@ do_open_tun (struct context *c)
/* run the up script */
run_up_down (c->options.up_script,
- c->c1.plugins,
+ c->plugins,
OPENVPN_PLUGIN_UP,
c->c1.tuntap->actual_name,
TUN_MTU_SIZE (&c->c2.frame),
@@ -755,7 +756,7 @@ do_open_tun (struct context *c)
/* possibly add routes */
if (!c->options.route_delay_defined)
- do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->c1.plugins, c->c2.es);
+ do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es);
/*
* Did tun/tap driver give us an MTU?
@@ -775,7 +776,7 @@ do_open_tun (struct context *c)
/* run the up script if user specified --up-restart */
if (c->options.up_restart)
run_up_down (c->options.up_script,
- c->c1.plugins,
+ c->plugins,
OPENVPN_PLUGIN_UP,
c->c1.tuntap->actual_name,
TUN_MTU_SIZE (&c->c2.frame),
@@ -836,7 +837,7 @@ do_close_tun (struct context *c, bool force)
/* Run the down script -- note that it will run at reduced
privilege if, for example, "--user nobody" was used. */
run_up_down (c->options.down_script,
- c->c1.plugins,
+ c->plugins,
OPENVPN_PLUGIN_DOWN,
tuntap_actual,
TUN_MTU_SIZE (&c->c2.frame),
@@ -858,7 +859,7 @@ do_close_tun (struct context *c, bool force)
/* run the down script on this restart if --up-restart was specified */
if (c->options.up_restart)
run_up_down (c->options.down_script,
- c->c1.plugins,
+ c->plugins,
OPENVPN_PLUGIN_DOWN,
tuntap_actual,
TUN_MTU_SIZE (&c->c2.frame),
@@ -946,18 +947,25 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
* These are the option categories which will be accepted by pull.
*/
unsigned int
-pull_permission_mask (void)
+pull_permission_mask (const struct context *c)
{
- return ( OPT_P_UP
- | OPT_P_ROUTE
- | OPT_P_IPWIN32
- | OPT_P_SETENV
- | OPT_P_SHAPER
- | OPT_P_TIMER
- | OPT_P_PERSIST
- | OPT_P_MESSAGES
- | OPT_P_EXPLICIT_NOTIFY
- | OPT_P_ECHO);
+ unsigned int flags =
+ OPT_P_UP
+ | OPT_P_ROUTE_EXTRAS
+ | OPT_P_IPWIN32
+ | OPT_P_SETENV
+ | OPT_P_SHAPER
+ | OPT_P_TIMER
+ | OPT_P_PERSIST
+ | OPT_P_MESSAGES
+ | OPT_P_EXPLICIT_NOTIFY
+ | OPT_P_ECHO
+ | OPT_P_PULL_MODE;
+
+ if (!c->options.route_nopull)
+ flags |= OPT_P_ROUTE;
+
+ return flags;
}
/*
@@ -1002,6 +1010,8 @@ do_deferred_options (struct context *c, const unsigned int found)
msg (D_PUSH, "OPTIONS IMPORT: --ifconfig/up options modified");
if (found & OPT_P_ROUTE)
msg (D_PUSH, "OPTIONS IMPORT: route options modified");
+ if (found & OPT_P_ROUTE_EXTRAS)
+ msg (D_PUSH, "OPTIONS IMPORT: route-related options modified");
if (found & OPT_P_IPWIN32)
msg (D_PUSH, "OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options modified");
if (found & OPT_P_SETENV)
@@ -1367,7 +1377,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.gremlin = c->options.gremlin;
#endif
- to.plugins = c->c1.plugins;
+ to.plugins = c->plugins;
#if P2MP_SERVER
to.auth_user_pass_verify_script = options->auth_user_pass_verify_script;
@@ -1724,7 +1734,7 @@ do_init_socket_1 (struct context *c, int mode)
c->options.inetd,
&c->c1.link_socket_addr,
c->options.ipchange,
- c->c1.plugins,
+ c->plugins,
c->options.resolve_retry_seconds,
c->options.connect_retry_seconds,
c->options.mtu_discover_type,
@@ -2094,32 +2104,68 @@ do_signal_on_tls_errors (struct context *c)
#endif
}
+#ifdef ENABLE_PLUGIN
-static void
-do_open_plugins (struct context *c)
+void
+open_plugins (struct context *c, const bool import_options)
{
-#ifdef ENABLE_PLUGIN
- if (c->options.plugin_list && !c->c1.plugins)
+ if (c->options.plugin_list && !c->plugins)
{
- c->c1.plugins = plugin_list_open (c->options.plugin_list, c->c2.es);
- c->c1.plugins_owned = true;
+ if (import_options)
+ {
+ struct plugin_return pr, config;
+ plugin_return_init (&pr);
+ c->plugins = plugin_list_open (c->options.plugin_list, &pr, c->c2.es);
+ c->plugins_owned = true;
+ plugin_return_get_column (&pr, &config, "config");
+ if (plugin_return_defined (&config))
+ {
+ int i;
+ for (i = 0; i < config.n; ++i)
+ {
+ unsigned int option_types_found = 0;
+ if (config.list[i] && config.list[i]->value)
+ options_plugin_import (&c->options,
+ config.list[i]->value,
+ D_IMPORT_ERRORS|M_OPTERR,
+ OPT_P_DEFAULT & ~OPT_P_PLUGIN,
+ &option_types_found,
+ c->es);
+ }
+ }
+ plugin_return_free (&pr);
+ }
+ else
+ {
+ c->plugins = plugin_list_open (c->options.plugin_list, NULL, c->c2.es);
+ c->plugins_owned = true;
+ }
}
-#endif
}
static void
do_close_plugins (struct context *c)
{
-#ifdef ENABLE_PLUGIN
- if (c->c1.plugins && c->c1.plugins_owned && !(c->sig->signal_received == SIGUSR1))
+ if (c->plugins && c->plugins_owned && !(c->sig->signal_received == SIGUSR1))
{
- plugin_list_close (c->c1.plugins);
- c->c1.plugins = NULL;
- c->c1.plugins_owned = false;
+ plugin_list_close (c->plugins);
+ c->plugins = NULL;
+ c->plugins_owned = false;
}
-#endif
}
+static void
+do_inherit_plugins (struct context *c, const struct context *src)
+{
+ if (!c->plugins && src->plugins)
+ {
+ c->plugins = plugin_list_inherit (src->plugins);
+ c->plugins_owned = true;
+ }
+}
+
+#endif
+
#ifdef ENABLE_MANAGEMENT
static void
@@ -2299,9 +2345,11 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
if (env)
do_inherit_env (c, env);
+#ifdef ENABLE_PLUGIN
/* initialize plugins */
if (c->mode == CM_P2P || c->mode == CM_TOP)
- do_open_plugins (c);
+ open_plugins (c, false);
+#endif
/* should we enable fast I/O? */
if (c->mode == CM_P2P || c->mode == CM_TOP)
@@ -2467,8 +2515,10 @@ close_instance (struct context *c)
/* close TUN/TAP device */
do_close_tun (c, false);
+#ifdef ENABLE_PLUGIN
/* call plugin close functions and unload */
do_close_plugins (c);
+#endif
/* close packet-id persistance file */
do_close_packet_id (c);
@@ -2538,8 +2588,10 @@ inherit_context_child (struct context *dest,
dest->c2.accept_from = src->c2.link_socket;
}
+#ifdef ENABLE_PLUGIN
/* inherit plugins */
- dest->c1.plugins = src->c1.plugins;
+ do_inherit_plugins (dest, src);
+#endif
/* context init */
init_instance (dest, src->c2.es, CC_USR1_TO_HUP | CC_GC_FREE);
@@ -2589,15 +2641,21 @@ inherit_context_top (struct context *dest,
gc_detach (&dest->gc);
gc_detach (&dest->c2.gc);
+ /* detach plugins */
+ dest->plugins_owned = false;
+
#if defined(USE_CRYPTO) && defined(USE_SSL)
dest->c2.tls_multi = NULL;
#endif
+ /* detach c1 ownership */
dest->c1.tuntap_owned = false;
dest->c1.status_output_owned = false;
#if P2MP_SERVER
dest->c1.ifconfig_pool_persist_owned = false;
#endif
+
+ /* detach c2 ownership */
dest->c2.event_set_owned = false;
dest->c2.link_socket_owned = false;
dest->c2.buffers_owned = false;
@@ -2715,7 +2773,7 @@ do_test_crypto (const struct options *o)
/* print version number */
msg (M_INFO, "%s", title_string);
- context_clear (&c);
+ context_clear (&c);
c.options = *o;
options_detach (&c.options);
c.first_time = true;
diff --git a/init.h b/init.h
index 6346e1a..bbb3b0a 100644
--- a/init.h
+++ b/init.h
@@ -77,7 +77,7 @@ void do_up (struct context *c,
bool pulled_options,
unsigned int option_types_found);
-unsigned int pull_permission_mask (void);
+unsigned int pull_permission_mask (const struct context *c);
const char *format_common_name (struct context *c, struct gc_arena *gc);
@@ -117,4 +117,8 @@ void management_show_net_callback (void *arg, const int msglevel);
void init_management_callback_p2p (struct context *c);
void uninit_management_callback (void);
+#ifdef ENABLE_PLUGIN
+void open_plugins (struct context *c, const bool import_options);
+#endif
+
#endif
diff --git a/install-win32/openvpn.nsi.in b/install-win32/openvpn.nsi.in
index 076479b..5813420 100755
--- a/install-win32/openvpn.nsi.in
+++ b/install-win32/openvpn.nsi.in
@@ -10,7 +10,7 @@
!include "MUI.nsh"
!include "setpath.nsi"
-!define HOME "c:\src\openvpn"
+!define HOME ".."
!define BIN "${HOME}\bin"
!define PRODUCT_NAME "OpenVPN"
diff --git a/manage.c b/manage.c
index f9ec934..f76ec7a 100644
--- a/manage.c
+++ b/manage.c
@@ -43,6 +43,14 @@
#include "memdbg.h"
+#define MANAGEMENT_ECHO_PULL_INFO 0 // JYFIXME
+
+#if MANAGEMENT_ECHO_PULL_INFO
+#define MANAGEMENT_ECHO_FLAGS LOG_PRINT_INTVAL
+#else
+#define MANAGEMENT_ECHO_FLAGS 0
+#endif
+
struct management *management; /* GLOBAL */
/* static forward declarations */
@@ -429,7 +437,7 @@ man_echo (struct management *man, const char *parm)
"echo",
man->persist.echo,
&man->connection.echo_realtime,
- LOG_PRINT_INT_DATE);
+ LOG_PRINT_INT_DATE|MANAGEMENT_ECHO_FLAGS);
}
static void
@@ -1361,7 +1369,7 @@ management_set_state (struct management *man,
}
void
-management_echo (struct management *man, const char *string)
+management_echo (struct management *man, const char *string, const bool pull)
{
if (man->persist.echo)
{
@@ -1372,13 +1380,13 @@ management_echo (struct management *man, const char *string)
update_time ();
CLEAR (e);
e.timestamp = now;
- e.u.msg_flags = 0;
e.string = string;
-
+ e.u.intval = BOOL_CAST (pull);
+
log_history_add (man->persist.echo, &e);
if (man->connection.echo_realtime)
- out = log_entry_print (&e, LOG_PRINT_INT_DATE|LOG_PRINT_ECHO_PREFIX|LOG_PRINT_CRLF, &gc);
+ out = log_entry_print (&e, LOG_PRINT_INT_DATE|LOG_PRINT_ECHO_PREFIX|LOG_PRINT_CRLF|MANAGEMENT_ECHO_FLAGS, &gc);
if (out)
man_output_list_push (man, out);
@@ -2028,6 +2036,8 @@ log_entry_print (const struct log_entry *e, unsigned int flags, struct gc_arena
buf_printf (&out, "%s,", msg_flags_string (e->u.msg_flags, gc));
if (flags & LOG_PRINT_STATE)
buf_printf (&out, "%s,", man_state_name (e->u.state));
+ if (flags & LOG_PRINT_INTVAL)
+ buf_printf (&out, "%d,", e->u.intval);
if (e->string)
buf_printf (&out, "%s", e->string);
if (flags & LOG_PRINT_LOCAL_IP)
diff --git a/manage.h b/manage.h
index d2dfd04..8015226 100644
--- a/manage.h
+++ b/manage.h
@@ -89,6 +89,7 @@ void output_list_advance (struct output_list *ol, int n);
union log_entry_union {
unsigned int msg_flags;
int state;
+ int intval;
};
struct log_entry
@@ -111,6 +112,8 @@ struct log_entry
#define LOG_PRINT_CRLF (1<<7)
#define LOG_FATAL_NOTIFY (1<<8)
+#define LOG_PRINT_INTVAL (1<<9)
+
const char *log_entry_print (const struct log_entry *e, unsigned int flags, struct gc_arena *gc);
struct log_history
@@ -327,7 +330,7 @@ void management_set_state (struct management *man,
* The management object keeps track of OpenVPN --echo
* parameters.
*/
-void management_echo (struct management *man, const char *string);
+void management_echo (struct management *man, const char *string, const bool pull);
/*
* OpenVPN calls here to indicate a password failure
diff --git a/misc.c b/misc.c
index 20dae2e..f4e7079 100644
--- a/misc.c
+++ b/misc.c
@@ -206,7 +206,7 @@ run_up_down (const char *command,
ifconfig_local, ifconfig_remote,
context);
- if (plugin_call (plugins, plugin_type, BSTR (&cmd), es))
+ if (plugin_call (plugins, plugin_type, BSTR (&cmd), NULL, es))
msg (M_FATAL, "ERROR: up/down plugin call failed");
}
diff --git a/multi.c b/multi.c
index cf10b51..b467963 100644
--- a/multi.c
+++ b/multi.c
@@ -64,6 +64,7 @@ learn_address_script (const struct multi_context *m,
struct gc_arena gc = gc_new ();
struct env_set *es;
bool ret = true;
+ struct plugin_list *plugins;
/* get environmental variable source */
if (mi && mi->context.c2.es)
@@ -71,7 +72,13 @@ learn_address_script (const struct multi_context *m,
else
es = env_set_create (&gc);
- if (plugin_defined (m->top.c1.plugins, OPENVPN_PLUGIN_LEARN_ADDRESS))
+ /* get plugin source */
+ if (mi)
+ plugins = mi->context.plugins;
+ else
+ plugins = m->top.plugins;
+
+ if (plugin_defined (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS))
{
struct buffer cmd = alloc_buf_gc (256, &gc);
@@ -81,7 +88,7 @@ learn_address_script (const struct multi_context *m,
if (mi)
buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, false));
- if (plugin_call (m->top.c1.plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, BSTR (&cmd), es))
+ if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, BSTR (&cmd), NULL, es))
{
msg (M_WARN, "WARNING: learn-address plugin call failed");
ret = false;
@@ -278,7 +285,7 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
*/
if (t->options.ifconfig_pool_defined)
{
- if (dev == DEV_TYPE_TAP || t->options.ifconfig_pool_linear)
+ if (dev == DEV_TYPE_TAP)
{
m->ifconfig_pool = ifconfig_pool_init (IFCONFIG_POOL_INDIV,
t->options.ifconfig_pool_start,
@@ -287,10 +294,11 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
}
else if (dev == DEV_TYPE_TUN)
{
- m->ifconfig_pool = ifconfig_pool_init (IFCONFIG_POOL_30NET,
- t->options.ifconfig_pool_start,
- t->options.ifconfig_pool_end,
- t->options.duplicate_cn);
+ m->ifconfig_pool = ifconfig_pool_init (
+ (t->options.topology == TOP_NET30) ? IFCONFIG_POOL_30NET : IFCONFIG_POOL_INDIV,
+ t->options.ifconfig_pool_start,
+ t->options.ifconfig_pool_end,
+ t->options.duplicate_cn);
}
else
{
@@ -409,9 +417,9 @@ multi_client_disconnect_script (struct multi_context *m,
{
multi_client_disconnect_setenv (m, mi);
- if (plugin_defined (m->top.c1.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT))
+ if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT))
{
- if (plugin_call (m->top.c1.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, mi->context.c2.es))
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es))
msg (M_WARN, "WARNING: client-disconnect plugin call failed");
}
@@ -759,6 +767,31 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
{
status_printf (so, "ERROR: bad status format version number");
}
+
+#ifdef PACKET_TRUNCATION_CHECK
+ {
+ status_printf (so, "HEADER,ERRORS,Common Name,TUN Read Trunc,TUN Write Trunc,Pre-encrypt Trunc,Post-decrypt Trunc");
+ hash_iterator_init (m->hash, &hi, true);
+ while ((he = hash_iterator_next (&hi)))
+ {
+ struct gc_arena gc = gc_new ();
+ const struct multi_instance *mi = (struct multi_instance *) he->value;
+
+ if (!mi->halt)
+ {
+ status_printf (so, "ERRORS,%s," counter_format "," counter_format "," counter_format "," counter_format,
+ tls_common_name (mi->context.c2.tls_multi, false),
+ m->top.c2.n_trunc_tun_read,
+ mi->context.c2.n_trunc_tun_write,
+ mi->context.c2.n_trunc_pre_encrypt,
+ mi->context.c2.n_trunc_post_decrypt);
+ }
+ gc_free (&gc);
+ }
+ hash_iterator_free (&hi);
+ }
+#endif
+
status_flush (so);
gc_free (&gc_top);
}
@@ -1034,6 +1067,20 @@ multi_delete_dup (struct multi_context *m, struct multi_instance *new_mi)
}
/*
+ * Ensure that endpoint to be pushed to client
+ * complies with --ifconfig-push-constraint directive.
+ */
+static bool
+ifconfig_push_constraint_satisfied (const struct context *c)
+{
+ const struct options *o = &c->options;
+ if (o->push_ifconfig_constraint_defined && c->c2.push_ifconfig_defined)
+ return (o->push_ifconfig_constraint_netmask & c->c2.push_ifconfig_local) == o->push_ifconfig_constraint_network;
+ else
+ return true;
+}
+
+/*
* Select a virtual address for a new client instance.
* Use an --ifconfig-push directive, if given (static IP).
* Otherwise use an --ifconfig-pool address (dynamic IP).
@@ -1072,27 +1119,30 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, cn);
if (mi->vaddr_handle >= 0)
{
- /* use pool ifconfig address(es) */
+ const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap);
+ const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap);
+
+ /* set push_ifconfig_remote_netmask from pool ifconfig address(es) */
mi->context.c2.push_ifconfig_local = remote;
- if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN)
- {
- if (mi->context.options.ifconfig_pool_linear)
- mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->local;
- else
- mi->context.c2.push_ifconfig_remote_netmask = local;
- mi->context.c2.push_ifconfig_defined = true;
- }
- else if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TAP)
+ if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET))
{
mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask;
if (!mi->context.c2.push_ifconfig_remote_netmask)
mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask;
- if (mi->context.c2.push_ifconfig_remote_netmask)
- mi->context.c2.push_ifconfig_defined = true;
- else
- msg (D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s",
- multi_instance_string (mi, false, &gc));
}
+ else if (tunnel_type == DEV_TYPE_TUN)
+ {
+ if (tunnel_topology == TOP_P2P)
+ mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->local;
+ else if (tunnel_topology == TOP_NET30)
+ mi->context.c2.push_ifconfig_remote_netmask = local;
+ }
+
+ if (mi->context.c2.push_ifconfig_remote_netmask)
+ mi->context.c2.push_ifconfig_defined = true;
+ else
+ msg (D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s",
+ multi_instance_string (mi, false, &gc));
}
else
{
@@ -1114,22 +1164,25 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi)
if (mi->context.c2.push_ifconfig_defined)
{
+ const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap);
+ const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap);
+
setenv_in_addr_t (mi->context.c2.es,
"ifconfig_pool_remote_ip",
mi->context.c2.push_ifconfig_local,
SA_SET_IF_NONZERO);
- if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN)
+ if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET))
{
setenv_in_addr_t (mi->context.c2.es,
- "ifconfig_pool_local_ip",
+ "ifconfig_pool_netmask",
mi->context.c2.push_ifconfig_remote_netmask,
SA_SET_IF_NONZERO);
}
- else if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TAP)
+ else if (tunnel_type == DEV_TYPE_TUN)
{
setenv_in_addr_t (mi->context.c2.es,
- "ifconfig_pool_netmask",
+ "ifconfig_pool_local_ip",
mi->context.c2.push_ifconfig_remote_netmask,
SA_SET_IF_NONZERO);
}
@@ -1137,7 +1190,7 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi)
}
/*
- * Called after client-connect script or plug-in is called
+ * Called after client-connect script is called
*/
static void
multi_client_connect_post (struct multi_context *m,
@@ -1171,6 +1224,50 @@ multi_client_connect_post (struct multi_context *m,
}
}
+#ifdef ENABLE_PLUGIN
+
+/*
+ * Called after client-connect plug-in is called
+ */
+static void
+multi_client_connect_post_plugin (struct multi_context *m,
+ struct multi_instance *mi,
+ const struct plugin_return *pr,
+ unsigned int option_permissions_mask,
+ unsigned int *option_types_found)
+{
+ struct plugin_return config;
+
+ plugin_return_get_column (pr, &config, "config");
+
+ /* Did script generate a dynamic config file? */
+ if (plugin_return_defined (&config))
+ {
+ int i;
+ for (i = 0; i < config.n; ++i)
+ {
+ if (config.list[i] && config.list[i]->value)
+ options_plugin_import (&mi->context.options,
+ config.list[i]->value,
+ D_IMPORT_ERRORS|M_OPTERR,
+ option_permissions_mask,
+ option_types_found,
+ mi->context.c2.es);
+ }
+
+ /*
+ * If the --client-connect script generates a config file
+ * with an --ifconfig-push directive, it will override any
+ * --ifconfig-push directive from the --client-config-dir
+ * directory or any --ifconfig-pool dynamic address.
+ */
+ multi_select_virtual_addr (m, mi);
+ multi_set_virtual_addr_env (m, mi);
+ }
+}
+
+#endif
+
/*
* Called as soon as the SSL/TLS connection authenticates.
*
@@ -1261,16 +1358,19 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
/* setenv client virtual IP address */
multi_set_virtual_addr_env (m, mi);
+#ifdef ENABLE_PLUGIN
/*
* Call client-connect plug-in.
*/
- if (plugin_defined (m->top.c1.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT))
+
+ /* deprecated callback, use a file for passing back return info */
+ if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT))
{
const char *dc_file = create_temp_filename (mi->context.options.tmp_dir, &gc);
delete_file (dc_file);
- if (plugin_call (m->top.c1.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, dc_file, mi->context.c2.es))
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, dc_file, NULL, mi->context.c2.es))
{
msg (M_WARN, "WARNING: client-connect plugin call failed");
cc_succeeded = false;
@@ -1282,6 +1382,28 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
}
}
+ /* V2 callback, use a plugin_return struct for passing back return info */
+ if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2))
+ {
+ struct plugin_return pr;
+
+ plugin_return_init (&pr);
+
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es))
+ {
+ msg (M_WARN, "WARNING: client-connect-v2 plugin call failed");
+ cc_succeeded = false;
+ }
+ else
+ {
+ multi_client_connect_post_plugin (m, mi, &pr, option_permissions_mask, &option_types_found);
+ ++cc_succeeded_count;
+ }
+
+ plugin_return_free (&pr);
+ }
+#endif
+
/*
* Run --client-connect script.
*/
@@ -1336,6 +1458,19 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
}
/*
+ * make sure that ifconfig settings comply with constraints
+ */
+ if (!ifconfig_push_constraint_satisfied (&mi->context))
+ {
+ /* JYFIXME -- this should cause the connection to fail */
+ msg (D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) violates tunnel network/netmask constraint (%s/%s)",
+ multi_instance_string (mi, false, &gc),
+ print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc),
+ print_in_addr_t (mi->context.options.push_ifconfig_constraint_network, 0, &gc),
+ print_in_addr_t (mi->context.options.push_ifconfig_constraint_netmask, 0, &gc));
+ }
+
+ /*
* For routed tunnels, set up internal route to endpoint
* plus add all iroute routes.
*/
diff --git a/openvpn-plugin.h b/openvpn-plugin.h
index fcd823e..62124e8 100644
--- a/openvpn-plugin.h
+++ b/openvpn-plugin.h
@@ -22,6 +22,8 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#define OPENVPN_PLUGIN_VERSION 2
+
/*
* Plug-in types. These types correspond to the set of script callbacks
* supported by OpenVPN.
@@ -35,7 +37,8 @@
#define OPENVPN_PLUGIN_CLIENT_CONNECT 6
#define OPENVPN_PLUGIN_CLIENT_DISCONNECT 7
#define OPENVPN_PLUGIN_LEARN_ADDRESS 8
-#define OPENVPN_PLUGIN_N 9
+#define OPENVPN_PLUGIN_CLIENT_CONNECT_V2 9
+#define OPENVPN_PLUGIN_N 10
/*
* Build a mask out of a set of plug-in types.
@@ -86,6 +89,20 @@ typedef void *openvpn_plugin_handle_t;
#endif
/*
+ * Used by openvpn_plugin_func to return structured
+ * data. The plugin should allocate all structure
+ * instances, name strings, and value strings with
+ * malloc, since OpenVPN will assume that it
+ * can free the list by calling free() over the same.
+ */
+struct openvpn_plugin_string_list
+{
+ struct openvpn_plugin_string_list *next;
+ char *name;
+ char *value;
+};
+
+/*
* Multiple plugin modules can be cascaded, and modules can be
* used in tandem with scripts. The order of operation is that
* the module func() functions are called in the order that
@@ -113,7 +130,7 @@ typedef void *openvpn_plugin_handle_t;
*/
/*
- * FUNCTION: openvpn_plugin_open_v1
+ * FUNCTION: openvpn_plugin_open_v2
*
* REQUIRED: YES
*
@@ -141,15 +158,20 @@ typedef void *openvpn_plugin_handle_t;
* these variables are not actually written to the "official"
* environmental variable store of the process.
*
+ * return_list : used to return data back to OpenVPN.
+ *
* RETURN VALUE
*
* An openvpn_plugin_handle_t value on success, NULL on failure
*/
-OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v1)
- (unsigned int *type_mask, const char *argv[], const char *envp[]);
+OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v2)
+ (unsigned int *type_mask,
+ const char *argv[],
+ const char *envp[],
+ struct openvpn_plugin_string_list **return_list);
/*
- * FUNCTION: openvpn_plugin_func_v1
+ * FUNCTION: openvpn_plugin_func_v2
*
* Called to perform the work of a given script type.
*
@@ -158,7 +180,7 @@ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_op
* ARGUMENTS
*
* handle : the openvpn_plugin_handle_t value which was returned by
- * openvpn_plugin_open_v1.
+ * openvpn_plugin_open.
*
* type : one of the PLUGIN_x types
*
@@ -171,12 +193,22 @@ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_op
* these variables are not actually written to the "official"
* environmental variable store of the process.
*
+ * per_client_context : the per-client context pointer which was returned by
+ * openvpn_plugin_client_constructor_v1, if defined.
+ *
+ * return_list : used to return data back to OpenVPN.
+ *
* RETURN VALUE
*
* OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure
*/
-OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v1)
- (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]);
+OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
+ (openvpn_plugin_handle_t handle,
+ const int type,
+ const char *argv[],
+ const char *envp[],
+ void *per_client_context,
+ struct openvpn_plugin_string_list **return_list);
/*
* FUNCTION: openvpn_plugin_close_v1
@@ -186,7 +218,7 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v1)
* ARGUMENTS
*
* handle : the openvpn_plugin_handle_t value which was returned by
- * openvpn_plugin_open_v1.
+ * openvpn_plugin_open.
*
* Called immediately prior to plug-in unload.
*/
@@ -201,11 +233,86 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_close_v1)
* ARGUMENTS
*
* handle : the openvpn_plugin_handle_t value which was returned by
- * openvpn_plugin_open_v1.
+ * openvpn_plugin_open.
*
* Called when OpenVPN is in the process of aborting due to a fatal error.
* Will only be called on an open context returned by a prior successful
- * openvpn_plugin_open_v1 callback.
+ * openvpn_plugin_open callback.
*/
OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_abort_v1)
(openvpn_plugin_handle_t handle);
+
+/*
+ * FUNCTION: openvpn_plugin_client_constructor_v1
+ *
+ * Called to allocate a per-client memory region, which
+ * is then passed to the openvpn_plugin_func_v2 function.
+ * This function is called every time the OpenVPN server
+ * constructs a client instance object, which normally
+ * occurs when a session-initiating packet is received
+ * by a new client, even before the client has authenticated.
+ *
+ * This function should allocate the private memory needed
+ * by the plugin to track individual OpenVPN clients, and
+ * return a void * to this memory region.
+ *
+ * REQUIRED: NO
+ *
+ * ARGUMENTS
+ *
+ * handle : the openvpn_plugin_handle_t value which was returned by
+ * openvpn_plugin_open.
+ *
+ * RETURN VALUE
+ *
+ * void * pointer to plugin's private per-client memory region, or NULL
+ * if no memory region is required.
+ */
+OPENVPN_PLUGIN_DEF void * OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_v1)
+ (openvpn_plugin_handle_t handle);
+
+/*
+ * FUNCTION: openvpn_plugin_client_destructor_v1
+ *
+ * This function is called on client instance object destruction.
+ *
+ * REQUIRED: NO
+ *
+ * ARGUMENTS
+ *
+ * handle : the openvpn_plugin_handle_t value which was returned by
+ * openvpn_plugin_open.
+ *
+ * per_client_context : the per-client context pointer which was returned by
+ * openvpn_plugin_client_constructor_v1, if defined.
+ */
+OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_destructor_v1)
+ (openvpn_plugin_handle_t handle, void *per_client_context);
+
+/*
+ * FUNCTION: openvpn_plugin_min_version_required_v1
+ *
+ * This function is called by OpenVPN to query the minimum
+ plugin interface version number required by the plugin.
+ *
+ * REQUIRED: NO
+ *
+ * RETURN VALUE
+ *
+ * The minimum OpenVPN plugin interface version number necessary to support
+ * this plugin.
+ */
+OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_min_version_required_v1)
+ (void);
+
+/*
+ * Deprecated functions which are still supported for backward compatibility.
+ */
+
+OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v1)
+ (unsigned int *type_mask,
+ const char *argv[],
+ const char *envp[]);
+
+OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v1)
+ (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]);
diff --git a/openvpn.8 b/openvpn.8
index ce7bfc8..8d55815 100644
--- a/openvpn.8
+++ b/openvpn.8
@@ -94,6 +94,7 @@ openvpn \- secure IP tunnel daemon.
.in +4
.ti -4
.B openvpn
+[\ \fB\-\-allow\-nonadmin\fR\ \fI[TAP\-adapter]\fR\ ]
[\ \fB\-\-askpass\fR\ \fI[file]\fR\ ]
[\ \fB\-\-auth\-nocache\fR\ ]
[\ \fB\-\-auth\-retry\fR\ \fItype\fR\ ]
@@ -209,7 +210,7 @@ openvpn \- secure IP tunnel daemon.
[\ \fB\-\-push\-reset\fR\ ]
[\ \fB\-\-push\fR\ \fI"option"\fR\ ]
[\ \fB\-\-rcvbuf\fR\ \fIsize\fR\ ]
-[\ \fB\-\-redirect\-gateway\fR\ \fI["local"]\ ["def1"]\fR\ ]
+[\ \fB\-\-redirect\-gateway\fR\ \fIflags...\fR\ ]
[\ \fB\-\-remap\-usr1\fR\ \fIsignal\fR\ ]
[\ \fB\-\-remote\-random\fR\ ]
[\ \fB\-\-remote\fR\ \fIhost\ [port]\fR\ ]
@@ -261,6 +262,7 @@ openvpn \- secure IP tunnel daemon.
[\ \fB\-\-tls\-timeout\fR\ \fIn\fR\ ]
[\ \fB\-\-tls\-verify\fR\ \fIcmd\fR\ ]
[\ \fB\-\-tmp\-dir\fR\ \fIdir\fR\ ]
+[\ \fB\-\-topology\fR\ \fImode\fR\ ]
[\ \fB\-\-tran\-window\fR\ \fIn\fR\ ]
[\ \fB\-\-tun\-ipv6\fR\ ]
[\ \fB\-\-tun\-mtu\-extra\fR\ \fIn\fR\ ]
@@ -732,9 +734,9 @@ or tap devices on both ends. You cannot mix them, as they
represent different underlying protocols.
.B tun
-devices encapsulate IPv4 while
+devices encapsulate IPv4 or IPv6 while
.B tap
-devices encapsulate ethernet 802.3.
+devices encapsulate Ethernet 802.3.
.\"*********************************************************
.TP
.B --dev-type device-type
@@ -752,6 +754,60 @@ or
.B tap.
.\"*********************************************************
.TP
+.B --topology mode
+Configure virtual addressing topology when running in
+.B --dev tun
+mode. This directive has no meaning in
+.B --dev tap
+mode, which always uses a
+.B subnet
+topology.
+
+If you set this directive on the server, the
+.B --server
+and
+.B --server-bridge
+directives will automatically push your chosen topology setting to clients
+as well. This directive can also be manually pushed to clients. Like the
+.B --dev
+directive, this directive must always be compatible between client and server.
+
+.B mode
+can be one of:
+
+.B net30 --
+Use a point-to-point topology, by allocating one /30 subnet per client.
+This is designed to allow point-to-point semantics when some
+or all of the connecting clients might be Windows systems. This is the
+default on OpenVPN 2.0.
+
+.B p2p --
+Use a point-to-point topology where the remote endpoint of the client's
+tun interface always points to the local endpoint of the server's tun interface.
+This mode allocates a single IP address per connecting client.
+Only use
+when none of the connecting clients are Windows systems. This mode
+is functionally equivalent to the
+.B --ifconfig-pool-linear
+directive which is available in OpenVPN 2.0 and is now deprecated.
+
+.B subnet --
+Use a subnet rather than a point-to-point topology by
+configuring the tun interface with a local IP address and subnet mask,
+similar to the topology used in
+.B --dev tap
+and ethernet bridging mode.
+This mode allocates a single IP address per connecting client and works on
+Windows as well. Only available when server and clients are OpenVPN 2.1 or
+higher, or OpenVPN 2.0.x which has been manually patched with the
+.B --topology
+directive code. When used on Windows, requires version 8.2 or higher
+of the TAP-Win32 driver. When used on *nix, requires that the tun
+driver supports an
+.BR ifconfig (8)
+command which sets a subnet instead of a remote endpoint IP address.
+.\"*********************************************************
+.TP
.B --tun-ipv6
Build a tun link capable of forwarding IPv6 traffic.
Should be used in conjunction with
@@ -996,7 +1052,7 @@ Don't add or remove routes automatically. Instead pass routes to
script using environmental variables.
.\"*********************************************************
.TP
-.B --redirect-gateway ["local"] ["def1"]
+.B --redirect-gateway flags...
(Experimental) Automatically execute routing commands to cause all outgoing IP traffic
to be redirected over the VPN.
@@ -1025,6 +1081,9 @@ is specified).
When the tunnel is torn down, all of the above steps are reversed so
that the original default route is restored.
+Option flags:
+
+.B local --
Add the
.B local
flag if both OpenVPN servers are directly connected via a common subnet,
@@ -1034,13 +1093,24 @@ flag will cause step
.B 1
above to be omitted.
-Add the
-.B def1
-flag to override
+.B def1 --
+Use this flag to override
the default gateway by using 0.0.0.0/1 and 128.0.0.0/1
rather than 0.0.0.0/0. This has the benefit of overriding
but not wiping out the original default gateway.
+.B bypass-dhcp --
+Add a direct route to the DHCP server (if it is non-local) which
+bypasses the tunnel
+(Available on Windows clients, may not be available
+on non-Windows clients).
+
+.B bypass-dns --
+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
+on non-Windows clients).
+
Using the def1 flag is highly recommended, and is currently
planned to become the default by OpenVPN 2.1.
.\"*********************************************************
@@ -2153,17 +2223,18 @@ expands as follows:
.sp
mode server
tls-server
+ push "topology [topology]"
- if dev tun:
+ if dev tun AND (topology == net30 OR topology == p2p):
ifconfig 10.8.0.1 10.8.0.2
ifconfig-pool 10.8.0.4 10.8.0.251
route 10.8.0.0 255.255.255.0
if client-to-client:
push "route 10.8.0.0 255.255.255.0"
- else
+ else if topology == net30:
push "route 10.8.0.1"
- if dev tap:
+ if dev tap OR (dev tun AND topology == subnet):
ifconfig 10.8.0.1 255.255.255.0
ifconfig-pool 10.8.0.2 10.8.0.254 255.255.255.0
push "route-gateway 10.8.0.1"
@@ -2346,6 +2417,10 @@ directive to
allocate individual TUN interface addresses for
clients rather than /30 subnets. NOTE: This option
is incompatible with Windows clients.
+
+This option is deprecated, and should be replaced with
+.B --topology p2p
+which is functionally equivalent.
.\"*********************************************************
.TP
.B --ifconfig-push local remote-netmask
@@ -4136,6 +4211,21 @@ option. On non-Windows systems, the
command provides similar functionality.
.\"*********************************************************
.TP
+.B --allow-nonadmin [TAP-adapter]
+(Standalone)
+Set
+.B TAP-adapter
+to allow access from non-administrative accounts. If
+.B TAP-adapter
+is omitted, all TAP adapters on the system will be configured to allow
+non-admin access.
+The non-admin access setting will only persist for the length of time that
+the TAP-Win32 device object and driver remain loaded, and will need
+to be re-enabled after a reboot, or if the driver is unloaded
+and reloaded.
+This directive can only be used by an administrator.
+.\"*********************************************************
+.TP
.B --show-valid-subnets
(Standalone)
Show valid subnets for
diff --git a/openvpn.c b/openvpn.c
index 47701f9..41150de 100644
--- a/openvpn.c
+++ b/openvpn.c
@@ -146,6 +146,12 @@ main (int argc, char *argv[])
/* parse command line options, and read configuration file */
parse_argv (&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es);
+#ifdef ENABLE_PLUGIN
+ /* plugins may contribute options configuration */
+ init_verb_mute (&c, IVM_LEVEL_1);
+ open_plugins (&c, true);
+#endif
+
/* init verbosity and mute levels */
init_verb_mute (&c, IVM_LEVEL_1);
diff --git a/openvpn.h b/openvpn.h
index 1ddcd59..5c93c8d 100644
--- a/openvpn.h
+++ b/openvpn.h
@@ -156,10 +156,6 @@ struct context_1
struct socks_proxy_info *socks_proxy;
#endif
- /* shared object plugins */
- struct plugin_list *plugins;
- bool plugins_owned;
-
#if P2MP
#if P2MP_SERVER
@@ -237,6 +233,12 @@ struct context_2
counter_type link_read_bytes;
counter_type link_read_bytes_auth;
counter_type link_write_bytes;
+#ifdef PACKET_TRUNCATION_CHECK
+ counter_type n_trunc_tun_read;
+ counter_type n_trunc_tun_write;
+ counter_type n_trunc_pre_encrypt;
+ counter_type n_trunc_post_decrypt;
+#endif
/*
* Timer objects for ping and inactivity
@@ -447,6 +449,10 @@ struct context
/* signal info */
struct signal_info *sig;
+ /* shared object plugins */
+ struct plugin_list *plugins;
+ bool plugins_owned;
+
/* level 1 context is preserved for
SIGUSR1 restarts, but initialized
for SIGHUP restarts */
diff --git a/options.c b/options.c
index 23383ba..77867ca 100644
--- a/options.c
+++ b/options.c
@@ -64,7 +64,7 @@ const char title_string[] =
#endif
#endif
#ifdef USE_LZO
- " [LZO]"
+ " [LZO" LZO_VERSION_NUM "]"
#endif
#if EPOLL
" [EPOLL]"
@@ -129,6 +129,7 @@ static const char usage_message[] =
" does not begin with \"tun\" or \"tap\".\n"
"--dev-node node : Explicitly set the device node rather than using\n"
" /dev/net/tun, /dev/tun, /dev/tap, etc.\n"
+ "--topology t : Set --dev tun topology: 'net30', 'p2p', or 'subnet'.\n"
"--tun-ipv6 : Build tun link capable of forwarding IPv6 traffic.\n"
"--ifconfig l rn : TUN: configure device to use IP address l as a local\n"
" endpoint and rn as a remote endpoint. l & rn should be\n"
@@ -159,7 +160,9 @@ static const char usage_message[] =
" VPN. Add 'local' flag if both " PACKAGE_NAME " servers are directly\n"
" connected via a common subnet, such as with WiFi.\n"
" Add 'def1' flag to set default route using using 0.0.0.0/1\n"
- " and 128.0.0.0/1 rather than 0.0.0.0/0.\n"
+ " and 128.0.0.0/1 rather than 0.0.0.0/0. Add 'bypass-dhcp'\n"
+ " flag to add a direct route to DHCP server, bypassing tunnel.\n"
+ " Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n"
"--setenv name value : Set a custom environmental variable to pass to script.\n"
"--shaper n : Restrict output to peer to n bytes per second.\n"
"--keepalive n m : Helper option for setting timeouts in server mode. Send\n"
@@ -496,6 +499,8 @@ static const char usage_message[] =
"--show-adapters : Show all TAP-Win32 adapters.\n"
"--show-net : Show " PACKAGE_NAME "'s view of routing table and net adapter list.\n"
"--show-valid-subnets : Show valid subnets for --dev tun emulation.\n"
+ "--allow-nonadmin [TAP-adapter] : Allow " PACKAGE_NAME " running without admin privileges\n"
+ " to access TAP adapter.\n"
#endif
"\n"
"Generate a random key (only for non-TLS static key encryption mode):\n"
@@ -526,6 +531,7 @@ init_options (struct options *o)
CLEAR (*o);
gc_init (&o->gc);
o->mode = MODE_POINT_TO_POINT;
+ o->topology = TOP_NET30;
o->proto = PROTO_UDPv4;
o->connect_retry_seconds = 5;
o->local_port = o->remote_port = OPENVPN_PORT;
@@ -793,7 +799,6 @@ show_p2mp_parms (const struct options *o)
msg (D_SHOW_PARMS, " ifconfig_pool_netmask = %s", print_in_addr_t (o->ifconfig_pool_netmask, 0, &gc));
SHOW_STR (ifconfig_pool_persist_filename);
SHOW_INT (ifconfig_pool_persist_refresh_freq);
- SHOW_BOOL (ifconfig_pool_linear);
SHOW_INT (n_bcast_buf);
SHOW_INT (tcp_queue_limit);
SHOW_INT (real_hash_size);
@@ -959,6 +964,7 @@ show_settings (const struct options *o)
SHOW_STR (dev);
SHOW_STR (dev_type);
SHOW_STR (dev_node);
+ SHOW_INT (topology);
SHOW_BOOL (tun_ipv6);
SHOW_STR (ifconfig_local);
SHOW_STR (ifconfig_remote_netmask);
@@ -1066,6 +1072,7 @@ show_settings (const struct options *o)
SHOW_INT (route_delay);
SHOW_INT (route_delay_window);
SHOW_BOOL (route_delay_defined);
+ SHOW_BOOL (route_nopull);
if (o->routes)
print_route_options (o->routes, D_SHOW_PARMS);
@@ -1463,13 +1470,13 @@ options_postprocess (struct options *options, bool first_time)
msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
if (options->proto != PROTO_UDPv4 && (options->cf_max || options->cf_per))
msg (M_USAGE, "--connect-freq only works with --mode server --proto udp. Try --max-clients instead.");
- if (dev != DEV_TYPE_TAP && options->ifconfig_pool_netmask)
+ if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask)
msg (M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode");
#ifdef ENABLE_OCC
if (options->explicit_exit_notification)
msg (M_USAGE, "--explicit-exit-notify cannot be used with --mode server");
#endif
- if (options->routes && options->routes->redirect_default_gateway)
+ if (options->routes && (options->routes->flags & RG_ENABLE))
msg (M_USAGE, "--redirect-gateway cannot be used with --mode server (however --push \"redirect-gateway\" is fine)");
if (options->route_delay_defined)
msg (M_USAGE, "--route-delay cannot be used with --mode server");
@@ -1525,8 +1532,6 @@ options_postprocess (struct options *options, bool first_time)
msg (M_USAGE, "--username-as-common-name requires --mode server");
if (options->auth_user_pass_verify_script)
msg (M_USAGE, "--auth-user-pass-verify requires --mode server");
- if (options->ifconfig_pool_linear)
- msg (M_USAGE, "--ifconfig-pool-linear requires --mode server");
}
#endif /* P2MP_SERVER */
@@ -1804,6 +1809,7 @@ options_string (const struct options *o,
{
tt = init_tun (o->dev,
o->dev_type,
+ o->topology,
o->ifconfig_local,
o->ifconfig_remote_netmask,
(in_addr_t)0,
@@ -2117,6 +2123,44 @@ foreign_option (struct options *o, char *argv[], int len, struct env_set *es)
}
}
+/*
+ * parse/print topology coding
+ */
+
+int
+parse_topology (const char *str, const int msglevel)
+{
+ if (streq (str, "net30"))
+ return TOP_NET30;
+ else if (streq (str, "p2p"))
+ return TOP_P2P;
+ else if (streq (str, "subnet"))
+ return TOP_SUBNET;
+ else
+ {
+ msg (msglevel, "--topology must be net30, p2p, or subnet");
+ return TOP_UNDEF;
+ }
+}
+
+const char *
+print_topology (const int topology)
+{
+ switch (topology)
+ {
+ case TOP_UNDEF:
+ return "undef";
+ case TOP_NET30:
+ return "net30";
+ case TOP_P2P:
+ return "p2p";
+ case TOP_SUBNET:
+ return "subnet";
+ default:
+ return "unknown";
+ }
+}
+
#if P2MP
/*
@@ -2405,6 +2449,13 @@ parse_line (const char *line,
return ret;
}
+static void
+bypass_doubledash (char **p)
+{
+ if (strlen (*p) >= 3 && !strncmp (*p, "--", 2))
+ *p += 2;
+}
+
static int
add_option (struct options *options,
int i,
@@ -2432,6 +2483,7 @@ read_config_file (struct options *options,
FILE *fp;
int line_num;
char line[OPTION_LINE_SIZE];
+ char *p[MAX_PARMS];
++level;
if (level <= max_recursive_levels)
@@ -2442,13 +2494,11 @@ read_config_file (struct options *options,
line_num = 0;
while (fgets(line, sizeof (line), fp))
{
- char *p[MAX_PARMS];
CLEAR (p);
++line_num;
if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc))
{
- if (strlen (p[0]) >= 3 && !strncmp (p[0], "--", 2))
- p[0] += 2;
+ bypass_doubledash (&p[0]);
add_option (options, 0, p, file, line_num, level, msglevel, permission_mask, option_types_found, es);
}
}
@@ -2465,6 +2515,34 @@ read_config_file (struct options *options,
}
}
+static void
+read_config_string (struct options *options,
+ const char *config,
+ const int msglevel,
+ const unsigned int permission_mask,
+ unsigned int *option_types_found,
+ struct env_set *es)
+{
+ const char *file = "[CONFIG-STRING]";
+ char line[OPTION_LINE_SIZE];
+ struct buffer multiline;
+ int line_num = 0;
+
+ buf_set_read (&multiline, (uint8_t*)config, strlen (config));
+
+ while (buf_parse (&multiline, '\n', line, sizeof (line)))
+ {
+ char *p[MAX_PARMS];
+ CLEAR (p);
+ ++line_num;
+ if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc))
+ {
+ bypass_doubledash (&p[0]);
+ add_option (options, 0, p, NULL, line_num, 0, msglevel, permission_mask, option_types_found, es);
+ }
+ }
+}
+
void
parse_argv (struct options *options,
const int argc,
@@ -2565,6 +2643,20 @@ options_server_import (struct options *o,
es);
}
+#ifdef ENABLE_PLUGIN
+
+void options_plugin_import (struct options *options,
+ const char *config,
+ const int msglevel,
+ const unsigned int permission_mask,
+ unsigned int *option_types_found,
+ struct env_set *es)
+{
+ read_config_string (options, config, msglevel, permission_mask, option_types_found, es);
+}
+
+#endif
+
#if P2MP
#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], (mask), permission_mask, option_types_found, msglevel)) goto err; }
@@ -2682,10 +2774,12 @@ add_option (struct options *options,
read_config_file (options, p[1], level, file, line, msglevel, permission_mask, option_types_found, es);
}
- else if (streq (p[0], "echo"))
+ else if (streq (p[0], "echo") || streq (p[0], "parameter"))
{
struct buffer string = alloc_buf_gc (OPTION_PARM_SIZE, &gc);
int j;
+ const bool pull_mode = BOOL_CAST (permission_mask & OPT_P_PULL_MODE);
+
VERIFY_PERMISSION (OPT_P_ECHO);
for (j = 1; j < MAX_PARMS; ++j)
@@ -2697,10 +2791,12 @@ add_option (struct options *options,
buf_printf (&string, " ");
buf_printf (&string, "%s", p[j]);
}
- msg (M_INFO, "ECHO:%s", BSTR (&string));
+ msg (M_INFO, "%s:%s",
+ pull_mode ? "ECHO-PULL" : "ECHO",
+ BSTR (&string));
#ifdef ENABLE_MANAGEMENT
if (management)
- management_echo (management, BSTR (&string));
+ management_echo (management, BSTR (&string), pull_mode);
#endif
}
#ifdef ENABLE_MANAGEMENT
@@ -2754,7 +2850,7 @@ add_option (struct options *options,
else if (streq (p[0], "plugin") && p[1])
{
++i;
- VERIFY_PERMISSION (OPT_P_SCRIPT);
+ VERIFY_PERMISSION (OPT_P_PLUGIN);
if (p[2])
++i;
if (!no_more_than_n_args (msglevel, p, 3, NM_QUOTE_HINT))
@@ -2802,6 +2898,12 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
options->dev_node = p[1];
}
+ else if (streq (p[0], "topology") && p[1])
+ {
+ ++i;
+ VERIFY_PERMISSION (OPT_P_UP);
+ options->topology = parse_topology (p[1], msglevel);
+ }
else if (streq (p[0], "tun-ipv6"))
{
VERIFY_PERMISSION (OPT_P_UP);
@@ -3502,12 +3604,12 @@ add_option (struct options *options,
else if (streq (p[0], "route-gateway") && p[1])
{
++i;
- VERIFY_PERMISSION (OPT_P_ROUTE);
+ VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
options->route_default_gateway = p[1];
}
else if (streq (p[0], "route-delay"))
{
- VERIFY_PERMISSION (OPT_P_ROUTE);
+ VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
options->route_delay_defined = true;
if (p[1])
{
@@ -3537,6 +3639,11 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_SCRIPT);
options->route_noexec = true;
}
+ else if (streq (p[0], "route-nopull"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->route_nopull = true;
+ }
else if (streq (p[0], "redirect-gateway"))
{
int j;
@@ -3546,16 +3653,20 @@ add_option (struct options *options,
{
++i;
if (streq (p[j], "local"))
- options->routes->redirect_local = true;
+ options->routes->flags |= RG_LOCAL;
else if (streq (p[j], "def1"))
- options->routes->redirect_def1 = true;
+ options->routes->flags |= RG_DEF1;
+ else if (streq (p[j], "bypass-dhcp"))
+ options->routes->flags |= RG_BYPASS_DHCP;
+ else if (streq (p[j], "bypass-dns"))
+ options->routes->flags |= RG_BYPASS_DNS;
else
{
msg (msglevel, "unknown --redirect-gateway flag: %s", p[j]);
goto err;
}
}
- options->routes->redirect_default_gateway = true;
+ options->routes->flags |= RG_ENABLE;
}
else if (streq (p[0], "setenv") && p[1] && p[2])
{
@@ -3602,6 +3713,18 @@ add_option (struct options *options,
options->server_defined = true;
options->server_network = network;
options->server_netmask = netmask;
+
+ if (p[3])
+ {
+ ++i;
+ if (streq (p[3], "nopool"))
+ options->server_flags |= SF_NOPOOL;
+ else
+ {
+ msg (msglevel, "error parsing --server: %s is not a recognized flag", p[3]);
+ goto err;
+ }
+ }
}
else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4])
{
@@ -3690,7 +3813,7 @@ add_option (struct options *options,
else if (streq (p[0], "ifconfig-pool-linear"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
- options->ifconfig_pool_linear = true;
+ options->topology = TOP_P2P;
}
else if (streq (p[0], "hash-size") && p[1] && p[2])
{
@@ -3886,6 +4009,26 @@ add_option (struct options *options,
goto err;
}
}
+ else if (streq (p[0], "ifconfig-push-constraint") && p[1] && p[2])
+ {
+ in_addr_t network, netmask;
+
+ i += 2;
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ network = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[1], 0, NULL, NULL);
+ netmask = getaddr (GETADDR_HOST_ORDER, p[2], 0, NULL, NULL);
+ if (network && netmask)
+ {
+ options->push_ifconfig_constraint_defined = true;
+ options->push_ifconfig_constraint_network = network;
+ options->push_ifconfig_constraint_netmask = netmask;
+ }
+ else
+ {
+ msg (msglevel, "cannot parse --ifconfig-push-constraint addresses");
+ goto err;
+ }
+ }
else if (streq (p[0], "disable"))
{
VERIFY_PERMISSION (OPT_P_INSTANCE);
@@ -3925,7 +4068,7 @@ add_option (struct options *options,
else if (streq (p[0], "route-method") && p[1])
{
++i;
- VERIFY_PERMISSION (OPT_P_ROUTE);
+ VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
if (streq (p[1], "ipapi"))
options->route_method = ROUTE_METHOD_IPAPI;
else if (streq (p[1], "exe"))
@@ -4117,6 +4260,14 @@ add_option (struct options *options,
options->exit_event_initial_state = (atoi(p[2]) != 0);
}
}
+ else if (streq (p[0], "allow-nonadmin"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ if (p[1])
+ ++i;
+ tap_allow_nonadmin_access (p[1]);
+ openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
+ }
else if (streq (p[0], "user") && p[1])
{
++i;
@@ -4153,7 +4304,7 @@ add_option (struct options *options,
else if (streq (p[0], "route-method") && p[1]) /* ignore when pushed to non-Windows OS */
{
++i;
- VERIFY_PERMISSION (OPT_P_ROUTE);
+ VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
}
#endif
#if PASSTOS_CAPABILITY
diff --git a/options.h b/options.h
index c7294be..b207c70 100644
--- a/options.h
+++ b/options.h
@@ -123,6 +123,7 @@ struct options
const char *dev;
const char *dev_type;
const char *dev_node;
+ int topology; /* one of the TOP_x values from proto.h */
const char *ifconfig_local;
const char *ifconfig_remote_netmask;
bool ifconfig_noexec;
@@ -239,6 +240,7 @@ struct options
int route_delay_window;
bool route_delay_defined;
struct route_option_list *routes;
+ bool route_nopull;
#ifdef ENABLE_HTTP_PROXY
struct http_proxy_options *http_proxy_options;
@@ -283,6 +285,9 @@ struct options
in_addr_t server_network;
in_addr_t server_netmask;
+# define SF_NOPOOL (1<<0)
+ unsigned int server_flags;
+
bool server_bridge_defined;
in_addr_t server_bridge_ip;
in_addr_t server_bridge_netmask;
@@ -296,7 +301,6 @@ struct options
in_addr_t ifconfig_pool_netmask;
const char *ifconfig_pool_persist_filename;
int ifconfig_pool_persist_refresh_freq;
- bool ifconfig_pool_linear;
int real_hash_size;
int virtual_hash_size;
const char *client_connect_script;
@@ -312,6 +316,9 @@ struct options
bool push_ifconfig_defined;
in_addr_t push_ifconfig_local;
in_addr_t push_ifconfig_remote_netmask;
+ bool push_ifconfig_constraint_defined;
+ in_addr_t push_ifconfig_constraint_network;
+ in_addr_t push_ifconfig_constraint_netmask;
bool enable_c2c;
bool duplicate_cn;
int cf_max;
@@ -437,8 +444,11 @@ struct options
#define OPT_P_EXPLICIT_NOTIFY (1<<19)
#define OPT_P_ECHO (1<<20)
#define OPT_P_INHERIT (1<<21)
+#define OPT_P_ROUTE_EXTRAS (1<<22)
+#define OPT_P_PULL_MODE (1<<23)
+#define OPT_P_PLUGIN (1<<24)
-#define OPT_P_DEFAULT (~OPT_P_INSTANCE)
+#define OPT_P_DEFAULT (~(OPT_P_INSTANCE|OPT_P_PULL_MODE))
#if P2MP
#define PULL_DEFINED(opt) ((opt)->pull)
@@ -546,6 +556,13 @@ int parse_line (const char *line,
struct gc_arena *gc);
/*
+ * parse/print topology coding
+ */
+
+int parse_topology (const char *str, const int msglevel);
+const char *print_topology (const int topology);
+
+/*
* Manage auth-retry variable
*/
@@ -561,4 +578,15 @@ const char *auth_retry_print (void);
#endif
+#ifdef ENABLE_PLUGIN
+
+void options_plugin_import (struct options *options,
+ const char *config,
+ const int msglevel,
+ const unsigned int permission_mask,
+ unsigned int *option_types_found,
+ struct env_set *es);
+
+#endif
+
#endif
diff --git a/otime.h b/otime.h
index 974d0af..0026646 100644
--- a/otime.h
+++ b/otime.h
@@ -60,7 +60,7 @@ static inline void
update_time (void)
{
const time_t real_time = time (NULL);
- if (real_time != now)
+ if (real_time > now)
now = real_time;
}
diff --git a/plugin.c b/plugin.c
index f0d14ba..72cdbf7 100644
--- a/plugin.c
+++ b/plugin.c
@@ -42,7 +42,7 @@
#define PLUGIN_SYMBOL_REQUIRED (1<<0)
/* used only for program aborts */
-static struct plugin_list *static_plugin_list = NULL; /* GLOBAL */
+static struct plugin_common *static_plugin_common = NULL; /* GLOBAL */
static void
plugin_show_string_array (int msglevel, const char *name, const char *array[])
@@ -81,6 +81,8 @@ plugin_type_name (const int type)
return "PLUGIN_AUTH_USER_PASS_VERIFY";
case OPENVPN_PLUGIN_CLIENT_CONNECT:
return "PLUGIN_CLIENT_CONNECT";
+ case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
+ return "PLUGIN_CLIENT_CONNECT";
case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
return "PLUGIN_CLIENT_DISCONNECT";
case OPENVPN_PLUGIN_LEARN_ADDRESS:
@@ -174,7 +176,10 @@ dll_resolve_symbol (HMODULE module, void **dest, const char *symbol, const char
#endif
static void
-plugin_init_item (struct plugin *p, const struct plugin_option *o, const char **envp)
+plugin_init_item (struct plugin *p,
+ const struct plugin_option *o,
+ struct openvpn_plugin_string_list **retlist,
+ const char **envp)
{
struct gc_arena gc = gc_new ();
const char **argv = make_arg_array (o->so_pathname, o->args, &gc);
@@ -182,35 +187,73 @@ plugin_init_item (struct plugin *p, const struct plugin_option *o, const char **
p->plugin_type_mask = plugin_supported_types ();
#if defined(USE_LIBDL)
+
p->handle = dlopen (p->so_pathname, RTLD_NOW);
if (!p->handle)
msg (M_ERR, "PLUGIN_INIT: could not load plugin shared object %s: %s", p->so_pathname, dlerror());
- libdl_resolve_symbol (p->handle, (void*)&p->open, "openvpn_plugin_open_v1", p->so_pathname, PLUGIN_SYMBOL_REQUIRED);
- libdl_resolve_symbol (p->handle, (void*)&p->func, "openvpn_plugin_func_v1", p->so_pathname, PLUGIN_SYMBOL_REQUIRED);
- libdl_resolve_symbol (p->handle, (void*)&p->close, "openvpn_plugin_close_v1", p->so_pathname, PLUGIN_SYMBOL_REQUIRED);
- libdl_resolve_symbol (p->handle, (void*)&p->abort, "openvpn_plugin_abort_v1", p->so_pathname, 0);
+
+# define PLUGIN_SYM(var, name, flags) libdl_resolve_symbol (p->handle, (void*)&p->var, name, p->so_pathname, flags)
+
#elif defined(USE_LOAD_LIBRARY)
+
p->module = LoadLibrary (p->so_pathname);
if (!p->module)
msg (M_ERR, "PLUGIN_INIT: could not load plugin DLL: %s", p->so_pathname);
- dll_resolve_symbol (p->module, (void*)&p->open, "openvpn_plugin_open_v1", p->so_pathname, PLUGIN_SYMBOL_REQUIRED);
- dll_resolve_symbol (p->module, (void*)&p->func, "openvpn_plugin_func_v1", p->so_pathname, PLUGIN_SYMBOL_REQUIRED);
- dll_resolve_symbol (p->module, (void*)&p->close, "openvpn_plugin_close_v1", p->so_pathname, PLUGIN_SYMBOL_REQUIRED);
- dll_resolve_symbol (p->module, (void*)&p->abort, "openvpn_plugin_abort_v1", p->so_pathname, 0);
+
+# define PLUGIN_SYM(var, name, flags) dll_resolve_symbol (p->module, (void*)&p->var, name, p->so_pathname, flags)
+
#endif
+ PLUGIN_SYM (open1, "openvpn_plugin_open_v1", 0);
+ PLUGIN_SYM (open2, "openvpn_plugin_open_v2", 0);
+ PLUGIN_SYM (func1, "openvpn_plugin_func_v1", 0);
+ PLUGIN_SYM (func2, "openvpn_plugin_func_v2", 0);
+ PLUGIN_SYM (close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED);
+ PLUGIN_SYM (abort, "openvpn_plugin_abort_v1", 0);
+ PLUGIN_SYM (min_version_required, "openvpn_plugin_min_version_required_v1", 0);
+ PLUGIN_SYM (client_constructor, "openvpn_plugin_client_constructor_v1", 0);
+ PLUGIN_SYM (client_destructor, "openvpn_plugin_client_destructor_v1", 0);
+
+ if (!p->open1 && !p->open2)
+ msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname);
+
+ if (!p->func1 && !p->func2)
+ msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname);
+
dmsg (D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE");
plugin_show_args_env (D_PLUGIN_DEBUG, argv, envp);
/*
+ * Verify that we are sufficiently up-to-date to handle the plugin
+ */
+ if (p->min_version_required)
+ {
+ const int plugin_needs_version = (*p->min_version_required)();
+ if (plugin_needs_version > OPENVPN_PLUGIN_VERSION)
+ msg (M_FATAL, "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s",
+ plugin_needs_version,
+ OPENVPN_PLUGIN_VERSION,
+ p->so_pathname);
+ }
+
+ if (retlist)
+ *retlist = NULL;
+
+ /*
* Call the plugin initialization
*/
- p->plugin_handle = (*p->open)(&p->plugin_type_mask, argv, envp);
+ if (p->open2)
+ p->plugin_handle = (*p->open2)(&p->plugin_type_mask, argv, envp, retlist);
+ else if (p->open1)
+ p->plugin_handle = (*p->open1)(&p->plugin_type_mask, argv, envp);
+ else
+ ASSERT (0);
- msg (D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s",
+ msg (D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s",
p->so_pathname,
o->args ? o->args : "[NULL]",
- plugin_mask_string (p->plugin_type_mask, &gc));
+ plugin_mask_string (p->plugin_type_mask, &gc),
+ (retlist && *retlist) ? "[RETLIST]" : "");
if ((p->plugin_type_mask | plugin_supported_types()) != plugin_supported_types())
msg (M_FATAL, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]",
@@ -226,7 +269,12 @@ plugin_init_item (struct plugin *p, const struct plugin_option *o, const char **
}
static int
-plugin_call_item (const struct plugin *p, const int type, const char *args, const char **envp)
+plugin_call_item (const struct plugin *p,
+ void *per_client_context,
+ const int type,
+ const char *args,
+ struct openvpn_plugin_string_list **retlist,
+ const char **envp)
{
int status = OPENVPN_PLUGIN_FUNC_SUCCESS;
@@ -238,10 +286,18 @@ plugin_call_item (const struct plugin *p, const int type, const char *args, cons
dmsg (D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name (type));
plugin_show_args_env (D_PLUGIN_DEBUG, argv, envp);
+ if (retlist)
+ *retlist = NULL;
+
/*
* Call the plugin work function
*/
- status = (*p->func)(p->plugin_handle, type, argv, envp);
+ if (p->func2)
+ status = (*p->func2)(p->plugin_handle, type, argv, envp, per_client_context, retlist);
+ else if (p->func1)
+ status = (*p->func1)(p->plugin_handle, type, argv, envp);
+ else
+ ASSERT (0);
msg (D_PLUGIN, "PLUGIN_CALL: POST %s/%s status=%d",
p->so_pathname,
@@ -288,69 +344,179 @@ plugin_abort_item (const struct plugin *p)
(*p->abort)(p->plugin_handle);
}
+static void
+plugin_per_client_init (const struct plugin_common *pc, struct plugin_per_client *cli)
+{
+ const int n = pc->n;
+ int i;
+
+ CLEAR (*cli);
+ for (i = 0; i < n; ++i)
+ {
+ const struct plugin *p = &pc->plugins[i];
+
+ if (p->client_constructor)
+ cli->per_client_context[i] = (*p->client_constructor)(p->plugin_handle);
+ }
+ cli->initialized = true;
+}
+
+static void
+plugin_per_client_destroy (const struct plugin_common *pc, struct plugin_per_client *cli)
+{
+ if (cli->initialized)
+ {
+ const int n = pc->n;
+ int i;
+
+ for (i = 0; i < n; ++i)
+ {
+ const struct plugin *p = &pc->plugins[i];
+ void *cc = cli->per_client_context[i];
+
+ if (p->client_destructor && cc)
+ (*p->client_destructor)(p->plugin_handle, cc);
+ }
+ CLEAR (*cli);
+ }
+}
+
struct plugin_list *
-plugin_list_open (const struct plugin_option_list *list, const struct env_set *es)
+plugin_list_inherit (const struct plugin_list *src)
+{
+ struct plugin_list *pl;
+ ALLOC_OBJ_CLEAR (pl, struct plugin_list);
+ pl->common = src->common;
+ ASSERT (pl->common);
+ plugin_per_client_init (pl->common, &pl->per_client);
+ return pl;
+}
+
+static struct plugin_common *
+plugin_common_open (const struct plugin_option_list *list,
+ struct plugin_return *pr,
+ const struct env_set *es)
{
struct gc_arena gc = gc_new ();
int i;
- struct plugin_list *pl;
+ struct plugin_common *pc;
const char **envp;
- ALLOC_OBJ_CLEAR (pl, struct plugin_list);
- static_plugin_list = pl;
+ ALLOC_OBJ_CLEAR (pc, struct plugin_common);
envp = make_env_array (es, &gc);
+ if (pr)
+ plugin_return_init (pr);
+
for (i = 0; i < list->n; ++i)
{
- plugin_init_item (&pl->plugins[i], &list->plugins[i], envp);
- pl->n = i + 1;
+ plugin_init_item (&pc->plugins[i],
+ &list->plugins[i],
+ pr ? &pr->list[i] : NULL,
+ envp);
+ pc->n = i + 1;
}
+ if (pr)
+ pr->n = i;
+
gc_free (&gc);
+ static_plugin_common = pc;
+ return pc;
+}
+
+static void
+plugin_common_close (struct plugin_common *pc)
+{
+ static_plugin_common = NULL;
+ if (pc)
+ {
+ int i;
+
+ for (i = 0; i < pc->n; ++i)
+ plugin_close_item (&pc->plugins[i]);
+ free (pc);
+ }
+}
+
+struct plugin_list *
+plugin_list_open (const struct plugin_option_list *list,
+ struct plugin_return *pr,
+ const struct env_set *es)
+{
+ struct plugin_list *pl;
+ ALLOC_OBJ_CLEAR (pl, struct plugin_list);
+ pl->common = plugin_common_open (list, pr, es);
+ pl->common_owned = true;
+ plugin_per_client_init (pl->common, &pl->per_client);
return pl;
}
int
-plugin_call (const struct plugin_list *pl, const int type, const char *args, struct env_set *es)
+plugin_call (const struct plugin_list *pl,
+ const int type,
+ const char *args,
+ struct plugin_return *pr,
+ struct env_set *es)
{
- int count = 0;
+ if (pr)
+ plugin_return_init (pr);
if (plugin_defined (pl, type))
{
struct gc_arena gc = gc_new ();
int i;
const char **envp;
+ const int n = plugin_n (pl);
+ int count = 0;
mutex_lock_static (L_PLUGIN);
setenv_del (es, "script_type");
envp = make_env_array (es, &gc);
- for (i = 0; i < pl->n; ++i)
+ for (i = 0; i < n; ++i)
{
- if (!plugin_call_item (&pl->plugins[i], type, args, envp))
+ if (!plugin_call_item (&pl->common->plugins[i],
+ pl->per_client.initialized
+ ? pl->per_client.per_client_context[i] : NULL,
+ type,
+ args,
+ pr ? &pr->list[i] : NULL,
+ envp))
++count;
}
+ if (pr)
+ pr->n = i;
+
mutex_unlock_static (L_PLUGIN);
gc_free (&gc);
- }
- return count == pl->n ? 0 : 1; /* if any one plugin in the chain failed, return failure (1) */
+ return count == n ? 0 : 1; /* if any one plugin in the chain failed, return failure (1) */
+ }
+ else
+ {
+ return 0;
+ }
}
void
plugin_list_close (struct plugin_list *pl)
{
- static_plugin_list = NULL;
if (pl)
{
- int i;
- for (i = 0; i < pl->n; ++i)
- plugin_close_item (&pl->plugins[i]);
+ if (pl->common)
+ {
+ plugin_per_client_destroy (pl->common, &pl->per_client);
+
+ if (pl->common_owned)
+ plugin_common_close (pl->common);
+ }
+
free (pl);
}
}
@@ -358,14 +524,14 @@ plugin_list_close (struct plugin_list *pl)
void
plugin_abort (void)
{
- struct plugin_list *pl = static_plugin_list;
- static_plugin_list = NULL;
- if (pl)
+ struct plugin_common *pc = static_plugin_common;
+ static_plugin_common = NULL;
+ if (pc)
{
int i;
- for (i = 0; i < pl->n; ++i)
- plugin_abort_item (&pl->plugins[i]);
+ for (i = 0; i < pc->n; ++i)
+ plugin_abort_item (&pc->plugins[i]);
}
}
@@ -373,22 +539,113 @@ bool
plugin_defined (const struct plugin_list *pl, const int type)
{
bool ret = false;
+
if (pl)
{
- int i;
- const unsigned int mask = OPENVPN_PLUGIN_MASK (type);
- for (i = 0; i < pl->n; ++i)
+ const struct plugin_common *pc = pl->common;
+
+ if (pc)
{
- if (pl->plugins[i].plugin_type_mask & mask)
+ int i;
+ const unsigned int mask = OPENVPN_PLUGIN_MASK (type);
+ for (i = 0; i < pc->n; ++i)
{
- ret = true;
- break;
+ if (pc->plugins[i].plugin_type_mask & mask)
+ {
+ ret = true;
+ break;
+ }
}
}
}
return ret;
}
+/*
+ * Plugin return functions
+ */
+
+static void
+openvpn_plugin_string_list_item_free (struct openvpn_plugin_string_list *l)
+{
+ if (l)
+ {
+ free (l->name);
+ free (l->value);
+ free (l);
+ }
+}
+
+static void
+openvpn_plugin_string_list_free (struct openvpn_plugin_string_list *l)
+{
+ struct openvpn_plugin_string_list *next;
+ while (l)
+ {
+ next = l->next;
+ openvpn_plugin_string_list_item_free (l);
+ l = next;
+ }
+}
+
+static struct openvpn_plugin_string_list *
+openvpn_plugin_string_list_find (struct openvpn_plugin_string_list *l, const char *name)
+{
+ while (l)
+ {
+ if (!strcmp (l->name, name))
+ return l;
+ l = l->next;
+ }
+ return NULL;
+}
+
+void
+plugin_return_get_column (const struct plugin_return *src,
+ struct plugin_return *dest,
+ const char *colname)
+{
+ int i;
+
+ dest->n = 0;
+ for (i = 0; i < src->n; ++i)
+ dest->list[i] = openvpn_plugin_string_list_find (src->list[i], colname);
+ dest->n = i;
+}
+
+void
+plugin_return_free (struct plugin_return *pr)
+{
+ int i;
+ for (i = 0; i < pr->n; ++i)
+ openvpn_plugin_string_list_free (pr->list[i]);
+ pr->n = 0;
+}
+
+#ifdef ENABLE_DEBUG
+void
+plugin_return_print (const int msglevel, const char *prefix, const struct plugin_return *pr)
+{
+ int i;
+ msg (msglevel, "PLUGIN_RETURN_PRINT %s", prefix);
+ for (i = 0; i < pr->n; ++i)
+ {
+ struct openvpn_plugin_string_list *l = pr->list[i];
+ int count = 0;
+
+ msg (msglevel, "PLUGIN #%d (%s)", i, prefix);
+ while (l)
+ {
+ msg (msglevel, "[%d] '%s' -> '%s'\n",
+ ++count,
+ l->name,
+ l->value);
+ l = l->next;
+ }
+ }
+}
+#endif
+
#else
static void dummy(void) {}
#endif /* ENABLE_PLUGIN */
diff --git a/plugin.h b/plugin.h
index 7d710b0..d72f954 100644
--- a/plugin.h
+++ b/plugin.h
@@ -35,7 +35,7 @@
#include "misc.h"
-#define MAX_PLUGINS 32
+#define MAX_PLUGINS 16
struct plugin_option {
const char *so_pathname;
@@ -50,24 +50,51 @@ struct plugin_option_list {
struct plugin {
const char *so_pathname;
unsigned int plugin_type_mask;
+
#if defined(USE_LIBDL)
void *handle;
#elif defined(USE_LOAD_LIBRARY)
HMODULE module;
#endif
- openvpn_plugin_open_v1 open;
- openvpn_plugin_func_v1 func;
+
+ openvpn_plugin_open_v1 open1;
+ openvpn_plugin_open_v2 open2;
+ openvpn_plugin_func_v1 func1;
+ openvpn_plugin_func_v2 func2;
openvpn_plugin_close_v1 close;
openvpn_plugin_abort_v1 abort;
+ openvpn_plugin_min_version_required_v1 min_version_required;
+ openvpn_plugin_client_constructor_v1 client_constructor;
+ openvpn_plugin_client_destructor_v1 client_destructor;
openvpn_plugin_handle_t plugin_handle;
};
-struct plugin_list {
+struct plugin_per_client
+{
+ bool initialized;
+ void *per_client_context[MAX_PLUGINS];
+};
+
+struct plugin_common
+{
int n;
struct plugin plugins[MAX_PLUGINS];
};
+struct plugin_list
+{
+ struct plugin_per_client per_client;
+ struct plugin_common *common;
+ bool common_owned;
+};
+
+struct plugin_return
+{
+ int n;
+ struct openvpn_plugin_string_list *list[MAX_PLUGINS];
+};
+
struct plugin_option_list *plugin_option_list_new (struct gc_arena *gc);
bool plugin_option_list_add (struct plugin_option_list *list, const char *so_pathname, const char *args);
@@ -75,14 +102,56 @@ bool plugin_option_list_add (struct plugin_option_list *list, const char *so_pat
void plugin_option_list_print (const struct plugin_option_list *list, int msglevel);
#endif
-struct plugin_list *plugin_list_open (const struct plugin_option_list *list, const struct env_set *es);
-int plugin_call (const struct plugin_list *pl, const int type, const char *args, struct env_set *es);
+struct plugin_list *plugin_list_open (const struct plugin_option_list *list,
+ struct plugin_return *pr,
+ const struct env_set *es);
+
+struct plugin_list *plugin_list_inherit (const struct plugin_list *src);
+
+int plugin_call (const struct plugin_list *pl,
+ const int type,
+ const char *args,
+ struct plugin_return *pr,
+ struct env_set *es);
+
void plugin_list_close (struct plugin_list *pl);
bool plugin_defined (const struct plugin_list *pl, const int type);
+void plugin_return_get_column (const struct plugin_return *src,
+ struct plugin_return *dest,
+ const char *colname);
+
+void plugin_return_free (struct plugin_return *pr);
+
+#ifdef ENABLE_DEBUG
+void plugin_return_print (const int msglevel, const char *prefix, const struct plugin_return *pr);
+#endif
+
+static inline int
+plugin_n (const struct plugin_list *pl)
+{
+ if (pl && pl->common)
+ return pl->common->n;
+ else
+ return 0;
+}
+
+static inline bool
+plugin_return_defined (const struct plugin_return *pr)
+{
+ return pr->n >= 0;
+}
+
+static inline void
+plugin_return_init (struct plugin_return *pr)
+{
+ pr->n = 0;
+}
+
#else
struct plugin_list { int dummy; };
+struct plugin_return { int dummy; };
static inline bool
plugin_defined (const struct plugin_list *pl, const int type)
@@ -91,7 +160,11 @@ plugin_defined (const struct plugin_list *pl, const int type)
}
static inline int
-plugin_call (const struct plugin_list *pl, const int type, const char *args, struct env_set *es)
+plugin_call (const struct plugin_list *pl,
+ const int type,
+ const char *args,
+ struct plugin_return *pr,
+ struct env_set *es)
{
return 0;
}
diff --git a/proto.c b/proto.c
index df5b77b..4e8a309 100644
--- a/proto.c
+++ b/proto.c
@@ -31,6 +31,7 @@
#include "syshead.h"
#include "proto.h"
+#include "error.h"
#include "memdbg.h"
@@ -72,3 +73,56 @@ is_ipv4 (int tunnel_type, struct buffer *buf)
else
return false;
}
+
+#ifdef PACKET_TRUNCATION_CHECK
+
+void
+ipv4_packet_size_verify (const uint8_t *data,
+ const int size,
+ const int tunnel_type,
+ const char *prefix,
+ counter_type *errors)
+{
+ if (size > 0)
+ {
+ struct buffer buf;
+
+ buf_set_read (&buf, data, size);
+
+ if (is_ipv4 (tunnel_type, &buf))
+ {
+ const struct openvpn_iphdr *pip;
+ int hlen;
+ int totlen;
+ const char *msgstr = "PACKET SIZE INFO";
+ unsigned int msglevel = D_PACKET_TRUNC_DEBUG;
+
+ if (BLEN (&buf) < (int) sizeof (struct openvpn_iphdr))
+ return;
+
+ verify_align_4 (&buf);
+ pip = (struct openvpn_iphdr *) BPTR (&buf);
+
+ hlen = OPENVPN_IPH_GET_LEN (pip->version_len);
+ totlen = ntohs (pip->tot_len);
+
+ if (BLEN (&buf) != totlen)
+ {
+ msgstr = "PACKET TRUNCATION ERROR";
+ msglevel = D_PACKET_TRUNC_ERR;
+ if (errors)
+ ++(*errors);
+ }
+
+ msg (msglevel, "%s %s: size=%d totlen=%d hlen=%d errcount=" counter_format,
+ msgstr,
+ prefix,
+ BLEN (&buf),
+ totlen,
+ hlen,
+ errors ? *errors : (counter_type)0);
+ }
+ }
+}
+
+#endif
diff --git a/proto.h b/proto.h
index 440d3d1..77d9c0d 100644
--- a/proto.h
+++ b/proto.h
@@ -25,6 +25,7 @@
#ifndef PROTO_H
#define PROTO_H
+#include "common.h"
#include "buffer.h"
/*
@@ -35,6 +36,13 @@
#define DEV_TYPE_TUN 2 /* point-to-point IP tunnel */
#define DEV_TYPE_TAP 3 /* ethernet (802.3) tunnel */
+/* TUN topologies */
+
+#define TOP_UNDEF 0
+#define TOP_NET30 1
+#define TOP_P2P 2
+#define TOP_SUBNET 3
+
/*
* IP and Ethernet protocol structs. For portability,
* OpenVPN needs its own definitions of these structs, and
@@ -160,4 +168,13 @@ struct openvpn_tcphdr {
*/
bool is_ipv4 (int tunnel_type, struct buffer *buf);
+#ifdef PACKET_TRUNCATION_CHECK
+void ipv4_packet_size_verify (const uint8_t *data,
+ const int size,
+ const int tunnel_type,
+ const char
+ *prefix,
+ counter_type *errors);
+#endif
+
#endif
diff --git a/push.c b/push.c
index 454b6e9..3db8e74 100644
--- a/push.c
+++ b/push.c
@@ -99,7 +99,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
status = process_incoming_push_msg (c,
buffer,
c->options.pull,
- pull_permission_mask (),
+ pull_permission_mask (c),
&option_types_found);
if (status == PUSH_MSG_ERROR)
diff --git a/route.c b/route.c
index 2c27eaf..3ec6c3f 100644
--- a/route.c
+++ b/route.c
@@ -46,6 +46,45 @@
static void add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
static void delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
static bool get_default_gateway (in_addr_t *ret);
+static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags);
+
+#ifdef ENABLE_DEBUG
+
+static void
+print_bypass_addresses (const struct route_bypass *rb)
+{
+ struct gc_arena gc = gc_new ();
+ int i;
+ for (i = 0; i < rb->n_bypass; ++i)
+ {
+ msg (D_ROUTE_DEBUG, "ROUTE DEBUG: bypass_host_route[%d]=%s",
+ i,
+ print_in_addr_t (rb->bypass[i], 0, &gc));
+ }
+ gc_free (&gc);
+}
+
+#endif
+
+static bool
+add_bypass_address (struct route_bypass *rb, const in_addr_t a)
+{
+ int i;
+ for (i = 0; i < rb->n_bypass; ++i)
+ {
+ if (a == rb->bypass[i]) /* avoid duplicates */
+ return true;
+ }
+ if (rb->n_bypass < N_ROUTE_BYPASS)
+ {
+ rb->bypass[rb->n_bypass++] = a;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
struct route_option_list *
new_route_option_list (struct gc_arena *a)
@@ -287,10 +326,13 @@ init_route_list (struct route_list *rl,
in_addr_t remote_host,
struct env_set *es)
{
+ struct gc_arena gc = gc_new ();
bool ret = true;
clear_route_list (rl);
+ rl->flags = opt->flags;
+
if (remote_host)
{
rl->spec.remote_host = remote_host;
@@ -301,10 +343,16 @@ init_route_list (struct route_list *rl,
if (rl->spec.net_gateway_defined)
{
setenv_route_addr (es, "net_gateway", rl->spec.net_gateway, -1);
+ dmsg (D_ROUTE_DEBUG, "ROUTE DEBUG: default_gateway=%s", print_in_addr_t (rl->spec.net_gateway, 0, &gc));
+ }
+
+ if (rl->flags & RG_ENABLE)
+ {
+ get_bypass_addresses (&rl->spec.bypass, rl->flags);
+#ifdef ENABLE_DEBUG
+ print_bypass_addresses (&rl->spec.bypass);
+#endif
}
- rl->redirect_default_gateway = opt->redirect_default_gateway;
- rl->redirect_local = opt->redirect_local;
- rl->redirect_def1 = opt->redirect_def1;
if (is_route_parm_defined (remote_endpoint))
{
@@ -348,6 +396,7 @@ init_route_list (struct route_list *rl,
rl->n = j;
}
+ gc_free (&gc);
return ret;
}
@@ -386,11 +435,51 @@ del_route3 (in_addr_t network,
}
static void
+add_bypass_routes (struct route_bypass *rb,
+ in_addr_t gateway,
+ const struct tuntap *tt,
+ unsigned int flags,
+ const struct env_set *es)
+{
+ int i;
+ for (i = 0; i < rb->n_bypass; ++i)
+ {
+ if (rb->bypass[i] != gateway)
+ add_route3 (rb->bypass[i],
+ ~0,
+ gateway,
+ tt,
+ flags,
+ es);
+ }
+}
+
+static void
+del_bypass_routes (struct route_bypass *rb,
+ in_addr_t gateway,
+ const struct tuntap *tt,
+ unsigned int flags,
+ const struct env_set *es)
+{
+ int i;
+ for (i = 0; i < rb->n_bypass; ++i)
+ {
+ if (rb->bypass[i] != gateway)
+ del_route3 (rb->bypass[i],
+ ~0,
+ gateway,
+ tt,
+ flags,
+ es);
+ }
+}
+
+static void
redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
{
const char err[] = "NOTE: unable to redirect default gateway --";
- if (rl->redirect_default_gateway)
+ if (rl->flags & RG_ENABLE)
{
if (!rl->spec.remote_endpoint_defined)
{
@@ -407,7 +496,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u
else
{
/* route remote host to original default gateway */
- if (!rl->redirect_local)
+ if (!(rl->flags & RG_LOCAL))
add_route3 (rl->spec.remote_host,
~0,
rl->spec.net_gateway,
@@ -415,7 +504,10 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u
flags,
es);
- if (rl->redirect_def1)
+ /* route DHCP/DNS server traffic through original default gateway */
+ add_bypass_routes (&rl->spec.bypass, rl->spec.net_gateway, tt, flags, es);
+
+ if (rl->flags & RG_DEF1)
{
/* add new default route (1st component) */
add_route3 (0x00000000,
@@ -464,7 +556,7 @@ undo_redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *
if (rl->did_redirect_default_gateway)
{
/* delete remote host route */
- if (!rl->redirect_local)
+ if (!(rl->flags & RG_LOCAL))
del_route3 (rl->spec.remote_host,
~0,
rl->spec.net_gateway,
@@ -472,7 +564,10 @@ undo_redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *
flags,
es);
- if (rl->redirect_def1)
+ /* delete special DHCP/DNS bypass route */
+ del_bypass_routes (&rl->spec.bypass, rl->spec.net_gateway, tt, flags, es);
+
+ if (rl->flags & RG_DEF1)
{
/* delete default route (1st component) */
del_route3 (0x00000000,
@@ -585,9 +680,9 @@ print_route_options (const struct route_option_list *rol,
int level)
{
int i;
- if (rol->redirect_default_gateway)
+ if (rol->flags & RG_ENABLE)
msg (level, " [redirect_default_gateway local=%d]",
- rol->redirect_local);
+ (rol->flags & RG_LOCAL) != 0);
for (i = 0; i < rol->n; ++i)
print_route_option (&rol->routes[i], level);
}
@@ -987,7 +1082,7 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
for (i = 0; i < rl->n; ++i)
test_route_helper (&ret, &count, &good, &ambig, adapters, rl->routes[i].gateway);
- if (rl->redirect_default_gateway && rl->spec.remote_endpoint_defined)
+ if ((rl->flags & RG_ENABLE) && rl->spec.remote_endpoint_defined)
test_route_helper (&ret, &count, &good, &ambig, adapters, rl->spec.remote_endpoint);
}
}
@@ -1004,40 +1099,55 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
return ret;
}
-static bool
-get_default_gateway (in_addr_t *ret)
+static const MIB_IPFORWARDROW *
+get_default_gateway_row (const MIB_IPFORWARDTABLE *routes)
{
- struct gc_arena gc = gc_new ();
- bool ret_bool = false;
+ DWORD lowest_index = ~0;
+ const MIB_IPFORWARDROW *ret = NULL;
int i;
- const MIB_IPFORWARDTABLE *routes = get_windows_routing_table (&gc);
- if (!routes)
- goto done;
-
- for (i = 0; i < routes->dwNumEntries; ++i)
+ if (routes)
{
- const MIB_IPFORWARDROW *row = &routes->table[i];
- const in_addr_t net = ntohl (row->dwForwardDest);
- const in_addr_t mask = ntohl (row->dwForwardMask);
- const in_addr_t gw = ntohl (row->dwForwardNextHop);
+ for (i = 0; i < routes->dwNumEntries; ++i)
+ {
+ const MIB_IPFORWARDROW *row = &routes->table[i];
+ const in_addr_t net = ntohl (row->dwForwardDest);
+ const in_addr_t mask = ntohl (row->dwForwardMask);
+ const DWORD index = row->dwForwardIfIndex;
#if 0
- msg (M_INFO, "route[%d] %s %s %s",
- i,
- print_in_addr_t ((in_addr_t) net, 0, &gc),
- print_in_addr_t ((in_addr_t) mask, 0, &gc),
- print_in_addr_t ((in_addr_t) gw, 0, &gc));
+ msg (M_INFO, "route[%d] %s %s %s",
+ i,
+ print_in_addr_t ((in_addr_t) net, 0, &gc),
+ print_in_addr_t ((in_addr_t) mask, 0, &gc),
+ print_in_addr_t ((in_addr_t) gw, 0, &gc));
#endif
- if (!net && !mask)
- {
- *ret = gw;
- ret_bool = true;
- break;
+
+ if (!net && !mask && index < lowest_index)
+ {
+ ret = row;
+ lowest_index = index;
+ }
}
}
-
- done:
+ return ret;
+}
+
+static bool
+get_default_gateway (in_addr_t *ret)
+{
+ struct gc_arena gc = gc_new ();
+ bool ret_bool = false;
+
+ const MIB_IPFORWARDTABLE *routes = get_windows_routing_table (&gc);
+ const MIB_IPFORWARDROW *row = get_default_gateway_row (routes);
+
+ if (row)
+ {
+ *ret = ntohl (row->dwForwardNextHop);
+ ret_bool = true;
+ }
+
gc_free (&gc);
return ret_bool;
}
@@ -1774,3 +1884,74 @@ netmask_to_netbits (const in_addr_t network, const in_addr_t netmask, int *netbi
}
return false;
}
+
+/*
+ * get_bypass_addresses() is used by the redirect-gateway bypass-x
+ * functions to build a route bypass to selected DHCP/DNS servers,
+ * so that outgoing packets to these servers don't end up in the tunnel.
+ */
+
+#if defined(WIN32)
+
+static void
+add_host_route_if_nonlocal (struct route_bypass *rb, const in_addr_t addr, const IP_ADAPTER_INFO *dgi)
+{
+ if (!is_ip_in_adapter_subnet (dgi, addr, NULL))
+ add_bypass_address (rb, addr);
+}
+
+static void
+add_host_route_array (struct route_bypass *rb, const IP_ADAPTER_INFO *dgi, const IP_ADDR_STRING *iplist)
+{
+ while (iplist)
+ {
+ bool succeed = false;
+ const in_addr_t ip = getaddr (GETADDR_HOST_ORDER, iplist->IpAddress.String, 0, &succeed, NULL);
+ if (succeed)
+ {
+ add_host_route_if_nonlocal (rb, ip, dgi);
+ }
+ iplist = iplist->Next;
+ }
+}
+
+static void
+get_bypass_addresses (struct route_bypass *rb, const unsigned int flags)
+{
+ struct gc_arena gc = gc_new ();
+ bool ret_bool = false;
+
+ /* get full routing table */
+ const MIB_IPFORWARDTABLE *routes = get_windows_routing_table (&gc);
+
+ /* get the route which represents the default gateway */
+ const MIB_IPFORWARDROW *row = get_default_gateway_row (routes);
+
+ if (row)
+ {
+ /* get the adapter which the default gateway is associated with */
+ const IP_ADAPTER_INFO *dgi = get_adapter_info (row->dwForwardIfIndex, &gc);
+
+ /* get extra adapter info, such as DNS addresses */
+ const IP_PER_ADAPTER_INFO *pai = get_per_adapter_info (row->dwForwardIfIndex, &gc);
+
+ /* Bypass DHCP server address */
+ if ((flags & RG_BYPASS_DHCP) && dgi && dgi->DhcpEnabled)
+ add_host_route_array (rb, dgi, &dgi->DhcpServer);
+
+ /* Bypass DNS server addresses */
+ if ((flags & RG_BYPASS_DNS) && pai)
+ add_host_route_array (rb, dgi, &pai->DnsServerList);
+ }
+
+ gc_free (&gc);
+}
+
+#else
+
+static void
+get_bypass_addresses (struct route_bypass *rb, const unsigned int flags)
+{
+}
+
+#endif
diff --git a/route.h b/route.h
index 7b7bf37..21f5465 100644
--- a/route.h
+++ b/route.h
@@ -48,6 +48,13 @@
*/
#define ROUTE_DELETE_FIRST 2
+struct route_bypass
+{
+# define N_ROUTE_BYPASS 8
+ int n_bypass;
+ in_addr_t bypass[N_ROUTE_BYPASS];
+};
+
struct route_special_addr
{
in_addr_t remote_endpoint;
@@ -56,6 +63,7 @@ struct route_special_addr
bool net_gateway_defined;
in_addr_t remote_host;
bool remote_host_defined;
+ struct route_bypass bypass;
};
struct route_option {
@@ -65,11 +73,16 @@ struct route_option {
const char *metric;
};
+/* redirect-gateway flags */
+#define RG_ENABLE (1<<0)
+#define RG_LOCAL (1<<1)
+#define RG_DEF1 (1<<2)
+#define RG_BYPASS_DHCP (1<<3)
+#define RG_BYPASS_DNS (1<<4)
+
struct route_option_list {
int n;
- bool redirect_default_gateway;
- bool redirect_local;
- bool redirect_def1;
+ unsigned int flags;
struct route_option routes[MAX_ROUTES];
};
@@ -86,11 +99,8 @@ struct route {
struct route_list {
bool routes_added;
struct route_special_addr spec;
- bool redirect_default_gateway;
- bool redirect_local;
- bool redirect_def1;
+ unsigned int flags;
bool did_redirect_default_gateway;
-
int n;
struct route routes[MAX_ROUTES];
};
diff --git a/sample-scripts/ucn.pl b/sample-scripts/ucn.pl
new file mode 100755
index 0000000..6d708f8
--- /dev/null
+++ b/sample-scripts/ucn.pl
@@ -0,0 +1,11 @@
+#!/usr/bin/perl -t
+
+# OpenVPN --auth-user-pass-verify script.
+# Only authenticate if username equals common_name.
+# In OpenVPN config file:
+# auth-user-pass-verify ./ucn.pl via-env
+
+$username = $ENV{'username'};
+$common_name = $ENV{'common_name'};
+
+exit !(length($username) > 0 && length($common_name) > 0 && $username eq $common_name);
diff --git a/service-win32/mkpatch b/service-win32/mkpatch
index d87af52..5e65b94 100755
--- a/service-win32/mkpatch
+++ b/service-win32/mkpatch
@@ -1,4 +1,4 @@
# build service.[ch] patch against original
# SDK sample
-diff -u service.c.orig service.c >service.patch
-diff -u service.h.orig service.h >>service.patch
+diff -ub service.c.orig service.c >service.patch
+diff -ub service.h.orig service.h >>service.patch
diff --git a/service-win32/service.patch b/service-win32/service.patch
index 0b60472..b4b2063 100755
--- a/service-win32/service.patch
+++ b/service-win32/service.patch
@@ -1,5 +1,5 @@
---- service.c.orig Sat Jan 15 17:39:20 2005
-+++ service.c Sun Feb 20 11:28:30 2005
+--- service.c.orig Mon Sep 5 14:38:41 2005
++++ service.c Tue Sep 6 13:58:52 2005
@@ -16,6 +16,7 @@
service_main(DWORD dwArgc, LPTSTR *lpszArgv);
CmdInstallService();
@@ -29,7 +29,7 @@
{
SERVICE_TABLE_ENTRY dispatchTable[] =
{
-@@ -77,12 +79,16 @@
+@@ -77,11 +79,15 @@
{
if ( _stricmp( "install", argv[1]+1 ) == 0 )
{
@@ -40,14 +40,13 @@
{
- CmdRemoveService();
+ return CmdRemoveService();
- }
++ }
+ else if ( _stricmp( "start", argv[1]+1 ) == 0)
+ {
+ return CmdStartService();
-+ }
+ }
else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
{
- bDebug = TRUE;
@@ -92,7 +98,7 @@
{
goto dispatch;
@@ -98,9 +97,8 @@
if ( !bDebug )
{
-- dwErr = GetLastError();
+ if (flags & MSG_FLAGS_SYS_CODE)
-+ dwErr = GetLastError();
+ dwErr = GetLastError();
+ else
+ dwErr = 0;
@@ -163,40 +161,16 @@
}
schSCManager = OpenSCManager(
-@@ -366,19 +384,19 @@
- if ( schSCManager )
- {
- schService = CreateService(
-- schSCManager, // SCManager database
-- TEXT(SZSERVICENAME), // name of service
-- TEXT(SZSERVICEDISPLAYNAME), // name to display
-- SERVICE_QUERY_STATUS, // desired access
-- SERVICE_WIN32_OWN_PROCESS, // service type
+@@ -371,7 +389,7 @@
+ TEXT(SZSERVICEDISPLAYNAME), // name to display
+ SERVICE_QUERY_STATUS, // desired access
+ SERVICE_WIN32_OWN_PROCESS, // service type
- SERVICE_DEMAND_START, // start type
-- SERVICE_ERROR_NORMAL, // error control type
-- szPath, // service's binary
-- NULL, // no load ordering group
-- NULL, // no tag identifier
-- TEXT(SZDEPENDENCIES), // dependencies
-- NULL, // LocalSystem account
-- NULL); // no password
-+ schSCManager, // SCManager database
-+ TEXT(SZSERVICENAME), // name of service
-+ TEXT(SZSERVICEDISPLAYNAME), // name to display
-+ SERVICE_QUERY_STATUS, // desired access
-+ SERVICE_WIN32_OWN_PROCESS, // service type
+ SERVICE_DEMAND_START, // start type -- alternative: SERVICE_AUTO_START
-+ SERVICE_ERROR_NORMAL, // error control type
-+ szPath, // service's binary
-+ NULL, // no load ordering group
-+ NULL, // no tag identifier
-+ TEXT(SZDEPENDENCIES), // dependencies
-+ NULL, // LocalSystem account
-+ NULL); // no password
-
- if ( schService )
- {
-@@ -388,15 +406,78 @@
+ SERVICE_ERROR_NORMAL, // error control type
+ szPath, // service's binary
+ NULL, // no load ordering group
+@@ -388,16 +406,79 @@
else
{
_tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
@@ -206,9 +180,8 @@
CloseServiceHandle(schSCManager);
}
else
-- _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
+ {
-+ _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
+ _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
+ ret = 1;
+ }
+ return ret;
@@ -233,7 +206,7 @@
+
+ SC_HANDLE schSCManager;
+ SC_HANDLE schService;
-+
+
+ // Open a handle to the SC Manager database.
+ schSCManager = OpenSCManager(
@@ -273,9 +246,10 @@
+ CloseServiceHandle(schSCManager);
+ return ret;
+}
-
++
//
// FUNCTION: CmdRemoveService()
+ //
@@ -407,15 +488,17 @@
// none
//
@@ -300,9 +274,8 @@
if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
_tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
else
-- _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
+ {
-+ _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
+ _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
+ ret = 1;
+ }
@@ -312,9 +285,8 @@
if ( DeleteService(schService) )
_tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
else
-- _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
+ {
-+ _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
+ _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
+ ret = 1;
+ }
@@ -322,18 +294,16 @@
CloseServiceHandle(schService);
}
else
-- _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
+ {
-+ _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
+ _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
+ ret = 1;
+ }
CloseServiceHandle(schSCManager);
}
else
-- _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
+ {
-+ _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
+ _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
+ ret = 1;
+ }
+ return ret;
@@ -349,8 +319,8 @@
}
if ( lpszTemp )
---- service.h.orig Sat Jan 15 17:39:20 2005
-+++ service.h Mon Feb 7 17:24:04 2005
+--- service.h.orig Mon Sep 5 14:38:41 2005
++++ service.h Tue Sep 6 13:58:59 2005
@@ -62,13 +62,13 @@
//// todo: change to desired strings
////
@@ -365,7 +335,7 @@
+#define SZSERVICEDISPLAYNAME "OpenVPN Service"
// list of service dependencies - "dep1\0dep2\0\0"
-#define SZDEPENDENCIES ""
-+#define SZDEPENDENCIES "TAP0801\0\0"
++#define SZDEPENDENCIES "TAP0801\0Dhcp\0\0"
//////////////////////////////////////////////////////////////////////////////
diff --git a/sig.c b/sig.c
index efb3880..d144d54 100644
--- a/sig.c
+++ b/sig.c
@@ -242,6 +242,12 @@ print_status (const struct context *c, struct status_output *so)
if (c->options.comp_lzo)
lzo_print_stats (&c->c2.lzo_compwork, so);
#endif
+#ifdef PACKET_TRUNCATION_CHECK
+ status_printf (so, "TUN read truncations," counter_format, c->c2.n_trunc_tun_read);
+ status_printf (so, "TUN write truncations," counter_format, c->c2.n_trunc_tun_write);
+ status_printf (so, "Pre-encrypt truncations," counter_format, c->c2.n_trunc_pre_encrypt);
+ status_printf (so, "Post-decrypt truncations," counter_format, c->c2.n_trunc_post_decrypt);
+#endif
#ifdef WIN32
if (tuntap_defined (c->c1.tuntap))
status_printf (so, "TAP-WIN32 driver status,\"%s\"",
diff --git a/socket.c b/socket.c
index 070e4ec..8e56896 100644
--- a/socket.c
+++ b/socket.c
@@ -1317,7 +1317,7 @@ link_socket_connection_initiated (const struct buffer *buf,
if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE))
{
const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual, true, " ", &gc);
- if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, es))
+ if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, NULL, es))
msg (M_WARN, "WARNING: ipchange plugin call failed");
}
diff --git a/ssl.c b/ssl.c
index 52bf8df..ba6857a 100644
--- a/ssl.c
+++ b/ssl.c
@@ -533,7 +533,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
ctx->error_depth,
subject);
- ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, command, opt->es);
+ ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, command, NULL, opt->es);
if (!ret)
{
@@ -2384,7 +2384,7 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
setenv_untrusted (session);
/* call command */
- retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, session->opt->es);
+ retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es);
if (!retval)
ret = true;
diff --git a/tap-win32/SOURCES b/tap-win32/SOURCES
index 5320ae3..f7c8dd6 100755
--- a/tap-win32/SOURCES
+++ b/tap-win32/SOURCES
@@ -15,7 +15,7 @@ INCLUDES=$(DDK_INCLUDE_PATH)
# config-win32.h
C_DEFINES=
C_DEFINES=$(C_DEFINES) -DTAP_DRIVER_MAJOR_VERSION=8
-C_DEFINES=$(C_DEFINES) -DTAP_DRIVER_MINOR_VERSION=1
+C_DEFINES=$(C_DEFINES) -DTAP_DRIVER_MINOR_VERSION=307
# Use 00:FF:XX:XX:XX:XX format MAC addresses where
# the Xs are random (like Linux tap driver).
diff --git a/tap-win32/common.h b/tap-win32/common.h
index ef121b1..3c183c2 100755
--- a/tap-win32/common.h
+++ b/tap-win32/common.h
@@ -39,6 +39,8 @@
#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)
@@ -49,6 +51,11 @@
#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
//=================
diff --git a/tap-win32/i386/OemWin2k.inf b/tap-win32/i386/OemWin2k.inf
index eb1e071..681c4b7 100755
--- a/tap-win32/i386/OemWin2k.inf
+++ b/tap-win32/i386/OemWin2k.inf
@@ -10,6 +10,11 @@
; chkinf c:\src\openvpn\tap-win32\i386\oemwin2k.inf
; OUTPUT -> file:///c:/WINDDK/3790/tools/chkinf/htm/c%23+src+openvpn+tap-win32+i386+__OemWin2k.htm
+; INSTALL/REMOVE DRIVER
+; tapinstall install OemWin2k.inf TAP0801
+; tapinstall update OemWin2k.inf TAP0801
+; tapinstall remove TAP0801
+
;*********************************************************
; Note to Developers:
;
@@ -91,22 +96,28 @@
HKR, , ProductName, 0, "%DeviceDescription%"
[tap0801.params.reg]
- HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
- HKR, Ndi\params\MTU, Type, 0, "int"
- HKR, Ndi\params\MTU, Default, 0, "1500"
- HKR, Ndi\params\MTU, Optional, 0, "0"
- HKR, Ndi\params\MTU, Min, 0, "100"
- HKR, Ndi\params\MTU, Max, 0, "1500"
- HKR, Ndi\params\MTU, Step, 0, "1"
- HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status"
- HKR, Ndi\params\MediaStatus, Type, 0, "enum"
- HKR, Ndi\params\MediaStatus, Default, 0, "0"
- HKR, Ndi\params\MediaStatus, Optional, 0, "0"
- HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled"
- HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected"
- HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address"
- HKR, Ndi\params\MAC, Type, 0, "edit"
- HKR, Ndi\params\MAC, Optional, 0, "1"
+ HKR, Ndi\params\MTU, ParamDesc, 0, "MTU"
+ HKR, Ndi\params\MTU, Type, 0, "int"
+ HKR, Ndi\params\MTU, Default, 0, "1500"
+ HKR, Ndi\params\MTU, Optional, 0, "0"
+ HKR, Ndi\params\MTU, Min, 0, "100"
+ HKR, Ndi\params\MTU, Max, 0, "1500"
+ HKR, Ndi\params\MTU, Step, 0, "1"
+ HKR, Ndi\params\MediaStatus, ParamDesc, 0, "Media Status"
+ HKR, Ndi\params\MediaStatus, Type, 0, "enum"
+ HKR, Ndi\params\MediaStatus, Default, 0, "0"
+ HKR, Ndi\params\MediaStatus, Optional, 0, "0"
+ HKR, Ndi\params\MediaStatus\enum, "0", 0, "Application Controlled"
+ HKR, Ndi\params\MediaStatus\enum, "1", 0, "Always Connected"
+ HKR, Ndi\params\MAC, ParamDesc, 0, "MAC Address"
+ HKR, Ndi\params\MAC, Type, 0, "edit"
+ HKR, Ndi\params\MAC, Optional, 0, "1"
+ HKR, Ndi\params\AllowNonAdmin, ParamDesc, 0, "Non-Admin Access"
+ HKR, Ndi\params\AllowNonAdmin, Type, 0, "enum"
+ HKR, Ndi\params\AllowNonAdmin, Default, 0, "1"
+ HKR, Ndi\params\AllowNonAdmin, Optional, 0, "0"
+ HKR, Ndi\params\AllowNonAdmin\enum, "0", 0, "Not Allowed"
+ HKR, Ndi\params\AllowNonAdmin\enum, "1", 0, "Allowed"
;----------------------------------------------------------------
; Service Section
diff --git a/tap-win32/prototypes.h b/tap-win32/prototypes.h
index 81f58f4..2237ed0 100755
--- a/tap-win32/prototypes.h
+++ b/tap-win32/prototypes.h
@@ -160,7 +160,8 @@ BOOLEAN ProcessARP
TapAdapterPointer p_Adapter,
const PARP_PACKET src,
const IPADDR adapter_ip,
- const IPADDR ip,
+ const IPADDR ip_network,
+ const IPADDR ip_netmask,
const MACADDR mac
);
@@ -177,11 +178,42 @@ VOID InjectPacket
const unsigned int len
);
-VOID CheckIfDhcpAndPointToPointMode
+VOID CheckIfDhcpAndTunMode
(
TapAdapterPointer p_Adapter
);
VOID HookDispatchFunctions();
+#if ENABLE_NONADMIN
+
+typedef struct _SECURITY_DESCRIPTOR {
+ unsigned char opaque[20];
+} SECURITY_DESCRIPTOR;
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+ZwSetSecurityObject (
+ IN HANDLE Handle,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor);
+
+VOID AllowNonAdmin (TapExtensionPointer p_Extension);
+
+#endif
+
+#if PACKET_TRUNCATION_CHECK
+
+VOID IPv4PacketSizeVerify
+ (
+ const UCHAR *data,
+ ULONG length,
+ BOOLEAN tun,
+ const char *prefix,
+ LONG *counter
+ );
+
+#endif
+
#endif
diff --git a/tap-win32/tapdrvr.c b/tap-win32/tapdrvr.c
index 7eecca7..0997bd5 100755
--- a/tap-win32/tapdrvr.c
+++ b/tap-win32/tapdrvr.c
@@ -35,7 +35,8 @@
// 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 ioctl.
+// TAP_IOCTL_CONFIG_POINT_TO_POINT or
+// TAP_IOCTL_CONFIG_TUN ioctl.
//======================================================
#define NDIS_MINIPORT_DRIVER
@@ -46,11 +47,27 @@
#define NTSTRSAFE_LIB
// Debug info output
-#define ALSO_DBGPRINT 1
-#define DEBUGP_AT_DISPATCH 0
+#define ALSO_DBGPRINT 1
+#define DEBUGP_AT_DISPATCH 0
+
+//========================================================
+// Check for truncated IPv4 packets, log errors if found.
+//========================================================
+#define PACKET_TRUNCATION_CHECK 1 // JYFIXME
+
+//========================================================
+// 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 // JYFIXME
#include <ndis.h>
#include <ntstrsafe.h>
+#include <ntddk.h>
#include "lock.h"
#include "constants.h"
@@ -274,6 +291,10 @@ NDIS_STATUS AdapterCreate
UINT l_Index;
NDIS_STATUS status;
+#if ENABLE_NONADMIN
+ BOOLEAN enable_non_admin = FALSE;
+#endif
+
//====================================
// Make sure adapter type is supported
//====================================
@@ -410,6 +431,25 @@ NDIS_STATUS AdapterCreate
}
}
+#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");
@@ -479,6 +519,11 @@ NDIS_STATUS AdapterCreate
l_Adapter->m_InterfaceIsRunning = TRUE;
+#if ENABLE_NONADMIN
+ if (enable_non_admin)
+ AllowNonAdmin (&l_Adapter->m_Extension);
+#endif
+
return NDIS_STATUS_SUCCESS;
}
@@ -1011,7 +1056,7 @@ NDIS_STATUS AdapterQuery
break;
case OID_GEN_LINK_SPEED:
- l_Query.m_Long = 100000;
+ l_Query.m_Long = 100000; // rate / 100 bps
break;
case OID_802_3_PERMANENT_ADDRESS:
@@ -1348,19 +1393,40 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
__try
{
- for (l_Index = 0; l_NDIS_Buffer && l_Index < l_PacketLength;
- l_Index += l_BufferLength)
+ 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
@@ -1381,6 +1447,7 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
(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;
}
@@ -1417,7 +1484,7 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
// In Point-To-Point mode, check to see whether
// packet is ARP or IPv4 (if neither, then drop).
//===============================================
- if (l_Adapter->m_PointToPoint)
+ if (l_Adapter->m_tun)
{
ETH_HEADER *e;
@@ -1438,7 +1505,8 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
ProcessARP (l_Adapter,
(PARP_PACKET) l_PacketBuffer->m_Data,
l_Adapter->m_localIP,
- l_Adapter->m_remoteIP,
+ l_Adapter->m_remoteNetwork,
+ l_Adapter->m_remoteNetmask,
l_Adapter->m_TapToUser.dest);
default:
@@ -1458,7 +1526,7 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
goto no_queue;
// Packet looks like IPv4, queue it.
- l_PacketBuffer->m_SizeFlags |= TP_POINT_TO_POINT;
+ l_PacketBuffer->m_SizeFlags |= TP_TUN;
}
}
@@ -1669,15 +1737,25 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
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]",
+#else
"State=%s Err=[%s/%d] #O=%d Tx=[%d,%d] Rx=[%d,%d] IrpQ=[%d,%d,%d] PktQ=[%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,
@@ -1708,21 +1786,65 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
}
#endif
- case TAP_IOCTL_CONFIG_POINT_TO_POINT:
+ 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_PointToPoint = FALSE;
+ 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_remoteIP =
- ((IPADDR*) (p_IRP->AssociatedIrp.SystemBuffer))[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);
@@ -1731,9 +1853,9 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
- l_Adapter->m_PointToPoint = TRUE;
+ l_Adapter->m_tun = TRUE;
- CheckIfDhcpAndPointToPointMode (l_Adapter);
+ CheckIfDhcpAndTunMode (l_Adapter);
p_IRP->IoStatus.Information = 1; // Simple boolean value
}
@@ -1791,7 +1913,7 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
l_Adapter->m_dhcp_enabled = TRUE;
l_Adapter->m_dhcp_server_arp = TRUE;
- CheckIfDhcpAndPointToPointMode (l_Adapter);
+ CheckIfDhcpAndTunMode (l_Adapter);
p_IRP->IoStatus.Information = 1; // Simple boolean value
}
@@ -1979,7 +2101,7 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
p_IRP->IoStatus.Status = l_Status = STATUS_UNSUCCESSFUL;
p_IRP->IoStatus.Information = 0;
}
- else if (!l_Adapter->m_PointToPoint && ((l_IrpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
+ else if (!l_Adapter->m_tun && ((l_IrpSp->Parameters.Write.Length) >= ETHERNET_HEADER_SIZE))
{
__try
{
@@ -1989,6 +2111,18 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
(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,
@@ -2011,7 +2145,7 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
p_IRP->IoStatus.Information = 0;
}
}
- else if (l_Adapter->m_PointToPoint && ((l_IrpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
+ else if (l_Adapter->m_tun && ((l_IrpSp->Parameters.Write.Length) >= IP_HEADER_SIZE))
{
__try
{
@@ -2022,6 +2156,18 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
(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,
@@ -2197,7 +2343,7 @@ CompleteIRP (IN PIRP p_IRP,
// component.
//-------------------------------------------
- if (p_PacketBuffer->m_SizeFlags & TP_POINT_TO_POINT)
+ if (p_PacketBuffer->m_SizeFlags & TP_TUN)
{
offset = ETHERNET_HEADER_SIZE;
len = (int) (p_PacketBuffer->m_SizeFlags & TP_SIZE_MASK) - ETHERNET_HEADER_SIZE;
@@ -2379,16 +2525,16 @@ SetMediaStatus (TapAdapterPointer p_Adapter, BOOLEAN state)
//======================================================
-// If DHCP mode is used together with Point-to-point
-// mode, consider the fact that the P2P remote endpoint
-// might be equal to the DHCP masq server address.
+// 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
-CheckIfDhcpAndPointToPointMode (TapAdapterPointer p_Adapter)
+CheckIfDhcpAndTunMode (TapAdapterPointer p_Adapter)
{
- if (p_Adapter->m_PointToPoint && p_Adapter->m_dhcp_enabled)
+ if (p_Adapter->m_tun && p_Adapter->m_dhcp_enabled)
{
- if (p_Adapter->m_dhcp_server_ip == p_Adapter->m_remoteIP)
+ 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;
@@ -2404,7 +2550,8 @@ BOOLEAN
ProcessARP (TapAdapterPointer p_Adapter,
const PARP_PACKET src,
const IPADDR adapter_ip,
- const IPADDR ip,
+ const IPADDR ip_network,
+ const IPADDR ip_netmask,
const MACADDR mac)
{
//-----------------------------------------------
@@ -2420,7 +2567,8 @@ ProcessARP (TapAdapterPointer p_Adapter,
&& 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)
+ && (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)
@@ -2442,7 +2590,7 @@ ProcessARP (TapAdapterPointer p_Adapter,
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 = ip;
+ arp->m_ARP_IP_Source = src->m_ARP_IP_Destination;
arp->m_ARP_IP_Destination = adapter_ip;
DUMP_PACKET ("ProcessARP",
@@ -2508,9 +2656,10 @@ InjectPacket (TapAdapterPointer p_Adapter,
VOID ResetTapAdapterState (TapAdapterPointer p_Adapter)
{
// Point-To-Point
- p_Adapter->m_PointToPoint = FALSE;
+ p_Adapter->m_tun = FALSE;
p_Adapter->m_localIP = 0;
- p_Adapter->m_remoteIP = 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));
@@ -2526,6 +2675,124 @@ VOID ResetTapAdapterState (TapAdapterPointer p_Adapter)
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 --git a/tap-win32/types.h b/tap-win32/types.h
index f5a4291..45e0033 100755
--- a/tap-win32/types.h
+++ b/tap-win32/types.h
@@ -92,8 +92,8 @@ TapExtension, *TapExtensionPointer;
typedef struct _TapPacket
{
# define TAP_PACKET_SIZE(data_size) (sizeof (TapPacket) + (data_size))
-# define TP_POINT_TO_POINT 0x80000000
-# define TP_SIZE_MASK (~TP_POINT_TO_POINT)
+# define TP_TUN 0x80000000
+# define TP_SIZE_MASK (~TP_TUN)
ULONG m_SizeFlags;
UCHAR m_Data []; // m_Data must be the last struct member
}
@@ -107,6 +107,9 @@ typedef struct _TapAdapter
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;
@@ -123,9 +126,10 @@ typedef struct _TapAdapter
char m_DeviceState;
// Info for point-to-point mode
- BOOLEAN m_PointToPoint;
+ BOOLEAN m_tun;
IPADDR m_localIP;
- IPADDR m_remoteIP;
+ IPADDR m_remoteNetwork;
+ IPADDR m_remoteNetmask;
ETH_HEADER m_TapToUser;
ETH_HEADER m_UserToTap;
MACADDR m_MAC_Broadcast;
diff --git a/tun.c b/tun.c
index 03df0c8..7fd0c51 100644
--- a/tun.c
+++ b/tun.c
@@ -169,14 +169,14 @@ static const char ifconfig_warn_how_to_silence[] = "(silence this warning with -
* like an IPv4 address.
*/
static void
-ifconfig_sanity_check (bool tun, in_addr_t addr)
+ifconfig_sanity_check (bool tun, in_addr_t addr, int topology)
{
struct gc_arena gc = gc_new ();
const bool looks_like_netmask = ((addr & 0xFF000000) == 0xFF000000);
if (tun)
{
- if (looks_like_netmask)
- msg (M_WARN, "WARNING: Since you are using --dev tun, the second argument to --ifconfig must be an IP address. You are using something (%s) that looks more like a netmask. %s",
+ if (looks_like_netmask && (topology == TOP_NET30 || topology == TOP_P2P))
+ msg (M_WARN, "WARNING: Since you are using --dev tun with a point-to-point topology, the second argument to --ifconfig must be an IP address. You are using something (%s) that looks more like a netmask. %s",
print_in_addr_t (addr, 0, &gc),
ifconfig_warn_how_to_silence);
}
@@ -283,7 +283,13 @@ ifconfig_options_string (const struct tuntap* tt, bool remote, bool disable, str
struct buffer out = alloc_buf_gc (256, gc);
if (tt->did_ifconfig_setup && !disable)
{
- if (tt->type == DEV_TYPE_TUN)
+ if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET))
+ {
+ buf_printf (&out, "%s %s",
+ print_in_addr_t (tt->local & tt->remote_netmask, 0, gc),
+ print_in_addr_t (tt->remote_netmask, 0, gc));
+ }
+ else if (tt->type == DEV_TYPE_TUN)
{
const char *l, *r;
if (remote)
@@ -298,12 +304,6 @@ ifconfig_options_string (const struct tuntap* tt, bool remote, bool disable, str
}
buf_printf (&out, "%s %s", r, l);
}
- else if (tt->type == DEV_TYPE_TAP)
- {
- buf_printf (&out, "%s %s",
- print_in_addr_t (tt->local & tt->remote_netmask, 0, gc),
- print_in_addr_t (tt->remote_netmask, 0, gc));
- }
else
buf_printf (&out, "[undef]");
}
@@ -346,6 +346,24 @@ tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc)
}
/*
+ * Return true for point-to-point topology, false for subnet topology
+ */
+bool
+is_tun_p2p (const struct tuntap *tt)
+{
+ bool tun = false;
+
+ if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET))
+ tun = false;
+ else if (tt->type == DEV_TYPE_TUN)
+ tun = true;
+ else
+ ASSERT (0); /* should have been caught in init_tun */
+
+ return tun;
+}
+
+/*
* Init tun/tap object.
*
* Set up tuntap structure for ifconfig,
@@ -354,6 +372,7 @@ tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc)
struct tuntap *
init_tun (const char *dev, /* --dev option */
const char *dev_type, /* --dev-type option */
+ int topology, /* one of the TOP_x values */
const char *ifconfig_local_parm, /* --ifconfig parm 1 */
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
in_addr_t local_public,
@@ -368,6 +387,7 @@ init_tun (const char *dev, /* --dev option */
clear_tuntap (tt);
tt->type = dev_type_enum (dev, dev_type);
+ tt->topology = topology;
if (ifconfig_local_parm && ifconfig_remote_netmask_parm)
{
@@ -379,12 +399,7 @@ init_tun (const char *dev, /* --dev option */
/*
* We only handle TUN/TAP devices here, not --dev null devices.
*/
- if (tt->type == DEV_TYPE_TUN)
- tun = true;
- else if (tt->type == DEV_TYPE_TAP)
- tun = false;
- else
- msg (M_FATAL, "'%s' is not a TUN/TAP device. The --ifconfig option works only for TUN/TAP devices.", dev);
+ tun = is_tun_p2p (tt);
/*
* Convert arguments to binary IPv4 addresses.
@@ -415,7 +430,7 @@ init_tun (const char *dev, /* --dev option */
*/
if (strict_warn)
{
- ifconfig_sanity_check (tun, tt->remote_netmask);
+ ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology);
/*
* If local_public or remote_public addresses are defined,
@@ -511,12 +526,7 @@ do_ifconfig (struct tuntap *tt,
/*
* We only handle TUN/TAP devices here, not --dev null devices.
*/
- if (tt->type == DEV_TYPE_TUN)
- tun = true;
- else if (tt->type == DEV_TYPE_TAP)
- tun = false;
- else
- ASSERT (0); /* should have been caught in init_tun */
+ tun = is_tun_p2p (tt);
/*
* Set ifconfig parameters
@@ -2376,6 +2386,34 @@ get_adapter_info_list (struct gc_arena *gc)
return pi;
}
+const IP_PER_ADAPTER_INFO *
+get_per_adapter_info (const DWORD index, struct gc_arena *gc)
+{
+ ULONG size = 0;
+ IP_PER_ADAPTER_INFO *pi = NULL;
+ DWORD status;
+
+ if ((status = GetPerAdapterInfo (index, NULL, &size)) != ERROR_BUFFER_OVERFLOW)
+ {
+ msg (M_INFO, "GetPerAdapterInfo #1 failed (status=%u) : %s",
+ (unsigned int)status,
+ strerror_win32 (status, gc));
+ }
+ else
+ {
+ pi = (PIP_PER_ADAPTER_INFO) gc_malloc (size, false, gc);
+ if ((status = GetPerAdapterInfo ((ULONG)index, pi, &size)) == ERROR_SUCCESS)
+ return pi;
+ else
+ {
+ msg (M_INFO, "GetPerAdapterInfo #2 failed (status=%u) : %s",
+ (unsigned int)status,
+ strerror_win32 (status, gc));
+ }
+ }
+ return pi;
+}
+
static const IP_INTERFACE_INFO *
get_interface_info_list (struct gc_arena *gc)
{
@@ -2443,7 +2481,7 @@ get_adapter (const IP_ADAPTER_INFO *ai, DWORD index)
return NULL;
}
-static const IP_ADAPTER_INFO *
+const IP_ADAPTER_INFO *
get_adapter_info (DWORD index, struct gc_arena *gc)
{
return get_adapter (get_adapter_info_list (gc), index);
@@ -2762,6 +2800,14 @@ show_adapter (int msglev, const IP_ADAPTER_INFO *a, struct gc_arena *gc)
msg (msglev, " PRI WINS = %s", format_ip_addr_string (&a->PrimaryWinsServer, gc));
msg (msglev, " SEC WINS = %s", format_ip_addr_string (&a->SecondaryWinsServer, gc));
}
+
+ {
+ const IP_PER_ADAPTER_INFO *pai = get_per_adapter_info (a->Index, gc);
+ if (pai)
+ {
+ msg (msglev, " DNS SERV = %s", format_ip_addr_string (&pai->DnsServerList, gc));
+ }
+ }
}
/*
@@ -2788,6 +2834,123 @@ show_adapters (int msglev)
}
/*
+ * Set a particular TAP-Win32 adapter (or all of them if
+ * adapter_name == NULL) to allow it to be opened from
+ * a non-admin account. This setting will only persist
+ * for the lifetime of the device object.
+ */
+
+static void
+tap_allow_nonadmin_access_handle (const char *device_path, HANDLE hand)
+{
+ struct security_attributes sa;
+ BOOL status;
+
+ if (!init_security_attributes_allow_all (&sa))
+ msg (M_ERR, "Error: init SA failed");
+
+ status = SetKernelObjectSecurity (hand, DACL_SECURITY_INFORMATION, &sa.sd);
+ if (!status)
+ {
+ msg (M_ERRNO, "Error: SetKernelObjectSecurity failed on %s", device_path);
+ }
+ else
+ {
+ msg (M_INFO|M_NOPREFIX, "TAP-Win32 device: %s [Non-admin access allowed]", device_path);
+ }
+}
+
+void
+tap_allow_nonadmin_access (const char *dev_node)
+{
+ struct gc_arena gc = gc_new ();
+ const struct tap_reg *tap_reg = get_tap_reg (&gc);
+ const struct panel_reg *panel_reg = get_panel_reg (&gc);
+ const char *device_guid = NULL;
+ HANDLE hand;
+ char guid_buffer[256];
+ char device_path[256];
+
+ at_least_one_tap_win32 (tap_reg);
+
+ if (dev_node)
+ {
+ /* Get the device GUID for the device specified with --dev-node. */
+ device_guid = get_device_guid (dev_node, guid_buffer, sizeof (guid_buffer), tap_reg, panel_reg, &gc);
+
+ if (!device_guid)
+ msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node);
+
+ /* Open Windows TAP-Win32 adapter */
+ openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s",
+ USERMODEDEVICEDIR,
+ device_guid,
+ TAPSUFFIX);
+
+ hand = CreateFile (
+ device_path,
+ MAXIMUM_ALLOWED,
+ 0, /* was: FILE_SHARE_READ */
+ 0,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
+ 0
+ );
+
+ if (hand == INVALID_HANDLE_VALUE)
+ msg (M_ERR, "CreateFile failed on TAP device: %s", device_path);
+
+ tap_allow_nonadmin_access_handle (device_path, hand);
+ CloseHandle (hand);
+ }
+ else
+ {
+ int device_number = 0;
+
+ /* Try opening all TAP devices */
+ while (true)
+ {
+ device_guid = get_unspecified_device_guid (device_number,
+ guid_buffer,
+ sizeof (guid_buffer),
+ tap_reg,
+ panel_reg,
+ &gc);
+
+ if (!device_guid)
+ break;
+
+ /* Open Windows TAP-Win32 adapter */
+ openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s",
+ USERMODEDEVICEDIR,
+ device_guid,
+ TAPSUFFIX);
+
+ hand = CreateFile (
+ device_path,
+ MAXIMUM_ALLOWED,
+ 0, /* was: FILE_SHARE_READ */
+ 0,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
+ 0
+ );
+
+ if (hand == INVALID_HANDLE_VALUE)
+ msg (M_WARN, "CreateFile failed on TAP device: %s", device_path);
+ else
+ {
+ tap_allow_nonadmin_access_handle (device_path, hand);
+ CloseHandle (hand);
+ }
+
+ device_number++;
+ }
+ }
+ gc_free (&gc);
+}
+
+/*
* DHCP release/renewal
*/
@@ -2963,7 +3126,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
device_guid = get_device_guid (dev_node, guid_buffer, sizeof (guid_buffer), tap_reg, panel_reg, &gc);
if (!device_guid)
- msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node);
+ msg (M_FATAL, "TAP-Win32 adapter '%s' not found", dev_node);
/* Open Windows TAP-Win32 adapter */
openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s",
@@ -3070,17 +3233,41 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
if (tt->type == DEV_TYPE_TUN)
{
- in_addr_t ep[2];
- ep[0] = htonl (tt->local);
- ep[1] = htonl (tt->remote_netmask);
if (!tt->did_ifconfig_setup)
{
msg (M_FATAL, "ERROR: --dev tun also requires --ifconfig");
}
- if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_POINT_TO_POINT,
- ep, sizeof (ep),
- ep, sizeof (ep), &len, NULL))
- msg (M_FATAL, "ERROR: The TAP-Win32 driver rejected a DeviceIoControl call to set Point-to-Point mode, which is required for --dev tun");
+
+ if (tt->topology == TOP_SUBNET)
+ {
+ in_addr_t ep[3];
+ BOOL status;
+
+ ep[0] = htonl (tt->local);
+ ep[1] = htonl (tt->local & tt->remote_netmask);
+ ep[2] = htonl (tt->remote_netmask);
+
+ status = DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_TUN,
+ ep, sizeof (ep),
+ ep, sizeof (ep), &len, NULL);
+
+ msg (status ? M_INFO : M_FATAL, "Set TAP-Win32 TUN subnet mode network/local/netmask = %s/%s/%s [%s]",
+ print_in_addr_t (ep[1], IA_NET_ORDER, &gc),
+ print_in_addr_t (ep[0], IA_NET_ORDER, &gc),
+ print_in_addr_t (ep[2], IA_NET_ORDER, &gc),
+ status ? "SUCCEEDED" : "FAILED");
+
+ } else {
+
+ in_addr_t ep[2];
+ ep[0] = htonl (tt->local);
+ ep[1] = htonl (tt->remote_netmask);
+
+ if (!DeviceIoControl (tt->hand, TAP_IOCTL_CONFIG_POINT_TO_POINT,
+ ep, sizeof (ep),
+ ep, sizeof (ep), &len, NULL))
+ msg (M_FATAL, "ERROR: The TAP-Win32 driver rejected a DeviceIoControl call to set Point-to-Point mode, which is required for --dev tun");
+ }
}
/* should we tell the TAP-Win32 driver to masquerade as a DHCP server as a means
@@ -3096,7 +3283,14 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
/* At what IP address should the DHCP server masquerade at? */
if (tt->type == DEV_TYPE_TUN)
{
- ep[2] = htonl (tt->remote_netmask);
+ if (tt->topology == TOP_SUBNET)
+ {
+ const in_addr_t netmask_inv = ~tt->remote_netmask;
+ ep[2] = netmask_inv ? htonl ((tt->local | netmask_inv) - 1) : 0;
+ }
+ else
+ ep[2] = htonl (tt->remote_netmask);
+
if (tt->options.dhcp_masq_custom_offset)
msg (M_WARN, "WARNING: because you are using '--dev tun' mode, the '--ip-win32 dynamic [offset]' option is ignoring the offset parameter");
}
@@ -3186,7 +3380,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
(unsigned int)index,
device_guid);
else
- msg (M_WARN, "NOTE: FlushIpNetTable failed on interface [%u] %s (status=%u) : %s",
+ msg (D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%u] %s (status=%u) : %s",
(unsigned int)index,
device_guid,
(unsigned int)status,
diff --git a/tun.h b/tun.h
index 76c4867..41264e6 100644
--- a/tun.h
+++ b/tun.h
@@ -119,6 +119,9 @@ struct tuntap
# define TUNNEL_TYPE(tt) ((tt) ? ((tt)->type) : DEV_TYPE_UNDEF)
int type; /* DEV_TYPE_x as defined in proto.h */
+# define TUNNEL_TOPOLOGY(tt) ((tt) ? ((tt)->topology) : TOP_UNDEF)
+ int topology; /* one of the TOP_x values */
+
bool did_ifconfig_setup;
bool did_ifconfig;
@@ -203,6 +206,7 @@ const char *guess_tuntap_dev (const char *dev,
struct tuntap *init_tun (const char *dev, /* --dev option */
const char *dev_type, /* --dev-type option */
+ int topology, /* one of the TOP_x values */
const char *ifconfig_local_parm, /* --ifconfig parm 1 */
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
in_addr_t local_public,
@@ -227,6 +231,8 @@ const char *dev_type_string (const char *dev, const char *dev_type);
const char *ifconfig_options_string (const struct tuntap* tt, bool remote, bool disable, struct gc_arena *gc);
+bool is_tun_p2p (const struct tuntap *tt);
+
/*
* Inline functions
*/
@@ -292,6 +298,10 @@ void verify_255_255_255_252 (in_addr_t local, in_addr_t remote);
const IP_ADAPTER_INFO *get_adapter_info_list (struct gc_arena *gc);
const IP_ADAPTER_INFO *get_tun_adapter (const struct tuntap *tt, const IP_ADAPTER_INFO *list);
+
+const IP_ADAPTER_INFO *get_adapter_info (DWORD index, struct gc_arena *gc);
+const IP_PER_ADAPTER_INFO *get_per_adapter_info (const DWORD index, struct gc_arena *gc);
+
bool is_adapter_up (const struct tuntap *tt, const IP_ADAPTER_INFO *list);
bool is_ip_in_adapter_subnet (const IP_ADAPTER_INFO *ai, const in_addr_t ip, in_addr_t *highest_netmask);
DWORD adapter_index_of_ip (const IP_ADAPTER_INFO *list, const in_addr_t ip, int *count);
@@ -299,6 +309,8 @@ DWORD adapter_index_of_ip (const IP_ADAPTER_INFO *list, const in_addr_t ip, int
void show_tap_win32_adapters (int msglev, int warnlev);
void show_adapters (int msglev);
+void tap_allow_nonadmin_access (const char *dev_node);
+
void show_valid_win32_tun_subnets (void);
const char *tap_win32_getinfo (const struct tuntap *tt, struct gc_arena *gc);
void tun_show_debug (struct tuntap *tt);