summaryrefslogtreecommitdiff
path: root/openvpn
diff options
context:
space:
mode:
Diffstat (limited to 'openvpn')
-rw-r--r--openvpn/INSTALL2
-rw-r--r--openvpn/configure.ac12
-rw-r--r--openvpn/doc/openvpn.835
-rw-r--r--openvpn/include/openvpn-plugin.h25
-rwxr-xr-xopenvpn/sample/sample-plugins/log/build2
-rw-r--r--openvpn/sample/sample-plugins/log/log_v3.c5
-rw-r--r--openvpn/src/openvpn/options.c36
-rw-r--r--openvpn/src/openvpn/plugin.c5
-rw-r--r--openvpn/src/openvpn/ssl.c26
-rw-r--r--openvpn/src/openvpn/ssl_backend.h30
-rw-r--r--openvpn/src/openvpn/ssl_common.h4
-rw-r--r--openvpn/src/openvpn/ssl_openssl.c39
-rw-r--r--openvpn/src/openvpn/ssl_polarssl.c40
-rw-r--r--openvpn/src/openvpn/ssl_verify.c2
-rw-r--r--openvpn/src/openvpn/tun.c338
-rw-r--r--openvpn/src/openvpn/tun.h3
16 files changed, 502 insertions, 102 deletions
diff --git a/openvpn/INSTALL b/openvpn/INSTALL
index ed696673..61dc9758 100644
--- a/openvpn/INSTALL
+++ b/openvpn/INSTALL
@@ -169,8 +169,6 @@ OPTIONS for ./configure:
--disable-server disable server support only (but retain client
support) [default=yes]
--disable-plugins disable plug-in support [default=yes]
- --disable-eurephia disable support for the eurephia plug-in
- [default=yes]
--disable-management disable management server support [default=yes]
--enable-pkcs11 enable pkcs11 support [default=no]
--disable-socks disable Socks support [default=yes]
diff --git a/openvpn/configure.ac b/openvpn/configure.ac
index 5da5772b..65c639c5 100644
--- a/openvpn/configure.ac
+++ b/openvpn/configure.ac
@@ -101,13 +101,6 @@ AC_ARG_ENABLE(
)
AC_ARG_ENABLE(
- [eurephia],
- [AS_HELP_STRING([--disable-eurephia], [disable support for the eurephia plug-in @<:@default=yes@:>@])],
- ,
- [enable_eurephia="yes"]
-)
-
-AC_ARG_ENABLE(
[management],
[AS_HELP_STRING([--disable-management], [disable management server support @<:@default=yes@:>@])],
,
@@ -459,7 +452,7 @@ SOCKET_INCLUDES="
"
AC_CHECK_HEADERS(
- [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h],
+ [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h],
,
,
[[${SOCKET_INCLUDES}]]
@@ -1019,8 +1012,7 @@ fi
if test "${enable_plugins}" = "yes"; then
OPTIONAL_DL_LIBS="${DL_LIBS}"
- AC_DEFINE([ENABLE_PLUGIN], [1], [Enable systemd support])
- test "${enable_eurephia}" = "yes" && AC_DEFINE([ENABLE_EUREPHIA], [1], [Enable support for the eurephia plug-in])
+ AC_DEFINE([ENABLE_PLUGIN], [1], [Enable plug-in support])
else
enable_plugin_auth_pam="no"
enable_plugin_down_root="no"
diff --git a/openvpn/doc/openvpn.8 b/openvpn/doc/openvpn.8
index 42c7bf6e..868fb841 100644
--- a/openvpn/doc/openvpn.8
+++ b/openvpn/doc/openvpn.8
@@ -804,6 +804,17 @@ also specify
or
.B \-\-dev-type tap.
+Under Mac OS X this option can be used to specify the default tun
+implementation. Using
+.B \-\-dev\-node utun
+forces usage of the native Darwin tun kernel support. Use
+.B \-\-dev\-node utunN
+to select a specific utun instance. To force using the tun.kext (/dev/tunX) use
+.B \-\-dev\-node tun
+. When not specifying a
+.B \-\-dev\-node
+option openvpn will first try to open utun, and fall back to tun.kext.
+
On Windows systems, select the TAP-Win32 adapter which
is named
.B node
@@ -1879,6 +1890,11 @@ reasons for having OpenVPN fail if it detects problems in a
config file. Having said that, there are valid reasons for wanting
new software features to gracefully degrade when encountered by
older software versions.
+
+It is also possible to tag a single directive so as not to trigger
+a fatal error if the directive isn't recognized. To do this,
+prepend the following before the directive:
+.B setenv opt
.\"*********************************************************
.TP
.B \-\-setenv-safe name value
@@ -4234,6 +4250,15 @@ when you built your peer's certificate (see
above).
.\"*********************************************************
.TP
+.B \-\-tls-version-min version ['or-highest']
+Sets the minimum
+TLS version we will accept from the peer (default is "1.0").
+Examples for version
+include "1.0", "1.1", or "1.2". If 'or-highest' is specified
+and version is not recognized, we will only accept the highest TLS
+version supported by the local SSL implementation.
+.\"*********************************************************
+.TP
.B \-\-pkcs12 file
Specify a PKCS #12 file containing local private key,
local certificate, and root CA certificate.
@@ -5965,6 +5990,16 @@ Set prior to execution of the
script.
.\"*********************************************************
.TP
+.B tls_digest_{n}
+Contains the certificate SHA1 fingerprint/digest hash value,
+where
+.B n
+is the verification level. Only set for TLS connections. Set prior
+to execution of
+.B \-\-tls-verify
+script.
+.\"*********************************************************
+.TP
.B tls_id_{n}
A series of certificate fields from the remote peer,
where
diff --git a/openvpn/include/openvpn-plugin.h b/openvpn/include/openvpn-plugin.h
index 0879f490..03da92ab 100644
--- a/openvpn/include/openvpn-plugin.h
+++ b/openvpn/include/openvpn-plugin.h
@@ -201,10 +201,15 @@ struct openvpn_plugin_string_list
*
* Version Comment
* 1 Initial plugin v3 structures providing the same API as
- * the v2 plugin interface + X509 certificate information.
+ * the v2 plugin interface, X509 certificate information +
+ * a logging API for plug-ins.
+ *
+ * 2 Added ssl_api member in struct openvpn_plugin_args_open_in
+ * which identifies the SSL implementation OpenVPN is compiled
+ * against.
*
*/
-#define OPENVPN_PLUGINv3_STRUCTVER 1
+#define OPENVPN_PLUGINv3_STRUCTVER 2
/**
* Definitions needed for the plug-in callback functions.
@@ -260,6 +265,18 @@ struct openvpn_plugin_callbacks
};
/**
+ * Used by the openvpn_plugin_open_v3() function to indicate to the
+ * plug-in what kind of SSL implementation OpenVPN uses. This is
+ * to avoid SEGV issues when OpenVPN is complied against PolarSSL
+ * and the plug-in against OpenSSL.
+ */
+typedef enum {
+ SSLAPI_NONE,
+ SSLAPI_OPENSSL,
+ SSLAPI_POLARSSL
+} ovpnSSLAPI;
+
+/**
* Arguments used to transport variables to the plug-in.
* The struct openvpn_plugin_args_open_in is only used
* by the openvpn_plugin_open_v3() function.
@@ -286,6 +303,7 @@ struct openvpn_plugin_args_open_in
const char ** const argv;
const char ** const envp;
struct openvpn_plugin_callbacks *callbacks;
+ const ovpnSSLAPI ssl_api;
};
@@ -557,7 +575,8 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
* ARGUMENTS
*
* version : fixed value, defines the API version of the OpenVPN plug-in API. The plug-in
- * should validate that this value is matching the OPENVPN_PLUGIN_VERSION value.
+ * should validate that this value is matching the OPENVPN_PLUGINv3_STRUCTVER
+ * value.
*
* arguments : Structure with all arguments available to the plug-in.
*
diff --git a/openvpn/sample/sample-plugins/log/build b/openvpn/sample/sample-plugins/log/build
index bbb05f7c..c07ec408 100755
--- a/openvpn/sample/sample-plugins/log/build
+++ b/openvpn/sample/sample-plugins/log/build
@@ -6,7 +6,7 @@
#
# This directory is where we will look for openvpn-plugin.h
-CPPFLAGS="${CPPFLAGS:--I../../..}"
+CPPFLAGS="${CPPFLAGS:--I../../../include}"
CC="${CC:-gcc}"
CFLAGS="${CFLAGS:--O2 -Wall -g}"
diff --git a/openvpn/sample/sample-plugins/log/log_v3.c b/openvpn/sample/sample-plugins/log/log_v3.c
index 742c7568..4d3af91a 100644
--- a/openvpn/sample/sample-plugins/log/log_v3.c
+++ b/openvpn/sample/sample-plugins/log/log_v3.c
@@ -85,6 +85,11 @@ openvpn_plugin_open_v3 (const int v3structver,
return OPENVPN_PLUGIN_FUNC_ERROR;
}
+ if( args->ssl_api != SSLAPI_OPENSSL ) {
+ printf("This plug-in can only be used against OpenVPN with OpenSSL\n");
+ return OPENVPN_PLUGIN_FUNC_ERROR;
+ }
+
/* Which callbacks to intercept. */
ret->type_mask =
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) |
diff --git a/openvpn/src/openvpn/options.c b/openvpn/src/openvpn/options.c
index e31f918f..48065f99 100644
--- a/openvpn/src/openvpn/options.c
+++ b/openvpn/src/openvpn/options.c
@@ -6,9 +6,7 @@
* packet compression.
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- *
- * Additions for eurephia plugin done by:
- * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2009
+ * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.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
@@ -107,9 +105,6 @@ const char title_string[] =
#ifdef ENABLE_PKCS11
" [PKCS11]"
#endif
-#ifdef ENABLE_EUREPHIA
- " [eurephia]"
-#endif
#if ENABLE_IP_PKTINFO
" [MH]"
#endif
@@ -582,6 +577,9 @@ static const char usage_message[] =
" by a Certificate Authority in --ca file.\n"
"--extra-certs file : one or more PEM certs that complete the cert chain.\n"
"--key file : Local private key in .pem format.\n"
+ "--tls-version-min <version> ['or-highest'] : sets the minimum TLS version we\n"
+ " will accept from the peer. If version is unrecognized and 'or-highest'\n"
+ " is specified, require max TLS version supported by SSL implementation.\n"
#ifndef ENABLE_CRYPTO_POLARSSL
"--pkcs12 file : PKCS#12 file containing local private key, local certificate\n"
" and optionally the root CA certificate.\n"
@@ -4013,7 +4011,18 @@ add_option (struct options *options,
const bool pull_mode = BOOL_CAST (permission_mask & OPT_P_PULL_MODE);
int msglevel_fc = msglevel_forward_compatible (options, msglevel);
- ASSERT (MAX_PARMS >= 5);
+ ASSERT (MAX_PARMS >= 7);
+
+ /*
+ * If directive begins with "setenv opt" prefix, don't raise an error if
+ * directive is unrecognized.
+ */
+ if (streq (p[0], "setenv") && p[1] && streq (p[1], "opt") && !(permission_mask & OPT_P_PULL_MODE))
+ {
+ p += 2;
+ msglevel_fc = M_WARN;
+ }
+
if (!file)
{
file = "[CMD-LINE]";
@@ -6408,6 +6417,19 @@ add_option (struct options *options,
options->priv_key_file_inline = p[2];
}
}
+ else if (streq (p[0], "tls-version-min") && p[1])
+ {
+ int ver;
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ ver = tls_version_min_parse(p[1], p[2]);
+ if (ver == TLS_VER_BAD)
+ {
+ msg (msglevel, "unknown tls-version-min parameter: %s", p[1]);
+ goto err;
+ }
+ options->ssl_flags &= ~(SSLF_TLS_VERSION_MASK << SSLF_TLS_VERSION_SHIFT);
+ options->ssl_flags |= (ver << SSLF_TLS_VERSION_SHIFT);
+ }
#ifndef ENABLE_CRYPTO_POLARSSL
else if (streq (p[0], "pkcs12") && p[1])
{
diff --git a/openvpn/src/openvpn/plugin.c b/openvpn/src/openvpn/plugin.c
index c96c121f..0948f238 100644
--- a/openvpn/src/openvpn/plugin.c
+++ b/openvpn/src/openvpn/plugin.c
@@ -40,8 +40,8 @@
#include "error.h"
#include "misc.h"
#include "plugin.h"
+#include "ssl_backend.h"
#include "win32.h"
-
#include "memdbg.h"
#define PLUGIN_SYMBOL_REQUIRED (1<<0)
@@ -374,7 +374,8 @@ plugin_open_item (struct plugin *p,
struct openvpn_plugin_args_open_in args = { p->plugin_type_mask,
(const char ** const) o->argv,
(const char ** const) envp,
- &callbacks };
+ &callbacks,
+ SSLAPI };
struct openvpn_plugin_args_open_return retargs;
CLEAR(retargs);
diff --git a/openvpn/src/openvpn/ssl.c b/openvpn/src/openvpn/ssl.c
index 7cf3b2e4..f78cca88 100644
--- a/openvpn/src/openvpn/ssl.c
+++ b/openvpn/src/openvpn/ssl.c
@@ -7,10 +7,7 @@
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
- *
- * Additions for eurephia plugin done by:
- * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2008-2009
- *
+ * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.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
@@ -448,6 +445,27 @@ ssl_put_auth_challenge (const char *cr_str)
#endif
/*
+ * Parse a TLS version string, returning a TLS_VER_x constant.
+ * If version string is not recognized and extra == "or-highest",
+ * return tls_version_max().
+ */
+int
+tls_version_min_parse(const char *vstr, const char *extra)
+{
+ const int max_version = tls_version_max();
+ if (!strcmp(vstr, "1.0") && TLS_VER_1_0 <= max_version)
+ return TLS_VER_1_0;
+ else if (!strcmp(vstr, "1.1") && TLS_VER_1_1 <= max_version)
+ return TLS_VER_1_1;
+ else if (!strcmp(vstr, "1.2") && TLS_VER_1_2 <= max_version)
+ return TLS_VER_1_2;
+ else if (extra && !strcmp(extra, "or-highest"))
+ return max_version;
+ else
+ return TLS_VER_BAD;
+}
+
+/*
* Initialize SSL context.
* All files are in PEM format.
*/
diff --git a/openvpn/src/openvpn/ssl_backend.h b/openvpn/src/openvpn/ssl_backend.h
index 72235ae5..4d2958c7 100644
--- a/openvpn/src/openvpn/ssl_backend.h
+++ b/openvpn/src/openvpn/ssl_backend.h
@@ -36,10 +36,17 @@
#ifdef ENABLE_CRYPTO_OPENSSL
#include "ssl_openssl.h"
#include "ssl_verify_openssl.h"
+#define SSLAPI SSLAPI_OPENSSL
#endif
#ifdef ENABLE_CRYPTO_POLARSSL
#include "ssl_polarssl.h"
#include "ssl_verify_polarssl.h"
+#define SSLAPI SSLAPI_POLARSSL
+#endif
+
+/* Ensure that SSLAPI got a sane value if SSL is disabled or unknown */
+#ifndef SSLAPI
+#define SSLAPI SSLAPI_NONE
#endif
/**
@@ -94,6 +101,29 @@ void tls_free_lib();
void tls_clear_error();
/**
+ * Parse a TLS version specifier
+ *
+ * @param vstr The TLS version string
+ * @param extra An optional extra parameter, may be NULL
+ *
+ * @return One of the TLS_VER_x constants or TLS_VER_BAD
+ * if a parse error should be flagged.
+ */
+#define TLS_VER_BAD -1
+#define TLS_VER_1_0 0 /* default */
+#define TLS_VER_1_1 1
+#define TLS_VER_1_2 2
+int tls_version_min_parse(const char *vstr, const char *extra);
+
+/**
+ * Return the maximum TLS version (as a TLS_VER_x constant)
+ * supported by current SSL implementation
+ *
+ * @return One of the TLS_VER_x constants (but not TLS_VER_BAD).
+ */
+int tls_version_max(void);
+
+/**
* Initialise a library-specific TLS context for a server.
*
* @param ctx TLS context to initialise
diff --git a/openvpn/src/openvpn/ssl_common.h b/openvpn/src/openvpn/ssl_common.h
index 7e52f9a2..04ba7892 100644
--- a/openvpn/src/openvpn/ssl_common.h
+++ b/openvpn/src/openvpn/ssl_common.h
@@ -290,12 +290,14 @@ struct tls_options
struct compress_options comp_options;
#endif
- /* configuration file boolean options */
+ /* configuration file SSL-related boolean and low-permutation options */
# define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0)
# define SSLF_USERNAME_AS_COMMON_NAME (1<<1)
# define SSLF_AUTH_USER_PASS_OPTIONAL (1<<2)
# define SSLF_OPT_VERIFY (1<<4)
# define SSLF_CRL_VERIFY_DIR (1<<5)
+# define SSLF_TLS_VERSION_SHIFT 6
+# define SSLF_TLS_VERSION_MASK 0xF /* (uses bit positions 6 to 9) */
unsigned int ssl_flags;
#ifdef MANAGEMENT_DEF_AUTH
diff --git a/openvpn/src/openvpn/ssl_openssl.c b/openvpn/src/openvpn/ssl_openssl.c
index 5db717df..12c725d9 100644
--- a/openvpn/src/openvpn/ssl_openssl.c
+++ b/openvpn/src/openvpn/ssl_openssl.c
@@ -114,7 +114,7 @@ tls_ctx_server_new(struct tls_root_ctx *ctx)
{
ASSERT(NULL != ctx);
- ctx->ctx = SSL_CTX_new (TLSv1_server_method ());
+ ctx->ctx = SSL_CTX_new (SSLv23_server_method ());
if (ctx->ctx == NULL)
msg (M_SSLERR, "SSL_CTX_new TLSv1_server_method");
@@ -127,7 +127,7 @@ tls_ctx_client_new(struct tls_root_ctx *ctx)
{
ASSERT(NULL != ctx);
- ctx->ctx = SSL_CTX_new (TLSv1_client_method ());
+ ctx->ctx = SSL_CTX_new (SSLv23_client_method ());
if (ctx->ctx == NULL)
msg (M_SSLERR, "SSL_CTX_new TLSv1_client_method");
@@ -174,13 +174,46 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret)
}
}
+/*
+ * Return maximum TLS version supported by local OpenSSL library.
+ * Assume that presence of SSL_OP_NO_TLSvX macro indicates that
+ * TLSvX is supported.
+ */
+int
+tls_version_max(void)
+{
+#if defined(SSL_OP_NO_TLSv1_2)
+ return TLS_VER_1_2;
+#elif defined(SSL_OP_NO_TLSv1_1)
+ return TLS_VER_1_1;
+#else
+ return TLS_VER_1_0;
+#endif
+}
+
void
tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
{
ASSERT(NULL != ctx);
+ /* process SSL options including minimum TLS version we will accept from peer */
+ {
+ long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+ const int tls_version_min = (ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK;
+ if (tls_version_min > TLS_VER_1_0)
+ sslopt |= SSL_OP_NO_TLSv1;
+#ifdef SSL_OP_NO_TLSv1_1
+ if (tls_version_min > TLS_VER_1_1)
+ sslopt |= SSL_OP_NO_TLSv1_1;
+#endif
+#ifdef SSL_OP_NO_TLSv1_2
+ if (tls_version_min > TLS_VER_1_2)
+ sslopt |= SSL_OP_NO_TLSv1_2;
+#endif
+ SSL_CTX_set_options (ctx->ctx, sslopt);
+ }
+
SSL_CTX_set_session_cache_mode (ctx->ctx, SSL_SESS_CACHE_OFF);
- SSL_CTX_set_options (ctx->ctx, SSL_OP_SINGLE_DH_USE);
SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback);
/* Require peer certificate verification */
diff --git a/openvpn/src/openvpn/ssl_polarssl.c b/openvpn/src/openvpn/ssl_polarssl.c
index 8a917b34..fb732254 100644
--- a/openvpn/src/openvpn/ssl_polarssl.c
+++ b/openvpn/src/openvpn/ssl_polarssl.c
@@ -501,6 +501,18 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
}
}
+int
+tls_version_max(void)
+{
+#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3)
+ return TLS_VER_1_2;
+#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2)
+ return TLS_VER_1_1;
+#else
+ return TLS_VER_1_0;
+#endif
+}
+
void key_state_ssl_init(struct key_state_ssl *ks_ssl,
const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session)
{
@@ -550,6 +562,34 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
/* TODO: PolarSSL does not currently support sending the CA chain to the client */
ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL );
+ /* Initialize minimum TLS version */
+ {
+ const int tls_version_min = (session->opt->ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK;
+ int polar_major;
+ int polar_minor;
+ switch (tls_version_min)
+ {
+ case TLS_VER_1_0:
+ default:
+ polar_major = SSL_MAJOR_VERSION_3;
+ polar_minor = SSL_MINOR_VERSION_1;
+ break;
+#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2)
+ case TLS_VER_1_1:
+ polar_major = SSL_MAJOR_VERSION_3;
+ polar_minor = SSL_MINOR_VERSION_2;
+ break;
+#endif
+#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3)
+ case TLS_VER_1_2:
+ polar_major = SSL_MAJOR_VERSION_3;
+ polar_minor = SSL_MINOR_VERSION_3;
+ break;
+#endif
+ }
+ ssl_set_min_version(ks_ssl->ctx, polar_major, polar_minor);
+ }
+
/* Initialise BIOs */
ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer);
ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer);
diff --git a/openvpn/src/openvpn/ssl_verify.c b/openvpn/src/openvpn/ssl_verify.c
index b1bbc96f..4dd3aa2d 100644
--- a/openvpn/src/openvpn/ssl_verify.c
+++ b/openvpn/src/openvpn/ssl_verify.c
@@ -425,7 +425,6 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert
setenv_str (es, envname, common_name);
#endif
-#ifdef ENABLE_EUREPHIA
/* export X509 cert SHA1 fingerprint */
{
unsigned char *sha1_hash = x509_get_sha1_hash(peer_cert, &gc);
@@ -434,7 +433,6 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert
setenv_str (es, envname, format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1,
":", &gc));
}
-#endif
/* export serial number as environmental variable */
serial = x509_get_serial(peer_cert, &gc);
diff --git a/openvpn/src/openvpn/tun.c b/openvpn/src/openvpn/tun.c
index 98cb16f3..bd62b392 100644
--- a/openvpn/src/openvpn/tun.c
+++ b/openvpn/src/openvpn/tun.c
@@ -74,6 +74,12 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co
#include <stropts.h>
#endif
+#if defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+#endif
+
static void clear_tuntap (struct tuntap *tuntap);
bool
@@ -1284,6 +1290,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -2062,23 +2149,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2145,59 +2215,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2557,10 +2584,177 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+
+/* Helper functions that tries to open utun device
+ return -2 on early initialization failures (utun not supported
+ at all (old OS X) and -1 on initlization failure of utun
+ device (utun works but utunX is already used */
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -2;
+ }
+
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -2;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ set_nonblock (fd);
+ set_cloexec (fd); /* don't pass fd to scripts */
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+ socklen_t utunname_len = sizeof(utunname);
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'"
+ "to use a utun device number X", dev_node);
+ }
+
+
+
+ CLEAR (ctlInfo);
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long");
+ }
+
+ /* try to open first available utun device if no specific utun is requested */
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ /* Break if the fd is valid,
+ * or if early initalization failed (-2) */
+ if (fd !=-1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ /* opening an utun device failed */
+ tt->fd = fd;
+
+ if (fd < 0)
+ return;
+
+ /* Retrieve the assigned interface name. */
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len))
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
+
+ tt->actual_name = string_alloc (utunname, NULL);
+
+ msg (M_INFO, "Opened utun device %s", utunname);
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+#ifdef HAVE_NET_IF_UTUN_H
+ /* If dev_node does not start start with utun assume regular tun/tap */
+ if ((!dev_node && tt->type==DEV_TYPE_TUN) ||
+ (dev_node && !strncmp (dev_node, "utun", 4)))
+ {
+
+ /* Check if user has specific dev_type tap and forced utun with
+ dev-node utun */
+ if (tt->type!=DEV_TYPE_TUN)
+ msg (M_FATAL, "Cannot use utun devices with --dev-type %s",
+ dev_type_string (dev, dev_type));
+
+ /* Try utun first and fall back to normal tun if utun fails
+ and dev_node is not specified */
+ open_darwin_utun(dev, dev_type, dev_node, tt);
+
+ if (!tt->is_utun)
+ {
+ if (!dev_node)
+ {
+ /* No explicit utun and utun failed, try the generic way) */
+ msg (M_INFO, "Failed to open utun device. Falling back to /dev/tun device");
+ open_tun_generic (dev, dev_type, NULL, true, true, tt);
+ }
+ else
+ {
+ /* Specific utun device or generic utun request with no tun
+ fall back failed, consider this a fatal failure */
+ msg (M_FATAL, "Cannot open utun device");
+ }
+ }
+ }
+ else
+#endif
+ {
+
+ /* Use plain dev-node tun to select /dev/tun style
+ * Unset dev_node variable prior to passing to open_tun_generic to
+ * let open_tun_generic pick the first available tun device */
+
+ if (dev_node && strcmp (dev_node, "tun")==0)
+ dev_node=NULL;
+
+ open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+ }
}
void
@@ -2593,13 +2787,23 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, len);
+#ifdef HAVE_NET_IF_UTUN_H
+ if (tt->is_utun)
+ return write_tun_header (tt, buf, len);
+ else
+#endif
+ return write (tt->fd, buf, len);
}
int
read_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return read (tt->fd, buf, len);
+#ifdef HAVE_NET_IF_UTUN_H
+ if (tt->is_utun)
+ return read_tun_header (tt, buf, len);
+ else
+#endif
+ return read (tt->fd, buf, len);
}
#elif defined(WIN32)
diff --git a/openvpn/src/openvpn/tun.h b/openvpn/src/openvpn/tun.h
index 2bbb8133..631b53c6 100644
--- a/openvpn/src/openvpn/tun.h
+++ b/openvpn/src/openvpn/tun.h
@@ -181,6 +181,9 @@ struct tuntap
int ip_fd;
#endif
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;