summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlberto Gonzalez Iniesta <agi@inittab.org>2016-11-21 09:37:33 +0100
committerAlberto Gonzalez Iniesta <agi@inittab.org>2016-11-21 09:37:33 +0100
commit20c8675ba46bda97330a4117c459a59a9f1c465e (patch)
treed888c714fb61947dd79dc44b64a4aaae2f70bfb7 /src
parentffca24bed7a03d95585ad02278667abe75d8b272 (diff)
New upstream version 2.4~beta1upstream/2.4_beta1
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in49
-rw-r--r--src/compat/Makefile.am1
-rw-r--r--src/compat/Makefile.in60
-rw-r--r--src/compat/compat-gettimeofday.c4
-rw-r--r--src/compat/compat-inet_ntop.c2
-rw-r--r--src/compat/compat-inet_pton.c2
-rw-r--r--src/compat/compat-lz4.c1524
-rw-r--r--src/compat/compat-lz4.h360
-rw-r--r--src/compat/compat.vcxproj3
-rw-r--r--src/compat/compat.vcxproj.filters3
-rw-r--r--src/openvpn/Makefile.am24
-rw-r--r--src/openvpn/Makefile.in214
-rw-r--r--src/openvpn/argv.c315
-rw-r--r--src/openvpn/argv.h70
-rw-r--r--src/openvpn/base64.c6
-rw-r--r--src/openvpn/base64.h4
-rw-r--r--src/openvpn/block_dns.c332
-rw-r--r--src/openvpn/block_dns.h40
-rw-r--r--src/openvpn/buffer.c69
-rw-r--r--src/openvpn/buffer.h38
-rw-r--r--src/openvpn/clinat.c4
-rw-r--r--src/openvpn/clinat.h2
-rw-r--r--src/openvpn/common.h2
-rw-r--r--src/openvpn/comp-lz4.c307
-rw-r--r--src/openvpn/comp-lz4.h42
-rw-r--r--src/openvpn/comp.c167
-rw-r--r--src/openvpn/comp.h198
-rw-r--r--src/openvpn/compstub.c169
-rw-r--r--src/openvpn/console.c228
-rw-r--r--src/openvpn/console.h89
-rw-r--r--src/openvpn/console_builtin.c261
-rw-r--r--src/openvpn/console_systemd.c122
-rw-r--r--src/openvpn/crypto.c821
-rw-r--r--src/openvpn/crypto.h162
-rw-r--r--src/openvpn/crypto_backend.h112
-rw-r--r--src/openvpn/crypto_mbedtls.c785
-rw-r--r--src/openvpn/crypto_mbedtls.h (renamed from src/openvpn/crypto_polarssl.h)77
-rw-r--r--src/openvpn/crypto_openssl.c282
-rw-r--r--src/openvpn/crypto_openssl.h7
-rw-r--r--src/openvpn/crypto_polarssl.c712
-rw-r--r--src/openvpn/cryptoapi.c2
-rw-r--r--src/openvpn/errlevel.h4
-rw-r--r--src/openvpn/error.c44
-rw-r--r--src/openvpn/error.h33
-rw-r--r--src/openvpn/event.c8
-rw-r--r--src/openvpn/event.h4
-rw-r--r--src/openvpn/fdmisc.c4
-rw-r--r--src/openvpn/fdmisc.h2
-rw-r--r--src/openvpn/forward-inline.h6
-rw-r--r--src/openvpn/forward.c304
-rw-r--r--src/openvpn/forward.h32
-rw-r--r--src/openvpn/helper.c2
-rw-r--r--src/openvpn/init.c1125
-rw-r--r--src/openvpn/init.h4
-rw-r--r--src/openvpn/interval.h9
-rw-r--r--src/openvpn/lzo.c151
-rw-r--r--src/openvpn/lzo.h222
-rw-r--r--src/openvpn/manage.c449
-rw-r--r--src/openvpn/manage.h39
-rw-r--r--src/openvpn/misc.c728
-rw-r--r--src/openvpn/misc.h73
-rw-r--r--src/openvpn/mroute.c143
-rw-r--r--src/openvpn/mroute.h57
-rw-r--r--src/openvpn/mtcp.c34
-rw-r--r--src/openvpn/mtu.c44
-rw-r--r--src/openvpn/mtu.h8
-rw-r--r--src/openvpn/mudp.c104
-rw-r--r--src/openvpn/mudp.h2
-rw-r--r--src/openvpn/multi.c410
-rw-r--r--src/openvpn/multi.h65
-rw-r--r--src/openvpn/occ.c2
-rw-r--r--src/openvpn/openvpn.c8
-rw-r--r--src/openvpn/openvpn.h71
-rw-r--r--src/openvpn/openvpn.vcxproj12
-rw-r--r--src/openvpn/openvpn.vcxproj.filters18
-rw-r--r--src/openvpn/options.c2026
-rw-r--r--src/openvpn/options.h130
-rw-r--r--src/openvpn/otime.h8
-rw-r--r--src/openvpn/packet_id.c7
-rw-r--r--src/openvpn/packet_id.h8
-rw-r--r--src/openvpn/pf.c2
-rw-r--r--src/openvpn/pkcs11.c7
-rw-r--r--src/openvpn/pkcs11_mbedtls.c (renamed from src/openvpn/pkcs11_polarssl.c)53
-rw-r--r--src/openvpn/platform.c20
-rw-r--r--src/openvpn/platform.h2
-rw-r--r--src/openvpn/plugin.c37
-rw-r--r--src/openvpn/plugin.h12
-rw-r--r--src/openvpn/proto.h39
-rw-r--r--src/openvpn/proxy.c131
-rw-r--r--src/openvpn/proxy.h21
-rw-r--r--src/openvpn/ps.c59
-rw-r--r--src/openvpn/ps.h2
-rw-r--r--src/openvpn/push.c444
-rw-r--r--src/openvpn/push.h8
-rw-r--r--src/openvpn/reliable.c4
-rw-r--r--src/openvpn/reliable.h4
-rw-r--r--src/openvpn/route.c1517
-rw-r--r--src/openvpn/route.h115
-rw-r--r--src/openvpn/session_id.c4
-rw-r--r--src/openvpn/session_id.h4
-rw-r--r--src/openvpn/shaper.h2
-rw-r--r--src/openvpn/sig.c67
-rw-r--r--src/openvpn/sig.h13
-rw-r--r--src/openvpn/socket.c1938
-rw-r--r--src/openvpn/socket.h297
-rw-r--r--src/openvpn/socks.c48
-rw-r--r--src/openvpn/socks.h13
-rw-r--r--src/openvpn/ssl.c1132
-rw-r--r--src/openvpn/ssl.h102
-rw-r--r--src/openvpn/ssl_backend.h67
-rw-r--r--src/openvpn/ssl_common.h84
-rw-r--r--src/openvpn/ssl_mbedtls.c (renamed from src/openvpn/ssl_polarssl.c)582
-rw-r--r--src/openvpn/ssl_mbedtls.h (renamed from src/openvpn/ssl_polarssl.h)36
-rw-r--r--src/openvpn/ssl_openssl.c301
-rw-r--r--src/openvpn/ssl_openssl.h7
-rw-r--r--src/openvpn/ssl_verify.c209
-rw-r--r--src/openvpn/ssl_verify.h47
-rw-r--r--src/openvpn/ssl_verify_backend.h51
-rw-r--r--src/openvpn/ssl_verify_mbedtls.c511
-rw-r--r--src/openvpn/ssl_verify_mbedtls.h (renamed from src/openvpn/ssl_verify_polarssl.h)22
-rw-r--r--src/openvpn/ssl_verify_openssl.c263
-rw-r--r--src/openvpn/ssl_verify_polarssl.c397
-rw-r--r--src/openvpn/syshead.h105
-rw-r--r--src/openvpn/tls_crypt.c254
-rw-r--r--src/openvpn/tls_crypt.h144
-rw-r--r--src/openvpn/tun.c830
-rw-r--r--src/openvpn/tun.h43
-rw-r--r--src/openvpn/win32.c285
-rw-r--r--src/openvpn/win32.h7
-rw-r--r--src/openvpn/win32_wfp.h359
-rw-r--r--src/openvpnserv/Makefile.am16
-rw-r--r--src/openvpnserv/Makefile.in181
-rw-r--r--src/openvpnserv/automatic.c415
-rw-r--r--src/openvpnserv/common.c218
-rw-r--r--src/openvpnserv/interactive.c1652
-rwxr-xr-xsrc/openvpnserv/openvpnserv.c534
-rw-r--r--src/openvpnserv/openvpnserv.vcxproj2
-rw-r--r--src/openvpnserv/service.c861
-rw-r--r--src/openvpnserv/service.h215
-rw-r--r--src/openvpnserv/validate.c249
-rw-r--r--src/openvpnserv/validate.h48
-rw-r--r--src/plugins/Makefile.in49
-rw-r--r--src/plugins/auth-pam/Makefile.am1
-rw-r--r--src/plugins/auth-pam/Makefile.in61
-rw-r--r--src/plugins/auth-pam/auth-pam.c91
-rw-r--r--src/plugins/auth-pam/utils.c113
-rw-r--r--src/plugins/auth-pam/utils.h66
-rw-r--r--src/plugins/down-root/Makefile.in57
148 files changed, 19466 insertions, 10135 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index a90f015..8aeb7f5 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -25,17 +25,7 @@
# Copyright (C) 2006-2012 Alon Bar-Lev <alon.barlev@gmail.com>
#
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -99,6 +89,7 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = src
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/m4/ax_socklen_t.m4 \
@@ -109,9 +100,9 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/compat.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_HEADER = $(top_builddir)/config.h \
+ $(top_builddir)/include/openvpn-plugin.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
@@ -169,7 +160,6 @@ am__define_uniq_tagged_files = \
ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
dir0=`pwd`; \
@@ -208,6 +198,7 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CMAKE = @CMAKE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
@@ -242,25 +233,31 @@ LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LZ4_CFLAGS = @LZ4_CFLAGS@
+LZ4_LIBS = @LZ4_LIBS@
LZO_CFLAGS = @LZO_CFLAGS@
LZO_LIBS = @LZO_LIBS@
MAKEINFO = @MAKEINFO@
MAN2HTML = @MAN2HTML@
MANIFEST_TOOL = @MANIFEST_TOOL@
+MBEDTLS_CFLAGS = @MBEDTLS_CFLAGS@
+MBEDTLS_LIBS = @MBEDTLS_LIBS@
MKDIR_P = @MKDIR_P@
NETSTAT = @NETSTAT@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
-OPENSSL_CRYPTO_CFLAGS = @OPENSSL_CRYPTO_CFLAGS@
-OPENSSL_CRYPTO_LIBS = @OPENSSL_CRYPTO_LIBS@
-OPENSSL_SSL_CFLAGS = @OPENSSL_SSL_CFLAGS@
-OPENSSL_SSL_LIBS = @OPENSSL_SSL_LIBS@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENVPN_VERSION_MAJOR = @OPENVPN_VERSION_MAJOR@
+OPENVPN_VERSION_MINOR = @OPENVPN_VERSION_MINOR@
+OPENVPN_VERSION_PATCH = @OPENVPN_VERSION_PATCH@
OPTIONAL_CRYPTO_CFLAGS = @OPTIONAL_CRYPTO_CFLAGS@
OPTIONAL_CRYPTO_LIBS = @OPTIONAL_CRYPTO_LIBS@
OPTIONAL_DL_LIBS = @OPTIONAL_DL_LIBS@
+OPTIONAL_LZ4_CFLAGS = @OPTIONAL_LZ4_CFLAGS@
+OPTIONAL_LZ4_LIBS = @OPTIONAL_LZ4_LIBS@
OPTIONAL_LZO_CFLAGS = @OPTIONAL_LZO_CFLAGS@
OPTIONAL_LZO_LIBS = @OPTIONAL_LZO_LIBS@
OPTIONAL_PKCS11_HELPER_CFLAGS = @OPTIONAL_PKCS11_HELPER_CFLAGS@
@@ -286,8 +283,6 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PLUGIN_AUTH_PAM_CFLAGS = @PLUGIN_AUTH_PAM_CFLAGS@
PLUGIN_AUTH_PAM_LIBS = @PLUGIN_AUTH_PAM_LIBS@
-POLARSSL_CFLAGS = @POLARSSL_CFLAGS@
-POLARSSL_LIBS = @POLARSSL_LIBS@
RANLIB = @RANLIB@
RC = @RC@
ROUTE = @ROUTE@
@@ -302,6 +297,11 @@ TAP_CFLAGS = @TAP_CFLAGS@
TAP_WIN_COMPONENT_ID = @TAP_WIN_COMPONENT_ID@
TAP_WIN_MIN_MAJOR = @TAP_WIN_MIN_MAJOR@
TAP_WIN_MIN_MINOR = @TAP_WIN_MIN_MINOR@
+TEST_CFLAGS = @TEST_CFLAGS@
+TEST_LDFLAGS = @TEST_LDFLAGS@
+VENDOR_BUILD_ROOT = @VENDOR_BUILD_ROOT@
+VENDOR_DIST_ROOT = @VENDOR_DIST_ROOT@
+VENDOR_SRC_ROOT = @VENDOR_SRC_ROOT@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -378,6 +378,7 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -673,8 +674,6 @@ uninstall-am:
mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
ps ps-am tags tags-am uninstall uninstall-am
-.PRECIOUS: Makefile
-
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am
index 273389e..06bab5c 100644
--- a/src/compat/Makefile.am
+++ b/src/compat/Makefile.am
@@ -27,4 +27,5 @@ libcompat_la_SOURCES = \
compat-daemon.c \
compat-inet_ntop.c \
compat-inet_pton.c \
+ compat-lz4.c compat-lz4.h \
compat-versionhelpers.h
diff --git a/src/compat/Makefile.in b/src/compat/Makefile.in
index 52970a7..c7236ed 100644
--- a/src/compat/Makefile.in
+++ b/src/compat/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -26,17 +26,7 @@
#
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -100,6 +90,8 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = src/compat
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/m4/ax_socklen_t.m4 \
@@ -110,16 +102,16 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/compat.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_HEADER = $(top_builddir)/config.h \
+ $(top_builddir)/include/openvpn-plugin.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libcompat_la_LIBADD =
am_libcompat_la_OBJECTS = compat-dirname.lo compat-basename.lo \
compat-gettimeofday.lo compat-daemon.lo compat-inet_ntop.lo \
- compat-inet_pton.lo
+ compat-inet_pton.lo compat-lz4.lo
libcompat_la_OBJECTS = $(am_libcompat_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -137,7 +129,7 @@ AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
-DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/include
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
@@ -185,7 +177,6 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@@ -199,6 +190,7 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CMAKE = @CMAKE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
@@ -233,25 +225,31 @@ LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LZ4_CFLAGS = @LZ4_CFLAGS@
+LZ4_LIBS = @LZ4_LIBS@
LZO_CFLAGS = @LZO_CFLAGS@
LZO_LIBS = @LZO_LIBS@
MAKEINFO = @MAKEINFO@
MAN2HTML = @MAN2HTML@
MANIFEST_TOOL = @MANIFEST_TOOL@
+MBEDTLS_CFLAGS = @MBEDTLS_CFLAGS@
+MBEDTLS_LIBS = @MBEDTLS_LIBS@
MKDIR_P = @MKDIR_P@
NETSTAT = @NETSTAT@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
-OPENSSL_CRYPTO_CFLAGS = @OPENSSL_CRYPTO_CFLAGS@
-OPENSSL_CRYPTO_LIBS = @OPENSSL_CRYPTO_LIBS@
-OPENSSL_SSL_CFLAGS = @OPENSSL_SSL_CFLAGS@
-OPENSSL_SSL_LIBS = @OPENSSL_SSL_LIBS@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENVPN_VERSION_MAJOR = @OPENVPN_VERSION_MAJOR@
+OPENVPN_VERSION_MINOR = @OPENVPN_VERSION_MINOR@
+OPENVPN_VERSION_PATCH = @OPENVPN_VERSION_PATCH@
OPTIONAL_CRYPTO_CFLAGS = @OPTIONAL_CRYPTO_CFLAGS@
OPTIONAL_CRYPTO_LIBS = @OPTIONAL_CRYPTO_LIBS@
OPTIONAL_DL_LIBS = @OPTIONAL_DL_LIBS@
+OPTIONAL_LZ4_CFLAGS = @OPTIONAL_LZ4_CFLAGS@
+OPTIONAL_LZ4_LIBS = @OPTIONAL_LZ4_LIBS@
OPTIONAL_LZO_CFLAGS = @OPTIONAL_LZO_CFLAGS@
OPTIONAL_LZO_LIBS = @OPTIONAL_LZO_LIBS@
OPTIONAL_PKCS11_HELPER_CFLAGS = @OPTIONAL_PKCS11_HELPER_CFLAGS@
@@ -277,8 +275,6 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PLUGIN_AUTH_PAM_CFLAGS = @PLUGIN_AUTH_PAM_CFLAGS@
PLUGIN_AUTH_PAM_LIBS = @PLUGIN_AUTH_PAM_LIBS@
-POLARSSL_CFLAGS = @POLARSSL_CFLAGS@
-POLARSSL_LIBS = @POLARSSL_LIBS@
RANLIB = @RANLIB@
RC = @RC@
ROUTE = @ROUTE@
@@ -293,6 +289,11 @@ TAP_CFLAGS = @TAP_CFLAGS@
TAP_WIN_COMPONENT_ID = @TAP_WIN_COMPONENT_ID@
TAP_WIN_MIN_MAJOR = @TAP_WIN_MIN_MAJOR@
TAP_WIN_MIN_MINOR = @TAP_WIN_MIN_MINOR@
+TEST_CFLAGS = @TEST_CFLAGS@
+TEST_LDFLAGS = @TEST_LDFLAGS@
+VENDOR_BUILD_ROOT = @VENDOR_BUILD_ROOT@
+VENDOR_DIST_ROOT = @VENDOR_DIST_ROOT@
+VENDOR_SRC_ROOT = @VENDOR_SRC_ROOT@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -367,6 +368,7 @@ libcompat_la_SOURCES = \
compat-daemon.c \
compat-inet_ntop.c \
compat-inet_pton.c \
+ compat-lz4.c compat-lz4.h \
compat-versionhelpers.h
all: all-am
@@ -385,6 +387,7 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/compat/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/compat/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -429,20 +432,21 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compat-gettimeofday.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compat-inet_ntop.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compat-inet_pton.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compat-lz4.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -661,8 +665,6 @@ uninstall-am:
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am
-.PRECIOUS: Makefile
-
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/compat/compat-gettimeofday.c b/src/compat/compat-gettimeofday.c
index 0f32d5d..19feaae 100644
--- a/src/compat/compat-gettimeofday.c
+++ b/src/compat/compat-gettimeofday.c
@@ -32,7 +32,7 @@
#include "compat.h"
-#ifdef WIN32
+#ifdef _WIN32
/*
* NOTICE: mingw has much faster gettimeofday!
* autoconf will set HAVE_GETTIMEOFDAY
@@ -126,6 +126,6 @@ gettimeofday (struct timeval *tv, void *tz)
return 0;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
#endif /* HAVE_GETTIMEOFDAY */
diff --git a/src/compat/compat-inet_ntop.c b/src/compat/compat-inet_ntop.c
index 0d52142..786c973 100644
--- a/src/compat/compat-inet_ntop.c
+++ b/src/compat/compat-inet_ntop.c
@@ -32,7 +32,7 @@
#include "compat.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <windows.h>
diff --git a/src/compat/compat-inet_pton.c b/src/compat/compat-inet_pton.c
index cdc8d4b..5965f0d 100644
--- a/src/compat/compat-inet_pton.c
+++ b/src/compat/compat-inet_pton.c
@@ -32,7 +32,7 @@
#include "compat.h"
-#ifdef WIN32
+#ifdef _WIN32
#include <windows.h>
#include <string.h>
diff --git a/src/compat/compat-lz4.c b/src/compat/compat-lz4.c
new file mode 100644
index 0000000..5855ca1
--- /dev/null
+++ b/src/compat/compat-lz4.c
@@ -0,0 +1,1524 @@
+/*
+ LZ4 - Fast LZ compression algorithm
+ Copyright (C) 2011-2015, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - LZ4 source repository : https://github.com/Cyan4973/lz4
+ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#ifdef NEED_COMPAT_LZ4
+
+/**************************************
+* Tuning parameters
+**************************************/
+/*
+ * HEAPMODE :
+ * Select how default compression functions will allocate memory for their hash table,
+ * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).
+ */
+#define HEAPMODE 0
+
+/*
+ * ACCELERATION_DEFAULT :
+ * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0
+ */
+#define ACCELERATION_DEFAULT 1
+
+
+/**************************************
+* CPU Feature Detection
+**************************************/
+/*
+ * LZ4_FORCE_SW_BITCOUNT
+ * Define this parameter if your target system or compiler does not support hardware bit count
+ */
+#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */
+# define LZ4_FORCE_SW_BITCOUNT
+#endif
+
+
+/**************************************
+* Includes
+**************************************/
+#include "compat-lz4.h"
+
+
+/**************************************
+* Compiler Options
+**************************************/
+#ifdef _MSC_VER /* Visual Studio */
+# define FORCE_INLINE static __forceinline
+# include <intrin.h>
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+# pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */
+#else
+# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
+# if defined(__GNUC__) || defined(__clang__)
+# define FORCE_INLINE static inline __attribute__((always_inline))
+# else
+# define FORCE_INLINE static inline
+# endif
+# else
+# define FORCE_INLINE static
+# endif /* __STDC_VERSION__ */
+#endif /* _MSC_VER */
+
+/* LZ4_GCC_VERSION is defined into lz4.h */
+#if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
+# define expect(expr,value) (__builtin_expect ((expr),(value)) )
+#else
+# define expect(expr,value) (expr)
+#endif
+
+#define likely(expr) expect((expr) != 0, 1)
+#define unlikely(expr) expect((expr) != 0, 0)
+
+
+/**************************************
+* Memory routines
+**************************************/
+#include <stdlib.h> /* malloc, calloc, free */
+#define ALLOCATOR(n,s) calloc(n,s)
+#define FREEMEM free
+#include <string.h> /* memset, memcpy */
+#define MEM_INIT memset
+
+
+/**************************************
+* Basic Types
+**************************************/
+#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
+# include <stdint.h>
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+#else
+ typedef unsigned char BYTE;
+ typedef unsigned short U16;
+ typedef unsigned int U32;
+ typedef signed int S32;
+ typedef unsigned long long U64;
+#endif
+
+
+/**************************************
+* Reading and writing into memory
+**************************************/
+#define STEPSIZE sizeof(size_t)
+
+static unsigned LZ4_64bits(void) { return sizeof(void*)==8; }
+
+static unsigned LZ4_isLittleEndian(void)
+{
+ const union { U32 i; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */
+ return one.c[0];
+}
+
+
+static U16 LZ4_read16(const void* memPtr)
+{
+ U16 val16;
+ memcpy(&val16, memPtr, 2);
+ return val16;
+}
+
+static U16 LZ4_readLE16(const void* memPtr)
+{
+ if (LZ4_isLittleEndian())
+ {
+ return LZ4_read16(memPtr);
+ }
+ else
+ {
+ const BYTE* p = (const BYTE*)memPtr;
+ return (U16)((U16)p[0] + (p[1]<<8));
+ }
+}
+
+static void LZ4_writeLE16(void* memPtr, U16 value)
+{
+ if (LZ4_isLittleEndian())
+ {
+ memcpy(memPtr, &value, 2);
+ }
+ else
+ {
+ BYTE* p = (BYTE*)memPtr;
+ p[0] = (BYTE) value;
+ p[1] = (BYTE)(value>>8);
+ }
+}
+
+static U32 LZ4_read32(const void* memPtr)
+{
+ U32 val32;
+ memcpy(&val32, memPtr, 4);
+ return val32;
+}
+
+static U64 LZ4_read64(const void* memPtr)
+{
+ U64 val64;
+ memcpy(&val64, memPtr, 8);
+ return val64;
+}
+
+static size_t LZ4_read_ARCH(const void* p)
+{
+ if (LZ4_64bits())
+ return (size_t)LZ4_read64(p);
+ else
+ return (size_t)LZ4_read32(p);
+}
+
+
+static void LZ4_copy4(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 4); }
+
+static void LZ4_copy8(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 8); }
+
+/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */
+static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
+{
+ BYTE* d = (BYTE*)dstPtr;
+ const BYTE* s = (const BYTE*)srcPtr;
+ BYTE* e = (BYTE*)dstEnd;
+ do { LZ4_copy8(d,s); d+=8; s+=8; } while (d<e);
+}
+
+
+/**************************************
+* Common Constants
+**************************************/
+#define MINMATCH 4
+
+#define COPYLENGTH 8
+#define LASTLITERALS 5
+#define MFLIMIT (COPYLENGTH+MINMATCH)
+static const int LZ4_minLength = (MFLIMIT+1);
+
+#define KB *(1 <<10)
+#define MB *(1 <<20)
+#define GB *(1U<<30)
+
+#define MAXD_LOG 16
+#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
+
+#define ML_BITS 4
+#define ML_MASK ((1U<<ML_BITS)-1)
+#define RUN_BITS (8-ML_BITS)
+#define RUN_MASK ((1U<<RUN_BITS)-1)
+
+
+/**************************************
+* Common Utils
+**************************************/
+#define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
+
+
+/**************************************
+* Common functions
+**************************************/
+static unsigned LZ4_NbCommonBytes (register size_t val)
+{
+ if (LZ4_isLittleEndian())
+ {
+ if (LZ4_64bits())
+ {
+# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanForward64( &r, (U64)val );
+ return (int)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_ctzll((U64)val) >> 3);
+# else
+ static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
+ return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+# endif
+ }
+ else /* 32 bits */
+ {
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r;
+ _BitScanForward( &r, (U32)val );
+ return (int)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_ctz((U32)val) >> 3);
+# else
+ static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
+ return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+# endif
+ }
+ }
+ else /* Big Endian CPU */
+ {
+ if (LZ4_64bits())
+ {
+# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanReverse64( &r, val );
+ return (unsigned)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_clzll((U64)val) >> 3);
+# else
+ unsigned r;
+ if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
+ if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ }
+ else /* 32 bits */
+ {
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanReverse( &r, (unsigned long)val );
+ return (unsigned)(r>>3);
+# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_clz((U32)val) >> 3);
+# else
+ unsigned r;
+ if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+ r += (!val);
+ return r;
+# endif
+ }
+ }
+}
+
+static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
+{
+ const BYTE* const pStart = pIn;
+
+ while (likely(pIn<pInLimit-(STEPSIZE-1)))
+ {
+ size_t diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
+ if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }
+ pIn += LZ4_NbCommonBytes(diff);
+ return (unsigned)(pIn - pStart);
+ }
+
+ if (LZ4_64bits()) if ((pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }
+ if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }
+ if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
+ return (unsigned)(pIn - pStart);
+}
+
+
+#ifndef LZ4_COMMONDEFS_ONLY
+/**************************************
+* Local Constants
+**************************************/
+#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2)
+#define HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
+#define HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
+
+static const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1));
+static const U32 LZ4_skipTrigger = 6; /* Increase this value ==> compression run slower on incompressible data */
+
+
+/**************************************
+* Local Structures and types
+**************************************/
+typedef struct {
+ U32 hashTable[HASH_SIZE_U32];
+ U32 currentOffset;
+ U32 initCheck;
+ const BYTE* dictionary;
+ BYTE* bufferStart; /* obsolete, used for slideInputBuffer */
+ U32 dictSize;
+} LZ4_stream_t_internal;
+
+typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive;
+typedef enum { byPtr, byU32, byU16 } tableType_t;
+
+typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
+typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;
+
+typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
+typedef enum { full = 0, partial = 1 } earlyEnd_directive;
+
+
+/**************************************
+* Local Utils
+**************************************/
+int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }
+int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); }
+int LZ4_sizeofState() { return LZ4_STREAMSIZE; }
+
+
+
+/********************************
+* Compression functions
+********************************/
+
+static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType)
+{
+ if (tableType == byU16)
+ return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
+ else
+ return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
+}
+
+static const U64 prime5bytes = 889523592379ULL;
+static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType)
+{
+ const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;
+ const U32 hashMask = (1<<hashLog) - 1;
+ return ((sequence * prime5bytes) >> (40 - hashLog)) & hashMask;
+}
+
+static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType)
+{
+ if (LZ4_64bits())
+ return LZ4_hashSequence64(sequence, tableType);
+ return LZ4_hashSequence((U32)sequence, tableType);
+}
+
+static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); }
+
+static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase)
+{
+ switch (tableType)
+ {
+ case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; }
+ case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; }
+ case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; }
+ }
+}
+
+static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ U32 h = LZ4_hashPosition(p, tableType);
+ LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
+}
+
+static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
+ if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
+ { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */
+}
+
+static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ U32 h = LZ4_hashPosition(p, tableType);
+ return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
+}
+
+FORCE_INLINE int LZ4_compress_generic(
+ void* const ctx,
+ const char* const source,
+ char* const dest,
+ const int inputSize,
+ const int maxOutputSize,
+ const limitedOutput_directive outputLimited,
+ const tableType_t tableType,
+ const dict_directive dict,
+ const dictIssue_directive dictIssue,
+ const U32 acceleration)
+{
+ LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx;
+
+ const BYTE* ip = (const BYTE*) source;
+ const BYTE* base;
+ const BYTE* lowLimit;
+ const BYTE* const lowRefLimit = ip - dictPtr->dictSize;
+ const BYTE* const dictionary = dictPtr->dictionary;
+ const BYTE* const dictEnd = dictionary + dictPtr->dictSize;
+ const size_t dictDelta = dictEnd - (const BYTE*)source;
+ const BYTE* anchor = (const BYTE*) source;
+ const BYTE* const iend = ip + inputSize;
+ const BYTE* const mflimit = iend - MFLIMIT;
+ const BYTE* const matchlimit = iend - LASTLITERALS;
+
+ BYTE* op = (BYTE*) dest;
+ BYTE* const olimit = op + maxOutputSize;
+
+ U32 forwardH;
+ size_t refDelta=0;
+
+ /* Init conditions */
+ if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
+ switch(dict)
+ {
+ case noDict:
+ default:
+ base = (const BYTE*)source;
+ lowLimit = (const BYTE*)source;
+ break;
+ case withPrefix64k:
+ base = (const BYTE*)source - dictPtr->currentOffset;
+ lowLimit = (const BYTE*)source - dictPtr->dictSize;
+ break;
+ case usingExtDict:
+ base = (const BYTE*)source - dictPtr->currentOffset;
+ lowLimit = (const BYTE*)source;
+ break;
+ }
+ if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
+ if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
+
+ /* First Byte */
+ LZ4_putPosition(ip, ctx, tableType, base);
+ ip++; forwardH = LZ4_hashPosition(ip, tableType);
+
+ /* Main Loop */
+ for ( ; ; )
+ {
+ const BYTE* match;
+ BYTE* token;
+ {
+ const BYTE* forwardIp = ip;
+ unsigned step = 1;
+ unsigned searchMatchNb = acceleration << LZ4_skipTrigger;
+
+ /* Find a match */
+ do {
+ U32 h = forwardH;
+ ip = forwardIp;
+ forwardIp += step;
+ step = (searchMatchNb++ >> LZ4_skipTrigger);
+
+ if (unlikely(forwardIp > mflimit)) goto _last_literals;
+
+ match = LZ4_getPositionOnHash(h, ctx, tableType, base);
+ if (dict==usingExtDict)
+ {
+ if (match<(const BYTE*)source)
+ {
+ refDelta = dictDelta;
+ lowLimit = dictionary;
+ }
+ else
+ {
+ refDelta = 0;
+ lowLimit = (const BYTE*)source;
+ }
+ }
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
+ LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+ } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0)
+ || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
+ || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) );
+ }
+
+ /* Catch up */
+ while ((ip>anchor) && (match+refDelta > lowLimit) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; }
+
+ {
+ /* Encode Literal length */
+ unsigned litLength = (unsigned)(ip - anchor);
+ token = op++;
+ if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
+ return 0; /* Check output limit */
+ if (litLength>=RUN_MASK)
+ {
+ int len = (int)litLength-RUN_MASK;
+ *token=(RUN_MASK<<ML_BITS);
+ for(; len >= 255 ; len-=255) *op++ = 255;
+ *op++ = (BYTE)len;
+ }
+ else *token = (BYTE)(litLength<<ML_BITS);
+
+ /* Copy Literals */
+ LZ4_wildCopy(op, anchor, op+litLength);
+ op+=litLength;
+ }
+
+_next_match:
+ /* Encode Offset */
+ LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
+
+ /* Encode MatchLength */
+ {
+ unsigned matchLength;
+
+ if ((dict==usingExtDict) && (lowLimit==dictionary))
+ {
+ const BYTE* limit;
+ match += refDelta;
+ limit = ip + (dictEnd-match);
+ if (limit > matchlimit) limit = matchlimit;
+ matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
+ ip += MINMATCH + matchLength;
+ if (ip==limit)
+ {
+ unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit);
+ matchLength += more;
+ ip += more;
+ }
+ }
+ else
+ {
+ matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
+ ip += MINMATCH + matchLength;
+ }
+
+ if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit)))
+ return 0; /* Check output limit */
+ if (matchLength>=ML_MASK)
+ {
+ *token += ML_MASK;
+ matchLength -= ML_MASK;
+ for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; }
+ if (matchLength >= 255) { matchLength-=255; *op++ = 255; }
+ *op++ = (BYTE)matchLength;
+ }
+ else *token += (BYTE)(matchLength);
+ }
+
+ anchor = ip;
+
+ /* Test end of chunk */
+ if (ip > mflimit) break;
+
+ /* Fill table */
+ LZ4_putPosition(ip-2, ctx, tableType, base);
+
+ /* Test next position */
+ match = LZ4_getPosition(ip, ctx, tableType, base);
+ if (dict==usingExtDict)
+ {
+ if (match<(const BYTE*)source)
+ {
+ refDelta = dictDelta;
+ lowLimit = dictionary;
+ }
+ else
+ {
+ refDelta = 0;
+ lowLimit = (const BYTE*)source;
+ }
+ }
+ LZ4_putPosition(ip, ctx, tableType, base);
+ if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1)
+ && (match+MAX_DISTANCE>=ip)
+ && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) )
+ { token=op++; *token=0; goto _next_match; }
+
+ /* Prepare next loop */
+ forwardH = LZ4_hashPosition(++ip, tableType);
+ }
+
+_last_literals:
+ /* Encode Last Literals */
+ {
+ const size_t lastRun = (size_t)(iend - anchor);
+ if ((outputLimited) && ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize))
+ return 0; /* Check output limit */
+ if (lastRun >= RUN_MASK)
+ {
+ size_t accumulator = lastRun - RUN_MASK;
+ *op++ = RUN_MASK << ML_BITS;
+ for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
+ *op++ = (BYTE) accumulator;
+ }
+ else
+ {
+ *op++ = (BYTE)(lastRun<<ML_BITS);
+ }
+ memcpy(op, anchor, lastRun);
+ op += lastRun;
+ }
+
+ /* End */
+ return (int) (((char*)op)-dest);
+}
+
+
+int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ LZ4_resetStream((LZ4_stream_t*)state);
+ if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
+
+ if (maxOutputSize >= LZ4_compressBound(inputSize))
+ {
+ if (inputSize < LZ4_64Klimit)
+ return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
+ else
+ return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+ }
+ else
+ {
+ if (inputSize < LZ4_64Klimit)
+ return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
+ else
+ return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+ }
+}
+
+
+int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+#if (HEAPMODE)
+ void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
+#else
+ LZ4_stream_t ctx;
+ void* ctxPtr = &ctx;
+#endif
+
+ int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration);
+
+#if (HEAPMODE)
+ FREEMEM(ctxPtr);
+#endif
+ return result;
+}
+
+
+int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+ return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1);
+}
+
+
+/* hidden debug function */
+/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */
+int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ LZ4_stream_t ctx;
+
+ LZ4_resetStream(&ctx);
+
+ if (inputSize < LZ4_64Klimit)
+ return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
+ else
+ return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration);
+}
+
+
+/********************************
+* destSize variant
+********************************/
+
+static int LZ4_compress_destSize_generic(
+ void* const ctx,
+ const char* const src,
+ char* const dst,
+ int* const srcSizePtr,
+ const int targetDstSize,
+ const tableType_t tableType)
+{
+ const BYTE* ip = (const BYTE*) src;
+ const BYTE* base = (const BYTE*) src;
+ const BYTE* lowLimit = (const BYTE*) src;
+ const BYTE* anchor = ip;
+ const BYTE* const iend = ip + *srcSizePtr;
+ const BYTE* const mflimit = iend - MFLIMIT;
+ const BYTE* const matchlimit = iend - LASTLITERALS;
+
+ BYTE* op = (BYTE*) dst;
+ BYTE* const oend = op + targetDstSize;
+ BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */;
+ BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */);
+ BYTE* const oMaxSeq = oMaxLit - 1 /* token */;
+
+ U32 forwardH;
+
+
+ /* Init conditions */
+ if (targetDstSize < 1) return 0; /* Impossible to store anything */
+ if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */
+ if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
+ if (*srcSizePtr<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
+
+ /* First Byte */
+ *srcSizePtr = 0;
+ LZ4_putPosition(ip, ctx, tableType, base);
+ ip++; forwardH = LZ4_hashPosition(ip, tableType);
+
+ /* Main Loop */
+ for ( ; ; )
+ {
+ const BYTE* match;
+ BYTE* token;
+ {
+ const BYTE* forwardIp = ip;
+ unsigned step = 1;
+ unsigned searchMatchNb = 1 << LZ4_skipTrigger;
+
+ /* Find a match */
+ do {
+ U32 h = forwardH;
+ ip = forwardIp;
+ forwardIp += step;
+ step = (searchMatchNb++ >> LZ4_skipTrigger);
+
+ if (unlikely(forwardIp > mflimit))
+ goto _last_literals;
+
+ match = LZ4_getPositionOnHash(h, ctx, tableType, base);
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
+ LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+ } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
+ || (LZ4_read32(match) != LZ4_read32(ip)) );
+ }
+
+ /* Catch up */
+ while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }
+
+ {
+ /* Encode Literal length */
+ unsigned litLength = (unsigned)(ip - anchor);
+ token = op++;
+ if (op + ((litLength+240)/255) + litLength > oMaxLit)
+ {
+ /* Not enough space for a last match */
+ op--;
+ goto _last_literals;
+ }
+ if (litLength>=RUN_MASK)
+ {
+ unsigned len = litLength - RUN_MASK;
+ *token=(RUN_MASK<<ML_BITS);
+ for(; len >= 255 ; len-=255) *op++ = 255;
+ *op++ = (BYTE)len;
+ }
+ else *token = (BYTE)(litLength<<ML_BITS);
+
+ /* Copy Literals */
+ LZ4_wildCopy(op, anchor, op+litLength);
+ op += litLength;
+ }
+
+_next_match:
+ /* Encode Offset */
+ LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
+
+ /* Encode MatchLength */
+ {
+ size_t matchLength;
+
+ matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
+
+ if (op + ((matchLength+240)/255) > oMaxMatch)
+ {
+ /* Match description too long : reduce it */
+ matchLength = (15-1) + (oMaxMatch-op) * 255;
+ }
+ //printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH);
+ ip += MINMATCH + matchLength;
+
+ if (matchLength>=ML_MASK)
+ {
+ *token += ML_MASK;
+ matchLength -= ML_MASK;
+ while (matchLength >= 255) { matchLength-=255; *op++ = 255; }
+ *op++ = (BYTE)matchLength;
+ }
+ else *token += (BYTE)(matchLength);
+ }
+
+ anchor = ip;
+
+ /* Test end of block */
+ if (ip > mflimit) break;
+ if (op > oMaxSeq) break;
+
+ /* Fill table */
+ LZ4_putPosition(ip-2, ctx, tableType, base);
+
+ /* Test next position */
+ match = LZ4_getPosition(ip, ctx, tableType, base);
+ LZ4_putPosition(ip, ctx, tableType, base);
+ if ( (match+MAX_DISTANCE>=ip)
+ && (LZ4_read32(match)==LZ4_read32(ip)) )
+ { token=op++; *token=0; goto _next_match; }
+
+ /* Prepare next loop */
+ forwardH = LZ4_hashPosition(++ip, tableType);
+ }
+
+_last_literals:
+ /* Encode Last Literals */
+ {
+ size_t lastRunSize = (size_t)(iend - anchor);
+ if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend)
+ {
+ /* adapt lastRunSize to fill 'dst' */
+ lastRunSize = (oend-op) - 1;
+ lastRunSize -= (lastRunSize+240)/255;
+ }
+ ip = anchor + lastRunSize;
+
+ if (lastRunSize >= RUN_MASK)
+ {
+ size_t accumulator = lastRunSize - RUN_MASK;
+ *op++ = RUN_MASK << ML_BITS;
+ for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
+ *op++ = (BYTE) accumulator;
+ }
+ else
+ {
+ *op++ = (BYTE)(lastRunSize<<ML_BITS);
+ }
+ memcpy(op, anchor, lastRunSize);
+ op += lastRunSize;
+ }
+
+ /* End */
+ *srcSizePtr = (int) (((const char*)ip)-src);
+ return (int) (((char*)op)-dst);
+}
+
+
+static int LZ4_compress_destSize_extState (void* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)
+{
+ LZ4_resetStream((LZ4_stream_t*)state);
+
+ if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) /* compression success is guaranteed */
+ {
+ return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);
+ }
+ else
+ {
+ if (*srcSizePtr < LZ4_64Klimit)
+ return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16);
+ else
+ return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, LZ4_64bits() ? byU32 : byPtr);
+ }
+}
+
+
+int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)
+{
+#if (HEAPMODE)
+ void* ctx = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */
+#else
+ LZ4_stream_t ctxBody;
+ void* ctx = &ctxBody;
+#endif
+
+ int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);
+
+#if (HEAPMODE)
+ FREEMEM(ctx);
+#endif
+ return result;
+}
+
+
+
+/********************************
+* Streaming functions
+********************************/
+
+LZ4_stream_t* LZ4_createStream(void)
+{
+ LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64);
+ LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */
+ LZ4_resetStream(lz4s);
+ return lz4s;
+}
+
+void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
+{
+ MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t));
+}
+
+int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
+{
+ FREEMEM(LZ4_stream);
+ return (0);
+}
+
+
+#define HASH_UNIT sizeof(size_t)
+int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)
+{
+ LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
+ const BYTE* p = (const BYTE*)dictionary;
+ const BYTE* const dictEnd = p + dictSize;
+ const BYTE* base;
+
+ if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */
+ LZ4_resetStream(LZ4_dict);
+
+ if (dictSize < (int)HASH_UNIT)
+ {
+ dict->dictionary = NULL;
+ dict->dictSize = 0;
+ return 0;
+ }
+
+ if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;
+ dict->currentOffset += 64 KB;
+ base = p - dict->currentOffset;
+ dict->dictionary = p;
+ dict->dictSize = (U32)(dictEnd - p);
+ dict->currentOffset += dict->dictSize;
+
+ while (p <= dictEnd-HASH_UNIT)
+ {
+ LZ4_putPosition(p, dict->hashTable, byU32, base);
+ p+=3;
+ }
+
+ return dict->dictSize;
+}
+
+
+static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src)
+{
+ if ((LZ4_dict->currentOffset > 0x80000000) ||
+ ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */
+ {
+ /* rescale hash table */
+ U32 delta = LZ4_dict->currentOffset - 64 KB;
+ const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;
+ int i;
+ for (i=0; i<HASH_SIZE_U32; i++)
+ {
+ if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;
+ else LZ4_dict->hashTable[i] -= delta;
+ }
+ LZ4_dict->currentOffset = 64 KB;
+ if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;
+ LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;
+ }
+}
+
+
+int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)
+{
+ LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream;
+ const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
+
+ const BYTE* smallest = (const BYTE*) source;
+ if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */
+ if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd;
+ LZ4_renormDictT(streamPtr, smallest);
+ if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
+
+ /* Check overlapping input/dictionary space */
+ {
+ const BYTE* sourceEnd = (const BYTE*) source + inputSize;
+ if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd))
+ {
+ streamPtr->dictSize = (U32)(dictEnd - sourceEnd);
+ if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;
+ if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;
+ streamPtr->dictionary = dictEnd - streamPtr->dictSize;
+ }
+ }
+
+ /* prefix mode : source data follows dictionary */
+ if (dictEnd == (const BYTE*)source)
+ {
+ int result;
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration);
+ else
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration);
+ streamPtr->dictSize += (U32)inputSize;
+ streamPtr->currentOffset += (U32)inputSize;
+ return result;
+ }
+
+ /* external dictionary mode */
+ {
+ int result;
+ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration);
+ else
+ result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration);
+ streamPtr->dictionary = (const BYTE*)source;
+ streamPtr->dictSize = (U32)inputSize;
+ streamPtr->currentOffset += (U32)inputSize;
+ return result;
+ }
+}
+
+
+/* Hidden debug function, to force external dictionary mode */
+int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize)
+{
+ LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict;
+ int result;
+ const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize;
+
+ const BYTE* smallest = dictEnd;
+ if (smallest > (const BYTE*) source) smallest = (const BYTE*) source;
+ LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest);
+
+ result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);
+
+ streamPtr->dictionary = (const BYTE*)source;
+ streamPtr->dictSize = (U32)inputSize;
+ streamPtr->currentOffset += (U32)inputSize;
+
+ return result;
+}
+
+
+int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)
+{
+ LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict;
+ const BYTE* previousDictEnd = dict->dictionary + dict->dictSize;
+
+ if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */
+ if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize;
+
+ memmove(safeBuffer, previousDictEnd - dictSize, dictSize);
+
+ dict->dictionary = (const BYTE*)safeBuffer;
+ dict->dictSize = (U32)dictSize;
+
+ return dictSize;
+}
+
+
+
+/*******************************
+* Decompression functions
+*******************************/
+/*
+ * This generic decompression function cover all use cases.
+ * It shall be instantiated several times, using different sets of directives
+ * Note that it is essential this generic function is really inlined,
+ * in order to remove useless branches during compilation optimization.
+ */
+FORCE_INLINE int LZ4_decompress_generic(
+ const char* const source,
+ char* const dest,
+ int inputSize,
+ int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */
+
+ int endOnInput, /* endOnOutputSize, endOnInputSize */
+ int partialDecoding, /* full, partial */
+ int targetOutputSize, /* only used if partialDecoding==partial */
+ int dict, /* noDict, withPrefix64k, usingExtDict */
+ const BYTE* const lowPrefix, /* == dest if dict == noDict */
+ const BYTE* const dictStart, /* only if dict==usingExtDict */
+ const size_t dictSize /* note : = 0 if noDict */
+ )
+{
+ /* Local Variables */
+ const BYTE* ip = (const BYTE*) source;
+ const BYTE* const iend = ip + inputSize;
+
+ BYTE* op = (BYTE*) dest;
+ BYTE* const oend = op + outputSize;
+ BYTE* cpy;
+ BYTE* oexit = op + targetOutputSize;
+ const BYTE* const lowLimit = lowPrefix - dictSize;
+
+ const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize;
+ const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4};
+ const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
+
+ const int safeDecode = (endOnInput==endOnInputSize);
+ const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB)));
+
+
+ /* Special cases */
+ if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
+ if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
+ if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
+
+
+ /* Main Loop */
+ while (1)
+ {
+ unsigned token;
+ size_t length;
+ const BYTE* match;
+
+ /* get literal length */
+ token = *ip++;
+ if ((length=(token>>ML_BITS)) == RUN_MASK)
+ {
+ unsigned s;
+ do
+ {
+ s = *ip++;
+ length += s;
+ }
+ while (likely((endOnInput)?ip<iend-RUN_MASK:1) && (s==255));
+ if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)(op))) goto _output_error; /* overflow detection */
+ if ((safeDecode) && unlikely((size_t)(ip+length)<(size_t)(ip))) goto _output_error; /* overflow detection */
+ }
+
+ /* copy literals */
+ cpy = op+length;
+ if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
+ || ((!endOnInput) && (cpy>oend-COPYLENGTH)))
+ {
+ if (partialDecoding)
+ {
+ if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
+ if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
+ }
+ else
+ {
+ if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
+ if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
+ }
+ memcpy(op, ip, length);
+ ip += length;
+ op += length;
+ break; /* Necessarily EOF, due to parsing restrictions */
+ }
+ LZ4_wildCopy(op, ip, cpy);
+ ip += length; op = cpy;
+
+ /* get offset */
+ match = cpy - LZ4_readLE16(ip); ip+=2;
+ if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */
+
+ /* get matchlength */
+ length = token & ML_MASK;
+ if (length == ML_MASK)
+ {
+ unsigned s;
+ do
+ {
+ if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
+ s = *ip++;
+ length += s;
+ } while (s==255);
+ if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */
+ }
+ length += MINMATCH;
+
+ /* check external dictionary */
+ if ((dict==usingExtDict) && (match < lowPrefix))
+ {
+ if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
+
+ if (length <= (size_t)(lowPrefix-match))
+ {
+ /* match can be copied as a single segment from external dictionary */
+ match = dictEnd - (lowPrefix-match);
+ memmove(op, match, length); op += length;
+ }
+ else
+ {
+ /* match encompass external dictionary and current segment */
+ size_t copySize = (size_t)(lowPrefix-match);
+ memcpy(op, dictEnd - copySize, copySize);
+ op += copySize;
+ copySize = length - copySize;
+ if (copySize > (size_t)(op-lowPrefix)) /* overlap within current segment */
+ {
+ BYTE* const endOfMatch = op + copySize;
+ const BYTE* copyFrom = lowPrefix;
+ while (op < endOfMatch) *op++ = *copyFrom++;
+ }
+ else
+ {
+ memcpy(op, lowPrefix, copySize);
+ op += copySize;
+ }
+ }
+ continue;
+ }
+
+ /* copy repeated sequence */
+ cpy = op + length;
+ if (unlikely((op-match)<8))
+ {
+ const size_t dec64 = dec64table[op-match];
+ op[0] = match[0];
+ op[1] = match[1];
+ op[2] = match[2];
+ op[3] = match[3];
+ match += dec32table[op-match];
+ LZ4_copy4(op+4, match);
+ op += 8; match -= dec64;
+ } else { LZ4_copy8(op, match); op+=8; match+=8; }
+
+ if (unlikely(cpy>oend-12))
+ {
+ if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals */
+ if (op < oend-8)
+ {
+ LZ4_wildCopy(op, match, oend-8);
+ match += (oend-8) - op;
+ op = oend-8;
+ }
+ while (op<cpy) *op++ = *match++;
+ }
+ else
+ LZ4_wildCopy(op, match, cpy);
+ op=cpy; /* correction */
+ }
+
+ /* end of decoding */
+ if (endOnInput)
+ return (int) (((char*)op)-dest); /* Nb of output bytes decoded */
+ else
+ return (int) (((const char*)ip)-source); /* Nb of input bytes read */
+
+ /* Overflow error detected */
+_output_error:
+ return (int) (-(((const char*)ip)-source))-1;
+}
+
+
+int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0);
+}
+
+int LZ4_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0);
+}
+
+int LZ4_decompress_fast(const char* source, char* dest, int originalSize)
+{
+ return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)(dest - 64 KB), NULL, 64 KB);
+}
+
+
+/* streaming decompression functions */
+
+typedef struct
+{
+ const BYTE* externalDict;
+ size_t extDictSize;
+ const BYTE* prefixEnd;
+ size_t prefixSize;
+} LZ4_streamDecode_t_internal;
+
+/*
+ * If you prefer dynamic allocation methods,
+ * LZ4_createStreamDecode()
+ * provides a pointer (void*) towards an initialized LZ4_streamDecode_t structure.
+ */
+LZ4_streamDecode_t* LZ4_createStreamDecode(void)
+{
+ LZ4_streamDecode_t* lz4s = (LZ4_streamDecode_t*) ALLOCATOR(1, sizeof(LZ4_streamDecode_t));
+ return lz4s;
+}
+
+int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)
+{
+ FREEMEM(LZ4_stream);
+ return 0;
+}
+
+/*
+ * LZ4_setStreamDecode
+ * Use this function to instruct where to find the dictionary
+ * This function is not necessary if previous data is still available where it was decoded.
+ * Loading a size of 0 is allowed (same effect as no dictionary).
+ * Return : 1 if OK, 0 if error
+ */
+int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+ lz4sd->prefixSize = (size_t) dictSize;
+ lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;
+ lz4sd->externalDict = NULL;
+ lz4sd->extDictSize = 0;
+ return 1;
+}
+
+/*
+*_continue() :
+ These decoding functions allow decompression of multiple blocks in "streaming" mode.
+ Previously decoded blocks must still be available at the memory position where they were decoded.
+ If it's not possible, save the relevant part of decoded data into a safe buffer,
+ and indicate where it stands using LZ4_setStreamDecode()
+*/
+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+ int result;
+
+ if (lz4sd->prefixEnd == (BYTE*)dest)
+ {
+ result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, full, 0,
+ usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize += result;
+ lz4sd->prefixEnd += result;
+ }
+ else
+ {
+ lz4sd->extDictSize = lz4sd->prefixSize;
+ lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;
+ result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,
+ endOnInputSize, full, 0,
+ usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = result;
+ lz4sd->prefixEnd = (BYTE*)dest + result;
+ }
+
+ return result;
+}
+
+int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize)
+{
+ LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode;
+ int result;
+
+ if (lz4sd->prefixEnd == (BYTE*)dest)
+ {
+ result = LZ4_decompress_generic(source, dest, 0, originalSize,
+ endOnOutputSize, full, 0,
+ usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize += originalSize;
+ lz4sd->prefixEnd += originalSize;
+ }
+ else
+ {
+ lz4sd->extDictSize = lz4sd->prefixSize;
+ lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize;
+ result = LZ4_decompress_generic(source, dest, 0, originalSize,
+ endOnOutputSize, full, 0,
+ usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize);
+ if (result <= 0) return result;
+ lz4sd->prefixSize = originalSize;
+ lz4sd->prefixEnd = (BYTE*)dest + originalSize;
+ }
+
+ return result;
+}
+
+
+/*
+Advanced decoding functions :
+*_usingDict() :
+ These decoding functions work the same as "_continue" ones,
+ the dictionary must be explicitly provided within parameters
+*/
+
+FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize)
+{
+ if (dictSize==0)
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0);
+ if (dictStart+dictSize == dest)
+ {
+ if (dictSize >= (int)(64 KB - 1))
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0);
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0);
+ }
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
+{
+ return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize);
+}
+
+int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)
+{
+ return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize);
+}
+
+/* debug function */
+int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
+}
+
+
+/***************************************************
+* Obsolete Functions
+***************************************************/
+/* obsolete compression functions */
+int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); }
+int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); }
+int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); }
+int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); }
+int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); }
+int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); }
+
+/*
+These function names are deprecated and should no longer be used.
+They are only provided here for compatibility with older user programs.
+- LZ4_uncompress is totally equivalent to LZ4_decompress_fast
+- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe
+*/
+int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
+int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
+
+
+/* Obsolete Streaming functions */
+
+int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; }
+
+static void LZ4_init(LZ4_stream_t_internal* lz4ds, BYTE* base)
+{
+ MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE);
+ lz4ds->bufferStart = base;
+}
+
+int LZ4_resetStreamState(void* state, char* inputBuffer)
+{
+ if ((((size_t)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */
+ LZ4_init((LZ4_stream_t_internal*)state, (BYTE*)inputBuffer);
+ return 0;
+}
+
+void* LZ4_create (char* inputBuffer)
+{
+ void* lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64);
+ LZ4_init ((LZ4_stream_t_internal*)lz4ds, (BYTE*)inputBuffer);
+ return lz4ds;
+}
+
+char* LZ4_slideInputBuffer (void* LZ4_Data)
+{
+ LZ4_stream_t_internal* ctx = (LZ4_stream_t_internal*)LZ4_Data;
+ int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB);
+ return (char*)(ctx->bufferStart + dictSize);
+}
+
+/* Obsolete streaming decompression functions */
+
+int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)
+{
+ return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
+}
+
+int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)
+{
+ return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB);
+}
+
+#endif /* LZ4_COMMONDEFS_ONLY */
+
+#endif /* NEED_COMPAT_LZ4 */
diff --git a/src/compat/compat-lz4.h b/src/compat/compat-lz4.h
new file mode 100644
index 0000000..3e74002
--- /dev/null
+++ b/src/compat/compat-lz4.h
@@ -0,0 +1,360 @@
+/*
+ LZ4 - Fast LZ compression algorithm
+ Header File
+ Copyright (C) 2011-2015, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - LZ4 source repository : https://github.com/Cyan4973/lz4
+ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+#pragma once
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*
+ * lz4.h provides block compression functions, and gives full buffer control to programmer.
+ * If you need to generate inter-operable compressed data (respecting LZ4 frame specification),
+ * and can let the library handle its own memory, please use lz4frame.h instead.
+*/
+
+/**************************************
+* Version
+**************************************/
+#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
+#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
+#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */
+#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
+int LZ4_versionNumber (void);
+
+/**************************************
+* Tuning parameter
+**************************************/
+/*
+ * LZ4_MEMORY_USAGE :
+ * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+ * Increasing memory usage improves compression ratio
+ * Reduced memory usage can improve speed, due to cache effect
+ * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
+ */
+#define LZ4_MEMORY_USAGE 14
+
+
+/**************************************
+* Simple Functions
+**************************************/
+
+int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize);
+int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
+
+/*
+LZ4_compress_default() :
+ Compresses 'sourceSize' bytes from buffer 'source'
+ into already allocated 'dest' buffer of size 'maxDestSize'.
+ Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize).
+ It also runs faster, so it's a recommended setting.
+ If the function cannot compress 'source' into a more limited 'dest' budget,
+ compression stops *immediately*, and the function result is zero.
+ As a consequence, 'dest' content is not valid.
+ This function never writes outside 'dest' buffer, nor read outside 'source' buffer.
+ sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE
+ maxDestSize : full or partial size of buffer 'dest' (which must be already allocated)
+ return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize)
+ or 0 if compression fails
+
+LZ4_decompress_safe() :
+ compressedSize : is the precise full size of the compressed block.
+ maxDecompressedSize : is the size of destination buffer, which must be already allocated.
+ return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize)
+ If destination buffer is not large enough, decoding will stop and output an error code (<0).
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ This function is protected against buffer overflow exploits, including malicious data packets.
+ It never writes outside output buffer, nor reads outside input buffer.
+*/
+
+
+/**************************************
+* Advanced Functions
+**************************************/
+#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
+#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
+
+/*
+LZ4_compressBound() :
+ Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible)
+ This function is primarily useful for memory allocation purposes (destination buffer size).
+ Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
+ Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize)
+ inputSize : max supported value is LZ4_MAX_INPUT_SIZE
+ return : maximum output size in a "worst case" scenario
+ or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
+*/
+int LZ4_compressBound(int inputSize);
+
+/*
+LZ4_compress_fast() :
+ Same as LZ4_compress_default(), but allows to select an "acceleration" factor.
+ The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
+ It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.
+ An acceleration value of "1" is the same as regular LZ4_compress_default()
+ Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1.
+*/
+int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration);
+
+
+/*
+LZ4_compress_fast_extState() :
+ Same compression function, just using an externally allocated memory space to store compression state.
+ Use LZ4_sizeofState() to know how much memory must be allocated,
+ and allocate it on 8-bytes boundaries (using malloc() typically).
+ Then, provide it as 'void* state' to compression function.
+*/
+int LZ4_sizeofState(void);
+int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration);
+
+
+/*
+LZ4_compress_destSize() :
+ Reverse the logic, by compressing as much data as possible from 'source' buffer
+ into already allocated buffer 'dest' of size 'targetDestSize'.
+ This function either compresses the entire 'source' content into 'dest' if it's large enough,
+ or fill 'dest' buffer completely with as much data as possible from 'source'.
+ *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'.
+ New value is necessarily <= old value.
+ return : Nb bytes written into 'dest' (necessarily <= targetDestSize)
+ or 0 if compression fails
+*/
+int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize);
+
+
+/*
+LZ4_decompress_fast() :
+ originalSize : is the original and therefore uncompressed size
+ return : the number of bytes read from the source buffer (in other words, the compressed size)
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes.
+ note : This function fully respect memory boundaries for properly formed compressed data.
+ It is a bit faster than LZ4_decompress_safe().
+ However, it does not provide any protection against intentionally modified data stream (malicious input).
+ Use this function in trusted environment only (data to decode comes from a trusted source).
+*/
+int LZ4_decompress_fast (const char* source, char* dest, int originalSize);
+
+/*
+LZ4_decompress_safe_partial() :
+ This function decompress a compressed block of size 'compressedSize' at position 'source'
+ into destination buffer 'dest' of size 'maxDecompressedSize'.
+ The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
+ reducing decompression time.
+ return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize)
+ Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
+ Always control how many bytes were decoded.
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
+*/
+int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize);
+
+
+/***********************************************
+* Streaming Compression Functions
+***********************************************/
+#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4)
+#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long))
+/*
+ * LZ4_stream_t
+ * information structure to track an LZ4 stream.
+ * important : init this structure content before first use !
+ * note : only allocated directly the structure if you are statically linking LZ4
+ * If you are using liblz4 as a DLL, please use below construction methods instead.
+ */
+typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t;
+
+/*
+ * LZ4_resetStream
+ * Use this function to init an allocated LZ4_stream_t structure
+ */
+void LZ4_resetStream (LZ4_stream_t* streamPtr);
+
+/*
+ * LZ4_createStream will allocate and initialize an LZ4_stream_t structure
+ * LZ4_freeStream releases its memory.
+ * In the context of a DLL (liblz4), please use these methods rather than the static struct.
+ * They are more future proof, in case of a change of LZ4_stream_t size.
+ */
+LZ4_stream_t* LZ4_createStream(void);
+int LZ4_freeStream (LZ4_stream_t* streamPtr);
+
+/*
+ * LZ4_loadDict
+ * Use this function to load a static dictionary into LZ4_stream.
+ * Any previous data will be forgotten, only 'dictionary' will remain in memory.
+ * Loading a size of 0 is allowed.
+ * Return : dictionary size, in bytes (necessarily <= 64 KB)
+ */
+int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);
+
+/*
+ * LZ4_compress_fast_continue
+ * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio.
+ * Important : Previous data blocks are assumed to still be present and unmodified !
+ * 'dst' buffer must be already allocated.
+ * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
+ * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero.
+ */
+int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration);
+
+/*
+ * LZ4_saveDict
+ * If previously compressed data block is not guaranteed to remain available at its memory location
+ * save it into a safer place (char* safeBuffer)
+ * Note : you don't need to call LZ4_loadDict() afterwards,
+ * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue()
+ * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error
+ */
+int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize);
+
+
+/************************************************
+* Streaming Decompression Functions
+************************************************/
+
+#define LZ4_STREAMDECODESIZE_U64 4
+#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
+typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t;
+/*
+ * LZ4_streamDecode_t
+ * information structure to track an LZ4 stream.
+ * init this structure content using LZ4_setStreamDecode or memset() before first use !
+ *
+ * In the context of a DLL (liblz4) please prefer usage of construction methods below.
+ * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future.
+ * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure
+ * LZ4_freeStreamDecode releases its memory.
+ */
+LZ4_streamDecode_t* LZ4_createStreamDecode(void);
+int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
+
+/*
+ * LZ4_setStreamDecode
+ * Use this function to instruct where to find the dictionary.
+ * Setting a size of 0 is allowed (same effect as reset).
+ * Return : 1 if OK, 0 if error
+ */
+int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);
+
+/*
+*_continue() :
+ These decoding functions allow decompression of multiple blocks in "streaming" mode.
+ Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB)
+ In the case of a ring buffers, decoding buffer must be either :
+ - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions)
+ In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB).
+ - Larger than encoding buffer, by a minimum of maxBlockSize more bytes.
+ maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block.
+ In which case, encoding and decoding buffers do not need to be synchronized,
+ and encoding ring buffer can have any size, including small ones ( < 64 KB).
+ - _At least_ 64 KB + 8 bytes + maxBlockSize.
+ In which case, encoding and decoding buffers do not need to be synchronized,
+ and encoding ring buffer can have any size, including larger than decoding buffer.
+ Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer,
+ and indicate where it is saved using LZ4_setStreamDecode()
+*/
+int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize);
+int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize);
+
+
+/*
+Advanced decoding functions :
+*_usingDict() :
+ These decoding functions work the same as
+ a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue()
+ They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure.
+*/
+int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize);
+int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize);
+
+
+
+/**************************************
+* Obsolete Functions
+**************************************/
+/* Deprecate Warnings */
+/* Should these warnings messages be a problem,
+ it is generally possible to disable them,
+ with -Wno-deprecated-declarations for gcc
+ or _CRT_SECURE_NO_WARNINGS in Visual for example.
+ You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */
+#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK
+# define LZ4_DEPRECATE_WARNING_DEFBLOCK
+# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+# if (LZ4_GCC_VERSION >= 405) || defined(__clang__)
+# define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))
+# elif (LZ4_GCC_VERSION >= 301)
+# define LZ4_DEPRECATED(message) __attribute__((deprecated))
+# elif defined(_MSC_VER)
+# define LZ4_DEPRECATED(message) __declspec(deprecated(message))
+# else
+# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler")
+# define LZ4_DEPRECATED(message)
+# endif
+#endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */
+
+/* Obsolete compression functions */
+/* These functions are planned to start generate warnings by r131 approximately */
+int LZ4_compress (const char* source, char* dest, int sourceSize);
+int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize);
+int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
+int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/* Obsolete decompression functions */
+/* These function names are completely deprecated and must no longer be used.
+ They are only provided here for compatibility with older programs.
+ - LZ4_uncompress is the same as LZ4_decompress_fast
+ - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe
+ These function prototypes are now disabled; uncomment them only if you really need them.
+ It is highly recommended to stop using these prototypes and migrate to maintained ones */
+/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */
+/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */
+
+/* Obsolete streaming functions; use new streaming interface whenever possible */
+LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer);
+LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void);
+LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer);
+LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state);
+
+/* Obsolete streaming decoding functions */
+LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);
+LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/src/compat/compat.vcxproj b/src/compat/compat.vcxproj
index 1dedb33..d2695e6 100644
--- a/src/compat/compat.vcxproj
+++ b/src/compat/compat.vcxproj
@@ -79,6 +79,7 @@
<ClCompile Include="compat-inet_ntop.c" />
<ClCompile Include="compat-inet_pton.c" />
<ClCompile Include="compat-daemon.c" />
+ <ClCompile Include="compat-lz4.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="compat.h" />
@@ -86,4 +87,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/compat/compat.vcxproj.filters b/src/compat/compat.vcxproj.filters
index 00bb0ff..0f78e86 100644
--- a/src/compat/compat.vcxproj.filters
+++ b/src/compat/compat.vcxproj.filters
@@ -33,6 +33,9 @@
<ClCompile Include="compat-daemon.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="compat-lz4.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="compat.h">
diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index 6d02fea..4c18449 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -18,7 +18,7 @@ EXTRA_DIST = \
openvpn.vcxproj \
openvpn.vcxproj.filters
-INCLUDES = \
+AM_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src/compat
@@ -26,6 +26,7 @@ AM_CFLAGS = \
$(TAP_CFLAGS) \
$(OPTIONAL_CRYPTO_CFLAGS) \
$(OPTIONAL_LZO_CFLAGS) \
+ $(OPTIONAL_LZ4_CFLAGS) \
$(OPTIONAL_PKCS11_HELPER_CFLAGS)
if WIN32
# we want unicode entry point but not the macro
@@ -35,15 +36,18 @@ endif
sbin_PROGRAMS = openvpn
openvpn_SOURCES = \
+ argv.c argv.h \
base64.c base64.h \
basic.h \
buffer.c buffer.h \
circ_list.h \
clinat.c clinat.h \
common.h \
+ comp.c comp.h compstub.c \
+ comp-lz4.c comp-lz4.h \
crypto.c crypto.h crypto_backend.h \
crypto_openssl.c crypto_openssl.h \
- crypto_polarssl.c crypto_polarssl.h \
+ crypto_mbedtls.c crypto_mbedtls.h \
dhcp.c dhcp.h \
errlevel.h \
error.c error.h \
@@ -65,7 +69,7 @@ openvpn_SOURCES = \
memdbg.h \
misc.c misc.h \
platform.c platform.h \
- console.c console.h \
+ console.c console.h console_builtin.c console_systemd.c \
mroute.c mroute.h \
mss.c mss.h \
mstats.c mstats.h \
@@ -77,7 +81,7 @@ openvpn_SOURCES = \
occ.c occ.h occ-inline.h \
pkcs11.c pkcs11.h pkcs11_backend.h \
pkcs11_openssl.c \
- pkcs11_polarssl.c \
+ pkcs11_mbedtls.c \
openvpn.c openvpn.h \
options.c options.h \
otime.c otime.h \
@@ -102,26 +106,28 @@ openvpn_SOURCES = \
socks.c socks.h \
ssl.c ssl.h ssl_backend.h \
ssl_openssl.c ssl_openssl.h \
- ssl_polarssl.c ssl_polarssl.h \
+ ssl_mbedtls.c ssl_mbedtls.h \
ssl_common.h \
ssl_verify.c ssl_verify.h ssl_verify_backend.h \
ssl_verify_openssl.c ssl_verify_openssl.h \
- ssl_verify_polarssl.c ssl_verify_polarssl.h \
+ ssl_verify_mbedtls.c ssl_verify_mbedtls.h \
status.c status.h \
syshead.h \
+ tls_crypt.c tls_crypt.h \
tun.c tun.h \
- win32.h win32_wfp.h win32.c \
+ win32.h win32.c \
cryptoapi.h cryptoapi.c
openvpn_LDADD = \
$(top_builddir)/src/compat/libcompat.la \
$(SOCKETS_LIBS) \
$(OPTIONAL_LZO_LIBS) \
+ $(OPTIONAL_LZ4_LIBS) \
$(OPTIONAL_PKCS11_HELPER_LIBS) \
$(OPTIONAL_CRYPTO_LIBS) \
$(OPTIONAL_SELINUX_LIBS) \
$(OPTIONAL_SYSTEMD_LIBS) \
$(OPTIONAL_DL_LIBS)
if WIN32
-openvpn_SOURCES += openvpn_win32_resources.rc
-openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lrpcrt4 -lwinmm
+openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h
+openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4
endif
diff --git a/src/openvpn/Makefile.in b/src/openvpn/Makefile.in
index 3691c96..ff15d6d 100644
--- a/src/openvpn/Makefile.in
+++ b/src/openvpn/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -37,17 +37,7 @@
# Required to build Windows resource file
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -110,11 +100,13 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+DIST_COMMON = $(top_srcdir)/build/ltrc.inc $(srcdir)/Makefile.in \
+ $(srcdir)/Makefile.am $(top_srcdir)/depcomp
# we want unicode entry point but not the macro
@WIN32_TRUE@am__append_1 = -municode -UUNICODE
sbin_PROGRAMS = openvpn$(EXEEXT)
-@WIN32_TRUE@am__append_2 = openvpn_win32_resources.rc
-@WIN32_TRUE@am__append_3 = -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lrpcrt4 -lwinmm
+@WIN32_TRUE@am__append_2 = openvpn_win32_resources.rc block_dns.c block_dns.h
+@WIN32_TRUE@am__append_3 = -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4
subdir = src/openvpn
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
@@ -126,63 +118,68 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/compat.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_HEADER = $(top_builddir)/config.h \
+ $(top_builddir)/include/openvpn-plugin.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(sbindir)"
PROGRAMS = $(sbin_PROGRAMS)
-am__openvpn_SOURCES_DIST = base64.c base64.h basic.h buffer.c buffer.h \
- circ_list.h clinat.c clinat.h common.h crypto.c crypto.h \
- crypto_backend.h crypto_openssl.c crypto_openssl.h \
- crypto_polarssl.c crypto_polarssl.h dhcp.c dhcp.h errlevel.h \
+am__openvpn_SOURCES_DIST = argv.c argv.h base64.c base64.h basic.h \
+ buffer.c buffer.h circ_list.h clinat.c clinat.h common.h \
+ comp.c comp.h compstub.c comp-lz4.c comp-lz4.h crypto.c \
+ crypto.h crypto_backend.h crypto_openssl.c crypto_openssl.h \
+ crypto_mbedtls.c crypto_mbedtls.h dhcp.c dhcp.h errlevel.h \
error.c error.h event.c event.h fdmisc.c fdmisc.h forward.c \
forward.h forward-inline.h fragment.c fragment.h gremlin.c \
gremlin.h helper.c helper.h httpdigest.c httpdigest.h lladdr.c \
lladdr.h init.c init.h integer.h interval.c interval.h list.c \
list.h lzo.c lzo.h manage.c manage.h mbuf.c mbuf.h memdbg.h \
misc.c misc.h platform.c platform.h console.c console.h \
- mroute.c mroute.h mss.c mss.h mstats.c mstats.h mtcp.c mtcp.h \
- mtu.c mtu.h mudp.c mudp.h multi.c multi.h ntlm.c ntlm.h occ.c \
- occ.h occ-inline.h pkcs11.c pkcs11.h pkcs11_backend.h \
- pkcs11_openssl.c pkcs11_polarssl.c openvpn.c openvpn.h \
- options.c options.h otime.c otime.h packet_id.c packet_id.h \
- perf.c perf.h pf.c pf.h pf-inline.h ping.c ping.h \
- ping-inline.h plugin.c plugin.h pool.c pool.h proto.c proto.h \
- proxy.c proxy.h ps.c ps.h push.c push.h pushlist.h reliable.c \
- reliable.h route.c route.h schedule.c schedule.h session_id.c \
- session_id.h shaper.c shaper.h sig.c sig.h socket.c socket.h \
- socks.c socks.h ssl.c ssl.h ssl_backend.h ssl_openssl.c \
- ssl_openssl.h ssl_polarssl.c ssl_polarssl.h ssl_common.h \
- ssl_verify.c ssl_verify.h ssl_verify_backend.h \
- ssl_verify_openssl.c ssl_verify_openssl.h \
- ssl_verify_polarssl.c ssl_verify_polarssl.h status.c status.h \
- syshead.h tun.c tun.h win32.h win32_wfp.h win32.c cryptoapi.h \
- cryptoapi.c openvpn_win32_resources.rc
-@WIN32_TRUE@am__objects_1 = openvpn_win32_resources.$(OBJEXT)
-am_openvpn_OBJECTS = base64.$(OBJEXT) buffer.$(OBJEXT) \
- clinat.$(OBJEXT) crypto.$(OBJEXT) crypto_openssl.$(OBJEXT) \
- crypto_polarssl.$(OBJEXT) dhcp.$(OBJEXT) error.$(OBJEXT) \
+ console_builtin.c console_systemd.c mroute.c mroute.h mss.c \
+ mss.h mstats.c mstats.h mtcp.c mtcp.h mtu.c mtu.h mudp.c \
+ mudp.h multi.c multi.h ntlm.c ntlm.h occ.c occ.h occ-inline.h \
+ pkcs11.c pkcs11.h pkcs11_backend.h pkcs11_openssl.c \
+ pkcs11_mbedtls.c openvpn.c openvpn.h options.c options.h \
+ otime.c otime.h packet_id.c packet_id.h perf.c perf.h pf.c \
+ pf.h pf-inline.h ping.c ping.h ping-inline.h plugin.c plugin.h \
+ pool.c pool.h proto.c proto.h proxy.c proxy.h ps.c ps.h push.c \
+ push.h pushlist.h reliable.c reliable.h route.c route.h \
+ schedule.c schedule.h session_id.c session_id.h shaper.c \
+ shaper.h sig.c sig.h socket.c socket.h socks.c socks.h ssl.c \
+ ssl.h ssl_backend.h ssl_openssl.c ssl_openssl.h ssl_mbedtls.c \
+ ssl_mbedtls.h ssl_common.h ssl_verify.c ssl_verify.h \
+ ssl_verify_backend.h ssl_verify_openssl.c ssl_verify_openssl.h \
+ ssl_verify_mbedtls.c ssl_verify_mbedtls.h status.c status.h \
+ syshead.h tls_crypt.c tls_crypt.h tun.c tun.h win32.h win32.c \
+ cryptoapi.h cryptoapi.c openvpn_win32_resources.rc block_dns.c \
+ block_dns.h
+@WIN32_TRUE@am__objects_1 = openvpn_win32_resources.$(OBJEXT) \
+@WIN32_TRUE@ block_dns.$(OBJEXT)
+am_openvpn_OBJECTS = argv.$(OBJEXT) base64.$(OBJEXT) buffer.$(OBJEXT) \
+ clinat.$(OBJEXT) comp.$(OBJEXT) compstub.$(OBJEXT) \
+ comp-lz4.$(OBJEXT) crypto.$(OBJEXT) crypto_openssl.$(OBJEXT) \
+ crypto_mbedtls.$(OBJEXT) dhcp.$(OBJEXT) error.$(OBJEXT) \
event.$(OBJEXT) fdmisc.$(OBJEXT) forward.$(OBJEXT) \
fragment.$(OBJEXT) gremlin.$(OBJEXT) helper.$(OBJEXT) \
httpdigest.$(OBJEXT) lladdr.$(OBJEXT) init.$(OBJEXT) \
interval.$(OBJEXT) list.$(OBJEXT) lzo.$(OBJEXT) \
manage.$(OBJEXT) mbuf.$(OBJEXT) misc.$(OBJEXT) \
- platform.$(OBJEXT) console.$(OBJEXT) mroute.$(OBJEXT) \
- mss.$(OBJEXT) mstats.$(OBJEXT) mtcp.$(OBJEXT) mtu.$(OBJEXT) \
- mudp.$(OBJEXT) multi.$(OBJEXT) ntlm.$(OBJEXT) occ.$(OBJEXT) \
- pkcs11.$(OBJEXT) pkcs11_openssl.$(OBJEXT) \
- pkcs11_polarssl.$(OBJEXT) openvpn.$(OBJEXT) options.$(OBJEXT) \
- otime.$(OBJEXT) packet_id.$(OBJEXT) perf.$(OBJEXT) \
- pf.$(OBJEXT) ping.$(OBJEXT) plugin.$(OBJEXT) pool.$(OBJEXT) \
- proto.$(OBJEXT) proxy.$(OBJEXT) ps.$(OBJEXT) push.$(OBJEXT) \
- reliable.$(OBJEXT) route.$(OBJEXT) schedule.$(OBJEXT) \
- session_id.$(OBJEXT) shaper.$(OBJEXT) sig.$(OBJEXT) \
- socket.$(OBJEXT) socks.$(OBJEXT) ssl.$(OBJEXT) \
- ssl_openssl.$(OBJEXT) ssl_polarssl.$(OBJEXT) \
- ssl_verify.$(OBJEXT) ssl_verify_openssl.$(OBJEXT) \
- ssl_verify_polarssl.$(OBJEXT) status.$(OBJEXT) tun.$(OBJEXT) \
+ platform.$(OBJEXT) console.$(OBJEXT) console_builtin.$(OBJEXT) \
+ console_systemd.$(OBJEXT) mroute.$(OBJEXT) mss.$(OBJEXT) \
+ mstats.$(OBJEXT) mtcp.$(OBJEXT) mtu.$(OBJEXT) mudp.$(OBJEXT) \
+ multi.$(OBJEXT) ntlm.$(OBJEXT) occ.$(OBJEXT) pkcs11.$(OBJEXT) \
+ pkcs11_openssl.$(OBJEXT) pkcs11_mbedtls.$(OBJEXT) \
+ openvpn.$(OBJEXT) options.$(OBJEXT) otime.$(OBJEXT) \
+ packet_id.$(OBJEXT) perf.$(OBJEXT) pf.$(OBJEXT) ping.$(OBJEXT) \
+ plugin.$(OBJEXT) pool.$(OBJEXT) proto.$(OBJEXT) \
+ proxy.$(OBJEXT) ps.$(OBJEXT) push.$(OBJEXT) reliable.$(OBJEXT) \
+ route.$(OBJEXT) schedule.$(OBJEXT) session_id.$(OBJEXT) \
+ shaper.$(OBJEXT) sig.$(OBJEXT) socket.$(OBJEXT) \
+ socks.$(OBJEXT) ssl.$(OBJEXT) ssl_openssl.$(OBJEXT) \
+ ssl_mbedtls.$(OBJEXT) ssl_verify.$(OBJEXT) \
+ ssl_verify_openssl.$(OBJEXT) ssl_verify_mbedtls.$(OBJEXT) \
+ status.$(OBJEXT) tls_crypt.$(OBJEXT) tun.$(OBJEXT) \
win32.$(OBJEXT) cryptoapi.$(OBJEXT) $(am__objects_1)
openvpn_OBJECTS = $(am_openvpn_OBJECTS)
am__DEPENDENCIES_1 =
@@ -190,7 +187,8 @@ openvpn_DEPENDENCIES = $(top_builddir)/src/compat/libcompat.la \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
@@ -207,7 +205,7 @@ AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
-DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/include
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
@@ -255,8 +253,6 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/build/ltrc.inc \
- $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@@ -270,6 +266,7 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CMAKE = @CMAKE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
@@ -304,25 +301,31 @@ LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LZ4_CFLAGS = @LZ4_CFLAGS@
+LZ4_LIBS = @LZ4_LIBS@
LZO_CFLAGS = @LZO_CFLAGS@
LZO_LIBS = @LZO_LIBS@
MAKEINFO = @MAKEINFO@
MAN2HTML = @MAN2HTML@
MANIFEST_TOOL = @MANIFEST_TOOL@
+MBEDTLS_CFLAGS = @MBEDTLS_CFLAGS@
+MBEDTLS_LIBS = @MBEDTLS_LIBS@
MKDIR_P = @MKDIR_P@
NETSTAT = @NETSTAT@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
-OPENSSL_CRYPTO_CFLAGS = @OPENSSL_CRYPTO_CFLAGS@
-OPENSSL_CRYPTO_LIBS = @OPENSSL_CRYPTO_LIBS@
-OPENSSL_SSL_CFLAGS = @OPENSSL_SSL_CFLAGS@
-OPENSSL_SSL_LIBS = @OPENSSL_SSL_LIBS@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENVPN_VERSION_MAJOR = @OPENVPN_VERSION_MAJOR@
+OPENVPN_VERSION_MINOR = @OPENVPN_VERSION_MINOR@
+OPENVPN_VERSION_PATCH = @OPENVPN_VERSION_PATCH@
OPTIONAL_CRYPTO_CFLAGS = @OPTIONAL_CRYPTO_CFLAGS@
OPTIONAL_CRYPTO_LIBS = @OPTIONAL_CRYPTO_LIBS@
OPTIONAL_DL_LIBS = @OPTIONAL_DL_LIBS@
+OPTIONAL_LZ4_CFLAGS = @OPTIONAL_LZ4_CFLAGS@
+OPTIONAL_LZ4_LIBS = @OPTIONAL_LZ4_LIBS@
OPTIONAL_LZO_CFLAGS = @OPTIONAL_LZO_CFLAGS@
OPTIONAL_LZO_LIBS = @OPTIONAL_LZO_LIBS@
OPTIONAL_PKCS11_HELPER_CFLAGS = @OPTIONAL_PKCS11_HELPER_CFLAGS@
@@ -348,8 +351,6 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PLUGIN_AUTH_PAM_CFLAGS = @PLUGIN_AUTH_PAM_CFLAGS@
PLUGIN_AUTH_PAM_LIBS = @PLUGIN_AUTH_PAM_LIBS@
-POLARSSL_CFLAGS = @POLARSSL_CFLAGS@
-POLARSSL_LIBS = @POLARSSL_LIBS@
RANLIB = @RANLIB@
RC = @RC@
ROUTE = @ROUTE@
@@ -364,6 +365,11 @@ TAP_CFLAGS = @TAP_CFLAGS@
TAP_WIN_COMPONENT_ID = @TAP_WIN_COMPONENT_ID@
TAP_WIN_MIN_MAJOR = @TAP_WIN_MIN_MAJOR@
TAP_WIN_MIN_MINOR = @TAP_WIN_MIN_MINOR@
+TEST_CFLAGS = @TEST_CFLAGS@
+TEST_LDFLAGS = @TEST_LDFLAGS@
+VENDOR_BUILD_ROOT = @VENDOR_BUILD_ROOT@
+VENDOR_DIST_ROOT = @VENDOR_DIST_ROOT@
+VENDOR_SRC_ROOT = @VENDOR_SRC_ROOT@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -432,42 +438,43 @@ EXTRA_DIST = \
openvpn.vcxproj \
openvpn.vcxproj.filters
-INCLUDES = \
+AM_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src/compat
AM_CFLAGS = $(TAP_CFLAGS) $(OPTIONAL_CRYPTO_CFLAGS) \
- $(OPTIONAL_LZO_CFLAGS) $(OPTIONAL_PKCS11_HELPER_CFLAGS) \
- $(am__append_1)
-openvpn_SOURCES = base64.c base64.h basic.h buffer.c buffer.h \
- circ_list.h clinat.c clinat.h common.h crypto.c crypto.h \
+ $(OPTIONAL_LZO_CFLAGS) $(OPTIONAL_LZ4_CFLAGS) \
+ $(OPTIONAL_PKCS11_HELPER_CFLAGS) $(am__append_1)
+openvpn_SOURCES = argv.c argv.h base64.c base64.h basic.h buffer.c \
+ buffer.h circ_list.h clinat.c clinat.h common.h comp.c comp.h \
+ compstub.c comp-lz4.c comp-lz4.h crypto.c crypto.h \
crypto_backend.h crypto_openssl.c crypto_openssl.h \
- crypto_polarssl.c crypto_polarssl.h dhcp.c dhcp.h errlevel.h \
+ crypto_mbedtls.c crypto_mbedtls.h dhcp.c dhcp.h errlevel.h \
error.c error.h event.c event.h fdmisc.c fdmisc.h forward.c \
forward.h forward-inline.h fragment.c fragment.h gremlin.c \
gremlin.h helper.c helper.h httpdigest.c httpdigest.h lladdr.c \
lladdr.h init.c init.h integer.h interval.c interval.h list.c \
list.h lzo.c lzo.h manage.c manage.h mbuf.c mbuf.h memdbg.h \
misc.c misc.h platform.c platform.h console.c console.h \
- mroute.c mroute.h mss.c mss.h mstats.c mstats.h mtcp.c mtcp.h \
- mtu.c mtu.h mudp.c mudp.h multi.c multi.h ntlm.c ntlm.h occ.c \
- occ.h occ-inline.h pkcs11.c pkcs11.h pkcs11_backend.h \
- pkcs11_openssl.c pkcs11_polarssl.c openvpn.c openvpn.h \
- options.c options.h otime.c otime.h packet_id.c packet_id.h \
- perf.c perf.h pf.c pf.h pf-inline.h ping.c ping.h \
- ping-inline.h plugin.c plugin.h pool.c pool.h proto.c proto.h \
- proxy.c proxy.h ps.c ps.h push.c push.h pushlist.h reliable.c \
- reliable.h route.c route.h schedule.c schedule.h session_id.c \
- session_id.h shaper.c shaper.h sig.c sig.h socket.c socket.h \
- socks.c socks.h ssl.c ssl.h ssl_backend.h ssl_openssl.c \
- ssl_openssl.h ssl_polarssl.c ssl_polarssl.h ssl_common.h \
- ssl_verify.c ssl_verify.h ssl_verify_backend.h \
- ssl_verify_openssl.c ssl_verify_openssl.h \
- ssl_verify_polarssl.c ssl_verify_polarssl.h status.c status.h \
- syshead.h tun.c tun.h win32.h win32_wfp.h win32.c cryptoapi.h \
- cryptoapi.c $(am__append_2)
+ console_builtin.c console_systemd.c mroute.c mroute.h mss.c \
+ mss.h mstats.c mstats.h mtcp.c mtcp.h mtu.c mtu.h mudp.c \
+ mudp.h multi.c multi.h ntlm.c ntlm.h occ.c occ.h occ-inline.h \
+ pkcs11.c pkcs11.h pkcs11_backend.h pkcs11_openssl.c \
+ pkcs11_mbedtls.c openvpn.c openvpn.h options.c options.h \
+ otime.c otime.h packet_id.c packet_id.h perf.c perf.h pf.c \
+ pf.h pf-inline.h ping.c ping.h ping-inline.h plugin.c plugin.h \
+ pool.c pool.h proto.c proto.h proxy.c proxy.h ps.c ps.h push.c \
+ push.h pushlist.h reliable.c reliable.h route.c route.h \
+ schedule.c schedule.h session_id.c session_id.h shaper.c \
+ shaper.h sig.c sig.h socket.c socket.h socks.c socks.h ssl.c \
+ ssl.h ssl_backend.h ssl_openssl.c ssl_openssl.h ssl_mbedtls.c \
+ ssl_mbedtls.h ssl_common.h ssl_verify.c ssl_verify.h \
+ ssl_verify_backend.h ssl_verify_openssl.c ssl_verify_openssl.h \
+ ssl_verify_mbedtls.c ssl_verify_mbedtls.h status.c status.h \
+ syshead.h tls_crypt.c tls_crypt.h tun.c tun.h win32.h win32.c \
+ cryptoapi.h cryptoapi.c $(am__append_2)
openvpn_LDADD = $(top_builddir)/src/compat/libcompat.la \
- $(SOCKETS_LIBS) $(OPTIONAL_LZO_LIBS) \
+ $(SOCKETS_LIBS) $(OPTIONAL_LZO_LIBS) $(OPTIONAL_LZ4_LIBS) \
$(OPTIONAL_PKCS11_HELPER_LIBS) $(OPTIONAL_CRYPTO_LIBS) \
$(OPTIONAL_SELINUX_LIBS) $(OPTIONAL_SYSTEMD_LIBS) \
$(OPTIONAL_DL_LIBS) $(am__append_3)
@@ -487,6 +494,7 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/build/ltrc.inc $(am_
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/openvpn/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/openvpn/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -495,7 +503,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
-$(top_srcdir)/build/ltrc.inc $(am__empty):
+$(top_srcdir)/build/ltrc.inc:
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
@@ -565,13 +573,20 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/argv.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/block_dns.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clinat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/comp-lz4.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/comp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compstub.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/console.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/console_builtin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/console_systemd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_mbedtls.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_openssl.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto_polarssl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cryptoapi.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dhcp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/error.Po@am__quote@
@@ -607,8 +622,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ping.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs11.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs11_mbedtls.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs11_openssl.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs11_polarssl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/platform.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool.Po@am__quote@
@@ -625,12 +640,13 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socks.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssl_mbedtls.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssl_openssl.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssl_polarssl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssl_verify.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssl_verify_mbedtls.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssl_verify_openssl.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssl_verify_polarssl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tls_crypt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tun.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/win32.Po@am__quote@
@@ -639,14 +655,14 @@ distclean-compile:
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -868,8 +884,6 @@ uninstall-am: uninstall-sbinPROGRAMS
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS
-.PRECIOUS: Makefile
-
.rc.lo:
$(LTRCCOMPILE) -i "$<" -o "$@"
diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c
new file mode 100644
index 0000000..596e59c
--- /dev/null
+++ b/src/openvpn/argv.c
@@ -0,0 +1,315 @@
+/*
+ * 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-2010 OpenVPN Technologies, Inc. <sales@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
+ *
+ *
+ * A printf-like function (that only recognizes a subset of standard printf
+ * format operators) that prints arguments to an argv list instead
+ * of a standard string. This is used to build up argv arrays for passing
+ * to execve.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#include "argv.h"
+#include "options.h"
+
+static void
+argv_init (struct argv *a)
+{
+ a->capacity = 0;
+ a->argc = 0;
+ a->argv = NULL;
+}
+
+struct argv
+argv_new (void)
+{
+ struct argv ret;
+ argv_init (&ret);
+ return ret;
+}
+
+void
+argv_reset (struct argv *a)
+{
+ size_t i;
+ for (i = 0; i < a->argc; ++i)
+ free (a->argv[i]);
+ free (a->argv);
+ argv_init (a);
+}
+
+static void
+argv_extend (struct argv *a, const size_t newcap)
+{
+ if (newcap > a->capacity)
+ {
+ char **newargv;
+ size_t i;
+ ALLOC_ARRAY_CLEAR (newargv, char *, newcap);
+ for (i = 0; i < a->argc; ++i)
+ newargv[i] = a->argv[i];
+ free (a->argv);
+ a->argv = newargv;
+ a->capacity = newcap;
+ }
+}
+
+static void
+argv_grow (struct argv *a, const size_t add)
+{
+ const size_t newargc = a->argc + add + 1;
+ ASSERT (newargc > a->argc);
+ argv_extend (a, adjust_power_of_2 (newargc));
+}
+
+static void
+argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */
+{
+ argv_grow (a, 1);
+ a->argv[a->argc++] = str;
+}
+
+static struct argv
+argv_clone (const struct argv *a, const size_t headroom)
+{
+ struct argv r;
+ size_t i;
+
+ argv_init (&r);
+ for (i = 0; i < headroom; ++i)
+ argv_append (&r, NULL);
+ if (a)
+ {
+ for (i = 0; i < a->argc; ++i)
+ argv_append (&r, string_alloc (a->argv[i], NULL));
+ }
+ return r;
+}
+
+struct argv
+argv_insert_head (const struct argv *a, const char *head)
+{
+ struct argv r;
+ r = argv_clone (a, 1);
+ r.argv[0] = string_alloc (head, NULL);
+ return r;
+}
+
+static char *
+argv_term (const char **f)
+{
+ const char *p = *f;
+ const char *term = NULL;
+ size_t termlen = 0;
+
+ if (*p == '\0')
+ return NULL;
+
+ while (true)
+ {
+ const int c = *p;
+ if (c == '\0')
+ break;
+ if (term)
+ {
+ if (!isspace (c))
+ ++termlen;
+ else
+ break;
+ }
+ else
+ {
+ if (!isspace (c))
+ {
+ term = p;
+ termlen = 1;
+ }
+ }
+ ++p;
+ }
+ *f = p;
+
+ if (term)
+ {
+ char *ret;
+ ASSERT (termlen > 0);
+ ret = malloc (termlen + 1);
+ check_malloc_return (ret);
+ memcpy (ret, term, termlen);
+ ret[termlen] = '\0';
+ return ret;
+ }
+ else
+ return NULL;
+}
+
+const char *
+argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
+{
+ if (a->argv)
+ return print_argv ((const char **)a->argv, gc, flags);
+ else
+ return "";
+}
+
+void
+argv_msg (const int msglev, const struct argv *a)
+{
+ struct gc_arena gc = gc_new ();
+ msg (msglev, "%s", argv_str (a, &gc, 0));
+ gc_free (&gc);
+}
+
+void
+argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
+{
+ struct gc_arena gc = gc_new ();
+ msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
+ gc_free (&gc);
+}
+
+static void
+argv_printf_arglist (struct argv *a, const char *format, va_list arglist)
+{
+ char *term;
+ const char *f = format;
+
+ argv_extend (a, 1); /* ensure trailing NULL */
+
+ while ((term = argv_term (&f)) != NULL)
+ {
+ if (term[0] == '%')
+ {
+ if (!strcmp (term, "%s"))
+ {
+ char *s = va_arg (arglist, char *);
+ if (!s)
+ s = "";
+ argv_append (a, string_alloc (s, NULL));
+ }
+ else if (!strcmp (term, "%d"))
+ {
+ char numstr[64];
+ openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
+ argv_append (a, string_alloc (numstr, NULL));
+ }
+ else if (!strcmp (term, "%u"))
+ {
+ char numstr[64];
+ openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
+ argv_append (a, string_alloc (numstr, NULL));
+ }
+ else if (!strcmp (term, "%s/%d"))
+ {
+ char numstr[64];
+ char *s = va_arg (arglist, char *);
+
+ if (!s)
+ s = "";
+
+ openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
+
+ {
+ const size_t len = strlen(s) + strlen(numstr) + 2;
+ char *combined = (char *) malloc (len);
+ check_malloc_return (combined);
+
+ strcpy (combined, s);
+ strcat (combined, "/");
+ strcat (combined, numstr);
+ argv_append (a, combined);
+ }
+ }
+ else if (!strcmp (term, "%s%sc"))
+ {
+ char *s1 = va_arg (arglist, char *);
+ char *s2 = va_arg (arglist, char *);
+ char *combined;
+
+ if (!s1) s1 = "";
+ if (!s2) s2 = "";
+ combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
+ check_malloc_return (combined);
+ strcpy (combined, s1);
+ strcat (combined, s2);
+ argv_append (a, combined);
+ }
+ else
+ ASSERT (0);
+ free (term);
+ }
+ else
+ {
+ argv_append (a, term);
+ }
+ }
+}
+
+void
+argv_printf (struct argv *a, const char *format, ...)
+{
+ va_list arglist;
+ argv_reset (a);
+ va_start (arglist, format);
+ argv_printf_arglist (a, format, arglist);
+ va_end (arglist);
+ }
+
+void
+argv_printf_cat (struct argv *a, const char *format, ...)
+{
+ va_list arglist;
+ va_start (arglist, format);
+ argv_printf_arglist (a, format, arglist);
+ va_end (arglist);
+}
+
+void
+argv_parse_cmd (struct argv *a, const char *s)
+{
+ int nparms;
+ char *parms[MAX_PARMS + 1];
+ struct gc_arena gc = gc_new ();
+
+ argv_reset (a);
+ argv_extend (a, 1); /* ensure trailing NULL */
+
+ nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
+ if (nparms)
+ {
+ int i;
+ for (i = 0; i < nparms; ++i)
+ argv_append (a, string_alloc (parms[i], NULL));
+ }
+ else
+ argv_append (a, string_alloc (s, NULL));
+
+ gc_free (&gc);
+}
diff --git a/src/openvpn/argv.h b/src/openvpn/argv.h
new file mode 100644
index 0000000..9aee641
--- /dev/null
+++ b/src/openvpn/argv.h
@@ -0,0 +1,70 @@
+/*
+ * 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-2010 OpenVPN Technologies, Inc. <sales@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
+ *
+ *
+ * A printf-like function (that only recognizes a subset of standard printf
+ * format operators) that prints arguments to an argv list instead
+ * of a standard string. This is used to build up argv arrays for passing
+ * to execve.
+ */
+
+#ifndef ARGV_H
+#define ARGV_H
+
+#include "buffer.h"
+
+struct argv {
+ size_t capacity;
+ size_t argc;
+ char **argv;
+};
+
+struct argv argv_new (void);
+void argv_reset (struct argv *a);
+const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
+struct argv argv_insert_head (const struct argv *a, const char *head);
+void argv_msg (const int msglev, const struct argv *a);
+void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
+void argv_parse_cmd (struct argv *a, const char *s);
+
+void argv_printf (struct argv *a, const char *format, ...)
+#ifdef __GNUC__
+#if __USE_MINGW_ANSI_STDIO
+ __attribute__ ((format (gnu_printf, 2, 3)))
+#else
+ __attribute__ ((format (__printf__, 2, 3)))
+#endif
+#endif
+ ;
+
+void argv_printf_cat (struct argv *a, const char *format, ...)
+#ifdef __GNUC__
+#if __USE_MINGW_ANSI_STDIO
+ __attribute__ ((format (gnu_printf, 2, 3)))
+#else
+ __attribute__ ((format (__printf__, 2, 3)))
+#endif
+#endif
+ ;
+
+#endif
diff --git a/src/openvpn/base64.c b/src/openvpn/base64.c
index 7dccec2..258b258 100644
--- a/src/openvpn/base64.c
+++ b/src/openvpn/base64.c
@@ -39,8 +39,6 @@
#include "syshead.h"
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY)
-
#include "base64.h"
#include "memdbg.h"
@@ -163,7 +161,3 @@ openvpn_base64_decode(const char *str, void *data, int size)
}
return q - (unsigned char *) data;
}
-
-#else
-static void dummy(void) {}
-#endif /* ENABLE_HTTP_PROXY, ENABLE_PKCS11, ENABLE_CLIENT_CR */
diff --git a/src/openvpn/base64.h b/src/openvpn/base64.h
index 28a9677..92a195a 100644
--- a/src/openvpn/base64.h
+++ b/src/openvpn/base64.h
@@ -34,11 +34,7 @@
#ifndef _BASE64_H_
#define _BASE64_H_
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY)
-
int openvpn_base64_encode(const void *data, int size, char **str);
int openvpn_base64_decode(const char *str, void *data, int size);
#endif
-
-#endif
diff --git a/src/openvpn/block_dns.c b/src/openvpn/block_dns.c
new file mode 100644
index 0000000..cb3ce88
--- /dev/null
+++ b/src/openvpn/block_dns.c
@@ -0,0 +1,332 @@
+/*
+ * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * 2015-2016 <iam@valdikss.org.ru>
+ * 2016 Selva Nair <selva.nair@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+#ifdef HAVE_CONFIG_VERSION_H
+#include "config-version.h"
+#endif
+
+#include "syshead.h"
+
+#ifdef _WIN32
+
+#include <fwpmu.h>
+#include <initguid.h>
+#include <fwpmtypes.h>
+#include <winsock2.h>
+#include <ws2ipdef.h>
+#include <iphlpapi.h>
+#include "block_dns.h"
+
+/*
+ * WFP-related defines and GUIDs not in mingw32
+ */
+
+#ifndef FWPM_SESSION_FLAG_DYNAMIC
+#define FWPM_SESSION_FLAG_DYNAMIC 0x00000001
+#endif
+
+// c38d57d1-05a7-4c33-904f-7fbceee60e82
+DEFINE_GUID(
+ FWPM_LAYER_ALE_AUTH_CONNECT_V4,
+ 0xc38d57d1,
+ 0x05a7,
+ 0x4c33,
+ 0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82
+);
+
+// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4
+DEFINE_GUID(
+ FWPM_LAYER_ALE_AUTH_CONNECT_V6,
+ 0x4a72393b,
+ 0x319f,
+ 0x44bc,
+ 0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4
+);
+
+// d78e1e87-8644-4ea5-9437-d809ecefc971
+DEFINE_GUID(
+ FWPM_CONDITION_ALE_APP_ID,
+ 0xd78e1e87,
+ 0x8644,
+ 0x4ea5,
+ 0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71
+);
+
+// c35a604d-d22b-4e1a-91b4-68f674ee674b
+DEFINE_GUID(
+ FWPM_CONDITION_IP_REMOTE_PORT,
+ 0xc35a604d,
+ 0xd22b,
+ 0x4e1a,
+ 0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b
+);
+
+// 4cd62a49-59c3-4969-b7f3-bda5d32890a4
+DEFINE_GUID(
+ FWPM_CONDITION_IP_LOCAL_INTERFACE,
+ 0x4cd62a49,
+ 0x59c3,
+ 0x4969,
+ 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4
+);
+
+/* UUID of WFP sublayer used by all instances of openvpn
+ 2f660d7e-6a37-11e6-a181-001e8c6e04a2 */
+DEFINE_GUID(
+ OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER,
+ 0x2f660d7e,
+ 0x6a37,
+ 0x11e6,
+ 0xa1, 0x81, 0x00, 0x1e, 0x8c, 0x6e, 0x04, 0xa2
+);
+
+static WCHAR *FIREWALL_NAME = L"OpenVPN";
+
+/*
+ * Default msg handler does nothing
+ */
+static inline void
+default_msg_handler (DWORD err, const char *msg)
+{
+ return;
+}
+
+#define CHECK_ERROR(err, msg) \
+ if (err) { msg_handler (err, msg); goto out; }
+
+/*
+ * Add a persistent sublayer with specified uuid.
+ */
+static DWORD
+add_sublayer (GUID uuid)
+{
+ FWPM_SESSION0 session;
+ HANDLE engine = NULL;
+ DWORD err = 0;
+ FWPM_SUBLAYER0 sublayer;
+
+ memset (&session, 0, sizeof(session));
+ memset (&sublayer, 0, sizeof(sublayer));
+
+ err = FwpmEngineOpen0 (NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engine);
+ if (err != ERROR_SUCCESS)
+ goto out;
+
+ sublayer.subLayerKey = uuid;
+ sublayer.displayData.name = FIREWALL_NAME;
+ sublayer.displayData.description = FIREWALL_NAME;
+ sublayer.flags = 0;
+ sublayer.weight = 0x100;
+
+ /* Add sublayer to the session */
+ err = FwpmSubLayerAdd0 (engine, &sublayer, NULL);
+
+out:
+ if (engine)
+ FwpmEngineClose0 (engine);
+ return err;
+}
+
+/*
+ * Block outgoing port 53 traffic except for
+ * (i) adapter with the specified index
+ * OR
+ * (ii) processes with the specified executable path
+ * The firewall filters added here are automatically removed when the process exits or
+ * on calling delete_block_dns_filters().
+ * Arguments:
+ * engine_handle : On successful return contains the handle for a newly opened fwp session
+ * in which the filters are added.
+ * May be closed by passing to delete_block_dns_filters to remove the filters.
+ * index : The index of adapter for which traffic is permitted.
+ * exe_path : Path of executable for which traffic is permitted.
+ * msg_handler : An optional callback function for error reporting.
+ * Returns 0 on success, a non-zero status code of the last failed action on failure.
+ */
+
+DWORD
+add_block_dns_filters (HANDLE *engine_handle,
+ int index,
+ const WCHAR *exe_path,
+ block_dns_msg_handler_t msg_handler
+ )
+{
+ FWPM_SESSION0 session = {0};
+ FWPM_SUBLAYER0 *sublayer_ptr = NULL;
+ NET_LUID tapluid;
+ UINT64 filterid;
+ FWP_BYTE_BLOB *openvpnblob = NULL;
+ FWPM_FILTER0 Filter = {0};
+ FWPM_FILTER_CONDITION0 Condition[2] = {0};
+ DWORD err = 0;
+
+ if (!msg_handler)
+ msg_handler = default_msg_handler;
+
+ /* Add temporary filters which don't survive reboots or crashes. */
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ *engine_handle = NULL;
+
+ err = FwpmEngineOpen0 (NULL, RPC_C_AUTHN_WINNT, NULL, &session, engine_handle);
+ CHECK_ERROR (err, "FwpEngineOpen: open fwp session failed");
+ msg_handler (0, "Block_DNS: WFP engine opened");
+
+ /* Check sublayer exists and add one if it does not. */
+ if (FwpmSubLayerGetByKey0 (*engine_handle, &OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER, &sublayer_ptr)
+ == ERROR_SUCCESS)
+ {
+ msg_handler (0, "Block_DNS: Using existing sublayer");
+ FwpmFreeMemory0 ((void **)&sublayer_ptr);
+ }
+ else
+ { /* Add a new sublayer -- as another process may add it in the meantime,
+ do not treat "already exists" as an error */
+ err = add_sublayer (OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER);
+
+ if (err == FWP_E_ALREADY_EXISTS || err == ERROR_SUCCESS)
+ msg_handler (0, "Block_DNS: Added a persistent sublayer with pre-defined UUID");
+ else
+ CHECK_ERROR (err, "add_sublayer: failed to add persistent sublayer");
+ }
+
+ err = ConvertInterfaceIndexToLuid (index, &tapluid);
+ CHECK_ERROR (err, "Convert interface index to luid failed");
+
+ err = FwpmGetAppIdFromFileName0 (exe_path, &openvpnblob);
+ CHECK_ERROR (err, "Get byte blob for openvpn executable name failed");
+
+ /* Prepare filter. */
+ Filter.subLayerKey = OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER;
+ Filter.displayData.name = FIREWALL_NAME;
+ Filter.weight.type = FWP_UINT8;
+ Filter.weight.uint8 = 0xF;
+ Filter.filterCondition = Condition;
+ Filter.numFilterConditions = 2;
+
+ /* First filter. Permit IPv4 DNS queries from OpenVPN itself. */
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
+ Filter.action.type = FWP_ACTION_PERMIT;
+
+ Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
+ Condition[0].matchType = FWP_MATCH_EQUAL;
+ Condition[0].conditionValue.type = FWP_UINT16;
+ Condition[0].conditionValue.uint16 = 53;
+
+ Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID;
+ Condition[1].matchType = FWP_MATCH_EQUAL;
+ Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE;
+ Condition[1].conditionValue.byteBlob = openvpnblob;
+
+ err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid);
+ CHECK_ERROR (err, "Add filter to permit IPv4 port 53 traffic from OpenVPN failed");
+
+ /* Second filter. Permit IPv6 DNS queries from OpenVPN itself. */
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
+
+ err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid);
+ CHECK_ERROR (err, "Add filter to permit IPv6 port 53 traffic from OpenVPN failed");
+
+ msg_handler (0, "Block_DNS: Added permit filters for exe_path");
+
+ /* Third filter. Block all IPv4 DNS queries. */
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
+ Filter.action.type = FWP_ACTION_BLOCK;
+ Filter.weight.type = FWP_EMPTY;
+ Filter.numFilterConditions = 1;
+
+ err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid);
+ CHECK_ERROR (err, "Add filter to block IPv4 DNS traffic failed");
+
+ /* Forth filter. Block all IPv6 DNS queries. */
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
+
+ err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid);
+ CHECK_ERROR (err, "Add filter to block IPv6 DNS traffic failed");
+
+ msg_handler (0, "Block_DNS: Added block filters for all interfaces");
+
+ /* Fifth filter. Permit IPv4 DNS queries from TAP.
+ * Use a non-zero weight so that the permit filters get higher priority
+ * over the block filter added with automatic weighting */
+
+ Filter.weight.type = FWP_UINT8;
+ Filter.weight.uint8 = 0xE;
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
+ Filter.action.type = FWP_ACTION_PERMIT;
+ Filter.numFilterConditions = 2;
+
+ Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE;
+ Condition[1].matchType = FWP_MATCH_EQUAL;
+ Condition[1].conditionValue.type = FWP_UINT64;
+ Condition[1].conditionValue.uint64 = &tapluid.Value;
+
+ err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid);
+ CHECK_ERROR (err, "Add filter to permit IPv4 DNS traffic through TAP failed");
+
+ /* Sixth filter. Permit IPv6 DNS queries from TAP.
+ * Use same weight as IPv4 filter */
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
+
+ err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid);
+ CHECK_ERROR (err, "Add filter to permit IPv6 DNS traffic through TAP failed");
+
+ msg_handler (0, "Block_DNS: Added permit filters for TAP interface");
+
+out:
+
+ if (openvpnblob)
+ FwpmFreeMemory0 ((void **)&openvpnblob);
+
+ if (err && *engine_handle)
+ {
+ FwpmEngineClose0 (*engine_handle);
+ *engine_handle = NULL;
+ }
+
+ return err;
+}
+
+DWORD
+delete_block_dns_filters (HANDLE engine_handle)
+{
+ DWORD err = 0;
+ /*
+ * For dynamic sessions closing the engine removes all filters added in the session
+ */
+ if (engine_handle)
+ {
+ err = FwpmEngineClose0(engine_handle);
+ }
+ return err;
+}
+
+#endif
diff --git a/src/openvpn/block_dns.h b/src/openvpn/block_dns.h
new file mode 100644
index 0000000..f8b6d4f
--- /dev/null
+++ b/src/openvpn/block_dns.h
@@ -0,0 +1,40 @@
+/*
+ * 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) 2016 Selva Nair <selva.nair@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef _WIN32
+
+#ifndef OPENVPN_BLOCK_DNS_H
+#define OPENVPN_BLOCK_DNS_H
+
+typedef void (*block_dns_msg_handler_t) (DWORD err, const char *msg);
+
+DWORD
+delete_block_dns_filters (HANDLE engine);
+
+DWORD
+add_block_dns_filters (HANDLE *engine, int iface_index, const WCHAR *exe_path,
+ block_dns_msg_handler_t msg_handler_callback);
+
+#endif
+#endif
diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c
index fb3b52d..52c6ab9 100644
--- a/src/openvpn/buffer.c
+++ b/src/openvpn/buffer.c
@@ -254,7 +254,7 @@ buf_puts(struct buffer *buf, const char *str)
*
* Return false on overflow.
*
- * This function is duplicated into service-win32/openvpnserv.c
+ * This functionality is duplicated in src/openvpnserv/common.c
* Any modifications here should be done to the other place as well.
*/
@@ -372,6 +372,44 @@ x_gc_free (struct gc_arena *a)
}
/*
+ * Functions to handle special objects in gc_entries
+ */
+
+void
+x_gc_freespecial (struct gc_arena *a)
+{
+ struct gc_entry_special *e;
+ e = a->list_special;
+ a->list_special = NULL;
+
+ while (e != NULL)
+ {
+ struct gc_entry_special *next = e->next;
+ e->free_fnc (e->addr);
+ free(e);
+ e = next;
+ }
+}
+
+void gc_addspecial (void *addr, void (free_function)(void*), struct gc_arena *a)
+{
+ ASSERT(a);
+ struct gc_entry_special *e;
+#ifdef DMALLOC
+ e = (struct gc_entry_special *) openvpn_dmalloc (file, line, sizeof (struct gc_entry_special));
+#else
+ e = (struct gc_entry_special *) malloc (sizeof (struct gc_entry_special));
+#endif
+ check_malloc_return (e);
+ e->free_fnc = free_function;
+ e->addr = addr;
+
+ e->next = a->list_special;
+ a->list_special = e;
+}
+
+
+/*
* Transfer src arena to dest, resetting src to an empty arena.
*/
void
@@ -397,18 +435,21 @@ gc_transfer (struct gc_arena *dest, struct gc_arena *src)
char *
format_hex_ex (const uint8_t *data, int size, int maxoutput,
- int space_break, const char* separator,
+ unsigned int space_break_flags, const char* separator,
struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (maxoutput ? maxoutput :
- ((size * 2) + (size / space_break) * (int) strlen (separator) + 2),
+ ((size * 2) + (size / (space_break_flags & FHE_SPACE_BREAK_MASK)) * (int) strlen (separator) + 2),
gc);
int i;
for (i = 0; i < size; ++i)
{
- if (separator && i && !(i % space_break))
+ if (separator && i && !(i % (space_break_flags & FHE_SPACE_BREAK_MASK)))
buf_printf (&out, "%s", separator);
- buf_printf (&out, "%02x", data[i]);
+ if (space_break_flags & FHE_CAPS)
+ buf_printf (&out, "%02X", data[i]);
+ else
+ buf_printf (&out, "%02x", data[i]);
}
buf_catrunc (&out, "[more...]");
return (char *)out.data;
@@ -938,9 +979,6 @@ valign4 (const struct buffer *buf, const char *file, const int line)
/*
* struct buffer_list
*/
-
-#ifdef ENABLE_BUFFER_LIST
-
struct buffer_list *
buffer_list_new (const int max_size)
{
@@ -1031,8 +1069,10 @@ buffer_list_peek (struct buffer_list *ol)
}
void
-buffer_list_aggregate (struct buffer_list *bl, const size_t max)
+buffer_list_aggregate_separator (struct buffer_list *bl, const size_t max, const char *sep)
{
+ int sep_len = strlen(sep);
+
if (bl->head)
{
struct buffer_entry *more = bl->head;
@@ -1040,7 +1080,7 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max)
int count = 0;
for (count = 0; more && size <= max; ++count)
{
- size += BLEN(&more->buf);
+ size += BLEN(&more->buf) + sep_len;
more = more->next;
}
@@ -1057,6 +1097,7 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max)
{
struct buffer_entry *next = e->next;
buf_copy (&f->buf, &e->buf);
+ buf_write(&f->buf, sep, sep_len);
free_buf (&e->buf);
free (e);
e = next;
@@ -1070,6 +1111,12 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max)
}
void
+buffer_list_aggregate (struct buffer_list *bl, const size_t max)
+{
+ buffer_list_aggregate_separator(bl, max, "");
+}
+
+void
buffer_list_pop (struct buffer_list *ol)
{
if (ol && ol->head)
@@ -1116,5 +1163,3 @@ buffer_list_file (const char *fn, int max_line_len)
}
return bl;
}
-
-#endif
diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h
index 58f0601..8070439 100644
--- a/src/openvpn/buffer.h
+++ b/src/openvpn/buffer.h
@@ -91,6 +91,18 @@ struct gc_entry
* linked list. */
};
+/**
+ * Gargabe collection entry for a specially allocated structure that needs
+ * a custom free function to be freed like struct addrinfo
+ *
+ */
+struct gc_entry_special
+{
+ struct gc_entry_special *next;
+ void (*free_fnc)(void*);
+ void *addr;
+};
+
/**
* Garbage collection arena used to keep track of dynamically allocated
@@ -106,6 +118,7 @@ struct gc_arena
{
struct gc_entry *list; /**< First element of the linked list of
* \c gc_entry structures. */
+ struct gc_entry_special *list_special;
};
@@ -163,6 +176,9 @@ struct buffer string_alloc_buf (const char *str, struct gc_arena *gc);
#endif
+void gc_addspecial (void *addr, void (*free_function)(void*), struct gc_arena *a);
+
+
#ifdef BUF_INIT_TRACKING
#define buf_init(buf, offset) buf_init_debug (buf, offset, __FILE__, __LINE__)
bool buf_init_debug (struct buffer *buf, int offset, const char *file, int line);
@@ -172,6 +188,11 @@ bool buf_init_debug (struct buffer *buf, int offset, const char *file, int line)
/* inline functions */
+inline static void
+gc_freeaddrinfo_callback (void *addr)
+{
+ freeaddrinfo((struct addrinfo*) addr);
+}
static inline bool
buf_defined (const struct buffer *buf)
@@ -382,9 +403,11 @@ bool buf_parse (struct buffer *buf, const int delim, char *line, const int size)
/*
* Hex dump -- Output a binary buffer to a hex string and return it.
*/
+#define FHE_SPACE_BREAK_MASK 0xFF /* space_break parameter in lower 8 bits */
+#define FHE_CAPS 0x100 /* output hex in caps */
char *
format_hex_ex (const uint8_t *data, int size, int maxoutput,
- int space_break, const char* separator,
+ unsigned int space_break_flags, const char* separator,
struct gc_arena *gc);
static inline char *
@@ -781,6 +804,7 @@ void character_class_debug (void);
void gc_transfer (struct gc_arena *dest, struct gc_arena *src);
void x_gc_free (struct gc_arena *a);
+void x_gc_freespecial (struct gc_arena *a);
static inline bool
gc_defined (struct gc_arena *a)
@@ -792,6 +816,7 @@ static inline void
gc_init (struct gc_arena *a)
{
a->list = NULL;
+ a->list_special = NULL;
}
static inline void
@@ -804,7 +829,7 @@ static inline struct gc_arena
gc_new (void)
{
struct gc_arena ret;
- ret.list = NULL;
+ gc_init (&ret);
return ret;
}
@@ -813,6 +838,8 @@ gc_free (struct gc_arena *a)
{
if (a->list)
x_gc_free (a);
+ if (a->list_special)
+ x_gc_freespecial(a);
}
static inline void
@@ -882,9 +909,6 @@ check_malloc_return (const void *p)
/*
* Manage lists of buffers
*/
-
-#ifdef ENABLE_BUFFER_LIST
-
struct buffer_entry
{
struct buffer buf;
@@ -912,9 +936,7 @@ void buffer_list_advance (struct buffer_list *ol, int n);
void buffer_list_pop (struct buffer_list *ol);
void buffer_list_aggregate (struct buffer_list *bl, const size_t max);
+void buffer_list_aggregate_separator (struct buffer_list *bl, const size_t max, const char *sep);
struct buffer_list *buffer_list_file (const char *fn, int max_line_len);
-
-#endif
-
#endif /* BUFFER_H */
diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c
index af75fc9..ddefe12 100644
--- a/src/openvpn/clinat.c
+++ b/src/openvpn/clinat.c
@@ -30,8 +30,6 @@
#include "syshead.h"
-#if defined(ENABLE_CLIENT_NAT)
-
#include "clinat.h"
#include "proto.h"
#include "socket.h"
@@ -265,5 +263,3 @@ client_nat_transform (const struct client_nat_option_list *list,
}
}
}
-
-#endif
diff --git a/src/openvpn/clinat.h b/src/openvpn/clinat.h
index d55a727..a5779e1 100644
--- a/src/openvpn/clinat.h
+++ b/src/openvpn/clinat.h
@@ -22,7 +22,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#if !defined(CLINAT_H) && defined(ENABLE_CLIENT_NAT)
+#if !defined(CLINAT_H)
#define CLINAT_H
#include "buffer.h"
diff --git a/src/openvpn/common.h b/src/openvpn/common.h
index 2f85bec..1134101 100644
--- a/src/openvpn/common.h
+++ b/src/openvpn/common.h
@@ -30,7 +30,7 @@
*/
#ifdef USE_64_BIT_COUNTERS
typedef unsigned long long int counter_type;
-# ifdef WIN32
+# ifdef _WIN32
# define counter_format "%I64u"
# else
# define counter_format "%llu"
diff --git a/src/openvpn/comp-lz4.c b/src/openvpn/comp-lz4.c
new file mode 100644
index 0000000..395f3d2
--- /dev/null
+++ b/src/openvpn/comp-lz4.c
@@ -0,0 +1,307 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2013 Gert Doering <gert@greenie.muc.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(ENABLE_LZ4)
+
+#if defined(NEED_COMPAT_LZ4)
+#include "compat-lz4.h"
+#else
+#include "lz4.h"
+#endif
+
+#include "comp.h"
+#include "error.h"
+
+#include "memdbg.h"
+
+static void
+lz4_compress_init (struct compress_context *compctx)
+{
+ msg (D_INIT_MEDIUM, "LZ4 compression initializing");
+ ASSERT(compctx->flags & COMP_F_SWAP);
+}
+
+static void
+lz4v2_compress_init (struct compress_context *compctx)
+{
+ msg (D_INIT_MEDIUM, "LZ4v2 compression initializing");
+}
+
+static void
+lz4_compress_uninit (struct compress_context *compctx)
+{
+}
+
+static bool
+do_lz4_compress (struct buffer *buf,
+ struct buffer *work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ /*
+ * In order to attempt compression, length must be at least COMPRESS_THRESHOLD.
+ */
+ if (buf->len >= COMPRESS_THRESHOLD)
+ {
+ const size_t ps = PAYLOAD_SIZE (frame);
+ int zlen_max = ps + COMP_EXTRA_BUFFER (ps);
+ int zlen;
+
+ ASSERT (buf_init (work, FRAME_HEADROOM (frame)));
+ ASSERT (buf_safe (work, zlen_max));
+
+ if (buf->len > ps)
+ {
+ dmsg (D_COMP_ERRORS, "LZ4 compression buffer overflow");
+ buf->len = 0;
+ return false;
+ }
+
+ zlen = LZ4_compress_limitedOutput((const char *)BPTR(buf), (char *)BPTR(work), BLEN(buf), zlen_max );
+
+ if (zlen <= 0)
+ {
+ dmsg (D_COMP_ERRORS, "LZ4 compression error");
+ buf->len = 0;
+ return false;
+ }
+
+ ASSERT (buf_safe (work, zlen));
+ work->len = zlen;
+
+
+ dmsg (D_COMP, "LZ4 compress %d -> %d", buf->len, work->len);
+ compctx->pre_compress += buf->len;
+ compctx->post_compress += work->len;
+ return true;
+ }
+ return false;
+}
+
+
+static void
+lz4_compress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ bool compressed;
+ if (buf->len <= 0)
+ return;
+
+ compressed = do_lz4_compress(buf, &work, compctx, frame);
+
+ /* On error do_lz4_compress sets buf len to zero, just return */
+ if (buf->len == 0)
+ return;
+
+ /* did compression save us anything? */
+ {
+ uint8_t comp_head_byte = NO_COMPRESS_BYTE_SWAP;
+ if (compressed && work.len < buf->len)
+ {
+ *buf = work;
+ comp_head_byte = LZ4_COMPRESS_BYTE;
+ }
+
+ {
+ uint8_t *head = BPTR (buf);
+ uint8_t *tail = BEND (buf);
+ ASSERT (buf_safe (buf, 1));
+ ++buf->len;
+
+ /* move head byte of payload to tail */
+ *tail = *head;
+ *head = comp_head_byte;
+ }
+ }
+}
+
+
+static void
+lz4v2_compress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ bool compressed;
+ if (buf->len <= 0)
+ return;
+
+ compressed = do_lz4_compress(buf, &work, compctx, frame);
+
+ /* On Error just return */
+ if (buf->len == 0)
+ return;
+
+ /* did compression save us anything? Include 2 byte compression header
+ in calculation */
+ if (compressed && work.len + 2 < buf->len)
+ {
+ ASSERT(buf_prepend(&work, 2));
+ uint8_t *head = BPTR (&work);
+ head[0] = COMP_ALGV2_INDICATOR_BYTE;
+ head[1] = COMP_ALGV2_LZ4_BYTE;
+ *buf = work;
+ }
+ else
+ {
+ compv2_escape_data_ifneeded(buf);
+ }
+}
+
+void
+do_lz4_decompress(size_t zlen_max,
+ struct buffer *work,
+ struct buffer *buf,
+ struct compress_context *compctx)
+{
+ int uncomp_len;
+ ASSERT (buf_safe (work, zlen_max));
+ uncomp_len = LZ4_decompress_safe((const char *)BPTR(buf), (char *)BPTR(work), (size_t)BLEN(buf), zlen_max);
+ if (uncomp_len <= 0)
+ {
+ dmsg (D_COMP_ERRORS, "LZ4 decompression error: %d", uncomp_len);
+ buf->len = 0;
+ return;
+ }
+
+ ASSERT (buf_safe (work, uncomp_len));
+ work->len = uncomp_len;
+
+ dmsg (D_COMP, "LZ4 decompress %d -> %d", buf->len, work->len);
+ compctx->pre_decompress += buf->len;
+ compctx->post_decompress += work->len;
+
+ *buf = *work;
+}
+
+static void
+lz4_decompress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ size_t zlen_max = EXPANDED_SIZE (frame);
+ uint8_t c; /* flag indicating whether or not our peer compressed */
+
+ if (buf->len <= 0)
+ return;
+
+ ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
+
+ /* do unframing/swap (assumes buf->len > 0) */
+ {
+ uint8_t *head = BPTR (buf);
+ c = *head;
+ --buf->len;
+ *head = *BEND (buf);
+ }
+
+ if (c == LZ4_COMPRESS_BYTE) /* packet was compressed */
+ {
+ do_lz4_decompress(zlen_max, &work, buf, compctx);
+ }
+ else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */
+ {
+ ;
+ }
+ else
+ {
+ dmsg (D_COMP_ERRORS, "Bad LZ4 decompression header byte: %d", c);
+ buf->len = 0;
+ }
+}
+
+static void
+lz4v2_decompress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ size_t zlen_max = EXPANDED_SIZE (frame);
+ uint8_t c; /* flag indicating whether or not our peer compressed */
+
+ if (buf->len <= 0)
+ return;
+
+ ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
+
+ /* do unframing/swap (assumes buf->len > 0) */
+ uint8_t *head = BPTR (buf);
+ c = *head;
+
+ /* Not compressed */
+ if (c != COMP_ALGV2_INDICATOR_BYTE) {
+ return;
+ }
+
+ /* Packet to short to make sense */
+ if (buf->len <= 1)
+ {
+ buf->len=0;
+ return;
+ }
+
+ c = head[1];
+ if (c == COMP_ALGV2_LZ4_BYTE) /* packet was compressed */
+ {
+ buf_advance(buf,2);
+ do_lz4_decompress(zlen_max, &work, buf, compctx);
+ }
+ else if (c == COMP_ALGV2_UNCOMPRESSED_BYTE)
+ {
+ buf_advance(buf,2);
+ }
+ else
+ {
+ dmsg (D_COMP_ERRORS, "Bad LZ4v2 decompression header byte: %d", c);
+ buf->len = 0;
+ }
+}
+
+const struct compress_alg lz4_alg = {
+ "lz4",
+ lz4_compress_init,
+ lz4_compress_uninit,
+ lz4_compress,
+ lz4_decompress
+};
+
+const struct compress_alg lz4v2_alg = {
+ "lz4v2",
+ lz4v2_compress_init,
+ lz4_compress_uninit,
+ lz4v2_compress,
+ lz4v2_decompress
+};
+
+#else
+static void dummy(void) {}
+#endif /* ENABLE_LZ4 */
diff --git a/src/openvpn/comp-lz4.h b/src/openvpn/comp-lz4.h
new file mode 100644
index 0000000..7774ca5
--- /dev/null
+++ b/src/openvpn/comp-lz4.h
@@ -0,0 +1,42 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2013 Gert Doering <gert@greenie.muc.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef OPENVPN_COMP_LZ4_H
+#define OPENVPN_COMP_LZ4_H
+
+#if defined(ENABLE_LZ4)
+
+#include "buffer.h"
+
+extern const struct compress_alg lz4_alg;
+extern const struct compress_alg lz4v2_alg;
+
+struct lz4_workspace
+{
+ int dummy;
+};
+
+#endif /* ENABLE_LZ4 */
+#endif
diff --git a/src/openvpn/comp.c b/src/openvpn/comp.c
new file mode 100644
index 0000000..499fef9
--- /dev/null
+++ b/src/openvpn/comp.c
@@ -0,0 +1,167 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#ifdef USE_COMP
+
+#include "comp.h"
+#include "error.h"
+#include "otime.h"
+
+#include "memdbg.h"
+
+struct compress_context *
+comp_init(const struct compress_options *opt)
+{
+ struct compress_context *compctx = NULL;
+ switch (opt->alg)
+ {
+ case COMP_ALG_STUB:
+ ALLOC_OBJ_CLEAR (compctx, struct compress_context);
+ compctx->flags = opt->flags;
+ compctx->alg = comp_stub_alg;
+ break;
+ case COMP_ALGV2_UNCOMPRESSED:
+ ALLOC_OBJ_CLEAR (compctx, struct compress_context);
+ compctx->flags = opt->flags;
+ compctx->alg = compv2_stub_alg;
+ break;
+#ifdef ENABLE_LZO
+ case COMP_ALG_LZO:
+ ALLOC_OBJ_CLEAR (compctx, struct compress_context);
+ compctx->flags = opt->flags;
+ compctx->alg = lzo_alg;
+ break;
+#endif
+#ifdef ENABLE_LZ4
+ case COMP_ALG_LZ4:
+ ALLOC_OBJ_CLEAR (compctx, struct compress_context);
+ compctx->flags = opt->flags;
+ compctx->alg = lz4_alg;
+ break;
+ case COMP_ALGV2_LZ4:
+ ALLOC_OBJ_CLEAR (compctx, struct compress_context);
+ compctx->flags = opt->flags;
+ compctx->alg = lz4v2_alg;
+ break;
+#endif
+ }
+ if (compctx)
+ (*compctx->alg.compress_init)(compctx);
+
+ return compctx;
+}
+
+/* In the v2 compression schemes, an uncompressed packet has
+ * has no opcode in front, unless the first byte is 0x50. In this
+ * case the packet needs to be escaped */
+void
+compv2_escape_data_ifneeded (struct buffer *buf)
+{
+ uint8_t *head = BPTR (buf);
+ if (head[0] != COMP_ALGV2_INDICATOR_BYTE)
+ return;
+
+ /* Header is 0x50 */
+ ASSERT(buf_prepend(buf, 2));
+
+ head = BPTR (buf);
+ head[0] = COMP_ALGV2_INDICATOR_BYTE;
+ head[1] = COMP_ALGV2_UNCOMPRESSED;
+}
+
+
+void
+comp_uninit(struct compress_context *compctx)
+{
+ if (compctx)
+ {
+ (*compctx->alg.compress_uninit)(compctx);
+ free(compctx);
+ }
+}
+
+void
+comp_add_to_extra_frame(struct frame *frame)
+{
+ /* Leave room for our one-byte compressed/didn't-compress prefix byte. */
+ frame_add_to_extra_frame (frame, COMP_PREFIX_LEN);
+}
+
+void
+comp_add_to_extra_buffer(struct frame *frame)
+{
+ /* Leave room for compression buffer to expand in worst case scenario
+ where data is totally uncompressible */
+ frame_add_to_extra_buffer (frame, COMP_EXTRA_BUFFER (EXPANDED_SIZE(frame)));
+}
+
+void
+comp_print_stats (const struct compress_context *compctx, struct status_output *so)
+{
+ if (compctx)
+ {
+ status_printf (so, "pre-compress bytes," counter_format, compctx->pre_compress);
+ status_printf (so, "post-compress bytes," counter_format, compctx->post_compress);
+ status_printf (so, "pre-decompress bytes," counter_format, compctx->pre_decompress);
+ status_printf (so, "post-decompress bytes," counter_format, compctx->post_decompress);
+ }
+}
+
+/*
+ * Tell our peer which compression algorithms we support.
+ */
+void
+comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out)
+{
+ if (opt)
+ {
+ bool lzo_avail = false;
+ if (!(opt->flags & COMP_F_ADVERTISE_STUBS_ONLY))
+ {
+#if defined(ENABLE_LZ4)
+ buf_printf (out, "IV_LZ4=1\n");
+ buf_printf (out, "IV_LZ4v2=1\n");
+#endif
+#if defined(ENABLE_LZO)
+ buf_printf (out, "IV_LZO=1\n");
+ lzo_avail = true;
+#endif
+ }
+ if (!lzo_avail)
+ buf_printf (out, "IV_LZO_STUB=1\n");
+ buf_printf (out, "IV_COMP_STUB=1\n");
+ buf_printf (out, "IV_COMP_STUBv2=1\n");
+ buf_printf (out, "IV_TCPNL=1\n");
+ }
+}
+
+#endif /* USE_COMP */
diff --git a/src/openvpn/comp.h b/src/openvpn/comp.h
new file mode 100644
index 0000000..9ed9532
--- /dev/null
+++ b/src/openvpn/comp.h
@@ -0,0 +1,198 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@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
+ */
+
+/*
+ * Generic compression support. Currently we support
+ * LZO 2 and LZ4.
+ */
+#ifndef OPENVPN_COMP_H
+#define OPENVPN_COMP_H
+
+#ifdef USE_COMP
+
+#include "buffer.h"
+#include "mtu.h"
+#include "common.h"
+#include "status.h"
+
+/* algorithms */
+#define COMP_ALG_UNDEF 0
+#define COMP_ALG_STUB 1 /* support compression command byte and framing without actual compression */
+#define COMP_ALG_LZO 2 /* LZO algorithm */
+#define COMP_ALG_SNAPPY 3 /* Snappy algorithm (no longer supported) */
+#define COMP_ALG_LZ4 4 /* LZ4 algorithm */
+
+
+/* algorithm v2 */
+#define COMP_ALGV2_UNCOMPRESSED 10
+#define COMP_ALGV2_LZ4 11
+/*
+#define COMP_ALGV2_LZO 12
+#define COMP_ALGV2_SNAPPY 13
+*/
+
+/* Compression flags */
+#define COMP_F_ADAPTIVE (1<<0) /* COMP_ALG_LZO only */
+#define COMP_F_ASYM (1<<1) /* only downlink is compressed, not uplink */
+#define COMP_F_SWAP (1<<2) /* initial command byte is swapped with last byte in buffer to preserve payload alignment */
+#define COMP_F_ADVERTISE_STUBS_ONLY (1<<3) /* tell server that we only support compression stubs */
+
+
+/*
+ * Length of prepended prefix on compressed packets
+ */
+#define COMP_PREFIX_LEN 1
+
+/*
+ * Prefix bytes
+ */
+
+/* V1 on wire codes */
+/* Initial command byte to tell our peer if we compressed */
+#define LZO_COMPRESS_BYTE 0x66
+#define LZ4_COMPRESS_BYTE 0x69
+#define NO_COMPRESS_BYTE 0xFA
+#define NO_COMPRESS_BYTE_SWAP 0xFB /* to maintain payload alignment, replace this byte with last byte of packet */
+
+/* V2 on wire code */
+#define COMP_ALGV2_INDICATOR_BYTE 0x50
+#define COMP_ALGV2_UNCOMPRESSED_BYTE 0
+#define COMP_ALGV2_LZ4_BYTE 1
+#define COMP_ALGV2_LZO_BYTE 2
+#define COMP_ALGV2_SNAPPY_BYTE 3
+
+/*
+ * Compress worst case size expansion (for any algorithm)
+ *
+ * LZO: len + len/8 + 128 + 3
+ * Snappy: len + len/6 + 32
+ * LZ4: len + len/255 + 16 (LZ4_COMPRESSBOUND(len))
+ */
+#define COMP_EXTRA_BUFFER(len) ((len)/6 + 128 + 3 + COMP_PREFIX_LEN)
+
+/*
+ * Don't try to compress any packet smaller than this.
+ */
+#define COMPRESS_THRESHOLD 100
+
+/* Forward declaration of compression context */
+struct compress_context;
+
+/*
+ * Virtual methods and other static info for each compression algorithm
+ */
+struct compress_alg
+{
+ const char *name;
+ void (*compress_init)(struct compress_context *compctx);
+ void (*compress_uninit)(struct compress_context *compctx);
+ void (*compress)(struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame);
+
+ void (*decompress)(struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame);
+};
+
+/*
+ * Headers for each compression implementation
+ */
+#ifdef ENABLE_LZO
+#include "lzo.h"
+#endif
+
+#ifdef ENABLE_LZ4
+#include "comp-lz4.h"
+#endif
+
+/*
+ * Information that basically identifies a compression
+ * algorithm and related flags.
+ */
+struct compress_options
+{
+ int alg;
+ unsigned int flags;
+};
+
+/*
+ * Workspace union of all supported compression algorithms
+ */
+union compress_workspace_union
+{
+#ifdef ENABLE_LZO
+ struct lzo_compress_workspace lzo;
+#endif
+#ifdef ENABLE_LZ4
+ struct lz4_workspace lz4;
+#endif
+};
+
+/*
+ * Context for active compression session
+ */
+struct compress_context
+{
+ unsigned int flags;
+ struct compress_alg alg;
+ union compress_workspace_union wu;
+
+ /* statistics */
+ counter_type pre_decompress;
+ counter_type post_decompress;
+ counter_type pre_compress;
+ counter_type post_compress;
+};
+
+extern const struct compress_alg comp_stub_alg;
+extern const struct compress_alg compv2_stub_alg;
+
+struct compress_context *comp_init(const struct compress_options *opt);
+
+void comp_uninit(struct compress_context *compctx);
+
+void comp_add_to_extra_frame(struct frame *frame);
+void comp_add_to_extra_buffer(struct frame *frame);
+
+void comp_print_stats (const struct compress_context *compctx, struct status_output *so);
+
+void comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out);
+
+void compv2_escape_data_ifneeded (struct buffer *buf);
+
+static inline bool
+comp_enabled(const struct compress_options *info)
+{
+ return info->alg != COMP_ALG_UNDEF;
+}
+
+static inline bool
+comp_unswapped_prefix(const struct compress_options *info)
+{
+ return !(info->flags & COMP_F_SWAP);
+}
+
+#endif /* USE_COMP */
+#endif
diff --git a/src/openvpn/compstub.c b/src/openvpn/compstub.c
new file mode 100644
index 0000000..9c6aad2
--- /dev/null
+++ b/src/openvpn/compstub.c
@@ -0,0 +1,169 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(USE_COMP)
+
+#include "comp.h"
+#include "error.h"
+#include "otime.h"
+
+#include "memdbg.h"
+
+static void
+stub_compress_init (struct compress_context *compctx)
+{
+}
+
+static void
+stub_compress_uninit (struct compress_context *compctx)
+{
+}
+
+static void
+stub_compress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ if (buf->len <= 0)
+ return;
+ if (compctx->flags & COMP_F_SWAP)
+ {
+ uint8_t *head = BPTR (buf);
+ uint8_t *tail = BEND (buf);
+ ASSERT (buf_safe (buf, 1));
+ ++buf->len;
+
+ /* move head byte of payload to tail */
+ *tail = *head;
+ *head = NO_COMPRESS_BYTE_SWAP;
+ }
+ else
+ {
+ uint8_t *header = buf_prepend (buf, 1);
+ *header = NO_COMPRESS_BYTE;
+ }
+}
+
+static void
+stub_decompress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ uint8_t c;
+ if (buf->len <= 0)
+ return;
+ if (compctx->flags & COMP_F_SWAP)
+ {
+ uint8_t *head = BPTR (buf);
+ c = *head;
+ --buf->len;
+ *head = *BEND (buf);
+ if (c != NO_COMPRESS_BYTE_SWAP)
+ {
+ dmsg (D_COMP_ERRORS, "Bad compression stub (swap) decompression header byte: %d", c);
+ buf->len = 0;
+ }
+ }
+ else
+ {
+ c = *BPTR (buf);
+ ASSERT (buf_advance (buf, 1));
+ if (c != NO_COMPRESS_BYTE)
+ {
+ dmsg (D_COMP_ERRORS, "Bad compression stub decompression header byte: %d", c);
+ buf->len = 0;
+ }
+ }
+}
+
+
+static void
+stubv2_compress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ if (buf->len <= 0)
+ return;
+
+ compv2_escape_data_ifneeded (buf);
+}
+
+static void
+stubv2_decompress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ if (buf->len <= 0)
+ return;
+
+ uint8_t *head = BPTR (buf);
+
+ /* no compression or packet to short*/
+ if (head[0] != COMP_ALGV2_INDICATOR_BYTE)
+ return;
+
+ /* compression header (0x50) is present */
+ buf_advance(buf, 1);
+
+ /* Packet buffer too short (only 1 byte) */
+ if (buf->len <= 0)
+ return;
+
+ head = BPTR (buf);
+ buf_advance(buf, 1);
+
+ if (head[0] != COMP_ALGV2_UNCOMPRESSED_BYTE) {
+ dmsg (D_COMP_ERRORS, "Bad compression stubv2 decompression header byte: %d", *head);
+ buf->len = 0;
+ return;
+ }
+}
+
+const struct compress_alg compv2_stub_alg = {
+ "stubv2",
+ stub_compress_init,
+ stub_compress_uninit,
+ stubv2_compress,
+ stubv2_decompress
+};
+
+const struct compress_alg comp_stub_alg = {
+ "stub",
+ stub_compress_init,
+ stub_compress_uninit,
+ stub_compress,
+ stub_decompress
+};
+
+#else
+static void dummy(void) {}
+#endif /* USE_STUB */
diff --git a/src/openvpn/console.c b/src/openvpn/console.c
index 86331a1..c3bb7c3 100644
--- a/src/openvpn/console.c
+++ b/src/openvpn/console.c
@@ -6,6 +6,8 @@
* packet compression.
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
+ * Copyright (C) 2016 David Sommerseth <davids@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
@@ -38,219 +40,43 @@
#include <systemd/sd-daemon.h>
#endif
-#ifdef WIN32
-#include "win32.h"
+struct _query_user query_user[QUERY_USER_NUMSLOTS]; /* GLOBAL */
-/*
- * Get input from console.
- *
- * Return false on input error, or if service
- * exit event is signaled.
- */
-
-static bool
-get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity)
-{
- HANDLE in = INVALID_HANDLE_VALUE;
- HANDLE err = INVALID_HANDLE_VALUE;
- DWORD len = 0;
-
- ASSERT (prompt);
- ASSERT (input);
- ASSERT (capacity > 0);
-
- input[0] = '\0';
-
- in = GetStdHandle (STD_INPUT_HANDLE);
- err = get_orig_stderr ();
-
- if (in != INVALID_HANDLE_VALUE
- && err != INVALID_HANDLE_VALUE
- && !win32_service_interrupt (&win32_signal)
- && WriteFile (err, prompt, strlen (prompt), &len, NULL))
- {
- bool is_console = (GetFileType (in) == FILE_TYPE_CHAR);
- DWORD flags_save = 0;
- int status = 0;
- WCHAR *winput;
-
- if (is_console)
- {
- if (GetConsoleMode (in, &flags_save))
- {
- DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
- if (echo)
- flags |= ENABLE_ECHO_INPUT;
- SetConsoleMode (in, flags);
- }
- else
- is_console = 0;
- }
-
- if (is_console)
- {
- winput = malloc (capacity * sizeof (WCHAR));
- if (winput == NULL)
- return false;
-
- status = ReadConsoleW (in, winput, capacity, &len, NULL);
- WideCharToMultiByte (CP_UTF8, 0, winput, len, input, capacity, NULL, NULL);
- free (winput);
- }
- else
- status = ReadFile (in, input, capacity, &len, NULL);
-
- string_null_terminate (input, (int)len, capacity);
- chomp (input);
-
- if (!echo)
- WriteFile (err, "\r\n", 2, &len, NULL);
- if (is_console)
- SetConsoleMode (in, flags_save);
- if (status && !win32_service_interrupt (&win32_signal))
- return true;
- }
-
- return false;
-}
-
-#endif
-
-#ifdef HAVE_GETPASS
-
-static FILE *
-open_tty (const bool write)
-{
- FILE *ret;
- ret = fopen ("/dev/tty", write ? "w" : "r");
- if (!ret)
- ret = write ? stderr : stdin;
- return ret;
-}
-
-static void
-close_tty (FILE *fp)
-{
- if (fp != stderr && fp != stdin)
- fclose (fp);
-}
-
-#endif
-#ifdef ENABLE_SYSTEMD
-
-/*
- * is systemd running
- */
-
-static bool
-check_systemd_running ()
+void query_user_clear()
{
- struct stat c;
-
- /* We simply test whether the systemd cgroup hierarchy is
- * mounted, as well as the systemd-ask-password executable
- * being available */
+ int i;
- return (sd_booted() > 0)
- && (stat(SYSTEMD_ASK_PASSWORD_PATH, &c) == 0);
-
-}
-
-static bool
-get_console_input_systemd (const char *prompt, const bool echo, char *input, const int capacity)
-{
- int std_out;
- bool ret = false;
- struct argv argv;
-
- argv_init (&argv);
- argv_printf (&argv, SYSTEMD_ASK_PASSWORD_PATH);
- argv_printf_cat (&argv, "%s", prompt);
-
- if ((std_out = openvpn_popen (&argv, NULL)) < 0) {
- return false;
- }
-
- memset (input, 0, capacity);
- if (read (std_out, input, capacity-1) > 0)
- {
- chomp (input);
- ret = true;
+ for( i = 0; i < QUERY_USER_NUMSLOTS; i++ ) {
+ CLEAR(query_user[i]);
}
- close (std_out);
-
- argv_reset (&argv);
-
- return ret;
}
-#endif
-
-/*
- * Get input from console
- */
-bool
-get_console_input (const char *prompt, const bool echo, char *input, const int capacity)
+void query_user_add(char *prompt, size_t prompt_len,
+ char *resp, size_t resp_len,
+ bool echo)
{
- bool ret = false;
- ASSERT (prompt);
- ASSERT (input);
- ASSERT (capacity > 0);
- input[0] = '\0';
-
-#ifdef ENABLE_SYSTEMD
- if (check_systemd_running ())
- return get_console_input_systemd (prompt, echo, input, capacity);
-#endif
+ int i;
-#if defined(WIN32)
- return get_console_input_win32 (prompt, echo, input, capacity);
-#elif defined(HAVE_GETPASS)
+ /* Ensure input is sane. All these must be present otherwise it is
+ * a programming error.
+ */
+ ASSERT( prompt_len > 0 && prompt != NULL && resp_len > 0 && resp != NULL );
- /* did we --daemon'ize before asking for passwords?
- * (in which case neither stdin or stderr are connected to a tty and
- * /dev/tty can not be open()ed anymore)
- */
- if ( !isatty(0) && !isatty(2) )
- {
- int fd = open( "/dev/tty", O_RDWR );
- if ( fd < 0 )
- { msg(M_FATAL, "neither stdin nor stderr are a tty device and you have neither a controlling tty nor systemd - can't ask for '%s'. If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prompt ); }
- close(fd);
- }
-
- if (echo)
- {
- FILE *fp;
-
- fp = open_tty (true);
- fprintf (fp, "%s", prompt);
- fflush (fp);
- close_tty (fp);
-
- fp = open_tty (false);
- if (fgets (input, capacity, fp) != NULL)
- {
- chomp (input);
- ret = true;
+ /* Seek to the last unused slot */
+ for (i = 0; i < QUERY_USER_NUMSLOTS; i++) {
+ if( query_user[i].prompt == NULL ) {
+ break;
}
- close_tty (fp);
}
- else
- {
- char *gp = getpass (prompt);
- if (gp)
- {
- strncpynt (input, gp, capacity);
- memset (gp, 0, strlen (gp));
- ret = true;
- }
- }
-#else
- msg (M_FATAL, "Sorry, but I can't get console input on this OS (%s)", prompt);
-#endif
- return ret;
+ ASSERT( i < QUERY_USER_NUMSLOTS ); /* Unlikely, but we want to panic if it happens */
+
+ /* Save the information needed for the user interaction */
+ query_user[i].prompt = prompt;
+ query_user[i].prompt_len = prompt_len;
+ query_user[i].response = resp;
+ query_user[i].response_len = resp_len;
+ query_user[i].echo = echo;
}
diff --git a/src/openvpn/console.h b/src/openvpn/console.h
index 268f3fe..ec32cf6 100644
--- a/src/openvpn/console.h
+++ b/src/openvpn/console.h
@@ -6,6 +6,8 @@
* packet compression.
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
+ * Copyright (C) 2016 David Sommerseth <davids@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
@@ -27,7 +29,90 @@
#include "basic.h"
-bool
-get_console_input (const char *prompt, const bool echo, char *input, const int capacity);
+/**
+ * Configuration setup for declaring what kind of information to ask a user for
+ */
+struct _query_user {
+ char *prompt; /**< Prompt to present to the user */
+ size_t prompt_len; /**< Lenght of the prompt string */
+ char *response; /**< The user's response */
+ size_t response_len; /**< Lenght the of the user reposone */
+ bool echo; /**< True: The user should see what is being typed, otherwise mask it */
+};
+
+#define QUERY_USER_NUMSLOTS 10
+extern struct _query_user query_user[]; /**< Global variable, declared in console.c */
+
+/**
+ * Wipes all data put into all of the query_user structs
+ *
+ */
+void query_user_clear ();
+
+
+/**
+ * Adds an item to ask the user for
+ *
+ * @param prompt Prompt to display to the user
+ * @param prompt_len Length of the prompt string
+ * @param resp String containing the user response
+ * @param resp_len Lenght of the response string
+ * @param echo Should the user input be echoed to the user? If False, input will be masked
+ *
+ */
+void query_user_add (char *prompt, size_t prompt_len,
+ char *resp, size_t resp_len,
+ bool echo);
+
+
+/**
+ * Executes a configured setup, using the built-in method for querying the user.
+ * This method uses the console/TTY directly.
+ *
+ * @param setup Pointer to the setup defining what to ask the user
+ *
+ * @return True if executing all the defined steps completed successfully
+ */
+bool query_user_exec_builtin ();
+
+
+#if defined(ENABLE_SYSTEMD)
+/**
+ * Executes a configured setup, using the compiled method for querying the user
+ *
+ * @param setup Pointer to the setup defining what to ask the user
+ *
+ * @return True if executing all the defined steps completed successfully
+ */
+bool query_user_exec ();
+
+#else /* ENABLE_SYSTEMD not defined*/
+/**
+ * Wrapper function enabling query_user_exec() if no alternative methods have
+ * been enabled
+ *
+ */
+static bool query_user_exec ()
+{
+ return query_user_exec_builtin();
+}
+#endif /* defined(ENABLE_SYSTEMD) */
+
+
+/**
+ * A plain "make Gert happy" wrapper. Same arguments as @query_user_add
+ *
+ * FIXME/TODO: Remove this when refactoring the complete user query process
+ * to be called at start-up initialization of OpenVPN.
+ *
+ */
+static inline bool query_user_SINGLE (char *prompt, size_t prompt_len,
+ char *resp, size_t resp_len,
+ bool echo)
+{
+ query_user_clear();
+ query_user_add(prompt, prompt_len, resp, resp_len, echo);
+ return query_user_exec();
+}
#endif
diff --git a/src/openvpn/console_builtin.c b/src/openvpn/console_builtin.c
new file mode 100644
index 0000000..6b0211d
--- /dev/null
+++ b/src/openvpn/console_builtin.c
@@ -0,0 +1,261 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2016 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
+ * Copyright (C) 2016 David Sommerseth <davids@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
+ */
+
+/*
+ * These functions covers handing user input/output using the default consoles
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+#include "console.h"
+#include "error.h"
+#include "buffer.h"
+#include "misc.h"
+
+#ifdef _WIN32
+
+#include "win32.h"
+
+/**
+ * Get input from a Windows console.
+ *
+ * @param prompt Prompt to display to the user
+ * @param echo Should the user input be displayed in the console
+ * @param input Pointer to the buffer the user input will be saved
+ * @param capacity Size of the buffer for the user input
+ *
+ * @return Return false on input error, or if service
+ * exit event is signaled.
+ */
+static bool get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity)
+{
+ HANDLE in = INVALID_HANDLE_VALUE;
+ HANDLE err = INVALID_HANDLE_VALUE;
+ DWORD len = 0;
+
+ ASSERT (prompt);
+ ASSERT (input);
+ ASSERT (capacity > 0);
+
+ input[0] = '\0';
+
+ in = GetStdHandle (STD_INPUT_HANDLE);
+ err = get_orig_stderr ();
+
+ if (in != INVALID_HANDLE_VALUE
+ && err != INVALID_HANDLE_VALUE
+ && !win32_service_interrupt (&win32_signal)
+ && WriteFile (err, prompt, strlen (prompt), &len, NULL))
+ {
+ bool is_console = (GetFileType (in) == FILE_TYPE_CHAR);
+ DWORD flags_save = 0;
+ int status = 0;
+ WCHAR *winput;
+
+ if (is_console)
+ {
+ if (GetConsoleMode (in, &flags_save))
+ {
+ DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
+ if (echo)
+ flags |= ENABLE_ECHO_INPUT;
+ SetConsoleMode (in, flags);
+ } else
+ is_console = 0;
+ }
+
+ if (is_console)
+ {
+ winput = malloc (capacity * sizeof (WCHAR));
+ if (winput == NULL)
+ return false;
+
+ status = ReadConsoleW (in, winput, capacity, &len, NULL);
+ WideCharToMultiByte (CP_UTF8, 0, winput, len, input, capacity, NULL, NULL);
+ free (winput);
+ } else
+ status = ReadFile (in, input, capacity, &len, NULL);
+
+ string_null_terminate (input, (int)len, capacity);
+ chomp (input);
+
+ if (!echo)
+ WriteFile (err, "\r\n", 2, &len, NULL);
+ if (is_console)
+ SetConsoleMode (in, flags_save);
+ if (status && !win32_service_interrupt (&win32_signal))
+ return true;
+ }
+
+ return false;
+}
+
+#endif /* _WIN32 */
+
+
+#ifdef HAVE_GETPASS
+
+/**
+ * Open the current console TTY for read/write operations
+ *
+ * @params write If true, the user wants to write to the console
+ * otherwise read from the console
+ *
+ * @returns Returns a FILE pointer to either the TTY in read or write mode
+ * or stdin/stderr, depending on the write flag
+ *
+ */
+static FILE * open_tty (const bool write)
+{
+ FILE *ret;
+ ret = fopen ("/dev/tty", write ? "w" : "r");
+ if (!ret)
+ ret = write ? stderr : stdin;
+ return ret;
+}
+
+/**
+ * Closes the TTY FILE pointer, but only if it is not a stdin/stderr FILE object.
+ *
+ * @params fp FILE pointer to close
+ *
+ */
+static void close_tty (FILE *fp)
+{
+ if (fp != stderr && fp != stdin)
+ fclose (fp);
+}
+
+#endif /* HAVE_GETPASS */
+
+
+/**
+ * Core function for getting input from console
+ *
+ * @params prompt The prompt to present to the user
+ * @params echo Should the user see what is being typed
+ * @params input Pointer to the buffer used to save the user input
+ * @params capacity Size of the input buffer
+ *
+ * @returns Returns True if user input was gathered
+ */
+static bool get_console_input (const char *prompt, const bool echo, char *input, const int capacity)
+{
+ bool ret = false;
+ ASSERT (prompt);
+ ASSERT (input);
+ ASSERT (capacity > 0);
+ input[0] = '\0';
+
+#if defined(_WIN32)
+ return get_console_input_win32 (prompt, echo, input, capacity);
+#elif defined(HAVE_GETPASS)
+
+ /* did we --daemon'ize before asking for passwords?
+ * (in which case neither stdin or stderr are connected to a tty and
+ * /dev/tty can not be open()ed anymore)
+ */
+ if ( !isatty(0) && !isatty(2) )
+ {
+ int fd = open( "/dev/tty", O_RDWR );
+ if ( fd < 0 )
+ {
+ msg(M_FATAL, "neither stdin nor stderr are a tty device and you have neither a "
+ "controlling tty nor systemd - can't ask for '%s'. If you used --daemon, "
+ "you need to use --askpass to make passphrase-protected keys work, and you "
+ "can not use --auth-nocache.", prompt );
+ }
+ close(fd);
+ }
+
+ if (echo)
+ {
+ FILE *fp;
+
+ fp = open_tty (true);
+ fprintf (fp, "%s", prompt);
+ fflush (fp);
+ close_tty (fp);
+
+ fp = open_tty (false);
+ if (fgets (input, capacity, fp) != NULL)
+ {
+ chomp (input);
+ ret = true;
+ }
+ close_tty (fp);
+ } else {
+ char *gp = getpass (prompt);
+ if (gp)
+ {
+ strncpynt (input, gp, capacity);
+ memset (gp, 0, strlen (gp));
+ ret = true;
+ }
+ }
+#else
+ msg (M_FATAL, "Sorry, but I can't get console input on this OS (%s)", prompt);
+#endif
+ return ret;
+}
+
+
+/**
+ * @copydoc query_user_exec()
+ *
+ * Default method for querying user using default stdin/stdout on a console.
+ * This needs to be available as a backup interface for the alternative
+ * implementations in case they cannot query through their implementation
+ * specific methods.
+ *
+ * If no alternative implementation is declared, a wrapper in console.h will ensure
+ * query_user_exec() will call this function instead.
+ *
+ */
+bool query_user_exec_builtin()
+{
+ bool ret = true; /* Presume everything goes okay */
+ int i;
+
+ /* Loop through configured query_user slots */
+ for (i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++)
+ {
+ if (!get_console_input(query_user[i].prompt, query_user[i].echo,
+ query_user[i].response, query_user[i].response_len) )
+ {
+ /* Force the final result state to failed on failure */
+ ret = false;
+ }
+ }
+
+ return ret;
+}
diff --git a/src/openvpn/console_systemd.c b/src/openvpn/console_systemd.c
new file mode 100644
index 0000000..8a953c9
--- /dev/null
+++ b/src/openvpn/console_systemd.c
@@ -0,0 +1,122 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
+ * Copyright (C) 2016 David Sommerseth <dazo@privateinternetaccess.com>
+ *
+ * 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
+ */
+
+/**
+ * @file Alternative method to query for user input, using systemd
+ *
+ */
+
+#include "config.h"
+
+#ifdef ENABLE_SYSTEMD
+#include "syshead.h"
+#include "console.h"
+#include "misc.h"
+
+#include <systemd/sd-daemon.h>
+
+/*
+ * is systemd running
+ */
+
+static bool
+check_systemd_running ()
+{
+ struct stat c;
+
+ /* We simply test whether the systemd cgroup hierarchy is
+ * mounted, as well as the systemd-ask-password executable
+ * being available */
+
+ return (sd_booted() > 0)
+ && (stat(SYSTEMD_ASK_PASSWORD_PATH, &c) == 0);
+
+}
+
+static bool
+get_console_input_systemd (const char *prompt, const bool echo, char *input, const int capacity)
+{
+ int std_out;
+ bool ret = false;
+ struct argv argv = argv_new ();
+
+ argv_printf (&argv, SYSTEMD_ASK_PASSWORD_PATH);
+#ifdef SYSTEMD_NEWER_THAN_216
+ /* the --echo support arrived in upstream systemd 217 */
+ if( echo )
+ {
+ argv_printf_cat(&argv, "--echo");
+ }
+#endif
+ argv_printf_cat (&argv, "--icon network-vpn");
+ argv_printf_cat (&argv, "%s", prompt);
+
+ if ((std_out = openvpn_popen (&argv, NULL)) < 0) {
+ return false;
+ }
+ memset (input, 0, capacity);
+ if (read (std_out, input, capacity-1) != 0)
+ {
+ chomp (input);
+ ret = true;
+ }
+ close (std_out);
+
+ argv_reset (&argv);
+
+ return ret;
+}
+
+/**
+ * Systemd aware implementation of query_user_exec(). If systemd is not running
+ * it will fall back to use query_user_exec_builtin() instead.
+ *
+ */
+bool query_user_exec()
+{
+ bool ret = true; /* Presume everything goes okay */
+ int i;
+
+ /* If systemd is not available, use the default built-in mechanism */
+ if (!check_systemd_running())
+ {
+ return query_user_exec_builtin();
+ }
+
+ /* Loop through the complete query setup and when needed, collect the information */
+ for (i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++)
+ {
+ if (!get_console_input_systemd(query_user[i].prompt, query_user[i].echo,
+ query_user[i].response, query_user[i].response_len) )
+ {
+ /* Force the final result state to failed on failure */
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+#endif /* ENABLE_SYSTEMD */
diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index 400bf11..05622ce 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -6,7 +6,7 @@
* packet compression.
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
+ * Copyright (C) 2010-2016 Fox Crypto B.V. <openvpn@fox-it.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -35,7 +35,8 @@
#include "crypto.h"
#include "error.h"
-#include "misc.h"
+#include "integer.h"
+#include "platform.h"
#include "memdbg.h"
@@ -62,38 +63,114 @@
* happen unless the frame parameters are wrong.
*/
-#define CRYPT_ERROR(format) \
- do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false)
+static void
+openvpn_encrypt_aead (struct buffer *buf, struct buffer work,
+ struct crypto_options *opt) {
+#ifdef HAVE_AEAD_CIPHER_MODES
+ struct gc_arena gc;
+ int outlen = 0;
+ const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt;
+ uint8_t *mac_out = NULL;
+ const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
+ const int mac_len = cipher_kt_tag_size (cipher_kt);
+
+ /* IV, packet-ID and implicit IV required for this mode. */
+ ASSERT (ctx->cipher);
+ ASSERT (cipher_kt_mode_aead (cipher_kt));
+ ASSERT (opt->flags & CO_USE_IV);
+ ASSERT (packet_id_initialized(&opt->packet_id));
-/**
- * As memcmp(), but constant-time.
- * Returns 0 when data is equal, non-zero otherwise.
- */
-static int
-memcmp_constant_time (const void *a, const void *b, size_t size) {
- const uint8_t * a1 = a;
- const uint8_t * b1 = b;
- int ret = 0;
- size_t i;
-
- for (i = 0; i < size; i++) {
- ret |= *a1++ ^ *b1++;
+ gc_init (&gc);
+
+ /* Prepare IV */
+ {
+ struct buffer iv_buffer;
+ struct packet_id_net pin;
+ uint8_t iv[OPENVPN_MAX_IV_LENGTH];
+ const int iv_len = cipher_ctx_iv_length (ctx->cipher);
+
+ ASSERT (iv_len >= OPENVPN_AEAD_MIN_IV_LEN && iv_len <= OPENVPN_MAX_IV_LENGTH);
+
+ memset(iv, 0, sizeof(iv));
+ buf_set_write (&iv_buffer, iv, iv_len);
+
+ /* IV starts with packet id to make the IV unique for packet */
+ packet_id_alloc_outgoing (&opt->packet_id.send, &pin, false);
+ ASSERT (packet_id_write (&pin, &iv_buffer, false, false));
+
+ /* Remainder of IV consists of implicit part (unique per session) */
+ ASSERT (buf_write (&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len));
+ ASSERT (iv_buffer.len == iv_len);
+
+ /* Write explicit part of IV to work buffer */
+ ASSERT (buf_write(&work, iv, iv_len - ctx->implicit_iv_len));
+ dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv, iv_len, 0, &gc));
+
+ /* Init cipher_ctx with IV. key & keylen are already initialized */
+ ASSERT (cipher_ctx_reset(ctx->cipher, iv));
}
- return ret;
+ /* Reserve space for authentication tag */
+ mac_out = buf_write_alloc (&work, mac_len);
+ ASSERT (mac_out);
+
+ dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc));
+
+ /* Buffer overflow check */
+ if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
+ {
+ msg (D_CRYPT_ERRORS,
+ "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d",
+ buf->capacity, buf->offset, buf->len, work.capacity, work.offset,
+ work.len);
+ goto err;
+ }
+
+ /* For AEAD ciphers, authenticate Additional Data, including opcode */
+ ASSERT (cipher_ctx_update_ad (ctx->cipher, BPTR (&work), BLEN (&work) - mac_len));
+ dmsg (D_PACKET_CONTENT, "ENCRYPT AD: %s",
+ format_hex (BPTR (&work), BLEN (&work) - mac_len, 0, &gc));
+
+ /* Encrypt packet ID, payload */
+ ASSERT (cipher_ctx_update (ctx->cipher, BEND (&work), &outlen, BPTR (buf), BLEN (buf)));
+ ASSERT (buf_inc_len (&work, outlen));
+
+ /* Flush the encryption buffer */
+ ASSERT (cipher_ctx_final (ctx->cipher, BEND (&work), &outlen));
+ ASSERT (buf_inc_len (&work, outlen));
+
+ /* Write authentication tag */
+ ASSERT (cipher_ctx_get_tag (ctx->cipher, mac_out, mac_len));
+
+ *buf = work;
+
+ dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc));
+
+ gc_free (&gc);
+ return;
+
+err:
+ crypto_clear_error();
+ buf->len = 0;
+ gc_free (&gc);
+ return;
+#else /* HAVE_AEAD_CIPHER_MODES */
+ ASSERT (0);
+#endif
}
-void
-openvpn_encrypt (struct buffer *buf, struct buffer work,
- const struct crypto_options *opt,
- const struct frame* frame)
+static void
+openvpn_encrypt_v1 (struct buffer *buf, struct buffer work,
+ struct crypto_options *opt)
{
struct gc_arena gc;
gc_init (&gc);
- if (buf->len > 0 && opt->key_ctx_bi)
+ if (buf->len > 0 && opt)
{
- struct key_ctx *ctx = &opt->key_ctx_bi->encrypt;
+ const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt;
+ uint8_t *mac_out = NULL;
+ const uint8_t *hmac_start = NULL;
/* Do Encrypt from buf -> work */
if (ctx->cipher)
@@ -103,6 +180,14 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
int outlen;
+ /* Reserve space for HMAC */
+ if (ctx->hmac)
+ {
+ mac_out = buf_write_alloc (&work, hmac_ctx_size(ctx->hmac));
+ ASSERT (mac_out);
+ hmac_start = BEND(&work);
+ }
+
if (cipher_kt_mode_cbc(cipher_kt))
{
CLEAR (iv_buf);
@@ -111,11 +196,11 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
if (opt->flags & CO_USE_IV)
prng_bytes (iv_buf, iv_size);
- /* Put packet ID in plaintext buffer or IV, depending on cipher mode */
- if (opt->packet_id)
+ /* Put packet ID in plaintext buffer */
+ if (packet_id_initialized(&opt->packet_id))
{
struct packet_id_net pin;
- packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM));
+ packet_id_alloc_outgoing (&opt->packet_id.send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM));
ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true));
}
}
@@ -124,10 +209,11 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
struct packet_id_net pin;
struct buffer b;
- ASSERT (opt->flags & CO_USE_IV); /* IV and packet-ID required */
- ASSERT (opt->packet_id); /* for this mode. */
+ /* IV and packet-ID required for this mode. */
+ ASSERT (opt->flags & CO_USE_IV);
+ ASSERT (packet_id_initialized(&opt->packet_id));
- packet_id_alloc_outgoing (&opt->packet_id->send, &pin, true);
+ packet_id_alloc_outgoing (&opt->packet_id.send, &pin, true);
memset (iv_buf, 0, iv_size);
buf_set_write (&b, iv_buf, iv_size);
ASSERT (packet_id_write (&pin, &b, true, false));
@@ -137,12 +223,12 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
ASSERT (0);
}
- /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
- ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
-
/* set the IV pseudo-randomly */
if (opt->flags & CO_USE_IV)
- dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc));
+ {
+ ASSERT (buf_write(&work, iv_buf, iv_size));
+ dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc));
+ }
dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s",
format_hex (BPTR (buf), BLEN (buf), 80, &gc));
@@ -165,52 +251,50 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
}
/* Encrypt packet ID, payload */
- ASSERT (cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf)));
+ ASSERT (cipher_ctx_update (ctx->cipher, BEND (&work), &outlen, BPTR (buf), BLEN (buf)));
ASSERT (buf_inc_len(&work, outlen));
/* Flush the encryption buffer */
- ASSERT (cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen));
+ ASSERT (cipher_ctx_final(ctx->cipher, BEND (&work), &outlen));
ASSERT (buf_inc_len(&work, outlen));
/* For all CBC mode ciphers, check the last block is complete */
ASSERT (cipher_kt_mode (cipher_kt) != OPENVPN_MODE_CBC ||
outlen == iv_size);
-
- /* prepend the IV to the ciphertext */
- if (opt->flags & CO_USE_IV)
- {
- uint8_t *output = buf_prepend (&work, iv_size);
- ASSERT (output);
- memcpy (output, iv_buf, iv_size);
- }
-
- dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s",
- format_hex (BPTR (&work), BLEN (&work), 80, &gc));
}
else /* No Encryption */
{
- if (opt->packet_id)
+ if (packet_id_initialized(&opt->packet_id))
{
struct packet_id_net pin;
- packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM));
+ packet_id_alloc_outgoing (&opt->packet_id.send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM));
ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true));
}
+ if (ctx->hmac)
+ {
+ hmac_start = BPTR(buf);
+ ASSERT (mac_out = buf_prepend (buf, hmac_ctx_size(ctx->hmac)));
+ }
+ if (BLEN(&work)) {
+ buf_write_prepend(buf, BPTR(&work), BLEN(&work));
+ }
work = *buf;
}
/* HMAC the ciphertext (or plaintext if !cipher) */
if (ctx->hmac)
{
- uint8_t *output = NULL;
-
hmac_ctx_reset (ctx->hmac);
- hmac_ctx_update (ctx->hmac, BPTR(&work), BLEN(&work));
- output = buf_prepend (&work, hmac_ctx_size(ctx->hmac));
- ASSERT (output);
- hmac_ctx_final (ctx->hmac, output);
+ hmac_ctx_update (ctx->hmac, hmac_start, BEND(&work) - hmac_start);
+ hmac_ctx_final (ctx->hmac, mac_out);
+ dmsg (D_PACKET_CONTENT, "ENCRYPT HMAC: %s",
+ format_hex (mac_out, hmac_ctx_size(ctx->hmac), 80, &gc));
}
*buf = work;
+
+ dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s",
+ format_hex (BPTR (&work), BLEN (&work), 80, &gc));
}
gc_free (&gc);
@@ -223,6 +307,47 @@ err:
return;
}
+void
+openvpn_encrypt (struct buffer *buf, struct buffer work,
+ struct crypto_options *opt)
+{
+ if (buf->len > 0 && opt)
+ {
+ const cipher_kt_t *cipher_kt =
+ cipher_ctx_get_cipher_kt(opt->key_ctx_bi.encrypt.cipher);
+
+ if (cipher_kt_mode_aead (cipher_kt))
+ openvpn_encrypt_aead(buf, work, opt);
+ else
+ openvpn_encrypt_v1(buf, work, opt);
+ }
+}
+
+bool crypto_check_replay(struct crypto_options *opt,
+ const struct packet_id_net *pin, const char *error_prefix,
+ struct gc_arena *gc) {
+ bool ret = false;
+ packet_id_reap_test (&opt->packet_id.rec);
+ if (packet_id_test (&opt->packet_id.rec, pin))
+ {
+ packet_id_add (&opt->packet_id.rec, pin);
+ if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM))
+ packet_id_persist_save_obj (opt->pid_persist, &opt->packet_id);
+ ret = true;
+ }
+ else
+ {
+ if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS))
+ {
+ msg (D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- "
+ "see the man page entry for --no-replay and --replay-window for "
+ "more info or silence this warning with --mute-replay-warnings",
+ error_prefix, packet_id_net_print (pin, true, gc));
+ }
+ }
+ return ret;
+}
+
/*
* If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet.
*
@@ -231,21 +356,169 @@ err:
* On success, buf is set to point to plaintext, true
* is returned.
*/
-bool
-openvpn_decrypt (struct buffer *buf, struct buffer work,
- const struct crypto_options *opt,
- const struct frame* frame)
+static bool
+openvpn_decrypt_aead (struct buffer *buf, struct buffer work,
+ struct crypto_options *opt, const struct frame* frame,
+ const uint8_t *ad_start)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+ static const char error_prefix[] = "AEAD Decrypt error";
+ struct packet_id_net pin = { 0 };
+ const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
+ const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
+ uint8_t *tag_ptr = NULL;
+ int tag_size = 0;
+ int outlen;
+ struct gc_arena gc;
+
+ gc_init (&gc);
+
+ ASSERT (opt);
+ ASSERT (frame);
+ ASSERT (buf->len > 0);
+ ASSERT (ctx->cipher);
+ ASSERT (cipher_kt_mode_aead (cipher_kt));
+
+ dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s",
+ format_hex (BPTR (buf), BLEN (buf), 80, &gc));
+
+ ASSERT (ad_start >= buf->data && ad_start <= BPTR (buf));
+
+ ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT)));
+
+ /* IV and Packet ID required for this mode */
+ ASSERT (packet_id_initialized (&opt->packet_id));
+ ASSERT (opt->flags & CO_USE_IV);
+
+ /* Combine IV from explicit part from packet and implicit part from context */
+ {
+ uint8_t iv[OPENVPN_MAX_IV_LENGTH] = { 0 };
+ const int iv_len = cipher_ctx_iv_length (ctx->cipher);
+ const size_t packet_iv_len = iv_len - ctx->implicit_iv_len;
+
+ ASSERT (ctx->implicit_iv_len <= iv_len);
+ if (buf->len + ctx->implicit_iv_len < iv_len)
+ CRYPT_ERROR ("missing IV info");
+
+ memcpy (iv, BPTR(buf), packet_iv_len);
+ memcpy (iv + packet_iv_len, ctx->implicit_iv, ctx->implicit_iv_len);
+
+ dmsg (D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex (iv, iv_len, 0, &gc));
+
+ /* Load IV, ctx->cipher was already initialized with key & keylen */
+ if (!cipher_ctx_reset (ctx->cipher, iv))
+ {
+ CRYPT_ERROR ("cipher init failed");
+ }
+ }
+
+ /* Read packet ID from packet */
+ if (!packet_id_read (&pin, buf, false))
+ {
+ CRYPT_ERROR ("error reading packet-id");
+ }
+
+ /* keep the tag value to feed in later */
+ tag_size = cipher_kt_tag_size(cipher_kt);
+ if (buf->len < tag_size)
+ {
+ CRYPT_ERROR ("missing tag");
+ }
+ tag_ptr = BPTR(buf);
+ ASSERT (buf_advance (buf, tag_size));
+ dmsg (D_PACKET_CONTENT, "DECRYPT MAC: %s", format_hex (tag_ptr, tag_size, 0, &gc));
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER < 0x10001040L
+ /* OpenSSL <= 1.0.1c bug requires set tag before processing ciphertext */
+ if (!EVP_CIPHER_CTX_ctrl (ctx->cipher, EVP_CTRL_GCM_SET_TAG, tag_size, tag_ptr))
+ {
+ CRYPT_ERROR ("setting tag failed");
+ }
+#endif
+
+ if (buf->len < 1)
+ {
+ CRYPT_ERROR ("missing payload");
+ }
+
+ dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s", format_hex (BPTR(buf), BLEN(buf), 0, &gc));
+
+ /* Buffer overflow check (should never fail) */
+ if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
+ {
+ CRYPT_ERROR ("potential buffer overflow");
+ }
+
+ {
+ /* feed in tag and the authenticated data */
+ const int ad_size = BPTR (buf) - ad_start - tag_size;
+ ASSERT (cipher_ctx_update_ad (ctx->cipher, ad_start, ad_size));
+ dmsg (D_PACKET_CONTENT, "DECRYPT AD: %s",
+ format_hex (BPTR (buf) - ad_size - tag_size, ad_size, 0, &gc));
+ }
+
+ /* Decrypt and authenticate packet */
+ if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf),
+ BLEN (buf)))
+ {
+ CRYPT_ERROR ("cipher update failed");
+ }
+ ASSERT (buf_inc_len (&work, outlen));
+ if (!cipher_ctx_final_check_tag (ctx->cipher, BPTR (&work) + outlen,
+ &outlen, tag_ptr, tag_size))
+ {
+ CRYPT_ERROR ("cipher final failed");
+ }
+ ASSERT (buf_inc_len (&work, outlen));
+
+ dmsg (D_PACKET_CONTENT, "DECRYPT TO: %s",
+ format_hex (BPTR (&work), BLEN (&work), 80, &gc));
+
+ if (!crypto_check_replay (opt, &pin, error_prefix, &gc))
+ {
+ goto error_exit;
+ }
+
+ *buf = work;
+
+ gc_free (&gc);
+ return true;
+
+ error_exit:
+ crypto_clear_error();
+ buf->len = 0;
+ gc_free (&gc);
+ return false;
+#else /* HAVE_AEAD_CIPHER_MODES */
+ ASSERT (0);
+ return false;
+#endif
+}
+
+/*
+ * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet.
+ *
+ * Set buf->len to 0 and return false on decrypt error.
+ *
+ * On success, buf is set to point to plaintext, true
+ * is returned.
+ */
+static bool
+openvpn_decrypt_v1 (struct buffer *buf, struct buffer work,
+ struct crypto_options *opt, const struct frame* frame)
{
static const char error_prefix[] = "Authenticate/Decrypt packet error";
struct gc_arena gc;
gc_init (&gc);
- if (buf->len > 0 && opt->key_ctx_bi)
+ if (buf->len > 0 && opt)
{
- struct key_ctx *ctx = &opt->key_ctx_bi->decrypt;
+ const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
struct packet_id_net pin;
bool have_pin = false;
+ dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s",
+ format_hex (BPTR (buf), BLEN (buf), 80, &gc));
+
/* Verify the HMAC */
if (ctx->hmac)
{
@@ -325,7 +598,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
{
if (cipher_kt_mode_cbc(cipher_kt))
{
- if (opt->packet_id)
+ if (packet_id_initialized(&opt->packet_id))
{
if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)))
CRYPT_ERROR ("error reading CBC packet-id");
@@ -336,8 +609,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
{
struct buffer b;
- ASSERT (opt->flags & CO_USE_IV); /* IV and packet-ID required */
- ASSERT (opt->packet_id); /* for this mode. */
+ /* IV and packet-ID required for this mode. */
+ ASSERT (opt->flags & CO_USE_IV);
+ ASSERT (packet_id_initialized(&opt->packet_id));
buf_set_read (&b, iv_buf, iv_size);
if (!packet_id_read (&pin, &b, true))
@@ -353,7 +627,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
else
{
work = *buf;
- if (opt->packet_id)
+ if (packet_id_initialized(&opt->packet_id))
{
if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)))
CRYPT_ERROR ("error reading packet-id");
@@ -361,22 +635,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
}
}
- if (have_pin)
+ if (have_pin && !crypto_check_replay(opt, &pin, error_prefix, &gc))
{
- packet_id_reap_test (&opt->packet_id->rec);
- if (packet_id_test (&opt->packet_id->rec, &pin))
- {
- packet_id_add (&opt->packet_id->rec, &pin);
- if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM))
- packet_id_persist_save_obj (opt->pid_persist, opt->packet_id);
- }
- else
- {
- if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS))
- msg (D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- see the man page entry for --no-replay and --replay-window for more info or silence this warning with --mute-replay-warnings",
- error_prefix, packet_id_net_print (&pin, true, &gc));
- goto error_exit;
- }
+ goto error_exit;
}
*buf = work;
}
@@ -391,14 +652,36 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
return false;
}
-/*
- * How many bytes will we add to frame buffer for a given
- * set of crypto options?
- */
+
+bool
+openvpn_decrypt (struct buffer *buf, struct buffer work,
+ struct crypto_options *opt, const struct frame* frame,
+ const uint8_t *ad_start)
+{
+ bool ret = false;
+
+ if (buf->len > 0 && opt)
+ {
+ const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
+ if (cipher_kt_mode_aead (cipher_ctx_get_cipher_kt (ctx->cipher)))
+ {
+ ret = openvpn_decrypt_aead (buf, work, opt, frame, ad_start);
+ }
+ else
+ {
+ ret = openvpn_decrypt_v1 (buf, work, opt, frame);
+ }
+ }
+ else
+ {
+ ret = true;
+ }
+ return ret;
+}
+
void
crypto_adjust_frame_parameters(struct frame *frame,
const struct key_type* kt,
- bool cipher_defined,
bool use_iv,
bool packet_id,
bool packet_id_long_form)
@@ -408,11 +691,14 @@ crypto_adjust_frame_parameters(struct frame *frame,
if (packet_id)
crypto_overhead += packet_id_size (packet_id_long_form);
- if (cipher_defined)
+ if (kt->cipher)
{
if (use_iv)
crypto_overhead += cipher_kt_iv_size (kt->cipher);
+ if (cipher_kt_mode_aead (kt->cipher))
+ crypto_overhead += cipher_kt_tag_size (kt->cipher);
+
/* extra block required by cipher_ctx_update() */
crypto_overhead += cipher_kt_block_size (kt->cipher);
}
@@ -421,8 +707,16 @@ crypto_adjust_frame_parameters(struct frame *frame,
frame_add_to_extra_frame (frame, crypto_overhead);
- msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for crypto by %zu bytes",
- __func__, crypto_overhead);
+ msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for crypto by %u bytes",
+ __func__, (unsigned int) crypto_overhead);
+}
+
+size_t
+crypto_max_overhead(void)
+{
+ return packet_id_size(true) + OPENVPN_MAX_IV_LENGTH +
+ OPENVPN_MAX_CIPHER_BLOCK_SIZE +
+ max_int (OPENVPN_MAX_HMAC_SIZE, OPENVPN_AEAD_TAG_LENGTH);
}
/*
@@ -430,39 +724,55 @@ crypto_adjust_frame_parameters(struct frame *frame,
*/
void
init_key_type (struct key_type *kt, const char *ciphername,
- bool ciphername_defined, const char *authname,
- bool authname_defined, int keysize,
- bool cfb_ofb_allowed, bool warn)
+ const char *authname, int keysize, bool tls_mode, bool warn)
{
+ bool aead_cipher = false;
+
+ ASSERT(ciphername);
+ ASSERT(authname);
+
CLEAR (*kt);
- if (ciphername && ciphername_defined)
+ if (strcmp (ciphername, "none") != 0)
{
kt->cipher = cipher_kt_get (translate_cipher_name_from_openvpn(ciphername));
+ if (!kt->cipher)
+ {
+ msg (M_FATAL, "Cipher %s not supported", ciphername);
+ }
+
kt->cipher_length = cipher_kt_key_size (kt->cipher);
if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH)
kt->cipher_length = keysize;
/* check legal cipher mode */
- {
- if (!(cipher_kt_mode_cbc(kt->cipher)
+ aead_cipher = cipher_kt_mode_aead(kt->cipher);
+ if (!(cipher_kt_mode_cbc(kt->cipher)
+ || (tls_mode && aead_cipher)
#ifdef ENABLE_OFB_CFB_MODE
- || (cfb_ofb_allowed && cipher_kt_mode_ofb_cfb(kt->cipher))
+ || (tls_mode && cipher_kt_mode_ofb_cfb(kt->cipher))
#endif
- ))
- msg (M_FATAL, "Cipher '%s' mode not supported", ciphername);
- }
+ ))
+ msg (M_FATAL, "Cipher '%s' mode not supported", ciphername);
+
+ if (OPENVPN_MAX_CIPHER_BLOCK_SIZE < cipher_kt_block_size(kt->cipher))
+ msg (M_FATAL, "Cipher '%s' not allowed: block size too big.", ciphername);
}
else
{
if (warn)
msg (M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used");
}
- if (authname && authname_defined)
+ if (strcmp (authname, "none") != 0)
{
- kt->digest = md_kt_get (authname);
- kt->hmac_length = md_kt_size (kt->digest);
+ if (!aead_cipher) { /* Ignore auth for AEAD ciphers */
+ kt->digest = md_kt_get (authname);
+ kt->hmac_length = md_kt_size (kt->digest);
+
+ if (OPENVPN_MAX_HMAC_SIZE < kt->hmac_length)
+ msg (M_FATAL, "HMAC '%s' not allowed: digest size too big.", authname);
+ }
}
- else
+ else if (!aead_cipher)
{
if (warn)
msg (M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used");
@@ -486,15 +796,21 @@ init_key_ctx (struct key_ctx *ctx, struct key *key,
msg (D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key",
prefix,
- cipher_kt_name(kt->cipher),
+ translate_cipher_name_to_openvpn(cipher_kt_name(kt->cipher)),
kt->cipher_length *8);
dmsg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix,
format_hex (key->cipher, kt->cipher_length, 0, &gc));
dmsg (D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d",
- prefix,
- cipher_kt_block_size(kt->cipher),
- cipher_kt_iv_size(kt->cipher));
+ prefix, cipher_kt_block_size(kt->cipher),
+ cipher_kt_iv_size(kt->cipher));
+ if (cipher_kt_block_size(kt->cipher) < 128/8)
+ {
+ msg (M_WARN, "WARNING: INSECURE cipher with block size less than 128"
+ " bit (%d bit). This allows attacks like SWEET32. Mitigate by "
+ "using a --cipher with a larger block size (e.g. AES-256-CBC).",
+ cipher_kt_block_size(kt->cipher)*8);
+ }
}
if (kt->digest && kt->hmac_length > 0)
{
@@ -532,6 +848,7 @@ free_key_ctx (struct key_ctx *ctx)
free(ctx->hmac);
ctx->hmac = NULL;
}
+ ctx->implicit_iv_len = 0;
}
void
@@ -541,7 +858,6 @@ free_key_ctx_bi (struct key_ctx_bi *ctx)
free_key_ctx(&ctx->decrypt);
}
-
static bool
key_is_zero (struct key *key, const struct key_type *kt)
{
@@ -621,8 +937,10 @@ check_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use
{
ASSERT(kt);
- if (cipher_kt_mode_ofb_cfb(kt->cipher) && !(packet_id && use_iv))
- msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB or OFB mode cipher");
+ if (!(packet_id && use_iv) && (cipher_kt_mode_ofb_cfb(kt->cipher) ||
+ cipher_kt_mode_aead(kt->cipher)))
+ msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB, OFB or "
+ "AEAD mode cipher");
}
/*
@@ -688,7 +1006,7 @@ key2_print (const struct key2* k,
}
void
-test_crypto (const struct crypto_options *co, struct frame* frame)
+test_crypto (struct crypto_options *co, struct frame* frame)
{
int i, j;
struct gc_arena gc = gc_new ();
@@ -697,10 +1015,35 @@ test_crypto (const struct crypto_options *co, struct frame* frame)
struct buffer encrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc);
struct buffer decrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc);
struct buffer buf = clear_buf();
+ void *buf_p;
/* init work */
ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
+#ifdef HAVE_AEAD_CIPHER_MODES
+ /* init implicit IV */
+ {
+ const cipher_kt_t *cipher =
+ cipher_ctx_get_cipher_kt(co->key_ctx_bi.encrypt.cipher);
+
+ if (cipher_kt_mode_aead(cipher))
+ {
+ size_t impl_iv_len = cipher_kt_iv_size(cipher) - sizeof(packet_id_type);
+ ASSERT (cipher_kt_iv_size(cipher) <= OPENVPN_MAX_IV_LENGTH);
+ ASSERT (cipher_kt_iv_size(cipher) >= OPENVPN_AEAD_MIN_IV_LEN);
+
+ /* Generate dummy implicit IV */
+ ASSERT (rand_bytes(co->key_ctx_bi.encrypt.implicit_iv,
+ OPENVPN_MAX_IV_LENGTH));
+ co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len;
+
+ memcpy(co->key_ctx_bi.decrypt.implicit_iv,
+ co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH);
+ co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len;
+ }
+ }
+#endif
+
msg (M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode.");
for (i = 1; i <= TUN_MTU_SIZE (frame); ++i)
{
@@ -718,13 +1061,18 @@ test_crypto (const struct crypto_options *co, struct frame* frame)
/* copy source to input buf */
buf = work;
- memcpy (buf_write_alloc (&buf, BLEN (&src)), BPTR (&src), BLEN (&src));
+ buf_p = buf_write_alloc (&buf, BLEN (&src));
+ ASSERT(buf_p);
+ memcpy (buf_p, BPTR (&src), BLEN (&src));
+
+ /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
+ ASSERT (buf_init (&encrypt_workspace, FRAME_HEADROOM (frame)));
/* encrypt */
- openvpn_encrypt (&buf, encrypt_workspace, co, frame);
+ openvpn_encrypt (&buf, encrypt_workspace, co);
/* decrypt */
- openvpn_decrypt (&buf, decrypt_workspace, co, frame);
+ openvpn_decrypt (&buf, decrypt_workspace, co, frame, BPTR (&buf));
/* compare */
if (buf.len != src.len)
@@ -741,90 +1089,47 @@ test_crypto (const struct crypto_options *co, struct frame* frame)
gc_free (&gc);
}
-#ifdef ENABLE_SSL
-
void
-get_tls_handshake_key (const struct key_type *key_type,
- struct key_ctx_bi *ctx,
- const char *passphrase_file,
- const int key_direction,
- const unsigned int flags)
+crypto_read_openvpn_key (const struct key_type *key_type,
+ struct key_ctx_bi *ctx, const char *key_file, const char *key_inline,
+ const int key_direction, const char *key_name, const char *opt_name)
{
- if (passphrase_file && key_type->hmac_length)
- {
- struct key2 key2;
- struct key_type kt = *key_type;
- struct key_direction_state kds;
-
- /* for control channel we are only authenticating, not encrypting */
- kt.cipher_length = 0;
- kt.cipher = NULL;
-
- if (flags & GHK_INLINE)
- {
- /* key was specified inline, key text is in passphrase_file */
- read_key_file (&key2, passphrase_file, RKF_INLINE|RKF_MUST_SUCCEED);
-
- /* succeeded? */
- if (key2.n == 2)
- msg (M_INFO, "Control Channel Authentication: tls-auth using INLINE static key file");
- else
- msg (M_FATAL, "INLINE tls-auth file lacks the requisite 2 keys");
- }
- else
- {
- /* first try to parse as an OpenVPN static key file */
- read_key_file (&key2, passphrase_file, 0);
-
- /* succeeded? */
- if (key2.n == 2)
- {
- msg (M_INFO,
- "Control Channel Authentication: using '%s' as a " PACKAGE_NAME " static key file",
- passphrase_file);
- }
- else
- {
- int hash_size;
-
- CLEAR (key2);
-
- /* failed, now try to get hash from a freeform file */
- hash_size = read_passphrase_hash (passphrase_file,
- kt.digest,
- key2.keys[0].hmac,
- MAX_HMAC_KEY_LENGTH);
- ASSERT (hash_size == kt.hmac_length);
+ struct key2 key2;
+ struct key_direction_state kds;
+ char log_prefix[128] = { 0 };
- /* suceeded */
- key2.n = 1;
+ if (key_inline)
+ {
+ read_key_file (&key2, key_inline, RKF_MUST_SUCCEED|RKF_INLINE);
+ }
+ else
+ {
+ read_key_file (&key2, key_file, RKF_MUST_SUCCEED);
+ }
- msg (M_INFO,
- "Control Channel Authentication: using '%s' as a free-form passphrase file",
- passphrase_file);
- msg (M_WARN, "DEPRECATED OPTION: Using freeform files for tls-auth is deprecated and is not supported in OpenVPN 2.4 or newer versions");
- }
- }
- /* handle key direction */
+ if (key2.n != 2)
+ {
+ msg (M_ERR, "File '%s' does not have OpenVPN Static Key format. Using "
+ "free-form passphrase file is not supported anymore.", key_file);
+ }
- key_direction_state_init (&kds, key_direction);
- must_have_n_keys (passphrase_file, "tls-auth", &key2, kds.need_keys);
+ /* check for and fix highly unlikely key problems */
+ verify_fix_key2 (&key2, key_type, key_file);
- /* initialize hmac key in both directions */
+ /* handle key direction */
+ key_direction_state_init (&kds, key_direction);
+ must_have_n_keys (key_file, opt_name, &key2, kds.need_keys);
- init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], &kt, OPENVPN_OP_ENCRYPT,
- "Outgoing Control Channel Authentication");
- init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], &kt, OPENVPN_OP_DECRYPT,
- "Incoming Control Channel Authentication");
+ /* initialize key in both directions */
+ openvpn_snprintf (log_prefix, sizeof (log_prefix), "Outgoing %s", key_name);
+ init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], key_type,
+ OPENVPN_OP_ENCRYPT, log_prefix);
+ openvpn_snprintf (log_prefix, sizeof (log_prefix), "Incoming %s", key_name);
+ init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], key_type,
+ OPENVPN_OP_DECRYPT, log_prefix);
- CLEAR (key2);
- }
- else
- {
- CLEAR (*ctx);
- }
+ CLEAR (key2);
}
-#endif
/* header and footer for static key file */
static const char static_key_head[] = "-----BEGIN OpenVPN Static key V1-----";
@@ -1002,9 +1307,6 @@ read_key_file (struct key2 *key2, const char *file, const unsigned int flags)
if (!(flags & RKF_INLINE))
buf_clear (&in);
- if (key2->n)
- warn_if_group_others_accessible (error_filename);
-
#if 0
/* DEBUGGING */
{
@@ -1028,55 +1330,6 @@ read_key_file (struct key2 *key2, const char *file, const unsigned int flags)
gc_free (&gc);
}
-int
-read_passphrase_hash (const char *passphrase_file,
- const md_kt_t *digest,
- uint8_t *output,
- int len)
-{
- unsigned int outlen = 0;
- md_ctx_t md;
-
- ASSERT (len >= md_kt_size(digest));
- memset (output, 0, len);
-
- md_ctx_init(&md, digest);
-
- /* read passphrase file */
- {
- const int min_passphrase_size = 8;
- uint8_t buf[64];
- int total_size = 0;
- int fd = platform_open (passphrase_file, O_RDONLY, 0);
-
- if (fd == -1)
- msg (M_ERR, "Cannot open passphrase file: '%s'", passphrase_file);
-
- for (;;)
- {
- int size = read (fd, buf, sizeof (buf));
- if (size == 0)
- break;
- if (size == -1)
- msg (M_ERR, "Read error on passphrase file: '%s'",
- passphrase_file);
- md_ctx_update(&md, buf, size);
- total_size += size;
- }
- close (fd);
-
- warn_if_group_others_accessible (passphrase_file);
-
- if (total_size < min_passphrase_size)
- msg (M_FATAL,
- "Passphrase file '%s' is too small (must have at least %d characters)",
- passphrase_file, min_passphrase_size);
- }
- md_ctx_final(&md, output);
- md_ctx_cleanup(&md);
- return md_kt_size(digest);
-}
-
/*
* Write key to file, return number of random bits
* written.
@@ -1367,7 +1620,6 @@ prng_bytes (uint8_t *output, int len)
const int md_size = md_kt_size (nonce_md);
while (len > 0)
{
- unsigned int outlen = 0;
const int blen = min_int (len, md_size);
md_full(nonce_md, nonce_data, md_size + nonce_secret_len, nonce_data);
memcpy (output, nonce_data, blen);
@@ -1397,79 +1649,42 @@ get_random()
return l;
}
-#ifndef ENABLE_SSL
+static const cipher_name_pair *
+get_cipher_name_pair(const char *cipher_name) {
+ const cipher_name_pair *pair;
+ size_t i = 0;
-void
-init_ssl_lib (void)
-{
- crypto_init_lib ();
-}
+ /* Search for a cipher name translation */
+ for (; i < cipher_name_translation_table_count; i++)
+ {
+ pair = &cipher_name_translation_table[i];
+ if (0 == strcmp (cipher_name, pair->openvpn_name) ||
+ 0 == strcmp (cipher_name, pair->lib_name))
+ return pair;
+ }
-void
-free_ssl_lib (void)
-{
- crypto_uninit_lib ();
- prng_uninit();
+ /* Nothing found, return null */
+ return NULL;
}
-#endif /* ENABLE_SSL */
-
-/*
- * md5 functions
- */
-
const char *
-md5sum (uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc)
-{
- uint8_t digest[MD5_DIGEST_LENGTH];
- const md_kt_t *md5_kt = md_kt_get("MD5");
-
- md_full(md5_kt, buf, len, digest);
-
- return format_hex (digest, MD5_DIGEST_LENGTH, n_print_chars, gc);
-}
-
-void
-md5_state_init (struct md5_state *s)
-{
- const md_kt_t *md5_kt = md_kt_get("MD5");
-
- md_ctx_init(&s->ctx, md5_kt);
-}
+translate_cipher_name_from_openvpn (const char *cipher_name) {
+ const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
-void
-md5_state_update (struct md5_state *s, void *data, size_t len)
-{
- md_ctx_update(&s->ctx, data, len);
-}
+ if (NULL == pair)
+ return cipher_name;
-void
-md5_state_final (struct md5_state *s, struct md5_digest *out)
-{
- md_ctx_final(&s->ctx, out->digest);
- md_ctx_cleanup(&s->ctx);
+ return pair->lib_name;
}
-void
-md5_digest_clear (struct md5_digest *digest)
-{
- CLEAR (*digest);
-}
+const char *
+translate_cipher_name_to_openvpn (const char *cipher_name) {
+ const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
-bool
-md5_digest_defined (const struct md5_digest *digest)
-{
- int i;
- for (i = 0; i < MD5_DIGEST_LENGTH; ++i)
- if (digest->digest[i])
- return true;
- return false;
-}
+ if (NULL == pair)
+ return cipher_name;
-bool
-md5_digest_equal (const struct md5_digest *d1, const struct md5_digest *d2)
-{
- return memcmp(d1->digest, d2->digest, MD5_DIGEST_LENGTH) == 0;
+ return pair->openvpn_name;
}
#endif /* ENABLE_CRYPTO */
diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h
index e489827..ff90745 100644
--- a/src/openvpn/crypto.h
+++ b/src/openvpn/crypto.h
@@ -86,6 +86,30 @@
* <tt> [ HMAC ] [ - IV - ] [ * packet payload * ] </tt>
*
* @par
+ * <b>GCM data channel crypto format</b> \n
+ * GCM modes are only supported in TLS mode. In these modes, the IV consists of
+ * the 32-bit packet counter followed by data from the HMAC key. The HMAC key
+ * can be used as IV, since in GCM and CCM modes the HMAC key is not used for
+ * the HMAC. The packet counter may not roll over within a single TLS sessions.
+ * This results in a unique IV for each packet, as required by GCM.
+ *
+ * @par
+ * The HMAC key data is pre-shared during the connection setup, and thus can be
+ * omitted in on-the-wire packets, saving 8 bytes per packet (for GCM and CCM).
+ *
+ * @par
+ * In GCM mode, P_DATA_V2 headers (the opcode and peer-id) are also
+ * authenticated as Additional Data.
+ *
+ * @par
+ * <i>GCM IV format:</i> \n
+ * <tt> [ - packet ID - ] [ - HMAC key data - ] </tt>\n
+ * <i>P_DATA_V1 GCM data channel crypto format:</i> \n
+ * <tt> [ opcode ] [ - packet ID - ] [ TAG ] [ * packet payload * ] </tt>
+ * <i>P_DATA_V2 GCM data channel crypto format:</i> \n
+ * <tt> [ - opcode/peer-id - ] [ - packet ID - ] [ TAG ] [ * packet payload * ] </tt>
+ *
+ * @par
* <b>No-crypto data channel format</b> \n
* In no-crypto mode (\c \-\-cipher \c none is specified), both TLS-mode and
* static key mode are supported. No encryption will be performed on the packet,
@@ -108,6 +132,11 @@
#include "packet_id.h"
#include "mtu.h"
+/** Wrapper struct to pass around MD5 digests */
+struct md5_digest {
+ uint8_t digest[MD5_DIGEST_LENGTH];
+};
+
/*
* Defines a key type and key length for both cipher and HMAC.
*/
@@ -133,13 +162,16 @@ struct key
/**
- * Container for one set of OpenSSL cipher and/or HMAC contexts.
+ * Container for one set of cipher and/or HMAC contexts.
* @ingroup control_processor
*/
struct key_ctx
{
cipher_ctx_t *cipher; /**< Generic cipher %context. */
- hmac_ctx_t *hmac; /**< Generic HMAC %context. */
+ hmac_ctx_t *hmac; /**< Generic HMAC %context. */
+ uint8_t implicit_iv[OPENVPN_MAX_IV_LENGTH];
+ /**< The implicit part of the IV */
+ size_t implicit_iv_len; /**< The length of implicit_iv */
};
#define KEY_DIRECTION_BIDIRECTIONAL 0 /* same keys for both directions */
@@ -190,10 +222,11 @@ struct key_direction_state
*/
struct key_ctx_bi
{
- struct key_ctx encrypt; /**< OpenSSL cipher and/or HMAC contexts
- * for sending direction. */
- struct key_ctx decrypt; /**< OpenSSL cipher and/or HMAC contexts
- * for receiving direction. */
+ struct key_ctx encrypt; /**< Cipher and/or HMAC contexts for sending
+ * direction. */
+ struct key_ctx decrypt; /**< cipher and/or HMAC contexts for
+ * receiving direction. */
+ bool initialized;
};
/**
@@ -202,11 +235,11 @@ struct key_ctx_bi
*/
struct crypto_options
{
- struct key_ctx_bi *key_ctx_bi;
+ struct key_ctx_bi key_ctx_bi;
/**< OpenSSL cipher and HMAC contexts for
* both sending and receiving
* directions. */
- struct packet_id *packet_id; /**< Current packet ID state for both
+ struct packet_id packet_id; /**< Current packet ID state for both
* sending and receiving directions. */
struct packet_id_persist *pid_persist;
/**< Persistent packet ID state for
@@ -233,6 +266,15 @@ struct crypto_options
* security operation functions. */
};
+#define CRYPT_ERROR(format) \
+ do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false)
+
+/**
+ * Minimal IV length for AEAD mode ciphers (in bytes):
+ * 4-byte packet id + 8 bytes implicit IV.
+ */
+#define OPENVPN_AEAD_MIN_IV_LEN (sizeof (packet_id_type) + 8)
+
#define RKF_MUST_SUCCEED (1<<0)
#define RKF_INLINE (1<<1)
void read_key_file (struct key2 *key2, const char *file, const unsigned int flags);
@@ -257,9 +299,20 @@ bool write_key (const struct key *key, const struct key_type *kt,
int read_key (struct key *key, const struct key_type *kt, struct buffer *buf);
+/**
+ * Initialize a key_type structure with.
+ *
+ * @param kt The struct key_type to initialize
+ * @param ciphername The name of the cipher to use
+ * @param authname The name of the HMAC digest to use
+ * @param keysize The length of the cipher key to use, in bytes. Only valid
+ * for ciphers that support variable length keys.
+ * @param tls_mode Specifies wether we are running in TLS mode, which allows
+ * more ciphers than static key mode.
+ * @param warn Print warnings when null cipher / auth is used.
+ */
void init_key_type (struct key_type *kt, const char *ciphername,
- bool ciphername_defined, const char *authname, bool authname_defined,
- int keysize, bool cfb_ofb_allowed, bool warn);
+ const char *authname, int keysize, bool tls_mode, bool warn);
/*
* Key context functions
@@ -296,18 +349,16 @@ void free_key_ctx_bi (struct key_ctx_bi *ctx);
*
* @param buf - The %buffer containing the packet on which to
* perform security operations.
- * @param work - A working %buffer.
+ * @param work - An initialized working %buffer.
* @param opt - The security parameter state for this VPN tunnel.
- * @param frame - The packet geometry parameters for this VPN
- * tunnel.
+ *
* @return This function returns void.\n On return, the \a buf argument
* will point to the resulting %buffer. This %buffer will either
* contain the processed packet ready for sending, or be empty if an
* error occurred.
*/
void openvpn_encrypt (struct buffer *buf, struct buffer work,
- const struct crypto_options *opt,
- const struct frame* frame);
+ struct crypto_options *opt);
/**
@@ -333,6 +384,8 @@ void openvpn_encrypt (struct buffer *buf, struct buffer work,
* @param opt - The security parameter state for this VPN tunnel.
* @param frame - The packet geometry parameters for this VPN
* tunnel.
+ * @param ad_start - A pointer into buf, indicating from where to start
+ * authenticating additional data (AEAD mode only).
*
* @return
* @li True, if the packet was authenticated and decrypted successfully.
@@ -342,18 +395,35 @@ void openvpn_encrypt (struct buffer *buf, struct buffer work,
* an error occurred.
*/
bool openvpn_decrypt (struct buffer *buf, struct buffer work,
- const struct crypto_options *opt,
- const struct frame* frame);
+ struct crypto_options *opt, const struct frame* frame,
+ const uint8_t *ad_start);
/** @} name Functions for performing security operations on data channel packets */
+/**
+ * Check packet ID for replay, and perform replay administration.
+ *
+ * @param opt Crypto options for this packet, contains replay state.
+ * @param pin Packet ID read from packet.
+ * @param error_prefix Prefix to use when printing error messages.
+ * @param gc Garbage collector to use.
+ *
+ * @return true if packet ID is validated to be not a replay, false otherwise.
+ */
+bool crypto_check_replay(struct crypto_options *opt,
+ const struct packet_id_net *pin, const char *error_prefix,
+ struct gc_arena *gc);
+
+
+/** Calculate crypto overhead and adjust frame to account for that */
void crypto_adjust_frame_parameters(struct frame *frame,
const struct key_type* kt,
- bool cipher_defined,
bool use_iv,
bool packet_id,
bool packet_id_long_form);
+/** Return the worst-case OpenVPN crypto overhead (in bytes) */
+size_t crypto_max_overhead(void);
/* Minimum length of the nonce used by the PRNG */
#define NONCE_SECRET_LEN_MIN 16
@@ -392,7 +462,7 @@ void prng_bytes (uint8_t *output, int len);
void prng_uninit ();
-void test_crypto (const struct crypto_options *co, struct frame* f);
+void test_crypto (struct crypto_options *co, struct frame* f);
/* key direction functions */
@@ -413,45 +483,31 @@ void key2_print (const struct key2* k,
const char* prefix0,
const char* prefix1);
-#ifdef ENABLE_SSL
-
-#define GHK_INLINE (1<<0)
-void get_tls_handshake_key (const struct key_type *key_type,
- struct key_ctx_bi *ctx,
- const char *passphrase_file,
- const int key_direction,
- const unsigned int flags);
-
-#else
-
-void init_ssl_lib (void);
-void free_ssl_lib (void);
-
-#endif /* ENABLE_SSL */
+void crypto_read_openvpn_key (const struct key_type *key_type,
+ struct key_ctx_bi *ctx, const char *key_file, const char *key_inline,
+ const int key_direction, const char *key_name, const char *opt_name);
/*
- * md5 functions
+ * Inline functions
*/
-struct md5_state {
- md_ctx_t ctx;
-};
-
-struct md5_digest {
- uint8_t digest [MD5_DIGEST_LENGTH];
-};
-
-const char *md5sum(uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc);
-void md5_state_init (struct md5_state *s);
-void md5_state_update (struct md5_state *s, void *data, size_t len);
-void md5_state_final (struct md5_state *s, struct md5_digest *out);
-void md5_digest_clear (struct md5_digest *digest);
-bool md5_digest_defined (const struct md5_digest *digest);
-bool md5_digest_equal (const struct md5_digest *d1, const struct md5_digest *d2);
-
-/*
- * Inline functions
+/**
+ * As memcmp(), but constant-time.
+ * Returns 0 when data is equal, non-zero otherwise.
*/
+static inline int
+memcmp_constant_time (const void *a, const void *b, size_t size) {
+ const uint8_t * a1 = a;
+ const uint8_t * b1 = b;
+ int ret = 0;
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ ret |= *a1++ ^ *b1++;
+ }
+
+ return ret;
+}
static inline bool
key_ctx_bi_defined(const struct key_ctx_bi* key)
diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h
index 4c1ce9f..bf7d78c 100644
--- a/src/openvpn/crypto_backend.h
+++ b/src/openvpn/crypto_backend.h
@@ -33,11 +33,29 @@
#ifdef ENABLE_CRYPTO_OPENSSL
#include "crypto_openssl.h"
#endif
-#ifdef ENABLE_CRYPTO_POLARSSL
-#include "crypto_polarssl.h"
+#ifdef ENABLE_CRYPTO_MBEDTLS
+#include "crypto_mbedtls.h"
#endif
#include "basic.h"
+/* TLS uses a tag of 128 bytes, let's do the same for OpenVPN */
+#define OPENVPN_AEAD_TAG_LENGTH 16
+
+/* Maximum cipher block size (bytes) */
+#define OPENVPN_MAX_CIPHER_BLOCK_SIZE 32
+
+/* Maximum HMAC digest size (bytes) */
+#define OPENVPN_MAX_HMAC_SIZE 64
+
+/** Struct used in cipher name translation table */
+typedef struct {
+ const char *openvpn_name; /**< Cipher name used by OpenVPN */
+ const char *lib_name; /**< Cipher name used by crypto library */
+} cipher_name_pair;
+
+/** Cipher name translation table */
+extern const cipher_name_pair cipher_name_translation_table[];
+extern const size_t cipher_name_translation_table_count;
/*
* This routine should have additional OpenSSL crypto library initialisations
@@ -177,7 +195,8 @@ void cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH],
* \c AES-128-CBC).
*
* @return A statically allocated structure containing parameters
- * for the given cipher.
+ * for the given cipher, or NULL if no matching parameters
+ * were found.
*/
const cipher_kt_t * cipher_kt_get (const char *ciphername);
@@ -221,6 +240,16 @@ int cipher_kt_iv_size (const cipher_kt_t *cipher_kt);
int cipher_kt_block_size (const cipher_kt_t *cipher_kt);
/**
+ * Returns the MAC tag size of the cipher, in bytes.
+ *
+ * @param ctx Static cipher parameters.
+ *
+ * @return Tag size in bytes, or 0 if the tag size could not be
+ * determined.
+ */
+int cipher_kt_tag_size (const cipher_kt_t *cipher_kt);
+
+/**
* Returns the mode that the cipher runs in.
*
* @param cipher_kt Static cipher parameters. May not be NULL.
@@ -248,6 +277,15 @@ bool cipher_kt_mode_cbc(const cipher_kt_t *cipher);
*/
bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher);
+/**
+ * Check if the supplied cipher is a supported AEAD mode cipher.
+ *
+ * @param cipher Static cipher parameters.
+ *
+ * @return true iff the cipher is a AEAD mode cipher.
+ */
+bool cipher_kt_mode_aead(const cipher_kt_t *cipher);
+
/**
*
@@ -263,7 +301,7 @@ bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher);
* @param key_len Length of the key, in bytes
* @param kt Static cipher parameters to use
* @param enc Whether to encrypt or decrypt (either
- * \c POLARSSL_OP_ENCRYPT or \c POLARSSL_OP_DECRYPT).
+ * \c MBEDTLS_OP_ENCRYPT or \c MBEDTLS_OP_DECRYPT).
*/
void cipher_ctx_init (cipher_ctx_t *ctx, uint8_t *key, int key_len,
const cipher_kt_t *kt, int enc);
@@ -287,6 +325,15 @@ void cipher_ctx_cleanup (cipher_ctx_t *ctx);
int cipher_ctx_iv_length (const cipher_ctx_t *ctx);
/**
+ * Gets the computed message authenticated code (MAC) tag for this cipher.
+ *
+ * @param ctx The cipher's context
+ * @param tag The buffer to write computed tag in.
+ * @param tag_size The tag buffer size, in bytes.
+ */
+int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len);
+
+/**
* Returns the block size of the cipher, in bytes.
*
* @param ctx The cipher's context
@@ -308,12 +355,12 @@ int cipher_ctx_mode (const cipher_ctx_t *ctx);
/**
* Returns the static cipher parameters for this context.
*
- * @param ctx Cipher's context. May not be NULL.
+ * @param ctx Cipher's context.
*
- * @return Static cipher parameters for the supplied context.
+ * @return Static cipher parameters for the supplied context, or
+ * NULL if unable to determine cipher parameters.
*/
-const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
- __attribute__((nonnull));
+const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx);
/**
* Resets the given cipher context, setting the IV to the specified value.
@@ -327,6 +374,18 @@ const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
int cipher_ctx_reset (cipher_ctx_t *ctx, uint8_t *iv_buf);
/**
+ * Updates the given cipher context, providing additional data (AD) for
+ * authenticated encryption with additional data (AEAD) cipher modes.
+ *
+ * @param ctx Cipher's context. May not be NULL.
+ * @param src Source buffer
+ * @param src_len Length of the source buffer, in bytes
+ *
+ * @return \c 0 on failure, \c 1 on success.
+ */
+int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len);
+
+/**
* Updates the given cipher context, encrypting data in the source buffer, and
* placing any complete blocks in the destination buffer.
*
@@ -358,6 +417,23 @@ int cipher_ctx_update (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len,
*/
int cipher_ctx_final (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len);
+/**
+ * Like \c cipher_ctx_final, but check the computed authentication tag against
+ * the supplied (expected) tag. This function reports failure when the tags
+ * don't match.
+ *
+ * @param ctx Cipher's context. May not be NULL.
+ * @param dst Destination buffer.
+ * @param dst_len Length of the destination buffer, in bytes.
+ * @param tag The expected authentication tag.
+ * @param tag_len The length of tag, in bytes.
+ *
+ * @return \c 0 on failure, \c 1 on success.
+ */
+int cipher_ctx_final_check_tag (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len,
+ uint8_t *tag, size_t tag_len);
+
+
/*
*
* Generic message digest information functions
@@ -525,4 +601,24 @@ void hmac_ctx_update (hmac_ctx_t *ctx, const uint8_t *src, int src_len);
*/
void hmac_ctx_final (hmac_ctx_t *ctx, uint8_t *dst);
+/**
+ * Translate an OpenVPN cipher name to a crypto library cipher name.
+ *
+ * @param cipher_name An OpenVPN cipher name
+ *
+ * @return The corresponding crypto library cipher name, or NULL
+ * if no matching cipher name was found.
+ */
+const char * translate_cipher_name_from_openvpn (const char *cipher_name);
+
+/**
+ * Translate a crypto library cipher name to an OpenVPN cipher name.
+ *
+ * @param cipher_name A crypto library cipher name
+ *
+ * @return The corresponding OpenVPN cipher name, or NULL if no
+ * matching cipher name was found.
+ */
+const char * translate_cipher_name_to_openvpn (const char *cipher_name);
+
#endif /* CRYPTO_BACKEND_H_ */
diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c
new file mode 100644
index 0000000..6ad5924
--- /dev/null
+++ b/src/openvpn/crypto_mbedtls.c
@@ -0,0 +1,785 @@
+/*
+ * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
+ *
+ * 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
+ */
+
+/**
+ * @file Data Channel Cryptography mbed TLS-specific backend interface
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS)
+
+#include "errlevel.h"
+#include "basic.h"
+#include "buffer.h"
+#include "integer.h"
+#include "crypto_backend.h"
+#include "otime.h"
+#include "misc.h"
+
+#include <mbedtls/des.h>
+#include <mbedtls/error.h>
+#include <mbedtls/md5.h>
+#include <mbedtls/cipher.h>
+#include <mbedtls/havege.h>
+
+#include <mbedtls/entropy.h>
+
+
+/*
+ *
+ * Hardware engine support. Allows loading/unloading of engines.
+ *
+ */
+
+void
+crypto_init_lib_engine (const char *engine_name)
+{
+ msg (M_WARN, "Note: mbed TLS hardware crypto engine functionality is not "
+ "available");
+}
+
+/*
+ *
+ * Functions related to the core crypto library
+ *
+ */
+
+void
+crypto_init_lib (void)
+{
+}
+
+void
+crypto_uninit_lib (void)
+{
+}
+
+void
+crypto_clear_error (void)
+{
+}
+
+bool mbed_log_err(unsigned int flags, int errval, const char *prefix)
+{
+ if (0 != errval)
+ {
+ char errstr[256];
+ mbedtls_strerror(errval, errstr, sizeof(errstr));
+
+ if (NULL == prefix) prefix = "mbed TLS error";
+ msg (flags, "%s: %s", prefix, errstr);
+ }
+
+ return 0 == errval;
+}
+
+bool mbed_log_func_line(unsigned int flags, int errval, const char *func,
+ int line)
+{
+ char prefix[256];
+
+ if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line))
+ return mbed_log_err(flags, errval, func);
+
+ return mbed_log_err(flags, errval, prefix);
+}
+
+
+#ifdef DMALLOC
+void
+crypto_init_dmalloc (void)
+{
+ msg (M_ERR, "Error: dmalloc support is not available for mbed TLS.");
+}
+#endif /* DMALLOC */
+
+const cipher_name_pair cipher_name_translation_table[] = {
+ { "BF-CBC", "BLOWFISH-CBC" },
+ { "BF-CFB", "BLOWFISH-CFB64" },
+ { "CAMELLIA-128-CFB", "CAMELLIA-128-CFB128" },
+ { "CAMELLIA-192-CFB", "CAMELLIA-192-CFB128" },
+ { "CAMELLIA-256-CFB", "CAMELLIA-256-CFB128" }
+};
+const size_t cipher_name_translation_table_count =
+ sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table);
+
+static void print_cipher(const cipher_kt_t *info)
+{
+ if (info && (cipher_kt_mode_cbc(info)
+#ifdef HAVE_AEAD_CIPHER_MODES
+ || cipher_kt_mode_aead(info)
+#endif
+ ))
+ {
+ const char *ssl_only = cipher_kt_mode_cbc(info) ?
+ "" : ", TLS client/server mode only";
+ const char *var_key_size = info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ?
+ " by default" : "";
+
+ printf ("%s (%d bit key%s, %d bit block%s)\n",
+ cipher_kt_name(info), cipher_kt_key_size(info) * 8, var_key_size,
+ cipher_kt_block_size(info) * 8, ssl_only);
+ }
+}
+
+void
+show_available_ciphers ()
+{
+ const int *ciphers = mbedtls_cipher_list();
+
+#ifndef ENABLE_SMALL
+ printf ("The following ciphers and cipher modes are available for use\n"
+ "with " PACKAGE_NAME ". Each cipher shown below may be used as a\n"
+ "parameter to the --cipher option. Using a CBC or GCM mode is\n"
+ "recommended. In static key mode only CBC mode is allowed.\n\n");
+#endif
+
+ while (*ciphers != 0)
+ {
+ const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers);
+ if (info && cipher_kt_block_size(info) >= 128/8)
+ {
+ print_cipher(info);
+ }
+ ciphers++;
+ }
+
+ printf ("\nThe following ciphers have a block size of less than 128 bits, \n"
+ "and are therefore deprecated. Do not use unless you have to.\n\n");
+ ciphers = mbedtls_cipher_list();
+ while (*ciphers != 0)
+ {
+ const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers);
+ if (info && cipher_kt_block_size(info) < 128/8)
+ {
+ print_cipher(info);
+ }
+ ciphers++;
+ }
+ printf ("\n");
+}
+
+void
+show_available_digests ()
+{
+ const int *digests = mbedtls_md_list();
+
+#ifndef ENABLE_SMALL
+ printf ("The following message digests are available for use with\n"
+ PACKAGE_NAME ". A message digest is used in conjunction with\n"
+ "the HMAC function, to authenticate received packets.\n"
+ "You can specify a message digest as parameter to\n"
+ "the --auth option.\n\n");
+#endif
+
+ while (*digests != 0)
+ {
+ const mbedtls_md_info_t *info = mbedtls_md_info_from_type(*digests);
+
+ if (info)
+ printf ("%s %d bit default key\n", mbedtls_md_get_name(info),
+ mbedtls_md_get_size(info) * 8);
+ digests++;
+ }
+ printf ("\n");
+}
+
+void
+show_available_engines ()
+{
+ printf ("Sorry, mbed TLS hardware crypto engine functionality is not "
+ "available\n");
+}
+
+/*
+ *
+ * Random number functions, used in cases where we want
+ * reasonably strong cryptographic random number generation
+ * without depleting our entropy pool. Used for random
+ * IV values and a number of other miscellaneous tasks.
+ *
+ */
+
+/*
+ * Initialise the given ctr_drbg context, using a personalisation string and an
+ * entropy gathering function.
+ */
+mbedtls_ctr_drbg_context * rand_ctx_get()
+{
+ static mbedtls_entropy_context ec = {0};
+ static mbedtls_ctr_drbg_context cd_ctx = {0};
+ static bool rand_initialised = false;
+
+ if (!rand_initialised)
+ {
+ struct gc_arena gc = gc_new();
+ struct buffer pers_string = alloc_buf_gc(100, &gc);
+
+ /*
+ * Personalisation string, should be as unique as possible (see NIST
+ * 800-90 section 8.7.1). We have very little information at this stage.
+ * Include Program Name, memory address of the context and PID.
+ */
+ buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(), &cd_ctx, time_string(0, 0, 0, &gc));
+
+ /* Initialise mbed TLS RNG, and built-in entropy sources */
+ mbedtls_entropy_init(&ec);
+
+ mbedtls_ctr_drbg_init(&cd_ctx);
+ if (!mbed_ok(mbedtls_ctr_drbg_seed(&cd_ctx, mbedtls_entropy_func, &ec,
+ BPTR(&pers_string), BLEN(&pers_string))))
+ msg (M_FATAL, "Failed to initialize random generator");
+
+ gc_free(&gc);
+ rand_initialised = true;
+ }
+
+ return &cd_ctx;
+}
+
+#ifdef ENABLE_PREDICTION_RESISTANCE
+void rand_ctx_enable_prediction_resistance()
+{
+ mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get();
+
+ mbedtls_ctr_drbg_set_prediction_resistance(cd_ctx, 1);
+}
+#endif /* ENABLE_PREDICTION_RESISTANCE */
+
+int
+rand_bytes (uint8_t *output, int len)
+{
+ mbedtls_ctr_drbg_context *rng_ctx = rand_ctx_get();
+
+ while (len > 0)
+ {
+ const size_t blen = min_int (len, MBEDTLS_CTR_DRBG_MAX_REQUEST);
+ if (0 != mbedtls_ctr_drbg_random(rng_ctx, output, blen))
+ return 0;
+
+ output += blen;
+ len -= blen;
+ }
+
+ return 1;
+}
+
+/*
+ *
+ * Key functions, allow manipulation of keys.
+ *
+ */
+
+
+int
+key_des_num_cblocks (const mbedtls_cipher_info_t *kt)
+{
+ int ret = 0;
+ if (kt->type == MBEDTLS_CIPHER_DES_CBC)
+ ret = 1;
+ if (kt->type == MBEDTLS_CIPHER_DES_EDE_CBC)
+ ret = 2;
+ if (kt->type == MBEDTLS_CIPHER_DES_EDE3_CBC)
+ ret = 3;
+
+ dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret);
+ return ret;
+}
+
+bool
+key_des_check (uint8_t *key, int key_len, int ndc)
+{
+ int i;
+ struct buffer b;
+
+ buf_set_read (&b, key, key_len);
+
+ for (i = 0; i < ndc; ++i)
+ {
+ unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE);
+ if (!key)
+ {
+ msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material");
+ goto err;
+ }
+ if (0 != mbedtls_des_key_check_weak(key))
+ {
+ msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected");
+ goto err;
+ }
+ if (0 != mbedtls_des_key_check_key_parity(key))
+ {
+ msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected");
+ goto err;
+ }
+ }
+ return true;
+
+ err:
+ return false;
+}
+
+void
+key_des_fixup (uint8_t *key, int key_len, int ndc)
+{
+ int i;
+ struct buffer b;
+
+ buf_set_read (&b, key, key_len);
+ for (i = 0; i < ndc; ++i)
+ {
+ unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE);
+ if (!key)
+ {
+ msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material");
+ return;
+ }
+ mbedtls_des_key_set_parity(key);
+ }
+}
+
+/*
+ *
+ * Generic cipher key type functions
+ *
+ */
+
+
+const mbedtls_cipher_info_t *
+cipher_kt_get (const char *ciphername)
+{
+ const mbedtls_cipher_info_t *cipher = NULL;
+
+ ASSERT (ciphername);
+
+ cipher = mbedtls_cipher_info_from_string(ciphername);
+
+ if (NULL == cipher)
+ {
+ msg (D_LOW, "Cipher algorithm '%s' not found", ciphername);
+ return NULL;
+ }
+
+ if (cipher->key_bitlen/8 > MAX_CIPHER_KEY_LENGTH)
+ {
+ msg (D_LOW, "Cipher algorithm '%s' uses a default key size (%d bytes) "
+ "which is larger than " PACKAGE_NAME "'s current maximum key size "
+ "(%d bytes)", ciphername, cipher->key_bitlen/8, MAX_CIPHER_KEY_LENGTH);
+ return NULL;
+ }
+
+ return cipher;
+}
+
+const char *
+cipher_kt_name (const mbedtls_cipher_info_t *cipher_kt)
+{
+ if (NULL == cipher_kt)
+ return "[null-cipher]";
+
+ return translate_cipher_name_to_openvpn(cipher_kt->name);
+}
+
+int
+cipher_kt_key_size (const mbedtls_cipher_info_t *cipher_kt)
+{
+ if (NULL == cipher_kt)
+ return 0;
+
+ return cipher_kt->key_bitlen/8;
+}
+
+int
+cipher_kt_iv_size (const mbedtls_cipher_info_t *cipher_kt)
+{
+ if (NULL == cipher_kt)
+ return 0;
+ return cipher_kt->iv_size;
+}
+
+int
+cipher_kt_block_size (const mbedtls_cipher_info_t *cipher_kt)
+{
+ if (NULL == cipher_kt)
+ return 0;
+ return cipher_kt->block_size;
+}
+
+int
+cipher_kt_tag_size (const mbedtls_cipher_info_t *cipher_kt)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+ if (cipher_kt && cipher_kt_mode_aead(cipher_kt))
+ return OPENVPN_AEAD_TAG_LENGTH;
+#endif
+ return 0;
+}
+
+int
+cipher_kt_mode (const mbedtls_cipher_info_t *cipher_kt)
+{
+ ASSERT(NULL != cipher_kt);
+ return cipher_kt->mode;
+}
+
+bool
+cipher_kt_mode_cbc(const cipher_kt_t *cipher)
+{
+ return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC;
+}
+
+bool
+cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
+{
+ return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB ||
+ cipher_kt_mode(cipher) == OPENVPN_MODE_CFB);
+}
+
+bool
+cipher_kt_mode_aead(const cipher_kt_t *cipher)
+{
+ return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_GCM;
+}
+
+
+/*
+ *
+ * Generic cipher context functions
+ *
+ */
+
+
+void
+cipher_ctx_init (mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len,
+ const mbedtls_cipher_info_t *kt, const mbedtls_operation_t operation)
+{
+ ASSERT(NULL != kt && NULL != ctx);
+
+ CLEAR (*ctx);
+
+ if (!mbed_ok(mbedtls_cipher_setup(ctx, kt)))
+ msg (M_FATAL, "mbed TLS cipher context init #1");
+
+ if (!mbed_ok(mbedtls_cipher_setkey(ctx, key, key_len*8, operation)))
+ msg (M_FATAL, "mbed TLS cipher set key");
+
+ /* make sure we used a big enough key */
+ ASSERT (ctx->key_bitlen <= key_len*8);
+}
+
+void cipher_ctx_cleanup (mbedtls_cipher_context_t *ctx)
+{
+ mbedtls_cipher_free(ctx);
+}
+
+int cipher_ctx_iv_length (const mbedtls_cipher_context_t *ctx)
+{
+ return mbedtls_cipher_get_iv_size(ctx);
+}
+
+int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+ if (tag_len > SIZE_MAX)
+ return 0;
+
+ if (!mbed_ok (mbedtls_cipher_write_tag (ctx, (unsigned char *) tag, tag_len)))
+ return 0;
+
+ return 1;
+#else
+ ASSERT(0);
+#endif /* HAVE_AEAD_CIPHER_MODES */
+}
+
+int cipher_ctx_block_size(const mbedtls_cipher_context_t *ctx)
+{
+ return mbedtls_cipher_get_block_size(ctx);
+}
+
+int cipher_ctx_mode (const mbedtls_cipher_context_t *ctx)
+{
+ ASSERT(NULL != ctx);
+
+ return cipher_kt_mode(ctx->cipher_info);
+}
+
+const cipher_kt_t *
+cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
+{
+ return ctx ? ctx->cipher_info : NULL;
+}
+
+int cipher_ctx_reset (mbedtls_cipher_context_t *ctx, uint8_t *iv_buf)
+{
+ if (!mbed_ok(mbedtls_cipher_reset(ctx)))
+ return 0;
+
+ if (!mbed_ok(mbedtls_cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size)))
+ return 0;
+
+ return 1;
+}
+
+int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+ if (src_len > SIZE_MAX)
+ return 0;
+
+ if (!mbed_ok (mbedtls_cipher_update_ad (ctx, src, src_len)))
+ return 0;
+
+ return 1;
+#else
+ ASSERT(0);
+#endif /* HAVE_AEAD_CIPHER_MODES */
+}
+
+int cipher_ctx_update (mbedtls_cipher_context_t *ctx, uint8_t *dst,
+ int *dst_len, uint8_t *src, int src_len)
+{
+ size_t s_dst_len = *dst_len;
+
+ if (!mbed_ok(mbedtls_cipher_update(ctx, src, (size_t) src_len, dst,
+ &s_dst_len)))
+ return 0;
+
+ *dst_len = s_dst_len;
+
+ return 1;
+}
+
+int cipher_ctx_final (mbedtls_cipher_context_t *ctx, uint8_t *dst, int *dst_len)
+{
+ size_t s_dst_len = *dst_len;
+
+ if (!mbed_ok(mbedtls_cipher_finish(ctx, dst, &s_dst_len)))
+ return 0;
+
+ *dst_len = s_dst_len;
+
+ return 1;
+}
+
+int cipher_ctx_final_check_tag (mbedtls_cipher_context_t *ctx, uint8_t *dst,
+ int *dst_len, uint8_t *tag, size_t tag_len)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+ size_t olen = 0;
+
+ if (MBEDTLS_DECRYPT != ctx->operation)
+ return 0;
+
+ if (tag_len > SIZE_MAX)
+ return 0;
+
+ if (!mbed_ok (mbedtls_cipher_finish (ctx, dst, &olen)))
+ {
+ msg (D_CRYPT_ERRORS, "%s: cipher_ctx_final() failed", __func__);
+ return 0;
+ }
+
+ if (olen > INT_MAX)
+ return 0;
+ *dst_len = olen;
+
+ if (!mbed_ok (mbedtls_cipher_check_tag (ctx, (const unsigned char *) tag,
+ tag_len)))
+ return 0;
+
+ return 1;
+#else
+ ASSERT(0);
+#endif /* HAVE_AEAD_CIPHER_MODES */
+}
+
+void
+cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH],
+ unsigned char *src,
+ unsigned char *dst)
+{
+ mbedtls_des_context ctx;
+
+ ASSERT (mbed_ok(mbedtls_des_setkey_enc(&ctx, key)));
+ ASSERT (mbed_ok(mbedtls_des_crypt_ecb(&ctx, src, dst)));
+}
+
+
+
+/*
+ *
+ * Generic message digest information functions
+ *
+ */
+
+
+const mbedtls_md_info_t *
+md_kt_get (const char *digest)
+{
+ const mbedtls_md_info_t *md = NULL;
+ ASSERT (digest);
+
+ md = mbedtls_md_info_from_string(digest);
+ if (!md)
+ msg (M_FATAL, "Message hash algorithm '%s' not found", digest);
+ if (mbedtls_md_get_size(md) > MAX_HMAC_KEY_LENGTH)
+ msg (M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d bytes)",
+ digest,
+ mbedtls_md_get_size(md),
+ MAX_HMAC_KEY_LENGTH);
+ return md;
+}
+
+const char *
+md_kt_name (const mbedtls_md_info_t *kt)
+{
+ if (NULL == kt)
+ return "[null-digest]";
+ return mbedtls_md_get_name (kt);
+}
+
+int
+md_kt_size (const mbedtls_md_info_t *kt)
+{
+ if (NULL == kt)
+ return 0;
+ return mbedtls_md_get_size(kt);
+}
+
+/*
+ *
+ * Generic message digest functions
+ *
+ */
+
+int
+md_full (const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst)
+{
+ return 0 == mbedtls_md(kt, src, src_len, dst);
+}
+
+
+void
+md_ctx_init (mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt)
+{
+ ASSERT(NULL != ctx && NULL != kt);
+
+ mbedtls_md_init(ctx);
+ ASSERT(0 == mbedtls_md_setup(ctx, kt, 0));
+ ASSERT(0 == mbedtls_md_starts(ctx));
+}
+
+void
+md_ctx_cleanup(mbedtls_md_context_t *ctx)
+{
+}
+
+int
+md_ctx_size (const mbedtls_md_context_t *ctx)
+{
+ if (NULL == ctx)
+ return 0;
+ return mbedtls_md_get_size(ctx->md_info);
+}
+
+void
+md_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len)
+{
+ ASSERT(0 == mbedtls_md_update(ctx, src, src_len));
+}
+
+void
+md_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst)
+{
+ ASSERT(0 == mbedtls_md_finish(ctx, dst));
+ mbedtls_md_free(ctx);
+}
+
+
+/*
+ *
+ * Generic HMAC functions
+ *
+ */
+
+
+/*
+ * TODO: re-enable dmsg for crypto debug
+ */
+void
+hmac_ctx_init (mbedtls_md_context_t *ctx, const uint8_t *key, int key_len,
+ const mbedtls_md_info_t *kt)
+{
+ ASSERT(NULL != kt && NULL != ctx);
+
+ mbedtls_md_init(ctx);
+ ASSERT(0 == mbedtls_md_setup(ctx, kt, 1));
+ ASSERT(0 == mbedtls_md_hmac_starts(ctx, key, key_len));
+
+ /* make sure we used a big enough key */
+ ASSERT (mbedtls_md_get_size(kt) <= key_len);
+}
+
+void
+hmac_ctx_cleanup(mbedtls_md_context_t *ctx)
+{
+ mbedtls_md_free(ctx);
+}
+
+int
+hmac_ctx_size (const mbedtls_md_context_t *ctx)
+{
+ if (NULL == ctx)
+ return 0;
+ return mbedtls_md_get_size(ctx->md_info);
+}
+
+void
+hmac_ctx_reset (mbedtls_md_context_t *ctx)
+{
+ ASSERT(0 == mbedtls_md_hmac_reset(ctx));
+}
+
+void
+hmac_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len)
+{
+ ASSERT(0 == mbedtls_md_hmac_update(ctx, src, src_len));
+}
+
+void
+hmac_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst)
+{
+ ASSERT(0 == mbedtls_md_hmac_finish(ctx, dst));
+}
+
+#endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_MBEDTLS */
diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_mbedtls.h
index 12b5146..574a63f 100644
--- a/src/openvpn/crypto_polarssl.h
+++ b/src/openvpn/crypto_mbedtls.h
@@ -24,48 +24,51 @@
*/
/**
- * @file Data Channel Cryptography PolarSSL-specific backend interface
+ * @file Data Channel Cryptography mbed TLS-specific backend interface
*/
-#ifndef CRYPTO_POLARSSL_H_
-#define CRYPTO_POLARSSL_H_
+#ifndef CRYPTO_MBEDTLS_H_
+#define CRYPTO_MBEDTLS_H_
-#include <polarssl/cipher.h>
-#include <polarssl/md.h>
-#include <polarssl/ctr_drbg.h>
+#include <mbedtls/cipher.h>
+#include <mbedtls/md.h>
+#include <mbedtls/ctr_drbg.h>
/** Generic cipher key type %context. */
-typedef cipher_info_t cipher_kt_t;
+typedef mbedtls_cipher_info_t cipher_kt_t;
/** Generic message digest key type %context. */
-typedef md_info_t md_kt_t;
+typedef mbedtls_md_info_t md_kt_t;
/** Generic cipher %context. */
-typedef cipher_context_t cipher_ctx_t;
+typedef mbedtls_cipher_context_t cipher_ctx_t;
/** Generic message digest %context. */
-typedef md_context_t md_ctx_t;
+typedef mbedtls_md_context_t md_ctx_t;
/** Generic HMAC %context. */
-typedef md_context_t hmac_ctx_t;
+typedef mbedtls_md_context_t hmac_ctx_t;
/** Maximum length of an IV */
-#define OPENVPN_MAX_IV_LENGTH POLARSSL_MAX_IV_LENGTH
+#define OPENVPN_MAX_IV_LENGTH MBEDTLS_MAX_IV_LENGTH
/** Cipher is in CBC mode */
-#define OPENVPN_MODE_CBC POLARSSL_MODE_CBC
+#define OPENVPN_MODE_CBC MBEDTLS_MODE_CBC
/** Cipher is in OFB mode */
-#define OPENVPN_MODE_OFB POLARSSL_MODE_OFB
+#define OPENVPN_MODE_OFB MBEDTLS_MODE_OFB
/** Cipher is in CFB mode */
-#define OPENVPN_MODE_CFB POLARSSL_MODE_CFB
+#define OPENVPN_MODE_CFB MBEDTLS_MODE_CFB
+
+/** Cipher is in GCM mode */
+#define OPENVPN_MODE_GCM MBEDTLS_MODE_GCM
/** Cipher should encrypt */
-#define OPENVPN_OP_ENCRYPT POLARSSL_ENCRYPT
+#define OPENVPN_OP_ENCRYPT MBEDTLS_ENCRYPT
/** Cipher should decrypt */
-#define OPENVPN_OP_DECRYPT POLARSSL_DECRYPT
+#define OPENVPN_OP_DECRYPT MBEDTLS_DECRYPT
#define MD4_DIGEST_LENGTH 16
#define MD5_DIGEST_LENGTH 16
@@ -73,16 +76,16 @@ typedef md_context_t hmac_ctx_t;
#define DES_KEY_LENGTH 8
/**
- * Returns a singleton instance of the PolarSSL random number generator.
+ * Returns a singleton instance of the mbed TLS random number generator.
*
- * For PolarSSL 1.1+, this is the CTR_DRBG random number generator. If it
+ * For PolarSSL/mbed TLS 1.1+, this is the CTR_DRBG random number generator. If it
* hasn't been initialised yet, the RNG will be initialised using the default
* entropy sources. Aside from the default platform entropy sources, an
* additional entropy source, the HAVEGE random number generator will also be
* added. During initialisation, a personalisation string will be added based
* on the time, the PID, and a pointer to the random context.
*/
-ctr_drbg_context * rand_ctx_get();
+mbedtls_ctr_drbg_context *rand_ctx_get();
#ifdef ENABLE_PREDICTION_RESISTANCE
/**
@@ -92,34 +95,34 @@ void rand_ctx_enable_prediction_resistance();
#endif
/**
- * Log the supplied PolarSSL error, prefixed by supplied prefix.
+ * Log the supplied mbed TLS error, prefixed by supplied prefix.
*
* @param flags Flags to indicate error type and priority.
- * @param errval PolarSSL error code to convert to error message.
- * @param prefix Prefix to PolarSSL error message.
+ * @param errval mbed TLS error code to convert to error message.
+ * @param prefix Prefix to mbed TLS error message.
*
* @returns true if no errors are detected, false otherwise.
*/
-bool polar_log_err(unsigned int flags, int errval, const char *prefix);
+bool mbed_log_err(unsigned int flags, int errval, const char *prefix);
/**
- * Log the supplied PolarSSL error, prefixed by function name and line number.
+ * Log the supplied mbed TLS error, prefixed by function name and line number.
*
* @param flags Flags to indicate error type and priority.
- * @param errval PolarSSL error code to convert to error message.
+ * @param errval mbed TLS error code to convert to error message.
* @param func Function name where error was reported.
* @param line Line number where error was reported.
*
* @returns true if no errors are detected, false otherwise.
*/
-bool polar_log_func_line(unsigned int flags, int errval, const char *func,
+bool mbed_log_func_line(unsigned int flags, int errval, const char *func,
int line);
-/** Wraps polar_log_func_line() to prevent function calls for non-errors */
-static inline bool polar_log_func_line_lite(unsigned int flags, int errval,
+/** Wraps mbed_log_func_line() to prevent function calls for non-errors */
+static inline bool mbed_log_func_line_lite(unsigned int flags, int errval,
const char *func, int line) {
if (errval) {
- return polar_log_func_line (flags, errval, func, line);
+ return mbed_log_func_line (flags, errval, func, line);
}
return true;
}
@@ -127,17 +130,17 @@ static inline bool polar_log_func_line_lite(unsigned int flags, int errval,
/**
* Check errval and log on error.
*
- * Convenience wrapper to put around polarssl library calls, e.g.
- * if (!polar_ok(polarssl_func())) return 0;
+ * Convenience wrapper to put around mbed TLS library calls, e.g.
+ * if (!mbed_ok (mbedtls_ssl_func())) return 0;
* or
- * ASSERT (polar_ok(polarssl_func()));
+ * ASSERT (mbed_ok (mbedtls_ssl_func()));
*
- * @param errval PolarSSL error code to convert to error message.
+ * @param errval mbed TLS error code to convert to error message.
*
* @returns true if no errors are detected, false otherwise.
*/
-#define polar_ok(errval) \
- polar_log_func_line_lite (D_CRYPT_ERRORS, errval, __func__, __LINE__)
+#define mbed_ok(errval) \
+ mbed_log_func_line_lite(D_CRYPT_ERRORS, errval, __func__, __LINE__)
-#endif /* CRYPTO_POLARSSL_H_ */
+#endif /* CRYPTO_MBEDTLS_H_ */
diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
index c147245..1ea06bb 100644
--- a/src/openvpn/crypto_openssl.c
+++ b/src/openvpn/crypto_openssl.c
@@ -42,9 +42,12 @@
#include "integer.h"
#include "crypto.h"
#include "crypto_backend.h"
-#include <openssl/objects.h>
-#include <openssl/evp.h>
+
#include <openssl/des.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/objects.h>
+#include <openssl/ssl.h>
/*
* Check for key size creepage.
@@ -58,41 +61,6 @@
#warning Some OpenSSL HMAC message digests now support key lengths greater than MAX_HMAC_KEY_LENGTH -- consider increasing MAX_HMAC_KEY_LENGTH
#endif
-/*
- *
- * Workarounds for incompatibilites between OpenSSL libraries.
- * Right now we accept OpenSSL libraries from 0.9.5 to 0.9.7.
- *
- */
-
-#if SSLEAY_VERSION_NUMBER < 0x00907000L
-
-/* Workaround: EVP_CIPHER_mode is defined wrong in OpenSSL 0.9.6 but is fixed in 0.9.7 */
-#undef EVP_CIPHER_mode
-#define EVP_CIPHER_mode(e) (((e)->flags) & EVP_CIPH_MODE)
-
-#define DES_cblock des_cblock
-#define DES_is_weak_key des_is_weak_key
-#define DES_check_key_parity des_check_key_parity
-#define DES_set_odd_parity des_set_odd_parity
-
-#define HMAC_CTX_init(ctx) CLEAR (*ctx)
-#define HMAC_Init_ex(ctx,sec,len,md,impl) HMAC_Init(ctx, sec, len, md)
-#define HMAC_CTX_cleanup(ctx) HMAC_cleanup(ctx)
-#define EVP_MD_CTX_cleanup(md) CLEAR (*md)
-
-#define INFO_CALLBACK_SSL_CONST
-
-#endif
-
-#ifndef EVP_CIPHER_name
-#define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e))
-#endif
-
-#ifndef EVP_MD_name
-#define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_type(e))
-#endif
-
#if HAVE_OPENSSL_ENGINE
#include <openssl/engine.h>
@@ -179,14 +147,6 @@ crypto_init_lib_engine (const char *engine_name)
void
crypto_init_lib (void)
{
-#ifndef ENABLE_SSL
- /* If SSL is enabled init is taken care of in ssl_openssl.c */
-#ifndef ENABLE_SMALL
- ERR_load_crypto_strings ();
-#endif
- OpenSSL_add_all_algorithms ();
-#endif
-
/*
* If you build the OpenSSL library and OpenVPN with
* CRYPTO_MDEBUG, you will get a listing of OpenSSL
@@ -201,14 +161,6 @@ crypto_init_lib (void)
void
crypto_uninit_lib (void)
{
-#ifndef ENABLE_SSL
- /* If SSL is enabled cleanup is taken care of in ssl_openssl.c */
- EVP_cleanup ();
-#ifndef ENABLE_SMALL
- ERR_free_strings ();
-#endif
-#endif
-
#ifdef CRYPTO_MDEBUG
FILE* fp = fopen ("sdlog", "w");
ASSERT (fp);
@@ -237,9 +189,21 @@ crypto_print_openssl_errors(const unsigned int flags) {
size_t err = 0;
while ((err = ERR_get_error ()))
- msg (flags, "OpenSSL: %s", ERR_error_string (err, NULL));
+ {
+ /* Be more clear about frequently occurring "no shared cipher" error */
+ if (err == ERR_PACK(ERR_LIB_SSL,SSL_F_SSL3_GET_CLIENT_HELLO,
+ SSL_R_NO_SHARED_CIPHER))
+ {
+ msg (D_CRYPT_ERRORS, "TLS error: The server has no TLS ciphersuites "
+ "in common with the client. Your --tls-cipher setting might be "
+ "too restrictive.");
+ }
+
+ msg (flags, "OpenSSL: %s", ERR_error_string (err, NULL));
+ }
}
+
/*
*
* OpenSSL memory debugging. If dmalloc debugging is enabled, tell
@@ -276,55 +240,97 @@ crypto_init_dmalloc (void)
}
#endif /* DMALLOC */
-const char *
-translate_cipher_name_from_openvpn (const char *cipher_name) {
- // OpenSSL doesn't require any translation
- return cipher_name;
+const cipher_name_pair cipher_name_translation_table[] = {
+ { "AES-128-GCM", "id-aes128-GCM" },
+ { "AES-192-GCM", "id-aes192-GCM" },
+ { "AES-256-GCM", "id-aes256-GCM" },
+};
+const size_t cipher_name_translation_table_count =
+ sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table);
+
+
+static int
+cipher_name_cmp(const void *a, const void *b)
+{
+ const EVP_CIPHER * const *cipher_a = a;
+ const EVP_CIPHER * const *cipher_b = b;
+
+ const char *cipher_name_a =
+ translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_a));
+ const char *cipher_name_b =
+ translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_b));
+
+ return strcmp(cipher_name_a, cipher_name_b);
}
-const char *
-translate_cipher_name_to_openvpn (const char *cipher_name) {
- // OpenSSL doesn't require any translation
- return cipher_name;
+static void
+print_cipher(const EVP_CIPHER *cipher)
+{
+ const char *var_key_size =
+ (EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ?
+ " by default" : "";
+ const char *ssl_only = cipher_kt_mode_cbc(cipher) ?
+ "" : ", TLS client/server mode only";
+
+ printf ("%s (%d bit key%s, %d bit block%s)\n",
+ translate_cipher_name_to_openvpn (EVP_CIPHER_name (cipher)),
+ EVP_CIPHER_key_length (cipher) * 8, var_key_size,
+ cipher_kt_block_size (cipher) * 8, ssl_only);
}
void
show_available_ciphers ()
{
int nid;
+ size_t i;
+ /* If we ever exceed this, we must be more selective */
+ const size_t cipher_list_len = 1000;
+ const EVP_CIPHER *cipher_list[cipher_list_len];
+ size_t num_ciphers = 0;
#ifndef ENABLE_SMALL
- printf ("The following ciphers and cipher modes are available\n"
- "for use with " PACKAGE_NAME ". Each cipher shown below may be\n"
- "used as a parameter to the --cipher option. The default\n"
- "key size is shown as well as whether or not it can be\n"
- "changed with the --keysize directive. Using a CBC mode\n"
- "is recommended. In static key mode only CBC mode is allowed.\n\n");
+ printf ("The following ciphers and cipher modes are available for use\n"
+ "with " PACKAGE_NAME ". Each cipher shown below may be use as a\n"
+ "parameter to the --cipher option. The default key size is\n"
+ "shown as well as whether or not it can be changed with the\n"
+ "--keysize directive. Using a CBC or GCM mode is recommended.\n"
+ "In static key mode only CBC mode is allowed.\n\n");
#endif
- for (nid = 0; nid < 10000; ++nid) /* is there a better way to get the size of the nid list? */
+ for (nid = 0; nid < 10000; ++nid)
{
- const EVP_CIPHER *cipher = EVP_get_cipherbynid (nid);
- if (cipher)
- {
- if (cipher_kt_mode_cbc(cipher)
+ const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid);
+ if (cipher && (cipher_kt_mode_cbc(cipher)
#ifdef ENABLE_OFB_CFB_MODE
|| cipher_kt_mode_ofb_cfb(cipher)
#endif
- )
- {
- const char *var_key_size =
- (EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ?
- "variable" : "fixed";
- const char *ssl_only = cipher_kt_mode_ofb_cfb(cipher) ?
- " (TLS client/server mode)" : "";
-
- printf ("%s %d bit default key (%s)%s\n", OBJ_nid2sn (nid),
- EVP_CIPHER_key_length (cipher) * 8, var_key_size,
- ssl_only);
- }
+#ifdef HAVE_AEAD_CIPHER_MODES
+ || cipher_kt_mode_aead(cipher)
+#endif
+ ))
+ {
+ cipher_list[num_ciphers++] = cipher;
+ }
+ if (num_ciphers == cipher_list_len)
+ {
+ msg (M_WARN, "WARNING: Too many ciphers, not showing all");
+ break;
}
}
+
+ qsort (cipher_list, num_ciphers, sizeof(*cipher_list), cipher_name_cmp);
+
+ for (i = 0; i < num_ciphers; i++) {
+ if (cipher_kt_block_size(cipher_list[i]) >= 128/8)
+ print_cipher(cipher_list[i]);
+ }
+
+ printf ("\nThe following ciphers have a block size of less than 128 bits, \n"
+ "and are therefore deprecated. Do not use unless you have to.\n\n");
+ for (i = 0; i < num_ciphers; i++) {
+ if (cipher_kt_block_size(cipher_list[i]) < 128/8)
+ print_cipher(cipher_list[i]);
+ }
printf ("\n");
}
@@ -498,13 +504,20 @@ cipher_kt_get (const char *ciphername)
cipher = EVP_get_cipherbyname (ciphername);
if (NULL == cipher)
- crypto_msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername);
+ {
+ crypto_msg (D_LOW, "Cipher algorithm '%s' not found", ciphername);
+ return NULL;
+ }
+
if (EVP_CIPHER_key_length (cipher) > MAX_CIPHER_KEY_LENGTH)
- msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)",
- ciphername,
- EVP_CIPHER_key_length (cipher),
- MAX_CIPHER_KEY_LENGTH);
+ {
+ msg (D_LOW, "Cipher algorithm '%s' uses a default key size (%d bytes) "
+ "which is larger than " PACKAGE_NAME "'s current maximum key size "
+ "(%d bytes)", ciphername, EVP_CIPHER_key_length (cipher),
+ MAX_CIPHER_KEY_LENGTH);
+ return NULL;
+ }
return cipher;
}
@@ -530,9 +543,46 @@ cipher_kt_iv_size (const EVP_CIPHER *cipher_kt)
}
int
-cipher_kt_block_size (const EVP_CIPHER *cipher_kt)
+cipher_kt_block_size (const EVP_CIPHER *cipher) {
+ /* OpenSSL reports OFB/CFB/GCM cipher block sizes as '1 byte'. To work
+ * around that, try to replace the mode with 'CBC' and return the block size
+ * reported for that cipher, if possible. If that doesn't work, just return
+ * the value reported by OpenSSL.
+ */
+ char *name = NULL;
+ char *mode_str = NULL;
+ const char *orig_name = NULL;
+ const EVP_CIPHER *cbc_cipher = NULL;
+
+ int block_size = EVP_CIPHER_block_size(cipher);
+
+ orig_name = cipher_kt_name(cipher);
+ if (!orig_name)
+ goto cleanup;
+
+ name = string_alloc(translate_cipher_name_to_openvpn(orig_name), NULL);
+ mode_str = strrchr (name, '-');
+ if (!mode_str || strlen(mode_str) < 4)
+ goto cleanup;
+
+ strcpy (mode_str, "-CBC");
+
+ cbc_cipher = EVP_get_cipherbyname(translate_cipher_name_from_openvpn(name));
+ if (cbc_cipher)
+ block_size = EVP_CIPHER_block_size(cbc_cipher);
+
+cleanup:
+ free (name);
+ return block_size;
+}
+
+int
+cipher_kt_tag_size (const EVP_CIPHER *cipher_kt)
{
- return EVP_CIPHER_block_size (cipher_kt);
+ if (cipher_kt_mode_aead(cipher_kt))
+ return OPENVPN_AEAD_TAG_LENGTH;
+ else
+ return 0;
}
int
@@ -565,6 +615,16 @@ cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
;
}
+bool
+cipher_kt_mode_aead(const cipher_kt_t *cipher)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+ return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_GCM);
+#else
+ return false;
+#endif
+}
+
/*
*
* Generic cipher context functions
@@ -606,6 +666,15 @@ cipher_ctx_iv_length (const EVP_CIPHER_CTX *ctx)
return EVP_CIPHER_CTX_iv_length (ctx);
}
+int cipher_ctx_get_tag (EVP_CIPHER_CTX *ctx, uint8_t *tag_buf, int tag_size)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+ return EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag_buf);
+#else
+ ASSERT (0);
+#endif
+}
+
int
cipher_ctx_block_size(const EVP_CIPHER_CTX *ctx)
{
@@ -621,7 +690,7 @@ cipher_ctx_mode (const EVP_CIPHER_CTX *ctx)
const cipher_kt_t *
cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
{
- return EVP_CIPHER_CTX_cipher(ctx);
+ return ctx ? EVP_CIPHER_CTX_cipher(ctx) : NULL;
}
@@ -632,6 +701,19 @@ cipher_ctx_reset (EVP_CIPHER_CTX *ctx, uint8_t *iv_buf)
}
int
+cipher_ctx_update_ad (EVP_CIPHER_CTX *ctx, const uint8_t *src, int src_len)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+ int len;
+ if (!EVP_CipherUpdate (ctx, NULL, &len, src, src_len))
+ crypto_msg(M_FATAL, "%s: EVP_CipherUpdate() failed", __func__);
+ return 1;
+#else
+ ASSERT (0);
+#endif
+}
+
+int
cipher_ctx_update (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len,
uint8_t *src, int src_len)
{
@@ -646,6 +728,20 @@ cipher_ctx_final (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len)
return EVP_CipherFinal (ctx, dst, dst_len);
}
+int
+cipher_ctx_final_check_tag (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len,
+ uint8_t *tag, size_t tag_len)
+{
+#ifdef HAVE_AEAD_CIPHER_MODES
+ ASSERT (tag_len < SIZE_MAX);
+ if (!EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag))
+ return 0;
+
+ return cipher_ctx_final (ctx, dst, dst_len);
+#else
+ ASSERT (0);
+#endif
+}
void
cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH],
diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h
index 42c7e9a..f157041 100644
--- a/src/openvpn/crypto_openssl.h
+++ b/src/openvpn/crypto_openssl.h
@@ -61,6 +61,13 @@ typedef HMAC_CTX hmac_ctx_t;
/** Cipher is in CFB mode */
#define OPENVPN_MODE_CFB EVP_CIPH_CFB_MODE
+#ifdef HAVE_AEAD_CIPHER_MODES
+
+/** Cipher is in GCM mode */
+#define OPENVPN_MODE_GCM EVP_CIPH_GCM_MODE
+
+#endif /* HAVE_AEAD_CIPHER_MODES */
+
/** Cipher should encrypt */
#define OPENVPN_OP_ENCRYPT 1
diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c
deleted file mode 100644
index 92fdb78..0000000
--- a/src/openvpn/crypto_polarssl.c
+++ /dev/null
@@ -1,712 +0,0 @@
-/*
- * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
- *
- * 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
- */
-
-/**
- * @file Data Channel Cryptography PolarSSL-specific backend interface
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#elif defined(_MSC_VER)
-#include "config-msvc.h"
-#endif
-
-#include "syshead.h"
-
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_POLARSSL)
-
-#include "errlevel.h"
-#include "basic.h"
-#include "buffer.h"
-#include "integer.h"
-#include "crypto_backend.h"
-#include "otime.h"
-#include "misc.h"
-
-#include <polarssl/des.h>
-#include <polarssl/error.h>
-#include <polarssl/md5.h>
-#include <polarssl/cipher.h>
-#include <polarssl/havege.h>
-
-#include <polarssl/entropy.h>
-
-/*
- *
- * Hardware engine support. Allows loading/unloading of engines.
- *
- */
-
-void
-crypto_init_lib_engine (const char *engine_name)
-{
- msg (M_WARN, "Note: PolarSSL hardware crypto engine functionality is not "
- "available");
-}
-
-/*
- *
- * Functions related to the core crypto library
- *
- */
-
-void
-crypto_init_lib (void)
-{
-}
-
-void
-crypto_uninit_lib (void)
-{
-}
-
-void
-crypto_clear_error (void)
-{
-}
-
-bool polar_log_err(unsigned int flags, int errval, const char *prefix)
-{
- if (0 != errval)
- {
- char errstr[256];
- polarssl_strerror(errval, errstr, sizeof(errstr));
-
- if (NULL == prefix) prefix = "PolarSSL error";
- msg (flags, "%s: %s", prefix, errstr);
- }
-
- return 0 == errval;
-}
-
-bool polar_log_func_line(unsigned int flags, int errval, const char *func,
- int line)
-{
- char prefix[256];
-
- if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line))
- return polar_log_err(flags, errval, func);
-
- return polar_log_err(flags, errval, prefix);
-}
-
-
-#ifdef DMALLOC
-void
-crypto_init_dmalloc (void)
-{
- msg (M_ERR, "Error: dmalloc support is not available for PolarSSL.");
-}
-#endif /* DMALLOC */
-
-typedef struct { const char * openvpn_name; const char * polarssl_name; } cipher_name_pair;
-cipher_name_pair cipher_name_translation_table[] = {
- { "BF-CBC", "BLOWFISH-CBC" },
- { "BF-CFB", "BLOWFISH-CFB64" },
- { "CAMELLIA-128-CFB", "CAMELLIA-128-CFB128" },
- { "CAMELLIA-192-CFB", "CAMELLIA-192-CFB128" },
- { "CAMELLIA-256-CFB", "CAMELLIA-256-CFB128" }
-};
-
-const cipher_name_pair *
-get_cipher_name_pair(const char *cipher_name) {
- cipher_name_pair *pair;
- size_t i = 0;
-
- /* Search for a cipher name translation */
- for (; i < sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); i++)
- {
- pair = &cipher_name_translation_table[i];
- if (0 == strcmp (cipher_name, pair->openvpn_name) ||
- 0 == strcmp (cipher_name, pair->polarssl_name))
- return pair;
- }
-
- /* Nothing found, return null */
- return NULL;
-}
-
-const char *
-translate_cipher_name_from_openvpn (const char *cipher_name) {
- const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
-
- if (NULL == pair)
- return cipher_name;
-
- return pair->polarssl_name;
-}
-
-const char *
-translate_cipher_name_to_openvpn (const char *cipher_name) {
- const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
-
- if (NULL == pair)
- return cipher_name;
-
- return pair->openvpn_name;
-}
-
-void
-show_available_ciphers ()
-{
- const int *ciphers = cipher_list();
-
-#ifndef ENABLE_SMALL
- printf ("The following ciphers and cipher modes are available\n"
- "for use with " PACKAGE_NAME ". Each cipher shown below may be\n"
- "used as a parameter to the --cipher option. The default\n"
- "key size is shown as well as whether or not it can be\n"
- "changed with the --keysize directive. Using a CBC mode\n"
- "is recommended.\n\n");
-#endif
-
- while (*ciphers != 0)
- {
- const cipher_info_t *info = cipher_info_from_type(*ciphers);
-
- if (info && info->mode == POLARSSL_MODE_CBC)
- printf ("%s %d bit default key\n",
- cipher_kt_name(info), cipher_kt_key_size(info) * 8);
-
- ciphers++;
- }
- printf ("\n");
-}
-
-void
-show_available_digests ()
-{
- const int *digests = md_list();
-
-#ifndef ENABLE_SMALL
- printf ("The following message digests are available for use with\n"
- PACKAGE_NAME ". A message digest is used in conjunction with\n"
- "the HMAC function, to authenticate received packets.\n"
- "You can specify a message digest as parameter to\n"
- "the --auth option.\n\n");
-#endif
-
- while (*digests != 0)
- {
- const md_info_t *info = md_info_from_type(*digests);
-
- if (info)
- printf ("%s %d bit default key\n",
- info->name, info->size * 8);
- digests++;
- }
- printf ("\n");
-}
-
-void
-show_available_engines ()
-{
- printf ("Sorry, PolarSSL hardware crypto engine functionality is not "
- "available\n");
-}
-
-/*
- *
- * Random number functions, used in cases where we want
- * reasonably strong cryptographic random number generation
- * without depleting our entropy pool. Used for random
- * IV values and a number of other miscellaneous tasks.
- *
- */
-
-/*
- * Initialise the given ctr_drbg context, using a personalisation string and an
- * entropy gathering function.
- */
-ctr_drbg_context * rand_ctx_get()
-{
- static entropy_context ec = {0};
- static ctr_drbg_context cd_ctx = {0};
- static bool rand_initialised = false;
-
- if (!rand_initialised)
- {
- struct gc_arena gc = gc_new();
- struct buffer pers_string = alloc_buf_gc(100, &gc);
-
- /*
- * Personalisation string, should be as unique as possible (see NIST
- * 800-90 section 8.7.1). We have very little information at this stage.
- * Include Program Name, memory address of the context and PID.
- */
- buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(), &cd_ctx, time_string(0, 0, 0, &gc));
-
- /* Initialise PolarSSL RNG, and built-in entropy sources */
- entropy_init(&ec);
-
- if (!polar_ok(ctr_drbg_init(&cd_ctx, entropy_func, &ec,
- BPTR(&pers_string), BLEN(&pers_string))))
- msg (M_FATAL, "Failed to initialize random generator");
-
- gc_free(&gc);
- rand_initialised = true;
- }
-
- return &cd_ctx;
-}
-
-#ifdef ENABLE_PREDICTION_RESISTANCE
-void rand_ctx_enable_prediction_resistance()
-{
- ctr_drbg_context *cd_ctx = rand_ctx_get();
-
- ctr_drbg_set_prediction_resistance(cd_ctx, 1);
-}
-#endif /* ENABLE_PREDICTION_RESISTANCE */
-
-int
-rand_bytes (uint8_t *output, int len)
-{
- ctr_drbg_context *rng_ctx = rand_ctx_get();
-
- while (len > 0)
- {
- const size_t blen = min_int (len, CTR_DRBG_MAX_REQUEST);
- if (0 != ctr_drbg_random(rng_ctx, output, blen))
- return 0;
-
- output += blen;
- len -= blen;
- }
-
- return 1;
-}
-
-/*
- *
- * Key functions, allow manipulation of keys.
- *
- */
-
-
-int
-key_des_num_cblocks (const cipher_info_t *kt)
-{
- int ret = 0;
- if (kt->type == POLARSSL_CIPHER_DES_CBC)
- ret = 1;
- if (kt->type == POLARSSL_CIPHER_DES_EDE_CBC)
- ret = 2;
- if (kt->type == POLARSSL_CIPHER_DES_EDE3_CBC)
- ret = 3;
-
- dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret);
- return ret;
-}
-
-bool
-key_des_check (uint8_t *key, int key_len, int ndc)
-{
- int i;
- struct buffer b;
-
- buf_set_read (&b, key, key_len);
-
- for (i = 0; i < ndc; ++i)
- {
- unsigned char *key = buf_read_alloc(&b, DES_KEY_SIZE);
- if (!key)
- {
- msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material");
- goto err;
- }
- if (0 != des_key_check_weak(key))
- {
- msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected");
- goto err;
- }
- if (0 != des_key_check_key_parity(key))
- {
- msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected");
- goto err;
- }
- }
- return true;
-
- err:
- return false;
-}
-
-void
-key_des_fixup (uint8_t *key, int key_len, int ndc)
-{
- int i;
- struct buffer b;
-
- buf_set_read (&b, key, key_len);
- for (i = 0; i < ndc; ++i)
- {
- unsigned char *key = buf_read_alloc(&b, DES_KEY_SIZE);
- if (!key)
- {
- msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material");
- return;
- }
- des_key_set_parity(key);
- }
-}
-
-/*
- *
- * Generic cipher key type functions
- *
- */
-
-
-const cipher_info_t *
-cipher_kt_get (const char *ciphername)
-{
- const cipher_info_t *cipher = NULL;
-
- ASSERT (ciphername);
-
- cipher = cipher_info_from_string(ciphername);
-
- if (NULL == cipher)
- msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername);
-
- if (cipher->key_length/8 > MAX_CIPHER_KEY_LENGTH)
- msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)",
- ciphername,
- cipher->key_length/8,
- MAX_CIPHER_KEY_LENGTH);
-
- return cipher;
-}
-
-const char *
-cipher_kt_name (const cipher_info_t *cipher_kt)
-{
- if (NULL == cipher_kt)
- return "[null-cipher]";
-
- return translate_cipher_name_to_openvpn(cipher_kt->name);
-}
-
-int
-cipher_kt_key_size (const cipher_info_t *cipher_kt)
-{
- if (NULL == cipher_kt)
- return 0;
- if (POLARSSL_CIPHER_ID_BLOWFISH == cipher_kt->base->cipher)
- return 128/8; /* Override PolarSSL 32 bit default key size with sane 128 bit default */
-
- return cipher_kt->key_length/8;
-}
-
-int
-cipher_kt_iv_size (const cipher_info_t *cipher_kt)
-{
- if (NULL == cipher_kt)
- return 0;
- return cipher_kt->iv_size;
-}
-
-int
-cipher_kt_block_size (const cipher_info_t *cipher_kt)
-{
- if (NULL == cipher_kt)
- return 0;
- return cipher_kt->block_size;
-}
-
-int
-cipher_kt_mode (const cipher_info_t *cipher_kt)
-{
- ASSERT(NULL != cipher_kt);
- return cipher_kt->mode;
-}
-
-bool
-cipher_kt_mode_cbc(const cipher_kt_t *cipher)
-{
- return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC;
-}
-
-bool
-cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
-{
- return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB ||
- cipher_kt_mode(cipher) == OPENVPN_MODE_CFB);
-}
-
-
-/*
- *
- * Generic cipher context functions
- *
- */
-
-
-void
-cipher_ctx_init (cipher_context_t *ctx, uint8_t *key, int key_len,
- const cipher_info_t *kt, int enc)
-{
- ASSERT(NULL != kt && NULL != ctx);
-
- CLEAR (*ctx);
-
- if (!polar_ok(cipher_init_ctx(ctx, kt)))
- msg (M_FATAL, "PolarSSL cipher context init #1");
-
- if (!polar_ok(cipher_setkey(ctx, key, key_len*8, enc)))
- msg (M_FATAL, "PolarSSL cipher set key");
-
- /* make sure we used a big enough key */
- ASSERT (ctx->key_length <= key_len*8);
-}
-
-void cipher_ctx_cleanup (cipher_context_t *ctx)
-{
- cipher_free(ctx);
-}
-
-int cipher_ctx_iv_length (const cipher_context_t *ctx)
-{
- return cipher_get_iv_size(ctx);
-}
-
-int cipher_ctx_block_size(const cipher_context_t *ctx)
-{
- return cipher_get_block_size(ctx);
-}
-
-int cipher_ctx_mode (const cipher_context_t *ctx)
-{
- ASSERT(NULL != ctx);
-
- return cipher_kt_mode(ctx->cipher_info);
-}
-
-const cipher_kt_t *
-cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
-{
- ASSERT(NULL != ctx);
-
- return ctx->cipher_info;
-}
-
-int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf)
-{
- if (!polar_ok(cipher_reset(ctx)))
- return 0;
-
- if (!polar_ok(cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size)))
- return 0;
-
- return 1;
-}
-
-int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len,
- uint8_t *src, int src_len)
-{
- size_t s_dst_len = *dst_len;
-
- if (!polar_ok(cipher_update(ctx, src, (size_t)src_len, dst, &s_dst_len)))
- return 0;
-
- *dst_len = s_dst_len;
-
- return 1;
-}
-
-int cipher_ctx_final (cipher_context_t *ctx, uint8_t *dst, int *dst_len)
-{
- size_t s_dst_len = *dst_len;
-
- if (!polar_ok(cipher_finish(ctx, dst, &s_dst_len)))
- return 0;
-
- *dst_len = s_dst_len;
-
- return 1;
-}
-
-void
-cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH],
- unsigned char *src,
- unsigned char *dst)
-{
- des_context ctx;
-
- ASSERT (polar_ok(des_setkey_enc(&ctx, key)));
- ASSERT (polar_ok(des_crypt_ecb(&ctx, src, dst)));
-}
-
-
-
-/*
- *
- * Generic message digest information functions
- *
- */
-
-
-const md_info_t *
-md_kt_get (const char *digest)
-{
- const md_info_t *md = NULL;
- ASSERT (digest);
-
- md = md_info_from_string(digest);
- if (!md)
- msg (M_FATAL, "Message hash algorithm '%s' not found", digest);
- if (md->size > MAX_HMAC_KEY_LENGTH)
- msg (M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d bytes)",
- digest,
- md->size,
- MAX_HMAC_KEY_LENGTH);
- return md;
-}
-
-const char *
-md_kt_name (const md_info_t *kt)
-{
- if (NULL == kt)
- return "[null-digest]";
- return md_get_name (kt);
-}
-
-int
-md_kt_size (const md_info_t *kt)
-{
- if (NULL == kt)
- return 0;
- return md_get_size(kt);
-}
-
-/*
- *
- * Generic message digest functions
- *
- */
-
-int
-md_full (const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst)
-{
- return 0 == md(kt, src, src_len, dst);
-}
-
-
-void
-md_ctx_init (md_context_t *ctx, const md_info_t *kt)
-{
- ASSERT(NULL != ctx && NULL != kt);
-
- CLEAR(*ctx);
-
- ASSERT(0 == md_init_ctx(ctx, kt));
- ASSERT(0 == md_starts(ctx));
-}
-
-void
-md_ctx_cleanup(md_context_t *ctx)
-{
-}
-
-int
-md_ctx_size (const md_context_t *ctx)
-{
- if (NULL == ctx)
- return 0;
- return md_get_size(ctx->md_info);
-}
-
-void
-md_ctx_update (md_context_t *ctx, const uint8_t *src, int src_len)
-{
- ASSERT(0 == md_update(ctx, src, src_len));
-}
-
-void
-md_ctx_final (md_context_t *ctx, uint8_t *dst)
-{
- ASSERT(0 == md_finish(ctx, dst));
- md_free(ctx);
-}
-
-
-/*
- *
- * Generic HMAC functions
- *
- */
-
-
-/*
- * TODO: re-enable dmsg for crypto debug
- */
-void
-hmac_ctx_init (md_context_t *ctx, const uint8_t *key, int key_len, const md_info_t *kt)
-{
- ASSERT(NULL != kt && NULL != ctx);
-
- CLEAR(*ctx);
-
- ASSERT(0 == md_init_ctx(ctx, kt));
- ASSERT(0 == md_hmac_starts(ctx, key, key_len));
-
- /* make sure we used a big enough key */
- ASSERT (md_get_size(kt) <= key_len);
-}
-
-void
-hmac_ctx_cleanup(md_context_t *ctx)
-{
- md_free(ctx);
-}
-
-int
-hmac_ctx_size (const md_context_t *ctx)
-{
- if (NULL == ctx)
- return 0;
- return md_get_size(ctx->md_info);
-}
-
-void
-hmac_ctx_reset (md_context_t *ctx)
-{
- ASSERT(0 == md_hmac_reset(ctx));
-}
-
-void
-hmac_ctx_update (md_context_t *ctx, const uint8_t *src, int src_len)
-{
- ASSERT(0 == md_hmac_update(ctx, src, src_len));
-}
-
-void
-hmac_ctx_final (md_context_t *ctx, uint8_t *dst)
-{
- ASSERT(0 == md_hmac_finish(ctx, dst));
-}
-
-#endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_POLARSSL */
diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c
index 853c07b..e107bd3 100644
--- a/src/openvpn/cryptoapi.c
+++ b/src/openvpn/cryptoapi.c
@@ -465,4 +465,4 @@ int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop)
#ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
static void dummy (void) {}
#endif
-#endif /* WIN32 */
+#endif /* _WIN32 */
diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h
index 3ee4ebc..9d56eb4 100644
--- a/src/openvpn/errlevel.h
+++ b/src/openvpn/errlevel.h
@@ -105,7 +105,6 @@
#define D_X509_ATTR LOGLEV(4, 59, 0) /* show x509-track attributes on connection */
#define D_INIT_MEDIUM LOGLEV(4, 60, 0) /* show medium frequency init messages */
#define D_MTU_INFO LOGLEV(4, 61, 0) /* show terse MTU info */
-#define D_SHOW_OCC_HASH LOGLEV(4, 62, 0) /* show MD5 hash of option compatibility string */
#define D_PID_DEBUG_LOW LOGLEV(4, 63, 0) /* show low-freq packet-id debugging info */
#define D_PID_DEBUG_MEDIUM LOGLEV(4, 64, 0) /* show medium-freq packet-id debugging info */
@@ -143,11 +142,12 @@
#define D_PS_PROXY_DEBUG LOGLEV(7, 70, M_DEBUG) /* port share proxy debug */
#define D_AUTO_USERID LOGLEV(7, 70, M_DEBUG) /* AUTO_USERID debugging */
#define D_TLS_KEYSELECT LOGLEV(7, 70, M_DEBUG) /* show information on key selection for data channel */
-#define D_ARGV_PARSE_CMD LOGLEV(7, 70, M_DEBUG) /* show parse_line() errors in argv_printf %sc */
+#define D_ARGV_PARSE_CMD LOGLEV(7, 70, M_DEBUG) /* show parse_line() errors in argv_parse_cmd */
#define D_CRYPTO_DEBUG LOGLEV(7, 70, M_DEBUG) /* show detailed info from crypto.c routines */
#define D_PID_DEBUG LOGLEV(7, 70, M_DEBUG) /* show packet-id debugging info */
#define D_PF_DROPPED_BCAST LOGLEV(7, 71, M_DEBUG) /* packet filter dropped a broadcast packet */
#define D_PF_DEBUG LOGLEV(7, 72, M_DEBUG) /* packet filter debugging, must also define PF_DEBUG in pf.h */
+#define D_PUSH_DEBUG LOGLEV(7, 73, M_DEBUG) /* show push/pull debugging info */
#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/src/openvpn/error.c b/src/openvpn/error.c
index 6ccdeae..425bc30 100644
--- a/src/openvpn/error.c
+++ b/src/openvpn/error.c
@@ -75,6 +75,10 @@ static bool std_redir; /* GLOBAL */
/* Should messages be written to the syslog? */
static bool use_syslog; /* GLOBAL */
+/* Should stdout/stderr be be parsable and always be prefixed with time
+ * and message flags */
+static bool machine_readable_output; /* GLOBAL */
+
/* Should timestamps be included on messages to stdout/stderr? */
static bool suppress_timestamps; /* GLOBAL */
@@ -148,10 +152,17 @@ set_suppress_timestamps (bool suppressed)
}
void
+set_machine_readable_output (bool parsable)
+{
+ machine_readable_output = parsable;
+}
+
+void
error_reset ()
{
use_syslog = std_redir = false;
suppress_timestamps = false;
+ machine_readable_output = false;
x_debug_level = 1;
mute_cutoff = 0;
mute_count = 0;
@@ -301,7 +312,22 @@ void x_msg_va (const unsigned int flags, const char *format, va_list arglist)
FILE *fp = msg_fp(flags);
const bool show_usec = check_debug_level (DEBUG_LEVEL_USEC_TIME);
- if ((flags & M_NOPREFIX) || suppress_timestamps)
+ if (machine_readable_output)
+ {
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+
+ fprintf (fp, "%lu.%06lu %x %s%s%s%s",
+ tv.tv_sec,
+ (unsigned long)tv.tv_usec,
+ flags,
+ prefix,
+ prefix_sep,
+ m1,
+ "\n");
+
+ }
+ else if ((flags & M_NOPREFIX) || suppress_timestamps)
{
fprintf (fp, "%s%s%s%s",
prefix,
@@ -427,7 +453,7 @@ close_syslog ()
#endif
}
-#ifdef WIN32
+#ifdef _WIN32
static HANDLE orig_stderr;
@@ -445,7 +471,7 @@ get_orig_stderr (void)
void
redirect_stdout_stderr (const char *file, bool append)
{
-#if defined(WIN32)
+#if defined(_WIN32)
if (!std_redir)
{
struct gc_arena gc = gc_new ();
@@ -577,7 +603,7 @@ x_check_status (int status,
const char *extended_msg = NULL;
msg (x_cs_verbose_level, "%s %s returned %d",
- sock ? proto2ascii (sock->info.proto, true) : "",
+ sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "",
description,
status);
@@ -596,7 +622,7 @@ x_check_status (int status,
sock->info.mtu_changed = true;
}
}
-#elif defined(WIN32)
+#elif defined(_WIN32)
/* get possible driver error from TAP-Windows driver */
extended_msg = tap_win_getinfo (tt, &gc);
#endif
@@ -605,14 +631,14 @@ x_check_status (int status,
if (extended_msg)
msg (x_cs_info_level, "%s %s [%s]: %s (code=%d)",
description,
- sock ? proto2ascii (sock->info.proto, true) : "",
+ sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "",
extended_msg,
strerror_ts (my_errno, &gc),
my_errno);
else
msg (x_cs_info_level, "%s %s: %s (code=%d)",
description,
- sock ? proto2ascii (sock->info.proto, true) : "",
+ sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "",
strerror_ts (my_errno, &gc),
my_errno);
@@ -651,7 +677,7 @@ openvpn_exit (const int status)
tun_abort();
-#ifdef WIN32
+#ifdef _WIN32
uninit_win32 ();
#endif
@@ -711,7 +737,7 @@ crash (void)
}
#endif
-#ifdef WIN32
+#ifdef _WIN32
const char *
strerror_win32 (DWORD errnum, struct gc_arena *gc)
diff --git a/src/openvpn/error.h b/src/openvpn/error.h
index 4024e5e..f43bc38 100644
--- a/src/openvpn/error.h
+++ b/src/openvpn/error.h
@@ -27,6 +27,11 @@
#include "basic.h"
+#include <errno.h>
+#include <stdbool.h>
+
+#include <assert.h>
+
/* #define ABORT_ON_ERROR */
#ifdef ENABLE_PKCS11
@@ -66,7 +71,7 @@ struct gc_arena;
/* String and Error functions */
-#ifdef WIN32
+#ifdef _WIN32
# define openvpn_errno() GetLastError()
# define openvpn_strerror(e, gc) strerror_win32(e, gc)
const char *strerror_win32 (DWORD errnum, struct gc_arena *gc);
@@ -138,12 +143,6 @@ extern int x_msg_line_num;
/** Check muting filter */
bool dont_mute (unsigned int flags);
-/** Return true if flags represent an enabled, not muted log level */
-static inline bool msg_test (unsigned int flags)
-{
- return ((flags & M_DEBUG_LEVEL) <= x_debug_level) && dont_mute (flags);
-}
-
/* Macro to ensure (and teach static analysis tools) we exit on fatal errors */
#define EXIT_FATAL(flags) do { if ((flags) & M_FATAL) _exit(1); } while (false)
@@ -197,6 +196,8 @@ void error_reset (void);
void errors_to_stderr (void);
void set_suppress_timestamps (bool suppressed);
+void set_machine_readable_output (bool parsable);
+
#define SDL_CONSTRAIN (1<<0)
bool set_debug_level (const int level, const unsigned int flags);
@@ -223,6 +224,14 @@ FILE *msg_fp(const unsigned int flags);
void assert_failed (const char *filename, int line, const char *condition)
__attribute__((__noreturn__));
+/* Poor-man's static_assert() for when not supplied by assert.h, taken from
+ * Linux's sys/cdefs.h under GPLv2 */
+#ifndef static_assert
+#define static_assert(expr, diagnostic) \
+ extern int (*__OpenVPN_static_assert_function (void)) \
+ [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })]
+#endif
+
#ifdef ENABLE_DEBUG
void crash (void); /* force a segfault (debugging only) */
#endif
@@ -235,6 +244,12 @@ check_debug_level (unsigned int level)
return (level & M_DEBUG_LEVEL) <= x_debug_level;
}
+/** Return true if flags represent an enabled, not muted log level */
+static inline bool msg_test (unsigned int flags)
+{
+ return check_debug_level (flags) && dont_mute (flags);
+}
+
/* Call if we forked */
void msg_forked (void);
@@ -246,7 +261,7 @@ void close_syslog ();
/* log file output */
void redirect_stdout_stderr (const char *file, bool append);
-#ifdef WIN32
+#ifdef _WIN32
/* get original stderr handle, even if redirected by --log/--log-append */
HANDLE get_orig_stderr (void);
#endif
@@ -341,7 +356,7 @@ static inline bool
ignore_sys_error (const int err)
{
/* I/O operation pending */
-#ifdef WIN32
+#ifdef _WIN32
if (err == WSAEWOULDBLOCK || err == WSAEINVAL)
return true;
#else
diff --git a/src/openvpn/event.c b/src/openvpn/event.c
index c642691..409ad13 100644
--- a/src/openvpn/event.c
+++ b/src/openvpn/event.c
@@ -49,7 +49,7 @@
/*
* All non-windows OSes are assumed to have select()
*/
-#ifdef WIN32
+#ifdef _WIN32
#define SELECT 0
#else
#define SELECT 1
@@ -74,7 +74,7 @@ tv_to_ms_timeout (const struct timeval *tv)
return max_int (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000, 1);
}
-#ifdef WIN32
+#ifdef _WIN32
struct we_set
{
@@ -462,7 +462,7 @@ we_init (int *maxevents, unsigned int flags)
return (struct event_set *) wes;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
#if EPOLL
@@ -1007,7 +1007,7 @@ static struct event_set *
event_set_init_simple (int *maxevents, unsigned int flags)
{
struct event_set *ret = NULL;
-#ifdef WIN32
+#ifdef _WIN32
ret = we_init (maxevents, flags);
#elif POLL && SELECT
#if 0 /* Define to 1 if EVENT_METHOD_US_TIMEOUT should cause select to be favored over poll */
diff --git a/src/openvpn/event.h b/src/openvpn/event.h
index bd29fdc..565343d 100644
--- a/src/openvpn/event.h
+++ b/src/openvpn/event.h
@@ -42,7 +42,7 @@
#define EVENT_METHOD_US_TIMEOUT (1<<0)
#define EVENT_METHOD_FAST (1<<1)
-#ifdef WIN32
+#ifdef _WIN32
typedef const struct rw_handle *event_t;
@@ -137,7 +137,7 @@ event_set_return_init (struct event_set_return *esr)
esr->arg = NULL;
}
-#ifdef WIN32
+#ifdef _WIN32
static inline void
wait_signal (struct event_set *es, void *arg)
diff --git a/src/openvpn/fdmisc.c b/src/openvpn/fdmisc.c
index 7fe449c..ce01319 100644
--- a/src/openvpn/fdmisc.c
+++ b/src/openvpn/fdmisc.c
@@ -39,7 +39,7 @@
bool
set_nonblock_action (int fd)
{
-#ifdef WIN32
+#ifdef _WIN32
u_long arg = 1;
if (ioctlsocket (fd, FIONBIO, &arg))
return false;
@@ -54,7 +54,7 @@ set_nonblock_action (int fd)
bool
set_cloexec_action (int fd)
{
-#ifndef WIN32
+#ifndef _WIN32
if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
return false;
#endif
diff --git a/src/openvpn/fdmisc.h b/src/openvpn/fdmisc.h
index 13d6552..d34db9b 100644
--- a/src/openvpn/fdmisc.h
+++ b/src/openvpn/fdmisc.h
@@ -37,7 +37,7 @@ void set_cloexec (int fd);
static inline void openvpn_fd_set(int fd, fd_set *setp)
{
-#ifndef WIN32 /* The Windows FD_SET() implementation does not overflow */
+#ifndef _WIN32 /* The Windows FD_SET() implementation does not overflow */
ASSERT (fd >= 0 && fd < FD_SETSIZE);
#endif
FD_SET (fd, setp);
diff --git a/src/openvpn/forward-inline.h b/src/openvpn/forward-inline.h
index 5853ce2..5d4e308 100644
--- a/src/openvpn/forward-inline.h
+++ b/src/openvpn/forward-inline.h
@@ -35,7 +35,7 @@
static inline void
check_tls (struct context *c)
{
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#if defined(ENABLE_CRYPTO)
void check_tls_dowork (struct context *c);
if (c->c2.tls_multi)
check_tls_dowork (c);
@@ -49,7 +49,7 @@ check_tls (struct context *c)
static inline void
check_tls_errors (struct context *c)
{
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#if defined(ENABLE_CRYPTO)
void check_tls_errors_co (struct context *c);
void check_tls_errors_nco (struct context *c);
if (c->c2.tls_multi && c->c2.tls_exit_signal)
@@ -125,7 +125,7 @@ check_server_poll_timeout (struct context *c)
{
void check_server_poll_timeout_dowork (struct context *c);
- if (c->options.server_poll_timeout
+ if (c->options.ce.connect_timeout
&& event_timeout_trigger (&c->c2.server_poll_interval, &c->c2.timeval, ETT_DEFAULT))
check_server_poll_timeout_dowork (c);
}
diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index d55fa3b..b50a2e0 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -39,6 +39,7 @@
#include "ps.h"
#include "dhcp.h"
#include "common.h"
+#include "ssl_verify.h"
#include "memdbg.h"
@@ -87,7 +88,7 @@ show_wait_status (struct context *c)
* traffic on the control-channel.
*
*/
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
void
check_tls_dowork (struct context *c)
{
@@ -116,9 +117,6 @@ check_tls_dowork (struct context *c)
if (wakeup)
context_reschedule_sec (c, wakeup);
}
-#endif
-
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
void
check_tls_errors_co (struct context *c)
@@ -132,8 +130,7 @@ check_tls_errors_nco (struct context *c)
{
register_signal (c, c->c2.tls_exit_signal, "tls-error"); /* SOFT-SIGUSR1 -- TLS error */
}
-
-#endif
+#endif /* ENABLE_CRYPTO */
#if P2MP
@@ -211,12 +208,14 @@ check_connection_established_dowork (struct context *c)
management_set_state (management,
OPENVPN_STATE_GET_CONFIG,
NULL,
- 0,
- 0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
#endif
- /* send push request in 1 sec */
- event_timeout_init (&c->c2.push_request_interval, 1, now);
+ /* fire up push request right away (already 1s delayed) */
+ event_timeout_init (&c->c2.push_request_interval, 0, now);
reset_coarse_timers (c);
}
else
@@ -238,7 +237,7 @@ check_connection_established_dowork (struct context *c)
bool
send_control_channel_string (struct context *c, const char *str, int msglevel)
{
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
if (c->c2.tls_multi) {
struct gc_arena gc = gc_new ();
bool stat;
@@ -263,7 +262,7 @@ send_control_channel_string (struct context *c, const char *str, int msglevel)
gc_free (&gc);
return stat;
}
-#endif
+#endif /* ENABLE_CRYPTO */
return true;
}
@@ -302,7 +301,7 @@ check_add_routes_dowork (struct context *c)
{
register_signal (c, SIGHUP, "ip-fail");
c->persist.restart_sleep_seconds = 10;
-#ifdef WIN32
+#ifdef _WIN32
show_routes (M_INFO|M_NOPREFIX);
show_adapters (M_INFO|M_NOPREFIX);
#endif
@@ -325,6 +324,13 @@ check_inactivity_timeout_dowork (struct context *c)
register_signal (c, SIGTERM, "inactive");
}
+int
+get_server_poll_remaining_time (struct event_timeout* server_poll_timeout)
+{
+ update_time();
+ int remaining = event_timeout_remaining(server_poll_timeout);
+ return max_int (0, remaining);
+}
#if P2MP
void
@@ -385,7 +391,7 @@ check_fragment_dowork (struct context *c)
struct link_socket_info *lsi = get_link_socket_info (c);
/* OS MTU Hint? */
- if (lsi->mtu_changed && c->c2.ipv4_tun)
+ if (lsi->mtu_changed)
{
frame_adjust_path_mtu (&c->c2.frame_fragment, c->c2.link_socket->mtu,
c->options.ce.proto);
@@ -433,6 +439,7 @@ encrypt_sign (struct context *c, bool comp_frag)
{
struct context_buffers *b = c->c2.buffers;
const uint8_t *orig_buf = c->c2.buf.data;
+ struct crypto_options *co = NULL;
#if P2MP_SERVER
/*
@@ -445,10 +452,10 @@ encrypt_sign (struct context *c, bool comp_frag)
if (comp_frag)
{
-#ifdef ENABLE_LZO
+#ifdef USE_COMP
/* Compress the packet. */
- if (lzo_defined (&c->c2.lzo_compwork))
- lzo_compress (&c->c2.buf, b->lzo_compress_buf, &c->c2.lzo_compwork, &c->c2.frame);
+ if (c->c2.comp_context)
+ (*c->c2.comp_context->alg.compress)(&c->c2.buf, b->compress_buf, c->c2.comp_context, &c->c2.frame);
#endif
#ifdef ENABLE_FRAGMENT
if (c->c2.fragment)
@@ -457,43 +464,41 @@ encrypt_sign (struct context *c, bool comp_frag)
}
#ifdef ENABLE_CRYPTO
-#ifdef ENABLE_SSL
- /*
- * If TLS mode, get the key we will use to encrypt
- * the packet.
- */
+ /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
+ ASSERT (buf_init (&b->encrypt_buf, FRAME_HEADROOM (&c->c2.frame)));
+
if (c->c2.tls_multi)
{
- tls_pre_encrypt (c->c2.tls_multi, &c->c2.buf, &c->c2.crypto_options);
+ /* Get the key we will use to encrypt the packet. */
+ tls_pre_encrypt (c->c2.tls_multi, &c->c2.buf, &co);
+ /* If using P_DATA_V2, prepend the 1-byte opcode and 3-byte peer-id to the
+ * packet before openvpn_encrypt(), so we can authenticate the opcode too.
+ */
+ if (c->c2.buf.len > 0 && !c->c2.tls_multi->opt.server && c->c2.tls_multi->use_peer_id)
+ tls_prepend_opcode_v2 (c->c2.tls_multi, &b->encrypt_buf);
+ }
+ else
+ {
+ co = &c->c2.crypto_options;
}
-#endif
- /*
- * Encrypt the packet and write an optional
- * HMAC signature.
- */
- openvpn_encrypt (&c->c2.buf, b->encrypt_buf, &c->c2.crypto_options, &c->c2.frame);
+ /* Encrypt and authenticate the packet */
+ openvpn_encrypt (&c->c2.buf, b->encrypt_buf, co);
+
+ /* Do packet administration */
+ if (c->c2.tls_multi)
+ {
+ if (c->c2.buf.len > 0 && (c->c2.tls_multi->opt.server || !c->c2.tls_multi->use_peer_id))
+ tls_prepend_opcode_v1(c->c2.tls_multi, &c->c2.buf);
+ tls_post_encrypt (c->c2.tls_multi, &c->c2.buf);
+ }
#endif
+
/*
* Get the address we will be sending the packet to.
*/
link_socket_get_outgoing_addr (&c->c2.buf, get_link_socket_info (c),
&c->c2.to_link_addr);
-#ifdef ENABLE_CRYPTO
-#ifdef ENABLE_SSL
- /*
- * In TLS mode, prepend the appropriate one-byte opcode
- * to the packet which identifies it as a data channel
- * packet and gives the low-permutation version of
- * the key-id to the recipient so it knows which
- * decrypt key to use.
- */
- if (c->c2.tls_multi)
- {
- tls_post_encrypt (c->c2.tls_multi, &c->c2.buf);
- }
-#endif
-#endif
/* if null encryption, copy result to read_tun_buf */
buffer_turnover (orig_buf, &c->c2.to_link, &c->c2.buf, &b->read_tun_buf);
@@ -540,13 +545,16 @@ process_coarse_timers (struct context *c)
return;
#if P2MP
- check_server_poll_timeout (c);
- if (c->sig->signal_received)
- return;
+ if (c->c2.tls_multi)
+ {
+ check_server_poll_timeout (c);
+ if (c->sig->signal_received)
+ return;
- check_scheduled_exit (c);
- if (c->sig->signal_received)
- return;
+ check_scheduled_exit (c);
+ if (c->sig->signal_received)
+ return;
+ }
#endif
#ifdef ENABLE_OCC
@@ -611,8 +619,6 @@ check_timeout_random_component (struct context *c)
tv_add (&c->c2.timeval, &c->c2.timeout_random_component);
}
-#ifdef ENABLE_SOCKS
-
/*
* Handle addition and removal of the 10-byte Socks5 header
* in UDP packets.
@@ -621,7 +627,7 @@ check_timeout_random_component (struct context *c)
static inline void
socks_postprocess_incoming_link (struct context *c)
{
- if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4)
+ if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP)
socks_process_incoming_udp (&c->c2.buf, &c->c2.from);
}
@@ -630,7 +636,7 @@ socks_preprocess_outgoing_link (struct context *c,
struct link_socket_actual **to_addr,
int *size_delta)
{
- if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4)
+ if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP)
{
*size_delta += socks_process_outgoing_udp (&c->c2.to_link, c->c2.to_link_addr);
*to_addr = &c->c2.link_socket->socks_relay;
@@ -650,7 +656,6 @@ link_socket_write_post_size_adjust (int *size,
*size = 0;
}
}
-#endif
/*
* Output: c->c2.buf
@@ -674,7 +679,6 @@ read_incoming_link (struct context *c)
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))
@@ -719,28 +723,17 @@ read_incoming_link (struct context *c)
/* check recvfrom status */
check_status (status, "read", c->c2.link_socket, NULL);
-#ifdef ENABLE_SOCKS
/* Remove socks header if applicable */
socks_postprocess_incoming_link (c);
-#endif
perf_pop ();
}
-/*
- * Input: c->c2.buf
- * Output: c->c2.to_tun
- */
-
-void
-process_incoming_link (struct context *c)
+bool
+process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bool floated)
{
struct gc_arena gc = gc_new ();
- bool decrypt_status;
- struct link_socket_info *lsi = get_link_socket_info (c);
- const uint8_t *orig_buf = c->c2.buf.data;
-
- perf_push (PERF_PROC_IN_LINK);
+ bool decrypt_status = false;
if (c->c2.buf.len > 0)
{
@@ -779,7 +772,7 @@ process_incoming_link (struct context *c)
fprintf (stderr, "R");
#endif
msg (D_LINK_RW, "%s READ [%d] from %s: %s",
- proto2ascii (lsi->proto, true),
+ proto2ascii (lsi->proto, lsi->af, true),
BLEN (&c->c2.buf),
print_link_socket_actual (&c->c2.from, &gc),
PROTO_DUMP (&c->c2.buf, &gc));
@@ -793,11 +786,12 @@ process_incoming_link (struct context *c)
*/
if (c->c2.buf.len > 0)
{
+ struct crypto_options *co = NULL;
+ const uint8_t *ad_start = NULL;
if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from))
link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from);
#ifdef ENABLE_CRYPTO
-#ifdef ENABLE_SSL
if (c->c2.tls_multi)
{
/*
@@ -810,7 +804,8 @@ process_incoming_link (struct context *c)
* will load crypto_options with the correct encryption key
* and return false.
*/
- if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &c->c2.crypto_options))
+ if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &co,
+ floated, &ad_start))
{
interval_action (&c->c2.tmp_int);
@@ -819,6 +814,10 @@ process_incoming_link (struct context *c)
event_timeout_reset (&c->c2.ping_rec_interval);
}
}
+ else
+ {
+ co = &c->c2.crypto_options;
+ }
#if P2MP_SERVER
/*
* Drop non-TLS packet if client-connect script/plugin has not
@@ -827,30 +826,44 @@ process_incoming_link (struct context *c)
if (c->c2.context_auth != CAS_SUCCEEDED)
c->c2.buf.len = 0;
#endif
-#endif /* ENABLE_SSL */
/* authenticate and decrypt the incoming packet */
- decrypt_status = openvpn_decrypt (&c->c2.buf, c->c2.buffers->decrypt_buf, &c->c2.crypto_options, &c->c2.frame);
+ decrypt_status = openvpn_decrypt (&c->c2.buf, c->c2.buffers->decrypt_buf,
+ co, &c->c2.frame, ad_start);
if (!decrypt_status && link_socket_connection_oriented (c->c2.link_socket))
{
/* decryption errors are fatal in TCP mode */
register_signal (c, SIGUSR1, "decryption-error"); /* SOFT-SIGUSR1 -- decryption error in TCP mode */
msg (D_STREAM_ERRORS, "Fatal decryption error (process_incoming_link), restarting");
- goto done;
}
-
+#else /* ENABLE_CRYPTO */
+ decrypt_status = true;
#endif /* ENABLE_CRYPTO */
+ }
+ else
+ {
+ buf_reset (&c->c2.to_tun);
+ }
+ gc_free (&gc);
+
+ return decrypt_status;
+}
+void
+process_incoming_link_part2 (struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf)
+{
+ if (c->c2.buf.len > 0)
+ {
#ifdef ENABLE_FRAGMENT
if (c->c2.fragment)
fragment_incoming (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment);
#endif
-#ifdef ENABLE_LZO
+#ifdef USE_COMP
/* decompress the incoming packet */
- if (lzo_defined (&c->c2.lzo_compwork))
- lzo_decompress (&c->c2.buf, c->c2.buffers->lzo_decompress_buf, &c->c2.lzo_compwork, &c->c2.frame);
+ if (c->c2.comp_context)
+ (*c->c2.comp_context->alg.decompress)(&c->c2.buf, c->c2.buffers->decompress_buf, c->c2.comp_context, &c->c2.frame);
#endif
#ifdef PACKET_TRUNCATION_CHECK
@@ -908,9 +921,20 @@ process_incoming_link (struct context *c)
{
buf_reset (&c->c2.to_tun);
}
- done:
+}
+
+void
+process_incoming_link (struct context *c)
+{
+ perf_push (PERF_PROC_IN_LINK);
+
+ struct link_socket_info *lsi = get_link_socket_info (c);
+ const uint8_t *orig_buf = c->c2.buf.data;
+
+ process_incoming_link_part1(c, lsi, false);
+ process_incoming_link_part2(c, lsi, orig_buf);
+
perf_pop ();
- gc_free (&gc);
}
/*
@@ -969,6 +993,76 @@ read_incoming_tun (struct context *c)
perf_pop ();
}
+/**
+ * Drops UDP packets which OS decided to route via tun.
+ *
+ * On Windows and OS X when netwotk adapter is disabled or
+ * disconnected, platform starts to use tun as external interface.
+ * When packet is sent to tun, it comes to openvpn, encapsulated
+ * and sent to routing table, which sends it again to tun.
+ */
+static void
+drop_if_recursive_routing (struct context *c, struct buffer *buf)
+{
+ bool drop = false;
+ struct openvpn_sockaddr tun_sa;
+ int ip_hdr_offset = 0;
+
+ if (c->c2.to_link_addr == NULL) /* no remote addr known */
+ return;
+
+ tun_sa = c->c2.to_link_addr->dest;
+
+ int proto_ver = get_tun_ip_ver (TUNNEL_TYPE (c->c1.tuntap), &c->c2.buf, &ip_hdr_offset);
+
+ if (proto_ver == 4)
+ {
+ const struct openvpn_iphdr *pip;
+
+ /* make sure we got whole IP header */
+ if (BLEN (buf) < ((int) sizeof (struct openvpn_iphdr) + ip_hdr_offset))
+ return;
+
+ /* skip ipv4 packets for ipv6 tun */
+ if (tun_sa.addr.sa.sa_family != AF_INET)
+ return;
+
+ pip = (struct openvpn_iphdr *) (BPTR (buf) + ip_hdr_offset);
+
+ /* drop packets with same dest addr as gateway */
+ if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr)
+ drop = true;
+ }
+ else if (proto_ver == 6)
+ {
+ const struct openvpn_ipv6hdr *pip6;
+
+ /* make sure we got whole IPv6 header */
+ if (BLEN (buf) < ((int) sizeof (struct openvpn_ipv6hdr) + ip_hdr_offset))
+ return;
+
+ /* skip ipv6 packets for ipv4 tun */
+ if (tun_sa.addr.sa.sa_family != AF_INET6)
+ return;
+
+ /* drop packets with same dest addr as gateway */
+ pip6 = (struct openvpn_ipv6hdr *) (BPTR (buf) + ip_hdr_offset);
+ if (IN6_ARE_ADDR_EQUAL(&tun_sa.addr.in6.sin6_addr, &pip6->daddr))
+ drop = true;
+ }
+
+ if (drop)
+ {
+ struct gc_arena gc = gc_new ();
+
+ c->c2.buf.len = 0;
+
+ msg(D_LOW, "Recursive routing detected, drop tun packet to %s",
+ print_link_socket_actual(c->c2.to_link_addr, &gc));
+ gc_free (&gc);
+ }
+}
+
/*
* Input: c->c2.buf
* Output: c->c2.to_link
@@ -994,6 +1088,8 @@ process_incoming_tun (struct context *c)
if (c->c2.buf.len > 0)
{
+ if ((c->options.mode == MODE_POINT_TO_POINT) && (!c->options.allow_recursive_routing))
+ drop_if_recursive_routing (c, &c->c2.buf);
/*
* The --passtos and --mssfix options require
* us to examine the IP header (IPv4 or IPv6).
@@ -1028,6 +1124,8 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf)
if (!c->options.passtos)
flags &= ~PIPV4_PASSTOS;
#endif
+ if (!c->options.client_nat)
+ flags &= ~PIPV4_CLIENT_NAT;
if (!c->options.route_gateway_via_dhcp)
flags &= ~PIPV4_EXTRACT_DHCP_ROUTER;
@@ -1037,11 +1135,13 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf)
* The --passtos and --mssfix options require
* us to examine the IPv4 header.
*/
+
+ if (flags & (PIP_MSSFIX
#if PASSTOS_CAPABILITY
- if (flags & (PIPV4_PASSTOS|PIP_MSSFIX))
-#else
- if (flags & PIP_MSSFIX)
+ | PIPV4_PASSTOS
#endif
+ | PIPV4_CLIENT_NAT
+ ))
{
struct buffer ipbuf = *buf;
if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf))
@@ -1056,14 +1156,12 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf)
if (flags & PIP_MSSFIX)
mss_fixup_ipv4 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
-#ifdef ENABLE_CLIENT_NAT
/* possibly do NAT on packet */
if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat)
{
const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING : CN_OUTGOING;
client_nat_transform (c->options.client_nat, &ipbuf, direction);
}
-#endif
/* possibly extract a DHCP router message */
if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
{
@@ -1090,6 +1188,7 @@ void
process_outgoing_link (struct context *c)
{
struct gc_arena gc = gc_new ();
+ int error_code = 0;
perf_push (PERF_PROC_OUT_LINK);
@@ -1133,7 +1232,7 @@ process_outgoing_link (struct context *c)
fprintf (stderr, "W");
#endif
msg (D_LINK_RW, "%s WRITE [%d] to %s: %s",
- proto2ascii (c->c2.link_socket->info.proto, true),
+ proto2ascii (c->c2.link_socket->info.proto, c->c2.link_socket->info.af, true),
BLEN (&c->c2.to_link),
print_link_socket_actual (c->c2.to_link_addr, &gc),
PROTO_DUMP (&c->c2.to_link, &gc));
@@ -1141,23 +1240,18 @@ process_outgoing_link (struct context *c)
/* Packet send complexified by possible Socks5 usage */
{
struct link_socket_actual *to_addr = c->c2.to_link_addr;
-#ifdef ENABLE_SOCKS
int size_delta = 0;
-#endif
-#ifdef ENABLE_SOCKS
/* If Socks5 over UDP, prepend header */
socks_preprocess_outgoing_link (c, &to_addr, &size_delta);
-#endif
+
/* Send packet */
size = link_socket_write (c->c2.link_socket,
&c->c2.to_link,
to_addr);
-#ifdef ENABLE_SOCKS
/* Undo effect of prepend */
link_socket_write_post_size_adjust (&size, size_delta, &c->c2.to_link);
-#endif
}
if (size > 0)
@@ -1182,6 +1276,7 @@ process_outgoing_link (struct context *c)
}
/* Check return status */
+ error_code = openvpn_errno();
check_status (size, "write", c->c2.link_socket, NULL);
if (size > 0)
@@ -1198,6 +1293,17 @@ process_outgoing_link (struct context *c)
/* if not a ping/control message, indicate activity regarding --inactive parameter */
if (c->c2.buf.len > 0 )
register_activity (c, size);
+
+
+#ifdef ENABLE_CRYPTO
+ /* for unreachable network and "connecting" state switch to the next host */
+ if (size < 0 && ENETUNREACH == error_code && c->c2.tls_multi &&
+ !tls_initial_packet_received (c->c2.tls_multi) && c->options.mode == MODE_POINT_TO_POINT)
+ {
+ msg (M_INFO, "Network unreachable, restarting");
+ register_signal (c, SIGUSR1, "network-unreachable");
+ }
+#endif
}
else
{
@@ -1314,7 +1420,7 @@ pre_select (struct context *c)
c->c2.timeval.tv_sec = BIG_TIMEOUT;
c->c2.timeval.tv_usec = 0;
-#if defined(WIN32)
+#if defined(_WIN32)
if (check_debug_level (D_TAP_WIN_DEBUG))
{
c->c2.timeval.tv_sec = 1;
@@ -1373,6 +1479,9 @@ io_wait_dowork (struct context *c, const unsigned int flags)
#ifdef ENABLE_MANAGEMENT
static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */
#endif
+#ifdef ENABLE_ASYNC_PUSH
+ static int file_shift = 8; /* listening inotify events */
+#endif
/*
* Decide what kind of events we want to wait for.
@@ -1467,6 +1576,11 @@ io_wait_dowork (struct context *c, const unsigned int flags)
management_socket_set (management, c->c2.event_set, (void*)&management_shift, NULL);
#endif
+#ifdef ENABLE_ASYNC_PUSH
+ /* arm inotify watcher */
+ event_ctl (c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void*)&file_shift);
+#endif
+
/*
* Possible scenarios:
* (1) tcp/udp port has data available to read
diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h
index 1830a00..0856aa7 100644
--- a/src/openvpn/forward.h
+++ b/src/openvpn/forward.h
@@ -103,7 +103,7 @@ void show_wait_status (struct context *c);
* once for each remaining fragment with this parameter set to false.
*/
void encrypt_sign (struct context *c, bool comp_frag);
-
+int get_server_poll_remaining_time (struct event_timeout* server_poll_timeout);
/**********************************************************************/
/**
@@ -127,12 +127,11 @@ void encrypt_sign (struct context *c, bool comp_frag);
*/
void read_incoming_link (struct context *c);
-
/**
- * Process a packet read from the external network interface.
+ * Starts processing a packet read from the external network interface.
* @ingroup external_multiplexer
*
- * This function controls the processing of a data channel packet which
+ * This function starts the processing of a data channel packet which
* has come out of a VPN tunnel. It's high-level structure is as follows:
* - Verify that a nonzero length packet has been received from a valid
* source address for the given context \a c.
@@ -146,6 +145,25 @@ void read_incoming_link (struct context *c);
* - Call \c openvpn_decrypt() of the \link data_crypto Data Channel
* Crypto module\endlink to authenticate and decrypt the packet using
* the security parameters loaded by \c tls_pre_decrypt() above.
+ *
+ * @param c - The context structure of the VPN tunnel associated with the
+ * packet.
+ * @param lsi - link_socket_info obtained from context before processing.
+ * @param floated - Flag indicates that peer has floated.
+ *
+ * @return true if packet is authenticated, false otherwise.
+ */
+bool process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bool floated);
+
+/**
+ * Continues processing a packet read from the external network interface.
+ * @ingroup external_multiplexer
+ *
+ * This function continues the processing of a data channel packet which
+ * has come out of a VPN tunnel. It must be called after
+ * \c process_incoming_link_part1() function.
+ *
+ * It's high-level structure is as follows:
* - Call \c fragment_incoming() of the \link fragmentation Data Channel
* Fragmentation module\endlink to reassemble the packet if it's
* fragmented.
@@ -158,9 +176,11 @@ void read_incoming_link (struct context *c);
*
* @param c - The context structure of the VPN tunnel associated with the
* packet.
+ * @param lsi - link_socket_info obtained from context before processing.
+ * @param orig_buf - Pointer to a buffer data.
+ *
*/
-void process_incoming_link (struct context *c);
-
+void process_incoming_link_part2 (struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf);
/**
* Write a packet to the external network interface.
diff --git a/src/openvpn/helper.c b/src/openvpn/helper.c
index 62f88ec..229523d 100644
--- a/src/openvpn/helper.c
+++ b/src/openvpn/helper.c
@@ -200,8 +200,6 @@ helper_client_server (struct options *o)
add_in6_addr( o->server_network_ipv6, 0x1000 );
o->ifconfig_ipv6_pool_netbits = o->server_netbits_ipv6;
- o->tun_ipv6 = true;
-
push_option( o, "tun-ipv6", M_USAGE );
}
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 2148777..470dc89 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -43,6 +43,9 @@
#include "lladdr.h"
#include "ping.h"
#include "mstats.h"
+#include "ssl_verify.h"
+#include "tls_crypt.h"
+#include "forward-inline.h"
#include "memdbg.h"
@@ -125,42 +128,25 @@ management_callback_proxy_cmd (void *arg, const char **p)
ret = true;
else if (p[2] && p[3])
{
- const int port = atoi(p[3]);
- if (!legal_ipv4_port (port))
- {
- msg (M_WARN, "Bad proxy port number: %s", p[3]);
- return false;
- }
-
if (streq (p[1], "HTTP"))
{
-#ifndef ENABLE_HTTP_PROXY
- msg (M_WARN, "HTTP proxy support is not available");
-#else
struct http_proxy_options *ho;
- if (ce->proto != PROTO_TCPv4 && ce->proto != PROTO_TCPv4_CLIENT &&
- ce->proto != PROTO_TCPv6 && ce->proto != PROTO_TCPv6_CLIENT)
+ if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT )
{
msg (M_WARN, "HTTP proxy support only works for TCP based connections");
return false;
}
ho = init_http_proxy_options_once (&ce->http_proxy_options, gc);
ho->server = string_alloc (p[2], gc);
- ho->port = port;
- ho->retry = true;
+ ho->port = string_alloc (p[3], gc);
ho->auth_retry = (p[4] && streq (p[4], "nct") ? PAR_NCT : PAR_ALL);
ret = true;
-#endif
}
else if (streq (p[1], "SOCKS"))
{
-#ifndef ENABLE_SOCKS
- msg (M_WARN, "SOCKS proxy support is not available");
-#else
ce->socks_proxy_server = string_alloc (p[2], gc);
- ce->socks_proxy_port = port;
+ ce->socks_proxy_port = p[3];
ret = true;
-#endif
}
}
else
@@ -227,8 +213,7 @@ management_callback_remote_cmd (void *arg, const char **p)
}
else if (!strcmp(p[1], "MOD") && p[2] && p[3])
{
- const int port = atoi(p[3]);
- if (strlen(p[2]) < RH_HOST_LEN && legal_ipv4_port(port))
+ if (strlen(p[2]) < RH_HOST_LEN && strlen(p[3]) < RH_PORT_LEN)
{
struct remote_host_store *rhs = c->options.rh_store;
if (!rhs)
@@ -237,8 +222,10 @@ management_callback_remote_cmd (void *arg, const char **p)
c->options.rh_store = rhs;
}
strncpynt(rhs->host, p[2], RH_HOST_LEN);
+ strncpynt(rhs->port, p[3], RH_PORT_LEN);
+
ce->remote = rhs->host;
- ce->remote_port = port;
+ ce->remote_port = rhs->port;
flags = CE_MAN_QUERY_REMOTE_MOD;
ret = true;
}
@@ -253,7 +240,7 @@ management_callback_remote_cmd (void *arg, const char **p)
}
static bool
-ce_management_query_remote (struct context *c, const char *remote_ip_hint)
+ce_management_query_remote (struct context *c)
{
struct gc_arena gc = gc_new ();
volatile struct connection_entry *ce = &c->options.ce;
@@ -262,7 +249,7 @@ ce_management_query_remote (struct context *c, const char *remote_ip_hint)
if (management)
{
struct buffer out = alloc_buf_gc (256, &gc);
- buf_printf (&out, ">REMOTE:%s,%d,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, false));
+ buf_printf (&out, ">REMOTE:%s,%s,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, ce->af, false));
management_notify_generic(management, BSTR (&out));
ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<<CE_MAN_QUERY_REMOTE_SHIFT);
ce->flags |= (CE_MAN_QUERY_REMOTE_QUERY<<CE_MAN_QUERY_REMOTE_SHIFT);
@@ -278,8 +265,6 @@ ce_management_query_remote (struct context *c, const char *remote_ip_hint)
}
{
const int flags = ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK);
- if (flags == CE_MAN_QUERY_REMOTE_ACCEPT && remote_ip_hint)
- ce->remote = remote_ip_hint;
ret = (flags != CE_MAN_QUERY_REMOTE_SKIP);
}
gc_free (&gc);
@@ -294,95 +279,129 @@ static void
init_connection_list (struct context *c)
{
struct connection_list *l = c->options.connection_list;
- if (l)
+
+ l->current = -1;
+ if (c->options.remote_random)
{
- l->current = -1;
- if (c->options.remote_random)
- {
- int i;
- for (i = 0; i < l->len; ++i)
- {
- const int j = get_random () % l->len;
- if (i != j)
- {
- struct connection_entry *tmp;
- tmp = l->array[i];
- l->array[i] = l->array[j];
- l->array[j] = tmp;
- }
- }
- }
+ int i;
+ for (i = 0; i < l->len; ++i)
+ {
+ const int j = get_random () % l->len;
+ if (i != j)
+ {
+ struct connection_entry *tmp;
+ tmp = l->array[i];
+ l->array[i] = l->array[j];
+ l->array[j] = tmp;
+ }
+ }
}
}
/*
+ * Clear the remote address list
+ */
+static void clear_remote_addrlist (struct link_socket_addr *lsa, bool free)
+{
+ if (lsa->remote_list && free)
+ freeaddrinfo(lsa->remote_list);
+ lsa->remote_list = NULL;
+ lsa->current_remote = NULL;
+}
+
+/*
* Increment to next connection entry
*/
static void
next_connection_entry (struct context *c)
{
struct connection_list *l = c->options.connection_list;
- if (l)
- {
- bool ce_defined;
- struct connection_entry *ce;
- int n_cycles = 0;
-
- do {
- const char *remote_ip_hint = NULL;
- bool newcycle = false;
+ bool ce_defined;
+ struct connection_entry *ce;
+ int n_cycles = 0;
- ce_defined = true;
- if (l->no_advance && l->current >= 0)
- {
- l->no_advance = false;
- }
- else
- {
- if (++l->current >= l->len)
+ do {
+ ce_defined = true;
+ if (c->options.no_advance && l->current >= 0)
+ {
+ c->options.no_advance = false;
+ }
+ else
+ {
+ /* Check if there is another resolved address to try for
+ * the current connection */
+ if (c->c1.link_socket_addr.current_remote &&
+ c->c1.link_socket_addr.current_remote->ai_next)
+ {
+ c->c1.link_socket_addr.current_remote =
+ c->c1.link_socket_addr.current_remote->ai_next;
+ }
+ else
+ {
+ /* FIXME (schwabe) fix the persist-remote-ip option for real,
+ * this is broken probably ever since connection lists and multiple
+ * remote existed
+ */
+ if (!c->options.persist_remote_ip)
{
- l->current = 0;
- ++l->n_cycles;
- if (++n_cycles >= 2)
- msg (M_FATAL, "No usable connection profiles are present");
+ /* close_instance should have cleared the addrinfo objects */
+ ASSERT (c->c1.link_socket_addr.current_remote == NULL);
+ ASSERT (c->c1.link_socket_addr.remote_list == NULL);
}
+ else
+ c->c1.link_socket_addr.current_remote =
+ c->c1.link_socket_addr.remote_list;
- if (l->current == 0)
- newcycle = true;
- }
+ /*
+ * Increase the number of connection attempts
+ * If this is connect-retry-max * size(l)
+ * OpenVPN will quit
+ */
- ce = l->array[l->current];
+ c->options.unsuccessful_attempts++;
- if (c->options.remote_ip_hint && !l->n_cycles)
- remote_ip_hint = c->options.remote_ip_hint;
+ if (++l->current >= l->len)
+ {
- if (ce->flags & CE_DISABLED)
- ce_defined = false;
+ l->current = 0;
+ if (++n_cycles >= 2)
+ msg (M_FATAL, "No usable connection profiles are present");
+ }
+ }
+ }
+
+ ce = l->array[l->current];
- c->options.ce = *ce;
+ if (ce->flags & CE_DISABLED)
+ ce_defined = false;
+
+ c->options.ce = *ce;
#ifdef ENABLE_MANAGEMENT
- if (ce_defined && management && management_query_remote_enabled(management))
- {
- /* allow management interface to override connection entry details */
- ce_defined = ce_management_query_remote(c, remote_ip_hint);
- if (IS_SIG (c))
- break;
- }
- else
+ if (ce_defined && management && management_query_remote_enabled(management))
+ {
+ /* allow management interface to override connection entry details */
+ ce_defined = ce_management_query_remote(c);
+ if (IS_SIG (c))
+ break;
+ }
+ else
#endif
- if (remote_ip_hint)
- c->options.ce.remote = remote_ip_hint;
#ifdef ENABLE_MANAGEMENT
- if (ce_defined && management && management_query_proxy_enabled (management))
- {
- ce_defined = ce_management_query_proxy (c);
- if (IS_SIG (c))
- break;
- }
+ if (ce_defined && management && management_query_proxy_enabled (management))
+ {
+ ce_defined = ce_management_query_proxy (c);
+ if (IS_SIG (c))
+ break;
+ }
#endif
- } while (!ce_defined);
- }
+ } while (!ce_defined);
+
+ /* Check if this connection attempt would bring us over the limit */
+ if (c->options.connect_retry_max > 0 &&
+ c->options.unsuccessful_attempts > (l->len * c->options.connect_retry_max))
+ msg(M_FATAL, "All connections have been connect-retry-max (%d) times unsuccessful, exiting",
+ c->options.connect_retry_max);
update_options_ce_post (&c->options);
}
@@ -392,7 +411,7 @@ next_connection_entry (struct context *c)
void
init_query_passwords (const struct context *c)
{
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
/* Certificate password input */
if (c->options.key_pass_file)
pem_password_setup (c->options.key_pass_file);
@@ -415,47 +434,30 @@ init_query_passwords (const struct context *c)
* Initialize/Uninitialize HTTP or SOCKS proxy
*/
-#ifdef GENERAL_PROXY_SUPPORT
-
-static int
-proxy_scope (struct context *c)
-{
- return connection_list_defined (&c->options) ? 2 : 1;
-}
-
static void
uninit_proxy_dowork (struct context *c)
{
-#ifdef ENABLE_HTTP_PROXY
if (c->c1.http_proxy_owned && c->c1.http_proxy)
{
http_proxy_close (c->c1.http_proxy);
c->c1.http_proxy = NULL;
c->c1.http_proxy_owned = false;
}
-#endif
-#ifdef ENABLE_SOCKS
if (c->c1.socks_proxy_owned && c->c1.socks_proxy)
{
socks_proxy_close (c->c1.socks_proxy);
c->c1.socks_proxy = NULL;
c->c1.socks_proxy_owned = false;
}
-#endif
}
static void
init_proxy_dowork (struct context *c)
{
-#ifdef ENABLE_HTTP_PROXY
bool did_http = false;
-#else
- const bool did_http = false;
-#endif
uninit_proxy_dowork (c);
-#ifdef ENABLE_HTTP_PROXY
if (c->options.ce.http_proxy_options)
{
/* Possible HTTP proxy user/pass input */
@@ -466,51 +468,31 @@ init_proxy_dowork (struct context *c)
c->c1.http_proxy_owned = true;
}
}
-#endif
-#ifdef ENABLE_SOCKS
- if (!did_http && c->options.ce.socks_proxy_server)
+ if (!did_http && c->options.ce.socks_proxy_server)
{
c->c1.socks_proxy = socks_proxy_new (c->options.ce.socks_proxy_server,
c->options.ce.socks_proxy_port,
- c->options.ce.socks_proxy_authfile,
- c->options.ce.socks_proxy_retry);
+ c->options.ce.socks_proxy_authfile);
if (c->c1.socks_proxy)
{
c->c1.socks_proxy_owned = true;
}
}
-#endif
}
static void
-init_proxy (struct context *c, const int scope)
+init_proxy (struct context *c)
{
- if (scope == proxy_scope (c))
- init_proxy_dowork (c);
+ init_proxy_dowork (c);
}
static void
uninit_proxy (struct context *c)
{
- if (c->sig->signal_received != SIGUSR1 || proxy_scope (c) == 2)
- uninit_proxy_dowork (c);
-}
-
-#else
-
-static inline void
-init_proxy (struct context *c, const int scope)
-{
-}
-
-static inline void
-uninit_proxy (struct context *c)
-{
+ uninit_proxy_dowork (c);
}
-#endif
-
void
context_init_1 (struct context *c)
{
@@ -544,8 +526,6 @@ context_init_1 (struct context *c)
}
#endif
- /* initialize HTTP or SOCKS proxy object at scope level 1 */
- init_proxy (c, 1);
}
void
@@ -598,7 +578,7 @@ init_static (void)
error_reset (); /* initialize error.c */
reset_check_status (); /* initialize status check code in socket.c */
-#ifdef WIN32
+#ifdef _WIN32
init_win32 ();
#endif
@@ -659,8 +639,10 @@ init_static (void)
#ifdef TEST_GET_DEFAULT_GATEWAY
{
struct route_gateway_info rgi;
+ struct route_ipv6_gateway_info rgi6;
get_default_gateway(&rgi);
- print_default_gateway(M_INFO, &rgi);
+ get_default_gateway_ipv6(&rgi6, NULL);
+ print_default_gateway(M_INFO, &rgi, &rgi6);
return false;
}
#endif
@@ -810,7 +792,7 @@ uninit_static (void)
close_port_share ();
#endif
-#if defined(MEASURE_TLS_HANDSHAKE_STATS) && defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#if defined(MEASURE_TLS_HANDSHAKE_STATS) && defined(ENABLE_CRYPTO)
show_tls_performance_stats ();
#endif
}
@@ -853,10 +835,7 @@ print_openssl_info (const struct options *options)
*/
#ifdef ENABLE_CRYPTO
if (options->show_ciphers || options->show_digests || options->show_engines
-#ifdef ENABLE_SSL
- || options->show_tls_ciphers
-#endif
- )
+ || options->show_tls_ciphers || options->show_curves)
{
if (options->show_ciphers)
show_available_ciphers ();
@@ -864,10 +843,10 @@ print_openssl_info (const struct options *options)
show_available_digests ();
if (options->show_engines)
show_available_engines ();
-#ifdef ENABLE_SSL
if (options->show_tls_ciphers)
show_available_tls_ciphers (options->cipher_list);
-#endif
+ if (options->show_curves)
+ show_available_curves();
return true;
}
#endif
@@ -916,10 +895,8 @@ do_persist_tuntap (const struct options *options)
|| options->ifconfig_remote_netmask
#ifdef ENABLE_CRYPTO
|| options->shared_secret_file
-#ifdef ENABLE_SSL
|| options->tls_server || options->tls_client
#endif
-#endif
)
msg (M_FATAL|M_OPTERR,
"options --mktun or --rmtun should only be used together with --dev");
@@ -1036,7 +1013,7 @@ const char *
format_common_name (struct context *c, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (256, gc);
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
if (c->c2.tls_multi)
{
buf_printf (&out, "[%s] ", tls_common_name (c->c2.tls_multi, false));
@@ -1048,7 +1025,7 @@ format_common_name (struct context *c, struct gc_arena *gc)
void
pre_setup (const struct options *options)
{
-#ifdef WIN32
+#ifdef _WIN32
if (options->exit_event_name)
{
win32_signal_open (&win32_signal,
@@ -1080,6 +1057,19 @@ reset_coarse_timers (struct context *c)
}
/*
+ * Initialise the server poll timeout timer
+ * This timer is used in the http/socks proxy setup so it needs to be setup
+ * before
+ */
+static void
+do_init_server_poll_timeout (struct context *c)
+{
+ update_time ();
+ if (c->options.ce.connect_timeout)
+ event_timeout_init (&c->c2.server_poll_interval, c->options.ce.connect_timeout, now);
+}
+
+/*
* Initialize timers
*/
static void
@@ -1100,11 +1090,6 @@ do_init_timers (struct context *c, bool deferred)
if (c->options.ping_rec_timeout)
event_timeout_init (&c->c2.ping_rec_interval, c->options.ping_rec_timeout, now);
-#if P2MP
- if (c->options.server_poll_timeout)
- event_timeout_init (&c->c2.server_poll_interval, c->options.server_poll_timeout, now);
-#endif
-
if (!deferred)
{
/* initialize connection establishment timer */
@@ -1126,9 +1111,7 @@ do_init_timers (struct context *c, bool deferred)
#ifdef ENABLE_CRYPTO
if (c->options.packet_id_file)
event_timeout_init (&c->c2.packet_id_persist_interval, 60, now);
-#endif
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
/* initialize tmp_int optimization that limits the number of times we call
tls_multi_process in the main event loop */
interval_init (&c->c2.tmp_int, TLS_MULTI_HORIZON, TLS_MULTI_REFRESH);
@@ -1161,9 +1144,9 @@ static void
do_alloc_route_list (struct context *c)
{
if (!c->c1.route_list)
- c->c1.route_list = new_route_list (c->options.max_routes, &c->gc);
+ ALLOC_OBJ_CLEAR_GC (c->c1.route_list, struct route_list, &c->gc);
if (c->options.routes_ipv6 && !c->c1.route_ipv6_list)
- c->c1.route_ipv6_list = new_route_ipv6_list (c->options.max_routes, &c->gc);
+ ALLOC_OBJ_CLEAR_GC (c->c1.route_ipv6_list, struct route_ipv6_list, &c->gc);
}
@@ -1175,7 +1158,6 @@ static void
do_init_route_list (const struct options *options,
struct route_list *route_list,
const struct link_socket_info *link_socket_info,
- bool fatal,
struct env_set *es)
{
const char *gw = NULL;
@@ -1189,18 +1171,13 @@ do_init_route_list (const struct options *options,
if (options->route_default_metric)
metric = options->route_default_metric;
- if (!init_route_list (route_list,
+ if (init_route_list (route_list,
options->routes,
gw,
metric,
link_socket_current_remote (link_socket_info),
es))
{
- if (fatal)
- openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
- }
- else
- {
/* copy routes to environment */
setenv_routes (es, route_list);
}
@@ -1209,11 +1186,10 @@ do_init_route_list (const struct options *options,
static void
do_init_route_ipv6_list (const struct options *options,
struct route_ipv6_list *route_ipv6_list,
- bool fatal,
+ const struct link_socket_info *link_socket_info,
struct env_set *es)
{
const char *gw = NULL;
- int dev = dev_type_enum (options->dev, options->dev_type);
int metric = -1; /* no metric set */
gw = options->ifconfig_ipv6_remote; /* default GW = remote end */
@@ -1225,17 +1201,28 @@ do_init_route_ipv6_list (const struct options *options,
if (options->route_default_metric)
metric = options->route_default_metric;
- if (!init_route_ipv6_list (route_ipv6_list,
+ /* redirect (IPv6) gateway to VPN? if yes, add a few more specifics
+ */
+ if ( options->routes_ipv6->flags & RG_REROUTE_GW )
+ {
+ char *opt_list[] = { "::/3", "2000::/4", "3000::/4", "fc00::/7", NULL };
+ int i;
+
+ for (i=0; opt_list[i]; i++)
+ {
+ add_route_ipv6_to_option_list( options->routes_ipv6,
+ string_alloc (opt_list[i], options->routes_ipv6->gc),
+ NULL, NULL );
+ }
+ }
+
+ if (init_route_ipv6_list (route_ipv6_list,
options->routes_ipv6,
gw,
metric,
+ link_socket_current_remote_ipv6 (link_socket_info),
es))
{
- if (fatal)
- openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
- }
- else
- {
/* copy routes to environment */
setenv_routes_ipv6 (es, route_ipv6_list);
}
@@ -1250,13 +1237,16 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
{
static const char message[] = "Initialization Sequence Completed";
+ /* Reset the unsuccessful connection counter on complete initialisation */
+ c->options.unsuccessful_attempts=0;
+
/* If we delayed UID/GID downgrade or chroot, do it now */
do_uid_gid_chroot (c, true);
/* Test if errors */
if (flags & ISC_ERRORS)
{
-#ifdef WIN32
+#ifdef _WIN32
show_routes (M_INFO|M_NOPREFIX);
show_adapters (M_INFO|M_NOPREFIX);
msg (M_INFO, "%s With Errors ( see http://openvpn.net/faq.html#dhcpclientserv )", message);
@@ -1267,11 +1257,11 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
else
msg (M_INFO, "%s", message);
- /* Flag connection_list that we initialized */
- if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0 && connection_list_defined (&c->options))
- connection_list_set_no_advance (&c->options);
+ /* Flag that we initialized */
+ if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0)
+ c->options.no_advance=true;
-#ifdef WIN32
+#ifdef _WIN32
fork_register_dns_action (c->c1.tuntap);
#endif
@@ -1279,26 +1269,52 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
/* Tell management interface that we initialized */
if (management)
{
- in_addr_t tun_local = 0;
- in_addr_t tun_remote = 0; /* FKS */
+ in_addr_t *tun_local = NULL;
+ struct in6_addr *tun_local6 = NULL;
+ struct openvpn_sockaddr local, remote;
+ struct link_socket_actual *actual;
+ socklen_t sa_len = sizeof(local);
const char *detail = "SUCCESS";
- if (c->c1.tuntap)
- tun_local = c->c1.tuntap->local;
- /* TODO(jjo): for ipv6 this will convert some 32bits in the ipv6 addr
- * to a meaningless ipv4 address.
- * In any case, is somewhat inconsistent to send local tunnel
- * addr with remote _endpoint_ addr (?)
- */
- tun_remote = htonl (c->c1.link_socket_addr.actual.dest.addr.in4.sin_addr.s_addr);
if (flags & ISC_ERRORS)
- detail = "ERROR";
+ detail = "ERROR";
+
+ CLEAR (local);
+ actual = &get_link_socket_info(c)->lsa->actual;
+ remote = actual->dest;
+ getsockname(c->c2.link_socket->sd, &local.addr.sa, &sa_len);
+#if ENABLE_IP_PKTINFO
+ if (!addr_defined(&local))
+ {
+ switch (local.addr.sa.sa_family)
+ {
+ case AF_INET:
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+ local.addr.in4.sin_addr = actual->pi.in4.ipi_spec_dst;
+#else
+ local.addr.in4.sin_addr = actual->pi.in4;
+#endif
+ break;
+ case AF_INET6:
+ local.addr.in6.sin6_addr = actual->pi.in6.ipi6_addr;
+ break;
+ }
+ }
+#endif
+
+ if (c->c1.tuntap)
+ {
+ tun_local = &c->c1.tuntap->local;
+ tun_local6 = &c->c1.tuntap->local_ipv6;
+ }
management_set_state (management,
OPENVPN_STATE_CONNECTED,
detail,
tun_local,
- tun_remote);
+ tun_local6,
+ &local,
+ &remote);
if (tun_local)
- management_post_tunnel_open (management, tun_local);
+ management_post_tunnel_open (management, *tun_local);
}
#endif
}
@@ -1335,12 +1351,12 @@ do_route (const struct options *options,
{
struct argv argv = argv_new ();
setenv_str (es, "script_type", "route-up");
- argv_printf (&argv, "%sc", options->route_script);
+ argv_parse_cmd (&argv, options->route_script);
openvpn_run_script (&argv, es, 0, "--route-up");
argv_reset (&argv);
}
-#ifdef WIN32
+#ifdef _WIN32
if (options->show_net_up)
{
show_routes (M_INFO|M_NOPREFIX);
@@ -1355,21 +1371,6 @@ do_route (const struct options *options,
}
/*
- * Save current pulled options string in the c1 context store, so we can
- * compare against it after possible future restarts.
- */
-#if P2MP
-static void
-save_pulled_options_digest (struct context *c, const struct md5_digest *newdigest)
-{
- if (newdigest)
- c->c1.pulled_options_digest_save = *newdigest;
- else
- md5_digest_clear (&c->c1.pulled_options_digest_save);
-}
-#endif
-
-/*
* initialize tun/tap device object
*/
static void
@@ -1383,14 +1384,11 @@ do_init_tun (struct context *c)
c->options.ifconfig_ipv6_local,
c->options.ifconfig_ipv6_netbits,
c->options.ifconfig_ipv6_remote,
- addr_host (&c->c1.link_socket_addr.local),
- addr_host (&c->c1.link_socket_addr.remote),
+ c->c1.link_socket_addr.bind_local,
+ c->c1.link_socket_addr.remote_list,
!c->options.ifconfig_nowarn,
c->c2.es);
- /* flag tunnel for IPv6 config if --tun-ipv6 is set */
- c->c1.tuntap->ipv6 = c->options.tun_ipv6;
-
init_tun_post (c->c1.tuntap,
&c->c2.frame,
&c->options.tuntap_options);
@@ -1408,22 +1406,39 @@ do_open_tun (struct context *c)
struct gc_arena gc = gc_new ();
bool ret = false;
- c->c2.ipv4_tun = (!c->options.tun_ipv6
- && is_dev_type (c->options.dev, c->options.dev_type, "tun"));
-
+#ifndef TARGET_ANDROID
if (!c->c1.tuntap)
{
+#endif
+
+#ifdef TARGET_ANDROID
+ /* If we emulate persist-tun on android we still have to open a new tun and
+ * then close the old */
+ int oldtunfd=-1;
+ if (c->c1.tuntap)
+ oldtunfd = c->c1.tuntap->fd;
+#endif
+
/* initialize (but do not open) tun/tap object */
do_init_tun (c);
+#ifdef _WIN32
+ /* store (hide) interactive service handle in tuntap_options */
+ c->c1.tuntap->options.msg_channel = c->options.msg_channel;
+ msg (D_ROUTE, "interactive service msg_channel=%u", (unsigned int) c->options.msg_channel);
+#endif
+
/* allocate route list structure */
do_alloc_route_list (c);
/* parse and resolve the route option list */
- 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);
- if (c->options.routes_ipv6 && c->c1.route_ipv6_list )
- do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, false, c->c2.es);
+ ASSERT(c->c2.link_socket);
+ if (c->options.routes && c->c1.route_list)
+ do_init_route_list (&c->options, c->c1.route_list,
+ &c->c2.link_socket->info, c->c2.es);
+ if (c->options.routes_ipv6 && c->c1.route_ipv6_list)
+ do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list,
+ &c->c2.link_socket->info, c->c2.es);
/* do ifconfig */
if (!c->options.ifconfig_noexec
@@ -1438,6 +1453,16 @@ do_open_tun (struct context *c)
do_ifconfig (c->c1.tuntap, guess, TUN_MTU_SIZE (&c->c2.frame), c->c2.es);
}
+ /* possibly add routes */
+ if (route_order() == ROUTE_BEFORE_TUN) {
+ /* Ignore route_delay, would cause ROUTE_BEFORE_TUN to be ignored */
+ do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
+ c->c1.tuntap, c->plugins, c->c2.es);
+ }
+#ifdef TARGET_ANDROID
+ /* Store the old fd inside the fd so open_tun can use it */
+ c->c1.tuntap->fd = oldtunfd;
+#endif
/* open the tun device */
open_tun (c->options.dev, c->options.dev_type, c->options.dev_node,
c->c1.tuntap);
@@ -1458,7 +1483,7 @@ do_open_tun (struct context *c)
c->plugins,
OPENVPN_PLUGIN_UP,
c->c1.tuntap->actual_name,
-#ifdef WIN32
+#ifdef _WIN32
c->c1.tuntap->adapter_index,
#endif
dev_type_string (c->options.dev, c->options.dev_type),
@@ -1471,17 +1496,17 @@ do_open_tun (struct context *c)
"up",
c->c2.es);
-#ifdef WIN32
+#if defined(_WIN32)
if (c->options.block_outside_dns)
{
dmsg (D_LOW, "Blocking outside DNS");
- if (!win_wfp_block_dns(c->c1.tuntap->adapter_index))
+ if (!win_wfp_block_dns(c->c1.tuntap->adapter_index, c->options.msg_channel))
msg (M_FATAL, "Blocking DNS failed!");
}
#endif
/* possibly add routes */
- if (!c->options.route_delay_defined)
+ if ((route_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined))
do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
c->c1.tuntap, c->plugins, c->c2.es);
@@ -1495,6 +1520,7 @@ do_open_tun (struct context *c)
ret = true;
static_context = c;
+#ifndef TARGET_ANDROID
}
else
{
@@ -1510,7 +1536,7 @@ do_open_tun (struct context *c)
c->plugins,
OPENVPN_PLUGIN_UP,
c->c1.tuntap->actual_name,
-#ifdef WIN32
+#ifdef _WIN32
c->c1.tuntap->adapter_index,
#endif
dev_type_string (c->options.dev, c->options.dev_type),
@@ -1522,7 +1548,17 @@ do_open_tun (struct context *c)
NULL,
"up",
c->c2.es);
+#if defined(_WIN32)
+ if (c->options.block_outside_dns)
+ {
+ dmsg (D_LOW, "Blocking outside DNS");
+ if (!win_wfp_block_dns(c->c1.tuntap->adapter_index, c->options.msg_channel))
+ msg (M_FATAL, "Blocking DNS failed!");
+ }
+#endif
+
}
+#endif
gc_free (&gc);
return ret;
}
@@ -1539,7 +1575,7 @@ do_close_tun_simple (struct context *c)
c->c1.tuntap = NULL;
c->c1.tuntap_owned = false;
#if P2MP
- save_pulled_options_digest (c, NULL); /* delete C1-saved pulled_options_digest */
+ CLEAR (c->c1.pulled_options_digest_save);
#endif
}
@@ -1550,7 +1586,7 @@ do_close_tun (struct context *c, bool force)
if (c->c1.tuntap && c->c1.tuntap_owned)
{
const char *tuntap_actual = string_alloc (c->c1.tuntap->actual_name, &gc);
-#ifdef WIN32
+#ifdef _WIN32
DWORD adapter_index = c->c1.tuntap->adapter_index;
#endif
const in_addr_t local = c->c1.tuntap->local;
@@ -1571,12 +1607,12 @@ do_close_tun (struct context *c, bool force)
/* delete any routes we added */
if (c->c1.route_list || c->c1.route_ipv6_list )
- {
+ {
run_up_down (c->options.route_predown_script,
c->plugins,
OPENVPN_PLUGIN_ROUTE_PREDOWN,
tuntap_actual,
-#ifdef WIN32
+#ifdef _WIN32
adapter_index,
#endif
NULL,
@@ -1604,7 +1640,7 @@ do_close_tun (struct context *c, bool force)
c->plugins,
OPENVPN_PLUGIN_DOWN,
tuntap_actual,
-#ifdef WIN32
+#ifdef _WIN32
adapter_index,
#endif
NULL,
@@ -1618,10 +1654,10 @@ do_close_tun (struct context *c, bool force)
"down",
c->c2.es);
-#ifdef WIN32
+#if defined(_WIN32)
if (c->options.block_outside_dns)
{
- if (!win_wfp_uninit())
+ if (!win_wfp_uninit(c->options.msg_channel))
msg (M_FATAL, "Uninitialising WFP failed!");
}
#endif
@@ -1638,7 +1674,7 @@ do_close_tun (struct context *c, bool force)
c->plugins,
OPENVPN_PLUGIN_DOWN,
tuntap_actual,
-#ifdef WIN32
+#ifdef _WIN32
adapter_index,
#endif
NULL,
@@ -1651,6 +1687,15 @@ do_close_tun (struct context *c, bool force)
c->sig->signal_text),
"down",
c->c2.es);
+
+#if defined(_WIN32)
+ if (c->options.block_outside_dns)
+ {
+ if (!win_wfp_uninit(c->options.msg_channel))
+ msg (M_FATAL, "Uninitialising WFP failed!");
+ }
+#endif
+
}
}
gc_free (&gc);
@@ -1671,7 +1716,22 @@ tun_abort()
* Handle delayed tun/tap interface bringup due to --up-delay or --pull
*/
-void
+#if P2MP
+/**
+ * Helper for do_up(). Take two option hashes and return true if they are not
+ * equal, or either one is all-zeroes.
+ */
+static bool
+options_hash_changed_or_zero(const struct md5_digest *a,
+ const struct md5_digest *b)
+{
+ const struct md5_digest zero = {{0}};
+ return memcmp (a, b, sizeof(struct md5_digest)) ||
+ !memcmp (a, &zero, sizeof(struct md5_digest));
+}
+#endif /* P2MP */
+
+bool
do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
{
if (!c->c2.do_up_ran)
@@ -1679,7 +1739,13 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
reset_coarse_timers (c);
if (pulled_options && option_types_found)
- do_deferred_options (c, option_types_found);
+ {
+ if (!do_deferred_options (c, option_types_found))
+ {
+ msg (D_PUSH_ERRORS, "ERROR: Failed to apply push options");
+ return false;
+ }
+ }
/* if --up-delay specified, open tun, do ifconfig, and run up script now */
if (c->options.up_delay || PULL_DEFINED (&c->options))
@@ -1695,8 +1761,8 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
if (!c->c2.did_open_tun
&& PULL_DEFINED (&c->options)
&& c->c1.tuntap
- && (!md5_digest_defined (&c->c1.pulled_options_digest_save) || !md5_digest_defined (&c->c2.pulled_options_digest)
- || !md5_digest_equal (&c->c1.pulled_options_digest_save, &c->c2.pulled_options_digest)))
+ && options_hash_changed_or_zero (&c->c1.pulled_options_digest_save,
+ &c->c2.pulled_options_digest))
{
/* if so, close tun, delete routes, then reinitialize tun and add routes */
msg (M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device.");
@@ -1711,11 +1777,11 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
if (c->c2.did_open_tun)
{
#if P2MP
- save_pulled_options_digest (c, &c->c2.pulled_options_digest);
+ c->c1.pulled_options_digest_save = c->c2.pulled_options_digest;
#endif
/* if --route-delay was specified, start timer */
- if (c->options.route_delay_defined)
+ if ((route_order() == ROUTE_AFTER_TUN) && c->options.route_delay_defined)
{
event_timeout_init (&c->c2.route_wakeup, c->options.route_delay, now);
event_timeout_init (&c->c2.route_wakeup_expire, c->options.route_delay + c->options.route_delay_window, now);
@@ -1734,6 +1800,7 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
c->c2.do_up_ran = true;
}
+ return true;
}
/*
@@ -1761,13 +1828,18 @@ pull_permission_mask (const struct context *c)
if (!c->options.route_nopull)
flags |= (OPT_P_ROUTE | OPT_P_IPWIN32);
+#ifdef ENABLE_CRYPTO
+ if (c->options.ncp_enabled)
+ flags |= OPT_P_NCP;
+#endif
+
return flags;
}
/*
* Handle non-tun-related pulled options.
*/
-void
+bool
do_deferred_options (struct context *c, const unsigned int found)
{
if (found & OPT_P_MESSAGES)
@@ -1794,14 +1866,12 @@ do_deferred_options (struct context *c, const unsigned int found)
}
#endif
-#ifdef ENABLE_LZO
+#ifdef USE_COMP
if (found & OPT_P_COMP)
{
- if (lzo_defined (&c->c2.lzo_compwork))
- {
- msg (D_PUSH, "OPTIONS IMPORT: LZO parms modified");
- lzo_modify_flags (&c->c2.lzo_compwork, c->options.lzo);
- }
+ msg (D_PUSH, "OPTIONS IMPORT: compression parms modified");
+ comp_uninit (c->c2.comp_context);
+ c->c2.comp_context = comp_init (&c->options.comp);
}
#endif
@@ -1836,7 +1906,7 @@ do_deferred_options (struct context *c, const unsigned int found)
if (found & OPT_P_SETENV)
msg (D_PUSH, "OPTIONS IMPORT: environment modified");
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
if (found & OPT_P_PEER_ID)
{
msg (D_PUSH, "OPTIONS IMPORT: peer-id set");
@@ -1856,20 +1926,37 @@ do_deferred_options (struct context *c, const unsigned int found)
" MTU problems", TUN_MTU_SIZE(&c->c2.frame) );
}
}
+
+ /* process (potentially pushed) crypto options */
+ if (c->options.pull)
+ {
+ struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
+ if (found & OPT_P_NCP)
+ msg (D_PUSH, "OPTIONS IMPORT: data channel crypto options modified");
+ /* Do not regenerate keys if server sends an extra push request */
+ if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized &&
+ !tls_session_update_crypto_params(session, &c->options, &c->c2.frame))
+ {
+ msg (D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options");
+ return false;
+ }
+ }
#endif
+ return true;
}
/*
- * Possible hold on initialization
+ * Possible hold on initialization, holdtime is the
+ * time OpenVPN would wait without management
*/
static bool
-do_hold (void)
+do_hold (int holdtime)
{
#ifdef ENABLE_MANAGEMENT
if (management)
{
/* block until management hold is released */
- if (management_hold (management))
+ if (management_hold (management, holdtime))
return true;
}
#endif
@@ -1882,31 +1969,16 @@ do_hold (void)
static void
socket_restart_pause (struct context *c)
{
- bool proxy = false;
int sec = 2;
-
-#ifdef ENABLE_HTTP_PROXY
- if (c->options.ce.http_proxy_options)
- proxy = true;
-#endif
-#ifdef ENABLE_SOCKS
- if (c->options.ce.socks_proxy_server)
- proxy = true;
-#endif
+ int backoff = 0;
switch (c->options.ce.proto)
{
- case PROTO_UDPv4:
- case PROTO_UDPv6:
- if (proxy)
- sec = c->options.ce.connect_retry_seconds;
- break;
- case PROTO_TCPv4_SERVER:
- case PROTO_TCPv6_SERVER:
+ case PROTO_TCP_SERVER:
sec = 1;
break;
- case PROTO_TCPv4_CLIENT:
- case PROTO_TCPv6_CLIENT:
+ case PROTO_UDP:
+ case PROTO_TCP_CLIENT:
sec = c->options.ce.connect_retry_seconds;
break;
}
@@ -1919,13 +1991,22 @@ socket_restart_pause (struct context *c)
#if P2MP
if (auth_retry_get () == AR_NOINTERACT)
sec = 10;
-
-#if 0 /* not really needed because of c->persist.restart_sleep_seconds */
- if (c->options.server_poll_timeout && sec > 1)
- sec = 1;
-#endif
#endif
+ /* Slow down reconnection after 5 retries per remote -- for tcp only in client mode */
+ if (c->options.ce.proto != PROTO_TCP_SERVER)
+ {
+ backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) - 4;
+ if (backoff > 0)
+ {
+ /* sec is less than 2^16; we can left shift it by up to 15 bits without overflow */
+ sec = max_int (sec, 1) << min_int (backoff, 15);
+ }
+
+ if (sec > c->options.ce.connect_retry_seconds_max)
+ sec = c->options.ce.connect_retry_seconds_max;
+ }
+
if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec)
sec = c->persist.restart_sleep_seconds;
else if (c->persist.restart_sleep_seconds == -1)
@@ -1933,8 +2014,10 @@ socket_restart_pause (struct context *c)
c->persist.restart_sleep_seconds = 0;
/* do managment hold on context restart, i.e. second, third, fourth, etc. initialization */
- if (do_hold ())
+ if (do_hold (sec))
+ {
sec = 0;
+ }
if (sec)
{
@@ -1952,7 +2035,7 @@ do_startup_pause (struct context *c)
if (!c->first_time)
socket_restart_pause (c);
else
- do_hold (); /* do management hold on first context initialization */
+ do_hold (0); /* do management hold on first context initialization */
}
/*
@@ -1977,6 +2060,7 @@ frame_finalize_options (struct context *c, const struct options *o)
|FRAME_HEADROOM_MARKER_READ_STREAM);
}
+ frame_add_to_extra_buffer (&c->c2.frame, PAYLOAD_ALIGN);
frame_finalize (&c->c2.frame,
o->ce.link_mtu_defined,
o->ce.link_mtu,
@@ -1992,13 +2076,11 @@ key_schedule_free (struct key_schedule *ks, bool free_ssl_ctx)
{
#ifdef ENABLE_CRYPTO
free_key_ctx_bi (&ks->static_key);
-#ifdef ENABLE_SSL
if (tls_ctx_initialised(&ks->ssl_ctx) && free_ssl_ctx)
{
tls_ctx_free (&ks->ssl_ctx);
- free_key_ctx_bi (&ks->tls_auth_key);
+ free_key_ctx_bi (&ks->tls_wrap_key);
}
-#endif /* ENABLE_SSL */
#endif /* ENABLE_CRYPTO */
CLEAR (*ks);
}
@@ -2018,14 +2100,6 @@ init_crypto_pre (struct context *c, const unsigned int flags)
packet_id_persist_load (&c->c1.pid_persist, c->options.packet_id_file);
}
- /* Initialize crypto options */
-
- if (c->options.use_iv)
- c->c2.crypto_options.flags |= CO_USE_IV;
-
- if (c->options.mute_replay_warnings)
- c->c2.crypto_options.flags |= CO_MUTE_REPLAY_WARNINGS;
-
#ifdef ENABLE_PREDICTION_RESISTANCE
if (c->options.use_prediction_resistance)
rand_ctx_enable_prediction_resistance();
@@ -2044,60 +2118,38 @@ do_init_crypto_static (struct context *c, const unsigned int flags)
init_crypto_pre (c, flags);
+ /* Initialize flags */
+ if (c->options.use_iv)
+ c->c2.crypto_options.flags |= CO_USE_IV;
+
+ if (c->options.mute_replay_warnings)
+ c->c2.crypto_options.flags |= CO_MUTE_REPLAY_WARNINGS;
+
/* Initialize packet ID tracking */
if (options->replay)
{
- packet_id_init (&c->c2.packet_id,
- link_socket_proto_connection_oriented (options->ce.proto),
+ packet_id_init (&c->c2.crypto_options.packet_id,
options->replay_window,
options->replay_time,
"STATIC", 0);
- c->c2.crypto_options.packet_id = &c->c2.packet_id;
c->c2.crypto_options.pid_persist = &c->c1.pid_persist;
c->c2.crypto_options.flags |= CO_PACKET_ID_LONG_FORM;
packet_id_persist_load_obj (&c->c1.pid_persist,
- c->c2.crypto_options.packet_id);
+ &c->c2.crypto_options.packet_id);
}
if (!key_ctx_bi_defined (&c->c1.ks.static_key))
{
- struct key2 key2;
- struct key_direction_state kds;
-
/* Get cipher & hash algorithms */
- init_key_type (&c->c1.ks.key_type, options->ciphername,
- options->ciphername_defined, options->authname,
- options->authname_defined, options->keysize,
- options->test_crypto, true);
+ init_key_type (&c->c1.ks.key_type, options->ciphername, options->authname,
+ options->keysize, options->test_crypto, true);
/* Read cipher and hmac keys from shared secret file */
- {
- unsigned int rkf_flags = RKF_MUST_SUCCEED;
- const char *rkf_file = options->shared_secret_file;
-
- if (options->shared_secret_file_inline)
- {
- rkf_file = options->shared_secret_file_inline;
- rkf_flags |= RKF_INLINE;
- }
- read_key_file (&key2, rkf_file, rkf_flags);
- }
-
- /* Check for and fix highly unlikely key problems */
- verify_fix_key2 (&key2, &c->c1.ks.key_type,
- options->shared_secret_file);
-
- /* Initialize OpenSSL key objects */
- key_direction_state_init (&kds, options->key_direction);
- must_have_n_keys (options->shared_secret_file, "secret", &key2,
- kds.need_keys);
- init_key_ctx (&c->c1.ks.static_key.encrypt, &key2.keys[kds.out_key],
- &c->c1.ks.key_type, OPENVPN_OP_ENCRYPT, "Static Encrypt");
- init_key_ctx (&c->c1.ks.static_key.decrypt, &key2.keys[kds.in_key],
- &c->c1.ks.key_type, OPENVPN_OP_DECRYPT, "Static Decrypt");
-
- /* Erase the temporary copy of key */
- CLEAR (key2);
+ crypto_read_openvpn_key (&c->c1.ks.key_type, &c->c1.ks.static_key,
+ options->shared_secret_file,
+ options->shared_secret_file_inline,
+ options->key_direction, "Static Key Encryption",
+ "secret");
}
else
{
@@ -2105,12 +2157,11 @@ do_init_crypto_static (struct context *c, const unsigned int flags)
}
/* Get key schedule */
- c->c2.crypto_options.key_ctx_bi = &c->c1.ks.static_key;
+ c->c2.crypto_options.key_ctx_bi = c->c1.ks.static_key;
/* Compute MTU parameters */
crypto_adjust_frame_parameters (&c->c2.frame,
&c->c1.ks.key_type,
- options->ciphername_defined,
options->use_iv, options->replay, true);
/* Sanity check on IV, sequence number, and cipher mode options */
@@ -2118,8 +2169,6 @@ do_init_crypto_static (struct context *c, const unsigned int flags)
options->use_iv);
}
-#ifdef ENABLE_SSL
-
/*
* Initialize the persistent component of OpenVPN's TLS mode,
* which is preserved across SIGUSR1 resets.
@@ -2160,9 +2209,8 @@ do_init_crypto_tls_c1 (struct context *c)
}
/* Get cipher & hash algorithms */
- init_key_type (&c->c1.ks.key_type, options->ciphername,
- options->ciphername_defined, options->authname,
- options->authname_defined, options->keysize, true, true);
+ init_key_type (&c->c1.ks.key_type, options->ciphername, options->authname,
+ options->keysize, true, true);
/* Initialize PRNG with config-specified digest */
prng_init (options->prng_hash, options->prng_nonce_secret_len);
@@ -2170,21 +2218,36 @@ do_init_crypto_tls_c1 (struct context *c)
/* TLS handshake authentication (--tls-auth) */
if (options->tls_auth_file)
{
- unsigned int flags = 0;
- const char *file = options->tls_auth_file;
-
- if (options->tls_auth_file_inline)
+ /* Initialize key_type for tls-auth with auth only */
+ CLEAR (c->c1.ks.tls_auth_key_type);
+ if (!streq (options->authname, "none"))
{
- flags |= GHK_INLINE;
- file = options->tls_auth_file_inline;
+ c->c1.ks.tls_auth_key_type.digest = md_kt_get (options->authname);
+ c->c1.ks.tls_auth_key_type.hmac_length =
+ md_kt_size (c->c1.ks.tls_auth_key_type.digest);
}
- get_tls_handshake_key (&c->c1.ks.key_type,
- &c->c1.ks.tls_auth_key,
- file,
- options->key_direction,
- flags);
+ else
+ {
+ msg (M_FATAL, "ERROR: tls-auth enabled, but no valid --auth "
+ "algorithm specified ('%s')", options->authname);
+ }
+
+ crypto_read_openvpn_key (&c->c1.ks.tls_auth_key_type,
+ &c->c1.ks.tls_wrap_key, options->tls_auth_file,
+ options->tls_auth_file_inline, options->key_direction,
+ "Control Channel Authentication", "tls-auth");
}
+ /* TLS handshake encryption+authentication (--tls-crypt) */
+ if (options->tls_crypt_file) {
+ tls_crypt_init_key (&c->c1.ks.tls_wrap_key, options->tls_crypt_file,
+ options->tls_crypt_inline, options->tls_server);
+ }
+
+ c->c1.ciphername = options->ciphername;
+ c->c1.authname = options->authname;
+ c->c1.keysize = options->keysize;
+
#if 0 /* was: #if ENABLE_INLINE_FILES -- Note that enabling this code will break restarts */
if (options->priv_key_file_inline)
{
@@ -2196,6 +2259,11 @@ do_init_crypto_tls_c1 (struct context *c)
else
{
msg (D_INIT_MEDIUM, "Re-using SSL/TLS context");
+
+ /* Restore pre-NCP cipher options */
+ c->options.ciphername = c->c1.ciphername;
+ c->options.authname = c->c1.authname;
+ c->options.keysize = c->c1.keysize;
}
}
@@ -2226,17 +2294,28 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
/* In short form, unique datagram identifier is 32 bits, in long form 64 bits */
packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher);
- /* Compute MTU parameters */
- crypto_adjust_frame_parameters (&c->c2.frame,
- &c->c1.ks.key_type,
- options->ciphername_defined,
- options->use_iv,
- options->replay, packet_id_long_form);
+ /* Compute MTU parameters (postpone if we push/pull options) */
+ if (c->options.pull || c->options.mode == MODE_SERVER)
+ {
+ /* Account for worst-case crypto overhead before allocating buffers */
+ frame_add_to_extra_frame (&c->c2.frame, crypto_max_overhead());
+ }
+ else
+ {
+ crypto_adjust_frame_parameters(&c->c2.frame, &c->c1.ks.key_type,
+ options->use_iv, options->replay, packet_id_long_form);
+ }
tls_adjust_frame_parameters (&c->c2.frame);
/* Set all command-line TLS-related options */
CLEAR (to);
+ if (options->use_iv)
+ to.crypto_flags |= CO_USE_IV;
+
+ if (options->mute_replay_warnings)
+ to.crypto_flags |= CO_MUTE_REPLAY_WARNINGS;
+
to.crypto_flags_and = ~(CO_PACKET_ID_LONG_FORM);
if (packet_id_long_form)
to.crypto_flags_or = CO_PACKET_ID_LONG_FORM;
@@ -2249,6 +2328,9 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.replay_window = options->replay_window;
to.replay_time = options->replay_time;
to.tcp_mode = link_socket_proto_connection_oriented (options->ce.proto);
+ to.config_ciphername = c->c1.ciphername;
+ to.config_authname = c->c1.authname;
+ to.ncp_enabled = options->ncp_enabled;
to.transition_window = options->transition_window;
to.handshake_window = options->handshake_window;
to.packet_timeout = options->tls_timeout;
@@ -2256,6 +2338,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.renegotiate_packets = options->renegotiate_packets;
to.renegotiate_seconds = options->renegotiate_seconds;
to.single_session = options->single_session;
+ to.mode = options->mode;
+ to.pull = options->pull;
#ifdef ENABLE_PUSH_PEER_INFO
if (options->push_peer_info) /* all there is */
to.push_peer_info_detail = 2;
@@ -2267,7 +2351,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
/* should we not xmit any packets until we get an initial
response from client? */
- if (to.server && options->ce.proto == PROTO_TCPv4_SERVER)
+ if (to.server && options->ce.proto == PROTO_TCP_SERVER)
to.xmit_hold = true;
#ifdef ENABLE_OCC
@@ -2279,6 +2363,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.verify_x509_type = (options->verify_x509_type & 0xff);
to.verify_x509_name = options->verify_x509_name;
to.crl_file = options->crl_file;
+ to.crl_file_inline = options->crl_file_inline;
to.ssl_flags = options->ssl_flags;
to.ns_cert_type = options->ns_cert_type;
memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku));
@@ -2308,11 +2393,11 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
if (options->ccd_exclusive)
to.client_config_dir_exclusive = options->client_config_dir;
to.auth_user_pass_file = options->auth_user_pass_file;
+ to.auth_token_generate = options->auth_token_generate;
+ to.auth_token_lifetime = options->auth_token_lifetime;
#endif
-#ifdef ENABLE_X509_TRACK
to.x509_track = options->x509_track;
-#endif
#if P2MP
#ifdef ENABLE_CLIENT_CR
@@ -2320,15 +2405,46 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
#endif
#endif
+#ifdef USE_COMP
+ to.comp_options = options->comp;
+#endif
+
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
+ if (options->keying_material_exporter_label)
+ {
+ to.ekm_size = options->keying_material_exporter_length;
+ if (to.ekm_size < 16 || to.ekm_size > 4095)
+ to.ekm_size = 0;
+
+ to.ekm_label = options->keying_material_exporter_label;
+ to.ekm_label_size = strlen(to.ekm_label);
+ }
+ else
+ {
+ to.ekm_size = 0;
+ }
+#endif
+
/* TLS handshake authentication (--tls-auth) */
if (options->tls_auth_file)
{
- to.tls_auth_key = c->c1.ks.tls_auth_key;
- to.tls_auth.pid_persist = &c->c1.pid_persist;
- to.tls_auth.flags |= CO_PACKET_ID_LONG_FORM;
+ to.tls_wrap.mode = TLS_WRAP_AUTH;
+ to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key;
+ to.tls_wrap.opt.pid_persist = &c->c1.pid_persist;
+ to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM;
crypto_adjust_frame_parameters (&to.frame,
- &c->c1.ks.key_type,
- false, false, true, true);
+ &c->c1.ks.tls_auth_key_type,
+ false, true, true);
+ }
+
+ /* TLS handshake encryption (--tls-crypt) */
+ if (options->tls_crypt_file)
+ {
+ to.tls_wrap.mode = TLS_WRAP_CRYPT;
+ to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key;
+ to.tls_wrap.opt.pid_persist = &c->c1.pid_persist;
+ to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM;
+ tls_crypt_adjust_frame_parameters (&to.frame);
}
/* If we are running over TCP, allow for
@@ -2364,10 +2480,6 @@ do_init_finalize_tls_frame (struct context *c)
}
}
-#endif /* ENABLE_SSL */
-#endif /* ENABLE_CRYPTO */
-
-#ifdef ENABLE_CRYPTO
/*
* No encryption or authentication.
*/
@@ -2386,54 +2498,70 @@ do_init_crypto (struct context *c, const unsigned int flags)
#ifdef ENABLE_CRYPTO
if (c->options.shared_secret_file)
do_init_crypto_static (c, flags);
-#ifdef ENABLE_SSL
else if (c->options.tls_server || c->options.tls_client)
do_init_crypto_tls (c, flags);
-#endif
else /* no encryption or authentication. */
do_init_crypto_none (c);
#else /* ENABLE_CRYPTO */
msg (M_WARN,
"******* WARNING *******: " PACKAGE_NAME
- " built without OpenSSL -- encryption and authentication features disabled -- all data will be tunnelled as cleartext");
+ " built without crypto library -- encryption and authentication features disabled -- all data will be tunnelled as cleartext");
#endif /* ENABLE_CRYPTO */
}
static void
do_init_frame (struct context *c)
{
-#ifdef ENABLE_LZO
+#ifdef USE_COMP
/*
- * Initialize LZO compression library.
+ * modify frame parameters if compression is enabled
*/
- if (c->options.lzo & LZO_SELECTED)
+ if (comp_enabled(&c->options.comp))
{
- lzo_adjust_frame_parameters (&c->c2.frame);
+ comp_add_to_extra_frame (&c->c2.frame);
+#if !defined(ENABLE_LZ4)
/*
- * LZO usage affects buffer alignment.
+ * Compression usage affects buffer alignment when non-swapped algs
+ * such as LZO is used.
+ * Newer algs like LZ4 and comp-stub with COMP_F_SWAP don't need
+ * any special alignment because of the control-byte swap approach.
+ * LZO alignment (on the other hand) is problematic because
+ * the presence of the control byte means that either the output of
+ * decryption must be written to an unaligned buffer, or the input
+ * to compression (or packet dispatch if packet is uncompressed)
+ * must be read from an unaligned buffer.
+ * This code tries to align the input to compression (or packet
+ * dispatch if packet is uncompressed) at the cost of requiring
+ * decryption output to be written to an unaligned buffer, so
+ * it's more of a tradeoff than an optimal solution and we don't
+ * include it when we are doing a modern build with LZ4.
+ * Strictly speaking, on the server it would be better to execute
+ * this code for every connection after we decide the compression
+ * method, but currently the frame code doesn't appear to be
+ * flexible enough for this, since the frame is already established
+ * before it is known which compression options will be pushed.
*/
- if (CIPHER_ENABLED (c))
+ if (comp_unswapped_prefix (&c->options.comp) && CIPHER_ENABLED (c))
{
- frame_add_to_align_adjust (&c->c2.frame, LZO_PREFIX_LEN);
+ frame_add_to_align_adjust (&c->c2.frame, COMP_PREFIX_LEN);
frame_or_align_flags (&c->c2.frame,
FRAME_HEADROOM_MARKER_FRAGMENT
|FRAME_HEADROOM_MARKER_DECRYPT);
}
+#endif
#ifdef ENABLE_FRAGMENT
- lzo_adjust_frame_parameters (&c->c2.frame_fragment_omit); /* omit LZO frame delta from final frame_fragment */
+ comp_add_to_extra_frame (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */
#endif
}
-#endif /* ENABLE_LZO */
+#endif /* USE_COMP */
-#ifdef ENABLE_SOCKS
/*
* Adjust frame size for UDP Socks support.
*/
if (c->options.ce.socks_proxy_server)
socks_adjust_frame_parameters (&c->c2.frame, c->options.ce.proto);
-#endif
/*
* Adjust frame size based on the --tun-mtu-extra parameter.
@@ -2454,16 +2582,27 @@ do_init_frame (struct context *c)
*/
frame_finalize_options (c, NULL);
+#ifdef USE_COMP
+ /*
+ * Modify frame parameters if compression is compiled in.
+ * Should be called after frame_finalize_options.
+ */
+ comp_add_to_extra_buffer (&c->c2.frame);
+#ifdef ENABLE_FRAGMENT
+ comp_add_to_extra_buffer (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */
+#endif
+#endif /* USE_COMP */
+
/* packets with peer-id (P_DATA_V2) need 3 extra bytes in frame (on client)
* and need link_mtu+3 bytes on socket reception (on server).
*
- * accomodate receive path in f->extra_link
- * send path in f->extra_buffer (+leave room for alignment)
+ * accomodate receive path in f->extra_link, which has the side effect of
+ * also increasing send buffers (BUF_SIZE() macro), which need to be
+ * allocated big enough before receiving peer-id option from server.
*
* f->extra_frame is adjusted when peer-id option is push-received
*/
frame_add_to_extra_link(&c->c2.frame, 3);
- frame_add_to_extra_buffer(&c->c2.frame, 8);
#ifdef ENABLE_FRAGMENT
/*
@@ -2546,7 +2685,6 @@ do_option_warnings (struct context *c)
if (!o->use_iv)
msg (M_WARN, "WARNING: You have disabled Crypto IVs (--no-iv) which may make " PACKAGE_NAME " less secure");
-#ifdef ENABLE_SSL
if (o->tls_server)
warn_on_use_of_common_subnets ();
if (o->tls_client
@@ -2556,12 +2694,6 @@ do_option_warnings (struct context *c)
&& !o->remote_cert_eku)
msg (M_WARN, "WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info.");
#endif
-#endif
-
-#ifndef CONNECT_NONBLOCK
- if (o->ce.connect_timeout_defined)
- msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS");
-#endif
/* If a script is used, print appropiate warnings */
if (o->user_script_used)
@@ -2578,7 +2710,7 @@ do_option_warnings (struct context *c)
static void
do_init_frame_tls (struct context *c)
{
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
do_init_finalize_tls_frame (c);
#endif
}
@@ -2600,9 +2732,9 @@ init_context_buffers (const struct frame *frame)
b->decrypt_buf = alloc_buf (BUF_SIZE (frame));
#endif
-#ifdef ENABLE_LZO
- b->lzo_compress_buf = alloc_buf (BUF_SIZE (frame));
- b->lzo_decompress_buf = alloc_buf (BUF_SIZE (frame));
+#ifdef USE_COMP
+ b->compress_buf = alloc_buf (BUF_SIZE (frame));
+ b->decompress_buf = alloc_buf (BUF_SIZE (frame));
#endif
return b;
@@ -2617,9 +2749,9 @@ free_context_buffers (struct context_buffers *b)
free_buf (&b->read_tun_buf);
free_buf (&b->aux_buf);
-#ifdef ENABLE_LZO
- free_buf (&b->lzo_compress_buf);
- free_buf (&b->lzo_decompress_buf);
+#ifdef USE_COMP
+ free_buf (&b->compress_buf);
+ free_buf (&b->decompress_buf);
#endif
#ifdef ENABLE_CRYPTO
@@ -2658,19 +2790,6 @@ do_init_fragment (struct context *c)
#endif
/*
- * Set the --mssfix option.
- */
-static void
-do_init_mssfix (struct context *c)
-{
- if (c->options.ce.mssfix)
- {
- frame_set_mtu_dynamic (&c->c2.frame,
- c->options.ce.mssfix, SET_MTU_UPPER_BOUND);
- }
-}
-
-/*
* Allocate our socket object.
*/
static void
@@ -2695,20 +2814,18 @@ do_init_socket_1 (struct context *c, const int mode)
#endif
link_socket_init_phase1 (c->c2.link_socket,
- connection_list_defined (&c->options),
c->options.ce.local,
c->options.ce.local_port,
c->options.ce.remote,
c->options.ce.remote_port,
+ c->c1.dns_cache,
c->options.ce.proto,
+ c->options.ce.af,
+ c->options.ce.bind_ipv6_only,
mode,
c->c2.accept_from,
-#ifdef ENABLE_HTTP_PROXY
c->c1.http_proxy,
-#endif
-#ifdef ENABLE_SOCKS
c->c1.socks_proxy,
-#endif
#ifdef ENABLE_DEBUG
c->options.gremlin,
#endif
@@ -2719,13 +2836,11 @@ do_init_socket_1 (struct context *c, const int mode)
c->options.ipchange,
c->plugins,
c->options.resolve_retry_seconds,
- c->options.ce.connect_retry_seconds,
- c->options.ce.connect_timeout,
- c->options.ce.connect_retry_max,
c->options.ce.mtu_discover_type,
c->options.rcvbuf,
c->options.sndbuf,
c->options.mark,
+ &c->c2.server_poll_interval,
sockflags);
}
@@ -2736,7 +2851,7 @@ static void
do_init_socket_2 (struct context *c)
{
link_socket_init_phase2 (c->c2.link_socket, &c->c2.frame,
- &c->sig->signal_received);
+ c->sig);
}
/*
@@ -2767,22 +2882,14 @@ do_compute_occ_strings (struct context *c)
c->c2.options_string_remote =
options_string (&c->options, &c->c2.frame, c->c1.tuntap, true, &gc);
- msg (D_SHOW_OCC, "Local Options String: '%s'", c->c2.options_string_local);
- msg (D_SHOW_OCC, "Expected Remote Options String: '%s'",
- c->c2.options_string_remote);
+ msg (D_SHOW_OCC, "Local Options String (VER=%s): '%s'",
+ options_string_version (c->c2.options_string_local, &gc),
+ c->c2.options_string_local);
+ msg (D_SHOW_OCC, "Expected Remote Options String (VER=%s): '%s'",
+ options_string_version (c->c2.options_string_remote, &gc),
+ c->c2.options_string_remote);
#ifdef ENABLE_CRYPTO
- msg (D_SHOW_OCC_HASH, "Local Options hash (VER=%s): '%s'",
- options_string_version (c->c2.options_string_local, &gc),
- md5sum ((uint8_t*)c->c2.options_string_local,
- strlen (c->c2.options_string_local), 9, &gc));
- msg (D_SHOW_OCC_HASH, "Expected Remote Options hash (VER=%s): '%s'",
- options_string_version (c->c2.options_string_remote, &gc),
- md5sum ((uint8_t*)c->c2.options_string_remote,
- strlen (c->c2.options_string_remote), 9, &gc));
-#endif
-
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
if (c->c2.tls_multi)
tls_multi_init_set_options (c->c2.tls_multi,
c->c2.options_string_local,
@@ -2859,7 +2966,7 @@ do_close_free_buf (struct context *c)
static void
do_close_tls (struct context *c)
{
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
if (c->c2.tls_multi)
{
tls_multi_free (c->c2.tls_multi, true);
@@ -2899,14 +3006,31 @@ do_close_link_socket (struct context *c)
c->c2.link_socket = NULL;
}
- if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip))
- {
- CLEAR (c->c1.link_socket_addr.remote);
+
+ /* Preserve the resolved list of remote if the user request to or if we want
+ * reconnect to the same host again or there are still addresses that need
+ * to be tried */
+ if (!(c->sig->signal_received == SIGUSR1 &&
+ ( (c->options.persist_remote_ip)
+ ||
+ ( c->sig->source != SIG_SOURCE_HARD &&
+ ((c->c1.link_socket_addr.current_remote && c->c1.link_socket_addr.current_remote->ai_next)
+ || c->options.no_advance))
+ )))
+ {
+ clear_remote_addrlist(&c->c1.link_socket_addr, !c->options.resolve_in_advance);
+ }
+
+ /* Clear the remote actual address when persist_remote_ip is not in use */
+ if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip))
CLEAR (c->c1.link_socket_addr.actual);
- }
- if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip))
- CLEAR (c->c1.link_socket_addr.local);
+ if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) {
+ if (c->c1.link_socket_addr.bind_local && !c->options.resolve_in_advance)
+ freeaddrinfo(c->c1.link_socket_addr.bind_local);
+
+ c->c1.link_socket_addr.bind_local=NULL;
+ }
}
/*
@@ -2916,7 +3040,7 @@ static void
do_close_packet_id (struct context *c)
{
#ifdef ENABLE_CRYPTO
- packet_id_free (&c->c2.packet_id);
+ packet_id_free (&c->c2.crypto_options.packet_id);
packet_id_persist_save (&c->c1.pid_persist);
if (!(c->sig->signal_received == SIGUSR1))
packet_id_persist_close (&c->c1.pid_persist);
@@ -3070,7 +3194,7 @@ do_setup_fast_io (struct context *c)
{
if (c->options.fast_io)
{
-#ifdef WIN32
+#ifdef _WIN32
msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows");
#else
if (!proto_is_udp(c->options.ce.proto))
@@ -3093,7 +3217,7 @@ do_setup_fast_io (struct context *c)
static void
do_signal_on_tls_errors (struct context *c)
{
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
if (c->options.tls_exit)
c->c2.tls_exit_signal = SIGTERM;
else
@@ -3183,7 +3307,7 @@ management_callback_status_p2p (void *arg, const int version, struct status_outp
void
management_show_net_callback (void *arg, const int msglevel)
{
-#ifdef WIN32
+#ifdef _WIN32
show_routes (msglevel);
show_adapters (msglevel);
msg (msglevel, "END");
@@ -3192,6 +3316,37 @@ management_show_net_callback (void *arg, const int msglevel)
#endif
}
+#ifdef TARGET_ANDROID
+int
+management_callback_network_change (void *arg, bool samenetwork)
+{
+ /* Check if the client should translate the network change to a SIGUSR1 to
+ reestablish the connection or just reprotect the socket
+
+ At the moment just assume that, for all settings that use pull (not
+ --static) and are not using peer-id reestablishing the connection is
+ required (unless the network is the same)
+
+ The function returns -1 on invalid fd and -2 if the socket cannot be
+ reused. On the -2 return value the man_network_change function triggers
+ a SIGUSR1 to force a reconnect.
+ */
+
+ int socketfd=-1;
+ struct context *c = (struct context *) arg;
+ if (!c->c2.link_socket)
+ return -1;
+ if (c->c2.link_socket->sd == SOCKET_UNDEFINED)
+ return -1;
+
+ socketfd = c->c2.link_socket->sd;
+ if (!c->options.pull || c->c2.tls_multi->use_peer_id || samenetwork)
+ return socketfd;
+ else
+ return -2;
+}
+#endif
+
#endif
void
@@ -3207,6 +3362,9 @@ init_management_callback_p2p (struct context *c)
cb.show_net = management_show_net_callback;
cb.proxy_cmd = management_callback_proxy_cmd;
cb.remote_cmd = management_callback_remote_cmd;
+#ifdef TARGET_ANDROID
+ cb.network_change = management_callback_network_change;
+#endif
management_set_callback (management, &cb);
}
#endif
@@ -3248,12 +3406,14 @@ open_management (struct context *c)
management_set_state (management,
OPENVPN_STATE_CONNECTING,
NULL,
- (in_addr_t)0,
- (in_addr_t)0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
/* initial management hold, called early, before first context initialization */
- do_hold ();
+ do_hold (0);
if (IS_SIG (c))
{
msg (M_WARN, "Signal received from management interface, exiting");
@@ -3326,10 +3486,14 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
/* init garbage collection level */
gc_init (&c->c2.gc);
+ /* inherit environmental variables */
+ if (env)
+ do_inherit_env (c, env);
+
/* signals caught here will abort */
c->sig->signal_received = 0;
c->sig->signal_text = NULL;
- c->sig->hard = false;
+ c->sig->source = SIG_SOURCE_SOFT;
if (c->mode == CM_P2P)
init_management_callback_p2p (c);
@@ -3342,14 +3506,20 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
goto sig;
}
+ if (c->options.resolve_in_advance)
+ {
+ do_preresolve (c);
+ if (IS_SIG (c))
+ goto sig;
+ }
+
/* map in current connection entry */
next_connection_entry (c);
/* link_socket_mode allows CM_CHILD_TCP
instances to inherit acceptable fds
from a top-level parent */
- if (c->options.ce.proto == PROTO_TCPv4_SERVER
- || c->options.ce.proto == PROTO_TCPv6_SERVER)
+ if (c->options.ce.proto == PROTO_TCP_SERVER)
{
if (c->mode == CM_TOP)
link_socket_mode = LS_MODE_TCP_LISTEN;
@@ -3378,10 +3548,6 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
if (c->mode == CM_P2P || c->mode == CM_TOP)
do_option_warnings (c);
- /* inherit environmental variables */
- if (env)
- do_inherit_env (c, env);
-
#ifdef ENABLE_PLUGIN
/* initialize plugins */
if (c->mode == CM_P2P || c->mode == CM_TOP)
@@ -3416,7 +3582,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
do_event_set_init (c, false);
/* initialize HTTP or SOCKS proxy object at scope level 2 */
- init_proxy (c, 2);
+ init_proxy (c);
/* allocate our socket object */
if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP)
@@ -3442,10 +3608,10 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
goto sig;
}
-#ifdef ENABLE_LZO
- /* initialize LZO compression library. */
- if ((options->lzo & LZO_SELECTED) && (c->mode == CM_P2P || child))
- lzo_compress_init (&c->c2.lzo_compwork, options->lzo);
+#ifdef USE_COMP
+ /* initialize compression library. */
+ if (comp_enabled(&options->comp) && (c->mode == CM_P2P || child))
+ c->c2.comp_context = comp_init (&options->comp);
#endif
/* initialize MTU variables */
@@ -3465,7 +3631,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
#endif
/* initialize dynamic MTU variable */
- do_init_mssfix (c);
+ frame_init_mssfix (&c->c2.frame, &c->options);
/* bind the TCP/UDP socket */
if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP)
@@ -3498,16 +3664,19 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
open_plugins (c, false, OPENVPN_PLUGIN_INIT_POST_DAEMON);
#endif
+ /* initialise connect timeout timer */
+ do_init_server_poll_timeout(c);
+
+ /* finalize the TCP/UDP socket */
+ if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP)
+ do_init_socket_2 (c);
+
/*
* Actually do UID/GID downgrade, and chroot, if requested.
* May be delayed by --client, --pull, or --up-delay.
*/
do_uid_gid_chroot (c, c->c2.did_open_tun);
- /* finalize the TCP/UDP socket */
- if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP)
- do_init_socket_2 (c);
-
/* initialize timers */
if (c->mode == CM_P2P || child)
do_init_timers (c, false);
@@ -3559,9 +3728,12 @@ close_instance (struct context *c)
/* if xinetd/inetd mode, don't allow restart */
do_close_check_if_restart_permitted (c);
-#ifdef ENABLE_LZO
- if (lzo_defined (&c->c2.lzo_compwork))
- lzo_compress_uninit (&c->c2.lzo_compwork);
+#ifdef USE_COMP
+ if (c->c2.comp_context)
+ {
+ comp_uninit (c->c2.comp_context);
+ c->c2.comp_context = NULL;
+ }
#endif
/* free buffers */
@@ -3636,11 +3808,14 @@ inherit_context_child (struct context *dest,
#ifdef ENABLE_CRYPTO
dest->c1.ks.key_type = src->c1.ks.key_type;
-#ifdef ENABLE_SSL
/* inherit SSL context */
dest->c1.ks.ssl_ctx = src->c1.ks.ssl_ctx;
- dest->c1.ks.tls_auth_key = src->c1.ks.tls_auth_key;
-#endif
+ dest->c1.ks.tls_wrap_key = src->c1.ks.tls_wrap_key;
+ dest->c1.ks.tls_auth_key_type = src->c1.ks.tls_auth_key_type;
+ /* inherit pre-NCP ciphers */
+ dest->c1.ciphername = src->c1.ciphername;
+ dest->c1.authname = src->c1.authname;
+ dest->c1.keysize = src->c1.keysize;
#endif
/* options */
@@ -3713,7 +3888,7 @@ inherit_context_top (struct context *dest,
/* detach plugins */
dest->plugins_owned = false;
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
dest->c2.tls_multi = NULL;
#endif
@@ -3733,6 +3908,10 @@ inherit_context_top (struct context *dest,
dest->c2.event_set = NULL;
if (proto_is_dgram(src->options.ce.proto))
do_event_set_init (dest, false);
+
+#ifdef USE_COMP
+ dest->c2.comp_context = NULL;
+#endif
}
void
@@ -3747,8 +3926,11 @@ close_context (struct context *c, int sig, unsigned int flags)
if (c->sig->signal_received == SIGUSR1)
{
if ((flags & CC_USR1_TO_HUP)
- || (c->sig->hard && (flags & CC_HARD_USR1_TO_HUP)))
- c->sig->signal_received = SIGHUP;
+ || (c->sig->source == SIG_SOURCE_HARD && (flags & CC_HARD_USR1_TO_HUP)))
+ {
+ c->sig->signal_received = SIGHUP;
+ c->sig->signal_text = "close_context usr1 to hup";
+ }
}
if (!(flags & CC_NO_CLOSE))
@@ -3773,6 +3955,7 @@ test_crypto_thread (void *arg)
ASSERT (options->test_crypto);
init_verb_mute (c, IVM_LEVEL_1);
context_init_1 (c);
+ next_connection_entry(c);
do_init_crypto_static (c, 0);
frame_finalize_options (c, options);
@@ -3780,13 +3963,13 @@ test_crypto_thread (void *arg)
test_crypto (&c->c2.crypto_options, &c->c2.frame);
key_schedule_free (&c->c1.ks, true);
- packet_id_free (&c->c2.packet_id);
+ packet_id_free (&c->c2.crypto_options.packet_id);
context_gc_free (c);
return NULL;
}
-#endif
+#endif /* ENABLE_CRYPTO */
bool
do_test_crypto (const struct options *o)
diff --git a/src/openvpn/init.h b/src/openvpn/init.h
index a819bd2..524bc64 100644
--- a/src/openvpn/init.h
+++ b/src/openvpn/init.h
@@ -81,7 +81,7 @@ bool do_test_crypto (const struct options *o);
void context_gc_free (struct context *c);
-void do_up (struct context *c,
+bool do_up (struct context *c,
bool pulled_options,
unsigned int option_types_found);
@@ -91,7 +91,7 @@ const char *format_common_name (struct context *c, struct gc_arena *gc);
void reset_coarse_timers (struct context *c);
-void do_deferred_options (struct context *c, const unsigned int found);
+bool do_deferred_options (struct context *c, const unsigned int found);
void inherit_context_child (struct context *dest,
const struct context *src);
diff --git a/src/openvpn/interval.h b/src/openvpn/interval.h
index 4814ec9..59eb1f6 100644
--- a/src/openvpn/interval.h
+++ b/src/openvpn/interval.h
@@ -186,6 +186,15 @@ event_timeout_modify_wakeup (struct event_timeout* et, interval_t n)
}
/*
+ * Will return the time left for a timeout, this function does not check
+ * if the timeout is actually valid
+ */
+static inline interval_t event_timeout_remaining (struct event_timeout* et)
+{
+ return (int) et->last + et->n - now;
+}
+
+/*
* This is the principal function for testing and triggering recurring
* timers and will return true on a timer signal event.
* If et_const_retry == ETT_DEFAULT and a signal occurs,
diff --git a/src/openvpn/lzo.c b/src/openvpn/lzo.c
index 195b819..25a839b 100644
--- a/src/openvpn/lzo.c
+++ b/src/openvpn/lzo.c
@@ -34,15 +34,14 @@
#include "syshead.h"
-#ifdef ENABLE_LZO
+#if defined(ENABLE_LZO)
-#include "lzo.h"
+#include "comp.h"
#include "error.h"
#include "otime.h"
#include "memdbg.h"
-#ifndef ENABLE_LZO_STUB
/**
* Perform adaptive compression housekeeping.
*
@@ -97,101 +96,69 @@ lzo_adaptive_compress_data (struct lzo_adaptive_compress *ac, int n_total, int n
ac->n_comp += n_comp;
}
-#endif /* ENABLE_LZO_STUB */
-
-void lzo_adjust_frame_parameters (struct frame *frame)
-{
- /* Leave room for our one-byte compressed/didn't-compress prefix byte. */
- frame_add_to_extra_frame (frame, LZO_PREFIX_LEN);
-
- /* Leave room for compression buffer to expand in worst case scenario
- where data is totally uncompressible */
- frame_add_to_extra_buffer (frame, LZO_EXTRA_BUFFER (EXPANDED_SIZE(frame)));
-}
-
-void
-lzo_compress_init (struct lzo_compress_workspace *lzowork, unsigned int flags)
+static void
+lzo_compress_init (struct compress_context *compctx)
{
- CLEAR (*lzowork);
-
- lzowork->flags = flags;
-#ifndef ENABLE_LZO_STUB
- lzowork->wmem_size = LZO_WORKSPACE;
-
+ msg (D_INIT_MEDIUM, "LZO compression initializing");
+ ASSERT(!(compctx->flags & COMP_F_SWAP));
+ compctx->wu.lzo.wmem_size = LZO_WORKSPACE;
if (lzo_init () != LZO_E_OK)
msg (M_FATAL, "Cannot initialize LZO compression library");
- lzowork->wmem = (lzo_voidp) lzo_malloc (lzowork->wmem_size);
- check_malloc_return (lzowork->wmem);
- msg (D_INIT_MEDIUM, "LZO compression initialized");
-#else
- msg (D_INIT_MEDIUM, "LZO stub compression initialized");
-#endif
- lzowork->defined = true;
+ compctx->wu.lzo.wmem = (lzo_voidp) lzo_malloc (compctx->wu.lzo.wmem_size);
+ check_malloc_return (compctx->wu.lzo.wmem);
}
-void
-lzo_compress_uninit (struct lzo_compress_workspace *lzowork)
+static void
+lzo_compress_uninit (struct compress_context *compctx)
{
- if (lzowork)
- {
- ASSERT (lzowork->defined);
-#ifndef ENABLE_LZO_STUB
- lzo_free (lzowork->wmem);
- lzowork->wmem = NULL;
-#endif
- lzowork->defined = false;
- }
+ lzo_free (compctx->wu.lzo.wmem);
+ compctx->wu.lzo.wmem = NULL;
}
static inline bool
-lzo_compression_enabled (struct lzo_compress_workspace *lzowork)
+lzo_compression_enabled (struct compress_context *compctx)
{
-#ifndef ENABLE_LZO_STUB
- if ((lzowork->flags & (LZO_SELECTED|LZO_ON)) == (LZO_SELECTED|LZO_ON))
+ if (compctx->flags & COMP_F_ASYM)
+ return false;
+ else
{
- if (lzowork->flags & LZO_ADAPTIVE)
- return lzo_adaptive_compress_test (&lzowork->ac);
+ if (compctx->flags & COMP_F_ADAPTIVE)
+ return lzo_adaptive_compress_test (&compctx->wu.lzo.ac);
else
return true;
}
-#endif
- return false;
}
-void
+static void
lzo_compress (struct buffer *buf, struct buffer work,
- struct lzo_compress_workspace *lzowork,
+ struct compress_context *compctx,
const struct frame* frame)
{
-#ifndef ENABLE_LZO_STUB
lzo_uint zlen = 0;
int err;
bool compressed = false;
-#endif
-
- ASSERT (lzowork->defined);
if (buf->len <= 0)
return;
-#ifndef ENABLE_LZO_STUB
/*
* In order to attempt compression, length must be at least COMPRESS_THRESHOLD,
* and our adaptive level must give the OK.
*/
- if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled (lzowork))
+ if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled (compctx))
{
+ const size_t ps = PAYLOAD_SIZE (frame);
ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
- ASSERT (buf_safe (&work, LZO_EXTRA_BUFFER (PAYLOAD_SIZE (frame))));
+ ASSERT (buf_safe (&work, ps + COMP_EXTRA_BUFFER (ps)));
- if (!(buf->len <= PAYLOAD_SIZE (frame)))
+ if (buf->len > ps)
{
dmsg (D_COMP_ERRORS, "LZO compression buffer overflow");
buf->len = 0;
return;
}
- err = LZO_COMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, lzowork->wmem);
+ err = LZO_COMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, compctx->wu.lzo.wmem);
if (err != LZO_E_OK)
{
dmsg (D_COMP_ERRORS, "LZO compression error: %d", err);
@@ -203,43 +170,38 @@ lzo_compress (struct buffer *buf, struct buffer work,
work.len = zlen;
compressed = true;
- dmsg (D_COMP, "compress %d -> %d", buf->len, work.len);
- lzowork->pre_compress += buf->len;
- lzowork->post_compress += work.len;
+ dmsg (D_COMP, "LZO compress %d -> %d", buf->len, work.len);
+ compctx->pre_compress += buf->len;
+ compctx->post_compress += work.len;
/* tell adaptive level about our success or lack thereof in getting any size reduction */
- if (lzowork->flags & LZO_ADAPTIVE)
- lzo_adaptive_compress_data (&lzowork->ac, buf->len, work.len);
+ if (compctx->flags & COMP_F_ADAPTIVE)
+ lzo_adaptive_compress_data (&compctx->wu.lzo.ac, buf->len, work.len);
}
/* did compression save us anything ? */
if (compressed && work.len < buf->len)
{
uint8_t *header = buf_prepend (&work, 1);
- *header = YES_COMPRESS;
+ *header = LZO_COMPRESS_BYTE;
*buf = work;
}
else
-#endif
{
uint8_t *header = buf_prepend (buf, 1);
- *header = NO_COMPRESS;
+ *header = NO_COMPRESS_BYTE;
}
}
-void
+static void
lzo_decompress (struct buffer *buf, struct buffer work,
- struct lzo_compress_workspace *lzowork,
+ struct compress_context *compctx,
const struct frame* frame)
{
-#ifndef ENABLE_LZO_STUB
lzo_uint zlen = EXPANDED_SIZE (frame);
int err;
-#endif
uint8_t c; /* flag indicating whether or not our peer compressed */
- ASSERT (lzowork->defined);
-
if (buf->len <= 0)
return;
@@ -248,12 +210,11 @@ lzo_decompress (struct buffer *buf, struct buffer work,
c = *BPTR (buf);
ASSERT (buf_advance (buf, 1));
- if (c == YES_COMPRESS) /* packet was compressed */
+ if (c == LZO_COMPRESS_BYTE) /* packet was compressed */
{
-#ifndef ENABLE_LZO_STUB
ASSERT (buf_safe (&work, zlen));
err = LZO_DECOMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen,
- lzowork->wmem);
+ compctx->wu.lzo.wmem);
if (err != LZO_E_OK)
{
dmsg (D_COMP_ERRORS, "LZO decompression error: %d", err);
@@ -264,18 +225,13 @@ lzo_decompress (struct buffer *buf, struct buffer work,
ASSERT (buf_safe (&work, zlen));
work.len = zlen;
- dmsg (D_COMP, "decompress %d -> %d", buf->len, work.len);
- lzowork->pre_decompress += buf->len;
- lzowork->post_decompress += work.len;
+ dmsg (D_COMP, "LZO decompress %d -> %d", buf->len, work.len);
+ compctx->pre_decompress += buf->len;
+ compctx->post_decompress += work.len;
*buf = work;
-#else
- dmsg (D_COMP_ERRORS, "LZO decompression error: LZO capability not compiled");
- buf->len = 0;
- return;
-#endif
}
- else if (c == NO_COMPRESS) /* packet was not compressed */
+ else if (c == NO_COMPRESS_BYTE) /* packet was not compressed */
{
;
}
@@ -286,24 +242,13 @@ lzo_decompress (struct buffer *buf, struct buffer work,
}
}
-void
-lzo_modify_flags (struct lzo_compress_workspace *lzowork, unsigned int flags)
-{
- ASSERT (lzowork->defined);
- lzowork->flags = flags;
-}
-
-void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct status_output *so)
-{
- ASSERT (lzo_compwork->defined);
-
-#ifndef ENABLE_LZO_STUB
- status_printf (so, "pre-compress bytes," counter_format, lzo_compwork->pre_compress);
- status_printf (so, "post-compress bytes," counter_format, lzo_compwork->post_compress);
- status_printf (so, "pre-decompress bytes," counter_format, lzo_compwork->pre_decompress);
- status_printf (so, "post-decompress bytes," counter_format, lzo_compwork->post_decompress);
-#endif
-}
+const struct compress_alg lzo_alg = {
+ "lzo",
+ lzo_compress_init,
+ lzo_compress_uninit,
+ lzo_compress,
+ lzo_decompress
+};
#else
static void dummy(void) {}
diff --git a/src/openvpn/lzo.h b/src/openvpn/lzo.h
index 472204d..f33e587 100644
--- a/src/openvpn/lzo.h
+++ b/src/openvpn/lzo.h
@@ -32,14 +32,13 @@
*/
-#ifdef ENABLE_LZO
+#if defined(ENABLE_LZO)
/**
* @addtogroup compression
* @{
*/
-#ifndef ENABLE_LZO_STUB
#if defined(HAVE_LZO_LZOUTIL_H)
#include "lzo/lzoutil.h"
#elif defined(HAVE_LZOUTIL_H)
@@ -50,28 +49,16 @@
#elif defined(HAVE_LZO1X_H)
#include "lzo1x.h"
#endif
-#endif
#include "buffer.h"
#include "mtu.h"
#include "common.h"
#include "status.h"
-/**************************************************************************/
-/** @name Bit-flags which control data channel packet compression *//******/
-/** @{ */
-#define LZO_SELECTED (1<<0) /**< Bit-flag indicating that compression
- * of data channel packets is enabled. */
-#define LZO_ON (1<<1) /**< Bit-flag indicating that compression
- * of data channel packets is active. */
-#define LZO_ADAPTIVE (1<<2) /**< Bit-flag indicating that adaptive
- * compression of data channel packets
- * has been selected. */
-/** @} name Bit-flags which control data channel packet compression *//****/
+extern const struct compress_alg lzo_alg;
/**************************************************************************/
/** @name LZO library interface defines *//** @{ *//***********************/
-#ifndef ENABLE_LZO_STUB
#define LZO_COMPRESS lzo1x_1_15_compress
/**< LZO library compression function.
*
@@ -93,36 +80,11 @@
* verify the integrity of incoming
* packets, you might want to consider
* using the non-safe version. */
-#endif /* ENABLE_LZO_STUB */
/** @} name LZO library interface *//**************************************/
/**************************************************************************/
-/** @name Miscellaneous compression defines *//** @{ *//*******************/
-#define LZO_EXTRA_BUFFER(len) ((len)/8 + 128 + 3)
- /**< LZO 2.0 worst-case size expansion. */
-#ifndef ENABLE_LZO_STUB
-#define COMPRESS_THRESHOLD 100 /**< Minimum packet size to attempt
- * compression. */
-#endif /* ENABLE_LZO_STUB */
-/** @} name Miscellaneous compression defines *//**************************/
-
-
-/**************************************************************************/
-/** @name Compression header defines *//** @{ *//**************************/
-#define LZO_PREFIX_LEN 1 /**< Length in bytes of prepended
- * compression header. */
-#define YES_COMPRESS 0x66 /**< Single-byte compression header
- * indicating this packet has been
- * compressed. */
-#define NO_COMPRESS 0xFA /**< Single-byte compression header
- * indicating this packet has not been
- * compressed. */
-/** @} name Compression header defines *//*********************************/
-
-/**************************************************************************/
/** @name Adaptive compression defines *//** @{ *//************************/
-#ifndef ENABLE_LZO_STUB
#define AC_SAMP_SEC 2 /**< Number of seconds in a sample period. */
#define AC_MIN_BYTES 1000 /**< Minimum number of bytes a sample
* period must contain for it to be
@@ -132,11 +94,8 @@
* turned off. */
#define AC_OFF_SEC 60 /**< Seconds to wait after compression has
* been turned off before retesting. */
-#endif /* ENABLE_LZO_STUB */
/** @} name Adaptive compression defines *//*******************************/
-#ifndef ENABLE_LZO_STUB
-
/**
* Adaptive compression state.
*/
@@ -147,8 +106,6 @@ struct lzo_adaptive_compress {
int n_comp;
};
-#endif /* ENABLE_LZO_STUB */
-
/**
* State for the compression and decompression routines.
@@ -162,186 +119,13 @@ struct lzo_adaptive_compress {
*/
struct lzo_compress_workspace
{
- bool defined;
- unsigned int flags;
-#ifndef ENABLE_LZO_STUB
lzo_voidp wmem;
int wmem_size;
struct lzo_adaptive_compress ac;
-
- /* statistics */
- counter_type pre_decompress;
- counter_type post_decompress;
- counter_type pre_compress;
- counter_type post_compress;
-#endif
};
-
-/**************************************************************************/
-/** @name Functions for initialization and cleanup *//** @{ *//************/
-
-/**
- * Adjust %frame parameters for data channel payload compression.
- *
- * Data channel packet compression requires a single-byte header to
- * indicate whether a packet has been compressed or not. The packet
- * handling buffers must also allow for worst-case payload compression
- * where the compressed content size is actually larger than the original
- * content size. This function adjusts the parameters of a given frame
- * structure to include the header and allow for worst-case compression
- * expansion.
- *
- * @param frame - The frame structure to adjust.
- */
-void lzo_adjust_frame_parameters(struct frame *frame);
-
-/**
- * Initialize a compression workspace structure.
- *
- * This function initializes the given workspace structure \a lzowork.
- * This includes allocating a work buffer for internal use and setting its
- * flags to the given value of \a flags.
- *
- * This function also initializes the lzo library.
- *
- * @param lzowork - A pointer to the workspace structure to
- * initialize.
- * @param flags - The initial flags to set in the workspace
- * structure.
- */
-void lzo_compress_init (struct lzo_compress_workspace *lzowork, unsigned int flags);
-
-/**
- * Cleanup a compression workspace structure.
- *
- * This function cleans up the given workspace structure \a lzowork. This
- * includes freeing the structure's internal work buffer.
- *
- * @param lzowork - A pointer to the workspace structure to clean up.
- */
-void lzo_compress_uninit (struct lzo_compress_workspace *lzowork);
-
-/**
- * Set a workspace structure's flags.
- *
- * @param lzowork - The workspace structure of which to modify the
- * flags.
- * @param flags - The new value to assign to the workspace
- * structure's flags.
- */
-void lzo_modify_flags (struct lzo_compress_workspace *lzowork, unsigned int flags);
-
-/** @} name Functions for initialization and cleanup *//*******************/
-
-
-/**************************************************************************/
-/** @name Function for packets to be sent to a remote OpenVPN peer *//*****/
-/** @{ */
-
-/**
- * Process an outgoing packet according to a VPN tunnel's settings.
- * @ingroup compression
- *
- * This function processes the packet contained in \a buf. Its behavior
- * depends on the settings contained within \a lzowork. If compression is
- * enabled and active, this function compresses the packet. After
- * compression, the size of the uncompressed and compressed packets are
- * compared, and the smallest is used.
- *
- * This function prepends a one-byte header indicating whether the packet
- * was or was not compressed, so as to let the peer know how to handle the
- * packet.
- *
- * If an error occurs during processing, an error message is logged and
- * the length of \a buf is set to zero.
- *
- * @param buf - A pointer to the buffer containing the outgoing
- * packet. This pointer will be modified to point
- * to the processed packet on return.
- * @param work - A preallocated working buffer.
- * @param lzowork - The compression workspace structure associated
- * with this VPN tunnel.
- * @param frame - The frame parameters of this tunnel.
- *
- * @return Void.\n On return, \a buf will point to a buffer containing
- * the processed, possibly compressed, packet data with a compression
- * header prepended.
- */
-void lzo_compress (struct buffer *buf, struct buffer work,
- struct lzo_compress_workspace *lzowork,
- const struct frame* frame);
-
-/** @} name Function for packets to be sent to a remote OpenVPN peer *//***/
-
-
-/**************************************************************************/
-/** @name Function for packets received from a remote OpenVPN peer *//*****/
-/** @{ */
-
-/**
- * Inspect an incoming packet and decompress if it is compressed.
- *
- * This function inspects the incoming packet contained in \a buf. If its
- * one-byte compression header indicates that it was compressed (i.e. \c
- * YES_COMPRESS), then it will be decompressed. If its header indicates
- * that it was not compressed (i.e. \c NO_COMPRESS), then the buffer is
- * not modified except for removing the compression header.
- *
- * If an error occurs during processing, for example if the compression
- * header has a value other than \c YES_COMPRESS or \c NO_COMPRESS, then
- * the error is logged and the length of \a buf is set to zero.
- *
- * @param buf - A pointer to the buffer containing the incoming
- * packet. This pointer will be modified to point
- * to the processed packet on return.
- * @param work - A preallocated working buffer.
- * @param lzowork - The compression workspace structure associated
- * with this VPN tunnel.
- * @param frame - The frame parameters of this tunnel.
- *
- * @return Void.\n On return, \a buf will point to a buffer containing
- * the uncompressed packet data and the one-byte compression header
- * will have been removed.
- */
-void lzo_decompress (struct buffer *buf, struct buffer work,
- struct lzo_compress_workspace *lzowork,
- const struct frame* frame);
-
-/** @} name Function for packets received from a remote OpenVPN peer *//***/
-
-
-/**************************************************************************/
-/** @name Utility functions *//** @{ *//***********************************/
-
-/**
- * Print statistics on compression and decompression performance.
- *
- * @param lzo_compwork - The workspace structure from which to get the
- * statistics.
- * @param so - The status output structure to which to write the
- * statistics.
- */
-void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct status_output *so);
-
-/**
- * Check whether compression is enabled for a workspace structure.
- *
- * @param lzowork - The workspace structure to check.
- *
- * @return true if compression is enabled; false otherwise.
- */
-static inline bool
-lzo_defined (const struct lzo_compress_workspace *lzowork)
-{
- return lzowork->defined;
-}
-
-/** @} name Utility functions *//******************************************/
-
-
/** @} addtogroup compression */
-#endif /* ENABLE_LZO */
+#endif /* ENABLE_LZO && USE_COMP */
#endif
diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c
index 0a4542a..77a8006 100644
--- a/src/openvpn/manage.c
+++ b/src/openvpn/manage.c
@@ -113,6 +113,8 @@ man_help ()
#ifdef MANAGMENT_EXTERNAL_KEY
msg (M_CLIENT, "rsa-sig : Enter an RSA signature in response to >RSA_SIGN challenge");
msg (M_CLIENT, " Enter signature base64 on subsequent lines followed by END");
+ msg (M_CLIENT, "certificate : Enter a client certificate in response to >NEED-CERT challenge");
+ msg (M_CLIENT, " Enter certificate base64 on subsequent lines followed by END");
#endif
msg (M_CLIENT, "signal s : Send signal s to daemon,");
msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2.");
@@ -268,7 +270,7 @@ man_delete_unix_socket (struct management *man)
static void
man_close_socket (struct management *man, const socket_descriptor_t sd)
{
-#ifndef WIN32
+#ifndef _WIN32
/*
* Windows doesn't need this because the ne32 event is permanently
* enabled at struct management scope.
@@ -701,7 +703,7 @@ man_query_need_str (struct management *man, const char *type, const char *action
static void
man_forget_passwords (struct management *man)
{
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
ssl_purge_auth (false);
msg (M_CLIENT, "SUCCESS: Passwords were forgotten");
#endif
@@ -868,6 +870,12 @@ in_extra_dispatch (struct management *man)
man->connection.ext_key_input = man->connection.in_extra;
man->connection.in_extra = NULL;
return;
+ case IEC_CERTIFICATE:
+ man->connection.ext_cert_state = EKS_READY;
+ buffer_list_free (man->connection.ext_cert_input);
+ man->connection.ext_cert_input = man->connection.in_extra;
+ man->connection.in_extra = NULL;
+ return;
#endif
}
in_extra_reset (&man->connection, IER_RESET);
@@ -1030,6 +1038,20 @@ man_rsa_sig (struct management *man)
msg (M_CLIENT, "ERROR: The rsa-sig command is not currently available");
}
+static void
+man_certificate (struct management *man)
+{
+ struct man_connection *mc = &man->connection;
+ if (mc->ext_cert_state == EKS_SOLICIT)
+ {
+ mc->ext_cert_state = EKS_INPUT;
+ mc->in_extra_cmd = IEC_CERTIFICATE;
+ in_extra_reset (mc, IER_NEW);
+ }
+ else
+ msg (M_CLIENT, "ERROR: The certificate command is not currently available");
+}
+
#endif
static void
@@ -1105,6 +1127,27 @@ man_remote (struct management *man, const char **p)
}
}
+#ifdef TARGET_ANDROID
+static void
+man_network_change (struct management *man, bool samenetwork)
+{
+ /* Called to signal the OpenVPN that the network configuration has changed and
+ the client should either float or reconnect.
+
+ The code is currently only used by ics-openvpn
+ */
+ if (man->persist.callback.network_change)
+ {
+ int fd = (*man->persist.callback.network_change)
+ (man->persist.callback.arg, samenetwork);
+ man->connection.fdtosend = fd;
+ msg (M_CLIENT, "PROTECTFD: fd '%d' sent to be protected", fd);
+ if (fd == -2)
+ man_signal (man, "SIGUSR1");
+ }
+}
+#endif
+
static void
man_dispatch_command (struct management *man, struct status_output *so, const char **p, const int nparms)
{
@@ -1148,6 +1191,16 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
if (man_need (man, p, 1, 0))
man_signal (man, p[1]);
}
+#ifdef TARGET_ANDROID
+ else if (streq (p[0], "network-change"))
+ {
+ bool samenetwork = false;
+ if (p[1] && streq(p[1], "samenetwork"))
+ samenetwork = true;
+
+ man_network_change(man, samenetwork);
+ }
+#endif
else if (streq (p[0], "load-stats"))
{
man_load_stats (man);
@@ -1311,6 +1364,10 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
{
man_rsa_sig (man);
}
+ else if (streq (p[0], "certificate"))
+ {
+ man_certificate (man);
+ }
#endif
#ifdef ENABLE_PKCS11
else if (streq (p[0], "pkcs11-id-count"))
@@ -1356,7 +1413,7 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
gc_free (&gc);
}
-#ifdef WIN32
+#ifdef _WIN32
static void
man_start_ne32 (struct management *man)
@@ -1446,7 +1503,7 @@ man_new_connection_post (struct management *man, const char *description)
man_connection_settings_reset (man);
-#ifdef WIN32
+#ifdef _WIN32
man_start_ne32 (man);
#endif
@@ -1461,7 +1518,7 @@ man_new_connection_post (struct management *man, const char *description)
#endif
msg (D_MANAGEMENT, "MANAGEMENT: %s %s",
description,
- print_sockaddr (&man->settings.local, &gc));
+ print_sockaddr (man->settings.local->ai_addr, &gc));
buffer_list_reset (man->connection.out);
@@ -1533,7 +1590,7 @@ man_accept (struct management *man)
if (socket_defined (man->connection.sd_top))
{
-#ifdef WIN32
+#ifdef _WIN32
man_stop_ne32 (man);
#endif
}
@@ -1568,8 +1625,9 @@ man_listen (struct management *man)
else
#endif
{
- man->connection.sd_top = create_socket_tcp (AF_INET);
- socket_bind (man->connection.sd_top, &man->settings.local, "MANAGEMENT");
+ man->connection.sd_top = create_socket_tcp (man->settings.local);
+ socket_bind (man->connection.sd_top, man->settings.local,
+ man->settings.local->ai_family, "MANAGEMENT", false);
}
/*
@@ -1593,10 +1651,10 @@ man_listen (struct management *man)
else
#endif
msg (D_MANAGEMENT, "MANAGEMENT: TCP Socket listening on %s",
- print_sockaddr (&man->settings.local, &gc));
+ print_sockaddr (man->settings.local->ai_addr, &gc));
}
-#ifdef WIN32
+#ifdef _WIN32
man_start_ne32 (man);
#endif
@@ -1634,9 +1692,9 @@ man_connect (struct management *man)
else
#endif
{
- man->connection.sd_cli = create_socket_tcp (AF_INET);
+ man->connection.sd_cli = create_socket_tcp (man->settings.local);
status = openvpn_connect (man->connection.sd_cli,
- &man->settings.local,
+ man->settings.local->ai_addr,
5,
&signal_received);
}
@@ -1661,7 +1719,7 @@ man_connect (struct management *man)
#endif
msg (D_LINK_ERRORS,
"MANAGEMENT: connect to %s failed: %s",
- print_sockaddr (&man->settings.local, &gc),
+ print_sockaddr (man->settings.local->ai_addr, &gc),
strerror_ts (status, &gc));
throw_signal_soft (SIGTERM, "management-connect-failed");
goto done;
@@ -1679,7 +1737,7 @@ man_reset_client_socket (struct management *man, const bool exiting)
{
if (socket_defined (man->connection.sd_cli))
{
-#ifdef WIN32
+#ifdef _WIN32
man_stop_ne32 (man);
#endif
man_close_socket (man, man->connection.sd_cli);
@@ -1694,7 +1752,7 @@ man_reset_client_socket (struct management *man, const bool exiting)
}
if (!exiting)
{
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
if (man->settings.flags & MF_FORGET_DISCONNECT)
ssl_purge_auth (false);
#endif
@@ -1779,6 +1837,120 @@ man_io_error (struct management *man, const char *prefix)
return false;
}
+#ifdef TARGET_ANDROID
+static ssize_t man_send_with_fd (int fd, void *ptr, size_t nbytes, int flags, int sendfd)
+{
+ struct msghdr msg;
+ struct iovec iov[1];
+
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof(int))];
+ } control_un;
+ struct cmsghdr *cmptr;
+
+ msg.msg_control = control_un.control;
+ msg.msg_controllen = sizeof(control_un.control);
+
+ cmptr = CMSG_FIRSTHDR(&msg);
+ cmptr->cmsg_len = CMSG_LEN(sizeof(int));
+ cmptr->cmsg_level = SOL_SOCKET;
+ cmptr->cmsg_type = SCM_RIGHTS;
+ *((int *) CMSG_DATA(cmptr)) = sendfd;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ iov[0].iov_base = ptr;
+ iov[0].iov_len = nbytes;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+
+ return (sendmsg(fd, &msg, flags));
+}
+
+static ssize_t man_recv_with_fd (int fd, void *ptr, size_t nbytes, int flags, int *recvfd)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ ssize_t n;
+
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof (int))];
+ } control_un;
+ struct cmsghdr *cmptr;
+
+ msghdr.msg_control = control_un.control;
+ msghdr.msg_controllen = sizeof(control_un.control);
+
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+
+ iov[0].iov_base = ptr;
+ iov[0].iov_len = nbytes;
+ msghdr.msg_iov = iov;
+ msghdr.msg_iovlen = 1;
+
+ if ( (n = recvmsg(fd, &msghdr, flags)) <= 0)
+ return (n);
+
+ if ( (cmptr = CMSG_FIRSTHDR(&msghdr)) != NULL &&
+ cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
+ if (cmptr->cmsg_level != SOL_SOCKET)
+ msg (M_ERR, "control level != SOL_SOCKET");
+ if (cmptr->cmsg_type != SCM_RIGHTS)
+ msg (M_ERR, "control type != SCM_RIGHTS");
+ *recvfd = *((int *) CMSG_DATA(cmptr));
+ } else
+ *recvfd = -1; /* descriptor was not passed */
+
+ return (n);
+}
+
+/*
+ * The android control method will instruct the GUI part of openvpn to do
+ * the route/ifconfig/open tun command. See doc/android.txt for details.
+ */
+bool management_android_control (struct management *man, const char *command, const char *msg)
+{
+ struct user_pass up;
+ CLEAR(up);
+ strncpy (up.username, msg, sizeof(up.username)-1);
+
+ management_query_user_pass(management, &up , command, GET_USER_PASS_NEED_OK,(void*) 0);
+ return strcmp ("ok", up.password)==0;
+}
+
+/*
+ * In Android 4.4 it is not possible to open a new tun device and then close the
+ * old tun device without breaking the whole VPNService stack until the device
+ * is rebooted. This management method ask the UI what method should be taken to
+ * ensure the optimal solution for the situation
+ */
+int managment_android_persisttun_action (struct management *man)
+{
+ struct user_pass up;
+ CLEAR(up);
+ strcpy(up.username,"tunmethod");
+ management_query_user_pass(management, &up , "PERSIST_TUN_ACTION",
+ GET_USER_PASS_NEED_OK,(void*) 0);
+ if (!strcmp("NOACTION", up.password))
+ return ANDROID_KEEP_OLD_TUN;
+ else if (!strcmp ("OPEN_AFTER_CLOSE", up.password))
+ return ANDROID_OPEN_AFTER_CLOSE;
+ else if (!strcmp ("OPEN_BEFORE_CLOSE", up.password))
+ return ANDROID_OPEN_BEFORE_CLOSE;
+ else
+ msg (M_ERR, "Got unrecognised '%s' from management for PERSIST_TUN_ACTION query", up.password);
+
+ ASSERT(0);
+ return ANDROID_OPEN_AFTER_CLOSE;
+}
+
+
+#endif
+
static int
man_read (struct management *man)
{
@@ -1788,7 +1960,15 @@ man_read (struct management *man)
unsigned char buf[256];
int len = 0;
+#ifdef TARGET_ANDROID
+ int fd;
+ len = man_recv_with_fd (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL, &fd);
+ if(fd >= 0)
+ man->connection.lastfdreceived = fd;
+#else
len = recv (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL);
+#endif
+
if (len == 0)
{
man_reset_client_socket (man, false);
@@ -1865,6 +2045,13 @@ man_write (struct management *man)
if (buf && BLEN (buf))
{
const int len = min_int (size_hint, BLEN (buf));
+#ifdef TARGET_ANDROID
+ if (man->connection.fdtosend > 0)
+ {
+ sent = man_send_with_fd (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL,man->connection.fdtosend);
+ man->connection.fdtosend = -1;
+ } else
+#endif
sent = send (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL);
if (sent >= 0)
{
@@ -1957,7 +2144,7 @@ man_persist_close (struct man_persist *mp)
static void
man_settings_init (struct man_settings *ms,
const char *addr,
- const int port,
+ const char *port,
const char *pass_file,
const char *client_user,
const char *client_group,
@@ -2010,12 +2197,6 @@ man_settings_init (struct man_settings *ms,
else
#endif
{
- /*
- * Initialize socket address
- */
- ms->local.addr.in4.sin_family = AF_INET;
- ms->local.addr.in4.sin_addr.s_addr = 0;
- ms->local.addr.in4.sin_port = htons (port);
/*
* Run management over tunnel, or
@@ -2027,8 +2208,15 @@ man_settings_init (struct man_settings *ms,
}
else
{
- ms->local.addr.in4.sin_addr.s_addr = getaddr
- (GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL);
+ int status;
+ int resolve_flags = GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL;
+
+ if (! (flags & MF_CONNECT_AS_CLIENT))
+ resolve_flags |= GETADDR_PASSIVE;
+
+ status = openvpn_getaddrinfo (resolve_flags, addr, port, 0,
+ NULL, AF_UNSPEC, &ms->local);
+ ASSERT(status==0);
}
}
@@ -2054,6 +2242,8 @@ man_settings_init (struct man_settings *ms,
static void
man_settings_close (struct man_settings *ms)
{
+ if (ms->local)
+ freeaddrinfo(ms->local);
free (ms->write_peer_info_file);
CLEAR (*ms);
}
@@ -2064,7 +2254,7 @@ man_connection_init (struct management *man)
{
if (man->connection.state == MS_INITIAL)
{
-#ifdef WIN32
+#ifdef _WIN32
/*
* This object is a sort of TCP/IP helper
* for Windows.
@@ -2105,7 +2295,7 @@ man_connection_close (struct management *man)
if (mc->es)
event_free (mc->es);
-#ifdef WIN32
+#ifdef _WIN32
net_event_win32_close (&mc->ne32);
#endif
if (socket_defined (mc->sd_top))
@@ -2147,7 +2337,7 @@ management_init (void)
bool
management_open (struct management *man,
const char *addr,
- const int port,
+ const char *port,
const char *pass_file,
const char *client_user,
const char *client_group,
@@ -2232,8 +2422,10 @@ void
management_set_state (struct management *man,
const int state,
const char *detail,
- const in_addr_t tun_local_ip,
- const in_addr_t tun_remote_ip)
+ const in_addr_t *tun_local_ip,
+ const struct in6_addr *tun_local_ip6,
+ const struct openvpn_sockaddr *local,
+ const struct openvpn_sockaddr *remote)
{
if (man->persist.state && (!(man->settings.flags & MF_SERVER) || state < OPENVPN_STATE_CLIENT_BASE))
{
@@ -2246,9 +2438,15 @@ management_set_state (struct management *man,
e.timestamp = now;
e.u.state = state;
e.string = detail;
- e.local_ip = tun_local_ip;
- e.remote_ip = tun_remote_ip;
-
+ if (tun_local_ip)
+ e.local_ip = *tun_local_ip;
+ if (tun_local_ip6)
+ e.local_ip6 = *tun_local_ip6;
+ if (local)
+ e.local_sock = *local;
+ if (remote)
+ e.remote_sock = *remote;
+
log_history_add (man->persist.state, &e);
if (man->connection.state_realtime)
@@ -2361,33 +2559,6 @@ management_notify_generic (struct management *man, const char *str)
#ifdef MANAGEMENT_DEF_AUTH
-static bool
-validate_peer_info_line(const char *line)
-{
- uint8_t c;
- int state = 0;
- while ((c=*line++))
- {
- switch (state)
- {
- case 0:
- case 1:
- if (c == '=' && state == 1)
- state = 2;
- else if (isalnum(c) || c == '_')
- state = 1;
- else
- return false;
- case 2:
- if (isprint(c))
- ;
- else
- return false;
- }
- }
- return (state == 2);
-}
-
static void
man_output_peer_info_env (struct management *man, struct man_def_auth_context *mdac)
{
@@ -2426,7 +2597,8 @@ management_notify_client_needing_auth (struct management *management,
mode = "REAUTH";
msg (M_CLIENT, ">CLIENT:%s,%lu,%u", mode, mdac->cid, mda_key_id);
man_output_extra_env (management, "CLIENT");
- man_output_peer_info_env(management, mdac);
+ if (management->connection.env_filter_level>0)
+ man_output_peer_info_env(management, mdac);
man_output_env (es, true, management->connection.env_filter_level, "CLIENT");
mdac->flags |= DAF_INITIAL_AUTH;
}
@@ -2513,7 +2685,13 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i
&& man->connection.state == MS_INITIAL)
{
/* listen on our local TUN/TAP IP address */
- man->settings.local.addr.in4.sin_addr.s_addr = htonl (tun_local_ip);
+ struct in_addr ia;
+ int ret;
+
+ ia.s_addr = htonl(tun_local_ip);
+ ret = openvpn_getaddrinfo(GETADDR_PASSIVE, inet_ntoa(ia), NULL, 0, NULL,
+ AF_INET, &man->settings.local);
+ ASSERT (ret==0);
man_connection_init (man);
}
@@ -2553,7 +2731,7 @@ man_persist_state (unsigned int *persistent, const int n)
return true;
}
-#ifdef WIN32
+#ifdef _WIN32
void
management_socket_set (struct management *man,
@@ -2845,7 +3023,8 @@ management_event_loop_n_seconds (struct management *man, int sec)
man_check_for_signals (&signal_received);
if (signal_received)
return;
- } while (expire);
+ update_time();
+ } while (expire && expire > now);
/* revert state */
man->persist.standalone_disabled = standalone_disabled_save;
@@ -2984,15 +3163,14 @@ management_query_user_pass (struct management *man,
#ifdef MANAGMENT_EXTERNAL_KEY
-char * /* returns allocated base64 signature */
-management_query_rsa_sig (struct management *man,
- const char *b64_data)
+int
+management_query_multiline (struct management *man,
+ const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input)
{
struct gc_arena gc = gc_new ();
- char *ret = NULL;
+ int ret = 0;
volatile int signal_received = 0;
struct buffer alert_msg = clear_buf();
- struct buffer *buf;
const bool standalone_disabled_save = man->persist.standalone_disabled;
struct man_connection *mc = &man->connection;
@@ -3001,10 +3179,15 @@ management_query_rsa_sig (struct management *man,
man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */
man->persist.special_state_msg = NULL;
- mc->ext_key_state = EKS_SOLICIT;
+ *state = EKS_SOLICIT;
- alert_msg = alloc_buf_gc (strlen(b64_data)+64, &gc);
- buf_printf (&alert_msg, ">RSA_SIGN:%s", b64_data);
+ if (b64_data) {
+ alert_msg = alloc_buf_gc (strlen(b64_data)+strlen(prompt)+3, &gc);
+ buf_printf (&alert_msg, ">%s:%s", prompt, b64_data);
+ } else {
+ alert_msg = alloc_buf_gc (strlen(prompt)+3, &gc);
+ buf_printf (&alert_msg, ">%s", prompt);
+ }
man_wait_for_client_connection (man, &signal_received, 0, MWCC_OTHER_WAIT);
@@ -3022,40 +3205,107 @@ management_query_rsa_sig (struct management *man,
man_check_for_signals (&signal_received);
if (signal_received)
goto done;
- } while (mc->ext_key_state != EKS_READY);
+ } while (*state != EKS_READY);
- if (buffer_list_defined(mc->ext_key_input))
- {
- buffer_list_aggregate (mc->ext_key_input, 2048);
- buf = buffer_list_peek (mc->ext_key_input);
- if (buf && BLEN(buf) > 0)
- {
- ret = (char *) malloc(BLEN(buf)+1);
- check_malloc_return(ret);
- memcpy(ret, buf->data, BLEN(buf));
- ret[BLEN(buf)] = '\0';
- }
- }
+ ret = 1;
}
done:
- if (mc->ext_key_state == EKS_READY && ret)
- msg (M_CLIENT, "SUCCESS: rsa-sig command succeeded");
- else if (mc->ext_key_state == EKS_INPUT || mc->ext_key_state == EKS_READY)
- msg (M_CLIENT, "ERROR: rsa-sig command failed");
+ if (*state == EKS_READY && ret)
+ msg (M_CLIENT, "SUCCESS: %s command succeeded", cmd);
+ else if (*state == EKS_INPUT || *state == EKS_READY)
+ msg (M_CLIENT, "ERROR: %s command failed", cmd);
/* revert state */
man->persist.standalone_disabled = standalone_disabled_save;
man->persist.special_state_msg = NULL;
in_extra_reset (mc, IER_RESET);
- mc->ext_key_state = EKS_UNDEF;
- buffer_list_free (mc->ext_key_input);
- mc->ext_key_input = NULL;
+ *state = EKS_UNDEF;
gc_free (&gc);
return ret;
}
+char * /* returns allocated base64 signature */
+management_query_multiline_flatten_newline (struct management *man,
+ const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input)
+{
+ int ok;
+ char *result = NULL;
+ struct buffer *buf;
+
+ ok = management_query_multiline(man, b64_data, prompt, cmd, state, input);
+ if (ok && buffer_list_defined(*input))
+ {
+ buffer_list_aggregate_separator (*input, 10000, "\n");
+ buf = buffer_list_peek (*input);
+ if (buf && BLEN(buf) > 0)
+ {
+ result = (char *) malloc(BLEN(buf)+1);
+ check_malloc_return(result);
+ memcpy(result, buf->data, BLEN(buf));
+ result[BLEN(buf)] = '\0';
+ }
+ }
+
+ buffer_list_free (*input);
+ *input = NULL;
+
+ return result;
+}
+
+char * /* returns allocated base64 signature */
+management_query_multiline_flatten (struct management *man,
+ const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input)
+{
+ int ok;
+ char *result = NULL;
+ struct buffer *buf;
+
+ ok = management_query_multiline(man, b64_data, prompt, cmd, state, input);
+ if (ok && buffer_list_defined(*input))
+ {
+ buffer_list_aggregate (*input, 2048);
+ buf = buffer_list_peek (*input);
+ if (buf && BLEN(buf) > 0)
+ {
+ result = (char *) malloc(BLEN(buf)+1);
+ check_malloc_return(result);
+ memcpy(result, buf->data, BLEN(buf));
+ result[BLEN(buf)] = '\0';
+ }
+ }
+
+ buffer_list_free (*input);
+ *input = NULL;
+
+ return result;
+}
+
+char * /* returns allocated base64 signature */
+management_query_rsa_sig (struct management *man,
+ const char *b64_data)
+{
+ return management_query_multiline_flatten(man, b64_data, "RSA_SIGN", "rsa-sign",
+ &man->connection.ext_key_state, &man->connection.ext_key_input);
+}
+
+
+char* management_query_cert (struct management *man, const char *cert_name)
+{
+ const char prompt_1[] = "NEED-CERTIFICATE:";
+ struct buffer buf_prompt = alloc_buf(strlen(cert_name) + 20);
+ buf_write(&buf_prompt, prompt_1, strlen(prompt_1));
+ buf_write(&buf_prompt, cert_name, strlen(cert_name)+1); // +1 for \0
+
+ char *result;
+ result = management_query_multiline_flatten_newline(management,
+ NULL, (char*)buf_bptr(&buf_prompt), "certificate",
+ &man->connection.ext_cert_state, &man->connection.ext_cert_input);
+ free_buf(&buf_prompt);
+ return result;
+}
+
#endif
/*
@@ -3082,12 +3332,13 @@ management_should_daemonize (struct management *man)
* Return true if the caller should not sleep for an additional time interval.
*/
bool
-management_hold (struct management *man)
+management_hold (struct management *man, int holdtime)
{
if (management_would_hold (man))
{
volatile int signal_received = 0;
const bool standalone_disabled_save = man->persist.standalone_disabled;
+ struct gc_arena gc = gc_new ();
man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */
man->persist.special_state_msg = NULL;
@@ -3097,7 +3348,9 @@ management_hold (struct management *man)
if (!signal_received)
{
- man->persist.special_state_msg = ">HOLD:Waiting for hold release";
+ struct buffer out = alloc_buf_gc (128, &gc);
+ buf_printf (&out, ">HOLD:Waiting for hold release:%d", holdtime);
+ man->persist.special_state_msg = BSTR (&out);
msg (M_CLIENT, "%s", man->persist.special_state_msg);
/* run command processing event loop until we get our username/password */
@@ -3116,6 +3369,7 @@ management_hold (struct management *man)
man->persist.special_state_msg = NULL;
man->settings.mansig &= ~MANSIG_IGNORE_USR1_HUP;
+ gc_free (&gc);
return true;
}
return false;
@@ -3218,7 +3472,14 @@ log_entry_print (const struct log_entry *e, unsigned int flags, struct gc_arena
if (flags & LOG_PRINT_LOCAL_IP)
buf_printf (&out, ",%s", print_in_addr_t (e->local_ip, IA_EMPTY_IF_UNDEF, gc));
if (flags & LOG_PRINT_REMOTE_IP)
- buf_printf (&out, ",%s", print_in_addr_t (e->remote_ip, IA_EMPTY_IF_UNDEF, gc));
+ {
+ buf_printf (&out, ",%s", (!addr_defined (&e->remote_sock) ? "," :
+ print_sockaddr_ex (&e->remote_sock.addr.sa, ",", PS_DONT_SHOW_FAMILY|PS_SHOW_PORT, gc)));
+ buf_printf (&out, ",%s", (!addr_defined (&e->local_sock) ? "," :
+ print_sockaddr_ex (&e->local_sock.addr.sa, ",", PS_DONT_SHOW_FAMILY|PS_SHOW_PORT, gc)));
+ }
+ if (flags & LOG_PRINT_LOCAL_IP && !IN6_IS_ADDR_UNSPECIFIED(&e->local_ip6))
+ buf_printf (&out, ",%s", print_in6_addr (e->local_ip6, IA_EMPTY_IF_UNDEF, gc));
if (flags & LOG_ECHO_TO_LOG)
msg (D_MANAGEMENT, "MANAGEMENT: %s", BSTR (&out));
if (flags & LOG_PRINT_CRLF)
diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h
index 28da69f..3ffced0 100644
--- a/src/openvpn/manage.h
+++ b/src/openvpn/manage.h
@@ -88,7 +88,9 @@ struct log_entry
time_t timestamp;
const char *string;
in_addr_t local_ip;
- in_addr_t remote_ip;
+ struct in6_addr local_ip6;
+ struct openvpn_sockaddr local_sock;
+ struct openvpn_sockaddr remote_sock;
union log_entry_union u;
};
@@ -173,6 +175,9 @@ struct management_callback
#endif
bool (*proxy_cmd) (void *arg, const char **p);
bool (*remote_cmd) (void *arg, const char **p);
+#ifdef TARGET_ANDROID
+ int (*network_change) (void *arg, bool samenetwork);
+#endif
};
/*
@@ -212,7 +217,7 @@ struct man_persist {
struct man_settings {
bool defined;
unsigned int flags; /* MF_x flags */
- struct openvpn_sockaddr local;
+ struct addrinfo* local;
#if UNIX_SOCK_SUPPORT
struct sockaddr_un local_unix;
#endif
@@ -252,7 +257,7 @@ struct man_connection {
socket_descriptor_t sd_cli;
struct openvpn_sockaddr remote;
-#ifdef WIN32
+#ifdef _WIN32
struct net_event_win32 ne32;
#endif
@@ -268,6 +273,7 @@ struct man_connection {
# define IEC_CLIENT_AUTH 1
# define IEC_CLIENT_PF 2
# define IEC_RSA_SIGN 3
+# define IEC_CERTIFICATE 4
int in_extra_cmd;
struct buffer_list *in_extra;
#ifdef MANAGEMENT_DEF_AUTH
@@ -281,6 +287,8 @@ struct man_connection {
# define EKS_READY 3
int ext_key_state;
struct buffer_list *ext_key_input;
+ int ext_cert_state;
+ struct buffer_list *ext_cert_input;
#endif
#endif
struct event_set *es;
@@ -299,6 +307,10 @@ struct man_connection {
#ifdef MANAGMENT_EXTERNAL_KEY
struct buffer_list *rsa_sig;
#endif
+#ifdef TARGET_ANDROID
+ int fdtosend;
+ int lastfdreceived;
+#endif
};
struct management
@@ -334,10 +346,11 @@ struct management *management_init (void);
#define MF_UP_DOWN (1<<10)
#define MF_QUERY_REMOTE (1<<11)
#define MF_QUERY_PROXY (1<<12)
+#define MF_EXTERNAL_CERT (1<<13)
bool management_open (struct management *man,
const char *addr,
- const int port,
+ const char *port,
const char *pass_file,
const char *client_user,
const char *client_group,
@@ -372,9 +385,18 @@ bool management_query_user_pass (struct management *man,
const unsigned int flags,
const char *static_challenge);
+#ifdef TARGET_ANDROID
+bool management_android_control (struct management *man, const char *command, const char *msg);
+
+#define ANDROID_KEEP_OLD_TUN 1
+#define ANDROID_OPEN_AFTER_CLOSE 2
+#define ANDROID_OPEN_BEFORE_CLOSE 3
+int managment_android_persisttun_action (struct management *man);
+#endif
+
bool management_should_daemonize (struct management *man);
bool management_would_hold (struct management *man);
-bool management_hold (struct management *man);
+bool management_hold (struct management *man, int holdtime);
void management_event_loop_n_seconds (struct management *man, int sec);
@@ -407,6 +429,7 @@ void management_learn_addr (struct management *management,
#ifdef MANAGMENT_EXTERNAL_KEY
char *management_query_rsa_sig (struct management *man, const char *b64_data);
+char* management_query_cert (struct management *man, const char *cert_name);
#endif
@@ -475,8 +498,10 @@ management_enable_def_auth (const struct management *man)
void management_set_state (struct management *man,
const int state,
const char *detail,
- const in_addr_t tun_local_ip,
- const in_addr_t tun_remote_ip);
+ const in_addr_t *tun_local_ip,
+ const struct in6_addr *tun_local_ip6,
+ const struct openvpn_sockaddr *local_addr,
+ const struct openvpn_sockaddr *remote_addr);
/*
* The management object keeps track of OpenVPN --echo
diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c
index 48ca0d5..56d43e0 100644
--- a/src/openvpn/misc.c
+++ b/src/openvpn/misc.c
@@ -6,6 +6,8 @@
* packet compression.
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
+ * Copyright (C) 2016 David Sommerseth <davids@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
@@ -62,7 +64,7 @@ run_up_down (const char *command,
const struct plugin_list *plugins,
int plugin_type,
const char *arg,
-#ifdef WIN32
+#ifdef _WIN32
DWORD adapter_index,
#endif
const char *dev_type,
@@ -85,7 +87,7 @@ run_up_down (const char *command,
setenv_str (es, "dev", arg);
if (dev_type)
setenv_str (es, "dev_type", dev_type);
-#ifdef WIN32
+#ifdef _WIN32
setenv_int (es, "dev_idx", adapter_index);
#endif
@@ -118,13 +120,9 @@ run_up_down (const char *command,
struct argv argv = argv_new ();
ASSERT (arg);
setenv_str (es, "script_type", script_type);
- argv_printf (&argv,
- "%sc %s %d %d %s %s %s",
- command,
- arg,
- tun_mtu, link_mtu,
- ifconfig_local, ifconfig_remote,
- context);
+ argv_parse_cmd (&argv, command);
+ argv_printf_cat (&argv, "%s %d %d %s %s %s", arg, tun_mtu, link_mtu,
+ ifconfig_local, ifconfig_remote, context);
argv_msg (M_INFO, &argv);
openvpn_run_script (&argv, es, S_FATAL, "--up/--down");
argv_reset (&argv);
@@ -192,38 +190,13 @@ save_inetd_socket_descriptor (void)
}
/*
- * Warn if a given file is group/others accessible.
- */
-void
-warn_if_group_others_accessible (const char* filename)
-{
-#ifndef WIN32
-#ifdef HAVE_STAT
- if (strcmp (filename, INLINE_FILE_TAG))
- {
- struct stat st;
- if (stat (filename, &st))
- {
- msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", filename);
- }
- else
- {
- if (st.st_mode & (S_IRWXG|S_IRWXO))
- msg (M_WARN, "WARNING: file '%s' is group or others accessible", filename);
- }
- }
-#endif
-#endif
-}
-
-/*
* Print an error message based on the status code returned by system().
*/
const char *
system_error_message (int stat, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (256, gc);
-#ifdef WIN32
+#ifdef _WIN32
if (stat == -1)
buf_printf (&out, "external program did not execute -- ");
buf_printf (&out, "returned error code %d", stat);
@@ -279,7 +252,7 @@ openvpn_execve_allowed (const unsigned int flags)
}
-#ifndef WIN32
+#ifndef _WIN32
/*
* Run execve() inside a fork(). Designed to replicate the semantics of system() but
* in a safer way that doesn't require the invocation of a shell or the risks
@@ -362,27 +335,29 @@ openvpn_popen (const struct argv *a, const struct env_set *es)
pid = fork ();
if (pid == (pid_t)0) /* child side */
{
- close (pipe_stdout[0]);
+ close (pipe_stdout[0]); /* Close read end */
dup2 (pipe_stdout[1],1);
execve (cmd, argv, envp);
exit (127);
}
- else if (pid < (pid_t)0) /* fork failed */
- {
- msg (M_ERR, "openvpn_popen: unable to fork");
- }
- else /* parent side */
+ else if (pid > (pid_t)0) /* parent side */
{
int status = 0;
+ close (pipe_stdout[1]); /* Close write end */
waitpid(pid, &status, 0);
ret = pipe_stdout[0];
+ }
+ else /* fork failed */
+ {
+ close (pipe_stdout[0]);
close (pipe_stdout[1]);
+ msg (M_ERR, "openvpn_popen: unable to fork %s", cmd);
}
}
else {
- msg (M_WARN, "openvpn_popen: unable to create stdout pipe");
- ret = -1;
+ msg (M_WARN, "openvpn_popen: unable to create stdout pipe for %s", cmd);
+ ret = -1;
}
}
else if (!warn_shown && (script_security < SSEC_SCRIPTS))
@@ -611,6 +586,16 @@ env_set_add (struct env_set *es, const char *str)
env_set_add_nolock (es, str);
}
+const char*
+env_set_get (const struct env_set *es, const char *name)
+{
+ const struct env_item *item = es->list;
+ while (item && !env_string_equal(item->string, name)) {
+ item = item->next;
+ }
+ return item ? item->string : NULL;
+}
+
void
env_set_print (int msglevel, const struct env_set *es)
{
@@ -701,14 +686,6 @@ env_set_remove_from_environment (const struct env_set *es)
}
}
-#ifdef HAVE_PUTENV
-
-/* companion functions to putenv */
-
-static struct env_item *global_env = NULL; /* GLOBAL */
-
-#endif
-
/* add/modify/delete environmental strings */
void
@@ -753,6 +730,28 @@ setenv_str_safe (struct env_set *es, const char *name, const char *value)
msg (M_WARN, "setenv_str_safe: name overflow");
}
+void setenv_str_incr(struct env_set *es, const char *name, const char *value)
+{
+ unsigned int counter = 1;
+ const size_t tmpname_len = strlen(name) + 5; /* 3 digits counter max */
+ char *tmpname = gc_malloc(tmpname_len, true, NULL);
+ strcpy(tmpname, name);
+ while (NULL != env_set_get(es, tmpname) && counter < 1000)
+ {
+ ASSERT (openvpn_snprintf (tmpname, tmpname_len, "%s_%u", name, counter));
+ counter++;
+ }
+ if (counter < 1000)
+ {
+ setenv_str (es, tmpname, value);
+ }
+ else
+ {
+ msg (D_TLS_DEBUG_MED, "Too many same-name env variables, ignoring: %s", name);
+ }
+ free (tmpname);
+}
+
void
setenv_del (struct env_set *es, const char *name)
{
@@ -830,32 +829,6 @@ setenv_str_i (struct env_set *es, const char *name, const char *value, const int
gc_free (&gc);
}
-/*
- * taken from busybox networking/ifupdown.c
- */
-unsigned int
-count_bits(unsigned int a)
-{
- unsigned int result;
- result = (a & 0x55) + ((a >> 1) & 0x55);
- result = (result & 0x33) + ((result >> 2) & 0x33);
- return((result & 0x0F) + ((result >> 4) & 0x0F));
-}
-
-int
-count_netmask_bits(const char *dotted_quad)
-{
- unsigned int result, a, b, c, d;
- /* Found a netmask... Check if it is dotted quad */
- if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
- return -1;
- result = count_bits(a);
- result += count_bits(b);
- result += count_bits(c);
- result += count_bits(d);
- return ((int)result);
-}
-
/* return true if filename can be opened for read */
bool
test_file (const char *filename)
@@ -977,7 +950,7 @@ hostname_randomize(const char *hostname, struct gc_arena *gc)
const char *
gen_path (const char *directory, const char *filename, struct gc_arena *gc)
{
-#if WIN32
+#ifdef _WIN32
const int CC_PATH_RESERVED = CC_LESS_THAN|CC_GREATER_THAN|CC_COLON|
CC_DOUBLE_QUOTE|CC_SLASH|CC_BACKSLASH|CC_PIPE|CC_QUESTION_MARK|CC_ASTERISK;
#else
@@ -988,7 +961,7 @@ gen_path (const char *directory, const char *filename, struct gc_arena *gc)
if (safe_filename
&& strcmp (safe_filename, ".")
&& strcmp (safe_filename, "..")
-#ifdef WIN32
+#ifdef _WIN32
&& win_safe_filename (safe_filename)
#endif
)
@@ -1016,7 +989,7 @@ absolute_pathname (const char *pathname)
if (pathname)
{
const int c = pathname[0];
-#ifdef WIN32
+#ifdef _WIN32
return c == '\\' || (isalpha(c) && pathname[1] == ':' && pathname[2] == '\\');
#else
return c == '/';
@@ -1085,13 +1058,23 @@ get_user_pass_cr (struct user_pass *up,
struct buffer user_prompt = alloc_buf_gc (128, &gc);
buf_printf (&user_prompt, "NEED-OK|%s|%s:", prefix, up->username);
-
- if (!get_console_input (BSTR (&user_prompt), true, up->password, USER_PASS_LEN))
- msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix);
+ if (!query_user_SINGLE (BSTR(&user_prompt), BLEN(&user_prompt),
+ up->password, USER_PASS_LEN, false))
+ {
+ msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix);
+ }
if (!strlen (up->password))
strcpy (up->password, "ok");
}
+ else if (flags & GET_USER_PASS_INLINE_CREDS)
+ {
+ struct buffer buf;
+ buf_set_read (&buf, (uint8_t*) auth_file, strlen (auth_file) + 1);
+ if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
+ buf_parse (&buf, '\n', up->username, USER_PASS_LEN);
+ buf_parse (&buf, '\n', up->password, USER_PASS_LEN);
+ }
/*
* Read from auth file unless this is a dynamic challenge request.
*/
@@ -1103,8 +1086,6 @@ get_user_pass_cr (struct user_pass *up,
FILE *fp;
char password_buf[USER_PASS_LEN] = { '\0' };
- warn_if_group_others_accessible (auth_file);
-
fp = platform_fopen (auth_file, "r");
if (!fp)
msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file);
@@ -1155,13 +1136,17 @@ get_user_pass_cr (struct user_pass *up,
if (ac)
{
char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc);
- struct buffer packed_resp;
+ struct buffer packed_resp, challenge;
+ challenge = alloc_buf_gc (14+strlen(ac->challenge_text), &gc);
+ buf_printf (&challenge, "CHALLENGE: %s", ac->challenge_text);
buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN);
- msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", ac->challenge_text);
- if (!get_console_input (ac->challenge_text, BOOL_CAST(ac->flags&CR_ECHO),
- response, USER_PASS_LEN))
- msg (M_FATAL, "ERROR: could not read challenge response from stdin");
+
+ if (!query_user_SINGLE (BSTR(&challenge), BLEN(&challenge),
+ response, USER_PASS_LEN, BOOL_CAST(ac->flags&CR_ECHO)))
+ {
+ msg (M_FATAL, "ERROR: could not read challenge response from stdin");
+ }
strncpynt (up->username, ac->user, USER_PASS_LEN);
buf_printf (&packed_resp, "CRV1::%s::%s", ac->state_id, response);
}
@@ -1176,32 +1161,49 @@ get_user_pass_cr (struct user_pass *up,
struct buffer user_prompt = alloc_buf_gc (128, &gc);
struct buffer pass_prompt = alloc_buf_gc (128, &gc);
+ query_user_clear ();
buf_printf (&user_prompt, "Enter %s Username:", prefix);
buf_printf (&pass_prompt, "Enter %s Password:", prefix);
if (username_from_stdin && !(flags & GET_USER_PASS_PASSWORD_ONLY))
{
- if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
- msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
+ query_user_add (BSTR(&user_prompt), BLEN(&user_prompt),
+ up->username, USER_PASS_LEN, true);
+ }
+
+ if (password_from_stdin)
+ {
+ query_user_add (BSTR(&pass_prompt), BLEN(&pass_prompt),
+ up->password, USER_PASS_LEN, false);
+ }
+
+ if( !query_user_exec () )
+ {
+ msg(M_FATAL, "ERROR: Failed retrieving username or password");
+ }
+
+ if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
+ {
if (strlen (up->username) == 0)
msg (M_FATAL, "ERROR: %s username is empty", prefix);
}
- if (password_from_stdin && !get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
- msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix);
-
#ifdef ENABLE_CLIENT_CR
if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE) && response_from_stdin)
{
char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc);
- struct buffer packed_resp;
+ struct buffer packed_resp, challenge;
char *pw64=NULL, *resp64=NULL;
- msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", auth_challenge);
+ challenge = alloc_buf_gc (14+strlen(auth_challenge), &gc);
+ buf_printf (&challenge, "CHALLENGE: %s", auth_challenge);
- if (!get_console_input (auth_challenge, BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO),
- response, USER_PASS_LEN))
- msg (M_FATAL, "ERROR: could not read static challenge response from stdin");
+ if (!query_user_SINGLE (BSTR(&challenge), BLEN(&challenge),
+ response, USER_PASS_LEN,
+ BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO)))
+ {
+ msg (M_FATAL, "ERROR: could not retrieve static challenge response");
+ }
if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1
|| openvpn_base64_encode(response, strlen(response), &resp64) == -1)
msg (M_FATAL, "ERROR: could not base64-encode password/static_response");
@@ -1555,465 +1557,6 @@ adjust_power_of_2 (size_t u)
}
/*
- * A printf-like function (that only recognizes a subset of standard printf
- * format operators) that prints arguments to an argv list instead
- * of a standard string. This is used to build up argv arrays for passing
- * to execve.
- */
-
-void
-argv_init (struct argv *a)
-{
- a->capacity = 0;
- a->argc = 0;
- a->argv = NULL;
- a->system_str = NULL;
-}
-
-struct argv
-argv_new (void)
-{
- struct argv ret;
- argv_init (&ret);
- return ret;
-}
-
-void
-argv_reset (struct argv *a)
-{
- size_t i;
- for (i = 0; i < a->argc; ++i)
- free (a->argv[i]);
- free (a->argv);
- free (a->system_str);
- argv_init (a);
-}
-
-static void
-argv_extend (struct argv *a, const size_t newcap)
-{
- if (newcap > a->capacity)
- {
- char **newargv;
- size_t i;
- ALLOC_ARRAY_CLEAR (newargv, char *, newcap);
- for (i = 0; i < a->argc; ++i)
- newargv[i] = a->argv[i];
- free (a->argv);
- a->argv = newargv;
- a->capacity = newcap;
- }
-}
-
-static void
-argv_grow (struct argv *a, const size_t add)
-{
- const size_t newargc = a->argc + add + 1;
- ASSERT (newargc > a->argc);
- argv_extend (a, adjust_power_of_2 (newargc));
-}
-
-static void
-argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */
-{
- argv_grow (a, 1);
- a->argv[a->argc++] = str;
-}
-
-static void
-argv_system_str_append (struct argv *a, const char *str, const bool enquote)
-{
- if (str)
- {
- char *newstr;
-
- /* compute length of new system_str */
- size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */
- if (a->system_str)
- l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */
- if (enquote)
- l += 2; /* space for two quotes */
-
- /* build new system_str */
- newstr = (char *) malloc (l);
- newstr[0] = '\0';
- check_malloc_return (newstr);
- if (a->system_str)
- {
- strcpy (newstr, a->system_str);
- strcat (newstr, " ");
- }
- if (enquote)
- strcat (newstr, "\"");
- strcat (newstr, str);
- if (enquote)
- strcat (newstr, "\"");
- free (a->system_str);
- a->system_str = newstr;
- }
-}
-
-static char *
-argv_extract_cmd_name (const char *path)
-{
- char *ret = NULL;
- if (path)
- {
- char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */
- const char *bn = basename (path_cp);
- if (bn)
- {
- char *dot = NULL;
- ret = string_alloc (bn, NULL);
- dot = strrchr (ret, '.');
- if (dot)
- *dot = '\0';
- free(path_cp);
- if (ret[0] == '\0')
- {
- free(ret);
- ret = NULL;
- }
- }
- }
- return ret;
-}
-
-const char *
-argv_system_str (const struct argv *a)
-{
- return a->system_str;
-}
-
-struct argv
-argv_clone (const struct argv *a, const size_t headroom)
-{
- struct argv r;
- size_t i;
-
- argv_init (&r);
- for (i = 0; i < headroom; ++i)
- argv_append (&r, NULL);
- if (a)
- {
- for (i = 0; i < a->argc; ++i)
- argv_append (&r, string_alloc (a->argv[i], NULL));
- r.system_str = string_alloc (a->system_str, NULL);
- }
- return r;
-}
-
-struct argv
-argv_insert_head (const struct argv *a, const char *head)
-{
- struct argv r;
- char *s;
-
- r = argv_clone (a, 1);
- r.argv[0] = string_alloc (head, NULL);
- s = r.system_str;
- r.system_str = string_alloc (head, NULL);
- if (s)
- {
- argv_system_str_append (&r, s, false);
- free (s);
- }
- return r;
-}
-
-char *
-argv_term (const char **f)
-{
- const char *p = *f;
- const char *term = NULL;
- size_t termlen = 0;
-
- if (*p == '\0')
- return NULL;
-
- while (true)
- {
- const int c = *p;
- if (c == '\0')
- break;
- if (term)
- {
- if (!isspace (c))
- ++termlen;
- else
- break;
- }
- else
- {
- if (!isspace (c))
- {
- term = p;
- termlen = 1;
- }
- }
- ++p;
- }
- *f = p;
-
- if (term)
- {
- char *ret;
- ASSERT (termlen > 0);
- ret = malloc (termlen + 1);
- check_malloc_return (ret);
- memcpy (ret, term, termlen);
- ret[termlen] = '\0';
- return ret;
- }
- else
- return NULL;
-}
-
-const char *
-argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags)
-{
- if (a->argv)
- return print_argv ((const char **)a->argv, gc, flags);
- else
- return "";
-}
-
-void
-argv_msg (const int msglev, const struct argv *a)
-{
- struct gc_arena gc = gc_new ();
- msg (msglev, "%s", argv_str (a, &gc, 0));
- gc_free (&gc);
-}
-
-void
-argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix)
-{
- struct gc_arena gc = gc_new ();
- msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0));
- gc_free (&gc);
-}
-
-void
-argv_printf (struct argv *a, const char *format, ...)
-{
- va_list arglist;
- va_start (arglist, format);
- argv_printf_arglist (a, format, 0, arglist);
- va_end (arglist);
- }
-
-void
-argv_printf_cat (struct argv *a, const char *format, ...)
-{
- va_list arglist;
- va_start (arglist, format);
- argv_printf_arglist (a, format, APA_CAT, arglist);
- va_end (arglist);
-}
-
-void
-argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist)
-{
- struct gc_arena gc = gc_new ();
- char *term;
- const char *f = format;
-
- if (!(flags & APA_CAT))
- argv_reset (a);
- argv_extend (a, 1); /* ensure trailing NULL */
-
- while ((term = argv_term (&f)) != NULL)
- {
- if (term[0] == '%')
- {
- if (!strcmp (term, "%s"))
- {
- char *s = va_arg (arglist, char *);
- if (!s)
- s = "";
- argv_append (a, string_alloc (s, NULL));
- argv_system_str_append (a, s, true);
- }
- else if (!strcmp (term, "%sc"))
- {
- char *s = va_arg (arglist, char *);
- if (s)
- {
- int nparms;
- char *parms[MAX_PARMS+1];
- int i;
-
- nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
- if (nparms)
- {
- for (i = 0; i < nparms; ++i)
- argv_append (a, string_alloc (parms[i], NULL));
- }
- else
- argv_append (a, string_alloc (s, NULL));
-
- argv_system_str_append (a, s, false);
- }
- else
- {
- argv_append (a, string_alloc ("", NULL));
- argv_system_str_append (a, "echo", false);
- }
- }
- else if (!strcmp (term, "%d"))
- {
- char numstr[64];
- openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
- argv_append (a, string_alloc (numstr, NULL));
- argv_system_str_append (a, numstr, false);
- }
- else if (!strcmp (term, "%u"))
- {
- char numstr[64];
- openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int));
- argv_append (a, string_alloc (numstr, NULL));
- argv_system_str_append (a, numstr, false);
- }
- else if (!strcmp (term, "%s/%d"))
- {
- char numstr[64];
- char *s = va_arg (arglist, char *);
-
- if (!s)
- s = "";
-
- openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
-
- {
- const size_t len = strlen(s) + strlen(numstr) + 2;
- char *combined = (char *) malloc (len);
- check_malloc_return (combined);
-
- strcpy (combined, s);
- strcat (combined, "/");
- strcat (combined, numstr);
- argv_append (a, combined);
- argv_system_str_append (a, combined, false);
- }
- }
- else if (!strcmp (term, "%s%sc"))
- {
- char *s1 = va_arg (arglist, char *);
- char *s2 = va_arg (arglist, char *);
- char *combined;
- char *cmd_name;
-
- if (!s1) s1 = "";
- if (!s2) s2 = "";
- combined = (char *) malloc (strlen(s1) + strlen(s2) + 1);
- check_malloc_return (combined);
- strcpy (combined, s1);
- strcat (combined, s2);
- argv_append (a, combined);
-
- cmd_name = argv_extract_cmd_name (combined);
- if (cmd_name)
- {
- argv_system_str_append (a, cmd_name, false);
- free (cmd_name);
- }
- }
- else
- ASSERT (0);
- free (term);
- }
- else
- {
- argv_append (a, term);
- argv_system_str_append (a, term, false);
- }
- }
- gc_free (&gc);
-}
-
-#ifdef ARGV_TEST
-void
-argv_test (void)
-{
- struct gc_arena gc = gc_new ();
- const char *s;
-
- struct argv a;
-
- argv_init (&a);
- argv_printf (&a, "%sc foo bar %s", "c:\\\\src\\\\test\\\\jyargs.exe", "foo bar");
- argv_msg_prefix (M_INFO, &a, "ARGV");
- msg (M_INFO, "ARGV-S: %s", argv_system_str(&a));
- /*openvpn_execve_check (&a, NULL, 0, "command failed");*/
-
- argv_printf (&a, "%sc %s %s", "c:\\\\src\\\\test files\\\\batargs.bat", "foo", "bar");
- argv_msg_prefix (M_INFO, &a, "ARGV");
- msg (M_INFO, "ARGV-S: %s", argv_system_str(&a));
- /*openvpn_execve_check (&a, NULL, 0, "command failed");*/
-
- argv_printf (&a, "%s%sc foo bar %s %s/%d %d %u", "/foo", "/bar.exe", "one two", "1.2.3.4", 24, -69, 96);
- argv_msg_prefix (M_INFO, &a, "ARGV");
- msg (M_INFO, "ARGV-S: %s", argv_system_str(&a));
- /*openvpn_execve_check (&a, NULL, 0, "command failed");*/
-
- argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42);
- s = argv_str (&a, &gc, PA_BRACKET);
- printf ("PF: %s\n", s);
- printf ("PF-S: %s\n", argv_system_str(&a));
-
- {
- struct argv b = argv_insert_head (&a, "MARK");
- s = argv_str (&b, &gc, PA_BRACKET);
- printf ("PF: %s\n", s);
- printf ("PF-S: %s\n", argv_system_str(&b));
- argv_reset (&b);
- }
-
- argv_printf (&a, "%sc foo bar %d", "\"multi term\" command following \\\"spaces", 99);
- s = argv_str (&a, &gc, PA_BRACKET);
- printf ("PF: %s\n", s);
- printf ("PF-S: %s\n", argv_system_str(&a));
- argv_reset (&a);
-
- s = argv_str (&a, &gc, PA_BRACKET);
- printf ("PF: %s\n", s);
- printf ("PF-S: %s\n", argv_system_str(&a));
- argv_reset (&a);
-
- argv_printf (&a, "foo bar %d", 99);
- argv_printf_cat (&a, "bar %d foo %sc", 42, "nonesuch");
- argv_printf_cat (&a, "cool %s %d u %s/%d end", "frood", 4, "hello", 7);
- s = argv_str (&a, &gc, PA_BRACKET);
- printf ("PF: %s\n", s);
- printf ("PF-S: %s\n", argv_system_str(&a));
- argv_reset (&a);
-
-#if 0
- {
- char line[512];
- while (fgets (line, sizeof(line), stdin) != NULL)
- {
- char *term;
- const char *f = line;
- int i = 0;
-
- while ((term = argv_term (&f)) != NULL)
- {
- printf ("[%d] '%s'\n", i, term);
- ++i;
- free (term);
- }
- }
- }
-#endif
-
- argv_reset (&a);
- gc_free (&gc);
-}
-#endif
-
-/*
* Remove security-sensitive strings from control message
* so that they will not be output to log file.
*/
@@ -2040,6 +1583,15 @@ sanitize_control_message(const char *src, struct gc_arena *gc)
skip = 4;
redact = true;
}
+ else if (!check_debug_level(D_SHOW_KEYS)
+ && (c == 'a' && !strncmp(src, "auth-token ", 11)))
+ {
+ /* Unless --verb is 7 or higher (D_SHOW_KEYS), hide
+ * the auth-token value coming in the src string
+ */
+ skip = 10;
+ redact = true;
+ }
if (c == ',') /* end of redacted item? */
{
@@ -2084,3 +1636,59 @@ compat_flag (unsigned int flag)
return (compat_flags & (flag >> 1));
}
+
+#if P2MP_SERVER
+
+/* helper to parse peer_info received from multi client, validate
+ * (this is untrusted data) and put into environment
+ */
+bool
+validate_peer_info_line(char *line)
+{
+ uint8_t c;
+ int state = 0;
+ while (*line)
+ {
+ c = *line;
+ switch (state)
+ {
+ case 0:
+ case 1:
+ if (c == '=' && state == 1)
+ state = 2;
+ else if (isalnum(c) || c == '_')
+ state = 1;
+ else
+ return false;
+ case 2:
+ /* after the '=', replace non-printable or shell meta with '_' */
+ if (!isprint(c) || isspace(c) ||
+ c == '$' || c == '(' || c == '`' )
+ *line = '_';
+ }
+ line++;
+ }
+ return (state == 2);
+}
+
+void
+output_peer_info_env (struct env_set *es, const char * peer_info)
+{
+ char line[256];
+ struct buffer buf;
+ buf_set_read (&buf, (const uint8_t *) peer_info, strlen(peer_info));
+ while (buf_parse (&buf, '\n', line, sizeof (line)))
+ {
+ chomp (line);
+ if (validate_peer_info_line(line) &&
+ (strncmp(line, "IV_", 3) == 0 || strncmp(line, "UV_", 3) == 0) )
+ {
+ msg (M_INFO, "peer info: %s", line);
+ env_set_add(es, line);
+ }
+ else
+ msg (M_WARN, "validation failed on peer_info line received from client");
+ }
+}
+
+#endif /* P2MP_SERVER */
diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h
index c1942b6..b8bbaa7 100644
--- a/src/openvpn/misc.h
+++ b/src/openvpn/misc.h
@@ -25,6 +25,7 @@
#ifndef MISC_H
#define MISC_H
+#include "argv.h"
#include "basic.h"
#include "common.h"
#include "integer.h"
@@ -37,14 +38,6 @@
/* forward declarations */
struct plugin_list;
-/* used by argv_x functions */
-struct argv {
- size_t capacity;
- size_t argc;
- char **argv;
- char *system_str;
-};
-
/*
* Handle environmental variable lists
*/
@@ -63,7 +56,7 @@ void run_up_down (const char *command,
const struct plugin_list *plugins,
int plugin_type,
const char *arg,
-#ifdef WIN32
+#ifdef _WIN32
DWORD adapter_index,
#endif
const char *dev_type,
@@ -78,9 +71,6 @@ void run_up_down (const char *command,
void write_pid (const char *filename);
-/* check file protections */
-void warn_if_group_others_accessible(const char* filename);
-
/* system flags */
#define S_SCRIPT (1<<0)
#define S_FATAL (1<<1)
@@ -136,6 +126,12 @@ void setenv_str (struct env_set *es, const char *name, const char *value);
void setenv_str_safe (struct env_set *es, const char *name, const char *value);
void setenv_del (struct env_set *es, const char *name);
+/**
+ * Store the supplied name value pair in the env_set. If the variable with the
+ * supplied name already exists, append _N to the name, starting at N=1.
+ */
+void setenv_str_incr(struct env_set *es, const char *name, const char *value);
+
void setenv_int_i (struct env_set *es, const char *name, const int value, const int i);
void setenv_str_i (struct env_set *es, const char *name, const char *value, const int i);
@@ -145,6 +141,7 @@ struct env_set *env_set_create (struct gc_arena *gc);
void env_set_destroy (struct env_set *es);
bool env_set_del (struct env_set *es, const char *str);
void env_set_add (struct env_set *es, const char *str);
+const char* env_set_get (const struct env_set *es, const char *name);
void env_set_print (int msglevel, const struct env_set *es);
@@ -162,10 +159,6 @@ const char **make_env_array (const struct env_set *es,
const char **make_arg_array (const char *first, const char *parms, struct gc_arena *gc);
const char **make_extended_arg_array (char **p, struct gc_arena *gc);
-/* convert netmasks for iproute2 */
-int count_netmask_bits(const char *);
-unsigned int count_bits(unsigned int );
-
/* an analogue to the random() function, but use OpenSSL functions if available */
#ifdef ENABLE_CRYPTO
long int get_random(void);
@@ -253,6 +246,8 @@ struct static_challenge_info {};
#define GET_USER_PASS_STATIC_CHALLENGE (1<<8) /* SCRV1 protocol -- static challenge */
#define GET_USER_PASS_STATIC_CHALLENGE_ECHO (1<<9) /* SCRV1 protocol -- echo response */
+#define GET_USER_PASS_INLINE_CREDS (1<<10) /* indicates that auth_file is actually inline creds */
+
bool get_user_pass_cr (struct user_pass *up,
const char *auth_file,
const char *prefix,
@@ -320,49 +315,17 @@ extern int script_security; /* GLOBAL */
/* return the next largest power of 2 */
size_t adjust_power_of_2 (size_t u);
-/*
- * A printf-like function (that only recognizes a subset of standard printf
- * format operators) that prints arguments to an argv list instead
- * of a standard string. This is used to build up argv arrays for passing
- * to execve.
- */
-void argv_init (struct argv *a);
-struct argv argv_new (void);
-void argv_reset (struct argv *a);
-char *argv_term (const char **f);
-const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags);
-struct argv argv_insert_head (const struct argv *a, const char *head);
-void argv_msg (const int msglev, const struct argv *a);
-void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix);
-const char *argv_system_str (const struct argv *a);
-
-#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */
-void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist);
-
-void argv_printf (struct argv *a, const char *format, ...)
-#ifdef __GNUC__
-#if __USE_MINGW_ANSI_STDIO
- __attribute__ ((format (gnu_printf, 2, 3)))
-#else
- __attribute__ ((format (__printf__, 2, 3)))
-#endif
-#endif
- ;
-
-void argv_printf_cat (struct argv *a, const char *format, ...)
-#ifdef __GNUC__
-#if __USE_MINGW_ANSI_STDIO
- __attribute__ ((format (gnu_printf, 2, 3)))
-#else
- __attribute__ ((format (__printf__, 2, 3)))
-#endif
-#endif
- ;
-
#define COMPAT_FLAG_QUERY 0 /** compat_flags operator: Query for a flag */
#define COMPAT_FLAG_SET (1<<0) /** compat_flags operator: Set a compat flag */
#define COMPAT_NAMES (1<<1) /** compat flag: --compat-names set */
#define COMPAT_NO_NAME_REMAPPING (1<<2) /** compat flag: --compat-names without char remapping */
bool compat_flag (unsigned int flag);
+#if P2MP_SERVER
+/* helper to parse peer_info received from multi client, validate
+ * (this is untrusted data) and put into environment */
+bool validate_peer_info_line(char *line);
+void output_peer_info_env (struct env_set *es, const char * peer_info);
+#endif /* P2MP_SERVER */
+
#endif
diff --git a/src/openvpn/mroute.c b/src/openvpn/mroute.c
index 850e336..c905af7 100644
--- a/src/openvpn/mroute.c
+++ b/src/openvpn/mroute.c
@@ -58,7 +58,8 @@ is_mac_mcast_addr (const uint8_t *mac)
static inline bool
is_mac_mcast_maddr (const struct mroute_addr *addr)
{
- return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER && is_mac_mcast_addr (addr->addr);
+ return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER &&
+ is_mac_mcast_addr (addr->eth_addr);
}
/*
@@ -73,7 +74,7 @@ mroute_learnable_address (const struct mroute_addr *addr)
for (i = 0; i < addr->len; ++i)
{
- int b = addr->addr[i];
+ int b = addr->raw_addr[i];
if (b != 0x00)
not_all_zeros = true;
if (b != 0xFF)
@@ -90,7 +91,7 @@ mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int
ma->type = MR_ADDR_IPV4 | mask;
ma->netbits = 0;
ma->len = 4;
- *(in_addr_t*)ma->addr = src;
+ ma->v4.addr = src;
}
}
@@ -102,7 +103,7 @@ mroute_get_in6_addr (struct mroute_addr *ma, const struct in6_addr src, unsigned
ma->type = MR_ADDR_IPV6 | mask;
ma->netbits = 0;
ma->len = 16;
- *(struct in6_addr *)ma->addr = src;
+ ma->v6.addr = src;
}
}
@@ -226,14 +227,14 @@ mroute_extract_addr_ether (struct mroute_addr *src,
src->type = MR_ADDR_ETHER;
src->netbits = 0;
src->len = 6;
- memcpy (src->addr, eth->source, 6);
+ memcpy (src->eth_addr, eth->source, sizeof(dest->eth_addr));
}
if (dest)
{
dest->type = MR_ADDR_ETHER;
dest->netbits = 0;
dest->len = 6;
- memcpy (dest->addr, eth->dest, 6);
+ memcpy (dest->eth_addr, eth->dest, sizeof(dest->eth_addr));
/* ethernet broadcast/multicast packet? */
if (is_mac_mcast_addr (eth->dest))
@@ -281,15 +282,15 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
addr->type = MR_ADDR_IPV4 | MR_WITH_PORT;
addr->netbits = 0;
addr->len = 6;
- memcpy (addr->addr, &osaddr->addr.in4.sin_addr.s_addr, 4);
- memcpy (addr->addr + 4, &osaddr->addr.in4.sin_port, 2);
+ addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr;
+ addr->v4.port = osaddr->addr.in4.sin_port;
}
else
{
addr->type = MR_ADDR_IPV4;
addr->netbits = 0;
addr->len = 4;
- memcpy (addr->addr, &osaddr->addr.in4.sin_addr.s_addr, 4);
+ addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr;
}
return true;
}
@@ -299,15 +300,15 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
addr->type = MR_ADDR_IPV6 | MR_WITH_PORT;
addr->netbits = 0;
addr->len = 18;
- memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16);
- memcpy (addr->addr + 16, &osaddr->addr.in6.sin6_port, 2);
+ addr->v6.addr = osaddr->addr.in6.sin6_addr;
+ addr->v6.port = osaddr->addr.in6.sin6_port;
}
else
{
addr->type = MR_ADDR_IPV6;
addr->netbits = 0;
addr->len = 16;
- memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16);
+ addr->v6.addr = osaddr->addr.in6.sin6_addr;
}
return true;
}
@@ -326,23 +327,29 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
void
mroute_addr_mask_host_bits (struct mroute_addr *ma)
{
- in_addr_t addr = ntohl(*(in_addr_t*)ma->addr);
if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4)
{
+ in_addr_t addr = ntohl (ma->v4.addr);
addr &= netbits_to_netmask (ma->netbits);
- *(in_addr_t*)ma->addr = htonl (addr);
+ ma->v4.addr = htonl (addr);
}
else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6)
{
- int byte = ma->len-1; /* rightmost byte in address */
+ int byte = sizeof (ma->v6.addr) - 1; /* rightmost byte in address */
int bits_to_clear = 128 - ma->netbits;
while( byte >= 0 && bits_to_clear > 0 )
{
if ( bits_to_clear >= 8 )
- { ma->addr[byte--] = 0; bits_to_clear -= 8; }
+ {
+ ma->v6.addr.s6_addr[byte--] = 0;
+ bits_to_clear -= 8;
+ }
else
- { ma->addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear); bits_to_clear = 0; }
+ {
+ ma->v6.addr.s6_addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear);
+ bits_to_clear = 0;
+ }
}
ASSERT( bits_to_clear == 0 );
}
@@ -390,44 +397,42 @@ mroute_addr_print_ex (const struct mroute_addr *ma,
switch (maddr.type & MR_ADDR_MASK)
{
case MR_ADDR_ETHER:
- buf_printf (&out, "%s", format_hex_ex (ma->addr, 6, 0, 1, ":", gc));
+ buf_printf (&out, "%s", format_hex_ex (ma->eth_addr,
+ sizeof(ma->eth_addr), 0, 1, ":", gc));
break;
case MR_ADDR_IPV4:
{
- struct buffer buf;
- in_addr_t addr;
- int port;
- bool status;
- buf_set_read (&buf, maddr.addr, maddr.len);
- addr = buf_read_u32 (&buf, &status);
- if (status)
+ if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP))
+ buf_printf (&out, "ARP/");
+ buf_printf (&out, "%s", print_in_addr_t (ntohl (maddr.v4.addr),
+ (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc));
+ if (maddr.type & MR_WITH_NETBITS)
{
- if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP))
- buf_printf (&out, "ARP/");
- buf_printf (&out, "%s", print_in_addr_t (addr, (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc));
- if (maddr.type & MR_WITH_NETBITS)
+ if (flags & MAPF_SUBNET)
{
- if (flags & MAPF_SUBNET)
- {
- const in_addr_t netmask = netbits_to_netmask (maddr.netbits);
- buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc));
- }
- else
- buf_printf (&out, "/%d", maddr.netbits);
+ const in_addr_t netmask = netbits_to_netmask (maddr.netbits);
+ buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc));
}
+ else
+ buf_printf (&out, "/%d", maddr.netbits);
}
if (maddr.type & MR_WITH_PORT)
{
- port = buf_read_u16 (&buf);
- if (port >= 0)
- buf_printf (&out, ":%d", port);
+ buf_printf (&out, ":%d", ntohs (maddr.v4.port));
}
}
break;
case MR_ADDR_IPV6:
{
- buf_printf (&out, "%s",
- print_in6_addr( *(struct in6_addr*)&maddr.addr, 0, gc));
+ if ( IN6_IS_ADDR_V4MAPPED( &maddr.v6.addr ) )
+ {
+ buf_printf (&out, "%s", print_in_addr_t (maddr.v4mappedv6.addr,
+ IA_NET_ORDER, gc));
+ }
+ else
+ {
+ buf_printf (&out, "%s", print_in6_addr (maddr.v6.addr, 0, gc));
+ }
if (maddr.type & MR_WITH_NETBITS)
{
buf_printf (&out, "/%d", maddr.netbits);
@@ -487,62 +492,28 @@ mroute_helper_regenerate (struct mroute_helper *mh)
}
void
-mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir)
-{
- if (ir->netbits >= 0)
- {
- ASSERT (ir->netbits < MR_HELPER_NET_LEN);
- ++mh->cache_generation;
- ++mh->net_len_refcount[ir->netbits];
- if (mh->net_len_refcount[ir->netbits] == 1)
- mroute_helper_regenerate (mh);
- }
-}
-
-void
-mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir)
-{
- if (ir->netbits >= 0)
- {
- ASSERT (ir->netbits < MR_HELPER_NET_LEN);
- ++mh->cache_generation;
- --mh->net_len_refcount[ir->netbits];
- ASSERT (mh->net_len_refcount[ir->netbits] >= 0);
- if (!mh->net_len_refcount[ir->netbits])
- mroute_helper_regenerate (mh);
- }
-}
-
-/* this is a bit inelegant, we really should have a helper to that
- * is only passed the netbits value, and not the whole struct iroute *
- * - thus one helper could do IPv4 and IPv6. For the sake of "not change
- * code unrelated to IPv4" this is left for later cleanup, for now.
- */
-void
-mroute_helper_add_iroute6 (struct mroute_helper *mh,
- const struct iroute_ipv6 *ir6)
+mroute_helper_add_iroute46 (struct mroute_helper *mh, int netbits)
{
- if (ir6->netbits >= 0)
+ if (netbits >= 0)
{
- ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
+ ASSERT (netbits < MR_HELPER_NET_LEN);
++mh->cache_generation;
- ++mh->net_len_refcount[ir6->netbits];
- if (mh->net_len_refcount[ir6->netbits] == 1)
+ ++mh->net_len_refcount[netbits];
+ if (mh->net_len_refcount[netbits] == 1)
mroute_helper_regenerate (mh);
}
}
void
-mroute_helper_del_iroute6 (struct mroute_helper *mh,
- const struct iroute_ipv6 *ir6)
+mroute_helper_del_iroute46 (struct mroute_helper *mh, int netbits)
{
- if (ir6->netbits >= 0)
+ if (netbits >= 0)
{
- ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
+ ASSERT (netbits < MR_HELPER_NET_LEN);
++mh->cache_generation;
- --mh->net_len_refcount[ir6->netbits];
- ASSERT (mh->net_len_refcount[ir6->netbits] >= 0);
- if (!mh->net_len_refcount[ir6->netbits])
+ --mh->net_len_refcount[netbits];
+ ASSERT (mh->net_len_refcount[netbits] >= 0);
+ if (!mh->net_len_refcount[netbits])
mroute_helper_regenerate (mh);
}
}
diff --git a/src/openvpn/mroute.h b/src/openvpn/mroute.h
index b72b5ff..8f7a064 100644
--- a/src/openvpn/mroute.h
+++ b/src/openvpn/mroute.h
@@ -31,6 +31,8 @@
#include "list.h"
#include "route.h"
+#include <stddef.h>
+
#define IP_MCAST_SUBNET_MASK ((in_addr_t)240<<24)
#define IP_MCAST_NETWORK ((in_addr_t)224<<24)
@@ -79,9 +81,45 @@ struct mroute_addr {
uint8_t type; /* MR_ADDR/MR_WITH flags */
uint8_t netbits; /* number of bits in network part of address,
valid if MR_WITH_NETBITS is set */
- uint8_t addr[MR_MAX_ADDR_LEN]; /* actual address */
+ union {
+ uint8_t raw_addr[MR_MAX_ADDR_LEN]; /* actual address */
+ uint8_t eth_addr[OPENVPN_ETH_ALEN];
+ struct {
+ in_addr_t addr; /* _network order_ IPv4 address */
+ in_port_t port; /* _network order_ TCP/UDP port */
+ } v4;
+ struct {
+ struct in6_addr addr;
+ in_port_t port; /* _network order_ TCP/UDP port */
+ } v6;
+ struct {
+ uint8_t prefix[12];
+ in_addr_t addr; /* _network order_ IPv4 address */
+ } v4mappedv6;
+ }
+#ifndef HAVE_ANONYMOUS_UNION_SUPPORT
+/* Wrappers to support compilers that do not grok anonymous unions */
+ mroute_union
+#define raw_addr mroute_union.raw_addr
+#define eth_addr mroute_union.eth_addr
+#define v4 mroute_union.v4
+#define v6 mroute_union.v6
+#define v4mappedv6 mroute_union.v4mappedv6
+#endif
+ ;
};
+/* Double-check that struct packing works as expected */
+static_assert (offsetof(struct mroute_addr, v4.port) ==
+ offsetof(struct mroute_addr, v4) + 4,
+ "Unexpected struct packing of v4");
+static_assert (offsetof(struct mroute_addr, v6.port) ==
+ offsetof(struct mroute_addr, v6) + 16,
+ "Unexpected struct packing of v6");
+static_assert (offsetof(struct mroute_addr, v4mappedv6.addr) ==
+ offsetof(struct mroute_addr, v4mappedv6) + 12,
+ "Unexpected struct packing of v4mappedv6");
+
/*
* Number of bits in an address. Should be raised for IPv6.
*/
@@ -125,10 +163,8 @@ void mroute_addr_mask_host_bits (struct mroute_addr *ma);
struct mroute_helper *mroute_helper_init (int ageable_ttl_secs);
void mroute_helper_free (struct mroute_helper *mh);
-void mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir);
-void mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir);
-void mroute_helper_add_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6);
-void mroute_helper_del_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6);
+void mroute_helper_add_iroute46 (struct mroute_helper *mh, int netbits);
+void mroute_helper_del_iroute46 (struct mroute_helper *mh, int netbits);
/*
* Given a raw packet in buf, return the src and dest
@@ -169,7 +205,7 @@ mroute_addr_equal (const struct mroute_addr *a1, const struct mroute_addr *a2)
return false;
if (a1->len != a2->len)
return false;
- return memcmp (a1->addr, a2->addr, a1->len) == 0;
+ return memcmp (a1->raw_addr, a2->raw_addr, a1->len) == 0;
}
static inline const uint8_t *
@@ -191,16 +227,17 @@ mroute_extract_in_addr_t (struct mroute_addr *dest, const in_addr_t src)
dest->type = MR_ADDR_IPV4;
dest->netbits = 0;
dest->len = 4;
- *(in_addr_t*)dest->addr = htonl (src);
+ dest->v4.addr = htonl (src);
}
static inline in_addr_t
in_addr_t_from_mroute_addr (const struct mroute_addr *addr)
{
- if ((addr->type & MR_ADDR_MASK) == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4)
- return ntohl(*(in_addr_t*)addr->addr);
- else
+ if ((addr->type & MR_ADDR_MASK) == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4) {
+ return ntohl(addr->v4.addr);
+ } else {
return 0;
+ }
}
static inline void
diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c
index dc15f09..78e5ccd 100644
--- a/src/openvpn/mtcp.c
+++ b/src/openvpn/mtcp.c
@@ -37,6 +37,10 @@
#include "memdbg.h"
+#ifdef HAVE_SYS_INOTIFY_H
+#include <sys/inotify.h>
+#endif
+
/*
* TCP States
*/
@@ -62,6 +66,10 @@
# define MTCP_MANAGEMENT ((void*)4)
#endif
+#ifdef ENABLE_ASYNC_PUSH
+#define MTCP_FILE_CLOSE_WRITE ((void*)5)
+#endif
+
#define MTCP_N ((void*)16) /* upper bound on MTCP_x */
struct ta_iow_flags
@@ -245,6 +253,12 @@ multi_tcp_wait (const struct context *c,
if (management)
management_socket_set (management, mtcp->es, MTCP_MANAGEMENT, &mtcp->management_persist_flags);
#endif
+
+#ifdef ENABLE_ASYNC_PUSH
+ /* arm inotify watcher */
+ event_ctl (mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE);
+#endif
+
status = event_wait (mtcp->es, &c->c2.timeval, mtcp->esr, mtcp->maxevents);
update_time ();
mtcp->n_esr = 0;
@@ -636,6 +650,12 @@ multi_tcp_process_io (struct multi_context *m)
{
get_signal (&m->top.sig->signal_received);
}
+#ifdef ENABLE_ASYNC_PUSH
+ else if (e->arg == MTCP_FILE_CLOSE_WRITE)
+ {
+ multi_process_file_closed (m, MPP_PRE_SELECT | MPP_RECORD_TOUCH);
+ }
+#endif
}
if (IS_SIG (&m->top))
break;
@@ -676,7 +696,7 @@ tunnel_server_tcp (struct context *top)
multi_init (&multi, top, true, MC_SINGLE_THREADED);
/* initialize our cloned top object */
- multi_top_init (&multi, top, true);
+ multi_top_init (&multi, top);
/* initialize management interface */
init_management_callback_multi (&multi);
@@ -684,6 +704,14 @@ tunnel_server_tcp (struct context *top)
/* finished with initialization */
initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto tcp-server */
+#ifdef ENABLE_ASYNC_PUSH
+ multi.top.c2.inotify_fd = inotify_init();
+ if (multi.top.c2.inotify_fd < 0)
+ {
+ msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno));
+ }
+#endif
+
/* per-packet event loop */
while (true)
{
@@ -712,6 +740,10 @@ tunnel_server_tcp (struct context *top)
perf_pop ();
}
+#ifdef ENABLE_ASYNC_PUSH
+ close(top->c2.inotify_fd);
+#endif
+
/* shut down management interface */
uninit_management_callback_multi (&multi);
diff --git a/src/openvpn/mtu.c b/src/openvpn/mtu.c
index 13f3f6c..8cbaa86 100644
--- a/src/openvpn/mtu.c
+++ b/src/openvpn/mtu.c
@@ -35,6 +35,7 @@
#include "error.h"
#include "integer.h"
#include "mtu.h"
+#include "options.h"
#include "memdbg.h"
@@ -78,8 +79,6 @@ frame_finalize (struct frame *frame,
}
frame->link_mtu_dynamic = frame->link_mtu;
-
- frame->extra_buffer += PAYLOAD_ALIGN;
}
/*
@@ -127,6 +126,15 @@ frame_subtract_extra (struct frame *frame, const struct frame *src)
}
void
+frame_init_mssfix (struct frame *frame, const struct options *options)
+{
+ if (options->ce.mssfix)
+ {
+ frame_set_mtu_dynamic (frame, options->ce.mssfix, SET_MTU_UPPER_BOUND);
+ }
+}
+
+void
frame_print (const struct frame *frame,
int level,
const char *prefix)
@@ -153,18 +161,32 @@ frame_print (const struct frame *frame,
#define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS"
void
-set_mtu_discover_type (int sd, int mtu_type)
+set_mtu_discover_type (int sd, int mtu_type, sa_family_t proto_af)
{
if (mtu_type >= 0)
{
-#if defined(HAVE_SETSOCKOPT) && defined(SOL_IP) && defined(IP_MTU_DISCOVER)
- if (setsockopt
- (sd, SOL_IP, IP_MTU_DISCOVER, &mtu_type, sizeof (mtu_type)))
- msg (M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket",
- mtu_type);
-#else
- msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG);
+ switch (proto_af)
+ {
+#if defined(HAVE_SETSOCKOPT) && defined(IP_MTU_DISCOVER)
+ case AF_INET:
+ if (setsockopt
+ (sd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu_type, sizeof (mtu_type)))
+ msg (M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket",
+ mtu_type);
+ break;
+#endif
+#if defined(HAVE_SETSOCKOPT) && defined(IPV6_MTU_DISCOVER)
+ case AF_INET6:
+ if (setsockopt
+ (sd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &mtu_type, sizeof (mtu_type)))
+ msg (M_ERR, "Error setting IPV6_MTU_DISCOVER type=%d on TCP6/UDP6 socket",
+ mtu_type);
+ break;
#endif
+ default:
+ msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG);
+ break;
+ }
}
}
@@ -288,7 +310,7 @@ void
set_sock_extended_error_passing (int sd)
{
int on = 1;
- if (setsockopt (sd, SOL_IP, IP_RECVERR, &on, sizeof (on)))
+ if (setsockopt (sd, SOL_IP, IP_RECVERR, (void *) &on, sizeof (on)))
msg (M_WARN | M_ERRNO,
"Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)");
}
diff --git a/src/openvpn/mtu.h b/src/openvpn/mtu.h
index bccd681..0320545 100644
--- a/src/openvpn/mtu.h
+++ b/src/openvpn/mtu.h
@@ -135,6 +135,9 @@ struct frame {
int align_adjust;
};
+/* Forward declarations, to prevent includes */
+struct options;
+
/* Routines which read struct frame should use the macros below */
/*
@@ -207,7 +210,7 @@ void frame_print (const struct frame *frame,
int level,
const char *prefix);
-void set_mtu_discover_type (int sd, int mtu_type);
+void set_mtu_discover_type (int sd, int mtu_type, sa_family_t proto_af);
int translate_mtu_discover_type_name (const char *name);
/*
@@ -227,6 +230,9 @@ void alloc_buf_sock_tun (struct buffer *buf,
const bool tuntap_buffer,
const unsigned int align_mask);
+/** Set the --mssfix option. */
+void frame_init_mssfix (struct frame *frame, const struct options *options);
+
/*
* EXTENDED_SOCKET_ERROR_CAPABILITY functions -- print extra error info
* on socket errors, such as PMTU size. As of 2003.05.11, only works
diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c
index 3468dab..fec5e8d 100644
--- a/src/openvpn/mudp.c
+++ b/src/openvpn/mudp.c
@@ -33,10 +33,15 @@
#if P2MP_SERVER
#include "multi.h"
+#include <inttypes.h>
#include "forward-inline.h"
#include "memdbg.h"
+#ifdef HAVE_SYS_INOTIFY_H
+#include <sys/inotify.h>
+#endif
+
/*
* Get a client instance based on real address. If
* the instance doesn't exist, create it while
@@ -44,26 +49,54 @@
*/
struct multi_instance *
-multi_get_create_instance_udp (struct multi_context *m)
+multi_get_create_instance_udp (struct multi_context *m, bool *floated)
{
struct gc_arena gc = gc_new ();
struct mroute_addr real;
struct multi_instance *mi = NULL;
struct hash *hash = m->hash;
- if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true))
+ if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true) &&
+ m->top.c2.buf.len > 0)
{
struct hash_element *he;
const uint32_t hv = hash_value (hash, &real);
struct hash_bucket *bucket = hash_bucket (hash, hv);
-
- he = hash_lookup_fast (hash, bucket, &real, hv);
+ uint8_t* ptr = BPTR(&m->top.c2.buf);
+ uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
+ bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3));
+ bool peer_id_disabled = false;
- if (he)
+ /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */
+ if (v2)
{
- mi = (struct multi_instance *) he->value;
+ uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF;
+ peer_id_disabled = (peer_id == MAX_PEER_ID);
+
+ if (!peer_id_disabled && (peer_id < m->max_clients) && (m->instances[peer_id]))
+ {
+ mi = m->instances[peer_id];
+
+ *floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from);
+
+ if (*floated)
+ {
+ /* reset prefix, since here we are not sure peer is the one it claims to be */
+ ungenerate_prefix(mi);
+ msg (D_MULTI_MEDIUM, "Float requested for peer %" PRIu32 " to %s", peer_id,
+ mroute_addr_print (&real, &gc));
+ }
+ }
}
- else
+ if (!v2 || peer_id_disabled)
+ {
+ he = hash_lookup_fast (hash, bucket, &real, hv);
+ if (he)
+ {
+ mi = (struct multi_instance *) he->value;
+ }
+ }
+ if (!mi)
{
if (!m->top.c2.tls_auth_standalone
|| tls_pre_decrypt_lite (m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf))
@@ -73,8 +106,27 @@ multi_get_create_instance_udp (struct multi_context *m)
mi = multi_create_instance (m, &real);
if (mi)
{
+ int i;
+
hash_add_fast (hash, bucket, &mi->real, hv, mi);
mi->did_real_hash = true;
+
+ /* max_clients must be less then max peer-id value */
+ ASSERT(m->max_clients < MAX_PEER_ID);
+
+ for (i = 0; i < m->max_clients; ++i)
+ {
+ if (!m->instances[i])
+ {
+ mi->context.c2.tls_multi->peer_id = i;
+ m->instances[i] = mi;
+ break;
+ }
+ }
+
+ /* should not really end up here, since multi_create_instance returns null
+ * if amount of clients exceeds max_clients */
+ ASSERT(i < m->max_clients);
}
}
else
@@ -89,15 +141,8 @@ multi_get_create_instance_udp (struct multi_context *m)
#ifdef ENABLE_DEBUG
if (check_debug_level (D_MULTI_DEBUG))
{
- const char *status;
-
- if (he && mi)
- status = "[succeeded]";
- else if (!he && mi)
- status = "[created]";
- else
- status = "[failed]";
-
+ const char *status = mi ? "[ok]" : "[failed]";
+
dmsg (D_MULTI_DEBUG, "GET INST BY REAL: %s %s",
mroute_addr_print (&real, &gc),
status);
@@ -143,6 +188,10 @@ multi_process_io_udp (struct multi_context *m)
strcat (buf, "TR/");
else if (status & TUN_WRITE)
strcat (buf, "TW/");
+#ifdef ENABLE_ASYNC_PUSH
+ else if (status & FILE_CLOSED)
+ strcat (buf, "FC/");
+#endif
printf ("IO %s\n", buf);
#endif
@@ -168,7 +217,6 @@ multi_process_io_udp (struct multi_context *m)
else if (status & SOCKET_READ)
{
read_incoming_link (&m->top);
- multi_release_io_lock (m);
if (!IS_SIG (&m->top))
multi_process_incoming_link (m, NULL, mpp_flags);
}
@@ -176,10 +224,16 @@ multi_process_io_udp (struct multi_context *m)
else if (status & TUN_READ)
{
read_incoming_tun (&m->top);
- multi_release_io_lock (m);
if (!IS_SIG (&m->top))
multi_process_incoming_tun (m, mpp_flags);
}
+#ifdef ENABLE_ASYNC_PUSH
+ /* INOTIFY callback */
+ else if (status & FILE_CLOSED)
+ {
+ multi_process_file_closed(m, mpp_flags);
+ }
+#endif
}
/*
@@ -234,7 +288,7 @@ tunnel_server_udp_single_threaded (struct context *top)
multi_init (&multi, top, false, MC_SINGLE_THREADED);
/* initialize our cloned top object */
- multi_top_init (&multi, top, true);
+ multi_top_init (&multi, top);
/* initialize management interface */
init_management_callback_multi (&multi);
@@ -242,6 +296,14 @@ tunnel_server_udp_single_threaded (struct context *top)
/* finished with initialization */
initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto udp */
+#ifdef ENABLE_ASYNC_PUSH
+ multi.top.c2.inotify_fd = inotify_init();
+ if (multi.top.c2.inotify_fd < 0)
+ {
+ msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno));
+ }
+#endif
+
/* per-packet event loop */
while (true)
{
@@ -270,6 +332,10 @@ tunnel_server_udp_single_threaded (struct context *top)
perf_pop ();
}
+#ifdef ENABLE_ASYNC_PUSH
+ close(top->c2.inotify_fd);
+#endif
+
/* shut down management interface */
uninit_management_callback_multi (&multi);
diff --git a/src/openvpn/mudp.h b/src/openvpn/mudp.h
index 97f961b..1f15d9d 100644
--- a/src/openvpn/mudp.h
+++ b/src/openvpn/mudp.h
@@ -65,7 +65,7 @@ void tunnel_server_udp (struct context *top);
* packet's source address or if one was a newly created successfully.
* NULL if one did not yet exist and a new one was not created.
*/
-struct multi_instance *multi_get_create_instance_udp (struct multi_context *m);
+struct multi_instance *multi_get_create_instance_udp (struct multi_context *m, bool *floated);
#endif
#endif
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 577c5d3..8f3d34e 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -28,6 +28,11 @@
#include "config-msvc.h"
#endif
+#ifdef HAVE_SYS_INOTIFY_H
+#include <sys/inotify.h>
+#define INOTIFY_EVENT_BUFFER_SIZE 16384
+#endif
+
#include "syshead.h"
#if P2MP_SERVER
@@ -38,6 +43,8 @@
#include "otime.h"
#include "gremlin.h"
#include "mstats.h"
+#include "ssl_verify.h"
+#include <inttypes.h>
#include "memdbg.h"
@@ -119,10 +126,8 @@ learn_address_script (const struct multi_context *m,
{
struct argv argv = argv_new ();
setenv_str (es, "script_type", "learn-address");
- argv_printf (&argv, "%sc %s %s",
- m->top.options.learn_address_script,
- op,
- mroute_addr_print (addr, &gc));
+ argv_parse_cmd (&argv, m->top.options.learn_address_script);
+ argv_printf_cat (&argv, "%s %s", op, mroute_addr_print (addr, &gc));
if (mi)
argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false));
if (!openvpn_run_script (&argv, es, 0, "--learn-address"))
@@ -241,6 +246,23 @@ cid_compare_function (const void *key1, const void *key2)
#endif
+#ifdef ENABLE_ASYNC_PUSH
+static uint32_t
+/*
+ * inotify watcher descriptors are used as hash value
+ */
+int_hash_function (const void *key, uint32_t iv)
+{
+ return (unsigned long)key;
+}
+
+static bool
+int_compare_function (const void *key1, const void *key2)
+{
+ return (unsigned long)key1 == (unsigned long)key2;
+}
+#endif
+
/*
* Main initialization function, init multi_context object.
*/
@@ -302,6 +324,17 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
cid_compare_function);
#endif
+#ifdef ENABLE_ASYNC_PUSH
+ /*
+ * Mapping between inotify watch descriptors and
+ * multi_instances.
+ */
+ m->inotify_watchers = hash_init (t->options.real_hash_size,
+ get_random(),
+ int_hash_function,
+ int_compare_function);
+#endif
+
/*
* This is our scheduler, for time-based wakeup
* events.
@@ -372,6 +405,8 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
*/
m->max_clients = t->options.max_clients;
+ m->instances = calloc(m->max_clients, sizeof(struct multi_instance*));
+
/*
* Initialize multi-socket TCP I/O wait object
*/
@@ -392,6 +427,8 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time);
event_timeout_init (&m->stale_routes_check_et, t->options.stale_routes_check_interval, 0);
}
+
+ m->deferred_shutdown_signal.signal_received = 0;
}
const char *
@@ -399,7 +436,7 @@ multi_instance_string (const struct multi_instance *mi, bool null, struct gc_are
{
if (mi)
{
- struct buffer out = alloc_buf_gc (256, gc);
+ struct buffer out = alloc_buf_gc (MULTI_PREFIX_MAX_LENGTH, gc);
const char *cn = tls_common_name (mi->context.c2.tls_multi, true);
if (cn)
@@ -416,21 +453,27 @@ multi_instance_string (const struct multi_instance *mi, bool null, struct gc_are
void
generate_prefix (struct multi_instance *mi)
{
- mi->msg_prefix = multi_instance_string (mi, true, &mi->gc);
+ struct gc_arena gc = gc_new();
+ const char *prefix = multi_instance_string (mi, true, &gc);
+ if (prefix)
+ strncpynt(mi->msg_prefix, prefix, sizeof(mi->msg_prefix));
+ else
+ mi->msg_prefix[0] = '\0';
set_prefix (mi);
+ gc_free(&gc);
}
void
ungenerate_prefix (struct multi_instance *mi)
{
- mi->msg_prefix = NULL;
+ mi->msg_prefix[0] = '\0';
set_prefix (mi);
}
static const char *
mi_prefix (const struct multi_instance *mi)
{
- if (mi && mi->msg_prefix)
+ if (mi && mi->msg_prefix[0])
return mi->msg_prefix;
else
return "UNDEF_I";
@@ -450,10 +493,10 @@ multi_del_iroutes (struct multi_context *m,
if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN)
{
for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next)
- mroute_helper_del_iroute (m->route_helper, ir);
+ mroute_helper_del_iroute46 (m->route_helper, ir->netbits);
for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next )
- mroute_helper_del_iroute6 (m->route_helper, ir6);
+ mroute_helper_del_iroute46 (m->route_helper, ir6->netbits);
}
}
@@ -500,7 +543,7 @@ multi_client_disconnect_script (struct multi_context *m,
{
struct argv argv = argv_new ();
setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
- argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script);
+ argv_parse_cmd (&argv, mi->context.options.client_disconnect_script);
openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect");
argv_reset (&argv);
}
@@ -552,6 +595,17 @@ multi_close_instance (struct multi_context *m,
}
#endif
+#ifdef ENABLE_ASYNC_PUSH
+ if (mi->inotify_watch != -1)
+ {
+ hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch);
+ mi->inotify_watch = -1;
+ }
+#endif
+
+ if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID)
+ m->instances[mi->context.c2.tls_multi->peer_id] = NULL;
+
schedule_remove_entry (m->schedule, (struct schedule_entry *) mi);
ifconfig_pool_release (m->ifconfig_pool, mi->vaddr_handle, false);
@@ -628,6 +682,13 @@ multi_uninit (struct multi_context *m)
#endif
m->hash = NULL;
+ free(m->instances);
+
+#ifdef ENABLE_ASYNC_PUSH
+ hash_free (m->inotify_watchers);
+ m->inotify_watchers = NULL;
+#endif
+
schedule_free (m->schedule);
mbuf_free (m->mbuf);
ifconfig_pool_free (m->ifconfig_pool);
@@ -704,6 +765,11 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real)
mi->context.c2.push_reply_deferred = true;
+#ifdef ENABLE_ASYNC_PUSH
+ mi->context.c2.push_request_received = false;
+ mi->inotify_watch = -1;
+#endif
+
if (!multi_process_post (m, mi, MPP_PRE_SELECT))
{
msg (D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization");
@@ -807,8 +873,8 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
*/
status_printf (so, "TITLE%c%s", sep, title_string);
status_printf (so, "TIME%c%s%c%u", sep, time_string (now, 0, false, &gc_top), sep, (unsigned int)now);
- status_printf (so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername",
- sep, sep, sep, sep, sep, sep, sep, sep, sep);
+ status_printf (so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID%cPeer ID",
+ sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep);
hash_iterator_init (m->hash, &hi);
while ((he = hash_iterator_next (&hi)))
{
@@ -817,15 +883,28 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
if (!mi->halt)
{
- status_printf (so, "CLIENT_LIST%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s",
+ status_printf (so, "CLIENT_LIST%c%s%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s%c"
+#ifdef MANAGEMENT_DEF_AUTH
+ "%lu"
+#else
+ ""
+#endif
+ "%c%"PRIu32,
sep, tls_common_name (mi->context.c2.tls_multi, false),
sep, mroute_addr_print (&mi->real, &gc),
sep, print_in_addr_t (mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc),
+ sep, print_in6_addr (mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc),
sep, mi->context.c2.link_read_bytes,
sep, mi->context.c2.link_write_bytes,
sep, time_string (mi->created, 0, false, &gc),
sep, (unsigned int)mi->created,
- sep, tls_username (mi->context.c2.tls_multi, false));
+ sep, tls_username (mi->context.c2.tls_multi, false),
+#ifdef MANAGEMENT_DEF_AUTH
+ sep, mi->context.c2.mda_context.cid,
+#else
+ sep,
+#endif
+ sep, mi->context.c2.tls_multi ? mi->context.c2.tls_multi->peer_id : UINT32_MAX);
}
gc_free (&gc);
}
@@ -896,6 +975,13 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
status_flush (so);
gc_free (&gc_top);
}
+
+#ifdef ENABLE_ASYNC_PUSH
+ if (m->inotify_watchers)
+ {
+ msg (D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers));
+ }
+#endif
}
/*
@@ -1113,7 +1199,7 @@ multi_learn_in6_addr (struct multi_context *m,
addr.len = 16;
addr.type = MR_ADDR_IPV6;
addr.netbits = 0;
- memcpy( &addr.addr, &a6, sizeof(a6) );
+ addr.v6.addr = a6;
if (netbits >= 0)
{
@@ -1158,23 +1244,18 @@ multi_add_iroutes (struct multi_context *m,
print_in_addr_t (ir->network, 0, &gc),
multi_instance_string (mi, false, &gc));
- mroute_helper_add_iroute (m->route_helper, ir);
+ mroute_helper_add_iroute46 (m->route_helper, ir->netbits);
multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false);
}
for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next )
{
- if (ir6->netbits >= 0)
- msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s",
+ msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s",
print_in6_addr (ir6->network, 0, &gc),
ir6->netbits,
multi_instance_string (mi, false, &gc));
- else
- msg (D_MULTI_LOW, "MULTI: internal route %s -> %s",
- print_in6_addr (ir6->network, 0, &gc),
- multi_instance_string (mi, false, &gc));
- mroute_helper_add_iroute6 (m->route_helper, ir6);
+ mroute_helper_add_iroute46 (m->route_helper, ir6->netbits);
multi_learn_in6_addr (m, mi, ir6->network, ir6->netbits, false);
}
@@ -1289,16 +1370,13 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
mi->context.c2.push_ifconfig_defined = true;
mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local;
mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask;
-#ifdef ENABLE_CLIENT_NAT
mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias;
-#endif
/* the current implementation does not allow "static IPv4, pool IPv6",
* (see below) so issue a warning if that happens - don't break the
* session, though, as we don't even know if this client WANTS IPv6
*/
- if ( mi->context.c1.tuntap->ipv6 &&
- mi->context.options.ifconfig_ipv6_pool_defined &&
+ if ( mi->context.options.ifconfig_ipv6_pool_defined &&
! mi->context.options.push_ifconfig_ipv6_defined )
{
msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." );
@@ -1351,10 +1429,10 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
if ( mi->context.options.ifconfig_ipv6_pool_defined )
{
mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6;
- mi->context.c2.push_ifconfig_ipv6_remote =
+ mi->context.c2.push_ifconfig_ipv6_remote =
mi->context.c1.tuntap->local_ipv6;
- mi->context.c2.push_ifconfig_ipv6_netbits =
- mi->context.options.ifconfig_ipv6_pool_netbits;
+ mi->context.c2.push_ifconfig_ipv6_netbits =
+ mi->context.options.ifconfig_ipv6_netbits;
mi->context.c2.push_ifconfig_ipv6_defined = true;
}
}
@@ -1371,8 +1449,7 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
* way round ("dynamic IPv4, static IPv6") or "both static" makes sense
* -> and so it's implemented right now
*/
- if ( mi->context.c1.tuntap->ipv6 &&
- mi->context.options.push_ifconfig_ipv6_defined )
+ if ( mi->context.options.push_ifconfig_ipv6_defined )
{
mi->context.c2.push_ifconfig_ipv6_local =
mi->context.options.push_ifconfig_ipv6_local;
@@ -1430,7 +1507,7 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi)
setenv_del (mi->context.c2.es, "ifconfig_pool_remote_ip6");
setenv_del (mi->context.c2.es, "ifconfig_pool_ip6_netbits");
- if (mi->context.c1.tuntap->ipv6 && mi->context.c2.push_ifconfig_ipv6_defined)
+ if (mi->context.c2.push_ifconfig_ipv6_defined)
{
setenv_in6_addr (mi->context.c2.es,
"ifconfig_pool_remote",
@@ -1755,9 +1832,8 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
goto script_failed;
}
- argv_printf (&argv, "%sc %s",
- mi->context.options.client_connect_script,
- dc_file);
+ argv_parse_cmd (&argv, mi->context.options.client_connect_script);
+ argv_printf_cat (&argv, "%s", dc_file);
if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect"))
{
@@ -1868,9 +1944,18 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
/* set our client's VPN endpoint for status reporting purposes */
mi->reporting_addr = mi->context.c2.push_ifconfig_local;
+ mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local;
/* set context-level authentication flag */
mi->context.c2.context_auth = CAS_SUCCEEDED;
+
+#ifdef ENABLE_ASYNC_PUSH
+ /* authentication complete, send push reply */
+ if (mi->context.c2.push_request_received)
+ {
+ process_incoming_push_request(&mi->context);
+ }
+#endif
}
else
{
@@ -1900,6 +1985,58 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
mi->context.c2.push_reply_deferred = false;
}
+#ifdef ENABLE_ASYNC_PUSH
+/*
+ * Called when inotify event is fired, which happens when acf file is closed or deleted.
+ * Continues authentication and sends push_reply.
+ */
+void
+multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags)
+{
+ char buffer[INOTIFY_EVENT_BUFFER_SIZE];
+ size_t buffer_i = 0;
+ int r = read (m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE);
+
+ while (buffer_i < r)
+ {
+ /* parse inotify events */
+ struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i];
+ size_t event_size = sizeof (struct inotify_event) + pevent->len;
+ buffer_i += event_size;
+
+ msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask);
+
+ struct multi_instance* mi = hash_lookup(m->inotify_watchers, (void*) (unsigned long) pevent->wd);
+
+ if (pevent->mask & IN_CLOSE_WRITE)
+ {
+ if (mi)
+ {
+ /* continue authentication and send push_reply */
+ multi_process_post (m, mi, mpp_flags);
+ }
+ else
+ {
+ msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!");
+ }
+ }
+ else if (pevent->mask & IN_IGNORED)
+ {
+ /* this event is _always_ fired when watch is removed or file is deleted */
+ if (mi)
+ {
+ hash_remove(m->inotify_watchers, (void*) (unsigned long) pevent->wd);
+ mi->inotify_watch = -1;
+ }
+ }
+ else
+ {
+ msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask);
+ }
+ }
+}
+#endif
+
/*
* Add a mbuf buffer to a particular
* instance.
@@ -2060,19 +2197,50 @@ multi_process_post (struct multi_context *m, struct multi_instance *mi, const un
if (!IS_SIG (&mi->context) && ((flags & MPP_PRE_SELECT) || ((flags & MPP_CONDITIONAL_PRE_SELECT) && !ANY_OUT (&mi->context))))
{
+#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH)
+ bool was_authenticated = false;
+ struct key_state *ks = NULL;
+ if (mi->context.c2.tls_multi)
+ {
+ ks = &mi->context.c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY];
+ was_authenticated = ks->authenticated;
+ }
+#endif
+
/* figure timeouts and fetch possible outgoing
to_link packets (such as ping or TLS control) */
pre_select (&mi->context);
- if (!IS_SIG (&mi->context))
+#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH)
+ if (ks && ks->auth_control_file && ks->auth_deferred && !was_authenticated)
{
- /* tell scheduler to wake us up at some point in the future */
- multi_schedule_context_wakeup(m, mi);
+ /* watch acf file */
+ long watch_descriptor = inotify_add_watch(m->top.c2.inotify_fd, ks->auth_control_file, IN_CLOSE_WRITE | IN_ONESHOT);
+ if (watch_descriptor >= 0)
+ {
+ if (mi->inotify_watch != -1)
+ {
+ hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch);
+ }
+ hash_add (m->inotify_watchers, (const uintptr_t*)watch_descriptor, mi, true);
+ mi->inotify_watch = watch_descriptor;
+ }
+ else
+ {
+ msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno));
+ }
+ }
+#endif
+ if (!IS_SIG (&mi->context))
+ {
/* connection is "established" when SSL/TLS key negotiation succeeds
and (if specified) auth user/pass succeeds */
if (!mi->connection_established_flag && CONNECTION_ESTABLISHED (&mi->context))
multi_connection_established (m, mi);
+
+ /* tell scheduler to wake us up at some point in the future */
+ multi_schedule_context_wakeup(m, mi);
}
}
@@ -2107,6 +2275,72 @@ multi_process_post (struct multi_context *m, struct multi_instance *mi, const un
return ret;
}
+void multi_process_float (struct multi_context* m, struct multi_instance* mi)
+{
+ struct mroute_addr real;
+ struct hash *hash = m->hash;
+ struct gc_arena gc = gc_new ();
+
+ if (!mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true))
+ goto done;
+
+ const uint32_t hv = hash_value (hash, &real);
+ struct hash_bucket *bucket = hash_bucket (hash, hv);
+
+ /* make sure that we don't float to an address taken by another client */
+ struct hash_element *he = hash_lookup_fast (hash, bucket, &real, hv);
+ if (he)
+ {
+ struct multi_instance *ex_mi = (struct multi_instance *) he->value;
+
+ struct tls_multi *m1 = mi->context.c2.tls_multi;
+ struct tls_multi *m2 = ex_mi->context.c2.tls_multi;
+
+ /* do not float if target address is taken by client with another cert */
+ if (!cert_hash_compare(m1->locked_cert_hash_set, m2->locked_cert_hash_set))
+ {
+ msg (D_MULTI_LOW, "Disallow float to an address taken by another client %s",
+ multi_instance_string (ex_mi, false, &gc));
+
+ mi->context.c2.buf.len = 0;
+
+ goto done;
+ }
+
+ msg (D_MULTI_MEDIUM, "closing instance %s", multi_instance_string (ex_mi, false, &gc));
+ multi_close_instance(m, ex_mi, false);
+ }
+
+ msg (D_MULTI_MEDIUM, "peer %" PRIu32 " (%s) floated from %s to %s",
+ mi->context.c2.tls_multi->peer_id,
+ tls_common_name (mi->context.c2.tls_multi, false),
+ mroute_addr_print (&mi->real, &gc),
+ print_link_socket_actual (&m->top.c2.from, &gc));
+
+ /* change external network address of the remote peer */
+ mi->real = real;
+ generate_prefix (mi);
+
+ mi->context.c2.from = m->top.c2.from;
+ mi->context.c2.to_link_addr = &mi->context.c2.from;
+
+ /* inherit parent link_socket and link_socket_info */
+ mi->context.c2.link_socket = m->top.c2.link_socket;
+ mi->context.c2.link_socket_info->lsa->actual = m->top.c2.from;
+
+ tls_update_remote_addr (mi->context.c2.tls_multi, &mi->context.c2.from);
+
+ ASSERT (hash_add (m->hash, &mi->real, mi, true));
+ ASSERT (hash_add (m->iter, &mi->real, mi, true));
+
+#ifdef MANAGEMENT_DEF_AUTH
+ ASSERT (hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, true));
+#endif
+
+done:
+ gc_free (&gc);
+}
+
/*
* Process packets in the TCP/UDP socket -> TUN/TAP interface direction,
* i.e. client -> server direction.
@@ -2121,6 +2355,7 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
unsigned int mroute_flags;
struct multi_instance *mi;
bool ret = true;
+ bool floated = false;
if (m->pending)
return true;
@@ -2130,7 +2365,7 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
#ifdef MULTI_DEBUG_EVENT_LOOP
printf ("TCP/UDP -> TUN [%d]\n", BLEN (&m->top.c2.buf));
#endif
- multi_set_pending (m, multi_get_create_instance_udp (m));
+ multi_set_pending (m, multi_get_create_instance_udp (m, &floated));
}
else
multi_set_pending (m, instance);
@@ -2148,13 +2383,30 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
c->c2.buf = m->top.c2.buf;
/* transfer from-addr from top-level context buffer to instance */
- c->c2.from = m->top.c2.from;
+ if (!floated)
+ c->c2.from = m->top.c2.from;
}
if (BLEN (&c->c2.buf) > 0)
{
+ struct link_socket_info *lsi;
+ const uint8_t *orig_buf;
+
/* decrypt in instance context */
- process_incoming_link (c);
+
+ perf_push (PERF_PROC_IN_LINK);
+ lsi = get_link_socket_info (c);
+ orig_buf = c->c2.buf.data;
+ if (process_incoming_link_part1(c, lsi, floated))
+ {
+ if (floated)
+ {
+ multi_process_float (m, m->pending);
+ }
+
+ process_incoming_link_part2(c, lsi, orig_buf);
+ }
+ perf_pop ();
if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TUN)
{
@@ -2176,7 +2428,7 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins
{
/* IPv6 link-local address (fe80::xxx)? */
if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 &&
- src.addr[0] == 0xfe && src.addr[1] == 0x80 )
+ IN6_IS_ADDR_LINKLOCAL (&src.v6.addr) )
{
/* do nothing, for now. TODO: add address learning */
}
@@ -2478,10 +2730,18 @@ multi_process_timeout (struct multi_context *m, const unsigned int mpp_flags)
/* instance marked for wakeup? */
if (m->earliest_wakeup)
{
- set_prefix (m->earliest_wakeup);
- ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+ if (m->earliest_wakeup == (struct multi_instance*)&m->deferred_shutdown_signal)
+ {
+ schedule_remove_entry(m->schedule, (struct schedule_entry*) &m->deferred_shutdown_signal);
+ throw_signal(m->deferred_shutdown_signal.signal_received);
+ }
+ else
+ {
+ set_prefix (m->earliest_wakeup);
+ ret = multi_process_post (m, m->earliest_wakeup, mpp_flags);
+ clear_prefix ();
+ }
m->earliest_wakeup = NULL;
- clear_prefix ();
}
return ret;
}
@@ -2591,12 +2851,10 @@ multi_process_per_second_timers_dowork (struct multi_context *m)
}
void
-multi_top_init (struct multi_context *m, const struct context *top, const bool alloc_buffers)
+multi_top_init (struct multi_context *m, const struct context *top)
{
inherit_context_top (&m->top, top);
- m->top.c2.buffers = NULL;
- if (alloc_buffers)
- m->top.c2.buffers = init_context_buffers (&top->c2.frame);
+ m->top.c2.buffers = init_context_buffers (&top->c2.frame);
}
void
@@ -2606,6 +2864,48 @@ multi_top_free (struct multi_context *m)
free_context_buffers (m->top.c2.buffers);
}
+static bool
+is_exit_restart(int sig)
+{
+ return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT);
+}
+
+static void
+multi_push_restart_schedule_exit(struct multi_context *m, bool next_server)
+{
+ struct hash_iterator hi;
+ struct hash_element *he;
+ struct timeval tv;
+
+ /* tell all clients to restart */
+ hash_iterator_init (m->iter, &hi);
+ while ((he = hash_iterator_next (&hi)))
+ {
+ struct multi_instance *mi = (struct multi_instance *) he->value;
+ if (!mi->halt)
+ {
+ send_control_channel_string (&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH);
+ multi_schedule_context_wakeup(m, mi);
+ }
+ }
+ hash_iterator_free (&hi);
+
+ /* reschedule signal */
+ ASSERT (!openvpn_gettimeofday (&m->deferred_shutdown_signal.wakeup, NULL));
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ tv_add (&m->deferred_shutdown_signal.wakeup, &tv);
+
+ m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received;
+
+ schedule_add_entry (m->schedule,
+ (struct schedule_entry *) &m->deferred_shutdown_signal,
+ &m->deferred_shutdown_signal.wakeup,
+ compute_wakeup_sigma (&m->deferred_shutdown_signal.wakeup));
+
+ m->top.sig->signal_received = 0;
+}
+
/*
* Return true if event loop should break,
* false if it should continue.
@@ -2621,6 +2921,14 @@ multi_process_signal (struct multi_context *m)
m->top.sig->signal_received = 0;
return false;
}
+ else if (proto_is_dgram(m->top.options.ce.proto) &&
+ is_exit_restart(m->top.sig->signal_received) &&
+ (m->deferred_shutdown_signal.signal_received == 0) &&
+ m->top.options.ce.explicit_exit_notification != 0)
+ {
+ multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2);
+ return false;
+ }
return true;
}
diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h
index 2bc0c8a..0d369f3 100644
--- a/src/openvpn/multi.h
+++ b/src/openvpn/multi.h
@@ -42,6 +42,8 @@
#include "mtcp.h"
#include "perf.h"
+#define MULTI_PREFIX_MAX_LENGTH 256
+
/*
* Walk (don't run) through the routing table,
* deleting old entries, and possibly multi_instance
@@ -55,6 +57,13 @@ struct multi_reap
};
+struct deferred_signal_schedule_entry
+{
+ struct schedule_entry se;
+ int signal_received;
+ struct timeval wakeup;
+};
+
/**
* Server-mode state structure for one single VPN tunnel.
*
@@ -80,7 +89,7 @@ struct multi_instance {
struct mroute_addr real; /**< External network address of the
* remote peer. */
ifconfig_pool_handle vaddr_handle;
- const char *msg_prefix;
+ char msg_prefix[MULTI_PREFIX_MAX_LENGTH];
/* queued outgoing data in Server/TCP mode */
unsigned int tcp_rwflags;
@@ -88,6 +97,7 @@ struct multi_instance {
bool socket_set_called;
in_addr_t reporting_addr; /* IP address shown in status listing */
+ struct in6_addr reporting_addr_ipv6; /* IPv6 address in status listing */
bool did_open_context;
bool did_real_hash;
@@ -102,6 +112,10 @@ struct multi_instance {
struct context context; /**< The context structure storing state
* for this VPN tunnel. */
+
+#ifdef ENABLE_ASYNC_PUSH
+ int inotify_watch; /* watch descriptor for acf */
+#endif
};
@@ -124,6 +138,9 @@ struct multi_context {
# define MC_WORK_THREAD (MC_MULTI_THREADED_WORKER|MC_MULTI_THREADED_SCHEDULER)
int thread_mode;
+ struct multi_instance** instances; /**< Array of multi_instances. An instance can be
+ * accessed using peer-id as an index. */
+
struct hash *hash; /**< VPN tunnel instances indexed by real
* address of the remote peer. */
struct hash *vhash; /**< VPN tunnel instances indexed by
@@ -166,6 +183,13 @@ struct multi_context {
* Timer object for stale route check
*/
struct event_timeout stale_routes_check_et;
+
+#ifdef ENABLE_ASYNC_PUSH
+ /* mapping between inotify watch descriptors and multi_instances */
+ struct hash *inotify_watchers;
+#endif
+
+ struct deferred_signal_schedule_entry deferred_shutdown_signal;
};
/*
@@ -209,7 +233,7 @@ const char *multi_instance_string (const struct multi_instance *mi, bool null, s
void multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode);
void multi_uninit (struct multi_context *m);
-void multi_top_init (struct multi_context *m, const struct context *top, const bool alloc_buffers);
+void multi_top_init (struct multi_context *m, const struct context *top);
void multi_top_free (struct multi_context *m);
struct multi_instance *multi_create_instance (struct multi_context *m, const struct mroute_addr *real);
@@ -217,6 +241,16 @@ void multi_close_instance (struct multi_context *m, struct multi_instance *mi, b
bool multi_process_timeout (struct multi_context *m, const unsigned int mpp_flags);
+/**
+ * Handles peer floating.
+ *
+ * If peer is floated to a taken address, either drops packet
+ * (if peer that owns address has different CN) or disconnects
+ * existing peer. Updates multi_instance with new address,
+ * updates hashtables in multi_context.
+ */
+void multi_process_float (struct multi_context* m, struct multi_instance* mi);
+
#define MPP_PRE_SELECT (1<<0)
#define MPP_CONDITIONAL_PRE_SELECT (1<<1)
#define MPP_CLOSE_ON_SIGNAL (1<<2)
@@ -311,6 +345,18 @@ void multi_close_instance_on_signal (struct multi_context *m, struct multi_insta
void init_management_callback_multi (struct multi_context *m);
void uninit_management_callback_multi (struct multi_context *m);
+
+#ifdef ENABLE_ASYNC_PUSH
+/**
+ * Called when inotify event is fired, which happens when acf file is closed or deleted.
+ * Continues authentication and sends push_repl
+ *
+ * @param m multi_context
+ * @param mpp_flags
+ */
+void multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags);
+#endif
+
/*
* Return true if our output queue is not full
*/
@@ -418,6 +464,12 @@ multi_route_defined (const struct multi_context *m,
}
/*
+ * Takes prefix away from multi_instance.
+ */
+void
+ungenerate_prefix (struct multi_instance *mi);
+
+/*
* Set a msg() function prefix with our current client instance ID.
*/
@@ -425,10 +477,10 @@ static inline void
set_prefix (struct multi_instance *mi)
{
#ifdef MULTI_DEBUG_EVENT_LOOP
- if (mi->msg_prefix)
+ if (mi->msg_prefix[0])
printf ("[%s]\n", mi->msg_prefix);
#endif
- msg_set_prefix (mi->msg_prefix);
+ msg_set_prefix (mi->msg_prefix[0] ? mi->msg_prefix : NULL);
}
static inline void
@@ -573,10 +625,5 @@ multi_set_pending (struct multi_context *m, struct multi_instance *mi)
m->pending = mi;
}
-static inline void
-multi_release_io_lock (struct multi_context *m)
-{
-}
-
#endif /* P2MP_SERVER */
#endif /* MULTI_H */
diff --git a/src/openvpn/occ.c b/src/openvpn/occ.c
index ff48706..d71381d 100644
--- a/src/openvpn/occ.c
+++ b/src/openvpn/occ.c
@@ -379,7 +379,7 @@ process_received_occ_msg (struct context *c)
&& c->c2.max_send_size_local > TUN_MTU_MIN
&& (c->c2.max_recv_size_remote < c->c2.max_send_size_local
|| c->c2.max_recv_size_local < c->c2.max_send_size_remote))
- msg (M_INFO, "NOTE: This connection is unable to accomodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.",
+ msg (M_INFO, "NOTE: This connection is unable to accommodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.",
c->c2.max_send_size_local);
}
event_timeout_clear (&c->c2.occ_mtu_load_test_interval);
diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c
index 823c3dd..5fb2fd9 100644
--- a/src/openvpn/openvpn.c
+++ b/src/openvpn/openvpn.c
@@ -138,7 +138,7 @@ openvpn_main (int argc, char *argv[])
return 1;
#endif
-#ifdef WIN32
+#ifdef _WIN32
SetConsoleOutputCP (CP_UTF8);
#endif
@@ -172,7 +172,7 @@ openvpn_main (int argc, char *argv[])
/* initialize environmental variable store */
c.es = env_set_create (NULL);
-#ifdef WIN32
+#ifdef _WIN32
set_win_sys_path_via_env (c.es);
#endif
@@ -220,7 +220,7 @@ openvpn_main (int argc, char *argv[])
/* print version number */
msg (M_INFO, "%s", title_string);
-#ifdef WIN32
+#ifdef _WIN32
show_windows_version(M_INFO);
#endif
show_library_versions(M_INFO);
@@ -312,7 +312,7 @@ openvpn_main (int argc, char *argv[])
return 0; /* NOTREACHED */
}
-#ifdef WIN32
+#ifdef _WIN32
int
wmain (int argc, wchar_t *wargv[]) {
char **argv;
diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
index 36c3100..fa5cc1d 100644
--- a/src/openvpn/openvpn.h
+++ b/src/openvpn/openvpn.h
@@ -31,7 +31,7 @@
#include "crypto.h"
#include "ssl.h"
#include "packet_id.h"
-#include "lzo.h"
+#include "comp.h"
#include "tun.h"
#include "interval.h"
#include "status.h"
@@ -62,14 +62,12 @@ struct key_schedule
/* pre-shared static key, read from a file */
struct key_ctx_bi static_key;
-#ifdef ENABLE_SSL
/* our global SSL context */
struct tls_root_ctx ssl_ctx;
- /* optional authentication HMAC key for TLS control channel */
- struct key_ctx_bi tls_auth_key;
-
-#endif /* ENABLE_SSL */
+ /* optional TLS control channel wrapping */
+ struct key_type tls_auth_key_type;
+ struct key_ctx_bi tls_wrap_key;
#else /* ENABLE_CRYPTO */
int dummy;
#endif /* ENABLE_CRYPTO */
@@ -104,10 +102,10 @@ struct context_buffers
struct buffer decrypt_buf;
#endif
- /* workspace buffers for LZO compression */
-#ifdef ENABLE_LZO
- struct buffer lzo_compress_buf;
- struct buffer lzo_decompress_buf;
+ /* workspace buffers for compression */
+#ifdef USE_COMP
+ struct buffer compress_buf;
+ struct buffer decompress_buf;
#endif
/*
@@ -165,6 +163,9 @@ struct context_1
/* tunnel session keys */
struct key_schedule ks;
+ /* preresolved and cached host names */
+ struct cached_dns_entry *dns_cache;
+
/* persist crypto sequence number to/from file */
struct packet_id_persist pid_persist;
@@ -184,17 +185,13 @@ struct context_1
struct status_output *status_output;
bool status_output_owned;
-#ifdef ENABLE_HTTP_PROXY
/* HTTP proxy object */
struct http_proxy_info *http_proxy;
bool http_proxy_owned;
-#endif
-#ifdef ENABLE_SOCKS
/* SOCKS proxy object */
struct socks_proxy_info *socks_proxy;
bool socks_proxy_owned;
-#endif
#if P2MP
@@ -213,6 +210,10 @@ struct context_1
struct user_pass *auth_user_pass;
/**< Username and password for
* authentication. */
+
+ const char *ciphername; /**< Data channel cipher from config file */
+ const char *authname; /**< Data channel auth from config file */
+ int keysize; /**< Data channel keysize from config file */
#endif
};
@@ -247,6 +248,9 @@ struct context_2
# define MANAGEMENT_READ (1<<6)
# define MANAGEMENT_WRITE (1<<7)
# endif
+#ifdef ENABLE_ASYNC_PUSH
+# define FILE_CLOSED (1<<8)
+#endif
unsigned int event_set_status;
@@ -335,8 +339,6 @@ struct context_2
/*
* TLS-mode crypto objects.
*/
-#ifdef ENABLE_SSL
-
struct tls_multi *tls_multi; /**< TLS state structure for this VPN
* tunnel. */
@@ -357,23 +359,19 @@ struct context_2
/* throw this signal on TLS errors */
int tls_exit_signal;
-#endif /* ENABLE_SSL */
-
struct crypto_options crypto_options;
/**< Security parameters and crypto state
* used by the \link data_crypto Data
* Channel Crypto module\endlink to
* process data channel packet. */
- /* used to keep track of data channel packet sequence numbers */
- struct packet_id packet_id;
struct event_timeout packet_id_persist_interval;
#endif /* ENABLE_CRYPTO */
-#ifdef ENABLE_LZO
- struct lzo_compress_workspace lzo_compwork;
- /**< Compression workspace used by the
+#ifdef USE_COMP
+ struct compress_context *comp_context;
+ /**< Compression context used by the
* \link compression Data Channel
* Compression module\endlink. */
#endif
@@ -393,11 +391,6 @@ struct context_2
struct buffer to_tun;
struct buffer to_link;
- /*
- * IPv4 TUN device?
- */
- bool ipv4_tun;
-
/* should we print R|W|r|w to console on packet transfers? */
bool log_rw;
@@ -423,6 +416,10 @@ struct context_2
time_t update_timeout_random_component;
struct timeval timeout_random_component;
+ /* Timer for everything up to the first packet from the *OpenVPN* server
+ * socks, http proxy, and tcp packets do not count */
+ struct event_timeout server_poll_interval;
+
/* indicates that the do_up_delay function has run */
bool do_up_ran;
@@ -446,13 +443,14 @@ struct context_2
#if P2MP_SERVER
/* --ifconfig endpoints to be pushed to client */
bool push_reply_deferred;
+#ifdef ENABLE_ASYNC_PUSH
+ bool push_request_received;
+#endif
bool push_ifconfig_defined;
time_t sent_push_reply_expiry;
in_addr_t push_ifconfig_local;
in_addr_t push_ifconfig_remote_netmask;
-#ifdef ENABLE_CLIENT_NAT
in_addr_t push_ifconfig_local_alias;
-#endif
bool push_ifconfig_ipv6_defined;
struct in6_addr push_ifconfig_ipv6_local;
@@ -474,11 +472,9 @@ struct context_2
/* hash of pulled options, so we can compare when options change */
bool pulled_options_md5_init_done;
- struct md5_state pulled_options_state;
+ md_ctx_t pulled_options_state;
struct md5_digest pulled_options_digest;
- struct event_timeout server_poll_interval;
-
struct event_timeout scheduled_exit;
int scheduled_exit_signal;
#endif
@@ -491,6 +487,10 @@ struct context_2
#ifdef MANAGEMENT_DEF_AUTH
struct man_def_auth_context mda_context;
#endif
+
+#ifdef ENABLE_ASYNC_PUSH
+ int inotify_fd; /* descriptor for monitoring file changes */
+#endif
};
@@ -566,7 +566,7 @@ struct context
* have been compiled in.
*/
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
#define TLS_MODE(c) ((c)->c2.tls_multi != NULL)
#define PROTO_DUMP_FLAGS (check_debug_level (D_LINK_RW_VERBOSE) ? (PD_SHOW_DATA|PD_VERBOSE) : 0)
#define PROTO_DUMP(buf, gc) protocol_dump((buf), \
@@ -591,4 +591,7 @@ struct context
#define CIPHER_ENABLED(c) (false)
#endif
+/* this represents "disabled peer-id" */
+#define MAX_PEER_ID 0xFFFFFF
+
#endif
diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj
index d691500..8dfbea5 100644
--- a/src/openvpn/openvpn.vcxproj
+++ b/src/openvpn/openvpn.vcxproj
@@ -64,7 +64,7 @@
<AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Link>
- <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -89,7 +89,7 @@
<AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Link>
- <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -102,6 +102,9 @@
<ClCompile Include="base64.c" />
<ClCompile Include="buffer.c" />
<ClCompile Include="clinat.c" />
+ <ClCompile Include="comp-lz4.c" />
+ <ClCompile Include="comp.c" />
+ <ClCompile Include="compstub.c" />
<ClCompile Include="console.c" />
<ClCompile Include="crypto.c" />
<ClCompile Include="crypto_openssl.c" />
@@ -171,6 +174,9 @@
<ClInclude Include="circ_list.h" />
<ClInclude Include="clinat.h" />
<ClInclude Include="common.h" />
+ <ClInclude Include="comp-lz4.h" />
+ <ClInclude Include="comp.h" />
+ <ClInclude Include="compstub.h" />
<ClInclude Include="console.h" />
<ClInclude Include="crypto.h" />
<ClInclude Include="crypto_backend.h" />
@@ -262,4 +268,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters
index dbed3cd..8b6a269 100644
--- a/src/openvpn/openvpn.vcxproj.filters
+++ b/src/openvpn/openvpn.vcxproj.filters
@@ -207,6 +207,15 @@
<ClCompile Include="win32.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="comp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="compstub.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="comp-lz4.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="base64.h">
@@ -227,6 +236,12 @@
<ClInclude Include="common.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="comp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="comp-lz4.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="console.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -449,9 +464,6 @@
<ClInclude Include="win32.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="win32_wfp.h">
- <Filter>Header Files</Filter>
- </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="openvpn_win32_resources.rc">
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index a49a4fb..7f128c3 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -56,39 +56,38 @@
#include "helper.h"
#include "manage.h"
#include "forward.h"
+#include "ssl_verify.h"
+#include "platform.h"
#include <ctype.h>
#include "memdbg.h"
const char title_string[] =
PACKAGE_STRING
+#ifdef CONFIGURE_GIT_REVISION
+ " [git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS "]"
+#endif
" " TARGET_ALIAS
#ifdef ENABLE_CRYPTO
-#ifdef ENABLE_SSL
-#if defined(ENABLE_CRYPTO_POLARSSL)
- " [SSL (PolarSSL)]"
+#if defined(ENABLE_CRYPTO_MBEDTLS)
+ " [SSL (mbed TLS)]"
#elif defined(ENABLE_CRYPTO_OPENSSL)
" [SSL (OpenSSL)]"
#else
" [SSL]"
-#endif /* defined(ENABLE_CRYPTO_POLARSSL) */
-#else /* ! ENABLE_SSL */
-#if defined(ENABLE_CRYPTO_POLARSSL)
- " [CRYPTO (PolarSSL)]"
-#elif defined(ENABLE_CRYPTO_OPENSSL)
- " [CRYPTO (OpenSSL)]"
-#else
- " [CRYPTO]"
-#endif /* defined(ENABLE_CRYPTO_POLARSSL) */
-#endif /* ENABLE_SSL */
+#endif /* defined(ENABLE_CRYPTO_MBEDTLS) */
#endif /* ENABLE_CRYPTO */
+#ifdef USE_COMP
#ifdef ENABLE_LZO
-#ifdef ENABLE_LZO_STUB
- " [LZO (STUB)]"
-#else
" [LZO]"
#endif
+#ifdef ENABLE_LZ4
+ " [LZ4]"
+#endif
+#ifdef ENABLE_COMP_STUB
+ " [COMP_STUB]"
#endif
+#endif /* USE_COMP */
#if EPOLL
" [EPOLL]"
#endif
@@ -99,9 +98,15 @@ const char title_string[] =
" [PKCS11]"
#endif
#if ENABLE_IP_PKTINFO
- " [MH]"
+# if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+ " [MH/PKTINFO]"
+# elif defined(IP_RECVDSTADDR)
+ " [MH/RECVDA]"
+# endif
+#endif
+#ifdef HAVE_AEAD_CIPHER_MODES
+ " [AEAD]"
#endif
- " [IPv6]"
" built on " __DATE__
;
@@ -125,11 +130,11 @@ static const char usage_message[] =
" p = udp (default), tcp-server, or tcp-client\n"
"--proto-force p : only consider protocol p in list of connection profiles.\n"
" p = udp6, tcp6-server, or tcp6-client (ipv6)\n"
- "--connect-retry n : For --proto tcp-client, number of seconds to wait\n"
- " between connection retries (default=%d).\n"
- "--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\n"
+ "--connect-retry n [m] : For client, number of seconds to wait between\n"
+ " connection retries (default=%d). On repeated retries\n"
+ " the wait time is exponentially increased to a maximum of m\n"
+ " (default=%d).\n"
"--connect-retry-max n : Maximum connection attempt retries, default infinite.\n"
-#ifdef ENABLE_HTTP_PROXY
"--http-proxy s p [up] [auth] : Connect to remote host\n"
" through an HTTP proxy at address s and port p.\n"
" If proxy authentication is required,\n"
@@ -139,21 +144,16 @@ static const char usage_message[] =
"--http-proxy s p 'auto[-nct]' : Like the above directive, but automatically\n"
" determine auth method and query for username/password\n"
" if needed. auto-nct disables weak proxy auth methods.\n"
- "--http-proxy-retry : Retry indefinitely on HTTP proxy errors.\n"
- "--http-proxy-timeout n : Proxy timeout in seconds, default=5.\n"
"--http-proxy-option type [parm] : Set extended HTTP proxy options.\n"
" Repeat to set multiple options.\n"
" VERSION version (default=1.0)\n"
" AGENT user-agent\n"
-#endif
-#ifdef ENABLE_SOCKS
"--socks-proxy s [p] [up] : Connect to remote host through a Socks5 proxy at\n"
" address s and port p (default port = 1080).\n"
" If proxy authentication is required,\n"
" up is a file containing username/password on 2 lines, or\n"
" 'stdin' to prompt for console.\n"
"--socks-proxy-retry : Retry indefinitely on Socks proxy errors.\n"
-#endif
"--resolv-retry n: If hostname resolve fails for --remote, retry\n"
" resolve for n seconds before failing (disabled by default).\n"
" Set n=\"infinite\" to retry indefinitely.\n"
@@ -162,16 +162,12 @@ static const char usage_message[] =
"--ipchange cmd : Run command cmd on remote ip address initial\n"
" setting or change -- execute as: cmd ip-address port#\n"
"--port port : TCP/UDP port # for both local and remote.\n"
- "--lport port : TCP/UDP port # for local (default=%d). Implies --bind.\n"
- "--rport port : TCP/UDP port # for remote (default=%d).\n"
+ "--lport port : TCP/UDP port # for local (default=%s). Implies --bind.\n"
+ "--rport port : TCP/UDP port # for remote (default=%s).\n"
"--bind : Bind to local address and port. (This is the default unless\n"
" --proto tcp-client"
-#ifdef ENABLE_HTTP_PROXY
" or --http-proxy"
-#endif
-#ifdef ENABLE_SOCKS
" or --socks-proxy"
-#endif
" is used).\n"
"--nobind : Do not bind to local address and port.\n"
"--dev tunX|tapX : tun/tap device (X can be omitted for dynamic device.\n"
@@ -182,7 +178,6 @@ static const char usage_message[] =
" /dev/net/tun, /dev/tun, /dev/tap, etc.\n"
"--lladdr hw : Set the link layer address of the tap device.\n"
"--topology t : Set --dev tun topology: 'net30', 'p2p', or 'subnet'.\n"
- "--tun-ipv6 : Build tun link capable of forwarding IPv6 traffic.\n"
#ifdef ENABLE_IPROUTE
"--iproute cmd : Use this command instead of default " IPROUTE_PATH ".\n"
#endif
@@ -207,9 +202,7 @@ static const char usage_message[] =
"--route-ipv6 network/bits [gateway] [metric] :\n"
" Add IPv6 route to routing table after connection\n"
" is established. Multiple routes can be specified.\n"
- " gateway default: taken from --route-ipv6-gateway or --ifconfig\n"
- "--max-routes n : Specify the maximum number of routes that may be defined\n"
- " or pulled from a server.\n"
+ " gateway default: taken from 'remote' in --ifconfig-ipv6\n"
"--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n"
"--route-metric m : Specify a default metric for use with --route.\n"
"--route-delay n [w] : Delay n seconds after connection initiation before\n"
@@ -234,9 +227,7 @@ static const char usage_message[] =
" Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n"
"--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n"
" the default gateway. Useful when pushing private subnets.\n"
-#ifdef ENABLE_CLIENT_NAT
"--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT rule.\n"
-#endif
#ifdef ENABLE_PUSH_PEER_INFO
"--push-peer-info : (client only) push client info to server.\n"
#endif
@@ -335,6 +326,7 @@ static const char usage_message[] =
"--log file : Output log to file which is created/truncated on open.\n"
"--log-append file : Append log to file, or create file if nonexistent.\n"
"--suppress-timestamps : Don't log timestamps to stdout/stderr.\n"
+ "--machine-readable-output : Always log timestamp, message flags to stdout/stderr.\n"
"--writepid file : Write main process ID to file.\n"
"--nice n : Change process priority (>0 = lower, <0 = higher).\n"
"--echo [parms ...] : Echo parameters to log output.\n"
@@ -359,12 +351,15 @@ static const char usage_message[] =
#ifdef ENABLE_DEBUG
"--gremlin mask : Special stress testing mode (for debugging only).\n"
#endif
-#ifdef ENABLE_LZO
- "--comp-lzo : Use fast LZO compression -- may add up to 1 byte per\n"
+#if defined(USE_COMP)
+ "--compress alg : Use compression algorithm alg\n"
+#if defined(ENABLE_LZO)
+ "--comp-lzo : Use LZO compression -- may add up to 1 byte per\n"
" packet for uncompressible data.\n"
"--comp-noadapt : Don't use adaptive compression when --comp-lzo\n"
" is specified.\n"
#endif
+#endif
#ifdef ENABLE_MANAGEMENT
"--management ip port [pass] : Enable a TCP server on ip:port to handle\n"
" management functions. pass is a password file\n"
@@ -442,6 +437,9 @@ static const char usage_message[] =
" Only valid in a client-specific config file.\n"
"--client-cert-not-required : Don't require client certificate, client\n"
" will authenticate using username/password.\n"
+ "--verify-client-cert [none|optional|require] : perform no, optional or\n"
+ " mandatory client certificate verification.\n"
+ " Default is to require the client to supply a certificate.\n"
"--username-as-common-name : For auth-user-pass authentication, use\n"
" the authenticated username as the common name,\n"
" rather than the common name from the client cert.\n"
@@ -449,6 +447,11 @@ static const char usage_message[] =
" run command cmd to verify. If method='via-env', pass\n"
" user/pass via environment, if method='via-file', pass\n"
" user/pass via temporary file.\n"
+ "--auth-gen-token [lifetime] Generate a random authentication token which is pushed\n"
+ " to each client, replacing the password. Usefull when\n"
+ " OTP based two-factor auth mechanisms are in use and\n"
+ " --reneg-* options are enabled. Optionally a lifetime in seconds\n"
+ " for generated tokens can be set.\n"
"--opt-verify : Clients that connect with options that are incompatible\n"
" with those of the server will be disconnected.\n"
"--auth-user-pass-optional : Allow connections by clients that don't\n"
@@ -476,6 +479,9 @@ static const char usage_message[] =
"--stale-routes-check n [t] : Remove routes with a last activity timestamp\n"
" older than n seconds. Run this check every t\n"
" seconds (defaults to n).\n"
+ "--explicit-exit-notify [n] : In UDP server mode send [RESTART] command on exit/restart to connected\n"
+ " clients. n = 1 - reconnect to same server,\n"
+ " 2 - advance to next server, default=1.\n"
#if PORT_SHARE
"--port-share host port [dir] : When run in TCP mode, proxy incoming HTTPS\n"
" sessions to a web server at host:port. dir specifies an\n"
@@ -493,13 +499,20 @@ static const char usage_message[] =
"--pull : Accept certain config file options from the peer as if they\n"
" were part of the local config file. Must be specified\n"
" when connecting to a '--mode server' remote host.\n"
+ "--pull-filter accept|ignore|reject t : Filter each option received from the\n"
+ " server if it starts with the text t. The action flag accept,\n"
+ " ignore or reject causes the option to be allowed, removed or\n"
+ " rejected with error. May be specified multiple times, and\n"
+ " each filter is applied in the order of appearance.\n"
"--auth-retry t : How to handle auth failures. Set t to\n"
" none (default), interact, or nointeract.\n"
"--static-challenge t e : Enable static challenge/response protocol using\n"
" challenge text t, with e indicating echo flag (0|1)\n"
- "--server-poll-timeout n : when polling possible remote servers to connect to\n"
+ "--connect-timeout n : when polling possible remote servers to connect to\n"
" in a round-robin fashion, spend no more than n seconds\n"
" waiting for a response before trying the next server.\n"
+ "--allow-recursive-routing : When this option is set, OpenVPN will not drop\n"
+ " incoming tun packets with same destination as host.\n"
#endif
#ifdef ENABLE_OCC
"--explicit-exit-notify [n] : On exit/restart, send exit signal to\n"
@@ -522,13 +535,15 @@ static const char usage_message[] =
"--cipher alg : Encrypt packets with cipher algorithm alg\n"
" (default=%s).\n"
" Set alg=none to disable encryption.\n"
+ "--ncp-ciphers list : List of ciphers that are allowed to be negotiated.\n"
+ "--ncp-disable : Disable cipher negotiation.\n"
"--prng alg [nsl] : For PRNG, use digest algorithm alg, and\n"
" nonce_secret_len=nsl. Set alg=none to disable PRNG.\n"
#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH
"--keysize n : Size of cipher key in bits (optional).\n"
" If unspecified, defaults to cipher-specific default.\n"
#endif
-#ifndef ENABLE_CRYPTO_POLARSSL
+#ifndef ENABLE_CRYPTO_MBEDTLS
"--engine [name] : Enable OpenSSL hardware crypto engine functionality.\n"
#endif
"--no-replay : Disable replay protection.\n"
@@ -545,7 +560,6 @@ static const char usage_message[] =
"--use-prediction-resistance: Enable prediction resistance on the random\n"
" number generator.\n"
#endif
-#ifdef ENABLE_SSL
"\n"
"TLS Key Negotiation Options:\n"
"(These options are meaningful only for TLS-mode)\n"
@@ -555,15 +569,10 @@ static const char usage_message[] =
" number, such as 1 (default), 2, etc.\n"
"--ca file : Certificate authority file in .pem format containing\n"
" root certificate.\n"
-#ifndef ENABLE_CRYPTO_POLARSSL
+#ifndef ENABLE_CRYPTO_MBEDTLS
"--capath dir : A directory of trusted certificates (CAs"
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
" and CRLs).\n"
-#else /* OPENSSL_VERSION_NUMBER >= 0x00907000L */
- ").\n"
- " WARNING: no support of CRL available with this version.\n"
-#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L */
-#endif /* ENABLE_CRYPTO_POLARSSL */
+#endif /* ENABLE_CRYPTO_MBEDTLS */
"--dh file : File containing Diffie Hellman parameters\n"
" in .pem format (for --tls-server only).\n"
" Use \"openssl dhparam -out dh1024.pem 1024\" to generate.\n"
@@ -575,7 +584,7 @@ static const char usage_message[] =
" will accept from the peer. If version is unrecognized and 'or-highest'\n"
" is specified, require max TLS version supported by SSL implementation.\n"
"--tls-version-max <version> : sets the maximum TLS version we will use.\n"
-#ifndef ENABLE_CRYPTO_POLARSSL
+#ifndef ENABLE_CRYPTO_MBEDTLS
"--pkcs12 file : PKCS#12 file containing local private key, local certificate\n"
" and optionally the root CA certificate.\n"
#endif
@@ -584,7 +593,7 @@ static const char usage_message[] =
" Default is CN in the Subject field.\n"
#endif
"--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n"
-#ifdef WIN32
+#ifdef _WIN32
"--cryptoapicert select-string : Load the certificate and private key from the\n"
" Windows Certificate System Store.\n"
#endif
@@ -602,10 +611,17 @@ static const char usage_message[] =
"--single-session: Allow only one session (reset state on restart).\n"
"--tls-exit : Exit on TLS negotiation failure.\n"
"--tls-auth f [d]: Add an additional layer of authentication on top of the TLS\n"
- " control channel to protect against DoS attacks.\n"
- " f (required) is a shared-secret passphrase file.\n"
+ " control channel to protect against attacks on the TLS stack\n"
+ " and DoS attacks.\n"
+ " f (required) is a shared-secret key file.\n"
" The optional d parameter controls key directionality,\n"
" see --secret option for more info.\n"
+ "--tls-crypt key : Add an additional layer of authenticated encryption on top\n"
+ " of the TLS control channel to hide the TLS certificate,\n"
+ " provide basic post-quantum security and protect against\n"
+ " attacks on the TLS stack and DoS attacks.\n"
+ " key (required) provides the pre-shared key file.\n"
+ " see --secret option for more info.\n"
"--askpass [file]: Get PEM password from controlling tty before we daemonize.\n"
"--auth-nocache : Don't cache --askpass or --auth-user-pass passwords.\n"
"--crl-verify crl ['dir']: Check peer certificate against a CRL.\n"
@@ -622,11 +638,12 @@ static const char usage_message[] =
" of verification.\n"
"--ns-cert-type t: Require that peer certificate was signed with an explicit\n"
" nsCertType designation t = 'client' | 'server'.\n"
-#ifdef ENABLE_X509_TRACK
"--x509-track x : Save peer X509 attribute x in environment for use by\n"
" plugins and management interface.\n"
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
+ "--keying-material-exporter label len : Save Exported Keying Material (RFC5705)\n"
+ " of len bytes (min. 16 bytes) using label in environment for use by plugins.\n"
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L || ENABLE_CRYPTO_POLARSSL
"--remote-cert-ku v ... : Require that the peer certificate was signed with\n"
" explicit key usage, you can specify more than one value.\n"
" value should be given in hex format.\n"
@@ -636,8 +653,6 @@ static const char usage_message[] =
"--remote-cert-tls t: Require that peer certificate was signed with explicit\n"
" key usage and extended key usage based on RFC3280 TLS rules.\n"
" t = 'client' | 'server'.\n"
-#endif /* OPENSSL_VERSION_NUMBER || ENABLE_CRYPTO_POLARSSL */
-#endif /* ENABLE_SSL */
#ifdef ENABLE_PKCS11
"\n"
"PKCS#11 Options:\n"
@@ -662,10 +677,8 @@ static const char usage_message[] =
"--show-ciphers : Show cipher algorithms to use with --cipher option.\n"
"--show-digests : Show message digest algorithms to use with --auth option.\n"
"--show-engines : Show hardware crypto accelerator engines (if available).\n"
-#ifdef ENABLE_SSL
"--show-tls : Show all TLS ciphers (TLS used only as a control channel).\n"
-#endif
-#ifdef WIN32
+#ifdef _WIN32
"\n"
"Windows Specific:\n"
"--win-sys path : Pathname of Windows system directory. Default is the pathname\n"
@@ -715,7 +728,9 @@ static const char usage_message[] =
" optional parameter controls the initial state of ex.\n"
"--show-net-up : Show " PACKAGE_NAME "'s view of routing table and net adapter list\n"
" after TAP adapter is up and routes have been added.\n"
+#ifdef _WIN32
"--block-outside-dns : Block DNS on other network adapters to prevent DNS leaks\n"
+#endif
"Windows Standalone Options:\n"
"\n"
"--show-adapters : Show all TAP-Windows adapters.\n"
@@ -775,10 +790,13 @@ init_options (struct options *o, const bool init_gc)
}
o->mode = MODE_POINT_TO_POINT;
o->topology = TOP_NET30;
- o->ce.proto = PROTO_UDPv4;
+ o->ce.proto = PROTO_UDP;
+ o->ce.af = AF_UNSPEC;
+ o->ce.bind_ipv6_only = false;
o->ce.connect_retry_seconds = 5;
- o->ce.connect_timeout = 10;
- o->ce.connect_retry_max = 0;
+ o->ce.connect_retry_seconds_max = 300;
+ o->ce.connect_timeout = 120;
+ o->connect_retry_max = 0;
o->ce.local_port = o->ce.remote_port = OPENVPN_PORT;
o->verbosity = 1;
o->status_file_update_freq = 60;
@@ -789,8 +807,8 @@ init_options (struct options *o, const bool init_gc)
o->ce.mtu_discover_type = -1;
o->ce.mssfix = MSSFIX_DEFAULT;
o->route_delay_window = 30;
- o->max_routes = MAX_ROUTES_DEFAULT;
o->resolve_retry_seconds = RESOLV_RETRY_INFINITE;
+ o->resolve_in_advance = false;
o->proto_force = -1;
#ifdef ENABLE_OCC
o->occ = true;
@@ -806,7 +824,7 @@ init_options (struct options *o, const bool init_gc)
#ifdef TARGET_LINUX
o->tuntap_options.txqueuelen = 100;
#endif
-#ifdef WIN32
+#ifdef _WIN32
#if 0
o->tuntap_options.ip_win32_type = IPW32_SET_ADAPTIVE;
#else
@@ -829,13 +847,16 @@ init_options (struct options *o, const bool init_gc)
#endif
#if P2MP
o->scheduled_exit_interval = 5;
- o->server_poll_timeout = 0;
#endif
#ifdef ENABLE_CRYPTO
o->ciphername = "BF-CBC";
- o->ciphername_defined = true;
+#ifdef HAVE_AEAD_CIPHER_MODES /* IV_NCP=2 requires GCM support */
+ o->ncp_enabled = true;
+#else
+ o->ncp_enabled = false;
+#endif
+ o->ncp_ciphers = "AES-256-GCM:AES-128-GCM";
o->authname = "SHA1";
- o->authname_defined = true;
o->prng_hash = "SHA1";
o->prng_nonce_secret_len = 16;
o->replay = true;
@@ -846,25 +867,27 @@ init_options (struct options *o, const bool init_gc)
#ifdef ENABLE_PREDICTION_RESISTANCE
o->use_prediction_resistance = false;
#endif
-#ifdef ENABLE_SSL
o->key_method = 2;
o->tls_timeout = 2;
+ o->renegotiate_bytes = -1;
o->renegotiate_seconds = 3600;
o->handshake_window = 60;
o->transition_window = 3600;
+ o->ecdh_curve = NULL;
#ifdef ENABLE_X509ALTUSERNAME
o->x509_username_field = X509_USERNAME_FIELD_DEFAULT;
#endif
-#endif /* ENABLE_SSL */
#endif /* ENABLE_CRYPTO */
#ifdef ENABLE_PKCS11
o->pkcs11_pin_cache_period = -1;
#endif /* ENABLE_PKCS11 */
-/* tmp is only used in P2MP server context */
+/* P2MP server context features */
#if P2MP_SERVER
+ o->auth_token_generate = false;
+
/* Set default --tmp-dir */
-#ifdef WIN32
+#ifdef _WIN32
/* On Windows, find temp dir via enviroment variables */
o->tmp_dir = win_get_tempdir();
#else
@@ -873,8 +896,9 @@ init_options (struct options *o, const bool init_gc)
if( !o->tmp_dir ) {
o->tmp_dir = "/tmp";
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
#endif /* P2MP_SERVER */
+ o->allow_recursive_routing = false;
}
void
@@ -886,6 +910,37 @@ uninit_options (struct options *o)
}
}
+struct pull_filter
+{
+# define PUF_TYPE_UNDEF 0 /** undefined filter type */
+# define PUF_TYPE_ACCEPT 1 /** filter type to accept a matching option */
+# define PUF_TYPE_IGNORE 2 /** filter type to ignore a matching option */
+# define PUF_TYPE_REJECT 3 /** filter type to reject and trigger SIGUSR1 */
+ int type;
+ int size;
+ char *pattern;
+ struct pull_filter *next;
+};
+
+struct pull_filter_list
+{
+ struct pull_filter *head;
+ struct pull_filter *tail;
+};
+
+static const char *
+pull_filter_type_name (int type)
+{
+ if (type == PUF_TYPE_ACCEPT)
+ return "accept";
+ if (type == PUF_TYPE_IGNORE)
+ return "ignore";
+ if (type == PUF_TYPE_REJECT)
+ return "reject";
+ else
+ return "???";
+}
+
#ifndef ENABLE_SMALL
#define SHOW_PARM(name, value, format) msg(D_SHOW_PARMS, " " #name " = " format, (value))
@@ -902,26 +957,22 @@ setenv_connection_entry (struct env_set *es,
const struct connection_entry *e,
const int i)
{
- setenv_str_i (es, "proto", proto2ascii (e->proto, false), i);
+ setenv_str_i (es, "proto", proto2ascii (e->proto, e->af, false), i);
setenv_str_i (es, "local", e->local, i);
- setenv_int_i (es, "local_port", e->local_port, i);
+ setenv_str_i (es, "local_port", e->local_port, i);
setenv_str_i (es, "remote", e->remote, i);
- setenv_int_i (es, "remote_port", e->remote_port, i);
+ setenv_str_i (es, "remote_port", e->remote_port, i);
-#ifdef ENABLE_HTTP_PROXY
if (e->http_proxy_options)
{
setenv_str_i (es, "http_proxy_server", e->http_proxy_options->server, i);
- setenv_int_i (es, "http_proxy_port", e->http_proxy_options->port, i);
+ setenv_str_i (es, "http_proxy_port", e->http_proxy_options->port, i);
}
-#endif
-#ifdef ENABLE_SOCKS
if (e->socks_proxy_server)
{
setenv_str_i (es, "socks_proxy_server", e->socks_proxy_server, i);
- setenv_int_i (es, "socks_proxy_port", e->socks_proxy_port, i);
+ setenv_str_i (es, "socks_proxy_port", e->socks_proxy_port, i);
}
-#endif
}
void
@@ -1064,7 +1115,7 @@ string_substitute (const char *src, int from, int to, struct gc_arena *gc)
return ret;
}
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
static uint8_t *
parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_arena *gc)
{
@@ -1098,7 +1149,7 @@ parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_aren
}
#endif
-#ifdef WIN32
+#ifdef _WIN32
#ifndef ENABLE_SMALL
@@ -1141,7 +1192,9 @@ show_tuntap_options (const struct tuntap_options *o)
}
#endif
+#endif
+#if defined(_WIN32) || defined(TARGET_ANDROID)
static void
dhcp_option_address_parse (const char *name, const char *parm, in_addr_t *array, int *len, int msglevel)
{
@@ -1231,9 +1284,11 @@ show_p2mp_parms (const struct options *o)
SHOW_INT (max_routes_per_client);
SHOW_STR (auth_user_pass_verify_script);
SHOW_BOOL (auth_user_pass_verify_script_via_file);
+ SHOW_BOOL (auth_token_generate);
+ SHOW_INT (auth_token_lifetime);
#if PORT_SHARE
SHOW_STR (port_share_host);
- SHOW_INT (port_share_port);
+ SHOW_STR (port_share_port);
#endif
#endif /* P2MP_SERVER */
@@ -1298,19 +1353,27 @@ option_iroute_ipv6 (struct options *o,
#endif /* P2MP_SERVER */
#endif /* P2MP */
-#if defined(ENABLE_HTTP_PROXY) && !defined(ENABLE_SMALL)
+#ifndef ENABLE_SMALL
static void
show_http_proxy_options (const struct http_proxy_options *o)
{
+ int i;
msg (D_SHOW_PARMS, "BEGIN http_proxy");
SHOW_STR (server);
- SHOW_INT (port);
+ SHOW_STR (port);
SHOW_STR (auth_method_string);
SHOW_STR (auth_file);
- SHOW_BOOL (retry);
- SHOW_INT (timeout);
SHOW_STR (http_version);
SHOW_STR (user_agent);
+ for (i=0; i < MAX_CUSTOM_HTTP_HEADER && o->custom_headers[i].name;i++)
+ {
+ if (o->custom_headers[i].content)
+ msg (D_SHOW_PARMS, " custom_header[%d] = %s: %s", i,
+ o->custom_headers[i].name, o->custom_headers[i].content);
+ else
+ msg (D_SHOW_PARMS, " custom_header[%d] = %s", i,
+ o->custom_headers[i].name);
+ }
msg (D_SHOW_PARMS, "END http_proxy");
}
#endif
@@ -1320,9 +1383,7 @@ options_detach (struct options *o)
{
gc_detach (&o->gc);
o->routes = NULL;
-#ifdef ENABLE_CLIENT_NAT
o->client_nat = NULL;
-#endif
#if P2MP_SERVER
clone_push_list(o);
#endif
@@ -1332,50 +1393,43 @@ void
rol_check_alloc (struct options *options)
{
if (!options->routes)
- options->routes = new_route_option_list (options->max_routes, &options->gc);
+ options->routes = new_route_option_list (&options->gc);
}
void
rol6_check_alloc (struct options *options)
{
if (!options->routes_ipv6)
- options->routes_ipv6 = new_route_ipv6_option_list (options->max_routes, &options->gc);
+ options->routes_ipv6 = new_route_ipv6_option_list (&options->gc);
}
-#ifdef ENABLE_CLIENT_NAT
static void
cnol_check_alloc (struct options *options)
{
if (!options->client_nat)
options->client_nat = new_client_nat_list (&options->gc);
}
-#endif
#ifndef ENABLE_SMALL
static void
show_connection_entry (const struct connection_entry *o)
{
- msg (D_SHOW_PARMS, " proto = %s", proto2ascii (o->proto, false));
+ msg (D_SHOW_PARMS, " proto = %s", proto2ascii (o->proto, o->af, false));
SHOW_STR (local);
- SHOW_INT (local_port);
+ SHOW_STR (local_port);
SHOW_STR (remote);
- SHOW_INT (remote_port);
+ SHOW_STR (remote_port);
SHOW_BOOL (remote_float);
SHOW_BOOL (bind_defined);
SHOW_BOOL (bind_local);
+ SHOW_BOOL (bind_ipv6_only);
SHOW_INT (connect_retry_seconds);
SHOW_INT (connect_timeout);
- SHOW_INT (connect_retry_max);
-#ifdef ENABLE_HTTP_PROXY
if (o->http_proxy_options)
show_http_proxy_options (o->http_proxy_options);
-#endif
-#ifdef ENABLE_SOCKS
SHOW_STR (socks_proxy_server);
- SHOW_INT (socks_proxy_port);
- SHOW_BOOL (socks_proxy_retry);
-#endif
+ SHOW_STR (socks_proxy_port);
SHOW_INT (tun_mtu);
SHOW_BOOL (tun_mtu_defined);
SHOW_INT (link_mtu);
@@ -1399,8 +1453,6 @@ show_connection_entry (const struct connection_entry *o)
static void
show_connection_entries (const struct options *o)
{
- msg (D_SHOW_PARMS, "Connection profiles [default]:");
- show_connection_entry (&o->ce);
if (o->connection_list)
{
const struct connection_list *l = o->connection_list;
@@ -1411,9 +1463,28 @@ show_connection_entries (const struct options *o)
show_connection_entry (l->array[i]);
}
}
+ else
+ {
+ msg (D_SHOW_PARMS, "Connection profiles [default]:");
+ show_connection_entry (&o->ce);
+ }
msg (D_SHOW_PARMS, "Connection profiles END");
}
+static void
+show_pull_filter_list (const struct pull_filter_list *l)
+{
+ struct pull_filter *f;
+ if (!l)
+ return;
+
+ msg (D_SHOW_PARMS, " Pull filters:");
+ for (f = l->head; f; f = f->next)
+ {
+ msg (D_SHOW_PARMS, " %s \"%s\"", pull_filter_type_name(f->type), f->pattern);
+ }
+}
+
#endif
void
@@ -1436,12 +1507,11 @@ show_settings (const struct options *o)
SHOW_BOOL (show_digests);
SHOW_BOOL (show_engines);
SHOW_BOOL (genkey);
-#ifdef ENABLE_SSL
SHOW_STR (key_pass_file);
SHOW_BOOL (show_tls_ciphers);
#endif
-#endif
+ SHOW_INT (connect_retry_max);
show_connection_entries (o);
SHOW_BOOL (remote_random);
@@ -1452,7 +1522,6 @@ show_settings (const struct options *o)
SHOW_STR (dev_node);
SHOW_STR (lladdr);
SHOW_INT (topology);
- SHOW_BOOL (tun_ipv6);
SHOW_STR (ifconfig_local);
SHOW_STR (ifconfig_remote_netmask);
SHOW_BOOL (ifconfig_noexec);
@@ -1488,6 +1557,7 @@ show_settings (const struct options *o)
#endif
SHOW_INT (resolve_retry_seconds);
+ SHOW_BOOL (resolve_in_advance);
SHOW_STR (username);
SHOW_STR (groupname);
@@ -1506,6 +1576,7 @@ show_settings (const struct options *o)
SHOW_INT (inetd);
SHOW_BOOL (log);
SHOW_BOOL (suppress_timestamps);
+ SHOW_BOOL (machine_readable_output);
SHOW_INT (nice);
SHOW_INT (verbosity);
SHOW_INT (mute);
@@ -1528,8 +1599,9 @@ show_settings (const struct options *o)
SHOW_BOOL (fast_io);
-#ifdef ENABLE_LZO
- SHOW_INT (lzo);
+#ifdef USE_COMP
+ SHOW_INT (comp.alg);
+ SHOW_INT (comp.flags);
#endif
SHOW_STR (route_script);
@@ -1541,19 +1613,18 @@ show_settings (const struct options *o)
SHOW_BOOL (route_delay_defined);
SHOW_BOOL (route_nopull);
SHOW_BOOL (route_gateway_via_dhcp);
- SHOW_INT (max_routes);
SHOW_BOOL (allow_pull_fqdn);
+ show_pull_filter_list (o->pull_filter_list);
+
if (o->routes)
print_route_options (o->routes, D_SHOW_PARMS);
-
-#ifdef ENABLE_CLIENT_NAT
+
if (o->client_nat)
print_client_nat_list(o->client_nat, D_SHOW_PARMS);
-#endif
#ifdef ENABLE_MANAGEMENT
SHOW_STR (management_addr);
- SHOW_INT (management_port);
+ SHOW_STR (management_port);
SHOW_STR (management_user_pass);
SHOW_INT (management_log_history_cache);
SHOW_INT (management_echo_buffer_size);
@@ -1570,16 +1641,14 @@ show_settings (const struct options *o)
#ifdef ENABLE_CRYPTO
SHOW_STR (shared_secret_file);
SHOW_INT (key_direction);
- SHOW_BOOL (ciphername_defined);
SHOW_STR (ciphername);
- SHOW_BOOL (authname_defined);
SHOW_STR (authname);
SHOW_STR (prng_hash);
SHOW_INT (prng_nonce_secret_len);
SHOW_INT (keysize);
-#ifndef ENABLE_CRYPTO_POLARSSL
+#ifndef ENABLE_CRYPTO_MBEDTLS
SHOW_BOOL (engine);
-#endif /* ENABLE_CRYPTO_POLARSSL */
+#endif /* ENABLE_CRYPTO_MBEDTLS */
SHOW_BOOL (replay);
SHOW_BOOL (mute_replay_warnings);
SHOW_INT (replay_window);
@@ -1591,13 +1660,17 @@ show_settings (const struct options *o)
SHOW_BOOL (use_prediction_resistance);
#endif
-#ifdef ENABLE_SSL
SHOW_BOOL (tls_server);
SHOW_BOOL (tls_client);
SHOW_INT (key_method);
SHOW_STR (ca_file);
SHOW_STR (ca_path);
SHOW_STR (dh_file);
+#ifdef MANAGMENT_EXTERNAL_KEY
+ if((o->management_flags & MF_EXTERNAL_CERT))
+ SHOW_PARM ("cert_file","EXTERNAL_CERT","%s");
+ else
+#endif
SHOW_STR (cert_file);
SHOW_STR (extra_certs_file);
@@ -1607,7 +1680,7 @@ show_settings (const struct options *o)
else
#endif
SHOW_STR (priv_key_file);
-#ifndef ENABLE_CRYPTO_POLARSSL
+#ifndef ENABLE_CRYPTO_MBEDTLS
SHOW_STR (pkcs12_file);
#endif
#ifdef ENABLE_CRYPTOAPI
@@ -1644,8 +1717,8 @@ show_settings (const struct options *o)
SHOW_BOOL (tls_exit);
SHOW_STR (tls_auth_file);
-#endif
-#endif
+ SHOW_STR (tls_crypt_file);
+#endif /* ENABLE_CRYPTO */
#ifdef ENABLE_PKCS11
{
@@ -1677,7 +1750,7 @@ show_settings (const struct options *o)
show_p2mp_parms (o);
#endif
-#ifdef WIN32
+#ifdef _WIN32
SHOW_BOOL (show_net_up);
SHOW_INT (route_method);
SHOW_BOOL (block_outside_dns);
@@ -1691,7 +1764,7 @@ show_settings (const struct options *o)
#undef SHOW_INT
#undef SHOW_BOOL
-#if HTTP_PROXY_OVERRIDE
+#ifdef ENABLE_MANAGEMENT
static struct http_proxy_options *
parse_http_proxy_override (const char *server,
@@ -1703,19 +1776,9 @@ parse_http_proxy_override (const char *server,
if (server && port)
{
struct http_proxy_options *ho;
- const int int_port = atoi(port);
-
- if (!legal_ipv4_port (int_port))
- {
- msg (msglevel, "Bad http-proxy port number: %s", port);
- return NULL;
- }
-
ALLOC_OBJ_CLEAR_GC (ho, struct http_proxy_options, gc);
ho->server = string_alloc(server, gc);
- ho->port = int_port;
- ho->retry = true;
- ho->timeout = 5;
+ ho->port = port;
if (flags && !strcmp(flags, "nct"))
ho->auth_retry = PAR_NCT;
else
@@ -1732,32 +1795,31 @@ void
options_postprocess_http_proxy_override (struct options *o)
{
const struct connection_list *l = o->connection_list;
- if (l)
+ int i;
+ bool succeed = false;
+ for (i = 0; i < l->len; ++i)
+ {
+ struct connection_entry *ce = l->array[i];
+ if (ce->proto == PROTO_TCP_CLIENT || ce->proto == PROTO_TCP)
+ {
+ ce->http_proxy_options = o->http_proxy_override;
+ succeed = true;
+ }
+ }
+ if (succeed)
{
- int i;
- bool succeed = false;
for (i = 0; i < l->len; ++i)
- {
- struct connection_entry *ce = l->array[i];
- if (ce->proto == PROTO_TCPv4_CLIENT || ce->proto == PROTO_TCPv4)
- {
- ce->http_proxy_options = o->http_proxy_override;
- succeed = true;
- }
- }
- if (succeed)
- {
- for (i = 0; i < l->len; ++i)
- {
- struct connection_entry *ce = l->array[i];
- if (ce->proto == PROTO_UDPv4)
- {
- ce->flags |= CE_DISABLED;
- }
- }
- }
- else
- msg (M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined");
+ {
+ struct connection_entry *ce = l->array[i];
+ if (ce->proto == PROTO_UDP)
+ {
+ ce->flags |= CE_DISABLED;
+ }
+ }
+ }
+ else
+ {
+ msg (M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined");
}
}
@@ -1811,15 +1873,46 @@ alloc_remote_entry (struct options *options, const int msglevel)
return e;
}
+static struct pull_filter_list *
+alloc_pull_filter_list (struct options *o)
+{
+ if (!o->pull_filter_list)
+ ALLOC_OBJ_CLEAR_GC (o->pull_filter_list, struct pull_filter_list, &o->gc);
+ return o->pull_filter_list;
+}
+
+static struct pull_filter *
+alloc_pull_filter (struct options *o, const int msglevel)
+{
+ struct pull_filter_list *l = alloc_pull_filter_list (o);
+ struct pull_filter *f;
+
+ ALLOC_OBJ_CLEAR_GC (f, struct pull_filter, &o->gc);
+ if (l->head)
+ {
+ ASSERT (l->tail);
+ l->tail->next = f;
+ }
+ else
+ {
+ ASSERT (!l->tail);
+ l->head = f;
+ }
+ l->tail = f;
+ return f;
+}
+
void
connection_entry_load_re (struct connection_entry *ce, const struct remote_entry *re)
{
if (re->remote)
ce->remote = re->remote;
- if (re->remote_port >= 0)
+ if (re->remote_port)
ce->remote_port = re->remote_port;
if (re->proto >= 0)
ce->proto = re->proto;
+ if (re->af > 0)
+ ce->af = re->af;
}
static void
@@ -1849,10 +1942,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
* If "proto tcp" is specified, make sure we know whether it is
* tcp-client or tcp-server.
*/
- if (ce->proto == PROTO_TCPv4)
+ if (ce->proto == PROTO_TCP)
msg (M_USAGE, "--proto tcp is ambiguous in this context. Please specify --proto tcp-server or --proto tcp-client");
- if (ce->proto == PROTO_TCPv6)
- msg (M_USAGE, "--proto tcp6 is ambiguous in this context. Please specify --proto tcp6-server or --proto tcp6-client");
/*
* Sanity check on daemon/inetd modes
@@ -1864,14 +1955,14 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
if (options->inetd && (ce->local || ce->remote))
msg (M_USAGE, "--local or --remote cannot be used with --inetd");
- if (options->inetd && ce->proto == PROTO_TCPv4_CLIENT)
+ if (options->inetd && ce->proto == PROTO_TCP_CLIENT)
msg (M_USAGE, "--proto tcp-client cannot be used with --inetd");
- if (options->inetd == INETD_NOWAIT && ce->proto != PROTO_TCPv4_SERVER)
+ if (options->inetd == INETD_NOWAIT && ce->proto != PROTO_TCP_SERVER)
msg (M_USAGE, "--inetd nowait can only be used with --proto tcp-server");
if (options->inetd == INETD_NOWAIT
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
&& !(options->tls_server || options->tls_client)
#endif
)
@@ -1885,20 +1976,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--lladdr can only be used in --dev tap mode");
/*
- * Sanity check on TCP mode options
- */
-
- if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT
- && ce->proto != PROTO_TCPv6_CLIENT)
- msg (M_USAGE, "--connect-retry doesn't make sense unless also used with "
- "--proto tcp-client or tcp6-client");
-
- if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT
- && ce->proto != PROTO_TCPv6_CLIENT)
- msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with "
- "--proto tcp-client or tcp6-client");
-
- /*
* Sanity check on MTU parameters
*/
if (options->ce.tun_mtu_defined && options->ce.link_mtu_defined)
@@ -1920,7 +1997,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
if (proto_is_net(ce->proto)
&& string_defined_equal (ce->local, ce->remote)
- && ce->local_port == ce->remote_port)
+ && string_defined_equal (ce->local_port, ce->remote_port))
msg (M_USAGE, "--remote and --local addresses are the same");
if (string_defined_equal (ce->remote, options->ifconfig_local)
@@ -1965,7 +2042,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
* Windows-specific options.
*/
-#ifdef WIN32
+#ifdef _WIN32
if (dev == DEV_TYPE_TUN && !(pull || (options->ifconfig_local && options->ifconfig_remote_netmask)))
msg (M_USAGE, "On Windows, --ifconfig is required when --dev tun is used");
@@ -1993,29 +2070,21 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp");
#endif
- if (!ce->remote && (ce->proto == PROTO_TCPv4_CLIENT
- || ce->proto == PROTO_TCPv6_CLIENT))
+ if (!ce->remote && ce->proto == PROTO_TCP_CLIENT)
msg (M_USAGE, "--remote MUST be used in TCP Client mode");
-#ifdef ENABLE_HTTP_PROXY
- if ((ce->http_proxy_options) && ce->proto != PROTO_TCPv4_CLIENT)
+ if ((ce->http_proxy_options) && ce->proto != PROTO_TCP_CLIENT)
msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)");
if ((ce->http_proxy_options) && !ce->http_proxy_options->server)
msg (M_USAGE, "--http-proxy not specified but other http proxy options present");
-#endif
-#if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_SOCKS)
if (ce->http_proxy_options && ce->socks_proxy_server)
msg (M_USAGE, "--http-proxy can not be used together with --socks-proxy");
-#endif
-#ifdef ENABLE_SOCKS
- if (ce->socks_proxy_server && ce->proto == PROTO_TCPv4_SERVER)
+ if (ce->socks_proxy_server && ce->proto == PROTO_TCP_SERVER)
msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode");
-#endif
- if ((ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_SERVER)
- && connection_list_defined (options))
+ if (ce->proto == PROTO_TCP_SERVER && (options->connection_list->len > 1))
msg (M_USAGE, "TCP server mode allows at most one --remote address");
#if P2MP_SERVER
@@ -2029,13 +2098,14 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--mode server only works with --dev tun or --dev tap");
if (options->pull)
msg (M_USAGE, "--pull cannot be used with --mode server");
- if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCPv4_SERVER
- || ce->proto == PROTO_TCPv6_SERVER))
+ if (options->pull_filter_list)
+ msg (M_USAGE, "--pull-filter cannot be used with --mode server");
+ if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCP_SERVER))
msg (M_USAGE, "--mode server currently only supports "
"--proto udp or --proto tcp-server or proto tcp6-server");
#if PORT_SHARE
if ((options->port_share_host || options->port_share_port) &&
- (ce->proto != PROTO_TCPv4_SERVER && ce->proto != PROTO_TCPv6_SERVER))
+ (ce->proto != PROTO_TCP_SERVER))
msg (M_USAGE, "--port-share only works in TCP server mode "
"(--proto tcp-server or tcp6-server)");
#endif
@@ -2045,38 +2115,29 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--remote cannot be used with --mode server");
if (!ce->bind_local)
msg (M_USAGE, "--nobind cannot be used with --mode server");
-#ifdef ENABLE_HTTP_PROXY
if (ce->http_proxy_options)
msg (M_USAGE, "--http-proxy cannot be used with --mode server");
-#endif
-#ifdef ENABLE_SOCKS
if (ce->socks_proxy_server)
msg (M_USAGE, "--socks-proxy cannot be used with --mode server");
-#endif
- if (options->connection_list)
- msg (M_USAGE, "<connection> cannot be used with --mode server");
-#if 0
- if (options->tun_ipv6)
- msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server");
-#endif
+ /* <connection> blocks force to have a remote embedded, so we check for the
+ * --remote and bail out if it is present */
+ if (options->connection_list->len >1 ||
+ options->connection_list->array[0]->remote)
+ msg (M_USAGE, "<connection> cannot be used with --mode server");
+
if (options->shaper)
msg (M_USAGE, "--shaper cannot be used with --mode server");
if (options->inetd)
msg (M_USAGE, "--inetd cannot be used with --mode server");
if (options->ipchange)
msg (M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)");
- if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCPv4_SERVER
- || ce->proto == PROTO_TCPv6_SERVER))
+ if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCP_SERVER))
msg (M_USAGE, "--mode server currently only supports "
"--proto udp or --proto tcp-server or --proto tcp6-server");
if (!proto_is_udp(ce->proto) && (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 || (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 (ce->explicit_exit_notification)
- msg (M_USAGE, "--explicit-exit-notify cannot be used with --mode server");
-#endif
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)
@@ -2087,9 +2148,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--ifconfig-pool-persist must be used with --ifconfig-pool");
if (options->ifconfig_ipv6_pool_defined && !options->ifconfig_ipv6_local )
msg (M_USAGE, "--ifconfig-ipv6-pool needs --ifconfig-ipv6");
- if (options->ifconfig_ipv6_local && !options->tun_ipv6 )
- msg (M_INFO, "Warning: --ifconfig-ipv6 without --tun-ipv6 will not do IPv6");
-
+ if (options->allow_recursive_routing)
+ msg (M_USAGE, "--allow-recursive-routing cannot be used with --mode server");
if (options->auth_user_pass_file)
msg (M_USAGE, "--auth-user-pass cannot be used with --mode server (it should be used on the client side only)");
if (options->ccd_exclusive && !options->client_config_dir)
@@ -2102,8 +2162,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
|| PLUGIN_OPTION_LIST (options)
|| MAN_CLIENT_AUTH_ENABLED (options));
const char *postfix = "must be used with --management-client-auth, an --auth-user-pass-verify script, or plugin";
- if ((options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) && !ccnr)
- msg (M_USAGE, "--client-cert-not-required %s", postfix);
+ if ((options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) && !ccnr)
+ msg (M_USAGE, "--verify-client-cert none|optional %s", postfix);
if ((options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && !ccnr)
msg (M_USAGE, "--username-as-common-name %s", postfix);
if ((options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) && !ccnr)
@@ -2137,8 +2197,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--duplicate-cn requires --mode server");
if (options->cf_max || options->cf_per)
msg (M_USAGE, "--connect-freq requires --mode server");
- if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
- msg (M_USAGE, "--client-cert-not-required requires --mode server");
+ if (options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL))
+ msg (M_USAGE, "--client-cert-not-required and --verify-client-cert require --mode server");
if (options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)
msg (M_USAGE, "--username-as-common-name requires --mode server");
if (options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL)
@@ -2151,6 +2211,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
"tcp-nodelay in the server configuration instead.");
if (options->auth_user_pass_verify_script)
msg (M_USAGE, "--auth-user-pass-verify requires --mode server");
+ if (options->auth_token_generate)
+ msg (M_USAGE, "--auth-gen-token requires --mode server");
#if PORT_SHARE
if (options->port_share_host || options->port_share_port)
msg (M_USAGE, "--port-share requires TCP server mode (--mode server --proto tcp-server)");
@@ -2165,14 +2227,14 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
#ifdef ENABLE_CRYPTO
+ if (options->ncp_enabled && !tls_check_ncp_cipher_list(options->ncp_ciphers))
+ {
+ msg (M_USAGE, "NCP cipher list contains unsupported ciphers.");
+ }
+
/*
* Check consistency of replay options
*/
- if ((!proto_is_udp(ce->proto))
- && (options->replay_window != defaults.replay_window
- || options->replay_time != defaults.replay_time))
- msg (M_USAGE, "--replay-window only makes sense with --proto udp");
-
if (!options->replay
&& (options->replay_window != defaults.replay_window
|| options->replay_time != defaults.replay_time))
@@ -2181,16 +2243,24 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
/*
* SSL/TLS mode sanity checks.
*/
-
-#ifdef ENABLE_SSL
if (options->tls_server + options->tls_client +
(options->shared_secret_file != NULL) > 1)
msg (M_USAGE, "specify only one of --tls-server, --tls-client, or --secret");
- if (options->tls_server)
+ if (options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL))
+ {
+ msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION "
+ "--verify-client-cert none|optional (or --client-cert-not-required) "
+ "may accept clients which do not present a certificate");
+ }
+
+ if (options->key_method == 1)
{
- notnull (options->dh_file, "DH file (--dh)");
+ msg (M_WARN, "WARNING: --key-method 1 is deprecated and will be removed "
+ "in OpenVPN 2.5. By default --key-method 2 will be used if not set "
+ "in the configuration file, which is the recommended approach.");
}
+
if (options->tls_server || options->tls_client)
{
#ifdef ENABLE_PKCS11
@@ -2209,6 +2279,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
#ifdef MANAGMENT_EXTERNAL_KEY
if (options->management_flags & MF_EXTERNAL_KEY)
msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs11-provider is also specified.");
+ if (options->management_flags & MF_EXTERNAL_CERT)
+ msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs11-provider is also specified.");
#endif
if (options->pkcs12_file)
msg(M_USAGE, "Parameter --pkcs12 cannot be used when --pkcs11-provider is also specified.");
@@ -2224,6 +2296,13 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
{
msg (M_USAGE, "--key and --management-external-key are mutually exclusive");
}
+ else if((options->management_flags & MF_EXTERNAL_CERT))
+ {
+ if (options->cert_file)
+ msg (M_USAGE, "--cert and --management-external-cert are mutually exclusive");
+ else if(!(options->management_flags & MF_EXTERNAL_KEY))
+ msg (M_USAGE, "--management-external-cert must be used with --management-external-key");
+ }
else
#endif
#ifdef ENABLE_CRYPTOAPI
@@ -2240,14 +2319,16 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
#ifdef MANAGMENT_EXTERNAL_KEY
if (options->management_flags & MF_EXTERNAL_KEY)
msg(M_USAGE, "Parameter --management-external-key cannot be used when --cryptoapicert is also specified.");
+ if (options->management_flags & MF_EXTERNAL_CERT)
+ msg(M_USAGE, "Parameter --management-external-cert cannot be used when --cryptoapicert is also specified.");
#endif
}
else
#endif
if (options->pkcs12_file)
{
-#ifdef ENABLE_CRYPTO_POLARSSL
- msg(M_USAGE, "Parameter --pkcs12 cannot be used with the PolarSSL version version of OpenVPN.");
+#ifdef ENABLE_CRYPTO_MBEDTLS
+ msg(M_USAGE, "Parameter --pkcs12 cannot be used with the mbed TLS version version of OpenVPN.");
#else
if (options->ca_path)
msg(M_USAGE, "Parameter --capath cannot be used when --pkcs12 is also specified.");
@@ -2257,17 +2338,19 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg(M_USAGE, "Parameter --key cannot be used when --pkcs12 is also specified.");
#ifdef MANAGMENT_EXTERNAL_KEY
if (options->management_flags & MF_EXTERNAL_KEY)
- msg(M_USAGE, "Parameter --external-management-key cannot be used when --pkcs12 is also specified.");
+ msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs12 is also specified.");
+ if (options->management_flags & MF_EXTERNAL_CERT)
+ msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs12 is also specified.");
#endif
#endif
}
else
{
-#ifdef ENABLE_CRYPTO_POLARSSL
+#ifdef ENABLE_CRYPTO_MBEDTLS
if (!(options->ca_file))
msg(M_USAGE, "You must define CA file (--ca)");
if (options->ca_path)
- msg(M_USAGE, "Parameter --capath cannot be used with the PolarSSL version version of OpenVPN.");
+ msg(M_USAGE, "Parameter --capath cannot be used with the mbed TLS version version of OpenVPN.");
#else
if ((!(options->ca_file)) && (!(options->ca_path)))
msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)");
@@ -2275,14 +2358,14 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
if (pull)
{
- const int sum = (options->cert_file != NULL) +
+ const int sum =
#ifdef MANAGMENT_EXTERNAL_KEY
- ((options->priv_key_file != NULL) || (options->management_flags & MF_EXTERNAL_KEY));
+ ((options->cert_file != NULL) || (options->management_flags & MF_EXTERNAL_CERT)) +
+ ((options->priv_key_file != NULL) || (options->management_flags & MF_EXTERNAL_KEY));
#else
- (options->priv_key_file != NULL);
+ (options->cert_file != NULL) + (options->priv_key_file != NULL);
#endif
-
if (sum == 0)
{
#if P2MP
@@ -2299,6 +2382,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
}
else
{
+#ifdef MANAGMENT_EXTERNAL_KEY
+ if (!(options->management_flags & MF_EXTERNAL_CERT))
+#endif
notnull (options->cert_file, "certificate file (--cert) or PKCS#12 file (--pkcs12)");
#ifdef MANAGMENT_EXTERNAL_KEY
if (!(options->management_flags & MF_EXTERNAL_KEY))
@@ -2306,6 +2392,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
notnull (options->priv_key_file, "private key file (--key) or PKCS#12 file (--pkcs12)");
}
}
+ if (options->tls_auth_file && options->tls_crypt_file)
+ {
+ msg (M_USAGE, "--tls-auth and --tls-crypt are mutually exclusive");
+ }
}
else
{
@@ -2323,7 +2413,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
MUST_BE_UNDEF (dh_file);
MUST_BE_UNDEF (cert_file);
MUST_BE_UNDEF (priv_key_file);
-#ifndef ENABLE_CRYPTO_POLARSSL
+#ifndef ENABLE_CRYPTO_MBEDTLS
MUST_BE_UNDEF (pkcs12_file);
#endif
MUST_BE_UNDEF (cipher_list);
@@ -2337,6 +2427,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
MUST_BE_UNDEF (handshake_window);
MUST_BE_UNDEF (transition_window);
MUST_BE_UNDEF (tls_auth_file);
+ MUST_BE_UNDEF (tls_crypt_file);
MUST_BE_UNDEF (single_session);
#ifdef ENABLE_PUSH_PEER_INFO
MUST_BE_UNDEF (push_peer_info);
@@ -2353,16 +2444,12 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
MUST_BE_UNDEF (pkcs11_id);
MUST_BE_UNDEF (pkcs11_id_management);
#endif
-#if P2MP
- MUST_BE_UNDEF (server_poll_timeout);
-#endif
if (pull)
msg (M_USAGE, err, "--pull");
}
#undef MUST_BE_UNDEF
#endif /* ENABLE_CRYPTO */
-#endif /* ENABLE_SSL */
#if P2MP
if (options->auth_user_pass_file && !options->pull)
@@ -2380,35 +2467,29 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce)
#if P2MP_SERVER
if (o->server_defined || o->server_bridge_defined || o->server_bridge_proxy_dhcp)
{
- if (ce->proto == PROTO_TCPv4)
- ce->proto = PROTO_TCPv4_SERVER;
- else if (ce->proto == PROTO_TCPv6)
- ce->proto = PROTO_TCPv6_SERVER;
+ if (ce->proto == PROTO_TCP)
+ ce->proto = PROTO_TCP_SERVER;
}
#endif
#if P2MP
if (o->client)
{
- if (ce->proto == PROTO_TCPv4)
- ce->proto = PROTO_TCPv4_CLIENT;
- else if (ce->proto == PROTO_TCPv6)
- ce->proto = PROTO_TCPv6_CLIENT;
+ if (ce->proto == PROTO_TCP)
+ ce->proto = PROTO_TCP_CLIENT;
}
#endif
- if (ce->proto == PROTO_TCPv4_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined)
+ if (ce->proto == PROTO_TCP_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined)
ce->bind_local = false;
-#ifdef ENABLE_SOCKS
- if (ce->proto == PROTO_UDPv4 && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined)
+ if (ce->proto == PROTO_UDP && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined)
ce->bind_local = false;
-#endif
if (!ce->bind_local)
- ce->local_port = 0;
+ ce->local_port = NULL;
/* if protocol forcing is enabled, disable all protocols except for the forced one */
- if (o->proto_force >= 0 && proto_is_tcp(o->proto_force) != proto_is_tcp(ce->proto))
+ if (o->proto_force >= 0 && o->proto_force != ce->proto)
ce->flags |= CE_DISABLED;
/*
@@ -2445,7 +2526,9 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce)
static void
options_postprocess_mutate_invariant (struct options *options)
{
+#ifdef _WIN32
const int dev = dev_type_enum (options->dev, options->dev_type);
+#endif
/*
* In forking TCP server mode, you don't need to ifconfig
@@ -2454,7 +2537,7 @@ options_postprocess_mutate_invariant (struct options *options)
if (options->inetd == INETD_NOWAIT)
options->ifconfig_noexec = true;
-#ifdef WIN32
+#ifdef _WIN32
if ((dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP) && !options->route_delay_defined)
{
if (options->mode == MODE_POINT_TO_POINT)
@@ -2477,7 +2560,7 @@ options_postprocess_mutate_invariant (struct options *options)
*/
if (options->mode == MODE_SERVER)
{
-#ifdef WIN32
+#ifdef _WIN32
/*
* We need to explicitly set --tap-sleep because
* we do not schedule event timers in the top-level context.
@@ -2516,6 +2599,7 @@ options_postprocess_verify (const struct options *o)
static void
options_postprocess_mutate (struct options *o)
{
+ int i;
/*
* Process helper-type options which map to other, more complex
* sequences of options.
@@ -2529,48 +2613,57 @@ options_postprocess_mutate (struct options *o)
if (o->remote_list && !o->connection_list)
{
/*
- * For compatibility with 2.0.x, map multiple --remote options
- * into connection list (connection lists added in 2.1).
+ * Convert remotes into connection list
*/
- if (o->remote_list->len > 1 || o->force_connection_list)
- {
- const struct remote_list *rl = o->remote_list;
- int i;
- for (i = 0; i < rl->len; ++i)
- {
- const struct remote_entry *re = rl->array[i];
- struct connection_entry ce = o->ce;
- struct connection_entry *ace;
-
- ASSERT (re->remote);
- connection_entry_load_re (&ce, re);
- ace = alloc_connection_entry (o, M_USAGE);
- ASSERT (ace);
- *ace = ce;
- }
- }
- else if (o->remote_list->len == 1) /* one --remote option specified */
- {
- connection_entry_load_re (&o->ce, o->remote_list->array[0]);
- }
- else
- {
- ASSERT (0);
- }
+ const struct remote_list *rl = o->remote_list;
+ for (i = 0; i < rl->len; ++i)
+ {
+ const struct remote_entry *re = rl->array[i];
+ struct connection_entry ce = o->ce;
+ struct connection_entry *ace;
+
+ ASSERT (re->remote);
+ connection_entry_load_re (&ce, re);
+ ace = alloc_connection_entry (o, M_USAGE);
+ ASSERT (ace);
+ *ace = ce;
+ }
}
- if (o->connection_list)
+ else if(!o->remote_list && !o->connection_list)
{
- int i;
- for (i = 0; i < o->connection_list->len; ++i)
+ struct connection_entry *ace;
+ ace = alloc_connection_entry (o, M_USAGE);
+ ASSERT (ace);
+ *ace = o->ce;
+ }
+
+ ASSERT (o->connection_list);
+ for (i = 0; i < o->connection_list->len; ++i)
options_postprocess_mutate_ce (o, o->connection_list->array[i]);
-#if HTTP_PROXY_OVERRIDE
- if (o->http_proxy_override)
+#ifdef ENABLE_CRYPTO
+ if (o->tls_server)
+ {
+ /* Check that DH file is specified, or explicitly disabled */
+ notnull (o->dh_file, "DH file (--dh)");
+ if (streq (o->dh_file, "none"))
+ o->dh_file = NULL;
+ }
+
+ /* cipher negotiation (NCP) currently assumes --pull or --mode server */
+ if ( o->ncp_enabled &&
+ ! (o->pull || o->mode == MODE_SERVER) )
+ {
+ msg( M_WARN, "disabling NCP mode (--ncp-disable) because not "
+ "in P2MP client or server mode" );
+ o->ncp_enabled = false;
+ }
+#endif
+
+#if ENABLE_MANAGEMENT
+ if (o->http_proxy_override)
options_postprocess_http_proxy_override(o);
#endif
- }
- else
- options_postprocess_mutate_ce (o, &o->ce);
#ifdef ENABLE_CRYPTOAPI
if (o->cryptoapi_cert)
@@ -2609,6 +2702,7 @@ options_postprocess_mutate (struct options *o)
#define CHKACC_FILEXSTWR (1<<2) /** If file exists, is it writable? */
#define CHKACC_INLINE (1<<3) /** File is present if it's an inline file */
#define CHKACC_ACPTSTDIN (1<<4) /** If filename is stdin, it's allowed and "exists" */
+#define CHKACC_PRIVATE (1<<5) /** Warn if this (private) file is group/others accessible */
static bool
check_file_access(const int type, const char *file, const int mode, const char *opt)
@@ -2649,6 +2743,23 @@ check_file_access(const int type, const char *file, const int mode, const char *
if (platform_access (file, W_OK) != 0)
errcode = errno;
+ /* Warn if a given private file is group/others accessible. */
+ if (type & CHKACC_PRIVATE)
+ {
+ platform_stat_t st;
+ if (platform_stat (file, &st))
+ {
+ msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", file);
+ }
+#ifndef _WIN32
+ else
+ {
+ if (st.st_mode & (S_IRWXG|S_IRWXO))
+ msg (M_WARN, "WARNING: file '%s' is group or others accessible", file);
+ }
+#endif
+ }
+
/* Scream if an error is found */
if( errcode > 0 )
msg (M_NOPREFIX|M_OPTERR, "%s fails with '%s': %s",
@@ -2724,7 +2835,7 @@ check_cmd_access(const char *command, const char *opt, const char *chroot)
/* Extract executable path and arguments */
argv = argv_new ();
- argv_printf (&argv, "%sc", command);
+ argv_parse_cmd (&argv, command);
/* if an executable is specified then check it; otherwise, complain */
if (argv.argv[0])
@@ -2754,8 +2865,8 @@ options_postprocess_filechecks (struct options *options)
{
bool errs = false;
+#ifdef ENABLE_CRYPTO
/* ** SSL/TLS/crypto related files ** */
-#ifdef ENABLE_SSL
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->dh_file, R_OK, "--dh");
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->ca_file, R_OK, "--ca");
errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->ca_path, R_OK, "--capath");
@@ -2765,41 +2876,40 @@ options_postprocess_filechecks (struct options *options)
#ifdef MANAGMENT_EXTERNAL_KEY
if(!(options->management_flags & MF_EXTERNAL_KEY))
#endif
- errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->priv_key_file, R_OK,
- "--key");
- errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->pkcs12_file, R_OK,
- "--pkcs12");
+ {
+ errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE,
+ options->priv_key_file, R_OK, "--key");
+ }
+ errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE,
+ options->pkcs12_file, R_OK, "--pkcs12");
if (options->ssl_flags & SSLF_CRL_VERIFY_DIR)
errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK|X_OK,
"--crl-verify directory");
else
- errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK,
- "--crl-verify");
-
- errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->tls_auth_file, R_OK,
- "--tls-auth");
-#endif /* ENABLE_SSL */
-#ifdef ENABLE_CRYPTO
- errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->shared_secret_file, R_OK,
- "--secret");
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE|CHKACC_INLINE,
+ options->crl_file, R_OK, "--crl-verify");
+
+ errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE,
+ options->tls_auth_file, R_OK, "--tls-auth");
+ errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE,
+ options->tls_crypt_file, R_OK, "--tls-crypt");
+ errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE,
+ options->shared_secret_file, R_OK, "--secret");
errs |= check_file_access (CHKACC_DIRPATH|CHKACC_FILEXSTWR,
- options->packet_id_file, R_OK|W_OK, "--replay-persist");
-#endif /* ENABLE_CRYPTO */
-
+ options->packet_id_file, R_OK|W_OK, "--replay-persist");
/* ** Password files ** */
-#ifdef ENABLE_SSL
- errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN,
- options->key_pass_file, R_OK, "--askpass");
-#endif /* ENABLE_SSL */
+ errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE,
+ options->key_pass_file, R_OK, "--askpass");
+#endif /* ENABLE_CRYPTO */
#ifdef ENABLE_MANAGEMENT
- errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN,
+ errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE,
options->management_user_pass, R_OK,
"--management user/password file");
#endif /* ENABLE_MANAGEMENT */
#if P2MP
- errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN,
+ errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE,
options->auth_user_pass_file, R_OK,
"--auth-user-pass");
#endif /* P2MP */
@@ -2815,10 +2925,10 @@ options_postprocess_filechecks (struct options *options)
R_OK|W_OK, "--status");
/* ** Config related ** */
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tls_export_cert,
R_OK|W_OK|X_OK, "--tls-export-cert");
-#endif /* ENABLE_SSL */
+#endif /* ENABLE_CRYPTO */
#if P2MP_SERVER
errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->client_config_dir,
R_OK|X_OK, "--client-config-dir");
@@ -2872,18 +2982,16 @@ pre_pull_save (struct options *o)
o->pre_pull->routes_ipv6 = clone_route_ipv6_option_list(o->routes_ipv6, &o->gc);
o->pre_pull->routes_ipv6_defined = true;
}
-#ifdef ENABLE_CLIENT_NAT
if (o->client_nat)
{
o->pre_pull->client_nat = clone_client_nat_option_list(o->client_nat, &o->gc);
o->pre_pull->client_nat_defined = true;
}
-#endif
}
}
void
-pre_pull_restore (struct options *o)
+pre_pull_restore (struct options *o, struct gc_arena *gc)
{
const struct options_pre_pull *pp = o->pre_pull;
if (pp)
@@ -2895,7 +3003,7 @@ pre_pull_restore (struct options *o)
if (pp->routes_defined)
{
rol_check_alloc (o);
- copy_route_option_list (o->routes, pp->routes);
+ copy_route_option_list (o->routes, pp->routes, gc);
}
else
o->routes = NULL;
@@ -2903,12 +3011,11 @@ pre_pull_restore (struct options *o)
if (pp->routes_ipv6_defined)
{
rol6_check_alloc (o);
- copy_route_ipv6_option_list (o->routes_ipv6, pp->routes_ipv6);
+ copy_route_ipv6_option_list (o->routes_ipv6, pp->routes_ipv6, gc);
}
else
o->routes_ipv6 = NULL;
-#ifdef ENABLE_CLIENT_NAT
if (pp->client_nat_defined)
{
cnol_check_alloc (o);
@@ -2916,7 +3023,6 @@ pre_pull_restore (struct options *o)
}
else
o->client_nat = NULL;
-#endif
o->foreign_option_index = pp->foreign_option_index;
}
@@ -2929,6 +3035,37 @@ pre_pull_restore (struct options *o)
#ifdef ENABLE_OCC
+/**
+ * Calculate the link-mtu to advertise to our peer. The actual value is not
+ * relevant, because we will possibly perform data channel cipher negotiation
+ * after this, but older clients will log warnings if we do not supply them the
+ * value they expect. This assumes that the traditional cipher/auth directives
+ * in the config match the config of the peer.
+ */
+static size_t
+calc_options_string_link_mtu(const struct options *o, const struct frame *frame)
+{
+ size_t link_mtu = EXPANDED_SIZE (frame);
+#ifdef ENABLE_CRYPTO
+ if (o->pull || o->mode == MODE_SERVER)
+ {
+ struct frame fake_frame = *frame;
+ struct key_type fake_kt;
+ init_key_type (&fake_kt, o->ciphername, o->authname, o->keysize, true,
+ false);
+ frame_add_to_extra_frame (&fake_frame, -(crypto_max_overhead()));
+ crypto_adjust_frame_parameters (&fake_frame, &fake_kt, o->use_iv,
+ o->replay, cipher_kt_mode_ofb_cfb (fake_kt.cipher));
+ frame_finalize(&fake_frame, o->ce.link_mtu_defined, o->ce.link_mtu,
+ o->ce.tun_mtu_defined, o->ce.tun_mtu);
+ msg (D_MTU_DEBUG, "%s: link-mtu %u -> %d", __func__, (unsigned int) link_mtu,
+ EXPANDED_SIZE (&fake_frame));
+ link_mtu = EXPANDED_SIZE (&fake_frame);
+ }
+#endif
+ return link_mtu;
+}
+
/*
* Build an options string to represent data channel encryption options.
* This string must match exactly between peers. The keysize is checked
@@ -2953,6 +3090,7 @@ pre_pull_restore (struct options *o)
* the other end of the connection]
*
* --comp-lzo
+ * --compress alg
* --fragment
*
* Crypto Options:
@@ -2972,7 +3110,6 @@ pre_pull_restore (struct options *o)
* --tls-server [matched with --tls-client on
* the other end of the connection]
*/
-
char *
options_string (const struct options *o,
const struct frame *frame,
@@ -2990,14 +3127,14 @@ options_string (const struct options *o,
*/
buf_printf (&out, ",dev-type %s", dev_type_string (o->dev, o->dev_type));
- buf_printf (&out, ",link-mtu %d", EXPANDED_SIZE (frame));
+ buf_printf (&out, ",link-mtu %u", (unsigned int) calc_options_string_link_mtu(o, frame));
buf_printf (&out, ",tun-mtu %d", PAYLOAD_SIZE (frame));
- buf_printf (&out, ",proto %s", proto2ascii (proto_remote (o->ce.proto, remote), true));
+ buf_printf (&out, ",proto %s", proto_remote (o->ce.proto, remote));
/* send tun_ipv6 only in peer2peer mode - in client/server mode, it
* is usually pushed by the server, triggering a non-helpful warning
*/
- if (o->tun_ipv6 && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o))
+ if (o->ifconfig_ipv6_local && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o))
buf_printf (&out, ",tun-ipv6");
/*
@@ -3014,8 +3151,8 @@ options_string (const struct options *o,
o->ifconfig_ipv6_local,
o->ifconfig_ipv6_netbits,
o->ifconfig_ipv6_remote,
- (in_addr_t)0,
- (in_addr_t)0,
+ NULL,
+ NULL,
false,
NULL);
if (tt)
@@ -3034,9 +3171,9 @@ options_string (const struct options *o,
tt = NULL;
}
-#ifdef ENABLE_LZO
- if (o->lzo & LZO_SELECTED)
- buf_printf (&out, ",comp-lzo");
+#ifdef USE_COMP
+ if (o->comp.alg != COMP_ALG_UNDEF)
+ buf_printf (&out, ",comp-lzo"); /* for compatibility, this simply indicates that compression context is active, not necessarily LZO per-se */
#endif
#ifdef ENABLE_FRAGMENT
@@ -3046,13 +3183,8 @@ options_string (const struct options *o,
#ifdef ENABLE_CRYPTO
-#ifdef ENABLE_SSL
#define TLS_CLIENT (o->tls_client)
#define TLS_SERVER (o->tls_server)
-#else
-#define TLS_CLIENT (false)
-#define TLS_SERVER (false)
-#endif
/*
* Key direction
@@ -3075,11 +3207,11 @@ options_string (const struct options *o,
+ (TLS_SERVER == true)
<= 1);
- init_key_type (&kt, o->ciphername, o->ciphername_defined,
- o->authname, o->authname_defined,
- o->keysize, true, false);
+ init_key_type (&kt, o->ciphername, o->authname, o->keysize, true,
+ false);
- buf_printf (&out, ",cipher %s", cipher_kt_name (kt.cipher));
+ buf_printf (&out, ",cipher %s",
+ translate_cipher_name_to_openvpn(cipher_kt_name (kt.cipher)));
buf_printf (&out, ",auth %s", md_kt_name (kt.digest));
buf_printf (&out, ",keysize %d", kt.cipher_length * 8);
if (o->shared_secret_file)
@@ -3095,7 +3227,6 @@ options_string (const struct options *o,
#endif
}
-#ifdef ENABLE_SSL
/*
* SSL Options
*/
@@ -3104,6 +3235,9 @@ options_string (const struct options *o,
{
if (o->tls_auth_file)
buf_printf (&out, ",tls-auth");
+ /* Not adding tls-crypt here, because we won't reach this code if
+ * tls-auth/tls-crypt does not match. Removing tls-auth here would
+ * break stuff, so leaving that in place. */
if (o->key_method > 1)
buf_printf (&out, ",key-method %d", o->key_method);
@@ -3124,7 +3258,6 @@ options_string (const struct options *o,
buf_printf (&out, ",tls-server");
}
}
-#endif /* ENABLE_SSL */
#undef TLS_CLIENT
#undef TLS_SERVER
@@ -3447,10 +3580,11 @@ usage (void)
struct options o;
init_options (&o, true);
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
fprintf (fp, usage_message,
title_string,
o.ce.connect_retry_seconds,
+ o.ce.connect_retry_seconds_max,
o.ce.local_port, o.ce.remote_port,
TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT,
o.verbosity,
@@ -3458,15 +3592,6 @@ usage (void)
o.replay_window, o.replay_time,
o.tls_timeout, o.renegotiate_seconds,
o.handshake_window, o.transition_window);
-#elif defined(ENABLE_CRYPTO)
- fprintf (fp, usage_message,
- title_string,
- o.ce.connect_retry_seconds,
- o.ce.local_port, o.ce.remote_port,
- TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT,
- o.verbosity,
- o.authname, o.ciphername,
- o.replay_window, o.replay_time);
#else
fprintf (fp, usage_message,
title_string,
@@ -3489,7 +3614,7 @@ usage_small (void)
openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
}
-#ifdef WIN32
+#ifdef _WIN32
void show_windows_version(const unsigned int flags)
{
struct gc_arena gc = gc_new ();
@@ -3501,7 +3626,7 @@ void show_windows_version(const unsigned int flags)
void
show_library_versions(const unsigned int flags)
{
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
#define SSL_LIB_VER_STR get_ssl_library_version()
#else
#define SSL_LIB_VER_STR ""
@@ -3523,7 +3648,7 @@ usage_version (void)
{
msg (M_INFO|M_NOPREFIX, "%s", title_string);
show_library_versions( M_INFO|M_NOPREFIX );
-#ifdef WIN32
+#ifdef _WIN32
show_windows_version( M_INFO|M_NOPREFIX );
#endif
msg (M_INFO|M_NOPREFIX, "Originally developed by James Yonan");
@@ -3535,9 +3660,6 @@ usage_version (void)
#ifdef CONFIGURE_SPECIAL_BUILD
msg (M_INFO|M_NOPREFIX, "special build: %s", CONFIGURE_SPECIAL_BUILD);
#endif
-#ifdef CONFIGURE_GIT_REVISION
- msg (M_INFO|M_NOPREFIX, "git revision: %s", CONFIGURE_GIT_REVISION);
-#endif
#endif
openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
}
@@ -3573,7 +3695,7 @@ positive_atoi (const char *str)
return i < 0 ? 0 : i;
}
-#ifdef WIN32 /* This function is only used when compiling on Windows */
+#ifdef _WIN32 /* This function is only used when compiling on Windows */
static unsigned int
atou (const char *str)
{
@@ -3809,7 +3931,7 @@ read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc)
buf_printf (&buf, "%s", line);
}
if (!endtagfound)
- msg (M_WARN, "WARNING: Endtag %s missing", close_tag);
+ msg (M_FATAL, "ERROR: Endtag %s missing", close_tag);
ret = string_alloc (BSTR (&buf), gc);
buf_clear (&buf);
free_buf (&buf);
@@ -4019,6 +4141,45 @@ parse_argv (struct options *options,
}
}
+/**
+ * Filter an option line by all pull filters.
+ *
+ * If a match is found, the line is modified depending on
+ * the filter type, and returns true. If the filter type is
+ * reject, SIGUSR1 is triggered and the return value is false.
+ * In that case the caller must end the push processing.
+ */
+static bool
+apply_pull_filter (const struct options *o, char *line)
+{
+ struct pull_filter *f;
+
+ if (!o->pull_filter_list) return true;
+
+ for (f = o->pull_filter_list->head; f; f = f->next)
+ {
+ if (f->type == PUF_TYPE_ACCEPT && strncmp (line, f->pattern, f->size) == 0)
+ {
+ msg (D_LOW, "Pushed option accepted by filter: '%s'", line);
+ return true;
+ }
+ else if (f->type == PUF_TYPE_IGNORE && strncmp (line, f->pattern, f->size) == 0)
+ {
+ msg (D_PUSH, "Pushed option removed by filter: '%s'", line);
+ *line = '\0';
+ return true;
+ }
+ else if (f->type == PUF_TYPE_REJECT && strncmp (line, f->pattern, f->size) == 0)
+ {
+ msg (M_WARN, "Pushed option rejected by filter: '%s'. Restarting.", line);
+ *line = '\0';
+ throw_signal_soft (SIGUSR1, "Offending option received from server");
+ return false;
+ }
+ }
+ return true;
+}
+
bool
apply_push_options (struct options *options,
struct buffer *buf,
@@ -4036,6 +4197,10 @@ apply_push_options (struct options *options,
char *p[MAX_PARMS];
CLEAR (p);
++line_num;
+ if (!apply_pull_filter(options, line))
+ {
+ return false; /* Cause push/pull error and stop push processing */
+ }
if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc))
{
add_option (options, p, file, line_num, 0, msglevel, permission_mask, option_types_found, es);
@@ -4222,13 +4387,18 @@ add_option (struct options *options,
{
VERIFY_PERMISSION (OPT_P_GENERAL);
usage ();
+ if (p[1])
+ {
+ msg (msglevel, "--help does not accept any parameters");
+ goto err;
+ }
}
- if (streq (p[0], "version"))
+ if (streq (p[0], "version") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
usage_version ();
}
- else if (streq (p[0], "config") && p[1])
+ else if (streq (p[0], "config") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_CONFIG);
@@ -4239,12 +4409,17 @@ add_option (struct options *options,
read_config_file (options, p[1], level, file, line, msglevel, permission_mask, option_types_found, es);
}
#if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL)
- else if (streq (p[0], "show-gateway"))
+ else if (streq (p[0], "show-gateway") && !p[2])
{
struct route_gateway_info rgi;
+ struct route_ipv6_gateway_info rgi6;
+ struct in6_addr remote = IN6ADDR_ANY_INIT;
VERIFY_PERMISSION (OPT_P_GENERAL);
+ if (p[1])
+ get_ipv6_addr (p[1], &remote, NULL, M_WARN);
get_default_gateway(&rgi);
- print_default_gateway(M_INFO, &rgi);
+ get_default_gateway_ipv6(&rgi6, &remote);
+ print_default_gateway(M_INFO, &rgi, &rgi6);
openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
}
#endif
@@ -4289,10 +4464,8 @@ add_option (struct options *options,
msg (M_WARN, "echo/parameter option overflow");
}
#ifdef ENABLE_MANAGEMENT
- else if (streq (p[0], "management") && p[1] && p[2])
+ else if (streq (p[0], "management") && p[1] && p[2] && !p[4])
{
- int port = 0;
-
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[2], "unix"))
{
@@ -4303,104 +4476,93 @@ add_option (struct options *options,
goto err;
#endif
}
- else
- {
- port = atoi (p[2]);
- if (!legal_ipv4_port (port))
- {
- msg (msglevel, "port number associated with --management directive is out of range");
- goto err;
- }
- }
options->management_addr = p[1];
- options->management_port = port;
+ options->management_port = p[2];
if (p[3])
{
options->management_user_pass = p[3];
}
}
- else if (streq (p[0], "management-client-user") && p[1])
+ else if (streq (p[0], "management-client-user") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_client_user = p[1];
}
- else if (streq (p[0], "management-client-group") && p[1])
+ else if (streq (p[0], "management-client-group") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_client_group = p[1];
}
- else if (streq (p[0], "management-query-passwords"))
+ else if (streq (p[0], "management-query-passwords") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_QUERY_PASSWORDS;
}
- else if (streq (p[0], "management-query-remote"))
+ else if (streq (p[0], "management-query-remote") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_QUERY_REMOTE;
}
- else if (streq (p[0], "management-query-proxy"))
+ else if (streq (p[0], "management-query-proxy") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_QUERY_PROXY;
- options->force_connection_list = true;
}
- else if (streq (p[0], "management-hold"))
+ else if (streq (p[0], "management-hold") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_HOLD;
}
- else if (streq (p[0], "management-signal"))
+ else if (streq (p[0], "management-signal") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_SIGNAL;
}
- else if (streq (p[0], "management-forget-disconnect"))
+ else if (streq (p[0], "management-forget-disconnect") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_FORGET_DISCONNECT;
}
- else if (streq (p[0], "management-up-down"))
+ else if (streq (p[0], "management-up-down") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_UP_DOWN;
}
- else if (streq (p[0], "management-client"))
+ else if (streq (p[0], "management-client") && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_CONNECT_AS_CLIENT;
options->management_write_peer_info_file = p[1];
}
#ifdef MANAGMENT_EXTERNAL_KEY
- else if (streq (p[0], "management-external-key"))
+ else if (streq (p[0], "management-external-key") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= MF_EXTERNAL_KEY;
}
-#endif
-#ifdef MANAGEMENT_DEF_AUTH
- else if (streq (p[0], "management-client-auth"))
+ else if (streq (p[0], "management-external-cert") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
- options->management_flags |= MF_CLIENT_AUTH;
+ options->management_flags |= MF_EXTERNAL_CERT;
+ options->management_certificate = p[1];
}
#endif
-#ifdef ENABLE_X509_TRACK
- else if (streq (p[0], "x509-track") && p[1])
+#ifdef MANAGEMENT_DEF_AUTH
+ else if (streq (p[0], "management-client-auth") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
- x509_track_add (&options->x509_track, p[1], msglevel, &options->gc);
+ options->management_flags |= MF_CLIENT_AUTH;
}
#endif
#ifdef MANAGEMENT_PF
- else if (streq (p[0], "management-client-pf"))
+ else if (streq (p[0], "management-client-pf") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->management_flags |= (MF_CLIENT_PF | MF_CLIENT_AUTH);
}
#endif
- else if (streq (p[0], "management-log-cache") && p[1])
+ else if (streq (p[0], "management-log-cache") && p[1] && !p[2])
{
int cache;
@@ -4415,7 +4577,7 @@ add_option (struct options *options,
}
#endif
#ifdef ENABLE_PLUGIN
- else if (streq (p[0], "plugin") && p[1])
+ else if (streq (p[0], "plugin") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_PLUGIN);
if (!options->plugin_list)
@@ -4427,7 +4589,7 @@ add_option (struct options *options,
}
}
#endif
- else if (streq (p[0], "mode") && p[1])
+ else if (streq (p[0], "mode") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], "p2p"))
@@ -4442,22 +4604,22 @@ add_option (struct options *options,
goto err;
}
}
- else if (streq (p[0], "dev") && p[1])
+ else if (streq (p[0], "dev") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->dev = p[1];
}
- else if (streq (p[0], "dev-type") && p[1])
+ else if (streq (p[0], "dev-type") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->dev_type = p[1];
}
- else if (streq (p[0], "dev-node") && p[1])
+ else if (streq (p[0], "dev-node") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->dev_node = p[1];
}
- else if (streq (p[0], "lladdr") && p[1])
+ else if (streq (p[0], "lladdr") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_UP);
if (mac_addr_safe (p[1])) /* MAC address only */
@@ -4468,24 +4630,24 @@ add_option (struct options *options,
goto err;
}
}
- else if (streq (p[0], "topology") && p[1])
+ else if (streq (p[0], "topology") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_UP);
options->topology = parse_topology (p[1], msglevel);
}
- else if (streq (p[0], "tun-ipv6"))
+ else if (streq (p[0], "tun-ipv6") && !p[1])
{
VERIFY_PERMISSION (OPT_P_UP);
- options->tun_ipv6 = true;
+ msg (M_WARN, "Note: option tun-ipv6 is ignored because modern operating systems do not need special IPv6 tun handling anymore.");
}
#ifdef ENABLE_IPROUTE
- else if (streq (p[0], "iproute") && p[1])
+ else if (streq (p[0], "iproute") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
iproute_path = p[1];
}
#endif
- else if (streq (p[0], "ifconfig") && p[1] && p[2])
+ else if (streq (p[0], "ifconfig") && p[1] && p[2] && !p[3])
{
VERIFY_PERMISSION (OPT_P_UP);
if (ip_or_dns_addr_safe (p[1], options->allow_pull_fqdn) && ip_or_dns_addr_safe (p[2], options->allow_pull_fqdn)) /* FQDN -- may be DNS name */
@@ -4499,7 +4661,7 @@ add_option (struct options *options,
goto err;
}
}
- else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] )
+ else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] && !p[3])
{
unsigned int netbits;
@@ -4523,27 +4685,27 @@ add_option (struct options *options,
goto err;
}
}
- else if (streq (p[0], "ifconfig-noexec"))
+ else if (streq (p[0], "ifconfig-noexec") && !p[1])
{
VERIFY_PERMISSION (OPT_P_UP);
options->ifconfig_noexec = true;
}
- else if (streq (p[0], "ifconfig-nowarn"))
+ else if (streq (p[0], "ifconfig-nowarn") && !p[1])
{
VERIFY_PERMISSION (OPT_P_UP);
options->ifconfig_nowarn = true;
}
- else if (streq (p[0], "local") && p[1])
+ else if (streq (p[0], "local") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.local = p[1];
}
- else if (streq (p[0], "remote-random"))
+ else if (streq (p[0], "remote-random") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->remote_random = true;
}
- else if (streq (p[0], "connection") && p[1])
+ else if (streq (p[0], "connection") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], INLINE_FILE_TAG) && p[2])
@@ -4605,47 +4767,38 @@ add_option (struct options *options,
options->ignore_unknown_option[i] = NULL;
}
- else if (streq (p[0], "remote-ip-hint") && p[1])
- {
- VERIFY_PERMISSION (OPT_P_GENERAL);
- options->remote_ip_hint = p[1];
- }
-#if HTTP_PROXY_OVERRIDE
- else if (streq (p[0], "http-proxy-override") && p[1] && p[2])
+#if ENABLE_MANAGEMENT
+ else if (streq (p[0], "http-proxy-override") && p[1] && p[2] && !p[4])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->http_proxy_override = parse_http_proxy_override(p[1], p[2], p[3], msglevel, &options->gc);
if (!options->http_proxy_override)
goto err;
- options->force_connection_list = true;
}
#endif
- else if (streq (p[0], "remote") && p[1])
+ else if (streq (p[0], "remote") && p[1] && !p[4])
{
struct remote_entry re;
- re.remote = NULL;
- re.remote_port = re.proto = -1;
+ re.remote = re.remote_port= NULL;
+ re.proto = -1;
+ re.af=0;
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
re.remote = p[1];
if (p[2])
{
- const int port = atoi (p[2]);
- if (!legal_ipv4_port (port))
- {
- msg (msglevel, "remote: port number associated with host %s is out of range", p[1]);
- goto err;
- }
- re.remote_port = port;
+ re.remote_port = p[2];
if (p[3])
{
const int proto = ascii2proto (p[3]);
+ const sa_family_t af = ascii2af (p[3]);
if (proto < 0)
{
msg (msglevel, "remote: bad protocol associated with host %s: '%s'", p[1], p[3]);
goto err;
}
re.proto = proto;
+ re.af = af;
}
}
if (permission_mask & OPT_P_GENERAL)
@@ -4660,7 +4813,7 @@ add_option (struct options *options,
connection_entry_load_re (&options->ce, &re);
}
}
- else if (streq (p[0], "resolv-retry") && p[1])
+ else if (streq (p[0], "resolv-retry") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], "infinite"))
@@ -4668,22 +4821,44 @@ add_option (struct options *options,
else
options->resolve_retry_seconds = positive_atoi (p[1]);
}
- else if (streq (p[0], "connect-retry") && p[1])
+ else if ((streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint")) && !p[2])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->resolve_in_advance = true;
+ /* Note the ip-remote-hint and the argument p[1] are for
+ backward compatibility */
+ if (p[1])
+ options->ip_remote_hint=p[1];
+ }
+ else if (streq (p[0], "connect-retry") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.connect_retry_seconds = positive_atoi (p[1]);
- options->ce.connect_retry_defined = true;
+ /*
+ * Limit the base value of retry wait interval to 16 bits to avoid
+ * overflow when scaled up for exponential backoff
+ */
+ if (options->ce.connect_retry_seconds > 0xFFFF)
+ {
+ options->ce.connect_retry_seconds = 0xFFFF;
+ msg (M_WARN, "connect retry wait interval truncated to %d",
+ options->ce.connect_retry_seconds);
+ }
+
+ if (p[2])
+ options->ce.connect_retry_seconds_max =
+ max_int (positive_atoi (p[2]), options->ce.connect_retry_seconds);
}
- else if (streq (p[0], "connect-timeout") && p[1])
+ else if ((streq (p[0], "connect-timeout") || streq (p[0], "server-poll-timeout"))
+ && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.connect_timeout = positive_atoi (p[1]);
- options->ce.connect_timeout_defined = true;
}
- else if (streq (p[0], "connect-retry-max") && p[1])
+ else if (streq (p[0], "connect-retry-max") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
- options->ce.connect_retry_max = positive_atoi (p[1]);
+ options->connect_retry_max = positive_atoi (p[1]);
}
else if (streq (p[0], "ipchange") && p[1])
{
@@ -4695,24 +4870,24 @@ add_option (struct options *options,
string_substitute (p[1], ',', ' ', &options->gc),
"ipchange", true);
}
- else if (streq (p[0], "float"))
+ else if (streq (p[0], "float") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.remote_float = true;
}
#ifdef ENABLE_DEBUG
- else if (streq (p[0], "gremlin") && p[1])
+ else if (streq (p[0], "gremlin") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->gremlin = positive_atoi (p[1]);
}
#endif
- else if (streq (p[0], "chroot") && p[1])
+ else if (streq (p[0], "chroot") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->chroot_dir = p[1];
}
- else if (streq (p[0], "cd") && p[1])
+ else if (streq (p[0], "cd") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (platform_chdir (p[1]))
@@ -4723,13 +4898,13 @@ add_option (struct options *options,
options->cd_dir = p[1];
}
#ifdef ENABLE_SELINUX
- else if (streq (p[0], "setcon") && p[1])
+ else if (streq (p[0], "setcon") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->selinux_context = p[1];
}
#endif
- else if (streq (p[0], "writepid") && p[1])
+ else if (streq (p[0], "writepid") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->writepid = p[1];
@@ -4748,27 +4923,27 @@ add_option (struct options *options,
goto err;
set_user_script (options, &options->down_script, p[1], "down", true);
}
- else if (streq (p[0], "down-pre"))
+ else if (streq (p[0], "down-pre") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->down_pre = true;
}
- else if (streq (p[0], "up-delay"))
+ else if (streq (p[0], "up-delay") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->up_delay = true;
}
- else if (streq (p[0], "up-restart"))
+ else if (streq (p[0], "up-restart") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->up_restart = true;
}
- else if (streq (p[0], "syslog"))
+ else if (streq (p[0], "syslog") && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
open_syslog (p[1], false);
}
- else if (streq (p[0], "daemon"))
+ else if (streq (p[0], "daemon") && !p[2])
{
bool didit = false;
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -4786,7 +4961,7 @@ add_option (struct options *options,
}
}
}
- else if (streq (p[0], "inetd"))
+ else if (streq (p[0], "inetd") && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (!options->inetd)
@@ -4841,44 +5016,50 @@ add_option (struct options *options,
open_syslog (name, true);
}
}
- else if (streq (p[0], "log") && p[1])
+ else if (streq (p[0], "log") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->log = true;
redirect_stdout_stderr (p[1], false);
}
- else if (streq (p[0], "suppress-timestamps"))
+ else if (streq (p[0], "suppress-timestamps") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->suppress_timestamps = true;
set_suppress_timestamps(true);
}
- else if (streq (p[0], "log-append") && p[1])
+ else if (streq (p[0], "machine-readable-output") && !p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->machine_readable_output = true;
+ set_machine_readable_output(true);
+ }
+ else if (streq (p[0], "log-append") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->log = true;
redirect_stdout_stderr (p[1], true);
}
#ifdef ENABLE_MEMSTATS
- else if (streq (p[0], "memstats") && p[1])
+ else if (streq (p[0], "memstats") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->memstats_fn = p[1];
}
#endif
- else if (streq (p[0], "mlock"))
+ else if (streq (p[0], "mlock") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->mlock = true;
}
#if ENABLE_IP_PKTINFO
- else if (streq (p[0], "multihome"))
+ else if (streq (p[0], "multihome") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->sockflags |= SF_USE_IP_PKTINFO;
}
#endif
- else if (streq (p[0], "verb") && p[1])
+ else if (streq (p[0], "verb") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_MESSAGES);
options->verbosity = positive_atoi (p[1]);
@@ -4889,17 +5070,17 @@ add_option (struct options *options,
options->verbosity);
#endif
}
- else if (streq (p[0], "mute") && p[1])
+ else if (streq (p[0], "mute") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_MESSAGES);
options->mute = positive_atoi (p[1]);
}
- else if (streq (p[0], "errors-to-stderr"))
+ else if (streq (p[0], "errors-to-stderr") && !p[1])
{
VERIFY_PERMISSION (OPT_P_MESSAGES);
errors_to_stderr();
}
- else if (streq (p[0], "status") && p[1])
+ else if (streq (p[0], "status") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->status_file = p[1];
@@ -4908,7 +5089,7 @@ add_option (struct options *options,
options->status_file_update_freq = positive_atoi (p[2]);
}
}
- else if (streq (p[0], "status-version") && p[1])
+ else if (streq (p[0], "status-version") && p[1] && !p[2])
{
int version;
@@ -4921,7 +5102,7 @@ add_option (struct options *options,
}
options->status_file_version = version;
}
- else if (streq (p[0], "remap-usr1") && p[1])
+ else if (streq (p[0], "remap-usr1") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], "SIGHUP"))
@@ -4934,19 +5115,19 @@ add_option (struct options *options,
goto err;
}
}
- else if ((streq (p[0], "link-mtu") || streq (p[0], "udp-mtu")) && p[1])
+ else if ((streq (p[0], "link-mtu") || streq (p[0], "udp-mtu")) && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION);
options->ce.link_mtu = positive_atoi (p[1]);
options->ce.link_mtu_defined = true;
}
- else if (streq (p[0], "tun-mtu") && p[1])
+ else if (streq (p[0], "tun-mtu") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION);
options->ce.tun_mtu = positive_atoi (p[1]);
options->ce.tun_mtu_defined = true;
}
- else if (streq (p[0], "tun-mtu-extra") && p[1])
+ else if (streq (p[0], "tun-mtu-extra") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION);
options->ce.tun_mtu_extra = positive_atoi (p[1]);
@@ -4959,41 +5140,41 @@ add_option (struct options *options,
msg (msglevel, "--mtu-dynamic has been replaced by --fragment");
goto err;
}
- else if (streq (p[0], "fragment") && p[1])
+ else if (streq (p[0], "fragment") && p[1] && !p[2])
{
/* VERIFY_PERMISSION (OPT_P_MTU); */
VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION);
options->ce.fragment = positive_atoi (p[1]);
}
#endif
- else if (streq (p[0], "mtu-disc") && p[1])
+ else if (streq (p[0], "mtu-disc") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION);
options->ce.mtu_discover_type = translate_mtu_discover_type_name (p[1]);
}
#ifdef ENABLE_OCC
- else if (streq (p[0], "mtu-test"))
+ else if (streq (p[0], "mtu-test") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->mtu_test = true;
}
#endif
- else if (streq (p[0], "nice") && p[1])
+ else if (streq (p[0], "nice") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_NICE);
options->nice = atoi (p[1]);
}
- else if (streq (p[0], "rcvbuf") && p[1])
+ else if (streq (p[0], "rcvbuf") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_SOCKBUF);
options->rcvbuf = positive_atoi (p[1]);
}
- else if (streq (p[0], "sndbuf") && p[1])
+ else if (streq (p[0], "sndbuf") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_SOCKBUF);
options->sndbuf = positive_atoi (p[1]);
}
- else if (streq (p[0], "mark") && p[1])
+ else if (streq (p[0], "mark") && p[1] && !p[2])
{
#if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -5012,7 +5193,7 @@ add_option (struct options *options,
msg (msglevel, "unknown socket flag: %s", p[j]);
}
}
- else if (streq (p[0], "txqueuelen") && p[1])
+ else if (streq (p[0], "txqueuelen") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
#ifdef TARGET_LINUX
@@ -5022,7 +5203,7 @@ add_option (struct options *options,
goto err;
#endif
}
- else if (streq (p[0], "shaper") && p[1])
+ else if (streq (p[0], "shaper") && p[1] && !p[2])
{
#ifdef ENABLE_FEATURE_SHAPER
int shaper;
@@ -5042,73 +5223,54 @@ add_option (struct options *options,
goto err;
#endif /* ENABLE_FEATURE_SHAPER */
}
- else if (streq (p[0], "port") && p[1])
+ else if (streq (p[0], "port") && p[1] && !p[2])
{
- int port;
-
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
- port = atoi (p[1]);
- if (!legal_ipv4_port (port))
- {
- msg (msglevel, "Bad port number: %s", p[1]);
- goto err;
- }
- options->ce.local_port = options->ce.remote_port = port;
+ options->ce.local_port = options->ce.remote_port = p[1];
}
- else if (streq (p[0], "lport") && p[1])
+ else if (streq (p[0], "lport") && p[1] && !p[2])
{
- int port;
-
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
- port = atoi (p[1]);
- if ((port != 0) && !legal_ipv4_port (port))
- {
- msg (msglevel, "Bad local port number: %s", p[1]);
- goto err;
- }
options->ce.local_port_defined = true;
- options->ce.local_port = port;
+ options->ce.local_port = p[1];
}
- else if (streq (p[0], "rport") && p[1])
+ else if (streq (p[0], "rport") && p[1] && !p[2])
{
- int port;
-
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
- port = atoi (p[1]);
- if (!legal_ipv4_port (port))
- {
- msg (msglevel, "Bad remote port number: %s", p[1]);
- goto err;
- }
- options->ce.remote_port = port;
+ options->ce.remote_port = p[1];
}
- else if (streq (p[0], "bind"))
+ else if (streq (p[0], "bind") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.bind_defined = true;
+ if (p[1] && streq (p[1], "ipv6only"))
+ options->ce.bind_ipv6_only=true;
+
}
- else if (streq (p[0], "nobind"))
+ else if (streq (p[0], "nobind") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.bind_local = false;
}
- else if (streq (p[0], "fast-io"))
+ else if (streq (p[0], "fast-io") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->fast_io = true;
}
- else if (streq (p[0], "inactive") && p[1])
+ else if (streq (p[0], "inactive") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_TIMER);
options->inactivity_timeout = positive_atoi (p[1]);
if (p[2])
options->inactivity_minimum_bytes = positive_atoi (p[2]);
}
- else if (streq (p[0], "proto") && p[1])
+ else if (streq (p[0], "proto") && p[1] && !p[2])
{
int proto;
+ sa_family_t af;
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
proto = ascii2proto (p[1]);
+ af = ascii2af(p[1]);
if (proto < 0)
{
msg (msglevel, "Bad protocol: '%s'. Allowed protocols with --proto option: %s",
@@ -5117,8 +5279,9 @@ add_option (struct options *options,
goto err;
}
options->ce.proto = proto;
+ options->ce.af = af;
}
- else if (streq (p[0], "proto-force") && p[1])
+ else if (streq (p[0], "proto-force") && p[1] && !p[2])
{
int proto_force;
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -5129,33 +5292,24 @@ add_option (struct options *options,
goto err;
}
options->proto_force = proto_force;
- options->force_connection_list = true;
}
-#ifdef ENABLE_HTTP_PROXY
- else if (streq (p[0], "http-proxy") && p[1])
+ else if (streq (p[0], "http-proxy") && p[1] && !p[5])
{
struct http_proxy_options *ho;
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
{
- int port;
if (!p[2])
{
msg (msglevel, "http-proxy port number not defined");
goto err;
}
- port = atoi (p[2]);
- if (!legal_ipv4_port (port))
- {
- msg (msglevel, "Bad http-proxy port number: %s", p[2]);
- goto err;
- }
ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc);
ho->server = p[1];
- ho->port = port;
+ ho->port = p[2];
}
if (p[3])
@@ -5183,101 +5337,124 @@ add_option (struct options *options,
ho->auth_method_string = "none";
}
}
- else if (streq (p[0], "http-proxy-retry"))
+ else if (streq (p[0], "http-proxy-user-pass") && p[1])
{
struct http_proxy_options *ho;
- VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc);
- ho->retry = true;
+ if (streq (p[1], INLINE_FILE_TAG) && p[2])
+ {
+ ho->auth_file = p[2];
+ ho->inline_creds = true;
+ }
+ else
+ ho->auth_file = p[1];
}
- else if (streq (p[0], "http-proxy-timeout") && p[1])
+ else if (streq (p[0], "http-proxy-retry") || streq (p[0], "socks-proxy-retry"))
{
- struct http_proxy_options *ho;
-
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
- ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc);
- ho->timeout = positive_atoi (p[1]);
+ msg (M_WARN, "DEPRECATED OPTION: http-proxy-retry and socks-proxy-retry: "
+ "In OpenVPN 2.4 proxy connection retries are handled like regular connections. "
+ "Use connect-retry-max 1 to get a similar behavior as before.");
}
- else if (streq (p[0], "http-proxy-option") && p[1])
+ else if (streq (p[0], "http-proxy-timeout") && p[1] && !p[2])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
+ msg (M_WARN, "DEPRECATED OPTION: http-proxy-timeout: In OpenVPN 2.4 the timeout until a connection to a "
+ "server is established is managed with a single timeout set by connect-timeout");
+ }
+ else if (streq (p[0], "http-proxy-option") && p[1] && !p[4])
{
struct http_proxy_options *ho;
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc);
- if (streq (p[1], "VERSION") && p[2])
+ if (streq (p[1], "VERSION") && p[2] && !p[3])
{
ho->http_version = p[2];
}
- else if (streq (p[1], "AGENT") && p[2])
+ else if (streq (p[1], "AGENT") && p[2] && !p[3])
{
ho->user_agent = p[2];
}
+ else if ((streq (p[1], "EXT1") || streq(p[1], "EXT2") || streq(p[1], "CUSTOM-HEADER"))
+ && p[2])
+ {
+ /* In the wild patched versions use both EXT1/2 and CUSTOM-HEADER
+ * with either two argument or one */
+
+ struct http_custom_header *custom_header = NULL;
+ int i;
+ /* Find the first free header */
+ for (i=0; i < MAX_CUSTOM_HTTP_HEADER; i++) {
+ if (!ho->custom_headers[i].name) {
+ custom_header = &ho->custom_headers[i];
+ break;
+ }
+ }
+ if (!custom_header)
+ {
+ msg (msglevel, "Cannot use more than %d http-proxy-option CUSTOM-HEADER : '%s'", MAX_CUSTOM_HTTP_HEADER, p[1]);
+ }
+ else
+ {
+ /* We will save p[2] and p[3], the proxy code will detect if
+ * p[3] is NULL */
+ custom_header->name = p[2];
+ custom_header->content = p[3];
+ }
+ }
else
{
- msg (msglevel, "Bad http-proxy-option or missing parameter: '%s'", p[1]);
+ msg (msglevel, "Bad http-proxy-option or missing or extra parameter: '%s'", p[1]);
}
}
-#endif
-#ifdef ENABLE_SOCKS
- else if (streq (p[0], "socks-proxy") && p[1])
+ else if (streq (p[0], "socks-proxy") && p[1] && !p[4])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
if (p[2])
- {
- int port;
- port = atoi (p[2]);
- if (!legal_ipv4_port (port))
- {
- msg (msglevel, "Bad socks-proxy port number: %s", p[2]);
- goto err;
- }
- options->ce.socks_proxy_port = port;
+ {
+ options->ce.socks_proxy_port = p[2];
}
else
{
- options->ce.socks_proxy_port = 1080;
+ options->ce.socks_proxy_port = "1080";
}
options->ce.socks_proxy_server = p[1];
options->ce.socks_proxy_authfile = p[3]; /* might be NULL */
}
- else if (streq (p[0], "socks-proxy-retry"))
- {
- VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
- options->ce.socks_proxy_retry = true;
- }
-#endif
- else if (streq (p[0], "keepalive") && p[1] && p[2])
+ else if (streq (p[0], "keepalive") && p[1] && p[2] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->keepalive_ping = atoi (p[1]);
options->keepalive_timeout = atoi (p[2]);
}
- else if (streq (p[0], "ping") && p[1])
+ else if (streq (p[0], "ping") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_TIMER);
options->ping_send_timeout = positive_atoi (p[1]);
}
- else if (streq (p[0], "ping-exit") && p[1])
+ else if (streq (p[0], "ping-exit") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_TIMER);
options->ping_rec_timeout = positive_atoi (p[1]);
options->ping_rec_timeout_action = PING_EXIT;
}
- else if (streq (p[0], "ping-restart") && p[1])
+ else if (streq (p[0], "ping-restart") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_TIMER);
options->ping_rec_timeout = positive_atoi (p[1]);
options->ping_rec_timeout_action = PING_RESTART;
}
- else if (streq (p[0], "ping-timer-rem"))
+ else if (streq (p[0], "ping-timer-rem") && !p[1])
{
VERIFY_PERMISSION (OPT_P_TIMER);
options->ping_timer_remote = true;
}
#ifdef ENABLE_OCC
- else if (streq (p[0], "explicit-exit-notify"))
+ else if (streq (p[0], "explicit-exit-notify") && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION|OPT_P_EXPLICIT_NOTIFY);
if (p[1])
@@ -5290,35 +5467,33 @@ add_option (struct options *options,
}
}
#endif
- else if (streq (p[0], "persist-tun"))
+ else if (streq (p[0], "persist-tun") && !p[1])
{
VERIFY_PERMISSION (OPT_P_PERSIST);
options->persist_tun = true;
}
- else if (streq (p[0], "persist-key"))
+ else if (streq (p[0], "persist-key") && !p[1])
{
VERIFY_PERMISSION (OPT_P_PERSIST);
options->persist_key = true;
}
- else if (streq (p[0], "persist-local-ip"))
+ else if (streq (p[0], "persist-local-ip") && !p[1])
{
VERIFY_PERMISSION (OPT_P_PERSIST_IP);
options->persist_local_ip = true;
}
- else if (streq (p[0], "persist-remote-ip"))
+ else if (streq (p[0], "persist-remote-ip") && !p[1])
{
VERIFY_PERMISSION (OPT_P_PERSIST_IP);
options->persist_remote_ip = true;
}
-#ifdef ENABLE_CLIENT_NAT
- else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4])
+ else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4] && !p[5])
{
VERIFY_PERMISSION (OPT_P_ROUTE);
cnol_check_alloc (options);
add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel);
}
-#endif
- else if (streq (p[0], "route") && p[1])
+ else if (streq (p[0], "route") && p[1] && !p[5])
{
VERIFY_PERMISSION (OPT_P_ROUTE);
rol_check_alloc (options);
@@ -5342,7 +5517,7 @@ add_option (struct options *options,
}
add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]);
}
- else if (streq (p[0], "route-ipv6") && p[1])
+ else if (streq (p[0], "route-ipv6") && p[1] && !p[4])
{
VERIFY_PERMISSION (OPT_P_ROUTE);
rol6_check_alloc (options);
@@ -5362,25 +5537,14 @@ add_option (struct options *options,
}
add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]);
}
- else if (streq (p[0], "max-routes") && p[1])
+ else if (streq (p[0], "max-routes") && !p[2])
{
- int max_routes;
-
- VERIFY_PERMISSION (OPT_P_GENERAL);
- max_routes = atoi (p[1]);
- if (max_routes < 0 || max_routes > 100000000)
- {
- msg (msglevel, "--max-routes parameter is out of range");
- goto err;
- }
- if (options->routes || options->routes_ipv6)
- {
- msg (msglevel, "--max-routes must to be specifed before any route/route-ipv6/redirect-gateway option");
- goto err;
- }
- options->max_routes = max_routes;
+ msg (M_WARN, "DEPRECATED OPTION: --max-routes option ignored."
+ "The number of routes is unlimited as of version 2.4. "
+ "This option will be removed in a future version, "
+ "please remove it from your configuration.");
}
- else if (streq (p[0], "route-gateway") && p[1])
+ else if (streq (p[0], "route-gateway") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
if (streq (p[1], "dhcp"))
@@ -5400,12 +5564,12 @@ add_option (struct options *options,
}
}
}
- else if (streq (p[0], "route-metric") && p[1])
+ else if (streq (p[0], "route-metric") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_ROUTE);
options->route_default_metric = positive_atoi (p[1]);
}
- else if (streq (p[0], "route-delay"))
+ else if (streq (p[0], "route-delay") && !p[3])
{
VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
options->route_delay_defined = true;
@@ -5439,17 +5603,37 @@ add_option (struct options *options,
p[1],
"route-pre-down", true);
}
- else if (streq (p[0], "route-noexec"))
+ else if (streq (p[0], "route-noexec") && !p[1])
{
VERIFY_PERMISSION (OPT_P_SCRIPT);
options->route_noexec = true;
}
- else if (streq (p[0], "route-nopull"))
+ else if (streq (p[0], "route-nopull") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->route_nopull = true;
}
- else if (streq (p[0], "allow-pull-fqdn"))
+ else if (streq (p[0], "pull-filter") && p[1] && p[2] && !p[3])
+ {
+ struct pull_filter *f;
+ VERIFY_PERMISSION (OPT_P_GENERAL)
+ f = alloc_pull_filter (options, msglevel);
+
+ if (strcmp ("accept", p[1]) == 0)
+ f->type = PUF_TYPE_ACCEPT;
+ else if (strcmp ("ignore", p[1]) == 0)
+ f->type = PUF_TYPE_IGNORE;
+ else if (strcmp ("reject", p[1]) == 0)
+ f->type = PUF_TYPE_REJECT;
+ else
+ {
+ msg (msglevel, "Unknown --pull-filter type: %s", p[1]);
+ goto err;
+ }
+ f->pattern = p[2];
+ f->size = strlen(p[2]);
+ }
+ else if (streq (p[0], "allow-pull-fqdn") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->allow_pull_fqdn = true;
@@ -5475,6 +5659,13 @@ add_option (struct options *options,
options->routes->flags |= RG_BYPASS_DNS;
else if (streq (p[j], "block-local"))
options->routes->flags |= RG_BLOCK_LOCAL;
+ else if (streq (p[j], "ipv6"))
+ {
+ rol6_check_alloc (options);
+ options->routes_ipv6->flags |= RG_REROUTE_GW;
+ }
+ else if (streq (p[j], "!ipv4"))
+ options->routes->flags &= ~RG_REROUTE_GW;
else
{
msg (msglevel, "unknown --%s flag: %s", p[0], p[j]);
@@ -5483,15 +5674,15 @@ add_option (struct options *options,
}
options->routes->flags |= RG_ENABLE;
}
- else if (streq (p[0], "remote-random-hostname"))
+ else if (streq (p[0], "remote-random-hostname") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->sockflags |= SF_HOST_RANDOMIZE;
}
- else if (streq (p[0], "setenv") && p[1])
+ else if (streq (p[0], "setenv") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
- if (streq (p[1], "REMOTE_RANDOM_HOSTNAME"))
+ if (streq (p[1], "REMOTE_RANDOM_HOSTNAME") && !p[2])
{
options->sockflags |= SF_HOST_RANDOMIZE;
}
@@ -5501,17 +5692,15 @@ add_option (struct options *options,
goto err;
}
#ifdef ENABLE_PUSH_PEER_INFO
- else if (streq (p[1], "PUSH_PEER_INFO"))
+ else if (streq (p[1], "PUSH_PEER_INFO") && !p[2])
{
options->push_peer_info = true;
}
#endif
-#if P2MP
else if (streq (p[1], "SERVER_POLL_TIMEOUT") && p[2])
{
- options->server_poll_timeout = positive_atoi(p[2]);
+ options->ce.connect_timeout = positive_atoi(p[2]);
}
-#endif
else
{
if (streq (p[1], "FORWARD_COMPATIBLE") && p[2] && streq (p[2], "1"))
@@ -5522,17 +5711,17 @@ add_option (struct options *options,
setenv_str (es, p[1], p[2] ? p[2] : "");
}
}
- else if (streq (p[0], "setenv-safe") && p[1])
+ else if (streq (p[0], "setenv-safe") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_SETENV);
setenv_str_safe (es, p[1], p[2] ? p[2] : "");
}
- else if (streq (p[0], "script-security") && p[1])
+ else if (streq (p[0], "script-security") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
script_security = atoi (p[1]);
}
- else if (streq (p[0], "mssfix"))
+ else if (streq (p[0], "mssfix") && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
if (p[1])
@@ -5544,7 +5733,7 @@ add_option (struct options *options,
}
#ifdef ENABLE_OCC
- else if (streq (p[0], "disable-occ"))
+ else if (streq (p[0], "disable-occ") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->occ = false;
@@ -5552,7 +5741,7 @@ add_option (struct options *options,
#endif
#if P2MP
#if P2MP_SERVER
- else if (streq (p[0], "server") && p[1] && p[2])
+ else if (streq (p[0], "server") && p[1] && p[2] && !p[4])
{
const int lev = M_WARN;
bool error = false;
@@ -5581,7 +5770,7 @@ add_option (struct options *options,
}
}
}
- else if (streq (p[0], "server-ipv6") && p[1] )
+ else if (streq (p[0], "server-ipv6") && p[1] && !p[3])
{
const int lev = M_WARN;
struct in6_addr network;
@@ -5608,7 +5797,7 @@ add_option (struct options *options,
goto err;
}
}
- else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4])
+ else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4] && !p[5])
{
const int lev = M_WARN;
bool error = false;
@@ -5630,7 +5819,7 @@ add_option (struct options *options,
options->server_bridge_pool_start = pool_start;
options->server_bridge_pool_end = pool_end;
}
- else if (streq (p[0], "server-bridge") && p[1] && streq (p[1], "nogw"))
+ else if (streq (p[0], "server-bridge") && p[1] && streq (p[1], "nogw") && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->server_bridge_proxy_dhcp = true;
@@ -5641,17 +5830,23 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
options->server_bridge_proxy_dhcp = true;
}
- else if (streq (p[0], "push") && p[1])
+ else if (streq (p[0], "push") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_PUSH);
push_options (options, &p[1], msglevel, &options->gc);
}
- else if (streq (p[0], "push-reset"))
+ else if (streq (p[0], "push-reset") && !p[1])
{
VERIFY_PERMISSION (OPT_P_INSTANCE);
push_reset (options);
}
- else if (streq (p[0], "ifconfig-pool") && p[1] && p[2])
+ else if (streq (p[0], "push-remove") && p[1] && !p[2])
+ {
+ VERIFY_PERMISSION (OPT_P_INSTANCE);
+ msg (D_PUSH, "PUSH_REMOVE '%s'", p[1]);
+ push_remove_option (options,p[1]);
+ }
+ else if (streq (p[0], "ifconfig-pool") && p[1] && p[2] && !p[4])
{
const int lev = M_WARN;
bool error = false;
@@ -5678,7 +5873,7 @@ add_option (struct options *options,
if (netmask)
options->ifconfig_pool_netmask = netmask;
}
- else if (streq (p[0], "ifconfig-pool-persist") && p[1])
+ else if (streq (p[0], "ifconfig-pool-persist") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ifconfig_pool_persist_filename = p[1];
@@ -5687,12 +5882,12 @@ add_option (struct options *options,
options->ifconfig_pool_persist_refresh_freq = positive_atoi (p[2]);
}
}
- else if (streq (p[0], "ifconfig-pool-linear"))
+ else if (streq (p[0], "ifconfig-pool-linear") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->topology = TOP_P2P;
}
- else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] )
+ else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] && !p[2])
{
const int lev = M_WARN;
struct in6_addr network;
@@ -5714,7 +5909,7 @@ add_option (struct options *options,
options->ifconfig_ipv6_pool_base = network;
options->ifconfig_ipv6_pool_netbits = netbits;
}
- else if (streq (p[0], "hash-size") && p[1] && p[2])
+ else if (streq (p[0], "hash-size") && p[1] && p[2] && !p[3])
{
int real, virtual;
@@ -5729,7 +5924,7 @@ add_option (struct options *options,
options->real_hash_size = real;
options->virtual_hash_size = real;
}
- else if (streq (p[0], "connect-freq") && p[1] && p[2])
+ else if (streq (p[0], "connect-freq") && p[1] && p[2] && !p[3])
{
int cf_max, cf_per;
@@ -5744,7 +5939,7 @@ add_option (struct options *options,
options->cf_max = cf_max;
options->cf_per = cf_per;
}
- else if (streq (p[0], "max-clients") && p[1])
+ else if (streq (p[0], "max-clients") && p[1] && !p[2])
{
int max_clients;
@@ -5755,29 +5950,55 @@ add_option (struct options *options,
msg (msglevel, "--max-clients must be at least 1");
goto err;
}
+ if (max_clients >= MAX_PEER_ID) /* max peer-id value */
+ {
+ msg (msglevel, "--max-clients must be less than %d", MAX_PEER_ID);
+ goto err;
+ }
options->max_clients = max_clients;
}
- else if (streq (p[0], "max-routes-per-client") && p[1])
+ else if (streq (p[0], "max-routes-per-client") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_INHERIT);
options->max_routes_per_client = max_int (atoi (p[1]), 1);
}
- else if (streq (p[0], "client-cert-not-required"))
+ else if (streq (p[0], "client-cert-not-required") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED;
+ msg (M_WARN, "DEPRECATED OPTION: --client-cert-not-required, use --verify-client-cert instead");
+ }
+ else if (streq (p[0], "verify-client-cert") && !p[2])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+
+ /* Reset any existing flags */
+ options->ssl_flags &= ~SSLF_CLIENT_CERT_OPTIONAL;
+ options->ssl_flags &= ~SSLF_CLIENT_CERT_NOT_REQUIRED;
+ if (p[1])
+ {
+ if (streq (p[1], "none"))
+ options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED;
+ else if (streq (p[1], "optional"))
+ options->ssl_flags |= SSLF_CLIENT_CERT_OPTIONAL;
+ else if (!streq (p[1], "require"))
+ {
+ msg (msglevel, "parameter to --verify-client-cert must be 'none', 'optional' or 'require'");
+ goto err;
+ }
+ }
}
- else if (streq (p[0], "username-as-common-name"))
+ else if (streq (p[0], "username-as-common-name") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ssl_flags |= SSLF_USERNAME_AS_COMMON_NAME;
}
- else if (streq (p[0], "auth-user-pass-optional"))
+ else if (streq (p[0], "auth-user-pass-optional") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ssl_flags |= SSLF_AUTH_USER_PASS_OPTIONAL;
}
- else if (streq (p[0], "opt-verify"))
+ else if (streq (p[0], "opt-verify") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ssl_flags |= SSLF_OPT_VERIFY;
@@ -5808,6 +6029,12 @@ add_option (struct options *options,
&options->auth_user_pass_verify_script,
p[1], "auth-user-pass-verify", true);
}
+ else if (streq (p[0], "auth-gen-token"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->auth_token_generate = true;
+ options->auth_token_lifetime = p[1] ? positive_atoi (p[1]) : 0;
+ }
else if (streq (p[0], "client-connect") && p[1])
{
VERIFY_PERMISSION (OPT_P_SCRIPT);
@@ -5832,22 +6059,22 @@ add_option (struct options *options,
set_user_script (options, &options->learn_address_script,
p[1], "learn-address", true);
}
- else if (streq (p[0], "tmp-dir") && p[1])
+ else if (streq (p[0], "tmp-dir") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->tmp_dir = p[1];
}
- else if (streq (p[0], "client-config-dir") && p[1])
+ else if (streq (p[0], "client-config-dir") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->client_config_dir = p[1];
}
- else if (streq (p[0], "ccd-exclusive"))
+ else if (streq (p[0], "ccd-exclusive") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ccd_exclusive = true;
}
- else if (streq (p[0], "bcast-buffers") && p[1])
+ else if (streq (p[0], "bcast-buffers") && p[1] && !p[2])
{
int n_bcast_buf;
@@ -5857,7 +6084,7 @@ add_option (struct options *options,
msg (msglevel, "--bcast-buffers parameter must be > 0");
options->n_bcast_buf = n_bcast_buf;
}
- else if (streq (p[0], "tcp-queue-limit") && p[1])
+ else if (streq (p[0], "tcp-queue-limit") && p[1] && !p[2])
{
int tcp_queue_limit;
@@ -5868,34 +6095,25 @@ add_option (struct options *options,
options->tcp_queue_limit = tcp_queue_limit;
}
#if PORT_SHARE
- else if (streq (p[0], "port-share") && p[1] && p[2])
+ else if (streq (p[0], "port-share") && p[1] && p[2] && !p[4])
{
- int port;
-
VERIFY_PERMISSION (OPT_P_GENERAL);
- port = atoi (p[2]);
- if (!legal_ipv4_port (port))
- {
- msg (msglevel, "port number associated with --port-share directive is out of range");
- goto err;
- }
-
options->port_share_host = p[1];
- options->port_share_port = port;
+ options->port_share_port = p[2];
options->port_share_journal_dir = p[3];
}
#endif
- else if (streq (p[0], "client-to-client"))
+ else if (streq (p[0], "client-to-client") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->enable_c2c = true;
}
- else if (streq (p[0], "duplicate-cn"))
+ else if (streq (p[0], "duplicate-cn") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->duplicate_cn = true;
}
- else if (streq (p[0], "iroute") && p[1])
+ else if (streq (p[0], "iroute") && p[1] && !p[3])
{
const char *netmask = NULL;
@@ -5906,12 +6124,12 @@ add_option (struct options *options,
}
option_iroute (options, p[1], netmask, msglevel);
}
- else if (streq (p[0], "iroute-ipv6") && p[1])
+ else if (streq (p[0], "iroute-ipv6") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_INSTANCE);
option_iroute_ipv6 (options, p[1], msglevel);
}
- else if (streq (p[0], "ifconfig-push") && p[1] && p[2])
+ else if (streq (p[0], "ifconfig-push") && p[1] && p[2] && !p[4])
{
in_addr_t local, remote_netmask;
@@ -5923,10 +6141,8 @@ add_option (struct options *options,
options->push_ifconfig_defined = true;
options->push_ifconfig_local = local;
options->push_ifconfig_remote_netmask = remote_netmask;
-#ifdef ENABLE_CLIENT_NAT
if (p[3])
options->push_ifconfig_local_alias = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL);
-#endif
}
else
{
@@ -5934,7 +6150,7 @@ add_option (struct options *options,
goto err;
}
}
- else if (streq (p[0], "ifconfig-push-constraint") && p[1] && p[2])
+ else if (streq (p[0], "ifconfig-push-constraint") && p[1] && p[2] && !p[3])
{
in_addr_t network, netmask;
@@ -5953,7 +6169,7 @@ add_option (struct options *options,
goto err;
}
}
- else if (streq (p[0], "ifconfig-ipv6-push") && p[1] )
+ else if (streq (p[0], "ifconfig-ipv6-push") && p[1] && !p[3])
{
struct in6_addr local, remote;
unsigned int netbits;
@@ -5989,18 +6205,19 @@ add_option (struct options *options,
options->push_ifconfig_ipv6_local = local;
options->push_ifconfig_ipv6_netbits = netbits;
options->push_ifconfig_ipv6_remote = remote;
+ options->push_ifconfig_ipv6_blocked = false;
}
- else if (streq (p[0], "disable"))
+ else if (streq (p[0], "disable") && !p[1])
{
VERIFY_PERMISSION (OPT_P_INSTANCE);
options->disable = true;
}
- else if (streq (p[0], "tcp-nodelay"))
+ else if (streq (p[0], "tcp-nodelay") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->server_flags |= SF_TCP_NODELAY_HELPER;
}
- else if (streq (p[0], "stale-routes-check") && p[1])
+ else if (streq (p[0], "stale-routes-check") && p[1] && !p[3])
{
int ageing_time, check_interval;
@@ -6021,27 +6238,22 @@ add_option (struct options *options,
}
#endif /* P2MP_SERVER */
- else if (streq (p[0], "client"))
+ else if (streq (p[0], "client") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->client = true;
}
- else if (streq (p[0], "pull"))
+ else if (streq (p[0], "pull") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->pull = true;
}
- else if (streq (p[0], "push-continuation") && p[1])
+ else if (streq (p[0], "push-continuation") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_PULL_MODE);
options->push_continuation = atoi(p[1]);
}
- else if (streq (p[0], "server-poll-timeout") && p[1])
- {
- VERIFY_PERMISSION (OPT_P_GENERAL);
- options->server_poll_timeout = positive_atoi(p[1]);
- }
- else if (streq (p[0], "auth-user-pass"))
+ else if (streq (p[0], "auth-user-pass") && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (p[1])
@@ -6051,13 +6263,13 @@ add_option (struct options *options,
else
options->auth_user_pass_file = "stdin";
}
- else if (streq (p[0], "auth-retry") && p[1])
+ else if (streq (p[0], "auth-retry") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
auth_retry_set (msglevel, p[1]);
}
#ifdef ENABLE_CLIENT_CR
- else if (streq (p[0], "static-challenge") && p[1] && p[2])
+ else if (streq (p[0], "static-challenge") && p[1] && p[2] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->sc_info.challenge_text = p[1];
@@ -6066,8 +6278,26 @@ add_option (struct options *options,
}
#endif
#endif
-#ifdef WIN32
- else if (streq (p[0], "win-sys") && p[1])
+ else if (streq (p[0], "msg-channel") && p[1])
+ {
+#ifdef _WIN32
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ HANDLE process = GetCurrentProcess ();
+ HANDLE handle = (HANDLE) atoi (p[1]);
+ if (!DuplicateHandle (process, handle, process, &options->msg_channel, 0,
+ FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
+ {
+ msg (msglevel, "could not duplicate service pipe handle");
+ goto err;
+ }
+ options->route_method = ROUTE_METHOD_SERVICE;
+#else
+ msg (msglevel, "--msg-channel is only supported on Windows");
+ goto err;
+#endif
+ }
+#ifdef _WIN32
+ else if (streq (p[0], "win-sys") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], "env"))
@@ -6077,7 +6307,7 @@ add_option (struct options *options,
else
set_win_sys_path (p[1], es);
}
- else if (streq (p[0], "route-method") && p[1])
+ else if (streq (p[0], "route-method") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
if (streq (p[1], "adaptive"))
@@ -6092,7 +6322,7 @@ add_option (struct options *options,
goto err;
}
}
- else if (streq (p[0], "ip-win32") && p[1])
+ else if (streq (p[0], "ip-win32") && p[1] && !p[4])
{
const int index = ascii2ipset (p[1]);
struct tuntap_options *to = &options->tuntap_options;
@@ -6146,7 +6376,9 @@ add_option (struct options *options,
to->ip_win32_type = index;
to->ip_win32_defined = true;
}
- else if (streq (p[0], "dhcp-option") && p[1])
+#endif
+#if defined(_WIN32) || defined(TARGET_ANDROID)
+ else if (streq (p[0], "dhcp-option") && p[1] && !p[3])
{
struct tuntap_options *o = &options->tuntap_options;
VERIFY_PERMISSION (OPT_P_IPWIN32);
@@ -6186,36 +6418,38 @@ add_option (struct options *options,
{
dhcp_option_address_parse ("NBDD", p[2], o->nbdd, &o->nbdd_len, msglevel);
}
- else if (streq (p[1], "DISABLE-NBT"))
+ else if (streq (p[1], "DISABLE-NBT") && !p[2])
{
o->disable_nbt = 1;
}
else
{
- msg (msglevel, "--dhcp-option: unknown option type '%s' or missing parameter", p[1]);
+ msg (msglevel, "--dhcp-option: unknown option type '%s' or missing or unknown parameter", p[1]);
goto err;
}
o->dhcp_options = true;
}
- else if (streq (p[0], "show-adapters"))
+#endif
+#ifdef _WIN32
+ else if (streq (p[0], "show-adapters") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
show_tap_win_adapters (M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX);
openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
}
- else if (streq (p[0], "show-net"))
+ else if (streq (p[0], "show-net") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
show_routes (M_INFO|M_NOPREFIX);
show_adapters (M_INFO|M_NOPREFIX);
openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
}
- else if (streq (p[0], "show-net-up"))
+ else if (streq (p[0], "show-net-up") && !p[1])
{
VERIFY_PERMISSION (OPT_P_UP);
options->show_net_up = true;
}
- else if (streq (p[0], "tap-sleep") && p[1])
+ else if (streq (p[0], "tap-sleep") && p[1] && !p[2])
{
int s;
VERIFY_PERMISSION (OPT_P_IPWIN32);
@@ -6227,22 +6461,22 @@ add_option (struct options *options,
}
options->tuntap_options.tap_sleep = s;
}
- else if (streq (p[0], "dhcp-renew"))
+ else if (streq (p[0], "dhcp-renew") && !p[1])
{
VERIFY_PERMISSION (OPT_P_IPWIN32);
options->tuntap_options.dhcp_renew = true;
}
- else if (streq (p[0], "dhcp-pre-release"))
+ else if (streq (p[0], "dhcp-pre-release") && !p[1])
{
VERIFY_PERMISSION (OPT_P_IPWIN32);
options->tuntap_options.dhcp_pre_release = true;
}
- else if (streq (p[0], "dhcp-release"))
+ else if (streq (p[0], "dhcp-release") && !p[1])
{
VERIFY_PERMISSION (OPT_P_IPWIN32);
options->tuntap_options.dhcp_release = true;
}
- else if (streq (p[0], "dhcp-internal") && p[1]) /* standalone method for internal use */
+ else if (streq (p[0], "dhcp-internal") && p[1] && !p[2]) /* standalone method for internal use */
{
unsigned int adapter_index;
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -6255,28 +6489,17 @@ add_option (struct options *options,
dhcp_renew_by_adapter_index (adapter_index);
openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
}
- else if (streq (p[0], "register-dns"))
+ else if (streq (p[0], "register-dns") && !p[1])
{
VERIFY_PERMISSION (OPT_P_IPWIN32);
options->tuntap_options.register_dns = true;
}
-#ifdef WIN32
else if (streq (p[0], "block-outside-dns") && !p[1])
{
VERIFY_PERMISSION (OPT_P_IPWIN32);
- if (win_wfp_init_funcs())
- {
- options->block_outside_dns = true;
- }
- else
- {
- msg (msglevel_fc, "Failed to enable --block-outside-dns. "
- "Maybe WFP is not supported on your system?");
- goto err;
- }
+ options->block_outside_dns = true;
}
-#endif
- else if (streq (p[0], "rdns-internal"))
+ else if (streq (p[0], "rdns-internal") && !p[1])
/* standalone method for internal use
*
* (if --register-dns is set, openvpn needs to call itself in a
@@ -6290,18 +6513,18 @@ add_option (struct options *options,
ipconfig_register_dns (NULL);
openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
}
- else if (streq (p[0], "show-valid-subnets"))
+ else if (streq (p[0], "show-valid-subnets") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
show_valid_win32_tun_subnets ();
openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
}
- else if (streq (p[0], "pause-exit"))
+ else if (streq (p[0], "pause-exit") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
set_pause_exit_win32 ();
}
- else if (streq (p[0], "service") && p[1])
+ else if (streq (p[0], "service") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->exit_event_name = p[1];
@@ -6310,62 +6533,75 @@ add_option (struct options *options,
options->exit_event_initial_state = (atoi(p[2]) != 0);
}
}
- else if (streq (p[0], "allow-nonadmin"))
+ else if (streq (p[0], "allow-nonadmin") && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
tap_allow_nonadmin_access (p[1]);
openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
}
- else if (streq (p[0], "user") && p[1])
+ else if (streq (p[0], "user") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
msg (M_WARN, "NOTE: --user option is not implemented on Windows");
}
- else if (streq (p[0], "group") && p[1])
+ else if (streq (p[0], "group") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
msg (M_WARN, "NOTE: --group option is not implemented on Windows");
}
#else
- else if (streq (p[0], "user") && p[1])
+ else if (streq (p[0], "user") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->username = p[1];
}
- else if (streq (p[0], "group") && p[1])
+ else if (streq (p[0], "group") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->groupname = p[1];
}
- else if (streq (p[0], "dhcp-option") && p[1])
+ else if (streq (p[0], "dhcp-option") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_IPWIN32);
foreign_option (options, p, 3, es);
}
- else if (streq (p[0], "route-method") && p[1]) /* ignore when pushed to non-Windows OS */
+ else if (streq (p[0], "route-method") && p[1] && !p[2]) /* ignore when pushed to non-Windows OS */
{
VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
}
#endif
#if PASSTOS_CAPABILITY
- else if (streq (p[0], "passtos"))
+ else if (streq (p[0], "passtos") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->passtos = true;
}
#endif
-#ifdef ENABLE_LZO
- else if (streq (p[0], "comp-lzo"))
+#if defined(USE_COMP)
+ else if (streq (p[0], "comp-lzo") && !p[2])
{
VERIFY_PERMISSION (OPT_P_COMP);
- if (p[1])
+
+#if defined(ENABLE_LZO)
+ if (p[1] && streq (p[1], "no"))
+#endif
+ {
+ options->comp.alg = COMP_ALG_STUB;
+ options->comp.flags = 0;
+ }
+#if defined(ENABLE_LZO)
+ else if (p[1])
{
if (streq (p[1], "yes"))
- options->lzo = LZO_SELECTED|LZO_ON;
- else if (streq (p[1], "no"))
- options->lzo = LZO_SELECTED;
+ {
+ options->comp.alg = COMP_ALG_LZO;
+ options->comp.flags = 0;
+ }
else if (streq (p[1], "adaptive"))
- options->lzo = LZO_SELECTED|LZO_ON|LZO_ADAPTIVE;
+ {
+ options->comp.alg = COMP_ALG_LZO;
+ options->comp.flags = COMP_F_ADAPTIVE;
+ }
else
{
msg (msglevel, "bad comp-lzo option: %s -- must be 'yes', 'no', or 'adaptive'", p[1]);
@@ -6373,31 +6609,81 @@ add_option (struct options *options,
}
}
else
- options->lzo = LZO_SELECTED|LZO_ON|LZO_ADAPTIVE;
+ {
+ options->comp.alg = COMP_ALG_LZO;
+ options->comp.flags = COMP_F_ADAPTIVE;
+ }
+#endif
+ }
+ else if (streq (p[0], "comp-noadapt") && !p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_COMP);
+ options->comp.flags &= ~COMP_F_ADAPTIVE;
}
- else if (streq (p[0], "comp-noadapt"))
+ else if (streq (p[0], "compress") && !p[2])
{
VERIFY_PERMISSION (OPT_P_COMP);
- options->lzo &= ~LZO_ADAPTIVE;
+ if (p[1])
+ {
+ if (streq (p[1], "stub"))
+ {
+ options->comp.alg = COMP_ALG_STUB;
+ options->comp.flags = (COMP_F_SWAP|COMP_F_ADVERTISE_STUBS_ONLY);
+ }
+ else if (streq(p[1], "stub-v2"))
+ {
+ options->comp.alg = COMP_ALGV2_UNCOMPRESSED;
+ options->comp.flags = COMP_F_ADVERTISE_STUBS_ONLY;
+ }
+#if defined(ENABLE_LZO)
+ else if (streq (p[1], "lzo"))
+ {
+ options->comp.alg = COMP_ALG_LZO;
+ options->comp.flags = 0;
+ }
+#endif
+#if defined(ENABLE_LZ4)
+ else if (streq (p[1], "lz4"))
+ {
+ options->comp.alg = COMP_ALG_LZ4;
+ options->comp.flags = COMP_F_SWAP;
+ }
+ else if (streq (p[1], "lz4-v2"))
+ {
+ options->comp.alg = COMP_ALGV2_LZ4;
+ options->comp.flags = 0;
+ }
+#endif
+ else
+ {
+ msg (msglevel, "bad comp option: %s", p[1]);
+ goto err;
+ }
+ }
+ else
+ {
+ options->comp.alg = COMP_ALG_STUB;
+ options->comp.flags = COMP_F_SWAP;
+ }
}
-#endif /* ENABLE_LZO */
+#endif /* USE_COMP */
#ifdef ENABLE_CRYPTO
- else if (streq (p[0], "show-ciphers"))
+ else if (streq (p[0], "show-ciphers") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->show_ciphers = true;
}
- else if (streq (p[0], "show-digests"))
+ else if (streq (p[0], "show-digests") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->show_digests = true;
}
- else if (streq (p[0], "show-engines"))
+ else if (streq (p[0], "show-engines") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->show_engines = true;
}
- else if (streq (p[0], "key-direction") && p[1])
+ else if (streq (p[0], "key-direction") && p[1] && !p[2])
{
int key_direction;
@@ -6407,7 +6693,7 @@ add_option (struct options *options,
else
goto err;
}
- else if (streq (p[0], "secret") && p[1])
+ else if (streq (p[0], "secret") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], INLINE_FILE_TAG) && p[2])
@@ -6427,46 +6713,34 @@ add_option (struct options *options,
}
options->shared_secret_file = p[1];
}
- else if (streq (p[0], "genkey"))
+ else if (streq (p[0], "genkey") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->genkey = true;
}
- else if (streq (p[0], "auth") && p[1])
+ else if (streq (p[0], "auth") && p[1] && !p[2])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
- options->authname_defined = true;
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->authname = p[1];
- if (streq (options->authname, "none"))
- {
- options->authname_defined = false;
- options->authname = NULL;
- }
}
- else if (streq (p[0], "auth"))
+ else if (streq (p[0], "cipher") && p[1] && !p[2])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
- options->authname_defined = true;
+ VERIFY_PERMISSION (OPT_P_NCP);
+ options->ciphername = p[1];
}
- else if (streq (p[0], "cipher") && p[1])
+ else if (streq (p[0], "ncp-ciphers") && p[1] && !p[2])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
- options->ciphername_defined = true;
- options->ciphername = p[1];
- if (streq (options->ciphername, "none"))
- {
- options->ciphername_defined = false;
- options->ciphername = NULL;
- }
+ VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE);
+ options->ncp_ciphers = p[1];
}
- else if (streq (p[0], "cipher"))
+ else if (streq (p[0], "ncp-disable") && !p[1])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
- options->ciphername_defined = true;
+ VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE);
+ options->ncp_enabled = false;
}
- else if (streq (p[0], "prng") && p[1])
+ else if (streq (p[0], "prng") && p[1] && !p[3])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], "none"))
options->prng_hash = NULL;
else
@@ -6486,14 +6760,14 @@ add_option (struct options *options,
}
}
}
- else if (streq (p[0], "no-replay"))
+ else if (streq (p[0], "no-replay") && !p[1])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->replay = false;
}
- else if (streq (p[0], "replay-window"))
+ else if (streq (p[0], "replay-window") && !p[3])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
if (p[1])
{
int replay_window;
@@ -6531,28 +6805,28 @@ add_option (struct options *options,
goto err;
}
}
- else if (streq (p[0], "mute-replay-warnings"))
+ else if (streq (p[0], "mute-replay-warnings") && !p[1])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->mute_replay_warnings = true;
}
- else if (streq (p[0], "no-iv"))
+ else if (streq (p[0], "no-iv") && !p[1])
{
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_GENERAL);
options->use_iv = false;
}
- else if (streq (p[0], "replay-persist") && p[1])
+ else if (streq (p[0], "replay-persist") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->packet_id_file = p[1];
}
- else if (streq (p[0], "test-crypto"))
+ else if (streq (p[0], "test-crypto") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->test_crypto = true;
}
-#ifndef ENABLE_CRYPTO_POLARSSL
- else if (streq (p[0], "engine"))
+#ifndef ENABLE_CRYPTO_MBEDTLS
+ else if (streq (p[0], "engine") && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (p[1])
@@ -6562,13 +6836,13 @@ add_option (struct options *options,
else
options->engine = "auto";
}
-#endif /* ENABLE_CRYPTO_POLARSSL */
+#endif /* ENABLE_CRYPTO_MBEDTLS */
#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH
- else if (streq (p[0], "keysize") && p[1])
+ else if (streq (p[0], "keysize") && p[1] && !p[2])
{
int keysize;
- VERIFY_PERMISSION (OPT_P_CRYPTO);
+ VERIFY_PERMISSION (OPT_P_NCP);
keysize = atoi (p[1]) / 8;
if (keysize < 0 || keysize > MAX_CIPHER_KEY_LENGTH)
{
@@ -6579,29 +6853,38 @@ add_option (struct options *options,
}
#endif
#ifdef ENABLE_PREDICTION_RESISTANCE
- else if (streq (p[0], "use-prediction-resistance"))
+ else if (streq (p[0], "use-prediction-resistance") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->use_prediction_resistance = true;
}
#endif
-#ifdef ENABLE_SSL
- else if (streq (p[0], "show-tls"))
+ else if (streq (p[0], "show-tls") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->show_tls_ciphers = true;
}
- else if (streq (p[0], "tls-server"))
+ else if (streq (p[0], "show-curves") && !p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->show_curves = true;
+ }
+ else if (streq (p[0], "ecdh-curve") && p[1] && !p[2])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->ecdh_curve= p[1];
+ }
+ else if (streq (p[0], "tls-server") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->tls_server = true;
}
- else if (streq (p[0], "tls-client"))
+ else if (streq (p[0], "tls-client") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->tls_client = true;
}
- else if (streq (p[0], "ca") && p[1])
+ else if (streq (p[0], "ca") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ca_file = p[1];
@@ -6610,14 +6893,14 @@ add_option (struct options *options,
options->ca_file_inline = p[2];
}
}
-#ifndef ENABLE_CRYPTO_POLARSSL
- else if (streq (p[0], "capath") && p[1])
+#ifndef ENABLE_CRYPTO_MBEDTLS
+ else if (streq (p[0], "capath") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ca_path = p[1];
}
-#endif /* ENABLE_CRYPTO_POLARSSL */
- else if (streq (p[0], "dh") && p[1])
+#endif /* ENABLE_CRYPTO_MBEDTLS */
+ else if (streq (p[0], "dh") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->dh_file = p[1];
@@ -6626,7 +6909,7 @@ add_option (struct options *options,
options->dh_file_inline = p[2];
}
}
- else if (streq (p[0], "cert") && p[1])
+ else if (streq (p[0], "cert") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->cert_file = p[1];
@@ -6635,7 +6918,7 @@ add_option (struct options *options,
options->cert_file_inline = p[2];
}
}
- else if (streq (p[0], "extra-certs") && p[1])
+ else if (streq (p[0], "extra-certs") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->extra_certs_file = p[1];
@@ -6644,19 +6927,19 @@ add_option (struct options *options,
options->extra_certs_file_inline = p[2];
}
}
- else if (streq (p[0], "verify-hash") && p[1])
+ else if (streq (p[0], "verify-hash") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc);
}
#ifdef ENABLE_CRYPTOAPI
- else if (streq (p[0], "cryptoapicert") && p[1])
+ else if (streq (p[0], "cryptoapicert") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->cryptoapi_cert = p[1];
}
#endif
- else if (streq (p[0], "key") && p[1])
+ else if (streq (p[0], "key") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->priv_key_file = p[1];
@@ -6665,7 +6948,7 @@ add_option (struct options *options,
options->priv_key_file_inline = p[2];
}
}
- else if (streq (p[0], "tls-version-min") && p[1])
+ else if (streq (p[0], "tls-version-min") && p[1] && !p[3])
{
int ver;
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -6679,7 +6962,7 @@ add_option (struct options *options,
~(SSLF_TLS_VERSION_MIN_MASK << SSLF_TLS_VERSION_MIN_SHIFT);
options->ssl_flags |= (ver << SSLF_TLS_VERSION_MIN_SHIFT);
}
- else if (streq (p[0], "tls-version-max") && p[1])
+ else if (streq (p[0], "tls-version-max") && p[1] && !p[2])
{
int ver;
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -6693,8 +6976,8 @@ add_option (struct options *options,
~(SSLF_TLS_VERSION_MAX_MASK << SSLF_TLS_VERSION_MAX_SHIFT);
options->ssl_flags |= (ver << SSLF_TLS_VERSION_MAX_SHIFT);
}
-#ifndef ENABLE_CRYPTO_POLARSSL
- else if (streq (p[0], "pkcs12") && p[1])
+#ifndef ENABLE_CRYPTO_MBEDTLS
+ else if (streq (p[0], "pkcs12") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->pkcs12_file = p[1];
@@ -6703,8 +6986,8 @@ add_option (struct options *options,
options->pkcs12_file_inline = p[2];
}
}
-#endif /* ENABLE_CRYPTO_POLARSSL */
- else if (streq (p[0], "askpass"))
+#endif /* ENABLE_CRYPTO_MBEDTLS */
+ else if (streq (p[0], "askpass") && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (p[1])
@@ -6714,12 +6997,12 @@ add_option (struct options *options,
else
options->key_pass_file = "stdin";
}
- else if (streq (p[0], "auth-nocache"))
+ else if (streq (p[0], "auth-nocache") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
ssl_set_auth_nocache ();
}
- else if (streq (p[0], "auth-token") && p[1])
+ else if (streq (p[0], "auth-token") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_ECHO);
ssl_set_auth_token(p[1]);
@@ -6728,34 +7011,39 @@ add_option (struct options *options,
management_auth_token (management, p[1]);
#endif
}
- else if (streq (p[0], "single-session"))
+ else if (streq (p[0], "single-session") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->single_session = true;
}
#ifdef ENABLE_PUSH_PEER_INFO
- else if (streq (p[0], "push-peer-info"))
+ else if (streq (p[0], "push-peer-info") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->push_peer_info = true;
}
#endif
- else if (streq (p[0], "tls-exit"))
+ else if (streq (p[0], "tls-exit") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->tls_exit = true;
}
- else if (streq (p[0], "tls-cipher") && p[1])
+ else if (streq (p[0], "tls-cipher") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->cipher_list = p[1];
}
- else if (streq (p[0], "crl-verify") && p[1])
+ else if (streq (p[0], "crl-verify") && p[1] && ((p[2] && streq(p[2], "dir"))
+ || (p[2] && streq (p[1], INLINE_FILE_TAG) ) || !p[2]) && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (p[2] && streq(p[2], "dir"))
options->ssl_flags |= SSLF_CRL_VERIFY_DIR;
options->crl_file = p[1];
+ if (streq (p[1], INLINE_FILE_TAG) && p[2])
+ {
+ options->crl_file_inline = p[2];
+ }
}
else if (streq (p[0], "tls-verify") && p[1])
{
@@ -6766,85 +7054,48 @@ add_option (struct options *options,
string_substitute (p[1], ',', ' ', &options->gc),
"tls-verify", true);
}
-#ifndef ENABLE_CRYPTO_POLARSSL
- else if (streq (p[0], "tls-export-cert") && p[1])
+#ifndef ENABLE_CRYPTO_MBEDTLS
+ else if (streq (p[0], "tls-export-cert") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->tls_export_cert = p[1];
}
#endif
- else if (streq (p[0], "compat-names"))
+#if P2MP_SERVER
+ else if (streq (p[0], "compat-names") && ((p[1] && streq (p[1], "no-remapping")) || !p[1]) && !p[2])
+#else
+ else if (streq (p[0], "compat-names") && !p[1])
+#endif
{
VERIFY_PERMISSION (OPT_P_GENERAL);
- if (options->verify_x509_type != VERIFY_X509_NONE &&
- options->verify_x509_type != TLS_REMOTE_SUBJECT_DN &&
- options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX)
+ if (options->verify_x509_type != VERIFY_X509_NONE)
{
msg (msglevel, "you cannot use --compat-names with --verify-x509-name");
goto err;
}
- msg (M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration");
+ msg (M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration. This will be removed in OpenVPN v2.5.");
compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
#if P2MP_SERVER
if (p[1] && streq (p[1], "no-remapping"))
compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING);
}
- else if (streq (p[0], "no-name-remapping"))
+ else if (streq (p[0], "no-name-remapping") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
- if (options->verify_x509_type != VERIFY_X509_NONE &&
- options->verify_x509_type != TLS_REMOTE_SUBJECT_DN &&
- options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX)
+ if (options->verify_x509_type != VERIFY_X509_NONE)
{
msg (msglevel, "you cannot use --no-name-remapping with --verify-x509-name");
goto err;
}
- msg (M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration");
+ msg (M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration. This will be removed in OpenVPN v2.5.");
compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING);
#endif
}
- else if (streq (p[0], "tls-remote") && p[1])
- {
- VERIFY_PERMISSION (OPT_P_GENERAL);
-
- if (options->verify_x509_type != VERIFY_X509_NONE &&
- options->verify_x509_type != TLS_REMOTE_SUBJECT_DN &&
- options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX)
- {
- msg (msglevel, "you cannot use --tls-remote with --verify-x509-name");
- goto err;
- }
- msg (M_WARN, "DEPRECATED OPTION: --tls-remote, please update your configuration");
-
- if (strlen (p[1]))
- {
- int is_username = (!strchr (p[1], '=') || !strstr (p[1], ", "));
- int type = TLS_REMOTE_SUBJECT_DN;
- if (p[1][0] != '/' && is_username)
- type = TLS_REMOTE_SUBJECT_RDN_PREFIX;
-
- /*
- * Enable legacy openvpn format for DNs that have not been converted
- * yet and --x509-username-field (not containing an '=' or ', ')
- */
- if (p[1][0] == '/' || is_username)
- compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
-
- options->verify_x509_type = type;
- options->verify_x509_name = p[1];
- }
- }
- else if (streq (p[0], "verify-x509-name") && p[1] && strlen (p[1]))
+ else if (streq (p[0], "verify-x509-name") && p[1] && strlen (p[1]) && !p[3])
{
int type = VERIFY_X509_SUBJECT_DN;
VERIFY_PERMISSION (OPT_P_GENERAL);
- if (options->verify_x509_type == TLS_REMOTE_SUBJECT_DN ||
- options->verify_x509_type == TLS_REMOTE_SUBJECT_RDN_PREFIX)
- {
- msg (msglevel, "you cannot use --verify-x509-name with --tls-remote");
- goto err;
- }
if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NAMES))
{
msg (msglevel, "you cannot use --verify-x509-name with "
@@ -6868,7 +7119,7 @@ add_option (struct options *options,
options->verify_x509_type = type;
options->verify_x509_name = p[1];
}
- else if (streq (p[0], "ns-cert-type") && p[1])
+ else if (streq (p[0], "ns-cert-type") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], "server"))
@@ -6881,7 +7132,6 @@ add_option (struct options *options,
goto err;
}
}
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L || ENABLE_CRYPTO_POLARSSL
else if (streq (p[0], "remote-cert-ku"))
{
int j;
@@ -6891,12 +7141,12 @@ add_option (struct options *options,
for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j)
sscanf (p[j], "%x", &(options->remote_cert_ku[j-1]));
}
- else if (streq (p[0], "remote-cert-eku") && p[1])
+ else if (streq (p[0], "remote-cert-eku") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->remote_cert_eku = p[1];
}
- else if (streq (p[0], "remote-cert-tls") && p[1])
+ else if (streq (p[0], "remote-cert-tls") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -6919,38 +7169,37 @@ add_option (struct options *options,
goto err;
}
}
-#endif /* OPENSSL_VERSION_NUMBER */
- else if (streq (p[0], "tls-timeout") && p[1])
+ else if (streq (p[0], "tls-timeout") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_TLS_PARMS);
options->tls_timeout = positive_atoi (p[1]);
}
- else if (streq (p[0], "reneg-bytes") && p[1])
+ else if (streq (p[0], "reneg-bytes") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_TLS_PARMS);
options->renegotiate_bytes = positive_atoi (p[1]);
}
- else if (streq (p[0], "reneg-pkts") && p[1])
+ else if (streq (p[0], "reneg-pkts") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_TLS_PARMS);
options->renegotiate_packets = positive_atoi (p[1]);
}
- else if (streq (p[0], "reneg-sec") && p[1])
+ else if (streq (p[0], "reneg-sec") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_TLS_PARMS);
options->renegotiate_seconds = positive_atoi (p[1]);
}
- else if (streq (p[0], "hand-window") && p[1])
+ else if (streq (p[0], "hand-window") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_TLS_PARMS);
options->handshake_window = positive_atoi (p[1]);
}
- else if (streq (p[0], "tran-window") && p[1])
+ else if (streq (p[0], "tran-window") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_TLS_PARMS);
options->transition_window = positive_atoi (p[1]);
}
- else if (streq (p[0], "tls-auth") && p[1])
+ else if (streq (p[0], "tls-auth") && p[1] && !p[3])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
if (streq (p[1], INLINE_FILE_TAG) && p[2])
@@ -6970,7 +7219,16 @@ add_option (struct options *options,
}
options->tls_auth_file = p[1];
}
- else if (streq (p[0], "key-method") && p[1])
+ else if (streq (p[0], "tls-crypt") && p[1] && !p[3])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ if (streq (p[1], INLINE_FILE_TAG) && p[2])
+ {
+ options->tls_crypt_inline = p[2];
+ }
+ options->tls_crypt_file = p[1];
+ }
+ else if (streq (p[0], "key-method") && p[1] && !p[2])
{
int key_method;
@@ -6986,8 +7244,13 @@ add_option (struct options *options,
}
options->key_method = key_method;
}
+ else if (streq (p[0], "x509-track") && p[1] && !p[2])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ x509_track_add (&options->x509_track, p[1], msglevel, &options->gc);
+ }
#ifdef ENABLE_X509ALTUSERNAME
- else if (streq (p[0], "x509-username-field") && p[1])
+ else if (streq (p[0], "x509-username-field") && p[1] && !p[2])
{
/* This option used to automatically upcase the fieldname passed as the
* option argument, e.g., "ou" became "OU". Now, this "helpfulness" is
@@ -7014,10 +7277,9 @@ add_option (struct options *options,
options->x509_username_field = p[1];
}
#endif /* ENABLE_X509ALTUSERNAME */
-#endif /* ENABLE_SSL */
#endif /* ENABLE_CRYPTO */
#ifdef ENABLE_PKCS11
- else if (streq (p[0], "show-pkcs11-ids"))
+ else if (streq (p[0], "show-pkcs11-ids") && !p[3])
{
char *provider = p[1];
bool cert_private = (p[2] == NULL ? false : ( atoi (p[2]) != 0 ));
@@ -7087,40 +7349,68 @@ add_option (struct options *options,
for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j)
options->pkcs11_cert_private[j-1] = atoi (p[j]) != 0 ? 1 : 0;
}
- else if (streq (p[0], "pkcs11-pin-cache") && p[1])
+ else if (streq (p[0], "pkcs11-pin-cache") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->pkcs11_pin_cache_period = atoi (p[1]);
}
- else if (streq (p[0], "pkcs11-id") && p[1])
+ else if (streq (p[0], "pkcs11-id") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->pkcs11_id = p[1];
}
- else if (streq (p[0], "pkcs11-id-management"))
+ else if (streq (p[0], "pkcs11-id-management") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->pkcs11_id_management = true;
}
#endif
- else if (streq (p[0], "rmtun"))
+ else if (streq (p[0], "rmtun") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->persist_config = true;
options->persist_mode = 0;
}
- else if (streq (p[0], "mktun"))
+ else if (streq (p[0], "mktun") && !p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
options->persist_config = true;
options->persist_mode = 1;
}
- else if (streq (p[0], "peer-id") && p[1])
+ else if (streq (p[0], "peer-id") && p[1] && !p[2])
{
VERIFY_PERMISSION (OPT_P_PEER_ID);
options->use_peer_id = true;
options->peer_id = atoi(p[1]);
}
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
+ else if (streq (p[0], "keying-material-exporter") && p[1] && p[2])
+ {
+ int ekm_length = positive_atoi (p[2]);
+
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+
+ if (strncmp(p[1], "EXPORTER", 8))
+ {
+ msg (msglevel, "Keying material exporter label must begin with "
+ "\"EXPORTER\"");
+ goto err;
+ }
+ if (ekm_length < 16 || ekm_length > 4095)
+ {
+ msg (msglevel, "Invalid keying material exporter length");
+ goto err;
+ }
+
+ options->keying_material_exporter_label = p[1];
+ options->keying_material_exporter_length = ekm_length;
+ }
+#endif
+ else if (streq (p[0], "allow-recursive-routing") && !p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->allow_recursive_routing = true;
+ }
else
{
int i;
@@ -7136,9 +7426,9 @@ add_option (struct options *options,
}
}
if (file)
- msg (msglevel, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION);
+ msg (msglevel, "Unrecognized option or missing or extra parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION);
else
- msg (msglevel, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION);
+ msg (msglevel, "Unrecognized option or missing or extra parameter(s): --%s (%s)", p[0], PACKAGE_VERSION);
}
err:
gc_free (&gc);
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index 26b09ea..a028556 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -39,7 +39,7 @@
#include "plugin.h"
#include "manage.h"
#include "proxy.h"
-#include "lzo.h"
+#include "comp.h"
#include "pushlist.h"
#include "clinat.h"
@@ -71,44 +71,37 @@ struct options_pre_pull
bool routes_ipv6_defined;
struct route_ipv6_option_list *routes_ipv6;
-#ifdef ENABLE_CLIENT_NAT
bool client_nat_defined;
struct client_nat_option_list *client_nat;
-#endif
int foreign_option_index;
};
#endif
-#if defined(ENABLE_CRYPTO) && !defined(ENABLE_CRYPTO_OPENSSL) && !defined(ENABLE_CRYPTO_POLARSSL)
-# error "At least one of OpenSSL or PolarSSL needs to be defined."
+#if defined(ENABLE_CRYPTO) && !defined(ENABLE_CRYPTO_OPENSSL) && !defined(ENABLE_CRYPTO_MBEDTLS)
+# error "At least one of OpenSSL or mbed TLS needs to be defined."
#endif
struct connection_entry
{
int proto;
- int local_port;
+ sa_family_t af;
+ const char* local_port;
bool local_port_defined;
- int remote_port;
+ const char *remote_port;
const char *local;
const char *remote;
bool remote_float;
bool bind_defined;
+ bool bind_ipv6_only;
bool bind_local;
int connect_retry_seconds;
- bool connect_retry_defined;
- int connect_retry_max;
+ int connect_retry_seconds_max;
int connect_timeout;
- bool connect_timeout_defined;
-#ifdef ENABLE_HTTP_PROXY
struct http_proxy_options *http_proxy_options;
-#endif
-#ifdef ENABLE_SOCKS
const char *socks_proxy_server;
- int socks_proxy_port;
+ const char *socks_proxy_port;
const char *socks_proxy_authfile;
- bool socks_proxy_retry;
-#endif
int tun_mtu; /* MTU of tun device */
bool tun_mtu_defined; /* true if user overriding parm with command line option */
@@ -124,9 +117,7 @@ struct connection_entry
int mssfix; /* Upper bound on TCP MSS */
bool mssfix_default; /* true if --mssfix was supplied without a parameter */
-#ifdef ENABLE_OCC
- int explicit_exit_notification; /* Explicitly tell peer when we are exiting via OCC_EXIT message */
-#endif
+ int explicit_exit_notification; /* Explicitly tell peer when we are exiting via OCC_EXIT or [RESTART] message */
# define CE_DISABLED (1<<0)
# define CE_MAN_QUERY_PROXY (1<<1)
@@ -143,8 +134,9 @@ struct connection_entry
struct remote_entry
{
const char *remote;
- int remote_port;
+ const char *remote_port;
int proto;
+ sa_family_t af;
};
#define CONNECTION_LIST_SIZE 64
@@ -153,8 +145,6 @@ struct connection_list
{
int len;
int current;
- int n_cycles;
- bool no_advance;
struct connection_entry *array[CONNECTION_LIST_SIZE];
};
@@ -168,6 +158,8 @@ struct remote_host_store
{
# define RH_HOST_LEN 80
char host[RH_HOST_LEN];
+#define RH_PORT_LEN 20
+ char port[RH_PORT_LEN];
};
/* Command line options */
@@ -198,20 +190,23 @@ struct options
bool show_ciphers;
bool show_digests;
bool show_engines;
-#ifdef ENABLE_SSL
bool show_tls_ciphers;
-#endif
+ bool show_curves;
bool genkey;
#endif
/* Networking parms */
+ int connect_retry_max;
struct connection_entry ce;
- char *remote_ip_hint;
struct connection_list *connection_list;
+
struct remote_list *remote_list;
- bool force_connection_list;
+ /* Do not advanced the connection or remote addr list*/
+ bool no_advance;
+ /* Counts the number of unsuccessful connection attempts */
+ unsigned int unsuccessful_attempts;
-#if HTTP_PROXY_OVERRIDE
+#if ENABLE_MANAGEMENT
struct http_proxy_options *http_proxy_override;
#endif
@@ -256,7 +251,6 @@ struct options
int ping_send_timeout; /* Send a TCP/UDP ping to remote every n seconds */
int ping_rec_timeout; /* Expect a TCP/UDP ping from remote at least once every n seconds */
bool ping_timer_remote; /* Run ping timer only if we have a remote address */
- bool tun_ipv6; /* Build tun dev that supports IPv6 */
# define PING_UNDEF 0
# define PING_EXIT 1
@@ -273,6 +267,8 @@ struct options
#endif
int resolve_retry_seconds; /* If hostname resolve fails, retry for n seconds */
+ bool resolve_in_advance;
+ const char *ip_remote_hint;
struct tuntap_options tuntap_options;
@@ -300,6 +296,7 @@ struct options
bool log;
bool suppress_timestamps;
+ bool machine_readable_output;
int nice;
int verbosity;
int mute;
@@ -315,9 +312,8 @@ struct options
/* optimize TUN/TAP/UDP writes */
bool fast_io;
-#ifdef ENABLE_LZO
- /* LZO_x flags from lzo.h */
- unsigned int lzo;
+#ifdef USE_COMP
+ struct compress_options comp;
#endif
/* buffer sizes */
@@ -339,16 +335,12 @@ struct options
int route_delay;
int route_delay_window;
bool route_delay_defined;
- int max_routes;
struct route_option_list *routes;
struct route_ipv6_option_list *routes_ipv6; /* IPv6 */
bool route_nopull;
bool route_gateway_via_dhcp;
bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */
-
-#ifdef ENABLE_CLIENT_NAT
struct client_nat_option_list *client_nat;
-#endif
#ifdef ENABLE_OCC
/* Enable options consistency check between peers */
@@ -357,7 +349,7 @@ struct options
#ifdef ENABLE_MANAGEMENT
const char *management_addr;
- int management_port;
+ const char *management_port;
const char *management_user_pass;
int management_log_history_cache;
int management_echo_buffer_size;
@@ -369,6 +361,7 @@ struct options
/* Mask of MF_ values of manage.h */
unsigned int management_flags;
+ const char *management_certificate;
#endif
#ifdef ENABLE_PLUGIN
@@ -429,9 +422,7 @@ struct options
bool push_ifconfig_defined;
in_addr_t push_ifconfig_local;
in_addr_t push_ifconfig_remote_netmask;
-#ifdef ENABLE_CLIENT_NAT
in_addr_t push_ifconfig_local_alias;
-#endif
bool push_ifconfig_constraint_defined;
in_addr_t push_ifconfig_constraint_network;
in_addr_t push_ifconfig_constraint_netmask;
@@ -439,6 +430,7 @@ struct options
struct in6_addr push_ifconfig_ipv6_local; /* IPv6 */
int push_ifconfig_ipv6_netbits; /* IPv6 */
struct in6_addr push_ifconfig_ipv6_remote; /* IPv6 */
+ bool push_ifconfig_ipv6_blocked; /* IPv6 */
bool enable_c2c;
bool duplicate_cn;
int cf_max;
@@ -450,9 +442,11 @@ struct options
const char *auth_user_pass_verify_script;
bool auth_user_pass_verify_script_via_file;
+ bool auth_token_generate;
+ unsigned int auth_token_lifetime;
#if PORT_SHARE
char *port_share_host;
- int port_share_port;
+ char *port_share_port;
const char *port_share_journal_dir;
#endif
#endif
@@ -464,8 +458,6 @@ struct options
const char *auth_user_pass_file;
struct options_pre_pull *pre_pull;
- int server_poll_timeout;
-
int scheduled_exit_interval;
#ifdef ENABLE_CLIENT_CR
@@ -478,9 +470,9 @@ struct options
const char *shared_secret_file;
const char *shared_secret_file_inline;
int key_direction;
- bool ciphername_defined;
const char *ciphername;
- bool authname_defined;
+ bool ncp_enabled;
+ const char *ncp_ciphers;
const char *authname;
int keysize;
const char *prng_hash;
@@ -497,7 +489,6 @@ struct options
bool use_prediction_resistance;
#endif
-#ifdef ENABLE_SSL
/* TLS (control channel) parms */
bool tls_server;
bool tls_client;
@@ -509,6 +500,7 @@ struct options
const char *priv_key_file;
const char *pkcs12_file;
const char *cipher_list;
+ const char *ecdh_curve;
const char *tls_verify;
int verify_x509_type;
const char *verify_x509_name;
@@ -518,6 +510,7 @@ struct options
const char *ca_file_inline;
const char *cert_file_inline;
const char *extra_certs_file_inline;
+ const char *crl_file_inline;
char *priv_key_file_inline;
const char *dh_file_inline;
const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */
@@ -565,10 +558,14 @@ struct options
/* Old key allowed to live n seconds after new key goes active */
int transition_window;
- /* Special authentication MAC for TLS control channel */
- const char *tls_auth_file; /* shared secret */
+ /* Shared secret used for TLS control channel authentication */
+ const char *tls_auth_file;
const char *tls_auth_file_inline;
+ /* Shared secret used for TLS control channel authenticated encryption */
+ const char *tls_crypt_file;
+ const char *tls_crypt_inline;
+
/* Allow only one session */
bool single_session;
@@ -578,17 +575,15 @@ struct options
bool tls_exit;
-#endif /* ENABLE_SSL */
#endif /* ENABLE_CRYPTO */
-#ifdef ENABLE_X509_TRACK
const struct x509_track *x509_track;
-#endif
/* special state parms */
int foreign_option_index;
-#ifdef WIN32
+#ifdef _WIN32
+ HANDLE msg_channel;
const char *exit_event_name;
bool exit_event_initial_state;
bool show_net_up;
@@ -598,6 +593,18 @@ struct options
bool use_peer_id;
uint32_t peer_id;
+
+#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000
+ /* Keying Material Exporters [RFC 5705] */
+ const char *keying_material_exporter_label;
+ int keying_material_exporter_length;
+#endif
+
+ struct pull_filter_list *pull_filter_list;
+
+ /* Useful when packets sent by openvpn itself are not subject
+ to the routing tables that would move packets into the tunnel. */
+ bool allow_recursive_routing;
};
#define streq(x, y) (!strcmp((x), (y)))
@@ -617,7 +624,7 @@ struct options
#define OPT_P_PERSIST_IP (1<<9)
#define OPT_P_COMP (1<<10) /* TODO */
#define OPT_P_MESSAGES (1<<11)
-#define OPT_P_CRYPTO (1<<12) /* TODO */
+#define OPT_P_NCP (1<<12) /**< Negotiable crypto parameters */
#define OPT_P_TLS_PARMS (1<<13) /* TODO */
#define OPT_P_MTU (1<<14) /* TODO */
#define OPT_P_NICE (1<<15)
@@ -652,7 +659,7 @@ struct options
#define PUSH_DEFINED(opt) (false)
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define ROUTE_OPTION_FLAGS(o) ((o)->route_method & ROUTE_METHOD_MASK)
#else
#define ROUTE_OPTION_FLAGS(o) (0)
@@ -690,7 +697,7 @@ void usage_small (void);
void show_library_versions(const unsigned int flags);
-#ifdef WIN32
+#ifdef _WIN32
void show_windows_version(const unsigned int flags);
#endif
@@ -722,7 +729,7 @@ void options_warning (char *actual, const char *expected);
void options_postprocess (struct options *options);
void pre_pull_save (struct options *o);
-void pre_pull_restore (struct options *o);
+void pre_pull_restore (struct options *o, struct gc_arena *gc);
bool apply_push_options (struct options *options,
struct buffer *buf,
@@ -784,20 +791,5 @@ void options_string_import (struct options *options,
bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
unsigned int * netbits, int msglevel );
-/*
- * inline functions
- */
-static inline bool
-connection_list_defined (const struct options *o)
-{
- return o->connection_list != NULL;
-}
-
-static inline void
-connection_list_set_no_advance (struct options *o)
-{
- if (o->connection_list)
- o->connection_list->no_advance = true;
-}
#endif
diff --git a/src/openvpn/otime.h b/src/openvpn/otime.h
index 4ca1032..c0b0f38 100644
--- a/src/openvpn/otime.h
+++ b/src/openvpn/otime.h
@@ -76,8 +76,8 @@ openvpn_gettimeofday (struct timeval *tv, void *tz)
static inline void
update_time (void)
{
-#ifdef WIN32
- /* on WIN32, gettimeofday is faster than time(NULL) */
+#ifdef _WIN32
+ /* on _WIN32, gettimeofday is faster than time(NULL) */
struct timeval tv;
openvpn_gettimeofday (&tv, NULL);
#else
@@ -90,8 +90,8 @@ update_time (void)
static inline void
update_time (void)
{
-#if defined(WIN32)
- /* on WIN32, gettimeofday is faster than time(NULL) */
+#if defined(_WIN32)
+ /* on _WIN32, gettimeofday is faster than time(NULL) */
struct timeval tv;
if (!gettimeofday (&tv, NULL))
{
diff --git a/src/openvpn/packet_id.c b/src/openvpn/packet_id.c
index baa4966..9874519 100644
--- a/src/openvpn/packet_id.c
+++ b/src/openvpn/packet_id.c
@@ -76,10 +76,9 @@ packet_id_debug (int msglevel,
}
void
-packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_backtrack, const char *name, int unit)
+packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit)
{
- dmsg (D_PID_DEBUG, "PID packet_id_init tcp_mode=%d seq_backtrack=%d time_backtrack=%d",
- tcp_mode,
+ dmsg (D_PID_DEBUG, "PID packet_id_init seq_backtrack=%d time_backtrack=%d",
seq_backtrack,
time_backtrack);
@@ -88,7 +87,7 @@ packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_
p->rec.name = name;
p->rec.unit = unit;
- if (seq_backtrack && !tcp_mode)
+ if (seq_backtrack)
{
ASSERT (MIN_SEQ_BACKTRACK <= seq_backtrack && seq_backtrack <= MAX_SEQ_BACKTRACK);
ASSERT (MIN_TIME_BACKTRACK <= time_backtrack && time_backtrack <= MAX_TIME_BACKTRACK);
diff --git a/src/openvpn/packet_id.h b/src/openvpn/packet_id.h
index 3ddaab6..fb059b7 100644
--- a/src/openvpn/packet_id.h
+++ b/src/openvpn/packet_id.h
@@ -210,7 +210,7 @@ struct packet_id
struct packet_id_rec rec;
};
-void packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_backtrack, const char *name, int unit);
+void packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit);
void packet_id_free (struct packet_id *p);
/* should we accept an incoming packet id ? */
@@ -258,6 +258,12 @@ bool packet_id_write (const struct packet_id_net *pin, struct buffer *buf, bool
* Inline functions.
*/
+/** Is this struct packet_id initialized? */
+static inline bool packet_id_initialized (const struct packet_id *pid)
+{
+ return pid->rec.initialized;
+}
+
/* are we in enabled state? */
static inline bool
packet_id_persist_enabled (const struct packet_id_persist *p)
diff --git a/src/openvpn/pf.c b/src/openvpn/pf.c
index 461beed..a3208db 100644
--- a/src/openvpn/pf.c
+++ b/src/openvpn/pf.c
@@ -35,8 +35,8 @@
#if defined(ENABLE_PF)
#include "init.h"
-
#include "memdbg.h"
+#include "ssl_verify.h"
#include "pf-inline.h"
diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c
index a1f13c5..2621058 100644
--- a/src/openvpn/pkcs11.c
+++ b/src/openvpn/pkcs11.c
@@ -744,9 +744,10 @@ _pkcs11_openvpn_show_pkcs11_ids_pin_prompt (
ASSERT (token!=NULL);
buf_printf (&pass_prompt, "Please enter '%s' token PIN or 'cancel': ", token->display);
-
- if (!get_console_input (BSTR (&pass_prompt), false, pin, pin_max)) {
- msg (M_FATAL, "Cannot read password from stdin");
+ if (!query_user_SINGLE(BSTR(&pass_prompt), BLEN(&pass_prompt),
+ pin, pin_max, false))
+ {
+ msg (M_FATAL, "Could not retrieve the PIN");
}
gc_free (&gc);
diff --git a/src/openvpn/pkcs11_polarssl.c b/src/openvpn/pkcs11_mbedtls.c
index a58beef..e208b61 100644
--- a/src/openvpn/pkcs11_polarssl.c
+++ b/src/openvpn/pkcs11_mbedtls.c
@@ -24,7 +24,7 @@
*/
/**
- * @file PKCS #11 PolarSSL backend
+ * @file PKCS #11 mbed TLS backend
*/
#ifdef HAVE_CONFIG_H
@@ -35,12 +35,12 @@
#include "syshead.h"
-#if defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_POLARSSL)
+#if defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_MBEDTLS)
#include "errlevel.h"
#include "pkcs11_backend.h"
-#include <polarssl/pkcs11.h>
-#include <polarssl/x509.h>
+#include <mbedtls/pkcs11.h>
+#include <mbedtls/x509.h>
int
pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
@@ -50,21 +50,22 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
ASSERT (NULL != ssl_ctx);
- ALLOC_OBJ_CLEAR (ssl_ctx->crt_chain, x509_crt);
- if (pkcs11_x509_cert_init(ssl_ctx->crt_chain, certificate)) {
- msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
+ ALLOC_OBJ_CLEAR (ssl_ctx->crt_chain, mbedtls_x509_crt);
+ if (mbedtls_pkcs11_x509_cert_bind(ssl_ctx->crt_chain, certificate)) {
+ msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object");
goto cleanup;
}
- ALLOC_OBJ_CLEAR (ssl_ctx->priv_key_pkcs11, pkcs11_context);
- if (pkcs11_priv_key_init(ssl_ctx->priv_key_pkcs11, certificate)) {
- msg (M_FATAL, "PKCS#11: Cannot initialize PolarSSL private key object");
+ ALLOC_OBJ_CLEAR (ssl_ctx->priv_key_pkcs11, mbedtls_pkcs11_context);
+ if (mbedtls_pkcs11_priv_key_bind(ssl_ctx->priv_key_pkcs11, certificate)) {
+ msg (M_FATAL, "PKCS#11: Cannot initialize mbed TLS private key object");
goto cleanup;
}
- ALLOC_OBJ_CLEAR (ssl_ctx->priv_key, pk_context);
- if (0 != pk_init_ctx_rsa_alt(ssl_ctx->priv_key, ssl_ctx->priv_key_pkcs11,
- ssl_pkcs11_decrypt, ssl_pkcs11_sign, ssl_pkcs11_key_len)) {
+ ALLOC_OBJ_CLEAR (ssl_ctx->priv_key, mbedtls_pk_context);
+ if (!mbed_ok(mbedtls_pk_setup_rsa_alt(ssl_ctx->priv_key,
+ ssl_ctx->priv_key_pkcs11, mbedtls_ssl_pkcs11_decrypt,
+ mbedtls_ssl_pkcs11_sign, mbedtls_ssl_pkcs11_key_len))) {
goto cleanup;
}
@@ -80,22 +81,22 @@ pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc)
char *ret = NULL;
char dn[1024] = {0};
- x509_crt polar_cert = {0};
+ mbedtls_x509_crt mbed_crt = {0};
- if (pkcs11_x509_cert_init(&polar_cert, cert)) {
- msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
+ if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) {
+ msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object");
goto cleanup;
}
- if (-1 == x509_dn_gets (dn, sizeof(dn), &polar_cert.subject)) {
- msg (M_FATAL, "PKCS#11: PolarSSL cannot parse subject");
+ if (-1 == mbedtls_x509_dn_gets (dn, sizeof(dn), &mbed_crt.subject)) {
+ msg (M_FATAL, "PKCS#11: mbed TLS cannot parse subject");
goto cleanup;
}
ret = string_alloc(dn, gc);
cleanup:
- x509_crt_free(&polar_cert);
+ mbedtls_x509_crt_free(&mbed_crt);
return ret;
}
@@ -106,23 +107,23 @@ pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial,
{
int ret = 1;
- x509_crt polar_cert = {0};
+ mbedtls_x509_crt mbed_crt = {0};
- if (pkcs11_x509_cert_init(&polar_cert, cert)) {
- msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
+ if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) {
+ msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object");
goto cleanup;
}
- if (-1 == x509_serial_gets (serial, serial_len, &polar_cert.serial)) {
- msg (M_FATAL, "PKCS#11: PolarSSL cannot parse serial");
+ if (-1 == mbedtls_x509_serial_gets (serial, serial_len, &mbed_crt.serial)) {
+ msg (M_FATAL, "PKCS#11: mbed TLS cannot parse serial");
goto cleanup;
}
ret = 0;
cleanup:
- x509_crt_free(&polar_cert);
+ mbedtls_x509_crt_free(&mbed_crt);
return ret;
}
-#endif /* defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_POLARSSL) */
+#endif /* defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_MBEDTLS) */
diff --git a/src/openvpn/platform.c b/src/openvpn/platform.c
index 16d4dac..6343647 100644
--- a/src/openvpn/platform.c
+++ b/src/openvpn/platform.c
@@ -158,7 +158,7 @@ platform_nice (int niceval)
unsigned int
platform_getpid ()
{
-#ifdef WIN32
+#ifdef _WIN32
return (unsigned int) GetCurrentProcessId ();
#else
#ifdef HAVE_GETPID
@@ -190,7 +190,7 @@ int
platform_chdir (const char* dir)
{
#ifdef HAVE_CHDIR
-#ifdef WIN32
+#ifdef _WIN32
int res;
struct gc_arena gc = gc_new ();
res = _wchdir (wide_string (dir, &gc));
@@ -210,7 +210,7 @@ platform_chdir (const char* dir)
bool
platform_system_ok (int stat)
{
-#ifdef WIN32
+#ifdef _WIN32
return stat == 0;
#else
return stat != -1 && WIFEXITED (stat) && WEXITSTATUS (stat) == 0;
@@ -220,7 +220,7 @@ platform_system_ok (int stat)
int
platform_access (const char *path, int mode)
{
-#ifdef WIN32
+#ifdef _WIN32
struct gc_arena gc = gc_new ();
int ret = _waccess (wide_string (path, &gc), mode & ~X_OK);
gc_free (&gc);
@@ -236,7 +236,7 @@ platform_access (const char *path, int mode)
void
platform_sleep_milliseconds (unsigned int n)
{
-#ifdef WIN32
+#ifdef _WIN32
Sleep (n);
#else
struct timeval tv;
@@ -252,7 +252,7 @@ platform_sleep_milliseconds (unsigned int n)
void
platform_sleep_until_signal (void)
{
-#ifdef WIN32
+#ifdef _WIN32
ASSERT (0);
#else
select (0, NULL, NULL, NULL, NULL);
@@ -263,7 +263,7 @@ platform_sleep_until_signal (void)
bool
platform_unlink (const char *filename)
{
-#if defined(WIN32)
+#if defined(_WIN32)
struct gc_arena gc = gc_new ();
BOOL ret = DeleteFileW (wide_string (filename, &gc));
gc_free (&gc);
@@ -278,7 +278,7 @@ platform_unlink (const char *filename)
FILE *
platform_fopen (const char *path, const char *mode)
{
-#ifdef WIN32
+#ifdef _WIN32
struct gc_arena gc = gc_new ();
FILE *f = _wfopen (wide_string (path, &gc), wide_string (mode, &gc));
gc_free (&gc);
@@ -291,7 +291,7 @@ platform_fopen (const char *path, const char *mode)
int
platform_open (const char *path, int flags, int mode)
{
-#ifdef WIN32
+#ifdef _WIN32
struct gc_arena gc = gc_new ();
int fd = _wopen (wide_string (path, &gc), flags, mode);
gc_free (&gc);
@@ -304,7 +304,7 @@ platform_open (const char *path, int flags, int mode)
int
platform_stat (const char *path, platform_stat_t *buf)
{
-#ifdef WIN32
+#ifdef _WIN32
struct gc_arena gc = gc_new ();
int res = _wstat (wide_string (path, &gc), buf);
gc_free (&gc);
diff --git a/src/openvpn/platform.h b/src/openvpn/platform.h
index 7c0a4d7..fe2685a 100644
--- a/src/openvpn/platform.h
+++ b/src/openvpn/platform.h
@@ -130,7 +130,7 @@ int platform_putenv (char *string);
FILE *platform_fopen (const char *path, const char *mode);
int platform_open (const char *path, int flags, int mode);
-#ifdef WIN32
+#ifdef _WIN32
typedef struct _stat platform_stat_t;
#else
typedef struct stat platform_stat_t;
diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c
index 4e5e6ce..2443438 100644
--- a/src/openvpn/plugin.c
+++ b/src/openvpn/plugin.c
@@ -27,6 +27,9 @@
#elif defined(_MSC_VER)
#include "config-msvc.h"
#endif
+#ifdef HAVE_CONFIG_VERSION_H
+#include "config-version.h"
+#endif
#include "syshead.h"
@@ -172,7 +175,7 @@ plugin_option_list_print (const struct plugin_option_list *list, int msglevel)
}
#endif
-#ifndef WIN32
+#ifndef _WIN32
static void
libdl_resolve_symbol (void *handle, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags)
@@ -203,7 +206,7 @@ plugin_init_item (struct plugin *p, const struct plugin_option *o)
p->so_pathname = o->so_pathname;
p->plugin_type_mask = plugin_supported_types ();
-#ifndef WIN32
+#ifndef _WIN32
p->handle = NULL;
#if defined(PLUGIN_LIBDIR)
@@ -347,6 +350,17 @@ static struct openvpn_plugin_callbacks callbacks = {
plugin_vlog
};
+
+/* Provide a wrapper macro for a version patch level string to plug-ins.
+ * This is located here purely to not make the code too messy with #ifndef
+ * inside a struct declaration
+ */
+#ifndef CONFIGURE_GIT_REVISION
+# define _OPENVPN_PATCH_LEVEL OPENVPN_VERSION_PATCH
+#else
+# define _OPENVPN_PATCH_LEVEL "git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS
+#endif
+
static void
plugin_open_item (struct plugin *p,
const struct plugin_option *o,
@@ -375,7 +389,12 @@ plugin_open_item (struct plugin *p,
(const char ** const) o->argv,
(const char ** const) envp,
&callbacks,
- SSLAPI };
+ SSLAPI,
+ PACKAGE_VERSION,
+ OPENVPN_VERSION_MAJOR,
+ OPENVPN_VERSION_MINOR,
+ _OPENVPN_PATCH_LEVEL
+ };
struct openvpn_plugin_args_open_return retargs;
CLEAR(retargs);
@@ -420,7 +439,7 @@ plugin_call_item (const struct plugin *p,
const struct argv *av,
struct openvpn_plugin_string_list **retlist,
const char **envp
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
, int certdepth,
openvpn_x509_cert_t *current_cert
#endif
@@ -449,7 +468,7 @@ plugin_call_item (const struct plugin *p,
(const char ** const) envp,
p->plugin_handle,
per_client_context,
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
(current_cert ? certdepth : -1),
current_cert
#else
@@ -500,10 +519,10 @@ plugin_close_item (struct plugin *p)
if (p->plugin_handle)
(*p->close)(p->plugin_handle);
-#ifndef WIN32
+#ifndef _WIN32
if (dlclose (p->handle))
msg (M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname);
-#elif defined(WIN32)
+#elif defined(_WIN32)
if (!FreeLibrary (p->module))
msg (M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname);
#endif
@@ -659,7 +678,7 @@ plugin_call_ssl (const struct plugin_list *pl,
const struct argv *av,
struct plugin_return *pr,
struct env_set *es
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
, int certdepth,
openvpn_x509_cert_t *current_cert
#endif
@@ -689,7 +708,7 @@ plugin_call_ssl (const struct plugin_list *pl,
av,
pr ? &pr->list[i] : NULL,
envp
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
,certdepth,
current_cert
#endif
diff --git a/src/openvpn/plugin.h b/src/openvpn/plugin.h
index 2f8416b..b1e0458 100644
--- a/src/openvpn/plugin.h
+++ b/src/openvpn/plugin.h
@@ -32,8 +32,8 @@
#ifdef ENABLE_CRYPTO_OPENSSL
#include "ssl_verify_openssl.h"
#endif
-#ifdef ENABLE_CRYPTO_POLARSSL
-#include "ssl_verify_polarssl.h"
+#ifdef ENABLE_CRYPTO_MBEDTLS
+#include "ssl_verify_mbedtls.h"
#endif
#include "openvpn-plugin.h"
@@ -59,7 +59,7 @@ struct plugin {
unsigned int plugin_type_mask;
int requested_initialization_point;
-#ifndef WIN32
+#ifndef _WIN32
void *handle;
#else
HMODULE module;
@@ -127,7 +127,7 @@ int plugin_call_ssl (const struct plugin_list *pl,
const struct argv *av,
struct plugin_return *pr,
struct env_set *es
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
, int current_cert_depth,
openvpn_x509_cert_t *current_cert
#endif
@@ -183,7 +183,7 @@ plugin_call_ssl (const struct plugin_list *pl,
const struct argv *av,
struct plugin_return *pr,
struct env_set *es
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
, int current_cert_depth,
openvpn_x509_cert_t *current_cert
#endif
@@ -202,7 +202,7 @@ plugin_call(const struct plugin_list *pl,
struct env_set *es)
{
return plugin_call_ssl(pl, type, av, pr, es
-#ifdef ENABLE_SSL
+#ifdef ENABLE_CRYPTO
, -1, NULL
#endif
);
diff --git a/src/openvpn/proto.h b/src/openvpn/proto.h
index f91e787..07612c8 100644
--- a/src/openvpn/proto.h
+++ b/src/openvpn/proto.h
@@ -219,6 +219,45 @@ struct ip_tcp_udp_hdr {
- sizeof(struct openvpn_tcphdr))
/*
+ * This returns an ip protocol version of packet inside tun
+ * and offset of IP header (via parameter).
+ */
+inline static int get_tun_ip_ver(int tunnel_type, struct buffer *buf, int *ip_hdr_offset)
+{
+ int ip_ver = -1;
+
+ /* for tun get ip version from ip header */
+ if (tunnel_type == DEV_TYPE_TUN)
+ {
+ *ip_hdr_offset = 0;
+ if (likely(BLEN (buf) >= (int) sizeof (struct openvpn_iphdr)))
+ {
+ ip_ver = OPENVPN_IPH_GET_VER (*BPTR(buf));
+ }
+ }
+ else if (tunnel_type == DEV_TYPE_TAP)
+ {
+ *ip_hdr_offset = (int)(sizeof (struct openvpn_ethhdr));
+ /* for tap get ip version from eth header */
+ if (likely(BLEN (buf) >= *ip_hdr_offset))
+ {
+ const struct openvpn_ethhdr *eh = (const struct openvpn_ethhdr *) BPTR (buf);
+ uint16_t proto = ntohs (eh->proto);
+ if (proto == OPENVPN_ETH_P_IPV6)
+ {
+ ip_ver = 6;
+ }
+ else if (proto == OPENVPN_ETH_P_IPV4)
+ {
+ ip_ver = 4;
+ }
+ }
+ }
+
+ return ip_ver;
+}
+
+/*
* If raw tunnel packet is IPv4 or IPv6, return true and increment
* buffer offset to start of IP header.
*/
diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c
index 89989d1..0f78020 100644
--- a/src/openvpn/proxy.c
+++ b/src/openvpn/proxy.c
@@ -41,8 +41,7 @@
#include "httpdigest.h"
#include "ntlm.h"
#include "memdbg.h"
-
-#ifdef ENABLE_HTTP_PROXY
+#include "forward.h"
#define UP_TYPE_PROXY "HTTP Proxy"
@@ -54,7 +53,6 @@ init_http_proxy_options_once (struct http_proxy_options **hpo,
{
ALLOC_OBJ_CLEAR_GC (*hpo, struct http_proxy_options, gc);
/* http proxy defaults */
- (*hpo)->timeout = 5;
(*hpo)->http_version = "1.0";
}
return *hpo;
@@ -243,6 +241,8 @@ get_user_pass_http (struct http_proxy_info *p, const bool force)
unsigned int flags = GET_USER_PASS_MANAGEMENT;
if (p->queried_creds)
flags |= GET_USER_PASS_PREVIOUS_CREDS_FAILED;
+ if (p->options.inline_creds)
+ flags |= GET_USER_PASS_INLINE_CREDS;
get_user_pass (&static_proxy_user_pass,
p->options.auth_file,
UP_TYPE_PROXY,
@@ -257,6 +257,8 @@ clear_user_pass_http (void)
purge_user_pass (&static_proxy_user_pass, true);
}
+#if 0
+/* function only used in #if 0 debug statement */
static void
dump_residual (socket_descriptor_t sd,
int timeout,
@@ -271,6 +273,7 @@ dump_residual (socket_descriptor_t sd,
msg (D_PROXY, "PROXY HEADER: '%s'", buf);
}
}
+#endif
/*
* Extract the Proxy-Authenticate header from the stream.
@@ -439,12 +442,11 @@ struct http_proxy_info *
http_proxy_new (const struct http_proxy_options *o)
{
struct http_proxy_info *p;
- struct http_proxy_options opt;
if (!o || !o->server)
msg (M_FATAL, "HTTP_PROXY: server not specified");
- ASSERT (legal_ipv4_port (o->port));
+ ASSERT ( o->port);
ALLOC_OBJ_CLEAR (p, struct http_proxy_info);
p->options = *o;
@@ -490,10 +492,72 @@ http_proxy_close (struct http_proxy_info *hp)
}
bool
+add_proxy_headers (struct http_proxy_info *p,
+ socket_descriptor_t sd, /* already open to proxy */
+ const char *host, /* openvpn server remote */
+ const char* port /* openvpn server port */
+ )
+{
+ char buf[512];
+ int i;
+ bool host_header_sent=false;
+
+ /*
+ * Send custom headers if provided
+ * If content is NULL the whole header is in name
+ * Also remember if we already sent a Host: header
+ */
+ for (i=0; i < MAX_CUSTOM_HTTP_HEADER && p->options.custom_headers[i].name;i++)
+ {
+ if (p->options.custom_headers[i].content)
+ {
+ openvpn_snprintf (buf, sizeof(buf), "%s: %s",
+ p->options.custom_headers[i].name,
+ p->options.custom_headers[i].content);
+ if (!strcasecmp(p->options.custom_headers[i].name, "Host"))
+ host_header_sent=true;
+ }
+ else
+ {
+ openvpn_snprintf (buf, sizeof(buf), "%s",
+ p->options.custom_headers[i].name);
+ if (!strncasecmp(p->options.custom_headers[i].name, "Host:", 5))
+ host_header_sent=true;
+ }
+
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
+ if (!send_line_crlf (sd, buf))
+ return false;
+ }
+
+ if (!host_header_sent)
+ {
+ openvpn_snprintf (buf, sizeof(buf), "Host: %s", host);
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
+ if (!send_line_crlf(sd, buf))
+ return false;
+ }
+
+ /* send User-Agent string if provided */
+ if (p->options.user_agent)
+ {
+ openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s",
+ p->options.user_agent);
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
+ if (!send_line_crlf (sd, buf))
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
establish_http_proxy_passthru (struct http_proxy_info *p,
socket_descriptor_t sd, /* already open to proxy */
const char *host, /* openvpn server remote */
- const int port, /* openvpn server port */
+ const char *port, /* openvpn server port */
+ struct event_timeout* server_poll_timeout,
struct buffer *lookahead,
volatile int *signal_received)
{
@@ -521,7 +585,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
else
{
/* format HTTP CONNECT message */
- openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
+ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%s HTTP/%s",
host,
port,
p->options.http_version);
@@ -532,18 +596,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
if (!send_line_crlf (sd, buf))
goto error;
- openvpn_snprintf(buf, sizeof(buf), "Host: %s", host);
- if (!send_line_crlf(sd, buf))
- goto error;
-
- /* send User-Agent string if provided */
- if (p->options.user_agent)
- {
- openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s",
- p->options.user_agent);
- if (!send_line_crlf (sd, buf))
- goto error;
- }
+ if (!add_proxy_headers (p, sd, host, port))
+ goto error;
/* auth specified? */
switch (p->auth_method)
@@ -586,7 +640,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
goto error;
/* receive reply from proxy */
- if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
+ if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received))
goto error;
/* remove trailing CR, LF */
@@ -615,7 +669,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
while (true)
{
- if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
+ if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received))
goto error;
chomp (buf);
msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
@@ -642,7 +696,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
/* now send the phase 3 reply */
/* format HTTP CONNECT message */
- openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
+ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%s HTTP/%s",
host,
port,
p->options.http_version);
@@ -658,14 +712,11 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
if (!send_line_crlf (sd, buf))
goto error;
-
/* send HOST etc, */
- openvpn_snprintf (buf, sizeof(buf), "Host: %s", host);
- msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
- if (!send_line_crlf (sd, buf))
- goto error;
+ if (!add_proxy_headers (p, sd, host, port))
+ goto error;
- msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3");
+ msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3");
{
const char *np3 = ntlm_phase_3 (p, buf2, &gc);
if (!np3)
@@ -685,7 +736,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
goto error;
/* receive reply from proxy */
- if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
+ if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received))
goto error;
/* remove trailing CR, LF */
@@ -730,7 +781,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
/* build the digest response */
- openvpn_snprintf (uri, sizeof(uri), "%s:%d",
+ openvpn_snprintf (uri, sizeof(uri), "%s:%s",
host,
port);
@@ -771,9 +822,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
goto error;
/* send HOST etc, */
- openvpn_snprintf (buf, sizeof(buf), "Host: %s", host);
- msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
- if (!send_line_crlf (sd, buf))
+ if (!add_proxy_headers (p, sd, host, port))
goto error;
/* send digest response */
@@ -795,7 +844,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
goto error;
/* receive reply from proxy */
- if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
+ if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received))
goto error;
/* remove trailing CR, LF */
@@ -819,7 +868,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
/* figure out what kind of authentication the proxy needs */
char *pa = NULL;
const int method = get_proxy_authenticate(sd,
- p->options.timeout,
+ get_server_poll_remaining_time (server_poll_timeout),
&pa,
NULL,
signal_received);
@@ -863,7 +912,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
msg (D_LINK_ERRORS, "HTTP proxy returned bad status");
#if 0
/* DEBUGGING -- show a multi-line HTTP error response */
- dump_residual(sd, p->options.timeout, signal_received);
+ dump_residual(sd, get_server_poll_remaining_time (server_poll_timeout), signal_received);
#endif
goto error;
}
@@ -871,7 +920,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
/* SUCCESS */
/* receive line from proxy and discard */
- if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received))
+ if (!recv_line (sd, NULL, 0, get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received))
goto error;
/*
@@ -894,14 +943,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
return ret;
error:
- /* on error, should we exit or restart? */
if (!*signal_received)
- *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */
+ *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- HTTP proxy error */
gc_free (&gc);
return ret;
}
-
-#else
-static void dummy(void) {}
-#endif /* ENABLE_HTTP_PROXY */
-
diff --git a/src/openvpn/proxy.h b/src/openvpn/proxy.h
index 5e476f1..7d2581c 100644
--- a/src/openvpn/proxy.h
+++ b/src/openvpn/proxy.h
@@ -28,8 +28,6 @@
#include "buffer.h"
#include "misc.h"
-#ifdef ENABLE_HTTP_PROXY
-
/* HTTP CONNECT authentication methods */
#define HTTP_AUTH_NONE 0
#define HTTP_AUTH_BASIC 1
@@ -38,11 +36,15 @@
#define HTTP_AUTH_NTLM2 4
#define HTTP_AUTH_N 5 /* number of HTTP_AUTH methods */
+struct http_custom_header {
+ const char *name;
+ const char *content;
+};
+
+#define MAX_CUSTOM_HTTP_HEADER 10
struct http_proxy_options {
const char *server;
- int port;
- bool retry;
- int timeout;
+ const char *port;
# define PAR_NO 0 /* don't support any auth retries */
# define PAR_ALL 1 /* allow all proxy auth protocols */
@@ -53,11 +55,13 @@ struct http_proxy_options {
const char *auth_file;
const char *http_version;
const char *user_agent;
+ struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER];
+ bool inline_creds;
};
struct http_proxy_options_simple {
const char *server;
- int port;
+ const char *port;
int auth_retry;
};
@@ -80,13 +84,12 @@ void http_proxy_close (struct http_proxy_info *hp);
bool establish_http_proxy_passthru (struct http_proxy_info *p,
socket_descriptor_t sd, /* already open to proxy */
const char *host, /* openvpn server remote */
- const int port, /* openvpn server port */
+ const char *port, /* openvpn server port */
+ struct event_timeout* server_poll_timeout,
struct buffer *lookahead,
volatile int *signal_received);
uint8_t *make_base64_string2 (const uint8_t *str, int str_len, struct gc_arena *gc);
uint8_t *make_base64_string (const uint8_t *str, struct gc_arena *gc);
-#endif /* ENABLE_HTTP_PROXY */
-
#endif /* PROXY_H */
diff --git a/src/openvpn/ps.c b/src/openvpn/ps.c
index 6495dc7..2cb68f1 100644
--- a/src/openvpn/ps.c
+++ b/src/openvpn/ps.c
@@ -223,12 +223,12 @@ port_share_sendmsg (const socket_descriptor_t sd,
if (socket_defined (sd_send))
{
- *((socket_descriptor_t*)CMSG_DATA(h)) = sd_send;
+ memcpy (CMSG_DATA(h), &sd_send, sizeof (sd_send));
}
else
{
socketpair (PF_UNIX, SOCK_DGRAM, 0, sd_null);
- *((socket_descriptor_t*)CMSG_DATA(h)) = sd_null[0];
+ memcpy (CMSG_DATA(h), &sd_null[0], sizeof (sd_null[0]));
}
status = sendmsg (sd, &mesg, MSG_NOSIGNAL);
@@ -330,8 +330,8 @@ journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_
if (!getpeername (pc->sd, (struct sockaddr *) &from.addr.sa, &slen)
&& !getsockname (cp->sd, (struct sockaddr *) &to.addr.sa, &dlen))
{
- const char *f = print_sockaddr_ex (&from, ":", PS_SHOW_PORT, &gc);
- const char *t = print_sockaddr_ex (&to, ":", PS_SHOW_PORT, &gc);
+ const char *f = print_openvpn_sockaddr (&from, &gc);
+ const char *t = print_openvpn_sockaddr (&to, &gc);
fnlen = strlen(journal_dir) + strlen(t) + 2;
jfn = (char *) malloc(fnlen);
check_malloc_return (jfn);
@@ -340,7 +340,8 @@ journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_
fd = platform_open (jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd != -1)
{
- write(fd, f, strlen(f));
+ if (write(fd, f, strlen(f)) != strlen(f))
+ msg(M_WARN, "PORT SHARE: writing to journal file (%s) failed", jfn);
close (fd);
cp->jfn = jfn;
}
@@ -371,17 +372,6 @@ proxy_list_close (struct proxy_connection **list)
}
}
-static void
-sock_addr_set (struct openvpn_sockaddr *osaddr,
- const in_addr_t addr,
- const int port)
-{
- CLEAR (*osaddr);
- osaddr->addr.in4.sin_family = AF_INET;
- osaddr->addr.in4.sin_addr.s_addr = htonl (addr);
- osaddr->addr.in4.sin_port = htons (port);
-}
-
static inline void
proxy_connection_io_requeue (struct proxy_connection *pc, const int rwflags_new, struct event_set *es)
{
@@ -403,26 +393,23 @@ proxy_connection_io_requeue (struct proxy_connection *pc, const int rwflags_new,
static bool
proxy_entry_new (struct proxy_connection **list,
struct event_set *es,
- const in_addr_t server_addr,
- const int server_port,
+ const struct sockaddr_in server_addr,
const socket_descriptor_t sd_client,
struct buffer *initial_data,
const char *journal_dir)
{
- struct openvpn_sockaddr osaddr;
socket_descriptor_t sd_server;
int status;
struct proxy_connection *pc;
struct proxy_connection *cp;
/* connect to port share server */
- sock_addr_set (&osaddr, server_addr, server_port);
if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
msg (M_WARN|M_ERRNO, "PORT SHARE PROXY: cannot create socket");
return false;
}
- status = openvpn_connect (sd_server, &osaddr, 5, NULL);
+ status = openvpn_connect (sd_server,(const struct sockaddr*) &server_addr, 5, NULL);
if (status)
{
msg (M_WARN, "PORT SHARE PROXY: connect to port-share server failed");
@@ -482,8 +469,7 @@ static bool
control_message_from_parent (const socket_descriptor_t sd_control,
struct proxy_connection **list,
struct event_set *es,
- const in_addr_t server_addr,
- const int server_port,
+ const struct sockaddr_in server_addr,
const int max_initial_buf,
const char *journal_dir)
{
@@ -516,7 +502,8 @@ control_message_from_parent (const socket_descriptor_t sd_control,
h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t));
h->cmsg_level = SOL_SOCKET;
h->cmsg_type = SCM_RIGHTS;
- *((socket_descriptor_t*)CMSG_DATA(h)) = SOCKET_UNDEFINED;
+ static const socket_descriptor_t socket_undefined = SOCKET_UNDEFINED;
+ memcpy (CMSG_DATA(h), &socket_undefined, sizeof(socket_undefined));
status = recvmsg (sd_control, &mesg, MSG_NOSIGNAL);
if (status != -1)
@@ -530,7 +517,8 @@ control_message_from_parent (const socket_descriptor_t sd_control,
}
else
{
- const socket_descriptor_t received_fd = *((socket_descriptor_t*)CMSG_DATA(h));
+ socket_descriptor_t received_fd;
+ memcpy (&received_fd, CMSG_DATA(h), sizeof(received_fd));
dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", (int)received_fd);
if (status >= 2 && command == COMMAND_REDIRECT)
@@ -539,7 +527,6 @@ control_message_from_parent (const socket_descriptor_t sd_control,
if (proxy_entry_new (list,
es,
server_addr,
- server_port,
received_fd,
&buf,
journal_dir))
@@ -716,8 +703,7 @@ proxy_connection_io_dispatch (struct proxy_connection *pc,
* This is the main function for the port share proxy background process.
*/
static void
-port_share_proxy (const in_addr_t hostaddr,
- const int port,
+port_share_proxy (const struct sockaddr_in hostaddr,
const socket_descriptor_t sd_control,
const int max_initial_buf,
const char *journal_dir)
@@ -754,7 +740,7 @@ port_share_proxy (const in_addr_t hostaddr,
const struct event_set_return *e = &esr[i];
if (e->arg == sd_control_marker)
{
- if (!control_message_from_parent (sd_control, &list, es, hostaddr, port, max_initial_buf, journal_dir))
+ if (!control_message_from_parent (sd_control, &list, es, hostaddr, max_initial_buf, journal_dir))
goto done;
}
else
@@ -789,14 +775,16 @@ port_share_proxy (const in_addr_t hostaddr,
*/
struct port_share *
port_share_open (const char *host,
- const int port,
+ const char *port,
const int max_initial_buf,
const char *journal_dir)
{
pid_t pid;
socket_descriptor_t fd[2];
- in_addr_t hostaddr;
+ struct sockaddr_in hostaddr;
struct port_share *ps;
+ int status;
+ struct addrinfo* ai;
ALLOC_OBJ_CLEAR (ps, struct port_share);
ps->foreground_fd = -1;
@@ -805,7 +793,12 @@ port_share_open (const char *host,
/*
* Get host's IP address
*/
- hostaddr = getaddr (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, host, 0, NULL, NULL);
+
+ status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_FATAL,
+ host, port, 0, NULL, AF_INET, &ai);
+ ASSERT (status==0);
+ hostaddr = *((struct sockaddr_in*) ai->ai_addr);
+ freeaddrinfo(ai);
/*
* Make a socket for foreground and background processes
@@ -881,7 +874,7 @@ port_share_open (const char *host,
prng_init (NULL, 0);
/* execute the event loop */
- port_share_proxy (hostaddr, port, fd[1], max_initial_buf, journal_dir);
+ port_share_proxy (hostaddr, fd[1], max_initial_buf, journal_dir);
openvpn_close_socket (fd[1]);
diff --git a/src/openvpn/ps.h b/src/openvpn/ps.h
index 4280635..e8919d4 100644
--- a/src/openvpn/ps.h
+++ b/src/openvpn/ps.h
@@ -44,7 +44,7 @@ struct port_share {
extern struct port_share *port_share;
struct port_share *port_share_open (const char *host,
- const int port,
+ const char *port,
const int max_initial_buf,
const char *journal_dir);
diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index 71f39c1..f86bdd3 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -33,12 +33,40 @@
#include "push.h"
#include "options.h"
#include "ssl.h"
+#include "ssl_verify.h"
#include "manage.h"
#include "memdbg.h"
#if P2MP
+static char push_reply_cmd[] = "PUSH_REPLY";
+
+/**
+ * Add an option to the given push list by providing a format string.
+ *
+ * The string added to the push options is allocated in o->gc, so the caller
+ * does not have to preserve anything.
+ *
+ * @param gc GC arena where options are allocated
+ * @param push_list Push list containing options
+ * @param msglevel The message level to use when printing errors
+ * @param fmt Format string for the option
+ * @param ... Format string arguments
+ *
+ * @return true on success, false on failure.
+ */
+static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list,
+ int msglevel, const char *fmt, ...)
+#ifdef __GNUC__
+#if __USE_MINGW_ANSI_STDIO
+ __attribute__ ((format (gnu_printf, 4, 5)))
+#else
+ __attribute__ ((format (__printf__, 4, 5)))
+#endif
+#endif
+ ;
+
/*
* Auth username/password
*
@@ -49,7 +77,8 @@ void
receive_auth_failed (struct context *c, const struct buffer *buffer)
{
msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer));
- connection_list_set_no_advance(&c->options);
+ c->options.no_advance=true;
+
if (c->options.pull)
{
switch (auth_retry_get ())
@@ -120,8 +149,7 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool
else if (m[i] == 'N')
{
/* next server? */
- if (c->options.connection_list)
- c->options.connection_list->no_advance = false;
+ c->options.no_advance = false;
}
}
}
@@ -214,11 +242,37 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
{
c->options.push_option_types_found |= option_types_found;
+ /* delay bringing tun/tap up until --push parms received from remote */
if (status == PUSH_MSG_REPLY)
- do_up (c, true, c->options.push_option_types_found ); /* delay bringing tun/tap up until --push parms received from remote */
+ {
+ if (!do_up (c, true, c->options.push_option_types_found))
+ {
+ msg (D_PUSH_ERRORS, "Failed to open tun/tap interface");
+ goto error;
+ }
+ }
event_timeout_clear (&c->c2.push_request_interval);
}
+ else if (status == PUSH_MSG_REQUEST)
+ {
+ if (c->options.mode == MODE_SERVER)
+ {
+ struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE];
+ /* Do not regenerate keys if client send a second push request */
+ if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized &&
+ !tls_session_update_crypto_params (session, &c->options,
+ &c->c2.frame))
+ {
+ msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
+ goto error;
+ }
+ }
+ }
+ goto cleanup;
+error:
+ register_signal (c, SIGUSR1, "process-push-msg-failed");
+cleanup:
gc_free (&gc);
}
@@ -241,79 +295,158 @@ send_push_request (struct context *c)
#if P2MP_SERVER
-bool
-send_push_reply (struct context *c)
+/**
+ * Prepare push options, based on local options and available peer info.
+ *
+ * @param context context structure storing data for VPN tunnel
+ * @param gc gc arena for allocating push options
+ * @param push_list push list to where options are added
+ *
+ * @return true on success, false on failure.
+ */
+static bool
+prepare_push_reply (struct context *c, struct gc_arena *gc,
+ struct push_list *push_list)
{
- struct gc_arena gc = gc_new ();
- struct buffer buf = alloc_buf_gc (PUSH_BUNDLE_SIZE, &gc);
- struct push_entry *e = c->options.push_list.head;
- bool multi_push = false;
- static char cmd[] = "PUSH_REPLY";
- const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */
- const int safe_cap = BCAP (&buf) - extra;
- bool push_sent = false;
+ const char *optstr = NULL;
+ struct tls_multi *tls_multi = c->c2.tls_multi;
+ const char * const peer_info = tls_multi->peer_info;
+ struct options *o = &c->options;
- msg( M_INFO, "send_push_reply(): safe_cap=%d", safe_cap );
+ /* ipv6 */
+ if (c->c2.push_ifconfig_ipv6_defined && !o->push_ifconfig_ipv6_blocked)
+ {
+ push_option_fmt (gc, push_list, M_USAGE, "ifconfig-ipv6 %s/%d %s",
+ print_in6_addr (c->c2.push_ifconfig_ipv6_local, 0, gc),
+ c->c2.push_ifconfig_ipv6_netbits,
+ print_in6_addr (c->c2.push_ifconfig_ipv6_remote,
+ 0, gc));
+ }
- buf_printf (&buf, "%s", cmd);
+ /* ipv4 */
+ if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local &&
+ c->c2.push_ifconfig_remote_netmask)
+ {
+ in_addr_t ifconfig_local = c->c2.push_ifconfig_local;
+ if (c->c2.push_ifconfig_local_alias)
+ ifconfig_local = c->c2.push_ifconfig_local_alias;
+ push_option_fmt (gc, push_list, M_USAGE, "ifconfig %s %s",
+ print_in_addr_t (ifconfig_local, 0, gc),
+ print_in_addr_t (c->c2.push_ifconfig_remote_netmask,
+ 0, gc));
+ }
+
+ /* Send peer-id if client supports it */
+ optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL;
+ if (optstr)
+ {
+ int proto = 0;
+ int r = sscanf(optstr, "IV_PROTO=%d", &proto);
+ if ((r == 1) && (proto >= 2))
+ {
+ push_option_fmt(gc, push_list, M_USAGE, "peer-id %d",
+ tls_multi->peer_id);
+ }
+ }
- if ( c->c2.push_ifconfig_ipv6_defined )
+ /* Push cipher if client supports Negotiable Crypto Parameters */
+ if (tls_peer_info_ncp_ver (peer_info) >= 2 && o->ncp_enabled)
{
- /* IPv6 is put into buffer first, could be lengthy */
- buf_printf( &buf, ",ifconfig-ipv6 %s/%d %s",
- print_in6_addr( c->c2.push_ifconfig_ipv6_local, 0, &gc),
- c->c2.push_ifconfig_ipv6_netbits,
- print_in6_addr( c->c2.push_ifconfig_ipv6_remote, 0, &gc) );
- if (BLEN (&buf) >= safe_cap)
+ /* if we have already created our key, we cannot change our own
+ * cipher, so disable NCP and warn = explain why
+ */
+ const struct tls_session *session = &tls_multi->session[TM_ACTIVE];
+ if ( session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized )
+ {
+ msg( M_INFO, "PUSH: client wants to negotiate cipher (NCP), but "
+ "server has already generated data channel keys, "
+ "ignoring client request" );
+ }
+ else
{
- msg (M_WARN, "--push ifconfig-ipv6 option is too long");
- goto fail;
+ /* Push the first cipher from --ncp-ciphers to the client.
+ * TODO: actual negotiation, instead of server dictatorship. */
+ char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc);
+ o->ciphername = strtok (push_cipher, ":");
+ push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername);
}
}
+ /* If server uses --auth-gen-token and we have an auth token
+ * to send to the client
+ */
+ if (false == tls_multi->auth_token_sent && NULL != tls_multi->auth_token)
+ {
+ push_option_fmt(gc, push_list, M_USAGE,
+ "auth-token %s", tls_multi->auth_token);
+ tls_multi->auth_token_sent = true;
+ }
+ return true;
+}
+
+static bool
+send_push_options (struct context *c, struct buffer *buf,
+ struct push_list *push_list, int safe_cap,
+ bool *push_sent, bool *multi_push)
+{
+ struct push_entry *e = push_list->head;
+
while (e)
{
if (e->enable)
{
const int l = strlen (e->option);
- if (BLEN (&buf) + l >= safe_cap)
+ if (BLEN (buf) + l >= safe_cap)
{
- buf_printf (&buf, ",push-continuation 2");
- {
- const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH);
- if (!status)
- goto fail;
- push_sent = true;
- multi_push = true;
- buf_reset_len (&buf);
- buf_printf (&buf, "%s", cmd);
- }
+ buf_printf (buf, ",push-continuation 2");
+ {
+ const bool status = send_control_channel_string (c, BSTR (buf), D_PUSH);
+ if (!status)
+ return false;
+ *push_sent = true;
+ *multi_push = true;
+ buf_reset_len (buf);
+ buf_printf (buf, "%s", push_reply_cmd);
+ }
}
- if (BLEN (&buf) + l >= safe_cap)
+ if (BLEN (buf) + l >= safe_cap)
{
msg (M_WARN, "--push option is too long");
- goto fail;
+ return false;
}
- buf_printf (&buf, ",%s", e->option);
+ buf_printf (buf, ",%s", e->option);
}
e = e->next;
}
+ return true;
+}
+
+static bool
+send_push_reply (struct context *c, struct push_list *per_client_push_list)
+{
+ struct gc_arena gc = gc_new ();
+ struct buffer buf = alloc_buf_gc (PUSH_BUNDLE_SIZE, &gc);
+ bool multi_push = false;
+ const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */
+ const int safe_cap = BCAP (&buf) - extra;
+ bool push_sent = false;
+
+ buf_printf (&buf, "%s", push_reply_cmd);
+
+ /* send options which are common to all clients */
+ if (!send_push_options (c, &buf, &c->options.push_list, safe_cap,
+ &push_sent, &multi_push))
+ goto fail;
+
+ /* send client-specific options */
+ if (!send_push_options (c, &buf, per_client_push_list, safe_cap,
+ &push_sent, &multi_push))
+ goto fail;
- if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask)
- {
- in_addr_t ifconfig_local = c->c2.push_ifconfig_local;
-#ifdef ENABLE_CLIENT_NAT
- if (c->c2.push_ifconfig_local_alias)
- ifconfig_local = c->c2.push_ifconfig_local_alias;
-#endif
- buf_printf (&buf, ",ifconfig %s %s",
- print_in_addr_t (ifconfig_local, 0, &gc),
- print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc));
- }
if (multi_push)
buf_printf (&buf, ",push-continuation 1");
- if (BLEN (&buf) > sizeof(cmd)-1)
+ if (BLEN (&buf) > sizeof(push_reply_cmd)-1)
{
const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH);
if (!status)
@@ -329,7 +462,7 @@ send_push_reply (struct context *c)
bool status = false;
buf_reset_len (&buf);
- buf_printf (&buf, "%s", cmd);
+ buf_printf (&buf, "%s", push_reply_cmd);
status = send_control_channel_string (c, BSTR(&buf), D_PUSH);
if (!status)
goto fail;
@@ -344,7 +477,8 @@ send_push_reply (struct context *c)
}
static void
-push_option_ex (struct options *o, const char *opt, bool enable, int msglevel)
+push_option_ex (struct gc_arena *gc, struct push_list *push_list,
+ const char *opt, bool enable, int msglevel)
{
if (!string_class (opt, CC_ANY, CC_COMMA))
{
@@ -353,20 +487,20 @@ push_option_ex (struct options *o, const char *opt, bool enable, int msglevel)
else
{
struct push_entry *e;
- ALLOC_OBJ_CLEAR_GC (e, struct push_entry, &o->gc);
+ ALLOC_OBJ_CLEAR_GC (e, struct push_entry, gc);
e->enable = true;
e->option = opt;
- if (o->push_list.head)
+ if (push_list->head)
{
- ASSERT(o->push_list.tail);
- o->push_list.tail->next = e;
- o->push_list.tail = e;
+ ASSERT(push_list->tail);
+ push_list->tail->next = e;
+ push_list->tail = e;
}
else
{
- ASSERT(!o->push_list.tail);
- o->push_list.head = e;
- o->push_list.tail = e;
+ ASSERT(!push_list->tail);
+ push_list->head = e;
+ push_list->tail = e;
}
}
}
@@ -374,7 +508,7 @@ push_option_ex (struct options *o, const char *opt, bool enable, int msglevel)
void
push_option (struct options *o, const char *opt, int msglevel)
{
- push_option_ex (o, opt, true, msglevel);
+ push_option_ex (&o->gc, &o->push_list, opt, true, msglevel);
}
void
@@ -386,7 +520,8 @@ clone_push_list (struct options *o)
push_reset (o);
while (e)
{
- push_option_ex (o, string_alloc (e->option, &o->gc), true, M_FATAL);
+ push_option_ex (&o->gc, &o->push_list,
+ string_alloc (e->option, &o->gc), true, M_FATAL);
e = e->next;
}
}
@@ -400,55 +535,137 @@ push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc)
push_option (o, opt, msglevel);
}
+static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list,
+ int msglevel, const char *format, ...)
+{
+ va_list arglist;
+ char tmp[256] = {0};
+ int len;
+ va_start (arglist, format);
+ len = vsnprintf (tmp, sizeof(tmp), format, arglist);
+ va_end (arglist);
+ if (len > sizeof(tmp)-1)
+ return false;
+ push_option_ex (gc, push_list, string_alloc (tmp, gc), true, msglevel);
+ return true;
+}
+
void
push_reset (struct options *o)
{
CLEAR (o->push_list);
}
+
+void
+push_remove_option (struct options *o, const char *p)
+{
+ msg (D_PUSH_DEBUG, "PUSH_REMOVE searching for: '%s'", p);
+
+ /* ifconfig-ipv6 is special, as not part of the push list */
+ if ( streq( p, "ifconfig-ipv6" ))
+ {
+ o->push_ifconfig_ipv6_blocked = true;
+ return;
+ }
+
+ if (o && o->push_list.head )
+ {
+ struct push_entry *e = o->push_list.head;
+
+ /* cycle through the push list */
+ while (e)
+ {
+ if ( e->enable &&
+ strncmp( e->option, p, strlen(p) ) == 0 )
+ {
+ msg (D_PUSH_DEBUG, "PUSH_REMOVE removing: '%s'", e->option);
+ e->enable = false;
+ }
+
+ e = e->next;
+ }
+ }
+}
#endif
+#if P2MP_SERVER
int
-process_incoming_push_msg (struct context *c,
- const struct buffer *buffer,
- bool honor_received_options,
- unsigned int permission_mask,
- unsigned int *option_types_found)
+process_incoming_push_request (struct context *c)
{
int ret = PUSH_MSG_ERROR;
- struct buffer buf = *buffer;
-#if P2MP_SERVER
- if (buf_string_compare_advance (&buf, "PUSH_REQUEST"))
+#ifdef ENABLE_ASYNC_PUSH
+ c->c2.push_request_received = true;
+#endif
+ if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED)
{
- if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED)
+ const char *client_reason = tls_client_reason (c->c2.tls_multi);
+ send_auth_failed (c, client_reason);
+ ret = PUSH_MSG_AUTH_FAILURE;
+ }
+ else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED)
+ {
+ time_t now;
+
+ openvpn_time (&now);
+ if (c->c2.sent_push_reply_expiry > now)
{
- const char *client_reason = tls_client_reason (c->c2.tls_multi);
- send_auth_failed (c, client_reason);
- ret = PUSH_MSG_AUTH_FAILURE;
+ ret = PUSH_MSG_ALREADY_REPLIED;
}
- else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED)
+ else
{
- time_t now;
+ /* per-client push options - peer-id, cipher, ifconfig, ipv6-ifconfig */
+ struct push_list push_list;
+ struct gc_arena gc = gc_new ();
- openvpn_time(&now);
- if (c->c2.sent_push_reply_expiry > now)
+ CLEAR (push_list);
+ if (prepare_push_reply (c, &gc, &push_list) &&
+ send_push_reply (c, &push_list))
{
- ret = PUSH_MSG_ALREADY_REPLIED;
- }
- else
- {
- if (send_push_reply (c))
- {
- ret = PUSH_MSG_REQUEST;
- c->c2.sent_push_reply_expiry = now + 30;
- }
+ ret = PUSH_MSG_REQUEST;
+ c->c2.sent_push_reply_expiry = now + 30;
}
+ gc_free(&gc);
}
- else
+ }
+ else
+ {
+ ret = PUSH_MSG_REQUEST_DEFERRED;
+ }
+
+ return ret;
+}
+#endif
+
+static void
+push_update_digest(md_ctx_t *ctx, struct buffer *buf)
+{
+ char line[OPTION_PARM_SIZE];
+ while (buf_parse (buf, ',', line, sizeof (line)))
+ {
+ /* peer-id might change on restart and this should not trigger reopening tun */
+ if (strstr (line, "peer-id ") != line)
{
- ret = PUSH_MSG_REQUEST_DEFERRED;
+ md_ctx_update (ctx, (const uint8_t *) line, strlen(line));
}
}
+}
+
+int
+process_incoming_push_msg (struct context *c,
+ const struct buffer *buffer,
+ bool honor_received_options,
+ unsigned int permission_mask,
+ unsigned int *option_types_found)
+{
+ int ret = PUSH_MSG_ERROR;
+ struct buffer buf = *buffer;
+
+#if P2MP_SERVER
+ if (buf_string_compare_advance (&buf, "PUSH_REQUEST"))
+ {
+ ret = process_incoming_push_request(c);
+ }
else
#endif
@@ -460,12 +677,12 @@ process_incoming_push_msg (struct context *c,
struct buffer buf_orig = buf;
if (!c->c2.pulled_options_md5_init_done)
{
- md5_state_init (&c->c2.pulled_options_state);
+ md_ctx_init(&c->c2.pulled_options_state, md_kt_get("MD5"));
c->c2.pulled_options_md5_init_done = true;
}
if (!c->c2.did_pre_pull_restore)
{
- pre_pull_restore (&c->options);
+ pre_pull_restore (&c->options, &c->c2.gc);
c->c2.did_pre_pull_restore = true;
}
if (apply_push_options (&c->options,
@@ -473,20 +690,22 @@ process_incoming_push_msg (struct context *c,
permission_mask,
option_types_found,
c->c2.es))
- switch (c->options.push_continuation)
- {
- case 0:
- case 1:
- md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig));
- md5_state_final (&c->c2.pulled_options_state, &c->c2.pulled_options_digest);
- c->c2.pulled_options_md5_init_done = false;
- ret = PUSH_MSG_REPLY;
- break;
- case 2:
- md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig));
- ret = PUSH_MSG_CONTINUATION;
- break;
- }
+ {
+ push_update_digest (&c->c2.pulled_options_state, &buf_orig);
+ switch (c->options.push_continuation)
+ {
+ case 0:
+ case 1:
+ md_ctx_final (&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest);
+ md_ctx_cleanup (&c->c2.pulled_options_state);
+ c->c2.pulled_options_md5_init_done = false;
+ ret = PUSH_MSG_REPLY;
+ break;
+ case 2:
+ ret = PUSH_MSG_CONTINUATION;
+ break;
+ }
+ }
}
else if (ch == '\0')
{
@@ -518,7 +737,8 @@ remove_iroutes_from_push_route_list (struct options *o)
/* parse the push item */
CLEAR (p);
- if (parse_line (e->option, p, SIZE (p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc))
+ if ( e->enable &&
+ parse_line (e->option, p, SIZE (p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc))
{
/* is the push item a route directive? */
if (p[0] && !strcmp (p[0], "route") && !p[3])
@@ -544,12 +764,12 @@ remove_iroutes_from_push_route_list (struct options *o)
}
}
}
- }
- /* should we copy the push item? */
- e->enable = enable;
- if (!enable)
- msg (D_PUSH, "REMOVE PUSH ROUTE: '%s'", e->option);
+ /* should we copy the push item? */
+ e->enable = enable;
+ if (!enable)
+ msg (D_PUSH, "REMOVE PUSH ROUTE: '%s'", e->option);
+ }
e = e->next;
}
diff --git a/src/openvpn/push.h b/src/openvpn/push.h
index 8c3f157..d6cb4b1 100644
--- a/src/openvpn/push.h
+++ b/src/openvpn/push.h
@@ -37,8 +37,7 @@
#define PUSH_MSG_CONTINUATION 5
#define PUSH_MSG_ALREADY_REPLIED 6
-void incoming_push_message (struct context *c,
- const struct buffer *buffer);
+int process_incoming_push_request (struct context *c);
int process_incoming_push_msg (struct context *c,
const struct buffer *buffer,
@@ -54,14 +53,15 @@ void server_pushed_signal (struct context *c, const struct buffer *buffer, const
#if P2MP_SERVER
+void incoming_push_message (struct context *c, const struct buffer *buffer);
+
void clone_push_list (struct options *o);
void push_option (struct options *o, const char *opt, int msglevel);
void push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc);
void push_reset (struct options *o);
-
-bool send_push_reply (struct context *c);
+void push_remove_option (struct options *o, const char *p);
void remove_iroutes_from_push_route_list (struct options *o);
diff --git a/src/openvpn/reliable.c b/src/openvpn/reliable.c
index 763169e..22883a7 100644
--- a/src/openvpn/reliable.c
+++ b/src/openvpn/reliable.c
@@ -35,7 +35,7 @@
#include "syshead.h"
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
#include "buffer.h"
#include "error.h"
@@ -754,4 +754,4 @@ reliable_debug_print (const struct reliable *rel, char *desc)
#else
static void dummy(void) {}
-#endif /* ENABLE_CRYPTO && ENABLE_SSL*/
+#endif /* ENABLE_CRYPTO */
diff --git a/src/openvpn/reliable.h b/src/openvpn/reliable.h
index 594ab82..828dcd3 100644
--- a/src/openvpn/reliable.h
+++ b/src/openvpn/reliable.h
@@ -29,7 +29,7 @@
*/
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
#ifndef RELIABLE_H
#define RELIABLE_H
@@ -477,4 +477,4 @@ void reliable_ack_debug_print (const struct reliable_ack *ack, char *desc);
#endif /* RELIABLE_H */
-#endif /* ENABLE_CRYPTO && ENABLE_SSL */
+#endif /* ENABLE_CRYPTO */
diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index 827bd79..fec12c1 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -42,12 +42,21 @@
#include "manage.h"
#include "win32.h"
#include "options.h"
-#include "win32.h"
#include "memdbg.h"
-#ifdef WIN32
+#if defined(TARGET_LINUX) || defined(TARGET_ANDROID)
+#include <linux/rtnetlink.h> /* RTM_GETROUTE etc. */
+#endif
+
+#ifdef _WIN32
+#include "openvpn-msg.h"
+
#define METRIC_NOT_USED ((DWORD)-1)
+static bool add_route_service (const struct route_ipv4 *, const struct tuntap *);
+static bool del_route_service (const struct route_ipv4 *, const struct tuntap *);
+static bool add_route_ipv6_service (const struct route_ipv6 *, const struct tuntap *);
+static bool del_route_ipv6_service (const struct route_ipv6 *, const struct tuntap *);
#endif
static void delete_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es);
@@ -93,76 +102,62 @@ add_bypass_address (struct route_bypass *rb, const in_addr_t a)
}
struct route_option_list *
-new_route_option_list (const int max_routes, struct gc_arena *a)
+new_route_option_list (struct gc_arena *a)
{
struct route_option_list *ret;
- ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_option_list, struct route_option, max_routes, a);
- ret->capacity = max_routes;
+ ALLOC_OBJ_CLEAR_GC (ret, struct route_option_list, a);
+ ret->gc = a;
return ret;
}
struct route_ipv6_option_list *
-new_route_ipv6_option_list (const int max_routes, struct gc_arena *a)
+new_route_ipv6_option_list (struct gc_arena *a)
{
struct route_ipv6_option_list *ret;
- ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_option_list, struct route_ipv6_option, max_routes, a);
- ret->capacity = max_routes;
+ ALLOC_OBJ_CLEAR_GC (ret, struct route_ipv6_option_list, a);
+ ret->gc = a;
return ret;
}
+/*
+ * NOTE: structs are cloned/copied shallow by design.
+ * The routes list from src will stay intact since it is allocated using
+ * the options->gc. The cloned/copied lists will share this common tail
+ * to avoid copying the data around between pulls. Pulled routes use
+ * the c2->gc so they get freed immediately after a reconnect.
+ */
struct route_option_list *
clone_route_option_list (const struct route_option_list *src, struct gc_arena *a)
{
- const size_t rl_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list));
- struct route_option_list *ret = gc_malloc (rl_size, false, a);
- memcpy (ret, src, rl_size);
+ struct route_option_list *ret;
+ ALLOC_OBJ_GC (ret, struct route_option_list, a);
+ *ret = *src;
return ret;
}
struct route_ipv6_option_list *
clone_route_ipv6_option_list (const struct route_ipv6_option_list *src, struct gc_arena *a)
{
- const size_t rl_size = array_mult_safe (sizeof(struct route_ipv6_option), src->capacity, sizeof(struct route_ipv6_option_list));
- struct route_ipv6_option_list *ret = gc_malloc (rl_size, false, a);
- memcpy (ret, src, rl_size);
+ struct route_ipv6_option_list *ret;
+ ALLOC_OBJ_GC (ret, struct route_ipv6_option_list, a);
+ *ret = *src;
return ret;
}
void
-copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src)
+copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a)
{
- const size_t src_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list));
- if (src->capacity > dest->capacity)
- msg (M_FATAL, PACKAGE_NAME " ROUTE: (copy) number of route options in src (%d) is greater than route list capacity in dest (%d)", src->capacity, dest->capacity);
- memcpy (dest, src, src_size);
+ *dest = *src;
+ dest->gc = a;
}
void
copy_route_ipv6_option_list (struct route_ipv6_option_list *dest,
- const struct route_ipv6_option_list *src)
+ const struct route_ipv6_option_list *src,
+ struct gc_arena *a)
{
- const size_t src_size = array_mult_safe (sizeof(struct route_ipv6_option), src->capacity, sizeof(struct route_ipv6_option_list));
- if (src->capacity > dest->capacity)
- msg (M_FATAL, PACKAGE_NAME " ROUTE: (copy) number of route options in src (%d) is greater than route list capacity in dest (%d)", src->capacity, dest->capacity);
- memcpy (dest, src, src_size);
-}
-
-struct route_list *
-new_route_list (const int max_routes, struct gc_arena *a)
-{
- struct route_list *ret;
- ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route_ipv4, max_routes, a);
- ret->capacity = max_routes;
- return ret;
-}
-
-struct route_ipv6_list *
-new_route_ipv6_list (const int max_routes, struct gc_arena *a)
-{
- struct route_ipv6_list *ret;
- ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_list, struct route_ipv6, max_routes, a);
- ret->capacity = max_routes;
- return ret;
+ *dest = *src;
+ dest->gc = a;
}
static const char *
@@ -292,15 +287,15 @@ init_route (struct route_ipv4 *r,
/* get_special_addr replaces specialaddr with a special ip addr
like gw. getaddrinfo is called to convert a a addrinfo struct */
- if(get_special_addr (rl, ro->network, &special.s_addr, &status))
+ if(get_special_addr (rl, ro->network, (in_addr_t *) &special.s_addr, &status))
{
special.s_addr = htonl(special.s_addr);
- ret = openvpn_getaddrinfo(0, inet_ntoa(special), 0, NULL,
+ ret = openvpn_getaddrinfo(0, inet_ntoa(special), NULL, 0, NULL,
AF_INET, network_list);
}
else
ret = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL,
- ro->network, 0, NULL, AF_INET, network_list);
+ ro->network, NULL, 0, NULL, AF_INET, network_list);
status = (ret == 0);
@@ -389,7 +384,7 @@ init_route_ipv6 (struct route_ipv6 *r6,
const struct route_ipv6_option *r6o,
const struct route_ipv6_list *rl6 )
{
- r6->defined = false;
+ CLEAR (*r6);
if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, M_WARN ))
goto fail;
@@ -402,7 +397,7 @@ init_route_ipv6 (struct route_ipv6 *r6,
msg( M_WARN, PACKAGE_NAME "ROUTE6: cannot parse gateway spec '%s'", r6o->gateway );
}
}
- else if (rl6->remote_endpoint_defined)
+ else if (rl6->spec_flags & RTSA_REMOTE_ENDPOINT)
{
r6->gateway = rl6->remote_endpoint_ipv6;
}
@@ -414,7 +409,6 @@ init_route_ipv6 (struct route_ipv6 *r6,
/* metric */
- r6->metric_defined = false;
r6->metric = -1;
if (is_route_parm_defined (r6o->metric))
{
@@ -426,22 +420,21 @@ init_route_ipv6 (struct route_ipv6 *r6,
r6o->metric);
goto fail;
}
- r6->metric_defined = true;
+ r6->flags |= RT_METRIC_DEFINED;
}
- else if (rl6->default_metric_defined)
+ else if (rl6->spec_flags & RTSA_DEFAULT_METRIC)
{
r6->metric = rl6->default_metric;
- r6->metric_defined = true;
+ r6->flags |= RT_METRIC_DEFINED;
}
- r6->defined = true;
+ r6->flags |= RT_DEFINED;
return true;
fail:
msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s",
r6o->prefix);
- r6->defined = false;
return false;
}
@@ -453,15 +446,14 @@ add_route_to_option_list (struct route_option_list *l,
const char *metric)
{
struct route_option *ro;
- if (l->n >= l->capacity)
- msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d routes -- please increase the max-routes option in the client configuration file",
- l->capacity);
- ro = &l->routes[l->n];
+ ALLOC_OBJ_GC (ro, struct route_option, l->gc);
ro->network = network;
ro->netmask = netmask;
ro->gateway = gateway;
ro->metric = metric;
- ++l->n;
+ ro->next = l->routes;
+ l->routes = ro;
+
}
void
@@ -471,32 +463,26 @@ add_route_ipv6_to_option_list (struct route_ipv6_option_list *l,
const char *metric)
{
struct route_ipv6_option *ro;
- if (l->n >= l->capacity)
- msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d IPv6 routes -- please increase the max-routes option in the client configuration file",
- l->capacity);
- ro = &l->routes_ipv6[l->n];
+ ALLOC_OBJ_GC (ro, struct route_ipv6_option, l->gc);
ro->prefix = prefix;
ro->gateway = gateway;
ro->metric = metric;
- ++l->n;
+ ro->next = l->routes_ipv6;
+ l->routes_ipv6 = ro;
}
void
clear_route_list (struct route_list *rl)
{
- const int capacity = rl->capacity;
- const size_t rl_size = array_mult_safe (sizeof(struct route_ipv4), capacity, sizeof(struct route_list));
- memset(rl, 0, rl_size);
- rl->capacity = capacity;
+ gc_free (&rl->gc);
+ CLEAR (*rl);
}
void
clear_route_ipv6_list (struct route_ipv6_list *rl6)
{
- const int capacity = rl6->capacity;
- const size_t rl6_size = array_mult_safe (sizeof(struct route_ipv6), capacity, sizeof(struct route_ipv6_list));
- memset(rl6, 0, rl6_size);
- rl6->capacity = capacity;
+ gc_free (&rl6->gc);
+ CLEAR (*rl6);
}
void
@@ -517,22 +503,27 @@ add_block_local_item (struct route_list *rl,
{
const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED);
if ((rl->rgi.flags & rgi_needed) == rgi_needed
- && rl->rgi.gateway.netmask < 0xFFFFFFFF
- && (rl->n)+2 <= rl->capacity)
+ && rl->rgi.gateway.netmask < 0xFFFFFFFF)
{
- struct route_ipv4 r;
+ struct route_ipv4 *r1, *r2;
unsigned int l2;
+ ALLOC_OBJ_GC (r1, struct route_ipv4, &rl->gc);
+ ALLOC_OBJ_GC (r2, struct route_ipv4, &rl->gc);
+
/* split a route into two smaller blocking routes, and direct them to target */
- CLEAR(r);
- r.flags = RT_DEFINED;
- r.gateway = target;
- r.network = gateway->addr & gateway->netmask;
l2 = ((~gateway->netmask)+1)>>1;
- r.netmask = ~(l2-1);
- rl->routes[rl->n++] = r;
- r.network += l2;
- rl->routes[rl->n++] = r;
+ r1->flags = RT_DEFINED;
+ r1->gateway = target;
+ r1->network = gateway->addr & gateway->netmask;
+ r1->netmask = ~(l2-1);
+ r1->next = rl->routes;
+ rl->routes = r1;
+
+ *r2 = *r1;
+ r2->network += l2;
+ r2->next = rl->routes;
+ rl->routes = r2;
}
}
@@ -547,8 +538,10 @@ add_block_local (struct route_list *rl)
{
size_t i;
+#ifndef TARGET_ANDROID
/* add bypass for gateway addr */
add_bypass_address (&rl->spec.bypass, rl->rgi.gateway.addr);
+#endif
/* block access to local subnet */
add_block_local_item (rl, &rl->rgi.gateway, rl->spec.remote_endpoint);
@@ -597,7 +590,7 @@ init_route_list (struct route_list *rl,
{
setenv_route_addr (es, "net_gateway", rl->rgi.gateway.addr, -1);
#if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL)
- print_default_gateway (D_ROUTE, &rl->rgi);
+ print_default_gateway (D_ROUTE, &rl->rgi, NULL);
#endif
}
else
@@ -644,72 +637,108 @@ init_route_list (struct route_list *rl,
/* parse the routes from opt to rl */
{
- int i = 0;
- int j = rl->n;
- bool warned = false;
- for (i = 0; i < opt->n; ++i)
+ struct route_option *ro;
+ for (ro = opt->routes; ro; ro = ro->next)
{
struct addrinfo* netlist = NULL;
struct route_ipv4 r;
- if (!init_route (&r,
- &netlist,
- &opt->routes[i],
- rl))
+ if (!init_route (&r, &netlist, ro, rl))
ret = false;
else
{
struct addrinfo* curele;
for (curele = netlist; curele; curele = curele->ai_next)
{
- if (j < rl->capacity)
- {
- r.network = ntohl(((struct sockaddr_in*)(curele)->ai_addr)->sin_addr.s_addr);
- rl->routes[j++] = r;
- }
- else
- {
- if (!warned)
- {
- msg (M_WARN, PACKAGE_NAME " ROUTE: routes dropped because number of expanded routes is greater than route list capacity (%d)", rl->capacity);
- warned = true;
- }
- }
+ struct route_ipv4 *new;
+ ALLOC_OBJ_GC (new, struct route_ipv4, &rl->gc);
+ *new = r;
+ new->network = ntohl (((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr);
+ new->next = rl->routes;
+ rl->routes = new;
}
}
if (netlist)
- freeaddrinfo(netlist);
+ gc_addspecial(netlist, &gc_freeaddrinfo_callback, &gc);
}
- rl->n = j;
}
gc_free (&gc);
return ret;
}
+/* check whether an IPv6 host address is covered by a given route_ipv6
+ * (not the most beautiful implementation in the world, but portable and
+ * "good enough")
+ */
+static bool
+route_ipv6_match_host( const struct route_ipv6 *r6,
+ const struct in6_addr *host )
+{
+ unsigned int bits = r6->netbits;
+ int i;
+ unsigned int mask;
+
+ if ( bits>128 )
+ return false;
+
+ for( i=0; bits >= 8; i++, bits -= 8 )
+ {
+ if ( r6->network.s6_addr[i] != host->s6_addr[i] )
+ return false;
+ }
+
+ if ( bits == 0 )
+ return true;
+
+ mask = 0xff << (8-bits);
+
+ if ( (r6->network.s6_addr[i] & mask) == (host->s6_addr[i] & mask ))
+ return true;
+
+ return false;
+}
+
bool
init_route_ipv6_list (struct route_ipv6_list *rl6,
const struct route_ipv6_option_list *opt6,
const char *remote_endpoint,
int default_metric,
+ const struct in6_addr *remote_host_ipv6,
struct env_set *es)
{
struct gc_arena gc = gc_new ();
bool ret = true;
+ bool need_remote_ipv6_route;
clear_route_ipv6_list (rl6);
rl6->flags = opt6->flags;
+ if (remote_host_ipv6)
+ {
+ rl6->remote_host_ipv6 = *remote_host_ipv6;
+ rl6->spec_flags |= RTSA_REMOTE_HOST;
+ }
+
if (default_metric >= 0 )
{
rl6->default_metric = default_metric;
- rl6->default_metric_defined = true;
+ rl6->spec_flags |= RTSA_DEFAULT_METRIC;
}
- /* "default_gateway" is stuff for "redirect-gateway", which we don't
- * do for IPv6 yet -> TODO
- */
+ msg (D_ROUTE, "GDG6: remote_host_ipv6=%s",
+ remote_host_ipv6? print_in6_addr (*remote_host_ipv6, 0, &gc): "n/a" );
+
+ get_default_gateway_ipv6 (&rl6->rgi6, remote_host_ipv6);
+ if (rl6->rgi6.flags & RGI_ADDR_DEFINED)
+ {
+ setenv_str (es, "net_gateway_ipv6", print_in6_addr (rl6->rgi6.gateway.addr_ipv6, 0, &gc));
+#if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL)
+ print_default_gateway (D_ROUTE, NULL, &rl6->rgi6);
+#endif
+ }
+ else
{
dmsg (D_ROUTE, "ROUTE6: default_gateway=UNDEF");
}
@@ -719,36 +748,81 @@ init_route_ipv6_list (struct route_ipv6_list *rl6,
if ( inet_pton( AF_INET6, remote_endpoint,
&rl6->remote_endpoint_ipv6) == 1 )
{
- rl6->remote_endpoint_defined = true;
+ rl6->spec_flags |= RTSA_REMOTE_ENDPOINT;
}
else
{
- msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve default gateway: %s", remote_endpoint);
+ msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve VPN endpoint: %s", remote_endpoint);
ret = false;
}
}
- else
- rl6->remote_endpoint_defined = false;
+ /* parse the routes from opt6 to rl6
+ * discovering potential overlaps with remote_host_ipv6 in the process
+ */
+ need_remote_ipv6_route = false;
- if (!(opt6->n >= 0 && opt6->n <= rl6->capacity))
- msg (M_FATAL, PACKAGE_NAME " ROUTE6: (init) number of route options (%d) is greater than route list capacity (%d)", opt6->n, rl6->capacity);
-
- /* parse the routes from opt to rl6 */
{
- int i, j = 0;
- for (i = 0; i < opt6->n; ++i)
+ struct route_ipv6_option *ro6;
+ for (ro6 = opt6->routes_ipv6; ro6; ro6 = ro6->next)
{
- if (!init_route_ipv6 (&rl6->routes_ipv6[j],
- &opt6->routes_ipv6[i],
- rl6 ))
+ struct route_ipv6 *r6;
+ ALLOC_OBJ_GC (r6, struct route_ipv6, &rl6->gc);
+ if (!init_route_ipv6 (r6, ro6, rl6))
ret = false;
else
- ++j;
+ {
+ r6->next = rl6->routes_ipv6;
+ rl6->routes_ipv6 = r6;
+
+#ifndef TARGET_ANDROID
+ /* On Android the VPNService protect function call will take of
+ * avoiding routing loops, so ignore this part and let
+ * need_remote_ipv6_route always evaluate to false
+ */
+ if ( remote_host_ipv6 &&
+ route_ipv6_match_host( r6, remote_host_ipv6 ) )
+ {
+ need_remote_ipv6_route = true;
+ msg (D_ROUTE, "ROUTE6: %s/%d overlaps IPv6 remote %s, adding host route to VPN endpoint",
+ print_in6_addr (r6->network, 0, &gc), r6->netbits,
+ print_in6_addr (*remote_host_ipv6, 0, &gc));
+ }
+#endif
+ }
}
- rl6->n = j;
}
+ /* add VPN server host route if needed */
+ if ( need_remote_ipv6_route )
+ {
+ if ( (rl6->rgi6.flags & (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) ) ==
+ (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) )
+ {
+ struct route_ipv6 *r6;
+ ALLOC_OBJ_CLEAR_GC (r6, struct route_ipv6, &rl6->gc);
+
+ r6->network = *remote_host_ipv6;
+ r6->netbits = 128;
+ if ( !(rl6->rgi6.flags & RGI_ON_LINK) )
+ { r6->gateway = rl6->rgi6.gateway.addr_ipv6; }
+ r6->metric = 1;
+#ifdef _WIN32
+ r6->adapter_index = rl6->rgi6.adapter_index;
+#else
+ r6->iface = rl6->rgi6.iface;
+#endif
+ r6->flags = RT_DEFINED | RT_METRIC_DEFINED;
+
+ r6->next = rl6->routes_ipv6;
+ rl6->routes_ipv6 = r6;
+ }
+ else
+ {
+ msg (M_WARN, "ROUTE6: IPv6 route overlaps with IPv6 remote address, but could not determine IPv6 gateway address + interface, expect failure\n" );
+ }
+ }
+
gc_free (&gc);
return ret;
}
@@ -854,6 +928,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u
}
else
{
+#ifndef TARGET_ANDROID
bool local = BOOL_CAST(rl->flags & RG_LOCAL);
if (rl->flags & RG_AUTO_LOCAL) {
const int tla = rl->spec.remote_host_local;
@@ -886,6 +961,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u
dmsg (D_ROUTE, "ROUTE remote_host protocol differs from tunneled");
}
}
+#endif
/* route DHCP/DNS server traffic through original default gateway */
add_bypass_routes (&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, &rl->rgi, es);
@@ -1015,22 +1091,23 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun
redirect_default_route_to_vpn (rl, tt, flags, es);
if ( rl && !(rl->iflags & RL_ROUTES_ADDED) )
{
- int i;
+ struct route_ipv4 *r;
#ifdef ENABLE_MANAGEMENT
- if (management && rl->n)
+ if (management && rl->routes)
{
management_set_state (management,
OPENVPN_STATE_ADD_ROUTES,
NULL,
- 0,
- 0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
#endif
-
- for (i = 0; i < rl->n; ++i)
+
+ for (r = rl->routes; r; r = r->next)
{
- struct route_ipv4 *r = &rl->routes[i];
check_subnet_conflict (r->network, r->netmask, "route");
if (flags & ROUTE_DELETE_FIRST)
delete_route (r, tt, flags, &rl->rgi, es);
@@ -1038,18 +1115,16 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun
}
rl->iflags |= RL_ROUTES_ADDED;
}
- if (rl6 && !rl6->routes_added)
+ if (rl6 && !(rl6->iflags & RL_ROUTES_ADDED) )
{
- int i;
-
- for (i = 0; i < rl6->n; ++i)
+ struct route_ipv6 *r;
+ for (r = rl6->routes_ipv6; r; r = r->next)
{
- struct route_ipv6 *r = &rl6->routes_ipv6[i];
if (flags & ROUTE_DELETE_FIRST)
delete_route_ipv6 (r, tt, flags, es);
add_route_ipv6 (r, tt, flags, es);
}
- rl6->routes_added = true;
+ rl6->iflags |= RL_ROUTES_ADDED;
}
}
@@ -1059,10 +1134,9 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
{
if ( rl && rl->iflags & RL_ROUTES_ADDED )
{
- int i;
- for (i = rl->n - 1; i >= 0; --i)
+ struct route_ipv4 *r;
+ for (r = rl->routes; r; r = r->next)
{
- struct route_ipv4 * r = &rl->routes[i];
delete_route (r, tt, flags, &rl->rgi, es);
}
rl->iflags &= ~RL_ROUTES_ADDED;
@@ -1075,15 +1149,14 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
clear_route_list (rl);
}
- if ( rl6 && rl6->routes_added )
+ if ( rl6 && (rl6->iflags & RL_ROUTES_ADDED) )
{
- int i;
- for (i = rl6->n - 1; i >= 0; --i)
+ struct route_ipv6 *r6;
+ for (r6 = rl6->routes_ipv6; r6; r6 = r6->next)
{
- const struct route_ipv6 *r6 = &rl6->routes_ipv6[i];
delete_route_ipv6 (r6, tt, flags, es);
}
- rl6->routes_added = false;
+ rl6->iflags &= ~RL_ROUTES_ADDED;
}
if ( rl6 )
@@ -1098,7 +1171,7 @@ static const char *
show_opt (const char *option)
{
if (!option)
- return "nil";
+ return "default (not set)";
else
return option;
}
@@ -1117,19 +1190,21 @@ void
print_route_options (const struct route_option_list *rol,
int level)
{
- int i;
+ struct route_option *ro;
if (rol->flags & RG_ENABLE)
msg (level, " [redirect_default_gateway local=%d]",
(rol->flags & RG_LOCAL) != 0);
- for (i = 0; i < rol->n; ++i)
- print_route_option (&rol->routes[i], level);
+ for (ro = rol->routes; ro; ro = ro->next)
+ print_route_option (ro, level);
}
void
-print_default_gateway(const int msglevel, const struct route_gateway_info *rgi)
+print_default_gateway(const int msglevel,
+ const struct route_gateway_info *rgi,
+ const struct route_ipv6_gateway_info *rgi6)
{
struct gc_arena gc = gc_new ();
- if (rgi->flags & RGI_ADDR_DEFINED)
+ if (rgi && (rgi->flags & RGI_ADDR_DEFINED))
{
struct buffer out = alloc_buf_gc (256, &gc);
buf_printf (&out, "ROUTE_GATEWAY");
@@ -1139,7 +1214,7 @@ print_default_gateway(const int msglevel, const struct route_gateway_info *rgi)
buf_printf (&out, " %s", print_in_addr_t (rgi->gateway.addr, 0, &gc));
if (rgi->flags & RGI_NETMASK_DEFINED)
buf_printf (&out, "/%s", print_in_addr_t (rgi->gateway.netmask, 0, &gc));
-#ifdef WIN32
+#ifdef _WIN32
if (rgi->flags & RGI_IFACE_DEFINED)
buf_printf (&out, " I=%u", (unsigned int)rgi->adapter_index);
#else
@@ -1150,6 +1225,27 @@ print_default_gateway(const int msglevel, const struct route_gateway_info *rgi)
buf_printf (&out, " HWADDR=%s", format_hex_ex (rgi->hwaddr, 6, 0, 1, ":", &gc));
msg (msglevel, "%s", BSTR (&out));
}
+
+ if (rgi6 && (rgi6->flags & RGI_ADDR_DEFINED))
+ {
+ struct buffer out = alloc_buf_gc (256, &gc);
+ buf_printf (&out, "ROUTE6_GATEWAY");
+ buf_printf (&out, " %s", print_in6_addr (rgi6->gateway.addr_ipv6, 0, &gc));
+ if (rgi6->flags & RGI_ON_LINK)
+ buf_printf (&out, " ON_LINK");
+ if (rgi6->flags & RGI_NETMASK_DEFINED)
+ buf_printf (&out, "/%d", rgi6->gateway.netbits_ipv6);
+#ifdef _WIN32
+ if (rgi6->flags & RGI_IFACE_DEFINED)
+ buf_printf (&out, " I=%u", (unsigned int)rgi6->adapter_index);
+#else
+ if (rgi6->flags & RGI_IFACE_DEFINED)
+ buf_printf (&out, " IFACE=%s", rgi6->iface);
+#endif
+ if (rgi6->flags & RGI_HWADDR_DEFINED)
+ buf_printf (&out, " HWADDR=%s", format_hex_ex (rgi6->hwaddr, 6, 0, 1, ":", &gc));
+ msg (msglevel, "%s", BSTR (&out));
+ }
gc_free (&gc);
}
@@ -1167,9 +1263,9 @@ print_route (const struct route_ipv4 *r, int level)
void
print_routes (const struct route_list *rl, int level)
{
- int i;
- for (i = 0; i < rl->n; ++i)
- print_route (&rl->routes[i], level);
+ struct route_ipv4 *r;
+ for (r = rl->routes; r; r = r->next)
+ print_route (r, level);
}
static void
@@ -1195,16 +1291,17 @@ setenv_route (struct env_set *es, const struct route_ipv4 *r, int i)
void
setenv_routes (struct env_set *es, const struct route_list *rl)
{
- int i;
- for (i = 0; i < rl->n; ++i)
- setenv_route (es, &rl->routes[i], i + 1);
+ int i = 1;
+ struct route_ipv4 *r;
+ for (r = rl->routes; r; r = r->next)
+ setenv_route (es, r, i++);
}
static void
setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i)
{
struct gc_arena gc = gc_new ();
- if (r6->defined)
+ if (r6->flags & RT_DEFINED)
{
struct buffer name1 = alloc_buf_gc( 256, &gc );
struct buffer val = alloc_buf_gc( 256, &gc );
@@ -1223,9 +1320,10 @@ setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i)
void
setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6)
{
- int i;
- for (i = 0; i < rl6->n; ++i)
- setenv_route_ipv6 (es, &rl6->routes_ipv6[i], i + 1);
+ int i = 1;
+ struct route_ipv6 *r6;
+ for (r6 = rl6->routes_ipv6; r6; r6 = r6->next)
+ setenv_route_ipv6 (es, r6, i++);
}
/*
@@ -1297,7 +1395,7 @@ add_route (struct route_ipv4 *r,
const struct env_set *es)
{
struct gc_arena gc;
- struct argv argv;
+ struct argv argv = argv_new ();
const char *network;
const char *netmask;
const char *gateway;
@@ -1308,7 +1406,6 @@ add_route (struct route_ipv4 *r,
return;
gc_init (&gc);
- argv_init (&argv);
network = print_in_addr_t (r->network, 0, &gc);
netmask = print_in_addr_t (r->netmask, 0, &gc);
@@ -1323,7 +1420,7 @@ add_route (struct route_ipv4 *r,
argv_printf (&argv, "%s route add %s/%d",
iproute_path,
network,
- count_netmask_bits(netmask));
+ netmask_to_netbits2(r->netmask));
if (r->flags & RT_METRIC_DEFINED)
argv_printf_cat (&argv, "metric %d", r->metric);
@@ -1348,7 +1445,16 @@ add_route (struct route_ipv4 *r,
argv_msg (D_ROUTE, &argv);
status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route add command failed");
-#elif defined (WIN32)
+#elif defined (TARGET_ANDROID)
+ struct buffer out = alloc_buf_gc (128, &gc);
+
+ if (rgi)
+ buf_printf (&out, "%s %s %s dev %s", network, netmask, gateway, rgi->iface);
+ else
+ buf_printf (&out, "%s %s %s", network, netmask, gateway);
+ management_android_control (management, "ROUTE", buf_bptr(&out));
+
+#elif defined (_WIN32)
{
DWORD ai = TUN_ADAPTER_INDEX_INVALID;
argv_printf (&argv, "%s%sc ADD %s MASK %s %s",
@@ -1367,7 +1473,12 @@ add_route (struct route_ipv4 *r,
argv_msg (D_ROUTE, &argv);
- if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI)
+ if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_SERVICE)
+ {
+ status = add_route_service (r, tt);
+ msg (D_ROUTE, "Route addition via service %s", status ? "succeeded" : "failed");
+ }
+ else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI)
{
status = add_route_ipapi (r, tt, ai);
msg (D_ROUTE, "Route addition via IPAPI %s", status ? "succeeded" : "failed");
@@ -1511,6 +1622,17 @@ add_route (struct route_ipv4 *r,
argv_msg (D_ROUTE, &argv);
status = openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route add command failed");
+#elif defined(TARGET_AIX)
+
+ {
+ int netbits = netmask_to_netbits2(r->netmask);
+ argv_printf (&argv, "%s add -net %s/%d %s",
+ ROUTE_PATH,
+ network, netbits, gateway);
+ argv_msg (D_ROUTE, &argv);
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: AIX route add command failed");
+ }
+
#else
msg (M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system. Try putting your routes in a --route-up script");
#endif
@@ -1525,33 +1647,30 @@ add_route (struct route_ipv4 *r,
}
-static const char *
-print_in6_addr_netbits_only( struct in6_addr network_copy, int netbits,
- struct gc_arena * gc)
+static void
+route_ipv6_clear_host_bits( struct route_ipv6 *r6 )
{
/* clear host bit parts of route
* (needed if routes are specified improperly, or if we need to
* explicitely setup/clear the "connected" network routes on some OSes)
*/
int byte = 15;
- int bits_to_clear = 128 - netbits;
+ int bits_to_clear = 128 - r6->netbits;
while( byte >= 0 && bits_to_clear > 0 )
{
if ( bits_to_clear >= 8 )
- { network_copy.s6_addr[byte--] = 0; bits_to_clear -= 8; }
+ { r6->network.s6_addr[byte--] = 0; bits_to_clear -= 8; }
else
- { network_copy.s6_addr[byte--] &= (0xff << bits_to_clear); bits_to_clear = 0; }
+ { r6->network.s6_addr[byte--] &= (0xff << bits_to_clear); bits_to_clear = 0; }
}
-
- return print_in6_addr( network_copy, 0, gc);
}
void
add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
{
struct gc_arena gc;
- struct argv argv;
+ struct argv argv = argv_new ();
const char *network;
const char *gateway;
@@ -1560,19 +1679,48 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
bool gateway_needed = false;
- if (!r6->defined)
+ if (! (r6->flags & RT_DEFINED) )
return;
+#ifndef _WIN32
+ if ( r6->iface != NULL ) /* vpn server special route */
+ {
+ device = r6->iface;
+ if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) )
+ gateway_needed = true;
+ }
+#endif
+
gc_init (&gc);
- argv_init (&argv);
- network = print_in6_addr_netbits_only( r6->network, r6->netbits, &gc);
+ route_ipv6_clear_host_bits (r6);
+
+ network = print_in6_addr( r6->network, 0, &gc);
gateway = print_in6_addr( r6->gateway, 0, &gc);
- if ( !tt->ipv6 )
+#if defined(TARGET_DARWIN) || \
+ defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \
+ defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
+
+ /* the BSD platforms cannot specify gateway and interface independently,
+ * but for link-local destinations, we MUST specify the interface, so
+ * we build a combined "$gateway%$interface" gateway string
+ */
+ if ( r6->iface != NULL && gateway_needed &&
+ IN6_IS_ADDR_LINKLOCAL(&r6->gateway) ) /* fe80::...%intf */
{
- msg( M_INFO, "add_route_ipv6(): not adding %s/%d, no IPv6 on if %s",
- network, r6->netbits, device );
+ int len = strlen(gateway) + 1 + strlen(r6->iface)+1;
+ char * tmp = gc_malloc( len, true, &gc );
+ snprintf( tmp, len, "%s%%%s", gateway, r6->iface );
+ gateway = tmp;
+ }
+#endif
+
+ if (!tt->did_ifconfig_ipv6_setup)
+ {
+ msg( M_INFO, "add_route_ipv6(): not adding %s/%d: "
+ "no IPv6 address been configured on interface %s",
+ network, r6->netbits, device);
return;
}
@@ -1591,7 +1739,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
* gateway unless the route is to be an on-link network
*/
if ( tt->type == DEV_TYPE_TAP &&
- !(r6->metric_defined && r6->metric == 0 ) )
+ !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) )
{
gateway_needed = true;
}
@@ -1605,7 +1753,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
device);
if (gateway_needed)
argv_printf_cat (&argv, "via %s", gateway);
- if (r6->metric_defined && r6->metric > 0 )
+ if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0 )
argv_printf_cat (&argv, " metric %d", r6->metric);
#else
@@ -1616,70 +1764,95 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
device);
if (gateway_needed)
argv_printf_cat (&argv, "gw %s", gateway);
- if (r6->metric_defined && r6->metric > 0 )
+ if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0 )
argv_printf_cat (&argv, " metric %d", r6->metric);
#endif /*ENABLE_IPROUTE*/
argv_msg (D_ROUTE, &argv);
status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 add command failed");
-#elif defined (WIN32)
+#elif defined (TARGET_ANDROID)
+ struct buffer out = alloc_buf_gc (64, &gc);
+
+ buf_printf (&out, "%s/%d %s", network, r6->netbits, device);
+
+ management_android_control (management, "ROUTE6", buf_bptr(&out));
+
+#elif defined (_WIN32)
- if (win32_version_info() != WIN_XP)
+ if (tt->options.msg_channel)
+ status = add_route_ipv6_service (r6, tt);
+ else
{
struct buffer out = alloc_buf_gc (64, &gc);
- buf_printf (&out, "interface=%d", tt->adapter_index );
+ if ( r6->adapter_index ) /* vpn server special route */
+ {
+ buf_printf (&out, "interface=%d", r6->adapter_index );
+ gateway_needed = true;
+ }
+ else
+ {
+ buf_printf (&out, "interface=%d", tt->adapter_index );
+ }
device = buf_bptr(&out);
- }
- /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
- argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s",
- get_win_sys_path(),
- NETSH_PATH_SUFFIX,
- network,
- r6->netbits,
- device);
-
- /* next-hop depends on TUN or TAP mode:
- * - in TAP mode, we use the "real" next-hop
- * - in TUN mode we use a special-case link-local address that the tapdrvr
- * knows about and will answer ND (neighbor discovery) packets for
- */
- if ( tt->type == DEV_TYPE_TUN )
- argv_printf_cat( &argv, " %s", "fe80::8" );
- else
- argv_printf_cat( &argv, " %s", gateway );
+ /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
+ argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ network,
+ r6->netbits,
+ device);
+
+ /* next-hop depends on TUN or TAP mode:
+ * - in TAP mode, we use the "real" next-hop
+ * - in TUN mode we use a special-case link-local address that the tapdrvr
+ * knows about and will answer ND (neighbor discovery) packets for
+ */
+ if ( tt->type == DEV_TYPE_TUN && !gateway_needed )
+ argv_printf_cat( &argv, " %s", "fe80::8" );
+ else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) )
+ argv_printf_cat( &argv, " %s", gateway );
#if 0
- if (r->metric_defined)
- argv_printf_cat (&argv, " METRIC %d", r->metric);
+ if (r6->flags & RT_METRIC_DEFINED)
+ argv_printf_cat (&argv, " METRIC %d", r->metric);
#endif
- /* in some versions of Windows, routes are persistent across reboots by
- * default, unless "store=active" is set (pointed out by Tony Lim, thanks)
- */
- argv_printf_cat( &argv, " store=active" );
+ /* in some versions of Windows, routes are persistent across reboots by
+ * default, unless "store=active" is set (pointed out by Tony Lim, thanks)
+ */
+ argv_printf_cat( &argv, " store=active" );
- argv_msg (D_ROUTE, &argv);
+ argv_msg (D_ROUTE, &argv);
- netcmd_semaphore_lock ();
- status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed");
- netcmd_semaphore_release ();
+ netcmd_semaphore_lock ();
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed");
+ netcmd_semaphore_release ();
+ }
#elif defined (TARGET_SOLARIS)
/* example: route add -inet6 2001:db8::/32 somegateway 0 */
- /* for some weird reason, this does not work for me unless I set
+ /* for some reason, routes to tun/tap do not work for me unless I set
* "metric 0" - otherwise, the routes will be nicely installed, but
- * packets will just disappear somewhere. So we use "0" now...
+ * packets will just disappear somewhere. So we always use "0" now,
+ * unless the route points to "gateway on other interface"...
+ *
+ * (Note: OpenSolaris can not specify host%interface gateways, so we just
+ * use the GW addresses - it seems to still work for fe80:: addresses,
+ * however this is done internally. NUD maybe?)
*/
-
- argv_printf (&argv, "%s add -inet6 %s/%d %s 0",
+ argv_printf (&argv, "%s add -inet6 %s/%d %s",
ROUTE_PATH,
network,
r6->netbits,
gateway );
+ /* on tun/tap, not "elsewhere"? -> metric 0 */
+ if ( !r6->iface )
+ argv_printf_cat (&argv, "0");
+
argv_msg (D_ROUTE, &argv);
status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add -inet6 command failed");
@@ -1730,11 +1903,22 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
argv_msg (D_ROUTE, &argv);
status = openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route add -inet6 command failed");
+#elif defined(TARGET_AIX)
+
+ argv_printf (&argv, "%s add -inet6 %s/%d %s",
+ ROUTE_PATH,
+ network, r6->netbits, gateway);
+ argv_msg (D_ROUTE, &argv);
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: AIX route add command failed");
+
#else
msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-up script");
#endif
- r6->defined = status;
+ if (status)
+ r6->flags |= RT_ADDED;
+ else
+ r6->flags &= ~RT_ADDED;
argv_reset (&argv);
gc_free (&gc);
}
@@ -1747,7 +1931,7 @@ delete_route (struct route_ipv4 *r,
const struct env_set *es)
{
struct gc_arena gc;
- struct argv argv;
+ struct argv argv = argv_new ();
const char *network;
const char *netmask;
const char *gateway;
@@ -1757,7 +1941,6 @@ delete_route (struct route_ipv4 *r,
return;
gc_init (&gc);
- argv_init (&argv);
network = print_in_addr_t (r->network, 0, &gc);
netmask = print_in_addr_t (r->netmask, 0, &gc);
@@ -1772,7 +1955,7 @@ delete_route (struct route_ipv4 *r,
argv_printf (&argv, "%s route del %s/%d",
iproute_path,
network,
- count_netmask_bits(netmask));
+ netmask_to_netbits2(r->netmask));
#else
argv_printf (&argv, "%s del -net %s netmask %s",
ROUTE_PATH,
@@ -1784,7 +1967,7 @@ delete_route (struct route_ipv4 *r,
argv_msg (D_ROUTE, &argv);
openvpn_execve_check (&argv, es, 0, "ERROR: Linux route delete command failed");
-#elif defined (WIN32)
+#elif defined (_WIN32)
argv_printf (&argv, "%s%sc DELETE %s MASK %s %s",
get_win_sys_path(),
@@ -1795,7 +1978,12 @@ delete_route (struct route_ipv4 *r,
argv_msg (D_ROUTE, &argv);
- if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI)
+ if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_SERVICE)
+ {
+ const bool status = del_route_service (r, tt);
+ msg (D_ROUTE, "Route deletion via service %s", status ? "succeeded" : "failed");
+ }
+ else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI)
{
const bool status = del_route_ipapi (r, tt);
msg (D_ROUTE, "Route deletion via IPAPI %s", status ? "succeeded" : "failed");
@@ -1889,6 +2077,20 @@ delete_route (struct route_ipv4 *r,
argv_msg (D_ROUTE, &argv);
openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete command failed");
+#elif defined(TARGET_ANDROID)
+ msg (M_NONFATAL, "Sorry, deleting routes on Android is not possible. The VpnService API allows routes to be set on connect only.");
+
+#elif defined(TARGET_AIX)
+
+ {
+ int netbits = netmask_to_netbits2(r->netmask);
+ argv_printf (&argv, "%s delete -net %s/%d %s",
+ ROUTE_PATH,
+ network, netbits, gateway);
+ argv_msg (D_ROUTE, &argv);
+ openvpn_execve_check (&argv, es, 0, "ERROR: AIX route delete command failed");
+ }
+
#else
msg (M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system. Try putting your routes in a --route-up script");
#endif
@@ -1903,27 +2105,45 @@ void
delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
{
struct gc_arena gc;
- struct argv argv;
+ struct argv argv = argv_new ();
const char *network;
const char *gateway;
const char *device = tt->actual_name;
bool gateway_needed = false;
- if (!r6->defined)
+ if ((r6->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED))
return;
+#ifndef _WIN32
+ if ( r6->iface != NULL ) /* vpn server special route */
+ {
+ device = r6->iface;
+ gateway_needed = true;
+ }
+#endif
+
gc_init (&gc);
- argv_init (&argv);
- network = print_in6_addr_netbits_only( r6->network, r6->netbits, &gc);
+ network = print_in6_addr( r6->network, 0, &gc);
gateway = print_in6_addr( r6->gateway, 0, &gc);
- if ( !tt->ipv6 )
+#if defined(TARGET_DARWIN) || \
+ defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \
+ defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
+
+ /* the BSD platforms cannot specify gateway and interface independently,
+ * but for link-local destinations, we MUST specify the interface, so
+ * we build a combined "$gateway%$interface" gateway string
+ */
+ if ( r6->iface != NULL && gateway_needed &&
+ IN6_IS_ADDR_LINKLOCAL(&r6->gateway) ) /* fe80::...%intf */
{
- msg( M_INFO, "delete_route_ipv6(): not deleting %s/%d, no IPv6 on if %s",
- network, r6->netbits, device );
- return;
+ int len = strlen(gateway) + 1 + strlen(r6->iface)+1;
+ char * tmp = gc_malloc( len, true, &gc );
+ snprintf( tmp, len, "%s%%%s", gateway, r6->iface );
+ gateway = tmp;
}
+#endif
msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits );
@@ -1931,7 +2151,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
* delete, otherwise some OSes will refuse to delete the route
*/
if ( tt->type == DEV_TYPE_TAP &&
- !(r6->metric_defined && r6->metric == 0 ) )
+ !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) )
{
gateway_needed = true;
}
@@ -1954,61 +2174,70 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
device);
if (gateway_needed)
argv_printf_cat (&argv, "gw %s", gateway);
- if (r6->metric_defined && r6->metric > 0 )
+ if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0 )
argv_printf_cat (&argv, " metric %d", r6->metric);
#endif /*ENABLE_IPROUTE*/
argv_msg (D_ROUTE, &argv);
openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 del command failed");
-#elif defined (WIN32)
+#elif defined (_WIN32)
- if (win32_version_info() != WIN_XP)
+ if (tt->options.msg_channel)
+ del_route_ipv6_service (r6, tt);
+ else
{
struct buffer out = alloc_buf_gc (64, &gc);
- buf_printf (&out, "interface=%d", tt->adapter_index );
+ if ( r6->adapter_index ) /* vpn server special route */
+ {
+ buf_printf (&out, "interface=%d", r6->adapter_index );
+ gateway_needed = true;
+ }
+ else
+ {
+ buf_printf (&out, "interface=%d", tt->adapter_index );
+ }
device = buf_bptr(&out);
- }
- /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
- argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s",
- get_win_sys_path(),
- NETSH_PATH_SUFFIX,
- network,
- r6->netbits,
- device);
-
- /* next-hop depends on TUN or TAP mode:
- * - in TAP mode, we use the "real" next-hop
- * - in TUN mode we use a special-case link-local address that the tapdrvr
- * knows about and will answer ND (neighbor discovery) packets for
- * (and "route deletion without specifying next-hop" does not work...)
- */
- if ( tt->type == DEV_TYPE_TUN )
- argv_printf_cat( &argv, " %s", "fe80::8" );
- else
- argv_printf_cat( &argv, " %s", gateway );
+ /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
+ argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ network,
+ r6->netbits,
+ device);
+
+ /* next-hop depends on TUN or TAP mode:
+ * - in TAP mode, we use the "real" next-hop
+ * - in TUN mode we use a special-case link-local address that the tapdrvr
+ * knows about and will answer ND (neighbor discovery) packets for
+ * (and "route deletion without specifying next-hop" does not work...)
+ */
+ if ( tt->type == DEV_TYPE_TUN && !gateway_needed )
+ argv_printf_cat( &argv, " %s", "fe80::8" );
+ else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) )
+ argv_printf_cat( &argv, " %s", gateway );
#if 0
- if (r->metric_defined)
- argv_printf_cat (&argv, "METRIC %d", r->metric);
+ if (r6->flags & RT_METRIC_DEFINED)
+ argv_printf_cat (&argv, "METRIC %d", r->metric);
#endif
- /* Windows XP to 7 "just delete" routes, wherever they came from, but
- * in Windows 8(.1?), if you create them with "store=active", this is
- * how you should delete them as well (pointed out by Cedric Tabary)
- */
- argv_printf_cat( &argv, " store=active" );
+ /* Windows XP to 7 "just delete" routes, wherever they came from, but
+ * in Windows 8(.1?), if you create them with "store=active", this is
+ * how you should delete them as well (pointed out by Cedric Tabary)
+ */
+ argv_printf_cat( &argv, " store=active" );
- argv_msg (D_ROUTE, &argv);
+ argv_msg (D_ROUTE, &argv);
- netcmd_semaphore_lock ();
- openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete ipv6 command failed");
- netcmd_semaphore_release ();
+ netcmd_semaphore_lock ();
+ openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete ipv6 command failed");
+ netcmd_semaphore_release ();
+ }
#elif defined (TARGET_SOLARIS)
/* example: route delete -inet6 2001:db8::/32 somegateway */
- /* GERT-TODO: this is untested, but should work */
argv_printf (&argv, "%s delete -inet6 %s/%d %s",
ROUTE_PATH,
@@ -2066,6 +2295,14 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
argv_msg (D_ROUTE, &argv);
openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route delete -inet6 command failed");
+#elif defined(TARGET_AIX)
+
+ argv_printf (&argv, "%s delete -inet6 %s/%d %s",
+ ROUTE_PATH,
+ network, r6->netbits, gateway);
+ argv_msg (D_ROUTE, &argv);
+ openvpn_execve_check (&argv, es, 0, "ERROR: AIX route add command failed");
+
#else
msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-down script");
#endif
@@ -2079,7 +2316,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
* to get the current default gateway.
*/
-#if defined(WIN32)
+#if defined(_WIN32)
static const MIB_IPFORWARDTABLE *
get_windows_routing_table (struct gc_arena *gc)
@@ -2148,6 +2385,7 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
int count = 0;
int good = 0;
int ambig = 0;
+ int len = -1;
bool adapter_up = false;
if (is_adapter_up (tt, adapters))
@@ -2157,9 +2395,9 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
if (rl)
{
- int i;
- for (i = 0; i < rl->n; ++i)
- test_route_helper (&ret, &count, &good, &ambig, adapters, rl->routes[i].gateway);
+ struct route_ipv4 *r;
+ for (r = rl->routes, len = 0; r; r = r->next, ++len)
+ test_route_helper (&ret, &count, &good, &ambig, adapters, r->gateway);
if ((rl->flags & RG_ENABLE) && (rl->spec.flags & RTSA_REMOTE_ENDPOINT))
test_route_helper (&ret, &count, &good, &ambig, adapters, rl->spec.remote_endpoint);
@@ -2169,7 +2407,7 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
msg (D_ROUTE, "TEST ROUTES: %d/%d succeeded len=%d ret=%d a=%d u/d=%s",
good,
count,
- rl ? rl->n : -1,
+ len,
(int)ret,
ambig,
adapter_up ? "up" : "down");
@@ -2301,6 +2539,81 @@ windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt
return ret;
}
+/* IPv6 implementation using GetBestRoute2()
+ * (TBD: dynamic linking so the binary can still run on XP?)
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365922(v=vs.85).aspx
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa814411(v=vs.85).aspx
+ */
+void
+get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6,
+ const struct in6_addr *dest)
+{
+ struct gc_arena gc = gc_new ();
+ MIB_IPFORWARD_ROW2 BestRoute;
+ SOCKADDR_INET DestinationAddress, BestSourceAddress;
+ DWORD BestIfIndex;
+ DWORD status;
+ NET_LUID InterfaceLuid;
+
+ CLEAR(*rgi6);
+ CLEAR(InterfaceLuid); // cleared = not used for lookup
+ CLEAR(DestinationAddress);
+
+ DestinationAddress.si_family = AF_INET6;
+ if ( dest )
+ {
+ DestinationAddress.Ipv6.sin6_addr = *dest;
+ }
+
+ status = GetBestInterfaceEx( &DestinationAddress, &BestIfIndex );
+
+ if (status != NO_ERROR)
+ {
+ msg (D_ROUTE, "NOTE: GetBestInterfaceEx returned error: %s (code=%u)",
+ strerror_win32 (status, &gc),
+ (unsigned int)status);
+ goto done;
+ }
+
+ msg( D_ROUTE, "GetBestInterfaceEx() returned if=%d", (int) BestIfIndex );
+
+ status = GetBestRoute2( &InterfaceLuid, BestIfIndex, NULL,
+ &DestinationAddress, 0,
+ &BestRoute, &BestSourceAddress );
+
+ if (status != NO_ERROR)
+ {
+ msg (D_ROUTE, "NOTE: GetIpForwardEntry2 returned error: %s (code=%u)",
+ strerror_win32 (status, &gc),
+ (unsigned int)status);
+ goto done;
+ }
+
+ msg( D_ROUTE, "GDG6: II=%d DP=%s/%d NH=%s",
+ BestRoute.InterfaceIndex,
+ print_in6_addr( BestRoute.DestinationPrefix.Prefix.Ipv6.sin6_addr, 0, &gc),
+ BestRoute.DestinationPrefix.PrefixLength,
+ print_in6_addr( BestRoute.NextHop.Ipv6.sin6_addr, 0, &gc) );
+ msg( D_ROUTE, "GDG6: Metric=%d, Loopback=%d, AA=%d, I=%d",
+ (int) BestRoute.Metric,
+ (int) BestRoute.Loopback,
+ (int) BestRoute.AutoconfigureAddress,
+ (int) BestRoute.Immortal );
+
+ rgi6->gateway.addr_ipv6 = BestRoute.NextHop.Ipv6.sin6_addr;
+ rgi6->adapter_index = BestRoute.InterfaceIndex;
+ rgi6->flags |= RGI_ADDR_DEFINED | RGI_IFACE_DEFINED;
+
+ /* on-link is signalled by receiving an empty (::) NextHop */
+ if ( IN6_IS_ADDR_UNSPECIFIED(&BestRoute.NextHop.Ipv6.sin6_addr) )
+ {
+ rgi6->flags |= RGI_ON_LINK;
+ }
+
+ done:
+ gc_free (&gc);
+}
+
bool
add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index)
{
@@ -2407,6 +2720,126 @@ del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt)
return ret;
}
+static bool
+do_route_service (const bool add, const route_message_t *rt, const size_t size, HANDLE pipe)
+{
+ DWORD len;
+ bool ret = false;
+ ack_message_t ack;
+ struct gc_arena gc = gc_new ();
+
+ if (!WriteFile (pipe, rt, size, &len, NULL) ||
+ !ReadFile (pipe, &ack, sizeof (ack), &len, NULL))
+ {
+ msg (M_WARN, "ROUTE: could not talk to service: %s [%lu]",
+ strerror_win32 (GetLastError (), &gc), GetLastError ());
+ goto out;
+ }
+
+ if (ack.error_number != NO_ERROR)
+ {
+ msg (M_WARN, "ROUTE: route %s failed using service: %s [status=%u if_index=%lu]",
+ (add ? "addition" : "deletion"), strerror_win32 (ack.error_number, &gc),
+ ack.error_number, rt->iface.index);
+ goto out;
+ }
+
+ ret = true;
+
+out:
+ gc_free (&gc);
+ return ret;
+}
+
+static bool
+do_route_ipv4_service (const bool add, const struct route_ipv4 *r, const struct tuntap *tt)
+{
+ DWORD if_index = windows_route_find_if_index (r, tt);
+ if (if_index == ~0)
+ return false;
+
+ route_message_t msg = {
+ .header = {
+ (add ? msg_add_route : msg_del_route),
+ sizeof (route_message_t),
+ 0 },
+ .family = AF_INET,
+ .prefix.ipv4.s_addr = htonl(r->network),
+ .gateway.ipv4.s_addr = htonl(r->gateway),
+ .iface = { .index = if_index, .name = "" },
+ .metric = (r->flags & RT_METRIC_DEFINED ? r->metric : -1)
+ };
+
+ netmask_to_netbits (r->network, r->netmask, &msg.prefix_len);
+ if (msg.prefix_len == -1)
+ msg.prefix_len = 32;
+
+ return do_route_service (add, &msg, sizeof (msg), tt->options.msg_channel);
+}
+
+static bool
+do_route_ipv6_service (const bool add, const struct route_ipv6 *r, const struct tuntap *tt)
+{
+ bool status;
+ route_message_t msg = {
+ .header = {
+ (add ? msg_add_route : msg_del_route),
+ sizeof (route_message_t),
+ 0 },
+ .family = AF_INET6,
+ .prefix.ipv6 = r->network,
+ .prefix_len = r->netbits,
+ .gateway.ipv6 = r->gateway,
+ .iface = { .index = tt->adapter_index, .name = "" },
+ .metric = ( (r->flags & RT_METRIC_DEFINED) ? r->metric : -1)
+ };
+
+ if ( r->adapter_index ) /* vpn server special route */
+ msg.iface.index = r->adapter_index;
+
+ /* In TUN mode we use a special link-local address as the next hop.
+ * The tapdrvr knows about it and will answer neighbor discovery packets.
+ */
+ if (tt->type == DEV_TYPE_TUN)
+ inet_pton (AF_INET6, "fe80::8", &msg.gateway.ipv6);
+
+ if (msg.iface.index == TUN_ADAPTER_INDEX_INVALID)
+ {
+ strncpy (msg.iface.name, tt->actual_name, sizeof (msg.iface.name));
+ msg.iface.name[sizeof (msg.iface.name) - 1] = '\0';
+ }
+
+ status = do_route_service (add, &msg, sizeof (msg), tt->options.msg_channel);
+ msg (D_ROUTE, "IPv6 route %s via service %s",
+ add ? "addition" : "deletion",
+ status ? "succeeded" : "failed");
+ return status;
+}
+
+static bool
+add_route_service (const struct route_ipv4 *r, const struct tuntap *tt)
+{
+ return do_route_ipv4_service (true, r, tt);
+}
+
+static bool
+del_route_service (const struct route_ipv4 *r, const struct tuntap *tt)
+{
+ return do_route_ipv4_service (false, r, tt);
+}
+
+static bool
+add_route_ipv6_service (const struct route_ipv6 *r, const struct tuntap *tt)
+{
+ return do_route_ipv6_service (true, r, tt);
+}
+
+static bool
+del_route_ipv6_service (const struct route_ipv6 *r, const struct tuntap *tt)
+{
+ return do_route_ipv6_service (false, r, tt);
+}
+
static const char *
format_route_entry (const MIB_IPFORWARDROW *r, struct gc_arena *gc)
{
@@ -2451,7 +2884,7 @@ show_routes (int msglev)
gc_free (&gc);
}
-#elif defined(TARGET_LINUX)
+#elif defined(TARGET_LINUX) || defined(TARGET_ANDROID)
void
get_default_gateway (struct route_gateway_info *rgi)
@@ -2463,6 +2896,7 @@ get_default_gateway (struct route_gateway_info *rgi)
CLEAR(*rgi);
+#ifndef TARGET_ANDROID
/* get default gateway IP addr */
{
FILE *fp = fopen ("/proc/net/route", "r");
@@ -2519,6 +2953,19 @@ get_default_gateway (struct route_gateway_info *rgi)
}
}
}
+#else
+ /* Android, set some pseudo GW, addr is in host byte order,
+ * Determining the default GW on Android 5.0+ is non trivial
+ * and serves almost no purpose since OpenVPN only uses the
+ * default GW address to add routes for networks that should
+ * NOT be routed over the VPN. Using a well known address
+ * (127.'d'.'g'.'w') for the default GW make detecting
+ * these routes easier from the controlling app.
+ */
+ rgi->gateway.addr = 127 << 24 | 'd' << 16 | 'g' << 8 | 'w';
+ rgi->flags |= RGI_ADDR_DEFINED;
+ strcpy(best_name, "android-gw");
+#endif
/* scan adapter list */
if (rgi->flags & RGI_ADDR_DEFINED)
@@ -2617,136 +3064,149 @@ get_default_gateway (struct route_gateway_info *rgi)
gc_free (&gc);
}
-#elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)||defined(TARGET_SOLARIS)
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <net/route.h>
-
-struct {
- struct rt_msghdr m_rtm;
- char m_space[512];
-} m_rtmsg;
-
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-
-/*
- * FIXME -- add support for netmask, hwaddr, and iface
+/* IPv6 implementation using netlink
+ * http://www.linuxjournal.com/article/7356
+ * netlink(3), netlink(7), rtnetlink(7)
+ * http://www.virtualbox.org/svn/vbox/trunk/src/VBox/NetworkServices/NAT/rtmon_linux.c
*/
-void
-get_default_gateway (struct route_gateway_info *rgi)
-{
- struct gc_arena gc = gc_new ();
- int s, seq, l, pid, rtm_addrs;
- unsigned int i;
- struct sockaddr so_dst, so_mask;
- char *cp = m_rtmsg.m_space;
- struct sockaddr *gate = NULL, *sa;
- struct rt_msghdr *rtm_aux;
-
-#if defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)
-
-#define NEXTADDR(w, u) \
- if (rtm_addrs & (w)) {\
- l = ROUNDUP(u.sa_len); memmove(cp, &(u), l); cp += l;\
- }
-
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-
-#else /* TARGET_SOLARIS */
-
-#define NEXTADDR(w, u) \
- if (rtm_addrs & (w)) {\
- l = ROUNDUP(sizeof(struct sockaddr_in)); memmove(cp, &(u), l); cp += l;\
- }
-
-#define ADVANCE(x, n) (x += ROUNDUP(sizeof(struct sockaddr_in)))
+struct rtreq {
+ struct nlmsghdr nh;
+ struct rtmsg rtm;
+ char attrbuf[512];
+};
-#endif
+void
+get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6,
+ const struct in6_addr *dest)
+{
+ int nls = -1;
+ struct rtreq rtreq;
+ struct rtattr *rta;
+
+ char rtbuf[2000];
+ ssize_t ssize;
+
+ CLEAR(*rgi6);
+
+ nls = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE );
+ if ( nls < 0 )
+ { msg(M_WARN|M_ERRNO, "GDG6: socket() failed" ); goto done; }
+
+ /* bind() is not needed, no unsolicited msgs coming in */
+
+ /* request best matching route, see netlink(7) for explanations
+ */
+ CLEAR(rtreq);
+ rtreq.nh.nlmsg_type = RTM_GETROUTE;
+ rtreq.nh.nlmsg_flags = NLM_F_REQUEST; /* best match only */
+ rtreq.rtm.rtm_family = AF_INET6;
+ rtreq.rtm.rtm_src_len = 0; /* not source dependent */
+ rtreq.rtm.rtm_dst_len = 128; /* exact dst */
+ rtreq.rtm.rtm_table = RT_TABLE_MAIN;
+ rtreq.rtm.rtm_protocol = RTPROT_UNSPEC;
+ rtreq.nh.nlmsg_len = NLMSG_SPACE(sizeof(rtreq.rtm));
+
+ /* set RTA_DST for target IPv6 address we want */
+ rta = (struct rtattr *)(((char *) &rtreq)+NLMSG_ALIGN(rtreq.nh.nlmsg_len));
+ rta->rta_type = RTA_DST;
+ rta->rta_len = RTA_LENGTH(16);
+ rtreq.nh.nlmsg_len = NLMSG_ALIGN(rtreq.nh.nlmsg_len) +
+ RTA_LENGTH(16);
+
+ if ( dest == NULL ) /* ::, unspecified */
+ memset( RTA_DATA(rta), 0, 16 ); /* :: = all-zero */
+ else
+ memcpy( RTA_DATA(rta), (void *)dest, 16 );
+ /* send and receive reply */
+ if ( send( nls, &rtreq, rtreq.nh.nlmsg_len, 0 ) < 0 )
+ { msg(M_WARN|M_ERRNO, "GDG6: send() failed" ); goto done; }
-#define rtm m_rtmsg.m_rtm
+ ssize = recv(nls, rtbuf, sizeof(rtbuf), MSG_TRUNC);
- CLEAR(*rgi);
+ if (ssize < 0)
+ { msg(M_WARN|M_ERRNO, "GDG6: recv() failed" ); goto done; }
- pid = getpid();
- seq = 0;
- rtm_addrs = RTA_DST | RTA_NETMASK;
+ if (ssize > sizeof(rtbuf))
+ {
+ msg(M_WARN, "get_default_gateway_ipv6: returned message too big for buffer (%d>%d)", (int)ssize, (int)sizeof(rtbuf) );
+ goto done;
+ }
- bzero(&so_dst, sizeof(so_dst));
- bzero(&so_mask, sizeof(so_mask));
- bzero(&rtm, sizeof(struct rt_msghdr));
+ struct nlmsghdr *nh;
- rtm.rtm_type = RTM_GET;
- rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
- rtm.rtm_version = RTM_VERSION;
- rtm.rtm_seq = ++seq;
- rtm.rtm_addrs = rtm_addrs;
+ for (nh = (struct nlmsghdr *)rtbuf;
+ NLMSG_OK(nh, ssize);
+ nh = NLMSG_NEXT(nh, ssize))
+ {
+ struct rtmsg *rtm;
+ int attrlen;
- so_dst.sa_family = AF_INET;
- so_mask.sa_family = AF_INET;
+ if (nh->nlmsg_type == NLMSG_DONE) { break; }
-#if defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)
- so_dst.sa_len = sizeof(struct sockaddr_in);
- so_mask.sa_len = sizeof(struct sockaddr_in);
-#endif
+ if (nh->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *ne = (struct nlmsgerr *)NLMSG_DATA(nh);
+ msg(M_WARN, "GDG6: NLSMG_ERROR: error %d\n", ne->error);
+ break;
+ }
- NEXTADDR(RTA_DST, so_dst);
- NEXTADDR(RTA_NETMASK, so_mask);
+ if (nh->nlmsg_type != RTM_NEWROUTE) {
+ /* shouldn't happen */
+ msg(M_WARN, "GDG6: unexpected msg_type %d", nh->nlmsg_type );
+ continue;
+ }
- rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
+ rtm = (struct rtmsg *)NLMSG_DATA(nh);
+ attrlen = RTM_PAYLOAD(nh);
- s = socket(PF_ROUTE, SOCK_RAW, 0);
+ /* we're only looking for routes in the main table, as "we have
+ * no IPv6" will lead to a lookup result in "Local" (::/0 reject)
+ */
+ if (rtm->rtm_family != AF_INET6 ||
+ rtm->rtm_table != RT_TABLE_MAIN)
+ { continue; } /* we're not interested */
- if (write(s, (char *)&m_rtmsg, l) < 0)
- {
- msg(M_WARN|M_ERRNO, "Could not retrieve default gateway from route socket:");
- gc_free (&gc);
- close(s);
- return;
+ for (rta = RTM_RTA(rtm);
+ RTA_OK(rta, attrlen);
+ rta = RTA_NEXT(rta, attrlen))
+ {
+ if (rta->rta_type == RTA_GATEWAY) {
+ if ( RTA_PAYLOAD(rta) != sizeof(struct in6_addr) )
+ { msg(M_WARN, "GDG6: RTA_GW size mismatch"); continue; }
+ rgi6->gateway.addr_ipv6 = *(struct in6_addr*) RTA_DATA(rta);
+ rgi6->flags |= RGI_ADDR_DEFINED;
+ }
+ else if (rta->rta_type == RTA_OIF) {
+ char ifname[IF_NAMESIZE+1];
+ int oif;
+ if ( RTA_PAYLOAD(rta) != sizeof(oif) )
+ { msg(M_WARN, "GDG6: oif size mismatch"); continue; }
+
+ memcpy(&oif, RTA_DATA(rta), sizeof(oif));
+ if_indextoname(oif,ifname);
+ strncpy( rgi6->iface, ifname, sizeof(rgi6->iface)-1 );
+ rgi6->flags |= RGI_IFACE_DEFINED;
+ }
+ }
}
- do {
- l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
- } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
-
- close(s);
-
- rtm_aux = &rtm;
-
- cp = ((char *)(rtm_aux + 1));
- if (rtm_aux->rtm_addrs) {
- for (i = 1; i; i <<= 1)
- if (i & rtm_aux->rtm_addrs) {
- sa = (struct sockaddr *)cp;
- if (i == RTA_GATEWAY )
- gate = sa;
- ADVANCE(cp, sa);
- }
- }
- else
+ /* if we have an interface but no gateway, the destination is on-link */
+ if ( ( rgi6->flags & (RGI_IFACE_DEFINED|RGI_ADDR_DEFINED) ) ==
+ RGI_IFACE_DEFINED )
{
- gc_free (&gc);
- return;
+ rgi6->flags |= (RGI_ADDR_DEFINED | RGI_ON_LINK);
+ if ( dest )
+ rgi6->gateway.addr_ipv6 = *dest;
}
-
- if (gate != NULL )
- {
- rgi->gateway.addr = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr);
- rgi->flags |= RGI_ADDR_DEFINED;
-
- gc_free (&gc);
- }
- else
- {
- gc_free (&gc);
- }
+ done:
+ if (nls >= 0)
+ close (nls);
}
-#elif defined(TARGET_DARWIN)
+#elif defined(TARGET_DARWIN) || defined(TARGET_SOLARIS) || \
+ defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \
+ defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
#include <sys/types.h>
#include <sys/socket.h>
@@ -2759,15 +3219,41 @@ struct rtmsg {
char m_space[512];
};
-#define ROUNDUP(a) \
+/* the route socket code is identical for all 4 supported BSDs and for
+ * MacOS X (Darwin), with one crucial difference: when going from
+ * 32 bit to 64 bit, the BSDs increased the structure size but kept
+ * source code compatibility by keeping the use of "long", while
+ * MacOS X decided to keep binary compatibility by *changing* the API
+ * to use "uint32_t", thus 32 bit on all OS X variants
+ *
+ * We used to have a large amount of duplicate code here which really
+ * differed only in this (long) vs. (uint32_t) - IMHO, worse than
+ * having a combined block for all BSDs with this single #ifdef inside
+ */
+
+#if defined(TARGET_DARWIN)
+# define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+#else
+# define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#endif
+
+#if defined(TARGET_SOLARIS)
+#define NEXTADDR(w, u) \
+ if (rtm_addrs & (w)) {\
+ l = ROUNDUP(sizeof(u)); memmove(cp, &(u), l); cp += l;\
+ }
+#define ADVANCE(x, n) (x += ROUNDUP(sizeof(struct sockaddr_in)))
+#else
#define NEXTADDR(w, u) \
if (rtm_addrs & (w)) {\
- l = ROUNDUP(u.sa_len); memmove(cp, &(u), l); cp += l;\
+ l = ROUNDUP( ((struct sockaddr *)&(u))->sa_len); memmove(cp, &(u), l); cp += l;\
}
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+#endif
#define max(a,b) ((a) > (b) ? (a) : (b))
@@ -2805,9 +3291,12 @@ get_default_gateway (struct route_gateway_info *rgi)
rtm.rtm_addrs = rtm_addrs;
so_dst.sa_family = AF_INET;
- so_dst.sa_len = sizeof(struct sockaddr_in);
so_mask.sa_family = AF_INET;
+
+#ifndef TARGET_SOLARIS
+ so_dst.sa_len = sizeof(struct sockaddr_in);
so_mask.sa_len = sizeof(struct sockaddr_in);
+#endif
NEXTADDR(RTA_DST, so_dst);
NEXTADDR(RTA_NETMASK, so_mask);
@@ -2865,7 +3354,6 @@ get_default_gateway (struct route_gateway_info *rgi)
{
/* get interface name */
const struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp;
- int len = adl->sdl_nlen;
if (adl->sdl_nlen && adl->sdl_nlen < sizeof(rgi->iface))
{
memcpy (rgi->iface, adl->sdl_data, adl->sdl_nlen);
@@ -2932,7 +3420,12 @@ get_default_gateway (struct route_gateway_info *rgi)
for (cp = buffer; cp <= buffer + ifc.ifc_len - sizeof(struct ifreq); )
{
ifr = (struct ifreq *)cp;
+#if defined(TARGET_SOLARIS)
+ const size_t len = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr);
+#else
const size_t len = sizeof(ifr->ifr_name) + max(sizeof(ifr->ifr_addr), ifr->ifr_addr.sa_len);
+#endif
+
if (!ifr->ifr_addr.sa_family)
break;
if (!strncmp(ifr->ifr_name, rgi->iface, IFNAMSIZ))
@@ -2954,121 +3447,162 @@ get_default_gateway (struct route_gateway_info *rgi)
gc_free (&gc);
}
-#undef max
-
-#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <net/route.h>
-
-struct {
- struct rt_msghdr m_rtm;
- char m_space[512];
-} m_rtmsg;
-
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+/* BSD implementation using routing socket (as does IPv4)
+ * (the code duplication is somewhat unavoidable if we want this to
+ * work on OpenSolaris as well. *sigh*)
+ */
-/*
- * FIXME -- add support for netmask, hwaddr, and iface
+/* Solaris has no length field - this is ugly, but less #ifdef in total
*/
+#if defined(TARGET_SOLARIS)
+# undef ADVANCE
+# define ADVANCE(x, n) (x += ROUNDUP(sizeof(struct sockaddr_in6)))
+#endif
+
void
-get_default_gateway (struct route_gateway_info *rgi)
+get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6,
+ const struct in6_addr *dest)
{
- struct gc_arena gc = gc_new ();
- int s, seq, l, rtm_addrs;
- unsigned int i;
- pid_t pid;
- struct sockaddr so_dst, so_mask;
- char *cp = m_rtmsg.m_space;
- struct sockaddr *gate = NULL, *sa;
- struct rt_msghdr *rtm_aux;
-#define NEXTADDR(w, u) \
- if (rtm_addrs & (w)) {\
- l = ROUNDUP(u.sa_len); memmove(cp, &(u), l); cp += l;\
- }
+ struct rtmsg m_rtmsg;
+ int sockfd = -1;
+ int seq, l, pid, rtm_addrs;
+ unsigned int i;
+ struct sockaddr_in6 so_dst, so_mask;
+ char *cp = m_rtmsg.m_space;
+ struct sockaddr *gate = NULL, *ifp = NULL, *sa;
+ struct rt_msghdr *rtm_aux;
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+ CLEAR(*rgi6);
-#define rtm m_rtmsg.m_rtm
+ /* setup data to send to routing socket */
+ pid = getpid();
+ seq = 0;
+ rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP;
- CLEAR(*rgi);
+ bzero(&m_rtmsg, sizeof(m_rtmsg));
+ bzero(&so_dst, sizeof(so_dst));
+ bzero(&so_mask, sizeof(so_mask));
+ bzero(&rtm, sizeof(struct rt_msghdr));
- pid = getpid();
- seq = 0;
- rtm_addrs = RTA_DST | RTA_NETMASK;
+ rtm.rtm_type = RTM_GET;
+ rtm.rtm_flags = RTF_UP;
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_seq = ++seq;
- bzero(&so_dst, sizeof(so_dst));
- bzero(&so_mask, sizeof(so_mask));
- bzero(&rtm, sizeof(struct rt_msghdr));
+ so_dst.sin6_family = AF_INET6;
+ so_mask.sin6_family = AF_INET6;
- rtm.rtm_type = RTM_GET;
- rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
- rtm.rtm_version = RTM_VERSION;
- rtm.rtm_seq = ++seq;
- rtm.rtm_addrs = rtm_addrs;
+ if ( dest != NULL && /* specific host? */
+ !IN6_IS_ADDR_UNSPECIFIED(dest) )
+ {
+ so_dst.sin6_addr = *dest;
+ /* :: needs /0 "netmask", host route wants "no netmask */
+ rtm_addrs &= ~RTA_NETMASK;
+ }
- so_dst.sa_family = AF_INET;
- so_dst.sa_len = sizeof(struct sockaddr_in);
- so_mask.sa_family = AF_INET;
- so_mask.sa_len = sizeof(struct sockaddr_in);
+ rtm.rtm_addrs = rtm_addrs;
- NEXTADDR(RTA_DST, so_dst);
- NEXTADDR(RTA_NETMASK, so_mask);
+#ifndef TARGET_SOLARIS
+ so_dst.sin6_len = sizeof(struct sockaddr_in6);
+ so_mask.sin6_len = sizeof(struct sockaddr_in6);
+#endif
- rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
+ NEXTADDR(RTA_DST, so_dst);
+ NEXTADDR(RTA_NETMASK, so_mask);
- s = socket(PF_ROUTE, SOCK_RAW, 0);
+ rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
- if (write(s, (char *)&m_rtmsg, l) < 0)
+ /* transact with routing socket */
+ sockfd = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (sockfd < 0)
{
- msg(M_WARN|M_ERRNO, "Could not retrieve default gateway from route socket:");
- gc_free (&gc);
- close(s);
- return;
+ msg (M_WARN, "GDG6: socket #1 failed");
+ goto done;
+ }
+ if (write(sockfd, (char *)&m_rtmsg, l) < 0)
+ {
+ msg (M_WARN, "GDG6: problem writing to routing socket");
+ goto done;
}
- do {
- l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
- } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
-
- close(s);
-
- rtm_aux = &rtm;
-
- cp = ((char *)(rtm_aux + 1));
- if (rtm_aux->rtm_addrs) {
- for (i = 1; i; i <<= 1)
- if (i & rtm_aux->rtm_addrs) {
- sa = (struct sockaddr *)cp;
- if (i == RTA_GATEWAY )
- gate = sa;
- ADVANCE(cp, sa);
- }
- }
- else
+ do
{
- gc_free (&gc);
- return;
+ l = read(sockfd, (char *)&m_rtmsg, sizeof(m_rtmsg));
}
+ while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
+ close(sockfd);
+ sockfd = -1;
- if (gate != NULL )
+ /* extract return data from routing socket */
+ rtm_aux = &rtm;
+ cp = ((char *)(rtm_aux + 1));
+ if (rtm_aux->rtm_addrs)
{
- rgi->gateway.addr = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr);
- rgi->flags |= RGI_ADDR_DEFINED;
-
- gc_free (&gc);
+ for (i = 1; i; i <<= 1)
+ {
+ if (i & rtm_aux->rtm_addrs)
+ {
+ sa = (struct sockaddr *)cp;
+ if (i == RTA_GATEWAY )
+ gate = sa;
+ else if (i == RTA_IFP)
+ ifp = sa;
+ ADVANCE(cp, sa);
+ }
+ }
}
- else
+ else
+ goto done;
+
+ /* get gateway addr and interface name */
+ if (gate != NULL )
{
- gc_free (&gc);
+ struct sockaddr_in6 * s6 = (struct sockaddr_in6 *)gate;
+ struct in6_addr gw = s6->sin6_addr;
+
+#ifndef TARGET_SOLARIS
+ /* You do not really want to know... from FreeBSD's route.c
+ * (KAME encodes the 16 bit scope_id in s6_addr[2] + [3],
+ * but for a correct link-local address these must be :0000: )
+ */
+ if ( gate->sa_len == sizeof(struct sockaddr_in6) &&
+ IN6_IS_ADDR_LINKLOCAL(&gw) )
+ {
+ gw.s6_addr[2] = gw.s6_addr[3] = 0;
+ }
+
+ if ( gate->sa_len != sizeof(struct sockaddr_in6) ||
+ IN6_IS_ADDR_UNSPECIFIED(&gw) )
+ {
+ rgi6->flags |= RGI_ON_LINK;
+ }
+ else
+#endif
+
+ rgi6->gateway.addr_ipv6 = gw;
+ rgi6->flags |= RGI_ADDR_DEFINED;
+
+ if (ifp)
+ {
+ /* get interface name */
+ const struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp;
+ if (adl->sdl_nlen && adl->sdl_nlen < sizeof(rgi6->iface))
+ {
+ memcpy (rgi6->iface, adl->sdl_data, adl->sdl_nlen);
+ rgi6->flags |= RGI_IFACE_DEFINED;
+ }
+ }
}
+
+ done:
+ if (sockfd >= 0)
+ close(sockfd);
}
+#undef max
+
#else
/*
@@ -3100,6 +3634,13 @@ get_default_gateway (struct route_gateway_info *rgi)
{
CLEAR(*rgi);
}
+void
+get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6,
+ const struct in6_addr *dest)
+{
+ msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system");
+ CLEAR(*rgi6);
+}
#endif
@@ -3127,13 +3668,33 @@ netmask_to_netbits (const in_addr_t network, const in_addr_t netmask, int *netbi
return false;
}
+/* similar to netmask_to_netbits(), but don't mess with base address
+ * etc., just convert to netbits - non-mappable masks are returned as "-1"
+ */
+int netmask_to_netbits2 (in_addr_t netmask)
+{
+ int i;
+ const int addrlen = sizeof (in_addr_t) * 8;
+
+ for (i = 0; i <= addrlen; ++i)
+ {
+ in_addr_t mask = netbits_to_netmask (i);
+ if (mask == netmask)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
/*
* 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)
+#if defined(_WIN32)
static void
add_host_route_if_nonlocal (struct route_bypass *rb, const in_addr_t addr)
@@ -3207,7 +3768,7 @@ get_bypass_addresses (struct route_bypass *rb, const unsigned int flags) /* PLA
* Used by redirect-gateway autolocal feature
*/
-#if defined(WIN32)
+#if defined(_WIN32)
int
test_local_addr (const in_addr_t addr, const struct route_gateway_info *rgi)
diff --git a/src/openvpn/route.h b/src/openvpn/route.h
index fe9b461..c358681 100644
--- a/src/openvpn/route.h
+++ b/src/openvpn/route.h
@@ -33,15 +33,14 @@
#include "tun.h"
#include "misc.h"
-#define MAX_ROUTES_DEFAULT 100
-
-#ifdef WIN32
+#ifdef _WIN32
/*
* Windows route methods
*/
#define ROUTE_METHOD_ADAPTIVE 0 /* try IP helper first then route.exe */
#define ROUTE_METHOD_IPAPI 1 /* use IP helper API */
#define ROUTE_METHOD_EXE 2 /* use route.exe */
+#define ROUTE_METHOD_SERVICE 3 /* use the privileged Windows service */
#define ROUTE_METHOD_MASK 3
#endif
@@ -74,6 +73,7 @@ struct route_special_addr
};
struct route_option {
+ struct route_option *next;
const char *network;
const char *netmask;
const char *gateway;
@@ -92,28 +92,28 @@ struct route_option {
struct route_option_list {
unsigned int flags; /* RG_x flags */
- int capacity;
- int n;
- struct route_option routes[EMPTY_ARRAY_SIZE];
+ struct route_option *routes;
+ struct gc_arena *gc;
};
struct route_ipv6_option {
+ struct route_ipv6_option *next;
const char *prefix; /* e.g. "2001:db8:1::/64" */
const char *gateway; /* e.g. "2001:db8:0::2" */
const char *metric; /* e.g. "5" */
};
struct route_ipv6_option_list {
- unsigned int flags;
- int capacity;
- int n;
- struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE];
+ unsigned int flags; /* RG_x flags, see route_option-list */
+ struct route_ipv6_option *routes_ipv6;
+ struct gc_arena *gc;
};
struct route_ipv4 {
# define RT_DEFINED (1<<0)
# define RT_ADDED (1<<1)
# define RT_METRIC_DEFINED (1<<2)
+ struct route_ipv4 *next;
unsigned int flags;
const struct route_option *option;
in_addr_t network;
@@ -123,26 +123,18 @@ struct route_ipv4 {
};
struct route_ipv6 {
- bool defined;
+ struct route_ipv6 *next;
+ unsigned int flags; /* RT_ flags, see route_ipv4 */
struct in6_addr network;
unsigned int netbits;
struct in6_addr gateway;
- bool metric_defined;
int metric;
-};
-
-struct route_ipv6_list {
- bool routes_added;
- unsigned int flags;
- int default_metric;
- bool default_metric_defined;
- struct in6_addr remote_endpoint_ipv6;
- bool remote_endpoint_defined;
- bool did_redirect_default_gateway; /* TODO (?) */
- bool did_local; /* TODO (?) */
- int capacity;
- int n;
- struct route_ipv6 routes_ipv6[EMPTY_ARRAY_SIZE];
+ /* gateway interface */
+# ifdef _WIN32
+ DWORD adapter_index; /* interface or ~0 if undefined */
+#else
+ char * iface; /* interface name (null terminated) */
+#endif
};
@@ -161,7 +153,7 @@ struct route_gateway_info {
unsigned int flags;
/* gateway interface */
-# ifdef WIN32
+# ifdef _WIN32
DWORD adapter_index; /* interface or ~0 if undefined */
#else
char iface[16]; /* interface name (null terminated), may be empty */
@@ -179,6 +171,34 @@ struct route_gateway_info {
struct route_gateway_address addrs[RGI_N_ADDRESSES]; /* local addresses attached to iface */
};
+struct route_ipv6_gateway_address {
+ struct in6_addr addr_ipv6;
+ int netbits_ipv6;
+};
+
+struct route_ipv6_gateway_info {
+/* RGI_ flags used as in route_gateway_info */
+ unsigned int flags;
+
+ /* gateway interface */
+# ifdef _WIN32
+ DWORD adapter_index; /* interface or ~0 if undefined */
+#else
+ char iface[16]; /* interface name (null terminated), may be empty */
+#endif
+
+ /* gateway interface hardware address */
+ uint8_t hwaddr[6];
+
+ /* gateway/router address */
+ struct route_ipv6_gateway_address gateway;
+
+ /* address/netmask pairs bound to interface */
+# define RGI_N_ADDRESSES 8
+ int n_addrs; /* len of addrs, may be 0 */
+ struct route_ipv6_gateway_address addrs[RGI_N_ADDRESSES]; /* local addresses attached to iface */
+};
+
struct route_list {
# define RL_DID_REDIRECT_DEFAULT_GATEWAY (1<<0)
# define RL_DID_LOCAL (1<<1)
@@ -188,9 +208,22 @@ struct route_list {
struct route_special_addr spec;
struct route_gateway_info rgi;
unsigned int flags; /* RG_x flags */
- int capacity;
- int n;
- struct route_ipv4 routes[EMPTY_ARRAY_SIZE];
+ struct route_ipv4 *routes;
+ struct gc_arena gc;
+};
+
+struct route_ipv6_list {
+ unsigned int iflags; /* RL_ flags, see route_list */
+
+ unsigned int spec_flags; /* RTSA_ flags, route_special_addr */
+ struct in6_addr remote_endpoint_ipv6; /* inside tun */
+ struct in6_addr remote_host_ipv6; /* --remote address */
+ int default_metric;
+
+ struct route_ipv6_gateway_info rgi6;
+ unsigned int flags; /* RG_x flags, see route_option_list */
+ struct route_ipv6 *routes_ipv6;
+ struct gc_arena gc;
};
#if P2MP
@@ -208,17 +241,15 @@ struct iroute_ipv6 {
};
#endif
-struct route_option_list *new_route_option_list (const int max_routes, struct gc_arena *a);
-struct route_ipv6_option_list *new_route_ipv6_option_list (const int max_routes, struct gc_arena *a);
+struct route_option_list *new_route_option_list (struct gc_arena *a);
+struct route_ipv6_option_list *new_route_ipv6_option_list (struct gc_arena *a);
struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a);
struct route_ipv6_option_list *clone_route_ipv6_option_list (const struct route_ipv6_option_list *src, struct gc_arena *a);
-void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src);
+void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a);
void copy_route_ipv6_option_list (struct route_ipv6_option_list *dest,
- const struct route_ipv6_option_list *src);
-
-struct route_list *new_route_list (const int max_routes, struct gc_arena *a);
-struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_arena *a);
+ const struct route_ipv6_option_list *src,
+ struct gc_arena *a);
void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
@@ -251,6 +282,7 @@ bool init_route_ipv6_list (struct route_ipv6_list *rl6,
const struct route_ipv6_option_list *opt6,
const char *remote_endpoint,
int default_metric,
+ const struct in6_addr *remote_host,
struct env_set *es);
void route_list_add_vpn_gateway (struct route_list *rl,
@@ -277,7 +309,11 @@ void setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6);
bool is_special_addr (const char *addr_str);
void get_default_gateway (struct route_gateway_info *rgi);
-void print_default_gateway(const int msglevel, const struct route_gateway_info *rgi);
+void get_default_gateway_ipv6 (struct route_ipv6_gateway_info *rgi,
+ const struct in6_addr *dest);
+void print_default_gateway(const int msglevel,
+ const struct route_gateway_info *rgi,
+ const struct route_ipv6_gateway_info *rgi6);
/*
* Test if addr is reachable via a local interface (return ILA_LOCAL),
@@ -297,7 +333,7 @@ void print_route_options (const struct route_option_list *rol,
void print_routes (const struct route_list *rl, int level);
-#ifdef WIN32
+#ifdef _WIN32
void show_routes (int msglev);
bool test_routes (const struct route_list *rl, const struct tuntap *tt);
@@ -309,6 +345,7 @@ static inline bool test_routes (const struct route_list *rl, const struct tuntap
#endif
bool netmask_to_netbits (const in_addr_t network, const in_addr_t netmask, int *netbits);
+int netmask_to_netbits2 (in_addr_t netmask);
static inline in_addr_t
netbits_to_netmask (const int netbits)
diff --git a/src/openvpn/session_id.c b/src/openvpn/session_id.c
index 2e07b54..0ebff65 100644
--- a/src/openvpn/session_id.c
+++ b/src/openvpn/session_id.c
@@ -39,7 +39,7 @@
#include "syshead.h"
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
#include "error.h"
#include "common.h"
@@ -64,4 +64,4 @@ session_id_print (const struct session_id *sid, struct gc_arena *gc)
#else
static void dummy(void) {}
-#endif /* ENABLE_CRYPTO && ENABLE_SSL*/
+#endif /* ENABLE_CRYPTO */
diff --git a/src/openvpn/session_id.h b/src/openvpn/session_id.h
index 33909dd..2a1f41f 100644
--- a/src/openvpn/session_id.h
+++ b/src/openvpn/session_id.h
@@ -30,7 +30,7 @@
* negotiated).
*/
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
#ifndef SESSION_ID_H
#define SESSION_ID_H
@@ -83,4 +83,4 @@ void session_id_random (struct session_id *sid);
const char *session_id_print (const struct session_id *sid, struct gc_arena *gc);
#endif /* SESSION_ID_H */
-#endif /* ENABLE_CRYPTO && ENABLE_SSL */
+#endif /* ENABLE_CRYPTO */
diff --git a/src/openvpn/shaper.h b/src/openvpn/shaper.h
index afeb9c3..fa132c4 100644
--- a/src/openvpn/shaper.h
+++ b/src/openvpn/shaper.h
@@ -75,7 +75,7 @@ bool shaper_soonest_event (struct timeval *tv, int delay);
static inline void
shaper_reset (struct shaper *s, int bytes_per_second)
{
- s->bytes_per_second = bytes_per_second ? constrain_int (bytes_per_second, SHAPER_MIN, SHAPER_MAX) : 0;
+ s->bytes_per_second = constrain_int (bytes_per_second, SHAPER_MIN, SHAPER_MAX);
#ifdef SHAPER_USE_FP
s->factor = 1000000.0 / (double)s->bytes_per_second;
diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c
index 0ebde24..0ff1437 100644
--- a/src/openvpn/sig.c
+++ b/src/openvpn/sig.c
@@ -97,14 +97,14 @@ void
throw_signal (const int signum)
{
siginfo_static.signal_received = signum;
- siginfo_static.hard = true;
+ siginfo_static.source = SIG_SOURCE_HARD;
}
void
throw_signal_soft (const int signum, const char *signal_text)
{
siginfo_static.signal_received = signum;
- siginfo_static.hard = false;
+ siginfo_static.source = SIG_SOURCE_SOFT;
siginfo_static.signal_text = signal_text;
}
@@ -115,7 +115,7 @@ signal_reset (struct signal_info *si)
{
si->signal_received = 0;
si->signal_text = NULL;
- si->hard = false;
+ si->source = SIG_SOURCE_SOFT;
}
}
@@ -124,9 +124,23 @@ print_signal (const struct signal_info *si, const char *title, int msglevel)
{
if (si)
{
- const char *hs = (si->hard ? "hard" : "soft");
const char *type = (si->signal_text ? si->signal_text : "");
const char *t = (title ? title : "process");
+ const char *hs = NULL;
+ switch (si->source)
+ {
+ case SIG_SOURCE_SOFT:
+ hs= "soft";
+ break;
+ case SIG_SOURCE_HARD:
+ hs = "hard";
+ break;
+ case SIG_SOURCE_CONNECTION_FAILED:
+ hs = "connection failed(soft)";
+ break;
+ default:
+ ASSERT(0);
+ }
switch (si->signal_received)
{
@@ -175,8 +189,10 @@ signal_restart_status (const struct signal_info *si)
management_set_state (management,
state,
si->signal_text ? si->signal_text : signal_name (si->signal_received, true),
- (in_addr_t)0,
- (in_addr_t)0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
#endif
}
@@ -205,7 +221,7 @@ static int signal_mode; /* GLOBAL */
void
pre_init_signal_catch (void)
{
-#ifndef WIN32
+#ifndef _WIN32
#ifdef HAVE_SIGNAL_H
signal_mode = SM_PRE_INIT;
signal (SIGINT, signal_handler);
@@ -215,13 +231,13 @@ pre_init_signal_catch (void)
signal (SIGUSR2, SIG_IGN);
signal (SIGPIPE, SIG_IGN);
#endif /* HAVE_SIGNAL_H */
-#endif /* WIN32 */
+#endif /* _WIN32 */
}
void
post_init_signal_catch (void)
{
-#ifndef WIN32
+#ifndef _WIN32
#ifdef HAVE_SIGNAL_H
signal_mode = SM_POST_INIT;
signal (SIGINT, signal_handler);
@@ -265,9 +281,9 @@ print_status (const struct context *c, struct status_output *so)
status_printf (so, "TCP/UDP read bytes," counter_format, c->c2.link_read_bytes);
status_printf (so, "TCP/UDP write bytes," counter_format, c->c2.link_write_bytes);
status_printf (so, "Auth read bytes," counter_format, c->c2.link_read_bytes_auth);
-#ifdef ENABLE_LZO
- if (lzo_defined (&c->c2.lzo_compwork))
- lzo_print_stats (&c->c2.lzo_compwork, so);
+#ifdef USE_COMP
+ if (c->c2.comp_context)
+ comp_print_stats (c->c2.comp_context, so);
#endif
#ifdef PACKET_TRUNCATION_CHECK
status_printf (so, "TUN read truncations," counter_format, c->c2.n_trunc_tun_read);
@@ -275,7 +291,7 @@ print_status (const struct context *c, struct status_output *so)
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
+#ifdef _WIN32
if (tuntap_defined (c->c1.tuntap))
status_printf (so, "TAP-WIN32 driver status,\"%s\"",
tap_win_getinfo (c->c1.tuntap, &gc));
@@ -360,12 +376,35 @@ process_sigterm (struct context *c)
return ret;
}
+/**
+ * If a restart signal is received during exit-notification, reset the
+ * signal and return true.
+ */
+static bool
+ignore_restart_signals (struct context *c)
+{
+ bool ret = false;
+#ifdef ENABLE_OCC
+ if ( (c->sig->signal_received == SIGUSR1 || c->sig->signal_received == SIGHUP) &&
+ event_timeout_defined(&c->c2.explicit_exit_notification_interval) )
+ {
+ msg (M_INFO, "Ignoring %s received during exit notification",
+ signal_name(c->sig->signal_received, true));
+ signal_reset (c->sig);
+ ret = true;
+ }
+#endif
+ return ret;
+}
+
bool
process_signal (struct context *c)
{
bool ret = true;
- if (c->sig->signal_received == SIGTERM || c->sig->signal_received == SIGINT)
+ if (ignore_restart_signals (c))
+ ret = false;
+ else if (c->sig->signal_received == SIGTERM || c->sig->signal_received == SIGINT)
{
ret = process_sigterm (c);
}
diff --git a/src/openvpn/sig.h b/src/openvpn/sig.h
index 987efef..2875a4c 100644
--- a/src/openvpn/sig.h
+++ b/src/openvpn/sig.h
@@ -28,6 +28,15 @@
#include "status.h"
#include "win32.h"
+
+
+#define SIG_SOURCE_SOFT 0
+#define SIG_SOURCE_HARD 1
+/* CONNECTION_FAILED is also a "soft" status,
+ * It is thrown if a connection attempt fails
+ */
+#define SIG_SOURCE_CONNECTION_FAILED 2
+
/*
* Signal information, including signal code
* and descriptive text.
@@ -35,7 +44,7 @@
struct signal_info
{
volatile int signal_received;
- volatile bool hard;
+ volatile int source;
const char *signal_text;
};
@@ -70,7 +79,7 @@ void register_signal (struct context *c, int sig, const char *text);
void process_explicit_exit_notification_timer_wakeup (struct context *c);
#endif
-#ifdef WIN32
+#ifdef _WIN32
static inline void
get_signal (volatile int *sig)
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
index b7ac339..c233f2b 100644
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -38,6 +38,9 @@
#include "ps.h"
#include "manage.h"
#include "misc.h"
+#include "manage.h"
+#include "openvpn.h"
+#include "forward.h"
#include "memdbg.h"
@@ -69,23 +72,6 @@ sf2gaf(const unsigned int getaddr_flags,
* Functions related to the translation of DNS names to IP addresses.
*/
-static const char*
-h_errno_msg(int h_errno_err)
-{
- switch (h_errno_err)
- {
- case HOST_NOT_FOUND:
- return "[HOST_NOT_FOUND] The specified host is unknown.";
- case NO_DATA:
- return "[NO_DATA] The requested name is valid but does not have an IP address.";
- case NO_RECOVERY:
- return "[NO_RECOVERY] A non-recoverable name server error occurred.";
- case TRY_AGAIN:
- return "[TRY_AGAIN] A temporary error occurred on an authoritative name server.";
- }
- return "[unknown h_errno value]";
-}
-
/*
* Translate IP addr or hostname to in_addr_t.
* If resolve error, try again for
@@ -100,8 +86,8 @@ getaddr (unsigned int flags,
{
struct addrinfo *ai;
int status;
- status = openvpn_getaddrinfo(flags, hostname, resolve_retry_seconds,
- signal_received, AF_INET, &ai);
+ status = openvpn_getaddrinfo (flags & ~GETADDR_HOST_ORDER, hostname, NULL,
+ resolve_retry_seconds, signal_received, AF_INET, &ai);
if(status==0) {
struct in_addr ia;
if(succeeded)
@@ -116,6 +102,178 @@ getaddr (unsigned int flags,
}
}
+static inline bool
+streqnull (const char* a, const char* b)
+{
+ if (a == NULL && b == NULL)
+ return true;
+ else if (a == NULL || b == NULL)
+ return false;
+ else
+ return streq (a, b);
+}
+
+/*
+ get_cached_dns_entry return 0 on success and -1
+ otherwise. (like getaddrinfo)
+ */
+static int
+get_cached_dns_entry (struct cached_dns_entry* dns_cache,
+ const char* hostname,
+ const char* servname,
+ int ai_family,
+ int resolve_flags,
+ struct addrinfo **ai)
+{
+ struct cached_dns_entry *ph;
+ int flags;
+
+ /* Only use flags that are relevant for the structure */
+ flags = resolve_flags & GETADDR_CACHE_MASK;
+
+ for (ph = dns_cache; ph ; ph = ph->next)
+ {
+ if (streqnull (ph->hostname, hostname) &&
+ streqnull (ph->servname, servname) &&
+ ph->ai_family == ai_family &&
+ ph->flags == flags)
+ {
+ *ai = ph->ai;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+static int
+do_preresolve_host (struct context *c,
+ const char *hostname,
+ const char *servname,
+ const int af,
+ const int flags)
+{
+ struct addrinfo *ai;
+ int status;
+
+ if (get_cached_dns_entry(c->c1.dns_cache,
+ hostname,
+ servname,
+ af,
+ flags,
+ &ai) == 0 )
+ {
+ /* entry already cached, return success */
+ return 0;
+ }
+
+ status = openvpn_getaddrinfo (flags, hostname, servname,
+ c->options.resolve_retry_seconds, NULL,
+ af, &ai);
+ if (status == 0)
+ {
+ struct cached_dns_entry *ph;
+
+ ALLOC_OBJ_CLEAR_GC (ph, struct cached_dns_entry, &c->gc);
+ ph->ai = ai;
+ ph->hostname = hostname;
+ ph->servname = servname;
+ ph->flags = flags & GETADDR_CACHE_MASK;
+
+ if (!c->c1.dns_cache)
+ c->c1.dns_cache = ph;
+ else
+ {
+ struct cached_dns_entry *prev = c->c1.dns_cache;
+ while (prev->next)
+ prev = prev->next;
+ prev->next = ph;
+ }
+
+ gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc);
+
+ }
+ return status;
+}
+
+void
+do_preresolve (struct context *c)
+{
+ int i;
+ struct connection_list *l = c->options.connection_list;
+ const unsigned int preresolve_flags = GETADDR_RESOLVE|
+ GETADDR_UPDATE_MANAGEMENT_STATE|
+ GETADDR_MENTION_RESOLVE_RETRY|
+ GETADDR_FATAL;
+
+
+ for (i = 0; i < l->len; ++i)
+ {
+ int status;
+ const char *remote;
+ int flags = preresolve_flags;
+
+ struct connection_entry* ce = c->options.connection_list->array[i];
+
+ if (proto_is_dgram(ce->proto))
+ flags |= GETADDR_DATAGRAM;
+
+ if (c->options.sockflags & SF_HOST_RANDOMIZE)
+ flags |= GETADDR_RANDOMIZE;
+
+ if (c->options.ip_remote_hint)
+ remote = c->options.ip_remote_hint;
+ else
+ remote = ce->remote;
+
+ /* HTTP remote hostname does not need to be resolved */
+ if (! ce->http_proxy_options)
+ {
+ status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags);
+ if (status != 0)
+ goto err;
+ }
+
+ /* Preresolve proxy */
+ if (ce->http_proxy_options)
+ {
+ status = do_preresolve_host (c,
+ ce->http_proxy_options->server,
+ ce->http_proxy_options->port,
+ ce->af,
+ preresolve_flags);
+
+ if (status != 0)
+ goto err;
+ }
+
+ if (ce->socks_proxy_server)
+ {
+ status = do_preresolve_host (c,
+ ce->socks_proxy_server,
+ ce->socks_proxy_port,
+ ce->af,
+ flags);
+ if (status != 0)
+ goto err;
+ }
+
+ if (ce->bind_local)
+ {
+ flags |= GETADDR_PASSIVE;
+ flags &= ~GETADDR_RANDOMIZE;
+ status = do_preresolve_host (c, ce->local, ce->local_port, ce->af, flags);
+ if (status != 0)
+ goto err;
+
+ }
+
+ }
+ return;
+
+ err:
+ throw_signal_soft (SIGHUP, "Preresolving failed");
+}
/*
* Translate IPv4/IPv6 addr or hostname into struct addrinfo
@@ -124,6 +282,7 @@ getaddr (unsigned int flags,
int
openvpn_getaddrinfo (unsigned int flags,
const char *hostname,
+ const char *servname,
int resolve_retry_seconds,
volatile int *signal_received,
int ai_family,
@@ -134,15 +293,27 @@ openvpn_getaddrinfo (unsigned int flags,
int sigrec = 0;
int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
struct gc_arena gc = gc_new ();
+ const char *print_hostname;
+ const char *print_servname;
ASSERT(res);
- if (!hostname)
- hostname = "::";
+ ASSERT (hostname || servname);
+ ASSERT (!(flags & GETADDR_HOST_ORDER));
- if (flags & GETADDR_RANDOMIZE)
+ if (hostname && (flags & GETADDR_RANDOMIZE))
hostname = hostname_randomize(hostname, &gc);
+ if(hostname)
+ print_hostname = hostname;
+ else
+ print_hostname = "undefined";
+
+ if(servname)
+ print_servname = servname;
+ else
+ print_servname = "";
+
if (flags & GETADDR_MSG_VIRT_OUT)
msglevel |= M_MSG_VIRT_OUT;
@@ -154,25 +325,35 @@ openvpn_getaddrinfo (unsigned int flags,
CLEAR(hints);
hints.ai_family = ai_family;
hints.ai_flags = AI_NUMERICHOST;
- hints.ai_socktype = SOCK_STREAM;
- status = getaddrinfo(hostname, NULL, &hints, res);
+ if(flags & GETADDR_PASSIVE)
+ hints.ai_flags |= AI_PASSIVE;
+
+ if(flags & GETADDR_DATAGRAM)
+ hints.ai_socktype = SOCK_DGRAM;
+ else
+ hints.ai_socktype = SOCK_STREAM;
+
+ status = getaddrinfo(hostname, servname, &hints, res);
if (status != 0) /* parse as numeric address failed? */
{
const int fail_wait_interval = 5; /* seconds */
- int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : (resolve_retry_seconds / fail_wait_interval);
+ /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */
+ int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 :
+ ((resolve_retry_seconds + 4)/ fail_wait_interval);
const char *fmt;
int level = 0;
- fmt = "RESOLVE: Cannot resolve host address: %s: %s";
+ fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)";
if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
&& !resolve_retry_seconds)
- fmt = "RESOLVE: Cannot resolve host address: %s: %s (I would have retried this name query if you had specified the --resolv-retry option.)";
+ fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) (I would have retried this name query if you had specified the --resolv-retry option.)";
if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
{
- msg (msglevel, "RESOLVE: Cannot parse IP address: %s", hostname);
+ msg (msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)",
+ print_hostname,print_servname, gai_strerror(status));
goto done;
}
@@ -183,8 +364,10 @@ openvpn_getaddrinfo (unsigned int flags,
management_set_state (management,
OPENVPN_STATE_RESOLVE,
NULL,
- (in_addr_t)0,
- (in_addr_t)0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
#endif
@@ -193,14 +376,14 @@ openvpn_getaddrinfo (unsigned int flags,
*/
while (true)
{
-#ifndef WIN32
+#ifndef _WIN32
res_init ();
#endif
/* try hostname lookup */
- hints.ai_flags = 0;
+ hints.ai_flags &= ~AI_NUMERICHOST;
dmsg (D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d",
flags, hints.ai_family, hints.ai_socktype);
- status = getaddrinfo(hostname, NULL, &hints, res);
+ status = getaddrinfo(hostname, servname, &hints, res);
if (signal_received)
{
@@ -239,7 +422,8 @@ openvpn_getaddrinfo (unsigned int flags,
msg (level,
fmt,
- hostname,
+ print_hostname,
+ print_servname,
gai_strerror(status));
if (--resolve_retries <= 0)
@@ -252,7 +436,8 @@ openvpn_getaddrinfo (unsigned int flags,
/* hostname resolve succeeded */
- /* Do not chose an IP Addresse by random or change the order *
+ /*
+ * Do not choose an IP Addresse by random or change the order *
* of IP addresses, doing so will break RFC 3484 address selection *
*/
}
@@ -422,59 +607,6 @@ mac_addr_safe (const char *mac_addr)
return true;
}
-static void
-update_remote (const char* host,
- struct openvpn_sockaddr *addr,
- bool *changed,
- const unsigned int sockflags)
-{
- switch(addr->addr.sa.sa_family)
- {
- case AF_INET:
- if (host && addr)
- {
- const in_addr_t new_addr = getaddr (
- sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags),
- host,
- 1,
- NULL,
- NULL);
- if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr)
- {
- addr->addr.in4.sin_addr.s_addr = new_addr;
- *changed = true;
- }
- }
- break;
- case AF_INET6:
- if (host && addr)
- {
- int status;
- struct addrinfo* ai;
-
- status = openvpn_getaddrinfo(sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), host, 1, NULL, AF_INET6, &ai);
-
- if ( status ==0 )
- {
- struct sockaddr_in6 sin6;
- CLEAR(sin6);
- sin6 = *((struct sockaddr_in6*)ai->ai_addr);
- if (!IN6_ARE_ADDR_EQUAL(&sin6.sin6_addr, &addr->addr.in6.sin6_addr))
- {
- int port = addr->addr.in6.sin6_port;
- /* ipv6 requires also eg. sin6_scope_id => easier to fully copy and override port */
- addr->addr.in6 = sin6;
- addr->addr.in6.sin6_port = port;
- }
- freeaddrinfo(ai);
- }
- }
- break;
- default:
- ASSERT(0);
- }
-}
-
static int
socket_get_sndbuf (int sd)
{
@@ -558,7 +690,7 @@ socket_set_buffers (int fd, const struct socket_buffer_size *sbs)
static bool
socket_set_tcp_nodelay (int sd, int state)
{
-#if defined(WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY))
+#if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY))
if (setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof (state)) != 0)
{
msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state);
@@ -579,7 +711,7 @@ static inline void
socket_set_mark (int sd, int mark)
{
#if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK
- if (mark && setsockopt (sd, SOL_SOCKET, SO_MARK, &mark, sizeof (mark)) != 0)
+ if (mark && setsockopt (sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof (mark)) != 0)
msg (M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark);
#endif
}
@@ -619,14 +751,17 @@ link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf)
*/
socket_descriptor_t
-create_socket_tcp (int af)
+create_socket_tcp (struct addrinfo* addrinfo)
{
socket_descriptor_t sd;
- if ((sd = socket (af, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ ASSERT (addrinfo);
+ ASSERT (addrinfo->ai_socktype == SOCK_STREAM);
+
+ if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
msg (M_ERR, "Cannot create TCP socket");
-#ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */
+#ifndef _WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */
/* set SO_REUSEADDR on socket */
{
int on = 1;
@@ -640,106 +775,134 @@ create_socket_tcp (int af)
}
static socket_descriptor_t
-create_socket_udp (const unsigned int flags)
+create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags)
{
socket_descriptor_t sd;
- if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
- msg (M_ERR, "UDP: Cannot create UDP socket");
+ ASSERT (addrinfo);
+ ASSERT (addrinfo->ai_socktype == SOCK_DGRAM);
+
+ if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
+ msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket");
#if ENABLE_IP_PKTINFO
else if (flags & SF_USE_IP_PKTINFO)
{
int pad = 1;
-#ifdef IP_PKTINFO
- if (setsockopt (sd, SOL_IP, IP_PKTINFO,
- (void*)&pad, sizeof(pad)) < 0)
- msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO");
+ if(addrinfo->ai_family == AF_INET)
+ {
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+ if (setsockopt (sd, SOL_IP, IP_PKTINFO,
+ (void*)&pad, sizeof(pad)) < 0)
+ msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO");
#elif defined(IP_RECVDSTADDR)
- if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR,
- (void*)&pad, sizeof(pad)) < 0)
- msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
+ if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR,
+ (void*)&pad, sizeof(pad)) < 0)
+ msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
#else
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
#endif
- }
-#endif
- return sd;
-}
-
-static socket_descriptor_t
-create_socket_udp6 (const unsigned int flags)
-{
- socket_descriptor_t sd;
-
- if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
- msg (M_ERR, "UDP: Cannot create UDP6 socket");
-#if ENABLE_IP_PKTINFO
- else if (flags & SF_USE_IP_PKTINFO)
- {
- int pad = 1;
+ }
+ else if (addrinfo->ai_family == AF_INET6 )
+ {
#ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */
- if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO,
- (void*)&pad, sizeof(pad)) < 0)
+ if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO,
+ (void*)&pad, sizeof(pad)) < 0)
#else
- if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
- (void*)&pad, sizeof(pad)) < 0)
+ if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (void*)&pad, sizeof(pad)) < 0)
#endif
- msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");
+ msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");
+ }
}
#endif
return sd;
}
+static void bind_local (struct link_socket *sock, const sa_family_t ai_family)
+{
+ /* bind to local address/port */
+ if (sock->bind_local)
+ {
+ if (sock->socks_proxy && sock->info.proto == PROTO_UDP)
+ socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local,
+ ai_family, "SOCKS", false);
+ else
+ socket_bind (sock->sd, sock->info.lsa->bind_local,
+ ai_family,
+ "TCP/UDP", sock->info.bind_ipv6_only);
+ }
+}
+
static void
-create_socket (struct link_socket *sock)
+create_socket (struct link_socket* sock, struct addrinfo* addr)
{
- /* create socket */
- if (sock->info.proto == PROTO_UDPv4)
+ if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM)
{
- sock->sd = create_socket_udp (sock->sockflags);
+ sock->sd = create_socket_udp (addr, sock->sockflags);
sock->sockflags |= SF_GETADDRINFO_DGRAM;
-#ifdef ENABLE_SOCKS
+ /* Assume that control socket and data socket to the socks proxy
+ * are using the same IP family */
if (sock->socks_proxy)
- sock->ctrl_sd = create_socket_tcp (AF_INET);
-#endif
- }
- else if (sock->info.proto == PROTO_TCPv4_SERVER
- || sock->info.proto == PROTO_TCPv4_CLIENT)
- {
- sock->sd = create_socket_tcp (AF_INET);
- }
- else if (sock->info.proto == PROTO_TCPv6_SERVER
- || sock->info.proto == PROTO_TCPv6_CLIENT)
- {
- sock->sd = create_socket_tcp (AF_INET6);
+ {
+ /* Construct a temporary addrinfo to create the socket,
+ * currently resolve two remote addresses is not supported,
+ * TODO: Rewrite the whole resolve_remote */
+ struct addrinfo addrinfo_tmp = *addr;
+ addrinfo_tmp.ai_socktype = SOCK_STREAM;
+ addrinfo_tmp.ai_protocol = IPPROTO_TCP;
+ sock->ctrl_sd = create_socket_tcp (&addrinfo_tmp);
+ }
}
- else if (sock->info.proto == PROTO_UDPv6)
+ else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM)
{
- sock->sd = create_socket_udp6 (sock->sockflags);
- sock->sockflags |= SF_GETADDRINFO_DGRAM;
+ sock->sd = create_socket_tcp (addr);
}
else
{
ASSERT (0);
}
+ /* set socket buffers based on --sndbuf and --rcvbuf options */
+ socket_set_buffers (sock->sd, &sock->socket_buffer_sizes);
+
+ /* set socket to --mark packets with given value */
+ socket_set_mark (sock->sd, sock->mark);
+
+ bind_local (sock, addr->ai_family);
+}
+
+#ifdef TARGET_ANDROID
+static void protect_fd_nonlocal (int fd, const struct sockaddr* addr)
+{
+ /* pass socket FD to management interface to pass on to VPNService API
+ * as "protected socket" (exempt from being routed into tunnel)
+ */
+ if (addr_local (addr)) {
+ msg(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd);
+ return;
+ }
+
+ msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd);
+ management->connection.fdtosend = fd;
+ management_android_control (management, "PROTECTFD", __func__);
}
+#endif
/*
* Functions used for establishing a TCP stream connection.
*/
-
static void
socket_do_listen (socket_descriptor_t sd,
- const struct openvpn_sockaddr *local,
+ const struct addrinfo *local,
bool do_listen,
bool do_set_nonblock)
{
struct gc_arena gc = gc_new ();
if (do_listen)
{
+ ASSERT(local);
msg (M_INFO, "Listening for incoming TCP connection on %s",
- print_sockaddr (local, &gc));
+ print_sockaddr (local->ai_addr, &gc));
if (listen (sd, 1))
msg (M_ERR, "TCP: listen() failed");
}
@@ -821,8 +984,7 @@ static int
socket_listen_accept (socket_descriptor_t sd,
struct link_socket_actual *act,
const char *remote_dynamic,
- bool *remote_changed,
- const struct openvpn_sockaddr *local,
+ const struct addrinfo *local,
bool do_listen,
bool nowait,
volatile int *signal_received)
@@ -868,18 +1030,26 @@ socket_listen_accept (socket_descriptor_t sd,
if (socket_defined (new_sd))
{
- update_remote (remote_dynamic, &remote_verify, remote_changed, 0);
- if (addr_defined (&remote_verify)
- && !addr_match (&remote_verify, &act->dest))
- {
- msg (M_WARN,
- "TCP NOTE: Rejected connection attempt from %s due to --remote setting",
- print_link_socket_actual (act, &gc));
- if (openvpn_close_socket (new_sd))
- msg (M_ERR, "TCP: close socket failed (new_sd)");
- }
+ struct addrinfo* ai = NULL;
+ if(remote_dynamic)
+ openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL,
+ remote_verify.addr.sa.sa_family, &ai);
+
+ if(ai && !addrlist_match(&remote_verify, ai))
+ {
+ msg (M_WARN,
+ "TCP NOTE: Rejected connection attempt from %s due to --remote setting",
+ print_link_socket_actual (act, &gc));
+ if (openvpn_close_socket (new_sd))
+ msg (M_ERR, "TCP: close socket failed (new_sd)");
+ freeaddrinfo(ai);
+ }
else
- break;
+ {
+ if(ai)
+ freeaddrinfo(ai);
+ break;
+ }
}
openvpn_sleep (1);
}
@@ -893,19 +1063,61 @@ socket_listen_accept (socket_descriptor_t sd,
return new_sd;
}
+/* older mingw versions and WinXP do not have this define,
+ * but Vista and up support the functionality - just define it here
+ */
+#ifdef _WIN32
+# ifndef IPV6_V6ONLY
+# define IPV6_V6ONLY 27
+# endif
+#endif
void
socket_bind (socket_descriptor_t sd,
- struct openvpn_sockaddr *local,
- const char *prefix)
+ struct addrinfo *local,
+ int ai_family,
+ const char *prefix,
+ bool ipv6only)
{
struct gc_arena gc = gc_new ();
- if (bind (sd, &local->addr.sa, af_addr_size(local->addr.sa.sa_family)))
+ /* FIXME (schwabe)
+ * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6
+ * entries for the requested protocol.
+ * For example if an address has multiple A records
+ * What is the correct way to deal with it?
+ */
+
+ struct addrinfo* cur;
+
+ ASSERT(local);
+
+
+ /* find the first addrinfo with correct ai_family */
+ for (cur = local; cur; cur=cur->ai_next)
+ {
+ if(cur->ai_family == ai_family)
+ break;
+ }
+ if (!cur)
+ msg (M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record",
+ prefix, addr_family_name(ai_family));
+
+ if (ai_family == AF_INET6)
+ {
+ int v6only = ipv6only ? 1: 0; /* setsockopt must have an "int" */
+
+ msg (M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only);
+ if (setsockopt (sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only)))
+ {
+ msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only);
+ }
+ }
+ if (bind (sd, cur->ai_addr, cur->ai_addrlen))
{
const int errnum = openvpn_errno ();
msg (M_FATAL, "%s: Socket bind failed on local address %s: %s",
prefix,
- print_sockaddr (local, &gc),
+ print_sockaddr_ex (local->ai_addr, ":", PS_SHOW_PORT, &gc),
strerror_ts (errnum, &gc));
}
gc_free (&gc);
@@ -913,19 +1125,23 @@ socket_bind (socket_descriptor_t sd,
int
openvpn_connect (socket_descriptor_t sd,
- struct openvpn_sockaddr *remote,
+ const struct sockaddr *remote,
int connect_timeout,
volatile int *signal_received)
{
int status = 0;
+#ifdef TARGET_ANDROID
+ protect_fd_nonlocal(sd, remote);
+#endif
+
#ifdef CONNECT_NONBLOCK
set_nonblock (sd);
- status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family));
+ status = connect (sd, remote, af_addr_size(remote->sa_family));
if (status)
status = openvpn_errno ();
if (
-#ifdef WIN32
+#ifdef _WIN32
status == WSAEWOULDBLOCK
#else
status == EINPROGRESS
@@ -968,7 +1184,7 @@ openvpn_connect (socket_descriptor_t sd,
{
if (--connect_timeout < 0)
{
-#ifdef WIN32
+#ifdef _WIN32
status = WSAETIMEDOUT;
#else
status = ETIMEDOUT;
@@ -995,7 +1211,7 @@ openvpn_connect (socket_descriptor_t sd,
}
}
#else
- status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family));
+ status = connect (sd, remote, af_addr_size(remote->sa_family));
if (status)
status = openvpn_errno ();
#endif
@@ -1003,85 +1219,72 @@ openvpn_connect (socket_descriptor_t sd,
return status;
}
+void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai)
+{
+ CLEAR (*actual);
+ ASSERT (ai);
+
+ if (ai->ai_family == AF_INET)
+ actual->dest.addr.in4 =
+ *((struct sockaddr_in*) ai->ai_addr);
+ else if (ai->ai_family == AF_INET6)
+ actual->dest.addr.in6 =
+ *((struct sockaddr_in6*) ai->ai_addr);
+ else
+ ASSERT(0);
+
+}
+
void
-socket_connect (socket_descriptor_t *sd,
- struct openvpn_sockaddr *local,
- bool bind_local,
- struct openvpn_sockaddr *remote,
- const bool connection_profiles_defined,
- const char *remote_dynamic,
- bool *remote_changed,
- const int connect_retry_seconds,
- const int connect_timeout,
- const int connect_retry_max,
- const unsigned int sockflags,
- volatile int *signal_received)
+socket_connect (socket_descriptor_t* sd,
+ const struct sockaddr* dest,
+ const int connect_timeout,
+ struct signal_info* sig_info)
{
struct gc_arena gc = gc_new ();
- int retry = 0;
+ int status;
#ifdef CONNECT_NONBLOCK
- msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]",
- print_sockaddr (remote, &gc));
+ msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]",
+ print_sockaddr (dest, &gc));
#else
- msg (M_INFO, "Attempting to establish TCP connection with %s",
- print_sockaddr (remote, &gc));
+ msg (M_INFO, "Attempting to establish TCP connection with %s",
+ print_sockaddr (dest, &gc));
#endif
- while (true)
- {
- int status;
-
#ifdef ENABLE_MANAGEMENT
- if (management)
+ if (management)
management_set_state (management,
OPENVPN_STATE_TCP_CONNECT,
NULL,
- (in_addr_t)0,
- (in_addr_t)0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
#endif
- status = openvpn_connect (*sd, remote, connect_timeout, signal_received);
+ /* Set the actual address */
+ status = openvpn_connect (*sd, dest, connect_timeout, &sig_info->signal_received);
- get_signal (signal_received);
- if (*signal_received)
+ get_signal (&sig_info->signal_received);
+ if (sig_info->signal_received)
goto done;
- if (!status)
- break;
+ if (status) {
- msg (D_LINK_ERRORS,
- "TCP: connect to %s failed, will try again in %d seconds: %s",
- print_sockaddr (remote, &gc),
- connect_retry_seconds,
- strerror_ts (status, &gc));
+ msg (D_LINK_ERRORS,
+ "TCP: connect to %s failed: %s",
+ print_sockaddr (dest, &gc),
+ strerror_ts (status, &gc));
- gc_reset (&gc);
-
- openvpn_close_socket (*sd);
- *sd = SOCKET_UNDEFINED;
-
- if ((connect_retry_max > 0 && ++retry >= connect_retry_max) || connection_profiles_defined)
- {
- *signal_received = SIGUSR1;
- goto done;
- }
-
- openvpn_sleep (connect_retry_seconds);
-
- get_signal (signal_received);
- if (*signal_received)
- goto done;
-
- *sd = create_socket_tcp (local->addr.sa.sa_family);
-
- if (bind_local)
- socket_bind (*sd, local, "TCP Client");
- update_remote (remote_dynamic, remote, remote_changed, sockflags);
- }
-
- msg (M_INFO, "TCP connection established with %s",
- print_sockaddr (remote, &gc));
+ openvpn_close_socket (*sd);
+ *sd = SOCKET_UNDEFINED;
+ sig_info->signal_received = SIGUSR1;
+ sig_info->source = SIG_SOURCE_CONNECTION_FAILED;
+ } else {
+ msg (M_INFO, "TCP connection established with %s",
+ print_sockaddr (dest, &gc));
+ }
done:
gc_free (&gc);
@@ -1093,7 +1296,7 @@ socket_connect (socket_descriptor_t *sd,
static void
socket_frame_init (const struct frame *frame, struct link_socket *sock)
{
-#ifdef WIN32
+#ifdef _WIN32
overlapped_io_init (&sock->reads, frame, FALSE, false);
overlapped_io_init (&sock->writes, frame, TRUE, false);
sock->rw_handle.read = sock->reads.overlapped.hEvent;
@@ -1102,7 +1305,7 @@ socket_frame_init (const struct frame *frame, struct link_socket *sock)
if (link_socket_connection_oriented (sock))
{
-#ifdef WIN32
+#ifdef _WIN32
stream_buf_init (&sock->stream_buf,
&sock->reads.buf_init,
sock->sockflags,
@@ -1132,70 +1335,39 @@ frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto)
}
static void
-resolve_bind_local (struct link_socket *sock)
+resolve_bind_local (struct link_socket *sock, const sa_family_t af)
{
struct gc_arena gc = gc_new ();
/* resolve local address if undefined */
- if (!addr_defined (&sock->info.lsa->local))
- {
- /* may return AF_{INET|INET6} guessed from local_host */
- switch(addr_guess_family(sock->info.proto, sock->local_host))
- {
- case AF_INET:
- sock->info.lsa->local.addr.in4.sin_family = AF_INET;
- sock->info.lsa->local.addr.in4.sin_addr.s_addr =
- (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
- sock->local_host,
- 0,
- NULL,
- NULL)
- : htonl (INADDR_ANY));
- sock->info.lsa->local.addr.in4.sin_port = htons (sock->local_port);
- break;
- case AF_INET6:
- {
- int status;
- CLEAR(sock->info.lsa->local.addr.in6);
- if (sock->local_host)
- {
- struct addrinfo *ai;
-
- status = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
- sock->local_host, 0, NULL, AF_INET6, &ai);
- if(status ==0) {
- sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr));
- freeaddrinfo(ai);
- }
- }
- else
- {
- sock->info.lsa->local.addr.in6.sin6_family = AF_INET6;
- sock->info.lsa->local.addr.in6.sin6_addr = in6addr_any;
- status = 0;
- }
- if (!status == 0)
- {
- msg (M_FATAL, "getaddr6() failed for local \"%s\": %s",
- sock->local_host,
- gai_strerror(status));
- }
- sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port);
- }
- break;
- }
- }
-
- /* bind to local address/port */
- if (sock->bind_local)
+ if (!sock->info.lsa->bind_local)
{
-#ifdef ENABLE_SOCKS
- if (sock->socks_proxy && sock->info.proto == PROTO_UDPv4)
- socket_bind (sock->ctrl_sd, &sock->info.lsa->local, "SOCKS");
- else
-#endif
- socket_bind (sock->sd, &sock->info.lsa->local, "TCP/UDP");
+ int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL |
+ GETADDR_FATAL | GETADDR_PASSIVE;
+ int status;
+
+ if(proto_is_dgram(sock->info.proto))
+ flags |= GETADDR_DATAGRAM;
+
+ /* will return AF_{INET|INET6}from local_host */
+ status = get_cached_dns_entry (sock->dns_cache,
+ sock->local_host,
+ sock->local_port,
+ af,
+ flags,
+ &sock->info.lsa->bind_local);
+
+ if (status)
+ status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
+ NULL, af, &sock->info.lsa->bind_local);
+
+ if(status !=0) {
+ msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s",
+ sock->local_host, sock->local_port,
+ gai_strerror(status));
+ }
}
+
gc_free (&gc);
}
@@ -1206,132 +1378,113 @@ resolve_remote (struct link_socket *sock,
volatile int *signal_received)
{
struct gc_arena gc = gc_new ();
- int af;
- if (!sock->did_resolve_remote)
+ /* resolve remote address if undefined */
+ if (!sock->info.lsa->remote_list)
{
- /* resolve remote address if undefined */
- if (!addr_defined (&sock->info.lsa->remote))
+ if (sock->remote_host)
{
- af = addr_guess_family(sock->info.proto, sock->remote_host);
- switch(af)
- {
- case AF_INET:
- sock->info.lsa->remote.addr.in4.sin_family = AF_INET;
- sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0;
- break;
- case AF_INET6:
- CLEAR(sock->info.lsa->remote.addr.in6);
- sock->info.lsa->remote.addr.in6.sin6_family = AF_INET6;
- sock->info.lsa->remote.addr.in6.sin6_addr = in6addr_any;
- break;
- }
-
- if (sock->remote_host)
+ unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
+ int retry = 0;
+ int status = -1;
+ struct addrinfo* ai;
+ if (proto_is_dgram(sock->info.proto))
+ flags |= GETADDR_DATAGRAM;
+
+ if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
{
- unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
- int retry = 0;
- int status = -1;
- struct addrinfo* ai;
-
- if (sock->connection_profiles_defined && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
+ if (phase == 2)
+ flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
+ retry = 0;
+ }
+ else if (phase == 1)
+ {
+ if (sock->resolve_retry_seconds)
{
- if (phase == 2)
- flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
retry = 0;
}
- else if (phase == 1)
+ else
{
- if (sock->resolve_retry_seconds)
- {
- retry = 0;
- }
- else
- {
- flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
- retry = 0;
- }
+ flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
+ retry = 0;
}
- else if (phase == 2)
+ }
+ else if (phase == 2)
+ {
+ if (sock->resolve_retry_seconds)
{
- if (sock->resolve_retry_seconds)
- {
- flags |= GETADDR_FATAL;
- retry = sock->resolve_retry_seconds;
- }
- else
- {
- ASSERT (0);
- }
+ flags |= GETADDR_FATAL;
+ retry = sock->resolve_retry_seconds;
}
else
{
ASSERT (0);
}
+ }
+ else
+ {
+ ASSERT (0);
+ }
- /* Temporary fix, this need to be changed for dual stack */
- status = openvpn_getaddrinfo(flags, sock->remote_host, retry,
- signal_received, af, &ai);
- if(status == 0)
- {
- if ( ai->ai_family == AF_INET6 )
- sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr));
- else
- sock->info.lsa->remote.addr.in4 = *((struct sockaddr_in*)(ai->ai_addr));
- freeaddrinfo(ai);
-
- dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
- flags,
- phase,
- retry,
- signal_received ? *signal_received : -1,
- status);
- }
- if (signal_received)
- {
- if (*signal_received)
- goto done;
- }
+
+ status = get_cached_dns_entry (sock->dns_cache,
+ sock->remote_host,
+ sock->remote_port,
+ sock->info.af,
+ flags, &ai);
+ if (status)
+ status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
+ retry, signal_received, sock->info.af, &ai);
+
+ if(status == 0) {
+ sock->info.lsa->remote_list = ai;
+ sock->info.lsa->current_remote = ai;
+
+ dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
+ flags,
+ phase,
+ retry,
+ signal_received ? *signal_received : -1,
+ status);
+ }
+ if (signal_received)
+ {
+ if (*signal_received)
+ goto done;
+ }
if (status!=0)
{
if (signal_received)
*signal_received = SIGUSR1;
goto done;
}
- }
- switch(af)
- {
- case AF_INET:
- sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port);
- break;
- case AF_INET6:
- sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port);
- break;
- }
}
+ }
- /* should we re-use previous active remote address? */
- if (link_socket_actual_defined (&sock->info.lsa->actual))
- {
- msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
- print_link_socket_actual (&sock->info.lsa->actual, &gc));
- if (remote_dynamic)
- *remote_dynamic = NULL;
- }
- else
+ /* should we re-use previous active remote address? */
+ if (link_socket_actual_defined (&sock->info.lsa->actual))
+ {
+ msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
+ print_link_socket_actual (&sock->info.lsa->actual, &gc));
+ if (remote_dynamic)
+ *remote_dynamic = NULL;
+ }
+ else
+ {
+ CLEAR (sock->info.lsa->actual);
+ if(sock->info.lsa->current_remote)
{
- CLEAR (sock->info.lsa->actual);
- sock->info.lsa->actual.dest = sock->info.lsa->remote;
+ set_actual_address (&sock->info.lsa->actual,
+ sock->info.lsa->current_remote);
}
-
- /* remember that we finished */
- sock->did_resolve_remote = true;
}
done:
gc_free (&gc);
}
+
+
struct link_socket *
link_socket_new (void)
{
@@ -1339,29 +1492,24 @@ link_socket_new (void)
ALLOC_OBJ_CLEAR (sock, struct link_socket);
sock->sd = SOCKET_UNDEFINED;
-#ifdef ENABLE_SOCKS
sock->ctrl_sd = SOCKET_UNDEFINED;
-#endif
return sock;
}
-/* bind socket if necessary */
void
link_socket_init_phase1 (struct link_socket *sock,
- const bool connection_profiles_defined,
const char *local_host,
- int local_port,
+ const char *local_port,
const char *remote_host,
- int remote_port,
+ const char *remote_port,
+ struct cached_dns_entry *dns_cache,
int proto,
+ sa_family_t af,
+ bool bind_ipv6_only,
int mode,
const struct link_socket *accept_from,
-#ifdef ENABLE_HTTP_PROXY
struct http_proxy_info *http_proxy,
-#endif
-#ifdef ENABLE_SOCKS
struct socks_proxy_info *socks_proxy,
-#endif
#ifdef ENABLE_DEBUG
int gremlin,
#endif
@@ -1372,38 +1520,25 @@ link_socket_init_phase1 (struct link_socket *sock,
const char *ipchange_command,
const struct plugin_list *plugins,
int resolve_retry_seconds,
- int connect_retry_seconds,
- int connect_timeout,
- int connect_retry_max,
int mtu_discover_type,
int rcvbuf,
int sndbuf,
int mark,
+ struct event_timeout* server_poll_timeout,
unsigned int sockflags)
{
ASSERT (sock);
- sock->connection_profiles_defined = connection_profiles_defined;
-
sock->local_host = local_host;
sock->local_port = local_port;
sock->remote_host = remote_host;
sock->remote_port = remote_port;
-
-#ifdef ENABLE_HTTP_PROXY
+ sock->dns_cache = dns_cache;
sock->http_proxy = http_proxy;
-#endif
-
-#ifdef ENABLE_SOCKS
sock->socks_proxy = socks_proxy;
-#endif
-
sock->bind_local = bind_local;
sock->inetd = inetd;
sock->resolve_retry_seconds = resolve_retry_seconds;
- sock->connect_retry_seconds = connect_retry_seconds;
- sock->connect_timeout = connect_timeout;
- sock->connect_retry_max = connect_retry_max;
sock->mtu_discover_type = mtu_discover_type;
#ifdef ENABLE_DEBUG
@@ -1414,31 +1549,30 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->socket_buffer_sizes.sndbuf = sndbuf;
sock->sockflags = sockflags;
+ sock->mark = mark;
sock->info.proto = proto;
+ sock->info.af = af;
sock->info.remote_float = remote_float;
sock->info.lsa = lsa;
+ sock->info.bind_ipv6_only = bind_ipv6_only;
sock->info.ipchange_command = ipchange_command;
sock->info.plugins = plugins;
+ sock->server_poll_timeout = server_poll_timeout;
sock->mode = mode;
if (mode == LS_MODE_TCP_ACCEPT_FROM)
{
ASSERT (accept_from);
- ASSERT (sock->info.proto == PROTO_TCPv4_SERVER
- || sock->info.proto == PROTO_TCPv6_SERVER
- );
+ ASSERT (sock->info.proto == PROTO_TCP_SERVER);
ASSERT (!sock->inetd);
sock->sd = accept_from->sd;
}
- if (false)
- ;
-#ifdef ENABLE_HTTP_PROXY
/* are we running in HTTP proxy mode? */
- else if (sock->http_proxy)
+ if (sock->http_proxy)
{
- ASSERT (sock->info.proto == PROTO_TCPv4_CLIENT);
+ ASSERT (sock->info.proto == PROTO_TCP_CLIENT);
ASSERT (!sock->inetd);
/* the proxy server */
@@ -1449,12 +1583,9 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->proxy_dest_host = remote_host;
sock->proxy_dest_port = remote_port;
}
-#endif
-#ifdef ENABLE_SOCKS
/* or in Socks proxy mode? */
else if (sock->socks_proxy)
{
- ASSERT (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_UDPv4);
ASSERT (!sock->inetd);
/* the proxy server */
@@ -1465,7 +1596,6 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->proxy_dest_host = remote_host;
sock->proxy_dest_port = remote_port;
}
-#endif
else
{
sock->remote_host = remote_host;
@@ -1473,7 +1603,7 @@ link_socket_init_phase1 (struct link_socket *sock,
}
/* bind behavior for TCP server vs. client */
- if (sock->info.proto == PROTO_TCPv4_SERVER)
+ if (sock->info.proto == PROTO_TCP_SERVER)
{
if (sock->mode == LS_MODE_TCP_ACCEPT_FROM)
sock->bind_local = false;
@@ -1484,43 +1614,255 @@ link_socket_init_phase1 (struct link_socket *sock,
/* were we started by inetd or xinetd? */
if (sock->inetd)
{
- ASSERT (sock->info.proto != PROTO_TCPv4_CLIENT
- && sock->info.proto != PROTO_TCPv6_CLIENT);
+ ASSERT (sock->info.proto != PROTO_TCP_CLIENT);
ASSERT (socket_defined (inetd_socket_descriptor));
sock->sd = inetd_socket_descriptor;
}
else if (mode != LS_MODE_TCP_ACCEPT_FROM)
{
- create_socket (sock);
+ if (sock->bind_local) {
+ resolve_bind_local (sock, sock->info.af);
+ }
+ resolve_remote (sock, 1, NULL, NULL);
+ }
+}
- /* set socket buffers based on --sndbuf and --rcvbuf options */
- socket_set_buffers (sock->sd, &sock->socket_buffer_sizes);
+static
+void phase2_inetd (struct link_socket* sock, const struct frame *frame,
+ const char *remote_dynamic, volatile int *signal_received)
+{
+ bool remote_changed = false;
- /* set socket to --mark packets with given value */
- socket_set_mark (sock->sd, mark);
+ if (sock->info.proto == PROTO_TCP_SERVER) {
+ /* AF_INET as default (and fallback) for inetd */
+ sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET;
+#ifdef HAVE_GETSOCKNAME
+ {
+ /* inetd: hint family type for dest = local's */
+ struct openvpn_sockaddr local_addr;
+ socklen_t addrlen = sizeof(local_addr);
+ if (getsockname (sock->sd, &local_addr.addr.sa, &addrlen) == 0) {
+ sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family;
+ dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)",
+ proto2ascii(sock->info.proto, sock->info.af, false),
+ local_addr.addr.sa.sa_family, sock->sd);
+ } else
+ msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
+ proto2ascii(sock->info.proto, sock->info.af, false), sock->sd);
+ }
+#else
+ msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() "
+ "function, using AF_INET",
+ proto2ascii(sock->info.proto, false));
+#endif
+ sock->sd =
+ socket_listen_accept (sock->sd,
+ &sock->info.lsa->actual,
+ remote_dynamic,
+ sock->info.lsa->bind_local,
+ false,
+ sock->inetd == INETD_NOWAIT,
+ signal_received);
- resolve_bind_local (sock);
- resolve_remote (sock, 1, NULL, NULL);
+ }
+ ASSERT (!remote_changed);
+}
+
+static void
+phase2_set_socket_flags (struct link_socket* sock)
+{
+ /* set misc socket parameters */
+ socket_set_flags (sock->sd, sock->sockflags);
+
+ /* set socket to non-blocking mode */
+ set_nonblock (sock->sd);
+
+ /* set socket file descriptor to not pass across execs, so that
+ scripts don't have access to it */
+ set_cloexec (sock->sd);
+
+ if (socket_defined (sock->ctrl_sd))
+ set_cloexec (sock->ctrl_sd);
+
+ /* set Path MTU discovery options on the socket */
+ set_mtu_discover_type (sock->sd, sock->mtu_discover_type, sock->info.af);
+
+#if EXTENDED_SOCKET_ERROR_CAPABILITY
+ /* if the OS supports it, enable extended error passing on the socket */
+ set_sock_extended_error_passing (sock->sd);
+#endif
+}
+
+
+static void
+linksock_print_addr (struct link_socket *sock)
+{
+ struct gc_arena gc = gc_new ();
+ const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
+
+ /* print local address */
+ if (sock->inetd)
+ msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true));
+ else if (sock->bind_local)
+ {
+ sa_family_t ai_family = sock->info.lsa->actual.dest.addr.sa.sa_family;
+ /* Socket is always bound on the first matching address,
+ * For bound sockets with no remote addr this is the element of
+ * the list */
+ struct addrinfo *cur;
+ for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
+ {
+ if(!ai_family || ai_family == cur->ai_family)
+ break;
+ }
+ ASSERT (cur);
+ msg (msglevel, "%s link local (bound): %s",
+ proto2ascii (sock->info.proto, sock->info.af, true),
+ print_sockaddr(cur->ai_addr,&gc));
}
+ else
+ msg (msglevel, "%s link local: (not bound)",
+ proto2ascii (sock->info.proto, sock->info.af, true));
+
+ /* print active remote address */
+ msg (msglevel, "%s link remote: %s",
+ proto2ascii (sock->info.proto, sock->info.af, true),
+ print_link_socket_actual_ex (&sock->info.lsa->actual,
+ ":",
+ PS_SHOW_PORT_IF_DEFINED,
+ &gc));
+ gc_free(&gc);
+}
+
+static void
+phase2_tcp_server (struct link_socket *sock, const char *remote_dynamic,
+ volatile int *signal_received)
+{
+ switch (sock->mode)
+ {
+ case LS_MODE_DEFAULT:
+ sock->sd = socket_listen_accept (sock->sd,
+ &sock->info.lsa->actual,
+ remote_dynamic,
+ sock->info.lsa->bind_local,
+ true,
+ false,
+ signal_received);
+ break;
+ case LS_MODE_TCP_LISTEN:
+ socket_do_listen (sock->sd,
+ sock->info.lsa->bind_local,
+ true,
+ false);
+ break;
+ case LS_MODE_TCP_ACCEPT_FROM:
+ sock->sd = socket_do_accept (sock->sd,
+ &sock->info.lsa->actual,
+ false);
+ if (!socket_defined (sock->sd))
+ {
+ *signal_received = SIGTERM;
+ return;
+ }
+ tcp_connection_established (&sock->info.lsa->actual);
+ break;
+ default:
+ ASSERT (0);
+ }
+}
+
+
+static void
+phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info)
+{
+ bool proxy_retry = false;
+ do {
+ socket_connect (&sock->sd,
+ sock->info.lsa->current_remote->ai_addr,
+ get_server_poll_remaining_time (sock->server_poll_timeout),
+ sig_info);
+
+ if (sig_info->signal_received)
+ return;
+
+ if (sock->http_proxy)
+ {
+ proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
+ sock->sd,
+ sock->proxy_dest_host,
+ sock->proxy_dest_port,
+ sock->server_poll_timeout,
+ &sock->stream_buf.residual,
+ &sig_info->signal_received);
+ }
+ else if (sock->socks_proxy)
+ {
+ establish_socks_proxy_passthru (sock->socks_proxy,
+ sock->sd,
+ sock->proxy_dest_host,
+ sock->proxy_dest_port,
+ &sig_info->signal_received);
+ }
+ if (proxy_retry)
+ {
+ openvpn_close_socket (sock->sd);
+ sock->sd = create_socket_tcp (sock->info.lsa->current_remote);
+ }
+
+ } while (proxy_retry);
+
+}
+
+static void
+phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info)
+{
+ socket_connect (&sock->ctrl_sd,
+ sock->info.lsa->current_remote->ai_addr,
+ get_server_poll_remaining_time (sock->server_poll_timeout),
+ sig_info);
+
+ if (sig_info->signal_received)
+ return;
+
+ establish_socks_proxy_udpassoc (sock->socks_proxy,
+ sock->ctrl_sd,
+ sock->sd,
+ &sock->socks_relay.dest,
+ &sig_info->signal_received);
+
+ if (sig_info->signal_received)
+ return;
+
+ sock->remote_host = sock->proxy_dest_host;
+ sock->remote_port = sock->proxy_dest_port;
+
+ addr_zero_host(&sock->info.lsa->actual.dest);
+ if (sock->info.lsa->remote_list)
+ {
+ freeaddrinfo(sock->info.lsa->remote_list);
+ sock->info.lsa->current_remote = NULL;
+ sock->info.lsa->remote_list = NULL;
+ }
+
+ resolve_remote (sock, 1, NULL, &sig_info->signal_received);
}
/* finalize socket initialization */
void
link_socket_init_phase2 (struct link_socket *sock,
const struct frame *frame,
- volatile int *signal_received)
+ struct signal_info *sig_info)
{
- struct gc_arena gc = gc_new ();
const char *remote_dynamic = NULL;
- bool remote_changed = false;
int sig_save = 0;
ASSERT (sock);
+ ASSERT (sig_info);
- if (signal_received && *signal_received)
+ if (sig_info->signal_received)
{
- sig_save = *signal_received;
- *signal_received = 0;
+ sig_save = sig_info->signal_received;
+ sig_info->signal_received = 0;
}
/* initialize buffers */
@@ -1537,246 +1879,83 @@ link_socket_init_phase2 (struct link_socket *sock,
/* were we started by inetd or xinetd? */
if (sock->inetd)
{
- if (sock->info.proto == PROTO_TCPv4_SERVER
- || sock->info.proto == PROTO_TCPv6_SERVER) {
- /* AF_INET as default (and fallback) for inetd */
- sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET;
-#ifdef HAVE_GETSOCKNAME
- {
- /* inetd: hint family type for dest = local's */
- struct openvpn_sockaddr local_addr;
- socklen_t addrlen = sizeof(local_addr);
- if (getsockname (sock->sd, (struct sockaddr *)&local_addr, &addrlen) == 0) {
- sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family;
- dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)",
- proto2ascii(sock->info.proto, false), local_addr.addr.sa.sa_family,
- sock->sd);
- } else
- msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
- proto2ascii(sock->info.proto, false), sock->sd);
- }
-#else
- msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() "
- "function, using AF_INET",
- proto2ascii(sock->info.proto, false));
-#endif
- sock->sd =
- socket_listen_accept (sock->sd,
- &sock->info.lsa->actual,
- remote_dynamic,
- &remote_changed,
- &sock->info.lsa->local,
- false,
- sock->inetd == INETD_NOWAIT,
- signal_received);
- }
- ASSERT (!remote_changed);
- if (*signal_received)
+ phase2_inetd (sock, frame, remote_dynamic, &sig_info->signal_received);
+ if (sig_info->signal_received)
goto done;
+
}
else
{
- resolve_remote (sock, 2, &remote_dynamic, signal_received);
+ /* Second chance to resolv/create socket */
+ resolve_remote (sock, 2, &remote_dynamic, &sig_info->signal_received);
- if (*signal_received)
- goto done;
+ /* If a valid remote has been found, create the socket with its addrinfo */
+ if (sock->info.lsa->current_remote)
+ create_socket (sock, sock->info.lsa->current_remote);
- /* TCP client/server */
- if (sock->info.proto == PROTO_TCPv4_SERVER
- ||sock->info.proto == PROTO_TCPv6_SERVER)
+ /* If socket has not already been created create it now */
+ if (sock->sd == SOCKET_UNDEFINED)
{
- switch (sock->mode)
+ /* If we have no --remote and have still not figured out the
+ * protocol family to use we will use the first of the bind */
+
+ if (sock->bind_local && !sock->remote_host && sock->info.lsa->bind_local)
{
- case LS_MODE_DEFAULT:
- sock->sd = socket_listen_accept (sock->sd,
- &sock->info.lsa->actual,
- remote_dynamic,
- &remote_changed,
- &sock->info.lsa->local,
- true,
- false,
- signal_received);
- break;
- case LS_MODE_TCP_LISTEN:
- socket_do_listen (sock->sd,
- &sock->info.lsa->local,
- true,
- false);
- break;
- case LS_MODE_TCP_ACCEPT_FROM:
- sock->sd = socket_do_accept (sock->sd,
- &sock->info.lsa->actual,
- false);
- if (!socket_defined (sock->sd))
- {
- *signal_received = SIGTERM;
- goto done;
+ /* Warn if this is because neither v4 or v6 was specified
+ * and we should not connect a remote */
+ if (sock->info.af == AF_UNSPEC)
+ {
+ msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s",
+ addr_family_name(sock->info.lsa->bind_local->ai_family));
+ sock->info.af = sock->info.lsa->bind_local->ai_family;
}
- tcp_connection_established (&sock->info.lsa->actual);
- break;
- default:
- ASSERT (0);
+
+ create_socket (sock, sock->info.lsa->bind_local);
}
}
- else if (sock->info.proto == PROTO_TCPv4_CLIENT
- ||sock->info.proto == PROTO_TCPv6_CLIENT)
- {
-#ifdef GENERAL_PROXY_SUPPORT
- bool proxy_retry = false;
-#else
- const bool proxy_retry = false;
-#endif
- do {
- socket_connect (&sock->sd,
- &sock->info.lsa->local,
- sock->bind_local,
- &sock->info.lsa->actual.dest,
- sock->connection_profiles_defined,
- remote_dynamic,
- &remote_changed,
- sock->connect_retry_seconds,
- sock->connect_timeout,
- sock->connect_retry_max,
- sock->sockflags,
- signal_received);
-
- if (*signal_received)
- goto done;
-
- if (false)
- ;
-#ifdef ENABLE_HTTP_PROXY
- else if (sock->http_proxy)
- {
- proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
- sock->sd,
- sock->proxy_dest_host,
- sock->proxy_dest_port,
- &sock->stream_buf.residual,
- signal_received);
- }
-#endif
-#ifdef ENABLE_SOCKS
- else if (sock->socks_proxy)
- {
- establish_socks_proxy_passthru (sock->socks_proxy,
- sock->sd,
- sock->proxy_dest_host,
- sock->proxy_dest_port,
- signal_received);
- }
-#endif
- if (proxy_retry)
- {
- openvpn_close_socket (sock->sd);
- sock->sd = create_socket_tcp (AF_INET);
- }
- } while (proxy_retry);
- }
-#ifdef ENABLE_SOCKS
- else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy)
+ /* Socket still undefined, give a warning and abort connection */
+ if (sock->sd == SOCKET_UNDEFINED)
{
- socket_connect (&sock->ctrl_sd,
- &sock->info.lsa->local,
- sock->bind_local,
- &sock->info.lsa->actual.dest,
- sock->connection_profiles_defined,
- remote_dynamic,
- &remote_changed,
- sock->connect_retry_seconds,
- sock->connect_timeout,
- sock->connect_retry_max,
- sock->sockflags,
- signal_received);
-
- if (*signal_received)
- goto done;
-
- establish_socks_proxy_udpassoc (sock->socks_proxy,
- sock->ctrl_sd,
- sock->sd,
- &sock->socks_relay.dest,
- signal_received);
-
- if (*signal_received)
- goto done;
-
- sock->remote_host = sock->proxy_dest_host;
- sock->remote_port = sock->proxy_dest_port;
- sock->did_resolve_remote = false;
-
- addr_zero_host(&sock->info.lsa->actual.dest);
- addr_zero_host(&sock->info.lsa->remote);
-
- resolve_remote (sock, 1, NULL, signal_received);
-
- if (*signal_received)
- goto done;
+ msg (M_WARN, "Could not determine IPv4/IPv6 protocol");
+ sig_info->signal_received = SIGUSR1;
+ goto done;
}
-#endif
- if (*signal_received)
+ if (sig_info->signal_received)
goto done;
- if (remote_changed)
+ if (sock->info.proto == PROTO_TCP_SERVER)
{
- msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment");
- addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest);
+ phase2_tcp_server (sock, remote_dynamic,
+ &sig_info->signal_received);
}
- }
-
- /* set misc socket parameters */
- socket_set_flags (sock->sd, sock->sockflags);
-
- /* set socket to non-blocking mode */
- set_nonblock (sock->sd);
-
- /* set socket file descriptor to not pass across execs, so that
- scripts don't have access to it */
- set_cloexec (sock->sd);
-
-#ifdef ENABLE_SOCKS
- if (socket_defined (sock->ctrl_sd))
- set_cloexec (sock->ctrl_sd);
-#endif
-
- /* set Path MTU discovery options on the socket */
- set_mtu_discover_type (sock->sd, sock->mtu_discover_type);
+ else if (sock->info.proto == PROTO_TCP_CLIENT)
+ {
+ phase2_tcp_client (sock, sig_info);
-#if EXTENDED_SOCKET_ERROR_CAPABILITY
- /* if the OS supports it, enable extended error passing on the socket */
- set_sock_extended_error_passing (sock->sd);
+ }
+ else if (sock->info.proto == PROTO_UDP && sock->socks_proxy)
+ {
+ phase2_socks_client (sock, sig_info);
+ }
+#ifdef TARGET_ANDROID
+ if (sock->sd != -1)
+ protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa);
#endif
+ if (sig_info->signal_received)
+ goto done;
+ }
- /* print local address */
- {
- const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
-
- if (sock->inetd)
- msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, true));
- else
- msg (msglevel, "%s link local%s: %s",
- proto2ascii (sock->info.proto, true),
- (sock->bind_local ? " (bound)" : ""),
- print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc));
-
- /* print active remote address */
- msg (msglevel, "%s link remote: %s",
- proto2ascii (sock->info.proto, true),
- print_link_socket_actual_ex (&sock->info.lsa->actual,
- ":",
- PS_SHOW_PORT_IF_DEFINED,
- &gc));
- }
+ phase2_set_socket_flags(sock);
+ linksock_print_addr(sock);
done:
- if (sig_save && signal_received)
+ if (sig_save)
{
- if (!*signal_received)
- *signal_received = sig_save;
+ if (!sig_info->signal_received)
+ sig_info->signal_received = sig_save;
}
- gc_free (&gc);
}
void
@@ -1792,7 +1971,7 @@ link_socket_close (struct link_socket *sock)
if (socket_defined (sock->sd))
{
-#ifdef WIN32
+#ifdef _WIN32
close_net_event_win32 (&sock->listen_handle, sock->sd, 0);
#endif
if (!gremlin)
@@ -1802,7 +1981,7 @@ link_socket_close (struct link_socket *sock)
msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed");
}
sock->sd = SOCKET_UNDEFINED;
-#ifdef WIN32
+#ifdef _WIN32
if (!gremlin)
{
overlapped_io_close (&sock->reads);
@@ -1811,14 +1990,12 @@ link_socket_close (struct link_socket *sock)
#endif
}
-#ifdef ENABLE_SOCKS
if (socket_defined (sock->ctrl_sd))
{
if (openvpn_close_socket (sock->ctrl_sd))
msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed");
sock->ctrl_sd = SOCKET_UNDEFINED;
}
-#endif
stream_buf_close (&sock->stream_buf);
free_buf (&sock->stream_buf_data);
@@ -1844,17 +2021,15 @@ setenv_trusted (struct env_set *es, const struct link_socket_info *info)
static void
ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc)
{
- const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc);
- const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc);
+ const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc);
if (include_cmd)
- argv_printf (argv, "%sc %s %s",
- info->ipchange_command,
- ip,
- port);
+ {
+ argv_parse_cmd (argv, info->ipchange_command);
+ argv_printf_cat (argv, "%s", host);
+ }
else
- argv_printf (argv, "%s %s",
- ip,
- port);
+ argv_printf (argv, "%s", host);
+
}
void
@@ -1911,6 +2086,7 @@ link_socket_bad_incoming_addr (struct buffer *buf,
const struct link_socket_actual *from_addr)
{
struct gc_arena gc = gc_new ();
+ struct addrinfo* ai;
switch(from_addr->dest.addr.sa.sa_family)
{
@@ -1920,7 +2096,12 @@ link_socket_bad_incoming_addr (struct buffer *buf,
"TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",
print_link_socket_actual (from_addr, &gc),
(int)from_addr->dest.addr.sa.sa_family,
- print_sockaddr (&info->lsa->remote, &gc));
+ print_sockaddr_ex (info->lsa->remote_list->ai_addr,":" ,PS_SHOW_PORT, &gc));
+ /* print additional remote addresses */
+ for(ai=info->lsa->remote_list->ai_next;ai;ai=ai->ai_next) {
+ msg(D_LINK_ERRORS,"or from peer address: %s",
+ print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc));
+ }
break;
}
buf->len = 0;
@@ -1945,18 +2126,43 @@ link_socket_current_remote (const struct link_socket_info *info)
* Maybe in the future consider PF_INET6 endpoints also ...
* by now just ignore it
*
+ * For --remote entries with multiple addresses this
+ * only return the actual endpoint we have sucessfully connected to
*/
if (lsa->actual.dest.addr.sa.sa_family != AF_INET)
return IPV4_INVALID_ADDR;
if (link_socket_actual_defined (&lsa->actual))
return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr);
- else if (addr_defined (&lsa->remote))
- return ntohl (lsa->remote.addr.in4.sin_addr.s_addr);
+ else if (lsa->current_remote)
+ return ntohl (((struct sockaddr_in*)lsa->current_remote->ai_addr)
+ ->sin_addr.s_addr);
else
return 0;
}
+const struct in6_addr *
+link_socket_current_remote_ipv6 (const struct link_socket_info *info)
+{
+ const struct link_socket_addr *lsa = info->lsa;
+
+/* This logic supports "redirect-gateway" semantic,
+ * for PF_INET6 routes over PF_INET6 endpoints
+ *
+ * For --remote entries with multiple addresses this
+ * only return the actual endpoint we have sucessfully connected to
+ */
+ if (lsa->actual.dest.addr.sa.sa_family != AF_INET6)
+ return NULL;
+
+ if (link_socket_actual_defined (&lsa->actual))
+ return &(lsa->actual.dest.addr.in6.sin6_addr);
+ else if (lsa->current_remote)
+ return &(((struct sockaddr_in6*)lsa->current_remote->ai_addr) ->sin6_addr);
+ else
+ return NULL;
+}
+
/*
* Return a status string describing socket state.
*/
@@ -1970,7 +2176,7 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena
{
buf_printf (&out, "S%s",
(s->rwflags_debug & EVENT_READ) ? "R" : "r");
-#ifdef WIN32
+#ifdef _WIN32
buf_printf (&out, "%s",
overlapped_io_state_ascii (&s->reads));
#endif
@@ -1979,7 +2185,7 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena
{
buf_printf (&out, "S%s",
(s->rwflags_debug & EVENT_WRITE) ? "W" : "w");
-#ifdef WIN32
+#ifdef _WIN32
buf_printf (&out, "%s",
overlapped_io_state_ascii (&s->writes));
#endif
@@ -2019,7 +2225,7 @@ stream_buf_init (struct stream_buf *sb,
sb->residual = alloc_buf (sb->maxlen);
sb->error = false;
#if PORT_SHARE
- sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCPv4_SERVER))
+ sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER))
? PS_ENABLED
: PS_DISABLED;
#endif
@@ -2154,7 +2360,7 @@ stream_buf_close (struct stream_buf* sb)
event_t
socket_listen_event_handle (struct link_socket *s)
{
-#ifdef WIN32
+#ifdef _WIN32
if (!defined_net_event_win32 (&s->listen_handle))
init_net_event_win32 (&s->listen_handle, FD_ACCEPT, s->sd, 0);
return &s->listen_handle;
@@ -2168,67 +2374,65 @@ socket_listen_event_handle (struct link_socket *s)
*/
const char *
-print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc)
-{
- return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc);
-}
-
-const char *
-print_sockaddr_ex (const struct openvpn_sockaddr *addr,
- const char* separator,
- const unsigned int flags,
- struct gc_arena *gc)
+print_sockaddr_ex (const struct sockaddr *sa,
+ const char* separator,
+ const unsigned int flags,
+ struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (128, gc);
- bool addr_is_defined;
- addr_is_defined = addr_defined (addr);
- if (!addr_is_defined) {
- return "[undef]";
- }
- switch(addr->addr.sa.sa_family)
+ bool addr_is_defined = false;
+ char hostaddr[NI_MAXHOST] = "";
+ char servname[NI_MAXSERV] = "";
+ int status;
+
+ socklen_t salen = 0;
+ switch(sa->sa_family)
{
case AF_INET:
- {
- const int port= ntohs (addr->addr.in4.sin_port);
- buf_puts (&out, "[AF_INET]");
-
- if (!(flags & PS_DONT_SHOW_ADDR))
- buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]"));
-
- if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
- && port)
- {
- if (separator)
- buf_printf (&out, "%s", separator);
-
- buf_printf (&out, "%d", port);
- }
- }
+ if (!(flags & PS_DONT_SHOW_FAMILY))
+ buf_puts (&out, "[AF_INET]");
+ salen = sizeof (struct sockaddr_in);
+ addr_is_defined = ((struct sockaddr_in*) sa)->sin_addr.s_addr != 0;
break;
case AF_INET6:
- {
- const int port= ntohs (addr->addr.in6.sin6_port);
- char buf[INET6_ADDRSTRLEN] = "";
- buf_puts (&out, "[AF_INET6]");
- if (addr_is_defined)
- {
- getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
- buf, sizeof (buf), NULL, 0, NI_NUMERICHOST);
- buf_puts (&out, buf);
- }
- if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED)))
- && port)
- {
- if (separator)
- buf_puts (&out, separator);
-
- buf_printf (&out, "%d", port);
- }
- }
+ if (!(flags & PS_DONT_SHOW_FAMILY))
+ buf_puts (&out, "[AF_INET6]");
+ salen = sizeof (struct sockaddr_in6);
+ addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*) sa)->sin6_addr);
break;
+ case AF_UNSPEC:
+ if (!(flags & PS_DONT_SHOW_FAMILY))
+ return "[AF_UNSPEC]";
+ else
+ return "";
default:
ASSERT(0);
}
+
+ status = getnameinfo(sa, salen, hostaddr, sizeof (hostaddr),
+ servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV);
+
+ if(status!=0) {
+ buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status));
+ return BSTR(&out);
+ }
+
+ if (!(flags & PS_DONT_SHOW_ADDR))
+ {
+ if (addr_is_defined)
+ buf_puts (&out, hostaddr);
+ else
+ buf_puts (&out, "[undef]");
+ }
+
+ if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED))
+ {
+ if (separator)
+ buf_puts (&out, separator);
+
+ buf_puts (&out, servname);
+ }
+
return BSTR (&out);
}
@@ -2252,7 +2456,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,
{
char ifname[IF_NAMESIZE] = "[undef]";
struct buffer out = alloc_buf_gc (128, gc);
- buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc));
+ buf_printf (&out, "%s", print_sockaddr_ex (&act->dest.addr.sa, separator, flags, gc));
#if ENABLE_IP_PKTINFO
if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
{
@@ -2263,7 +2467,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,
struct openvpn_sockaddr sa;
CLEAR (sa);
sa.addr.in4.sin_family = AF_INET;
-#ifdef IP_PKTINFO
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
if_indextoname(act->pi.in4.ipi_ifindex, ifname);
#elif defined(IP_RECVDSTADDR)
@@ -2273,7 +2477,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
#endif
buf_printf (&out, " (via %s%%%s)",
- print_sockaddr_ex (&sa, separator, 0, gc),
+ print_sockaddr_ex (&sa.addr.sa, separator, 0, gc),
ifname);
}
break;
@@ -2392,9 +2596,20 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openv
}
break;
case AF_INET6:
- openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix);
- getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
- buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+ if ( IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr ))
+ {
+ struct in_addr ia;
+ memcpy (&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12],
+ sizeof (ia.s_addr));
+ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix);
+ openvpn_snprintf (buf, sizeof(buf), "%s", inet_ntoa(ia) );
+ }
+ else
+ {
+ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix);
+ getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
+ buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+ }
setenv_str (es, name_buf, buf);
if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port)
@@ -2451,22 +2666,28 @@ setenv_link_socket_actual (struct env_set *es,
struct proto_names {
const char *short_form;
const char *display_form;
- bool is_dgram;
- bool is_net;
- unsigned short proto_af;
+ sa_family_t proto_af;
+ int proto;
};
/* Indexed by PROTO_x */
-static const struct proto_names proto_names[PROTO_N] = {
- {"proto-uninitialized", "proto-NONE",0,0, AF_UNSPEC},
- {"udp", "UDPv4",1,1, AF_INET},
- {"tcp-server", "TCPv4_SERVER",0,1, AF_INET},
- {"tcp-client", "TCPv4_CLIENT",0,1, AF_INET},
- {"tcp", "TCPv4",0,1, AF_INET},
- {"udp6" ,"UDPv6",1,1, AF_INET6},
- {"tcp6-server","TCPv6_SERVER",0,1, AF_INET6},
- {"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6},
- {"tcp6" ,"TCPv6",0,1, AF_INET6},
+static const struct proto_names proto_names[] = {
+ {"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE},
+ /* try IPv4 and IPv6 (client), bind dual-stack (server) */
+ {"udp", "UDP", AF_UNSPEC, PROTO_UDP},
+ {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER},
+ {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT},
+ {"tcp", "TCP", AF_UNSPEC, PROTO_TCP},
+ /* force IPv4 */
+ {"udp4", "UDPv4", AF_INET, PROTO_UDP},
+ {"tcp4-server","TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER},
+ {"tcp4-client","TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT},
+ {"tcp4", "TCPv4", AF_INET, PROTO_TCP},
+ /* force IPv6 */
+ {"udp6" ,"UDPv6", AF_INET6, PROTO_UDP},
+ {"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER},
+ {"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT},
+ {"tcp6" ,"TCPv6", AF_INET6, PROTO_TCP},
};
bool
@@ -2474,59 +2695,66 @@ proto_is_net(int proto)
{
if (proto < 0 || proto >= PROTO_N)
ASSERT(0);
- return proto_names[proto].is_net;
+ return proto != PROTO_NONE;
}
bool
proto_is_dgram(int proto)
{
- if (proto < 0 || proto >= PROTO_N)
- ASSERT(0);
- return proto_names[proto].is_dgram;
+ return proto_is_udp(proto);
}
+
bool
proto_is_udp(int proto)
{
if (proto < 0 || proto >= PROTO_N)
ASSERT(0);
- return proto_names[proto].is_dgram&&proto_names[proto].is_net;
+ return proto == PROTO_UDP;
}
+
bool
proto_is_tcp(int proto)
{
if (proto < 0 || proto >= PROTO_N)
ASSERT(0);
- return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net;
-}
-
-unsigned short
-proto_sa_family(int proto)
-{
- if (proto < 0 || proto >= PROTO_N)
- ASSERT(0);
- return proto_names[proto].proto_af;
+ return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER;
}
int
ascii2proto (const char* proto_name)
{
int i;
- ASSERT (PROTO_N == SIZE (proto_names));
- for (i = 0; i < PROTO_N; ++i)
+ for (i = 0; i < SIZE (proto_names); ++i)
if (!strcmp (proto_name, proto_names[i].short_form))
- return i;
+ return proto_names[i].proto;
return -1;
}
+sa_family_t
+ascii2af (const char* proto_name)
+{
+ int i;
+ for (i = 0; i < SIZE (proto_names); ++i)
+ if (!strcmp (proto_name, proto_names[i].short_form))
+ return proto_names[i].proto_af;
+ return 0;
+}
+
const char *
-proto2ascii (int proto, bool display_form)
+proto2ascii (int proto, sa_family_t af, bool display_form)
{
- ASSERT (PROTO_N == SIZE (proto_names));
- if (proto < 0 || proto >= PROTO_N)
- return "[unknown protocol]";
- else if (display_form)
- return proto_names[proto].display_form;
- else
- return proto_names[proto].short_form;
+ unsigned int i;
+ for (i = 0; i < SIZE (proto_names); ++i)
+ {
+ if(proto_names[i].proto_af == af && proto_names[i].proto == proto)
+ {
+ if(display_form)
+ return proto_names[i].display_form;
+ else
+ return proto_names[i].short_form;
+ }
+ }
+
+ return "[unknown protocol]";
}
const char *
@@ -2535,40 +2763,15 @@ proto2ascii_all (struct gc_arena *gc)
struct buffer out = alloc_buf_gc (256, gc);
int i;
- ASSERT (PROTO_N == SIZE (proto_names));
- for (i = 0; i < PROTO_N; ++i)
+ for (i = 0; i < SIZE (proto_names); ++i)
{
if (i)
buf_printf(&out, " ");
- buf_printf(&out, "[%s]", proto2ascii(i, false));
+ buf_printf(&out, "[%s]", proto_names[i].short_form);
}
return BSTR (&out);
}
-int
-addr_guess_family(int proto, const char *name)
-{
- unsigned short ret;
- if (proto)
- {
- return proto_sa_family(proto); /* already stamped */
- }
- else
- {
- struct addrinfo hints , *ai;
- int err;
- CLEAR(hints);
- hints.ai_flags = AI_NUMERICHOST;
- err = getaddrinfo(name, NULL, &hints, &ai);
- if ( 0 == err )
- {
- ret=ai->ai_family;
- freeaddrinfo(ai);
- return ret;
- }
- }
- return AF_INET; /* default */
-}
const char *
addr_family_name (int af)
{
@@ -2592,31 +2795,22 @@ addr_family_name (int af)
* has always sent UDPv4, TCPv4 over the wire. Keep these
* strings for backward compatbility
*/
-int
+const char*
proto_remote (int proto, bool remote)
{
ASSERT (proto >= 0 && proto < PROTO_N);
- if (remote)
- {
- switch (proto)
- {
- case PROTO_TCPv4_SERVER: return PROTO_TCPv4_CLIENT;
- case PROTO_TCPv4_CLIENT: return PROTO_TCPv4_SERVER;
- case PROTO_TCPv6_SERVER: return PROTO_TCPv4_CLIENT;
- case PROTO_TCPv6_CLIENT: return PROTO_TCPv4_SERVER;
- case PROTO_UDPv6: return PROTO_UDPv4;
- }
- }
- else
- {
- switch (proto)
- {
- case PROTO_TCPv6_SERVER: return PROTO_TCPv4_SERVER;
- case PROTO_TCPv6_CLIENT: return PROTO_TCPv4_CLIENT;
- case PROTO_UDPv6: return PROTO_UDPv4;
- }
- }
- return proto;
+ if (proto == PROTO_UDP)
+ return "UDPv4";
+
+ if ( (remote && proto == PROTO_TCP_CLIENT) ||
+ (!remote && proto == PROTO_TCP_SERVER))
+ return "TCPv4_SERVER";
+ if ( (remote && proto == PROTO_TCP_SERVER) ||
+ (!remote && proto == PROTO_TCP_CLIENT))
+ return "TCPv4_CLIENT";
+
+ ASSERT (0);
+ return ""; /* Make the compiler happy */
}
/*
@@ -2643,7 +2837,7 @@ link_socket_read_tcp (struct link_socket *sock,
if (!sock->stream_buf.residual_fully_formed)
{
-#ifdef WIN32
+#ifdef _WIN32
len = socket_finalize (sock->sd, &sock->reads, buf, NULL);
#else
struct buffer frag;
@@ -2668,51 +2862,39 @@ link_socket_read_tcp (struct link_socket *sock,
return buf->len = 0; /* no error, but packet is still incomplete */
}
-#ifndef WIN32
+#ifndef _WIN32
#if ENABLE_IP_PKTINFO
-#pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */
-struct openvpn_in4_pktinfo
-{
- struct cmsghdr cmsghdr;
-#ifdef HAVE_IN_PKTINFO
- struct in_pktinfo pi4;
-#elif defined(IP_RECVDSTADDR)
- struct in_addr pi4;
+/* make the buffer large enough to handle ancilliary socket data for
+ * both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292)
+ */
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \
+ CMSG_SPACE(sizeof (struct in_pktinfo)) )
+#else
+#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \
+ CMSG_SPACE(sizeof (struct in_addr)) )
#endif
-};
-struct openvpn_in6_pktinfo
-{
- struct cmsghdr cmsghdr;
- struct in6_pktinfo pi6;
-};
-
-union openvpn_pktinfo {
- struct openvpn_in4_pktinfo msgpi4;
- struct openvpn_in6_pktinfo msgpi6;
-};
-#pragma pack()
static socklen_t
link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
struct buffer *buf,
- int maxsize,
struct link_socket_actual *from)
{
struct iovec iov;
- union openvpn_pktinfo opi;
+ uint8_t pktinfo_buf[PKTINFO_BUF_SIZE];
struct msghdr mesg;
socklen_t fromlen = sizeof (from->dest.addr);
iov.iov_base = BPTR (buf);
- iov.iov_len = maxsize;
+ iov.iov_len = buf_forward_capacity_total (buf);
mesg.msg_iov = &iov;
mesg.msg_iovlen = 1;
mesg.msg_name = &from->dest.addr;
mesg.msg_namelen = fromlen;
- mesg.msg_control = &opi;
- mesg.msg_controllen = sizeof opi;
+ mesg.msg_control = pktinfo_buf;
+ mesg.msg_controllen = sizeof pktinfo_buf;
buf->len = recvmsg (sock->sd, &mesg, 0);
if (buf->len >= 0)
{
@@ -2721,18 +2903,19 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
cmsg = CMSG_FIRSTHDR (&mesg);
if (cmsg != NULL
&& CMSG_NXTHDR (&mesg, cmsg) == NULL
-#ifdef IP_PKTINFO
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
&& cmsg->cmsg_level == SOL_IP
&& cmsg->cmsg_type == IP_PKTINFO
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) )
#elif defined(IP_RECVDSTADDR)
&& cmsg->cmsg_level == IPPROTO_IP
&& cmsg->cmsg_type == IP_RECVDSTADDR
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) )
#else
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
#endif
- && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo))
{
-#ifdef IP_PKTINFO
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
from->pi.in4.ipi_ifindex = pkti->ipi_ifindex;
from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst;
@@ -2746,13 +2929,18 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
&& CMSG_NXTHDR (&mesg, cmsg) == NULL
&& cmsg->cmsg_level == IPPROTO_IPV6
&& cmsg->cmsg_type == IPV6_PKTINFO
- && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo))
+ && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in6_pktinfo)) )
{
struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex;
from->pi.in6.ipi6_addr = pkti6->ipi6_addr;
}
+ else if (cmsg != NULL)
+ {
+ msg(M_WARN, "CMSG received that cannot be parsed (cmsg_level=%d, cmsg_type=%d, cmsg=len=%d)", (int)cmsg->cmsg_level, (int)cmsg->cmsg_type, (int)cmsg->cmsg_len );
+ }
}
+
return fromlen;
}
#endif
@@ -2760,21 +2948,20 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
int
link_socket_read_udp_posix (struct link_socket *sock,
struct buffer *buf,
- int maxsize,
struct link_socket_actual *from)
{
socklen_t fromlen = sizeof (from->dest.addr);
- socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto));
+ socklen_t expectedlen = af_addr_size(sock->info.af);
addr_zero_host(&from->dest);
- ASSERT (buf_safe (buf, maxsize));
#if ENABLE_IP_PKTINFO
/* Both PROTO_UDPv4 and PROTO_UDPv6 */
- if (proto_is_udp(sock->info.proto) && sock->sockflags & SF_USE_IP_PKTINFO)
- fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from);
+ if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO)
+ fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, from);
else
#endif
- buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0,
+ buf->len = recvfrom (sock->sd, BPTR (buf), buf_forward_capacity(buf), 0,
&from->dest.addr.sa, &fromlen);
+ /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */
if (buf->len >= 0 && expectedlen && fromlen != expectedlen)
bad_address_length (fromlen, expectedlen);
return buf->len;
@@ -2796,7 +2983,7 @@ link_socket_write_tcp (struct link_socket *sock,
ASSERT (len <= sock->stream_buf.maxlen);
len = htonps (len);
ASSERT (buf_write_prepend (buf, &len, sizeof (len)));
-#ifdef WIN32
+#ifdef _WIN32
return link_socket_write_win32 (sock, buf, to);
#else
return link_socket_write_tcp_posix (sock, buf, to);
@@ -2805,7 +2992,7 @@ link_socket_write_tcp (struct link_socket *sock,
#if ENABLE_IP_PKTINFO
-int
+size_t
link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct buffer *buf,
struct link_socket_actual *to)
@@ -2813,24 +3000,24 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct iovec iov;
struct msghdr mesg;
struct cmsghdr *cmsg;
- union openvpn_pktinfo opi;
+ uint8_t pktinfo_buf[PKTINFO_BUF_SIZE];
iov.iov_base = BPTR (buf);
iov.iov_len = BLEN (buf);
mesg.msg_iov = &iov;
mesg.msg_iovlen = 1;
- switch (sock->info.lsa->remote.addr.sa.sa_family)
+ switch (to->dest.addr.sa.sa_family)
{
case AF_INET:
{
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in);
- mesg.msg_control = &opi;
+ mesg.msg_control = pktinfo_buf;
mesg.msg_flags = 0;
-#ifdef HAVE_IN_PKTINFO
- mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo);
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_pktinfo));
cmsg = CMSG_FIRSTHDR (&mesg);
- cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo);
+ cmsg->cmsg_len = CMSG_LEN(sizeof (struct in_pktinfo));
cmsg->cmsg_level = SOL_IP;
cmsg->cmsg_type = IP_PKTINFO;
{
@@ -2841,7 +3028,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
pkti->ipi_addr.s_addr = 0;
}
#elif defined(IP_RECVDSTADDR)
- ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(opi) );
+ ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(pktinfo_buf) );
mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr));
cmsg = CMSG_FIRSTHDR (&mesg);
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
@@ -2858,13 +3045,16 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct in6_pktinfo *pkti6;
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in6);
- mesg.msg_control = &opi;
- mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo);
+
+ ASSERT( CMSG_SPACE(sizeof (struct in6_pktinfo)) <= sizeof(pktinfo_buf) );
+ mesg.msg_control = pktinfo_buf;
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in6_pktinfo));
mesg.msg_flags = 0;
cmsg = CMSG_FIRSTHDR (&mesg);
- cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
+
pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex;
pkti6->ipi6_addr = to->pi.in6.ipi6_addr;
@@ -2881,7 +3071,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
* Win32 overlapped socket I/O functions.
*/
-#ifdef WIN32
+#ifdef _WIN32
int
socket_recv_queue (struct link_socket *sock, int maxsize)
@@ -2919,10 +3109,7 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
if (proto_is_udp(sock->info.proto))
{
sock->reads.addr_defined = true;
- if (sock->info.proto == PROTO_UDPv6)
- sock->reads.addrlen = sizeof (sock->reads.addr6);
- else
- sock->reads.addrlen = sizeof (sock->reads.addr);
+ sock->reads.addrlen = sizeof (sock->reads.addr6);
status = WSARecvFrom(
sock->sd,
wsabuf,
@@ -2954,9 +3141,10 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
if (!status) /* operation completed immediately? */
{
- int addrlen = af_addr_size(sock->info.lsa->local.addr.sa.sa_family);
- if (sock->reads.addr_defined && sock->reads.addrlen != addrlen)
- bad_address_length (sock->reads.addrlen, addrlen);
+ /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */
+ int af_len = af_addr_size (sock->info.af);
+ if (sock->reads.addr_defined && af_len && sock->reads.addrlen != af_len)
+ bad_address_length (sock->reads.addrlen, af_len);
sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
/* since we got an immediate return, we must signal the event object ourselves */
@@ -3018,7 +3206,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li
{
/* set destination address for UDP writes */
sock->writes.addr_defined = true;
- if (sock->info.proto == PROTO_UDPv6)
+ if (to->dest.addr.sa.sa_family == AF_INET6)
{
sock->writes.addr6 = to->dest.addr.in6;
sock->writes.addrlen = sizeof (sock->writes.addr6);
@@ -3191,7 +3379,7 @@ socket_finalize (SOCKET s,
case sizeof(struct sockaddr_in):
case sizeof(struct sockaddr_in6):
/* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6
- * under WIN32*/
+ * under _WIN32*/
case sizeof(struct sockaddr_in6)-4:
break;
default:
@@ -3217,7 +3405,7 @@ socket_finalize (SOCKET s,
return ret;
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
/*
* Socket event notification
@@ -3238,7 +3426,7 @@ socket_set (struct link_socket *s,
rwflags &= ~EVENT_READ;
}
-#ifdef WIN32
+#ifdef _WIN32
if (rwflags & EVENT_READ)
socket_recv_queue (s, 0);
#endif
diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h
index b7a4e01..2a82d88 100644
--- a/src/openvpn/socket.h
+++ b/src/openvpn/socket.h
@@ -39,7 +39,7 @@
/*
* OpenVPN's default port number as assigned by IANA.
*/
-#define OPENVPN_PORT 1194
+#define OPENVPN_PORT "1194"
/*
* Number of seconds that "resolv-retry infinite"
@@ -72,14 +72,25 @@ struct openvpn_sockaddr
} addr;
};
+/* struct to hold preresolved host names */
+struct cached_dns_entry {
+ const char *hostname;
+ const char *servname;
+ int ai_family;
+ int flags;
+ struct addrinfo *ai;
+ struct cached_dns_entry *next;
+};
+
/* actual address of remote, based on source address of received packets */
struct link_socket_actual
{
/*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */
+
struct openvpn_sockaddr dest;
#if ENABLE_IP_PKTINFO
union {
-#ifdef HAVE_IN_PKTINFO
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
struct in_pktinfo in4;
#elif defined(IP_RECVDSTADDR)
struct in_addr in4;
@@ -92,8 +103,10 @@ struct link_socket_actual
/* IP addresses which are persistant across SIGUSR1s */
struct link_socket_addr
{
- struct openvpn_sockaddr local;
- struct openvpn_sockaddr remote; /* initial remote */
+ struct addrinfo* bind_local;
+ struct addrinfo* remote_list; /* complete remote list */
+ struct addrinfo* current_remote; /* remote used in the
+ current connection attempt */
struct link_socket_actual actual; /* reply to this address */
};
@@ -105,6 +118,8 @@ struct link_socket_info
const struct plugin_list *plugins;
bool remote_float;
int proto; /* Protocol (PROTO_x defined below) */
+ sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/
+ bool bind_ipv6_only;
int mtu_changed; /* Set to true when mtu value is changed */
};
@@ -152,12 +167,9 @@ struct link_socket
struct link_socket_info info;
socket_descriptor_t sd;
-
-#ifdef ENABLE_SOCKS
socket_descriptor_t ctrl_sd; /* only used for UDP over Socks */
-#endif
-#ifdef WIN32
+#ifdef _WIN32
struct overlapped_io reads;
struct overlapped_io writes;
struct rw_handle rw_handle;
@@ -170,13 +182,11 @@ struct link_socket
/* used for long-term queueing of pre-accepted socket listen */
bool listen_persistent_queued;
- /* Does config file contain any <connection> ... </connection> blocks? */
- bool connection_profiles_defined;
-
const char *remote_host;
- int remote_port;
+ const char *remote_port;
const char *local_host;
- int local_port;
+ const char *local_port;
+ struct cached_dns_entry *dns_cache;
bool bind_local;
# define INETD_NONE 0
@@ -190,45 +200,39 @@ struct link_socket
int mode;
int resolve_retry_seconds;
- int connect_retry_seconds;
- int connect_timeout;
- int connect_retry_max;
int mtu_discover_type;
struct socket_buffer_size socket_buffer_sizes;
int mtu; /* OS discovered MTU, or 0 if unknown */
- bool did_resolve_remote;
-
# define SF_USE_IP_PKTINFO (1<<0)
# define SF_TCP_NODELAY (1<<1)
# define SF_PORT_SHARE (1<<2)
# define SF_HOST_RANDOMIZE (1<<3)
# define SF_GETADDRINFO_DGRAM (1<<4)
unsigned int sockflags;
+ int mark;
/* for stream sockets */
struct stream_buf stream_buf;
struct buffer stream_buf_data;
bool stream_reset;
-#ifdef ENABLE_HTTP_PROXY
/* HTTP proxy */
struct http_proxy_info *http_proxy;
-#endif
-#ifdef ENABLE_SOCKS
/* Socks proxy */
struct socks_proxy_info *socks_proxy;
struct link_socket_actual socks_relay; /* Socks UDP relay address */
-#endif
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS)
/* The OpenVPN server we will use the proxy to connect to */
const char *proxy_dest_host;
- int proxy_dest_port;
-#endif
+ const char *proxy_dest_port;
+
+ /* Pointer to the server-poll to trigger the timeout in function which have
+ * their own loop instead of using the main oop */
+ struct event_timeout* server_poll_timeout;
#if PASSTOS_CAPABILITY
/* used to get/set TOS. */
@@ -253,7 +257,7 @@ struct link_socket
#define MSG_NOSIGNAL 0
#endif
-#ifdef WIN32
+#ifdef _WIN32
#define openvpn_close_socket(s) closesocket(s)
@@ -278,34 +282,36 @@ int socket_finalize (
struct link_socket *link_socket_new (void);
void socket_bind (socket_descriptor_t sd,
- struct openvpn_sockaddr *local,
- const char *prefix);
+ struct addrinfo *local,
+ int af_family,
+ const char *prefix,
+ bool ipv6only);
int openvpn_connect (socket_descriptor_t sd,
- struct openvpn_sockaddr *remote,
+ const struct sockaddr *remote,
int connect_timeout,
volatile int *signal_received);
+
+
/*
* Initialize link_socket object.
*/
void
link_socket_init_phase1 (struct link_socket *sock,
- const bool connection_profiles_defined,
const char *local_host,
- int local_port,
+ const char *local_port,
const char *remote_host,
- int remote_port,
+ const char *remote_port,
+ struct cached_dns_entry *dns_cache,
int proto,
+ sa_family_t af,
+ bool bind_ipv6_only,
int mode,
const struct link_socket *accept_from,
-#ifdef ENABLE_HTTP_PROXY
struct http_proxy_info *http_proxy,
-#endif
-#ifdef ENABLE_SOCKS
struct socks_proxy_info *socks_proxy,
-#endif
#ifdef ENABLE_DEBUG
int gremlin,
#endif
@@ -316,18 +322,18 @@ link_socket_init_phase1 (struct link_socket *sock,
const char *ipchange_command,
const struct plugin_list *plugins,
int resolve_retry_seconds,
- int connect_retry_seconds,
- int connect_timeout,
- int connect_retry_max,
int mtu_discover_type,
int rcvbuf,
int sndbuf,
int mark,
+ struct event_timeout* server_poll_timeout,
unsigned int sockflags);
void link_socket_init_phase2 (struct link_socket *sock,
const struct frame *frame,
- volatile int *signal_received);
+ struct signal_info *sig_info);
+
+void do_preresolve(struct context *c);
void socket_adjust_frame_parameters (struct frame *frame, int proto);
@@ -341,15 +347,37 @@ void sd_close (socket_descriptor_t *sd);
#define PS_SHOW_PORT (1<<1)
#define PS_SHOW_PKTINFO (1<<2)
#define PS_DONT_SHOW_ADDR (1<<3)
+#define PS_DONT_SHOW_FAMILY (1<<4)
-const char *print_sockaddr_ex (const struct openvpn_sockaddr *addr,
+const char *print_sockaddr_ex (const struct sockaddr *addr,
const char* separator,
const unsigned int flags,
struct gc_arena *gc);
+static inline
+const char *print_openvpn_sockaddr_ex (const struct openvpn_sockaddr *addr,
+ const char* separator,
+ const unsigned int flags,
+ struct gc_arena *gc)
+{
+ return print_sockaddr_ex(&addr->addr.sa, separator, flags, gc);
+}
+
+static inline
+const char *print_openvpn_sockaddr (const struct openvpn_sockaddr *addr,
+ struct gc_arena *gc)
+{
+ return print_sockaddr_ex (&addr->addr.sa, ":", PS_SHOW_PORT, gc);
+}
+
+static inline
+const char *print_sockaddr (const struct sockaddr *addr,
+ struct gc_arena *gc)
+{
+ return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc);
+}
+
-const char *print_sockaddr (const struct openvpn_sockaddr *addr,
- struct gc_arena *gc);
const char *print_link_socket_actual_ex (const struct link_socket_actual *act,
const char* separator,
@@ -395,6 +423,8 @@ void bad_address_length (int actual, int expected);
*/
#define IPV4_INVALID_ADDR 0xffffffff
in_addr_t link_socket_current_remote (const struct link_socket_info *info);
+const struct in6_addr * link_socket_current_remote_ipv6
+ (const struct link_socket_info *info);
void link_socket_connection_initiated (const struct buffer *buf,
struct link_socket_info *info,
@@ -406,6 +436,9 @@ void link_socket_bad_incoming_addr (struct buffer *buf,
const struct link_socket_info *info,
const struct link_socket_actual *from_addr);
+void set_actual_address (struct link_socket_actual* actual,
+ struct addrinfo* ai);
+
void link_socket_bad_outgoing_addr (void);
void setenv_trusted (struct env_set *es, const struct link_socket_info *info);
@@ -429,7 +462,7 @@ bool ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn);
bool mac_addr_safe (const char *mac_addr);
bool ipv6_addr_safe (const char *ipv6_text_addr);
-socket_descriptor_t create_socket_tcp (int af);
+socket_descriptor_t create_socket_tcp (struct addrinfo*);
socket_descriptor_t socket_do_accept (socket_descriptor_t sd,
struct link_socket_actual *act,
@@ -481,6 +514,10 @@ bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *
#define GETADDR_TRY_ONCE (1<<7)
#define GETADDR_UPDATE_MANAGEMENT_STATE (1<<8)
#define GETADDR_RANDOMIZE (1<<9)
+#define GETADDR_PASSIVE (1<<10)
+#define GETADDR_DATAGRAM (1<<11)
+
+#define GETADDR_CACHE_MASK (GETADDR_DATAGRAM|GETADDR_PASSIVE)
in_addr_t getaddr (unsigned int flags,
const char *hostname,
@@ -490,6 +527,7 @@ in_addr_t getaddr (unsigned int flags,
int openvpn_getaddrinfo (unsigned int flags,
const char *hostname,
+ const char *servname,
int resolve_retry_seconds,
volatile int *signal_received,
int ai_family,
@@ -505,21 +543,18 @@ int openvpn_getaddrinfo (unsigned int flags,
*/
enum proto_num {
PROTO_NONE, /* catch for uninitialized */
- PROTO_UDPv4,
- PROTO_TCPv4_SERVER,
- PROTO_TCPv4_CLIENT,
- PROTO_TCPv4,
- PROTO_UDPv6,
- PROTO_TCPv6_SERVER,
- PROTO_TCPv6_CLIENT,
- PROTO_TCPv6,
+ PROTO_UDP,
+ PROTO_TCP,
+ PROTO_TCP_SERVER,
+ PROTO_TCP_CLIENT,
PROTO_N
};
int ascii2proto (const char* proto_name);
-const char *proto2ascii (int proto, bool display_form);
+sa_family_t ascii2af (const char* proto_name);
+const char *proto2ascii (int proto, sa_family_t af, bool display_form);
const char *proto2ascii_all (struct gc_arena *gc);
-int proto_remote (int proto, bool remote);
+const char *proto_remote (int proto, bool remote);
const char *addr_family_name(int af);
/*
@@ -544,12 +579,6 @@ datagram_overhead (int proto)
*/
static inline bool
-legal_ipv4_port (int port)
-{
- return port > 0 && port < 65536;
-}
-
-static inline bool
link_socket_proto_connection_oriented (int proto)
{
return !proto_is_dgram(proto);
@@ -574,13 +603,30 @@ addr_defined (const struct openvpn_sockaddr *addr)
default: return 0;
}
}
+
+static inline bool
+addr_local (const struct sockaddr *addr)
+{
+ if (!addr)
+ return false;
+ switch (addr->sa_family) {
+ case AF_INET:
+ return ((const struct sockaddr_in*)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
+ case AF_INET6:
+ return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6*)addr)->sin6_addr);
+ default:
+ return false;
+ }
+}
+
+
static inline bool
addr_defined_ipi (const struct link_socket_actual *lsa)
{
#if ENABLE_IP_PKTINFO
if (!lsa) return 0;
switch (lsa->dest.addr.sa.sa_family) {
-#ifdef HAVE_IN_PKTINFO
+#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST)
case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0;
#elif defined(IP_RECVDSTADDR)
case AF_INET: return lsa->pi.in4.s_addr != 0;
@@ -613,6 +659,29 @@ addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2
return false;
}
+static inline bool
+addrlist_match (const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist)
+{
+ const struct addrinfo *curele;
+ for (curele = addrlist; curele; curele=curele->ai_next)
+ {
+ switch(a1->addr.sa.sa_family)
+ {
+ case AF_INET:
+ if (a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr)
+ return true;
+ break;
+ case AF_INET6:
+ if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr))
+ return true;
+ break;
+ default:
+ ASSERT(0);
+ }
+ }
+ return false;
+}
+
static inline in_addr_t
addr_host (const struct openvpn_sockaddr *addr)
{
@@ -626,6 +695,36 @@ addr_host (const struct openvpn_sockaddr *addr)
return ntohl (addr->addr.in4.sin_addr.s_addr);
}
+
+static inline bool
+addrlist_port_match (const struct openvpn_sockaddr *a1, const struct addrinfo *a2)
+{
+ const struct addrinfo *curele;
+ for(curele=a2;curele;curele = curele->ai_next)
+ {
+ switch(a1->addr.sa.sa_family)
+ {
+ case AF_INET:
+ if (curele->ai_family == AF_INET
+ && a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr
+ && a1->addr.in4.sin_port == ((struct sockaddr_in*)curele->ai_addr)->sin_port)
+ return true;
+ break;
+ case AF_INET6:
+ if (curele->ai_family == AF_INET6
+ && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr)
+ && a1->addr.in6.sin6_port == ((struct sockaddr_in6*) curele->ai_addr)->sin6_port)
+ return true;
+ break;
+ default:
+ ASSERT(0);
+ }
+ }
+ return false;
+}
+
+
+
static inline bool
addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
{
@@ -634,7 +733,7 @@ addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockadd
return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr
&& a1->addr.in4.sin_port == a2->addr.in4.sin_port;
case AF_INET6:
- return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr)
+ return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr)
&& a1->addr.in6.sin6_port == a2->addr.in6.sin6_port;
}
ASSERT(0);
@@ -651,6 +750,17 @@ addr_match_proto (const struct openvpn_sockaddr *a1,
: addr_port_match (a1, a2);
}
+
+static inline bool
+addrlist_match_proto (const struct openvpn_sockaddr *a1,
+ struct addrinfo *addr_list,
+ const int proto)
+{
+ return link_socket_proto_connection_oriented (proto)
+ ? addrlist_match (a1, addr_list)
+ : addrlist_port_match (a1, addr_list);
+}
+
static inline void
addr_zero_host(struct openvpn_sockaddr *addr)
{
@@ -670,28 +780,15 @@ addr_copy_sa(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src)
dst->addr = src->addr;
}
-static inline void
-addr_copy_host(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src)
-{
- switch(src->addr.sa.sa_family) {
- case AF_INET:
- dst->addr.in4.sin_addr.s_addr = src->addr.in4.sin_addr.s_addr;
- break;
- case AF_INET6:
- dst->addr.in6.sin6_addr = src->addr.in6.sin6_addr;
- break;
- }
-}
-
static inline bool
addr_inet4or6(struct sockaddr *addr)
{
return addr->sa_family == AF_INET || addr->sa_family == AF_INET6;
}
-int addr_guess_family(int proto, const char *name);
+int addr_guess_family(sa_family_t af,const char *name);
static inline int
-af_addr_size(unsigned short af)
+af_addr_size(sa_family_t af)
{
switch(af) {
case AF_INET: return sizeof (struct sockaddr_in);
@@ -745,7 +842,7 @@ socket_connection_reset (const struct link_socket *sock, int status)
else if (status < 0)
{
const int err = openvpn_errno ();
-#ifdef WIN32
+#ifdef _WIN32
return err == WSAECONNRESET || err == WSAECONNABORTED;
#else
return err == ECONNRESET;
@@ -767,9 +864,9 @@ link_socket_verify_incoming_addr (struct buffer *buf,
case AF_INET:
if (!link_socket_actual_defined (from_addr))
return false;
- if (info->remote_float || !addr_defined (&info->lsa->remote))
+ if (info->remote_float || (!info->lsa->remote_list))
return true;
- if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto))
+ if (addrlist_match_proto (&from_addr->dest, info->lsa->remote_list, info->proto))
return true;
}
}
@@ -806,13 +903,15 @@ link_socket_set_outgoing_addr (const struct buffer *buf,
{
struct link_socket_addr *lsa = info->lsa;
if (
- /* new or changed address? */
- (!info->connection_established
- || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto))
- /* address undef or address == remote or --float */
- && (info->remote_float
- || !addr_defined (&lsa->remote)
- || addr_match_proto (&act->dest, &lsa->remote, info->proto))
+ /* new or changed address? */
+ (!info->connection_established
+ || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto)
+ )
+ &&
+ /* address undef or address == remote or --float */
+ (info->remote_float ||
+ (!lsa->remote_list || addrlist_match_proto (&act->dest, lsa->remote_list, info->proto))
+ )
)
{
link_socket_connection_initiated (buf, info, act, common_name, es);
@@ -851,7 +950,7 @@ stream_buf_read_setup (struct link_socket* sock)
int link_socket_read_tcp (struct link_socket *sock,
struct buffer *buf);
-#ifdef WIN32
+#ifdef _WIN32
static inline int
link_socket_read_udp_win32 (struct link_socket *sock,
@@ -865,7 +964,6 @@ link_socket_read_udp_win32 (struct link_socket *sock,
int link_socket_read_udp_posix (struct link_socket *sock,
struct buffer *buf,
- int maxsize,
struct link_socket_actual *from);
#endif
@@ -874,17 +972,16 @@ int link_socket_read_udp_posix (struct link_socket *sock,
static inline int
link_socket_read (struct link_socket *sock,
struct buffer *buf,
- int maxsize,
struct link_socket_actual *from)
{
if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */
{
int res;
-#ifdef WIN32
+#ifdef _WIN32
res = link_socket_read_udp_win32 (sock, buf, from);
#else
- res = link_socket_read_udp_posix (sock, buf, maxsize, from);
+ res = link_socket_read_udp_posix (sock, buf, from);
#endif
return res;
}
@@ -909,7 +1006,7 @@ int link_socket_write_tcp (struct link_socket *sock,
struct buffer *buf,
struct link_socket_actual *to);
-#ifdef WIN32
+#ifdef _WIN32
static inline int
link_socket_write_win32 (struct link_socket *sock,
@@ -936,13 +1033,13 @@ link_socket_write_win32 (struct link_socket *sock,
#else
-static inline int
+static inline size_t
link_socket_write_udp_posix (struct link_socket *sock,
struct buffer *buf,
struct link_socket_actual *to)
{
#if ENABLE_IP_PKTINFO
- int link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
+ size_t link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct buffer *buf,
struct link_socket_actual *to);
@@ -956,7 +1053,7 @@ link_socket_write_udp_posix (struct link_socket *sock,
(socklen_t) af_addr_size(to->dest.addr.sa.sa_family));
}
-static inline int
+static inline size_t
link_socket_write_tcp_posix (struct link_socket *sock,
struct buffer *buf,
struct link_socket_actual *to)
@@ -966,12 +1063,12 @@ link_socket_write_tcp_posix (struct link_socket *sock,
#endif
-static inline int
+static inline size_t
link_socket_write_udp (struct link_socket *sock,
struct buffer *buf,
struct link_socket_actual *to)
{
-#ifdef WIN32
+#ifdef _WIN32
return link_socket_write_win32 (sock, buf, to);
#else
return link_socket_write_udp_posix (sock, buf, to);
@@ -1041,7 +1138,7 @@ socket_read_residual (const struct link_socket *s)
static inline event_t
socket_event_handle (const struct link_socket *s)
{
-#ifdef WIN32
+#ifdef _WIN32
return &s->rw_handle;
#else
return s->sd;
@@ -1072,7 +1169,7 @@ socket_set_listen_persistent (struct link_socket *s,
static inline void
socket_reset_listen_persistent (struct link_socket *s)
{
-#ifdef WIN32
+#ifdef _WIN32
reset_net_event_win32 (&s->listen_handle, s->sd);
#endif
}
diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c
index 57dc02a..5a9ea6c 100644
--- a/src/openvpn/socks.c
+++ b/src/openvpn/socks.c
@@ -38,8 +38,6 @@
#include "syshead.h"
-#ifdef ENABLE_SOCKS
-
#include "common.h"
#include "misc.h"
#include "win32.h"
@@ -55,22 +53,21 @@
void
socks_adjust_frame_parameters (struct frame *frame, int proto)
{
- if (proto == PROTO_UDPv4)
+ if (proto == PROTO_UDP)
frame_add_to_extra_link (frame, 10);
}
struct socks_proxy_info *
socks_proxy_new (const char *server,
- int port,
- const char *authfile,
- bool retry)
+ const char *port,
+ const char *authfile)
{
struct socks_proxy_info *p;
ALLOC_OBJ_CLEAR (p, struct socks_proxy_info);
ASSERT (server);
- ASSERT (legal_ipv4_port (port));
+ ASSERT (port);
strncpynt (p->server, server, sizeof (p->server));
p->port = port;
@@ -80,7 +77,6 @@ socks_proxy_new (const char *server,
else
p->authfile[0] = 0;
- p->retry = retry;
p->defined = true;
return p;
@@ -404,11 +400,27 @@ recv_socks_reply (socket_descriptor_t sd,
return true;
}
+static int
+port_from_servname(const char* servname)
+{
+ int port =0;
+ port = atoi(servname);
+ if(port >0 && port < 65536)
+ return port;
+
+ struct servent* service;
+ service = getservbyname(servname, NULL);
+ if(service)
+ return service->s_port;
+
+ return 0;
+}
+
void
establish_socks_proxy_passthru (struct socks_proxy_info *p,
socket_descriptor_t sd, /* already open to proxy */
const char *host, /* openvpn server remote */
- const int port, /* openvpn server port */
+ const char *servname, /* openvpn server port */
volatile int *signal_received)
{
char buf[128];
@@ -429,6 +441,13 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p,
buf[4] = (char) len;
memcpy(buf + 5, host, len);
+ int port = port_from_servname (servname);
+ if (port ==0)
+ {
+ msg (D_LINK_ERRORS, "establish_socks_proxy_passthrough: Cannot convert %s to port number", servname);
+ goto error;
+ }
+
buf[5 + len] = (char) (port >> 8);
buf[5 + len + 1] = (char) (port & 0xff);
@@ -441,6 +460,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p,
}
}
+
/* receive reply from Socks proxy and discard */
if (!recv_socks_reply (sd, NULL, signal_received))
goto error;
@@ -448,9 +468,8 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p,
return;
error:
- /* on error, should we exit or restart? */
if (!*signal_received)
- *signal_received = (p->retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- socks error */
+ *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- socks error */
return;
}
@@ -486,9 +505,8 @@ establish_socks_proxy_udpassoc (struct socks_proxy_info *p,
return;
error:
- /* on error, should we exit or restart? */
if (!*signal_received)
- *signal_received = (p->retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- socks error */
+ *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- socks error */
return;
}
@@ -553,7 +571,3 @@ socks_process_outgoing_udp (struct buffer *buf,
return 10;
}
-
-#else
-static void dummy(void) {}
-#endif /* ENABLE_SOCKS */
diff --git a/src/openvpn/socks.h b/src/openvpn/socks.h
index b55ff6f..a2843b9 100644
--- a/src/openvpn/socks.h
+++ b/src/openvpn/socks.h
@@ -30,8 +30,6 @@
#ifndef SOCKS_H
#define SOCKS_H
-#ifdef ENABLE_SOCKS
-
#include "buffer.h"
struct openvpn_sockaddr;
@@ -39,26 +37,24 @@ struct link_socket_actual;
struct socks_proxy_info {
bool defined;
- bool retry;
char server[128];
- int port;
+ const char *port;
char authfile[256];
};
void socks_adjust_frame_parameters (struct frame *frame, int proto);
struct socks_proxy_info *socks_proxy_new (const char *server,
- int port,
- const char *authfile,
- bool retry);
+ const char *port,
+ const char *authfile);
void socks_proxy_close (struct socks_proxy_info *sp);
void establish_socks_proxy_passthru (struct socks_proxy_info *p,
socket_descriptor_t sd, /* already open to proxy */
const char *host, /* openvpn server remote */
- const int port, /* openvpn server port */
+ const char *servname, /* openvpn server port */
volatile int *signal_received);
void establish_socks_proxy_udpassoc (struct socks_proxy_info *p,
@@ -74,4 +70,3 @@ int socks_process_outgoing_udp (struct buffer *buf,
const struct link_socket_actual *to);
#endif
-#endif
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index 9e31c3c..dc06350 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -35,7 +35,6 @@
* Both the TLS session and the data channel are multiplexed
* over the same TCP/UDP port.
*/
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
@@ -45,11 +44,10 @@
#include "syshead.h"
#include "win32.h"
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#if defined(ENABLE_CRYPTO)
#include "error.h"
#include "common.h"
-#include "integer.h"
#include "socket.h"
#include "misc.h"
#include "fdmisc.h"
@@ -58,9 +56,8 @@
#include "status.h"
#include "gremlin.h"
#include "pkcs11.h"
-#include "list.h"
-#include "base64.h"
#include "route.h"
+#include "tls_crypt.h"
#include "ssl.h"
#include "ssl_verify.h"
@@ -150,6 +147,7 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
{"DHE-RSA-CAMELLIA128-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA"},
{"DHE-RSA-CAMELLIA256-SHA256", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
{"DHE-RSA-CAMELLIA256-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"DHE-RSA-CHACHA20-POLY1305", "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256"},
{"DHE-RSA-SEED-SHA", "TLS-DHE-RSA-WITH-SEED-CBC-SHA"},
{"DH-RSA-SEED-SHA", "TLS-DH-RSA-WITH-SEED-CBC-SHA"},
{"ECDH-ECDSA-AES128-GCM-SHA256", "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256"},
@@ -178,6 +176,7 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
{"ECDHE-ECDSA-CAMELLIA128-SHA", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA"},
{"ECDHE-ECDSA-CAMELLIA256-SHA256", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA256"},
{"ECDHE-ECDSA-CAMELLIA256-SHA", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"ECDHE-ECDSA-CHACHA20-POLY1305", "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"},
{"ECDHE-ECDSA-DES-CBC3-SHA", "TLS-ECDHE-ECDSA-WITH-3DES-EDE-CBC-SHA"},
{"ECDHE-ECDSA-DES-CBC-SHA", "TLS-ECDHE-ECDSA-WITH-DES-CBC-SHA"},
{"ECDHE-ECDSA-RC4-SHA", "TLS-ECDHE-ECDSA-WITH-RC4-128-SHA"},
@@ -193,6 +192,7 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
{"ECDHE-RSA-CAMELLIA128-SHA", "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA"},
{"ECDHE-RSA-CAMELLIA256-SHA256", "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
{"ECDHE-RSA-CAMELLIA256-SHA", "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"ECDHE-RSA-CHACHA20-POLY1305", "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"},
{"ECDHE-RSA-DES-CBC3-SHA", "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA"},
{"ECDHE-RSA-DES-CBC-SHA", "TLS-ECDHE-RSA-WITH-DES-CBC-SHA"},
{"ECDHE-RSA-RC4-SHA", "TLS-ECDHE-RSA-WITH-RC4-128-SHA"},
@@ -237,21 +237,37 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
{"SRP-RSA-AES-128-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-128-CBC-SHA"},
{"SRP-RSA-AES-256-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-256-CBC-SHA"},
#ifdef ENABLE_CRYPTO_OPENSSL
+ /* OpenSSL-specific group names */
{"DEFAULT", "DEFAULT"},
{"ALL", "ALL"},
- {"HIGH", "HIGH"},
- {"MEDIUM", "MEDIUM"},
- {"LOW", "LOW"},
- {"ECDH", "ECDH"},
- {"ECDSA", "ECDSA"},
- {"EDH", "EDH"},
- {"EXP", "EXP"},
- {"RSA", "RSA"},
- {"SRP", "SRP"},
+ {"HIGH", "HIGH"}, {"!HIGH", "!HIGH"},
+ {"MEDIUM", "MEDIUM"}, {"!MEDIUM", "!MEDIUM"},
+ {"LOW", "LOW"}, {"!LOW", "!LOW"},
+ {"ECDH", "ECDH"}, {"!ECDH", "!ECDH"},
+ {"ECDSA", "ECDSA"}, {"!ECDSA", "!ECDSA"},
+ {"EDH", "EDH"}, {"!EDH", "!EDH"},
+ {"EXP", "EXP"}, {"!EXP", "!EXP"},
+ {"RSA", "RSA"}, {"!RSA", "!RSA"},
+ {"kRSA", "kRSA"}, {"!kRSA", "!kRSA"},
+ {"SRP", "SRP"}, {"!SRP", "!SRP"},
#endif
{NULL, NULL}
};
+/**
+ * Update the implicit IV for a key_ctx_bi based on TLS session ids and cipher
+ * used.
+ *
+ * Note that the implicit IV is based on the HMAC key, but only in AEAD modes
+ * where the HMAC key is not used for an actual HMAC.
+ *
+ * @param ctx Encrypt/decrypt key context
+ * @param key HMAC key, used to calculate implicit IV
+ * @param key_len HMAC key length
+ */
+static void
+key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len);
+
const tls_cipher_name_pair *
tls_get_cipher_name_pair (const char * cipher_name, size_t len) {
const tls_cipher_name_pair * pair = tls_cipher_name_translation_table;
@@ -268,6 +284,27 @@ tls_get_cipher_name_pair (const char * cipher_name, size_t len) {
return NULL;
}
+/**
+ * Limit the reneg_bytes value when using a small-block (<128 bytes) cipher.
+ *
+ * @param cipher The current cipher (may be NULL).
+ * @param reneg_bytes Pointer to the current reneg_bytes, updated if needed.
+ * May *not* be NULL.
+ */
+static void
+tls_limit_reneg_bytes (const cipher_kt_t *cipher, int *reneg_bytes)
+{
+ if (cipher && (cipher_kt_block_size(cipher) < 128/8))
+ {
+ if (*reneg_bytes == -1) /* Not user-specified */
+ {
+ msg (M_WARN, "WARNING: cipher with small block size in use, "
+ "reducing reneg-bytes to 64MB to mitigate SWEET32 attacks.");
+ *reneg_bytes = 64 * 1024 * 1024;
+ }
+ }
+}
+
/*
* Max number of bytes we will add
* for data structures common to both
@@ -488,12 +525,15 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
if (options->tls_server)
{
- tls_ctx_server_new(new_ctx, options->ssl_flags);
- tls_ctx_load_dh_params(new_ctx, options->dh_file, options->dh_file_inline);
+ tls_ctx_server_new(new_ctx);
+
+ if (options->dh_file)
+ tls_ctx_load_dh_params(new_ctx, options->dh_file,
+ options->dh_file_inline);
}
else /* if client */
{
- tls_ctx_client_new(new_ctx, options->ssl_flags);
+ tls_ctx_client_new(new_ctx);
}
tls_ctx_set_options(new_ctx, options->ssl_flags);
@@ -522,10 +562,19 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
}
#endif
#ifdef MANAGMENT_EXTERNAL_KEY
- else if ((options->management_flags & MF_EXTERNAL_KEY) && options->cert_file)
- {
- tls_ctx_use_external_private_key(new_ctx, options->cert_file,
- options->cert_file_inline);
+ else if ((options->management_flags & MF_EXTERNAL_KEY) &&
+ (options->cert_file || options->management_flags & MF_EXTERNAL_CERT))
+ {
+ if (options->cert_file) {
+ tls_ctx_use_external_private_key(new_ctx, options->cert_file,
+ options->cert_file_inline);
+ } else {
+ char *external_certificate = management_query_cert(management,
+ options->management_certificate);
+ tls_ctx_use_external_private_key(new_ctx, INLINE_FILE_TAG,
+ external_certificate);
+ free(external_certificate);
+ }
}
#endif
else
@@ -552,7 +601,7 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
/* Load extra certificates that are part of our own certificate
chain but shouldn't be included in the verify chain */
- if (options->extra_certs_file || options->extra_certs_file_inline)
+ if (options->extra_certs_file)
{
tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_file_inline);
}
@@ -560,10 +609,20 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
/* Check certificate notBefore and notAfter */
tls_ctx_check_cert_time(new_ctx);
+ /* Read CRL */
+ if (options->crl_file && !(options->ssl_flags & SSLF_CRL_VERIFY_DIR))
+ {
+ tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline);
+ }
+
+ /* Once keys and cert are loaded, load ECDH parameters */
+ if (options->tls_server)
+ tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve);
+
/* Allowable ciphers */
tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
-#ifdef ENABLE_CRYPTO_POLARSSL
+#ifdef ENABLE_CRYPTO_MBEDTLS
/* Personalise the random by mixing in the certificate */
tls_ctx_personalise_random (new_ctx);
#endif
@@ -766,11 +825,17 @@ key_state_init (struct tls_session *session, struct key_state *ks)
reliable_set_timeout (ks->send_reliable, session->opt->packet_timeout);
/* init packet ID tracker */
- packet_id_init (&ks->packet_id,
- session->opt->tcp_mode,
- session->opt->replay_window,
- session->opt->replay_time,
- "SSL", ks->key_id);
+ if (session->opt->replay)
+ {
+ packet_id_init (&ks->crypto_options.packet_id,
+ session->opt->replay_window, session->opt->replay_time, "SSL",
+ ks->key_id);
+ }
+
+ ks->crypto_options.pid_persist = NULL;
+ ks->crypto_options.flags = session->opt->crypto_flags;
+ ks->crypto_options.flags &= session->opt->crypto_flags_and;
+ ks->crypto_options.flags |= session->opt->crypto_flags_or;
#ifdef MANAGEMENT_DEF_AUTH
ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++;
@@ -798,7 +863,7 @@ key_state_free (struct key_state *ks, bool clear)
key_state_ssl_free(&ks->ks_ssl);
- free_key_ctx_bi (&ks->key);
+ free_key_ctx_bi (&ks->crypto_options.key_ctx_bi);
free_buf (&ks->plaintext_read_buf);
free_buf (&ks->plaintext_write_buf);
free_buf (&ks->ack_write_buf);
@@ -822,7 +887,7 @@ key_state_free (struct key_state *ks, bool clear)
if (ks->key_src)
free (ks->key_src);
- packet_id_free (&ks->packet_id);
+ packet_id_free (&ks->crypto_options.packet_id);
#ifdef PLUGIN_DEF_AUTH
key_state_rm_auth_control_file (ks);
@@ -837,11 +902,23 @@ key_state_free (struct key_state *ks, bool clear)
/** @} addtogroup control_processor */
-/*
- * Must be called if we move a tls_session in memory.
+/**
+ * Returns whether or not the server should check for username/password
+ *
+ * @param session The current TLS session
+ *
+ * @return true if username and password verification is enabled,
+ * false if not.
*/
-static inline void tls_session_set_self_referential_pointers (struct tls_session* session) {
- session->tls_auth.packet_id = &session->tls_auth_pid;
+static inline bool
+tls_session_user_pass_enabled(struct tls_session *session)
+{
+ return (session->opt->auth_user_pass_verify_script
+ || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
+#ifdef MANAGEMENT_DEF_AUTH
+ || management_enable_def_auth (management)
+#endif
+ );
}
@@ -895,20 +972,18 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session)
}
/* Initialize control channel authentication parameters */
- session->tls_auth = session->opt->tls_auth;
-
- /* Set session internal pointers (also called if session object is moved in memory) */
- tls_session_set_self_referential_pointers (session);
+ session->tls_wrap = session->opt->tls_wrap;
+ session->tls_wrap.work = alloc_buf (TLS_CHANNEL_BUF_SIZE);
/* initialize packet ID replay window for --tls-auth */
- packet_id_init (session->tls_auth.packet_id,
- session->opt->tcp_mode,
+ packet_id_init (&session->tls_wrap.opt.packet_id,
session->opt->replay_window,
session->opt->replay_time,
- "TLS_AUTH", session->key_id);
+ "TLS_WRAP", session->key_id);
/* load most recent packet-id to replay protect on --tls-auth */
- packet_id_persist_load_obj (session->tls_auth.pid_persist, session->tls_auth.packet_id);
+ packet_id_persist_load_obj (session->tls_wrap.opt.pid_persist,
+ &session->tls_wrap.opt.packet_id);
key_state_init (session, &session->key[KS_PRIMARY]);
@@ -935,8 +1010,10 @@ tls_session_free (struct tls_session *session, bool clear)
{
int i;
- if (session->tls_auth.packet_id)
- packet_id_free (session->tls_auth.packet_id);
+ if (packet_id_initialized(&session->tls_wrap.opt.packet_id))
+ packet_id_free (&session->tls_wrap.opt.packet_id);
+
+ free_buf (&session->tls_wrap.work);
for (i = 0; i < KS_SIZE; ++i)
key_state_free (&session->key[i], false);
@@ -967,7 +1044,6 @@ move_session (struct tls_multi* multi, int dest, int src, bool reinit_src)
ASSERT (dest >= 0 && dest < TM_SIZE);
tls_session_free (&multi->session[dest], false);
multi->session[dest] = multi->session[src];
- tls_session_set_self_referential_pointers (&multi->session[dest]);
if (reinit_src)
tls_session_init (multi, &multi->session[src]);
@@ -984,22 +1060,6 @@ reset_session (struct tls_multi *multi, struct tls_session *session)
tls_session_init (multi, session);
}
-#if 0
-/*
- * Transmit a TLS reset on our untrusted channel.
- */
-static void
-initiate_untrusted_session (struct tls_multi *multi, struct sockaddr_in *to)
-{
- struct tls_session *session = &multi->session[TM_UNTRUSTED];
- struct key_state *ks = &session->key[KS_PRIMARY];
-
- reset_session (multi, session);
- ks->remote_addr = *to;
- msg (D_TLS_DEBUG_LOW, "TLS: initiate_untrusted_session: addr=%s", print_sockaddr (to));
-}
-#endif
-
/*
* Used to determine in how many seconds we should be
* called again.
@@ -1048,9 +1108,6 @@ tls_multi_init (struct tls_options *tls_options)
/* get command line derived options */
ret->opt = *tls_options;
- /* set up pointer to HMAC object for TLS packet authentication */
- ret->opt.tls_auth.key_ctx_bi = &ret->opt.tls_auth_key;
-
/* set up list of keys to be scanned by data channel encrypt and decrypt routines */
ASSERT (SIZE (ret->key_scan) == 3);
ret->key_scan[0] = &ret->session[TM_ACTIVE].key[KS_PRIMARY];
@@ -1088,10 +1145,14 @@ tls_auth_standalone_init (struct tls_options *tls_options,
ALLOC_OBJ_CLEAR_GC (tas, struct tls_auth_standalone, gc);
- /* set up pointer to HMAC object for TLS packet authentication */
- tas->tls_auth_key = tls_options->tls_auth_key;
- tas->tls_auth_options.key_ctx_bi = &tas->tls_auth_key;
- tas->tls_auth_options.flags |= CO_PACKET_ID_LONG_FORM;
+ tas->tls_wrap = tls_options->tls_wrap;
+
+ /*
+ * Standalone tls-auth is in read-only mode with respect to TLS
+ * control channel state. After we build a new client instance
+ * object, we will process this session-initiating packet for real.
+ */
+ tas->tls_wrap.opt.flags |= CO_IGNORE_PACKET_ID;
/* get initial frame parms, still need to finalize */
tas->frame = tls_options->frame;
@@ -1136,6 +1197,8 @@ tls_multi_free (struct tls_multi *multi, bool clear)
#ifdef MANAGEMENT_DEF_AUTH
man_def_auth_set_client_reason(multi, NULL);
+#endif
+#if P2MP_SERVER
free (multi->peer_info);
#endif
@@ -1147,6 +1210,12 @@ tls_multi_free (struct tls_multi *multi, bool clear)
cert_hash_free (multi->locked_cert_hash_set);
+ if (multi->auth_token)
+ {
+ memset (multi->auth_token, 0, AUTH_TOKEN_SIZE);
+ free (multi->auth_token);
+ }
+
for (i = 0; i < TM_SIZE; ++i)
tls_session_free (&multi->session[i], false);
@@ -1171,11 +1240,11 @@ tls_multi_free (struct tls_multi *multi, bool clear)
static bool
swap_hmac (struct buffer *buf, const struct crypto_options *co, bool incoming)
{
- struct key_ctx *ctx;
+ const struct key_ctx *ctx;
ASSERT (co);
- ctx = (incoming ? &co->key_ctx_bi->decrypt : &co->key_ctx_bi->encrypt);
+ ctx = (incoming ? &co->key_ctx_bi.decrypt : &co->key_ctx_bi.encrypt);
ASSERT (ctx->hmac);
{
@@ -1230,20 +1299,34 @@ write_control_auth (struct tls_session *session,
int max_ack,
bool prepend_ack)
{
- uint8_t *header;
+ uint8_t header = ks->key_id | (opcode << P_OPCODE_SHIFT);
struct buffer null = clear_buf ();
ASSERT (link_socket_actual_defined (&ks->remote_addr));
ASSERT (reliable_ack_write
(ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack));
- ASSERT (session_id_write_prepend (&session->session_id, buf));
- ASSERT (header = buf_prepend (buf, 1));
- *header = ks->key_id | (opcode << P_OPCODE_SHIFT);
- if (session->tls_auth.key_ctx_bi->encrypt.hmac)
+
+ if (session->tls_wrap.mode == TLS_WRAP_AUTH ||
+ session->tls_wrap.mode == TLS_WRAP_NONE)
+ {
+ ASSERT (session_id_write_prepend (&session->session_id, buf));
+ ASSERT (buf_write_prepend (buf, &header, sizeof(header)));
+ }
+ if (session->tls_wrap.mode == TLS_WRAP_AUTH)
{
/* no encryption, only write hmac */
- openvpn_encrypt (buf, null, &session->tls_auth, NULL);
- ASSERT (swap_hmac (buf, &session->tls_auth, false));
+ openvpn_encrypt (buf, null, &session->tls_wrap.opt);
+ ASSERT (swap_hmac (buf, &session->tls_wrap.opt, false));
+ }
+ else if (session->tls_wrap.mode == TLS_WRAP_CRYPT)
+ {
+ buf_init (&session->tls_wrap.work, buf->offset);
+ ASSERT (buf_write (&session->tls_wrap.work, &header, sizeof(header)));
+ ASSERT (session_id_write (&session->session_id, &session->tls_wrap.work));
+ ASSERT (tls_crypt_wrap (buf, &session->tls_wrap.work, &session->tls_wrap.opt));
+ /* Don't change the original data in buf, it's used by the reliability
+ * layer to resend on failure. */
+ *buf = session->tls_wrap.work;
}
*to_link_addr = &ks->remote_addr;
}
@@ -1253,17 +1336,18 @@ write_control_auth (struct tls_session *session,
*/
static bool
read_control_auth (struct buffer *buf,
- const struct crypto_options *co,
+ struct tls_wrap_ctx *ctx,
const struct link_socket_actual *from)
{
struct gc_arena gc = gc_new ();
+ bool ret = false;
- if (co->key_ctx_bi->decrypt.hmac)
+ if (ctx->mode == TLS_WRAP_AUTH)
{
struct buffer null = clear_buf ();
/* move the hmac record to the front of the packet */
- if (!swap_hmac (buf, co, true))
+ if (!swap_hmac (buf, &ctx->opt, true))
{
msg (D_TLS_ERRORS,
"TLS Error: cannot locate HMAC in incoming packet from %s",
@@ -1274,24 +1358,41 @@ read_control_auth (struct buffer *buf,
/* authenticate only (no decrypt) and remove the hmac record
from the head of the buffer */
- openvpn_decrypt (buf, null, co, NULL);
+ openvpn_decrypt (buf, null, &ctx->opt, NULL, BPTR (buf));
if (!buf->len)
{
msg (D_TLS_ERRORS,
"TLS Error: incoming packet authentication failed from %s",
print_link_socket_actual (from, &gc));
- gc_free (&gc);
- return false;
+ goto cleanup;
}
}
+ else if (ctx->mode == TLS_WRAP_CRYPT)
+ {
+ struct buffer tmp = alloc_buf (buf_forward_capacity_total (buf));
+ if (!tls_crypt_unwrap (buf, &tmp, &ctx->opt))
+ {
+ msg (D_TLS_ERRORS, "TLS Error: tls-crypt unwrapping failed from %s",
+ print_link_socket_actual (from, &gc));
+ goto cleanup;
+ }
+ ASSERT (buf_init (buf, buf->offset));
+ ASSERT (buf_copy (buf, &tmp));
+ free_buf (&tmp);
+ }
- /* advance buffer pointer past opcode & session_id since our caller
- already read it */
- buf_advance (buf, SID_SIZE + 1);
+ if (ctx->mode == TLS_WRAP_NONE || ctx->mode == TLS_WRAP_AUTH)
+ {
+ /* advance buffer pointer past opcode & session_id since our caller
+ already read it */
+ buf_advance (buf, SID_SIZE + 1);
+ }
+ ret = true;
+cleanup:
gc_free (&gc);
- return true;
+ return ret;
}
/*
@@ -1352,7 +1453,7 @@ tls1_P_hash(const md_kt_t *md_kt,
int olen)
{
struct gc_arena gc = gc_new ();
- int chunk,n;
+ int chunk;
hmac_ctx_t ctx;
hmac_ctx_t ctx_tmp;
uint8_t A1[MAX_HMAC_KEY_LENGTH];
@@ -1378,7 +1479,6 @@ tls1_P_hash(const md_kt_t *md_kt,
hmac_ctx_update(&ctx,seed,seed_len);
hmac_ctx_final(&ctx, A1);
- n=0;
for (;;)
{
hmac_ctx_reset(&ctx);
@@ -1429,7 +1529,7 @@ tls1_P_hash(const md_kt_t *md_kt,
* (2) The pre-master secret is generated by the client.
*/
static void
-tls1_PRF(uint8_t *label,
+tls1_PRF(const uint8_t *label,
int label_len,
const uint8_t *sec,
int slen,
@@ -1581,6 +1681,13 @@ generate_key_expansion (struct key_ctx_bi *key,
OPENVPN_OP_DECRYPT,
"Data Channel Decrypt");
+ /* Initialize implicit IVs */
+ key_ctx_update_implicit_iv (&key->encrypt, key2.keys[(int)server].hmac,
+ MAX_HMAC_KEY_LENGTH);
+ key_ctx_update_implicit_iv (&key->decrypt, key2.keys[1-(int)server].hmac,
+ MAX_HMAC_KEY_LENGTH);
+
+ key->initialized = true;
ret = true;
exit:
@@ -1590,6 +1697,96 @@ generate_key_expansion (struct key_ctx_bi *key,
return ret;
}
+static void
+key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) {
+ const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
+
+ /* Only use implicit IV in AEAD cipher mode, where HMAC key is not used */
+ if (cipher_kt_mode_aead (cipher_kt))
+ {
+ size_t impl_iv_len = 0;
+ ASSERT (cipher_kt_iv_size (cipher_kt) >= OPENVPN_AEAD_MIN_IV_LEN);
+ impl_iv_len = cipher_kt_iv_size (cipher_kt) - sizeof (packet_id_type);
+ ASSERT (impl_iv_len <= OPENVPN_MAX_IV_LENGTH);
+ ASSERT (impl_iv_len <= key_len);
+ memcpy (ctx->implicit_iv, key, impl_iv_len);
+ ctx->implicit_iv_len = impl_iv_len;
+ }
+}
+
+static bool
+item_in_list(const char *item, const char *list)
+{
+ char *tmp_ciphers = string_alloc (list, NULL);
+ char *tmp_ciphers_orig = tmp_ciphers;
+
+ const char *token = strtok (tmp_ciphers, ":");
+ while(token)
+ {
+ if (0 == strcmp (token, item))
+ break;
+ token = strtok (NULL, ":");
+ }
+ free(tmp_ciphers_orig);
+
+ return token != NULL;
+}
+
+bool
+tls_session_update_crypto_params(struct tls_session *session,
+ const struct options *options, struct frame *frame)
+{
+ bool ret = false;
+ struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
+
+ ASSERT (ks->authenticated);
+
+ if (!session->opt->server &&
+ 0 != strcmp(options->ciphername, session->opt->config_ciphername) &&
+ !item_in_list(options->ciphername, options->ncp_ciphers))
+ {
+ msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s",
+ options->ciphername, session->opt->config_ciphername,
+ options->ncp_ciphers);
+ return false;
+ }
+
+ init_key_type (&session->opt->key_type, options->ciphername,
+ options->authname, options->keysize, true, true);
+
+ bool packet_id_long_form = cipher_kt_mode_ofb_cfb (session->opt->key_type.cipher);
+ session->opt->crypto_flags_and &= ~(CO_PACKET_ID_LONG_FORM);
+ if (packet_id_long_form)
+ session->opt->crypto_flags_and = CO_PACKET_ID_LONG_FORM;
+
+ /* Update frame parameters: undo worst-case overhead, add actual overhead */
+ frame_add_to_extra_frame (frame, -(crypto_max_overhead()));
+ crypto_adjust_frame_parameters (frame, &session->opt->key_type,
+ options->use_iv, options->replay, packet_id_long_form);
+ frame_finalize(frame, options->ce.link_mtu_defined, options->ce.link_mtu,
+ options->ce.tun_mtu_defined, options->ce.tun_mtu);
+ frame_init_mssfix(frame, options);
+ frame_print (frame, D_MTU_INFO, "Data Channel MTU parms");
+
+ const struct session_id *client_sid = session->opt->server ?
+ &ks->session_id_remote : &session->session_id;
+ const struct session_id *server_sid = !session->opt->server ?
+ &ks->session_id_remote : &session->session_id;
+ if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi,
+ &session->opt->key_type, ks->key_src, client_sid, server_sid,
+ session->opt->server))
+ {
+ msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed");
+ goto cleanup;
+ }
+ tls_limit_reneg_bytes (session->opt->key_type.cipher,
+ &session->opt->renegotiate_bytes);
+ ret = true;
+cleanup:
+ CLEAR (*ks->key_src);
+ return ret;
+}
+
static bool
random_bytes_to_buf (struct buffer *buf,
uint8_t *out,
@@ -1762,7 +1959,6 @@ key_method_1_write (struct buffer *buf, struct tls_session *session)
{
struct key key;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
ASSERT (session->opt->key_method == 1);
ASSERT (buf_init (buf, 0));
@@ -1780,8 +1976,9 @@ key_method_1_write (struct buffer *buf, struct tls_session *session)
return false;
}
- init_key_ctx (&ks->key.encrypt, &key, &session->opt->key_type,
- OPENVPN_OP_ENCRYPT, "Data Channel Encrypt");
+ init_key_ctx (&ks->crypto_options.key_ctx_bi.encrypt, &key,
+ &session->opt->key_type, OPENVPN_OP_ENCRYPT,
+ "Data Channel Encrypt");
CLEAR (key);
/* send local options string */
@@ -1827,17 +2024,30 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
buf_printf (&out, "IV_PLAT=netbsd\n");
#elif defined(TARGET_FREEBSD)
buf_printf (&out, "IV_PLAT=freebsd\n");
-#elif defined(WIN32)
+#elif defined(TARGET_ANDROID)
+ buf_printf (&out, "IV_PLAT=android\n");
+#elif defined(_WIN32)
buf_printf (&out, "IV_PLAT=win\n");
#endif
- /* push LZO status */
-#ifdef ENABLE_LZO_STUB
- buf_printf (&out, "IV_LZO_STUB=1\n");
-#endif
/* support for P_DATA_V2 */
buf_printf(&out, "IV_PROTO=2\n");
+ /* support for Negotiable Crypto Paramters */
+ if (session->opt->ncp_enabled &&
+ (session->opt->mode == MODE_SERVER || session->opt->pull))
+ {
+ buf_printf(&out, "IV_NCP=2\n");
+ }
+
+ /* push compression status */
+#ifdef USE_COMP
+ comp_generate_peer_info_string(&session->opt->comp_options, &out);
+#endif
+
+ /* support for redirecting IPv6 gateway */
+ buf_printf(&out, "IV_RGI6=1\n");
+
if (session->opt->push_peer_info_detail >= 2)
{
/* push mac addr */
@@ -1846,17 +2056,19 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
if (rgi.flags & RGI_HWADDR_DEFINED)
buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc));
buf_printf (&out, "IV_SSL=%s\n", get_ssl_library_version() );
-#if defined(WIN32)
+#if defined(_WIN32)
buf_printf (&out, "IV_PLAT_VER=%s\n", win32_version_string (&gc, false));
#endif
}
- /* push env vars that begin with UV_ and IV_GUI_VER */
+ /* push env vars that begin with UV_, IV_PLAT_VER and IV_GUI_VER */
for (e=es->list; e != NULL; e=e->next)
{
if (e->string)
{
- if (((strncmp(e->string, "UV_", 3)==0 && session->opt->push_peer_info_detail >= 2)
+ if ((((strncmp(e->string, "UV_", 3)==0 ||
+ strncmp(e->string, "IV_PLAT_VER=", sizeof("IV_PLAT_VER=")-1)==0)
+ && session->opt->push_peer_info_detail >= 2)
|| (strncmp(e->string,"IV_GUI_VER=",sizeof("IV_GUI_VER=")-1)==0))
&& buf_safe(&out, strlen(e->string)+1))
buf_printf (&out, "%s\n", e->string);
@@ -1883,7 +2095,6 @@ static bool
key_method_2_write (struct buffer *buf, struct tls_session *session)
{
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
ASSERT (session->opt->key_method == 2);
ASSERT (buf_init (buf, 0));
@@ -1931,14 +2142,17 @@ key_method_2_write (struct buffer *buf, struct tls_session *session)
if (!push_peer_info (buf, session))
goto error;
- /*
- * generate tunnel keys if server
+ /* Generate tunnel keys if we're a TLS server.
+ * If we're a p2mp server and IV_NCP >= 2 is negotiated, the first key
+ * generation is postponed until after the pull/push, so we can process pushed
+ * cipher directives.
*/
- if (session->opt->server)
+ if (session->opt->server && !(session->opt->ncp_enabled &&
+ session->opt->mode == MODE_SERVER && ks->key_id <= 0))
{
if (ks->authenticated)
{
- if (!generate_key_expansion (&ks->key,
+ if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi,
&session->opt->key_type,
ks->key_src,
&ks->session_id_remote,
@@ -1951,6 +2165,8 @@ key_method_2_write (struct buffer *buf, struct tls_session *session)
}
CLEAR (*ks->key_src);
+ tls_limit_reneg_bytes (session->opt->key_type.cipher,
+ &session->opt->renegotiate_bytes);
}
return true;
@@ -1967,7 +2183,6 @@ key_method_1_read (struct buffer *buf, struct tls_session *session)
int status;
struct key key;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
ASSERT (session->opt->key_method == 1);
@@ -2010,8 +2225,9 @@ key_method_1_read (struct buffer *buf, struct tls_session *session)
buf_clear (buf);
- init_key_ctx (&ks->key.decrypt, &key, &session->opt->key_type,
- OPENVPN_OP_DECRYPT, "Data Channel Decrypt");
+ init_key_ctx (&ks->crypto_options.key_ctx_bi.decrypt, &key,
+ &session->opt->key_type, OPENVPN_OP_DECRYPT,
+ "Data Channel Decrypt");
CLEAR (key);
ks->authenticated = true;
return true;
@@ -2026,13 +2242,13 @@ static bool
key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_session *session)
{
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
int key_method_flags;
bool username_status, password_status;
struct gc_arena gc = gc_new ();
char *options;
+ struct user_pass *up;
/* allocate temporary objects */
ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc);
@@ -2072,15 +2288,31 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
ks->authenticated = false;
- if (verify_user_pass_enabled(session))
- {
- /* Perform username/password authentication */
- struct user_pass *up;
+ /* always extract username + password fields from buf, even if not
+ * authenticating for it, because otherwise we can't get at the
+ * peer_info data which follows behind
+ */
+ ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
+ username_status = read_string (buf, up->username, USER_PASS_LEN);
+ password_status = read_string (buf, up->password, USER_PASS_LEN);
+
+#if P2MP_SERVER
+ /* get peer info from control channel */
+ free (multi->peer_info);
+ multi->peer_info = read_string_alloc (buf);
+ if ( multi->peer_info )
+ output_peer_info_env (session->opt->es, multi->peer_info);
- ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
- username_status = read_string (buf, up->username, USER_PASS_LEN);
- password_status = read_string (buf, up->password, USER_PASS_LEN);
+ if (tls_peer_info_ncp_ver (multi->peer_info) < 2)
+ {
+ /* Peer does not support NCP */
+ session->opt->ncp_enabled = false;
+ }
+#endif
+ if (tls_session_user_pass_enabled(session))
+ {
+ /* Perform username/password authentication */
if (!username_status || !password_status)
{
CLEAR (*up);
@@ -2091,14 +2323,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
}
}
-#ifdef MANAGEMENT_DEF_AUTH
- /* get peer info from control channel */
- free (multi->peer_info);
- multi->peer_info = read_string_alloc (buf);
-#endif
-
verify_user_pass(up, multi, session);
- CLEAR (*up);
}
else
{
@@ -2112,6 +2337,9 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
ks->authenticated = true;
}
+ /* clear username and password from memory */
+ CLEAR (*up);
+
/* Perform final authentication checks */
if (ks->authenticated)
{
@@ -2140,16 +2368,22 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
*/
if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
{
+ key_state_export_keying_material(&ks->ks_ssl, session);
+
if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
ks->authenticated = false;
+
+ setenv_del (session->opt->es, "exported_keying_material");
}
/*
- * Generate tunnel keys if client
+ * Generate tunnel keys if we're a client.
+ * If --pull is enabled, the first key generation is postponed until after the
+ * pull/push, so we can process pushed cipher directives.
*/
- if (!session->opt->server)
+ if (!session->opt->server && (!session->opt->pull || ks->key_id > 0))
{
- if (!generate_key_expansion (&ks->key,
+ if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi,
&session->opt->key_type,
ks->key_src,
&session->session_id,
@@ -2159,8 +2393,10 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
msg (D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed");
goto error;
}
-
+
CLEAR (*ks->key_src);
+ tls_limit_reneg_bytes (session->opt->key_type.cipher,
+ &session->opt->renegotiate_bytes);
}
gc_free (&gc);
@@ -2217,11 +2453,11 @@ tls_process (struct tls_multi *multi,
if (ks->state >= S_ACTIVE &&
((session->opt->renegotiate_seconds
&& now >= ks->established + session->opt->renegotiate_seconds)
- || (session->opt->renegotiate_bytes
+ || (session->opt->renegotiate_bytes > 0
&& ks->n_bytes >= session->opt->renegotiate_bytes)
|| (session->opt->renegotiate_packets
&& ks->n_packets >= session->opt->renegotiate_packets)
- || (packet_id_close_to_wrapping (&ks->packet_id.send))))
+ || (packet_id_close_to_wrapping (&ks->crypto_options.packet_id.send))))
{
msg (D_TLS_DEBUG_LOW,
"TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" counter_format "/%d",
@@ -2257,269 +2493,274 @@ tls_process (struct tls_multi *multi,
* CHANGED with 2.0 -> now we may send tunnel configuration
* info over the control channel.
*/
- if (true)
+
+ /* Initial handshake */
+ if (ks->state == S_INITIAL)
{
- /* Initial handshake */
- if (ks->state == S_INITIAL)
+ buf = reliable_get_buf_output_sequenced (ks->send_reliable);
+ if (buf)
{
- buf = reliable_get_buf_output_sequenced (ks->send_reliable);
- if (buf)
- {
- ks->must_negotiate = now + session->opt->handshake_window;
- ks->auth_deferred_expire = now + auth_deferred_expire_window (session->opt);
+ ks->must_negotiate = now + session->opt->handshake_window;
+ ks->auth_deferred_expire = now + auth_deferred_expire_window (session->opt);
- /* null buffer */
- reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode);
- INCR_GENERATED;
+ /* null buffer */
+ reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode);
+ INCR_GENERATED;
- ks->state = S_PRE_START;
- state_change = true;
- dmsg (D_TLS_DEBUG, "TLS: Initial Handshake, sid=%s",
- session_id_print (&session->session_id, &gc));
+ ks->state = S_PRE_START;
+ state_change = true;
+ dmsg (D_TLS_DEBUG, "TLS: Initial Handshake, sid=%s",
+ session_id_print (&session->session_id, &gc));
#ifdef ENABLE_MANAGEMENT
- if (management && ks->initial_opcode != P_CONTROL_SOFT_RESET_V1)
- {
- management_set_state (management,
- OPENVPN_STATE_WAIT,
- NULL,
- 0,
- 0);
- }
-#endif
+ if (management && ks->initial_opcode != P_CONTROL_SOFT_RESET_V1)
+ {
+ management_set_state (management,
+ OPENVPN_STATE_WAIT,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
+#endif
}
+ }
- /* Are we timed out on receive? */
- if (now >= ks->must_negotiate)
+ /* Are we timed out on receive? */
+ if (now >= ks->must_negotiate)
+ {
+ if (ks->state < S_ACTIVE)
{
- if (ks->state < S_ACTIVE)
- {
- msg (D_TLS_ERRORS,
- "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)",
- session->opt->handshake_window);
- goto error;
- }
- else /* assume that ks->state == S_ACTIVE */
- {
- dmsg (D_TLS_DEBUG_MED, "STATE S_NORMAL_OP");
- ks->state = S_NORMAL_OP;
- ks->must_negotiate = 0;
- }
+ msg (D_TLS_ERRORS,
+ "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)",
+ session->opt->handshake_window);
+ goto error;
}
+ else /* assume that ks->state == S_ACTIVE */
+ {
+ dmsg (D_TLS_DEBUG_MED, "STATE S_NORMAL_OP");
+ ks->state = S_NORMAL_OP;
+ ks->must_negotiate = 0;
+ }
+ }
- /* Wait for Initial Handshake ACK */
- if (ks->state == S_PRE_START && FULL_SYNC)
+ /* Wait for Initial Handshake ACK */
+ if (ks->state == S_PRE_START && FULL_SYNC)
+ {
+ ks->state = S_START;
+ state_change = true;
+
+ /* Reload the CRL before TLS negotiation */
+ if (session->opt->crl_file &&
+ !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR))
{
- ks->state = S_START;
- state_change = true;
- dmsg (D_TLS_DEBUG_MED, "STATE S_START");
+ tls_ctx_reload_crl(&session->opt->ssl_ctx,
+ session->opt->crl_file, session->opt->crl_file_inline);
}
- /* Wait for ACK */
- if (((ks->state == S_GOT_KEY && !session->opt->server) ||
- (ks->state == S_SENT_KEY && session->opt->server)))
+ dmsg (D_TLS_DEBUG_MED, "STATE S_START");
+ }
+
+ /* Wait for ACK */
+ if (((ks->state == S_GOT_KEY && !session->opt->server) ||
+ (ks->state == S_SENT_KEY && session->opt->server)))
+ {
+ if (FULL_SYNC)
{
- if (FULL_SYNC)
- {
- ks->established = now;
- dmsg (D_TLS_DEBUG_MED, "STATE S_ACTIVE");
- if (check_debug_level (D_HANDSHAKE))
- print_details (&ks->ks_ssl, "Control Channel:");
- state_change = true;
- ks->state = S_ACTIVE;
- INCR_SUCCESS;
+ ks->established = now;
+ dmsg (D_TLS_DEBUG_MED, "STATE S_ACTIVE");
+ if (check_debug_level (D_HANDSHAKE))
+ print_details (&ks->ks_ssl, "Control Channel:");
+ state_change = true;
+ ks->state = S_ACTIVE;
+ INCR_SUCCESS;
- /* Set outgoing address for data channel packets */
- link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es);
+ /* Set outgoing address for data channel packets */
+ link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es);
- /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */
- flush_payload_buffer (ks);
+ /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */
+ flush_payload_buffer (ks);
#ifdef MEASURE_TLS_HANDSHAKE_STATS
- show_tls_performance_stats();
+ show_tls_performance_stats();
#endif
- }
}
+ }
- /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs
- for previously received packets) */
- if (!to_link->len && reliable_can_send (ks->send_reliable))
- {
- int opcode;
- struct buffer b;
-
- buf = reliable_send (ks->send_reliable, &opcode);
- ASSERT (buf);
- b = *buf;
- INCR_SENT;
-
- write_control_auth (session, ks, &b, to_link_addr, opcode,
- CONTROL_SEND_ACK_MAX, true);
- *to_link = b;
- active = true;
- state_change = true;
- dmsg (D_TLS_DEBUG, "Reliable -> TCP/UDP");
- break;
- }
+ /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs
+ for previously received packets) */
+ if (!to_link->len && reliable_can_send (ks->send_reliable))
+ {
+ int opcode;
+ struct buffer b;
+
+ buf = reliable_send (ks->send_reliable, &opcode);
+ ASSERT (buf);
+ b = *buf;
+ INCR_SENT;
+
+ write_control_auth (session, ks, &b, to_link_addr, opcode,
+ CONTROL_SEND_ACK_MAX, true);
+ *to_link = b;
+ active = true;
+ state_change = true;
+ dmsg (D_TLS_DEBUG, "Reliable -> TCP/UDP");
+ break;
+ }
#ifndef TLS_AGGREGATE_ACK
- /* Send 1 or more ACKs (each received control packet gets one ACK) */
- if (!to_link->len && !reliable_ack_empty (ks->rec_ack))
- {
- buf = &ks->ack_write_buf;
- ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame)));
- write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1,
- RELIABLE_ACK_SIZE, false);
- *to_link = *buf;
- active = true;
- state_change = true;
- dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP");
- break;
- }
+ /* Send 1 or more ACKs (each received control packet gets one ACK) */
+ if (!to_link->len && !reliable_ack_empty (ks->rec_ack))
+ {
+ buf = &ks->ack_write_buf;
+ ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame)));
+ write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1,
+ RELIABLE_ACK_SIZE, false);
+ *to_link = *buf;
+ active = true;
+ state_change = true;
+ dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP");
+ break;
+ }
#endif
- /* Write incoming ciphertext to TLS object */
- buf = reliable_get_buf_sequenced (ks->rec_reliable);
- if (buf)
- {
- int status = 0;
- if (buf->len)
- {
- status = key_state_write_ciphertext (&ks->ks_ssl, buf);
- if (status == -1)
- {
- msg (D_TLS_ERRORS,
- "TLS Error: Incoming Ciphertext -> TLS object write error");
- goto error;
- }
- }
- else
- {
- status = 1;
- }
- if (status == 1)
- {
- reliable_mark_deleted (ks->rec_reliable, buf, true);
- state_change = true;
- dmsg (D_TLS_DEBUG, "Incoming Ciphertext -> TLS");
- }
- }
-
- /* Read incoming plaintext from TLS object */
- buf = &ks->plaintext_read_buf;
- if (!buf->len)
+ /* Write incoming ciphertext to TLS object */
+ buf = reliable_get_buf_sequenced (ks->rec_reliable);
+ if (buf)
+ {
+ int status = 0;
+ if (buf->len)
{
- int status;
-
- ASSERT (buf_init (buf, 0));
- status = key_state_read_plaintext (&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE);
- update_time ();
+ status = key_state_write_ciphertext (&ks->ks_ssl, buf);
if (status == -1)
{
- msg (D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error");
+ msg (D_TLS_ERRORS,
+ "TLS Error: Incoming Ciphertext -> TLS object write error");
goto error;
}
- if (status == 1)
- {
- state_change = true;
- dmsg (D_TLS_DEBUG, "TLS -> Incoming Plaintext");
- }
-#if 0 /* show null plaintext reads */
- if (!status)
- msg (M_INFO, "TLS plaintext read -> NULL return");
-#endif
}
-
- /* Send Key */
- buf = &ks->plaintext_write_buf;
- if (!buf->len && ((ks->state == S_START && !session->opt->server) ||
- (ks->state == S_GOT_KEY && session->opt->server)))
+ else
{
- if (session->opt->key_method == 1)
- {
- if (!key_method_1_write (buf, session))
- goto error;
- }
- else if (session->opt->key_method == 2)
- {
- if (!key_method_2_write (buf, session))
- goto error;
- }
- else
- {
- ASSERT (0);
- }
+ status = 1;
+ }
+ if (status == 1)
+ {
+ reliable_mark_deleted (ks->rec_reliable, buf, true);
+ state_change = true;
+ dmsg (D_TLS_DEBUG, "Incoming Ciphertext -> TLS");
+ }
+ }
+
+ /* Read incoming plaintext from TLS object */
+ buf = &ks->plaintext_read_buf;
+ if (!buf->len)
+ {
+ int status;
+ ASSERT (buf_init (buf, 0));
+ status = key_state_read_plaintext (&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE);
+ update_time ();
+ if (status == -1)
+ {
+ msg (D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error");
+ goto error;
+ }
+ if (status == 1)
+ {
state_change = true;
- dmsg (D_TLS_DEBUG_MED, "STATE S_SENT_KEY");
- ks->state = S_SENT_KEY;
+ dmsg (D_TLS_DEBUG, "TLS -> Incoming Plaintext");
}
+ }
- /* Receive Key */
- buf = &ks->plaintext_read_buf;
- if (buf->len
- && ((ks->state == S_SENT_KEY && !session->opt->server)
- || (ks->state == S_START && session->opt->server)))
+ /* Send Key */
+ buf = &ks->plaintext_write_buf;
+ if (!buf->len && ((ks->state == S_START && !session->opt->server) ||
+ (ks->state == S_GOT_KEY && session->opt->server)))
+ {
+ if (session->opt->key_method == 1)
{
- if (session->opt->key_method == 1)
- {
- if (!key_method_1_read (buf, session))
- goto error;
- }
- else if (session->opt->key_method == 2)
- {
- if (!key_method_2_read (buf, multi, session))
- goto error;
- }
- else
- {
- ASSERT (0);
- }
+ if (!key_method_1_write (buf, session))
+ goto error;
+ }
+ else if (session->opt->key_method == 2)
+ {
+ if (!key_method_2_write (buf, session))
+ goto error;
+ }
+ else
+ {
+ ASSERT (0);
+ }
+
+ state_change = true;
+ dmsg (D_TLS_DEBUG_MED, "STATE S_SENT_KEY");
+ ks->state = S_SENT_KEY;
+ }
+ /* Receive Key */
+ buf = &ks->plaintext_read_buf;
+ if (buf->len
+ && ((ks->state == S_SENT_KEY && !session->opt->server)
+ || (ks->state == S_START && session->opt->server)))
+ {
+ if (session->opt->key_method == 1)
+ {
+ if (!key_method_1_read (buf, session))
+ goto error;
+ }
+ else if (session->opt->key_method == 2)
+ {
+ if (!key_method_2_read (buf, multi, session))
+ goto error;
+ }
+ else
+ {
+ ASSERT (0);
+ }
+
+ state_change = true;
+ dmsg (D_TLS_DEBUG_MED, "STATE S_GOT_KEY");
+ ks->state = S_GOT_KEY;
+ }
+
+ /* Write outgoing plaintext to TLS object */
+ buf = &ks->plaintext_write_buf;
+ if (buf->len)
+ {
+ int status = key_state_write_plaintext (&ks->ks_ssl, buf);
+ if (status == -1)
+ {
+ msg (D_TLS_ERRORS,
+ "TLS ERROR: Outgoing Plaintext -> TLS object write error");
+ goto error;
+ }
+ if (status == 1)
+ {
state_change = true;
- dmsg (D_TLS_DEBUG_MED, "STATE S_GOT_KEY");
- ks->state = S_GOT_KEY;
+ dmsg (D_TLS_DEBUG, "Outgoing Plaintext -> TLS");
}
+ }
- /* Write outgoing plaintext to TLS object */
- buf = &ks->plaintext_write_buf;
- if (buf->len)
+ /* Outgoing Ciphertext to reliable buffer */
+ if (ks->state >= S_START)
+ {
+ buf = reliable_get_buf_output_sequenced (ks->send_reliable);
+ if (buf)
{
- int status = key_state_write_plaintext (&ks->ks_ssl, buf);
+ int status = key_state_read_ciphertext (&ks->ks_ssl, buf, PAYLOAD_SIZE_DYNAMIC (&multi->opt.frame));
if (status == -1)
{
msg (D_TLS_ERRORS,
- "TLS ERROR: Outgoing Plaintext -> TLS object write error");
+ "TLS Error: Ciphertext -> reliable TCP/UDP transport read error");
goto error;
}
if (status == 1)
{
+ reliable_mark_active_outgoing (ks->send_reliable, buf, P_CONTROL_V1);
+ INCR_GENERATED;
state_change = true;
- dmsg (D_TLS_DEBUG, "Outgoing Plaintext -> TLS");
- }
- }
-
- /* Outgoing Ciphertext to reliable buffer */
- if (ks->state >= S_START)
- {
- buf = reliable_get_buf_output_sequenced (ks->send_reliable);
- if (buf)
- {
- int status = key_state_read_ciphertext (&ks->ks_ssl, buf, PAYLOAD_SIZE_DYNAMIC (&multi->opt.frame));
- if (status == -1)
- {
- msg (D_TLS_ERRORS,
- "TLS Error: Ciphertext -> reliable TCP/UDP transport read error");
- goto error;
- }
- if (status == 1)
- {
- reliable_mark_active_outgoing (ks->send_reliable, buf, P_CONTROL_V1);
- INCR_GENERATED;
- state_change = true;
- dmsg (D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable");
- }
+ dmsg (D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable");
}
}
}
@@ -2532,11 +2773,11 @@ tls_process (struct tls_multi *multi,
/* Send 1 or more ACKs (each received control packet gets one ACK) */
if (!to_link->len && !reliable_ack_empty (ks->rec_ack))
{
- buf = &ks->ack_write_buf;
- ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame)));
- write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1,
+ struct buffer buf = ks->ack_write_buf;
+ ASSERT (buf_init (&buf, FRAME_HEADROOM (&multi->opt.frame)));
+ write_control_auth (session, ks, &buf, to_link_addr, P_ACK_V1,
RELIABLE_ACK_SIZE, false);
- *to_link = *buf;
+ *to_link = buf;
active = true;
state_change = true;
dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP");
@@ -2775,7 +3016,9 @@ bool
tls_pre_decrypt (struct tls_multi *multi,
const struct link_socket_actual *from,
struct buffer *buf,
- struct crypto_options *opt)
+ struct crypto_options **opt,
+ bool floated,
+ const uint8_t **ad_start)
{
struct gc_arena gc = gc_new ();
bool ret = false;
@@ -2819,18 +3062,29 @@ tls_pre_decrypt (struct tls_multi *multi,
#ifdef ENABLE_DEF_AUTH
&& !ks->auth_deferred
#endif
- && link_socket_actual_match (from, &ks->remote_addr))
+ && (floated || link_socket_actual_match (from, &ks->remote_addr)))
{
- /* return appropriate data channel decrypt key in opt */
- opt->key_ctx_bi = &ks->key;
- opt->packet_id = multi->opt.replay ? &ks->packet_id : NULL;
- opt->pid_persist = NULL;
- opt->flags &= multi->opt.crypto_flags_and;
- opt->flags |= multi->opt.crypto_flags_or;
+ if (!ks->crypto_options.key_ctx_bi.initialized)
+ {
+ msg (D_TLS_DEBUG_LOW,
+ "Key %s [%d] not initialized (yet), dropping packet.",
+ print_link_socket_actual (from, &gc), key_id);
+ goto error_lite;
+ }
- ASSERT (buf_advance (buf, 1));
+ /* return appropriate data channel decrypt key in opt */
+ *opt = &ks->crypto_options;
if (op == P_DATA_V2)
{
+ *ad_start = BPTR(buf);
+ }
+ ASSERT (buf_advance (buf, 1));
+ if (op == P_DATA_V1)
+ {
+ *ad_start = BPTR(buf);
+ }
+ else if (op == P_DATA_V2)
+ {
if (buf->len < 4)
{
msg (D_TLS_ERRORS, "Protocol error: received P_DATA_V2 from %s but length is < 4",
@@ -2848,23 +3102,6 @@ tls_pre_decrypt (struct tls_multi *multi,
gc_free (&gc);
return ret;
}
-#if 0 /* keys out of sync? */
- else
- {
- dmsg (D_TLS_ERRORS, "TLS_PRE_DECRYPT: [%d] dken=%d rkid=%d lkid=%d auth=%d def=%d match=%d",
- i,
- DECRYPT_KEY_ENABLED (multi, ks),
- key_id,
- ks->key_id,
- ks->authenticated,
-#ifdef ENABLE_DEF_AUTH
- ks->auth_deferred,
-#else
- -1,
-#endif
- link_socket_actual_match (from, &ks->remote_addr));
- }
-#endif
}
msg (D_TLS_ERRORS,
@@ -2991,8 +3228,10 @@ tls_pre_decrypt (struct tls_multi *multi,
management_set_state (management,
OPENVPN_STATE_AUTH,
NULL,
- 0,
- 0);
+ NULL,
+ NULL,
+ NULL,
+ NULL);
}
#endif
@@ -3036,7 +3275,7 @@ tls_pre_decrypt (struct tls_multi *multi,
goto error;
}
- if (!read_control_auth (buf, &session->tls_auth, from))
+ if (!read_control_auth (buf, &session->tls_wrap, from))
goto error;
/*
@@ -3087,7 +3326,7 @@ tls_pre_decrypt (struct tls_multi *multi,
if (op == P_CONTROL_SOFT_RESET_V1
&& DECRYPT_KEY_ENABLED (multi, ks))
{
- if (!read_control_auth (buf, &session->tls_auth, from))
+ if (!read_control_auth (buf, &session->tls_wrap, from))
goto error;
key_state_soft_reset (session);
@@ -3104,7 +3343,7 @@ tls_pre_decrypt (struct tls_multi *multi,
if (op == P_CONTROL_SOFT_RESET_V1)
do_burst = true;
- if (!read_control_auth (buf, &session->tls_auth, from))
+ if (!read_control_auth (buf, &session->tls_wrap, from))
goto error;
dmsg (D_TLS_DEBUG,
@@ -3215,10 +3454,7 @@ tls_pre_decrypt (struct tls_multi *multi,
done:
buf->len = 0;
- opt->key_ctx_bi = NULL;
- opt->packet_id = NULL;
- opt->pid_persist = NULL;
- opt->flags &= multi->opt.crypto_flags_and;
+ *opt = NULL;
gc_free (&gc);
return ret;
@@ -3297,18 +3533,11 @@ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
{
struct buffer newbuf = clone_buf (buf);
- struct crypto_options co = tas->tls_auth_options;
+ struct tls_wrap_ctx tls_wrap_tmp = tas->tls_wrap;
bool status;
- /*
- * We are in read-only mode at this point with respect to TLS
- * control channel state. After we build a new client instance
- * object, we will process this session-initiating packet for real.
- */
- co.flags |= CO_IGNORE_PACKET_ID;
-
/* HMAC test, if --tls-auth was specified */
- status = read_control_auth (&newbuf, &co, from);
+ status = read_control_auth (&newbuf, &tls_wrap_tmp, from);
free_buf (&newbuf);
if (!status)
goto error;
@@ -3344,7 +3573,7 @@ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
/* Choose the key with which to encrypt a data packet */
void
tls_pre_encrypt (struct tls_multi *multi,
- struct buffer *buf, struct crypto_options *opt)
+ struct buffer *buf, struct crypto_options **opt)
{
multi->save_ks = NULL;
if (buf->len > 0)
@@ -3356,6 +3585,7 @@ tls_pre_encrypt (struct tls_multi *multi,
struct key_state *ks = multi->key_scan[i];
if (ks->state >= S_ACTIVE
&& ks->authenticated
+ && ks->crypto_options.key_ctx_bi.initialized
#ifdef ENABLE_DEF_AUTH
&& !ks->auth_deferred
#endif
@@ -3373,11 +3603,7 @@ tls_pre_encrypt (struct tls_multi *multi,
if (ks_select)
{
- opt->key_ctx_bi = &ks_select->key;
- opt->packet_id = multi->opt.replay ? &ks_select->packet_id : NULL;
- opt->pid_persist = NULL;
- opt->flags &= multi->opt.crypto_flags_and;
- opt->flags |= multi->opt.crypto_flags_or;
+ *opt = &ks_select->crypto_options;
multi->save_ks = ks_select;
dmsg (D_TLS_KEYSELECT, "TLS: tls_pre_encrypt: key_id=%d", ks_select->key_id);
return;
@@ -3392,36 +3618,48 @@ tls_pre_encrypt (struct tls_multi *multi,
}
buf->len = 0;
- opt->key_ctx_bi = NULL;
- opt->packet_id = NULL;
- opt->pid_persist = NULL;
- opt->flags &= multi->opt.crypto_flags_and;
+ *opt = NULL;
}
-/* Prepend the appropriate opcode to encrypted buffer prior to TCP/UDP send */
void
-tls_post_encrypt (struct tls_multi *multi, struct buffer *buf)
+tls_prepend_opcode_v1 (const struct tls_multi *multi, struct buffer *buf)
{
- struct key_state *ks;
- uint8_t *op;
+ struct key_state *ks = multi->save_ks;
+ uint8_t op;
+
+ msg (D_TLS_DEBUG, __func__);
+
+ ASSERT (ks);
+
+ op = (P_DATA_V1 << P_OPCODE_SHIFT) | ks->key_id;
+ ASSERT (buf_write_prepend (buf, &op, 1));
+}
+
+void
+tls_prepend_opcode_v2 (const struct tls_multi *multi, struct buffer *buf)
+{
+ struct key_state *ks = multi->save_ks;
uint32_t peer;
- ks = multi->save_ks;
+ msg (D_TLS_DEBUG, __func__);
+
+ ASSERT (ks);
+
+ peer = htonl(((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24
+ | (multi->peer_id & 0xFFFFFF));
+ ASSERT (buf_write_prepend (buf, &peer, 4));
+}
+
+void
+tls_post_encrypt (struct tls_multi *multi, struct buffer *buf)
+{
+ struct key_state *ks = multi->save_ks;
multi->save_ks = NULL;
+
if (buf->len > 0)
{
ASSERT (ks);
- if (!multi->opt.server && multi->use_peer_id)
- {
- peer = htonl(((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24 | (multi->peer_id & 0xFFFFFF));
- ASSERT (buf_write_prepend (buf, &peer, 4));
- }
- else
- {
- ASSERT (op = buf_prepend (buf, 1));
- *op = (P_DATA_V1 << P_OPCODE_SHIFT) | ks->key_id;
- }
++ks->n_packets;
ks->n_bytes += buf->len;
}
@@ -3494,6 +3732,70 @@ tls_rec_payload (struct tls_multi *multi,
return ret;
}
+void
+tls_update_remote_addr (struct tls_multi *multi, const struct link_socket_actual *addr)
+{
+ struct gc_arena gc = gc_new ();
+ int i, j;
+
+ for (i = 0; i < TM_SIZE; ++i)
+ {
+ struct tls_session *session = &multi->session[i];
+
+ for (j = 0; j < KS_SIZE; ++j)
+ {
+ struct key_state *ks = &session->key[j];
+
+ if (!link_socket_actual_defined(&ks->remote_addr) ||
+ link_socket_actual_match (addr, &ks->remote_addr))
+ continue;
+
+ dmsg (D_TLS_KEYSELECT, "TLS: tls_update_remote_addr from IP=%s to IP=%s",
+ print_link_socket_actual (&ks->remote_addr, &gc),
+ print_link_socket_actual (addr, &gc));
+
+ ks->remote_addr = *addr;
+ }
+ }
+ gc_free (&gc);
+}
+
+int
+tls_peer_info_ncp_ver(const char *peer_info)
+{
+ const char *ncpstr = peer_info ? strstr (peer_info, "IV_NCP=") : NULL;
+ if (ncpstr)
+ {
+ int ncp = 0;
+ int r = sscanf(ncpstr, "IV_NCP=%d", &ncp);
+ if (r == 1)
+ return ncp;
+ }
+ return 0;
+}
+
+bool
+tls_check_ncp_cipher_list(const char *list) {
+ bool unsupported_cipher_found = false;
+
+ ASSERT (list);
+
+ char * const tmp_ciphers = string_alloc (list, NULL);
+ const char *token = strtok (tmp_ciphers, ":");
+ while (token)
+ {
+ if (!cipher_kt_get (translate_cipher_name_from_openvpn (token)))
+ {
+ msg (M_WARN, "Unsupported cipher in --ncp-ciphers: %s", token);
+ unsupported_cipher_found = true;
+ }
+ token = strtok (NULL, ":");
+ }
+ free (tmp_ciphers);
+
+ return 0 < strlen(list) && !unsupported_cipher_found;
+}
+
/*
* Dump a human-readable rendition of an openvpn packet
* into a garbage collectable string which is returned.
@@ -3594,4 +3896,4 @@ done:
#else
static void dummy(void) {}
-#endif /* ENABLE_CRYPTO && ENABLE_SSL*/
+#endif /* ENABLE_CRYPTO */
diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h
index 6a14768..777b621 100644
--- a/src/openvpn/ssl.h
+++ b/src/openvpn/ssl.h
@@ -30,7 +30,7 @@
#ifndef OPENVPN_SSL_H
#define OPENVPN_SSL_H
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#if defined(ENABLE_CRYPTO)
#include "basic.h"
#include "common.h"
@@ -44,7 +44,6 @@
#include "plugin.h"
#include "ssl_common.h"
-#include "ssl_verify.h"
#include "ssl_backend.h"
/* Used in the TLS PRF function */
@@ -137,8 +136,7 @@
*/
struct tls_auth_standalone
{
- struct key_ctx_bi tls_auth_key;
- struct crypto_options tls_auth_options;
+ struct tls_wrap_ctx tls_wrap;
struct frame frame;
};
@@ -294,9 +292,10 @@ int tls_multi_process (struct tls_multi *multi,
* of this packet.
* @param from - The source address of the packet.
* @param buf - A buffer structure containing the incoming packet.
- * @param opt - A crypto options structure that will be loaded with the
- * appropriate security parameters to handle the packet if it is a
- * data channel packet.
+ * @param opt - Returns a crypto options structure with the appropriate security
+ * parameters to handle the packet if it is a data channel packet.
+ * @param ad_start - Returns a pointer to the start of the authenticated data of
+ * of this packet
*
* @return
* @li True if the packet is a control channel packet that has been
@@ -307,7 +306,9 @@ int tls_multi_process (struct tls_multi *multi,
bool tls_pre_decrypt (struct tls_multi *multi,
const struct link_socket_actual *from,
struct buffer *buf,
- struct crypto_options *opt);
+ struct crypto_options **opt,
+ bool floated,
+ const uint8_t **ad_start);
/**************************************************************************/
@@ -356,20 +357,53 @@ bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
* @ingroup data_crypto
*
* If no appropriate security parameters can be found, or if some other
- * error occurs, then the buffer is set to empty.
+ * error occurs, then the buffer is set to empty, and the parameters to a NULL
+ * pointer.
*
* @param multi - The TLS state for this packet's destination VPN tunnel.
* @param buf - The buffer containing the outgoing packet.
- * @param opt - The crypto options structure into which the appropriate
- * security parameters should be loaded.
+ * @param opt - Returns a crypto options structure with the security parameters.
*/
void tls_pre_encrypt (struct tls_multi *multi,
- struct buffer *buf, struct crypto_options *opt);
+ struct buffer *buf, struct crypto_options **opt);
/**
- * Prepend the one-byte OpenVPN header to the packet, and perform some
- * accounting for the key state used.
+ * Prepend a one-byte OpenVPN data channel P_DATA_V1 opcode to the packet.
+ *
+ * The opcode identifies the packet as a V1 data channel packet and gives the
+ * low-permutation version of the key-id to the recipient, so it knows which
+ * decrypt key to use.
+ *
+ * @param multi - The TLS state for this packet's destination VPN tunnel.
+ * @param buf - The buffer to write the header to.
+ *
+ * @ingroup data_crypto
+ */
+void
+tls_prepend_opcode_v1 (const struct tls_multi *multi, struct buffer *buf);
+
+/**
+ * Prepend an OpenVPN data channel P_DATA_V2 header to the packet. The
+ * P_DATA_V2 header consists of a 1-byte opcode, followed by a 3-byte peer-id.
+ *
+ * The opcode identifies the packet as a V2 data channel packet and gives the
+ * low-permutation version of the key-id to the recipient, so it knows which
+ * decrypt key to use.
+ *
+ * The peer-id is sent by clients to servers to help the server determine to
+ * select the decrypt key when the client is roaming between addresses/ports.
+ *
+ * @param multi - The TLS state for this packet's destination VPN tunnel.
+ * @param buf - The buffer to write the header to.
+ *
+ * @ingroup data_crypto
+ */
+void
+tls_prepend_opcode_v2 (const struct tls_multi *multi, struct buffer *buf);
+
+/**
+ * Perform some accounting for the key state used.
* @ingroup data_crypto
*
* @param multi - The TLS state for this packet's destination VPN tunnel.
@@ -432,6 +466,29 @@ bool tls_send_payload (struct tls_multi *multi,
bool tls_rec_payload (struct tls_multi *multi,
struct buffer *buf);
+/**
+ * Updates remote address in TLS sessions.
+ *
+ * @param multi - Tunnel to update
+ * @param addr - new address
+ */
+void tls_update_remote_addr (struct tls_multi *multi,
+ const struct link_socket_actual *addr);
+
+/**
+ * Update TLS session crypto parameters (cipher and auth) and derive data
+ * channel keys based on the supplied options.
+ *
+ * @param session The TLS session to update.
+ * @param options The options to use when updating session.
+ * @param frame The frame options for this session (frame overhead is
+ * adjusted based on the selected cipher/auth).
+ *
+ * @return true if updating succeeded, false otherwise.
+ */
+bool tls_session_update_crypto_params(struct tls_session *session,
+ const struct options *options, struct frame *frame);
+
#ifdef MANAGEMENT_DEF_AUTH
static inline char *
tls_get_peer_info(const struct tls_multi *multi)
@@ -440,6 +497,21 @@ tls_get_peer_info(const struct tls_multi *multi)
}
#endif
+/**
+ * Return the Negotiable Crypto Parameters version advertised in the peer info
+ * string, or 0 if none specified.
+ */
+int tls_peer_info_ncp_ver(const char *peer_info);
+
+/**
+ * Check whether the ciphers in the supplied list are supported.
+ *
+ * @param list Colon-separated list of ciphers
+ *
+ * @returns true iff all ciphers in list are supported.
+ */
+bool tls_check_ncp_cipher_list(const char *list);
+
/*
* inline functions
*/
@@ -503,6 +575,6 @@ void show_tls_performance_stats(void);
/*#define EXTRACT_X509_FIELD_TEST*/
void extract_x509_field_test (void);
-#endif /* ENABLE_CRYPTO && ENABLE_SSL */
+#endif /* ENABLE_CRYPTO */
#endif
diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
index 4b35e51..0777c61 100644
--- a/src/openvpn/ssl_backend.h
+++ b/src/openvpn/ssl_backend.h
@@ -38,10 +38,10 @@
#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
+#ifdef ENABLE_CRYPTO_MBEDTLS
+#include "ssl_mbedtls.h"
+#include "ssl_verify_mbedtls.h"
+#define SSLAPI SSLAPI_MBEDTLS
#endif
/* Ensure that SSLAPI got a sane value if SSL is disabled or unknown */
@@ -124,21 +124,21 @@ int tls_version_parse(const char *vstr, const char *extra);
*/
int tls_version_max(void);
+#ifdef ENABLE_CRYPTO
+
/**
* Initialise a library-specific TLS context for a server.
*
* @param ctx TLS context to initialise
- * @param ssl_flags SSLF_x flags from ssl_common.h
*/
-void tls_ctx_server_new(struct tls_root_ctx *ctx, unsigned int ssl_flags);
+void tls_ctx_server_new(struct tls_root_ctx *ctx);
/**
* Initialises a library-specific TLS context for a client.
*
* @param ctx TLS context to initialise
- * @param ssl_flags SSLF_x flags from ssl_common.h
*/
-void tls_ctx_client_new(struct tls_root_ctx *ctx, unsigned int ssl_flags);
+void tls_ctx_client_new(struct tls_root_ctx *ctx);
/**
* Frees the library-specific TLSv1 context
@@ -170,8 +170,9 @@ void tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags);
/**
* Restrict the list of ciphers that can be used within the TLS context.
*
- * @param ctx TLS context to restrict
- * @param ciphers String containing : delimited cipher names.
+ * @param ctx TLS context to restrict, must be valid.
+ * @param ciphers String containing : delimited cipher names, or NULL to use
+ * sane defaults.
*/
void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers);
@@ -197,6 +198,16 @@ void tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file,
const char *dh_file_inline);
/**
+ * Load Elliptic Curve Parameters, and load them into the library-specific
+ * TLS context.
+ *
+ * @param ctx TLS context to use
+ * @param curve_name The name of the elliptic curve to load.
+ */
+void tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
+ );
+
+/**
* Load PKCS #12 file for key, cert and (optionally) CA certs, and add to
* library-specific TLS context.
*
@@ -221,7 +232,7 @@ int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
*/
#ifdef ENABLE_CRYPTOAPI
void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert);
-#endif /* WIN32 */
+#endif /* _WIN32 */
/**
* Load certificate file into the given TLS context. If the given certificate
@@ -299,9 +310,9 @@ void tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs
const char *extra_certs_file_inline
);
-#ifdef ENABLE_CRYPTO_POLARSSL
+#ifdef ENABLE_CRYPTO_MBEDTLS
/**
- * Add a personalisation string to the PolarSSL RNG, based on the certificate
+ * Add a personalisation string to the mbed TLS RNG, based on the certificate
* loaded into the given context.
*
* @param ctx TLS context to use
@@ -334,6 +345,30 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
*/
void key_state_ssl_free(struct key_state_ssl *ks_ssl);
+/**
+ * Reload the Certificate Revocation List for the SSL channel
+ *
+ * @param ssl_ctx The TLS context to use when reloading the CRL
+ * @param crl_file The file name to load the CRL from, or
+ * "[[INLINE]]" in the case of inline files.
+ * @param crl_inline A string containing the CRL
+ */
+void tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx,
+ const char *crl_file, const char *crl_inline);
+
+/**
+ * Keying Material Exporters [RFC 5705] allows additional keying material to be
+ * derived from existing TLS channel. This exported keying material can then be
+ * used for a variety of purposes.
+ *
+ * @param ks_ssl The SSL channel's state info
+ * @param session The session associated with the given key_state
+ */
+
+void
+key_state_export_keying_material(struct key_state_ssl *ks_ssl,
+ struct tls_session *session) __attribute__((nonnull));
+
/**************************************************************************/
/** @addtogroup control_tls
* @{ */
@@ -472,6 +507,11 @@ void print_details (struct key_state_ssl * ks_ssl, const char *prefix);
void show_available_tls_ciphers (const char *tls_ciphers);
/*
+ * Show the available elliptic curves in the crypto library
+ */
+void show_available_curves (void);
+
+/*
* The OpenSSL library has a notion of preference in TLS ciphers. Higher
* preference == more secure. Return the highest preference cipher.
*/
@@ -483,4 +523,5 @@ void get_highest_preference_tls_cipher (char *buf, int size);
*/
const char * get_ssl_library_version(void);
+#endif /* ENABLE_CRYPTO */
#endif /* SSL_BACKEND_H_ */
diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h
index 449172d..28702af 100644
--- a/src/openvpn/ssl_common.h
+++ b/src/openvpn/ssl_common.h
@@ -149,7 +149,12 @@ struct key_source2 {
struct key_state
{
int state;
- int key_id; /* inherited from struct tls_session below */
+
+ /**
+ * Key id for this key_state, inherited from struct tls_session.
+ * @see tls_session::key_id.
+ */
+ int key_id;
struct key_state_ssl ks_ssl; /* contains SSL object and BIOs for the control channel */
@@ -160,9 +165,8 @@ struct key_state
int initial_opcode; /* our initial P_ opcode */
struct session_id session_id_remote; /* peer's random session ID */
struct link_socket_actual remote_addr; /* peer's IP addr */
- struct packet_id packet_id; /* for data channel, to prevent replay attacks */
- struct key_ctx_bi key; /* data channel keys for encrypt/decrypt/hmac */
+ struct crypto_options crypto_options;/* data channel crypto options */
struct key_source2 *key_src; /* source entropy for key expansion */
@@ -200,6 +204,18 @@ struct key_state
#endif
};
+/** Control channel wrapping (--tls-auth/--tls-crypt) context */
+struct tls_wrap_ctx
+{
+ enum {
+ TLS_WRAP_NONE = 0, /**< No control channel wrapping */
+ TLS_WRAP_AUTH, /**< Control channel authentication */
+ TLS_WRAP_CRYPT, /**< Control channel encryption and authentication */
+ } mode; /**< Control channel wrapping mode */
+ struct crypto_options opt; /**< Crypto state */
+ struct buffer work; /**< Work buffer (only for --tls-crypt) */
+};
+
/*
* Our const options, obtained directly or derived from
* command line options.
@@ -232,6 +248,8 @@ struct tls_options
#ifdef ENABLE_OCC
bool disable_occ;
#endif
+ int mode;
+ bool pull;
#ifdef ENABLE_PUSH_PEER_INFO
int push_peer_info_detail;
#endif
@@ -248,6 +266,7 @@ struct tls_options
int verify_x509_type;
const char *verify_x509_name;
const char *crl_file;
+ const char *crl_file_inline;
int ns_cert_type;
unsigned remote_cert_ku[MAX_PARMS];
const char *remote_cert_eku;
@@ -259,6 +278,7 @@ struct tls_options
bool pass_config_info;
/* struct crypto_option flags */
+ unsigned int crypto_flags;
unsigned int crypto_flags_and;
unsigned int crypto_flags_or;
@@ -266,9 +286,12 @@ struct tls_options
int replay_time; /* --replay-window parm */
bool tcp_mode;
- /* packet authentication for TLS handshake */
- struct crypto_options tls_auth;
- struct key_ctx_bi tls_auth_key;
+ const char *config_ciphername;
+ const char *config_authname;
+ bool ncp_enabled;
+
+ /** TLS handshake wrapping state */
+ struct tls_wrap_ctx tls_wrap;
/* frame parameters for TLS control channel */
struct frame frame;
@@ -278,6 +301,9 @@ struct tls_options
bool auth_user_pass_verify_script_via_file;
const char *tmp_dir;
const char *auth_user_pass_file;
+ bool auth_token_generate; /**< Generate auth-tokens on successful user/pass auth,
+ * set via options->auth_token_generate. */
+ unsigned int auth_token_lifetime;
/* use the client-config-dir as a positive authenticator */
const char *client_config_dir_exclusive;
@@ -286,10 +312,16 @@ struct tls_options
struct env_set *es;
const struct plugin_list *plugins;
+ /* compression parms */
+#ifdef USE_COMP
+ struct compress_options comp_options;
+#endif
+
/* 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_CLIENT_CERT_OPTIONAL (1<<1)
+# define SSLF_USERNAME_AS_COMMON_NAME (1<<2)
+# define SSLF_AUTH_USER_PASS_OPTIONAL (1<<3)
# define SSLF_OPT_VERIFY (1<<4)
# define SSLF_CRL_VERIFY_DIR (1<<5)
# define SSLF_TLS_VERSION_MIN_SHIFT 6
@@ -302,9 +334,7 @@ struct tls_options
struct man_def_auth_context *mda_context;
#endif
-#ifdef ENABLE_X509_TRACK
const struct x509_track *x509_track;
-#endif
#ifdef ENABLE_CLIENT_CR
const struct static_challenge_info *sci;
@@ -312,6 +342,11 @@ struct tls_options
/* --gremlin bits */
int gremlin;
+
+ /* Keying Material Exporter [RFC 5705] parameters */
+ const char *ekm_label;
+ size_t ekm_label_size;
+ size_t ekm_size;
};
/** @addtogroup control_processor
@@ -328,6 +363,9 @@ struct tls_options
/** @} name Index of key_state objects within a tls_session structure */
/** @} addtogroup control_processor */
+#define AUTH_TOKEN_SIZE 32 /**< Size of server side generated auth tokens.
+ * 32 bytes == 256 bits
+ */
/**
* Security parameter state of a single session within a VPN tunnel.
@@ -354,12 +392,17 @@ struct tls_session
bool burst;
/* authenticate control packets */
- struct crypto_options tls_auth;
- struct packet_id tls_auth_pid;
+ struct tls_wrap_ctx tls_wrap;
int initial_opcode; /* our initial P_ opcode */
struct session_id session_id; /* our random session ID */
- int key_id; /* increments with each soft reset (for key renegotiation) */
+
+ /**
+ * The current active key id, used to keep track of renegotiations.
+ * key_id increments with each soft reset to KEY_ID_MASK then recycles back
+ * to 1. This way you know that if key_id is 0, it is the first key.
+ */
+ int key_id;
int limit_next; /* used for traffic shaping on the control channel */
@@ -481,20 +524,29 @@ struct tls_multi
*/
char *client_reason;
+ /* Time of last call to tls_authentication_status */
+ time_t tas_last;
+#endif
+
+#if P2MP_SERVER
/*
* A multi-line string of general-purpose info received from peer
* over control channel.
*/
char *peer_info;
-
- /* Time of last call to tls_authentication_status */
- time_t tas_last;
#endif
/* For P_DATA_V2 */
uint32_t peer_id;
bool use_peer_id;
+ char *auth_token; /**< If server sends a generated auth-token,
+ * this is the token to use for future
+ * user/pass authentications in this session.
+ */
+ time_t auth_token_tstamp; /**< timestamp of the generated token */
+ bool auth_token_sent; /**< If server uses --auth-gen-token and
+ * token has been sent to client */
/*
* Our session objects.
*/
diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_mbedtls.c
index 1f58369..7fa35a7 100644
--- a/src/openvpn/ssl_polarssl.c
+++ b/src/openvpn/ssl_mbedtls.c
@@ -25,7 +25,7 @@
*/
/**
- * @file Control Channel PolarSSL Backend
+ * @file Control Channel mbed TLS Backend
*/
#ifdef HAVE_CONFIG_H
@@ -36,7 +36,7 @@
#include "syshead.h"
-#if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL)
+#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS)
#include "errlevel.h"
#include "ssl_backend.h"
@@ -46,15 +46,16 @@
#include "manage.h"
#include "ssl_common.h"
-#include <polarssl/havege.h>
+#include <mbedtls/havege.h>
-#include "ssl_verify_polarssl.h"
-#include <polarssl/debug.h>
-#include <polarssl/error.h>
-#include <polarssl/oid.h>
-#include <polarssl/pem.h>
-#include <polarssl/sha256.h>
-#include <polarssl/version.h>
+#include "ssl_verify_mbedtls.h"
+#include <mbedtls/debug.h>
+#include <mbedtls/error.h>
+#include <mbedtls/net.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/pem.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/version.h>
void
tls_init_lib()
@@ -72,29 +73,29 @@ tls_clear_error()
}
void
-tls_ctx_server_new(struct tls_root_ctx *ctx, unsigned int ssl_flags)
+tls_ctx_server_new(struct tls_root_ctx *ctx)
{
ASSERT(NULL != ctx);
CLEAR(*ctx);
- ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
+ ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context);
- ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt);
+ ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt);
- ctx->endpoint = SSL_IS_SERVER;
+ ctx->endpoint = MBEDTLS_SSL_IS_SERVER;
ctx->initialised = true;
}
void
-tls_ctx_client_new(struct tls_root_ctx *ctx, unsigned int ssl_flags)
+tls_ctx_client_new(struct tls_root_ctx *ctx)
{
ASSERT(NULL != ctx);
CLEAR(*ctx);
- ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
- ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt);
+ ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context);
+ ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt);
- ctx->endpoint = SSL_IS_CLIENT;
+ ctx->endpoint = MBEDTLS_SSL_IS_CLIENT;
ctx->initialised = true;
}
@@ -103,25 +104,31 @@ tls_ctx_free(struct tls_root_ctx *ctx)
{
if (ctx)
{
- pk_free(ctx->priv_key);
+ mbedtls_pk_free(ctx->priv_key);
if (ctx->priv_key)
free(ctx->priv_key);
- x509_crt_free(ctx->ca_chain);
+ mbedtls_x509_crt_free(ctx->ca_chain);
if (ctx->ca_chain)
free(ctx->ca_chain);
- x509_crt_free(ctx->crt_chain);
+ mbedtls_x509_crt_free(ctx->crt_chain);
if (ctx->crt_chain)
free(ctx->crt_chain);
- dhm_free(ctx->dhm_ctx);
+ mbedtls_dhm_free(ctx->dhm_ctx);
if (ctx->dhm_ctx)
free(ctx->dhm_ctx);
+ mbedtls_x509_crl_free(ctx->crl);
+ if (ctx->crl)
+ {
+ free(ctx->crl);
+ }
+
#if defined(ENABLE_PKCS11)
if (ctx->priv_key_pkcs11 != NULL) {
- pkcs11_priv_key_free(ctx->priv_key_pkcs11);
+ mbedtls_pkcs11_priv_key_free(ctx->priv_key_pkcs11);
free(ctx->priv_key_pkcs11);
}
#endif
@@ -148,6 +155,12 @@ tls_ctx_initialised(struct tls_root_ctx *ctx)
}
void
+key_state_export_keying_material(struct key_state_ssl *ssl,
+ struct tls_session *session)
+{
+}
+
+void
tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
{
}
@@ -176,7 +189,12 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
{
char *tmp_ciphers, *tmp_ciphers_orig, *token;
int i, cipher_count;
- int ciphers_len = strlen (ciphers);
+ int ciphers_len;
+
+ if (NULL == ciphers)
+ return; /* Nothing to do */
+
+ ciphers_len = strlen (ciphers);
ASSERT (NULL != ctx);
ASSERT (0 != ciphers_len);
@@ -196,7 +214,7 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
token = strtok (tmp_ciphers, ":");
while(token)
{
- ctx->allowed_ciphers[i] = ssl_get_ciphersuite_id (
+ ctx->allowed_ciphers[i] = mbedtls_ssl_get_ciphersuite_id (
tls_translate_cipher_name (token));
if (0 != ctx->allowed_ciphers[i])
i++;
@@ -214,12 +232,12 @@ tls_ctx_check_cert_time (const struct tls_root_ctx *ctx)
return; /* Nothing to check if there is no certificate */
}
- if (x509_time_future (&ctx->crt_chain->valid_from))
+ if (mbedtls_x509_time_is_future (&ctx->crt_chain->valid_from))
{
msg (M_WARN, "WARNING: Your certificate is not yet valid!");
}
- if (x509_time_expired (&ctx->crt_chain->valid_to))
+ if (mbedtls_x509_time_is_past (&ctx->crt_chain->valid_to))
{
msg (M_WARN, "WARNING: Your certificate has expired!");
}
@@ -232,18 +250,27 @@ tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
{
if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_inline)
{
- if (!polar_ok(dhm_parse_dhm(ctx->dhm_ctx,
- (const unsigned char *) dh_inline, strlen(dh_inline))))
+ if (!mbed_ok(mbedtls_dhm_parse_dhm(ctx->dhm_ctx,
+ (const unsigned char *) dh_inline, strlen(dh_inline)+1)))
msg (M_FATAL, "Cannot read inline DH parameters");
}
else
{
- if (!polar_ok(dhm_parse_dhmfile(ctx->dhm_ctx, dh_file)))
+ if (!mbed_ok(mbedtls_dhm_parse_dhmfile(ctx->dhm_ctx, dh_file)))
msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file);
}
msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with " counter_format " bit key",
- (counter_type) 8 * mpi_size(&ctx->dhm_ctx->P));
+ (counter_type) 8 * mbedtls_mpi_size(&ctx->dhm_ctx->P));
+}
+
+void
+tls_ctx_load_ecdh_params (struct tls_root_ctx *ctx, const char *curve_name
+ )
+{
+ if (NULL != curve_name)
+ msg(M_WARN, "WARNING: mbed TLS builds do not support specifying an ECDH "
+ "curve, using default curves.");
}
int
@@ -252,7 +279,7 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
bool load_ca_file
)
{
- msg(M_FATAL, "PKCS #12 files not yet supported for PolarSSL.");
+ msg(M_FATAL, "PKCS #12 files not yet supported for mbed TLS.");
return 0;
}
@@ -260,9 +287,9 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
void
tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
{
- msg(M_FATAL, "Windows CryptoAPI not yet supported for PolarSSL.");
+ msg(M_FATAL, "Windows CryptoAPI not yet supported for mbed TLS.");
}
-#endif /* WIN32 */
+#endif /* _WIN32 */
void
tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
@@ -273,18 +300,18 @@ tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
if (!ctx->crt_chain)
{
- ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt);
+ ALLOC_OBJ_CLEAR(ctx->crt_chain, mbedtls_x509_crt);
}
if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_inline)
{
- if (!polar_ok(x509_crt_parse(ctx->crt_chain,
- (const unsigned char *) cert_inline, strlen(cert_inline))))
+ if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain,
+ (const unsigned char *) cert_inline, strlen(cert_inline)+1)))
msg (M_FATAL, "Cannot load inline certificate file");
}
else
{
- if (!polar_ok(x509_crt_parse_file(ctx->crt_chain, cert_file)))
+ if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, cert_file)))
{
msg (M_FATAL, "Cannot load certificate file %s", cert_file);
}
@@ -301,51 +328,51 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
if (!ctx->priv_key)
{
- ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context);
+ ALLOC_OBJ_CLEAR(ctx->priv_key, mbedtls_pk_context);
}
if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_inline)
{
- status = pk_parse_key(ctx->priv_key,
- (const unsigned char *) priv_key_inline, strlen(priv_key_inline),
+ status = mbedtls_pk_parse_key(ctx->priv_key,
+ (const unsigned char *) priv_key_inline, strlen(priv_key_inline)+1,
NULL, 0);
- if (POLARSSL_ERR_PK_PASSWORD_REQUIRED == status)
+ if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status)
{
char passbuf[512] = {0};
pem_password_callback(passbuf, 512, 0, NULL);
- status = pk_parse_key(ctx->priv_key,
- (const unsigned char *) priv_key_inline, strlen(priv_key_inline),
- (unsigned char *) passbuf, strlen(passbuf));
+ status = mbedtls_pk_parse_key(ctx->priv_key,
+ (const unsigned char *) priv_key_inline,
+ strlen(priv_key_inline)+1, (unsigned char *) passbuf,
+ strlen(passbuf));
}
}
else
{
- status = pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL);
- if (POLARSSL_ERR_PK_PASSWORD_REQUIRED == status)
+ status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL);
+ if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status)
{
char passbuf[512] = {0};
pem_password_callback(passbuf, 512, 0, NULL);
- status = pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
+ status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
}
}
- if (!polar_ok(status))
+ if (!mbed_ok(status))
{
#ifdef ENABLE_MANAGEMENT
- if (management && (POLARSSL_ERR_PK_PASSWORD_MISMATCH == status))
+ if (management && (MBEDTLS_ERR_PK_PASSWORD_MISMATCH == status))
management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
#endif
msg (M_WARN, "Cannot load private key file %s", priv_key_file);
return 1;
}
- warn_if_group_others_accessible (priv_key_file);
+ if (!mbed_ok(mbedtls_pk_check_pair(&ctx->crt_chain->pk, ctx->priv_key)))
+ {
+ msg (M_WARN, "Private key does not match the certificate");
+ return 1;
+ }
- /* TODO: Check Private Key */
-#if 0
- if (!SSL_CTX_check_private_key (ctx))
- msg (M_SSLERR, "Private key does not match the certificate");
-#endif
return 0;
}
@@ -357,7 +384,7 @@ struct external_context {
};
/**
- * external_pkcs1_sign implements a PolarSSL rsa_sign_func callback, that uses
+ * external_pkcs1_sign implements a mbed TLS rsa_sign_func callback, that uses
* the management interface to request an RSA signature for the supplied hash.
*
* @param ctx_voidptr Management external key context.
@@ -366,18 +393,18 @@ struct external_context {
* @param mode RSA mode (should be RSA_PRIVATE).
* @param md_alg Message digest ('hash') algorithm type.
* @param hashlen Length of hash (overridden by length specified by md_alg
- * if md_alg != POLARSSL_MD_NONE).
+ * if md_alg != MBEDTLS_MD_NONE).
* @param hash The digest ('hash') to sign. Should have a size
- * matching the length of md_alg (if != POLARSSL_MD_NONE),
+ * matching the length of md_alg (if != MBEDTLS_MD_NONE),
* or hashlen otherwise.
* @param sig Buffer that returns the signature. Should be at least of
* size ctx->signature_length.
*
- * @return 0 on success, non-zero polarssl error code on failure.
+ * @return 0 on success, non-zero mbed TLS error code on failure.
*/
static inline int external_pkcs1_sign( void *ctx_voidptr,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode,
- md_type_t md_alg, unsigned int hashlen, const unsigned char *hash,
+ mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash,
unsigned char *sig )
{
struct external_context * const ctx = ctx_voidptr;
@@ -389,35 +416,35 @@ static inline int external_pkcs1_sign( void *ctx_voidptr,
const char *oid = NULL;
if( NULL == ctx )
- return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+ return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
- if( RSA_PRIVATE != mode )
- return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+ if( MBEDTLS_RSA_PRIVATE != mode )
+ return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
/*
* Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW,
* but TLSv1.2 needs the full suite of hashes.
*
- * This code has been taken from PolarSSL pkcs11_sign(), under the GPLv2.0+.
+ * This code has been taken from mbed TLS pkcs11_sign(), under the GPLv2.0+.
*/
- if( md_alg != POLARSSL_MD_NONE )
+ if( md_alg != MBEDTLS_MD_NONE )
{
- const md_info_t *md_info = md_info_from_type( md_alg );
+ const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg );
if( md_info == NULL )
- return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
- if (!polar_ok(oid_get_oid_by_md( md_alg, &oid, &oid_size )))
- return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+ if (!mbed_ok(mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size )))
+ return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
- hashlen = md_get_size( md_info );
+ hashlen = mbedtls_md_get_size( md_info );
asn_len = 10 + oid_size;
}
sig_len = ctx->signature_length;
if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len )
- return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+ return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
- if( md_alg != POLARSSL_MD_NONE )
+ if( md_alg != MBEDTLS_MD_NONE )
{
/*
* DigestInfo ::= SEQUENCE {
@@ -428,17 +455,17 @@ static inline int external_pkcs1_sign( void *ctx_voidptr,
*
* Digest ::= OCTET STRING
*/
- *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
+ *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
*p++ = (unsigned char) ( 0x08 + oid_size + hashlen );
- *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
+ *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
*p++ = (unsigned char) ( 0x04 + oid_size );
- *p++ = ASN1_OID;
+ *p++ = MBEDTLS_ASN1_OID;
*p++ = oid_size & 0xFF;
memcpy( p, oid, oid_size );
p += oid_size;
- *p++ = ASN1_NULL;
+ *p++ = MBEDTLS_ASN1_NULL;
*p++ = 0x00;
- *p++ = ASN1_OCTET_STRING;
+ *p++ = MBEDTLS_ASN1_OCTET_STRING;
*p++ = hashlen;
/* Determine added ASN length */
@@ -451,7 +478,7 @@ static inline int external_pkcs1_sign( void *ctx_voidptr,
/* convert 'from' to base64 */
if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0)
{
- rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+ rv = MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
goto done;
}
@@ -460,7 +487,7 @@ static inline int external_pkcs1_sign( void *ctx_voidptr,
out_b64 = management_query_rsa_sig (management, in_b64);
if (!out_b64)
{
- rv = POLARSSL_ERR_RSA_PRIVATE_FAILED;
+ rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
goto done;
}
@@ -468,7 +495,7 @@ static inline int external_pkcs1_sign( void *ctx_voidptr,
if ( openvpn_base64_decode (out_b64, sig, ctx->signature_length) !=
ctx->signature_length )
{
- rv = POLARSSL_ERR_RSA_PRIVATE_FAILED;
+ rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED;
goto done;
}
@@ -501,10 +528,10 @@ tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
return 0;
ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context);
- ctx->external_key->signature_length = pk_get_len(&ctx->crt_chain->pk);
+ ctx->external_key->signature_length = mbedtls_pk_get_len (&ctx->crt_chain->pk);
- ALLOC_OBJ_CLEAR (ctx->priv_key, pk_context);
- if (!polar_ok (pk_init_ctx_rsa_alt(ctx->priv_key, ctx->external_key,
+ ALLOC_OBJ_CLEAR (ctx->priv_key, mbedtls_pk_context);
+ if (!mbed_ok (mbedtls_pk_setup_rsa_alt (ctx->priv_key, ctx->external_key,
NULL, external_pkcs1_sign, external_key_len)))
return 0;
@@ -513,21 +540,22 @@ tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
#endif
void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
- const char *ca_inline, const char *ca_path, bool tls_server)
+ const char *ca_inline, const char *ca_path, bool tls_server
+ )
{
if (ca_path)
- msg(M_FATAL, "ERROR: PolarSSL cannot handle the capath directive");
+ msg(M_FATAL, "ERROR: mbed TLS cannot handle the capath directive");
if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_inline)
{
- if (!polar_ok(x509_crt_parse(ctx->ca_chain,
- (const unsigned char *) ca_inline, strlen(ca_inline))))
+ if (!mbed_ok (mbedtls_x509_crt_parse (ctx->ca_chain,
+ (const unsigned char *) ca_inline, strlen(ca_inline)+1)))
msg (M_FATAL, "Cannot load inline CA certificates");
}
else
{
/* Load CA file for verifying peer supplied certificate */
- if (!polar_ok(x509_crt_parse_file(ctx->ca_chain, ca_file)))
+ if (!mbed_ok (mbedtls_x509_crt_parse_file (ctx->ca_chain, ca_file)))
msg (M_FATAL, "Cannot load CA certificate file %s", ca_file);
}
}
@@ -541,19 +569,19 @@ tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file
if (!ctx->crt_chain)
{
- ALLOC_OBJ_CLEAR (ctx->crt_chain, x509_crt);
+ ALLOC_OBJ_CLEAR (ctx->crt_chain, mbedtls_x509_crt);
}
if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline)
{
- if (!polar_ok(x509_crt_parse(ctx->crt_chain,
+ if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain,
(const unsigned char *) extra_certs_inline,
- strlen(extra_certs_inline))))
+ strlen(extra_certs_inline)+1)))
msg (M_FATAL, "Cannot load inline extra-certs file");
}
else
{
- if (!polar_ok(x509_crt_parse_file(ctx->crt_chain, extra_certs_file)))
+ if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, extra_certs_file)))
msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file);
}
}
@@ -588,13 +616,12 @@ static void buf_free_entries(endless_buffer *buf)
buf->last_block = NULL;
}
-static int endless_buf_read( void * ctx, unsigned char * out, size_t out_len )
+static int endless_buf_read( endless_buffer *in, unsigned char * out, size_t out_len )
{
- endless_buffer *in = (endless_buffer *) ctx;
size_t read_len = 0;
if (in->first_block == NULL)
- return POLARSSL_ERR_NET_WANT_READ;
+ return MBEDTLS_ERR_SSL_WANT_READ;
while (in->first_block != NULL && read_len < out_len)
{
@@ -627,18 +654,17 @@ static int endless_buf_read( void * ctx, unsigned char * out, size_t out_len )
return read_len;
}
-static int endless_buf_write( void *ctx, const unsigned char *in, size_t len )
+static int endless_buf_write( endless_buffer *out, const unsigned char *in, size_t len )
{
- endless_buffer *out = (endless_buffer *) ctx;
buffer_entry *new_block = malloc(sizeof(buffer_entry));
if (NULL == new_block)
- return POLARSSL_ERR_NET_SEND_FAILED;
+ return MBEDTLS_ERR_NET_SEND_FAILED;
new_block->data = malloc(len);
if (NULL == new_block->data)
{
free(new_block);
- return POLARSSL_ERR_NET_SEND_FAILED;
+ return MBEDTLS_ERR_NET_SEND_FAILED;
}
new_block->length = len;
@@ -657,10 +683,23 @@ static int endless_buf_write( void *ctx, const unsigned char *in, size_t len )
return len;
}
-static void my_debug( void *ctx, int level, const char *str )
+static int ssl_bio_read( void *ctx, unsigned char *out, size_t out_len)
+{
+ bio_ctx *my_ctx = (bio_ctx *) ctx;
+ return endless_buf_read (&my_ctx->in, out, out_len);
+}
+
+static int ssl_bio_write( void *ctx, const unsigned char *in, size_t in_len)
+{
+ bio_ctx *my_ctx = (bio_ctx *) ctx;
+ return endless_buf_write (&my_ctx->out, in, in_len);
+}
+
+static void my_debug( void *ctx, int level, const char *file, int line,
+ const char *str )
{
int my_loglevel = (level < 3) ? D_TLS_DEBUG_MED : D_TLS_DEBUG;
- msg (my_loglevel, "PolarSSL msg: %s", str);
+ msg (my_loglevel, "mbed TLS msg (%s:%d): %s", file, line, str);
}
/*
@@ -670,16 +709,16 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
{
static char old_sha256_hash[32] = {0};
unsigned char sha256_hash[32] = {0};
- ctr_drbg_context *cd_ctx = rand_ctx_get();
+ mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get();
if (NULL != ctx->crt_chain)
{
- x509_crt *cert = ctx->crt_chain;
+ mbedtls_x509_crt *cert = ctx->crt_chain;
- sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false);
+ mbedtls_sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false);
if ( 0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash)))
{
- ctr_drbg_update(cd_ctx, sha256_hash, 32);
+ mbedtls_ctr_drbg_update(cd_ctx, sha256_hash, 32);
memcpy(old_sha256_hash, sha256_hash, sizeof(old_sha256_hash));
}
}
@@ -688,9 +727,9 @@ 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)
+#if defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_3)
return TLS_VER_1_2;
-#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2)
+#elif defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_2)
return TLS_VER_1_1;
#else
return TLS_VER_1_0;
@@ -698,13 +737,13 @@ tls_version_max(void)
}
/**
- * Convert an OpenVPN tls-version variable to PolarSSl format (i.e. a major and
+ * Convert an OpenVPN tls-version variable to mbed TLS format (i.e. a major and
* minor ssl version number).
*
* @param tls_ver The tls-version variable to convert.
- * @param major Returns the TLS major version in polarssl format.
+ * @param major Returns the TLS major version in mbed TLS format.
* Must be a valid pointer.
- * @param minor Returns the TLS minor version in polarssl format.
+ * @param minor Returns the TLS minor version in mbed TLS format.
* Must be a valid pointer.
*/
static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) {
@@ -714,16 +753,16 @@ static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) {
switch (tls_ver)
{
case TLS_VER_1_0:
- *major = SSL_MAJOR_VERSION_3;
- *minor = SSL_MINOR_VERSION_1;
+ *major = MBEDTLS_SSL_MAJOR_VERSION_3;
+ *minor = MBEDTLS_SSL_MINOR_VERSION_1;
break;
case TLS_VER_1_1:
- *major = SSL_MAJOR_VERSION_3;
- *minor = SSL_MINOR_VERSION_2;
+ *major = MBEDTLS_SSL_MAJOR_VERSION_3;
+ *minor = MBEDTLS_SSL_MINOR_VERSION_2;
break;
case TLS_VER_1_2:
- *major = SSL_MAJOR_VERSION_3;
- *minor = SSL_MINOR_VERSION_3;
+ *major = MBEDTLS_SSL_MAJOR_VERSION_3;
+ *minor = MBEDTLS_SSL_MINOR_VERSION_3;
break;
default:
msg(M_FATAL, "%s: invalid TLS version %d", __func__, tls_ver);
@@ -731,6 +770,41 @@ static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) {
}
}
+void
+tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file,
+ const char *crl_inline)
+{
+ ASSERT (crl_file);
+
+ if (ctx->crl == NULL)
+ {
+ ALLOC_OBJ_CLEAR(ctx->crl, mbedtls_x509_crl);
+ }
+ mbedtls_x509_crl_free(ctx->crl);
+
+ if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline)
+ {
+ if (!mbed_ok(mbedtls_x509_crl_parse(ctx->crl,
+ (const unsigned char *)crl_inline, strlen(crl_inline)+1)))
+ {
+ msg (M_WARN, "CRL: cannot parse inline CRL");
+ goto err;
+ }
+ }
+ else
+ {
+ if (!mbed_ok(mbedtls_x509_crl_parse_file(ctx->crl, crl_file)))
+ {
+ msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
+ goto err;
+ }
+ }
+ return;
+
+err:
+ mbedtls_x509_crl_free(ctx->crl);
+}
+
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)
{
@@ -738,88 +812,92 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
ASSERT(ks_ssl);
CLEAR(*ks_ssl);
- ALLOC_OBJ_CLEAR(ks_ssl->ctx, ssl_context);
- if (polar_ok(ssl_init(ks_ssl->ctx)))
+ /* Initialise SSL config */
+ mbedtls_ssl_config_init(&ks_ssl->ssl_config);
+ mbedtls_ssl_config_defaults(&ks_ssl->ssl_config, ssl_ctx->endpoint,
+ MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
+#ifdef MBEDTLS_DEBUG_C
+ mbedtls_debug_set_threshold(3);
+#endif
+ mbedtls_ssl_conf_dbg (&ks_ssl->ssl_config, my_debug, NULL);
+ mbedtls_ssl_conf_rng (&ks_ssl->ssl_config, mbedtls_ctr_drbg_random,
+ rand_ctx_get());
+
+ if (ssl_ctx->allowed_ciphers)
+ mbedtls_ssl_conf_ciphersuites (&ks_ssl->ssl_config, ssl_ctx->allowed_ciphers);
+
+ /* Disable record splitting (for now). OpenVPN assumes records are sent
+ * unfragmented, and changing that will require thorough review and
+ * testing. Since OpenVPN is not susceptible to BEAST, we can just
+ * disable record splitting as a quick fix. */
+#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
+ mbedtls_ssl_conf_cbc_record_splitting (&ks_ssl->ssl_config,
+ MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED);
+#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */
+
+ /* Initialise authentication information */
+ if (is_server)
+ mbed_ok (mbedtls_ssl_conf_dh_param_ctx(&ks_ssl->ssl_config,
+ ssl_ctx->dhm_ctx));
+
+ mbed_ok (mbedtls_ssl_conf_own_cert(&ks_ssl->ssl_config, ssl_ctx->crt_chain,
+ ssl_ctx->priv_key));
+
+ /* Initialise SSL verification */
+#if P2MP_SERVER
+ if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL)
{
- /* Initialise SSL context */
- debug_set_threshold(3);
- ssl_set_dbg (ks_ssl->ctx, my_debug, NULL);
- ssl_set_endpoint (ks_ssl->ctx, ssl_ctx->endpoint);
-
- ssl_set_rng (ks_ssl->ctx, ctr_drbg_random, rand_ctx_get());
+ mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+ }
+ else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED))
+#endif
+ {
+ mbedtls_ssl_conf_authmode (&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_REQUIRED);
+ }
+ mbedtls_ssl_conf_verify (&ks_ssl->ssl_config, verify_callback, session);
- if (ssl_ctx->allowed_ciphers)
- ssl_set_ciphersuites (ks_ssl->ctx, ssl_ctx->allowed_ciphers);
+ /* TODO: mbed TLS does not currently support sending the CA chain to the client */
+ mbedtls_ssl_conf_ca_chain (&ks_ssl->ssl_config, ssl_ctx->ca_chain, ssl_ctx->crl);
- /* Disable record splitting (for now). OpenVPN assumes records are sent
- * unfragmented, and changing that will require thorough review and
- * testing. Since OpenVPN is not susceptible to BEAST, we can just
- * disable record splitting as a quick fix. */
-#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
- ssl_set_cbc_record_splitting (ks_ssl->ctx, SSL_CBC_RECORD_SPLITTING_DISABLED);
-#endif /* POLARSSL_SSL_CBC_RECORD_SPLITTING */
+ /* Initialize minimum TLS version */
+ {
+ const int tls_version_min =
+ (session->opt->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) &
+ SSLF_TLS_VERSION_MIN_MASK;
- /* Initialise authentication information */
- if (is_server)
- polar_ok (ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx));
+ /* default to TLS 1.0 */
+ int major = MBEDTLS_SSL_MAJOR_VERSION_3;
+ int minor = MBEDTLS_SSL_MINOR_VERSION_1;
- polar_ok (ssl_set_own_cert (ks_ssl->ctx, ssl_ctx->crt_chain,
- ssl_ctx->priv_key));
+ if (tls_version_min > TLS_VER_UNSPEC)
+ tls_version_to_major_minor(tls_version_min, &major, &minor);
- /* Initialise SSL verification */
-#if P2MP_SERVER
- if (session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
- {
- msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION "
- "--client-cert-not-required may accept clients which do not present "
- "a certificate");
- }
- else
-#endif
- {
- ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED);
- ssl_set_verify (ks_ssl->ctx, verify_callback, session);
- }
+ mbedtls_ssl_conf_min_version(&ks_ssl->ssl_config, major, minor);
+ }
- /* 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 maximum TLS version */
+ {
+ const int tls_version_max =
+ (session->opt->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) &
+ SSLF_TLS_VERSION_MAX_MASK;
- /* Initialize minimum TLS version */
+ if (tls_version_max > TLS_VER_UNSPEC)
{
- const int tls_version_min =
- (session->opt->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) &
- SSLF_TLS_VERSION_MIN_MASK;
-
- /* default to TLS 1.0 */
- int major = SSL_MAJOR_VERSION_3;
- int minor = SSL_MINOR_VERSION_1;
-
- if (tls_version_min > TLS_VER_UNSPEC)
- tls_version_to_major_minor(tls_version_min, &major, &minor);
-
- ssl_set_min_version(ks_ssl->ctx, major, minor);
+ int major, minor;
+ tls_version_to_major_minor(tls_version_max, &major, &minor);
+ mbedtls_ssl_conf_max_version(&ks_ssl->ssl_config, major, minor);
}
+ }
- /* Initialize maximum TLS version */
- {
- const int tls_version_max =
- (session->opt->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) &
- SSLF_TLS_VERSION_MAX_MASK;
-
- if (tls_version_max > TLS_VER_UNSPEC)
- {
- int major, minor;
- tls_version_to_major_minor(tls_version_max, &major, &minor);
- ssl_set_max_version(ks_ssl->ctx, major, minor);
- }
- }
+ /* Initialise SSL context */
+ ALLOC_OBJ_CLEAR(ks_ssl->ctx, mbedtls_ssl_context);
+ mbedtls_ssl_init(ks_ssl->ctx);
+ mbedtls_ssl_setup(ks_ssl->ctx, &ks_ssl->ssl_config);
- /* Initialise BIOs */
- ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer);
- ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer);
- ssl_set_bio (ks_ssl->ctx, endless_buf_read, ks_ssl->ct_in,
- endless_buf_write, ks_ssl->ct_out);
- }
+ /* Initialise BIOs */
+ CLEAR (ks_ssl->bio_ctx);
+ mbedtls_ssl_set_bio (ks_ssl->ctx, &ks_ssl->bio_ctx, ssl_bio_write,
+ ssl_bio_read, NULL);
}
void
@@ -828,17 +906,12 @@ key_state_ssl_free(struct key_state_ssl *ks_ssl)
if (ks_ssl) {
if (ks_ssl->ctx)
{
- ssl_free(ks_ssl->ctx);
+ mbedtls_ssl_free(ks_ssl->ctx);
free(ks_ssl->ctx);
}
- if (ks_ssl->ct_in) {
- buf_free_entries(ks_ssl->ct_in);
- free(ks_ssl->ct_in);
- }
- if (ks_ssl->ct_out) {
- buf_free_entries(ks_ssl->ct_out);
- free(ks_ssl->ct_out);
- }
+ mbedtls_ssl_config_free(&ks_ssl->ssl_config);
+ buf_free_entries(&ks_ssl->bio_ctx.in);
+ buf_free_entries(&ks_ssl->bio_ctx.out);
CLEAR(*ks_ssl);
}
}
@@ -847,46 +920,18 @@ int
key_state_write_plaintext (struct key_state_ssl *ks, struct buffer *buf)
{
int retval = 0;
- perf_push (PERF_BIO_WRITE_PLAINTEXT);
- ASSERT (NULL != ks);
ASSERT (buf);
- ASSERT (buf->len >= 0);
- if (0 == buf->len)
- {
- perf_pop ();
- return 0;
- }
-
- retval = ssl_write(ks->ctx, BPTR(buf), buf->len);
-
- if (retval < 0)
- {
- perf_pop ();
- if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
- return 0;
- msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_plaintext error");
- return -1;
- }
+ retval = key_state_write_plaintext_const(ks, BPTR(buf), BLEN(buf));
- if (retval != buf->len)
+ if (1 == retval)
{
- msg (D_TLS_ERRORS,
- "TLS ERROR: write tls_write_plaintext incomplete %d/%d",
- retval, buf->len);
- perf_pop ();
- return -1;
+ memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
+ buf->len = 0;
}
- /* successful write */
- dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_plaintext %d bytes", retval);
-
- memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
- buf->len = 0;
-
- perf_pop ();
- return 1;
+ return retval;
}
int
@@ -906,14 +951,14 @@ key_state_write_plaintext_const (struct key_state_ssl *ks, const uint8_t *data,
ASSERT (data);
- retval = ssl_write(ks->ctx, data, len);
+ retval = mbedtls_ssl_write(ks->ctx, data, len);
if (retval < 0)
{
perf_pop ();
- if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
+ if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval)
return 0;
- polar_log_err (D_TLS_ERRORS, retval,
+ mbed_log_err (D_TLS_ERRORS, retval,
"TLS ERROR: write tls_write_plaintext_const error");
return -1;
}
@@ -957,15 +1002,15 @@ key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf,
if (maxlen < len)
len = maxlen;
- retval = endless_buf_read(ks->ct_out, BPTR(buf), len);
+ retval = endless_buf_read(&ks->bio_ctx.out, BPTR(buf), len);
/* Error during read, check for retry error */
if (retval < 0)
{
perf_pop ();
- if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
+ if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval)
return 0;
- polar_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_ciphertext error");
+ mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_ciphertext error");
buf->len = 0;
return -1;
}
@@ -1000,15 +1045,15 @@ key_state_write_ciphertext (struct key_state_ssl *ks, struct buffer *buf)
return 0;
}
- retval = endless_buf_write(ks->ct_in, BPTR(buf), buf->len);
+ retval = endless_buf_write(&ks->bio_ctx.in, BPTR(buf), buf->len);
if (retval < 0)
{
perf_pop ();
- if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
+ if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval)
return 0;
- polar_log_err (D_TLS_ERRORS, retval,
+ mbed_log_err (D_TLS_ERRORS, retval,
"TLS ERROR: write tls_write_ciphertext error");
return -1;
}
@@ -1054,14 +1099,14 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
if (maxlen < len)
len = maxlen;
- retval = ssl_read(ks->ctx, BPTR(buf), len);
+ retval = mbedtls_ssl_read(ks->ctx, BPTR(buf), len);
/* Error during read, check for retry error */
if (retval < 0)
{
- if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
+ if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval)
return 0;
- polar_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_plaintext error");
+ mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_plaintext error");
buf->len = 0;
perf_pop ();
return -1;
@@ -1092,20 +1137,21 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
void
print_details (struct key_state_ssl * ks_ssl, const char *prefix)
{
- const x509_crt *cert;
+ const mbedtls_x509_crt *cert;
char s1[256];
char s2[256];
s1[0] = s2[0] = 0;
openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s",
prefix,
- ssl_get_version (ks_ssl->ctx),
- ssl_get_ciphersuite(ks_ssl->ctx));
+ mbedtls_ssl_get_version (ks_ssl->ctx),
+ mbedtls_ssl_get_ciphersuite (ks_ssl->ctx));
- cert = ssl_get_peer_cert(ks_ssl->ctx);
+ cert = mbedtls_ssl_get_peer_cert (ks_ssl->ctx);
if (cert != NULL)
{
- openvpn_snprintf (s2, sizeof (s2), ", %zu bit key", pk_get_size(&cert->pk));
+ openvpn_snprintf (s2, sizeof (s2), ", %u bit key",
+ (unsigned int) mbedtls_pk_get_bitlen (&cert->pk));
}
msg (D_HANDSHAKE, "%s%s", s1, s2);
@@ -1115,12 +1161,13 @@ void
show_available_tls_ciphers (const char *cipher_list)
{
struct tls_root_ctx tls_ctx;
- const int *ciphers = ssl_list_ciphersuites();
+ const int *ciphers = mbedtls_ssl_list_ciphersuites ();
- if (cipher_list) {
- tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
+ tls_ctx_server_new(&tls_ctx);
+ tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
+
+ if (tls_ctx.allowed_ciphers)
ciphers = tls_ctx.allowed_ciphers;
- }
#ifndef ENABLE_SMALL
printf ("Available TLS Ciphers,\n");
@@ -1129,32 +1176,51 @@ show_available_tls_ciphers (const char *cipher_list)
while (*ciphers != 0)
{
- printf ("%s\n", ssl_get_ciphersuite_name(*ciphers));
+ printf ("%s\n", mbedtls_ssl_get_ciphersuite_name (*ciphers));
ciphers++;
}
printf ("\n" SHOW_TLS_CIPHER_LIST_WARNING);
+
+ tls_ctx_free(&tls_ctx);
+}
+
+void
+show_available_curves (void)
+{
+ const mbedtls_ecp_curve_info *pcurve = mbedtls_ecp_curve_list ();
+
+ if (NULL == pcurve)
+ msg (M_FATAL, "Cannot retrieve curve list from mbed TLS");
+
+ /* Print curve list */
+ printf ("Available Elliptic curves, listed in order of preference:\n\n");
+ while (MBEDTLS_ECP_DP_NONE != pcurve->grp_id)
+ {
+ printf("%s\n", pcurve->name);
+ pcurve++;
+ }
}
void
get_highest_preference_tls_cipher (char *buf, int size)
{
const char *cipher_name;
- const int *ciphers = ssl_list_ciphersuites();
+ const int *ciphers = mbedtls_ssl_list_ciphersuites();
if (*ciphers == 0)
msg (M_FATAL, "Cannot retrieve list of supported SSL ciphers.");
- cipher_name = ssl_get_ciphersuite_name(*ciphers);
+ cipher_name = mbedtls_ssl_get_ciphersuite_name(*ciphers);
strncpynt (buf, cipher_name, size);
}
const char *
get_ssl_library_version(void)
{
- static char polar_version[30];
- unsigned int pv = version_get_number();
- sprintf( polar_version, "PolarSSL %d.%d.%d",
+ static char mbedtls_version[30];
+ unsigned int pv = mbedtls_version_get_number();
+ sprintf( mbedtls_version, "mbed TLS %d.%d.%d",
(pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff );
- return polar_version;
+ return mbedtls_version;
}
-#endif /* defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL) */
+#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */
diff --git a/src/openvpn/ssl_polarssl.h b/src/openvpn/ssl_mbedtls.h
index b80a509..3edeedc 100644
--- a/src/openvpn/ssl_polarssl.h
+++ b/src/openvpn/ssl_mbedtls.h
@@ -24,19 +24,19 @@
*/
/**
- * @file Control Channel PolarSSL Backend
+ * @file Control Channel mbed TLS Backend
*/
-#ifndef SSL_POLARSSL_H_
-#define SSL_POLARSSL_H_
+#ifndef SSL_MBEDTLS_H_
+#define SSL_MBEDTLS_H_
#include "syshead.h"
-#include <polarssl/ssl.h>
-#include <polarssl/x509_crt.h>
+#include <mbedtls/ssl.h>
+#include <mbedtls/x509_crt.h>
#if defined(ENABLE_PKCS11)
-#include <polarssl/pkcs11.h>
+#include <mbedtls/pkcs11.h>
#endif
typedef struct _buffer_entry buffer_entry;
@@ -53,6 +53,11 @@ typedef struct {
buffer_entry *last_block;
} endless_buffer;
+typedef struct {
+ endless_buffer in;
+ endless_buffer out;
+} bio_ctx;
+
/**
* Structure that wraps the TLS context. Contents differ depending on the
* SSL library used.
@@ -64,12 +69,13 @@ struct tls_root_ctx {
int endpoint; /**< Whether or not this is a server or a client */
- dhm_context *dhm_ctx; /**< Diffie-Helmann-Merkle context */
- x509_crt *crt_chain; /**< Local Certificate chain */
- x509_crt *ca_chain; /**< CA chain for remote verification */
- pk_context *priv_key; /**< Local private key */
+ mbedtls_dhm_context *dhm_ctx; /**< Diffie-Helmann-Merkle context */
+ mbedtls_x509_crt *crt_chain; /**< Local Certificate chain */
+ mbedtls_x509_crt *ca_chain; /**< CA chain for remote verification */
+ mbedtls_pk_context *priv_key; /**< Local private key */
+ mbedtls_x509_crl *crl; /**< Certificate Revocation List */
#if defined(ENABLE_PKCS11)
- pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */
+ mbedtls_pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */
#endif
#ifdef MANAGMENT_EXTERNAL_KEY
struct external_context *external_key; /**< Management external key */
@@ -78,10 +84,10 @@ struct tls_root_ctx {
};
struct key_state_ssl {
- ssl_context *ctx;
- endless_buffer *ct_in;
- endless_buffer *ct_out;
+ mbedtls_ssl_config ssl_config; /**< mbedTLS global ssl config */
+ mbedtls_ssl_context *ctx; /**< mbedTLS connection context */
+ bio_ctx bio_ctx;
};
-#endif /* SSL_POLARSSL_H_ */
+#endif /* SSL_MBEDTLS_H_ */
diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index 1dfbb23..51669fc 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -35,7 +35,7 @@
#include "syshead.h"
-#if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL)
+#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL)
#include "errlevel.h"
#include "buffer.h"
@@ -56,6 +56,9 @@
#include <openssl/pkcs12.h>
#include <openssl/x509.h>
#include <openssl/crypto.h>
+#ifndef OPENSSL_NO_EC
+#include <openssl/ec.h>
+#endif
/*
* Allocate space in SSL objects in which to store a struct tls_session
@@ -93,62 +96,23 @@ tls_clear_error()
ERR_clear_error ();
}
-/*
- * OpenSSL callback to get a temporary RSA key, mostly
- * used for export ciphers.
- */
-static RSA *
-tmp_rsa_cb (SSL * s, int is_export, int keylength)
-{
- static RSA *rsa_tmp = NULL;
- if (rsa_tmp == NULL)
- {
- int ret = -1;
- BIGNUM *bn = BN_new();
- rsa_tmp = RSA_new();
-
- msg (D_HANDSHAKE, "Generating temp (%d bit) RSA key", keylength);
-
- if(!bn || !BN_set_word(bn, RSA_F4) ||
- !RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL))
- crypto_msg(M_FATAL, "Failed to generate temp RSA key");
-
- if (bn) BN_free( bn );
- }
- return (rsa_tmp);
-}
-
void
-tls_ctx_server_new(struct tls_root_ctx *ctx, unsigned int ssl_flags)
+tls_ctx_server_new(struct tls_root_ctx *ctx)
{
- const int tls_version_max =
- (ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK;
-
ASSERT(NULL != ctx);
- if (tls_version_max == TLS_VER_1_0)
- ctx->ctx = SSL_CTX_new (TLSv1_server_method ());
- else
- ctx->ctx = SSL_CTX_new (SSLv23_server_method ());
+ ctx->ctx = SSL_CTX_new (SSLv23_server_method ());
if (ctx->ctx == NULL)
crypto_msg (M_FATAL, "SSL_CTX_new SSLv23_server_method");
-
- SSL_CTX_set_tmp_rsa_callback (ctx->ctx, tmp_rsa_cb);
}
void
-tls_ctx_client_new(struct tls_root_ctx *ctx, unsigned int ssl_flags)
+tls_ctx_client_new(struct tls_root_ctx *ctx)
{
- const int tls_version_max =
- (ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK;
-
ASSERT(NULL != ctx);
- if (tls_version_max == TLS_VER_1_0)
- ctx->ctx = SSL_CTX_new (TLSv1_client_method ());
- else
- ctx->ctx = SSL_CTX_new (SSLv23_client_method ());
+ ctx->ctx = SSL_CTX_new (SSLv23_client_method ());
if (ctx->ctx == NULL)
crypto_msg (M_FATAL, "SSL_CTX_new SSLv23_client_method");
@@ -169,6 +133,38 @@ bool tls_ctx_initialised(struct tls_root_ctx *ctx)
return NULL != ctx->ctx;
}
+void
+key_state_export_keying_material(struct key_state_ssl *ssl,
+ struct tls_session *session)
+{
+ if (session->opt->ekm_size > 0)
+ {
+#if (OPENSSL_VERSION_NUMBER >= 0x10001000)
+ unsigned int size = session->opt->ekm_size;
+ struct gc_arena gc = gc_new();
+ unsigned char* ekm = (unsigned char*) gc_malloc(size, true, &gc);
+
+ if (SSL_export_keying_material(ssl->ssl, ekm, size,
+ session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0))
+ {
+ unsigned int len = (size * 2) + 2;
+
+ const char *key = format_hex_ex (ekm, size, len, 0, NULL, &gc);
+ setenv_str (session->opt->es, "exported_keying_material", key);
+
+ dmsg(D_TLS_DEBUG_MED, "%s: exported keying material: %s",
+ __func__, key);
+ }
+ else
+ {
+ msg (M_WARN, "WARNING: Export keying material failed!");
+ setenv_del (session->opt->es, "exported_keying_material");
+ }
+ gc_free(&gc);
+#endif
+ }
+}
+
/*
* Print debugging information on SSL/TLS session negotiation.
*/
@@ -217,14 +213,18 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
{
ASSERT(NULL != ctx);
+ /* default certificate verification flags */
+ int flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+
/* process SSL options including minimum TLS version we will accept from peer */
{
long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+ int tls_ver_max = TLS_VER_UNSPEC;
const int tls_ver_min =
(ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & SSLF_TLS_VERSION_MIN_MASK;
- int tls_ver_max =
- (ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK;
+ tls_ver_max =
+ (ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK;
if (tls_ver_max <= TLS_VER_UNSPEC)
tls_ver_max = tls_version_max();
@@ -245,6 +245,9 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
SSL_CTX_set_options (ctx->ctx, sslopt);
}
+#ifdef SSL_MODE_RELEASE_BUFFERS
+ SSL_CTX_set_mode (ctx->ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
SSL_CTX_set_session_cache_mode (ctx->ctx, SSL_SESS_CACHE_OFF);
SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback);
@@ -252,14 +255,14 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
#if P2MP_SERVER
if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
{
- msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION "
- "--client-cert-not-required may accept clients which do not present "
- "a certificate");
+ flags = 0;
+ }
+ else if (ssl_flags & SSLF_CLIENT_CERT_OPTIONAL)
+ {
+ flags = SSL_VERIFY_PEER;
}
- else
#endif
- SSL_CTX_set_verify (ctx->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
- verify_callback);
+ SSL_CTX_set_verify (ctx->ctx, flags, verify_callback);
SSL_CTX_set_info_callback (ctx->ctx, info_callback);
}
@@ -275,12 +278,17 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
"DEFAULT"
/* Disable export ciphers and openssl's 'low' and 'medium' ciphers */
":!EXP:!LOW:!MEDIUM"
+ /* Disable static (EC)DH keys (no forward secrecy) */
+ ":!kDH:!kECDH"
+ /* Disable DSA private keys */
+ ":!DSS"
/* Disable unsupported TLS modes */
":!PSK:!SRP:!kRSA"))
crypto_msg (M_FATAL, "Failed to set default TLS cipher list.");
return;
}
+ /* Parse supplied cipher list and pass on to OpenSSL */
size_t begin_of_cipher, end_of_cipher;
const char *current_cipher;
@@ -309,8 +317,8 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
// Issue warning on missing translation
// %.*s format specifier expects length of type int, so guarantee
// that length is small enough and cast to int.
- msg (M_WARN, "No valid translation found for TLS cipher '%.*s'",
- (int) MIN(current_cipher_len, 256), current_cipher);
+ msg (D_LOW, "No valid translation found for TLS cipher '%.*s'",
+ constrain_int(current_cipher_len, 0, 256), current_cipher);
}
else
{
@@ -319,7 +327,8 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
current_cipher_len = strlen(current_cipher);
if (end_of_cipher - begin_of_cipher == current_cipher_len &&
- 0 == memcmp (&ciphers[begin_of_cipher], cipher_pair->openssl_name, end_of_cipher - begin_of_cipher))
+ 0 != memcmp (&ciphers[begin_of_cipher], cipher_pair->iana_name,
+ end_of_cipher - begin_of_cipher))
{
// Non-IANA name used, show warning
msg (M_WARN, "Deprecated TLS cipher name '%s', please use IANA name '%s'", cipher_pair->openssl_name, cipher_pair->iana_name);
@@ -436,6 +445,78 @@ tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
DH_free (dh);
}
+void
+tls_ctx_load_ecdh_params (struct tls_root_ctx *ctx, const char *curve_name
+ )
+{
+#ifndef OPENSSL_NO_EC
+ int nid = NID_undef;
+ EC_KEY *ecdh = NULL;
+ const char *sname = NULL;
+
+ /* Generate a new ECDH key for each SSL session (for non-ephemeral ECDH) */
+ SSL_CTX_set_options(ctx->ctx, SSL_OP_SINGLE_ECDH_USE);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ /* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter loading */
+ if (NULL == curve_name) {
+ SSL_CTX_set_ecdh_auto(ctx->ctx, 1);
+ return;
+ }
+#endif
+ /* For older OpenSSL, we'll have to do the parameter loading on our own */
+ if (curve_name != NULL)
+ {
+ /* Use user supplied curve if given */
+ msg (D_TLS_DEBUG, "Using user specified ECDH curve (%s)", curve_name);
+ nid = OBJ_sn2nid(curve_name);
+ }
+ else
+ {
+ /* Extract curve from key */
+ EC_KEY *eckey = NULL;
+ const EC_GROUP *ecgrp = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ /* Little hack to get private key ref from SSL_CTX, yay OpenSSL... */
+ SSL ssl;
+ ssl.cert = ctx->ctx->cert;
+ pkey = SSL_get_privatekey(&ssl);
+
+ msg (D_TLS_DEBUG, "Extracting ECDH curve from private key");
+
+ if (pkey != NULL && (eckey = EVP_PKEY_get1_EC_KEY(pkey)) != NULL &&
+ (ecgrp = EC_KEY_get0_group(eckey)) != NULL)
+ nid = EC_GROUP_get_curve_name(ecgrp);
+ }
+
+ /* Translate NID back to name , just for kicks */
+ sname = OBJ_nid2sn(nid);
+ if (sname == NULL) sname = "(Unknown)";
+
+ /* Create new EC key and set as ECDH key */
+ if (NID_undef == nid || NULL == (ecdh = EC_KEY_new_by_curve_name(nid)))
+ {
+ /* Creating key failed, fall back on sane default */
+ ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
+ const char *source = (NULL == curve_name) ?
+ "extract curve from certificate" : "use supplied curve";
+ msg (D_TLS_DEBUG_LOW,
+ "Failed to %s (%s), using secp384r1 instead.", source, sname);
+ sname = OBJ_nid2sn(NID_secp384r1);
+ }
+
+ if (!SSL_CTX_set_tmp_ecdh(ctx->ctx, ecdh))
+ crypto_msg (M_FATAL, "SSL_CTX_set_tmp_ecdh: cannot add curve");
+
+ msg (D_TLS_DEBUG_LOW, "ECDH curve %s added", sname);
+
+ EC_KEY_free(ecdh);
+#else
+ msg (M_DEBUG, "Your OpenSSL library was built without elliptic curve support."
+ " Skipping ECDH parameter loading.");
+#endif /* OPENSSL_NO_EC */
+}
+
int
tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
const char *pkcs12_file_inline,
@@ -501,7 +582,6 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
/* Load Private Key */
if (!SSL_CTX_use_PrivateKey (ctx->ctx, pkey))
crypto_msg (M_FATAL, "Cannot use private key");
- warn_if_group_others_accessible (pkcs12_file);
/* Check Private Key */
if (!SSL_CTX_check_private_key (ctx->ctx))
@@ -552,7 +632,7 @@ tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
if (!SSL_CTX_use_CryptoAPI_certificate (ctx->ctx, cryptoapi_cert))
crypto_msg (M_FATAL, "Cannot load certificate \"%s\" from Microsoft Certificate Store", cryptoapi_cert);
}
-#endif /* WIN32 */
+#endif /* ENABLE_CRYPTOAPI */
static void
tls_ctx_add_extra_certs (struct tls_root_ctx *ctx, BIO *bio)
@@ -645,7 +725,6 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
const char *priv_key_file_inline
)
{
- int status;
SSL_CTX *ssl_ctx = NULL;
BIO *in = NULL;
EVP_PKEY *pkey = NULL;
@@ -678,7 +757,6 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
crypto_msg (M_WARN, "Cannot load private key file %s", priv_key_file);
goto end;
}
- warn_if_group_others_accessible (priv_key_file);
/* Check Private Key */
if (!SSL_CTX_check_private_key (ssl_ctx))
@@ -693,6 +771,64 @@ end:
return ret;
}
+void
+tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file,
+ const char *crl_inline)
+{
+ X509_CRL *crl = NULL;
+ BIO *in = NULL;
+
+ X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx);
+ if (!store)
+ crypto_msg (M_FATAL, "Cannot get certificate store");
+
+ /* Always start with a cleared CRL list, for that we
+ * we need to manually find the CRL object from the stack
+ * and remove it */
+ for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++)
+ {
+ X509_OBJECT* obj = sk_X509_OBJECT_value(store->objs, i);
+ ASSERT(obj);
+ if (obj->type == X509_LU_CRL)
+ {
+ sk_X509_OBJECT_delete(store->objs, i);
+ X509_OBJECT_free_contents(obj);
+ OPENSSL_free(obj);
+ }
+ }
+
+ X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
+
+ if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline)
+ in = BIO_new_mem_buf ((char *)crl_inline, -1);
+ else
+ in = BIO_new_file (crl_file, "r");
+
+ if (in == NULL)
+ {
+ msg (M_WARN, "CRL: cannot read: %s", crl_file);
+ goto end;
+ }
+
+ crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
+ if (crl == NULL)
+ {
+ msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
+ goto end;
+ }
+
+ if (!X509_STORE_add_crl(store, crl))
+ {
+ msg (M_WARN, "CRL: cannot add %s to store", crl_file);
+ goto end;
+ }
+
+end:
+ X509_CRL_free(crl);
+ BIO_free(in);
+}
+
+
#ifdef MANAGMENT_EXTERNAL_KEY
/* encrypt */
@@ -780,10 +916,11 @@ tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
X509 *cert = NULL;
ASSERT (NULL != ctx);
- ASSERT (NULL != cert);
tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, &cert);
+ ASSERT (NULL != cert);
+
/* allocate custom RSA method object */
ALLOC_OBJ_CLEAR (rsa_meth, RSA_METHOD);
rsa_meth->name = "OpenVPN external private key RSA Method";
@@ -965,11 +1102,7 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
msg(M_WARN, "WARNING: experimental option --capath %s", ca_path);
else
crypto_msg (M_FATAL, "Cannot add lookup at --capath %s", ca_path);
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
-#else
- msg(M_WARN, "WARNING: this version of OpenSSL cannot handle CRL files in capath");
-#endif
}
}
@@ -1385,7 +1518,6 @@ show_available_tls_ciphers (const char *cipher_list)
struct tls_root_ctx tls_ctx;
SSL *ssl;
const char *cipher_name;
- const char *print_name;
const tls_cipher_name_pair *pair;
int priority = 0;
@@ -1419,6 +1551,43 @@ show_available_tls_ciphers (const char *cipher_list)
SSL_CTX_free (tls_ctx.ctx);
}
+/*
+ * Show the Elliptic curves that are available for us to use
+ * in the OpenSSL library.
+ */
+void
+show_available_curves()
+{
+#ifndef OPENSSL_NO_EC
+ EC_builtin_curve *curves = NULL;
+ size_t crv_len = 0;
+ size_t n = 0;
+
+ crv_len = EC_get_builtin_curves(NULL, 0);
+ ALLOC_ARRAY(curves, EC_builtin_curve, crv_len);
+ if (EC_get_builtin_curves(curves, crv_len))
+ {
+ printf ("Available Elliptic curves:\n");
+ for (n = 0; n < crv_len; n++)
+ {
+ const char *sname;
+ sname = OBJ_nid2sn(curves[n].nid);
+ if (sname == NULL) sname = "";
+
+ printf("%s\n", sname);
+ }
+ }
+ else
+ {
+ crypto_msg (M_FATAL, "Cannot get list of builtin curves");
+ }
+ free(curves);
+#else
+ msg (M_WARN, "Your OpenSSL library was built without elliptic curve support. "
+ "No curves available.");
+#endif
+}
+
void
get_highest_preference_tls_cipher (char *buf, int size)
{
@@ -1446,4 +1615,4 @@ get_ssl_library_version(void)
return SSLeay_version(SSLEAY_VERSION);
}
-#endif /* defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL) */
+#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) */
diff --git a/src/openvpn/ssl_openssl.h b/src/openvpn/ssl_openssl.h
index 73a6c49..97dc742 100644
--- a/src/openvpn/ssl_openssl.h
+++ b/src/openvpn/ssl_openssl.h
@@ -35,15 +35,14 @@
/**
* SSL_OP_NO_TICKET tells OpenSSL to disable "stateless session resumption",
* as this is something we do not want nor need, but could potentially be
- * used for a future attack. For compatibility reasons, in the 2.3.x
- * series, we keep building if the OpenSSL version is too old to support
- * this. 2.4 requires it and will fail configure if not present.
+ * used for a future attack. For compatibility reasons we keep building if the
+ * OpenSSL version is too old (pre-0.9.8f) to support stateless session
+ * resumption (and the accompanying SSL_OP_NO_TICKET flag).
*/
#ifndef SSL_OP_NO_TICKET
# define SSL_OP_NO_TICKET 0
#endif
-
/**
* Structure that wraps the TLS context. Contents differ depending on the
* SSL library used.
diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c
index ca69b41..a099776 100644
--- a/src/openvpn/ssl_verify.c
+++ b/src/openvpn/ssl_verify.c
@@ -35,10 +35,12 @@
#include "syshead.h"
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#ifdef ENABLE_CRYPTO
#include "misc.h"
#include "manage.h"
+#include "otime.h"
+#include "base64.h"
#include "ssl_verify.h"
#include "ssl_verify_backend.h"
@@ -191,40 +193,25 @@ tls_username (const struct tls_multi *multi, const bool null)
}
void
-cert_hash_remember (struct tls_session *session, const int error_depth, const unsigned char *sha1_hash)
+cert_hash_remember (struct tls_session *session, const int error_depth,
+ const struct buffer *cert_hash)
{
if (error_depth >= 0 && error_depth < MAX_CERT_DEPTH)
{
if (!session->cert_hash_set)
- ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set);
+ {
+ ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set);
+ }
if (!session->cert_hash_set->ch[error_depth])
- ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash);
- {
- struct cert_hash *ch = session->cert_hash_set->ch[error_depth];
- memcpy (ch->sha1_hash, sha1_hash, SHA_DIGEST_LENGTH);
- }
- }
-}
-
-#if 0
-static void
-cert_hash_print (const struct cert_hash_set *chs, int msglevel)
-{
- struct gc_arena gc = gc_new ();
- msg (msglevel, "CERT_HASH");
- if (chs)
- {
- int i;
- for (i = 0; i < MAX_CERT_DEPTH; ++i)
{
- const struct cert_hash *ch = chs->ch[i];
- if (ch)
- msg (msglevel, "%d:%s", i, format_hex(ch->sha1_hash, SHA_DIGEST_LENGTH, 0, &gc));
+ ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash);
}
+
+ struct cert_hash *ch = session->cert_hash_set->ch[error_depth];
+ ASSERT (sizeof (ch->sha256_hash) == BLEN (cert_hash));
+ memcpy (ch->sha256_hash, BPTR (cert_hash), sizeof (ch->sha256_hash));
}
- gc_free (&gc);
}
-#endif
void
cert_hash_free (struct cert_hash_set *chs)
@@ -238,7 +225,7 @@ cert_hash_free (struct cert_hash_set *chs)
}
}
-static bool
+bool
cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set *chs2)
{
if (chs1 && chs2)
@@ -251,7 +238,8 @@ cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set
if (!ch1 && !ch2)
continue;
- else if (ch1 && ch2 && !memcmp (ch1->sha1_hash, ch2->sha1_hash, SHA_DIGEST_LENGTH))
+ else if (ch1 && ch2 && !memcmp (ch1->sha256_hash, ch2->sha256_hash,
+ sizeof(ch1->sha256_hash)))
continue;
else
return false;
@@ -278,7 +266,8 @@ cert_hash_copy (const struct cert_hash_set *chs)
if (ch)
{
ALLOC_OBJ (dest->ch[i], struct cert_hash);
- memcpy (dest->ch[i]->sha1_hash, ch->sha1_hash, SHA_DIGEST_LENGTH);
+ memcpy (dest->ch[i]->sha256_hash, ch->sha256_hash,
+ sizeof(dest->ch[i]->sha256_hash));
}
}
}
@@ -337,8 +326,6 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert,
}
}
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L || ENABLE_CRYPTO_POLARSSL
-
/* verify certificate ku */
if (opt->remote_cert_ku[0] != 0)
{
@@ -367,8 +354,6 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert,
}
}
-#endif /* OPENSSL_VERSION_NUMBER */
-
/* verify X509 name or username against --verify-x509-[user]name */
if (opt->verify_x509_type != VERIFY_X509_NONE)
{
@@ -397,22 +382,17 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert,
*/
static void
verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert_depth,
- const char *subject, const char *common_name
-#ifdef ENABLE_X509_TRACK
- , const struct x509_track *x509_track
-#endif
- )
+ const char *subject, const char *common_name,
+ const struct x509_track *x509_track)
{
char envname[64];
char *serial = NULL;
struct gc_arena gc = gc_new ();
/* Save X509 fields in environment */
-#ifdef ENABLE_X509_TRACK
if (x509_track)
x509_setenv_track (x509_track, es, cert_depth, peer_cert);
else
-#endif
x509_setenv (es, cert_depth, peer_cert);
/* export subject name string as environmental variable */
@@ -425,13 +405,19 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert
setenv_str (es, envname, common_name);
#endif
- /* export X509 cert SHA1 fingerprint */
+ /* export X509 cert fingerprints */
{
- unsigned char *sha1_hash = x509_get_sha1_hash(peer_cert, &gc);
+ struct buffer sha1 = x509_get_sha1_fingerprint(peer_cert, &gc);
+ struct buffer sha256 = x509_get_sha256_fingerprint(peer_cert, &gc);
openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", cert_depth);
- setenv_str (es, envname, format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1,
- ":", &gc));
+ setenv_str (es, envname,
+ format_hex_ex(BPTR(&sha1), BLEN(&sha1), 0, 1, ":", &gc));
+
+ openvpn_snprintf (envname, sizeof(envname), "tls_digest_sha256_%d",
+ cert_depth);
+ setenv_str (es, envname,
+ format_hex_ex(BPTR(&sha256), BLEN(&sha256), 0, 1, ":", &gc));
}
/* export serial number as environmental variable */
@@ -530,7 +516,8 @@ verify_cert_call_command(const char *verify_command, struct env_set *es,
}
}
- argv_printf (&argv, "%sc %d %s", verify_command, cert_depth, subject);
+ argv_parse_cmd (&argv, verify_command);
+ argv_printf_cat (&argv, "%d %s", cert_depth, subject);
argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command");
ret = openvpn_run_script (&argv, es, 0, "--tls-verify script");
@@ -647,8 +634,8 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep
/* verify level 1 cert, i.e. the CA that signed our leaf cert */
if (cert_depth == 1 && opt->verify_hash)
{
- unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc);
- if (memcmp (sha1_hash, opt->verify_hash, SHA_DIGEST_LENGTH))
+ struct buffer sha1_hash = x509_get_sha1_fingerprint(cert, &gc);
+ if (memcmp (BPTR (&sha1_hash), opt->verify_hash, BLEN(&sha1_hash)))
{
msg (D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed");
goto cleanup;
@@ -662,11 +649,8 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep
session->verify_maxlevel = max_int (session->verify_maxlevel, cert_depth);
/* export certificate values to the environment */
- verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name
-#ifdef ENABLE_X509_TRACK
- , opt->x509_track
-#endif
- );
+ verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name,
+ opt->x509_track);
/* export current untrusted IP */
setenv_untrusted (session);
@@ -688,15 +672,18 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep
if (opt->crl_file)
{
if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)
- {
- if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert))
- goto cleanup;
- }
+ {
+ if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert))
+ goto cleanup;
+ }
else
- {
- if (SUCCESS != x509_verify_crl(opt->crl_file, cert, subject))
- goto cleanup;
- }
+ {
+ if (tls_verify_crl_missing (opt))
+ {
+ msg (D_TLS_ERRORS, "VERIFY ERROR: CRL not loaded");
+ goto cleanup;
+ }
+ }
}
msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", cert_depth, subject);
@@ -1000,7 +987,8 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
setenv_untrusted (session);
/* format command line */
- argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
+ argv_parse_cmd (&argv, session->opt->auth_user_pass_verify_script);
+ argv_printf_cat (&argv, "%s", tmp_file);
/* call command */
ret = openvpn_run_script (&argv, session->opt->es, 0,
@@ -1030,7 +1018,9 @@ static int
verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username)
{
int retval = OPENVPN_PLUGIN_FUNC_ERROR;
+#ifdef PLUGIN_DEF_AUTH
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
+#endif
/* Is username defined? */
if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
@@ -1154,6 +1144,63 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,
string_mod_remap_name (up->username, COMMON_NAME_CHAR_CLASS);
string_mod (up->password, CC_PRINT, CC_CRLF, '_');
+ /* If server is configured with --auth-gen-token and we have an
+ * authentication token for this client, this authentication
+ * round will be done internally using the token instead of
+ * calling any external authentication modules.
+ */
+ if (session->opt->auth_token_generate && multi->auth_token_sent
+ && NULL != multi->auth_token)
+ {
+ unsigned int ssl_flags = session->opt->ssl_flags;
+
+ /* Ensure that the username has not changed */
+ if (!tls_lock_username(multi, up->username))
+ {
+ ks->authenticated = false;
+ goto done;
+ }
+
+ /* If auth-token lifetime has been enabled,
+ * ensure the token has not expired
+ */
+ if (session->opt->auth_token_lifetime > 0
+ && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now)
+ {
+ msg (D_HANDSHAKE, "Auth-token for client expired\n");
+ ks->authenticated = false;
+ goto done;
+ }
+
+ /* The core authentication of the token itself */
+ if (memcmp_constant_time(multi->auth_token, up->password,
+ strlen(multi->auth_token)) != 0)
+ {
+ memset (multi->auth_token, 0, AUTH_TOKEN_SIZE);
+ free (multi->auth_token);
+ multi->auth_token = NULL;
+ multi->auth_token_sent = false;
+ ks->authenticated = false;
+ tls_deauthenticate (multi);
+
+ msg (D_TLS_ERRORS, "TLS Auth Error: Auth-token verification "
+ "failed for username '%s' %s", up->username,
+ (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
+ }
+ else
+ {
+ ks->authenticated = true;
+
+ if (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)
+ set_common_name (session, up->username);
+ msg (D_HANDSHAKE, "TLS: Username/auth-token authentication "
+ "succeeded for username '%s' %s",
+ up->username,
+ (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : "");
+ }
+ goto done;
+ }
+
/* call plugin(s) and/or script */
#ifdef MANAGEMENT_DEF_AUTH
if (man_def_auth == KMDA_DEF)
@@ -1191,6 +1238,43 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,
if (man_def_auth != KMDA_UNDEF)
ks->auth_deferred = true;
#endif
+
+ if ((session->opt->auth_token_generate) && (NULL == multi->auth_token))
+ {
+ /* Server is configured with --auth-gen-token but no token has yet
+ * been generated for this client. Generate one and save it.
+ */
+ uint8_t tok[AUTH_TOKEN_SIZE];
+
+ if (!rand_bytes(tok, AUTH_TOKEN_SIZE))
+ {
+ msg( M_FATAL, "Failed to get enough randomness for "
+ "authentication token");
+ }
+
+ /* The token should be longer than the input when
+ * being base64 encoded
+ */
+ if( openvpn_base64_encode(tok, AUTH_TOKEN_SIZE,
+ &multi->auth_token) < AUTH_TOKEN_SIZE)
+ {
+ msg(D_TLS_ERRORS, "BASE64 encoding of token failed. "
+ "No auth-token will be activated now");
+ if (multi->auth_token)
+ {
+ memset (multi->auth_token, 0, AUTH_TOKEN_SIZE);
+ free (multi->auth_token);
+ multi->auth_token = NULL;
+ }
+ }
+ else
+ {
+ multi->auth_token_tstamp = now;
+ dmsg (D_SHOW_KEYS, "Generated token for client: %s",
+ multi->auth_token);
+ }
+ }
+
if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME))
set_common_name (session, up->username);
#ifdef ENABLE_DEF_AUTH
@@ -1210,6 +1294,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi,
msg (D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer");
}
+ done:
gc_free (&gc);
}
@@ -1270,4 +1355,4 @@ verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session)
gc_free (&gc);
}
}
-#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) */
+#endif /* ENABLE_CRYPTO */
diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h
index e0bcba4..98312fd 100644
--- a/src/openvpn/ssl_verify.h
+++ b/src/openvpn/ssl_verify.h
@@ -30,17 +30,18 @@
#ifndef SSL_VERIFY_H_
#define SSL_VERIFY_H_
+#ifdef ENABLE_CRYPTO
+
#include "syshead.h"
#include "misc.h"
-#include "manage.h"
#include "ssl_common.h"
/* Include OpenSSL-specific code */
#ifdef ENABLE_CRYPTO_OPENSSL
#include "ssl_verify_openssl.h"
#endif
-#ifdef ENABLE_CRYPTO_POLARSSL
-#include "ssl_verify_polarssl.h"
+#ifdef ENABLE_CRYPTO_MBEDTLS
+#include "ssl_verify_mbedtls.h"
#endif
#include "ssl_verify_backend.h"
@@ -54,7 +55,7 @@
/** Structure containing the hash for a single certificate */
struct cert_hash {
- unsigned char sha1_hash[SHA_DIGEST_LENGTH]; /**< The SHA1 hash for a certificate */
+ unsigned char sha256_hash[256/8];
};
/** Structure containing the hashes for a full certificate chain */
@@ -66,8 +67,6 @@ struct cert_hash_set {
#define VERIFY_X509_SUBJECT_DN 1
#define VERIFY_X509_SUBJECT_RDN 2
#define VERIFY_X509_SUBJECT_RDN_PREFIX 3
-#define TLS_REMOTE_SUBJECT_DN 1 + 0x100
-#define TLS_REMOTE_SUBJECT_RDN_PREFIX 3 + 0x100
#define TLS_AUTHENTICATION_SUCCEEDED 0
#define TLS_AUTHENTICATION_FAILED 1
@@ -136,6 +135,14 @@ const char *tls_common_name (const struct tls_multi* multi, const bool null);
*/
const char *tls_username (const struct tls_multi *multi, const bool null);
+/**
+ * Compares certificates hashes, returns true if hashes are equal.
+ *
+ * @param chs1 cert 1 hash set
+ * @param chs2 cert 2 hash set
+ */
+bool cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set *chs2);
+
#ifdef ENABLE_PF
/**
@@ -166,25 +173,6 @@ tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t *
#endif
/**
- * Returns whether or not the server should check for username/password
- *
- * @param session The current TLS session
- *
- * @return true if username and password verification is enabled,
- * false if not.
- *
- */
-static inline bool verify_user_pass_enabled(struct tls_session *session)
-{
- return (session->opt->auth_user_pass_verify_script
- || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
-#ifdef MANAGEMENT_DEF_AUTH
- || management_enable_def_auth (management)
-#endif
- );
-}
-
-/**
* Verify the given username and password, using either an external script, a
* plugin, or the management interface.
*
@@ -211,8 +199,6 @@ void verify_user_pass(struct user_pass *up, struct tls_multi *multi,
*/
void verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session);
-#ifdef ENABLE_X509_TRACK
-
struct x509_track
{
const struct x509_track *next;
@@ -222,10 +208,6 @@ struct x509_track
int nid;
};
-void x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc);
-
-#endif
-
/*
* Certificate checking for verify_nsCertType
*/
@@ -254,5 +236,6 @@ tls_client_reason (struct tls_multi *multi)
#endif
}
-#endif /* SSL_VERIFY_H_ */
+#endif /* ENABLE_CRYPTO */
+#endif /* SSL_VERIFY_H_ */
diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h
index 01e453e..de304b9 100644
--- a/src/openvpn/ssl_verify_backend.h
+++ b/src/openvpn/ssl_verify_backend.h
@@ -66,10 +66,10 @@ result_t verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int
*
* @param session TLS Session associated with this tunnel
* @param cert_depth Depth of the current certificate
- * @param sha1_hash Hash of the current certificate
+ * @param cert_hash Hash of the current certificate
*/
void cert_hash_remember (struct tls_session *session, const int cert_depth,
- const unsigned char *sha1_hash);
+ const struct buffer *cert_hash);
/*
* Library-specific functions.
@@ -87,14 +87,27 @@ void cert_hash_remember (struct tls_session *session, const int cert_depth,
*/
char *x509_get_subject (openvpn_x509_cert_t *cert, struct gc_arena *gc);
-/* Retrieve the certificate's SHA1 hash.
+/**
+ * Retrieve the certificate's SHA1 fingerprint.
*
- * @param cert Certificate to retrieve the hash from.
+ * @param cert Certificate to retrieve the fingerprint from.
* @param gc Garbage collection arena to use when allocating string.
*
- * @return a string containing the SHA1 hash of the certificate
+ * @return a string containing the certificate fingerprint
*/
-unsigned char *x509_get_sha1_hash (openvpn_x509_cert_t *cert, struct gc_arena *gc);
+struct buffer x509_get_sha1_fingerprint (openvpn_x509_cert_t *cert,
+ struct gc_arena *gc);
+
+/**
+ * Retrieve the certificate's SHA256 fingerprint.
+ *
+ * @param cert Certificate to retrieve the fingerprint from.
+ * @param gc Garbage collection arena to use when allocating string.
+ *
+ * @return a string containing the certificate fingerprint
+ */
+struct buffer x509_get_sha256_fingerprint (openvpn_x509_cert_t *cert,
+ struct gc_arena *gc);
/*
* Retrieve the certificate's username from the specified field.
@@ -150,8 +163,6 @@ char *backend_x509_get_serial_hex (openvpn_x509_cert_t *cert,
*/
void x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert);
-#ifdef ENABLE_X509_TRACK
-
/*
* Start tracking the given attribute.
*
@@ -189,8 +200,6 @@ void x509_track_add (const struct x509_track **ll_head, const char *name,
void x509_setenv_track (const struct x509_track *xt, struct env_set *es,
const int depth, openvpn_x509_cert_t *x509);
-#endif
-
/*
* Check X.509 Netscape certificate type field, if available.
*
@@ -204,8 +213,6 @@ void x509_setenv_track (const struct x509_track *xt, struct env_set *es,
*/
result_t x509_verify_ns_cert_type(const openvpn_x509_cert_t *cert, const int usage);
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L || ENABLE_CRYPTO_POLARSSL
-
/*
* Verify X.509 key usage extension field.
*
@@ -234,8 +241,6 @@ result_t x509_verify_cert_ku (openvpn_x509_cert_t *x509, const unsigned * const
*/
result_t x509_verify_cert_eku (openvpn_x509_cert_t *x509, const char * const expected_oid);
-#endif
-
/*
* Store the given certificate in pem format in a temporary file in tmp_dir
*
@@ -247,18 +252,12 @@ result_t x509_verify_cert_eku (openvpn_x509_cert_t *x509, const char * const exp
*/
result_t x509_write_pem(FILE *peercert_file, openvpn_x509_cert_t *peercert);
-/*
- * Check the certificate against a CRL file.
- *
- * @param crl_file File name of the CRL file
- * @param cert Certificate to verify
- * @param subject Subject of the given certificate
- *
- * @return \c SUCCESS if the CRL was not signed by the issuer of the
- * certificate or does not contain an entry for it.
- * \c FAILURE otherwise.
+/**
+ * Return true iff a CRL is configured, but is not loaded. This can be caused
+ * by e.g. a CRL parsing error, a missing CRL file or CRL file permission
+ * errors. (These conditions are checked upon startup, but the CRL might be
+ * updated and reloaded during runtime.)
*/
-result_t x509_verify_crl(const char *crl_file, openvpn_x509_cert_t *cert,
- const char *subject);
+bool tls_verify_crl_missing(const struct tls_options *opt);
#endif /* SSL_VERIFY_BACKEND_H_ */
diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c
new file mode 100644
index 0000000..332f04b
--- /dev/null
+++ b/src/openvpn/ssl_verify_mbedtls.c
@@ -0,0 +1,511 @@
+/*
+ * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
+ *
+ * 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
+ */
+
+/**
+ * @file Control Channel Verification Module mbed TLS backend
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS)
+
+#include "crypto_mbedtls.h"
+#include "ssl_verify.h"
+#include <mbedtls/asn1.h>
+#include <mbedtls/error.h>
+#include <mbedtls/bignum.h>
+#include <mbedtls/oid.h>
+#include <mbedtls/sha1.h>
+
+#define MAX_SUBJECT_LENGTH 256
+
+int
+verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth,
+ uint32_t *flags)
+{
+ struct tls_session *session = (struct tls_session *) session_obj;
+ struct gc_arena gc = gc_new();
+
+ ASSERT (cert);
+ ASSERT (session);
+
+ session->verified = false;
+
+ /* Remember certificate hash */
+ struct buffer cert_fingerprint = x509_get_sha256_fingerprint (cert, &gc);
+ cert_hash_remember (session, cert_depth, &cert_fingerprint);
+
+ /* did peer present cert which was signed by our root cert? */
+ if (*flags != 0)
+ {
+ int ret = 0;
+ char errstr[512] = { 0 };
+ char *subject = x509_get_subject(cert, &gc);
+
+ ret = mbedtls_x509_crt_verify_info (errstr, sizeof(errstr)-1, "", *flags);
+ if (ret <= 0 && !openvpn_snprintf(errstr, sizeof(errstr),
+ "Could not retrieve error string, flags=%"PRIx32, *flags))
+ {
+ errstr[0] = '\0';
+ }
+ else
+ {
+ chomp(errstr);
+ }
+
+ if (subject)
+ {
+ msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, subject=%s: %s",
+ cert_depth, subject, errstr);
+ }
+ else
+ {
+ msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, (could not extract X509 "
+ "subject string from certificate): %s", cert_depth, errstr);
+ }
+
+ /* Leave flags set to non-zero to indicate that the cert is not ok */
+ }
+ else if (SUCCESS != verify_cert(session, cert, cert_depth))
+ {
+ *flags |= MBEDTLS_X509_BADCERT_OTHER;
+ }
+
+ gc_free(&gc);
+
+ /*
+ * PolarSSL/mbed TLS-1.2.0+ expects 0 on anything except fatal errors.
+ */
+ return 0;
+}
+
+#ifdef ENABLE_X509ALTUSERNAME
+# warning "X509 alt user name not yet supported for mbed TLS"
+#endif
+
+result_t
+backend_x509_get_username (char *cn, int cn_len,
+ char *x509_username_field, mbedtls_x509_crt *cert)
+{
+ mbedtls_x509_name *name;
+
+ ASSERT( cn != NULL );
+
+ name = &cert->subject;
+
+ /* Find common name */
+ while( name != NULL )
+ {
+ if (0 == memcmp (name->oid.p, MBEDTLS_OID_AT_CN,
+ MBEDTLS_OID_SIZE (MBEDTLS_OID_AT_CN)))
+ break;
+
+ name = name->next;
+ }
+
+ /* Not found, return an error if this is the peer's certificate */
+ if( name == NULL )
+ return FAILURE;
+
+ /* Found, extract CN */
+ if (cn_len > name->val.len)
+ {
+ memcpy( cn, name->val.p, name->val.len );
+ cn[name->val.len] = '\0';
+ }
+ else
+ {
+ memcpy( cn, name->val.p, cn_len);
+ cn[cn_len-1] = '\0';
+ }
+
+ return SUCCESS;
+}
+
+char *
+backend_x509_get_serial (mbedtls_x509_crt *cert, struct gc_arena *gc)
+{
+ char *buf = NULL;
+ size_t buflen = 0;
+ mbedtls_mpi serial_mpi = { 0 };
+
+ /* Transform asn1 integer serial into mbed TLS MPI */
+ mbedtls_mpi_init(&serial_mpi);
+ if (!mbed_ok(mbedtls_mpi_read_binary(&serial_mpi, cert->serial.p,
+ cert->serial.len)))
+ {
+ msg(M_WARN, "Failed to retrieve serial from certificate.");
+ goto end;
+ }
+
+ /* Determine decimal representation length, allocate buffer */
+ mbedtls_mpi_write_string(&serial_mpi, 10, NULL, 0, &buflen);
+ buf = gc_malloc(buflen, true, gc);
+
+ /* Write MPI serial as decimal string into buffer */
+ if (!mbed_ok(mbedtls_mpi_write_string(&serial_mpi, 10, buf, buflen, &buflen)))
+ {
+ msg(M_WARN, "Failed to write serial to string.");
+ buf = NULL;
+ goto end;
+ }
+
+end:
+ mbedtls_mpi_free(&serial_mpi);
+ return buf;
+}
+
+char *
+backend_x509_get_serial_hex (mbedtls_x509_crt *cert, struct gc_arena *gc)
+{
+ char *buf = NULL;
+ size_t len = cert->serial.len * 3 + 1;
+
+ buf = gc_malloc(len, true, gc);
+
+ if(mbedtls_x509_serial_gets(buf, len-1, &cert->serial) < 0)
+ buf = NULL;
+
+ return buf;
+}
+
+static struct buffer
+x509_get_fingerprint (const mbedtls_md_info_t *md_info, mbedtls_x509_crt *cert,
+ struct gc_arena *gc)
+{
+ const size_t md_size = mbedtls_md_get_size (md_info);
+ struct buffer fingerprint = alloc_buf_gc (md_size, gc);
+ mbedtls_md(md_info, cert->raw.p, cert->tbs.len, BPTR (&fingerprint));
+ ASSERT (buf_inc_len(&fingerprint, md_size));
+ return fingerprint;
+}
+
+struct buffer
+x509_get_sha1_fingerprint (mbedtls_x509_crt *cert, struct gc_arena *gc)
+{
+ return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1),
+ cert, gc);
+}
+
+struct buffer
+x509_get_sha256_fingerprint (mbedtls_x509_crt *cert, struct gc_arena *gc)
+{
+ return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
+ cert, gc);
+}
+
+char *
+x509_get_subject(mbedtls_x509_crt *cert, struct gc_arena *gc)
+{
+ char tmp_subject[MAX_SUBJECT_LENGTH] = {0};
+ char *subject = NULL;
+
+ int ret = 0;
+
+ ret = mbedtls_x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject );
+ if (ret > 0)
+ {
+ /* Allocate the required space for the subject */
+ subject = string_alloc(tmp_subject, gc);
+ }
+
+ return subject;
+}
+
+static void
+do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth)
+{
+ char *name_expand;
+ size_t name_expand_size;
+
+ string_mod (value, CC_ANY, CC_CRLF, '?');
+ msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth);
+ name_expand_size = 64 + strlen (name);
+ name_expand = (char *) malloc (name_expand_size);
+ check_malloc_return (name_expand);
+ openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name);
+ setenv_str (es, name_expand, value);
+ free (name_expand);
+}
+
+static char *
+asn1_buf_to_c_string(const mbedtls_asn1_buf *orig, struct gc_arena *gc)
+{
+ size_t i;
+ char *val;
+
+ for (i = 0; i < orig->len; ++i)
+ if (orig->p[i] == '\0')
+ return "ERROR: embedded null value";
+ val = gc_malloc(orig->len+1, false, gc);
+ memcpy(val, orig->p, orig->len);
+ val[orig->len] = '\0';
+ return val;
+}
+
+static void
+do_setenv_name(struct env_set *es, const struct x509_track *xt,
+ const mbedtls_x509_crt *cert, int depth, struct gc_arena *gc)
+{
+ const mbedtls_x509_name *xn;
+ for (xn = &cert->subject; xn != NULL; xn = xn->next)
+ {
+ const char *xn_short_name = NULL;
+ if (0 == mbedtls_oid_get_attr_short_name (&xn->oid, &xn_short_name) &&
+ 0 == strcmp (xt->name, xn_short_name))
+ {
+ char *val_str = asn1_buf_to_c_string (&xn->val, gc);
+ do_setenv_x509 (es, xt->name, val_str, depth);
+ }
+ }
+}
+
+void
+x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc)
+{
+ struct x509_track *xt;
+ ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc);
+ if (*name == '+')
+ {
+ xt->flags |= XT_FULL_CHAIN;
+ ++name;
+ }
+ xt->name = name;
+ xt->next = *ll_head;
+ *ll_head = xt;
+}
+
+void
+x509_setenv_track (const struct x509_track *xt, struct env_set *es,
+ const int depth, mbedtls_x509_crt *cert)
+{
+ struct gc_arena gc = gc_new();
+ while (xt)
+ {
+ if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
+ {
+ if (0 == strcmp(xt->name, "SHA1") || 0 == strcmp(xt->name, "SHA256"))
+ {
+ /* Fingerprint is not part of X509 structure */
+ struct buffer cert_hash;
+ char *fingerprint;
+
+ if (0 == strcmp(xt->name, "SHA1"))
+ cert_hash = x509_get_sha1_fingerprint(cert, &gc);
+ else
+ cert_hash = x509_get_sha256_fingerprint(cert, &gc);
+
+ fingerprint = format_hex_ex(BPTR(&cert_hash),
+ BLEN(&cert_hash), 0, 1 | FHE_CAPS, ":", &gc);
+ do_setenv_x509(es, xt->name, fingerprint, depth);
+ }
+ else
+ {
+ do_setenv_name(es, xt, cert, depth, &gc);
+ }
+ }
+ xt = xt->next;
+ }
+ gc_free(&gc);
+}
+
+/*
+ * Save X509 fields to environment, using the naming convention:
+ *
+ * X509_{cert_depth}_{name}={value}
+ */
+void
+x509_setenv (struct env_set *es, int cert_depth, mbedtls_x509_crt *cert)
+{
+ int i;
+ unsigned char c;
+ const mbedtls_x509_name *name;
+ char s[128];
+
+ name = &cert->subject;
+
+ memset( s, 0, sizeof( s ) );
+
+ while( name != NULL )
+ {
+ char name_expand[64+8];
+ const char *shortname;
+
+ if( 0 == mbedtls_oid_get_attr_short_name(&name->oid, &shortname) )
+ {
+ openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s",
+ cert_depth, shortname);
+ }
+ else
+ {
+ openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?",
+ cert_depth);
+ }
+
+ for( i = 0; i < name->val.len; i++ )
+ {
+ if( i >= (int) sizeof( s ) - 1 )
+ break;
+
+ c = name->val.p[i];
+ if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
+ s[i] = '?';
+ else s[i] = c;
+ }
+ s[i] = '\0';
+
+ /* Check both strings, set environment variable */
+ string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
+ string_mod ((char*)s, CC_PRINT, CC_CRLF, '_');
+ setenv_str_incr (es, name_expand, (char*)s);
+
+ name = name->next;
+ }
+}
+
+result_t
+x509_verify_ns_cert_type(const mbedtls_x509_crt *cert, const int usage)
+{
+ if (usage == NS_CERT_CHECK_NONE)
+ return SUCCESS;
+ if (usage == NS_CERT_CHECK_CLIENT)
+ return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE)
+ && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT)) ?
+ SUCCESS : FAILURE;
+ if (usage == NS_CERT_CHECK_SERVER)
+ return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE)
+ && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER)) ?
+ SUCCESS : FAILURE;
+
+ return FAILURE;
+}
+
+result_t
+x509_verify_cert_ku (mbedtls_x509_crt *cert, const unsigned * const expected_ku,
+ int expected_len)
+{
+ result_t fFound = FAILURE;
+
+ if(!(cert->ext_types & MBEDTLS_X509_EXT_KEY_USAGE))
+ {
+ msg (D_HANDSHAKE, "Certificate does not have key usage extension");
+ }
+ else
+ {
+ int i;
+ unsigned nku = cert->key_usage;
+
+ msg (D_HANDSHAKE, "Validating certificate key usage");
+ for (i=0; SUCCESS != fFound && i<expected_len; i++)
+ {
+ if (expected_ku[i] != 0)
+ {
+ msg (D_HANDSHAKE, "++ Certificate has key usage %04x, expects "
+ "%04x", nku, expected_ku[i]);
+
+ if (nku == expected_ku[i])
+ {
+ fFound = SUCCESS;
+ }
+ }
+ }
+ }
+ return fFound;
+}
+
+result_t
+x509_verify_cert_eku (mbedtls_x509_crt *cert, const char * const expected_oid)
+{
+ result_t fFound = FAILURE;
+
+ if (!(cert->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE))
+ {
+ msg (D_HANDSHAKE, "Certificate does not have extended key usage extension");
+ }
+ else
+ {
+ mbedtls_x509_sequence *oid_seq = &(cert->ext_key_usage);
+
+ msg (D_HANDSHAKE, "Validating certificate extended key usage");
+ while (oid_seq != NULL)
+ {
+ mbedtls_x509_buf *oid = &oid_seq->buf;
+ char oid_num_str[1024];
+ const char *oid_str;
+
+ if (0 == mbedtls_oid_get_extended_key_usage( oid, &oid_str ))
+ {
+ msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s",
+ oid_str, expected_oid);
+ if (!strcmp (expected_oid, oid_str))
+ {
+ fFound = SUCCESS;
+ break;
+ }
+ }
+
+ if (0 < mbedtls_oid_get_numeric_string( oid_num_str,
+ sizeof (oid_num_str), oid))
+ {
+ msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s",
+ oid_num_str, expected_oid);
+ if (!strcmp (expected_oid, oid_num_str))
+ {
+ fFound = SUCCESS;
+ break;
+ }
+ }
+ oid_seq = oid_seq->next;
+ }
+ }
+
+ return fFound;
+}
+
+result_t
+x509_write_pem(FILE *peercert_file, mbedtls_x509_crt *peercert)
+{
+ msg (M_WARN, "mbed TLS does not support writing peer certificate in PEM format");
+ return FAILURE;
+}
+
+bool
+tls_verify_crl_missing(const struct tls_options *opt)
+{
+ if (opt->crl_file && !(opt->ssl_flags & SSLF_CRL_VERIFY_DIR)
+ && (opt->ssl_ctx.crl == NULL || opt->ssl_ctx.crl->version == 0))
+ {
+ return true;
+ }
+ return false;
+}
+
+#endif /* #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */
diff --git a/src/openvpn/ssl_verify_polarssl.h b/src/openvpn/ssl_verify_mbedtls.h
index b5157ed..e26d08f 100644
--- a/src/openvpn/ssl_verify_polarssl.h
+++ b/src/openvpn/ssl_verify_mbedtls.h
@@ -24,20 +24,18 @@
*/
/**
- * @file Control Channel Verification Module PolarSSL backend
+ * @file Control Channel Verification Module mbed TLS backend
*/
-#ifndef SSL_VERIFY_POLARSSL_H_
-#define SSL_VERIFY_POLARSSL_H_
+#ifndef SSL_VERIFY_MBEDTLS_H_
+#define SSL_VERIFY_MBEDTLS_H_
#include "syshead.h"
-#include "misc.h"
-#include "manage.h"
-#include <polarssl/x509_crt.h>
+#include <mbedtls/x509_crt.h>
#ifndef __OPENVPN_X509_CERT_T_DECLARED
#define __OPENVPN_X509_CERT_T_DECLARED
-typedef x509_crt openvpn_x509_cert_t;
+typedef mbedtls_x509_crt openvpn_x509_cert_t;
#endif
/** @name Function for authenticating a new connection from a remote OpenVPN peer
@@ -52,7 +50,7 @@ typedef x509_crt openvpn_x509_cert_t;
* determine whether the remote OpenVPN peer's certificate is allowed to
* connect. It is called for once for every certificate in the chain. The
* callback functionality is configured in the \c init_ssl() function, which
- * calls the PolarSSL library's \c ssl_set_verify_callback() function with \c
+ * calls the mbed TLS library's \c ssl_set_verify_callback() function with \c
* verify_callback() as its callback argument.
*
* It checks *flags and registers the certificate hash. If these steps succeed,
@@ -61,7 +59,7 @@ typedef x509_crt openvpn_x509_cert_t;
*
* @param session_obj - The OpenVPN \c tls_session associated with this object,
* as set during SSL session setup.
- * @param cert - The certificate used by PolarSSL.
+ * @param cert - The certificate used by mbed TLS.
* @param cert_depth - The depth of the current certificate in the chain, with
* 0 being the actual certificate.
* @param flags - Whether the remote OpenVPN peer's certificate
@@ -72,9 +70,9 @@ typedef x509_crt openvpn_x509_cert_t;
*
* @return The return value is 0 unless a fatal error occurred.
*/
-int verify_callback (void *session_obj, x509_crt *cert, int cert_depth,
- int *flags);
+int verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth,
+ uint32_t *flags);
/** @} name Function for authenticating a new connection from a remote OpenVPN peer */
-#endif /* SSL_VERIFY_POLARSSL_H_ */
+#endif /* SSL_VERIFY_MBEDTLS_H_ */
diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c
index 4750f02..3d1c85e 100644
--- a/src/openvpn/ssl_verify_openssl.c
+++ b/src/openvpn/ssl_verify_openssl.c
@@ -35,11 +35,15 @@
#include "syshead.h"
-#if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL)
+#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL)
+#include "ssl_verify_openssl.h"
+
+#include "error.h"
+#include "ssl_openssl.h"
#include "ssl_verify.h"
#include "ssl_verify_backend.h"
-#include "ssl_openssl.h"
+
#include <openssl/x509v3.h>
#include <openssl/err.h>
@@ -57,8 +61,8 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
session = (struct tls_session *) SSL_get_ex_data (ssl, mydata_index);
ASSERT (session);
- cert_hash_remember (session, ctx->error_depth,
- x509_get_sha1_hash(ctx->current_cert, &gc));
+ struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc);
+ cert_hash_remember (session, ctx->error_depth, &cert_hash);
/* did peer present cert which was signed by our root cert? */
if (!preverify_ok)
@@ -66,15 +70,28 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
/* get the X509 name */
char *subject = x509_get_subject(ctx->current_cert, &gc);
- if (subject)
+ if (!subject)
+ {
+ subject = "(Failed to retrieve certificate subject)";
+ }
+
+ /* Log and ignore missing CRL errors */
+ if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL)
{
- /* Remote site specified a certificate, but it's not correct */
- msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s",
- ctx->error_depth,
- X509_verify_cert_error_string (ctx->error),
- subject);
+ msg (D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s",
+ ctx->error_depth,
+ X509_verify_cert_error_string (ctx->error),
+ subject);
+ ret = 1;
+ goto cleanup;
}
+ /* Remote site specified a certificate, but it's not correct */
+ msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s",
+ ctx->error_depth,
+ X509_verify_cert_error_string (ctx->error),
+ subject);
+
ERR_clear_error();
session->verified = false;
@@ -134,8 +151,8 @@ bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size)
}
break;
default:
- msg (D_TLS_ERRORS, "ASN1 ERROR: can not handle field type %i",
- name->type);
+ msg (D_TLS_DEBUG, "%s: ignoring general name field type %i",
+ __func__, name->type);
break;
}
}
@@ -165,8 +182,8 @@ extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out,
int tmp = -1;
X509_NAME_ENTRY *x509ne = 0;
ASN1_STRING *asn1 = 0;
- unsigned char *buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
- int nid = OBJ_txt2nid((char *)field_name);
+ unsigned char *buf = NULL;
+ int nid = OBJ_txt2nid(field_name);
ASSERT (size > 0);
*out = '\0';
@@ -244,11 +261,21 @@ backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc)
return format_hex_ex(asn1_i->data, asn1_i->length, 0, 1, ":", gc);
}
-unsigned char *
-x509_get_sha1_hash (X509 *cert, struct gc_arena *gc)
+struct buffer
+x509_get_sha1_fingerprint (X509 *cert, struct gc_arena *gc)
+{
+ struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc);
+ memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash));
+ ASSERT (buf_inc_len(&hash, sizeof (cert->sha1_hash)));
+ return hash;
+}
+
+struct buffer
+x509_get_sha256_fingerprint (X509 *cert, struct gc_arena *gc)
{
- unsigned char *hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
- memcpy(hash, cert->sha1_hash, SHA_DIGEST_LENGTH);
+ struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc);
+ X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL);
+ ASSERT (buf_inc_len(&hash, (EVP_sha256())->md_size));
return hash;
}
@@ -299,7 +326,26 @@ err:
}
-#ifdef ENABLE_X509_TRACK
+/*
+ * x509-track implementation -- save X509 fields to environment,
+ * using the naming convention:
+ *
+ * X509_{cert_depth}_{name}={value}
+ *
+ * This function differs from x509_setenv below in the following ways:
+ *
+ * (1) Only explicitly named attributes in xt are saved, per usage
+ * of "x509-track" program options.
+ * (2) Only the level 0 cert info is saved unless the XT_FULL_CHAIN
+ * flag is set in xt->flags (corresponds with prepending a '+'
+ * to the name when specified by "x509-track" program option).
+ * (3) This function supports both X509 subject name fields as
+ * well as X509 V3 extensions.
+ * (4) This function can return the SHA1 fingerprint of a cert, e.g.
+ * x509-track "+SHA1"
+ * will return the SHA1 fingerprint for each certificate in the
+ * peer chain.
+ */
void
x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc)
@@ -342,60 +388,82 @@ do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth)
void
x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509)
{
+ struct gc_arena gc = gc_new();
X509_NAME *x509_name = X509_get_subject_name (x509);
const char nullc = '\0';
- int i;
while (xt)
{
if (depth == 0 || (xt->flags & XT_FULL_CHAIN))
{
- i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1);
- if (i >= 0)
- {
- X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
- if (ent)
- {
- ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent);
- unsigned char *buf;
- buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
- if (ASN1_STRING_to_UTF8 (&buf, val) > 0)
- {
- do_setenv_x509(es, xt->name, (char *)buf, depth);
- OPENSSL_free (buf);
- }
- }
- }
- else
+ switch (xt->nid)
{
- i = X509_get_ext_by_NID(x509, xt->nid, -1);
- if (i >= 0)
- {
- X509_EXTENSION *ext = X509_get_ext(x509, i);
- if (ext)
- {
- BIO *bio = BIO_new(BIO_s_mem());
- if (bio)
- {
- if (X509V3_EXT_print(bio, ext, 0, 0))
- {
- if (BIO_write(bio, &nullc, 1) == 1)
- {
- char *str;
- BIO_get_mem_data(bio, &str);
- do_setenv_x509(es, xt->name, str, depth);
- }
- }
- BIO_free(bio);
- }
- }
- }
+ case NID_sha1:
+ case NID_sha256:
+ {
+ struct buffer fp_buf;
+ char *fp_str = NULL;
+
+ if (xt->nid == NID_sha1)
+ fp_buf = x509_get_sha1_fingerprint(x509, &gc);
+ else
+ fp_buf = x509_get_sha256_fingerprint(x509, &gc);
+
+ fp_str = format_hex_ex(BPTR(&fp_buf), BLEN(&fp_buf), 0,
+ 1 | FHE_CAPS, ":", &gc);
+ do_setenv_x509(es, xt->name, fp_str, depth);
+ }
+ break;
+ default:
+ {
+ int i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1);
+ if (i >= 0)
+ {
+ X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
+ if (ent)
+ {
+ ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent);
+ unsigned char *buf;
+ buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
+ if (ASN1_STRING_to_UTF8 (&buf, val) > 0)
+ {
+ do_setenv_x509(es, xt->name, (char *)buf, depth);
+ OPENSSL_free (buf);
+ }
+ }
+ }
+ else
+ {
+ i = X509_get_ext_by_NID(x509, xt->nid, -1);
+ if (i >= 0)
+ {
+ X509_EXTENSION *ext = X509_get_ext(x509, i);
+ if (ext)
+ {
+ BIO *bio = BIO_new(BIO_s_mem());
+ if (bio)
+ {
+ if (X509V3_EXT_print(bio, ext, 0, 0))
+ {
+ if (BIO_write(bio, &nullc, 1) == 1)
+ {
+ char *str;
+ BIO_get_mem_data(bio, &str);
+ do_setenv_x509(es, xt->name, str, depth);
+ }
+ }
+ BIO_free(bio);
+ }
+ }
+ }
+ }
+ }
}
}
xt = xt->next;
}
+ gc_free(&gc);
}
-#endif
/*
* Save X509 fields to environment, using the naming convention:
@@ -444,7 +512,7 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert)
objbuf);
string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_');
- setenv_str (es, name_expand, (char*)buf);
+ setenv_str_incr (es, name_expand, (char*)buf);
free (name_expand);
OPENSSL_free (buf);
}
@@ -465,8 +533,6 @@ x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage)
return FAILURE;
}
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
-
result_t
x509_verify_cert_ku (X509 *x509, const unsigned * const expected_ku,
int expected_len)
@@ -572,61 +638,28 @@ x509_write_pem(FILE *peercert_file, X509 *peercert)
return SUCCESS;
}
-#endif /* OPENSSL_VERSION_NUMBER */
-
-/*
- * check peer cert against CRL
- */
-result_t
-x509_verify_crl(const char *crl_file, X509 *peer_cert, const char *subject)
+bool
+tls_verify_crl_missing(const struct tls_options *opt)
{
- X509_CRL *crl=NULL;
- X509_REVOKED *revoked;
- BIO *in=NULL;
- int n,i;
- result_t retval = FAILURE;
- struct gc_arena gc = gc_new();
- char *serial;
-
- in = BIO_new_file (crl_file, "r");
-
- if (in == NULL) {
- msg (M_WARN, "CRL: cannot read: %s", crl_file);
- goto end;
- }
- crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL);
- if (crl == NULL) {
- msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
- goto end;
- }
-
- if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(peer_cert)) != 0) {
- msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of "
- "certificate %s", crl_file, subject);
- retval = SUCCESS;
- goto end;
- }
-
- n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
- for (i = 0; i < n; i++) {
- revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
- if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(peer_cert)) == 0) {
- serial = backend_x509_get_serial_hex(peer_cert, &gc);
- msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE"));
- goto end;
+ if (!opt->crl_file || (opt->ssl_flags & SSLF_CRL_VERIFY_DIR))
+ {
+ return false;
}
- }
-
- retval = SUCCESS;
- msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
-end:
- gc_free(&gc);
- BIO_free(in);
- if (crl)
- X509_CRL_free (crl);
+ X509_STORE *store = SSL_CTX_get_cert_store(opt->ssl_ctx.ctx);
+ if (!store)
+ crypto_msg (M_FATAL, "Cannot get certificate store");
- return retval;
+ for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++)
+ {
+ X509_OBJECT* obj = sk_X509_OBJECT_value(store->objs, i);
+ ASSERT(obj);
+ if (obj->type == X509_LU_CRL)
+ {
+ return false;
+ }
+ }
+ return true;
}
-#endif /* defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL) */
+#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) */
diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c
deleted file mode 100644
index 7ed87d6..0000000
--- a/src/openvpn/ssl_verify_polarssl.c
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
- *
- * 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
- */
-
-/**
- * @file Control Channel Verification Module PolarSSL backend
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#elif defined(_MSC_VER)
-#include "config-msvc.h"
-#endif
-
-#include "syshead.h"
-
-#if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL)
-
-#include "ssl_verify.h"
-#include <polarssl/bignum.h>
-#include <polarssl/error.h>
-#include <polarssl/oid.h>
-#include <polarssl/sha1.h>
-
-#define MAX_SUBJECT_LENGTH 256
-
-int
-verify_callback (void *session_obj, x509_crt *cert, int cert_depth,
- int *flags)
-{
- struct tls_session *session = (struct tls_session *) session_obj;
- struct gc_arena gc = gc_new();
-
- ASSERT (cert);
- ASSERT (session);
-
- session->verified = false;
-
- /* Remember certificate hash */
- cert_hash_remember (session, cert_depth, x509_get_sha1_hash(cert, &gc));
-
- /* did peer present cert which was signed by our root cert? */
- if (*flags != 0)
- {
- char *subject = x509_get_subject(cert, &gc);
-
- if (subject)
- msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, %s", cert_depth, *flags, subject);
- else
- msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, could not extract X509 "
- "subject string from certificate", *flags, cert_depth);
-
- /* Leave flags set to non-zero to indicate that the cert is not ok */
- }
- else if (SUCCESS != verify_cert(session, cert, cert_depth))
- {
- *flags |= BADCERT_OTHER;
- }
-
- gc_free(&gc);
-
- /*
- * PolarSSL-1.2.0+ expects 0 on anything except fatal errors.
- */
- return 0;
-}
-
-#ifdef ENABLE_X509ALTUSERNAME
-# warning "X509 alt user name not yet supported for PolarSSL"
-#endif
-
-result_t
-backend_x509_get_username (char *cn, int cn_len,
- char *x509_username_field, x509_crt *cert)
-{
- x509_name *name;
-
- ASSERT( cn != NULL );
-
- name = &cert->subject;
-
- /* Find common name */
- while( name != NULL )
- {
- if( memcmp( name->oid.p, OID_AT_CN, OID_SIZE(OID_AT_CN) ) == 0)
- break;
-
- name = name->next;
- }
-
- /* Not found, return an error if this is the peer's certificate */
- if( name == NULL )
- return FAILURE;
-
- /* Found, extract CN */
- if (cn_len > name->val.len)
- memcpy( cn, name->val.p, name->val.len );
- else
- {
- memcpy( cn, name->val.p, cn_len);
- cn[cn_len-1] = '\0';
- }
-
- return SUCCESS;
-}
-
-char *
-backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc)
-{
- char *buf = NULL;
- size_t buflen = 0;
- mpi serial_mpi = { 0 };
-
- /* Transform asn1 integer serial into PolarSSL MPI */
- mpi_init(&serial_mpi);
- if (!polar_ok(mpi_read_binary(&serial_mpi, cert->serial.p, cert->serial.len)))
- {
- msg(M_WARN, "Failed to retrieve serial from certificate.");
- return NULL;
- }
-
- /* Determine decimal representation length, allocate buffer */
- mpi_write_string(&serial_mpi, 10, buf, &buflen);
- buf = gc_malloc(buflen, true, gc);
-
- /* Write MPI serial as decimal string into buffer */
- if (!polar_ok(mpi_write_string(&serial_mpi, 10, buf, &buflen)))
- {
- msg(M_WARN, "Failed to write serial to string.");
- return NULL;
- }
-
- return buf;
-}
-
-char *
-backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc)
-{
- char *buf = NULL;
- size_t len = cert->serial.len * 3 + 1;
-
- buf = gc_malloc(len, true, gc);
-
- if(x509_serial_gets(buf, len-1, &cert->serial) < 0)
- buf = NULL;
-
- return buf;
-}
-
-unsigned char *
-x509_get_sha1_hash (x509_crt *cert, struct gc_arena *gc)
-{
- unsigned char *sha1_hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
- sha1(cert->tbs.p, cert->tbs.len, sha1_hash);
- return sha1_hash;
-}
-
-char *
-x509_get_subject(x509_crt *cert, struct gc_arena *gc)
-{
- char tmp_subject[MAX_SUBJECT_LENGTH] = {0};
- char *subject = NULL;
-
- int ret = 0;
-
- ret = x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject );
- if (ret > 0)
- {
- /* Allocate the required space for the subject */
- subject = string_alloc(tmp_subject, gc);
- }
-
- return subject;
-}
-
-/*
- * Save X509 fields to environment, using the naming convention:
- *
- * X509_{cert_depth}_{name}={value}
- */
-void
-x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert)
-{
- int i;
- unsigned char c;
- const x509_name *name;
- char s[128];
-
- name = &cert->subject;
-
- memset( s, 0, sizeof( s ) );
-
- while( name != NULL )
- {
- char name_expand[64+8];
- const char *shortname;
-
- if( 0 == oid_get_attr_short_name(&name->oid, &shortname) )
- {
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s",
- cert_depth, shortname);
- }
- else
- {
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?",
- cert_depth);
- }
-
- for( i = 0; i < name->val.len; i++ )
- {
- if( i >= (int) sizeof( s ) - 1 )
- break;
-
- c = name->val.p[i];
- if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
- s[i] = '?';
- else s[i] = c;
- }
- s[i] = '\0';
-
- /* Check both strings, set environment variable */
- string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
- string_mod ((char*)s, CC_PRINT, CC_CRLF, '_');
- setenv_str (es, name_expand, (char*)s);
-
- name = name->next;
- }
-}
-
-result_t
-x509_verify_ns_cert_type(const x509_crt *cert, const int usage)
-{
- if (usage == NS_CERT_CHECK_NONE)
- return SUCCESS;
- if (usage == NS_CERT_CHECK_CLIENT)
- return ((cert->ext_types & EXT_NS_CERT_TYPE)
- && (cert->ns_cert_type & NS_CERT_TYPE_SSL_CLIENT)) ? SUCCESS : FAILURE;
- if (usage == NS_CERT_CHECK_SERVER)
- return ((cert->ext_types & EXT_NS_CERT_TYPE)
- && (cert->ns_cert_type & NS_CERT_TYPE_SSL_SERVER)) ? SUCCESS : FAILURE;
-
- return FAILURE;
-}
-
-result_t
-x509_verify_cert_ku (x509_crt *cert, const unsigned * const expected_ku,
- int expected_len)
-{
- result_t fFound = FAILURE;
-
- if(!(cert->ext_types & EXT_KEY_USAGE))
- {
- msg (D_HANDSHAKE, "Certificate does not have key usage extension");
- }
- else
- {
- int i;
- unsigned nku = cert->key_usage;
-
- msg (D_HANDSHAKE, "Validating certificate key usage");
- for (i=0; SUCCESS != fFound && i<expected_len; i++)
- {
- if (expected_ku[i] != 0)
- {
- msg (D_HANDSHAKE, "++ Certificate has key usage %04x, expects "
- "%04x", nku, expected_ku[i]);
-
- if (nku == expected_ku[i])
- {
- fFound = SUCCESS;
- }
- }
- }
- }
- return fFound;
-}
-
-result_t
-x509_verify_cert_eku (x509_crt *cert, const char * const expected_oid)
-{
- result_t fFound = FAILURE;
-
- if (!(cert->ext_types & EXT_EXTENDED_KEY_USAGE))
- {
- msg (D_HANDSHAKE, "Certificate does not have extended key usage extension");
- }
- else
- {
- x509_sequence *oid_seq = &(cert->ext_key_usage);
-
- msg (D_HANDSHAKE, "Validating certificate extended key usage");
- while (oid_seq != NULL)
- {
- x509_buf *oid = &oid_seq->buf;
- char oid_num_str[1024];
- const char *oid_str;
-
- if (0 == oid_get_extended_key_usage( oid, &oid_str ))
- {
- msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s",
- oid_str, expected_oid);
- if (!strcmp (expected_oid, oid_str))
- {
- fFound = SUCCESS;
- break;
- }
- }
-
- if (0 < oid_get_numeric_string( oid_num_str,
- sizeof (oid_num_str), oid))
- {
- msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s",
- oid_num_str, expected_oid);
- if (!strcmp (expected_oid, oid_num_str))
- {
- fFound = SUCCESS;
- break;
- }
- }
- oid_seq = oid_seq->next;
- }
- }
-
- return fFound;
-}
-
-result_t
-x509_write_pem(FILE *peercert_file, x509_crt *peercert)
-{
- msg (M_WARN, "PolarSSL does not support writing peer certificate in PEM format");
- return FAILURE;
-}
-
-/*
- * check peer cert against CRL
- */
-result_t
-x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject)
-{
- result_t retval = FAILURE;
- x509_crl crl = {0};
- struct gc_arena gc = gc_new();
- char *serial;
-
- if (!polar_ok(x509_crl_parse_file(&crl, crl_file)))
- {
- msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file);
- goto end;
- }
-
- if(cert->issuer_raw.len != crl.issuer_raw.len ||
- memcmp(crl.issuer_raw.p, cert->issuer_raw.p, crl.issuer_raw.len) != 0)
- {
- msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of "
- "certificate %s", crl_file, subject);
- retval = SUCCESS;
- goto end;
- }
-
- if (!polar_ok(x509_crt_revoked(cert, &crl)))
- {
- serial = backend_x509_get_serial_hex(cert, &gc);
- msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE"));
- goto end;
- }
-
- retval = SUCCESS;
- msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
-
-end:
- gc_free(&gc);
- x509_crl_free(&crl);
- return retval;
-}
-
-#endif /* #if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL) */
diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h
index 24926ae..8de7d87 100644
--- a/src/openvpn/syshead.h
+++ b/src/openvpn/syshead.h
@@ -37,7 +37,7 @@
# define unlikely(x) (x)
#endif
-#ifdef WIN32
+#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#define sleep(x) Sleep((x)*1000)
@@ -64,7 +64,7 @@
# include <sys/wait.h>
#endif
-#ifndef WIN32
+#ifndef _WIN32
#ifndef WEXITSTATUS
# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
@@ -217,7 +217,7 @@
#include <net/if_tap.h>
#endif
-#ifdef TARGET_LINUX
+#if defined(TARGET_LINUX) || defined (TARGET_ANDROID)
#ifdef HAVE_LINUX_IF_TUN_H
#include <linux/if_tun.h>
@@ -358,9 +358,14 @@
#endif /* TARGET_DARWIN */
-#ifdef WIN32
-#include <iphlpapi.h>
+#ifdef _WIN32
+ // Missing declarations for MinGW 32.
+ // #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2
+ typedef int MIB_TCP_STATE;
+ // #endif
+#include <naptypes.h>
#include <ntddndis.h>
+#include <iphlpapi.h>
#include <wininet.h>
#include <shellapi.h>
/* The following two headers are needed of PF_INET6 */
@@ -379,16 +384,13 @@
* Pedantic mode is meant to accomplish lint-style program checking,
* not to build a working executable.
*/
-#ifdef __STRICT_ANSI__
-# define PEDANTIC 1
+#ifdef PEDANTIC
# undef HAVE_CPP_VARARG_MACRO_GCC
# undef HAVE_CPP_VARARG_MACRO_ISO
# undef EMPTY_ARRAY_SIZE
# define EMPTY_ARRAY_SIZE 1
# undef inline
# define inline
-#else
-# define PEDANTIC 0
#endif
/*
@@ -403,18 +405,11 @@
/*
* Do we have nanoseconds gettimeofday?
*/
-#if defined(HAVE_GETTIMEOFDAY) || defined(WIN32)
+#if defined(HAVE_GETTIMEOFDAY) || defined(_WIN32)
#define HAVE_GETTIMEOFDAY_NANOSECONDS 1
#endif
/*
- * do we have the MIN() macro?
- */
-#ifndef MIN
-#define MIN(a,b) (((a)<(b))?(a):(b))
-#endif
-
-/*
* Do we have the capability to report extended socket errors?
*/
#if defined(HAVE_LINUX_TYPES_H) && defined(HAVE_LINUX_ERRQUEUE_H) && defined(HAVE_SOCK_EXTENDED_ERR) && defined(HAVE_MSGHDR) && defined(HAVE_CMSGHDR) && defined(CMSG_FIRSTHDR) && defined(CMSG_NXTHDR) && defined(IP_RECVERR) && defined(MSG_ERRQUEUE) && defined(SOL_IP) && defined(HAVE_IOVEC)
@@ -442,6 +437,13 @@
#endif
/*
+ * Define type sa_family_t if it isn't defined in the socket headers
+ */
+#ifndef HAVE_SA_FAMILY_T
+typedef unsigned short sa_family_t;
+#endif
+
+/*
* Disable ESEC
*/
#if 0
@@ -468,26 +470,16 @@
/*
* Directory separation char
*/
-#ifdef WIN32
+#ifdef _WIN32
#define OS_SPECIFIC_DIRSEP '\\'
#else
#define OS_SPECIFIC_DIRSEP '/'
#endif
/*
- * Define a boolean value based
- * on Win32 status.
- */
-#ifdef WIN32
-#define WIN32_0_1 1
-#else
-#define WIN32_0_1 0
-#endif
-
-/*
* Our socket descriptor type.
*/
-#ifdef WIN32
+#ifdef _WIN32
#define SOCKET_UNDEFINED (INVALID_SOCKET)
typedef SOCKET socket_descriptor_t;
#else
@@ -518,7 +510,7 @@ socket_defined (const socket_descriptor_t sd)
* Do we have point-to-multipoint capability?
*/
-#if defined(ENABLE_CLIENT_SERVER) && defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) && defined(HAVE_GETTIMEOFDAY_NANOSECONDS)
+#if defined(ENABLE_CLIENT_SERVER) && defined(ENABLE_CRYPTO) && defined(HAVE_GETTIMEOFDAY_NANOSECONDS)
#define P2MP 1
#else
#define P2MP 0
@@ -555,14 +547,14 @@ socket_defined (const socket_descriptor_t sd)
/*
* Enable external private key
*/
-#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_SSL)
+#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_CRYPTO)
#define MANAGMENT_EXTERNAL_KEY
#endif
-/* Enable PolarSSL RNG prediction resistance support */
-#ifdef ENABLE_CRYPTO_POLARSSL
+/* Enable mbed TLS RNG prediction resistance support */
+#ifdef ENABLE_CRYPTO_MBEDTLS
#define ENABLE_PREDICTION_RESISTANCE
-#endif /* ENABLE_CRYPTO_POLARSSL */
+#endif /* ENABLE_CRYPTO_MBEDTLS */
/*
* MANAGEMENT_IN_EXTRA allows the management interface to
@@ -588,18 +580,13 @@ socket_defined (const socket_descriptor_t sd)
/*
* Do we support Unix domain sockets?
*/
-#if defined(PF_UNIX) && !defined(WIN32)
+#if defined(PF_UNIX) && !defined(_WIN32)
#define UNIX_SOCK_SUPPORT 1
#else
#define UNIX_SOCK_SUPPORT 0
#endif
/*
- * Compile the struct buffer_list code
- */
-#define ENABLE_BUFFER_LIST
-
-/*
* Should we include OCC (options consistency check) code?
*/
#ifndef ENABLE_SMALL
@@ -609,7 +596,7 @@ socket_defined (const socket_descriptor_t sd)
/*
* Should we include NTLM proxy functionality
*/
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_HTTP_PROXY)
+#if defined(ENABLE_CRYPTO)
#define NTLM 1
#else
#define NTLM 0
@@ -618,34 +605,20 @@ socket_defined (const socket_descriptor_t sd)
/*
* Should we include proxy digest auth functionality
*/
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_HTTP_PROXY)
+#if defined(ENABLE_CRYPTO)
#define PROXY_DIGEST_AUTH 1
#else
#define PROXY_DIGEST_AUTH 0
#endif
/*
- * Should we include code common to all proxy methods?
- */
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS)
-#define GENERAL_PROXY_SUPPORT
-#endif
-
-/*
* Do we have CryptoAPI capability?
*/
-#if defined(WIN32) && defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL)
+#if defined(_WIN32) && defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL)
#define ENABLE_CRYPTOAPI
#endif
/*
- * Enable x509-track feature?
- */
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) && defined (ENABLE_CRYPTO_OPENSSL)
-#define ENABLE_X509_TRACK
-#endif
-
-/*
* Is poll available on this platform?
*/
#if defined(HAVE_POLL) && defined(HAVE_SYS_POLL_H)
@@ -670,15 +643,6 @@ socket_defined (const socket_descriptor_t sd)
#endif
/*
- * Should we include http proxy override functionality
- */
-#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_HTTP_PROXY)
-#define HTTP_PROXY_OVERRIDE 1
-#else
-#define HTTP_PROXY_OVERRIDE 0
-#endif
-
-/*
* Reduce sensitivity to system clock instability
* and backtracks.
*/
@@ -719,14 +683,17 @@ socket_defined (const socket_descriptor_t sd)
/*
* Do we support pushing peer info?
*/
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+#if defined(ENABLE_CRYPTO)
#define ENABLE_PUSH_PEER_INFO
#endif
/*
- * Do we support internal client-side NAT?
+ * Compression support
*/
-#define ENABLE_CLIENT_NAT
+#if defined(ENABLE_LZO) || defined(ENABLE_LZ4) || \
+ defined(ENABLE_COMP_STUB)
+#define USE_COMP
+#endif
/*
* Enable --memstats option
diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c
new file mode 100644
index 0000000..d40532e
--- /dev/null
+++ b/src/openvpn/tls_crypt.c
@@ -0,0 +1,254 @@
+/*
+ * 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) 2016 Fox Crypto B.V. <openvpn@fox-it.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#ifdef ENABLE_CRYPTO
+#include "crypto.h"
+#include "session_id.h"
+
+#include "tls_crypt.h"
+
+int tls_crypt_buf_overhead(void)
+{
+ return packet_id_size (true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE;
+}
+
+void
+tls_crypt_init_key (struct key_ctx_bi *key, const char *key_file,
+ const char *key_inline, bool tls_server) {
+ const int key_direction = tls_server ?
+ KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE;
+
+ struct key_type kt;
+ kt.cipher = cipher_kt_get ("AES-256-CTR");
+ kt.cipher_length = cipher_kt_key_size (kt.cipher);
+ kt.digest = md_kt_get ("SHA256");
+ kt.hmac_length = md_kt_size (kt.digest);
+
+ if (!kt.cipher)
+ {
+ msg (M_FATAL, "ERROR: --tls-crypt requires AES-256-CTR support.");
+ }
+ if (!kt.digest)
+ {
+ msg (M_FATAL, "ERROR: --tls-crypt requires HMAC-SHA-256 support.");
+ }
+
+ crypto_read_openvpn_key (&kt, key, key_file, key_inline, key_direction,
+ "Control Channel Encryption", "tls-crypt");
+}
+
+void
+tls_crypt_adjust_frame_parameters(struct frame *frame)
+{
+ frame_add_to_extra_frame (frame, tls_crypt_buf_overhead());
+
+ msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for tls-crypt by %i bytes",
+ __func__, tls_crypt_buf_overhead());
+}
+
+
+bool
+tls_crypt_wrap (const struct buffer *src, struct buffer *dst,
+ struct crypto_options *opt) {
+ const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt;
+ struct gc_arena gc;
+
+ /* IV, packet-ID and implicit IV required for this mode. */
+ ASSERT (ctx->cipher);
+ ASSERT (ctx->hmac);
+ ASSERT (packet_id_initialized(&opt->packet_id));
+ ASSERT (hmac_ctx_size(ctx->hmac) == 256/8);
+
+ gc_init (&gc);
+
+ dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP FROM: %s",
+ format_hex (BPTR (src), BLEN (src), 80, &gc));
+
+ /* Get packet ID */
+ {
+ struct packet_id_net pin;
+ packet_id_alloc_outgoing (&opt->packet_id.send, &pin, true);
+ packet_id_write (&pin, dst, true, false);
+ }
+
+ dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s",
+ format_hex (BPTR (dst), BLEN (dst), 0, &gc));
+
+ /* Buffer overflow check */
+ if (!buf_safe (dst, BLEN (src) + TLS_CRYPT_BLOCK_SIZE + TLS_CRYPT_TAG_SIZE))
+ {
+ msg (D_CRYPT_ERRORS, "TLS-CRYPT WRAP: buffer size error, "
+ "sc=%d so=%d sl=%d dc=%d do=%d dl=%d", src->capacity, src->offset,
+ src->len, dst->capacity, dst->offset, dst->len);
+ goto err;
+ }
+
+ /* Calculate auth tag and synthetic IV */
+ {
+ uint8_t *tag = NULL;
+ hmac_ctx_reset (ctx->hmac);
+ hmac_ctx_update (ctx->hmac, BPTR (dst), BLEN (dst));
+ hmac_ctx_update (ctx->hmac, BPTR (src), BLEN (src));
+
+ ASSERT (tag = buf_write_alloc (dst, TLS_CRYPT_TAG_SIZE));
+ hmac_ctx_final (ctx->hmac, tag);
+
+ dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP TAG: %s",
+ format_hex (tag, TLS_CRYPT_TAG_SIZE, 0, &gc));
+
+ /* Use the 128 most significant bits of the tag as IV */
+ ASSERT (cipher_ctx_reset (ctx->cipher, tag));
+ }
+
+ /* Encrypt src */
+ {
+ int outlen = 0;
+ ASSERT (cipher_ctx_update (ctx->cipher, BEND (dst), &outlen,
+ BPTR (src), BLEN(src)));
+ ASSERT (buf_inc_len (dst, outlen));
+ ASSERT (cipher_ctx_final (ctx->cipher, BPTR (dst), &outlen));
+ ASSERT (buf_inc_len (dst, outlen));
+ }
+
+ dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP TO: %s",
+ format_hex (BPTR (dst), BLEN (dst), 80, &gc));
+
+ gc_free (&gc);
+ return true;
+
+err:
+ crypto_clear_error();
+ dst->len = 0;
+ gc_free (&gc);
+ return false;
+}
+
+bool
+tls_crypt_unwrap (const struct buffer *src, struct buffer *dst,
+ struct crypto_options *opt)
+{
+ static const char error_prefix[] = "tls-crypt unwrap error";
+ const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt;
+ struct gc_arena gc;
+
+ gc_init (&gc);
+
+ ASSERT (opt);
+ ASSERT (src->len > 0);
+ ASSERT (ctx->cipher);
+ ASSERT (packet_id_initialized (&opt->packet_id) ||
+ (opt->flags & CO_IGNORE_PACKET_ID));
+
+ dmsg (D_PACKET_CONTENT, "TLS-CRYPT UNWRAP FROM: %s",
+ format_hex (BPTR (src), BLEN (src), 80, &gc));
+
+ if (buf_len (src) < TLS_CRYPT_OFF_CT)
+ {
+ CRYPT_ERROR ("packet too short");
+ }
+
+ /* Decrypt cipher text */
+ {
+ int outlen = 0;
+
+ /* Buffer overflow check (should never fail) */
+ if (!buf_safe (dst, BLEN (src) - TLS_CRYPT_OFF_CT + TLS_CRYPT_BLOCK_SIZE))
+ {
+ CRYPT_ERROR ("potential buffer overflow");
+ }
+
+ if (!cipher_ctx_reset (ctx->cipher, BPTR (src) + TLS_CRYPT_OFF_TAG))
+ {
+ CRYPT_ERROR ("cipher reset failed");
+ }
+ if (!cipher_ctx_update (ctx->cipher, BPTR (dst), &outlen,
+ BPTR (src) + TLS_CRYPT_OFF_CT, BLEN (src) - TLS_CRYPT_OFF_CT))
+ {
+ CRYPT_ERROR ("cipher update failed");
+ }
+ ASSERT (buf_inc_len (dst, outlen));
+ if (!cipher_ctx_final (ctx->cipher, BPTR(dst), &outlen))
+ {
+ CRYPT_ERROR ("cipher final failed");
+ }
+ ASSERT (buf_inc_len (dst, outlen));
+ }
+
+ /* Check authentication */
+ {
+ const uint8_t *tag = BPTR (src) + TLS_CRYPT_OFF_TAG;
+ uint8_t tag_check[TLS_CRYPT_TAG_SIZE] = { 0 };
+
+ dmsg (D_PACKET_CONTENT, "TLS-CRYPT UNWRAP AD: %s",
+ format_hex (BPTR (src), TLS_CRYPT_OFF_TAG, 0, &gc));
+ dmsg (D_PACKET_CONTENT, "TLS-CRYPT UNWRAP TO: %s",
+ format_hex (BPTR (dst), BLEN (dst), 80, &gc));
+
+ hmac_ctx_reset (ctx->hmac);
+ hmac_ctx_update (ctx->hmac, BPTR (src), TLS_CRYPT_OFF_TAG);
+ hmac_ctx_update (ctx->hmac, BPTR (dst), BLEN (dst));
+ hmac_ctx_final (ctx->hmac, tag_check);
+
+ if (memcmp_constant_time (tag, tag_check, sizeof(tag_check)))
+ {
+ dmsg (D_CRYPTO_DEBUG, "tag : %s",
+ format_hex (tag, sizeof(tag_check), 0, &gc));
+ dmsg (D_CRYPTO_DEBUG, "tag_check: %s",
+ format_hex (tag_check, sizeof(tag_check), 0, &gc));
+ CRYPT_ERROR ("packet authentication failed");
+ }
+ }
+
+ /* Check replay */
+ if (!(opt->flags & CO_IGNORE_PACKET_ID))
+ {
+ struct packet_id_net pin;
+ struct buffer tmp = *src;
+ ASSERT (buf_advance (&tmp, TLS_CRYPT_OFF_PID));
+ ASSERT (packet_id_read (&pin, &tmp, true));
+ if (!crypto_check_replay (opt, &pin, error_prefix, &gc))
+ {
+ CRYPT_ERROR ("packet replay");
+ }
+ }
+
+ gc_free (&gc);
+ return true;
+
+ error_exit:
+ crypto_clear_error();
+ dst->len = 0;
+ gc_free (&gc);
+ return false;
+}
+
+#endif /* EMABLE_CRYPTO */
diff --git a/src/openvpn/tls_crypt.h b/src/openvpn/tls_crypt.h
new file mode 100644
index 0000000..d1962c9
--- /dev/null
+++ b/src/openvpn/tls_crypt.h
@@ -0,0 +1,144 @@
+/*
+ * 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) 2016 Fox Crypto B.V. <openvpn@fox-it.com>
+ *
+ * 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
+ */
+
+/**
+ * @defgroup tls_crypt Control channel encryption (--tls-crypt)
+ * @ingroup control_tls
+ * @{
+ *
+ * @par
+ * Control channel encryption uses a pre-shared static key (like the --tls-auth
+ * key) to encrypt control channel packets.
+ *
+ * @par
+ * Encrypting control channel packets has three main advantages:
+ * - It provides more privacy by hiding the certificate used for the TLS
+ * connection.
+ * - It is harder to identify OpenVPN traffic as such.
+ * - It provides "poor-man's" post-quantum security, against attackers who
+ * will never know the pre-shared key (i.e. no forward secrecy).
+ *
+ * @par Specification
+ * Control channel encryption is based on the SIV construction [0], to achieve
+ * nonce misuse-resistant authenticated encryption:
+ *
+ * @par
+ * \code{.unparsed}
+ * msg = control channel plaintext
+ * header = opcode (1 byte) || session_id (8 bytes) || packet_id (8 bytes)
+ * Ka = authentication key (256 bits)
+ * Ke = encryption key (256 bits)
+ * (Ka and Ke are pre-shared keys, like with --tls-auth)
+ *
+ * auth_tag = HMAC-SHA256(Ka, header || msg)
+ * IV = 128 most-significant bits of auth_tag
+ * ciph = AES256-CTR(Ke, IV, msg)
+ *
+ * output = Header || Tag || Ciph
+ * \endcode
+ *
+ * @par
+ * This boils down to the following on-the-wire packet format:
+ *
+ * @par
+ * \code{.unparsed}
+ * - opcode - || - session_id - || - packet_id - || auth_tag || * payload *
+ * \endcode
+ *
+ * @par
+ * Where
+ * <tt>- XXX -</tt> means authenticated, and
+ * <tt>* XXX *</tt> means authenticated and encrypted.
+ */
+
+#ifndef TLSCRYPT_H
+#define TLSCRYPT_H
+
+#include "buffer.h"
+#include "crypto.h"
+#include "session_id.h"
+
+#define TLS_CRYPT_TAG_SIZE (256/8)
+#define TLS_CRYPT_PID_SIZE (sizeof (packet_id_type) + sizeof (net_time_t))
+#define TLS_CRYPT_BLOCK_SIZE (128/8)
+
+#define TLS_CRYPT_OFF_PID (1 + SID_SIZE)
+#define TLS_CRYPT_OFF_TAG (TLS_CRYPT_OFF_PID + TLS_CRYPT_PID_SIZE)
+#define TLS_CRYPT_OFF_CT (TLS_CRYPT_OFF_TAG + TLS_CRYPT_TAG_SIZE)
+
+/**
+ * Initialize a key_ctx_bi structure for use with --tls-crypt.
+ *
+ * @param key The key context to initialize
+ * @param key_file The file to read the key from (or the inline tag to
+ * indicate and inline key).
+ * @param key_inline Array containing (zero-terminated) inline key, or NULL
+ * if not used.
+ * @param tls_server Must be set to true is this is a TLS server instance.
+ */
+void tls_crypt_init_key (struct key_ctx_bi *key, const char *key_file,
+ const char *key_inline, bool tls_server);
+
+/**
+ * Returns the maximum overhead (in bytes) added to the destination buffer by
+ * tls_crypt_wrap().
+ */
+int tls_crypt_buf_overhead(void);
+
+/**
+ * Adjust frame parameters for --tls-crypt overhead.
+ */
+void tls_crypt_adjust_frame_parameters(struct frame *frame);
+
+/**
+ * Wrap a control channel packet (both authenticates and encrypts the data).
+ *
+ * @param src Data to authenticate and encrypt.
+ * @param dst Any data present in this buffer is first authenticated, then
+ * the wrapped packet id and data from the src buffer are appended.
+ * Must have at least tls_crypt_buf_overhead()+BLEN(src) headroom.
+ * @param opt The crypto state for this --tls-crypt instance.
+ *
+ * @returns true iff wrapping succeeded.
+ */
+bool tls_crypt_wrap (const struct buffer *src, struct buffer *dst,
+ struct crypto_options *opt);
+
+/**
+ * Unwrap a control channel packet (decrypts, authenticates and performs
+ * replay checks).
+ *
+ * @param src Data to decrypt and authenticate.
+ * @param dst Returns the decrypted data, if unwrapping was successful.
+ * @param opt The crypto state for this --tls-crypt instance.
+ *
+ * @returns true iff unwrapping succeeded (data authenticated correctly and was
+ * no replay).
+ */
+bool tls_crypt_unwrap (const struct buffer *src, struct buffer *dst,
+ struct crypto_options *opt);
+
+/** @} */
+
+#endif /* TLSCRYPT_H */
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index b70410d..77ae72f 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -49,7 +49,13 @@
#include "memdbg.h"
-#ifdef WIN32
+#ifdef _WIN32
+#include "openvpn-msg.h"
+#endif
+
+#include <string.h>
+
+#ifdef _WIN32
/* #define SIMULATE_DHCP_FAILED */ /* simulate bad DHCP negotiation */
@@ -62,12 +68,70 @@ static void netsh_ifconfig (const struct tuntap_options *to,
const in_addr_t ip,
const in_addr_t netmask,
const unsigned int flags);
-static void netsh_command (const struct argv *a, int n);
+static void netsh_command (const struct argv *a, int n, int msglevel);
static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc);
static DWORD get_adapter_index_flexible (const char *name);
+static bool
+do_address_service (const bool add, const short family, const struct tuntap *tt)
+{
+ DWORD len;
+ bool ret = false;
+ ack_message_t ack;
+ struct gc_arena gc = gc_new ();
+ HANDLE pipe = tt->options.msg_channel;
+
+ address_message_t addr = {
+ .header = {
+ (add ? msg_add_address : msg_del_address),
+ sizeof (address_message_t),
+ 0 },
+ .family = family,
+ .iface = { .index = tt->adapter_index, .name = "" }
+ };
+
+ if (addr.iface.index == TUN_ADAPTER_INDEX_INVALID)
+ {
+ strncpy (addr.iface.name, tt->actual_name, sizeof (addr.iface.name));
+ addr.iface.name[sizeof (addr.iface.name) - 1] = '\0';
+ }
+
+ if (addr.family == AF_INET)
+ {
+ addr.address.ipv4.s_addr = tt->local;
+ addr.prefix_len = 32;
+ }
+ else
+ {
+ addr.address.ipv6 = tt->local_ipv6;
+ addr.prefix_len = tt->netbits_ipv6;
+ }
+
+ if (!WriteFile (pipe, &addr, sizeof (addr), &len, NULL) ||
+ !ReadFile (pipe, &ack, sizeof (ack), &len, NULL))
+ {
+ msg (M_WARN, "TUN: could not talk to service: %s [%lu]",
+ strerror_win32 (GetLastError (), &gc), GetLastError ());
+ goto out;
+ }
+
+ if (ack.error_number != NO_ERROR)
+ {
+ msg (M_WARN, "TUN: %s address failed using service: %s [status=%u if_index=%lu]",
+ (add ? "adding" : "deleting"), strerror_win32 (ack.error_number, &gc),
+ ack.error_number, addr.iface.index);
+ goto out;
+ }
+
+ ret = true;
+
+out:
+ gc_free (&gc);
+ return ret;
+}
+
#endif
#ifdef TARGET_SOLARIS
@@ -134,7 +198,7 @@ guess_tuntap_dev (const char *dev,
const char *dev_node,
struct gc_arena *gc)
{
-#ifdef WIN32
+#ifdef _WIN32
const int dt = dev_type_enum (dev, dev_type);
if (dt == DEV_TYPE_TUN || dt == DEV_TYPE_TAP)
{
@@ -357,7 +421,7 @@ tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc)
{
buf_printf (&out, "T%s",
(tt->rwflags_debug & EVENT_READ) ? "R" : "r");
-#ifdef WIN32
+#ifdef _WIN32
buf_printf (&out, "%s",
overlapped_io_state_ascii (&tt->reads));
#endif
@@ -366,7 +430,7 @@ tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc)
{
buf_printf (&out, "T%s",
(tt->rwflags_debug & EVENT_WRITE) ? "W" : "w");
-#ifdef WIN32
+#ifdef _WIN32
buf_printf (&out, "%s",
overlapped_io_state_ascii (&tt->writes));
#endif
@@ -455,8 +519,8 @@ init_tun (const char *dev, /* --dev option */
const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 IPv6 */
int ifconfig_ipv6_netbits_parm,
const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 IPv6 */
- in_addr_t local_public,
- in_addr_t remote_public,
+ struct addrinfo *local_public,
+ struct addrinfo *remote_public,
const bool strict_warn,
struct env_set *es)
{
@@ -507,6 +571,7 @@ init_tun (const char *dev, /* --dev option */
*/
if (strict_warn)
{
+ struct addrinfo *curele;
ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology);
/*
@@ -514,17 +579,23 @@ init_tun (const char *dev, /* --dev option */
* make sure they do not clash with our virtual subnet.
*/
- check_addr_clash ("local",
+ for(curele=local_public;curele;curele=curele->ai_next) {
+ if(curele->ai_family == AF_INET)
+ check_addr_clash ("local",
tt->type,
- local_public,
+ ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr,
tt->local,
tt->remote_netmask);
+ }
- check_addr_clash ("remote",
- tt->type,
- remote_public,
- tt->local,
- tt->remote_netmask);
+ for (curele=remote_public;curele;curele=curele->ai_next) {
+ if (curele->ai_family == AF_INET)
+ check_addr_clash ("remote",
+ tt->type,
+ ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr,
+ tt->local,
+ tt->remote_netmask);
+ }
if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET))
check_subnet_conflict (tt->local, tt->remote_netmask, "TUN/TAP adapter");
@@ -540,6 +611,21 @@ init_tun (const char *dev, /* --dev option */
tt->broadcast = generate_ifconfig_broadcast_addr (tt->local, tt->remote_netmask);
}
+#ifdef _WIN32
+ /*
+ * Make sure that both ifconfig addresses are part of the
+ * same .252 subnet.
+ */
+ if (tun)
+ {
+ verify_255_255_255_252 (tt->local, tt->remote_netmask);
+ tt->adapter_netmask = ~3;
+ }
+ else
+ {
+ tt->adapter_netmask = tt->remote_netmask;
+ }
+#endif
tt->did_ifconfig_setup = true;
}
@@ -579,7 +665,7 @@ init_tun_post (struct tuntap *tt,
const struct tuntap_options *options)
{
tt->options = *options;
-#ifdef WIN32
+#ifdef _WIN32
overlapped_io_init (&tt->reads, frame, FALSE, true);
overlapped_io_init (&tt->writes, frame, TRUE, true);
tt->rw_handle.read = tt->reads.overlapped.hEvent;
@@ -588,7 +674,7 @@ init_tun_post (struct tuntap *tt,
#endif
}
-#if defined(WIN32) || \
+#if defined(_WIN32) || \
defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD)
/* some of the platforms will auto-add a "network route" pointing
@@ -601,12 +687,12 @@ void add_route_connected_v6_net(struct tuntap * tt,
{
struct route_ipv6 r6;
- r6.defined = true;
+ CLEAR(r6);
r6.network = tt->local_ipv6;
r6.netbits = tt->netbits_ipv6;
r6.gateway = tt->local_ipv6;
r6.metric = 0; /* connected route */
- r6.metric_defined = true;
+ r6.flags = RT_DEFINED | RT_METRIC_DEFINED;
add_route_ipv6 (&r6, tt, 0, es);
}
@@ -615,17 +701,18 @@ void delete_route_connected_v6_net(struct tuntap * tt,
{
struct route_ipv6 r6;
- r6.defined = true;
+ CLEAR(r6);
r6.network = tt->local_ipv6;
r6.netbits = tt->netbits_ipv6;
r6.gateway = tt->local_ipv6;
r6.metric = 0; /* connected route */
- r6.metric_defined = true;
+ r6.flags = RT_DEFINED | RT_ADDED | RT_METRIC_DEFINED;
delete_route_ipv6 (&r6, tt, 0, es);
}
#endif
-#if defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)
+#if defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)||\
+ defined(TARGET_OPENBSD)
/* we can't use true subnet mode on tun on all platforms, as that
* conflicts with IPv6 (wants to use ND then, which we don't do),
* but the OSes want "a remote address that is different from ours"
@@ -635,8 +722,8 @@ void delete_route_connected_v6_net(struct tuntap * tt,
* is still point to point and no layer 2 resolution is done...
*/
-const char *
-create_arbitrary_remote( struct tuntap *tt, struct gc_arena * gc )
+in_addr_t
+create_arbitrary_remote( struct tuntap *tt )
{
in_addr_t remote;
@@ -644,7 +731,7 @@ create_arbitrary_remote( struct tuntap *tt, struct gc_arena * gc )
if ( remote == tt->local ) remote ++;
- return print_in_addr_t (remote, 0, gc);
+ return remote;
}
#endif
@@ -664,14 +751,11 @@ do_ifconfig (struct tuntap *tt,
const char *ifconfig_remote_netmask = NULL;
const char *ifconfig_broadcast = NULL;
const char *ifconfig_ipv6_local = NULL;
- const char *ifconfig_ipv6_remote = NULL;
bool do_ipv6 = false;
- struct argv argv;
-
- argv_init (&argv);
+ struct argv argv = argv_new ();
- msg( M_INFO, "do_ifconfig, tt->ipv6=%d, tt->did_ifconfig_ipv6_setup=%d",
- tt->ipv6, tt->did_ifconfig_ipv6_setup );
+ msg( M_DEBUG, "do_ifconfig, tt->did_ifconfig_ipv6_setup=%d",
+ tt->did_ifconfig_ipv6_setup );
/*
* We only handle TUN/TAP devices here, not --dev null devices.
@@ -684,10 +768,9 @@ do_ifconfig (struct tuntap *tt,
ifconfig_local = print_in_addr_t (tt->local, 0, &gc);
ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc);
- if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
+ if (tt->did_ifconfig_ipv6_setup )
{
ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
- ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc);
do_ipv6 = true;
}
@@ -703,8 +786,10 @@ do_ifconfig (struct tuntap *tt,
management_set_state (management,
OPENVPN_STATE_ASSIGN_IP,
NULL,
- tt->local,
- 0);
+ &tt->local,
+ &tt->local_ipv6,
+ NULL,
+ NULL);
}
#endif
@@ -743,7 +828,7 @@ do_ifconfig (struct tuntap *tt,
iproute_path,
actual,
ifconfig_local,
- count_netmask_bits(ifconfig_remote_netmask),
+ netmask_to_netbits2(tt->remote_netmask),
ifconfig_broadcast
);
argv_msg (M_INFO, &argv);
@@ -799,8 +884,35 @@ do_ifconfig (struct tuntap *tt,
tt->did_ifconfig = true;
#endif /*ENABLE_IPROUTE*/
-#elif defined(TARGET_SOLARIS)
+#elif defined(TARGET_ANDROID)
+
+ if (do_ipv6) {
+ struct buffer out6 = alloc_buf_gc (64, &gc);
+ buf_printf (&out6, "%s/%d", ifconfig_ipv6_local,tt->netbits_ipv6);
+ management_android_control(management, "IFCONFIG6",buf_bptr(&out6));
+ }
+
+ struct buffer out = alloc_buf_gc (64, &gc);
+
+ char* top;
+ switch(tt->topology) {
+ case TOP_NET30:
+ top="net30";
+ break;
+ case TOP_P2P:
+ top="p2p";
+ break;
+ case TOP_SUBNET:
+ top="subnet";
+ break;
+ default:
+ top="undef";
+ }
+
+ buf_printf (&out, "%s %s %d %s", ifconfig_local, ifconfig_remote_netmask, tun_mtu, top);
+ management_android_control (management, "IFCONFIG", buf_bptr(&out));
+#elif defined(TARGET_SOLARIS)
/* Solaris 2.6 (and 7?) cannot set all parameters in one go...
* example:
* ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 up
@@ -862,6 +974,9 @@ do_ifconfig (struct tuntap *tt,
if ( tt->type == DEV_TYPE_TUN )
{
+ const char *ifconfig_ipv6_remote =
+ print_in6_addr (tt->remote_ipv6, 0, &gc);
+
argv_printf (&argv,
"%s %s inet6 plumb %s/%d %s up",
IFCONFIG_PATH,
@@ -916,6 +1031,8 @@ do_ifconfig (struct tuntap *tt,
#elif defined(TARGET_OPENBSD)
+ in_addr_t remote_end; /* for "virtual" subnet topology */
+
/*
* On OpenBSD, tun interfaces are persistent if created with
* "ifconfig tunX create", and auto-destroyed if created by
@@ -935,12 +1052,13 @@ do_ifconfig (struct tuntap *tt,
else
if ( tt->topology == TOP_SUBNET )
{
+ remote_end = create_arbitrary_remote( tt );
argv_printf (&argv,
"%s %s %s %s mtu %d netmask %s up -link0",
IFCONFIG_PATH,
actual,
ifconfig_local,
- ifconfig_local,
+ print_in_addr_t (remote_end, 0, &gc),
tun_mtu,
ifconfig_remote_netmask
);
@@ -957,6 +1075,19 @@ do_ifconfig (struct tuntap *tt,
);
argv_msg (M_INFO, &argv);
openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed");
+
+ /* Add a network route for the local tun interface */
+ if (!tun && tt->topology == TOP_SUBNET)
+ {
+ struct route_ipv4 r;
+ CLEAR (r);
+ r.flags = RT_DEFINED;
+ r.network = tt->local & tt->remote_netmask;
+ r.netmask = tt->remote_netmask;
+ r.gateway = remote_end;
+ add_route (&r, tt, 0, NULL, es);
+ }
+
if ( do_ipv6 )
{
argv_printf (&argv,
@@ -976,13 +1107,6 @@ do_ifconfig (struct tuntap *tt,
#elif defined(TARGET_NETBSD)
-/* whether or not NetBSD can do IPv6 can be seen by the availability of
- * the TUNSIFHEAD ioctl() - see next TARGET_NETBSD block for more details
- */
-#ifdef TUNSIFHEAD
-# define NETBSD_MULTI_AF
-#endif
-
if (tun)
argv_printf (&argv,
"%s %s %s %s mtu %d netmask 255.255.255.255 up",
@@ -1025,7 +1149,6 @@ do_ifconfig (struct tuntap *tt,
if ( do_ipv6 )
{
-#ifdef NETBSD_MULTI_AF
argv_printf (&argv,
"%s %s inet6 %s/%d",
IFCONFIG_PATH,
@@ -1038,10 +1161,6 @@ do_ifconfig (struct tuntap *tt,
/* and, hooray, we explicitely need to add a route... */
add_route_connected_v6_net(tt, es);
-#else
- msg( M_INFO, "no IPv6 support for tun interfaces on NetBSD before 4.0 (if your system is newer, recompile openvpn)" );
- tt->ipv6 = false;
-#endif
}
tt->did_ifconfig = true;
@@ -1126,6 +1245,8 @@ do_ifconfig (struct tuntap *tt,
#elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)
+ in_addr_t remote_end; /* for "virtual" subnet topology */
+
/* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
if (tun)
argv_printf (&argv,
@@ -1138,12 +1259,13 @@ do_ifconfig (struct tuntap *tt,
);
else if ( tt->topology == TOP_SUBNET )
{
+ remote_end = create_arbitrary_remote( tt );
argv_printf (&argv,
"%s %s %s %s mtu %d netmask %s up",
IFCONFIG_PATH,
actual,
ifconfig_local,
- create_arbitrary_remote( tt, &gc ),
+ print_in_addr_t (remote_end, 0, &gc),
tun_mtu,
ifconfig_remote_netmask
);
@@ -1170,7 +1292,7 @@ do_ifconfig (struct tuntap *tt,
r.flags = RT_DEFINED;
r.network = tt->local & tt->remote_netmask;
r.netmask = tt->remote_netmask;
- r.gateway = tt->local;
+ r.gateway = remote_end;
add_route (&r, tt, 0, NULL, es);
}
@@ -1187,21 +1309,46 @@ do_ifconfig (struct tuntap *tt,
openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed");
}
-#elif defined (WIN32)
+#elif defined(TARGET_AIX)
{
- /*
- * Make sure that both ifconfig addresses are part of the
- * same .252 subnet.
- */
+ /* AIX ifconfig will complain if it can't find ODM path in env */
+ struct env_set *aix_es = env_set_create (NULL);
+ env_set_add( aix_es, "ODMDIR=/etc/objrepos" );
+
if (tun)
+ msg(M_FATAL, "no tun support on AIX (canthappen)");
+
+ /* example: ifconfig tap0 172.30.1.1 netmask 255.255.254.0 up */
+ argv_printf (&argv,
+ "%s %s %s netmask %s mtu %d up",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_local,
+ ifconfig_remote_netmask,
+ tun_mtu
+ );
+
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, aix_es, S_FATAL, "AIX ifconfig failed");
+ tt->did_ifconfig = true;
+
+ if ( do_ipv6 )
{
- verify_255_255_255_252 (tt->local, tt->remote_netmask);
- tt->adapter_netmask = ~3;
- }
- else
- {
- tt->adapter_netmask = tt->remote_netmask;
+ argv_printf (&argv,
+ "%s %s inet6 %s/%d",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_ipv6_local,
+ tt->netbits_ipv6
+ );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, aix_es, S_FATAL, "AIX ifconfig inet6 failed");
}
+ env_set_destroy (aix_es);
+ }
+#elif defined (_WIN32)
+ {
+ ASSERT (actual != NULL);
switch (tt->options.ip_win32_type)
{
@@ -1212,9 +1359,6 @@ do_ifconfig (struct tuntap *tt,
print_in_addr_t (tt->adapter_netmask, 0, &gc));
break;
case IPW32_SET_NETSH:
- if (!strcmp (actual, "NULL"))
- msg (M_FATAL, "Error: When using --ip-win32 netsh, if you have more than one TAP-Windows adapter, you must also specify --dev-node");
-
netsh_ifconfig (&tt->options,
actual,
tt->local,
@@ -1226,39 +1370,28 @@ do_ifconfig (struct tuntap *tt,
tt->did_ifconfig = true;
}
- /* IPv6 always uses "netsh" interface */
if ( do_ipv6 )
{
- char * saved_actual;
- char iface[64];
- DWORD idx;
-
- if (!strcmp (actual, "NULL"))
- msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than one TAP-Windows adapter, you must also specify --dev-node");
-
- idx = get_adapter_index_flexible(actual);
- openvpn_snprintf(iface, sizeof(iface), "interface=%lu", idx);
-
- /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */
- argv_printf (&argv,
- "%s%sc interface ipv6 set address %s %s store=active",
- get_win_sys_path(),
- NETSH_PATH_SUFFIX,
- win32_version_info() == WIN_XP ? actual : iface,
- ifconfig_ipv6_local);
- netsh_command (&argv, 4);
+ if (tt->options.msg_channel)
+ {
+ do_address_service (true, AF_INET6, tt);
+ }
+ else
+ {
+ /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */
+ char iface[64];
+ openvpn_snprintf(iface, sizeof(iface), "interface=%lu", tt->adapter_index );
+ argv_printf (&argv,
+ "%s%sc interface ipv6 set address %s %s store=active",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ iface,
+ ifconfig_ipv6_local );
+ netsh_command (&argv, 4, M_FATAL);
+ }
/* explicit route needed */
- /* on windows, OpenVPN does ifconfig first, open_tun later, so
- * tt->actual_name might not yet be initialized, but routing code
- * needs to know interface name - point to "actual", restore later
- */
- saved_actual = tt->actual_name;
- tt->actual_name = (char*) actual;
- /* we use adapter_index in add_route_ipv6 */
- tt->adapter_index = idx;
add_route_connected_v6_net(tt, es);
- tt->actual_name = saved_actual;
}
#else
msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script.");
@@ -1272,7 +1405,7 @@ static void
clear_tuntap (struct tuntap *tuntap)
{
CLEAR (*tuntap);
-#ifdef WIN32
+#ifdef _WIN32
tuntap->hand = NULL;
#else
tuntap->fd = -1;
@@ -1280,7 +1413,6 @@ clear_tuntap (struct tuntap *tuntap)
#ifdef TARGET_SOLARIS
tuntap->ip_fd = -1;
#endif
- tuntap->ipv6 = false;
}
static void
@@ -1333,7 +1465,7 @@ write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
iph = (struct ip *) buf;
- if (tt->ipv6 && iph->ip_v == 6)
+ if (iph->ip_v == 6)
type = htonl (AF_INET6);
else
type = htonl (AF_INET);
@@ -1370,20 +1502,15 @@ read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
#endif
-#ifndef WIN32
+#if !(defined(_WIN32) || defined(TARGET_LINUX))
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
- bool ipv6_explicitly_supported, bool dynamic,
- struct tuntap *tt)
+ bool dynamic, struct tuntap *tt)
{
char tunname[256];
char dynamic_name[256];
bool dynamic_opened = false;
-
- if ( tt->ipv6 && ! ipv6_explicitly_supported )
- msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
-
if (tt->type == DEV_TYPE_NULL)
{
open_null (tt);
@@ -1477,7 +1604,9 @@ open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
tt->actual_name = string_alloc (dynamic_opened ? dynamic_name : dev, NULL);
}
}
+#endif /* !_WIN32 && !TARGET_LINUX */
+#if !defined(_WIN32)
static void
close_tun_generic (struct tuntap *tt)
{
@@ -1487,12 +1616,83 @@ close_tun_generic (struct tuntap *tt)
free (tt->actual_name);
clear_tuntap (tt);
}
+#endif /* !_WIN32 */
-#endif
+#if defined (TARGET_ANDROID)
+void
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+#define ANDROID_TUNNAME "vpnservice-tun"
+ int i;
+ struct user_pass up;
+ struct gc_arena gc = gc_new ();
+ bool opentun;
-#if defined(TARGET_LINUX)
+ int oldtunfd = tt->fd;
+
+ for (i = 0; i < tt->options.dns_len; ++i) {
+ management_android_control (management, "DNSSERVER",
+ print_in_addr_t(tt->options.dns[i], 0, &gc));
+ }
-#ifdef HAVE_LINUX_IF_TUN_H /* New driver support */
+ if(tt->options.domain)
+ management_android_control (management, "DNSDOMAIN", tt->options.domain);
+
+ int android_method = managment_android_persisttun_action (management);
+
+ /* Android 4.4 workaround */
+ if (oldtunfd >=0 && android_method == ANDROID_OPEN_AFTER_CLOSE)
+ {
+ close(oldtunfd);
+ openvpn_sleep(2);
+ }
+
+ if (oldtunfd >=0 && android_method == ANDROID_KEEP_OLD_TUN) {
+ /* keep the old fd */
+ opentun = true;
+ } else {
+ opentun = management_android_control (management, "OPENTUN", dev);
+ /* Pick up the fd from management interface after calling the
+ * OPENTUN command */
+ tt->fd = management->connection.lastfdreceived;
+ management->connection.lastfdreceived=-1;
+ }
+
+ if (oldtunfd>=0 && android_method == ANDROID_OPEN_BEFORE_CLOSE)
+ close(oldtunfd);
+
+ /* Set the actual name to a dummy name */
+ tt->actual_name = string_alloc (ANDROID_TUNNAME, NULL);
+
+ if ((tt->fd < 0) || !opentun)
+ msg (M_ERR, "ERROR: Cannot open TUN");
+
+ gc_free (&gc);
+}
+
+void
+close_tun (struct tuntap *tt)
+{
+ if (tt)
+ {
+ close_tun_generic (tt);
+ free (tt);
+ }
+}
+
+int
+write_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+ return read (tt->fd, buf, len);
+}
+
+#elif defined(TARGET_LINUX)
#ifndef HAVE_LINUX_SOCKIOS_H
#error header file linux/sockios.h required
@@ -1533,8 +1733,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
* Process --tun-ipv6
*/
CLEAR (ifr);
- if (!tt->ipv6)
- ifr.ifr_flags = IFF_NO_PI;
+ ifr.ifr_flags = IFF_NO_PI;
#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)
ifr.ifr_flags |= IFF_ONE_QUEUE;
@@ -1615,32 +1814,10 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
ASSERT (0);
}
-#endif
-
-#else
-
-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, false, true, tt);
-}
-
-#endif /* HAVE_LINUX_IF_TUN_H */
+#endif /* !PENDANTIC */
#ifdef ENABLE_FEATURE_TUN_PERSIST
-/*
- * This can be removed in future
- * when all systems will use newer
- * linux-headers
- */
-#ifndef TUNSETOWNER
-#define TUNSETOWNER _IOW('T', 204, int)
-#endif
-#ifndef TUNSETGROUP
-#define TUNSETGROUP _IOW('T', 206, int)
-#endif
-
void
tuncfg (const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options)
{
@@ -1686,9 +1863,8 @@ close_tun (struct tuntap *tt)
{
if (tt->type != DEV_TYPE_NULL && tt->did_ifconfig)
{
- struct argv argv;
+ struct argv argv = argv_new ();
struct gc_arena gc = gc_new ();
- argv_init (&argv);
#ifdef ENABLE_IPROUTE
if (is_tun_p2p (tt))
@@ -1708,7 +1884,7 @@ close_tun (struct tuntap *tt)
iproute_path,
tt->actual_name,
print_in_addr_t (tt->local, 0, &gc),
- count_netmask_bits(print_in_addr_t (tt->remote_netmask, 0, &gc))
+ netmask_to_netbits2(tt->remote_netmask)
);
}
#else
@@ -1722,7 +1898,7 @@ close_tun (struct tuntap *tt)
argv_msg (M_INFO, &argv);
openvpn_execve_check (&argv, NULL, 0, "Linux ip addr del failed");
- if (tt->ipv6 && tt->did_ifconfig_ipv6_setup)
+ if (tt->did_ifconfig_ipv6_setup)
{
const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
@@ -1759,53 +1935,13 @@ close_tun (struct tuntap *tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- if (tt->ipv6)
- {
- struct tun_pi pi;
- struct iphdr *iph;
- struct iovec vect[2];
- int ret;
-
- iph = (struct iphdr *)buf;
-
- pi.flags = 0;
-
- if(iph->version == 6)
- pi.proto = htons(OPENVPN_ETH_P_IPV6);
- else
- pi.proto = htons(OPENVPN_ETH_P_IPV4);
-
- vect[0].iov_len = sizeof(pi);
- vect[0].iov_base = &pi;
- vect[1].iov_len = len;
- vect[1].iov_base = buf;
-
- ret = writev(tt->fd, vect, 2);
- return(ret - sizeof(pi));
- }
- else
- return write (tt->fd, buf, len);
+ return write (tt->fd, buf, len);
}
int
read_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- if (tt->ipv6)
- {
- struct iovec vect[2];
- struct tun_pi pi;
- int ret;
-
- vect[0].iov_len = sizeof(pi);
- vect[0].iov_base = &pi;
- vect[1].iov_len = len;
- vect[1].iov_base = buf;
-
- ret = readv(tt->fd, vect, 2);
- return(ret - sizeof(pi));
- }
- else
- return read (tt->fd, buf, len);
+ return read (tt->fd, buf, len);
}
#elif defined(TARGET_SOLARIS)
@@ -2009,10 +2145,9 @@ solaris_close_tun (struct tuntap *tt)
if (tt)
{
/* IPv6 interfaces need to be 'manually' de-configured */
- if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
+ if ( tt->did_ifconfig_ipv6_setup )
{
- struct argv argv;
- argv_init (&argv);
+ struct argv argv = argv_new ();
argv_printf( &argv, "%s %s inet6 unplumb",
IFCONFIG_PATH, tt->actual_name );
argv_msg (M_INFO, &argv);
@@ -2075,8 +2210,7 @@ static void
solaris_error_close (struct tuntap *tt, const struct env_set *es,
const char *actual, bool unplumb_inet6 )
{
- struct argv argv;
- argv_init (&argv);
+ struct argv argv = argv_new ();
if (unplumb_inet6)
{
@@ -2123,7 +2257,7 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
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);
+ open_tun_generic (dev, dev_type, dev_node, true, tt);
/* Enable multicast on the interface */
if (tt->fd >= 0)
@@ -2168,12 +2302,11 @@ close_tun (struct tuntap* tt)
else if (tt)
{
struct gc_arena gc = gc_new ();
- struct argv argv;
+ struct argv argv = argv_new ();
/* setup command, close tun dev (clears tt->actual_name!), run command
*/
- argv_init (&argv);
argv_printf (&argv, "%s %s destroy",
IFCONFIG_PATH, tt->actual_name);
@@ -2217,11 +2350,7 @@ read_tun (struct tuntap *tt, uint8_t *buf, int len)
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
-#ifdef NETBSD_MULTI_AF
- open_tun_generic (dev, dev_type, dev_node, true, true, tt);
-#else
- open_tun_generic (dev, dev_type, dev_node, false, true, tt);
-#endif
+ open_tun_generic (dev, dev_type, dev_node, true, tt);
if (tt->fd >= 0)
{
@@ -2230,7 +2359,6 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
i = 0;
ioctl (tt->fd, TUNSLMODE, &i); /* link layer mode off */
-#ifdef NETBSD_MULTI_AF
if ( tt->type == DEV_TYPE_TUN )
{
i = 1;
@@ -2239,7 +2367,6 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
}
}
-#endif
}
}
@@ -2260,12 +2387,11 @@ close_tun (struct tuntap *tt)
else if (tt)
{
struct gc_arena gc = gc_new ();
- struct argv argv;
+ struct argv argv = argv_new ();
/* setup command, close tun dev (clears tt->actual_name!), run command
*/
- argv_init (&argv);
argv_printf (&argv, "%s %s destroy",
IFCONFIG_PATH, tt->actual_name);
@@ -2278,8 +2404,6 @@ close_tun (struct tuntap *tt)
}
}
-#ifdef NETBSD_MULTI_AF
-
static inline int
netbsd_modify_read_write_return (int len)
{
@@ -2300,7 +2424,7 @@ write_tun (struct tuntap* tt, uint8_t *buf, int len)
iph = (struct openvpn_iphdr *) buf;
- if (tt->ipv6 && OPENVPN_IPH_GET_VER(iph->version_len) == 6)
+ if (OPENVPN_IPH_GET_VER(iph->version_len) == 6)
type = htonl (AF_INET6);
else
type = htonl (AF_INET);
@@ -2335,21 +2459,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
return read (tt->fd, buf, len);
}
-#else /* not NETBSD_MULTI_AF -> older code, IPv4 only */
-
-int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
-{
- return write (tt->fd, buf, len);
-}
-
-int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
-{
- return read (tt->fd, buf, len);
-}
-#endif /* NETBSD_MULTI_AF */
-
#elif defined(TARGET_FREEBSD)
static inline int
@@ -2364,7 +2473,7 @@ freebsd_modify_read_write_return (int len)
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);
+ open_tun_generic (dev, dev_type, dev_node, true, tt);
if (tt->fd >= 0 && tt->type == DEV_TYPE_TUN)
{
@@ -2397,12 +2506,11 @@ close_tun (struct tuntap *tt)
}
else if (tt) /* close and destroy */
{
- struct argv argv;
+ struct argv argv = argv_new ();
/* setup command, close tun dev (clears tt->actual_name!), run command
*/
- argv_init (&argv);
argv_printf (&argv, "%s %s destroy",
IFCONFIG_PATH, tt->actual_name);
@@ -2426,7 +2534,7 @@ write_tun (struct tuntap* tt, uint8_t *buf, int len)
iph = (struct ip *) buf;
- if (tt->ipv6 && iph->ip_v == 6)
+ if (iph->ip_v == 6)
type = htonl (AF_INET6);
else
type = htonl (AF_INET);
@@ -2475,7 +2583,7 @@ dragonfly_modify_read_write_return (int len)
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);
+ open_tun_generic (dev, dev_type, dev_node, true, tt);
if (tt->fd >= 0)
{
@@ -2509,7 +2617,7 @@ write_tun (struct tuntap* tt, uint8_t *buf, int len)
iph = (struct ip *) buf;
- if (tt->ipv6 && iph->ip_v == 6)
+ if (iph->ip_v == 6)
type = htonl (AF_INET6);
else
type = htonl (AF_INET);
@@ -2702,7 +2810,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
{
/* 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);
+ open_tun_generic (dev, dev_type, NULL, true, tt);
}
else
{
@@ -2723,7 +2831,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
if (dev_node && strcmp (dev_node, "tun")==0)
dev_node=NULL;
- open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+ open_tun_generic (dev, dev_type, dev_node, true, tt);
}
}
@@ -2733,10 +2841,9 @@ close_tun (struct tuntap* tt)
if (tt)
{
struct gc_arena gc = gc_new ();
- struct argv argv;
- argv_init (&argv);
+ struct argv argv = argv_new ();
- if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
+ if (tt->did_ifconfig_ipv6_setup )
{
const char * ifconfig_ipv6_local =
print_in6_addr (tt->local_ipv6, 0, &gc);
@@ -2776,7 +2883,137 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
return read (tt->fd, buf, len);
}
-#elif defined(WIN32)
+#elif defined(TARGET_AIX)
+
+void
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ char tunname[256];
+ char dynamic_name[20];
+ const char *p;
+
+ if (tt->type == DEV_TYPE_NULL)
+ {
+ open_null (tt);
+ return;
+ }
+
+ if ( tt->type == DEV_TYPE_TUN)
+ {
+ msg(M_FATAL, "no support for 'tun' devices on AIX" );
+ }
+
+ if ( strncmp( dev, "tap", 3 ) != 0 || dev_node )
+ {
+ msg(M_FATAL, "'--dev %s' and/or '--dev-node' not supported on AIX, use '--dev tap0', 'tap1', etc.", dev );
+ }
+
+ if ( strcmp( dev, "tap" ) == 0 ) /* find first free tap dev */
+ { /* (= no /dev/tapN node) */
+ int i;
+ for (i=0; i<99; i++ )
+ {
+ openvpn_snprintf (tunname, sizeof (tunname), "/dev/tap%d", i);
+ if ( access( tunname, F_OK ) < 0 && errno == ENOENT )
+ { break; }
+ }
+ if ( i >= 99 )
+ msg( M_FATAL, "cannot find unused tap device" );
+
+ openvpn_snprintf( dynamic_name, sizeof(dynamic_name), "tap%d", i );
+ dev = dynamic_name;
+ }
+ else /* name given, sanity check */
+ {
+ /* ensure that dev name is "tap+<digits>" *only* */
+ p = &dev[3];
+ while( isdigit(*p) ) p++;
+ if ( *p != '\0' )
+ msg( M_FATAL, "TAP device name must be '--dev tapNNNN'" );
+
+ openvpn_snprintf (tunname, sizeof (tunname), "/dev/%s", dev);
+ }
+
+ /* pre-existing device?
+ */
+ if ( access( tunname, F_OK ) < 0 && errno == ENOENT )
+ {
+
+ /* tunnel device must be created with 'ifconfig tapN create'
+ */
+ struct argv argv = argv_new ();
+ struct env_set *es = env_set_create (NULL);
+ argv_printf (&argv, "%s %s create", IFCONFIG_PATH, dev);
+ argv_msg (M_INFO, &argv);
+ env_set_add( es, "ODMDIR=/etc/objrepos" );
+ openvpn_execve_check (&argv, es, S_FATAL, "AIX 'create tun interface' failed");
+ env_set_destroy (es);
+ }
+ else
+ {
+ /* we didn't make it, we're not going to break it */
+ tt->persistent_if = TRUE;
+ }
+
+ if ((tt->fd = open (tunname, O_RDWR)) < 0)
+ {
+ msg (M_ERR, "Cannot open TAP device '%s'", tunname);
+ }
+
+ set_nonblock (tt->fd);
+ set_cloexec (tt->fd); /* don't pass fd to scripts */
+ msg (M_INFO, "TUN/TAP device %s opened", tunname);
+
+ /* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */
+ tt->actual_name = string_alloc(dev, NULL);
+}
+
+/* tap devices need to be manually destroyed on AIX
+ */
+void
+close_tun (struct tuntap* tt)
+{
+ struct gc_arena gc = gc_new ();
+ struct argv argv = argv_new ();
+ struct env_set *es = env_set_create (NULL);
+
+ if (!tt) return;
+
+ /* persistent devices need IP address unconfig, others need destroyal
+ */
+ if (tt->persistent_if)
+ {
+ argv_printf (&argv, "%s %s 0.0.0.0 down",
+ IFCONFIG_PATH, tt->actual_name);
+ }
+ else
+ {
+ argv_printf (&argv, "%s %s destroy",
+ IFCONFIG_PATH, tt->actual_name);
+ }
+
+ close_tun_generic (tt);
+ argv_msg (M_INFO, &argv);
+ env_set_add( es, "ODMDIR=/etc/objrepos" );
+ openvpn_execve_check (&argv, es, 0, "AIX 'destroy tap interface' failed (non-critical)");
+
+ free(tt);
+ env_set_destroy (es);
+}
+
+int
+write_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+ return read (tt->fd, buf, len);
+}
+
+#elif defined(_WIN32)
int
tun_read_queue (struct tuntap *tt, int maxsize)
@@ -4246,7 +4483,7 @@ dhcp_renew (const struct tuntap *tt)
*/
static void
-netsh_command (const struct argv *a, int n)
+netsh_command (const struct argv *a, int n, int msglevel)
{
int i;
for (i = 0; i < n; ++i)
@@ -4261,21 +4498,19 @@ netsh_command (const struct argv *a, int n)
return;
openvpn_sleep (4);
}
- msg (M_FATAL, "NETSH: command failed");
+ msg (msglevel, "NETSH: command failed");
}
void
ipconfig_register_dns (const struct env_set *es)
{
- struct argv argv;
+ struct argv argv = argv_new ();
bool status;
const char err[] = "ERROR: Windows ipconfig command failed";
msg (D_TUNTAP_INFO, "Start net commands...");
netcmd_semaphore_lock ();
- argv_init (&argv);
-
argv_printf (&argv, "%s%sc stop dnscache",
get_win_sys_path(),
WIN_NET_PATH_SUFFIX);
@@ -4411,7 +4646,7 @@ netsh_ifconfig_options (const char *type,
NETSH_PATH_SUFFIX,
type,
flex_name);
- netsh_command (&argv, 2);
+ netsh_command (&argv, 2, M_FATAL);
}
/* add new DNS/WINS settings to TAP interface */
@@ -4432,7 +4667,7 @@ netsh_ifconfig_options (const char *type,
type,
flex_name,
print_in_addr_t (addr_list[i], 0, &gc));
- netsh_command (&argv, 2);
+ netsh_command (&argv, 2, M_FATAL);
++count;
}
@@ -4507,7 +4742,7 @@ netsh_ifconfig (const struct tuntap_options *to,
print_in_addr_t (ip, 0, &gc),
print_in_addr_t (netmask, 0, &gc));
- netsh_command (&argv, 4);
+ netsh_command (&argv, 4, M_FATAL);
}
}
@@ -4543,8 +4778,7 @@ static void
netsh_enable_dhcp (const struct tuntap_options *to,
const char *actual_name)
{
- struct argv argv;
- argv_init (&argv);
+ struct argv argv = argv_new ();
/* example: netsh interface ip set address my-tap dhcp */
argv_printf (&argv,
@@ -4553,7 +4787,7 @@ netsh_enable_dhcp (const struct tuntap_options *to,
NETSH_PATH_SUFFIX,
actual_name);
- netsh_command (&argv, 4);
+ netsh_command (&argv, 4, M_FATAL);
argv_reset (&argv);
}
@@ -4750,10 +4984,43 @@ fork_dhcp_action (struct tuntap *tt)
}
}
+static void
+register_dns_service (const struct tuntap *tt)
+{
+ DWORD len;
+ HANDLE msg_channel = tt->options.msg_channel;
+ ack_message_t ack;
+ struct gc_arena gc = gc_new ();
+
+ message_header_t rdns = { msg_register_dns, sizeof(message_header_t), 0 };
+
+ if (!WriteFile (msg_channel, &rdns, sizeof (rdns), &len, NULL) ||
+ !ReadFile (msg_channel, &ack, sizeof (ack), &len, NULL))
+ {
+ msg (M_WARN, "Register_dns: could not talk to service: %s [status=0x%lx]",
+ strerror_win32 (GetLastError (), &gc), GetLastError ());
+ }
+
+ else if (ack.error_number != NO_ERROR)
+ {
+ msg (M_WARN, "Register_dns failed using service: %s [status=0x%x]",
+ strerror_win32 (ack.error_number, &gc), ack.error_number);
+ }
+
+ else
+ msg (M_INFO, "Register_dns request sent to the service");
+
+ gc_free (&gc);
+}
+
void
fork_register_dns_action (struct tuntap *tt)
{
- if (tt && tt->options.register_dns)
+ if (tt && tt->options.register_dns && tt->options.msg_channel)
+ {
+ register_dns_service (tt);
+ }
+ else if (tt && tt->options.register_dns)
{
struct gc_arena gc = gc_new ();
struct buffer cmd = alloc_buf_gc (256, &gc);
@@ -4798,7 +5065,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
/*netcmd_semaphore_lock ();*/
- msg( M_INFO, "open_tun, tt->ipv6=%d", tt->ipv6 );
+ msg( M_INFO, "open_tun");
if (tt->type == DEV_TYPE_NULL)
{
@@ -4924,11 +5191,10 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
/* usage of numeric constants is ugly, but this is really tied to
* *this* version of the driver
*/
- if ( tt->ipv6 && tt->type == DEV_TYPE_TUN &&
+ if (tt->type == DEV_TYPE_TUN &&
info[0] == 9 && info[1] < 8)
{
- msg( M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will be disabled. Upgrade to Tap-Win32 9.8 (2.2-beta3 release or later) or use TAP mode to get IPv6", (int) info[0], (int) info[1] );
- tt->ipv6 = false;
+ msg( M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will not work. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] );
}
/* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy
@@ -4936,7 +5202,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
if ( tt->type == DEV_TYPE_TUN &&
info[0] == 9 && info[1] == 8)
{
- msg( M_FATAL, "ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade to Tap-Win32 9.9 (2.2.2 release or later) or use TAP mode", (int) info[0], (int) info[1] );
+ msg( M_FATAL, "ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] );
}
}
@@ -5122,13 +5388,35 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu
/* flush arp cache */
if (index != TUN_ADAPTER_INDEX_INVALID)
{
- DWORD status;
+ DWORD status = -1;
+
+ if (tt->options.msg_channel)
+ {
+ ack_message_t ack;
+ flush_neighbors_message_t msg = {
+ .header = {
+ msg_flush_neighbors,
+ sizeof (flush_neighbors_message_t),
+ 0 },
+ .family = AF_INET,
+ .iface = { .index = index, .name = "" }
+ };
+
+ if (!WriteFile (tt->options.msg_channel, &msg, sizeof (msg), &len, NULL) ||
+ !ReadFile (tt->options.msg_channel, &ack, sizeof (ack), &len, NULL))
+ msg (M_WARN, "TUN: could not talk to service: %s [%lu]",
+ strerror_win32 (GetLastError (), &gc), GetLastError ());
+
+ status = ack.error_number;
+ }
+ else
+ status = FlushIpNetTable (index);
- if ((status = FlushIpNetTable (index)) == NO_ERROR)
+ if (status == NO_ERROR)
msg (M_INFO, "Successful ARP Flush on interface [%u] %s",
(unsigned int)index,
device_guid);
- else
+ else if (status != -1)
msg (D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%u] %s (status=%u) : %s",
(unsigned int)index,
device_guid,
@@ -5247,30 +5535,36 @@ close_tun (struct tuntap *tt)
if (tt)
{
- if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
+ if ( tt->did_ifconfig_ipv6_setup )
{
- const char *ifconfig_ipv6_local;
- struct argv argv;
- argv_init (&argv);
-
- /* remove route pointing to interface */
- delete_route_connected_v6_net(tt, NULL);
-
- /* "store=active" is needed in Windows 8(.1) to delete the
- * address we added (pointed out by Cedric Tabary).
- */
-
- /* netsh interface ipv6 delete address \"%s\" %s */
- ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
- argv_printf (&argv,
- "%s%sc interface ipv6 delete address %s %s store=active",
- get_win_sys_path(),
- NETSH_PATH_SUFFIX,
- tt->actual_name,
- ifconfig_ipv6_local );
-
- netsh_command (&argv, 1);
- argv_reset (&argv);
+ if (tt->options.msg_channel)
+ {
+ do_address_service (false, AF_INET6, tt);
+ }
+ else
+ {
+ const char *ifconfig_ipv6_local;
+ struct argv argv = argv_new ();
+
+ /* remove route pointing to interface */
+ delete_route_connected_v6_net(tt, NULL);
+
+ /* "store=active" is needed in Windows 8(.1) to delete the
+ * address we added (pointed out by Cedric Tabary).
+ */
+
+ /* netsh interface ipv6 delete address \"%s\" %s */
+ ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
+ argv_printf (&argv,
+ "%s%sc interface ipv6 delete address %s %s store=active",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ tt->actual_name,
+ ifconfig_ipv6_local);
+
+ netsh_command (&argv, 1, M_WARN);
+ argv_reset (&argv);
+ }
}
#if 1
if (tt->ipapi_context_defined)
@@ -5377,7 +5671,7 @@ ipset2ascii_all (struct gc_arena *gc)
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, false, true, tt);
+ open_tun_generic (dev, dev_type, dev_node, true, tt);
}
void
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index 7089f7c..dedd915 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -25,7 +25,7 @@
#ifndef TUN_H
#define TUN_H
-#ifdef WIN32
+#ifdef _WIN32
#include <winioctl.h>
#include <tap-windows.h>
#endif
@@ -38,7 +38,7 @@
#include "proto.h"
#include "misc.h"
-#ifdef WIN32
+#if defined(_WIN32) || defined(TARGET_ANDROID)
#define TUN_ADAPTER_INDEX_INVALID ((DWORD)-1)
@@ -58,6 +58,10 @@ struct tuntap_options {
# define IPW32_SET_N 5
int ip_win32_type;
+#ifdef _WIN32
+ HANDLE msg_channel;
+#endif
+
/* --ip-win32 dynamic options */
bool dhcp_masq_custom_offset;
int dhcp_masq_offset;
@@ -135,8 +139,6 @@ struct tuntap
bool did_ifconfig_ipv6_setup;
bool did_ifconfig;
- bool ipv6;
-
bool persistent_if; /* if existed before, keep on program end */
struct tuntap_options options; /* options set on command line */
@@ -155,7 +157,7 @@ struct tuntap
struct in6_addr remote_ipv6;
int netbits_ipv6;
-#ifdef WIN32
+#ifdef _WIN32
HANDLE hand;
struct overlapped_io reads;
struct overlapped_io writes;
@@ -195,7 +197,7 @@ struct tuntap
static inline bool
tuntap_defined (const struct tuntap *tt)
{
-#ifdef WIN32
+#ifdef _WIN32
return tt && tt->hand != NULL;
#else
return tt && tt->fd >= 0;
@@ -232,8 +234,8 @@ struct tuntap *init_tun (const char *dev, /* --dev option */
const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 / IPv6 */
int ifconfig_ipv6_netbits_parm, /* --ifconfig parm 1 / bits */
const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 / IPv6 */
- in_addr_t local_public,
- in_addr_t remote_public,
+ struct addrinfo *local_public,
+ struct addrinfo *remote_public,
const bool strict_warn,
struct env_set *es);
@@ -296,14 +298,31 @@ ifconfig_order(void)
return IFCONFIG_AFTER_TUN_OPEN;
#elif defined(TARGET_NETBSD)
return IFCONFIG_AFTER_TUN_OPEN;
-#elif defined(WIN32)
+#elif defined(_WIN32)
+ return IFCONFIG_AFTER_TUN_OPEN;
+#elif defined(TARGET_ANDROID)
return IFCONFIG_BEFORE_TUN_OPEN;
#else
return IFCONFIG_DEFAULT;
#endif
}
-#ifdef WIN32
+#define ROUTE_BEFORE_TUN 0
+#define ROUTE_AFTER_TUN 1
+#define ROUTE_ORDER_DEFAULT ROUTE_AFTER_TUN
+
+static inline int
+route_order(void)
+{
+#if defined(TARGET_ANDROID)
+ return ROUTE_BEFORE_TUN;
+#else
+ return ROUTE_ORDER_DEFAULT;
+#endif
+}
+
+
+#ifdef _WIN32
#define TUN_PASS_BUFFER
@@ -457,7 +476,7 @@ tun_standby (struct tuntap *tt)
static inline event_t
tun_event_handle (const struct tuntap *tt)
{
-#ifdef WIN32
+#ifdef _WIN32
return &tt->rw_handle;
#else
return tt->fd;
@@ -480,7 +499,7 @@ tun_set (struct tuntap *tt,
if (persistent)
*persistent = rwflags;
}
-#ifdef WIN32
+#ifdef _WIN32
if (rwflags & EVENT_READ)
tun_read_queue (tt, 0);
#endif
diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c
index e17cca1..00bc7ac 100644
--- a/src/openvpn/win32.c
+++ b/src/openvpn/win32.c
@@ -35,7 +35,7 @@
#include "syshead.h"
-#ifdef WIN32
+#ifdef _WIN32
#include "buffer.h"
#include "error.h"
@@ -43,34 +43,20 @@
#include "sig.h"
#include "win32.h"
#include "misc.h"
+#include "openvpn-msg.h"
#include "memdbg.h"
-#include "win32_wfp.h"
-
#ifdef HAVE_VERSIONHELPERS_H
#include <versionhelpers.h>
#else
#include "compat-versionhelpers.h"
#endif
-/* WFP function pointers. Initialized in win_wfp_init_funcs() */
-func_ConvertInterfaceIndexToLuid ConvertInterfaceIndexToLuid = NULL;
-func_FwpmEngineOpen0 FwpmEngineOpen0 = NULL;
-func_FwpmEngineClose0 FwpmEngineClose0 = NULL;
-func_FwpmFilterAdd0 FwpmFilterAdd0 = NULL;
-func_FwpmSubLayerAdd0 FwpmSubLayerAdd0 = NULL;
-func_FwpmSubLayerDeleteByKey0 FwpmSubLayerDeleteByKey0 = NULL;
-func_FwpmFreeMemory0 FwpmFreeMemory0 = NULL;
-func_FwpmGetAppIdFromFileName0 FwpmGetAppIdFromFileName0 = NULL;
-
-/*
- * WFP firewall name.
- */
-WCHAR * FIREWALL_NAME = L"OpenVPN"; /* GLOBAL */
+#include "block_dns.h"
/*
- * WFP handle and GUID.
+ * WFP handle
*/
static HANDLE m_hEngineHandle = NULL; /* GLOBAL */
@@ -119,7 +105,6 @@ init_win32 (void)
}
window_title_clear (&window_title);
win32_signal_clear (&win32_signal);
- netcmd_semaphore_init ();
}
void
@@ -598,7 +583,7 @@ win32_signal_get (struct win32_signal *ws)
if (ret)
{
siginfo_static.signal_received = ret;
- siginfo_static.hard = true;
+ siginfo_static.source = SIG_SOURCE_HARD;
}
}
return ret;
@@ -765,6 +750,10 @@ void
netcmd_semaphore_lock (void)
{
const int timeout_seconds = 600;
+
+ if (!netcmd_semaphore.hand)
+ netcmd_semaphore_init ();
+
if (!semaphore_lock (&netcmd_semaphore, timeout_seconds * 1000))
msg (M_FATAL, "Cannot lock net command semaphore");
}
@@ -773,6 +762,8 @@ void
netcmd_semaphore_release (void)
{
semaphore_release (&netcmd_semaphore);
+ /* netcmd_semaphore has max count of 1 - safe to close after release */
+ semaphore_close (&netcmd_semaphore);
}
/*
@@ -1106,211 +1097,109 @@ win_get_tempdir()
return tmpdir;
}
-bool
-win_wfp_init_funcs ()
+static bool
+win_block_dns_service (bool add, int index, const HANDLE pipe)
{
- /* Initialize all WFP-related function pointers */
- HMODULE iphlpapiHandle;
- HMODULE fwpuclntHandle;
-
- iphlpapiHandle = LoadLibrary("iphlpapi.dll");
- if (iphlpapiHandle == NULL)
- {
- msg (M_NONFATAL, "Can't load iphlpapi.dll");
- return false;
- }
+ DWORD len;
+ bool ret = false;
+ ack_message_t ack;
+ struct gc_arena gc = gc_new ();
- fwpuclntHandle = LoadLibrary("fwpuclnt.dll");
- if (fwpuclntHandle == NULL)
- {
- msg (M_NONFATAL, "Can't load fwpuclnt.dll");
- return false;
- }
-
- ConvertInterfaceIndexToLuid = (func_ConvertInterfaceIndexToLuid)GetProcAddress(iphlpapiHandle, "ConvertInterfaceIndexToLuid");
- FwpmFilterAdd0 = (func_FwpmFilterAdd0)GetProcAddress(fwpuclntHandle, "FwpmFilterAdd0");
- FwpmEngineOpen0 = (func_FwpmEngineOpen0)GetProcAddress(fwpuclntHandle, "FwpmEngineOpen0");
- FwpmEngineClose0 = (func_FwpmEngineClose0)GetProcAddress(fwpuclntHandle, "FwpmEngineClose0");
- FwpmSubLayerAdd0 = (func_FwpmSubLayerAdd0)GetProcAddress(fwpuclntHandle, "FwpmSubLayerAdd0");
- FwpmSubLayerDeleteByKey0 = (func_FwpmSubLayerDeleteByKey0)GetProcAddress(fwpuclntHandle, "FwpmSubLayerDeleteByKey0");
- FwpmFreeMemory0 = (func_FwpmFreeMemory0)GetProcAddress(fwpuclntHandle, "FwpmFreeMemory0");
- FwpmGetAppIdFromFileName0 = (func_FwpmGetAppIdFromFileName0)GetProcAddress(fwpuclntHandle, "FwpmGetAppIdFromFileName0");
-
- if (!ConvertInterfaceIndexToLuid ||
- !FwpmFilterAdd0 ||
- !FwpmEngineOpen0 ||
- !FwpmEngineClose0 ||
- !FwpmSubLayerAdd0 ||
- !FwpmSubLayerDeleteByKey0 ||
- !FwpmFreeMemory0 ||
- !FwpmGetAppIdFromFileName0)
- {
- msg (M_NONFATAL, "Can't get address for all WFP-related procedures.");
- return false;
- }
+ block_dns_message_t data = {
+ .header = {
+ (add ? msg_add_block_dns : msg_del_block_dns),
+ sizeof (block_dns_message_t),
+ 0 },
+ .iface = { .index = index, .name = "" }
+ };
- return true;
-}
+ if (!WriteFile (pipe, &data, sizeof (data), &len, NULL) ||
+ !ReadFile (pipe, &ack, sizeof (ack), &len, NULL))
+ {
+ msg (M_WARN, "Block_DNS: could not talk to service: %s [%lu]",
+ strerror_win32 (GetLastError (), &gc), GetLastError ());
+ goto out;
+ }
-bool
-win_wfp_add_filter (HANDLE engineHandle,
- const FWPM_FILTER0 *filter,
- PSECURITY_DESCRIPTOR sd,
- UINT64 *id)
-{
- if (FwpmFilterAdd0(engineHandle, filter, sd, id) != ERROR_SUCCESS)
+ if (ack.error_number != NO_ERROR)
{
- msg (M_NONFATAL, "Can't add WFP filter");
- return false;
+ msg (M_WARN, "Block_DNS: %s block dns filters using service failed: %s [status=0x%x if_index=%d]",
+ (add ? "adding" : "deleting"), strerror_win32 (ack.error_number, &gc),
+ ack.error_number, data.iface.index);
+ goto out;
}
- return true;
+
+ ret = true;
+ msg (M_INFO, "%s outside dns using service succeeded.", (add ? "Blocking" : "Unblocking"));
+out:
+ gc_free (&gc);
+ return ret;
}
-bool
-win_wfp_block_dns (const NET_IFINDEX index)
+static void
+block_dns_msg_handler (DWORD err, const char *msg)
{
- FWPM_SESSION0 session = {0};
- FWPM_SUBLAYER0 SubLayer = {0};
- NET_LUID tapluid;
- UINT64 filterid;
- WCHAR openvpnpath[MAX_PATH];
- FWP_BYTE_BLOB *openvpnblob = NULL;
- FWPM_FILTER0 Filter = {0};
- FWPM_FILTER_CONDITION0 Condition[2] = {0};
-
- /* Add temporary filters which don't survive reboots or crashes. */
- session.flags = FWPM_SESSION_FLAG_DYNAMIC;
-
- dmsg (D_LOW, "Opening WFP engine");
+ struct gc_arena gc = gc_new ();
- if (FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &m_hEngineHandle) != ERROR_SUCCESS)
+ if (err == 0)
{
- msg (M_NONFATAL, "Can't open WFP engine");
- return false;
+ msg (M_INFO, "%s", msg);
+ }
+ else
+ {
+ msg (M_WARN, "Error in add_block_dns_filters(): %s : %s [status=0x%lx]",
+ msg, strerror_win32 (err, &gc), err);
}
- if (UuidCreate(&SubLayer.subLayerKey) != NO_ERROR)
- return false;
+ gc_free (&gc);
+}
- /* Populate packet filter layer information. */
- SubLayer.displayData.name = FIREWALL_NAME;
- SubLayer.displayData.description = FIREWALL_NAME;
- SubLayer.flags = 0;
- SubLayer.weight = 0x100;
+bool
+win_wfp_block_dns (const NET_IFINDEX index, const HANDLE msg_channel)
+{
+ WCHAR openvpnpath[MAX_PATH];
+ bool ret = false;
+ DWORD status;
- /* Add packet filter to our interface. */
- dmsg (D_LOW, "Adding WFP sublayer");
- if (FwpmSubLayerAdd0(m_hEngineHandle, &SubLayer, NULL) != ERROR_SUCCESS)
+ if (msg_channel)
{
- msg (M_NONFATAL, "Can't add WFP sublayer");
- return false;
+ dmsg (D_LOW, "Using service to add block dns filters");
+ ret = win_block_dns_service (true, index, msg_channel);
+ goto out;
}
- dmsg (D_LOW, "Blocking DNS using WFP");
- if (ConvertInterfaceIndexToLuid(index, &tapluid) != NO_ERROR)
+ status = GetModuleFileNameW (NULL, openvpnpath, sizeof(openvpnpath));
+ if (status == 0 || status == sizeof(openvpnpath))
{
- msg (M_NONFATAL, "Can't convert interface index to LUID");
- return false;
+ msg (M_WARN|M_ERRNO, "block_dns: cannot get executable path");
+ goto out;
}
- dmsg (D_LOW, "Tap Luid: %I64d", tapluid.Value);
-
- /* Get OpenVPN path. */
- GetModuleFileNameW(NULL, openvpnpath, MAX_PATH);
-
- if (FwpmGetAppIdFromFileName0(openvpnpath, &openvpnblob) != ERROR_SUCCESS)
- return false;
-
- /* Prepare filter. */
- Filter.subLayerKey = SubLayer.subLayerKey;
- Filter.displayData.name = FIREWALL_NAME;
- Filter.weight.type = FWP_UINT8;
- Filter.weight.uint8 = 0xF;
- Filter.filterCondition = Condition;
- Filter.numFilterConditions = 2;
-
- /* First filter. Permit IPv4 DNS queries from OpenVPN itself. */
- Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
- Filter.action.type = FWP_ACTION_PERMIT;
-
- Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
- Condition[0].matchType = FWP_MATCH_EQUAL;
- Condition[0].conditionValue.type = FWP_UINT16;
- Condition[0].conditionValue.uint16 = 53;
-
- Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID;
- Condition[1].matchType = FWP_MATCH_EQUAL;
- Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE;
- Condition[1].conditionValue.byteBlob = openvpnblob;
-
- /* Add filter condition to our interface. */
- if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
- goto err;
- dmsg (D_LOW, "Filter (Permit OpenVPN IPv4 DNS) added with ID=%I64d", filterid);
-
- /* Second filter. Permit IPv6 DNS queries from OpenVPN itself. */
- Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
-
- /* Add filter condition to our interface. */
- if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
- goto err;
- dmsg (D_LOW, "Filter (Permit OpenVPN IPv6 DNS) added with ID=%I64d", filterid);
-
- /* Third filter. Block all IPv4 DNS queries. */
- Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
- Filter.action.type = FWP_ACTION_BLOCK;
- Filter.weight.type = FWP_EMPTY;
- Filter.numFilterConditions = 1;
-
- if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
- goto err;
- dmsg (D_LOW, "Filter (Block IPv4 DNS) added with ID=%I64d", filterid);
-
- /* Forth filter. Block all IPv6 DNS queries. */
- Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
-
- if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
- goto err;
- dmsg (D_LOW, "Filter (Block IPv6 DNS) added with ID=%I64d", filterid);
-
- /* Fifth filter. Permit IPv4 DNS queries from TAP. */
- Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
- Filter.action.type = FWP_ACTION_PERMIT;
- Filter.numFilterConditions = 2;
-
- Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE;
- Condition[1].matchType = FWP_MATCH_EQUAL;
- Condition[1].conditionValue.type = FWP_UINT64;
- Condition[1].conditionValue.uint64 = &tapluid.Value;
-
- /* Add filter condition to our interface. */
- if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
- goto err;
- dmsg (D_LOW, "Filter (Permit IPv4 DNS queries from TAP) added with ID=%I64d", filterid);
-
- /* Sixth filter. Permit IPv6 DNS queries from TAP. */
- Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
-
- /* Add filter condition to our interface. */
- if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
- goto err;
- dmsg (D_LOW, "Filter (Permit IPv6 DNS queries from TAP) added with ID=%I64d", filterid);
-
- FwpmFreeMemory0((void **)&openvpnblob);
- return true;
- err:
- FwpmFreeMemory0((void **)&openvpnblob);
- return false;
+ status = add_block_dns_filters (&m_hEngineHandle, index, openvpnpath,
+ block_dns_msg_handler);
+ ret = (status == 0);
+
+out:
+
+ return ret;
}
bool
-win_wfp_uninit()
+win_wfp_uninit(const HANDLE msg_channel)
{
dmsg (D_LOW, "Uninitializing WFP");
- if (m_hEngineHandle) {
- FwpmEngineClose0(m_hEngineHandle);
+
+ if (msg_channel)
+ {
+ msg (D_LOW, "Using service to delete block dns filters");
+ win_block_dns_service (false, -1, msg_channel);
+ }
+ else
+ {
+ delete_block_dns_filters (m_hEngineHandle);
m_hEngineHandle = NULL;
- }
+ }
+
return true;
}
diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h
index 0990182..11e42f4 100644
--- a/src/openvpn/win32.h
+++ b/src/openvpn/win32.h
@@ -22,7 +22,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifdef WIN32
+#ifdef _WIN32
#ifndef OPENVPN_WIN32_H
#define OPENVPN_WIN32_H
@@ -271,9 +271,8 @@ const char *win_get_tempdir();
/* Convert a string from UTF-8 to UCS-2 */
WCHAR *wide_string (const char* utf8, struct gc_arena *gc);
-bool win_wfp_init_funcs();
-bool win_wfp_block_dns(const NET_IFINDEX index);
-bool win_wfp_uninit();
+bool win_wfp_block_dns(const NET_IFINDEX index, const HANDLE msg_channel);
+bool win_wfp_uninit(const HANDLE msg_channel);
#define WIN_XP 0
#define WIN_VISTA 1
diff --git a/src/openvpn/win32_wfp.h b/src/openvpn/win32_wfp.h
deleted file mode 100644
index 7559e5b..0000000
--- a/src/openvpn/win32_wfp.h
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- This Software is provided under the Zope Public License (ZPL) Version 2.1.
-
- Copyright (c) 2009, 2010 by the mingw-w64 project
-
- See the AUTHORS file for the list of contributors to the mingw-w64 project.
-
- This license has been certified as open source. It has also been designated
- as GPL compatible by the Free Software Foundation (FSF).
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions in source code must retain the accompanying copyright
- notice, this list of conditions, and the following disclaimer.
- 2. Redistributions in binary form must reproduce the accompanying
- copyright notice, this list of conditions, and the following disclaimer
- in the documentation and/or other materials provided with the
- distribution.
- 3. Names of the copyright holders must not be used to endorse or promote
- products derived from this software without prior written permission
- from the copyright holders.
- 4. The right to distribute this software or to use it for any purpose does
- not give you the right to use Servicemarks (sm) or Trademarks (tm) of
- the copyright holders. Use of them is covered by separate agreement
- with the copyright holders.
- 5. If any files are modified, you must cause the modified files to carry
- prominent notices stating that you changed the files and the date of
- any change.
-
- Disclaimer
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
- OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
- OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/*
- * Windows Filtering Platform (WFP) related prototypes, mostly stripped out of
- * mingw-w64.
- */
-
-/*
- * WFP-related defines and GUIDs.
- */
-
-#ifndef WIN32_WFP_H
-#define WIN32_WFP_H
-
-#include <initguid.h>
-#include <iphlpapi.h>
-#include <rpc.h>
-#include <rpcdce.h>
-
-#ifndef FWPM_SESSION_FLAG_DYNAMIC
-#define FWPM_SESSION_FLAG_DYNAMIC 0x00000001
-#endif
-
-// c38d57d1-05a7-4c33-904f-7fbceee60e82
-DEFINE_GUID(
- FWPM_LAYER_ALE_AUTH_CONNECT_V4,
- 0xc38d57d1,
- 0x05a7,
- 0x4c33,
- 0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82
-);
-
-// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4
-DEFINE_GUID(
- FWPM_LAYER_ALE_AUTH_CONNECT_V6,
- 0x4a72393b,
- 0x319f,
- 0x44bc,
- 0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4
-);
-
-// d78e1e87-8644-4ea5-9437-d809ecefc971
-DEFINE_GUID(
- FWPM_CONDITION_ALE_APP_ID,
- 0xd78e1e87,
- 0x8644,
- 0x4ea5,
- 0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71
-);
-
-// c35a604d-d22b-4e1a-91b4-68f674ee674b
-DEFINE_GUID(
- FWPM_CONDITION_IP_REMOTE_PORT,
- 0xc35a604d,
- 0xd22b,
- 0x4e1a,
- 0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b
-);
-
-// 4cd62a49-59c3-4969-b7f3-bda5d32890a4
-DEFINE_GUID(
- FWPM_CONDITION_IP_LOCAL_INTERFACE,
- 0x4cd62a49,
- 0x59c3,
- 0x4969,
- 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4
-);
-
-/* From fwptypes.h */
-
-#define FWP_ACTION_FLAG_TERMINATING (0x00001000)
-#define FWP_ACTION_FLAG_NON_TERMINATING (0x00002000)
-
-#define FWP_ACTION_BLOCK (0x1 | FWP_ACTION_FLAG_TERMINATING)
-#define FWP_ACTION_PERMIT (0x2 | FWP_ACTION_FLAG_TERMINATING)
-
-typedef UINT32 FWP_ACTION_TYPE;
-
-typedef enum FWP_DATA_TYPE_ {
- FWP_EMPTY = 0,
- FWP_UINT8 = 1,
- FWP_UINT16 = 2,
- FWP_UINT32 = 3,
- FWP_UINT64 = 4,
- FWP_INT8 = 5,
- FWP_INT16 = 6,
- FWP_INT32 = 7,
- FWP_INT64 = 8,
- FWP_FLOAT = 9,
- FWP_DOUBLE = 10,
- FWP_BYTE_ARRAY16_TYPE = 11,
- FWP_BYTE_BLOB_TYPE = 12,
- FWP_SID = 13,
- FWP_SECURITY_DESCRIPTOR_TYPE = 14,
- FWP_TOKEN_INFORMATION_TYPE = 15,
- FWP_TOKEN_ACCESS_INFORMATION_TYPE = 16,
- FWP_UNICODE_STRING_TYPE = 17,
- FWP_BYTE_ARRAY6_TYPE = 18,
- FWP_SINGLE_DATA_TYPE_MAX = 0xff,
- FWP_V4_ADDR_MASK = 0x100,
- FWP_V6_ADDR_MASK = 0x101,
- FWP_RANGE_TYPE = 0x102,
- FWP_DATA_TYPE_MAX = 0x103
-} FWP_DATA_TYPE;
-
-typedef enum FWP_MATCH_TYPE_ {
- FWP_MATCH_EQUAL = 0,
- FWP_MATCH_GREATER = 1,
- FWP_MATCH_LESS = 2,
- FWP_MATCH_GREATER_OR_EQUAL = 3,
- FWP_MATCH_LESS_OR_EQUAL = 4,
- FWP_MATCH_RANGE = 5,
- FWP_MATCH_FLAGS_ALL_SET = 6,
- FWP_MATCH_FLAGS_ANY_SET = 7,
- FWP_MATCH_FLAGS_NONE_SET = 8,
- FWP_MATCH_EQUAL_CASE_INSENSITIVE = 9,
- FWP_MATCH_NOT_EQUAL = 10,
- FWP_MATCH_TYPE_MAX = 11
-} FWP_MATCH_TYPE;
-
-typedef struct FWP_BYTE_ARRAY6_ {
- UINT8 byteArray6[6];
-} FWP_BYTE_ARRAY6;
-
-typedef struct FWP_BYTE_ARRAY16_ {
- UINT8 byteArray16[16];
-} FWP_BYTE_ARRAY16;
-
-typedef struct FWP_BYTE_BLOB_ {
- UINT32 size;
- UINT8 *data;
-} FWP_BYTE_BLOB;
-
-typedef struct FWP_TOKEN_INFORMATION_ {
- ULONG sidCount;
- PSID_AND_ATTRIBUTES sids;
- ULONG restrictedSidCount;
- PSID_AND_ATTRIBUTES restrictedSids;
-} FWP_TOKEN_INFORMATION;
-
-typedef struct FWP_VALUE0_ {
- FWP_DATA_TYPE type;
- union {
- UINT8 uint8;
- UINT16 uint16;
- UINT32 uint32;
- UINT64 *uint64;
- INT8 int8;
- INT16 int16;
- INT32 int32;
- INT64 *int64;
- float float32;
- double *double64;
- FWP_BYTE_ARRAY16 *byteArray16;
- FWP_BYTE_BLOB *byteBlob;
- SID *sid;
- FWP_BYTE_BLOB *sd;
- FWP_TOKEN_INFORMATION *tokenInformation;
- FWP_BYTE_BLOB *tokenAccessInformation;
- LPWSTR unicodeString;
- FWP_BYTE_ARRAY6 *byteArray6;
- };
-} FWP_VALUE0;
-
-typedef struct FWP_V4_ADDR_AND_MASK_ {
- UINT32 addr;
- UINT32 mask;
-} FWP_V4_ADDR_AND_MASK;
-
-typedef struct FWP_V6_ADDR_AND_MASK_ {
- UINT8 addr[16];
- UINT8 prefixLength;
-} FWP_V6_ADDR_AND_MASK;
-
-typedef struct FWP_RANGE0_ {
- FWP_VALUE0 valueLow;
- FWP_VALUE0 valueHigh;
-} FWP_RANGE0;
-
-typedef struct FWP_CONDITION_VALUE0_ {
- FWP_DATA_TYPE type;
- union {
- UINT8 uint8;
- UINT16 uint16;
- UINT32 uint32;
- UINT64 *uint64;
- INT8 int8;
- INT16 int16;
- INT32 int32;
- INT64 *int64;
- float float32;
- double *double64;
- FWP_BYTE_ARRAY16 *byteArray16;
- FWP_BYTE_BLOB *byteBlob;
- SID *sid;
- FWP_BYTE_BLOB *sd;
- FWP_TOKEN_INFORMATION *tokenInformation;
- FWP_BYTE_BLOB *tokenAccessInformation;
- LPWSTR unicodeString;
- FWP_BYTE_ARRAY6 *byteArray6;
- FWP_V4_ADDR_AND_MASK *v4AddrMask;
- FWP_V6_ADDR_AND_MASK *v6AddrMask;
- FWP_RANGE0 *rangeValue;
- };
-} FWP_CONDITION_VALUE0;
-
-typedef struct FWPM_DISPLAY_DATA0_ {
- wchar_t *name;
- wchar_t *description;
-} FWPM_DISPLAY_DATA0;
-
-/* From fwpmtypes.h */
-
-typedef struct FWPM_ACTION0_ {
- FWP_ACTION_TYPE type;
- union {
- GUID filterType;
- GUID calloutKey;
- };
-} FWPM_ACTION0;
-
-typedef struct FWPM_SESSION0_ {
- GUID sessionKey;
- FWPM_DISPLAY_DATA0 displayData;
- UINT32 flags;
- UINT32 txnWaitTimeoutInMSec;
- DWORD processId;
- SID *sid;
- wchar_t *username;
- BOOL kernelMode;
-} FWPM_SESSION0;
-
-typedef struct FWPM_SUBLAYER0_ {
- GUID subLayerKey;
- FWPM_DISPLAY_DATA0 displayData;
- UINT16 flags;
- GUID *providerKey;
- FWP_BYTE_BLOB providerData;
- UINT16 weight;
-} FWPM_SUBLAYER0;
-
-typedef struct FWPM_FILTER_CONDITION0_ {
- GUID fieldKey;
- FWP_MATCH_TYPE matchType;
- FWP_CONDITION_VALUE0 conditionValue;
-} FWPM_FILTER_CONDITION0;
-
-typedef struct FWPM_FILTER0_ {
- GUID filterKey;
- FWPM_DISPLAY_DATA0 displayData;
- UINT32 flags;
- GUID *providerKey;
- FWP_BYTE_BLOB providerData;
- GUID layerKey;
- GUID subLayerKey;
- FWP_VALUE0 weight;
- UINT32 numFilterConditions;
- FWPM_FILTER_CONDITION0 *filterCondition;
- FWPM_ACTION0 action;
- union {
- UINT64 rawContext;
- GUID providerContextKey;
- };
- GUID *reserved;
- UINT64 filterId;
- FWP_VALUE0 effectiveWeight;
-} FWPM_FILTER0;
-
-/* Typedefs of WFP functions */
-
-#define NETIO_STATUS DWORD
-
-typedef NETIO_STATUS *(WINAPI *func_ConvertInterfaceIndexToLuid)(
- NET_IFINDEX InterfaceIndex,
- PNET_LUID InterfaceLuid
-);
-
-typedef DWORD *(WINAPI *func_FwpmEngineOpen0)(
- const wchar_t *serverName,
- UINT32 authnService,
- SEC_WINNT_AUTH_IDENTITY_W *authIdentity,
- const FWPM_SESSION0 *session,
- HANDLE *engineHandle
-);
-
-typedef DWORD *(WINAPI *func_FwpmEngineClose0)(
- HANDLE engineHandle
-);
-
-typedef DWORD *(WINAPI *func_FwpmFilterAdd0)(
- HANDLE engineHandle,
- const FWPM_FILTER0 *filter,
- PSECURITY_DESCRIPTOR sd,
- UINT64 *id
-);
-
-typedef DWORD *(WINAPI *func_FwpmSubLayerAdd0)(
- HANDLE engineHandle,
- const FWPM_SUBLAYER0 *subLayer,
- PSECURITY_DESCRIPTOR sd
-);
-
-typedef DWORD *(WINAPI *func_FwpmSubLayerDeleteByKey0)(
- HANDLE engineHandle,
- const GUID *key
-);
-
-typedef void *(WINAPI *func_FwpmFreeMemory0)(
- void **p
-);
-
-typedef DWORD *(WINAPI *func_FwpmGetAppIdFromFileName0)(
- const wchar_t *fileName,
- FWP_BYTE_BLOB **appId
-);
-
-#endif
diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am
index a989c25..3521a34 100644
--- a/src/openvpnserv/Makefile.am
+++ b/src/openvpnserv/Makefile.am
@@ -17,11 +17,23 @@ EXTRA_DIST = \
openvpnserv.vcxproj \
openvpnserv.vcxproj.filters
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include -I$(top_srcdir)/src/openvpn -I$(top_srcdir)/src/compat
+
if WIN32
sbin_PROGRAMS = openvpnserv
+openvpnserv_CFLAGS = \
+ -municode -D_UNICODE \
+ -UNTDDI_VERSION -U_WIN32_WINNT \
+ -D_WIN32_WINNT=_WIN32_WINNT_VISTA
+openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lfwpuclnt -lrpcrt4 -lshlwapi -lnetapi32 -lws2_32
endif
openvpnserv_SOURCES = \
- openvpnserv.c \
- service.h service.c \
+ common.c \
+ automatic.c \
+ interactive.c \
+ service.c service.h \
+ validate.c validate.h \
+ $(top_srcdir)/src/openvpn/block_dns.c $(top_srcdir)/src/openvpn/block_dns.h \
openvpnserv_resources.rc
diff --git a/src/openvpnserv/Makefile.in b/src/openvpnserv/Makefile.in
index ed1ee90..74a802b 100644
--- a/src/openvpnserv/Makefile.in
+++ b/src/openvpnserv/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -37,17 +37,7 @@
# Required to build Windows resource file
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -110,6 +100,8 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
+DIST_COMMON = $(top_srcdir)/build/ltrc.inc $(srcdir)/Makefile.in \
+ $(srcdir)/Makefile.am $(top_srcdir)/depcomp
@WIN32_TRUE@sbin_PROGRAMS = openvpnserv$(EXEEXT)
subdir = src/openvpnserv
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -122,21 +114,28 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/compat.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_HEADER = $(top_builddir)/config.h \
+ $(top_builddir)/include/openvpn-plugin.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__installdirs = "$(DESTDIR)$(sbindir)"
PROGRAMS = $(sbin_PROGRAMS)
-am_openvpnserv_OBJECTS = openvpnserv.$(OBJEXT) service.$(OBJEXT) \
+am_openvpnserv_OBJECTS = openvpnserv-common.$(OBJEXT) \
+ openvpnserv-automatic.$(OBJEXT) \
+ openvpnserv-interactive.$(OBJEXT) \
+ openvpnserv-service.$(OBJEXT) openvpnserv-validate.$(OBJEXT) \
+ openvpnserv-block_dns.$(OBJEXT) \
openvpnserv_resources.$(OBJEXT)
openvpnserv_OBJECTS = $(am_openvpnserv_OBJECTS)
-openvpnserv_LDADD = $(LDADD)
+openvpnserv_DEPENDENCIES =
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
+openvpnserv_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(openvpnserv_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@@ -149,7 +148,7 @@ AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
-DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/include
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
@@ -197,8 +196,6 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/build/ltrc.inc \
- $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@@ -212,6 +209,7 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CMAKE = @CMAKE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
@@ -246,25 +244,31 @@ LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LZ4_CFLAGS = @LZ4_CFLAGS@
+LZ4_LIBS = @LZ4_LIBS@
LZO_CFLAGS = @LZO_CFLAGS@
LZO_LIBS = @LZO_LIBS@
MAKEINFO = @MAKEINFO@
MAN2HTML = @MAN2HTML@
MANIFEST_TOOL = @MANIFEST_TOOL@
+MBEDTLS_CFLAGS = @MBEDTLS_CFLAGS@
+MBEDTLS_LIBS = @MBEDTLS_LIBS@
MKDIR_P = @MKDIR_P@
NETSTAT = @NETSTAT@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
-OPENSSL_CRYPTO_CFLAGS = @OPENSSL_CRYPTO_CFLAGS@
-OPENSSL_CRYPTO_LIBS = @OPENSSL_CRYPTO_LIBS@
-OPENSSL_SSL_CFLAGS = @OPENSSL_SSL_CFLAGS@
-OPENSSL_SSL_LIBS = @OPENSSL_SSL_LIBS@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENVPN_VERSION_MAJOR = @OPENVPN_VERSION_MAJOR@
+OPENVPN_VERSION_MINOR = @OPENVPN_VERSION_MINOR@
+OPENVPN_VERSION_PATCH = @OPENVPN_VERSION_PATCH@
OPTIONAL_CRYPTO_CFLAGS = @OPTIONAL_CRYPTO_CFLAGS@
OPTIONAL_CRYPTO_LIBS = @OPTIONAL_CRYPTO_LIBS@
OPTIONAL_DL_LIBS = @OPTIONAL_DL_LIBS@
+OPTIONAL_LZ4_CFLAGS = @OPTIONAL_LZ4_CFLAGS@
+OPTIONAL_LZ4_LIBS = @OPTIONAL_LZ4_LIBS@
OPTIONAL_LZO_CFLAGS = @OPTIONAL_LZO_CFLAGS@
OPTIONAL_LZO_LIBS = @OPTIONAL_LZO_LIBS@
OPTIONAL_PKCS11_HELPER_CFLAGS = @OPTIONAL_PKCS11_HELPER_CFLAGS@
@@ -290,8 +294,6 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PLUGIN_AUTH_PAM_CFLAGS = @PLUGIN_AUTH_PAM_CFLAGS@
PLUGIN_AUTH_PAM_LIBS = @PLUGIN_AUTH_PAM_LIBS@
-POLARSSL_CFLAGS = @POLARSSL_CFLAGS@
-POLARSSL_LIBS = @POLARSSL_LIBS@
RANLIB = @RANLIB@
RC = @RC@
ROUTE = @ROUTE@
@@ -306,6 +308,11 @@ TAP_CFLAGS = @TAP_CFLAGS@
TAP_WIN_COMPONENT_ID = @TAP_WIN_COMPONENT_ID@
TAP_WIN_MIN_MAJOR = @TAP_WIN_MIN_MAJOR@
TAP_WIN_MIN_MINOR = @TAP_WIN_MIN_MINOR@
+TEST_CFLAGS = @TEST_CFLAGS@
+TEST_LDFLAGS = @TEST_LDFLAGS@
+VENDOR_BUILD_ROOT = @VENDOR_BUILD_ROOT@
+VENDOR_DIST_ROOT = @VENDOR_DIST_ROOT@
+VENDOR_SRC_ROOT = @VENDOR_SRC_ROOT@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -372,9 +379,22 @@ EXTRA_DIST = \
openvpnserv.vcxproj \
openvpnserv.vcxproj.filters
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include -I$(top_srcdir)/src/openvpn -I$(top_srcdir)/src/compat
+
+@WIN32_TRUE@openvpnserv_CFLAGS = \
+@WIN32_TRUE@ -municode -D_UNICODE \
+@WIN32_TRUE@ -UNTDDI_VERSION -U_WIN32_WINNT \
+@WIN32_TRUE@ -D_WIN32_WINNT=_WIN32_WINNT_VISTA
+
+@WIN32_TRUE@openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lfwpuclnt -lrpcrt4 -lshlwapi -lnetapi32 -lws2_32
openvpnserv_SOURCES = \
- openvpnserv.c \
- service.h service.c \
+ common.c \
+ automatic.c \
+ interactive.c \
+ service.c service.h \
+ validate.c validate.h \
+ $(top_srcdir)/src/openvpn/block_dns.c $(top_srcdir)/src/openvpn/block_dns.h \
openvpnserv_resources.rc
all: all-am
@@ -393,6 +413,7 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/build/ltrc.inc $(am_
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/openvpnserv/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/openvpnserv/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -401,7 +422,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
-$(top_srcdir)/build/ltrc.inc $(am__empty):
+$(top_srcdir)/build/ltrc.inc:
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
@@ -463,7 +484,7 @@ clean-sbinPROGRAMS:
openvpnserv$(EXEEXT): $(openvpnserv_OBJECTS) $(openvpnserv_DEPENDENCIES) $(EXTRA_openvpnserv_DEPENDENCIES)
@rm -f openvpnserv$(EXEEXT)
- $(AM_V_CCLD)$(LINK) $(openvpnserv_OBJECTS) $(openvpnserv_LDADD) $(LIBS)
+ $(AM_V_CCLD)$(openvpnserv_LINK) $(openvpnserv_OBJECTS) $(openvpnserv_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -471,22 +492,26 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/service.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-automatic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-block_dns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-interactive.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-service.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openvpnserv-validate.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -495,6 +520,90 @@ distclean-compile:
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+openvpnserv-common.o: common.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-common.o -MD -MP -MF $(DEPDIR)/openvpnserv-common.Tpo -c -o openvpnserv-common.o `test -f 'common.c' || echo '$(srcdir)/'`common.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-common.Tpo $(DEPDIR)/openvpnserv-common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common.c' object='openvpnserv-common.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-common.o `test -f 'common.c' || echo '$(srcdir)/'`common.c
+
+openvpnserv-common.obj: common.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-common.obj -MD -MP -MF $(DEPDIR)/openvpnserv-common.Tpo -c -o openvpnserv-common.obj `if test -f 'common.c'; then $(CYGPATH_W) 'common.c'; else $(CYGPATH_W) '$(srcdir)/common.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-common.Tpo $(DEPDIR)/openvpnserv-common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='common.c' object='openvpnserv-common.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-common.obj `if test -f 'common.c'; then $(CYGPATH_W) 'common.c'; else $(CYGPATH_W) '$(srcdir)/common.c'; fi`
+
+openvpnserv-automatic.o: automatic.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-automatic.o -MD -MP -MF $(DEPDIR)/openvpnserv-automatic.Tpo -c -o openvpnserv-automatic.o `test -f 'automatic.c' || echo '$(srcdir)/'`automatic.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-automatic.Tpo $(DEPDIR)/openvpnserv-automatic.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='automatic.c' object='openvpnserv-automatic.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-automatic.o `test -f 'automatic.c' || echo '$(srcdir)/'`automatic.c
+
+openvpnserv-automatic.obj: automatic.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-automatic.obj -MD -MP -MF $(DEPDIR)/openvpnserv-automatic.Tpo -c -o openvpnserv-automatic.obj `if test -f 'automatic.c'; then $(CYGPATH_W) 'automatic.c'; else $(CYGPATH_W) '$(srcdir)/automatic.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-automatic.Tpo $(DEPDIR)/openvpnserv-automatic.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='automatic.c' object='openvpnserv-automatic.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-automatic.obj `if test -f 'automatic.c'; then $(CYGPATH_W) 'automatic.c'; else $(CYGPATH_W) '$(srcdir)/automatic.c'; fi`
+
+openvpnserv-interactive.o: interactive.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-interactive.o -MD -MP -MF $(DEPDIR)/openvpnserv-interactive.Tpo -c -o openvpnserv-interactive.o `test -f 'interactive.c' || echo '$(srcdir)/'`interactive.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-interactive.Tpo $(DEPDIR)/openvpnserv-interactive.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='interactive.c' object='openvpnserv-interactive.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-interactive.o `test -f 'interactive.c' || echo '$(srcdir)/'`interactive.c
+
+openvpnserv-interactive.obj: interactive.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-interactive.obj -MD -MP -MF $(DEPDIR)/openvpnserv-interactive.Tpo -c -o openvpnserv-interactive.obj `if test -f 'interactive.c'; then $(CYGPATH_W) 'interactive.c'; else $(CYGPATH_W) '$(srcdir)/interactive.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-interactive.Tpo $(DEPDIR)/openvpnserv-interactive.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='interactive.c' object='openvpnserv-interactive.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-interactive.obj `if test -f 'interactive.c'; then $(CYGPATH_W) 'interactive.c'; else $(CYGPATH_W) '$(srcdir)/interactive.c'; fi`
+
+openvpnserv-service.o: service.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-service.o -MD -MP -MF $(DEPDIR)/openvpnserv-service.Tpo -c -o openvpnserv-service.o `test -f 'service.c' || echo '$(srcdir)/'`service.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-service.Tpo $(DEPDIR)/openvpnserv-service.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='service.c' object='openvpnserv-service.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-service.o `test -f 'service.c' || echo '$(srcdir)/'`service.c
+
+openvpnserv-service.obj: service.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-service.obj -MD -MP -MF $(DEPDIR)/openvpnserv-service.Tpo -c -o openvpnserv-service.obj `if test -f 'service.c'; then $(CYGPATH_W) 'service.c'; else $(CYGPATH_W) '$(srcdir)/service.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-service.Tpo $(DEPDIR)/openvpnserv-service.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='service.c' object='openvpnserv-service.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-service.obj `if test -f 'service.c'; then $(CYGPATH_W) 'service.c'; else $(CYGPATH_W) '$(srcdir)/service.c'; fi`
+
+openvpnserv-validate.o: validate.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-validate.o -MD -MP -MF $(DEPDIR)/openvpnserv-validate.Tpo -c -o openvpnserv-validate.o `test -f 'validate.c' || echo '$(srcdir)/'`validate.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-validate.Tpo $(DEPDIR)/openvpnserv-validate.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='validate.c' object='openvpnserv-validate.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-validate.o `test -f 'validate.c' || echo '$(srcdir)/'`validate.c
+
+openvpnserv-validate.obj: validate.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-validate.obj -MD -MP -MF $(DEPDIR)/openvpnserv-validate.Tpo -c -o openvpnserv-validate.obj `if test -f 'validate.c'; then $(CYGPATH_W) 'validate.c'; else $(CYGPATH_W) '$(srcdir)/validate.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-validate.Tpo $(DEPDIR)/openvpnserv-validate.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='validate.c' object='openvpnserv-validate.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-validate.obj `if test -f 'validate.c'; then $(CYGPATH_W) 'validate.c'; else $(CYGPATH_W) '$(srcdir)/validate.c'; fi`
+
+openvpnserv-block_dns.o: $(top_srcdir)/src/openvpn/block_dns.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-block_dns.o -MD -MP -MF $(DEPDIR)/openvpnserv-block_dns.Tpo -c -o openvpnserv-block_dns.o `test -f '$(top_srcdir)/src/openvpn/block_dns.c' || echo '$(srcdir)/'`$(top_srcdir)/src/openvpn/block_dns.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-block_dns.Tpo $(DEPDIR)/openvpnserv-block_dns.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/src/openvpn/block_dns.c' object='openvpnserv-block_dns.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-block_dns.o `test -f '$(top_srcdir)/src/openvpn/block_dns.c' || echo '$(srcdir)/'`$(top_srcdir)/src/openvpn/block_dns.c
+
+openvpnserv-block_dns.obj: $(top_srcdir)/src/openvpn/block_dns.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -MT openvpnserv-block_dns.obj -MD -MP -MF $(DEPDIR)/openvpnserv-block_dns.Tpo -c -o openvpnserv-block_dns.obj `if test -f '$(top_srcdir)/src/openvpn/block_dns.c'; then $(CYGPATH_W) '$(top_srcdir)/src/openvpn/block_dns.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/openvpn/block_dns.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/openvpnserv-block_dns.Tpo $(DEPDIR)/openvpnserv-block_dns.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/src/openvpn/block_dns.c' object='openvpnserv-block_dns.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(openvpnserv_CFLAGS) $(CFLAGS) -c -o openvpnserv-block_dns.obj `if test -f '$(top_srcdir)/src/openvpn/block_dns.c'; then $(CYGPATH_W) '$(top_srcdir)/src/openvpn/block_dns.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/openvpn/block_dns.c'; fi`
+
mostlyclean-libtool:
-rm -f *.lo
@@ -708,8 +817,6 @@ uninstall-am: uninstall-sbinPROGRAMS
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS
-.PRECIOUS: Makefile
-
.rc.lo:
$(LTRCCOMPILE) -i "$<" -o "$@"
diff --git a/src/openvpnserv/automatic.c b/src/openvpnserv/automatic.c
new file mode 100644
index 0000000..aa7618f
--- /dev/null
+++ b/src/openvpnserv/automatic.c
@@ -0,0 +1,415 @@
+/*
+ * 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-2010 OpenVPN Technologies, Inc. <sales@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
+ */
+
+/*
+ * This program allows one or more OpenVPN processes to be started
+ * as a service. To build, you must get the service sample from the
+ * Platform SDK and replace Simple.c with this file.
+ *
+ * You should also apply service.patch to
+ * service.c and service.h from the Platform SDK service sample.
+ *
+ * This code is designed to be built with the mingw compiler.
+ */
+
+#include "service.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <process.h>
+
+/* bool definitions */
+#define bool int
+#define true 1
+#define false 0
+
+static SERVICE_STATUS_HANDLE service;
+static SERVICE_STATUS status;
+
+openvpn_service_t automatic_service = {
+ automatic,
+ TEXT(PACKAGE_NAME "ServiceLegacy"),
+ TEXT(PACKAGE_NAME " Legacy Service"),
+ TEXT(SERVICE_DEPENDENCIES),
+ SERVICE_DEMAND_START
+};
+
+struct security_attributes
+{
+ SECURITY_ATTRIBUTES sa;
+ SECURITY_DESCRIPTOR sd;
+};
+
+/*
+ * Which registry key in HKLM should
+ * we get config info from?
+ */
+#define REG_KEY "SOFTWARE\\" PACKAGE_NAME
+
+static HANDLE exit_event = NULL;
+
+/* clear an object */
+#define CLEAR(x) memset(&(x), 0, sizeof(x))
+
+
+bool
+init_security_attributes_allow_all (struct security_attributes *obj)
+{
+ CLEAR (*obj);
+
+ obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES);
+ obj->sa.lpSecurityDescriptor = &obj->sd;
+ obj->sa.bInheritHandle = TRUE;
+ if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION))
+ return false;
+ if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE))
+ return false;
+ return true;
+}
+
+/*
+ * This event is initially created in the non-signaled
+ * state. It will transition to the signaled state when
+ * we have received a terminate signal from the Service
+ * Control Manager which will cause an asynchronous call
+ * of ServiceStop below.
+ */
+#define EXIT_EVENT_NAME TEXT(PACKAGE "_exit_1")
+
+HANDLE
+create_event (LPCTSTR name, bool allow_all, bool initial_state, bool manual_reset)
+{
+ if (allow_all)
+ {
+ struct security_attributes sa;
+ if (!init_security_attributes_allow_all (&sa))
+ return NULL;
+ return CreateEvent (&sa.sa, (BOOL)manual_reset, (BOOL)initial_state, name);
+ }
+ else
+ return CreateEvent (NULL, (BOOL)manual_reset, (BOOL)initial_state, name);
+}
+
+void
+close_if_open (HANDLE h)
+{
+ if (h != NULL)
+ CloseHandle (h);
+}
+
+static bool
+match (const WIN32_FIND_DATA *find, LPCTSTR ext)
+{
+ int i;
+
+ if (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ return false;
+
+ if (!_tcslen (ext))
+ return true;
+
+ i = _tcslen (find->cFileName) - _tcslen (ext) - 1;
+ if (i < 1)
+ return false;
+
+ return find->cFileName[i] == '.' && !_tcsicmp (find->cFileName + i + 1, ext);
+}
+
+/*
+ * Modify the extension on a filename.
+ */
+static bool
+modext (LPTSTR dest, int size, LPCTSTR src, LPCTSTR newext)
+{
+ int i;
+
+ if (size > 0 && (_tcslen (src) + 1) <= size)
+ {
+ _tcscpy (dest, src);
+ dest [size - 1] = TEXT('\0');
+ i = _tcslen (dest);
+ while (--i >= 0)
+ {
+ if (dest[i] == TEXT('\\'))
+ break;
+ if (dest[i] == TEXT('.'))
+ {
+ dest[i] = TEXT('\0');
+ break;
+ }
+ }
+ if (_tcslen (dest) + _tcslen(newext) + 2 <= size)
+ {
+ _tcscat (dest, TEXT("."));
+ _tcscat (dest, newext);
+ return true;
+ }
+ dest[0] = TEXT('\0');
+ }
+ return false;
+}
+
+static DWORD WINAPI
+ServiceCtrlAutomatic (DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
+{
+ SERVICE_STATUS *status = ctx;
+ switch (ctrl_code)
+ {
+ case SERVICE_CONTROL_STOP:
+ status->dwCurrentState = SERVICE_STOP_PENDING;
+ ReportStatusToSCMgr (service, status);
+ if (exit_event)
+ SetEvent (exit_event);
+ return NO_ERROR;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ return NO_ERROR;
+
+ default:
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+}
+
+
+VOID WINAPI
+ServiceStartAutomatic (DWORD dwArgc, LPTSTR *lpszArgv)
+{
+ DWORD error = NO_ERROR;
+ settings_t settings;
+
+ service = RegisterServiceCtrlHandlerEx (automatic_service.name, ServiceCtrlAutomatic, &status);
+ if (!service)
+ return;
+
+ status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
+ status.dwCurrentState = SERVICE_START_PENDING;
+ status.dwServiceSpecificExitCode = NO_ERROR;
+ status.dwWin32ExitCode = NO_ERROR;
+ status.dwWaitHint = 3000;
+
+ if (!ReportStatusToSCMgr(service, &status))
+ {
+ MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr #1 failed"));
+ goto finish;
+ }
+
+ /*
+ * Create our exit event
+ */
+ exit_event = create_event (EXIT_EVENT_NAME, false, false, true);
+ if (!exit_event)
+ {
+ MsgToEventLog (M_ERR, TEXT("CreateEvent failed"));
+ goto finish;
+ }
+
+ /*
+ * If exit event is already signaled, it means we were not
+ * shut down properly.
+ */
+ if (WaitForSingleObject (exit_event, 0) != WAIT_TIMEOUT)
+ {
+ MsgToEventLog (M_ERR, TEXT("Exit event is already signaled -- we were not shut down properly"));
+ goto finish;
+ }
+
+ if (!ReportStatusToSCMgr(service, &status))
+ {
+ MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr #2 failed"));
+ goto finish;
+ }
+
+ /*
+ * Read info from registry in key HKLM\SOFTWARE\OpenVPN
+ */
+ error = GetOpenvpnSettings (&settings);
+ if (error != ERROR_SUCCESS)
+ goto finish;
+
+ /*
+ * Instantiate an OpenVPN process for each configuration
+ * file found.
+ */
+ {
+ WIN32_FIND_DATA find_obj;
+ HANDLE find_handle;
+ BOOL more_files;
+ TCHAR find_string[MAX_PATH];
+
+ openvpn_sntprintf (find_string, MAX_PATH, TEXT("%s\\*"), settings.config_dir);
+
+ find_handle = FindFirstFile (find_string, &find_obj);
+ if (find_handle == INVALID_HANDLE_VALUE)
+ {
+ MsgToEventLog (M_ERR, TEXT("Cannot get configuration file list using: %s"), find_string);
+ goto finish;
+ }
+
+ /*
+ * Loop over each config file
+ */
+ do {
+ HANDLE log_handle = NULL;
+ STARTUPINFO start_info;
+ PROCESS_INFORMATION proc_info;
+ struct security_attributes sa;
+ TCHAR log_file[MAX_PATH];
+ TCHAR log_path[MAX_PATH];
+ TCHAR command_line[256];
+
+ CLEAR (start_info);
+ CLEAR (proc_info);
+ CLEAR (sa);
+
+ if (!ReportStatusToSCMgr(service, &status))
+ {
+ MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr #3 failed"));
+ FindClose (find_handle);
+ goto finish;
+ }
+
+ /* does file have the correct type and extension? */
+ if (match (&find_obj, settings.ext_string))
+ {
+ /* get log file pathname */
+ if (!modext (log_file, _countof (log_file), find_obj.cFileName, TEXT("log")))
+ {
+ MsgToEventLog (M_ERR, TEXT("Cannot construct logfile name based on: %s"), find_obj.cFileName);
+ FindClose (find_handle);
+ goto finish;
+ }
+ openvpn_sntprintf (log_path, _countof (log_path),
+ TEXT("%s\\%s"), settings.log_dir, log_file);
+
+ /* construct command line */
+ openvpn_sntprintf (command_line, _countof (command_line), TEXT(PACKAGE " --service %s 1 --config \"%s\""),
+ EXIT_EVENT_NAME,
+ find_obj.cFileName);
+
+ /* Make security attributes struct for logfile handle so it can
+ be inherited. */
+ if (!init_security_attributes_allow_all (&sa))
+ {
+ error = MsgToEventLog (M_SYSERR, TEXT("InitializeSecurityDescriptor start_" PACKAGE " failed"));
+ goto finish;
+ }
+
+ /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */
+ log_handle = CreateFile (log_path,
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ &sa.sa,
+ settings.append ? OPEN_ALWAYS : CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (log_handle == INVALID_HANDLE_VALUE)
+ {
+ error = MsgToEventLog (M_SYSERR, TEXT("Cannot open logfile: %s"), log_path);
+ FindClose (find_handle);
+ goto finish;
+ }
+
+ /* append to logfile? */
+ if (settings.append)
+ {
+ if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
+ {
+ error = MsgToEventLog (M_SYSERR, TEXT("Cannot seek to end of logfile: %s"), log_path);
+ FindClose (find_handle);
+ goto finish;
+ }
+ }
+
+ /* fill in STARTUPINFO struct */
+ GetStartupInfo(&start_info);
+ start_info.cb = sizeof(start_info);
+ start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ start_info.wShowWindow = SW_HIDE;
+ start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ start_info.hStdOutput = start_info.hStdError = log_handle;
+
+ /* create an OpenVPN process for one config file */
+ if (!CreateProcess(settings.exe_path,
+ command_line,
+ NULL,
+ NULL,
+ TRUE,
+ settings.priority | CREATE_NEW_CONSOLE,
+ NULL,
+ settings.config_dir,
+ &start_info,
+ &proc_info))
+ {
+ error = MsgToEventLog (M_SYSERR, TEXT("CreateProcess failed, exe='%s' cmdline='%s' dir='%s'"),
+ settings.exe_path,
+ command_line,
+ settings.config_dir);
+
+ FindClose (find_handle);
+ CloseHandle (log_handle);
+ goto finish;
+ }
+
+ /* close unneeded handles */
+ Sleep (1000); /* try to prevent race if we close logfile
+ handle before child process DUPs it */
+ if (!CloseHandle (proc_info.hProcess)
+ || !CloseHandle (proc_info.hThread)
+ || !CloseHandle (log_handle))
+ {
+ error = MsgToEventLog (M_SYSERR, TEXT("CloseHandle failed"));
+ goto finish;
+ }
+ }
+
+ /* more files to process? */
+ more_files = FindNextFile (find_handle, &find_obj);
+
+ } while (more_files);
+
+ FindClose (find_handle);
+ }
+
+ /* we are now fully started */
+ status.dwCurrentState = SERVICE_RUNNING;
+ status.dwWaitHint = 0;
+ if (!ReportStatusToSCMgr(service, &status))
+ {
+ MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr SERVICE_RUNNING failed"));
+ goto finish;
+ }
+
+ /* wait for our shutdown signal */
+ if (WaitForSingleObject (exit_event, INFINITE) != WAIT_OBJECT_0)
+ MsgToEventLog (M_ERR, TEXT("wait for shutdown signal failed"));
+
+finish:
+ if (exit_event)
+ CloseHandle (exit_event);
+
+ status.dwCurrentState = SERVICE_STOPPED;
+ status.dwWin32ExitCode = error;
+ ReportStatusToSCMgr (service, &status);
+}
diff --git a/src/openvpnserv/common.c b/src/openvpnserv/common.c
new file mode 100644
index 0000000..dba4724
--- /dev/null
+++ b/src/openvpnserv/common.c
@@ -0,0 +1,218 @@
+/*
+ * 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) 2011 Heiko Hund <heiko.hund@sophos.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <service.h>
+#include <validate.h>
+/*
+ * These are necessary due to certain buggy implementations of (v)snprintf,
+ * that don't guarantee null termination for size > 0.
+ */
+int
+openvpn_vsntprintf (LPTSTR str, size_t size, LPCTSTR format, va_list arglist)
+{
+ int len = -1;
+ if (size > 0)
+ {
+ len = _vsntprintf (str, size, format, arglist);
+ str[size - 1] = 0;
+ }
+ return (len >= 0 && len < size);
+}
+int
+openvpn_sntprintf (LPTSTR str, size_t size, LPCTSTR format, ...)
+{
+ va_list arglist;
+ int len = -1;
+ if (size > 0)
+ {
+ va_start (arglist, format);
+ len = openvpn_vsntprintf (str, size, format, arglist);
+ va_end (arglist);
+ }
+ return len;
+}
+
+#define REG_KEY TEXT("SOFTWARE\\" PACKAGE_NAME)
+
+static DWORD
+GetRegString (HKEY key, LPCTSTR value, LPTSTR data, DWORD size)
+{
+ DWORD type;
+ LONG status = RegQueryValueEx (key, value, NULL, &type, (LPBYTE) data, &size);
+
+ if (status == ERROR_SUCCESS && type != REG_SZ)
+ status = ERROR_DATATYPE_MISMATCH;
+
+ if (status != ERROR_SUCCESS)
+ {
+ SetLastError (status);
+ return MsgToEventLog (M_SYSERR, TEXT("Error querying registry value: HKLM\\%s\\%s"), REG_KEY, value);
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+DWORD
+GetOpenvpnSettings (settings_t *s)
+{
+ TCHAR priority[64];
+ TCHAR append[2];
+ DWORD error;
+ HKEY key;
+
+ LONG status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_KEY, 0, KEY_READ, &key);
+ if (status != ERROR_SUCCESS)
+ {
+ SetLastError (status);
+ return MsgToEventLog (M_SYSERR, TEXT("Could not open Registry key HKLM\\%s not found"), REG_KEY);
+ }
+
+ error = GetRegString (key, TEXT("exe_path"), s->exe_path, sizeof (s->exe_path));
+ if (error != ERROR_SUCCESS)
+ goto out;
+
+ error = GetRegString (key, TEXT("config_dir"), s->config_dir, sizeof (s->config_dir));
+ if (error != ERROR_SUCCESS)
+ goto out;
+
+ error = GetRegString (key, TEXT("config_ext"), s->ext_string, sizeof (s->ext_string));
+ if (error != ERROR_SUCCESS)
+ goto out;
+
+ error = GetRegString (key, TEXT("log_dir"), s->log_dir, sizeof (s->log_dir));
+ if (error != ERROR_SUCCESS)
+ goto out;
+
+ error = GetRegString (key, TEXT("priority"), priority, sizeof (priority));
+ if (error != ERROR_SUCCESS)
+ goto out;
+
+ error = GetRegString (key, TEXT("log_append"), append, sizeof (append));
+ if (error != ERROR_SUCCESS)
+ goto out;
+
+ /* read if present, else use default */
+ error = GetRegString (key, TEXT("ovpn_admin_group"), s->ovpn_admin_group, sizeof (s->ovpn_admin_group));
+ if (error != ERROR_SUCCESS)
+ {
+ openvpn_sntprintf(s->ovpn_admin_group, _countof(s->ovpn_admin_group), OVPN_ADMIN_GROUP);
+ error = 0; /* this error is not fatal */
+ }
+ /* set process priority */
+ if (!_tcsicmp (priority, TEXT("IDLE_PRIORITY_CLASS")))
+ s->priority = IDLE_PRIORITY_CLASS;
+ else if (!_tcsicmp (priority, TEXT("BELOW_NORMAL_PRIORITY_CLASS")))
+ s->priority = BELOW_NORMAL_PRIORITY_CLASS;
+ else if (!_tcsicmp (priority, TEXT("NORMAL_PRIORITY_CLASS")))
+ s->priority = NORMAL_PRIORITY_CLASS;
+ else if (!_tcsicmp (priority, TEXT("ABOVE_NORMAL_PRIORITY_CLASS")))
+ s->priority = ABOVE_NORMAL_PRIORITY_CLASS;
+ else if (!_tcsicmp (priority, TEXT("HIGH_PRIORITY_CLASS")))
+ s->priority = HIGH_PRIORITY_CLASS;
+ else
+ {
+ SetLastError (ERROR_INVALID_DATA);
+ error = MsgToEventLog (M_SYSERR, TEXT("Unknown priority name: %s"), priority);
+ goto out;
+ }
+
+ /* set log file append/truncate flag */
+ if (append[0] == TEXT('0'))
+ s->append = FALSE;
+ else if (append[0] == TEXT('1'))
+ s->append = TRUE;
+ else
+ {
+ SetLastError (ERROR_INVALID_DATA);
+ error = MsgToEventLog (M_ERR, TEXT("Log file append flag (given as '%s') must be '0' or '1'"), append);
+ goto out;
+ }
+
+out:
+ RegCloseKey (key);
+ return error;
+}
+
+
+LPCTSTR
+GetLastErrorText ()
+{
+ static TCHAR buf[256];
+ DWORD len;
+ LPTSTR tmp = NULL;
+
+ len = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&tmp, 0, NULL);
+
+ if (len == 0 || (long) _countof (buf) < (long) len + 14)
+ buf[0] = TEXT('\0');
+ else
+ {
+ tmp[_tcslen (tmp) - 2] = TEXT('\0'); /* remove CR/LF characters */
+ openvpn_sntprintf (buf, _countof (buf), TEXT("%s (0x%x)"), tmp, GetLastError());
+ }
+
+ if (tmp)
+ LocalFree (tmp);
+
+ return buf;
+}
+
+
+DWORD
+MsgToEventLog (DWORD flags, LPCTSTR format, ...)
+{
+ HANDLE hEventSource;
+ TCHAR msg[2][256];
+ DWORD error = 0;
+ LPCTSTR err_msg = TEXT("");
+ va_list arglist;
+
+ if (flags & MSG_FLAGS_SYS_CODE)
+ {
+ error = GetLastError ();
+ err_msg = GetLastErrorText ();
+ }
+
+ hEventSource = RegisterEventSource (NULL, APPNAME);
+ if (hEventSource != NULL)
+ {
+ openvpn_sntprintf (msg[0], _countof (msg[0]),
+ TEXT("%s%s: %s"), APPNAME,
+ (flags & MSG_FLAGS_ERROR) ? TEXT(" error") : TEXT(""), err_msg);
+
+ va_start (arglist, format);
+ openvpn_vsntprintf (msg[1], _countof (msg[1]), format, arglist);
+ va_end (arglist);
+
+ const TCHAR *mesg[] = { msg[0], msg[1] };
+ ReportEvent (hEventSource, flags & MSG_FLAGS_ERROR ?
+ EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
+ 0, 0, NULL, 2, 0, mesg, NULL);
+ DeregisterEventSource (hEventSource);
+ }
+
+ return error;
+}
diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c
new file mode 100644
index 0000000..ffaa171
--- /dev/null
+++ b/src/openvpnserv/interactive.c
@@ -0,0 +1,1652 @@
+/*
+ * 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) 2012 Heiko Hund <heiko.hund@sophos.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "service.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <iphlpapi.h>
+#include <userenv.h>
+#include <accctrl.h>
+#include <aclapi.h>
+#include <stdio.h>
+#include <sddl.h>
+#include <shellapi.h>
+
+#include "openvpn-msg.h"
+#include "validate.h"
+#include "block_dns.h"
+
+#define IO_TIMEOUT 2000 /*ms*/
+
+#define ERROR_OPENVPN_STARTUP 0x20000000
+#define ERROR_STARTUP_DATA 0x20000001
+#define ERROR_MESSAGE_DATA 0x20000002
+#define ERROR_MESSAGE_TYPE 0x20000003
+
+static SERVICE_STATUS_HANDLE service;
+static SERVICE_STATUS status;
+static HANDLE exit_event = NULL;
+static settings_t settings;
+static HANDLE rdns_semaphore = NULL;
+#define RDNS_TIMEOUT 600 /* seconds to wait for the semaphore */
+
+
+openvpn_service_t interactive_service = {
+ interactive,
+ TEXT(PACKAGE_NAME "ServiceInteractive"),
+ TEXT(PACKAGE_NAME " Interactive Service"),
+ TEXT(SERVICE_DEPENDENCIES),
+ SERVICE_AUTO_START
+};
+
+
+typedef struct {
+ WCHAR *directory;
+ WCHAR *options;
+ WCHAR *std_input;
+} STARTUP_DATA;
+
+
+/* Datatype for linked lists */
+typedef struct _list_item {
+ struct _list_item *next;
+ LPVOID data;
+} list_item_t;
+
+
+/* Datatypes for undo information */
+typedef enum {
+ address,
+ route,
+ block_dns,
+ _undo_type_max
+} undo_type_t;
+typedef list_item_t* undo_lists_t[_undo_type_max];
+
+
+static DWORD
+AddListItem (list_item_t **pfirst, LPVOID data)
+{
+ list_item_t *new_item = malloc (sizeof (list_item_t));
+ if (new_item == NULL)
+ return ERROR_OUTOFMEMORY;
+
+ new_item->next = *pfirst;
+ new_item->data = data;
+
+ *pfirst = new_item;
+ return NO_ERROR;
+}
+
+typedef BOOL (*match_fn_t) (LPVOID item, LPVOID ctx);
+
+static LPVOID
+RemoveListItem (list_item_t **pfirst, match_fn_t match, LPVOID ctx)
+{
+ LPVOID data = NULL;
+ list_item_t **pnext;
+
+ for (pnext = pfirst; *pnext; pnext = &(*pnext)->next)
+ {
+ list_item_t *item = *pnext;
+ if (!match (item->data, ctx))
+ continue;
+
+ /* Found item, remove from the list and free memory */
+ *pnext = item->next;
+ data = item->data;
+ free (item);
+ break;
+ }
+ return data;
+}
+
+
+static HANDLE
+CloseHandleEx (LPHANDLE handle)
+{
+ if (handle && *handle && *handle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle (*handle);
+ *handle = INVALID_HANDLE_VALUE;
+ }
+ return INVALID_HANDLE_VALUE;
+}
+
+
+static HANDLE
+InitOverlapped (LPOVERLAPPED overlapped)
+{
+ ZeroMemory (overlapped, sizeof (OVERLAPPED));
+ overlapped->hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+ return overlapped->hEvent;
+}
+
+
+static BOOL
+ResetOverlapped (LPOVERLAPPED overlapped)
+{
+ HANDLE io_event = overlapped->hEvent;
+ if (!ResetEvent (io_event))
+ return FALSE;
+ ZeroMemory (overlapped, sizeof (OVERLAPPED));
+ overlapped->hEvent = io_event;
+ return TRUE;
+}
+
+
+typedef enum {
+ peek,
+ read,
+ write
+} async_op_t;
+
+static DWORD
+AsyncPipeOp (async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
+{
+ int i;
+ BOOL success;
+ HANDLE io_event;
+ DWORD res, bytes = 0;
+ OVERLAPPED overlapped;
+ LPHANDLE handles = NULL;
+
+ io_event = InitOverlapped (&overlapped);
+ if (!io_event)
+ goto out;
+
+ handles = malloc ((count + 1) * sizeof (HANDLE));
+ if (!handles)
+ goto out;
+
+ if (op == write)
+ success = WriteFile (pipe, buffer, size, NULL, &overlapped);
+ else
+ success = ReadFile (pipe, buffer, size, NULL, &overlapped);
+ if (!success && GetLastError () != ERROR_IO_PENDING && GetLastError () != ERROR_MORE_DATA)
+ goto out;
+
+ handles[0] = io_event;
+ for (i = 0; i < count; i++)
+ handles[i + 1] = events[i];
+
+ res = WaitForMultipleObjects (count + 1, handles, FALSE,
+ op == peek ? INFINITE : IO_TIMEOUT);
+ if (res != WAIT_OBJECT_0)
+ {
+ CancelIo (pipe);
+ goto out;
+ }
+
+ if (op == peek)
+ PeekNamedPipe (pipe, NULL, 0, NULL, &bytes, NULL);
+ else
+ GetOverlappedResult (pipe, &overlapped, &bytes, TRUE);
+
+out:
+ CloseHandleEx (&io_event);
+ free (handles);
+ return bytes;
+}
+
+static DWORD
+PeekNamedPipeAsync (HANDLE pipe, DWORD count, LPHANDLE events)
+{
+ return AsyncPipeOp (peek, pipe, NULL, 0, count, events);
+}
+
+static DWORD
+ReadPipeAsync (HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events)
+{
+ return AsyncPipeOp (read, pipe, buffer, size, count, events);
+}
+
+static DWORD
+WritePipeAsync (HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events)
+{
+ return AsyncPipeOp (write, pipe, data, size, count, events);
+}
+
+static VOID
+ReturnProcessId (HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events)
+{
+ const WCHAR msg[] = L"Process ID";
+ WCHAR buf[22 + _countof(msg)]; /* 10 chars each for error and PID and 2 for line breaks */
+
+ /*
+ * Same format as error messages (3 line string) with error = 0 in
+ * 0x%08x format, PID on line 2 and a description "Process ID" on line 3
+ */
+ _snwprintf (buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg);
+ buf[_countof(buf) - 1] = '\0';
+
+ WritePipeAsync (pipe, buf, wcslen (buf) * 2, count, events);
+}
+
+static VOID
+ReturnError (HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events)
+{
+ DWORD result_len;
+ LPWSTR result = L"0xffffffff\nFormatMessage failed\nCould not return result";
+ DWORD_PTR args[] = {
+ (DWORD_PTR) error,
+ (DWORD_PTR) func,
+ (DWORD_PTR) ""
+ };
+
+ if (error != ERROR_OPENVPN_STARTUP)
+ {
+ FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ 0, error, 0, (LPWSTR) &args[2], 0, NULL);
+ }
+
+ result_len = FormatMessageW (FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ L"0x%1!08x!\n%2!s!\n%3!s!", 0, 0,
+ (LPWSTR) &result, 0, (va_list*) args);
+
+ WritePipeAsync (pipe, result, wcslen (result) * 2, count, events);
+#ifdef UNICODE
+ MsgToEventLog (MSG_FLAGS_ERROR, result);
+#else
+ MsgToEventLog (MSG_FLAGS_ERROR, "%S", result);
+#endif
+
+ if (error != ERROR_OPENVPN_STARTUP)
+ LocalFree ((LPVOID) args[2]);
+ if (result_len)
+ LocalFree (result);
+}
+
+
+static VOID
+ReturnLastError (HANDLE pipe, LPCWSTR func)
+{
+ ReturnError (pipe, GetLastError (), func, 1, &exit_event);
+}
+
+
+static VOID
+ReturnOpenvpnOutput (HANDLE pipe, HANDLE ovpn_output, DWORD count, LPHANDLE events)
+{
+ WCHAR *wide_output = NULL;
+ CHAR output[512];
+ DWORD size;
+
+ ReadFile (ovpn_output, output, sizeof (output), &size, NULL);
+ if (size == 0)
+ return;
+
+ wide_output = malloc ((size) * sizeof (WCHAR));
+ if (wide_output)
+ {
+ MultiByteToWideChar (CP_UTF8, 0, output, size, wide_output, size);
+ wide_output[size - 1] = 0;
+ }
+
+ ReturnError (pipe, ERROR_OPENVPN_STARTUP, wide_output, count, events);
+ free (wide_output);
+}
+
+/*
+ * Validate options against a white list. Also check the config_file is
+ * inside the config_dir. The white list is defined in validate.c
+ * Returns true on success
+ */
+static BOOL
+ValidateOptions (HANDLE pipe, const WCHAR *workdir, const WCHAR *options)
+{
+ WCHAR **argv;
+ int argc;
+ WCHAR buf[256];
+ BOOL ret = FALSE;
+ int i;
+ const WCHAR *msg1 = L"You have specified a config file location (%s relative to %s)"
+ " that requires admin approval. This error may be avoided"
+ " by adding your account to the \"%s\" group";
+
+ const WCHAR *msg2 = L"You have specified an option (%s) that may be used"
+ " only with admin approval. This error may be avoided"
+ " by adding your account to the \"%s\" group";
+
+ argv = CommandLineToArgvW (options, &argc);
+
+ if (!argv)
+ {
+ ReturnLastError (pipe, L"CommandLineToArgvW");
+ ReturnError (pipe, ERROR_STARTUP_DATA, L"Cannot validate options", 1, &exit_event);
+ goto out;
+ }
+
+ /* Note: argv[0] is the first option */
+ if (argc < 1) /* no options */
+ {
+ ret = TRUE;
+ goto out;
+ }
+
+ /*
+ * If only one argument, it is the config file
+ */
+ if (argc == 1)
+ {
+ WCHAR *argv_tmp[2] = { L"--config", argv[0] };
+
+ if (!CheckOption (workdir, 2, argv_tmp, &settings))
+ {
+ snwprintf (buf, _countof(buf), msg1, argv[0], workdir,
+ settings.ovpn_admin_group);
+ buf[_countof(buf) - 1] = L'\0';
+ ReturnError (pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event);
+ }
+ goto out;
+ }
+
+ for (i = 0; i < argc; ++i)
+ {
+ if (!IsOption(argv[i]))
+ continue;
+
+ if (!CheckOption (workdir, argc-i, &argv[i], &settings))
+ {
+ if (wcscmp(L"--config", argv[i]) == 0 && argc-i > 1)
+ {
+ snwprintf (buf, _countof(buf), msg1, argv[i+1], workdir,
+ settings.ovpn_admin_group);
+ buf[_countof(buf) - 1] = L'\0';
+ ReturnError (pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event);
+ }
+ else
+ {
+ snwprintf (buf, _countof(buf), msg2, argv[i],
+ settings.ovpn_admin_group);
+ buf[_countof(buf) - 1] = L'\0';
+ ReturnError (pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event);
+ }
+ goto out;
+ }
+ }
+
+ /* all options passed */
+ ret = TRUE;
+
+out:
+ if (argv)
+ LocalFree (argv);
+ return ret;
+}
+
+static BOOL
+GetStartupData (HANDLE pipe, STARTUP_DATA *sud)
+{
+ size_t len;
+ BOOL ret = FALSE;
+ WCHAR *data = NULL;
+ DWORD size, bytes, read;
+
+ bytes = PeekNamedPipeAsync (pipe, 1, &exit_event);
+ if (bytes == 0)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("PeekNamedPipeAsync failed"));
+ ReturnLastError (pipe, L"PeekNamedPipeAsync");
+ goto out;
+ }
+
+ size = bytes / sizeof (*data);
+ data = malloc (bytes);
+ if (data == NULL)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("malloc failed"));
+ ReturnLastError (pipe, L"malloc");
+ goto out;
+ }
+
+ read = ReadPipeAsync (pipe, data, bytes, 1, &exit_event);
+ if (bytes != read)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("ReadPipeAsync failed"));
+ ReturnLastError (pipe, L"ReadPipeAsync");
+ goto out;
+ }
+
+ if (data[size - 1] != 0)
+ {
+ MsgToEventLog (M_ERR, TEXT("Startup data is not NULL terminated"));
+ ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
+ goto out;
+ }
+
+ sud->directory = data;
+ len = wcslen (sud->directory) + 1;
+ size -= len;
+ if (size <= 0)
+ {
+ MsgToEventLog (M_ERR, TEXT("Startup data ends at working directory"));
+ ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
+ goto out;
+ }
+
+ sud->options = sud->directory + len;
+ len = wcslen (sud->options) + 1;
+ size -= len;
+ if (size <= 0)
+ {
+ MsgToEventLog (M_ERR, TEXT("Startup data ends at command line options"));
+ ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event);
+ goto out;
+ }
+
+ sud->std_input = sud->options + len;
+ data = NULL; /* don't free data */
+ ret = TRUE;
+
+out:
+ free (data);
+ return ret;
+}
+
+
+static VOID
+FreeStartupData (STARTUP_DATA *sud)
+{
+ free (sud->directory);
+}
+
+
+static SOCKADDR_INET
+sockaddr_inet (short family, inet_address_t *addr)
+{
+ SOCKADDR_INET sa_inet;
+ ZeroMemory (&sa_inet, sizeof (sa_inet));
+ sa_inet.si_family = family;
+ if (family == AF_INET)
+ sa_inet.Ipv4.sin_addr = addr->ipv4;
+ else if (family == AF_INET6)
+ sa_inet.Ipv6.sin6_addr = addr->ipv6;
+ return sa_inet;
+}
+
+static DWORD
+InterfaceLuid (const char *iface_name, PNET_LUID luid)
+{
+ NETIO_STATUS status;
+ LPWSTR wide_name;
+ int n;
+
+ typedef NETIO_STATUS WINAPI (*ConvertInterfaceAliasToLuidFn) (LPCWSTR, PNET_LUID);
+ static ConvertInterfaceAliasToLuidFn ConvertInterfaceAliasToLuid = NULL;
+ if (!ConvertInterfaceAliasToLuid)
+ {
+ HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll"));
+ if (iphlpapi == NULL)
+ return GetLastError ();
+
+ ConvertInterfaceAliasToLuid = (ConvertInterfaceAliasToLuidFn) GetProcAddress (iphlpapi, "ConvertInterfaceAliasToLuid");
+ if (!ConvertInterfaceAliasToLuid)
+ return GetLastError ();
+ }
+
+ n = MultiByteToWideChar (CP_UTF8, 0, iface_name, -1, NULL, 0);
+ wide_name = malloc (n * sizeof (WCHAR));
+ MultiByteToWideChar (CP_UTF8, 0, iface_name, -1, wide_name, n);
+ status = ConvertInterfaceAliasToLuid (wide_name, luid);
+ free (wide_name);
+
+ return status;
+}
+
+static BOOL
+CmpAddress (LPVOID item, LPVOID address)
+{
+ return memcmp (item, address, sizeof (MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE;
+}
+
+static DWORD
+DeleteAddress (PMIB_UNICASTIPADDRESS_ROW addr_row)
+{
+ typedef NETIOAPI_API (*DeleteUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW);
+ static DeleteUnicastIpAddressEntryFn DeleteUnicastIpAddressEntry = NULL;
+
+ if (!DeleteUnicastIpAddressEntry)
+ {
+ HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll"));
+ if (iphlpapi == NULL)
+ return GetLastError ();
+
+ DeleteUnicastIpAddressEntry = (DeleteUnicastIpAddressEntryFn) GetProcAddress (iphlpapi, "DeleteUnicastIpAddressEntry");
+ if (!DeleteUnicastIpAddressEntry)
+ return GetLastError ();
+ }
+
+ return DeleteUnicastIpAddressEntry (addr_row);
+}
+
+static DWORD
+HandleAddressMessage (address_message_t *msg, undo_lists_t *lists)
+{
+ DWORD err;
+ PMIB_UNICASTIPADDRESS_ROW addr_row;
+ BOOL add = msg->header.type == msg_add_address;
+
+ typedef NETIOAPI_API (*CreateUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW);
+ typedef NETIOAPI_API (*InitializeUnicastIpAddressEntryFn) (PMIB_UNICASTIPADDRESS_ROW);
+ static CreateUnicastIpAddressEntryFn CreateUnicastIpAddressEntry = NULL;
+ static InitializeUnicastIpAddressEntryFn InitializeUnicastIpAddressEntry = NULL;
+
+ if (!CreateUnicastIpAddressEntry || !InitializeUnicastIpAddressEntry)
+ {
+ HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll"));
+ if (iphlpapi == NULL)
+ return GetLastError ();
+
+ CreateUnicastIpAddressEntry = (CreateUnicastIpAddressEntryFn) GetProcAddress (iphlpapi, "CreateUnicastIpAddressEntry");
+ if (!CreateUnicastIpAddressEntry)
+ return GetLastError ();
+
+ InitializeUnicastIpAddressEntry = (InitializeUnicastIpAddressEntryFn) GetProcAddress (iphlpapi, "InitializeUnicastIpAddressEntry");
+ if (!InitializeUnicastIpAddressEntry)
+ return GetLastError ();
+ }
+
+ addr_row = malloc (sizeof (*addr_row));
+ if (addr_row == NULL)
+ return ERROR_OUTOFMEMORY;
+
+ InitializeUnicastIpAddressEntry (addr_row);
+ addr_row->Address = sockaddr_inet (msg->family, &msg->address);
+ addr_row->OnLinkPrefixLength = (UINT8) msg->prefix_len;
+
+ if (msg->iface.index != -1)
+ {
+ addr_row->InterfaceIndex = msg->iface.index;
+ }
+ else
+ {
+ NET_LUID luid;
+ err = InterfaceLuid (msg->iface.name, &luid);
+ if (err)
+ goto out;
+ addr_row->InterfaceLuid = luid;
+ }
+
+ if (add)
+ {
+ err = CreateUnicastIpAddressEntry (addr_row);
+ if (err)
+ goto out;
+
+ err = AddListItem (&(*lists)[address], addr_row);
+ if (err)
+ DeleteAddress (addr_row);
+ }
+ else
+ {
+ err = DeleteAddress (addr_row);
+ if (err)
+ goto out;
+
+ free (RemoveListItem (&(*lists)[address], CmpAddress, addr_row));
+ }
+
+out:
+ if (!add || err)
+ free (addr_row);
+
+ return err;
+}
+
+static BOOL
+CmpRoute (LPVOID item, LPVOID route)
+{
+ return memcmp (item, route, sizeof (MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE;
+}
+
+static DWORD
+DeleteRoute (PMIB_IPFORWARD_ROW2 fwd_row)
+{
+ typedef NETIOAPI_API (*DeleteIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2);
+ static DeleteIpForwardEntry2Fn DeleteIpForwardEntry2 = NULL;
+
+ if (!DeleteIpForwardEntry2)
+ {
+ HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll"));
+ if (iphlpapi == NULL)
+ return GetLastError ();
+
+ DeleteIpForwardEntry2 = (DeleteIpForwardEntry2Fn) GetProcAddress (iphlpapi, "DeleteIpForwardEntry2");
+ if (!DeleteIpForwardEntry2)
+ return GetLastError ();
+ }
+
+ return DeleteIpForwardEntry2 (fwd_row);
+}
+
+static DWORD
+HandleRouteMessage (route_message_t *msg, undo_lists_t *lists)
+{
+ DWORD err;
+ PMIB_IPFORWARD_ROW2 fwd_row;
+ BOOL add = msg->header.type == msg_add_route;
+
+ typedef NETIOAPI_API (*CreateIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2);
+ static CreateIpForwardEntry2Fn CreateIpForwardEntry2 = NULL;
+
+ if (!CreateIpForwardEntry2)
+ {
+ HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll"));
+ if (iphlpapi == NULL)
+ return GetLastError ();
+
+ CreateIpForwardEntry2 = (CreateIpForwardEntry2Fn) GetProcAddress (iphlpapi, "CreateIpForwardEntry2");
+ if (!CreateIpForwardEntry2)
+ return GetLastError ();
+ }
+
+ fwd_row = malloc (sizeof (*fwd_row));
+ if (fwd_row == NULL)
+ return ERROR_OUTOFMEMORY;
+
+ ZeroMemory (fwd_row, sizeof (*fwd_row));
+ fwd_row->ValidLifetime = 0xffffffff;
+ fwd_row->PreferredLifetime = 0xffffffff;
+ fwd_row->Protocol = MIB_IPPROTO_NETMGMT;
+ fwd_row->Metric = msg->metric;
+ fwd_row->DestinationPrefix.Prefix = sockaddr_inet (msg->family, &msg->prefix);
+ fwd_row->DestinationPrefix.PrefixLength = (UINT8) msg->prefix_len;
+ fwd_row->NextHop = sockaddr_inet (msg->family, &msg->gateway);
+
+ if (msg->iface.index != -1)
+ {
+ fwd_row->InterfaceIndex = msg->iface.index;
+ }
+ else if (strlen (msg->iface.name))
+ {
+ NET_LUID luid;
+ err = InterfaceLuid (msg->iface.name, &luid);
+ if (err)
+ goto out;
+ fwd_row->InterfaceLuid = luid;
+ }
+
+ if (add)
+ {
+ err = CreateIpForwardEntry2 (fwd_row);
+ if (err)
+ goto out;
+
+ err = AddListItem (&(*lists)[route], fwd_row);
+ if (err)
+ DeleteRoute (fwd_row);
+ }
+ else
+ {
+ err = DeleteRoute (fwd_row);
+ if (err)
+ goto out;
+
+ free (RemoveListItem (&(*lists)[route], CmpRoute, fwd_row));
+ }
+
+out:
+ if (!add || err)
+ free (fwd_row);
+
+ return err;
+}
+
+
+static DWORD
+HandleFlushNeighborsMessage (flush_neighbors_message_t *msg)
+{
+ typedef NETIOAPI_API (*FlushIpNetTable2Fn) (ADDRESS_FAMILY, NET_IFINDEX);
+ static FlushIpNetTable2Fn flush_fn = NULL;
+
+ if (msg->family == AF_INET)
+ return FlushIpNetTable (msg->iface.index);
+
+ if (!flush_fn)
+ {
+ HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll"));
+ if (iphlpapi == NULL)
+ return GetLastError ();
+
+ flush_fn = (FlushIpNetTable2Fn) GetProcAddress (iphlpapi, "FlushIpNetTable2");
+ if (!flush_fn)
+ {
+ if (GetLastError () == ERROR_PROC_NOT_FOUND)
+ return WSAEPFNOSUPPORT;
+ else
+ return GetLastError ();
+ }
+ }
+ return flush_fn (msg->family, msg->iface.index);
+}
+
+static void
+BlockDNSErrHandler (DWORD err, const char *msg)
+{
+ TCHAR buf[256];
+ LPCTSTR err_str;
+
+ if (!err) return;
+
+ err_str = TEXT("Unknown Win32 Error");
+
+ if (FormatMessage (FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ NULL, err, 0, buf, sizeof (buf), NULL))
+ {
+ err_str = buf;
+ }
+
+#ifdef UNICODE
+ MsgToEventLog (M_ERR, L"%S (status = %lu): %s", msg, err, err_str);
+#else
+ MsgToEventLog (M_ERR, "%s (status = %lu): %s", msg, err, err_str);
+#endif
+
+}
+
+/* Use an always-true match_fn to get the head of the list */
+static BOOL
+CmpEngine (LPVOID item, LPVOID any)
+{
+ return TRUE;
+}
+
+static DWORD
+HandleBlockDNSMessage (const block_dns_message_t *msg, undo_lists_t *lists)
+{
+ DWORD err = 0;
+ HANDLE engine = NULL;
+ LPCWSTR exe_path;
+
+#ifdef UNICODE
+ exe_path = settings.exe_path;
+#else
+ WCHAR wide_path[MAX_PATH];
+ MultiByteToWideChar (CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH);
+ exe_path = wide_path;
+#endif
+
+ if (msg->header.type == msg_add_block_dns)
+ {
+ err = add_block_dns_filters (&engine, msg->iface.index, exe_path, BlockDNSErrHandler);
+ if (!err)
+ err = AddListItem (&(*lists)[block_dns], engine);
+ }
+ else
+ {
+ engine = RemoveListItem (&(*lists)[block_dns], CmpEngine, NULL);
+ if (engine)
+ {
+ err = delete_block_dns_filters (engine);
+ engine = NULL;
+ }
+ else
+ MsgToEventLog (M_ERR, TEXT("No previous block DNS filters to delete"));
+ }
+
+ if (err && engine)
+ {
+ delete_block_dns_filters (engine);
+ }
+
+ return err;
+}
+
+/*
+ * Execute a command and return its exit code. If timeout > 0, terminate
+ * the process if still running after timeout milliseconds. In that case
+ * the return value is the windows error code WAIT_TIMEOUT = 0x102
+ */
+static DWORD
+ExecCommand (const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout)
+{
+ DWORD exit_code;
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT;
+ WCHAR *cmdline_dup = NULL;
+
+ ZeroMemory (&si, sizeof(si));
+ ZeroMemory (&pi, sizeof(pi));
+
+ si.cb = sizeof(si);
+
+ /* CreateProcess needs a modifiable cmdline: make a copy */
+ cmdline_dup = wcsdup (cmdline);
+ if ( cmdline_dup && CreateProcessW (argv0, cmdline_dup, NULL, NULL, FALSE,
+ proc_flags, NULL, NULL, &si, &pi) )
+ {
+ WaitForSingleObject (pi.hProcess, timeout ? timeout : INFINITE);
+ if (!GetExitCodeProcess (pi.hProcess, &exit_code))
+ {
+ MsgToEventLog (M_SYSERR, TEXT("ExecCommand: Error getting exit_code:"));
+ exit_code = GetLastError();
+ }
+ else if (exit_code == STILL_ACTIVE)
+ {
+ exit_code = WAIT_TIMEOUT; /* Windows error code 0x102 */
+
+ /* kill without impunity */
+ TerminateProcess (pi.hProcess, exit_code);
+ MsgToEventLog (M_ERR, TEXT("ExecCommand: \"%s %s\" killed after timeout"),
+ argv0, cmdline);
+ }
+ else if (exit_code)
+ MsgToEventLog (M_ERR, TEXT("ExecCommand: \"%s %s\" exited with status = %lu"),
+ argv0, cmdline, exit_code);
+ else
+ MsgToEventLog (M_INFO, TEXT("ExecCommand: \"%s %s\" completed"), argv0, cmdline);
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ else
+ {
+ exit_code = GetLastError();
+ MsgToEventLog (M_SYSERR, TEXT("ExecCommand: could not run \"%s %s\" :"),
+ argv0, cmdline);
+ }
+
+ free (cmdline_dup);
+ return exit_code;
+}
+
+/*
+ * Entry point for register-dns thread.
+ */
+static DWORD WINAPI
+RegisterDNS (LPVOID unused)
+{
+ DWORD err;
+ DWORD i;
+ WCHAR sys_path[MAX_PATH];
+ DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */
+
+ /* default paths of net and ipconfig commands */
+ WCHAR net[MAX_PATH] = L"C:\\Windows\\system32\\net.exe";
+ WCHAR ipcfg[MAX_PATH] = L"C:\\Windows\\system32\\ipconfig.exe";
+
+ struct
+ {
+ WCHAR *argv0;
+ WCHAR *cmdline;
+ DWORD timeout;
+ } cmds [] = {
+ { net, L"net stop dnscache", timeout },
+ { net, L"net start dnscache", timeout },
+ { ipcfg, L"ipconfig /flushdns", timeout },
+ { ipcfg, L"ipconfig /registerdns", timeout },
+ };
+ int ncmds = sizeof (cmds) / sizeof (cmds[0]);
+
+ HANDLE wait_handles[2] = {rdns_semaphore, exit_event};
+
+ if(GetSystemDirectory(sys_path, MAX_PATH))
+ {
+ _snwprintf (net, MAX_PATH, L"%s\\%s", sys_path, L"net.exe");
+ net[MAX_PATH-1] = L'\0';
+
+ _snwprintf (ipcfg, MAX_PATH, L"%s\\%s", sys_path, L"ipconfig.exe");
+ ipcfg[MAX_PATH-1] = L'\0';
+ }
+
+ if (WaitForMultipleObjects (2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0)
+ {
+ /* Semaphore locked */
+ for (i = 0; i < ncmds; ++i)
+ {
+ ExecCommand (cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout);
+ }
+ err = 0;
+ if ( !ReleaseSemaphore (rdns_semaphore, 1, NULL) )
+ err = MsgToEventLog (M_SYSERR, TEXT("RegisterDNS: Failed to release regsiter-dns semaphore:"));
+ }
+ else
+ {
+ MsgToEventLog (M_ERR, TEXT("RegisterDNS: Failed to lock register-dns semaphore"));
+ err = ERROR_SEM_TIMEOUT; /* Windows error code 0x79 */
+ }
+ return err;
+}
+
+static DWORD
+HandleRegisterDNSMessage (void)
+{
+ DWORD err;
+ HANDLE thread = NULL;
+
+ /* Delegate this job to a sub-thread */
+ thread = CreateThread (NULL, 0, RegisterDNS, NULL, 0, NULL);
+
+ /*
+ * We don't add these thread handles to the undo list -- the thread and
+ * processes it spawns are all supposed to terminate or timeout by themselves.
+ */
+ if (thread)
+ {
+ err = 0;
+ CloseHandle (thread);
+ }
+ else
+ err = GetLastError();
+
+ return err;
+}
+
+static VOID
+HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists)
+{
+ DWORD read;
+ union {
+ message_header_t header;
+ address_message_t address;
+ route_message_t route;
+ flush_neighbors_message_t flush_neighbors;
+ block_dns_message_t block_dns;
+ } msg;
+ ack_message_t ack = {
+ .header = {
+ .type = msg_acknowledgement,
+ .size = sizeof (ack),
+ .message_id = -1
+ },
+ .error_number = ERROR_MESSAGE_DATA
+ };
+
+ read = ReadPipeAsync (pipe, &msg, bytes, count, events);
+ if (read != bytes || read < sizeof (msg.header) || read != msg.header.size)
+ goto out;
+
+ ack.header.message_id = msg.header.message_id;
+
+ switch (msg.header.type)
+ {
+ case msg_add_address:
+ case msg_del_address:
+ if (msg.header.size == sizeof (msg.address))
+ ack.error_number = HandleAddressMessage (&msg.address, lists);
+ break;
+
+ case msg_add_route:
+ case msg_del_route:
+ if (msg.header.size == sizeof (msg.route))
+ ack.error_number = HandleRouteMessage (&msg.route, lists);
+ break;
+
+ case msg_flush_neighbors:
+ if (msg.header.size == sizeof (msg.flush_neighbors))
+ ack.error_number = HandleFlushNeighborsMessage (&msg.flush_neighbors);
+ break;
+
+ case msg_add_block_dns:
+ case msg_del_block_dns:
+ if (msg.header.size == sizeof (msg.block_dns))
+ ack.error_number = HandleBlockDNSMessage (&msg.block_dns, lists);
+ break;
+
+ case msg_register_dns:
+ ack.error_number = HandleRegisterDNSMessage ();
+ break;
+
+ default:
+ ack.error_number = ERROR_MESSAGE_TYPE;
+ MsgToEventLog (MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type);
+ break;
+ }
+
+out:
+ WritePipeAsync (pipe, &ack, sizeof (ack), count, events);
+}
+
+
+static VOID
+Undo (undo_lists_t *lists)
+{
+ undo_type_t type;
+ for (type = 0; type < _undo_type_max; type++)
+ {
+ list_item_t **pnext = &(*lists)[type];
+ while (*pnext)
+ {
+ list_item_t *item = *pnext;
+ switch (type)
+ {
+ case address:
+ DeleteAddress (item->data);
+ break;
+
+ case route:
+ DeleteRoute (item->data);
+ break;
+
+ case block_dns:
+ delete_block_dns_filters (item->data);
+ item->data = NULL;
+ break;
+ }
+
+ /* Remove from the list and free memory */
+ *pnext = item->next;
+ free (item->data);
+ free (item);
+ }
+ }
+}
+
+static DWORD WINAPI
+RunOpenvpn (LPVOID p)
+{
+ HANDLE pipe = p;
+ HANDLE ovpn_pipe, svc_pipe;
+ PTOKEN_USER svc_user, ovpn_user;
+ HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL;
+ HANDLE stdin_read = NULL, stdin_write = NULL;
+ HANDLE stdout_write = NULL;
+ DWORD pipe_mode, len, exit_code = 0;
+ STARTUP_DATA sud = { 0, 0, 0 };
+ STARTUPINFOW startup_info;
+ PROCESS_INFORMATION proc_info;
+ LPVOID user_env = NULL;
+ TCHAR ovpn_pipe_name[36];
+ LPCWSTR exe_path;
+ WCHAR *cmdline = NULL;
+ size_t cmdline_size;
+ undo_lists_t undo_lists;
+
+ SECURITY_ATTRIBUTES inheritable = {
+ .nLength = sizeof (inheritable),
+ .lpSecurityDescriptor = NULL,
+ .bInheritHandle = TRUE
+ };
+
+ PACL ovpn_dacl;
+ EXPLICIT_ACCESS ea[2];
+ SECURITY_DESCRIPTOR ovpn_sd;
+ SECURITY_ATTRIBUTES ovpn_sa = {
+ .nLength = sizeof (ovpn_sa),
+ .lpSecurityDescriptor = &ovpn_sd,
+ .bInheritHandle = FALSE
+ };
+
+ ZeroMemory (&ea, sizeof (ea));
+ ZeroMemory (&startup_info, sizeof (startup_info));
+ ZeroMemory (&undo_lists, sizeof (undo_lists));
+ ZeroMemory (&proc_info, sizeof (proc_info));
+
+ if (!GetStartupData (pipe, &sud))
+ goto out;
+
+ if (!InitializeSecurityDescriptor (&ovpn_sd, SECURITY_DESCRIPTOR_REVISION))
+ {
+ ReturnLastError (pipe, L"InitializeSecurityDescriptor");
+ goto out;
+ }
+
+ /* Get SID of user the service is running under */
+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &svc_token))
+ {
+ ReturnLastError (pipe, L"OpenProcessToken");
+ goto out;
+ }
+ len = 0;
+ svc_user = NULL;
+ while (!GetTokenInformation (svc_token, TokenUser, svc_user, len, &len))
+ {
+ if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ {
+ ReturnLastError (pipe, L"GetTokenInformation (service token)");
+ goto out;
+ }
+ free (svc_user);
+ svc_user = malloc (len);
+ if (svc_user == NULL)
+ {
+ ReturnLastError (pipe, L"malloc (service token user)");
+ goto out;
+ }
+ }
+ if (!IsValidSid (svc_user->User.Sid))
+ {
+ ReturnLastError (pipe, L"IsValidSid (service token user)");
+ goto out;
+ }
+
+ if (!ImpersonateNamedPipeClient (pipe))
+ {
+ ReturnLastError (pipe, L"ImpersonateNamedPipeClient");
+ goto out;
+ }
+ if (!OpenThreadToken (GetCurrentThread (), TOKEN_ALL_ACCESS, FALSE, &imp_token))
+ {
+ ReturnLastError (pipe, L"OpenThreadToken");
+ goto out;
+ }
+ len = 0;
+ ovpn_user = NULL;
+ while (!GetTokenInformation (imp_token, TokenUser, ovpn_user, len, &len))
+ {
+ if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ {
+ ReturnLastError (pipe, L"GetTokenInformation (impersonation token)");
+ goto out;
+ }
+ free (ovpn_user);
+ ovpn_user = malloc (len);
+ if (ovpn_user == NULL)
+ {
+ ReturnLastError (pipe, L"malloc (impersonation token user)");
+ goto out;
+ }
+ }
+ if (!IsValidSid (ovpn_user->User.Sid))
+ {
+ ReturnLastError (pipe, L"IsValidSid (impersonation token user)");
+ goto out;
+ }
+
+ /* Check user is authorized or options are white-listed */
+ if (!IsAuthorizedUser (ovpn_user->User.Sid, &settings) &&
+ !ValidateOptions (pipe, sud.directory, sud.options))
+ {
+ goto out;
+ }
+
+ /* OpenVPN process DACL entry for access by service and user */
+ ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
+ ea[0].grfAccessMode = SET_ACCESS;
+ ea[0].grfInheritance = NO_INHERITANCE;
+ ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
+ ea[0].Trustee.ptstrName = (LPTSTR) svc_user->User.Sid;
+ ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ |
+ SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION;
+ ea[1].grfAccessMode = SET_ACCESS;
+ ea[1].grfInheritance = NO_INHERITANCE;
+ ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
+ ea[1].Trustee.ptstrName = (LPTSTR) ovpn_user->User.Sid;
+
+ /* Set owner and DACL of OpenVPN security descriptor */
+ if (!SetSecurityDescriptorOwner (&ovpn_sd, svc_user->User.Sid, FALSE))
+ {
+ ReturnLastError (pipe, L"SetSecurityDescriptorOwner");
+ goto out;
+ }
+ if (SetEntriesInAcl (2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS)
+ {
+ ReturnLastError (pipe, L"SetEntriesInAcl");
+ goto out;
+ }
+ if (!SetSecurityDescriptorDacl (&ovpn_sd, TRUE, ovpn_dacl, FALSE))
+ {
+ ReturnLastError (pipe, L"SetSecurityDescriptorDacl");
+ goto out;
+ }
+
+ /* Create primary token from impersonation token */
+ if (!DuplicateTokenEx (imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token))
+ {
+ ReturnLastError (pipe, L"DuplicateTokenEx");
+ goto out;
+ }
+
+ /* use /dev/null for stdout of openvpn (client should use --log for output) */
+ stdout_write = CreateFile(_T("NUL"), GENERIC_WRITE, FILE_SHARE_WRITE,
+ &inheritable, OPEN_EXISTING, 0, NULL);
+ if (stdout_write == INVALID_HANDLE_VALUE)
+ {
+ ReturnLastError (pipe, L"CreateFile for stdout");
+ goto out;
+ }
+
+ if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0) ||
+ !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0))
+ {
+ ReturnLastError (pipe, L"CreatePipe");
+ goto out;
+ }
+
+ openvpn_sntprintf (ovpn_pipe_name, _countof (ovpn_pipe_name),
+ TEXT("\\\\.\\pipe\\openvpn\\service_%lu"), GetCurrentThreadId ());
+ ovpn_pipe = CreateNamedPipe (ovpn_pipe_name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL);
+ if (ovpn_pipe == INVALID_HANDLE_VALUE)
+ {
+ ReturnLastError (pipe, L"CreateNamedPipe");
+ goto out;
+ }
+
+ svc_pipe = CreateFile (ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0,
+ &inheritable, OPEN_EXISTING, 0, NULL);
+ if (svc_pipe == INVALID_HANDLE_VALUE)
+ {
+ ReturnLastError (pipe, L"CreateFile");
+ goto out;
+ }
+
+ pipe_mode = PIPE_READMODE_MESSAGE;
+ if (!SetNamedPipeHandleState (svc_pipe, &pipe_mode, NULL, NULL))
+ {
+ ReturnLastError (pipe, L"SetNamedPipeHandleState");
+ goto out;
+ }
+
+ cmdline_size = wcslen (sud.options) + 128;
+ cmdline = malloc (cmdline_size * sizeof (*cmdline));
+ if (cmdline == NULL)
+ {
+ ReturnLastError (pipe, L"malloc");
+ goto out;
+ }
+ openvpn_sntprintf (cmdline, cmdline_size, L"openvpn %s --msg-channel %lu",
+ sud.options, svc_pipe);
+
+ if (!CreateEnvironmentBlock (&user_env, imp_token, FALSE))
+ {
+ ReturnLastError (pipe, L"CreateEnvironmentBlock");
+ goto out;
+ }
+
+ startup_info.cb = sizeof (startup_info);
+ startup_info.lpDesktop = L"winsta0\\default";
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+ startup_info.hStdInput = stdin_read;
+ startup_info.hStdOutput = stdout_write;
+ startup_info.hStdError = stdout_write;
+
+#ifdef UNICODE
+ exe_path = settings.exe_path;
+#else
+ WCHAR wide_path[MAX_PATH];
+ MultiByteToWideChar (CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH);
+ exe_path = wide_path;
+#endif
+
+ // TODO: make sure HKCU is correct or call LoadUserProfile()
+ if (!CreateProcessAsUserW (pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE,
+ settings.priority | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
+ user_env, sud.directory, &startup_info, &proc_info))
+ {
+ ReturnLastError (pipe, L"CreateProcessAsUser");
+ goto out;
+ }
+
+ if (!RevertToSelf ())
+ {
+ TerminateProcess (proc_info.hProcess, 1);
+ ReturnLastError (pipe, L"RevertToSelf");
+ goto out;
+ }
+
+ ReturnProcessId (pipe, proc_info.dwProcessId, 1, &exit_event);
+
+ CloseHandleEx (&stdout_write);
+ CloseHandleEx (&stdin_read);
+ CloseHandleEx (&svc_pipe);
+
+ DWORD input_size = WideCharToMultiByte (CP_UTF8, 0, sud.std_input, -1, NULL, 0, NULL, NULL);
+ LPSTR input = NULL;
+ if (input_size && (input = malloc (input_size)))
+ {
+ DWORD written;
+ WideCharToMultiByte (CP_UTF8, 0, sud.std_input, -1, input, input_size, NULL, NULL);
+ WriteFile (stdin_write, input, strlen (input), &written, NULL);
+ free (input);
+ }
+
+ while (TRUE)
+ {
+ DWORD bytes = PeekNamedPipeAsync (ovpn_pipe, 1, &exit_event);
+ if (bytes == 0)
+ break;
+
+ HandleMessage (ovpn_pipe, bytes, 1, &exit_event, &undo_lists);
+ }
+
+ WaitForSingleObject (proc_info.hProcess, IO_TIMEOUT);
+ GetExitCodeProcess (proc_info.hProcess, &exit_code);
+ if (exit_code == STILL_ACTIVE)
+ TerminateProcess (proc_info.hProcess, 1);
+ else if (exit_code != 0)
+ {
+ WCHAR buf[256];
+ int len = _snwprintf (buf, _countof (buf),
+ L"OpenVPN exited with error: exit code = %lu", exit_code);
+ buf[_countof (buf) - 1] = L'\0';
+ ReturnError (pipe, ERROR_OPENVPN_STARTUP, buf, 1, &exit_event);
+ }
+ Undo (&undo_lists);
+
+out:
+ FlushFileBuffers (pipe);
+ DisconnectNamedPipe (pipe);
+
+ free (ovpn_user);
+ free (svc_user);
+ free (cmdline);
+ DestroyEnvironmentBlock (user_env);
+ FreeStartupData (&sud);
+ CloseHandleEx (&proc_info.hProcess);
+ CloseHandleEx (&proc_info.hThread);
+ CloseHandleEx (&stdin_read);
+ CloseHandleEx (&stdin_write);
+ CloseHandleEx (&stdout_write);
+ CloseHandleEx (&svc_token);
+ CloseHandleEx (&imp_token);
+ CloseHandleEx (&pri_token);
+ CloseHandleEx (&ovpn_pipe);
+ CloseHandleEx (&svc_pipe);
+ CloseHandleEx (&pipe);
+
+ return 0;
+}
+
+
+static DWORD WINAPI
+ServiceCtrlInteractive (DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx)
+{
+ SERVICE_STATUS *status = ctx;
+ switch (ctrl_code)
+ {
+ case SERVICE_CONTROL_STOP:
+ status->dwCurrentState = SERVICE_STOP_PENDING;
+ ReportStatusToSCMgr (service, status);
+ if (exit_event)
+ SetEvent (exit_event);
+ return NO_ERROR;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ return NO_ERROR;
+
+ default:
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+}
+
+
+static HANDLE
+CreateClientPipeInstance (VOID)
+{
+ HANDLE pipe = NULL;
+ PACL old_dacl, new_dacl;
+ PSECURITY_DESCRIPTOR sd;
+ static EXPLICIT_ACCESS ea[2];
+ static BOOL initialized = FALSE;
+ DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED;
+
+ if (!initialized)
+ {
+ PSID everyone, anonymous;
+
+ ConvertStringSidToSid (TEXT("S-1-1-0"), &everyone);
+ ConvertStringSidToSid (TEXT("S-1-5-7"), &anonymous);
+
+ ea[0].grfAccessPermissions = FILE_GENERIC_WRITE;
+ ea[0].grfAccessMode = GRANT_ACCESS;
+ ea[0].grfInheritance = NO_INHERITANCE;
+ ea[0].Trustee.pMultipleTrustee = NULL;
+ ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+ ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
+ ea[0].Trustee.ptstrName = (LPTSTR) everyone;
+
+ ea[1].grfAccessPermissions = 0;
+ ea[1].grfAccessMode = REVOKE_ACCESS;
+ ea[1].grfInheritance = NO_INHERITANCE;
+ ea[1].Trustee.pMultipleTrustee = NULL;
+ ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+ ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
+ ea[1].Trustee.ptstrName = (LPTSTR) anonymous;
+
+ flags |= FILE_FLAG_FIRST_PIPE_INSTANCE;
+ initialized = TRUE;
+ }
+
+ pipe = CreateNamedPipe (TEXT("\\\\.\\pipe\\openvpn\\service"), flags,
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
+ PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL);
+ if (pipe == INVALID_HANDLE_VALUE)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("Could not create named pipe"));
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if (GetSecurityInfo (pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
+ NULL, NULL, &old_dacl, NULL, &sd) != ERROR_SUCCESS)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("Could not get pipe security info"));
+ return CloseHandleEx (&pipe);
+ }
+
+ if (SetEntriesInAcl (2, ea, old_dacl, &new_dacl) != ERROR_SUCCESS)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("Could not set entries in new acl"));
+ return CloseHandleEx (&pipe);
+ }
+
+ if (SetSecurityInfo (pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
+ NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("Could not set pipe security info"));
+ return CloseHandleEx (&pipe);
+ }
+
+ return pipe;
+}
+
+
+static DWORD
+UpdateWaitHandles (LPHANDLE *handles_ptr, LPDWORD count,
+ HANDLE io_event, HANDLE exit_event, list_item_t *threads)
+{
+ static DWORD size = 10;
+ static LPHANDLE handles = NULL;
+ DWORD pos = 0;
+
+ if (handles == NULL)
+ {
+ handles = malloc (size * sizeof (HANDLE));
+ *handles_ptr = handles;
+ if (handles == NULL)
+ return ERROR_OUTOFMEMORY;
+ }
+
+ handles[pos++] = io_event;
+
+ if (!threads)
+ handles[pos++] = exit_event;
+
+ while (threads)
+ {
+ if (pos == size)
+ {
+ LPHANDLE tmp;
+ size += 10;
+ tmp = realloc (handles, size * sizeof (HANDLE));
+ if (tmp == NULL)
+ {
+ size -= 10;
+ *count = pos;
+ return ERROR_OUTOFMEMORY;
+ }
+ handles = tmp;
+ *handles_ptr = handles;
+ }
+ handles[pos++] = threads->data;
+ threads = threads->next;
+ }
+
+ *count = pos;
+ return NO_ERROR;
+}
+
+
+static VOID
+FreeWaitHandles (LPHANDLE h)
+{
+ free (h);
+}
+
+
+VOID WINAPI
+ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv)
+{
+ HANDLE pipe, io_event = NULL;
+ OVERLAPPED overlapped;
+ DWORD error = NO_ERROR;
+ list_item_t *threads = NULL;
+ PHANDLE handles = NULL;
+ DWORD handle_count;
+ BOOL CmpHandle (LPVOID item, LPVOID hnd) { return item == hnd; }
+
+ service = RegisterServiceCtrlHandlerEx (interactive_service.name, ServiceCtrlInteractive, &status);
+ if (!service)
+ return;
+
+ status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
+ status.dwCurrentState = SERVICE_START_PENDING;
+ status.dwServiceSpecificExitCode = NO_ERROR;
+ status.dwWin32ExitCode = NO_ERROR;
+ status.dwWaitHint = 3000;
+ ReportStatusToSCMgr (service, &status);
+
+ /* Read info from registry in key HKLM\SOFTWARE\OpenVPN */
+ error = GetOpenvpnSettings (&settings);
+ if (error != ERROR_SUCCESS)
+ goto out;
+
+ io_event = InitOverlapped (&overlapped);
+ exit_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+ if (!exit_event || !io_event)
+ {
+ error = MsgToEventLog (M_SYSERR, TEXT("Could not create event"));
+ goto out;
+ }
+
+ rdns_semaphore = CreateSemaphoreW (NULL, 1, 1, NULL);
+ if (!rdns_semaphore)
+ {
+ error = MsgToEventLog (M_SYSERR, TEXT("Could not create semaphore for register-dns"));
+ goto out;
+ }
+
+ error = UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads);
+ if (error != NO_ERROR)
+ goto out;
+
+ pipe = CreateClientPipeInstance ();
+ if (pipe == INVALID_HANDLE_VALUE)
+ goto out;
+
+ status.dwCurrentState = SERVICE_RUNNING;
+ status.dwWaitHint = 0;
+ ReportStatusToSCMgr (service, &status);
+
+ while (TRUE)
+ {
+ if (ConnectNamedPipe (pipe, &overlapped) == FALSE &&
+ GetLastError () != ERROR_PIPE_CONNECTED &&
+ GetLastError () != ERROR_IO_PENDING)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("Could not connect pipe"));
+ break;
+ }
+
+ error = WaitForMultipleObjects (handle_count, handles, FALSE, INFINITE);
+ if (error == WAIT_OBJECT_0)
+ {
+ /* Client connected, spawn a worker thread for it */
+ HANDLE next_pipe = CreateClientPipeInstance ();
+ HANDLE thread = CreateThread (NULL, 0, RunOpenvpn, pipe, CREATE_SUSPENDED, NULL);
+ if (thread)
+ {
+ error = AddListItem (&threads, thread);
+ if (!error)
+ error = UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads);
+ if (error)
+ {
+ ReturnError (pipe, error, L"Insufficient resources to service new clients", 1, &exit_event);
+ /* Update wait handles again after removing the last worker thread */
+ RemoveListItem (&threads, CmpHandle, thread);
+ UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads);
+ TerminateThread (thread, 1);
+ CloseHandleEx (&thread);
+ CloseHandleEx (&pipe);
+ }
+ else
+ ResumeThread (thread);
+ }
+ else
+ CloseHandleEx (&pipe);
+
+ ResetOverlapped (&overlapped);
+ pipe = next_pipe;
+ }
+ else
+ {
+ CancelIo (pipe);
+ if (error == WAIT_FAILED)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("WaitForMultipleObjects failed"));
+ SetEvent (exit_event);
+ /* Give some time for worker threads to exit and then terminate */
+ Sleep (1000);
+ break;
+ }
+ if (!threads)
+ {
+ /* exit event signaled */
+ CloseHandleEx (&pipe);
+ ResetEvent (exit_event);
+ error = NO_ERROR;
+ break;
+ }
+
+ /* Worker thread ended */
+ HANDLE thread = RemoveListItem (&threads, CmpHandle, handles[error]);
+ UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads);
+ CloseHandleEx (&thread);
+ }
+ }
+
+out:
+ FreeWaitHandles (handles);
+ CloseHandleEx (&io_event);
+ CloseHandleEx (&exit_event);
+ CloseHandleEx (&rdns_semaphore);
+
+ status.dwCurrentState = SERVICE_STOPPED;
+ status.dwWin32ExitCode = error;
+ ReportStatusToSCMgr (service, &status);
+}
diff --git a/src/openvpnserv/openvpnserv.c b/src/openvpnserv/openvpnserv.c
deleted file mode 100755
index 56f5a02..0000000
--- a/src/openvpnserv/openvpnserv.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * 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-2010 OpenVPN Technologies, Inc. <sales@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
- */
-
-/*
- * This program allows one or more OpenVPN processes to be started
- * as a service. To build, you must get the service sample from the
- * Platform SDK and replace Simple.c with this file.
- *
- * You should also apply service.patch to
- * service.c and service.h from the Platform SDK service sample.
- *
- * This code is designed to be built with the mingw compiler.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#elif defined(_MSC_VER)
-#include "config-msvc.h"
-#endif
-#include <windows.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <process.h>
-#include "service.h"
-
-/* bool definitions */
-#define bool int
-#define true 1
-#define false 0
-
-/* These are new for 2000/XP, so they aren't in the mingw headers yet */
-#ifndef BELOW_NORMAL_PRIORITY_CLASS
-#define BELOW_NORMAL_PRIORITY_CLASS 0x00004000
-#endif
-#ifndef ABOVE_NORMAL_PRIORITY_CLASS
-#define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
-#endif
-
-struct security_attributes
-{
- SECURITY_ATTRIBUTES sa;
- SECURITY_DESCRIPTOR sd;
-};
-
-/*
- * This event is initially created in the non-signaled
- * state. It will transition to the signaled state when
- * we have received a terminate signal from the Service
- * Control Manager which will cause an asynchronous call
- * of ServiceStop below.
- */
-#define EXIT_EVENT_NAME PACKAGE "_exit_1"
-
-/*
- * Which registry key in HKLM should
- * we get config info from?
- */
-#define REG_KEY "SOFTWARE\\" PACKAGE_NAME
-
-static HANDLE exit_event = NULL;
-
-/* clear an object */
-#define CLEAR(x) memset(&(x), 0, sizeof(x))
-
-/*
- * Message handling
- */
-#define M_INFO (0) /* informational */
-#define M_SYSERR (MSG_FLAGS_ERROR|MSG_FLAGS_SYS_CODE) /* error + system code */
-#define M_ERR (MSG_FLAGS_ERROR) /* error */
-
-/* write error to event log */
-#define MSG(flags, ...) \
- { \
- char x_msg[256]; \
- openvpn_snprintf (x_msg, sizeof(x_msg), __VA_ARGS__); \
- AddToMessageLog ((flags), x_msg); \
- }
-
-/* get a registry string */
-#define QUERY_REG_STRING(name, data) \
- { \
- len = sizeof (data); \
- status = RegQueryValueEx(openvpn_key, name, NULL, &type, data, &len); \
- if (status != ERROR_SUCCESS || type != REG_SZ) \
- { \
- SetLastError (status); \
- MSG (M_SYSERR, error_format_str, name); \
- RegCloseKey (openvpn_key); \
- goto finish; \
- } \
- }
-
-/* get a registry string */
-#define QUERY_REG_DWORD(name, data) \
- { \
- len = sizeof (DWORD); \
- status = RegQueryValueEx(openvpn_key, name, NULL, &type, (LPBYTE)&data, &len); \
- if (status != ERROR_SUCCESS || type != REG_DWORD || len != sizeof (DWORD)) \
- { \
- SetLastError (status); \
- MSG (M_SYSERR, error_format_dword, name); \
- RegCloseKey (openvpn_key); \
- goto finish; \
- } \
- }
-
-/*
- * This is necessary due to certain buggy implementations of snprintf,
- * that don't guarantee null termination for size > 0.
- * (copied from ../buffer.c, line 217)
- * (git: 100644 blob e2f8caab0a5b2a870092c6cd508a1a50c21c3ba3 buffer.c)
- */
-
-int openvpn_snprintf(char *str, size_t size, const char *format, ...)
-{
- va_list arglist;
- int len = -1;
- if (size > 0)
- {
- va_start (arglist, format);
- len = vsnprintf (str, size, format, arglist);
- va_end (arglist);
- str[size - 1] = 0;
- }
- return (len >= 0 && len < size);
-}
-
-
-bool
-init_security_attributes_allow_all (struct security_attributes *obj)
-{
- CLEAR (*obj);
-
- obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES);
- obj->sa.lpSecurityDescriptor = &obj->sd;
- obj->sa.bInheritHandle = TRUE;
- if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION))
- return false;
- if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE))
- return false;
- return true;
-}
-
-HANDLE
-create_event (const char *name, bool allow_all, bool initial_state, bool manual_reset)
-{
- if (allow_all)
- {
- struct security_attributes sa;
- if (!init_security_attributes_allow_all (&sa))
- return NULL;
- return CreateEvent (&sa.sa, (BOOL)manual_reset, (BOOL)initial_state, name);
- }
- else
- return CreateEvent (NULL, (BOOL)manual_reset, (BOOL)initial_state, name);
-}
-
-void
-close_if_open (HANDLE h)
-{
- if (h != NULL)
- CloseHandle (h);
-}
-
-static bool
-match (const WIN32_FIND_DATA *find, const char *ext)
-{
- int i;
-
- if (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- return false;
-
- if (!strlen (ext))
- return true;
-
- i = strlen (find->cFileName) - strlen (ext) - 1;
- if (i < 1)
- return false;
-
- return find->cFileName[i] == '.' && !_stricmp (find->cFileName + i + 1, ext);
-}
-
-/*
- * Modify the extension on a filename.
- */
-static bool
-modext (char *dest, int size, const char *src, const char *newext)
-{
- int i;
-
- if (size > 0 && (strlen (src) + 1) <= size)
- {
- strcpy (dest, src);
- dest [size - 1] = '\0';
- i = strlen (dest);
- while (--i >= 0)
- {
- if (dest[i] == '\\')
- break;
- if (dest[i] == '.')
- {
- dest[i] = '\0';
- break;
- }
- }
- if (strlen (dest) + strlen(newext) + 2 <= size)
- {
- strcat (dest, ".");
- strcat (dest, newext);
- return true;
- }
- dest [0] = '\0';
- }
- return false;
-}
-
-VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
-{
- char exe_path[MAX_PATH];
- char config_dir[MAX_PATH];
- char ext_string[16];
- char log_dir[MAX_PATH];
- char priority_string[64];
- char append_string[2];
-
- DWORD priority;
- bool append;
-
- ResetError ();
-
- if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
- {
- MSG (M_ERR, "ReportStatusToSCMgr #1 failed");
- goto finish;
- }
-
- /*
- * Create our exit event
- */
- exit_event = create_event (EXIT_EVENT_NAME, false, false, true);
- if (!exit_event)
- {
- MSG (M_ERR, "CreateEvent failed");
- goto finish;
- }
-
- /*
- * If exit event is already signaled, it means we were not
- * shut down properly.
- */
- if (WaitForSingleObject (exit_event, 0) != WAIT_TIMEOUT)
- {
- MSG (M_ERR, "Exit event is already signaled -- we were not shut down properly");
- goto finish;
- }
-
- if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
- {
- MSG (M_ERR, "ReportStatusToSCMgr #2 failed");
- goto finish;
- }
-
- /*
- * Read info from registry in key HKLM\SOFTWARE\OpenVPN
- */
- {
- HKEY openvpn_key;
- LONG status;
- DWORD len;
- DWORD type;
-
- static const char error_format_str[] =
- "Error querying registry key of type REG_SZ: HKLM\\" REG_KEY "\\%s";
-
- static const char error_format_dword[] =
- "Error querying registry key of type REG_DWORD: HKLM\\" REG_KEY "\\%s";
-
- status = RegOpenKeyEx(
- HKEY_LOCAL_MACHINE,
- REG_KEY,
- 0,
- KEY_READ,
- &openvpn_key);
-
- if (status != ERROR_SUCCESS)
- {
- SetLastError (status);
- MSG (M_SYSERR, "Registry key HKLM\\" REG_KEY " not found");
- goto finish;
- }
-
- /* get path to openvpn.exe */
- QUERY_REG_STRING ("exe_path", exe_path);
-
- /* get path to configuration directory */
- QUERY_REG_STRING ("config_dir", config_dir);
-
- /* get extension on configuration files */
- QUERY_REG_STRING ("config_ext", ext_string);
-
- /* get path to log directory */
- QUERY_REG_STRING ("log_dir", log_dir);
-
- /* get priority for spawned OpenVPN subprocesses */
- QUERY_REG_STRING ("priority", priority_string);
-
- /* should we truncate or append to logfile? */
- QUERY_REG_STRING ("log_append", append_string);
-
- RegCloseKey (openvpn_key);
- }
-
- /* set process priority */
- priority = NORMAL_PRIORITY_CLASS;
- if (!_stricmp (priority_string, "IDLE_PRIORITY_CLASS"))
- priority = IDLE_PRIORITY_CLASS;
- else if (!_stricmp (priority_string, "BELOW_NORMAL_PRIORITY_CLASS"))
- priority = BELOW_NORMAL_PRIORITY_CLASS;
- else if (!_stricmp (priority_string, "NORMAL_PRIORITY_CLASS"))
- priority = NORMAL_PRIORITY_CLASS;
- else if (!_stricmp (priority_string, "ABOVE_NORMAL_PRIORITY_CLASS"))
- priority = ABOVE_NORMAL_PRIORITY_CLASS;
- else if (!_stricmp (priority_string, "HIGH_PRIORITY_CLASS"))
- priority = HIGH_PRIORITY_CLASS;
- else
- {
- MSG (M_ERR, "Unknown priority name: %s", priority_string);
- goto finish;
- }
-
- /* set log file append/truncate flag */
- append = false;
- if (append_string[0] == '0')
- append = false;
- else if (append_string[0] == '1')
- append = true;
- else
- {
- MSG (M_ERR, "Log file append flag (given as '%s') must be '0' or '1'", append_string);
- goto finish;
- }
-
- /*
- * Instantiate an OpenVPN process for each configuration
- * file found.
- */
- {
- WIN32_FIND_DATA find_obj;
- HANDLE find_handle;
- BOOL more_files;
- char find_string[MAX_PATH];
-
- openvpn_snprintf (find_string, MAX_PATH, "%s\\*", config_dir);
-
- find_handle = FindFirstFile (find_string, &find_obj);
- if (find_handle == INVALID_HANDLE_VALUE)
- {
- MSG (M_ERR, "Cannot get configuration file list using: %s", find_string);
- goto finish;
- }
-
- /*
- * Loop over each config file
- */
- do {
- HANDLE log_handle = NULL;
- STARTUPINFO start_info;
- PROCESS_INFORMATION proc_info;
- struct security_attributes sa;
- char log_file[MAX_PATH];
- char log_path[MAX_PATH];
- char command_line[256];
-
- CLEAR (start_info);
- CLEAR (proc_info);
- CLEAR (sa);
-
- if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000))
- {
- MSG (M_ERR, "ReportStatusToSCMgr #3 failed");
- FindClose (find_handle);
- goto finish;
- }
-
- /* does file have the correct type and extension? */
- if (match (&find_obj, ext_string))
- {
- /* get log file pathname */
- if (!modext (log_file, sizeof (log_file), find_obj.cFileName, "log"))
- {
- MSG (M_ERR, "Cannot construct logfile name based on: %s", find_obj.cFileName);
- FindClose (find_handle);
- goto finish;
- }
- openvpn_snprintf (log_path, sizeof(log_path),
- "%s\\%s", log_dir, log_file);
-
- /* construct command line */
- openvpn_snprintf (command_line, sizeof(command_line), PACKAGE " --service %s 1 --config \"%s\"",
- EXIT_EVENT_NAME,
- find_obj.cFileName);
-
- /* Make security attributes struct for logfile handle so it can
- be inherited. */
- if (!init_security_attributes_allow_all (&sa))
- {
- MSG (M_SYSERR, "InitializeSecurityDescriptor start_" PACKAGE " failed");
- goto finish;
- }
-
- /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */
- log_handle = CreateFile (log_path,
- GENERIC_WRITE,
- FILE_SHARE_READ,
- &sa.sa,
- append ? OPEN_ALWAYS : CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
-
- if (log_handle == INVALID_HANDLE_VALUE)
- {
- MSG (M_SYSERR, "Cannot open logfile: %s", log_path);
- FindClose (find_handle);
- goto finish;
- }
-
- /* append to logfile? */
- if (append)
- {
- if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
- {
- MSG (M_SYSERR, "Cannot seek to end of logfile: %s", log_path);
- FindClose (find_handle);
- goto finish;
- }
- }
-
- /* fill in STARTUPINFO struct */
- GetStartupInfo(&start_info);
- start_info.cb = sizeof(start_info);
- start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
- start_info.wShowWindow = SW_HIDE;
- start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
- start_info.hStdOutput = start_info.hStdError = log_handle;
-
- /* create an OpenVPN process for one config file */
- if (!CreateProcess(exe_path,
- command_line,
- NULL,
- NULL,
- TRUE,
- priority | CREATE_NEW_CONSOLE,
- NULL,
- config_dir,
- &start_info,
- &proc_info))
- {
- MSG (M_SYSERR, "CreateProcess failed, exe='%s' cmdline='%s' dir='%s'",
- exe_path,
- command_line,
- config_dir);
-
- FindClose (find_handle);
- CloseHandle (log_handle);
- goto finish;
- }
-
- /* close unneeded handles */
- Sleep (1000); /* try to prevent race if we close logfile
- handle before child process DUPs it */
- if (!CloseHandle (proc_info.hProcess)
- || !CloseHandle (proc_info.hThread)
- || !CloseHandle (log_handle))
- {
- MSG (M_SYSERR, "CloseHandle failed");
- goto finish;
- }
- }
-
- /* more files to process? */
- more_files = FindNextFile (find_handle, &find_obj);
-
- } while (more_files);
-
- FindClose (find_handle);
- }
-
- /* we are now fully started */
- if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
- {
- MSG (M_ERR, "ReportStatusToSCMgr SERVICE_RUNNING failed");
- goto finish;
- }
-
- /* wait for our shutdown signal */
- if (WaitForSingleObject (exit_event, INFINITE) != WAIT_OBJECT_0)
- {
- MSG (M_ERR, "wait for shutdown signal failed");
- }
-
- finish:
- ServiceStop ();
- if (exit_event)
- CloseHandle (exit_event);
-}
-
-VOID ServiceStop()
-{
- if (exit_event)
- SetEvent(exit_event);
-}
diff --git a/src/openvpnserv/openvpnserv.vcxproj b/src/openvpnserv/openvpnserv.vcxproj
index 2a8943d..c6760da 100644
--- a/src/openvpnserv/openvpnserv.vcxproj
+++ b/src/openvpnserv/openvpnserv.vcxproj
@@ -111,4 +111,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/openvpnserv/service.c b/src/openvpnserv/service.c
index d7562b3..82f5551 100644
--- a/src/openvpnserv/service.c
+++ b/src/openvpnserv/service.c
@@ -1,700 +1,245 @@
-/*---------------------------------------------------------------------------
-THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
-ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
-TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
-PARTICULAR PURPOSE.
-
-Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved.
-
-MODULE: service.c
-
-PURPOSE: Implements functions required by all Windows NT services
-
-FUNCTIONS:
- main(int argc, char **argv);
- service_ctrl(DWORD dwCtrlCode);
- service_main(DWORD dwArgc, LPTSTR *lpszArgv);
- CmdInstallService();
- CmdRemoveService();
- CmdStartService();
- CmdDebugService(int argc, char **argv);
- ControlHandler ( DWORD dwCtrlType );
- GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
-
----------------------------------------------------------------------------*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#elif defined(_MSC_VER)
-#include "config-msvc.h"
-#endif
-#include <windows.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <process.h>
-#include <tchar.h>
+/*
+ * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+ * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
+ * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+ * PARTICULAR PURPOSE.
+ *
+ * Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved.
+ * 2013 Heiko Hund <heiko.hund@sophos.com>
+ */
#include "service.h"
-// internal variables
-SERVICE_STATUS ssStatus; // current status of the service
-SERVICE_STATUS_HANDLE sshStatusHandle;
-DWORD dwErr = 0;
-BOOL bDebug = FALSE;
-TCHAR szErr[256];
-
-// internal function prototypes
-VOID WINAPI service_ctrl(DWORD dwCtrlCode);
-VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
-int CmdInstallService();
-int CmdRemoveService();
-int CmdStartService();
-VOID CmdDebugService(int argc, char **argv);
-BOOL WINAPI ControlHandler ( DWORD dwCtrlType );
-LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
-
-//
-// FUNCTION: main
-//
-// PURPOSE: entrypoint for service
-//
-// PARAMETERS:
-// argc - number of command line arguments
-// argv - array of command line arguments
-//
-// RETURN VALUE:
-// none
-//
-// COMMENTS:
-// main() either performs the command line task, or
-// call StartServiceCtrlDispatcher to register the
-// main service thread. When the this call returns,
-// the service has stopped, so exit.
-//
-int __cdecl main(int argc, char **argv)
-{
- SERVICE_TABLE_ENTRY dispatchTable[] =
- {
- { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
- { NULL, NULL}
- };
-
- if ( (argc > 1) &&
- ((*argv[1] == '-') || (*argv[1] == '/')) )
- {
- if ( _stricmp( "install", argv[1]+1 ) == 0 )
- {
- return CmdInstallService();
- }
- else if ( _stricmp( "remove", argv[1]+1 ) == 0 )
- {
- return CmdRemoveService();
- }
- else if ( _stricmp( "start", argv[1]+1 ) == 0)
- {
- return CmdStartService();
- }
- else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
- {
- bDebug = TRUE;
- CmdDebugService(argc, argv);
- }
- else
- {
- goto dispatch;
- }
- return 0;
- }
-
- // if it doesn't match any of the above parameters
- // the service control manager may be starting the service
- // so we must call StartServiceCtrlDispatcher
- dispatch:
- // this is just to be friendly
- printf( "%s -install to install the service\n", SZAPPNAME );
- printf( "%s -start to start the service\n", SZAPPNAME );
- printf( "%s -remove to remove the service\n", SZAPPNAME );
- printf( "%s -debug <params> to run as a console app for debugging\n", SZAPPNAME );
- printf( "\nStartServiceCtrlDispatcher being called.\n" );
- printf( "This may take several seconds. Please wait.\n" );
-
- if (!StartServiceCtrlDispatcher(dispatchTable))
- AddToMessageLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed."));
-
- return 0;
-}
-
-
-
-//
-// FUNCTION: service_main
-//
-// PURPOSE: To perform actual initialization of the service
-//
-// PARAMETERS:
-// dwArgc - number of command line arguments
-// lpszArgv - array of command line arguments
-//
-// RETURN VALUE:
-// none
-//
-// COMMENTS:
-// This routine performs the service initialization and then calls
-// the user defined ServiceStart() routine to perform majority
-// of the work.
-//
-void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
-{
-
- // register our service control handler:
- //
- sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl);
-
- if (!sshStatusHandle)
- goto cleanup;
-
- // SERVICE_STATUS members that don't change in example
- //
- ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- ssStatus.dwServiceSpecificExitCode = 0;
-
-
- // report the status to the service control manager.
- //
- if (!ReportStatusToSCMgr(
- SERVICE_START_PENDING, // service state
- NO_ERROR, // exit code
- 3000)) // wait hint
- goto cleanup;
-
-
- ServiceStart( dwArgc, lpszArgv );
-
- cleanup:
+#include <windows.h>
+#include <stdio.h>
+#include <process.h>
- // try to report the stopped status to the service control manager.
- //
- if (sshStatusHandle)
- (VOID)ReportStatusToSCMgr(
- SERVICE_STOPPED,
- dwErr,
- 0);
- return;
-}
+openvpn_service_t openvpn_service[_service_max];
-
-//
-// FUNCTION: service_ctrl
-//
-// PURPOSE: This function is called by the SCM whenever
-// ControlService() is called on this service.
-//
-// PARAMETERS:
-// dwCtrlCode - type of control requested
-//
-// RETURN VALUE:
-// none
-//
-// COMMENTS:
-//
-VOID WINAPI service_ctrl(DWORD dwCtrlCode)
+BOOL
+ReportStatusToSCMgr (SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status)
{
- // Handle the requested control code.
- //
- switch (dwCtrlCode)
- {
- // Stop the service.
- //
- // SERVICE_STOP_PENDING should be reported before
- // setting the Stop Event - hServerStopEvent - in
- // ServiceStop(). This avoids a race condition
- // which may result in a 1053 - The Service did not respond...
- // error.
- case SERVICE_CONTROL_STOP:
- ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
- ServiceStop();
- return;
-
- // Update the service status.
- //
- case SERVICE_CONTROL_INTERROGATE:
- break;
-
- // invalid control code
- //
- default:
- break;
-
- }
-
- ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
+ static DWORD dwCheckPoint = 1;
+ BOOL res = TRUE;
+
+ if (status->dwCurrentState == SERVICE_START_PENDING)
+ status->dwControlsAccepted = 0;
+ else
+ status->dwControlsAccepted = SERVICE_ACCEPT_STOP;
+
+ if (status->dwCurrentState == SERVICE_RUNNING ||
+ status->dwCurrentState == SERVICE_STOPPED)
+ status->dwCheckPoint = 0;
+ else
+ status->dwCheckPoint = dwCheckPoint++;
+
+ /* Report the status of the service to the service control manager. */
+ res = SetServiceStatus (service, status);
+ if (!res)
+ MsgToEventLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus"));
+
+ return res;
}
-
-
-//
-// FUNCTION: ReportStatusToSCMgr()
-//
-// PURPOSE: Sets the current status of the service and
-// reports it to the Service Control Manager
-//
-// PARAMETERS:
-// dwCurrentState - the state of the service
-// dwWin32ExitCode - error code to report
-// dwWaitHint - worst case estimate to next checkpoint
-//
-// RETURN VALUE:
-// TRUE - success
-// FALSE - failure
-//
-// COMMENTS:
-//
-BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
- DWORD dwWin32ExitCode,
- DWORD dwWaitHint)
+static int
+CmdInstallServices ()
{
- static DWORD dwCheckPoint = 1;
- BOOL fResult = TRUE;
-
-
- if ( !bDebug ) // when debugging we don't report to the SCM
- {
- if (dwCurrentState == SERVICE_START_PENDING)
- ssStatus.dwControlsAccepted = 0;
- else
- ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
-
- ssStatus.dwCurrentState = dwCurrentState;
- ssStatus.dwWin32ExitCode = dwWin32ExitCode;
- ssStatus.dwWaitHint = dwWaitHint;
+ SC_HANDLE service;
+ SC_HANDLE svc_ctl_mgr;
+ TCHAR path[512];
+ int i, ret = _service_max;
+
+ if (GetModuleFileName (NULL, path + 1, 510) == 0)
+ {
+ _tprintf (TEXT("Unable to install service - %s\n"), GetLastErrorText ());
+ return 1;
+ }
+
+ path[0] = TEXT('\"');
+ _tcscat (path, TEXT("\""));
+
+ svc_ctl_mgr = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
+ if (svc_ctl_mgr == NULL)
+ {
+ _tprintf (TEXT("OpenSCManager failed - %s\n"), GetLastErrorText ());
+ return 1;
+ }
- if ( ( dwCurrentState == SERVICE_RUNNING ) ||
- ( dwCurrentState == SERVICE_STOPPED ) )
- ssStatus.dwCheckPoint = 0;
+ for (i = 0; i < _service_max; i++)
+ {
+ service = CreateService (svc_ctl_mgr,
+ openvpn_service[i].name,
+ openvpn_service[i].display_name,
+ SERVICE_QUERY_STATUS,
+ SERVICE_WIN32_SHARE_PROCESS,
+ openvpn_service[i].start_type,
+ SERVICE_ERROR_NORMAL,
+ path, NULL, NULL,
+ openvpn_service[i].dependencies,
+ NULL, NULL);
+ if (service)
+ {
+ _tprintf (TEXT("%s installed.\n"), openvpn_service[i].display_name);
+ CloseServiceHandle (service);
+ --ret;
+ }
else
- ssStatus.dwCheckPoint = dwCheckPoint++;
-
+ _tprintf (TEXT("CreateService failed - %s\n"), GetLastErrorText ());
+ }
- // Report the status of the service to the service control manager.
- //
- if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus)))
- {
- AddToMessageLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus"));
- }
- }
- return fResult;
+ CloseServiceHandle (svc_ctl_mgr);
+ return ret;
}
-
-//
-// FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
-//
-// PURPOSE: Allows any thread to log an error message
-//
-// PARAMETERS:
-// lpszMsg - text for message
-//
-// RETURN VALUE:
-// none
-//
-// COMMENTS:
-//
-void AddToMessageLog(DWORD flags, LPTSTR lpszMsg)
+static int
+CmdStartService (openvpn_service_type type)
{
- TCHAR szMsg [(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100 ];
- HANDLE hEventSource;
- LPCSTR lpszStrings[2];
-
- if ( !bDebug )
- {
- if (flags & MSG_FLAGS_SYS_CODE)
- dwErr = GetLastError();
- else
- dwErr = 0;
-
- // Use event logging to log the error.
- //
- hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
-
- _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), (int)dwErr);
- lpszStrings[0] = szMsg;
- lpszStrings[1] = lpszMsg;
-
- if (hEventSource != NULL)
- {
- ReportEvent(hEventSource, // handle of event source
- // event type
- (flags & MSG_FLAGS_ERROR)
- ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE,
- 0, // event category
- 0, // event ID
- NULL, // current user's SID
- 2, // strings in lpszStrings
- 0, // no bytes of raw data
- lpszStrings, // array of error strings
- NULL); // no raw data
-
- (VOID) DeregisterEventSource(hEventSource);
- }
- }
-}
-
-void ResetError (void)
-{
- dwErr = 0;
-}
+ int ret = 1;
+ SC_HANDLE svc_ctl_mgr;
+ SC_HANDLE service;
-///////////////////////////////////////////////////////////////////
-//
-// The following code handles service installation and removal
-//
-
-
-//
-// FUNCTION: CmdInstallService()
-//
-// PURPOSE: Installs the service
-//
-// PARAMETERS:
-// none
-//
-// RETURN VALUE:
-// 0 if success
-//
-// COMMENTS:
-//
-int CmdInstallService()
-{
- SC_HANDLE schService;
- SC_HANDLE schSCManager;
-
- TCHAR szPath[512];
-
- int ret = 0;
-
- if ( GetModuleFileName( NULL, szPath+1, 510 ) == 0 )
- {
- _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
+ svc_ctl_mgr = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (svc_ctl_mgr == NULL)
+ {
+ _tprintf (TEXT("OpenSCManager failed - %s\n"), GetLastErrorText ());
return 1;
- }
- szPath[0] = '\"';
- strcat(szPath, "\"");
-
- schSCManager = OpenSCManager(
- NULL, // machine (NULL == local)
- NULL, // database (NULL == default)
- SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE // access required
- );
- 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
- 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 )
- {
- _tprintf(TEXT("%s installed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
- CloseServiceHandle(schService);
- }
- else
- {
- _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
- ret = 1;
- }
-
- CloseServiceHandle(schSCManager);
- }
- else
- {
- _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
- ret = 1;
- }
- return ret;
-}
-
-//
-// FUNCTION: CmdStartService()
-//
-// PURPOSE: Start the service
-//
-// PARAMETERS:
-// none
-//
-// RETURN VALUE:
-// 0 if success
-//
-// COMMENTS:
-
-int CmdStartService()
-{
- int ret = 0;
-
- SC_HANDLE schSCManager;
- SC_HANDLE schService;
-
-
- // Open a handle to the SC Manager database.
- schSCManager = OpenSCManager(
- NULL, // local machine
- NULL, // ServicesActive database
- SC_MANAGER_ALL_ACCESS); // full access rights
-
- if (NULL == schSCManager) {
- _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
- ret = 1;
}
- schService = OpenService(
- schSCManager, // SCM database
- SZSERVICENAME, // service name
- SERVICE_ALL_ACCESS);
+ service = OpenService (svc_ctl_mgr, openvpn_service[type].name, SERVICE_ALL_ACCESS);
+ if (service)
+ {
+ if (StartService (service, 0, NULL))
+ {
+ _tprintf (TEXT("Service Started\n"));
+ ret = 0;
+ }
+ else
+ _tprintf (TEXT("StartService failed - %s\n"), GetLastErrorText ());
- if (schService == NULL) {
- _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
- ret = 1;
+ CloseServiceHandle(service);
}
-
- if (!StartService(
- schService, // handle to service
- 0, // number of arguments
- NULL) ) // no arguments
+ else
{
- _tprintf(TEXT("StartService failed - %s\n"), GetLastErrorText(szErr,256));
- ret = 1;
+ _tprintf (TEXT("OpenService failed - %s\n"), GetLastErrorText ());
}
- else
- {
- _tprintf(TEXT("Service Started\n"));
- ret = 0;
- }
- CloseServiceHandle(schService);
- CloseServiceHandle(schSCManager);
- return ret;
-}
-//
-// FUNCTION: CmdRemoveService()
-//
-// PURPOSE: Stops and removes the service
-//
-// PARAMETERS:
-// none
-//
-// RETURN VALUE:
-// 0 if success
-//
-// COMMENTS:
-//
-int CmdRemoveService()
-{
- SC_HANDLE schService;
- SC_HANDLE schSCManager;
+ CloseServiceHandle(svc_ctl_mgr);
+ return ret;
+}
- int ret = 0;
- schSCManager = OpenSCManager(
- NULL, // machine (NULL == local)
- NULL, // database (NULL == default)
- SC_MANAGER_CONNECT // access required
- );
- if ( schSCManager )
- {
- schService = OpenService(schSCManager, TEXT(SZSERVICENAME), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
+static int
+CmdRemoveServices ()
+{
+ SC_HANDLE service;
+ SC_HANDLE svc_ctl_mgr;
+ SERVICE_STATUS status;
+ int i, ret = _service_max;
- if (schService)
- {
- // try to stop the service
- if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
- {
- _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
- Sleep( 1000 );
+ svc_ctl_mgr = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT);
+ if (svc_ctl_mgr == NULL)
+ {
+ _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText ());
+ return 1;
+ }
- while ( QueryServiceStatus( schService, &ssStatus ) )
+ for (i = 0; i < _service_max; i++)
+ {
+ openvpn_service_t *ovpn_svc = &openvpn_service[i];
+ service = OpenService (svc_ctl_mgr, ovpn_svc->name,
+ DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
+ if (service == NULL)
+ {
+ _tprintf (TEXT("OpenService failed - %s\n"), GetLastErrorText ());
+ goto out;
+ }
+
+ /* try to stop the service */
+ if (ControlService (service, SERVICE_CONTROL_STOP, &status))
+ {
+ _tprintf (TEXT("Stopping %s."), ovpn_svc->display_name);
+ Sleep (1000);
+
+ while (QueryServiceStatus (service, &status))
{
- if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
- {
- _tprintf(TEXT("."));
- Sleep( 1000 );
- }
- else
- break;
+ if (status.dwCurrentState == SERVICE_STOP_PENDING)
+ {
+ _tprintf (TEXT("."));
+ Sleep (1000);
+ }
+ else
+ break;
}
- if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
- _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
- else
- {
- _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
- ret = 1;
- }
-
- }
-
- // now remove the service
- if ( DeleteService(schService) )
- _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
- else
- {
- _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
- ret = 1;
- }
-
-
- CloseServiceHandle(schService);
- }
+ if (status.dwCurrentState == SERVICE_STOPPED)
+ _tprintf (TEXT("\n%s stopped.\n"), ovpn_svc->display_name);
+ else
+ _tprintf (TEXT("\n%s failed to stop.\n"), ovpn_svc->display_name);
+ }
+
+ /* now remove the service */
+ if (DeleteService (service))
+ {
+ _tprintf (TEXT("%s removed.\n"), ovpn_svc->display_name);
+ --ret;
+ }
else
- {
- _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
- ret = 1;
- }
-
- CloseServiceHandle(schSCManager);
- }
- else
- {
- _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
- ret = 1;
- }
- return ret;
-}
-
-
-
-
-///////////////////////////////////////////////////////////////////
-//
-// The following code is for running the service as a console app
-//
-
-
-//
-// FUNCTION: CmdDebugService(int argc, char ** argv)
-//
-// PURPOSE: Runs the service as a console application
-//
-// PARAMETERS:
-// argc - number of command line arguments
-// argv - array of command line arguments
-//
-// RETURN VALUE:
-// none
-//
-// COMMENTS:
-//
-void CmdDebugService(int argc, char ** argv)
-{
- DWORD dwArgc;
- LPTSTR *lpszArgv;
-
-#ifdef UNICODE
- lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
- if (NULL == lpszArgv)
- {
- // CommandLineToArvW failed!!
- _tprintf(TEXT("CmdDebugService CommandLineToArgvW returned NULL\n"));
- return;
- }
-#else
- dwArgc = (DWORD) argc;
- lpszArgv = argv;
-#endif
-
- _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
-
- SetConsoleCtrlHandler( ControlHandler, TRUE );
+ _tprintf (TEXT("DeleteService failed - %s\n"), GetLastErrorText ());
- ServiceStart( dwArgc, lpszArgv );
-
-#ifdef UNICODE
-// Must free memory allocated for arguments
-
- GlobalFree(lpszArgv);
-#endif // UNICODE
+ CloseServiceHandle (service);
+ }
+out:
+ CloseServiceHandle (svc_ctl_mgr);
+ return ret;
}
-//
-// FUNCTION: ControlHandler ( DWORD dwCtrlType )
-//
-// PURPOSE: Handled console control events
-//
-// PARAMETERS:
-// dwCtrlType - type of control event
-//
-// RETURN VALUE:
-// True - handled
-// False - unhandled
-//
-// COMMENTS:
-//
-BOOL WINAPI ControlHandler ( DWORD dwCtrlType )
+int
+_tmain (int argc, TCHAR *argv[])
{
- switch ( dwCtrlType )
- {
- case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
- case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
- _tprintf(TEXT("Stopping %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
- ServiceStop();
- return TRUE;
- break;
-
- }
- return FALSE;
-}
-
-//
-// FUNCTION: GetLastErrorText
-//
-// PURPOSE: copies error message text to string
-//
-// PARAMETERS:
-// lpszBuf - destination buffer
-// dwSize - size of buffer
-//
-// RETURN VALUE:
-// destination buffer
-//
-// COMMENTS:
-//
-LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
-{
- DWORD dwRet;
- LPTSTR lpszTemp = NULL;
-
- dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
- NULL,
- GetLastError(),
- LANG_NEUTRAL,
- (LPTSTR)&lpszTemp,
- 0,
- NULL );
-
- // supplied buffer is not long enough
- if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
- lpszBuf[0] = TEXT('\0');
- else
- {
- lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
- _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, (int)GetLastError() );
- }
-
- if ( lpszTemp )
- LocalFree((HLOCAL) lpszTemp );
-
- return lpszBuf;
+ SERVICE_TABLE_ENTRY dispatchTable[] = {
+ { automatic_service.name, ServiceStartAutomatic },
+ { interactive_service.name, ServiceStartInteractive },
+ { NULL, NULL }
+ };
+
+ openvpn_service[0] = automatic_service;
+ openvpn_service[1] = interactive_service;
+
+ if (argc > 1 && (*argv[1] == TEXT('-') || *argv[1] == TEXT('/')))
+ {
+ if (_tcsicmp (TEXT("install"), argv[1] + 1) == 0)
+ return CmdInstallServices ();
+ else if (_tcsicmp (TEXT("remove"), argv[1] + 1) == 0)
+ return CmdRemoveServices ();
+ else if (_tcsicmp (TEXT("start"), argv[1] + 1) == 0)
+ {
+ BOOL is_auto = argc < 3 || _tcsicmp (TEXT("interactive"), argv[2]) != 0;
+ return CmdStartService (is_auto ? automatic : interactive);
+ }
+ else
+ goto dispatch;
+
+ return 0;
+ }
+
+ /* If it doesn't match any of the above parameters
+ * the service control manager may be starting the service
+ * so we must call StartServiceCtrlDispatcher
+ */
+dispatch:
+ _tprintf (TEXT("%s -install to install the services\n"), APPNAME);
+ _tprintf (TEXT("%s -start <name> to start a service (\"automatic\" or \"interactive\")\n"), APPNAME);
+ _tprintf (TEXT("%s -remove to remove the services\n"), APPNAME);
+ _tprintf (TEXT("\nStartServiceCtrlDispatcher being called.\n"));
+ _tprintf (TEXT("This may take several seconds. Please wait.\n"));
+
+ if (!StartServiceCtrlDispatcher (dispatchTable))
+ MsgToEventLog (MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed."));
+
+ return 0;
}
diff --git a/src/openvpnserv/service.h b/src/openvpnserv/service.h
index e89a89f..94bfb07 100644
--- a/src/openvpnserv/service.h
+++ b/src/openvpnserv/service.h
@@ -1,139 +1,92 @@
-/*---------------------------------------------------------------------------
-THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
-ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
-TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
-PARTICULAR PURPOSE.
-
-Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved.
-
- MODULE: service.h
-
- Comments: The use of this header file and the accompanying service.c
- file simplifies the process of writting a service. You as a developer
- simply need to follow the TODO's outlined in this header file, and
- implement the ServiceStart() and ServiceStop() functions.
-
- There is no need to modify the code in service.c. Just add service.c
- to your project and link with the following libraries...
-
- libcmt.lib kernel32.lib advapi.lib shell32.lib
-
- This code also supports unicode. Be sure to compile both service.c and
- and code #include "service.h" with the same Unicode setting.
-
- Upon completion, your code will have the following command line interface
-
- <service exe> -? to display this list
- <service exe> -install to install the service
- <service exe> -remove to remove the service
- <service exe> -debug <params> to run as a console app for debugging
-
- Note: This code also implements Ctrl+C and Ctrl+Break handlers
- when using the debug option. These console events cause
- your ServiceStop routine to be called
-
- Also, this code only handles the OWN_SERVICE service type
- running in the LOCAL_SYSTEM security context.
-
- To control your service ( start, stop, etc ) you may use the
- Services control panel applet or the NET.EXE program.
-
- To aid in writing/debugging service, the
- SDK contains a utility (MSTOOLS\BIN\SC.EXE) that
- can be used to control, configure, or obtain service status.
- SC displays complete status for any service/driver
- in the service database, and allows any of the configuration
- parameters to be easily changed at the command line.
- For more information on SC.EXE, type SC at the command line.
-
-
-------------------------------------------------------------------------------*/
+/*
+ * 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) 2013 Heiko Hund <heiko.hund@sophos.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
#ifndef _SERVICE_H
#define _SERVICE_H
-
-#ifdef __cplusplus
-extern "C" {
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
#endif
-//////////////////////////////////////////////////////////////////////////////
-//// todo: change to desired strings
-////
-// name of the executable
-#define SZAPPNAME PACKAGE "serv"
-// internal name of the service
-#define SZSERVICENAME PACKAGE_NAME "Service"
-// displayed name of the service
-#define SZSERVICEDISPLAYNAME PACKAGE_NAME " Service"
-// list of service dependencies - "dep1\0dep2\0\0"
-#define SZDEPENDENCIES TAP_WIN_COMPONENT_ID "\0Dhcp\0\0"
-//////////////////////////////////////////////////////////////////////////////
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//// todo: ServiceStart()must be defined by in your code.
-//// The service should use ReportStatusToSCMgr to indicate
-//// progress. This routine must also be used by StartService()
-//// to report to the SCM when the service is running.
-////
-//// If a ServiceStop procedure is going to take longer than
-//// 3 seconds to execute, it should spawn a thread to
-//// execute the stop code, and return. Otherwise, the
-//// ServiceControlManager will believe that the service has
-//// stopped responding
-////
- VOID ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv);
- VOID ServiceStop();
-//////////////////////////////////////////////////////////////////////////////
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//// The following are procedures which
-//// may be useful to call within the above procedures,
-//// but require no implementation by the user.
-//// They are implemented in service.c
-
-//
-// FUNCTION: ReportStatusToSCMgr()
-//
-// PURPOSE: Sets the current status of the service and
-// reports it to the Service Control Manager
-//
-// PARAMETERS:
-// dwCurrentState - the state of the service
-// dwWin32ExitCode - error code to report
-// dwWaitHint - worst case estimate to next checkpoint
-//
-// RETURN VALUE:
-// TRUE - success
-// FALSE - failure
-//
- BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
-
-
-//
-// FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
-//
-// PURPOSE: Allows any thread to log an error message
-//
-// PARAMETERS:
-// lpszMsg - text for message
-//
-// RETURN VALUE:
-// none
-//
-# define MSG_FLAGS_ERROR (1<<0)
-# define MSG_FLAGS_SYS_CODE (1<<1)
- void AddToMessageLog(DWORD flags, LPTSTR lpszMsg);
- void ResetError (void);
-//////////////////////////////////////////////////////////////////////////////
-
-
-#ifdef __cplusplus
-}
-#endif
+#include <windows.h>
+#include <stdlib.h>
+#include <tchar.h>
+
+#define APPNAME TEXT(PACKAGE "serv")
+#define SERVICE_DEPENDENCIES TAP_WIN_COMPONENT_ID "\0Dhcp\0\0"
+
+/*
+ * Message handling
+ */
+#define MSG_FLAGS_ERROR (1<<0)
+#define MSG_FLAGS_SYS_CODE (1<<1)
+#define M_INFO (0) /* informational */
+#define M_SYSERR (MSG_FLAGS_ERROR|MSG_FLAGS_SYS_CODE) /* error + system code */
+#define M_ERR (MSG_FLAGS_ERROR) /* error */
+
+typedef enum {
+ automatic,
+ interactive,
+ _service_max
+} openvpn_service_type;
+
+typedef struct {
+ openvpn_service_type type;
+ TCHAR *name;
+ TCHAR *display_name;
+ TCHAR *dependencies;
+ DWORD start_type;
+} openvpn_service_t;
+
+#define MAX_NAME 256
+typedef struct {
+ TCHAR exe_path[MAX_PATH];
+ TCHAR config_dir[MAX_PATH];
+ TCHAR ext_string[16];
+ TCHAR log_dir[MAX_PATH];
+ TCHAR ovpn_admin_group[MAX_NAME];
+ DWORD priority;
+ BOOL append;
+} settings_t;
+
+extern openvpn_service_t automatic_service;
+extern openvpn_service_t interactive_service;
+
+
+VOID WINAPI ServiceStartAutomatic (DWORD argc, LPTSTR *argv);
+VOID WINAPI ServiceStartInteractive (DWORD argc, LPTSTR *argv);
+
+int openvpn_vsntprintf (LPTSTR str, size_t size, LPCTSTR format, va_list arglist);
+int openvpn_sntprintf (LPTSTR str, size_t size, LPCTSTR format, ...);
+
+DWORD GetOpenvpnSettings (settings_t *s);
+
+BOOL ReportStatusToSCMgr (SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status);
+
+LPCTSTR GetLastErrorText ();
+DWORD MsgToEventLog (DWORD flags, LPCTSTR lpszMsg, ...);
#endif
diff --git a/src/openvpnserv/validate.c b/src/openvpnserv/validate.c
new file mode 100644
index 0000000..7458d75
--- /dev/null
+++ b/src/openvpnserv/validate.c
@@ -0,0 +1,249 @@
+/*
+ * 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) 2016 Selva Nair <selva.nair@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "validate.h"
+
+#include <lmaccess.h>
+#include <shlwapi.h>
+#include <lm.h>
+
+static const WCHAR *white_list[] =
+ {
+ L"auth-retry",
+ L"config",
+ L"log",
+ L"log-append",
+ L"management",
+ L"management-forget-disconnect",
+ L"management-hold",
+ L"management-query-passwords",
+ L"management-query-proxy",
+ L"management-signal",
+ L"management-up-down",
+ L"mute",
+ L"setenv",
+ L"service",
+ L"verb",
+
+ NULL /* last value */
+ };
+
+/*
+ * Check workdir\fname is inside config_dir
+ * The logic here is simple: we may reject some valid paths if ..\ is in any of the strings
+ */
+static BOOL
+CheckConfigPath (const WCHAR *workdir, const WCHAR *fname, const settings_t *s)
+{
+ WCHAR tmp[MAX_PATH];
+ const WCHAR *config_file = NULL;
+ const WCHAR *config_dir = NULL;
+
+ /* convert fname to full path */
+ if (PathIsRelativeW (fname) )
+ {
+ snwprintf (tmp, _countof(tmp), L"%s\\%s", workdir, fname);
+ tmp[_countof(tmp)-1] = L'\0';
+ config_file = tmp;
+ }
+ else
+ {
+ config_file = fname;
+ }
+
+#ifdef UNICODE
+ config_dir = s->config_dir;
+#else
+ if (MultiByteToWideChar (CP_UTF8, 0, s->config_dir, -1, widepath, MAX_PATH) == 0)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("Failed to convert config_dir name to WideChar"));
+ return FALSE;
+ }
+ config_dir = widepath;
+#endif
+
+ if (wcsncmp (config_dir, config_file, wcslen(config_dir)) == 0 &&
+ wcsstr (config_file + wcslen(config_dir), L"..") == NULL )
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/*
+ * A simple linear search meant for a small wchar_t *array.
+ * Returns index to the item if found, -1 otherwise.
+ */
+static int
+OptionLookup (const WCHAR *name, const WCHAR *white_list[])
+{
+ int i;
+
+ for (i = 0 ; white_list[i]; i++)
+ {
+ if ( wcscmp(white_list[i], name) == 0 )
+ return i;
+ }
+
+ return -1;
+}
+
+/*
+ * The Administrators group may be localized or renamed by admins.
+ * Get the local name of the group using the SID.
+ */
+static BOOL
+GetBuiltinAdminGroupName (WCHAR *name, DWORD nlen)
+{
+ BOOL b = FALSE;
+ PSID admin_sid = NULL;
+ DWORD sid_size = SECURITY_MAX_SID_SIZE;
+ SID_NAME_USE snu;
+
+ WCHAR domain[MAX_NAME];
+ DWORD dlen = _countof(domain);
+
+ admin_sid = malloc(sid_size);
+ if (!admin_sid)
+ return FALSE;
+
+ b = CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, admin_sid, &sid_size);
+ if(b)
+ {
+ b = LookupAccountSidW(NULL, admin_sid, name, &nlen, domain, &dlen, &snu);
+ }
+
+ free (admin_sid);
+
+ return b;
+}
+
+/*
+ * Check whether user is a member of Administrators group or
+ * the group specified in s->ovpn_admin_group
+ */
+BOOL
+IsAuthorizedUser (SID *sid, settings_t *s)
+{
+ LOCALGROUP_USERS_INFO_0 *groups = NULL;
+ DWORD nread;
+ DWORD nmax;
+ WCHAR *tmp = NULL;
+ const WCHAR *admin_group[2];
+ WCHAR username[MAX_NAME];
+ WCHAR domain[MAX_NAME];
+ WCHAR sysadmin_group[MAX_NAME];
+ DWORD err, len = MAX_NAME;
+ int i;
+ BOOL ret = FALSE;
+ SID_NAME_USE sid_type;
+
+ /* Get username */
+ if (!LookupAccountSidW (NULL, sid, username, &len, domain, &len, &sid_type))
+ {
+ MsgToEventLog (M_SYSERR, TEXT("LookupAccountSid"));
+ goto out;
+ }
+
+ /* Get an array of groups the user is member of */
+ err = NetUserGetLocalGroups (NULL, username, 0, LG_INCLUDE_INDIRECT, (LPBYTE *) &groups,
+ MAX_PREFERRED_LENGTH, &nread, &nmax);
+ if (err && err != ERROR_MORE_DATA)
+ {
+ SetLastError (err);
+ MsgToEventLog (M_SYSERR, TEXT("NetUserGetLocalGroups"));
+ goto out;
+ }
+
+ if (GetBuiltinAdminGroupName(sysadmin_group, _countof(sysadmin_group)))
+ {
+ admin_group[0] = sysadmin_group;
+ }
+ else
+ {
+ MsgToEventLog (M_SYSERR, TEXT("Failed to get the name of Administrators group. Using the default."));
+ /* use the default value */
+ admin_group[0] = SYSTEM_ADMIN_GROUP;
+ }
+
+#ifdef UNICODE
+ admin_group[1] = s->ovpn_admin_group;
+#else
+ tmp = NULL;
+ len = MultiByteToWideChar (CP_UTF8, 0, s->ovpn_admin_group, -1, NULL, 0);
+ if (len == 0 || (tmp = malloc (len*sizeof(WCHAR))) == NULL)
+ {
+ MsgToEventLog (M_SYSERR, TEXT("Failed to convert admin group name to WideChar"));
+ goto out;
+ }
+ MultiByteToWideChar (CP_UTF8, 0, s->ovpn_admin_group, -1, tmp, len);
+ admin_group[1] = tmp;
+#endif
+
+ /* Check if user's groups include any of the admin groups */
+ for (i = 0; i < nread; i++)
+ {
+ if ( wcscmp (groups[i].lgrui0_name, admin_group[0]) == 0 ||
+ wcscmp (groups[i].lgrui0_name, admin_group[1]) == 0
+ )
+ {
+ MsgToEventLog (M_INFO, TEXT("Authorizing user %s by virtue of membership in group %s"),
+ username, groups[i].lgrui0_name);
+ ret = TRUE;
+ break;
+ }
+ }
+
+out:
+ if (groups)
+ NetApiBufferFree (groups);
+ free (tmp);
+
+ return ret;
+}
+
+/*
+ * Check whether option argv[0] is white-listed. If argv[0] == "--config",
+ * also check that argv[1], if present, passes CheckConfigPath().
+ * The caller should set argc to the number of valid elements in argv[] array.
+ */
+BOOL
+CheckOption (const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s)
+{
+ /* Do not modify argv or *argv -- ideally it should be const WCHAR *const *, but alas...*/
+
+ if ( wcscmp (argv[0], L"--config") == 0 &&
+ argc > 1 &&
+ !CheckConfigPath (workdir, argv[1], s)
+ )
+ {
+ return FALSE;
+ }
+
+ /* option name starts at 2 characters from argv[i] */
+ if (OptionLookup (argv[0] + 2, white_list) == -1) /* not found */
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/src/openvpnserv/validate.h b/src/openvpnserv/validate.h
new file mode 100644
index 0000000..0d0270a
--- /dev/null
+++ b/src/openvpnserv/validate.h
@@ -0,0 +1,48 @@
+
+/*
+ * 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) 2016 Selva Nair <selva.nair@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef VALIDATE_H
+#define VALIDATE_H
+
+#include "service.h"
+
+/* Authorized groups who can use any options and config locations */
+#define SYSTEM_ADMIN_GROUP TEXT("Administrators")
+#define OVPN_ADMIN_GROUP TEXT("OpenVPN Administrators")
+/* The last one may be reset in registry: HKLM\Software\OpenVPN\ovpn_admin_group */
+
+BOOL
+IsAuthorizedUser (SID *sid, settings_t *s);
+
+BOOL
+CheckOption (const WCHAR *workdir, int narg, WCHAR *argv[], const settings_t *s);
+
+static inline BOOL
+IsOption (const WCHAR *o)
+{
+ return (wcsncmp (o, L"--", 2) == 0);
+}
+
+#endif
diff --git a/src/plugins/Makefile.in b/src/plugins/Makefile.in
index cc26bf4..0d1d59b 100644
--- a/src/plugins/Makefile.in
+++ b/src/plugins/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -25,17 +25,7 @@
# Copyright (C) 2006-2012 Alon Bar-Lev <alon.barlev@gmail.com>
#
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -99,6 +89,7 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = src/plugins
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/m4/ax_socklen_t.m4 \
@@ -109,9 +100,9 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/compat.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_HEADER = $(top_builddir)/config.h \
+ $(top_builddir)/include/openvpn-plugin.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
@@ -169,7 +160,6 @@ am__define_uniq_tagged_files = \
ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
am__relativize = \
dir0=`pwd`; \
@@ -208,6 +198,7 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CMAKE = @CMAKE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
@@ -242,25 +233,31 @@ LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LZ4_CFLAGS = @LZ4_CFLAGS@
+LZ4_LIBS = @LZ4_LIBS@
LZO_CFLAGS = @LZO_CFLAGS@
LZO_LIBS = @LZO_LIBS@
MAKEINFO = @MAKEINFO@
MAN2HTML = @MAN2HTML@
MANIFEST_TOOL = @MANIFEST_TOOL@
+MBEDTLS_CFLAGS = @MBEDTLS_CFLAGS@
+MBEDTLS_LIBS = @MBEDTLS_LIBS@
MKDIR_P = @MKDIR_P@
NETSTAT = @NETSTAT@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
-OPENSSL_CRYPTO_CFLAGS = @OPENSSL_CRYPTO_CFLAGS@
-OPENSSL_CRYPTO_LIBS = @OPENSSL_CRYPTO_LIBS@
-OPENSSL_SSL_CFLAGS = @OPENSSL_SSL_CFLAGS@
-OPENSSL_SSL_LIBS = @OPENSSL_SSL_LIBS@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENVPN_VERSION_MAJOR = @OPENVPN_VERSION_MAJOR@
+OPENVPN_VERSION_MINOR = @OPENVPN_VERSION_MINOR@
+OPENVPN_VERSION_PATCH = @OPENVPN_VERSION_PATCH@
OPTIONAL_CRYPTO_CFLAGS = @OPTIONAL_CRYPTO_CFLAGS@
OPTIONAL_CRYPTO_LIBS = @OPTIONAL_CRYPTO_LIBS@
OPTIONAL_DL_LIBS = @OPTIONAL_DL_LIBS@
+OPTIONAL_LZ4_CFLAGS = @OPTIONAL_LZ4_CFLAGS@
+OPTIONAL_LZ4_LIBS = @OPTIONAL_LZ4_LIBS@
OPTIONAL_LZO_CFLAGS = @OPTIONAL_LZO_CFLAGS@
OPTIONAL_LZO_LIBS = @OPTIONAL_LZO_LIBS@
OPTIONAL_PKCS11_HELPER_CFLAGS = @OPTIONAL_PKCS11_HELPER_CFLAGS@
@@ -286,8 +283,6 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PLUGIN_AUTH_PAM_CFLAGS = @PLUGIN_AUTH_PAM_CFLAGS@
PLUGIN_AUTH_PAM_LIBS = @PLUGIN_AUTH_PAM_LIBS@
-POLARSSL_CFLAGS = @POLARSSL_CFLAGS@
-POLARSSL_LIBS = @POLARSSL_LIBS@
RANLIB = @RANLIB@
RC = @RC@
ROUTE = @ROUTE@
@@ -302,6 +297,11 @@ TAP_CFLAGS = @TAP_CFLAGS@
TAP_WIN_COMPONENT_ID = @TAP_WIN_COMPONENT_ID@
TAP_WIN_MIN_MAJOR = @TAP_WIN_MIN_MAJOR@
TAP_WIN_MIN_MINOR = @TAP_WIN_MIN_MINOR@
+TEST_CFLAGS = @TEST_CFLAGS@
+TEST_LDFLAGS = @TEST_LDFLAGS@
+VENDOR_BUILD_ROOT = @VENDOR_BUILD_ROOT@
+VENDOR_DIST_ROOT = @VENDOR_DIST_ROOT@
+VENDOR_SRC_ROOT = @VENDOR_SRC_ROOT@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -378,6 +378,7 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/plugins/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -673,8 +674,6 @@ uninstall-am:
mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
ps ps-am tags tags-am uninstall uninstall-am
-.PRECIOUS: Makefile
-
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/plugins/auth-pam/Makefile.am b/src/plugins/auth-pam/Makefile.am
index 2aef311..e6dc27e 100644
--- a/src/plugins/auth-pam/Makefile.am
+++ b/src/plugins/auth-pam/Makefile.am
@@ -18,6 +18,7 @@ dist_doc_DATA = README.auth-pam
endif
openvpn_plugin_auth_pam_la_SOURCES = \
+ utils.c \
auth-pam.c \
pamdl.c pamdl.h \
auth-pam.exports
diff --git a/src/plugins/auth-pam/Makefile.in b/src/plugins/auth-pam/Makefile.in
index ee67141..90d5058 100644
--- a/src/plugins/auth-pam/Makefile.in
+++ b/src/plugins/auth-pam/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,17 +22,7 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -96,6 +86,8 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = src/plugins/auth-pam
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(am__dist_doc_DATA_DIST)
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/m4/ax_socklen_t.m4 \
@@ -106,10 +98,9 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/compat.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_doc_DATA_DIST) \
- $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_HEADER = $(top_builddir)/config.h \
+ $(top_builddir)/include/openvpn-plugin.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
@@ -143,7 +134,7 @@ am__installdirs = "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(docdir)"
LTLIBRARIES = $(plugin_LTLIBRARIES)
am__DEPENDENCIES_1 =
openvpn_plugin_auth_pam_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
-am_openvpn_plugin_auth_pam_la_OBJECTS = auth-pam.lo pamdl.lo
+am_openvpn_plugin_auth_pam_la_OBJECTS = utils.lo auth-pam.lo pamdl.lo
openvpn_plugin_auth_pam_la_OBJECTS = \
$(am_openvpn_plugin_auth_pam_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
@@ -168,7 +159,7 @@ AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
-DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/include
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
@@ -218,7 +209,6 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@@ -232,6 +222,7 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CMAKE = @CMAKE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
@@ -266,25 +257,31 @@ LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LZ4_CFLAGS = @LZ4_CFLAGS@
+LZ4_LIBS = @LZ4_LIBS@
LZO_CFLAGS = @LZO_CFLAGS@
LZO_LIBS = @LZO_LIBS@
MAKEINFO = @MAKEINFO@
MAN2HTML = @MAN2HTML@
MANIFEST_TOOL = @MANIFEST_TOOL@
+MBEDTLS_CFLAGS = @MBEDTLS_CFLAGS@
+MBEDTLS_LIBS = @MBEDTLS_LIBS@
MKDIR_P = @MKDIR_P@
NETSTAT = @NETSTAT@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
-OPENSSL_CRYPTO_CFLAGS = @OPENSSL_CRYPTO_CFLAGS@
-OPENSSL_CRYPTO_LIBS = @OPENSSL_CRYPTO_LIBS@
-OPENSSL_SSL_CFLAGS = @OPENSSL_SSL_CFLAGS@
-OPENSSL_SSL_LIBS = @OPENSSL_SSL_LIBS@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENVPN_VERSION_MAJOR = @OPENVPN_VERSION_MAJOR@
+OPENVPN_VERSION_MINOR = @OPENVPN_VERSION_MINOR@
+OPENVPN_VERSION_PATCH = @OPENVPN_VERSION_PATCH@
OPTIONAL_CRYPTO_CFLAGS = @OPTIONAL_CRYPTO_CFLAGS@
OPTIONAL_CRYPTO_LIBS = @OPTIONAL_CRYPTO_LIBS@
OPTIONAL_DL_LIBS = @OPTIONAL_DL_LIBS@
+OPTIONAL_LZ4_CFLAGS = @OPTIONAL_LZ4_CFLAGS@
+OPTIONAL_LZ4_LIBS = @OPTIONAL_LZ4_LIBS@
OPTIONAL_LZO_CFLAGS = @OPTIONAL_LZO_CFLAGS@
OPTIONAL_LZO_LIBS = @OPTIONAL_LZO_LIBS@
OPTIONAL_PKCS11_HELPER_CFLAGS = @OPTIONAL_PKCS11_HELPER_CFLAGS@
@@ -310,8 +307,6 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PLUGIN_AUTH_PAM_CFLAGS = @PLUGIN_AUTH_PAM_CFLAGS@
PLUGIN_AUTH_PAM_LIBS = @PLUGIN_AUTH_PAM_LIBS@
-POLARSSL_CFLAGS = @POLARSSL_CFLAGS@
-POLARSSL_LIBS = @POLARSSL_LIBS@
RANLIB = @RANLIB@
RC = @RC@
ROUTE = @ROUTE@
@@ -326,6 +321,11 @@ TAP_CFLAGS = @TAP_CFLAGS@
TAP_WIN_COMPONENT_ID = @TAP_WIN_COMPONENT_ID@
TAP_WIN_MIN_MAJOR = @TAP_WIN_MIN_MAJOR@
TAP_WIN_MIN_MINOR = @TAP_WIN_MIN_MINOR@
+TEST_CFLAGS = @TEST_CFLAGS@
+TEST_LDFLAGS = @TEST_LDFLAGS@
+VENDOR_BUILD_ROOT = @VENDOR_BUILD_ROOT@
+VENDOR_DIST_ROOT = @VENDOR_DIST_ROOT@
+VENDOR_SRC_ROOT = @VENDOR_SRC_ROOT@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -394,6 +394,7 @@ AM_CFLAGS = \
@ENABLE_PLUGIN_AUTH_PAM_TRUE@plugin_LTLIBRARIES = openvpn-plugin-auth-pam.la
@ENABLE_PLUGIN_AUTH_PAM_TRUE@dist_doc_DATA = README.auth-pam
openvpn_plugin_auth_pam_la_SOURCES = \
+ utils.c \
auth-pam.c \
pamdl.c pamdl.h \
auth-pam.exports
@@ -421,6 +422,7 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/auth-pam/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/plugins/auth-pam/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -485,20 +487,21 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth-pam.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pamdl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -743,8 +746,6 @@ uninstall-am: uninstall-dist_docDATA uninstall-pluginLTLIBRARIES
tags tags-am uninstall uninstall-am uninstall-dist_docDATA \
uninstall-pluginLTLIBRARIES
-.PRECIOUS: Makefile
-
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c
index 710accc..5ad3ec8 100644
--- a/src/plugins/auth-pam/auth-pam.c
+++ b/src/plugins/auth-pam/auth-pam.c
@@ -39,7 +39,6 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
-#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -48,7 +47,7 @@
#include <fcntl.h>
#include <signal.h>
#include <syslog.h>
-#include <stdint.h>
+#include "utils.h"
#include <openvpn-plugin.h>
@@ -117,94 +116,6 @@ struct user_pass {
/* Background process function */
static void pam_server (int fd, const char *service, int verb, const struct name_value_list *name_value_list);
-/* Read 'tosearch', replace all occurences of 'searchfor' with 'replacewith' and return
- * a pointer to the NEW string. Does not modify the input strings. Will not enter an
- * infinite loop with clever 'searchfor' and 'replacewith' strings.
- * Daniel Johnson - Progman2000@usa.net / djohnson@progman.us
- *
- * Retuns NULL when
- * - any parameter is NULL
- * - the worst-case result is to large ( >= SIZE_MAX)
- */
-static char *
-searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith)
-{
- if (!tosearch || !searchfor || !replacewith) return NULL;
-
- size_t tosearchlen = strlen(tosearch);
- size_t replacewithlen = strlen(replacewith);
- size_t templen = tosearchlen * replacewithlen;
-
- if (tosearchlen == 0 || strlen(searchfor) == 0 || replacewithlen == 0) {
- return NULL;
- }
-
- bool is_potential_integer_overflow = (templen == SIZE_MAX) || (templen / tosearchlen != replacewithlen);
-
- if (is_potential_integer_overflow) {
- return NULL;
- }
-
- // state: all parameters are valid
-
- const char *searching=tosearch;
- char *scratch;
-
- char temp[templen+1];
- temp[0]=0;
-
- scratch = strstr(searching,searchfor);
- if (!scratch) return strdup(tosearch);
-
- while (scratch) {
- strncat(temp,searching,scratch-searching);
- strcat(temp,replacewith);
-
- searching=scratch+strlen(searchfor);
- scratch = strstr(searching,searchfor);
- }
- return strdup(temp);
-}
-
-/*
- * Given an environmental variable name, search
- * the envp array for its value, returning it
- * if found or NULL otherwise.
- */
-static const char *
-get_env (const char *name, const char *envp[])
-{
- if (envp)
- {
- int i;
- const int namelen = strlen (name);
- for (i = 0; envp[i]; ++i)
- {
- if (!strncmp (envp[i], name, namelen))
- {
- const char *cp = envp[i] + namelen;
- if (*cp == '=')
- return cp + 1;
- }
- }
- }
- return NULL;
-}
-
-/*
- * Return the length of a string array
- */
-static int
-string_array_len (const char *array[])
-{
- int i = 0;
- if (array)
- {
- while (array[i])
- ++i;
- }
- return i;
-}
/*
* Socket read/write functions.
diff --git a/src/plugins/auth-pam/utils.c b/src/plugins/auth-pam/utils.c
new file mode 100644
index 0000000..4f2bec1
--- /dev/null
+++ b/src/plugins/auth-pam/utils.c
@@ -0,0 +1,113 @@
+/*
+ * 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-2010 OpenVPN Technologies, Inc. <sales@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
+ */
+
+/*
+ * OpenVPN plugin module to do PAM authentication using a split
+ * privilege model.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+#include "utils.h"
+
+char *
+searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith)
+{
+ if (!tosearch || !searchfor || !replacewith) return NULL;
+
+ size_t tosearchlen = strlen(tosearch);
+ size_t replacewithlen = strlen(replacewith);
+ size_t templen = tosearchlen * replacewithlen;
+
+ if (tosearchlen == 0 || strlen(searchfor) == 0 || replacewithlen == 0) {
+ return NULL;
+ }
+
+ bool is_potential_integer_overflow = (templen == SIZE_MAX) || (templen / tosearchlen != replacewithlen);
+
+ if (is_potential_integer_overflow) {
+ return NULL;
+ }
+
+ // state: all parameters are valid
+
+ const char *searching=tosearch;
+ char *scratch;
+
+ char temp[templen+1];
+ temp[0]=0;
+
+ scratch = strstr(searching,searchfor);
+ if (!scratch) return strdup(tosearch);
+
+ while (scratch) {
+ strncat(temp,searching,scratch-searching);
+ strcat(temp,replacewith);
+
+ searching=scratch+strlen(searchfor);
+ scratch = strstr(searching,searchfor);
+ }
+ return strdup(temp);
+}
+
+const char *
+get_env (const char *name, const char *envp[])
+{
+ if (envp)
+ {
+ int i;
+ const int namelen = strlen (name);
+ for (i = 0; envp[i]; ++i)
+ {
+ if (!strncmp (envp[i], name, namelen))
+ {
+ const char *cp = envp[i] + namelen;
+ if (*cp == '=')
+ return cp + 1;
+ }
+ }
+ }
+ return NULL;
+}
+
+int
+string_array_len (const char *array[])
+{
+ int i = 0;
+ if (array)
+ {
+ while (array[i])
+ ++i;
+ }
+ return i;
+}
diff --git a/src/plugins/auth-pam/utils.h b/src/plugins/auth-pam/utils.h
new file mode 100644
index 0000000..2f72040
--- /dev/null
+++ b/src/plugins/auth-pam/utils.h
@@ -0,0 +1,66 @@
+/*
+ * 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-2010 OpenVPN Technologies, Inc. <sales@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
+ */
+
+#ifndef _PLUGIN_AUTH_PAM_UTILS__H
+#define _PLUGIN_AUTH_PAM_UTILS__H
+
+/**
+ * Read 'tosearch', replace all occurences of 'searchfor' with 'replacewith' and return
+ * a pointer to the NEW string. Does not modify the input strings. Will not enter an
+ * infinite loop with clever 'searchfor' and 'replacewith' strings.
+ *
+ * @author Daniel Johnson - Progman2000@usa.net / djohnson@progman.us
+ *
+ * @param tosearch haystack to search in
+ * @param searchfor needle to search for in the haystack
+ * @param replacewith when a match is found, replace needle with this string
+ *
+ * @return Retuns NULL when any parameter is NULL or the worst-case result is to large ( >= SIZE_MAX).
+ * Otherwise it returns a pointer to a new buffer containing the modified input
+ */
+char *
+searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith);
+
+/**
+ * Given an environmental variable name, search
+ * the envp array for its value
+ *
+ * @param name Environment variable to look up
+ * @param envp Environment variable table with all key/value pairs
+ *
+ * @return Returns a pointer to the value of the enviroment variable if found, otherwise NULL is returned.
+ */
+const char *
+get_env (const char *name, const char *envp[]);
+
+/**
+ * Return the length of a string array
+ *
+ * @param array Pointer to the array to calculate size of
+ *
+ */
+int
+string_array_len (const char *array[]);
+
+#endif
diff --git a/src/plugins/down-root/Makefile.in b/src/plugins/down-root/Makefile.in
index c9768d5..e5c0ad5 100644
--- a/src/plugins/down-root/Makefile.in
+++ b/src/plugins/down-root/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -22,17 +22,7 @@
VPATH = @srcdir@
-am__is_gnu_make = { \
- if test -z '$(MAKELEVEL)'; then \
- false; \
- elif test -n '$(MAKE_HOST)'; then \
- true; \
- elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
- true; \
- else \
- false; \
- fi; \
-}
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
@@ -96,6 +86,8 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = src/plugins/down-root
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(am__dist_doc_DATA_DIST)
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/m4/ax_socklen_t.m4 \
@@ -106,10 +98,9 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
$(top_srcdir)/compat.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
-DIST_COMMON = $(srcdir)/Makefile.am $(am__dist_doc_DATA_DIST) \
- $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
-CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_HEADER = $(top_builddir)/config.h \
+ $(top_builddir)/include/openvpn-plugin.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
@@ -167,7 +158,7 @@ AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
-DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -I$(top_builddir)/include
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
@@ -217,7 +208,6 @@ am__define_uniq_tagged_files = \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
-am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
@@ -231,6 +221,7 @@ AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CMAKE = @CMAKE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
@@ -265,25 +256,31 @@ LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
-LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LZ4_CFLAGS = @LZ4_CFLAGS@
+LZ4_LIBS = @LZ4_LIBS@
LZO_CFLAGS = @LZO_CFLAGS@
LZO_LIBS = @LZO_LIBS@
MAKEINFO = @MAKEINFO@
MAN2HTML = @MAN2HTML@
MANIFEST_TOOL = @MANIFEST_TOOL@
+MBEDTLS_CFLAGS = @MBEDTLS_CFLAGS@
+MBEDTLS_LIBS = @MBEDTLS_LIBS@
MKDIR_P = @MKDIR_P@
NETSTAT = @NETSTAT@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
-OPENSSL_CRYPTO_CFLAGS = @OPENSSL_CRYPTO_CFLAGS@
-OPENSSL_CRYPTO_LIBS = @OPENSSL_CRYPTO_LIBS@
-OPENSSL_SSL_CFLAGS = @OPENSSL_SSL_CFLAGS@
-OPENSSL_SSL_LIBS = @OPENSSL_SSL_LIBS@
+OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
+OPENSSL_LIBS = @OPENSSL_LIBS@
+OPENVPN_VERSION_MAJOR = @OPENVPN_VERSION_MAJOR@
+OPENVPN_VERSION_MINOR = @OPENVPN_VERSION_MINOR@
+OPENVPN_VERSION_PATCH = @OPENVPN_VERSION_PATCH@
OPTIONAL_CRYPTO_CFLAGS = @OPTIONAL_CRYPTO_CFLAGS@
OPTIONAL_CRYPTO_LIBS = @OPTIONAL_CRYPTO_LIBS@
OPTIONAL_DL_LIBS = @OPTIONAL_DL_LIBS@
+OPTIONAL_LZ4_CFLAGS = @OPTIONAL_LZ4_CFLAGS@
+OPTIONAL_LZ4_LIBS = @OPTIONAL_LZ4_LIBS@
OPTIONAL_LZO_CFLAGS = @OPTIONAL_LZO_CFLAGS@
OPTIONAL_LZO_LIBS = @OPTIONAL_LZO_LIBS@
OPTIONAL_PKCS11_HELPER_CFLAGS = @OPTIONAL_PKCS11_HELPER_CFLAGS@
@@ -309,8 +306,6 @@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PLUGIN_AUTH_PAM_CFLAGS = @PLUGIN_AUTH_PAM_CFLAGS@
PLUGIN_AUTH_PAM_LIBS = @PLUGIN_AUTH_PAM_LIBS@
-POLARSSL_CFLAGS = @POLARSSL_CFLAGS@
-POLARSSL_LIBS = @POLARSSL_LIBS@
RANLIB = @RANLIB@
RC = @RC@
ROUTE = @ROUTE@
@@ -325,6 +320,11 @@ TAP_CFLAGS = @TAP_CFLAGS@
TAP_WIN_COMPONENT_ID = @TAP_WIN_COMPONENT_ID@
TAP_WIN_MIN_MAJOR = @TAP_WIN_MIN_MAJOR@
TAP_WIN_MIN_MINOR = @TAP_WIN_MIN_MINOR@
+TEST_CFLAGS = @TEST_CFLAGS@
+TEST_LDFLAGS = @TEST_LDFLAGS@
+VENDOR_BUILD_ROOT = @VENDOR_BUILD_ROOT@
+VENDOR_DIST_ROOT = @VENDOR_DIST_ROOT@
+VENDOR_SRC_ROOT = @VENDOR_SRC_ROOT@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
@@ -415,6 +415,7 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/down-root/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign src/plugins/down-root/Makefile
+.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
@@ -484,14 +485,14 @@ distclean-compile:
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -736,8 +737,6 @@ uninstall-am: uninstall-dist_docDATA uninstall-pluginLTLIBRARIES
tags tags-am uninstall uninstall-am uninstall-dist_docDATA \
uninstall-pluginLTLIBRARIES
-.PRECIOUS: Makefile
-
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.