diff options
Diffstat (limited to 'app/openvpn')
114 files changed, 6988 insertions, 3623 deletions
diff --git a/app/openvpn/.gitignore b/app/openvpn/.gitignore index 6a69be43..538c0208 100644 --- a/app/openvpn/.gitignore +++ b/app/openvpn/.gitignore @@ -25,6 +25,7 @@ aclocal.m4 autodefs.h autom4te.cache config.guess +config.h config.h.in config.log config.status @@ -53,3 +54,6 @@ tests/t_client.sh tests/t_client-*-20??????-??????/ src/openvpn/openvpn config-version.h +nbproject +test-driver +compile diff --git a/app/openvpn/Android.mk b/app/openvpn/Android.mk index 1a949451..6dfe6777 100644 --- a/app/openvpn/Android.mk +++ b/app/openvpn/Android.mk @@ -3,16 +3,32 @@ LOCAL_PATH:= $(call my-dir)/ include $(CLEAR_VARS) LOCAL_LDLIBS := -lz -LOCAL_C_INCLUDES := openssl/include lzo/include openssl/crypto openssl openvpn/src/compat openvpn/src/openvpn openvpn/include +LOCAL_C_INCLUDES := openssl/include lzo/include openssl/crypto openssl openvpn/src/compat openvpn/src/openvpn openvpn/include google-breakpad/src google-breakpad/src/common/android/include polarssl/include snappy + + -LOCAL_SHARED_LIBRARIES := libssl libcrypto -#LOCAL_STATIC_LIBRARIES := libssl_static libcrypto_static liblzo-static LOCAL_CFLAGS= -DHAVE_CONFIG_H -DTARGET_ABI=\"${TARGET_ABI}\" -LOCAL_STATIC_LIBRARIES := liblzo-static +LOCAL_STATIC_LIBRARIES := liblzo-static snappy-static + +ifeq ($(WITH_POLAR),1) +LOCAL_STATIC_LIBRARIES += polarssl-static +LOCAL_CFLAGS += -DENABLE_CRYPTO_POLARSSL=1 +else +#LOCAL_SHARED_LIBRARIES := libssl libcrypto +LOCAL_STATIC_LIBRARIES += libssl_static libcrypto_static +LOCAL_CFLAGS += -DENABLE_CRYPTO_OPENSSL=1 +endif + +ifeq ($(WITH_BREAKPAD),1) +LOCAL_STATIC_LIBRARIES += breakpad_client +LOCAL_CFLAGS += -DGOOGLE_BREAKPAD=1 +endif LOCAL_MODULE = openvpn + + LOCAL_SRC_FILES:= \ src/compat/compat-basename.c \ src/compat/compat-daemon.c \ @@ -20,13 +36,14 @@ LOCAL_SRC_FILES:= \ src/compat/compat-gettimeofday.c \ src/compat/compat-inet_ntop.c \ src/compat/compat-inet_pton.c \ - src/compat/compat-rsa_generate_key.c \ + src/compat/compat-lz4.c \ src/openvpn/base64.c \ src/openvpn/buffer.c \ src/openvpn/clinat.c \ src/openvpn/console.c \ src/openvpn/crypto.c \ src/openvpn/crypto_openssl.c \ + src/openvpn/crypto_polarssl.c \ src/openvpn/cryptoapi.c \ src/openvpn/dhcp.c \ src/openvpn/error.c \ @@ -80,11 +97,22 @@ LOCAL_SRC_FILES:= \ src/openvpn/socks.c \ src/openvpn/ssl.c \ src/openvpn/ssl_openssl.c \ + src/openvpn/ssl_polarssl.c \ src/openvpn/ssl_verify.c \ src/openvpn/ssl_verify_openssl.c \ src/openvpn/ssl_verify_polarssl.c \ src/openvpn/status.c \ - src/openvpn/tun.c + src/openvpn/tun.c \ + src/openvpn/snappy.c \ + src/openvpn/comp-lz4.c \ + src/openvpn/comp.c \ + src/openvpn/compstub.c \ + + +ifeq ($(WITH_BREAKPAD),1) +LOCAL_SRC_FILES+=src/openvpn/breakpad.cpp +endif + include $(BUILD_SHARED_LIBRARY) #include $(BUILD_EXECUTABLE) diff --git a/app/openvpn/ChangeLog.IPv6 b/app/openvpn/ChangeLog.IPv6 deleted file mode 100644 index 283fe6e6..00000000 --- a/app/openvpn/ChangeLog.IPv6 +++ /dev/null @@ -1,440 +0,0 @@ -Do 31. Dez 15:32:40 CET 2009 Gert Doering - - * Basic IPv6 p2mp functionality implemented - - * new options: - - server-ipv6 - - ifconfig-ipv6 - - ifconfig-ipv6-pool - - route-ipv6 - - iroute-ipv6 - - * modules touched: - - init.c: init & setup IPv6 route list & add/delete IPv6 routes - - tun.c: add "ifconfig" and "route" handling for IPv6 - - multi.c: IPv6 ifconfig-pool assignments - put to route-hash table - push to client - - pool.c: extend pools to handle IPv4+IPv6, and also return IPv6 address - IPv6 address saved to file if ifconfig-pool-persist is set - (but ignored on read due to the way pools work) - - mroute.c: handle reading src/dst addresses from IPv6 packets - (so multi.c can check against route-hash table) - handle printing of IPv6 mroute_addr structure - - helper.c: implement "server-ipv6" macro (->ifconfig-ipv6, pool, ...) - - options.c: implement all the new options - add helper functions for IPv6 address handling - - forward.c: tell do_route() about IPv6 routes - - route.c: handle IPv6 route lists + route option lists - extend add_routes() to do IPv4 + IPv6 route lists - extend delete_routes() to do IPv4 + IPv6 route lists - implement add_route_ipv6(), delete_route_ipv6() to call - system-dependend external program to do the work - - push.c: handle pushing of "ifconfig-ipv6" option - - socket.c: helper function to check & print IPv6 address strings - - * known issues: - - operating system support on all but Linux (ifconfig, route) - - route-ipv6 gateway handling - - iroute-ipv6 not implemented - - TAP support: ifconfig, routing (route needs gateway!) - - * release as patch 20091231-1 - -Thu Dec 31 17:02:08 CET 2009 - - * NetBSD port (NetBSD 3.1 on Sparc64) - - * mroute.c, socket.c: make byte/word access to in6_addr more portable - - * tun.c: fix IPv6 ifconfig arguments on NetBSD - - still doesn't work on NetBSD 3.1, "ifconfig tun0 inet6..." errors with - - ifconfig: SIOCAIFADDR: Address family not supported by protocol family - - (sys/net/if_tun.c, needs to be revision 1.80 or later, NetBSD PR 32944, - included in NetBSD 4.0 and up) - - -Fri Jan 1 14:07:15 CET 2010 - - * FreeBSD port (FreeBSD 6.3-p12 on i386) - - * tun.c: implement IPv6 ifconfig setting for FreeBSD - - * route.c: fix %s/%s argument to IPv6 route add/delete command for *BSD - - * TEST SUCCESS: FreeBSD 6.3-p12, server-ipv6, route-ipv6, ccd/iroute-ipv6 - - * multi.c: implement setting and deleting of iroute-ipv6 - (multi_add_iroutes(), multi_del_iroutes()) - * mroute.c: add mroute_helper_add_iroute6(), mroute_helper_del_iroute6() - * mroute.h: add prototypes, increase MR_HELPER_NET_LEN to 129 (/0.../128) - * multi.c: zeroize host part of IPv6 iroutes in multi_learn_in6_addr() - * mroute.c: implement mroute_addr_mask_host_bits() for IPv6 - - * TEST SUCCESS: Linux 2.6.30 (Gentoo)/iproute2, server-ipv6, ccd/iroute-ipv6 - - * TEST SUCCESS: Linux 2.6.30 (Gentoo)/ifconfig, client-ipv6 - - * TEST FAIL: NetBSD 5.0, IPv6 client - - "ifconfig tun0 .../64" does not create a "connected" route - - adding routes fails - - --> more work to do here. - - * release as patch 20100101-1 - - * TEST FAIL: - FreeBSD 6.3-p12 server "--topology subnet" - Linux/ifconfig client - - BSD sends ICMP6 neighbor solicitations, which are ignored by Linux - - server tun interface is not in p2p mode, client tun interface *is* - - * TEST SUCCESS: non-ipv6 enabled client -> "--server-ipv6" server - (warnings in the log file, but no malfunctions) - - -Sat Jan 2 19:48:35 CET 2010 - - * tun.c: change "ipv6_support()", do not turn off tt->ipv6 unconditionally - if we don't know about OS IPv6 support - just log warning - - * tun.c: implement "ifconfig inet6" setting for MacOS X / Darwin - - * route.c: split *BSD system dependent part of add/delete_route_ipv6() - into FreeBSD/Dragonfly and NetBSD/Darwin/OpenBSD variants - ("2001:db8::/64" vs. "2001:db8:: --prefixlen 64"). - - * tun.c: on MacOS X, NetBSD and OpenBSD, explicitely set on-link route - - * TEST SUCCESS: MacOS X, client-ipv6 with route-ipv6 - - -Sun Jan 3 10:55:31 CET 2010 - - * route.c: NetBSD fails with "-iface tun0", needs gateway address - (assume that the same syntax is needed for OpenBSD) - - * route.h: introduce "remote_endpoint_ipv6" into "struct route_ipv6_list" - - * init.c: pass "ifconfig_ipv6_remote" as gateway to init_route_ipv6_list() - - * route.c: - - init_route_ipv6(): use "remote_endpoint_ipv6" as IPv6 gateway address - if no gateway was specified explicitely - - - init_route_ipv6_list(): fill in "remote_endpoint_ipv6", if parseable - - - get rid of "GATEWAY-LESS ROUTE6" warning - - * route.c, add_route_ipv6() - - explicitely clear host bits of base address, to be able to more - easily set up "connected" /64 routes on NetBSD+Darwin - - - split system-dependent part between Darwin and NetBSD/OpenBSD - (Darwin can use "-iface tun0", NetBSD/OpenBSD get gateway address) - - - change Solaris comments from "known-broken" to "unknown" - - * tun.c: rework NetBSD tunnel initialization and tun_read() / tun_write() - to work the same way OpenBSD and NetBSD do - tunnel is put into - "multi-af" mode, and all packet read/write activity is prepended by - a 32 bit value specifying the address family. - - * TEST SUCCESS: NetBSD 5.0/Sparc64: client-ipv6 with route-ipv6 - - * TEST SUCCESS: MacOS X 10.5: client-ipv6 with route-ipv6 - - * (RE-)TEST SUCCESS: Linux/iproute2: server-ipv6 - Linux/ifconfig: client-ipv6 - FreeBSD 6.3: server-ipv6 - - * release as patch 20100103-1 - - * options.c: document all new options in "--help" - - * tun.c: fix typo in Solaris-specific section - - * socket.h, socket.c: change u_int32_t to uint32_t - (Solaris - and all the rest of the code uses "uintNN" anyway) - -Mon Jan 4 17:46:58 CET 2010 - - * socket.c: rework add_in6_addr() to use 32-bit access to struct in6_addr - (Solaris has no 16-bit values in union, but this is more elegant as well) - - * tun.c: fix "ifconfig inet6" command for Solaris - - * tun.c: make sure "tun0 inet6" is unplumbed first, cleanup leftovers - - * route.c: add routes with "metric 0" on solaris, otherwise they just - don't work (someone who understands Solaris might want to fix this). - - * Solaris "sort of" works now - ifconfig works, route add does not give - errors, "netstat -rn" looks right, but packets are discarded unless - the routes are installed with "metric 0". So we just use "metric 0"... - - * CAVEAT: Solaris "ifconfig ... preferred" interferes with source address - selection. So if there are any active IPv6 interfaces configured with - "preferred", packets leaving out the tunnel will use the wrong source - IPv6 address. Not fixable from within OpenVPN. - - * CAVEAT2: Solaris insists on doing DHCPv6 on tun0 interfaces by default, - so DHCPv6 solicitation packets will be seen. Since the server end has - no idea what to do with them, they are a harmless nuisance. Fixable - on the Solaris side via "ndpd.conf" (see ``man ifconfig''). - - * release as patch 20100104-1 - -Fri Jan 8 10:00:50 CET 2010 - - * import into git repository - - * options.c: add sanity checks for most typical error cases - (--ifconfig-ipv6-pool configured with no --ifconfig-ipv6, etc) - - * options.c: modify get_ipv6_addr() to be more flexible about netbits - (optional now, default to /64) and to return the address-without-netbits - string now (-> for options that want the IPv6 address in printable - form, but without /nn) - - * options.c: modify --ifconfig-ipv6 to optionally accept /netbits, - you can do now "ifconfig-ipv6 2001:df8::1/64 2001:df8::2" or just - "ifconfig-ipv6 2001:df8::5 2001:df8::7", defaulting to /64 - - * options.h: add necessary structure elements for --ifconfig-ipv6-push - - * options.c: implement "parse options" side of --ifconfig-ipv6-push - -Tue Jan 12 22:42:09 CET 2010 - - * tun.c: in TARGET_NETBSD #ifdef, distinguish between "old" code - (IPv4 only, but unmodified read/write) and "new" code (multi-af, - extra 32 bit AF on read/write of the tun interface) - pre-4.0 - NetBSD systems don't have TUNSIFHEAD, no way to have common code. - - * TEST SUCCESS: NetBSD 5.0/Sparc64: client-ipv6 with route-ipv6 (v4+v6) - - * TEST SUCCESS: NetBSD 3.1/Sparc64: client-ipv6 with route-ipv6 (v4-only) - -Thu Jan 14 15:41:50 CET 2010 - - * multi.c: if "--ifconfig-push" is used together with "--ifconfig-ipv6-pool" - and no "--ifconfig-ipv6-push" is seen, issue warning - the current - implementation of pools has IPv6 tied to IPv4, so if v4 does not use - the pool, it breaks for IPv6. Not a *big* problem (since there is - enough v6, just give those users a static v6 address as well), but needs - to be pointed out clearly. - - * release as patch 20100114-1 - -Tue Feb 16 14:43:28 CET 2010 - - * options.c: print "IPv6 payload patch" release date in "--version" - - * tun.c: undo change to init_tun() (moving "bool tun" and call to - "is_tun_p2p()" further up) - it wasn't needed and breaks "make check" - - * git stuff: rebase on David Sommerseth's openvpn-testing git tree - - * release as patch 20100216-1 - -Fri Feb 26 19:59:01 CET 2010 - - * init.c: initialize tuntap->ipv6 in do_init_tun() (to make sure it's - always initialized early-enough, independent of the sequence of - do_ifconfig()/open_tun() [see ifconfig_order() in tun.h]) - - * tun.c, init.c: remove "bool ipv6" argument to tuncfg(), open_tun() - and open_tun_generic() - obsoleted by previous change - - * tun.c: remove ipv6_support() - original purpose was unclear, and all - current platforms (except linux-very-old) fully support IPv6 now :-) - - * tun.c: initial implementation of "netsh" IPv6-ifconfig for Win32 - - * RE-TEST SUCCESS: Linux/i386/ifconfig, client-tun/net30, v4+v6 - -Sun Feb 28 17:05:57 CET 2010 - - * tun.c: NetBSD dependent part: correct destroying/re-creation of tun dev - - * tun.c: move adding of "connected" IPv6 prefix to new helper function, - add_route_connected_v6_net() - - * RE-TEST SUCCESS: NetBSD 5.0/Sparc64, client-tun/net30, v4+v6 - - * RE-TEST SUCCESS: NetBSD 3.1/Sparc64: client-tun/net30, v4-only - - * RE-TEST SUCCESS: Linux/i386/iproute2: server-tun/net30, v4+v6 - - * tun.c: add #ifdef TARGET_DARWIN block for *_tun() functions, to - be able to modify close_tun() for unconfiguring IPv6 - - * tun.c: on close_tun() on MacOS X, need to de-configure "lo0" route for - configured IPv6 address - - * RE-TEST SUCCESS: MacOS X (10.5)/i386: client-tun/net30, v4+v6 - - * route.c: implement ipv6 route adding / deletion via "netsh" for WIN32 - - * TEST FAIL: Windows XP fails, because the tun/tap driver does not - forward IPv6 frames kernel->userland if in "tun" mode - - * options.c: set IPv6 version to 20100228-1 - - * release as patch 20100228-1 - -Sun Mar 7 19:17:33 CET 2010 - - * options.c: set IPv6 version to 20100307-1 - - * TODO.IPv6: add note about OpenBSD TODO (#16) - - * route.c: set (and remove) "magic next hop" fe80::8 for IPv6 routes on - Win32 - - * install-win32/settings.in: bump TAP driver version from 9.6 to 9.7 - and TAP_RELDATE to "07/03/2010" - - * tap-win32/proto.h: add data types and definitions needed for IPv6 - - * tap-win32/types.h: add m_UserToTap_IPv6 ethernet header for IPv6 packets - - * tap-win32/tapdrvr.c: implement support for IPv6 in TUN mode: - - IPv6 packets User->OS need correct ether type - - IPv6 packets OS->User get correctly forwarded - - IPv6 neighbour discovery packets for "fe80::8" (magic address - installed as route-nexthop by OpenVPN.exe) get answered locally - - * TEST SUCCESS: WindowsXP/32bit: client-tun/net30, v4+v6 - - * tun.c: if IPv6 requested in TUN mode, and TUN/TAP driver version - is older than 9.7, log warning and disable IPv6 (won't work anyway). - - * release as patch 20100307-1 - -Sat Jul 10 14:37:52 CEST 2010 - - * TEST SUCCESS: point-to-point tun mode with --ifconfig-ipv6 between - Solaris10/sparc and Linux (Michal Ludvig) - (using the whiteboard tun driver on Solaris, otherwise "no IPv6") - -Sun Aug 8 12:30:44 CEST 2010 - - * route.c: split NetBSD and OpenBSD parts of add_route_ipv6() and - delete_route_ipv6(), implement OpenBSD variant - (needs "-prefixlen nn" while NetBSD uses "/nn") - - * tun.c: implement IPv6 ifconfig for OpenBSD - - * tun.c: destroy tunX interface at tun_close() on OpenBSD (cleanup) - - * TEST SUCCESS: OpenBSD 4.7: client-tun/net30, v4+v6 - -Thu Sep 2 21:18:32 CEST 2010 - - * tun.c: the TAP binary in 2.2-beta3 has the IPv6 related changes, but - the version number is 9.8 now -> check for 9.8, not 9.7 - -Wed Sep 22 22:20:37 CEST 2010 - - * tun.c: bugfix for Linux/iproute2/"topology subnet". Works :-) - - * TEST SUCCESS: Linux/ifconfig: client-tun/net30+subnet, v4+v6 - - * TEST SUCCESS: Linux/iproute2: client-tun/net30+subnet, v4+v6 - - * options.c: tag as 20100922-1 so "allmerged" users can see IPv6 change - -Fri Sep 24 17:57:41 CEST 2010 - - * TEST SUCCESS: Linux/<both>: client-tap, v4+v6, ping6 on connected addr - - * TEST FAIL: Linux/<both>: client-tap, v6, route6 (gateway missing) - -Do 21. Okt 19:36:49 CEST 2010 - - * t_client.sh.in: cherrypick commit f25fe91a40aa3f and 6f1e61b41be52 - (proper exit codes to signal "SKIP" if we do not want to run) - -So 16. Jan 17:25:23 CET 2011 - - * tun.c, route.c: cherrypick 121755c2cb4891f and f0eac1a5979096c67 - (TAP driver and "topology subnet" support for Solaris) - - * tun.c: add IPv6 configuration for TAP interfaces (<device>:1 inet6) - - * tun.c: on close_tun on Solaris, unplumb IPv6 TUN or TAP interfaces - - * TEST SUCCESS: OpenSolaris: client-tun, v4+v6 - TEST SUCCESS: OpenSolaris: client-tap, v4+v6, ping6 on connected addr - TEST FAIL: OpenSolaris: client-tap, v6, route6 (gateway missing) - -So 24. Apr 16:51:45 CEST 2011 - - * rebase to "beta2.2" branch (at 2.2RC2 tag) - - * mroute.c: remove mroute_helper_lock/_unlock() calls for IPv6 - * socket.c: remove locking with L_INET_NTOA mutex - (all the threading stuff got removed by David Sommerseth for 2.2) - - * mroute.c: remove duplicate mroute_helper_add_iroute6() and - mroute_helper_del_iroute6() - "git rebase" artefact - - * ChangeLog.IPv6 and TODO.IPv6: add to commit - - * options.c: tag as 20110424-2 (2.2RC2) - - * TEST SUCCESS: Linux/ifconfig: client-tun/net30+subnet, v4+v6 - - * TEST SUCCESS: Linux/iproute2: client-tun/net30+subnet, v4+v6 - -Thu Apr 28 19:10:01 CEST 2011 - - * rebase to "origin/release/2.2" branch (at v2.2.0 tag) - -Thu May 19 20:51:12 CEST 2011 - - * include Windows "netsh add" -> "netsh set ... store=active" patch from - Seth Mos, to fix restart problems on Windows due to persistant addresses - - * TEST SUCCESS: Windows XP SP3: client-tun/net30, v4+v6 - -Sat May 21 17:03:20 CEST 2011 - - * tun.c: Solaris cleanup (use CLEAR() to zero-out "ifr") - - * tun.c: Windows cleanup: remove route and IPv6 address on disconnect - - * route.c, route.h: remove "static" from delete_route_ipv6(), needed - for ipv6-route cleanup on disconnect - - * TEST SUCCESS: Windows XP SP3: client-tun/net30, v4+v6 - - * TEST SUCCESS: Windows 7 Home Premium: client-tun/net30, v4+v6 - -So 22. Mai 14:46:12 CEST 2011 - - * Tony Lim: removing routes fails on windows if certain bits are set - in the "host part" (others are silently ignored) --> - - * route.c: create print_in6_addr_netbits_only() helper, call from - add_route_ipv6() and delete_route_ipv6() to get only network part - of route-to-be-modified - - * route.c: set 'store=active' on adding routes on WIN32 as well (Tony Lim) - - * options.c: bump IPv6 release to 20110522-1 - - * TEST SUCCESS: Linux/iproute2: client-tun/net30+subnet, v4+v6 - - * TEST SUCCESS: Windows XP SP3: client-tun/net30, v4+v6 - - * TEST SUCCESS: Windows 7 Home Premium: client-tun/net30, v4+v6 - - * TEST SUCCESS: OpenBSD 4.7: client-tun/net30, v4+v6 - TEST FAIL: OpenBSD 4.7: client-tun/subnet, v4 - (seems to be due to "topology subnet has just not been implemented yet") diff --git a/app/openvpn/INSTALL b/app/openvpn/INSTALL index 4ca72883..2ef7904b 100644 --- a/app/openvpn/INSTALL +++ b/app/openvpn/INSTALL @@ -12,36 +12,53 @@ QUICK START: Unix: ./configure && make && make-install - Windows MinGW, using MSYS bash shell: - ./domake-win (see comments in the script for more info) + Cross-compile for Windows on Unix - Windows Visual Studio: - python win\build_all.py + See INSTALL-win32.txt ************************************************************************* To download OpenVPN, go to: - http://openvpn.net/download.html + http://openvpn.net/download.html -For step-by-step installation instructions with real-world -examples see: +OpenVPN releases are also available as Debian/RPM packages: - http://openvpn.net/howto.html + https://community.openvpn.net/openvpn/wiki/OpenvpnSoftwareRepos + +To download easy-rsa go to: + + https://github.com/OpenVPN/easy-rsa + +To download tap-windows driver source code go to: + + https://github.com/OpenVPN/tap-windows + +To get the cross-compilation environment go to: + + https://github.com/OpenVPN/openvpn-build + +For step-by-step instructions with real-world examples see: + + http://openvpn.net/howto.html + https://community.openvpn.net/openvpn/wiki For examples see: - http://openvpn.net/examples.html + http://openvpn.net/examples.html + +Also see the man page for more information, usage examples, and information on +firewall configuration. ************************************************************************* SUPPORTED PLATFORMS: - (1) Linux 2.2+ + (1) Linux (kernel 2.6+) (2) Solaris - (3) OpenBSD 3.0+ (Comes with OpenSSL and TUN devices by default) - (4) Mac OS X Darwin - (5) FreeBSD - (6) NetBSD + (3) OpenBSD 5.1+ + (4) Mac OS X Darwin 10.5+ + (5) FreeBSD 7.4+ + (6) NetBSD 5.0+ (7) Windows (WinXP and higher) SUPPORTED PROCESSOR ARCHITECTURES: @@ -55,34 +72,42 @@ REQUIRES: TUN/TAP Driver Configuration section below for more info. OPTIONAL (but recommended): - (1) OpenSSL library, necessary for encryption, version 0.9.5 or higher + (1) OpenSSL library, necessary for encryption, version 0.9.8 or higher required, available from http://www.openssl.org/ - (2) LZO real-time compression library, required for link compression, + (2) PolarSSL library, an alternative for encryption, version 1.1 or higher + required, available from https://polarssl.org/ + (3) LZO real-time compression library, required for link compression, available from http://www.oberhumer.com/opensource/lzo/ OpenBSD users can use ports or packages to install lzo, but remember to add CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" directives to "configure", since gcc will not find them otherwise. - (3) Pthread library. OPTIONAL (for developers only): (1) Autoconf 2.59 or higher + Automake 1.9 or higher -- available from http://www.gnu.org/software/software.html (2) Dmalloc library -- available from http://dmalloc.com/ + (3) If using t_client.sh test framework, fping/fping6 is needed + -- Available from http://www.fping.org/ + Note: t_client.sh needs an external configured OpenVPN server. + See t_client.rc-sample for more info. ************************************************************************* CHECK OUT SOURCE FROM SOURCE REPOSITORY: - git clone https://github.com/OpenVPN/openvpn + Clone the repository: + + git clone https://github.com/OpenVPN/openvpn + git clone git://openvpn.git.sourceforge.net/gitroot/openvpn/openvpn Check out stable version: - git checkout -b 2.2 remotes/origin/release/2.2 + git checkout -b 2.2 remotes/origin/release/2.2 Check out master (unstable) branch: - git checkout master + git checkout master ************************************************************************* @@ -112,7 +137,7 @@ BUILD A TARBALL FROM SOURCE REPOSITORY CHECKOUT: ************************************************************************* -LOOPBACK TESTS (after BUILD): +TESTS (after BUILD): make check (Run all tests below) @@ -126,6 +151,9 @@ Test SSL/TLS negotiations (runs for 2 minutes): ./openvpn --config sample/sample-config-files/loopback-client (In one window) ./openvpn --config sample/sample-config-files/loopback-server (Simultaneously in another window) +For more thorough client-server tests you can configure your own, private test +environment. See tests/t_client.rc-sample for details. + ************************************************************************* OPTIONS for ./configure: @@ -145,8 +173,6 @@ OPTIONS for ./configure: --disable-server disable server support only (but retain client support) [default=yes] --disable-plugins disable plug-in support [default=yes] - --disable-eurephia disable support for the eurephia plug-in - [default=yes] --disable-management disable management server support [default=yes] --enable-pkcs11 enable pkcs11 support [default=no] --disable-socks disable Socks support [default=yes] @@ -205,7 +231,7 @@ ENVIRONMENT for ./configure: ************************************************************************* -BUILDING ON LINUX 2.4+ FROM RPM +BUILDING ON LINUX 2.6+ FROM RPM You can build a binary RPM directly from the OpenVPN tarball file: @@ -224,7 +250,7 @@ startup or shutdown, based on OpenVPN .conf files in /etc/openvpn. See the comments in openvpn.init for more information. Installing the RPM will also configure the TUN/TAP device node -for linux 2.4. +for linux 2.6. Note that the current openvpn.spec file, which instructs the rpm tool how to build a package, will build OpenVPN with all options enabled, @@ -236,56 +262,15 @@ you edit the openvpn.spec file. TUN/TAP Driver Configuration: -* Linux 2.4 or higher (with integrated TUN/TAP driver): - - (1) make device node: mknod /dev/net/tun c 10 200 - (2a) add to /etc/modules.conf: alias char-major-10-200 tun - (2b) load driver: modprobe tun - (3) enable routing: echo 1 > /proc/sys/net/ipv4/ip_forward - - Note that either of steps (2a) or (2b) is sufficient. While (2a) - only needs to be done once per install, (2b) needs to be done once - per reboot. If you install from RPM (see above) and use the - openvpn.init script, these steps are taken care of for you. +* Linux 2.6 or higher (with integrated TUN/TAP driver): -* Linux 2.2 or Solaris: + (1) load driver: modprobe tun + (2) enable routing: echo 1 > /proc/sys/net/ipv4/ip_forward - You should obtain - version 1.1 of the TUN/TAP driver from - http://vtun.sourceforge.net/tun/ - and follow the installation instructions. + Note that (1) needs to be done once per reboot. If you install from RPM (see + above) and use the openvpn.init script, these steps are taken care of for you. - If you use OpenVPN on Linux 2.2 or 2.4 or Solaris, you may be - suffering from a bug which causes connections to hang under heavy load. - The symptoms are very similar to the MTU problems discussed frequently - in the OpenVPN mailing lists. But it turns out that this bug is not caused by - MTU problems. It's a bug in the tun/tap driver. A patch is provided here: - - http://openvpn.net/patch/tun-sb.patch - -* Solaris - - For 64 bit, I used the tun-1.1.tar.gz source and compiled it. - - Of course there is a but :) - In the tun-1-1\solaris\Makefile I changed a line so it compiles with 64 bit - - CFLAGS = $(DEFS) -m64 -O2 -Wall -D_KERNEL -I. - - I just added -m64 and it worked. - - The tun driver works fine as said previously, however we noticed there is a - minor problem when creating multiple tunnels on Solaris. - Mr Tycho Fruru changed the code in tun.c file where he locked the tun device - number to -1. This way it is impossible to specify the name of the tun device - but it is still possible to have multiple devices. - The modification will increment automatically meaning starting from tun0 ---> - tunX I know you are not responsible for the tun coding but if you think the - modification can be useful for you feel free to use it. - - http://openvpn.net/solaris/tun.c - -* FreeBSD 4.1.1+: +* FreeBSD: FreeBSD ships with the TUN/TAP driver, and the device nodes for tap0, tap1, tap2, tap3, tun0, tun1, tun2 and tun3 are made by default. @@ -303,41 +288,23 @@ TUN/TAP Driver Configuration: * OpenBSD: - OpenBSD ships with tun0 and tun1 installed by default on pre-3.5 systems, - while 3.5 and later have dynamically created tun* devices so you only need + OpenBSD has dynamically created tun* devices so you only need to create an empty /etc/hostname.tun0 (tun1, tun2 and so on) for each tun you plan to use to create the device(s) at boot. -* Mac OS X: - - 2005.02.13: Angelo Laub has developed a GUI for OS X: - - http://rechenknecht.net/OpenVPN-GUI/ - - 2004.10.26: Mattias Nissler has developed a new TUN/TAP driver for - MAC OS X: - - http://www-user.rhrk.uni-kl.de/~nissler/tuntap/ - - Christoph Pfisterer's old TUN driver can be obtained at - http://chrisp.de/en/projects/tunnel.html -- note that it - is no longer being maintained. +* Solaris: -* Solaris9 Sparc/64 + You need a TUN/TAP kernel driver for OpenVPN to work: - The kernel module for solaris - can be generated by adding the -m64 switch to a modern - gcc compiler (I'm using 3.2) The resulting kernel driver - needs to be manually copied to /kernel/drv/sparcv9/ and then a - reconfiguration reboot. (boot -r). + http://www.whiteboard.ne.jp/~admin2/tuntap/ -* Windows XP/2003/Vista +* Windows XP/2003/Vista/7: - See domake-win for building instructions. - See INSTALL-win32.txt for usage info. + OpenVPN on Windows needs a TUN/TAP kernel driver to work. OpenVPN installers + include this driver, so installing it separately is not usually required. + The driver source code is available here: - See the man page for more information, usage examples, and - information on firewall configuration. + https://github.com/OpenVPN/tap-windows ************************************************************************* diff --git a/app/openvpn/INSTALL-win32.txt b/app/openvpn/INSTALL-win32.txt index 1ef3869c..7c056858 100644 --- a/app/openvpn/INSTALL-win32.txt +++ b/app/openvpn/INSTALL-win32.txt @@ -46,3 +46,32 @@ the lower-right corner of the screen. Right click on the system tray icon, and a menu should appear showing the names of your OpenVPN configuration files, and giving you the option to connect. + +BUILDING OPENVPN FOR WINDOWS + +Official OpenVPN Windows releases are cross-compiled on Linux using the +openvpn-build buildsystem: + + https://community.openvpn.net/openvpn/wiki/BuildingUsingGenericBuildsystem + +First setup the build environment as shown in the above article. Then fetch the +openvpn-build repository: + + git clone https://github.com/OpenVPN/openvpn-build.git + +Review the build configuration: + + openvpn-build/generic/build.vars + openvpn-build/windows-nsis/build-complete.vars + +Build (unsigned): + + cd openvpn-build/windows-nsis + ./build-complete + +Build (signed): + + cd openvpn-build/windows-nsis + ./build-complete --sign --sign-pkcs12=<pkcs12-file>\ + --sign-pkcs12-pass=<pkcs12-file-password> \ + --sign-timestamp="<timestamp-url>" diff --git a/app/openvpn/Makefile.am b/app/openvpn/Makefile.am index c5805797..66d9f23a 100644 --- a/app/openvpn/Makefile.am +++ b/app/openvpn/Makefile.am @@ -41,7 +41,7 @@ MAINTAINERCLEANFILES = \ $(srcdir)/config.guess $(srcdir)/config.sub CLEANFILES = \ - config-version.h + config-version.h tests/t_client.sh EXTRA_DIST = \ contrib \ @@ -66,7 +66,6 @@ dist_doc_DATA = \ dist_noinst_DATA = \ .gitignore \ .gitattributes \ - config-version.h.in \ PORTS \ README.IPv6 TODO.IPv6 \ README.polarssl \ @@ -91,8 +90,12 @@ root_DATA = version.sh endif config-version.h: - @CONFIGURE_GIT_REVISION="`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) rev-parse --symbolic-full-name HEAD`/`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) rev-parse --short=16 HEAD`"; \ - $(SED) "s#@CONFIGURE_GIT_REVISION[@]#$${CONFIGURE_GIT_REVISION}#g" "$(srcdir)/config-version.h.in" > config-version.h.tmp + @CONFIGURE_GIT_CHFILES="`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) diff-files --name-status -r --ignore-submodules --quiet -- || echo \"+\"`"; \ + CONFIGURE_GIT_UNCOMMITTED="`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) diff-index --cached --quiet --ignore-submodules HEAD || echo \"*\"`"; \ + CONFIGURE_GIT_REVISION="`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) rev-parse --symbolic-full-name HEAD | cut -d/ -f3-`/`GIT_DIR=\"$(top_srcdir)/.git\" $(GIT) rev-parse --short=16 HEAD`"; \ + echo "#define CONFIGURE_GIT_REVISION \"$${CONFIGURE_GIT_REVISION}\"" > config-version.h.tmp; \ + echo "#define CONFIGURE_GIT_FLAGS \"$${CONFIGURE_GIT_CHFILES}$${CONFIGURE_GIT_UNCOMMITTED}\"" >> config-version.h.tmp + @if ! [ -f config-version.h ] || ! cmp -s config-version.h.tmp config-version.h; then \ echo "replacing config-version.h"; \ mv config-version.h.tmp config-version.h; \ diff --git a/app/openvpn/README b/app/openvpn/README index 2c5e6f6f..349e08af 100644 --- a/app/openvpn/README +++ b/app/openvpn/README @@ -40,36 +40,33 @@ Other Files & Directories: * configure.ac -- script to rebuild our configure script and makefile. -* openvpn.spec -- RPM Spec file - To build an OpenVPN binary RPM, use the command: - - rpmbuild -tb [tarball] - - When you install the binary RPM, it will automatically - install sample-scripts/openvpn.init (see below) - -* sample-scripts/openvpn.init - - A sample init script for OpenVPN. See the file for - comments and additional information. - -* sample-scripts/verify-cn +* sample/sample-scripts/verify-cn A sample perl script which can be used with OpenVPN's --tls-verify option to provide a customized authentication test on embedded X509 certificate fields. -* sample-keys/ +* sample/sample-keys/ Sample RSA keys and certificates. DON'T USE THESE FILES FOR ANYTHING OTHER THAN TESTING BECAUSE THEY ARE TOTALLY INSECURE. -* sample-config-files/ +* sample/sample-config-files/ A collection of OpenVPN config files and scripts from the HOWTO at http://openvpn.net/howto.html -* easy-rsa/ +************************************************************************* + +Note that easy-rsa and tap-windows are now maintained in their own subprojects. +Their source code is available here: + + https://github.com/OpenVPN/easy-rsa + https://github.com/OpenVPN/tap-windows + +The old cross-compilation environment (domake-win) and the Python-based +buildsystem have been replaced with openvpn-build: + + https://github.com/OpenVPN/openvpn-build - A simple guide to RSA key management, scripts included. - Also see http://openvpn.net/easyrsa.html +See the INSTALL file for usage information. diff --git a/app/openvpn/README.IPv6 b/app/openvpn/README.IPv6 index d504f4ff..18068fee 100644 --- a/app/openvpn/README.IPv6 +++ b/app/openvpn/README.IPv6 @@ -1,97 +1,56 @@ +Since 2.3.0, OpenVPN officially supports IPv6, and all widely used +patches floating around for older versions have been integrated. + IPv6 payload support -------------------- -Latest IPv6 payload support code and documentation can be found from here: +This is for "IPv6 inside OpenVPN", with server-pushed IPv6 configuration +on the client, and support for IPv6 configuration on the tun/tap interface +from within the openvpn config. + +The code in 2.3.0 supersedes the IPv6 payload patches from Gert Doering, +formerly located at http://www.greenie.net/ipv6/openvpn.html + - http://www.greenie.net/ipv6/openvpn.html +The following options have been added to handle IPv6 configuration, +analogous to their IPv4 counterparts (--server <-> --server-ipv6, etc.) -For TODO list, see TODO.IPv6. + - server-ipv6 + - ifconfig-ipv6 + - ifconfig-ipv6-pool + - ifconfig-ipv6-push + - route-ipv6 + - iroute-ipv6 -Gert Doering, 31.12.2009 +see "man openvpn" for details how they are used. IPv6 transport support ---------------------- -[ Last updated: 25-Mar-2011. ] - -OpenVPN-2.1 over UDP6/TCP6 README for ipv6-0.4.x patch releases: -( --udp6 and --tcp6-{client,server} ) - -* Availability - Source code under GPLv2 from http://github.com/jjo/openvpn-ipv6 - - Distro ready repos/packages: - o Debian sid official repo, by Alberto Gonzalez Iniesta, - starting from openvpn_2.1~rc20-2 - o Gentoo official portage tree, by Marcel Pennewiss: - - https://bugs.gentoo.org/show_bug.cgi?id=287896 - o Ubuntu package, by Bernhard Schmidt: - - https://launchpad.net/~berni/+archive/ipv6/+packages - o Freetz.org, milestone freetz-1.2 - - http://trac.freetz.org/milestone/freetz-1.2 - -* Status: - o OK: - - upd6,tcp6: GNU/Linux, win32, openbsd-4.7, freebsd-8.1 - - udp4->upd6,tcp4->tcp6 (ipv4/6 mapped): GNU/Linux - (gives a warning on local!=remote proto matching) - o NOT: - - win32: tcp4->tcp6 (ipv4/6 mapped) fails w/connection refused - o NOT tested: - - mgmt console - -* Build setup: - ./configure --enable-ipv6 (by default) - -* Usage: - For IPv6 just specify "-p upd6" an proper IPv6 hostnames, adapting the example - from man page ... - - On may: - openvpn --proto udp6 --remote <june_IPv6_addr> --dev tun1 \ - --ifconfig 10.4.0.1 10.4.0.2 --verb 5 --secret key - - On june: - openvpn --proto udp6 --remote <may_IPv6_addr> --dev tun1 \ - --ifconfig 10.4.0.2 10.4.0.1 --verb 5 --secret key - - Same for --proto tcp6-client, tcp6-server. - -* Main code changes summary: - - socket.h: New struct openvpn_sockaddr type that holds sockaddrs and pktinfo, - (here I omitted #ifdef USE_PF_xxxx, see socket.h ) - - struct openvpn_sockaddr { - union { - struct sockaddr sa; - struct sockaddr_in in; - struct sockaddr_in6 in6; - } addr; - }; - - struct link_socket_addr - { - struct openvpn_sockaddr local; - struct openvpn_sockaddr remote; - struct openvpn_sockaddr actual; - }; - - PRO: allows simple type overloading: local.addr.sa, local.addr.in, local.addr.in6 ... etc - (also local.pi.in and local.pi.in6) - - - several function prototypes moved from sockaddr_in to openvpn_sockaddr - - several new sockaddr functions needed to "generalize" AF_xxxx operations: - addr_copy(), addr_zero(), ...etc - proto_is_udp(), proto_is_dgram(), proto_is_net() - -* For TODO list, see TODO.IPv6 - --- -JuanJo Ciarlante jjo () google () com ............................ -: : -. Linux IP Aliasing author . -. Modular algo (AES et all) support for FreeSWAN/OpenSWAN author . -. OpenVPN over IPv6 support . -:...... plus other scattered free software bits in the wild ...: +This is to enable OpenVPN peers or client/servers to talk to each other +over an IPv6 network ("OpenVPN over IPv6"). + +The code in 2.3.0 supersedes the IPv6 transport patches from JuanJo Ciarlante, +formerly located at http://github.com/jjo/openvpn-ipv6 + +OpenVPN 2.4.0 includes a big overhaul of the IPv6 transport patches +originally implemented for the Android client (ics-openvpn) + +IPv4/IPv6 transport is automatically is selected when resolving addresses. +Use a 6 or 4 suffix to force IPv6/IPv4: + + --proto udp6 + --proto tcp4 + --proto tcp6-client + --proto tcp4-server + --proto tcp6 --client / --proto tcp6 --server + +On systems that allow IPv4 connections on IPv6 sockets +(all systems supporting IPV6_V6ONLY setsockopt), an OpenVPN server can +handle IPv4 connections on the IPv6 socket as well, making it a true +dual-stacked server. Use bind ipv6only to disable this behaviour. + +On other systems, as of 2.3.0, you need to run separate server instances +for IPv4 and IPv6. diff --git a/app/openvpn/README.ec b/app/openvpn/README.ec new file mode 100644 index 00000000..32938017 --- /dev/null +++ b/app/openvpn/README.ec @@ -0,0 +1,35 @@ +Since 2.4.0, OpenVPN has official support for elliptic curve crypto. Elliptic +curves are an alternative to RSA for asymmetric encryption. + +Elliptic curve crypto ('ECC') can be used for the ('TLS') control channel only +in OpenVPN; the data channel (encrypting the actual network traffic) uses +symmetric encryption. ECC can be used in TLS for authentication (ECDSA) and key +exchange (ECDH). + +Key exchange (ECDH) +------------------- +OpenVPN 2.4.0 and newer automatically initialize ECDH parameters. When ECDSA is +used for authentication, the curve used for the server certificate will be used +for ECDH too. When autodetection fails (e.g. when using RSA certificates) +OpenVPN lets the crypto library decide if possible, or falls back to the +secp384r1 curve. + +An administrator can force an OpenVPN/OpenSSL server to use a specific curve +using the --ecdh-curve <curvename> option with one of the curves listed as +available by the --show-curves option. Clients will use the same curve as +selected by the server. + +Note that not all curves listed by --show-curves are available for use with TLS; +in that case connecting will fail with a 'no shared cipher' TLS error. + +Authentication (ECDSA) +---------------------- +Since OpenVPN 2.4.0, using ECDSA certificates works 'out of the box'. Which +specific curves and cipher suites are available depends on your version and +configuration of the crypto library. The crypto library will automatically +select a cipher suite for the TLS control channel. + +Support for generating an ECDSA certificate chain is available in EasyRSA (in +spite of it's name) since EasyRSA 3.0. The parameters you're looking for are +'--use-algo=ec' and '--curve=<curve_name>'. See the EasyRSA documentation for +more details on generating ECDSA certificates. diff --git a/app/openvpn/TODO.IPv6 b/app/openvpn/TODO.IPv6 index 29d75546..24bf865a 100644 --- a/app/openvpn/TODO.IPv6 +++ b/app/openvpn/TODO.IPv6 @@ -183,7 +183,7 @@ tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500 TODO for IPv6 transport support ------------------------------- -[ Last updated: 10-Jun-2012. ] +[ Last updated: 2014-01-03. ] * All platforms: o mgmt console: as currently passes straight in_addr_t bits around @@ -191,19 +191,25 @@ TODO for IPv6 transport support o make possible to get AF from getaddrinfo() answer, ie allow openvpn to use ipv4/6 if DNS returns A/AAAA without specifying protocol. Hard: requires deep changes in initialization/calling logic + - Done by dual stack patches o use AI_PASSIVE + - Done by dual stack patches o the getaddr()/getaddr6() interface is not prepared for handling socktype "tagging", currently I abuse the sockflags bits for getting the ai_socktype downstream. + - Still done by flags, seems clean enough. o implement comparison for mapped addesses: server in dual stack listening IPv6 must permit incoming streams from allowed IPv4 peer, currently you need to pass eg: --remote ffff::1.2.3.4 - + - OpenVPN will compare all address of a remote + but will still fail on mapped addresses * win32: o find out about mapped addresses, as I can't make it work with bound at ::1 and connect to 127.0.0.1 + - Should be fixed by 8832c6c - "Implement listing on IPv4/IPv6 dual + socket on all platform" diff --git a/app/openvpn/config-msvc.h b/app/openvpn/config-msvc.h index 99c00f9f..fa993843 100644 --- a/app/openvpn/config-msvc.h +++ b/app/openvpn/config-msvc.h @@ -76,6 +76,9 @@ #define HAVE_OPENSSL_ENGINE 1 +#define PATH_SEPARATOR '\\' +#define PATH_SEPARATOR_STR "\\" + #ifndef __cplusplus #define inline __inline #endif @@ -89,7 +92,10 @@ #define strncasecmp strnicmp #define strcasecmp _stricmp #define snprintf _snprintf + +#if _MSC_VER < 1800 #define strtoull strtoul +#endif #define in_addr_t uint32_t #define ssize_t SSIZE_T diff --git a/app/openvpn/config-version.h.in b/app/openvpn/config-version.h.in deleted file mode 100644 index 27ee36af..00000000 --- a/app/openvpn/config-version.h.in +++ /dev/null @@ -1 +0,0 @@ -#define CONFIGURE_GIT_REVISION "@CONFIGURE_GIT_REVISION@" diff --git a/app/openvpn/config.h b/app/openvpn/config.h index 0d86c1d9..b825e2bd 100644 --- a/app/openvpn/config.h +++ b/app/openvpn/config.h @@ -450,13 +450,13 @@ #define PACKAGE_NAME "OpenVPN" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "OpenVPN 2.3_rc1+dspatch3" +#define PACKAGE_STRING "OpenVPN 2.4-icsopenvpn" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "openvpn" /* Define to the version of this package. */ -#define PACKAGE_VERSION "2.3_beta1" +#define PACKAGE_VERSION "2.4_master" /* Define to the necessary symbol if this constant uses a non-standard name on your system. */ @@ -539,6 +539,9 @@ /* Use LZO compression library */ #define ENABLE_LZO 1 +#define ENABLE_SNAPPY 1 +#define ENABLE_LZ4 1 +#define NEED_COMPAT_LZ4 1 /* Enable PKCS11 capability */ /* #undef USE_PKCS11 */ @@ -550,13 +553,16 @@ #define ENABLE_SSL 1 #define USE_SSL 1 #define ENABLE_CRYPTO 1 -#define ENABLE_CRYPTO_OPENSSL 1 + +/* via android.mk */ +/*#define ENABLE_CRYPTO_OPENSSL 1*/ +/* #define ENABLE_CRYPTO_POLARSSL 1 */ /* Use valgrind memory debugging library */ /* #undef USE_VALGRIND */ /* Version number of package */ -#define VERSION "2.1.4" +#define VERSION "2.3.1" /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE @@ -616,3 +622,12 @@ #define HAVE_LZO_LZO1X_H 1 #define HAVE_SYS_TIME_H 1 #define HAVE_TIME_H 1 +#define HAVE_CONFIG_VERSION_H 1 +#define PATH_SEPARATOR_STR "/" +#define HAVE_SA_FAMILY_T 1 + + +// Workaround for bionc +#define IPPROTO_IP IPPROTO_IP +#define IPPROTO_TCP IPPROTO_TCP + diff --git a/app/openvpn/configure.ac b/app/openvpn/configure.ac index 2f780b7a..55c40847 100644 --- a/app/openvpn/configure.ac +++ b/app/openvpn/configure.ac @@ -32,7 +32,7 @@ m4_include(compat.m4) AC_DEFINE([OPENVPN_VERSION_RESOURCE], [PRODUCT_VERSION_RESOURCE], [Version in windows resource format]) AC_CONFIG_AUX_DIR([.]) -AM_CONFIG_HEADER([config.h]) +AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/openvpn/syshead.h]) AC_CONFIG_MACRO_DIR([m4]) AM_INIT_AUTOMAKE @@ -46,11 +46,22 @@ AC_ARG_ENABLE( [enable_lzo="yes"] ) -AC_ARG_ENABLE( - [lzo-stub], - [AS_HELP_STRING([--enable-lzo-stub], [don't compile LZO compression support but still allow limited interoperability with LZO-enabled peers @<:@default=no@:>@])], - , - [enable_lzo_stub="no"] +AC_ARG_ENABLE(snappy, + [ --disable-snappy Disable Snappy compression support], + [enable_snappy="$enableval"], + [enable_snappy="yes"] +) + +AC_ARG_ENABLE(lz4, + [ --disable-lz4 Disable LZ4 compression support], + [enable_lz4="$enableval"], + [enable_lz4="yes"] +) + +AC_ARG_ENABLE(comp-stub, + [ --enable-comp-stub Don't compile compression support but still allow limited interoperability with compression-enabled peers], + [enable_comp_stub="$enableval"], + [enable_comp_stub="no"] ) AC_ARG_ENABLE( @@ -96,13 +107,6 @@ AC_ARG_ENABLE( ) AC_ARG_ENABLE( - [eurephia], - [AS_HELP_STRING([--disable-eurephia], [disable support for the eurephia plug-in @<:@default=yes@:>@])], - , - [enable_eurephia="yes"] -) - -AC_ARG_ENABLE( [management], [AS_HELP_STRING([--disable-management], [disable management server support @<:@default=yes@:>@])], , @@ -117,20 +121,6 @@ AC_ARG_ENABLE( ) AC_ARG_ENABLE( - [socks], - [AS_HELP_STRING([--disable-socks], [disable Socks support @<:@default=yes@:>@])], - , - [enable_socks="yes"] -) - -AC_ARG_ENABLE( - [http-proxy], - [AS_HELP_STRING([--disable-http-proxy], [disable HTTP proxy support @<:@default=yes@:>@])], - , - [enable_http_proxy="yes"] -) - -AC_ARG_ENABLE( [fragment], [AS_HELP_STRING([--disable-fragment], [disable internal fragmentation support (--fragment) @<:@default=yes@:>@])], , @@ -240,6 +230,13 @@ AC_ARG_ENABLE( ) AC_ARG_ENABLE( + [werror], + [AS_HELP_STRING([--enable-werror], [promote compiler warnings to errors, will cause builds to fail is the compiler issues warnings (debugging option) @<:@default=no@:>@])], + , + [enable_werror="no"] +) + +AC_ARG_ENABLE( [strict-options], [AS_HELP_STRING([--enable-strict-options], [enable strict options check between peers (debugging option) @<:@default=no@:>@])], , @@ -454,7 +451,7 @@ SOCKET_INCLUDES=" " AC_CHECK_HEADERS( - [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h], + [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h], , , [[${SOCKET_INCLUDES}]] @@ -497,6 +494,12 @@ AC_CHECK_TYPE( [[${SOCKET_INCLUDES}]] ) AC_CHECK_TYPE( + [sa_family_t], + [AC_DEFINE([HAVE_SA_FAMILY_T], [1], [sa_family_t, needed to hold AF_* info])], + , + [[${SOCKET_INCLUDES}]] +) +AC_CHECK_TYPE( [struct sockaddr_in6], , [AC_MSG_ERROR([struct sockaddr_in6 not found, needed for ipv6 transport support.])], @@ -676,7 +679,7 @@ fi case "${with_mem_check}" in valgrind) - AC_CHECK_HEADER( + AC_CHECK_HEADERS( [valgrind/memcheck.h], [ CFLAGS="${CFLAGS} -g -fno-inline" @@ -690,7 +693,7 @@ case "${with_mem_check}" in ) ;; dmalloc) - AC_CHECK_HEADER( + AC_CHECK_HEADERS( [dmalloc.h], [AC_CHECK_LIB( [dmalloc], @@ -726,8 +729,15 @@ case "${with_mem_check}" in esac PKG_CHECK_MODULES( + [PKCS11_HELPER], + [libpkcs11-helper-1 >= 1.11], + [have_pkcs11_helper="yes"], + [] +) + +PKG_CHECK_MODULES( [OPENSSL_CRYPTO], - [libcrypto >= 0.9.6], + [libcrypto >= 0.9.8], [have_openssl_crypto="yes"], [AC_CHECK_LIB( [crypto], @@ -741,7 +751,7 @@ PKG_CHECK_MODULES( PKG_CHECK_MODULES( [OPENSSL_SSL], - [libssl >= 0.9.6], + [libssl >= 0.9.8], [have_openssl_ssl="yes"], [AC_CHECK_LIB( [ssl], @@ -749,7 +759,9 @@ PKG_CHECK_MODULES( [ have_openssl_ssl="yes" OPENSSL_SSL_LIBS="-lssl" - ] + ], + [], + [-lcrypto] )] ) @@ -774,6 +786,24 @@ if test "${have_openssl_crypto}" = "yes"; then LIBS="${saved_LIBS}" fi +if test "${have_openssl_ssl}" = "yes"; then + saved_CPPFLAGS="${CPPFLAGS}" + CPPFLAGS="${CPPFLAGS} ${OPENSSL_CRYPTO_CFLAGS}" + AC_MSG_CHECKING([for SSL_OP_NO_TICKET flag in OpenSSL]) + AC_EGREP_CPP(have_ssl_op_no_ticket, [ + #include <openssl/ssl.h> + #ifdef SSL_OP_NO_TICKET + have_ssl_op_no_ticket + #endif + ], [ + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + AC_ERROR([OpenVPN 2.4+ requires SSL_OP_NO_TICKET in OpenSSL]) + ]) + CPPFLAGS="${saved_CPPFLAGS}" +fi + AC_ARG_VAR([POLARSSL_CFLAGS], [C compiler flags for polarssl]) AC_ARG_VAR([POLARSSL_LIBS], [linker flags for polarssl]) have_polarssl_ssl="yes" @@ -789,9 +819,11 @@ if test -z "${POLARSSL_LIBS}"; then [polarssl], [aes_crypt_cbc], , - [have_polarssl_crypto="no"] + [have_polarssl_crypto="no"], + [${PKCS11_HELPER_LIBS}] ) - ] + ], + [${PKCS11_HELPER_LIBS}] ) fi @@ -805,15 +837,45 @@ if test "${with_crypto_library}" = "polarssl" ; then #include <polarssl/version.h> ]], [[ -#if POLARSSL_VERSION_NUMBER < 0x01010000 +#if POLARSSL_VERSION_NUMBER < 0x01030300 || POLARSSL_VERSION_NUMBER >= 0x01040000 #error invalid version #endif ]] )], [AC_MSG_RESULT([ok])], - [AC_MSG_ERROR([invalid polarssl version])] + [AC_MSG_ERROR([PolarSSL 1.3.x required and must be 1.3.3 or later])] ) + + polarssl_with_pkcs11="no" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include <polarssl/config.h> + ]], + [[ +#ifndef POLARSSL_PKCS11_C +#error pkcs11 wrapper missing +#endif + ]] + )], + polarssl_with_pkcs11="yes") CFLAGS="${old_CFLAGS}" + + AC_MSG_CHECKING([polarssl pkcs11 support]) + if test "${enable_pkcs11}" = "yes"; then + if test "${polarssl_with_pkcs11}" = "yes"; then + AC_MSG_RESULT([ok]) + else + AC_MSG_ERROR([polarssl has no pkcs11 wrapper compiled in]) + fi + else + if test "${polarssl_with_pkcs11}" != "yes"; then + AC_MSG_RESULT([ok]) + else + AC_MSG_ERROR([PolarSSL compiled with PKCS11, while OpenVPN is not]) + fi + fi + fi AC_ARG_VAR([LZO_CFLAGS], [C compiler flags for lzo]) @@ -856,12 +918,87 @@ if test "${have_lzo}" = "yes"; then CFLAGS="${saved_CFLAGS}" fi -PKG_CHECK_MODULES( - [PKCS11_HELPER], - [libpkcs11-helper-1 >= 1.02], - [have_pkcs11_helper="yes"], - [] -) +dnl +dnl check for Snappy library +dnl + +AC_ARG_VAR([SNAPPY_CFLAGS], [C compiler flags for snappy]) +AC_ARG_VAR([SNAPPY_LIBS], [linker flags for snappy]) +if test "$enable_snappy" = "yes" && test "$enable_comp_stub" = "no"; then + AC_CHECKING([for Snappy Library and Header files]) + havesnappylib=1 + + # if SNAPPY_LIBS is set, we assume it will work, otherwise test + if test -z "${SNAPPY_LIBS}"; then + AC_CHECK_LIB(snappy, snappy_compress, + [ SNAPPY_LIBS="-lsnappy" ], + [ + AC_MSG_RESULT([Snappy library not found.]) + havesnappylib=0 + ]) + fi + + saved_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} ${SNAPPY_CFLAGS}" + AC_CHECK_HEADERS(snappy-c.h, + , + [ + AC_MSG_RESULT([Snappy headers not found.]) + havesnappylib=0 + ]) + + if test $havesnappylib = 0 ; then + AC_MSG_RESULT([Snappy library available from http://code.google.com/p/snappy/]) + AC_MSG_ERROR([Or try ./configure --disable-snappy OR ./configure --enable-comp-stub]) + fi + OPTIONAL_SNAPPY_CFLAGS="${SNAPPY_CFLAGS}" + OPTIONAL_SNAPPY_LIBS="${SNAPPY_LIBS}" + AC_DEFINE(ENABLE_SNAPPY, 1, [Enable Snappy compression library]) + CFLAGS="${saved_CFLAGS}" +fi + +dnl +dnl check for LZ4 library +dnl + +AC_ARG_VAR([LZ4_CFLAGS], [C compiler flags for lz4]) +AC_ARG_VAR([LZ4_LIBS], [linker flags for lz4]) +if test "$enable_lz4" = "yes" && test "$enable_comp_stub" = "no"; then + AC_CHECKING([for LZ4 Library and Header files]) + havelz4lib=1 + + # if LZ4_LIBS is set, we assume it will work, otherwise test + if test -z "${LZ4_LIBS}"; then + AC_CHECK_LIB(lz4, LZ4_compress, + [ LZ4_LIBS="-llz4" ], + [ + AC_MSG_RESULT([LZ4 library not found.]) + havelz4lib=0 + ]) + fi + + saved_CFLAGS="${CFLAGS}" + CFLAGS="${CFLAGS} ${LZ4_CFLAGS}" + AC_CHECK_HEADERS(lz4.h, + , + [ + AC_MSG_RESULT([LZ4 headers not found.]) + havelz4lib=0 + ]) + + if test $havelz4lib = 0 ; then + AC_MSG_RESULT([LZ4 library or header not found, using version in src/compat/compat-lz4.*]) + AC_DEFINE([NEED_COMPAT_LZ4], [1], [use copy of LZ4 source in compat/]) + LZ4_LIBS="" + fi + OPTIONAL_LZ4_CFLAGS="${LZ4_CFLAGS}" + OPTIONAL_LZ4_LIBS="${LZ4_LIBS}" + AC_DEFINE(ENABLE_LZ4, 1, [Enable LZ4 compression library]) + CFLAGS="${saved_CFLAGS}" +fi + + + AC_MSG_CHECKING([git checkout]) GIT_CHECKOUT="no" @@ -892,8 +1029,6 @@ test "${ac_cv_header_sys_uio_h}" = "yes" && AC_DEFINE([HAVE_IOVEC], [1], [struct test "${enable_multi}" = "yes" && AC_DEFINE([ENABLE_CLIENT_SERVER], [1], [Enable client/server capability]) test "${enable_server}" = "no" && AC_DEFINE([ENABLE_CLIENT_ONLY], [1], [Enable client capability only]) test "${enable_management}" = "yes" && AC_DEFINE([ENABLE_MANAGEMENT], [1], [Enable management server capability]) -test "${enable_socks}" = "yes" && AC_DEFINE([ENABLE_SOCKS], [1], [Enable Socks proxy support]) -test "${enable_http_proxy}" = "yes" && AC_DEFINE([ENABLE_HTTP_PROXY], [1], [Enable HTTP proxy support]) test "${enable_multihome}" = "yes" && AC_DEFINE([ENABLE_MULTIHOME], [1], [Enable multi-homed UDP server capability]) test "${enable_debug}" = "yes" && AC_DEFINE([ENABLE_DEBUG], [1], [Enable debugging support]) test "${enable_small}" = "yes" && AC_DEFINE([ENABLE_SMALL], [1], [Enable smaller executable size]) @@ -942,8 +1077,7 @@ fi if test "${enable_plugins}" = "yes"; then OPTIONAL_DL_LIBS="${DL_LIBS}" - AC_DEFINE([ENABLE_PLUGIN], [1], [Enable systemd support]) - test "${enable_eurephia}" = "yes" && AC_DEFINE([ENABLE_EUREPHIA], [1], [Enable support for the eurephia plug-in]) + AC_DEFINE([ENABLE_PLUGIN], [1], [Enable plug-in support]) else enable_plugin_auth_pam="no" enable_plugin_down_root="no" @@ -971,10 +1105,11 @@ if test "${enable_lzo}" = "yes"; then OPTIONAL_LZO_LIBS="${LZO_LIBS}" AC_DEFINE([ENABLE_LZO], [1], [Enable LZO compression library]) fi -if test "${enable_lzo_stub}" = "yes"; then - test "${enable_lzo}" = "yes" && AC_MSG_ERROR([Cannot have both lzo stub and lzo enabled]) - AC_DEFINE([ENABLE_LZO_STUB], [1], [Enable LZO stub capability]) - AC_DEFINE([ENABLE_LZO], [1], [Enable LZO compression library]) +if test "${enable_comp_stub}" = "yes"; then + test "${enable_lzo}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and lzo enabled (use --disable-lzo)]) + test "${enable_snappy}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and snappy enabled (use --disable-snappy)]) + test "${enable_lz4}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and LZ4 enabled (use --disable-lz4)]) + AC_DEFINE([ENABLE_COMP_STUB], [1], [Enable compression stub capability]) fi if test "${enable_pkcs11}" = "yes"; then @@ -993,6 +1128,9 @@ fi if test "${enable_strict}" = "yes"; then CFLAGS="${CFLAGS} -Wall -Wno-unused-parameter -Wno-unused-function" fi +if test "${enable_werror}" = "yes"; then + CFLAGS="${CFLAGS} -Werror" +fi if test "${WIN32}" = "yes"; then test -z "${MAN2HTML}" && AC_MSG_ERROR([man2html is required for win32]) @@ -1028,6 +1166,10 @@ AC_SUBST([OPTIONAL_CRYPTO_CFLAGS]) AC_SUBST([OPTIONAL_CRYPTO_LIBS]) AC_SUBST([OPTIONAL_LZO_CFLAGS]) AC_SUBST([OPTIONAL_LZO_LIBS]) +AC_SUBST([OPTIONAL_SNAPPY_CFLAGS]) +AC_SUBST([OPTIONAL_SNAPPY_LIBS]) +AC_SUBST([OPTIONAL_LZ4_CFLAGS]) +AC_SUBST([OPTIONAL_LZ4_LIBS]) AC_SUBST([OPTIONAL_PKCS11_HELPER_CFLAGS]) AC_SUBST([OPTIONAL_PKCS11_HELPER_LIBS]) diff --git a/app/openvpn/contrib/OCSP_check/OCSP_check.sh b/app/openvpn/contrib/OCSP_check/OCSP_check.sh index 847be450..553c3dce 100644 --- a/app/openvpn/contrib/OCSP_check/OCSP_check.sh +++ b/app/openvpn/contrib/OCSP_check/OCSP_check.sh @@ -71,7 +71,7 @@ if [ $check_depth -eq -1 ] || [ $cur_depth -eq $check_depth ]; then # - The serial number must not be empty # - The exit status of "openssl ocsp" must be zero # - The output of the above command must contain the line - # "0x${serial}: good" + # "${serial}: good" # # Everything else fails with exit status 1. @@ -83,7 +83,7 @@ if [ $check_depth -eq -1 ] || [ $cur_depth -eq $check_depth ]; then # Sample output that is assumed here: # # Response verify OK - # 0x428740A5: good + # 4287405: good # This Update: Apr 24 19:38:49 2010 GMT # Next Update: May 2 14:23:42 2010 GMT # @@ -97,11 +97,11 @@ if [ $check_depth -eq -1 ] || [ $cur_depth -eq $check_depth ]; then "$nonce" \ -CAfile "$verify" \ -url "$ocsp_url" \ - -serial "0x${serial}" 2>/dev/null) + -serial "${serial}" 2>/dev/null) if [ $? -eq 0 ]; then # check that it's good - if echo "$status" | grep -Fq "0x${serial}: good"; then + if echo "$status" | grep -Fq "^${serial}: good"; then exit 0 fi fi diff --git a/app/openvpn/doc/android.txt b/app/openvpn/doc/android.txt new file mode 100644 index 00000000..871e3997 --- /dev/null +++ b/app/openvpn/doc/android.txt @@ -0,0 +1,76 @@ +This file documents the support in OpenVPN for Android 4.0 and up. + +This support is primarily used in the "OpenVPN for Android" app +(http://code.google.com/p/ics-openvpn/). For building see the developer +README: http://code.google.com/p/ics-openvpn/source/browse/README.txt. + +Android provides the VPNService API +(http://developer.android.com/reference/android/net/VpnService.html) +which allows establishing VPN connections without rooting the device. + +Since all the interfaces are are Android specific the calls to this +interface are made from the UI instead of OpenVPN directly. The API +needs the following parameters: + +- IP and netmask of tun interface +- Networks that should be routed to the tun interface +- DNS Servers and DNS Domain +- MTU + +All IPs/Routes are in CIDR style. Non CIDR routes are not supported. +Notable is the lack of support for setting routes to other interfaces +usually used to avoid the server connection going over the tun +interface. The Android VPNService API has the concept of protecting +a socket from being routed over a interface. Calling protect (fd) +will internally bind the socket to the interface used for the +external connection (usually WiFi or mobile data). + +To use OpenVPN with the VPNService API OpenVPN must be build with +the TARGET_ANDROID compile option. Also the UI must use a UNIX +domain socket to connect to OpenVPN. When compiled as TARGET_ANDROID +OpenVPN will use management callbacks instead of executing traditional +ifconfig/route commands use the need-ok callback mechanism which +will ask + +> NEED-OK command + +where command can be: + +IFCONFIG6 IPv6/netmask +IFCONFIG local remoteOrNetmask MTU topology + +To tell the UI which IPs addresses OpenVPN expects on the interface. +Topology is one of "net30","p2p","subnet" or "undef". + +ROUTE6 network/netmask +ROUTE network netmask + +To tell the UI which routes should be set on the tun interface. + +DNSSERVER serverip +DNSDOMAIN searchdomain + +To set the DNS server and search domain. + +The GUI will then respond with a "needok 'command' ok' or "needok +'command' cancel', e.g. "needok 'IFCONFIG' ok". + +To protect a socket the OpenVPN will send a PROTECTFD to the UI. +When sending the PROTECTFD command command to the UI it will send +the fd of the socket as ancillary message over the UNIX socket. +The UI will then call protect(fd) on the received socket protecting +it from being routed over the VPN. + +When opening a tun device the OpenVPN process will first send all +route, ifconfig and DNS related configuration to the UI and after +that calls the OPENTUN command to receive a tun fd with the requested +configuration. The UI will than use the collected information to +call the VPNService's establish() method to receive a fd which in +turn is send to the OpenVPN process as ancillary message to the +"needok 'OPENTUN' ok' response. + +The OpenVPN for Android UI extensively uses other features that +are not specific to Android but are rarely used on other platform. +For example using SIGUSR1 and management-hold to restart, pause, +continue the VPN on network changes or the external key management +--management-external-key option and inline files. diff --git a/app/openvpn/doc/doxygen/openvpn.doxyfile b/app/openvpn/doc/doxygen/openvpn.doxyfile index 5d87172c..cf26c42a 100644 --- a/app/openvpn/doc/doxygen/openvpn.doxyfile +++ b/app/openvpn/doc/doxygen/openvpn.doxyfile @@ -235,7 +235,7 @@ EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = -PREDEFINED = WIN32 NTLM USE_LZO ENABLE_FRAGMENT P2MP P2MP_SERVER USE_CRYPTO USE_SSL ENABLE_PLUGIN ENABLE_MANAGEMENT ENABLE_OCC HAVE_GETTIMEOFDAY +PREDEFINED = WIN32 NTLM USE_LZO ENABLE_FRAGMENT P2MP P2MP_SERVER ENABLE_CRYPTO ENABLE_CRYPTO_OPENSSL ENABLE_SSL ENABLE_PLUGIN ENABLE_MANAGEMENT ENABLE_OCC HAVE_GETTIMEOFDAY EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- diff --git a/app/openvpn/doc/openvpn.8 b/app/openvpn/doc/openvpn.8 index d66bd665..34894e5a 100644 --- a/app/openvpn/doc/openvpn.8 +++ b/app/openvpn/doc/openvpn.8 @@ -221,6 +221,9 @@ options. indicates the protocol to use when connecting with the remote, and may be "tcp" or "udp". +For forcing IPv4 or IPv6 connection suffix tcp or udp +with 4/6 like udp4/udp6/tcp4/tcp6. + The client will move on to the next host in the list, in the event of connection failure. Note that at any given time, the OpenVPN client @@ -271,7 +274,7 @@ failover capability. .\"********************************************************* .TP .B \-\-remote-random-hostname -Add a random string (6 characters) to first DNS label of hostname to prevent +Prepend a random string (6 bytes, 12 hex characters) to hostname to prevent DNS caching. For example, "foo.bar.gov" would be modified to "<random-chars>.foo.bar.gov". .\"********************************************************* @@ -346,20 +349,27 @@ block: .B connect-retry, .B connect-retry-max, .B connect-timeout, +.B explicit-exit-notify, .B float, +.B fragment, .B http-proxy, .B http-proxy-option, .B http-proxy-retry, .B http-proxy-timeout, +.B link-mtu, .B local, .B lport, +.B mssfix, +.B mtu-disc, .B nobind, .B port, .B proto, .B remote, .B rport, -.B socks-proxy, and -.B socks-proxy-retry. +.B socks-proxy, +.B socks-proxy-retry, +.B tun-mtu and +.B tun-mtu-extra. A defaulting mechanism exists for specifying options to apply to all @@ -471,13 +481,13 @@ seconds (default=10). .TP .B \-\-connect-retry-max n .B n -specifies the number of times all -.B \-\-remote -respectively +specifies the number of times all +.B \-\-remote +respectively .B <connection> -statements are tried. Specifiying +statements are tried. Specifiying .B n -as one would try each entry exactly once. A sucessful connection +as one would try each entry exactly once. A sucessful connection resets the counter. (default=umlimited). .\"********************************************************* .TP @@ -544,14 +554,24 @@ Set HTTP version number to .B AGENT user-agent \-\- Set HTTP "User-Agent" string to .B user-agent. + +.B CUSTOM\-HEADER name content \-\- +Adds the custom Header with +.B name +as name and +.B content +as the content of the custom HTTP header. .\"********************************************************* .TP -.B \-\-socks-proxy server [port] +.B \-\-socks-proxy server [port] [authfile] Connect to remote host through a Socks5 proxy at address .B server and port .B port (default=1080). +.B authfile +(optional) is a file containing a username and password on 2 lines, or +"stdin" to prompt from console. .\"********************************************************* .TP .B \-\-socks-proxy-retry @@ -664,7 +684,7 @@ TCP/UDP port number or name for bind. TCP/UDP port number or name for remote. .\"********************************************************* .TP -.B \-\-bind +.B \-\-bind [ipv6only] Bind to local address and port. This is the default unless any of .B \-\-proto tcp-client , @@ -672,6 +692,12 @@ Bind to local address and port. This is the default unless any of or .B \-\-socks-proxy are used. + +If the +.B ipv6only +keyword is present OpenVPN will bind only to IPv6 (as oposed +to IPv6 and IPv4) when a IPv6 socket is opened. + .\"********************************************************* .TP .B \-\-nobind @@ -797,6 +823,17 @@ also specify or .B \-\-dev-type tap. +Under Mac OS X this option can be used to specify the default tun +implementation. Using +.B \-\-dev\-node utun +forces usage of the native Darwin tun kernel support. Use +.B \-\-dev\-node utunN +to select a specific utun instance. To force using the tun.kext (/dev/tunX) use +.B \-\-dev\-node tun\fR. +When not specifying a +.B \-\-dev\-node +option openvpn will first try to open utun, and fall back to tun.kext. + On Windows systems, select the TAP-Win32 adapter which is named .B node @@ -1872,6 +1909,18 @@ reasons for having OpenVPN fail if it detects problems in a config file. Having said that, there are valid reasons for wanting new software features to gracefully degrade when encountered by older software versions. + +It is also possible to tag a single directive so as not to trigger +a fatal error if the directive isn't recognized. To do this, +prepend the following before the directive: +.B setenv opt + +Versions prior to OpenVPN 2.3.3 will always ignore options set with the +.B setenv opt +directive. + +See also +.B \-\-ignore-unknown-option .\"********************************************************* .TP .B \-\-setenv-safe name value @@ -1885,6 +1934,25 @@ is a safety precaution to prevent a LD_PRELOAD style attack from a malicious or compromised server. .\"********************************************************* .TP +.B \-\-ignore-unknown-option opt1 opt2 opt3 ... optN +When one of options +.B opt1 ... optN +is encountered in the configuration file the configuration +file parsing does not fail if this OpenVPN version does not +support the option. Multiple +.B \-\-ignore-unknown-option +options can be given to support a larger number of options to ignore. + +This option should be used with caution, as there are good security +reasons for having OpenVPN fail if it detects problems in a +config file. Having said that, there are valid reasons for wanting +new software features to gracefully degrade when encountered by +older software versions. + +.B \-\-ignore-unknown-option +is available since OpenVPN 2.3.3. +.\"********************************************************* +.TP .B \-\-script-security level This directive offers policy-level control over OpenVPN's usage of external programs and scripts. Lower @@ -2029,6 +2097,16 @@ In many cases, the parameter can point to an empty directory, however complications can result when scripts or restarts are executed after the chroot operation. + +Note: if OpenVPN is built using the PolarSSL SSL +library, +.B \-\-chroot +will only work if a /dev/urandom device node is available +inside the chroot directory +.B dir. +This is due to the way PolarSSL works (it wants to open +/dev/urandom every time randomness is needed, not just once +at startup) and nothing OpenVPN can influence. .\"********************************************************* .TP .B \-\-setcon context @@ -2205,6 +2283,12 @@ otherwise would be prepended. In particular, this applies to log messages sent to stdout. .\"********************************************************* .TP +.B \-\-machine-readable-output +Always write timestamps and message flags to log messages, even when they +otherwise would not be prefixed. In particular, this applies to +log messages sent to stdout. +.\"********************************************************* +.TP .B \-\-writepid file Write OpenVPN's main process ID to .B file. @@ -2259,18 +2343,23 @@ is NOT specified. .\"********************************************************* .TP .B \-\-multihome -Configure a multi-homed UDP server. This option can be used when -OpenVPN has been configured to listen on all interfaces, and will -attempt to bind client sessions to the interface on which packets -are being received, so that outgoing packets will be sent out -of the same interface. Note that this option is only relevant for -UDP servers and currently is only implemented on Linux. - -Note: clients connecting to a -.B \-\-multihome -server should always use the -.B \-\-nobind -option. +Configure a multi-homed UDP server. This option needs to be used when +a server has more than one IP address (e.g. multiple interfaces, or +secondary IP addresses), and is not using +.B \-\-local +to force binding to one specific address only. This option will +add some extra lookups to the packet path to ensure that the UDP reply +packets are always sent from the address that the client is +talking to. This is not supported on all platforms, and it adds more +processing, so it's not enabled by default. + +Note: this option is only relevant for UDP servers. + +Note 2: if you do an IPv6+IPv4 dual-stack bind on a Linux machine with +multiple IPv4 address, connections to IPv4 addresses will not work +right on kernels before 3.15, due to missing kernel support for the +IPv4-mapped case (some distributions have ported this to earlier kernel +versions, though). .\"********************************************************* .TP .B \-\-echo [parms...] @@ -2344,12 +2433,34 @@ consecutive messages in the same category. This is useful to limit repetitive logging of similar message types. .\"********************************************************* .TP +.B \-\-compress [algorithm] +Enable a compression algorithm. + +The +.B algorithm +parameter may be "snappy", "lzo", "lz4", or empty. Snappy, LZO and LZ4 +are different compression algorithms, with Snappy generally +offering the best performance while LZ4 is faster with less CPU usage. +For backwards compatibility with OpenVPN versions before 2.4, use "lzo" +(which is identical to the older option "\-\-comp-lzo yes"). + +If the +.B algorithm +parameter is empty, compression will be turned off, but the packet +framing for compression will still be enabled, allowing a different +setting to be pushed later. +.\"********************************************************* +.TP .B \-\-comp-lzo [mode] -Use fast LZO compression \-\- may add up to 1 byte per +Use LZO compression \-\- may add up to 1 byte per packet for incompressible data. .B mode may be "yes", "no", or "adaptive" (default). +This option is deprecated in favor of the newer +.B --compress +option. + In a server mode setup, it is possible to selectively turn compression on or off for individual clients. @@ -2479,6 +2590,7 @@ Allow management interface to override .B \-\-remote directives (client-only). .\"********************************************************* +.TP .B \-\-management-external-key Allows usage for external private key file instead of .B \-\-key @@ -3423,7 +3535,7 @@ the authenticated username as the common name, rather than the common name from the client cert. .\"********************************************************* .TP -.B \-\-compat\-names [no\-remapping] +.B \-\-compat\-names [no\-remapping] (DEPRECATED) Until OpenVPN v2.3 the format of the X.509 Subject fields was formatted like this: .IP @@ -3454,25 +3566,42 @@ characters in the usernames, X.509 Subject fields and Common Name variables and it complies to the RFC 2253, UTF\-8 String Representation of Distinguished Names. -As a backwards compatibility for the removed \-\-no\-name\-remapping feature in -older OpenVPN versions, the +The .B no\-remapping mode flag can be used with the .B \-\-compat\-names -option. -When this mode flag is used, the Common Name, Subject, and username strings are -allowed to include any printable character including space, but excluding -control characters such as tab, newline, and carriage-return. It ensures -compatibility with the -.B \-\-no\-name\-remapping -option of OpenVPN versions before v2.3. +option to be compatible with the now deprecated \-\-no\-name\-remapping option. +It is only available at the server. When this mode flag is used, the Common Name, +Subject, and username strings are allowed to include any printable character +including space, but excluding control characters such as tab, newline, and +carriage-return. no-remapping is only available on the server side. .B Please note: -This option will not be around for a long time. It is only implemented +This option is immediately deprecated. It is only implemented to make the transition to the new formatting less intrusive. It will be -removed either in OpenVPN v2.4 or v2.5. So please make sure you start -the process to support the new formatting as soon as possible. +removed either in OpenVPN v2.4 or v2.5. So please make sure you use the +.B \-\-verify-x509-name +option instead of +.B \-\-tls-remote +as soon as possible and update your scripts where necessary. +.\"********************************************************* +.TP +.B \-\-no\-name\-remapping (DEPRECATED) +The +.B \-\-no\-name\-remapping +option is an alias for +.B \-\-compat\-names\ no\-remapping. +It ensures compatibility with server configurations using the +.B \-\-no\-name\-remapping +option. + +.B Please note: +This option is now deprecated. It will be removed either in OpenVPN v2.4 +or v2.5. So please make sure you support the new X.509 name formatting +described with the +.B \-\-compat\-names +option as soon as possible. .\"********************************************************* .TP .B \-\-port-share host port [dir] @@ -4122,6 +4251,13 @@ included with the OpenVPN distribution. Diffie Hellman parameters may be considered public. .\"********************************************************* .TP +.B \-\-ecdh-curve name +Specify the curve to use for elliptic curve Diffie Hellman. Available +curves can be listed with +.B \-\-show-curves +. The specified curve will only be used for ECDH TLS-ciphers. +.\"********************************************************* +.TP .B \-\-cert file Local peer's signed certificate in .pem format \-\- must be signed by a certificate authority whose certificate is in @@ -4189,6 +4325,15 @@ when you built your peer's certificate (see above). .\"********************************************************* .TP +.B \-\-tls-version-min version ['or-highest'] +Sets the minimum +TLS version we will accept from the peer (default is "1.0"). +Examples for version +include "1.0", "1.1", or "1.2". If 'or-highest' is specified +and version is not recognized, we will only accept the highest TLS +version supported by the local SSL implementation. +.\"********************************************************* +.TP .B \-\-pkcs12 file Specify a PKCS #12 file containing local private key, local certificate, and root CA certificate. @@ -4649,11 +4794,11 @@ is available via the peer_cert environment variable. Field in x509 certificate subject to be used as username (default=CN). .B Fieldname will be uppercased before matching. When this option is used, the ---tls-remote option will match against the chosen fieldname instead -of the CN. +.B \-\-verify-x509-username +option will match against the chosen fieldname instead of the CN. .\"********************************************************* .TP -.B \-\-tls-remote name +.B \-\-tls-remote name (DEPRECATED) Accept connections only from a host with X509 name or common name equal to .B name. @@ -4685,6 +4830,59 @@ option to verify the remote host, because works in a .B \-\-chroot environment too. + +.B Please also note: +This option is now deprecated. It will be removed either in OpenVPN v2.4 +or v2.5. So please make sure you support the new X.509 name formatting +described with the +.B \-\-compat-names +option as soon as possible by updating your configurations to use +.B \-\-verify-x509-name +instead. +.\"********************************************************* +.TP +.B \-\-verify-x509-name name type +Accept connections only if a host's X.509 name is equal to +.B name. +The remote host must also pass all other tests of verification. + +Which X.509 name is compared to +.B name +depends on the setting of type. +.B type +can be "subject" to match the complete subject DN (default), +"name" to match a subject RDN or "name-prefix" to match a subject RDN prefix. +Which RDN is verified as name depends on the +.B \-\-x509-username-field +option. But it defaults to the common name (CN), e.g. a certificate with a +subject DN "C=KG, ST=NA, L=Bishkek, CN=Server-1" would be matched by: + +.B \-\-verify-x509-name 'C=KG, ST=NA, L=Bishkek, CN=Server-1' +and +.B \-\-verify-x509-name Server-1 name +or you could use +.B \-\-verify-x509-name Server- name-prefix +if you want a client to only accept connections to "Server-1", "Server-2", etc. + +.B \-\-verify-x509-name +is a useful replacement for the +.B \-\-tls-verify +option to verify the remote host, because +.B \-\-verify-x509-name +works in a +.B \-\-chroot +environment without any dependencies. + +Using a name prefix is a useful alternative to managing +a CRL (Certificate Revocation List) on the client, since it allows the client +to refuse all certificates except for those associated +with designated servers. + +.B NOTE: +Test against a name prefix only when you are using OpenVPN with +a custom CA certificate that is under your control. +Never use this option with type "name-prefix" when your client certificates +are signed by a third party, such as a commercial web CA. .\"********************************************************* .TP .B \-\-x509-track attribute @@ -4722,7 +4920,7 @@ a man-in-the-middle attack where an authorized client attempts to connect to another client by impersonating the server. The attack is easily prevented by having clients verify the server certificate using any one of -.B \-\-ns-cert-type, \-\-tls-remote, +.B \-\-ns-cert-type, \-\-verify-x509-name, or .B \-\-tls-verify. .\"********************************************************* @@ -4780,7 +4978,7 @@ a man-in-the-middle attack where an authorized client attempts to connect to another client by impersonating the server. The attack is easily prevented by having clients verify the server certificate using any one of -.B \-\-remote-cert-tls, \-\-tls-remote, +.B \-\-remote-cert-tls, \-\-verify-x509-name, or .B \-\-tls-verify. .\"********************************************************* @@ -4841,6 +5039,13 @@ lowest. Show currently available hardware-based crypto acceleration engines supported by the OpenSSL library. .\"********************************************************* +.TP +.B \-\-show-curves +(Standalone) +Show all available elliptic curves to use with the +.B \-\-ecdh-curve +option. +.\"********************************************************* .SS Generate a random key: Used only for non-TLS static key encryption mode. .\"********************************************************* @@ -5267,9 +5472,11 @@ option can be used BEFORE this option to produce debugging information. .SS IPv6 Related Options .\"********************************************************* The following options exist to support IPv6 tunneling in peer-to-peer -and client-server mode. As of now, this is just very basic -documentation of the IPv6-related options. More documentation can be -found on http://www.greenie.net/ipv6/openvpn.html. +and client-server mode. All options are modeled after their IPv4 +counterparts, so more detailed explanations given there apply here +as well (except for +.B \-\-topology +, which has no effect on IPv6). .TP .B --ifconfig-ipv6 ipv6addr/bits ipv6remote configure IPv6 address @@ -5280,7 +5487,11 @@ if no gateway is specified. .TP .B --route-ipv6 ipv6addr/bits [gateway] [metric] setup IPv6 routing in the system to send the specified IPv6 network -into OpenVPN's ``tun'' device +into OpenVPN's ``tun''. The gateway parameter is only used for +IPv6 routes across ``tap'' devices, and if missing, the ``ipv6remote'' +field from +.B --ifconfig-ipv6 +is used. .TP .B --server-ipv6 ipv6addr/bits convenience-function to enable a number of IPv6 related options at @@ -5296,7 +5507,8 @@ pool starts at .B ipv6addr and increments by +1 for every new client (linear mode). The .B /bits -setting controls the size of the pool. +setting controls the size of the pool. Due to implementation details, +the pool size must be between /64 and /112. .TP .B --ifconfig-ipv6-push ipv6addr/bits ipv6remote for ccd/ per-client static IPv6 interface configuration, see @@ -5863,6 +6075,16 @@ Set prior to execution of the script. .\"********************************************************* .TP +.B tls_digest_{n} +Contains the certificate SHA1 fingerprint/digest hash value, +where +.B n +is the verification level. Only set for TLS connections. Set prior +to execution of +.B \-\-tls-verify +script. +.\"********************************************************* +.TP .B tls_id_{n} A series of certificate fields from the remote peer, where @@ -5880,14 +6102,20 @@ where is the verification level. Only set for TLS connections. Set prior to execution of .B \-\-tls-verify -script. This is in the form of a hex string like "37AB46E0", which is -suitable for doing serial-based OCSP queries (with OpenSSL, you have -to prepend "0x" to the string). If something goes wrong while reading +script. This is in the form of a decimal string like "933971680", which is +suitable for doing serial-based OCSP queries (with OpenSSL, do not +prepend "0x" to the string) If something goes wrong while reading the value from the certificate it will be an empty string, so your code should check that. See the contrib/OCSP_check/OCSP_check.sh script for an example. .\"********************************************************* .TP +.B tls_serial_hex_{n} +Like +.B tls_serial_{n}\fR, +but in hex form (e.g. "12:34:56:78:9A"). +.\"********************************************************* +.TP .B tun_mtu The MTU of the TUN/TAP device. Set prior to diff --git a/app/openvpn/include/openvpn-plugin.h b/app/openvpn/include/openvpn-plugin.h index 0879f490..5f2d4079 100644 --- a/app/openvpn/include/openvpn-plugin.h +++ b/app/openvpn/include/openvpn-plugin.h @@ -29,10 +29,10 @@ #ifdef ENABLE_SSL #ifdef ENABLE_CRYPTO_POLARSSL -#include <polarssl/x509.h> +#include <polarssl/x509_crt.h> #ifndef __OPENVPN_X509_CERT_T_DECLARED #define __OPENVPN_X509_CERT_T_DECLARED -typedef x509_cert openvpn_x509_cert_t; +typedef x509_crt openvpn_x509_cert_t; #endif #else #include <openssl/x509.h> @@ -201,10 +201,15 @@ struct openvpn_plugin_string_list * * Version Comment * 1 Initial plugin v3 structures providing the same API as - * the v2 plugin interface + X509 certificate information. + * the v2 plugin interface, X509 certificate information + + * a logging API for plug-ins. + * + * 2 Added ssl_api member in struct openvpn_plugin_args_open_in + * which identifies the SSL implementation OpenVPN is compiled + * against. * */ -#define OPENVPN_PLUGINv3_STRUCTVER 1 +#define OPENVPN_PLUGINv3_STRUCTVER 2 /** * Definitions needed for the plug-in callback functions. @@ -260,6 +265,18 @@ struct openvpn_plugin_callbacks }; /** + * Used by the openvpn_plugin_open_v3() function to indicate to the + * plug-in what kind of SSL implementation OpenVPN uses. This is + * to avoid SEGV issues when OpenVPN is complied against PolarSSL + * and the plug-in against OpenSSL. + */ +typedef enum { + SSLAPI_NONE, + SSLAPI_OPENSSL, + SSLAPI_POLARSSL +} ovpnSSLAPI; + +/** * Arguments used to transport variables to the plug-in. * The struct openvpn_plugin_args_open_in is only used * by the openvpn_plugin_open_v3() function. @@ -286,6 +303,7 @@ struct openvpn_plugin_args_open_in const char ** const argv; const char ** const envp; struct openvpn_plugin_callbacks *callbacks; + const ovpnSSLAPI ssl_api; }; @@ -557,7 +575,8 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2) * ARGUMENTS * * version : fixed value, defines the API version of the OpenVPN plug-in API. The plug-in - * should validate that this value is matching the OPENVPN_PLUGIN_VERSION value. + * should validate that this value is matching the OPENVPN_PLUGINv3_STRUCTVER + * value. * * arguments : Structure with all arguments available to the plug-in. * diff --git a/app/openvpn/sample/sample-keys/README b/app/openvpn/sample/sample-keys/README index 1cd473a1..9f4f9187 100644 --- a/app/openvpn/sample/sample-keys/README +++ b/app/openvpn/sample/sample-keys/README @@ -1,7 +1,6 @@ -Sample RSA keys. +Sample RSA and EC keys. -See the examples section of the man page -for usage examples. +See the examples section of the man page for usage examples. NOTE: THESE KEYS ARE FOR TESTING PURPOSES ONLY. DON'T USE THEM FOR ANY REAL WORK BECAUSE @@ -12,3 +11,4 @@ client.{crt,key} -- sample client key/cert server.{crt,key} -- sample server key/cert (nsCertType=server) pass.{crt,key} -- sample client key/cert with password-encrypted key password = "password" +ec-*.{crt,key} -- sample elliptic curve variants of the above diff --git a/app/openvpn/sample/sample-keys/ec-ca.crt b/app/openvpn/sample/sample-keys/ec-ca.crt new file mode 100644 index 00000000..e190801d --- /dev/null +++ b/app/openvpn/sample/sample-keys/ec-ca.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB4jCCAWmgAwIBAgIJALGEGB2g6cAXMAoGCCqGSM49BAMCMBUxEzARBgNVBAMT +CkVDLVRlc3QgQ0EwHhcNMTQwMTE4MTYwMTUzWhcNMjQwMTE2MTYwMTUzWjAVMRMw +EQYDVQQDEwpFQy1UZXN0IENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE2S4AZT7j +ZlPG/CXpT12CzCNSySyKmJt+fWyW/wzbRulVJpGHXRHpZZj2VNOUE72kqGUeshh6 +Um1o7lHGDSAkHOJpeW5FtryiKhwFc+4dsOCLTNLVFXQsEtY3gY14Uquio4GEMIGB +MB0GA1UdDgQWBBS0mkFcuCZ8SLWZRAD/8LpBQcgGPDBFBgNVHSMEPjA8gBS0mkFc +uCZ8SLWZRAD/8LpBQcgGPKEZpBcwFTETMBEGA1UEAxMKRUMtVGVzdCBDQYIJALGE +GB2g6cAXMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoGCCqGSM49BAMCA2cA +MGQCMHWlVTi0xNZstR8ZNH+7z0WlyIXyZe23ne3EXkO0thZLdv86kpxFMPW/llB+ +RMRKuQIweN97n7FQy5DTenr91U98KDFJ5Av4mDFRL1mkXiu3W1//4XD8yEYDQTRz +/GARuOLL +-----END CERTIFICATE----- diff --git a/app/openvpn/sample/sample-keys/ec-ca.key b/app/openvpn/sample/sample-keys/ec-ca.key new file mode 100644 index 00000000..51a72e1a --- /dev/null +++ b/app/openvpn/sample/sample-keys/ec-ca.key @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDASU6X/mh2m2PayviL3 +teoml5soyIUcZfwZpVn6oNtnrLcAbIRsAJbM4xyGVp77G/6hZANiAATZLgBlPuNm +U8b8JelPXYLMI1LJLIqYm359bJb/DNtG6VUmkYddEellmPZU05QTvaSoZR6yGHpS +bWjuUcYNICQc4ml5bkW2vKIqHAVz7h2w4ItM0tUVdCwS1jeBjXhSq6I= +-----END PRIVATE KEY----- diff --git a/app/openvpn/sample/sample-keys/ec-client.crt b/app/openvpn/sample/sample-keys/ec-client.crt new file mode 100644 index 00000000..b797b022 --- /dev/null +++ b/app/openvpn/sample/sample-keys/ec-client.crt @@ -0,0 +1,61 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 2 (0x2) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN=EC-Test CA + Validity + Not Before: Jan 18 16:02:37 2014 GMT + Not After : Jan 16 16:02:37 2024 GMT + Subject: CN=ec-client + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:40:d9:b9:a2:44:1b:01:39:2c:14:ee:aa:70:6b: + 31:98:28:44:c9:61:bc:b7:0b:b5:53:49:c2:c0:0a: + 43:b0:08:50:cd:80:2f:5d:a4:89:f1:ff:7d:11:78: + f5:0c:b2:86:e2:59:f8:17:76:1b:22:f2:23:67:e7: + 55:90:ea:ce:0a:aa:da:05:f4:85:19:c9:ed:ae:6d: + a3:ad:56:7a:f6:33:c6:cf:bb:c7:39:fa:e4:d3:67: + df:f0:b8:4a:88:57:98 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + D8:E2:35:7B:CA:66:71:6B:D8:5B:F5:12:13:82:2D:ED:CD:E5:ED:7F + X509v3 Authority Key Identifier: + keyid:B4:9A:41:5C:B8:26:7C:48:B5:99:44:00:FF:F0:BA:41:41:C8:06:3C + DirName:/CN=EC-Test CA + serial:B1:84:18:1D:A0:E9:C0:17 + + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Key Usage: + Digital Signature + Netscape Comment: + Easy-RSA Generated Certificate + Netscape Cert Type: + SSL Client + Signature Algorithm: ecdsa-with-SHA256 + 30:64:02:30:41:8b:1a:fd:97:a8:bb:7c:d0:eb:1c:a2:ba:c0: + ac:2f:6d:80:07:5b:5c:ef:55:59:1a:92:56:66:94:ce:49:6a: + a9:57:49:b2:41:73:64:7e:01:ac:31:3a:7c:2a:bf:a5:02:30: + 2b:c4:a6:b1:0c:03:82:e3:e4:03:39:fb:19:d7:76:21:1b:7e: + 7f:aa:22:5d:90:a4:e1:2e:cd:ca:92:0f:b6:3f:80:dc:26:d2: + 09:34:8c:d1:61:bb:9d:ac:6d:8f:68:f0 +-----BEGIN CERTIFICATE----- +MIICLTCCAbSgAwIBAgIBAjAKBggqhkjOPQQDAjAVMRMwEQYDVQQDEwpFQy1UZXN0 +IENBMB4XDTE0MDExODE2MDIzN1oXDTI0MDExNjE2MDIzN1owFDESMBAGA1UEAxMJ +ZWMtY2xpZW50MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEQNm5okQbATksFO6qcGsx +mChEyWG8twu1U0nCwApDsAhQzYAvXaSJ8f99EXj1DLKG4ln4F3YbIvIjZ+dVkOrO +CqraBfSFGcntrm2jrVZ69jPGz7vHOfrk02ff8LhKiFeYo4HYMIHVMAkGA1UdEwQC +MAAwHQYDVR0OBBYEFNjiNXvKZnFr2Fv1EhOCLe3N5e1/MEUGA1UdIwQ+MDyAFLSa +QVy4JnxItZlEAP/wukFByAY8oRmkFzAVMRMwEQYDVQQDEwpFQy1UZXN0IENBggkA +sYQYHaDpwBcwEwYDVR0lBAwwCgYIKwYBBQUHAwIwCwYDVR0PBAQDAgeAMC0GCWCG +SAGG+EIBDQQgFh5FYXN5LVJTQSBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwEQYJYIZI +AYb4QgEBBAQDAgeAMAoGCCqGSM49BAMCA2cAMGQCMEGLGv2XqLt80OscorrArC9t +gAdbXO9VWRqSVmaUzklqqVdJskFzZH4BrDE6fCq/pQIwK8SmsQwDguPkAzn7Gdd2 +IRt+f6oiXZCk4S7NypIPtj+A3CbSCTSM0WG7naxtj2jw +-----END CERTIFICATE----- diff --git a/app/openvpn/sample/sample-keys/ec-client.key b/app/openvpn/sample/sample-keys/ec-client.key new file mode 100644 index 00000000..60636ed2 --- /dev/null +++ b/app/openvpn/sample/sample-keys/ec-client.key @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDD9Agj8nr/8sIr0XHky +mcn1oMb3vqOh2axFBaIvmOHYmqs11SIH1tKYelkNYy9zHTChZANiAARA2bmiRBsB +OSwU7qpwazGYKETJYby3C7VTScLACkOwCFDNgC9dpInx/30RePUMsobiWfgXdhsi +8iNn51WQ6s4KqtoF9IUZye2ubaOtVnr2M8bPu8c5+uTTZ9/wuEqIV5g= +-----END PRIVATE KEY----- diff --git a/app/openvpn/sample/sample-keys/ec-server.crt b/app/openvpn/sample/sample-keys/ec-server.crt new file mode 100644 index 00000000..99994729 --- /dev/null +++ b/app/openvpn/sample/sample-keys/ec-server.crt @@ -0,0 +1,61 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1 (0x1) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: CN=EC-Test CA + Validity + Not Before: Jan 18 16:02:31 2014 GMT + Not After : Jan 16 16:02:31 2024 GMT + Subject: CN=ec-server + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (384 bit) + pub: + 04:bd:8c:3a:af:2e:2f:2e:de:cf:d2:39:8d:b9:a6: + 13:96:80:6d:b5:b2:ee:97:62:3b:a2:32:38:77:1e: + fb:2a:ef:86:4b:d0:9e:4b:55:e0:9b:07:f9:64:2f: + 6b:a7:17:fd:65:dd:50:3f:1c:fa:fa:2f:39:2e:97: + d4:86:e5:4e:5a:d2:50:0b:f4:d7:08:62:67:53:44: + 62:e3:25:f2:fa:36:84:87:1d:03:e3:e9:9d:d9:66: + 51:dd:b4:c4:db:0b:05 + ASN1 OID: secp384r1 + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + EA:DF:7E:A3:D4:61:73:D7:01:AF:6E:0A:38:8D:33:D0:BD:24:4B:E1 + X509v3 Authority Key Identifier: + keyid:B4:9A:41:5C:B8:26:7C:48:B5:99:44:00:FF:F0:BA:41:41:C8:06:3C + DirName:/CN=EC-Test CA + serial:B1:84:18:1D:A0:E9:C0:17 + + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Key Usage: + Digital Signature, Key Encipherment + Netscape Comment: + Easy-RSA Generated Certificate + Netscape Cert Type: + SSL Server + Signature Algorithm: ecdsa-with-SHA256 + 30:64:02:30:20:39:12:92:cc:a2:ca:45:b9:1a:8f:e0:c1:e7: + b7:4a:79:4d:07:07:81:72:08:b4:d4:7b:46:53:d7:72:32:d0: + d7:3e:e8:88:2b:c9:ba:8b:d5:94:4f:41:6c:d0:2e:a4:02:30: + 75:ff:c3:8a:c1:f5:79:1c:1a:08:16:31:c2:c1:6e:d4:33:dc: + 9f:04:0f:90:94:d9:75:c1:6d:71:28:62:cc:f6:89:7c:91:86: + a4:96:45:34:a0:8d:92:7e:dd:e3:da:4d +-----BEGIN CERTIFICATE----- +MIICLTCCAbSgAwIBAgIBATAKBggqhkjOPQQDAjAVMRMwEQYDVQQDEwpFQy1UZXN0 +IENBMB4XDTE0MDExODE2MDIzMVoXDTI0MDExNjE2MDIzMVowFDESMBAGA1UEAxMJ +ZWMtc2VydmVyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEvYw6ry4vLt7P0jmNuaYT +loBttbLul2I7ojI4dx77Ku+GS9CeS1Xgmwf5ZC9rpxf9Zd1QPxz6+i85LpfUhuVO +WtJQC/TXCGJnU0Ri4yXy+jaEhx0D4+md2WZR3bTE2wsFo4HYMIHVMAkGA1UdEwQC +MAAwHQYDVR0OBBYEFOrffqPUYXPXAa9uCjiNM9C9JEvhMEUGA1UdIwQ+MDyAFLSa +QVy4JnxItZlEAP/wukFByAY8oRmkFzAVMRMwEQYDVQQDEwpFQy1UZXN0IENBggkA +sYQYHaDpwBcwEwYDVR0lBAwwCgYIKwYBBQUHAwEwCwYDVR0PBAQDAgWgMC0GCWCG +SAGG+EIBDQQgFh5FYXN5LVJTQSBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwEQYJYIZI +AYb4QgEBBAQDAgZAMAoGCCqGSM49BAMCA2cAMGQCMCA5EpLMospFuRqP4MHnt0p5 +TQcHgXIItNR7RlPXcjLQ1z7oiCvJuovVlE9BbNAupAIwdf/DisH1eRwaCBYxwsFu +1DPcnwQPkJTZdcFtcShizPaJfJGGpJZFNKCNkn7d49pN +-----END CERTIFICATE----- diff --git a/app/openvpn/sample/sample-keys/ec-server.key b/app/openvpn/sample/sample-keys/ec-server.key new file mode 100644 index 00000000..bb3cdf1a --- /dev/null +++ b/app/openvpn/sample/sample-keys/ec-server.key @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDD8bQlwrFrXHPmem0bt +cBcU6nYfaZQbPdIDAB7edOOyevvzYH0qMtbaW95iSZLMRVWhZANiAAS9jDqvLi8u +3s/SOY25phOWgG21su6XYjuiMjh3Hvsq74ZL0J5LVeCbB/lkL2unF/1l3VA/HPr6 +Lzkul9SG5U5a0lAL9NcIYmdTRGLjJfL6NoSHHQPj6Z3ZZlHdtMTbCwU= +-----END PRIVATE KEY----- diff --git a/app/openvpn/sample/sample-plugins/log/log_v3.c b/app/openvpn/sample/sample-plugins/log/log_v3.c index 742c7568..4d3af91a 100644 --- a/app/openvpn/sample/sample-plugins/log/log_v3.c +++ b/app/openvpn/sample/sample-plugins/log/log_v3.c @@ -85,6 +85,11 @@ openvpn_plugin_open_v3 (const int v3structver, return OPENVPN_PLUGIN_FUNC_ERROR; } + if( args->ssl_api != SSLAPI_OPENSSL ) { + printf("This plug-in can only be used against OpenVPN with OpenSSL\n"); + return OPENVPN_PLUGIN_FUNC_ERROR; + } + /* Which callbacks to intercept. */ ret->type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | diff --git a/app/openvpn/src/compat/Makefile.am b/app/openvpn/src/compat/Makefile.am index 7ad44525..4591b851 100644 --- a/app/openvpn/src/compat/Makefile.am +++ b/app/openvpn/src/compat/Makefile.am @@ -26,4 +26,5 @@ libcompat_la_SOURCES = \ compat-gettimeofday.c \ compat-daemon.c \ compat-inet_ntop.c \ - compat-inet_pton.c + compat-inet_pton.c \ + compat-lz4.c compat-lz4.h diff --git a/app/openvpn/src/compat/compat-lz4.c b/app/openvpn/src/compat/compat-lz4.c new file mode 100644 index 00000000..c63c18ba --- /dev/null +++ b/app/openvpn/src/compat/compat-lz4.c @@ -0,0 +1,830 @@ +/* + LZ4 - Fast LZ compression algorithm + Copyright (C) 2011-2013, 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 : http://code.google.com/p/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 +//************************************** +// 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 MEMORY_USAGE 14 + +// 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 memory allocation (malloc)). +#define HEAPMODE 0 + + +//************************************** +// CPU Feature Detection +//************************************** +// 32 or 64 bits ? +#if (defined(__x86_64__) || defined(_M_X64) || defined(_WIN64) \ + || defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) \ + || defined(__64BIT__) || defined(_LP64) || defined(__LP64__) \ + || defined(__ia64) || defined(__itanium__) || defined(_M_IA64) ) // Detects 64 bits mode +# define LZ4_ARCH64 1 +#else +# define LZ4_ARCH64 0 +#endif + +// Little Endian or Big Endian ? +// Overwrite the #define below if you know your architecture endianess +#if defined (__GLIBC__) +# include <endian.h> +# if (__BYTE_ORDER == __BIG_ENDIAN) +# define LZ4_BIG_ENDIAN 1 +# endif +#elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN)) +# define LZ4_BIG_ENDIAN 1 +#elif defined(__sparc) || defined(__sparc__) \ + || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \ + || defined(__hpux) || defined(__hppa) \ + || defined(_MIPSEB) || defined(__s390__) +# define LZ4_BIG_ENDIAN 1 +#else +// Little Endian assumed. PDP Endian and other very rare endian format are unsupported. +#endif + +// Unaligned memory access is automatically enabled for "common" CPU, such as x86. +// For others CPU, such as ARM, the compiler may be more cautious, inserting unnecessary extra code to ensure aligned access property +// If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance +#if defined(__ARM_FEATURE_UNALIGNED) +# define LZ4_FORCE_UNALIGNED_ACCESS 1 +#endif + +// 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 + +// BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE : +// This option may provide a small boost to performance for some big endian cpu, although probably modest. +// You may set this option to 1 if data will remain within closed environment. +// This option is useless on Little_Endian CPU (such as x86) +//#define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 + + +//************************************** +// Compiler Options +//************************************** +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) // C99 +/* "restrict" is a known keyword */ +#else +# define restrict // Disable restrict +#endif + +#ifdef _MSC_VER // Visual Studio +# define FORCE_INLINE static __forceinline +# include <intrin.h> // For Visual 2005 +# if LZ4_ARCH64 // 64-bits +# pragma intrinsic(_BitScanForward64) // For Visual 2005 +# pragma intrinsic(_BitScanReverse64) // For Visual 2005 +# else // 32-bits +# pragma intrinsic(_BitScanForward) // For Visual 2005 +# pragma intrinsic(_BitScanReverse) // For Visual 2005 +# endif +# pragma warning(disable : 4127) // disable: C4127: conditional expression is constant +#else +# ifdef __GNUC__ +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif +#endif + +#ifdef _MSC_VER +# define lz4_bswap16(x) _byteswap_ushort(x) +#else +# define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))) +#endif + +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) + +#if (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 + + +//************************************** +// Includes +//************************************** +#include "compat-lz4.h" + + +//************************************** +// 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 + +#if defined(__GNUC__) && !defined(LZ4_FORCE_UNALIGNED_ACCESS) +# define _PACKED __attribute__ ((packed)) +#else +# define _PACKED +#endif + +#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) +# if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack(1) +# else +# pragma pack(push, 1) +# endif +#endif + +typedef struct { U16 v; } _PACKED U16_S; +typedef struct { U32 v; } _PACKED U32_S; +typedef struct { U64 v; } _PACKED U64_S; +typedef struct {size_t v;} _PACKED size_t_S; + +#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) +# if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# pragma pack(0) +# else +# pragma pack(pop) +# endif +#endif + +#define A16(x) (((U16_S *)(x))->v) +#define A32(x) (((U32_S *)(x))->v) +#define A64(x) (((U64_S *)(x))->v) +#define AARCH(x) (((size_t_S *)(x))->v) + + +//************************************** +// Constants +//************************************** +#define LZ4_HASHLOG (MEMORY_USAGE-2) +#define HASHTABLESIZE (1 << MEMORY_USAGE) +#define HASHNBCELLS4 (1 << LZ4_HASHLOG) + +#define MINMATCH 4 + +#define COPYLENGTH 8 +#define LASTLITERALS 5 +#define MFLIMIT (COPYLENGTH+MINMATCH) +const int LZ4_minLength = (MFLIMIT+1); + +#define LZ4_64KLIMIT ((1<<16) + (MFLIMIT-1)) +#define SKIPSTRENGTH 6 // Increasing this value will make the compression run slower on incompressible data + +#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) + +#define KB *(1U<<10) +#define MB *(1U<<20) +#define GB *(1U<<30) + + +//************************************** +// Structures and local types +//************************************** + +typedef struct { + U32 hashTable[HASHNBCELLS4]; + const BYTE* bufferStart; + const BYTE* base; + const BYTE* nextBlock; +} LZ4_Data_Structure; + +typedef enum { notLimited = 0, limited = 1 } limitedOutput_directive; +typedef enum { byPtr, byU32, byU16 } tableType_t; + +typedef enum { noPrefix = 0, withPrefix = 1 } prefix64k_directive; + +typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; +typedef enum { full = 0, partial = 1 } earlyEnd_directive; + + +//************************************** +// Architecture-specific macros +//************************************** +#define STEPSIZE sizeof(size_t) +#define LZ4_COPYSTEP(d,s) { AARCH(d) = AARCH(s); d+=STEPSIZE; s+=STEPSIZE; } +#define LZ4_COPY8(d,s) { LZ4_COPYSTEP(d,s); if (STEPSIZE<8) LZ4_COPYSTEP(d,s); } +#define LZ4_SECURECOPY(d,s,e) { if ((STEPSIZE==4)||(d<e)) LZ4_WILDCOPY(d,s,e); } + +#if LZ4_ARCH64 // 64-bit +# define HTYPE U32 +# define INITBASE(base) const BYTE* const base = ip +#else // 32-bit +# define HTYPE const BYTE* +# define INITBASE(base) const int base = 0 +#endif + +#if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE)) +# define LZ4_READ_LITTLEENDIAN_16(d,s,p) { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; } +# define LZ4_WRITE_LITTLEENDIAN_16(p,i) { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p+=2; } +#else // Little Endian +# define LZ4_READ_LITTLEENDIAN_16(d,s,p) { d = (s) - A16(p); } +# define LZ4_WRITE_LITTLEENDIAN_16(p,v) { A16(p) = v; p+=2; } +#endif + + +//************************************** +// Macros +//************************************** +#define LZ4_WILDCOPY(d,s,e) { do { LZ4_COPY8(d,s) } while (d<e); } // at the end, d>=e; + + +//**************************** +// Private functions +//**************************** +#if LZ4_ARCH64 + +FORCE_INLINE int LZ4_NbCommonBytes (register U64 val) +{ +# if defined(LZ4_BIG_ENDIAN) +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clzll(val) >> 3); +# else + int 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 +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanForward64( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctzll(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 +# endif +} + +#else + +FORCE_INLINE int LZ4_NbCommonBytes (register U32 val) +{ +# if defined(LZ4_BIG_ENDIAN) +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clz(val) >> 3); +# else + int r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; +# endif +# else +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r; + _BitScanForward( &r, val ); + return (int)(r>>3); +# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctz(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 +# endif +} + +#endif + + +//**************************** +// Compression functions +//**************************** +FORCE_INLINE int LZ4_hashSequence(U32 sequence, tableType_t tableType) +{ + if (tableType == byU16) + return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + else + return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); +} + +FORCE_INLINE int LZ4_hashPosition(const BYTE* p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); } + +FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +{ + switch (tableType) + { + case byPtr: { const BYTE** hashTable = (const BYTE**) tableBase; hashTable[h] = p; break; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); break; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); break; } + } +} + +FORCE_INLINE 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); +} + +FORCE_INLINE 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 +} + +FORCE_INLINE 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* ctx, + const char* source, + char* dest, + int inputSize, + int maxOutputSize, + + limitedOutput_directive limitedOutput, + tableType_t tableType, + prefix64k_directive prefix) +{ + const BYTE* ip = (const BYTE*) source; + const BYTE* const base = (prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->base : (const BYTE*) source; + const BYTE* const lowLimit = ((prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->bufferStart : (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 oend = op + maxOutputSize; + + int length; + const int skipStrength = SKIPSTRENGTH; + U32 forwardH; + + // Init conditions + if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; // Unsupported input size, too large (or negative) + if ((prefix==withPrefix) && (ip != ((LZ4_Data_Structure*)ctx)->nextBlock)) return 0; // must continue from end of previous block + if (prefix==withPrefix) ((LZ4_Data_Structure*)ctx)->nextBlock=iend; // do it now, due to potential early exit + 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 ( ; ; ) + { + int findMatchAttempts = (1U << skipStrength) + 3; + const BYTE* forwardIp = ip; + const BYTE* ref; + BYTE* token; + + // Find a match + do { + U32 h = forwardH; + int step = findMatchAttempts++ >> skipStrength; + ip = forwardIp; + forwardIp = ip + step; + + if unlikely(forwardIp > mflimit) { goto _last_literals; } + + forwardH = LZ4_hashPosition(forwardIp, tableType); + ref = LZ4_getPositionOnHash(h, ctx, tableType, base); + LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + + } while ((ref + MAX_DISTANCE < ip) || (A32(ref) != A32(ip))); + + // Catch up + while ((ip>anchor) && (ref > lowLimit) && unlikely(ip[-1]==ref[-1])) { ip--; ref--; } + + // Encode Literal length + length = (int)(ip - anchor); + token = op++; + if ((limitedOutput) && unlikely(op + length + (2 + 1 + LASTLITERALS) + (length/255) > oend)) return 0; // Check output limit + if (length>=(int)RUN_MASK) + { + int len = length-RUN_MASK; + *token=(RUN_MASK<<ML_BITS); + for(; len >= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(length<<ML_BITS); + + // Copy Literals + { BYTE* end=(op)+(length); LZ4_WILDCOPY(op,anchor,end); op=end; } + +_next_match: + // Encode Offset + LZ4_WRITE_LITTLEENDIAN_16(op,(U16)(ip-ref)); + + // Start Counting + ip+=MINMATCH; ref+=MINMATCH; // MinMatch already verified + anchor = ip; + while likely(ip<matchlimit-(STEPSIZE-1)) + { + size_t diff = AARCH(ref) ^ AARCH(ip); + if (!diff) { ip+=STEPSIZE; ref+=STEPSIZE; continue; } + ip += LZ4_NbCommonBytes(diff); + goto _endCount; + } + if (LZ4_ARCH64) if ((ip<(matchlimit-3)) && (A32(ref) == A32(ip))) { ip+=4; ref+=4; } + if ((ip<(matchlimit-1)) && (A16(ref) == A16(ip))) { ip+=2; ref+=2; } + if ((ip<matchlimit) && (*ref == *ip)) ip++; +_endCount: + + // Encode MatchLength + length = (int)(ip - anchor); + if ((limitedOutput) && unlikely(op + (1 + LASTLITERALS) + (length>>8) > oend)) return 0; // Check output limit + if (length>=(int)ML_MASK) + { + *token += ML_MASK; + length -= ML_MASK; + for (; length > 509 ; length-=510) { *op++ = 255; *op++ = 255; } + if (length >= 255) { length-=255; *op++ = 255; } + *op++ = (BYTE)length; + } + else *token += (BYTE)(length); + + // Test end of chunk + if (ip > mflimit) { anchor = ip; break; } + + // Fill table + LZ4_putPosition(ip-2, ctx, tableType, base); + + // Test next position + ref = LZ4_getPosition(ip, ctx, tableType, base); + LZ4_putPosition(ip, ctx, tableType, base); + if ((ref + MAX_DISTANCE >= ip) && (A32(ref) == A32(ip))) { token = op++; *token=0; goto _next_match; } + + // Prepare next loop + anchor = ip++; + forwardH = LZ4_hashPosition(ip, tableType); + } + +_last_literals: + // Encode Last Literals + { + int lastRun = (int)(iend - anchor); + if ((limitedOutput) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; // Check output limit + if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun >= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } + else *op++ = (BYTE)(lastRun<<ML_BITS); + memcpy(op, anchor, iend - anchor); + op += iend-anchor; + } + + // End + return (int) (((char*)op)-dest); +} + + +int LZ4_compress(const char* source, char* dest, int inputSize) +{ +#if (HEAPMODE) + void* ctx = ALLOCATOR(HASHNBCELLS4, 4); // Aligned on 4-bytes boundaries +#else + U32 ctx[1U<<(MEMORY_USAGE-2)] = {0}; // Ensure data is aligned on 4-bytes boundaries +#endif + int result; + + if (inputSize < (int)LZ4_64KLIMIT) + result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, byU16, noPrefix); + else + result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix); + +#if (HEAPMODE) + FREEMEM(ctx); +#endif + return result; +} + +int LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize) +{ + return LZ4_compress_generic(LZ4_Data, source, dest, inputSize, 0, notLimited, byU32, withPrefix); +} + + +int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) +{ +#if (HEAPMODE) + void* ctx = ALLOCATOR(HASHNBCELLS4, 4); // Aligned on 4-bytes boundaries +#else + U32 ctx[1U<<(MEMORY_USAGE-2)] = {0}; // Ensure data is aligned on 4-bytes boundaries +#endif + int result; + + if (inputSize < (int)LZ4_64KLIMIT) + result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limited, byU16, noPrefix); + else + result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix); + +#if (HEAPMODE) + FREEMEM(ctx); +#endif + return result; +} + +int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_compress_generic(LZ4_Data, source, dest, inputSize, maxOutputSize, limited, byU32, withPrefix); +} + + +//**************************** +// Stream functions +//**************************** + +FORCE_INLINE void LZ4_init(LZ4_Data_Structure* lz4ds, const BYTE* base) +{ + MEM_INIT(lz4ds->hashTable, 0, sizeof(lz4ds->hashTable)); + lz4ds->bufferStart = base; + lz4ds->base = base; + lz4ds->nextBlock = base; +} + + +void* LZ4_create (const char* inputBuffer) +{ + void* lz4ds = ALLOCATOR(1, sizeof(LZ4_Data_Structure)); + LZ4_init ((LZ4_Data_Structure*)lz4ds, (const BYTE*)inputBuffer); + return lz4ds; +} + + +int LZ4_free (void* LZ4_Data) +{ + FREEMEM(LZ4_Data); + return (0); +} + + +char* LZ4_slideInputBuffer (void* LZ4_Data) +{ + LZ4_Data_Structure* lz4ds = (LZ4_Data_Structure*)LZ4_Data; + size_t delta = lz4ds->nextBlock - (lz4ds->bufferStart + 64 KB); + + if ( (lz4ds->base - delta > lz4ds->base) // underflow control + || ((size_t)(lz4ds->nextBlock - lz4ds->base) > 0xE0000000) ) // close to 32-bits limit + { + size_t deltaLimit = (lz4ds->nextBlock - 64 KB) - lz4ds->base; + int nH; + + for (nH=0; nH < HASHNBCELLS4; nH++) + { + if ((size_t)(lz4ds->hashTable[nH]) < deltaLimit) lz4ds->hashTable[nH] = 0; + else lz4ds->hashTable[nH] -= (U32)deltaLimit; + } + memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB); + lz4ds->base = lz4ds->bufferStart; + lz4ds->nextBlock = lz4ds->base + 64 KB; + } + else + { + memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB); + lz4ds->nextBlock -= delta; + lz4ds->base -= delta; + } + + return (char*)(lz4ds->nextBlock); +} + + +//**************************** +// Decompression functions +//**************************** + +// This generic decompression function cover all use cases. +// It shall be instanciated 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 optimisation. +FORCE_INLINE int LZ4_decompress_generic( + const char* source, + char* dest, + int inputSize, // + int outputSize, // If endOnInput==endOnInputSize, this value is the max size of Output Buffer. + + int endOnInput, // endOnOutputSize, endOnInputSize + int prefix64k, // noPrefix, withPrefix + int partialDecoding, // full, partial + int targetOutputSize // only used if partialDecoding==partial + ) +{ + // Local Variables + const BYTE* restrict ip = (const BYTE*) source; + const BYTE* ref; + const BYTE* const iend = ip + inputSize; + + BYTE* op = (BYTE*) dest; + BYTE* const oend = op + outputSize; + BYTE* cpy; + BYTE* oexit = op + targetOutputSize; + + const size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; // static reduces speed for LZ4_decompress_safe() on GCC64 + static const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; + + + // 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; + + // get runlength + token = *ip++; + if ((length=(token>>ML_BITS)) == RUN_MASK) + { + unsigned s=255; + while (((endOnInput)?ip<iend:1) && (s==255)) + { + s = *ip++; + length += s; + } + } + + // 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 -= (op-cpy); op = cpy; + + // get offset + LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2; + if ((prefix64k==noPrefix) && unlikely(ref < (BYTE* const)dest)) goto _output_error; // Error : offset outside destination buffer + + // get matchlength + if ((length=(token&ML_MASK)) == ML_MASK) + { + while ((!endOnInput) || (ip<iend-(LASTLITERALS+1))) // Ensure enough bytes remain for LASTLITERALS + token + { + unsigned s = *ip++; + length += s; + if (s==255) continue; + break; + } + } + + // copy repeated sequence + if unlikely((op-ref)<(int)STEPSIZE) + { + const size_t dec64 = dec64table[(sizeof(void*)==4) ? 0 : op-ref]; + op[0] = ref[0]; + op[1] = ref[1]; + op[2] = ref[2]; + op[3] = ref[3]; + op += 4, ref += 4; ref -= dec32table[op-ref]; + A32(op) = A32(ref); + op += STEPSIZE-4; ref -= dec64; + } else { LZ4_COPYSTEP(op,ref); } + cpy = op + length - (STEPSIZE-4); + + if unlikely(cpy>oend-COPYLENGTH-(STEPSIZE-4)) + { + if (cpy > oend-LASTLITERALS) goto _output_error; // Error : last 5 bytes must be literals + LZ4_SECURECOPY(op, ref, (oend-COPYLENGTH)); + while(op<cpy) *op++=*ref++; + op=cpy; + continue; + } + LZ4_WILDCOPY(op, ref, cpy); + op=cpy; // correction + } + + // end of decoding + if (endOnInput) + return (int) (((char*)op)-dest); // Nb of output bytes decoded + else + return (int) (((char*)ip)-source); // Nb of input bytes read + + // Overflow error detected +_output_error: + return (int) (-(((char*)ip)-source))-1; +} + + +int LZ4_decompress_safe(const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, noPrefix, full, 0); +} + +int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, withPrefix, full, 0); +} + +int LZ4_decompress_safe_partial(const char* source, char* dest, int inputSize, int targetOutputSize, int maxOutputSize) +{ + return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, noPrefix, partial, targetOutputSize); +} + +int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int outputSize) +{ + return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, withPrefix, full, 0); +} + +int LZ4_decompress_fast(const char* source, char* dest, int outputSize) +{ +#ifdef _MSC_VER // This version is faster with Visual + return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, noPrefix, full, 0); +#else + return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, withPrefix, full, 0); +#endif +} +#endif diff --git a/app/openvpn/src/compat/compat-lz4.h b/app/openvpn/src/compat/compat-lz4.h new file mode 100644 index 00000000..a289fcfd --- /dev/null +++ b/app/openvpn/src/compat/compat-lz4.h @@ -0,0 +1,205 @@ +/* + LZ4 - Fast LZ compression algorithm + Header File + Copyright (C) 2011-2013, 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 homepage : http://fastcompression.blogspot.com/p/lz4.html + - LZ4 source repository : http://code.google.com/p/lz4/ +*/ +#pragma once + +#if defined (__cplusplus) +extern "C" { +#endif + + +//************************************** +// Compiler Options +//************************************** +#if defined(_MSC_VER) && !defined(__cplusplus) // Visual Studio +# define inline __inline // Visual C is not C99, but supports some kind of inline +#endif + + +//**************************** +// Simple Functions +//**************************** + +int LZ4_compress (const char* source, char* dest, int inputSize); +int LZ4_decompress_safe (const char* source, char* dest, int inputSize, int maxOutputSize); + +/* +LZ4_compress() : + Compresses 'inputSize' bytes from 'source' into 'dest'. + Destination buffer must be already allocated, + and must be sized to handle worst cases situations (input data not compressible) + Worst case size evaluation is provided by function LZ4_compressBound() + inputSize : Max supported value is LZ4_MAX_INPUT_VALUE + return : the number of bytes written in buffer dest + or 0 if the compression fails + +LZ4_decompress_safe() : + maxOutputSize : is the size of the destination buffer (which must be already allocated) + return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize) + 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 (never writes outside of output buffer, and never reads outside of input buffer). Therefore, it is protected against malicious data packets +*/ + + +//**************************** +// Advanced Functions +//**************************** +#define LZ4_MAX_INPUT_SIZE 0x7E000000 // 2 113 929 216 bytes +#define LZ4_COMPRESSBOUND(isize) ((unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) +static inline int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } + +/* +LZ4_compressBound() : + Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible) + primarily useful for memory allocation of output buffer. + inline function is recommended for the general case, + macro is also provided when result needs to be evaluated at compilation (such as stack memory allocation). + + isize : is the input size. 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_compress_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize); + +/* +LZ4_compress_limitedOutput() : + Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'. + If it cannot achieve it, compression will stop, and result of the function will be zero. + This function never writes outside of provided output buffer. + + inputSize : Max supported value is LZ4_MAX_INPUT_VALUE + maxOutputSize : is the size of the destination buffer (which must be already allocated) + return : the number of bytes written in buffer 'dest' + or 0 if the compression fails +*/ + + +int LZ4_decompress_fast (const char* source, char* dest, int outputSize); + +/* +LZ4_decompress_fast() : + outputSize : is the original (uncompressed) size + return : the number of bytes read from the source buffer (in other words, the compressed size) + If the source stream is malformed, the function will stop decoding and return a negative result. + note : This function is a bit faster than LZ4_decompress_safe() + This function never writes outside of output buffers, but may read beyond input buffer in case of malicious data packet. + Use this function preferably into a trusted environment (data to decode comes from a trusted source). + Destination buffer must be already allocated. Its size must be a minimum of 'outputSize' bytes. +*/ + +int LZ4_decompress_safe_partial (const char* source, char* dest, int inputSize, int targetOutputSize, int maxOutputSize); + +/* +LZ4_decompress_safe_partial() : + This function decompress a compressed block of size 'inputSize' at position 'source' + into output buffer 'dest' of size 'maxOutputSize'. + 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 <= maxOutputSize) + 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 +*/ + + +//**************************** +// Stream Functions +//**************************** + +void* LZ4_create (const char* inputBuffer); +int LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize); +int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize); +char* LZ4_slideInputBuffer (void* LZ4_Data); +int LZ4_free (void* LZ4_Data); + +/* +These functions allow the compression of dependent blocks, where each block benefits from prior 64 KB within preceding blocks. +In order to achieve this, it is necessary to start creating the LZ4 Data Structure, thanks to the function : + +void* LZ4_create (const char* inputBuffer); +The result of the function is the (void*) pointer on the LZ4 Data Structure. +This pointer will be needed in all other functions. +If the pointer returned is NULL, then the allocation has failed, and compression must be aborted. +The only parameter 'const char* inputBuffer' must, obviously, point at the beginning of input buffer. +The input buffer must be already allocated, and size at least 192KB. +'inputBuffer' will also be the 'const char* source' of the first block. + +All blocks are expected to lay next to each other within the input buffer, starting from 'inputBuffer'. +To compress each block, use either LZ4_compress_continue() or LZ4_compress_limitedOutput_continue(). +Their behavior are identical to LZ4_compress() or LZ4_compress_limitedOutput(), +but require the LZ4 Data Structure as their first argument, and check that each block starts right after the previous one. +If next block does not begin immediately after the previous one, the compression will fail (return 0). + +When it's no longer possible to lay the next block after the previous one (not enough space left into input buffer), a call to : +char* LZ4_slideInputBuffer(void* LZ4_Data); +must be performed. It will typically copy the latest 64KB of input at the beginning of input buffer. +Note that, for this function to work properly, minimum size of an input buffer must be 192KB. +==> The memory position where the next input data block must start is provided as the result of the function. + +Compression can then resume, using LZ4_compress_continue() or LZ4_compress_limitedOutput_continue(), as usual. + +When compression is completed, a call to LZ4_free() will release the memory used by the LZ4 Data Structure. +*/ + + +int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int inputSize, int maxOutputSize); +int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int outputSize); + +/* +*_withPrefix64k() : + These decoding functions work the same as their "normal name" versions, + but can use up to 64KB of data in front of 'char* dest'. + These functions are necessary to decode inter-dependant blocks. +*/ + + +//**************************** +// Obsolete Functions +//**************************** + +static inline int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } +static inline int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } + +/* +These functions are deprecated and should no longer be used. +They are provided here for compatibility with existing user programs. +*/ + + + +#if defined (__cplusplus) +} +#endif diff --git a/app/openvpn/src/compat/compat-rsa_generate_key.c b/app/openvpn/src/compat/compat-rsa_generate_key.c deleted file mode 100644 index 99725da1..00000000 --- a/app/openvpn/src/compat/compat-rsa_generate_key.c +++ /dev/null @@ -1,47 +0,0 @@ -#include <stdio.h> -#include <time.h> -#include "cryptlib.h" -#include <openssl/bn.h> -#include <openssl/rsa.h> - -RSA *RSA_generate_key(int bits, unsigned long e_value, - void (*callback)(int,int,void *), void *cb_arg) -{ - BN_GENCB cb; - int i; - RSA *rsa = RSA_new(); - BIGNUM *e = BN_new(); - - if(!rsa || !e) goto err; - - /* The problem is when building with 8, 16, or 32 BN_ULONG, - * unsigned long can be larger */ - for (i=0; i<(int)sizeof(unsigned long)*8; i++) - { - if (e_value & (1UL<<i)) - if (BN_set_bit(e,i) == 0) - goto err; - } - - BN_GENCB_set_old(&cb, callback, cb_arg); - - if(RSA_generate_key_ex(rsa, bits, e, &cb)) { - BN_free(e); - return rsa; - } - err: - if(e) BN_free(e); - if(rsa) RSA_free(rsa); - return 0; -} - - - -void mlockall(){} -char * -getpass (prompt) - const char *prompt; -{ - return ""; -} - diff --git a/app/openvpn/src/openvpn/Makefile.am b/app/openvpn/src/openvpn/Makefile.am index 5d38628d..fd593c57 100644 --- a/app/openvpn/src/openvpn/Makefile.am +++ b/app/openvpn/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,8 @@ AM_CFLAGS = \ $(TAP_CFLAGS) \ $(OPTIONAL_CRYPTO_CFLAGS) \ $(OPTIONAL_LZO_CFLAGS) \ + $(OPTIONAL_SNAPPY_CFLAGS) \ + $(OPTIONAL_LZ4_CFLAGS) \ $(OPTIONAL_PKCS11_HELPER_CFLAGS) if WIN32 # we want unicode entry point but not the macro @@ -41,6 +43,8 @@ openvpn_SOURCES = \ 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 \ @@ -98,6 +102,7 @@ openvpn_SOURCES = \ session_id.c session_id.h \ shaper.c shaper.h \ sig.c sig.h \ + snappy.c snappy.h \ socket.c socket.h \ socks.c socks.h \ ssl.c ssl.h ssl_backend.h \ @@ -116,6 +121,8 @@ openvpn_LDADD = \ $(top_builddir)/src/compat/libcompat.la \ $(SOCKETS_LIBS) \ $(OPTIONAL_LZO_LIBS) \ + $(OPTIONAL_SNAPPY_LIBS) \ + $(OPTIONAL_LZ4_LIBS) \ $(OPTIONAL_PKCS11_HELPER_LIBS) \ $(OPTIONAL_CRYPTO_LIBS) \ $(OPTIONAL_SELINUX_LIBS) \ diff --git a/app/openvpn/src/openvpn/base64.c b/app/openvpn/src/openvpn/base64.c index bb89aae3..6dc8479f 100644 --- a/app/openvpn/src/openvpn/base64.c +++ b/app/openvpn/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/app/openvpn/src/openvpn/base64.h b/app/openvpn/src/openvpn/base64.h index 28a9677c..92a195aa 100644 --- a/app/openvpn/src/openvpn/base64.h +++ b/app/openvpn/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/app/openvpn/src/openvpn/breakpad.cpp b/app/openvpn/src/openvpn/breakpad.cpp index 77c469f3..cfcc10a8 100644 --- a/app/openvpn/src/openvpn/breakpad.cpp +++ b/app/openvpn/src/openvpn/breakpad.cpp @@ -19,7 +19,7 @@ static google_breakpad::ExceptionHandler* eh; void breakpad_setup(void) { printf("Initializing Google Breakpad!\n"); - desc = new google_breakpad::MinidumpDescriptor("/data/data/se.leap.openvpn/cache"); + desc = new google_breakpad::MinidumpDescriptor("/data/data/de.blinkt.openvpn/cache"); eh = new google_breakpad::ExceptionHandler(*desc, NULL, DumpCallback, NULL, true,-1); } diff --git a/app/openvpn/src/openvpn/buffer.c b/app/openvpn/src/openvpn/buffer.c index 56d14b1a..46f874b2 100644 --- a/app/openvpn/src/openvpn/buffer.c +++ b/app/openvpn/src/openvpn/buffer.c @@ -327,19 +327,28 @@ gc_malloc (size_t size, bool clear, struct gc_arena *a) #endif { void *ret; - struct gc_entry *e; - ASSERT (NULL != a); - + if (a) + { + struct gc_entry *e; #ifdef DMALLOC - e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry)); + e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry)); #else - e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry)); + e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry)); #endif - check_malloc_return (e); - ret = (char *) e + sizeof (struct gc_entry); - e->next = a->list; - a->list = e; - + check_malloc_return (e); + ret = (char *) e + sizeof (struct gc_entry); + e->next = a->list; + a->list = e; + } + else + { +#ifdef DMALLOC + ret = openvpn_dmalloc (file, line, size); +#else + ret = malloc (size); +#endif + check_malloc_return (ret); + } #ifndef ZERO_BUFFER_ON_ALLOC if (clear) #endif @@ -363,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 @@ -929,9 +976,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) { @@ -1107,5 +1151,3 @@ buffer_list_file (const char *fn, int max_line_len) } return bl; } - -#endif diff --git a/app/openvpn/src/openvpn/buffer.h b/app/openvpn/src/openvpn/buffer.h index 5e11de05..7469da63 100644 --- a/app/openvpn/src/openvpn/buffer.h +++ b/app/openvpn/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) @@ -668,6 +689,10 @@ buf_read_u32 (struct buffer *buf, bool *good) } } +/** + * Compare src buffer contents with match. + * *NOT* constant time. Do not use when comparing HMACs. + */ static inline bool buf_string_match (const struct buffer *src, const void *match, int size) { @@ -676,6 +701,10 @@ buf_string_match (const struct buffer *src, const void *match, int size) return memcmp (BPTR (src), match, size) == 0; } +/** + * Compare first size bytes of src buffer contents with match. + * *NOT* constant time. Do not use when comparing HMACs. + */ static inline bool buf_string_match_head (const struct buffer *src, const void *match, int size) { @@ -689,16 +718,6 @@ bool buf_string_compare_advance (struct buffer *src, const char *match); int buf_substring_len (const struct buffer *buf, int delim); /* - * Bitwise operations - */ -static inline void -xor (uint8_t *dest, const uint8_t *src, int len) -{ - while (len-- > 0) - *dest++ ^= *src++; -} - -/* * Print a string which might be NULL */ const char *np (const char *str); @@ -780,6 +799,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) @@ -791,6 +811,7 @@ static inline void gc_init (struct gc_arena *a) { a->list = NULL; + a->list_special = NULL; } static inline void @@ -803,7 +824,7 @@ static inline struct gc_arena gc_new (void) { struct gc_arena ret; - ret.list = NULL; + gc_init (&ret); return ret; } @@ -812,6 +833,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 @@ -881,9 +904,6 @@ check_malloc_return (void *p) /* * Manage lists of buffers */ - -#ifdef ENABLE_BUFFER_LIST - struct buffer_entry { struct buffer buf; @@ -913,7 +933,4 @@ void buffer_list_pop (struct buffer_list *ol); void buffer_list_aggregate (struct buffer_list *bl, const size_t max); struct buffer_list *buffer_list_file (const char *fn, int max_line_len); - -#endif - #endif /* BUFFER_H */ diff --git a/app/openvpn/src/openvpn/clinat.c b/app/openvpn/src/openvpn/clinat.c index af75fc9d..ddefe123 100644 --- a/app/openvpn/src/openvpn/clinat.c +++ b/app/openvpn/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/app/openvpn/src/openvpn/clinat.h b/app/openvpn/src/openvpn/clinat.h index d55a727a..a5779e15 100644 --- a/app/openvpn/src/openvpn/clinat.h +++ b/app/openvpn/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/app/openvpn/src/openvpn/common.h b/app/openvpn/src/openvpn/common.h index dd2c83f4..2f85bec2 100644 --- a/app/openvpn/src/openvpn/common.h +++ b/app/openvpn/src/openvpn/common.h @@ -100,6 +100,6 @@ typedef unsigned long ptr_type; /* * Script security warning */ -#define SCRIPT_SECURITY_WARNING "WARNING: External program may not be called unless '--script-security 2' or higher is enabled. Use '--script-security 3 system' for backward compatibility with 2.1_rc8 and earlier. See --help text or man page for detailed info." +#define SCRIPT_SECURITY_WARNING "WARNING: External program may not be called unless '--script-security 2' or higher is enabled. See --help text or man page for detailed info." #endif diff --git a/app/openvpn/src/openvpn/comp-lz4.c b/app/openvpn/src/openvpn/comp-lz4.c new file mode 100644 index 00000000..46511485 --- /dev/null +++ b/app/openvpn/src/openvpn/comp-lz4.c @@ -0,0 +1,194 @@ +/* + * 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" + +/* Initial command byte to tell our peer if we compressed */ +#define LZ4_COMPRESS_BYTE 0x69 + +static void +lz4_compress_init (struct compress_context *compctx) +{ + msg (D_INIT_MEDIUM, "LZ4 compression initializing"); + ASSERT(compctx->flags & COMP_F_SWAP); +} + +static void +lz4_compress_uninit (struct compress_context *compctx) +{ +} + +static void +lz4_compress (struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame* frame) +{ + bool compressed = false; + + if (buf->len <= 0) + return; + + /* + * 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; + } + + 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; + } + + ASSERT (buf_safe (&work, zlen)); + work.len = zlen; + compressed = true; + + dmsg (D_COMP, "LZ4 compress %d -> %d", buf->len, work.len); + compctx->pre_compress += buf->len; + compctx->post_compress += work.len; + } + + /* 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 +lz4_decompress (struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame* frame) +{ + size_t zlen_max = EXPANDED_SIZE (frame); + int uncomp_len; + 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 */ + { + 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; + } + 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; + } +} + +const struct compress_alg lz4_alg = { + "lz4", + lz4_compress_init, + lz4_compress_uninit, + lz4_compress, + lz4_decompress +}; + +#else +static void dummy(void) {} +#endif /* ENABLE_LZ4 */ diff --git a/app/openvpn/src/openvpn/comp-lz4.h b/app/openvpn/src/openvpn/comp-lz4.h new file mode 100644 index 00000000..ca1dfa9b --- /dev/null +++ b/app/openvpn/src/openvpn/comp-lz4.h @@ -0,0 +1,40 @@ +/* + * 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; + +struct lz4_workspace +{ +}; + +#endif /* ENABLE_LZ4 */ +#endif diff --git a/app/openvpn/src/openvpn/comp.c b/app/openvpn/src/openvpn/comp.c new file mode 100644 index 00000000..4ac589f9 --- /dev/null +++ b/app/openvpn/src/openvpn/comp.c @@ -0,0 +1,146 @@ +/* + * 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; + (*compctx->alg.compress_init)(compctx); + break; +#ifdef ENABLE_LZO + case COMP_ALG_LZO: + ALLOC_OBJ_CLEAR (compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = lzo_alg; + (*compctx->alg.compress_init)(compctx); + break; +#endif +#ifdef ENABLE_SNAPPY + case COMP_ALG_SNAPPY: + ALLOC_OBJ_CLEAR (compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = snappy_alg; + (*compctx->alg.compress_init)(compctx); + break; +#endif +#ifdef ENABLE_LZ4 + case COMP_ALG_LZ4: + ALLOC_OBJ_CLEAR (compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = lz4_alg; + (*compctx->alg.compress_init)(compctx); + break; +#endif + } + return compctx; +} + +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"); +#endif +#if defined(ENABLE_SNAPPY) + buf_printf (out, "IV_SNAPPY=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"); + } +} + +#endif /* USE_COMP */ diff --git a/app/openvpn/src/openvpn/comp.h b/app/openvpn/src/openvpn/comp.h new file mode 100644 index 00000000..bfa25fd3 --- /dev/null +++ b/app/openvpn/src/openvpn/comp.h @@ -0,0 +1,180 @@ +/* + * 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 + * Snappy, 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 */ +#define COMP_ALG_LZ4 4 /* LZ4 algorithm */ + +/* 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 + */ +#define NO_COMPRESS_BYTE 0xFA +#define NO_COMPRESS_BYTE_SWAP 0xFB /* to maintain payload alignment, replace this byte with last byte of packet */ + +/* + * 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_SNAPPY +#include "snappy.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_SNAPPY + struct snappy_workspace snappy; +#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; + +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); + +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/app/openvpn/src/openvpn/compstub.c b/app/openvpn/src/openvpn/compstub.c new file mode 100644 index 00000000..2ab7163e --- /dev/null +++ b/app/openvpn/src/openvpn/compstub.c @@ -0,0 +1,118 @@ +/* + * 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; + } + } +} + +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/app/openvpn/src/openvpn/crypto.c b/app/openvpn/src/openvpn/crypto.c index ac2eecdd..c4c356dc 100644 --- a/app/openvpn/src/openvpn/crypto.c +++ b/app/openvpn/src/openvpn/crypto.c @@ -65,6 +65,24 @@ #define CRYPT_ERROR(format) \ do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false) +/** + * 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++; + } + + return ret; +} + void openvpn_encrypt (struct buffer *buf, struct buffer work, const struct crypto_options *opt, @@ -244,7 +262,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, hmac_ctx_final (ctx->hmac, local_hmac); /* Compare locally computed HMAC with packet HMAC */ - if (memcmp (local_hmac, BPTR (buf), hmac_len)) + if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len)) CRYPT_ERROR ("packet HMAC authentication failed"); ASSERT (buf_advance (buf, hmac_len)); @@ -401,7 +419,7 @@ init_key_type (struct key_type *kt, const char *ciphername, CLEAR (*kt); if (ciphername && ciphername_defined) { - kt->cipher = cipher_kt_get (ciphername); + kt->cipher = cipher_kt_get (translate_cipher_name_from_openvpn(ciphername)); kt->cipher_length = cipher_kt_key_size (kt->cipher); if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH) kt->cipher_length = keysize; @@ -1010,7 +1028,6 @@ read_passphrase_hash (const char *passphrase_file, uint8_t *output, int len) { - unsigned int outlen = 0; md_ctx_t md; ASSERT (len >= md_kt_size(digest)); @@ -1343,7 +1360,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); diff --git a/app/openvpn/src/openvpn/crypto_backend.h b/app/openvpn/src/openvpn/crypto_backend.h index 1eac6115..5ae47e6c 100644 --- a/app/openvpn/src/openvpn/crypto_backend.h +++ b/app/openvpn/src/openvpn/crypto_backend.h @@ -63,6 +63,18 @@ void crypto_init_lib_engine (const char *engine_name); void crypto_init_dmalloc (void); #endif /* DMALLOC */ +/** + * Translate a data channel cipher name from the OpenVPN config file + * 'language' to the crypto library specific name. + */ +const char * translate_cipher_name_from_openvpn (const char *cipher_name); + +/** + * Translate a data channel cipher name from the crypto library specific name + * to the OpenVPN config file 'language'. + */ +const char * translate_cipher_name_from_openvpn (const char *cipher_name); + void show_available_ciphers (void); void show_available_digests (void); diff --git a/app/openvpn/src/openvpn/crypto_openssl.c b/app/openvpn/src/openvpn/crypto_openssl.c index 53425029..c3480e02 100644 --- a/app/openvpn/src/openvpn/crypto_openssl.c +++ b/app/openvpn/src/openvpn/crypto_openssl.c @@ -57,59 +57,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 - -static inline int -EVP_CipherInit_ov (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, uint8_t *key, uint8_t *iv, int enc) -{ - return EVP_CipherInit (ctx, type, key, iv, enc); -} - -static inline int -EVP_CipherUpdate_ov (EVP_CIPHER_CTX *ctx, uint8_t *out, int *outl, uint8_t *in, int inl) -{ - return EVP_CipherUpdate (ctx, out, outl, in, inl); -} - -static inline bool -cipher_ok (const char* name) -{ - return true; -} - -#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> @@ -194,7 +141,8 @@ crypto_init_lib_engine (const char *engine_name) void crypto_init_lib (void) { -#ifndef USE_SSL +#ifndef ENABLE_SSL + /* If SSL is enabled init is taken care of in ssl_openssl.c */ #ifndef ENABLE_SMALL ERR_load_crypto_strings (); #endif @@ -215,7 +163,8 @@ crypto_init_lib (void) void crypto_uninit_lib (void) { -#ifndef USE_SSL +#ifndef ENABLE_SSL + /* If SSL is enabled cleanup is taken care of in ssl_openssl.c */ EVP_cleanup (); #ifndef ENABLE_SMALL ERR_free_strings (); @@ -281,6 +230,18 @@ 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 char * +translate_cipher_name_to_openvpn (const char *cipher_name) { + // OpenSSL doesn't require any translation + return cipher_name; +} + void show_available_ciphers () { @@ -298,7 +259,7 @@ show_available_ciphers () for (nid = 0; nid < 10000; ++nid) /* is there a better way to get the size of the nid list? */ { const EVP_CIPHER *cipher = EVP_get_cipherbynid (nid); - if (cipher && cipher_ok (OBJ_nid2sn (nid))) + if (cipher) { const unsigned int mode = EVP_CIPHER_mode (cipher); if (mode == EVP_CIPH_CBC_MODE @@ -477,7 +438,7 @@ cipher_kt_get (const char *ciphername) cipher = EVP_get_cipherbyname (ciphername); - if ((NULL == cipher) || !cipher_ok (OBJ_nid2sn (EVP_CIPHER_nid (cipher)))) + if (NULL == cipher) msg (M_SSLERR, "Cipher algorithm '%s' not found", ciphername); if (EVP_CIPHER_key_length (cipher) > MAX_CIPHER_KEY_LENGTH) @@ -538,13 +499,13 @@ cipher_ctx_init (EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len, CLEAR (*ctx); EVP_CIPHER_CTX_init (ctx); - if (!EVP_CipherInit_ov (ctx, kt, NULL, NULL, enc)) + if (!EVP_CipherInit (ctx, kt, NULL, NULL, enc)) msg (M_SSLERR, "EVP cipher init #1"); #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH if (!EVP_CIPHER_CTX_set_key_length (ctx, key_len)) msg (M_SSLERR, "EVP set key size"); #endif - if (!EVP_CipherInit_ov (ctx, NULL, key, NULL, enc)) + if (!EVP_CipherInit (ctx, NULL, key, NULL, enc)) msg (M_SSLERR, "EVP cipher init #2"); /* make sure we used a big enough key */ @@ -578,14 +539,14 @@ cipher_ctx_mode (const EVP_CIPHER_CTX *ctx) int cipher_ctx_reset (EVP_CIPHER_CTX *ctx, uint8_t *iv_buf) { - return EVP_CipherInit_ov (ctx, NULL, NULL, iv_buf, -1); + return EVP_CipherInit (ctx, NULL, NULL, iv_buf, -1); } int cipher_ctx_update (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, uint8_t *src, int src_len) { - return EVP_CipherUpdate_ov (ctx, dst, dst_len, src, src_len); + return EVP_CipherUpdate (ctx, dst, dst_len, src, src_len); } int diff --git a/app/openvpn/src/openvpn/crypto_polarssl.c b/app/openvpn/src/openvpn/crypto_polarssl.c index 3978a3c6..7dc8aa5b 100644 --- a/app/openvpn/src/openvpn/crypto_polarssl.c +++ b/app/openvpn/src/openvpn/crypto_polarssl.c @@ -94,6 +94,53 @@ crypto_init_dmalloc (void) } #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 () { @@ -114,7 +161,7 @@ show_available_ciphers () if (info && info->mode == POLARSSL_MODE_CBC) printf ("%s %d bit default key\n", - info->name, info->key_length); + cipher_kt_name(info), cipher_kt_key_size(info) * 8); ciphers++; } @@ -331,7 +378,8 @@ cipher_kt_name (const cipher_info_t *cipher_kt) { if (NULL == cipher_kt) return "[null-cipher]"; - return cipher_kt->name; + + return translate_cipher_name_to_openvpn(cipher_kt->name); } int @@ -339,6 +387,9 @@ 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; } @@ -415,7 +466,12 @@ int cipher_ctx_mode (const cipher_context_t *ctx) int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf) { - return 0 == cipher_reset(ctx, iv_buf); + int retval = cipher_reset(ctx); + + if (0 == retval) + retval = cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size); + + return 0 == retval; } int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len, diff --git a/app/openvpn/src/openvpn/crypto_polarssl.h b/app/openvpn/src/openvpn/crypto_polarssl.h index bfabb91b..b6da4363 100644 --- a/app/openvpn/src/openvpn/crypto_polarssl.h +++ b/app/openvpn/src/openvpn/crypto_polarssl.h @@ -30,7 +30,6 @@ #ifndef CRYPTO_POLARSSL_H_ #define CRYPTO_POLARSSL_H_ -#include <polarssl/version.h> #include <polarssl/cipher.h> #include <polarssl/md.h> #include <polarssl/ctr_drbg.h> @@ -60,7 +59,7 @@ typedef md_context_t hmac_ctx_t; #define OPENVPN_MODE_OFB POLARSSL_MODE_OFB /** Cipher is in CFB mode */ -#define OPENVPN_MODE_CFB POLARSSL_MODE_CFB128 +#define OPENVPN_MODE_CFB POLARSSL_MODE_CFB /** Cipher should encrypt */ #define OPENVPN_OP_ENCRYPT POLARSSL_ENCRYPT diff --git a/app/openvpn/src/openvpn/error.c b/app/openvpn/src/openvpn/error.c index 98611a1b..af865f32 100644 --- a/app/openvpn/src/openvpn/error.c +++ b/app/openvpn/src/openvpn/error.c @@ -86,6 +86,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 */ @@ -159,10 +163,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; @@ -334,7 +345,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, + tv.tv_usec, + flags, + prefix, + prefix_sep, + m1, + "\n"); + + } + else if ((flags & M_NOPREFIX) || suppress_timestamps) { fprintf (fp, "%s%s%s%s", prefix, diff --git a/app/openvpn/src/openvpn/error.h b/app/openvpn/src/openvpn/error.h index 27c48b69..1e1f2acf 100644 --- a/app/openvpn/src/openvpn/error.h +++ b/app/openvpn/src/openvpn/error.h @@ -194,6 +194,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); diff --git a/app/openvpn/src/openvpn/event.c b/app/openvpn/src/openvpn/event.c index 2a13e1cf..34a3c451 100644 --- a/app/openvpn/src/openvpn/event.c +++ b/app/openvpn/src/openvpn/event.c @@ -34,6 +34,7 @@ #include "error.h" #include "integer.h" #include "event.h" +#include "fdmisc.h" #include "memdbg.h" @@ -582,6 +583,8 @@ ep_init (int *maxevents, unsigned int flags) if (fd < 0) return NULL; + set_cloexec (fd); + ALLOC_OBJ_CLEAR (eps, struct ep_set); /* set dispatch functions */ diff --git a/app/openvpn/src/openvpn/forward-inline.h b/app/openvpn/src/openvpn/forward-inline.h index 7eb480dd..5853ce29 100644 --- a/app/openvpn/src/openvpn/forward-inline.h +++ b/app/openvpn/src/openvpn/forward-inline.h @@ -228,7 +228,6 @@ context_reschedule_sec (struct context *c, int sec) static inline struct link_socket_info * get_link_socket_info (struct context *c) { - if (c->c2.link_socket_info) return c->c2.link_socket_info; else diff --git a/app/openvpn/src/openvpn/forward.c b/app/openvpn/src/openvpn/forward.c index 9e9c406c..a43361b4 100644 --- a/app/openvpn/src/openvpn/forward.c +++ b/app/openvpn/src/openvpn/forward.c @@ -39,6 +39,7 @@ #include "ps.h" #include "dhcp.h" #include "common.h" +#include "ssl_verify.h" #include "memdbg.h" @@ -444,10 +445,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) @@ -610,8 +611,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. @@ -649,7 +648,6 @@ link_socket_write_post_size_adjust (int *size, *size = 0; } } -#endif /* * Output: c->c2.buf @@ -718,10 +716,8 @@ 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 (); } @@ -846,10 +842,10 @@ process_incoming_link (struct context *c) 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 @@ -1017,6 +1013,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; @@ -1026,11 +1024,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)) @@ -1045,14 +1045,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) { @@ -1122,7 +1120,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, 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)); @@ -1130,23 +1128,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) diff --git a/app/openvpn/src/openvpn/init.c b/app/openvpn/src/openvpn/init.c index b3125282..ede955a1 100644 --- a/app/openvpn/src/openvpn/init.c +++ b/app/openvpn/src/openvpn/init.c @@ -43,6 +43,7 @@ #include "lladdr.h" #include "ping.h" #include "mstats.h" +#include "ssl_verify.h" #include "memdbg.h" @@ -127,11 +128,9 @@ management_callback_proxy_cmd (void *arg, const char **p) { 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_TCP && ce->proto != PROTO_TCP_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; } @@ -141,17 +140,12 @@ management_callback_proxy_cmd (void *arg, const char **p) ho->retry = true; 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 = p[3]; ret = true; -#endif } } else @@ -174,10 +168,12 @@ ce_management_query_proxy (struct context *c) if (management) { gc = gc_new (); - struct buffer out = alloc_buf_gc (256, &gc); - buf_printf (&out, ">PROXY:%u,%s,%s", (l ? l->current : 0) + 1, - (proto_is_udp (ce->proto) ? "UDP" : "TCP"), np (ce->remote)); - management_notify_generic (management, BSTR (&out)); + { + struct buffer out = alloc_buf_gc (256, &gc); + buf_printf (&out, ">PROXY:%u,%s,%s", (l ? l->current : 0) + 1, + (proto_is_udp (ce->proto) ? "UDP" : "TCP"), np (ce->remote)); + management_notify_generic (management, BSTR (&out)); + } ce->flags |= CE_MAN_QUERY_PROXY; while (ce->flags & CE_MAN_QUERY_PROXY) { @@ -282,6 +278,7 @@ static void init_connection_list (struct context *c) { struct connection_list *l = c->options.connection_list; + l->current = -1; if (c->options.remote_random) { @@ -303,11 +300,10 @@ init_connection_list (struct context *c) /* * Clear the remote address list */ -static void clear_remote_addrlist (struct link_socket_addr *lsa) +static void clear_remote_addrlist (struct link_socket_addr *lsa, bool free) { - if (lsa->remote_list) { - freeaddrinfo(lsa->remote_list); - } + if (lsa->remote_list && free) + freeaddrinfo(lsa->remote_list); lsa->remote_list = NULL; lsa->current_remote = NULL; } @@ -322,7 +318,7 @@ next_connection_entry (struct context *c) bool ce_defined; struct connection_entry *ce; int n_cycles = 0; - + do { ce_defined = true; if (c->options.no_advance && l->current >= 0) @@ -345,9 +341,12 @@ next_connection_entry (struct context *c) * this is broken probably ever since connection lists and multiple * remote existed */ - if (!c->options.persist_remote_ip) - clear_remote_addrlist (&c->c1.link_socket_addr); + { + /* 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; @@ -357,7 +356,7 @@ next_connection_entry (struct context *c) * If this is connect-retry-max * size(l) * OpenVPN will quit */ - + c->options.unsuccessful_attempts++; if (++l->current >= l->len) @@ -396,7 +395,7 @@ next_connection_entry (struct context *c) } #endif } 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)) @@ -434,41 +433,30 @@ init_query_passwords (struct context *c) * Initialize/Uninitialize HTTP or SOCKS proxy */ -#ifdef GENERAL_PROXY_SUPPORT - 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 */ @@ -479,10 +467,8 @@ 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, @@ -493,7 +479,6 @@ init_proxy_dowork (struct context *c) c->c1.socks_proxy_owned = true; } } -#endif } static void @@ -508,20 +493,6 @@ uninit_proxy (struct context *c) uninit_proxy_dowork (c); } -#else - -static inline void -init_proxy (struct context *c, const int scope) -{ -} - -static inline void -uninit_proxy (struct context *c) -{ -} - -#endif - void context_init_1 (struct context *c) { @@ -865,7 +836,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 + || options->show_tls_ciphers || options->show_curves #endif ) { @@ -877,7 +848,9 @@ print_openssl_info (const struct options *options) show_available_engines (); #ifdef ENABLE_SSL if (options->show_tls_ciphers) - show_available_tls_ciphers (); + show_available_tls_ciphers (options->cipher_list); + if (options->show_curves) + show_available_curves(); #endif return true; } @@ -1156,16 +1129,17 @@ do_init_traffic_shaper (struct context *c) } /* - * Allocate a route list structure if at least one - * --route option was specified. + * Allocate route list structures for IPv4 and IPv6 + * (we do this for IPv4 even if no --route option has been seen, as other + * parts of OpenVPN might want to fill the route-list with info, e.g. DHCP) */ static void do_alloc_route_list (struct context *c) { - if (c->options.routes && !c->c1.route_list) - c->c1.route_list = new_route_list (c->options.max_routes, &c->gc); + if (!c->c1.route_list) + 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); } @@ -1215,7 +1189,6 @@ do_init_route_ipv6_list (const struct options *options, 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 */ @@ -1251,7 +1224,7 @@ void 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; @@ -1420,15 +1393,15 @@ do_open_tun (struct context *c) 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 */ + * then close the old */ int oldtunfd=-1; - if(c->c1.tuntap) - oldtunfd = c->c1.tuntap->fd; + if (c->c1.tuntap) + oldtunfd = c->c1.tuntap->fd; #endif - + /* initialize (but do not open) tun/tap object */ do_init_tun (c); @@ -1455,19 +1428,19 @@ do_open_tun (struct context *c) } /* possibly add routes */ - if(ifconfig_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); - } - + 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); -#ifdef TARGET_ANDROID - if(oldtunfd>=0) - close(oldtunfd); -#endif + /* set the hardware address */ if (c->options.lladdr) set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es); @@ -1495,7 +1468,7 @@ do_open_tun (struct context *c) c->c2.es); /* possibly add routes */ - if ((ifconfig_order() == ROUTE_AFTER_TUN) && (!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); @@ -1578,7 +1551,7 @@ 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, @@ -1705,7 +1678,7 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) #endif /* if --route-delay was specified, start timer */ - if ((ifconfig_order() == ROUTE_AFTER_TUN) && 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); @@ -1783,14 +1756,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 @@ -1853,18 +1824,8 @@ do_hold (struct context *c) 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 - switch (c->options.ce.proto) { case PROTO_TCP_SERVER: @@ -2222,7 +2183,12 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.renegotiate_seconds = options->renegotiate_seconds; to.single_session = options->single_session; #ifdef ENABLE_PUSH_PEER_INFO - to.push_peer_info = options->push_peer_info; + if (options->push_peer_info) /* all there is */ + to.push_peer_info_detail = 2; + else if (options->pull) /* pull clients send some details */ + to.push_peer_info_detail = 1; + else /* default: no peer-info at all */ + to.push_peer_info_detail = 0; #endif /* should we not xmit any packets until we get an initial @@ -2236,7 +2202,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.verify_command = options->tls_verify; to.verify_export_cert = options->tls_export_cert; - to.verify_x509name = options->tls_remote; + to.verify_x509_type = (options->verify_x509_type & 0xff); + to.verify_x509_name = options->verify_x509_name; to.crl_file = options->crl_file; to.ssl_flags = options->ssl_flags; to.ns_cert_type = options->ns_cert_type; @@ -2278,6 +2245,10 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) #endif #endif +#ifdef USE_COMP + to.comp_options = options->comp; +#endif + /* TLS handshake authentication (--tls-auth) */ if (options->tls_auth_file) { @@ -2360,38 +2331,56 @@ do_init_crypto (struct context *c, const unsigned int flags) 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_SNAPPY) && !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 Snappy 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 Snappy or 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. @@ -2412,6 +2401,17 @@ 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 */ + #ifdef ENABLE_FRAGMENT /* * Set frame parameter for fragment code. This is necessary because @@ -2498,12 +2498,10 @@ do_option_warnings (struct context *c) warn_on_use_of_common_subnets (); if (o->tls_client && !o->tls_verify - && !o->tls_remote + && o->verify_x509_type == VERIFY_X509_NONE && !(o->ns_cert_type & NS_CERT_CHECK_SERVER) && !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."); - if (o->tls_remote) - msg (M_WARN, "WARNING: Make sure you understand the semantics of --tls-remote before using it (see the man page)."); #endif #endif @@ -2512,6 +2510,16 @@ do_option_warnings (struct context *c) 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) + { + if (script_security >= SSEC_SCRIPTS) + msg (M_WARN, "NOTE: the current --script-security setting may allow this configuration to call user-defined scripts"); + else if (script_security >= SSEC_PW_ENV) + msg (M_WARN, "WARNING: the current --script-security setting may allow passwords to be passed to scripts via environmental variables"); + else + msg (M_WARN, "NOTE: starting with " PACKAGE_NAME " 2.1, '--script-security 2' or higher is required to call user-defined scripts or executables"); + } } static void @@ -2539,9 +2547,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; @@ -2556,9 +2564,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 @@ -2638,16 +2646,14 @@ do_init_socket_1 (struct context *c, const int mode) 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.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 @@ -2857,7 +2863,7 @@ do_close_link_socket (struct context *c) || c->options.no_advance)) ))) { - clear_remote_addrlist(&c->c1.link_socket_addr); + 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 */ @@ -2865,8 +2871,9 @@ do_close_link_socket (struct context *c) CLEAR (c->c1.link_socket_addr.actual); if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) { - if (c->c1.link_socket_addr.bind_local) - freeaddrinfo(c->c1.link_socket_addr.bind_local); + 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; } } @@ -3003,7 +3010,7 @@ do_close_ifconfig_pool_persist (struct context *c) static void do_inherit_env (struct context *c, const struct env_set *src) { - c->c2.es = env_set_create (&c->c2.gc); + c->c2.es = env_set_create (NULL); c->c2.es_owned = true; env_set_inherit (c->c2.es, src); } @@ -3154,6 +3161,20 @@ management_show_net_callback (void *arg, const int msglevel) #endif } +#ifdef TARGET_ANDROID +int +managmenet_callback_network_change (void *arg) +{ + struct context *c = (struct context *) arg; + if (!c->c2.link_socket) + return -1; + if (c->c2.link_socket->sd == SOCKET_UNDEFINED) + return -1; + + return c->c2.link_socket->sd; +} +#endif + #endif void @@ -3169,6 +3190,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 = managmenet_callback_network_change; +#endif management_set_callback (management, &cb); } #endif @@ -3288,6 +3312,10 @@ 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; @@ -3304,6 +3332,13 @@ 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); @@ -3339,10 +3374,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) @@ -3403,10 +3434,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 */ @@ -3520,9 +3551,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 */ @@ -3694,6 +3728,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 @@ -3737,6 +3775,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); diff --git a/app/openvpn/src/openvpn/lzo.c b/app/openvpn/src/openvpn/lzo.c index 195b8194..daa02ed0 100644 --- a/app/openvpn/src/openvpn/lzo.c +++ b/app/openvpn/src/openvpn/lzo.c @@ -34,15 +34,17 @@ #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 +/* Initial command byte to tell our peer if we compressed */ +#define LZO_COMPRESS_BYTE 0x66 + /** * Perform adaptive compression housekeeping. * @@ -97,101 +99,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 +173,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 +213,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 +228,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 +245,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/app/openvpn/src/openvpn/lzo.h b/app/openvpn/src/openvpn/lzo.h index 472204d0..f33e587a 100644 --- a/app/openvpn/src/openvpn/lzo.h +++ b/app/openvpn/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/app/openvpn/src/openvpn/manage.c b/app/openvpn/src/openvpn/manage.c index c4e834b2..e7a7fe85 100644 --- a/app/openvpn/src/openvpn/manage.c +++ b/app/openvpn/src/openvpn/manage.c @@ -1105,6 +1105,19 @@ man_remote (struct management *man, const char **p) } } +#ifdef TARGET_ANDROID +static void +man_network_change (struct management *man) +{ + if (man->persist.callback.network_change) + { + int fd = (*man->persist.callback.network_change)(man->persist.callback.arg); + man->connection.fdtosend = fd; + msg (M_CLIENT, "PROTECTFD: fd '%d' sent to be protected", fd); + } +} +#endif + static void man_dispatch_command (struct management *man, struct status_output *so, const char **p, const int nparms) { @@ -1148,6 +1161,12 @@ 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")) + { + man_network_change(man); + } +#endif else if (streq (p[0], "load-stats")) { man_load_stats (man); @@ -1568,9 +1587,9 @@ man_listen (struct management *man) else #endif { - man->connection.sd_top = create_socket_tcp (AF_INET); + man->connection.sd_top = create_socket_tcp (man->settings.local); socket_bind (man->connection.sd_top, man->settings.local, - AF_INET, "MANAGEMENT"); + man->settings.local->ai_family, "MANAGEMENT", false); } /* @@ -1635,7 +1654,7 @@ 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->ai_addr, 5, @@ -1781,77 +1800,118 @@ man_io_error (struct management *man, const char *prefix) } #ifdef TARGET_ANDROID -static ssize_t write_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 read_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 */ - +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; } -#endif +/* + * 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) @@ -1864,8 +1924,8 @@ man_read (struct management *man) #ifdef TARGET_ANDROID int fd; - len = read_fd (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL, &fd); - if(fd >= 0) + 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); @@ -1948,9 +2008,9 @@ man_write (struct management *man) { const int len = min_int (size_hint, BLEN (buf)); #ifdef TARGET_ANDROID - if (man->connection.fdtosend > 0) + if (man->connection.fdtosend > 0) { - sent = write_fd (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL,man->connection.fdtosend); + sent = man_send_with_fd (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL,man->connection.fdtosend); man->connection.fdtosend = -1; } else #endif @@ -2110,8 +2170,14 @@ man_settings_init (struct man_settings *ms, } else { - int status = openvpn_getaddrinfo(GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, - addr, port, 0, NULL, AF_INET, &ms->local); + 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); } } @@ -2138,6 +2204,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); } @@ -2445,33 +2513,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) { @@ -2510,7 +2551,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; } @@ -2599,9 +2641,9 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i /* listen on our local TUN/TAP IP address */ struct in_addr ia; int ret; - + ia.s_addr = htonl(tun_local_ip); - ret = openvpn_getaddrinfo(0, inet_ntoa(ia), NULL, 0, NULL, + ret = openvpn_getaddrinfo(GETADDR_PASSIVE, inet_ntoa(ia), NULL, 0, NULL, AF_INET, &man->settings.local); ASSERT (ret==0); man_connection_init (man); diff --git a/app/openvpn/src/openvpn/manage.h b/app/openvpn/src/openvpn/manage.h index d2790dd4..c48875c7 100644 --- a/app/openvpn/src/openvpn/manage.h +++ b/app/openvpn/src/openvpn/manage.h @@ -173,6 +173,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); +#endif }; /* @@ -300,8 +303,8 @@ struct man_connection { struct buffer_list *rsa_sig; #endif #ifdef TARGET_ANDROID - int fdtosend; - int lastfdreceived; + int fdtosend; + int lastfdreceived; #endif }; @@ -376,6 +379,15 @@ 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); diff --git a/app/openvpn/src/openvpn/mbuf.h b/app/openvpn/src/openvpn/mbuf.h index a0de679d..1085adc7 100644 --- a/app/openvpn/src/openvpn/mbuf.h +++ b/app/openvpn/src/openvpn/mbuf.h @@ -83,7 +83,7 @@ mbuf_defined (const struct mbuf_set *ms) return ms && ms->len; } -static inline bool +static inline unsigned int mbuf_len (const struct mbuf_set *ms) { return ms->len; diff --git a/app/openvpn/src/openvpn/misc.c b/app/openvpn/src/openvpn/misc.c index fcc85526..7483184f 100644 --- a/app/openvpn/src/openvpn/misc.c +++ b/app/openvpn/src/openvpn/misc.c @@ -701,21 +701,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 */ - -void -manage_env (char *str) -{ - remove_env_item (str, true, &global_env); - add_env_item (str, false, &global_env, NULL); -} - -#endif - /* add/modify/delete environmental strings */ void @@ -789,27 +774,18 @@ setenv_str_ex (struct env_set *es, if (value) val_tmp = string_mod_const (value, value_include, value_exclude, value_replace, &gc); - if (es) + ASSERT (es); + + if (val_tmp) { - if (val_tmp) - { - const char *str = construct_name_value (name_tmp, val_tmp, &gc); - env_set_add (es, str); + const char *str = construct_name_value (name_tmp, val_tmp, &gc); + env_set_add (es, str); #if DEBUG_VERBOSE_SETENV - msg (M_INFO, "SETENV_ES '%s'", str); + msg (M_INFO, "SETENV_ES '%s'", str); #endif - } - else - env_set_del (es, name_tmp); } else - { - char *str = construct_name_value (name_tmp, val_tmp, NULL); - if (platform_putenv(str)) - { - msg (M_WARN | M_ERRNO, "putenv('%s') failed", str); - } - } + env_set_del (es, name_tmp); gc_free (&gc); } @@ -950,32 +926,23 @@ create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc } /* - * Add a random string to first DNS label of hostname to prevent DNS caching. + * Prepend a random string to hostname to prevent DNS caching. * For example, foo.bar.gov would be modified to <random-chars>.foo.bar.gov. - * Of course, this requires explicit support in the DNS server. + * Of course, this requires explicit support in the DNS server (wildcard). */ const char * hostname_randomize(const char *hostname, struct gc_arena *gc) { # define n_rnd_bytes 6 - char *hst = string_alloc(hostname, gc); - char *dot = strchr(hst, '.'); + uint8_t rnd_bytes[n_rnd_bytes]; + const char *rnd_str; + struct buffer hname = alloc_buf_gc (strlen(hostname)+sizeof(rnd_bytes)*2+4, gc); - if (dot) - { - uint8_t rnd_bytes[n_rnd_bytes]; - const char *rnd_str; - struct buffer hname = alloc_buf_gc (strlen(hostname)+sizeof(rnd_bytes)*2+4, gc); - - *dot++ = '\0'; - prng_bytes (rnd_bytes, sizeof (rnd_bytes)); - rnd_str = format_hex_ex (rnd_bytes, sizeof (rnd_bytes), 40, 0, NULL, gc); - buf_printf(&hname, "%s-0x%s.%s", hst, rnd_str, dot); - return BSTR(&hname); - } - else - return hostname; + prng_bytes (rnd_bytes, sizeof (rnd_bytes)); + rnd_str = format_hex_ex (rnd_bytes, sizeof (rnd_bytes), 40, 0, NULL, gc); + buf_printf(&hname, "%s.%s", rnd_str, hostname); + return BSTR(&hname); # undef n_rnd_bytes } @@ -2087,3 +2054,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/app/openvpn/src/openvpn/misc.h b/app/openvpn/src/openvpn/misc.h index 183898e3..41748bd8 100644 --- a/app/openvpn/src/openvpn/misc.h +++ b/app/openvpn/src/openvpn/misc.h @@ -369,4 +369,11 @@ void argv_printf_cat (struct argv *a, const char *format, ...) #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/app/openvpn/src/openvpn/mroute.c b/app/openvpn/src/openvpn/mroute.c index 850e3363..ba4ef46f 100644 --- a/app/openvpn/src/openvpn/mroute.c +++ b/app/openvpn/src/openvpn/mroute.c @@ -487,62 +487,28 @@ mroute_helper_regenerate (struct mroute_helper *mh) } void -mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir) +mroute_helper_add_iroute46 (struct mroute_helper *mh, int netbits) { - if (ir->netbits >= 0) + if (netbits >= 0) { - ASSERT (ir->netbits < MR_HELPER_NET_LEN); + ASSERT (netbits < MR_HELPER_NET_LEN); ++mh->cache_generation; - ++mh->net_len_refcount[ir->netbits]; - if (mh->net_len_refcount[ir->netbits] == 1) + ++mh->net_len_refcount[netbits]; + if (mh->net_len_refcount[netbits] == 1) mroute_helper_regenerate (mh); } } void -mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir) +mroute_helper_del_iroute46 (struct mroute_helper *mh, int netbits) { - if (ir->netbits >= 0) + if (netbits >= 0) { - ASSERT (ir->netbits < MR_HELPER_NET_LEN); + ASSERT (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) -{ - if (ir6->netbits >= 0) - { - ASSERT (ir6->netbits < MR_HELPER_NET_LEN); - ++mh->cache_generation; - ++mh->net_len_refcount[ir6->netbits]; - if (mh->net_len_refcount[ir6->netbits] == 1) - mroute_helper_regenerate (mh); - } -} - -void -mroute_helper_del_iroute6 (struct mroute_helper *mh, - const struct iroute_ipv6 *ir6) -{ - if (ir6->netbits >= 0) - { - ASSERT (ir6->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/app/openvpn/src/openvpn/mroute.h b/app/openvpn/src/openvpn/mroute.h index b72b5ffc..608f70be 100644 --- a/app/openvpn/src/openvpn/mroute.h +++ b/app/openvpn/src/openvpn/mroute.h @@ -125,10 +125,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 diff --git a/app/openvpn/src/openvpn/multi.c b/app/openvpn/src/openvpn/multi.c index ab3f10cb..16250dc2 100644 --- a/app/openvpn/src/openvpn/multi.c +++ b/app/openvpn/src/openvpn/multi.c @@ -38,6 +38,7 @@ #include "otime.h" #include "gremlin.h" #include "mstats.h" +#include "ssl_verify.h" #include "memdbg.h" @@ -450,10 +451,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); } } @@ -807,8 +808,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", + 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 +818,26 @@ 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 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 } gc_free (&gc); } @@ -1158,23 +1170,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,9 +1296,7 @@ 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 @@ -1847,6 +1852,7 @@ 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; diff --git a/app/openvpn/src/openvpn/multi.h b/app/openvpn/src/openvpn/multi.h index 2bc0c8a1..fc2ffb24 100644 --- a/app/openvpn/src/openvpn/multi.h +++ b/app/openvpn/src/openvpn/multi.h @@ -88,6 +88,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; diff --git a/app/openvpn/src/openvpn/openvpn.c b/app/openvpn/src/openvpn/openvpn.c index a177d9e8..94d0167e 100644 --- a/app/openvpn/src/openvpn/openvpn.c +++ b/app/openvpn/src/openvpn/openvpn.c @@ -175,7 +175,7 @@ openvpn_main (int argc, char *argv[]) gc_init (&c.gc); /* initialize environmental variable store */ - c.es = env_set_create (&c.gc); + c.es = env_set_create (NULL); #ifdef WIN32 set_win_sys_path_via_env (c.es); #endif @@ -224,6 +224,7 @@ openvpn_main (int argc, char *argv[]) /* print version number */ msg (M_INFO, "%s", title_string); + show_library_versions(M_INFO); /* misc stuff */ pre_setup (&c.options); diff --git a/app/openvpn/src/openvpn/openvpn.h b/app/openvpn/src/openvpn/openvpn.h index bdfa6852..eab8cd5b 100644 --- a/app/openvpn/src/openvpn/openvpn.h +++ b/app/openvpn/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" @@ -104,10 +104,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 /* @@ -166,6 +166,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; @@ -185,17 +188,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 @@ -372,9 +371,9 @@ struct context_2 #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 @@ -451,9 +450,7 @@ struct context_2 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; diff --git a/app/openvpn/src/openvpn/options.c b/app/openvpn/src/openvpn/options.c index 64c81cf2..fc764616 100644 --- a/app/openvpn/src/openvpn/options.c +++ b/app/openvpn/src/openvpn/options.c @@ -5,10 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> - * - * Additions for eurephia plugin done by: - * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2009 + * Copyright (C) 2002-2013 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -58,12 +56,16 @@ #include "helper.h" #include "manage.h" #include "forward.h" +#include "ssl_verify.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 @@ -84,13 +86,20 @@ const char title_string[] = #endif /* defined(ENABLE_CRYPTO_POLARSSL) */ #endif /* ENABLE_SSL */ #endif /* ENABLE_CRYPTO */ +#ifdef USE_COMP #ifdef ENABLE_LZO -#ifdef ENABLE_LZO_STUB - " [LZO (STUB)]" -#else " [LZO]" #endif +#ifdef ENABLE_SNAPPY + " [SNAPPY]" +#endif +#ifdef ENABLE_LZ4 + " [LZ4]" #endif +#ifdef ENABLE_COMP_STUB + " [COMP_STUB]" +#endif +#endif /* USE_COMP */ #if EPOLL " [EPOLL]" #endif @@ -100,9 +109,6 @@ const char title_string[] = #ifdef ENABLE_PKCS11 " [PKCS11]" #endif -#ifdef ENABLE_EUREPHIA - " [eurephia]" -#endif #if ENABLE_IP_PKTINFO " [MH]" #endif @@ -134,7 +140,6 @@ static const char usage_message[] = " between connection retries (default=%d).\n" "--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\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" @@ -150,15 +155,12 @@ static const char usage_message[] = " 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" @@ -171,12 +173,8 @@ static const char usage_message[] = "--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" @@ -212,9 +210,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" @@ -239,15 +235,15 @@ 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 "--setenv name value : Set a custom environmental variable to pass to script.\n" "--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n" " directives for future OpenVPN versions to be ignored.\n" + "--ignore-unkown-option opt1 opt2 ...: Relax config file syntax. Allow\n" + " these options to be ignored when unknown\n" "--script-security level: Where level can be:\n" " 0 -- strictly no calling of external programs\n" " 1 -- (default) only call built-ins such as ifconfig\n" @@ -338,6 +334,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" @@ -362,12 +359,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" @@ -558,12 +558,7 @@ static const char usage_message[] = " root certificate.\n" #ifndef ENABLE_CRYPTO_POLARSSL "--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 */ "--dh file : File containing Diffie Hellman parameters\n" " in .pem format (for --tls-server only).\n" @@ -572,6 +567,9 @@ static const char usage_message[] = " by a Certificate Authority in --ca file.\n" "--extra-certs file : one or more PEM certs that complete the cert chain.\n" "--key file : Local private key in .pem format.\n" + "--tls-version-min <version> ['or-highest'] : sets the minimum TLS version we\n" + " will accept from the peer. If version is unrecognized and 'or-highest'\n" + " is specified, require max TLS version supported by SSL implementation.\n" #ifndef ENABLE_CRYPTO_POLARSSL "--pkcs12 file : PKCS#12 file containing local private key, local certificate\n" " and optionally the root CA certificate.\n" @@ -614,8 +612,8 @@ static const char usage_message[] = "--tls-export-cert [directory] : Get peer cert in PEM format and store it \n" " in an openvpn temporary file in [directory]. Peer cert is \n" " stored before tls-verify script execution and deleted after.\n" - "--tls-remote x509name: Accept connections only from a host with X509 name\n" - " x509name. The remote host must also pass all other tests\n" + "--verify-x509-name name: Accept connections only from a host with X509 subject\n" + " DN name. The remote host must also pass all other tests\n" " of verification.\n" "--ns-cert-type t: Require that peer certificate was signed with an explicit\n" " nsCertType designation t = 'client' | 'server'.\n" @@ -623,7 +621,6 @@ static const char usage_message[] = "--x509-track x : Save peer X509 attribute x in environment for use by\n" " plugins and management interface.\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" @@ -633,7 +630,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" @@ -769,6 +765,7 @@ init_options (struct options *o, const bool init_gc) o->topology = TOP_NET30; 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->connect_retry_max = 0; @@ -782,8 +779,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; @@ -848,6 +845,7 @@ init_options (struct options *o, const bool init_gc) 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 @@ -882,7 +880,7 @@ uninit_options (struct options *o) } } -#ifdef ENABLE_DEBUG +#ifndef ENABLE_SMALL #define SHOW_PARM(name, value, format) msg(D_SHOW_PARMS, " " #name " = " format, (value)) #define SHOW_STR(var) SHOW_PARM(var, (o->var ? o->var : "[UNDEF]"), "'%s'") @@ -904,20 +902,16 @@ setenv_connection_entry (struct env_set *es, setenv_str_i (es, "remote", e->remote, 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_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_str_i (es, "socks_proxy_port", e->socks_proxy_port, i); } -#endif } void @@ -1082,7 +1076,7 @@ parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_aren #ifdef WIN32 -#ifdef ENABLE_DEBUG +#ifndef ENABLE_SMALL static void show_dhcp_option_addrs (const char *name, const in_addr_t *array, int len) @@ -1125,7 +1119,7 @@ show_tuntap_options (const struct tuntap_options *o) #endif #endif -#if defined(WIN32) || defined(TARGET_ANDROID) +#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) { @@ -1156,7 +1150,7 @@ dhcp_option_address_parse (const char *name, const char *parm, in_addr_t *array, #if P2MP -#ifdef ENABLE_DEBUG +#ifndef ENABLE_SMALL static void show_p2mp_parms (const struct options *o) @@ -1228,7 +1222,7 @@ show_p2mp_parms (const struct options *o) gc_free (&gc); } -#endif /* ENABLE_DEBUG */ +#endif /* ! ENABLE_SMALL */ #if P2MP_SERVER @@ -1282,10 +1276,11 @@ option_iroute_ipv6 (struct options *o, #endif /* P2MP_SERVER */ #endif /* P2MP */ -#if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_DEBUG) +#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_STR (port); @@ -1295,6 +1290,15 @@ show_http_proxy_options (const struct http_proxy_options *o) 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 @@ -1304,9 +1308,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 @@ -1316,26 +1318,24 @@ 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 -#ifdef ENABLE_DEBUG +#ifndef ENABLE_SMALL static void show_connection_entry (const struct connection_entry *o) { @@ -1347,18 +1347,15 @@ show_connection_entry (const struct connection_entry *o) 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); -#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_STR (socks_proxy_port); SHOW_BOOL (socks_proxy_retry); -#endif SHOW_INT (tun_mtu); SHOW_BOOL (tun_mtu_defined); SHOW_INT (link_mtu); @@ -1382,8 +1379,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; @@ -1394,6 +1389,11 @@ 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"); } @@ -1402,7 +1402,7 @@ show_connection_entries (const struct options *o) void show_settings (const struct options *o) { -#ifdef ENABLE_DEBUG +#ifndef ENABLE_SMALL msg (D_SHOW_PARMS, "Current Parameter Settings:"); SHOW_STR (config); @@ -1472,6 +1472,7 @@ show_settings (const struct options *o) #endif SHOW_INT (resolve_retry_seconds); + SHOW_BOOL (resolve_in_advance); SHOW_STR (username); SHOW_STR (groupname); @@ -1490,6 +1491,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); @@ -1512,8 +1514,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); @@ -1525,15 +1528,12 @@ 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); 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); @@ -1599,7 +1599,8 @@ show_settings (const struct options *o) SHOW_STR (cipher_list); SHOW_STR (tls_verify); SHOW_STR (tls_export_cert); - SHOW_STR (tls_remote); + SHOW_INT (verify_x509_type); + SHOW_STR (verify_x509_name); SHOW_STR (crl_file); SHOW_INT (ns_cert_type); { @@ -1672,7 +1673,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, @@ -1961,24 +1962,23 @@ options_postprocess_verify_ce (const struct options *options, const struct conne 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_TCP_CLIENT) msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)"); -#endif + if ((ce->http_proxy_options) && !ce->http_proxy_options->server) + msg (M_USAGE, "--http-proxy not specified but other http proxy options present"); -#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_TCP_SERVER) msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode"); -#endif if (ce->proto == PROTO_TCP_SERVER && (options->connection_list->len > 1)) msg (M_USAGE, "TCP server mode allows at most one --remote address"); + if (options->routes && ((options->routes->flags & RG_BLOCK_LOCAL) && (options->routes->flags & RG_UNBLOCK_LOCAL))) + msg (M_USAGE, "unblock-local and block-local options of redirect-gateway/redirect-private are mutatlly exclusive"); + #if P2MP_SERVER /* @@ -2005,16 +2005,16 @@ 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"); + /* <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 0 if (options->tun_ipv6) msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server"); @@ -2038,6 +2038,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #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) msg (M_USAGE, "--route-delay cannot be used with --mode server"); if (options->up_delay) @@ -2115,7 +2116,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne if (options->stale_routes_check_interval) msg (M_USAGE, "--stale-routes-check requires --mode server"); - if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NO_NAME_REMAPPING)) msg (M_USAGE, "--compat-x509-names no-remapping requires --mode server"); } @@ -2287,7 +2287,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne MUST_BE_UNDEF (cipher_list); MUST_BE_UNDEF (tls_verify); MUST_BE_UNDEF (tls_export_cert); - MUST_BE_UNDEF (tls_remote); + MUST_BE_UNDEF (verify_x509_name); MUST_BE_UNDEF (tls_timeout); MUST_BE_UNDEF (renegotiate_bytes); MUST_BE_UNDEF (renegotiate_packets); @@ -2350,10 +2350,8 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce) 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_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 = NULL; @@ -2361,7 +2359,7 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce) /* if protocol forcing is enabled, disable all protocols except for the forced one */ if (o->proto_force >= 0 && o->proto_force != ce->proto) ce->flags |= CE_DISABLED; - + /* * If --mssfix is supplied without a parameter, default * it to --fragment value, if --fragment is specified. @@ -2396,7 +2394,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 @@ -2458,6 +2458,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. @@ -2474,13 +2475,12 @@ options_postprocess_mutate (struct options *o) * Convert remotes into 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); @@ -2497,11 +2497,10 @@ options_postprocess_mutate (struct options *o) } ASSERT (o->connection_list); - int i; for (i = 0; i < o->connection_list->len; ++i) options_postprocess_mutate_ce (o, o->connection_list->array[i]); - -#if HTTP_PROXY_OVERRIDE + +#if ENABLE_MANAGEMENT if (o->http_proxy_override) options_postprocess_http_proxy_override(o); #endif @@ -2574,6 +2573,44 @@ check_file_access(const int type, const char *file, const int mode, const char * return (errcode != 0 ? true : false); } +/* A wrapper for check_file_access() which also takes a chroot directory. + * If chroot is NULL, behaviour is exactly the same as calling check_file_access() directly, + * otherwise it will look for the file inside the given chroot directory instead. + */ +static bool +check_file_access_chroot(const char *chroot, const int type, const char *file, const int mode, const char *opt) +{ + bool ret = false; + + /* If no file configured, no errors to look for */ + if (!file) + return false; + + /* If chroot is set, look for the file/directory inside the chroot */ + if( chroot ) + { + struct gc_arena gc = gc_new(); + struct buffer chroot_file; + int len = 0; + + /* Build up a new full path including chroot directory */ + len = strlen(chroot) + strlen(PATH_SEPARATOR_STR) + strlen(file) + 1; + chroot_file = alloc_buf_gc(len, &gc); + buf_printf(&chroot_file, "%s%s%s", chroot, PATH_SEPARATOR_STR, file); + ASSERT (chroot_file.len > 0); + + ret = check_file_access(type, BSTR(&chroot_file), mode, opt); + gc_free(&gc); + } + else + { + /* No chroot in play, just call core file check function */ + ret = check_file_access(type, file, mode, opt); + } + return ret; +} + + /* * Verifies that the path in the "command" that comes after certain script options (e.g., --up) is a * valid file with appropriate permissions. @@ -2591,7 +2628,7 @@ check_file_access(const int type, const char *file, const int mode, const char * * check_file_access() arguments. */ static bool -check_cmd_access(const char *command, const char *opt) +check_cmd_access(const char *command, const char *opt, const char *chroot) { struct argv argv; bool return_code; @@ -2610,7 +2647,7 @@ check_cmd_access(const char *command, const char *opt) * only requires X_OK to function on Unix - a scenario not unlikely to * be seen on suid binaries. */ - return_code = check_file_access(CHKACC_FILE, argv.argv[0], X_OK, opt); + return_code = check_file_access_chroot(chroot, CHKACC_FILE, argv.argv[0], X_OK, opt); else { msg (M_NOPREFIX|M_OPTERR, "%s fails with '%s': No path to executable.", @@ -2636,7 +2673,7 @@ options_postprocess_filechecks (struct options *options) #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 (CHKACC_FILE, options->ca_path, R_OK, "--capath"); + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->ca_path, R_OK, "--capath"); errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->cert_file, R_OK, "--cert"); errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->extra_certs_file, R_OK, "--extra-certs"); @@ -2649,10 +2686,10 @@ options_postprocess_filechecks (struct options *options) "--pkcs12"); if (options->ssl_flags & SSLF_CRL_VERIFY_DIR) - errs |= check_file_access (CHKACC_FILE, options->crl_file, R_OK|X_OK, + 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 (CHKACC_FILE, options->crl_file, R_OK, + 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, @@ -2694,37 +2731,15 @@ options_postprocess_filechecks (struct options *options) /* ** Config related ** */ #ifdef ENABLE_SSL - errs |= check_file_access (CHKACC_FILE, options->tls_export_cert, + 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 */ #if P2MP_SERVER - errs |= check_file_access (CHKACC_FILE, options->client_config_dir, + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->client_config_dir, R_OK|X_OK, "--client-config-dir"); - errs |= check_file_access (CHKACC_FILE, options->tmp_dir, + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tmp_dir, R_OK|W_OK|X_OK, "Temporary directory (--tmp-dir)"); - /* ** Script hooks that accept an optionally quoted and/or escaped executable path, ** */ - /* ** optionally followed by arguments ** */ - errs |= check_cmd_access (options->auth_user_pass_verify_script, - "--auth-user-pass-verify script"); - errs |= check_cmd_access (options->client_connect_script, - "--client-connect script"); - errs |= check_cmd_access (options->client_disconnect_script, - "--client-disconnect script"); - errs |= check_cmd_access (options->tls_verify, - "--tls-verify script"); - errs |= check_cmd_access (options->up_script, - "--up script"); - errs |= check_cmd_access (options->down_script, - "--down script"); - errs |= check_cmd_access (options->ipchange, - "--ipchange script"); - errs |= check_cmd_access (options->route_script, - "--route-up script"); - errs |= check_cmd_access (options->route_predown_script, - "--route-pre-down script"); - errs |= check_cmd_access (options->learn_address_script, - "--learn-address script"); #endif /* P2MP_SERVER */ if (errs) @@ -2772,18 +2787,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) @@ -2795,7 +2808,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; @@ -2803,12 +2816,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); @@ -2816,12 +2828,12 @@ pre_pull_restore (struct options *o) } else o->client_nat = NULL; -#endif o->foreign_option_index = pp->foreign_option_index; } o->push_continuation = 0; + o->push_option_types_found = 0; } #endif @@ -2852,6 +2864,7 @@ pre_pull_restore (struct options *o) * the other end of the connection] * * --comp-lzo + * --compress alg * --fragment * * Crypto Options: @@ -2933,9 +2946,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 @@ -3388,10 +3401,31 @@ usage_small (void) openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */ } +void +show_library_versions(const unsigned int flags) +{ +#ifdef ENABLE_SSL +#define SSL_LIB_VER_STR get_ssl_library_version() +#else +#define SSL_LIB_VER_STR "" +#endif +#ifdef ENABLE_LZO +#define LZO_LIB_VER_STR ", LZO ", lzo_version_string() +#else +#define LZO_LIB_VER_STR "", "" +#endif + + msg (flags, "library versions: %s%s%s", SSL_LIB_VER_STR, LZO_LIB_VER_STR); + +#undef SSL_LIB_VER_STR +#undef LZO_LIB_VER_STR +} + static void usage_version (void) { msg (M_INFO|M_NOPREFIX, "%s", title_string); + show_library_versions( M_INFO|M_NOPREFIX ); msg (M_INFO|M_NOPREFIX, "Originally developed by James Yonan"); msg (M_INFO|M_NOPREFIX, "Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>"); #ifndef ENABLE_SMALL @@ -3401,9 +3435,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 */ } @@ -3746,9 +3777,13 @@ read_config_file (struct options *options, line_num = 0; while (fgets(line, sizeof (line), fp)) { + int offset = 0; CLEAR (p); ++line_num; - if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc)) + /* Ignore UTF-8 BOM at start of stream */ + if (line_num == 1 && strncmp (line, "\xEF\xBB\xBF", 3) == 0) + offset = 3; + if (parse_line (line + offset, p, SIZE (p), file, line_num, msglevel, &options->gc)) { bypass_doubledash (&p[0]); check_inline_file_via_fp (fp, p, &options->gc); @@ -3795,7 +3830,7 @@ read_config_string (const char *prefix, { bypass_doubledash (&p[0]); check_inline_file_via_buf (&multiline, p, &options->gc); - add_option (options, p, NULL, line_num, 0, msglevel, permission_mask, option_types_found, es); + add_option (options, p, prefix, line_num, 0, msglevel, permission_mask, option_types_found, es); } CLEAR (p); } @@ -3915,27 +3950,43 @@ void options_string_import (struct options *options, #if P2MP -#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, (mask), permission_mask, option_types_found, msglevel)) goto err; } +#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, line, (mask), permission_mask, option_types_found, msglevel, options)) goto err; } static bool verify_permission (const char *name, const char* file, + int line, const unsigned int type, const unsigned int allowed, unsigned int *found, - const int msglevel) + const int msglevel, + struct options* options) { if (!(type & allowed)) { msg (msglevel, "option '%s' cannot be used in this context (%s)", name, file); return false; } - else + + if (found) + *found |= type; + +#ifndef ENABLE_SMALL + /* Check if this options is allowed in connection block, + * but we are currently not in a connection block + * Parsing a connection block uses a temporary options struct without + * connection_list + */ + + if ((type & OPT_P_CONNECTION) && options->connection_list) { - if (found) - *found |= type; - return true; + if (file) + msg (M_WARN, "Option '%s' in %s:%d is ignored by previous <connection> blocks ", name, file, line); + else + msg (M_WARN, "Option '%s' is ignored by previous <connection> blocks", name); } +#endif + return true; } #else @@ -3982,11 +4033,30 @@ msglevel_forward_compatible (struct options *options, const int msglevel) } static void -warn_multiple_script (const char *script, const char *type) { - if (script) { - msg (M_WARN, "Multiple --%s scripts defined. " - "The previously configured script is overridden.", type); - } +set_user_script (struct options *options, + const char **script, + const char *new_script, + const char *type, + bool in_chroot) +{ + if (*script) { + msg (M_WARN, "Multiple --%s scripts defined. " + "The previously configured script is overridden.", type); + } + *script = new_script; + options->user_script_used = true; + +#ifndef ENABLE_SMALL + { + char script_name[100]; + openvpn_snprintf (script_name, sizeof(script_name), + "--%s script", type); + + if (check_cmd_access (*script, script_name, (in_chroot ? options->chroot_dir : NULL))) + msg (M_USAGE, "Please correct this error."); + + } +#endif } @@ -4005,7 +4075,18 @@ add_option (struct options *options, const bool pull_mode = BOOL_CAST (permission_mask & OPT_P_PULL_MODE); int msglevel_fc = msglevel_forward_compatible (options, msglevel); - ASSERT (MAX_PARMS >= 5); + ASSERT (MAX_PARMS >= 7); + + /* + * If directive begins with "setenv opt" prefix, don't raise an error if + * directive is unrecognized. + */ + if (streq (p[0], "setenv") && p[1] && streq (p[1], "opt") && !(permission_mask & OPT_P_PULL_MODE)) + { + p += 2; + msglevel_fc = M_WARN; + } + if (!file) { file = "[CMD-LINE]"; @@ -4031,7 +4112,7 @@ add_option (struct options *options, read_config_file (options, p[1], level, file, line, msglevel, permission_mask, option_types_found, es); } -#ifdef ENABLE_DEBUG +#if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) else if (streq (p[0], "show-gateway")) { struct route_gateway_info rgi; @@ -4354,7 +4435,44 @@ add_option (struct options *options, uninit_options (&sub); } } -#if HTTP_PROXY_OVERRIDE + else if (streq (p[0], "ignore-unknown-option") && p[1]) + { + int i; + int j; + int numignored=0; + const char **ignore; + + VERIFY_PERMISSION (OPT_P_GENERAL); + /* Find out how many options to be ignored */ + for (i=1;p[i];i++) + numignored++; + + /* add number of options already ignored */ + for (i=0;options->ignore_unknown_option && + options->ignore_unknown_option[i]; i++) + numignored++; + + /* Allocate array */ + ALLOC_ARRAY_GC (ignore, const char*, numignored+1, &options->gc); + for (i=0;options->ignore_unknown_option && + options->ignore_unknown_option[i]; i++) + ignore[i]=options->ignore_unknown_option[i]; + + options->ignore_unknown_option=ignore; + + for (j=1;p[j];j++) + { + /* Allow the user to specify ignore-unknown-option --opt too */ + if (p[j][0]=='-' && p[j][1]=='-') + options->ignore_unknown_option[i] = (p[j]+2); + else + options->ignore_unknown_option[i] = p[j]; + i++; + } + + options->ignore_unknown_option[i] = NULL; + } +#if ENABLE_MANAGEMENT else if (streq (p[0], "http-proxy-override") && p[1] && p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -4378,14 +4496,14 @@ add_option (struct options *options, if (p[3]) { const int proto = ascii2proto (p[3]); - const sa_family_t af = ascii2af (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; + re.af = af; } } if (permission_mask & OPT_P_GENERAL) @@ -4408,6 +4526,15 @@ add_option (struct options *options, else options->resolve_retry_seconds = positive_atoi (p[1]); } + else if (streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint")) + { + 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]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); @@ -4429,8 +4556,10 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - warn_multiple_script (options->ipchange, "ipchange"); - options->ipchange = string_substitute (p[1], ',', ' ', &options->gc); + set_user_script (options, + &options->ipchange, + string_substitute (p[1], ',', ' ', &options->gc), + "ipchange", true); } else if (streq (p[0], "float")) { @@ -4476,16 +4605,14 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - warn_multiple_script (options->up_script, "up"); - options->up_script = p[1]; + set_user_script (options, &options->up_script, p[1], "up", false); } else if (streq (p[0], "down") && p[1]) { VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - warn_multiple_script (options->down_script, "down"); - options->down_script = p[1]; + set_user_script (options, &options->down_script, p[1], "down", true); } else if (streq (p[0], "down-pre")) { @@ -4592,6 +4719,12 @@ add_option (struct options *options, options->suppress_timestamps = true; set_suppress_timestamps(true); } + else if (streq (p[0], "machine-readable-output")) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->machine_readable_output = true; + set_machine_readable_output(true); + } else if (streq (p[0], "log-append") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -4621,6 +4754,12 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_MESSAGES); options->verbosity = positive_atoi (p[1]); +#if !defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) + /* Warn when a debug verbosity is supplied when built without debug support */ + if (options->verbosity >= 7) + msg (M_WARN, "NOTE: debug verbosity (--verb %d) is enabled but this build lacks debug support.", + options->verbosity); +#endif } else if (streq (p[0], "mute") && p[1]) { @@ -4795,6 +4934,9 @@ add_option (struct options *options, { 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")) { @@ -4842,7 +4984,6 @@ add_option (struct options *options, } options->proto_force = proto_force; } -#ifdef ENABLE_HTTP_PROXY else if (streq (p[0], "http-proxy") && p[1]) { struct http_proxy_options *ho; @@ -4917,13 +5058,38 @@ add_option (struct options *options, { 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]); } } -#endif -#ifdef ENABLE_SOCKS else if (streq (p[0], "socks-proxy") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); @@ -4944,7 +5110,6 @@ add_option (struct options *options, 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]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -4976,8 +5141,7 @@ add_option (struct options *options, #ifdef ENABLE_OCC else if (streq (p[0], "explicit-exit-notify")) { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); -/* VERIFY_PERMISSION (OPT_P_EXPLICIT_NOTIFY); */ + VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION|OPT_P_EXPLICIT_NOTIFY); if (p[1]) { options->ce.explicit_exit_notification = positive_atoi (p[1]); @@ -5008,14 +5172,12 @@ add_option (struct options *options, 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]) { 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]) { VERIFY_PERMISSION (OPT_P_ROUTE); @@ -5060,23 +5222,12 @@ 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")) { - 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]) { @@ -5125,16 +5276,17 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - warn_multiple_script (options->route_script, "route-up"); - options->route_script = p[1]; + set_user_script (options, &options->route_script, p[1], "route-up", false); } else if (streq (p[0], "route-pre-down") && p[1]) { VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - warn_multiple_script (options->route_predown_script, "route-pre-down"); - options->route_predown_script = p[1]; + set_user_script (options, + &options->route_predown_script, + p[1], + "route-pre-down", true); } else if (streq (p[0], "route-noexec")) { @@ -5172,6 +5324,8 @@ 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], "unblock-local")) + options->routes->flags |= RG_UNBLOCK_LOCAL; else { msg (msglevel, "unknown --%s flag: %s", p[0], p[j]); @@ -5401,9 +5555,9 @@ add_option (struct options *options, msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters"); goto err; } - if ( netbits != 64 ) + if ( netbits < 64 || netbits > 112 ) { - msg( msglevel, "--ifconfig-ipv6-pool settings: only /64 supported right now (not /%d)", netbits ); + msg( msglevel, "--ifconfig-ipv6-pool settings: only /64../112 supported right now (not /%d)", netbits ); goto err; } @@ -5474,13 +5628,6 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->ssl_flags |= SSLF_AUTH_USER_PASS_OPTIONAL; } - else if (streq (p[0], "compat-names")) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES); - if (p[1] && streq (p[1], "no-remapping")) - compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING); - } else if (streq (p[0], "opt-verify")) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -5508,32 +5655,33 @@ add_option (struct options *options, msg (msglevel, "--auth-user-pass-verify requires a second parameter ('via-env' or 'via-file')"); goto err; } - warn_multiple_script (options->auth_user_pass_verify_script, "auth-user-pass-verify"); - options->auth_user_pass_verify_script = p[1]; + set_user_script (options, + &options->auth_user_pass_verify_script, + p[1], "auth-user-pass-verify", true); } else if (streq (p[0], "client-connect") && p[1]) { VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - warn_multiple_script (options->client_connect_script, "client-connect"); - options->client_connect_script = p[1]; + set_user_script (options, &options->client_connect_script, + p[1], "client-connect", true); } else if (streq (p[0], "client-disconnect") && p[1]) { VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - warn_multiple_script (options->client_disconnect_script, "client-disconnect"); - options->client_disconnect_script = p[1]; + set_user_script (options, &options->client_disconnect_script, + p[1], "client-disconnect", true); } else if (streq (p[0], "learn-address") && p[1]) { VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - warn_multiple_script (options->learn_address_script, "learn-address"); - options->learn_address_script = p[1]; + set_user_script (options, &options->learn_address_script, + p[1], "learn-address", true); } else if (streq (p[0], "tmp-dir") && p[1]) { @@ -5617,10 +5765,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 { @@ -6036,18 +6182,31 @@ add_option (struct options *options, options->passtos = true; } #endif -#ifdef ENABLE_LZO +#if defined(USE_COMP) else if (streq (p[0], "comp-lzo")) { 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]); @@ -6055,14 +6214,61 @@ 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")) { VERIFY_PERMISSION (OPT_P_COMP); - options->lzo &= ~LZO_ADAPTIVE; + options->comp.flags &= ~COMP_F_ADAPTIVE; } -#endif /* ENABLE_LZO */ + else if (streq (p[0], "compress")) + { + VERIFY_PERMISSION (OPT_P_COMP); + 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); + } +#if defined(ENABLE_LZO) + else if (streq (p[1], "lzo")) + { + options->comp.alg = COMP_ALG_LZO; + options->comp.flags = 0; + } +#endif +#if defined(ENABLE_SNAPPY) + else if (streq (p[1], "snappy")) + { + options->comp.alg = COMP_ALG_SNAPPY; + options->comp.flags = COMP_F_SWAP; + } +#endif +#if defined(ENABLE_LZ4) + else if (streq (p[1], "lz4")) + { + options->comp.alg = COMP_ALG_LZ4; + options->comp.flags = COMP_F_SWAP; + } +#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 /* USE_COMP */ #ifdef ENABLE_CRYPTO else if (streq (p[0], "show-ciphers")) { @@ -6273,6 +6479,16 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->show_tls_ciphers = true; } + else if (streq (p[0], "show-curves")) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->show_curves = true; + } + else if (streq (p[0], "ecdh-curve") && p[1]) + { + VERIFY_PERMISSION (OPT_P_CRYPTO); + options->ecdh_curve= p[1]; + } else if (streq (p[0], "tls-server")) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6347,6 +6563,19 @@ add_option (struct options *options, options->priv_key_file_inline = p[2]; } } + else if (streq (p[0], "tls-version-min") && p[1]) + { + int ver; + VERIFY_PERMISSION (OPT_P_GENERAL); + ver = tls_version_min_parse(p[1], p[2]); + if (ver == TLS_VER_BAD) + { + msg (msglevel, "unknown tls-version-min parameter: %s", p[1]); + goto err; + } + options->ssl_flags &= ~(SSLF_TLS_VERSION_MASK << SSLF_TLS_VERSION_SHIFT); + options->ssl_flags |= (ver << SSLF_TLS_VERSION_SHIFT); + } #ifndef ENABLE_CRYPTO_POLARSSL else if (streq (p[0], "pkcs12") && p[1]) { @@ -6416,8 +6645,9 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_SCRIPT); if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) goto err; - warn_multiple_script (options->tls_verify, "tls-verify"); - options->tls_verify = string_substitute (p[1], ',', ' ', &options->gc); + set_user_script (options, &options->tls_verify, + string_substitute (p[1], ',', ' ', &options->gc), + "tls-verify", true); } #ifndef ENABLE_CRYPTO_POLARSSL else if (streq (p[0], "tls-export-cert") && p[1]) @@ -6426,10 +6656,100 @@ add_option (struct options *options, options->tls_export_cert = p[1]; } #endif + else if (streq (p[0], "compat-names")) + { + 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 --compat-names with --verify-x509-name"); + goto err; + } + msg (M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration"); + 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")) + { + 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 --no-name-remapping with --verify-x509-name"); + goto err; + } + msg (M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration"); + 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); - options->tls_remote = p[1]; + + 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])) + { + 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 " + "--compat-names or --no-name-remapping"); + goto err; + } + if (p[2]) + { + if (streq (p[2], "subject")) + type = VERIFY_X509_SUBJECT_DN; + else if (streq (p[2], "name")) + type = VERIFY_X509_SUBJECT_RDN; + else if (streq (p[2], "name-prefix")) + type = VERIFY_X509_SUBJECT_RDN_PREFIX; + else + { + msg (msglevel, "unknown X.509 name type: %s", p[2]); + goto err; + } + } + options->verify_x509_type = type; + options->verify_x509_name = p[1]; } else if (streq (p[0], "ns-cert-type") && p[1]) { @@ -6444,7 +6764,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; @@ -6482,7 +6801,6 @@ add_option (struct options *options, goto err; } } -#endif /* OPENSSL_VERSION_NUMBER */ else if (streq (p[0], "tls-timeout") && p[1]) { VERIFY_PERMISSION (OPT_P_TLS_PARMS); @@ -6641,10 +6959,22 @@ add_option (struct options *options, #endif else { + int i; + int msglevel= msglevel_fc; + /* Check if an option is in --ignore-unknown-option and + set warning level to non fatal */ + for(i=0; options->ignore_unknown_option && options->ignore_unknown_option[i]; i++) + { + if (streq(p[0], options->ignore_unknown_option[i])) + { + msglevel = M_WARN; + break; + } + } if (file) - msg (msglevel_fc, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION); + msg (msglevel, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION); else - msg (msglevel_fc, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION); + msg (msglevel, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION); } err: gc_free (&gc); diff --git a/app/openvpn/src/openvpn/options.h b/app/openvpn/src/openvpn/options.h index 909cb38a..21c210ee 100644 --- a/app/openvpn/src/openvpn/options.h +++ b/app/openvpn/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,10 +71,8 @@ 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; }; @@ -90,24 +88,21 @@ struct connection_entry sa_family_t af; const char* local_port; bool local_port_defined; - const char* 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; 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; 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 */ @@ -186,6 +181,8 @@ struct options /* enable forward compatibility for post-2.1 features */ bool forward_compatible; + /* list of options that should be ignored even if unkown */ + const char ** ignore_unknown_option; /* persist parms */ bool persist_config; @@ -198,6 +195,7 @@ struct options bool show_engines; #ifdef ENABLE_SSL bool show_tls_ciphers; + bool show_curves; #endif bool genkey; #endif @@ -213,7 +211,7 @@ struct options /* 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 @@ -275,6 +273,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; @@ -289,6 +289,7 @@ struct options const char *writepid; const char *up_script; const char *down_script; + bool user_script_used; bool down_pre; bool up_delay; bool up_restart; @@ -301,6 +302,7 @@ struct options bool log; bool suppress_timestamps; + bool machine_readable_output; int nice; int verbosity; int mute; @@ -316,9 +318,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 */ @@ -340,16 +341,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 */ @@ -430,9 +427,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; @@ -461,6 +456,7 @@ struct options bool client; bool pull; /* client pull of config options from server */ int push_continuation; + unsigned int push_option_types_found; const char *auth_user_pass_file; struct options_pre_pull *pre_pull; @@ -509,9 +505,11 @@ 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; const char *tls_export_cert; - const char *tls_remote; const char *crl_file; const char *ca_file_inline; @@ -682,6 +680,8 @@ void notnull (const char *arg, const char *description); void usage_small (void); +void show_library_versions(const unsigned int flags); + void init_options (struct options *o, const bool init_gc); void uninit_options (struct options *o); @@ -710,7 +710,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, diff --git a/app/openvpn/src/openvpn/pf.c b/app/openvpn/src/openvpn/pf.c index aafe9ff0..a3208db1 100644 --- a/app/openvpn/src/openvpn/pf.c +++ b/app/openvpn/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" @@ -417,7 +417,7 @@ lookup_cn_rule (struct hash *h, const char *cn, const uint32_t cn_hash) bool pf_cn_test (struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix) { - if (!pfs->kill) + if (pfs && !pfs->kill) { const char *cn; uint32_t cn_hash; diff --git a/app/openvpn/src/openvpn/pkcs11_openssl.c b/app/openvpn/src/openvpn/pkcs11_openssl.c index af843b7b..87eb166e 100644 --- a/app/openvpn/src/openvpn/pkcs11_openssl.c +++ b/app/openvpn/src/openvpn/pkcs11_openssl.c @@ -49,7 +49,7 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate, int ret = 1; X509 *x509 = NULL; - RSA *rsa = NULL; + EVP_PKEY *evp = NULL; pkcs11h_openssl_session_t openssl_session = NULL; if ((openssl_session = pkcs11h_openssl_createSession (certificate)) == NULL) @@ -63,9 +63,9 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate, */ certificate = NULL; - if ((rsa = pkcs11h_openssl_session_getRSA (openssl_session)) == NULL) + if ((evp = pkcs11h_openssl_session_getEVP (openssl_session)) == NULL) { - msg (M_WARN, "PKCS#11: Unable get rsa object"); + msg (M_WARN, "PKCS#11: Unable get evp object"); goto cleanup; } @@ -75,7 +75,7 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate, goto cleanup; } - if (!SSL_CTX_use_RSAPrivateKey (ssl_ctx->ctx, rsa)) + if (!SSL_CTX_use_PrivateKey (ssl_ctx->ctx, evp)) { msg (M_WARN, "PKCS#11: Cannot set private key for openssl"); goto cleanup; @@ -108,10 +108,10 @@ cleanup: x509 = NULL; } - if (rsa != NULL) + if (evp != NULL) { - RSA_free (rsa); - rsa = NULL; + EVP_PKEY_free (evp); + evp = NULL; } if (openssl_session != NULL) diff --git a/app/openvpn/src/openvpn/pkcs11_polarssl.c b/app/openvpn/src/openvpn/pkcs11_polarssl.c index 03b2bab5..be4e9737 100644 --- a/app/openvpn/src/openvpn/pkcs11_polarssl.c +++ b/app/openvpn/src/openvpn/pkcs11_polarssl.c @@ -40,6 +40,7 @@ #include "errlevel.h" #include "pkcs11_backend.h" #include <polarssl/pkcs11.h> +#include <polarssl/x509.h> int pkcs11_init_tls_session(pkcs11h_certificate_t certificate, @@ -78,14 +79,14 @@ pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc) char *ret = NULL; char dn[1024] = {0}; - x509_cert polar_cert = {0}; + x509_crt polar_cert = {0}; if (pkcs11_x509_cert_init(&polar_cert, cert)) { msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object"); goto cleanup; } - if (-1 == x509parse_dn_gets (dn, sizeof(dn), &polar_cert.subject)) { + if (-1 == x509_dn_gets (dn, sizeof(dn), &polar_cert.subject)) { msg (M_FATAL, "PKCS#11: PolarSSL cannot parse subject"); goto cleanup; } @@ -93,7 +94,7 @@ pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc) ret = string_alloc(dn, gc); cleanup: - x509_free(&polar_cert); + x509_crt_free(&polar_cert); return ret; } @@ -104,14 +105,14 @@ pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial, { int ret = 1; - x509_cert polar_cert = {0}; + x509_crt polar_cert = {0}; if (pkcs11_x509_cert_init(&polar_cert, cert)) { msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object"); goto cleanup; } - if (-1 == x509parse_serial_gets (serial, serial_len, &polar_cert.serial)) { + if (-1 == x509_serial_gets (serial, serial_len, &polar_cert.serial)) { msg (M_FATAL, "PKCS#11: PolarSSL cannot parse serial"); goto cleanup; } @@ -119,7 +120,7 @@ pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial, ret = 0; cleanup: - x509_free(&polar_cert); + x509_crt_free(&polar_cert); return ret; } diff --git a/app/openvpn/src/openvpn/platform.c b/app/openvpn/src/openvpn/platform.c index e79de7a7..16d4daca 100644 --- a/app/openvpn/src/openvpn/platform.c +++ b/app/openvpn/src/openvpn/platform.c @@ -275,34 +275,6 @@ platform_unlink (const char *filename) #endif } -int platform_putenv(char *string) -{ - int status; -#if defined(WIN32) - struct gc_arena gc = gc_new (); - char *s = string_alloc(string, &gc); - char *value = strchr(s, '='); - if (value!=NULL) - { - *value = '\0'; - value++; - if (*value == '\0') - value = NULL; - } - - status = SetEnvironmentVariableW (wide_string (s, &gc), - wide_string (value, &gc)) ? 1: 0; - gc_free (&gc); -#elif defined(HAVE_PUTENV) - void manage_env (char *str); /* TODO: Resolve properly */ - status = putenv (string); - if (!status) - manage_env (string); -#endif - - return status; -} - FILE * platform_fopen (const char *path, const char *mode) { diff --git a/app/openvpn/src/openvpn/plugin.c b/app/openvpn/src/openvpn/plugin.c index 83f79e4f..0948f238 100644 --- a/app/openvpn/src/openvpn/plugin.c +++ b/app/openvpn/src/openvpn/plugin.c @@ -40,8 +40,8 @@ #include "error.h" #include "misc.h" #include "plugin.h" +#include "ssl_backend.h" #include "win32.h" - #include "memdbg.h" #define PLUGIN_SYMBOL_REQUIRED (1<<0) @@ -155,7 +155,7 @@ plugin_option_list_add (struct plugin_option_list *list, char **p, struct gc_are return false; } -#ifdef ENABLE_DEBUG +#ifndef ENABLE_SMALL void plugin_option_list_print (const struct plugin_option_list *list, int msglevel) { @@ -374,7 +374,8 @@ plugin_open_item (struct plugin *p, struct openvpn_plugin_args_open_in args = { p->plugin_type_mask, (const char ** const) o->argv, (const char ** const) envp, - &callbacks }; + &callbacks, + SSLAPI }; struct openvpn_plugin_args_open_return retargs; CLEAR(retargs); diff --git a/app/openvpn/src/openvpn/plugin.h b/app/openvpn/src/openvpn/plugin.h index 4ba150d6..2f8416b1 100644 --- a/app/openvpn/src/openvpn/plugin.h +++ b/app/openvpn/src/openvpn/plugin.h @@ -108,7 +108,7 @@ struct plugin_return struct plugin_option_list *plugin_option_list_new (struct gc_arena *gc); bool plugin_option_list_add (struct plugin_option_list *list, char **p, struct gc_arena *gc); -#ifdef ENABLE_DEBUG +#ifndef ENABLE_SMALL void plugin_option_list_print (const struct plugin_option_list *list, int msglevel); #endif diff --git a/app/openvpn/src/openvpn/proto.c b/app/openvpn/src/openvpn/proto.c index b437f1ad..7b58e6ab 100644 --- a/app/openvpn/src/openvpn/proto.c +++ b/app/openvpn/src/openvpn/proto.c @@ -60,7 +60,7 @@ is_ipv_X ( int tunnel_type, struct buffer *buf, int ip_ver ) + sizeof (struct openvpn_iphdr))) return false; eh = (const struct openvpn_ethhdr *) BPTR (buf); - if (ntohs (eh->proto) != OPENVPN_ETH_P_IPV4) + if (ntohs (eh->proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4)) return false; offset = sizeof (struct openvpn_ethhdr); } diff --git a/app/openvpn/src/openvpn/proxy.c b/app/openvpn/src/openvpn/proxy.c index 17748504..2568e191 100644 --- a/app/openvpn/src/openvpn/proxy.c +++ b/app/openvpn/src/openvpn/proxy.c @@ -42,8 +42,6 @@ #include "ntlm.h" #include "memdbg.h" -#ifdef ENABLE_HTTP_PROXY - #define UP_TYPE_PROXY "HTTP Proxy" struct http_proxy_options * @@ -439,7 +437,6 @@ 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"); @@ -490,6 +487,67 @@ 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 */ @@ -499,7 +557,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, { struct gc_arena gc = gc_new (); char buf[512]; - char buf2[128]; + char buf2[129]; char get[80]; int status; int nparms; @@ -532,18 +590,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) @@ -622,7 +670,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1); nparms = sscanf (buf, get, buf2); - buf2[127] = 0; /* we only need the beginning - ensure it's null terminated. */ + buf2[128] = 0; /* we only need the beginning - ensure it's null terminated. */ /* check for "Proxy-Authenticate: NTLM TlRM..." */ if (nparms == 1) @@ -658,14 +706,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) @@ -771,9 +816,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 */ @@ -900,8 +943,3 @@ establish_http_proxy_passthru (struct http_proxy_info *p, gc_free (&gc); return ret; } - -#else -static void dummy(void) {} -#endif /* ENABLE_HTTP_PROXY */ - diff --git a/app/openvpn/src/openvpn/proxy.h b/app/openvpn/src/openvpn/proxy.h index 9d75e063..4715940c 100644 --- a/app/openvpn/src/openvpn/proxy.h +++ b/app/openvpn/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,6 +36,12 @@ #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; const char *port; @@ -53,6 +57,7 @@ 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]; }; struct http_proxy_options_simple { @@ -87,6 +92,4 @@ bool establish_http_proxy_passthru (struct http_proxy_info *p, 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/app/openvpn/src/openvpn/ps.c b/app/openvpn/src/openvpn/ps.c index c1868642..6807aac0 100644 --- a/app/openvpn/src/openvpn/ps.c +++ b/app/openvpn/src/openvpn/ps.c @@ -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; } @@ -408,20 +409,18 @@ proxy_entry_new (struct proxy_connection **list, 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 */ - osaddr.addr.in4 = server_addr; 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"); @@ -803,8 +802,8 @@ port_share_open (const char *host, /* * Get host's IP address */ - - status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, + + status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_FATAL, host, port, 0, NULL, AF_INET, &ai); ASSERT (status==0); hostaddr = *((struct sockaddr_in*) ai->ai_addr); diff --git a/app/openvpn/src/openvpn/push.c b/app/openvpn/src/openvpn/push.c index 994b7ba7..24d12c7b 100644 --- a/app/openvpn/src/openvpn/push.c +++ b/app/openvpn/src/openvpn/push.c @@ -33,6 +33,7 @@ #include "push.h" #include "options.h" #include "ssl.h" +#include "ssl_verify.h" #include "manage.h" #include "memdbg.h" @@ -49,7 +50,8 @@ void receive_auth_failed (struct context *c, const struct buffer *buffer) { msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); - c->options.no_advance=true; + c->options.no_advance=true; + if (c->options.pull) { switch (auth_retry_get ()) @@ -202,8 +204,10 @@ incoming_push_message (struct context *c, const struct buffer *buffer) msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc)); else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) { + c->options.push_option_types_found |= option_types_found; + if (status == PUSH_MSG_REPLY) - do_up (c, true, option_types_found); /* delay bringing tun/tap up until --push parms received from remote */ + do_up (c, true, c->options.push_option_types_found ); /* delay bringing tun/tap up until --push parms received from remote */ event_timeout_clear (&c->c2.push_request_interval); } @@ -290,10 +294,8 @@ send_push_reply (struct context *c) 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)); @@ -453,7 +455,7 @@ process_incoming_push_msg (struct context *c, } 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, diff --git a/app/openvpn/src/openvpn/route.c b/app/openvpn/src/openvpn/route.c index 8a778884..bcc6fcee 100644 --- a/app/openvpn/src/openvpn/route.c +++ b/app/openvpn/src/openvpn/route.c @@ -49,7 +49,7 @@ #define METRIC_NOT_USED ((DWORD)-1) #endif -static void delete_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es); +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); static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags); @@ -92,80 +92,66 @@ 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 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, 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) + const struct route_ipv6_option_list *src, + 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 * -route_string (const struct route *r, struct gc_arena *gc) +route_string (const struct route_ipv4 *r, struct gc_arena *gc) { struct buffer out = alloc_buf_gc (256, gc); buf_printf (&out, "ROUTE network %s netmask %s gateway %s", @@ -267,7 +253,7 @@ is_special_addr (const char *addr_str) } static bool -init_route (struct route *r, +init_route (struct route_ipv4 *r, struct addrinfo **network_list, const struct route_option *ro, const struct route_list *rl) @@ -452,15 +438,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 @@ -470,32 +455,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), 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 @@ -503,6 +482,7 @@ route_list_add_vpn_gateway (struct route_list *rl, struct env_set *es, const in_addr_t addr) { + ASSERT(rl); rl->spec.remote_endpoint = addr; rl->spec.flags |= RTSA_REMOTE_ENDPOINT; setenv_route_addr (es, "vpn_gateway", rl->spec.remote_endpoint, -1); @@ -515,26 +495,76 @@ 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 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; } } static void +add_unblock_local (struct route_list *rl) +{ + const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED); + + if (rl->flags & RG_UNBLOCK_LOCAL + && (rl->rgi.flags & rgi_needed) == rgi_needed) + { + /* unblock access to local subnet */ + struct route_ipv4 *r; + + ALLOC_OBJ_GC (r, struct route_ipv4, &rl->gc); + int i; + + CLEAR(*r); + r->flags = RT_DEFINED; + r->network = rl->rgi.gateway.addr & rl->rgi.gateway.netmask; + r->netmask = rl->rgi.gateway.netmask; + r->gateway = rl->rgi.gateway.addr; + r->next = rl->routes; + rl->routes = r; + + /* Additional local networks */ + for (i = 0; i < rl->rgi.n_addrs; ++i) + { + const struct route_gateway_address *gwa = &rl->rgi.addrs[i]; + + /* omit the add/subnet in &rl->rgi which we processed above */ + if (!((rl->rgi.gateway.addr & rl->rgi.gateway.netmask) == (gwa->addr & gwa->netmask) + && rl->rgi.gateway.netmask == gwa->netmask)) + { + ALLOC_OBJ_GC (r, struct route_ipv4, &rl->gc); + CLEAR(*r); + r->flags = RT_DEFINED; + r->network = gwa->addr & gwa->netmask; + r->netmask = gwa->netmask; + r->gateway = gwa->addr; + r->next = rl->routes; + rl->routes=r; + } + } + } +} + + +static void add_block_local (struct route_list *rl) { const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED); @@ -545,8 +575,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); @@ -563,6 +595,8 @@ add_block_local (struct route_list *rl) } } + + bool init_route_list (struct route_list *rl, const struct route_option_list *opt, @@ -594,7 +628,7 @@ init_route_list (struct route_list *rl, if (rl->rgi.flags & RGI_ADDR_DEFINED) { setenv_route_addr (es, "net_gateway", rl->rgi.gateway.addr, -1); -#ifdef ENABLE_DEBUG +#if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) print_default_gateway (D_ROUTE, &rl->rgi); #endif } @@ -631,6 +665,8 @@ init_route_list (struct route_list *rl, } } + + add_unblock_local (rl); if (rl->flags & RG_ENABLE) { add_block_local (rl); @@ -642,42 +678,29 @@ 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; - struct route r; + 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; + gc_addspecial(netlist, &gc_freeaddrinfo_callback, &gc); 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; } - freeaddrinfo(netlist); } } - rl->n = j; } gc_free (&gc); @@ -728,22 +751,21 @@ init_route_ipv6_list (struct route_ipv6_list *rl6, rl6->remote_endpoint_defined = 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 */ + /* parse the routes from opt6 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; + } } - rl6->n = j; } gc_free (&gc); @@ -759,7 +781,7 @@ add_route3 (in_addr_t network, const struct route_gateway_info *rgi, const struct env_set *es) { - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED; r.network = network; @@ -777,7 +799,7 @@ del_route3 (in_addr_t network, const struct route_gateway_info *rgi, const struct env_set *es) { - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED|RT_ADDED; r.network = network; @@ -851,6 +873,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; @@ -883,6 +906,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); @@ -1012,10 +1036,10 @@ 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, @@ -1024,10 +1048,9 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun 0); } #endif - - for (i = 0; i < rl->n; ++i) + + for (r = rl->routes; r; r = r->next) { - struct route *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); @@ -1037,11 +1060,9 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun } if (rl6 && !rl6->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); @@ -1056,10 +1077,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 * r = &rl->routes[i]; delete_route (r, tt, flags, &rl->rgi, es); } rl->iflags &= ~RL_ROUTES_ADDED; @@ -1074,10 +1094,9 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6, if ( rl6 && rl6->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; @@ -1089,7 +1108,7 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6, } } -#ifdef ENABLE_DEBUG +#ifndef ENABLE_SMALL static const char * show_opt (const char *option) @@ -1114,12 +1133,12 @@ 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 @@ -1153,7 +1172,7 @@ print_default_gateway(const int msglevel, const struct route_gateway_info *rgi) #endif static void -print_route (const struct route *r, int level) +print_route (const struct route_ipv4 *r, int level) { struct gc_arena gc = gc_new (); if (r->flags & RT_DEFINED) @@ -1164,13 +1183,13 @@ print_route (const struct route *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 -setenv_route (struct env_set *es, const struct route *r, int i) +setenv_route (struct env_set *es, const struct route_ipv4 *r, int i) { struct gc_arena gc = gc_new (); if (r->flags & RT_DEFINED) @@ -1192,9 +1211,10 @@ setenv_route (struct env_set *es, const struct route *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 @@ -1220,9 +1240,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++); } /* @@ -1287,7 +1308,7 @@ is_on_link (const int is_local_route, const unsigned int flags, const struct rou } void -add_route (struct route *r, +add_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, /* may be NULL */ @@ -1343,15 +1364,13 @@ add_route (struct route *r, status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route add command failed"); #elif defined (TARGET_ANDROID) + struct buffer out = alloc_buf_gc (128, &gc); - struct user_pass up; - struct buffer out = alloc_buf_gc (64, &gc); - - buf_printf (&out, "%s %s", network, netmask); - - strcpy(up.username, buf_bptr(&out)); - management_query_user_pass(management, &up , "ROUTE", GET_USER_PASS_NEED_OK,(void*) 0); - + 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) { @@ -1408,17 +1427,20 @@ add_route (struct route *r, argv_printf (&argv, "%s add", ROUTE_PATH); -#if 0 - if (r->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "-rtt %d", r->metric); -#endif - argv_printf_cat (&argv, "%s -netmask %s %s", network, netmask, gateway); - /* FIXME -- add on-link support for Solaris */ + /* Solaris can only distinguish between "metric 0" == "on-link on the + * interface where the IP address given is configured" and "metric > 0" + * == "use gateway specified" (no finer-grained route metrics available) + * + * More recent versions of Solaris can also do "-interface", but that + * would break backwards compatibility with older versions for no gain. + */ + if (r->flags & RT_METRIC_DEFINED ) + argv_printf_cat (&argv, "%d", r->metric); argv_msg (D_ROUTE, &argv); status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add command failed"); @@ -1625,13 +1647,11 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 add command failed"); #elif defined (TARGET_ANDROID) - struct user_pass up; struct buffer out = alloc_buf_gc (64, &gc); - - buf_printf (&out, "%s/%d", network, r6->netbits); - - strcpy(up.username, buf_bptr(&out)); - management_query_user_pass(management, &up , "ROUTE6", GET_USER_PASS_NEED_OK,(void*) 0); + + buf_printf (&out, "%s/%d %s", network, r6->netbits, device); + + management_android_control (management, "ROUTE6", buf_bptr(&out)); #elif defined (WIN32) @@ -1744,7 +1764,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla } static void -delete_route (struct route *r, +delete_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, @@ -1991,10 +2011,16 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne 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" ); + argv_msg (D_ROUTE, &argv); netcmd_semaphore_lock (); - openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed"); + openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete ipv6 command failed"); netcmd_semaphore_release (); #elif defined (TARGET_SOLARIS) @@ -2140,6 +2166,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)) @@ -2149,9 +2176,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); @@ -2161,7 +2188,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"); @@ -2249,7 +2276,7 @@ get_default_gateway (struct route_gateway_info *rgi) } static DWORD -windows_route_find_if_index (const struct route *r, const struct tuntap *tt) +windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt) { struct gc_arena gc = gc_new (); DWORD ret = TUN_ADAPTER_INDEX_INVALID; @@ -2294,7 +2321,7 @@ windows_route_find_if_index (const struct route *r, const struct tuntap *tt) } bool -add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_index) +add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index) { struct gc_arena gc = gc_new (); bool ret = false; @@ -2368,7 +2395,7 @@ add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_i } bool -del_route_ipapi (const struct route *r, const struct tuntap *tt) +del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt) { struct gc_arena gc = gc_new (); bool ret = false; @@ -2609,164 +2636,9 @@ get_default_gateway (struct route_gateway_info *rgi) gc_free (&gc); } -#elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY) - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> - -/* all of this is taken from <net/route.h> in FreeBSD */ -#define RTA_DST 0x1 -#define RTA_GATEWAY 0x2 -#define RTA_NETMASK 0x4 - -#define RTM_GET 0x4 -#define RTM_VERSION 5 - -#define RTF_UP 0x1 -#define RTF_GATEWAY 0x2 - -/* - * These numbers are used by reliable protocols for determining - * retransmission behavior and are included in the routing structure. - */ -struct rt_metrics { - u_long rmx_locks; /* Kernel must leave these values alone */ - u_long rmx_mtu; /* MTU for this path */ - u_long rmx_hopcount; /* max hops expected */ - u_long rmx_expire; /* lifetime for route, e.g. redirect */ - u_long rmx_recvpipe; /* inbound delay-bandwidth product */ - u_long rmx_sendpipe; /* outbound delay-bandwidth product */ - u_long rmx_ssthresh; /* outbound gateway buffer limit */ - u_long rmx_rtt; /* estimated round trip time */ - u_long rmx_rttvar; /* estimated rtt variance */ - u_long rmx_pksent; /* packets sent using this route */ - u_long rmx_filler[4]; /* will be used for T/TCP later */ -}; - -/* - * Structures for routing messages. - */ -struct rt_msghdr { - u_short rtm_msglen; /* to skip over non-understood messages */ - u_char rtm_version; /* future binary compatibility */ - u_char rtm_type; /* message type */ - u_short rtm_index; /* index for associated ifp */ - int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ - int rtm_addrs; /* bitmask identifying sockaddrs in msg */ - pid_t rtm_pid; /* identify sender */ - int rtm_seq; /* for sender to identify action */ - int rtm_errno; /* why failed */ - int rtm_use; /* from rtentry */ - u_long rtm_inits; /* which metrics we are initializing */ - struct rt_metrics rtm_rmx; /* metrics themselves */ -}; - -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 - */ -void -get_default_gateway (struct route_gateway_info *rgi) -{ - struct gc_arena gc = gc_new (); - int s, seq, l, pid, rtm_addrs, i; - 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;\ - } - -#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) - -#define rtm m_rtmsg.m_rtm - - CLEAR(*rgi); - - pid = getpid(); - seq = 0; - rtm_addrs = RTA_DST | RTA_NETMASK; - - bzero(&so_dst, sizeof(so_dst)); - bzero(&so_mask, sizeof(so_mask)); - bzero(&rtm, sizeof(struct rt_msghdr)); - - 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; - - 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); - - NEXTADDR(RTA_DST, so_dst); - NEXTADDR(RTA_NETMASK, so_mask); - - rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; - - s = socket(PF_ROUTE, SOCK_RAW, 0); - - 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; - } - - 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 - { - gc_free (&gc); - return; - } - - - 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); - } -} - -#elif defined(TARGET_DARWIN) +#elif defined(TARGET_DARWIN) || \ + defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \ + defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) #include <sys/types.h> #include <sys/socket.h> @@ -2779,8 +2651,25 @@ 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 #define NEXTADDR(w, u) \ if (rtm_addrs & (w)) {\ @@ -2884,7 +2773,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); @@ -2975,163 +2863,6 @@ get_default_gateway (struct route_gateway_info *rgi) #undef max -#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) - -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> - -/* all of this is taken from <net/route.h> in OpenBSD 3.6 */ -#define RTA_DST 0x1 /* destination sockaddr present */ -#define RTA_GATEWAY 0x2 /* gateway sockaddr present */ -#define RTA_NETMASK 0x4 /* netmask sockaddr present */ - -#define RTM_GET 0x4 /* Report Metrics */ - -#define RTM_VERSION 3 /* Up the ante and ignore older versions */ - -#define RTF_UP 0x1 /* route usable */ -#define RTF_GATEWAY 0x2 /* destination is a gateway */ - -/* - * Huge version for userland compatibility. - */ -struct rt_metrics { - u_long rmx_locks; /* Kernel must leave these values alone */ - u_long rmx_mtu; /* MTU for this path */ - u_long rmx_hopcount; /* max hops expected */ - u_long rmx_expire; /* lifetime for route, e.g. redirect */ - u_long rmx_recvpipe; /* inbound delay-bandwidth product */ - u_long rmx_sendpipe; /* outbound delay-bandwidth product */ - u_long rmx_ssthresh; /* outbound gateway buffer limit */ - u_long rmx_rtt; /* estimated round trip time */ - u_long rmx_rttvar; /* estimated rtt variance */ - u_long rmx_pksent; /* packets sent using this route */ -}; - -/* - * Structures for routing messages. - */ -struct rt_msghdr { - u_short rtm_msglen; /* to skip over non-understood messages */ - u_char rtm_version; /* future binary compatibility */ - u_char rtm_type; /* message type */ - u_short rtm_index; /* index for associated ifp */ - int rtm_flags; /* flags, incl. kern & message, e.g. DONE */ - int rtm_addrs; /* bitmask identifying sockaddrs in msg */ - pid_t rtm_pid; /* identify sender */ - int rtm_seq; /* for sender to identify action */ - int rtm_errno; /* why failed */ - int rtm_use; /* from rtentry */ - u_long rtm_inits; /* which metrics we are initializing */ - struct rt_metrics rtm_rmx; /* metrics themselves */ -}; - -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 - */ -void -get_default_gateway (struct route_gateway_info *rgi) -{ - struct gc_arena gc = gc_new (); - int s, seq, l, rtm_addrs, 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;\ - } - -#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) - -#define rtm m_rtmsg.m_rtm - - CLEAR(*rgi); - - pid = getpid(); - seq = 0; - rtm_addrs = RTA_DST | RTA_NETMASK; - - bzero(&so_dst, sizeof(so_dst)); - bzero(&so_mask, sizeof(so_mask)); - bzero(&rtm, sizeof(struct rt_msghdr)); - - 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; - - 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); - - NEXTADDR(RTA_DST, so_dst); - NEXTADDR(RTA_NETMASK, so_mask); - - rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; - - s = socket(PF_ROUTE, SOCK_RAW, 0); - - 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; - } - - 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 - { - gc_free (&gc); - return; - } - - - 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); - } -} - #else /* diff --git a/app/openvpn/src/openvpn/route.h b/app/openvpn/src/openvpn/route.h index e63db595..2b1ae3e8 100644 --- a/app/openvpn/src/openvpn/route.h +++ b/app/openvpn/src/openvpn/route.h @@ -33,8 +33,6 @@ #include "tun.h" #include "misc.h" -#define MAX_ROUTES_DEFAULT 100 - #ifdef WIN32 /* * Windows route methods @@ -74,6 +72,7 @@ struct route_special_addr }; struct route_option { + struct route_option *next; const char *network; const char *netmask; const char *gateway; @@ -89,15 +88,16 @@ struct route_option { #define RG_REROUTE_GW (1<<5) #define RG_AUTO_LOCAL (1<<6) #define RG_BLOCK_LOCAL (1<<7) +#define RG_UNBLOCK_LOCAL (1<<8) 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" */ @@ -105,15 +105,15 @@ struct route_ipv6_option { struct route_ipv6_option_list { unsigned int flags; - int capacity; - int n; - struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE]; + struct route_ipv6_option *routes_ipv6; + struct gc_arena *gc; }; -struct route { +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,6 +123,7 @@ struct route { }; struct route_ipv6 { + struct route_ipv6 *next; bool defined; struct in6_addr network; unsigned int netbits; @@ -140,9 +141,8 @@ struct route_ipv6_list { 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]; + struct route_ipv6 *routes_ipv6; + struct gc_arena gc; }; @@ -188,9 +188,8 @@ 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 routes[EMPTY_ARRAY_SIZE]; + struct route_ipv4 *routes; + struct gc_arena gc; }; #if P2MP @@ -208,22 +207,20 @@ 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); -void add_route (struct route *r, +void add_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, @@ -290,7 +287,7 @@ void print_default_gateway(const int msglevel, const struct route_gateway_info * #define TLA_LOCAL 2 int test_local_addr (const in_addr_t addr, const struct route_gateway_info *rgi); -#ifdef ENABLE_DEBUG +#ifndef ENABLE_SMALL void print_route_options (const struct route_option_list *rol, int level); #endif @@ -301,8 +298,8 @@ void print_routes (const struct route_list *rl, int level); void show_routes (int msglev); bool test_routes (const struct route_list *rl, const struct tuntap *tt); -bool add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_index); -bool del_route_ipapi (const struct route *r, const struct tuntap *tt); +bool add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index); +bool del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt); #else static inline bool test_routes (const struct route_list *rl, const struct tuntap *tt) { return true; } diff --git a/app/openvpn/src/openvpn/sig.c b/app/openvpn/src/openvpn/sig.c index 7ddfd0ed..90e39a42 100644 --- a/app/openvpn/src/openvpn/sig.c +++ b/app/openvpn/src/openvpn/sig.c @@ -279,9 +279,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); diff --git a/app/openvpn/src/openvpn/snappy.c b/app/openvpn/src/openvpn/snappy.c new file mode 100644 index 00000000..24440bae --- /dev/null +++ b/app/openvpn/src/openvpn/snappy.c @@ -0,0 +1,189 @@ +/* + * 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(ENABLE_SNAPPY) + +#include "snappy-c.h" + +#include "comp.h" +#include "error.h" +#include "otime.h" + +#include "memdbg.h" + +/* Initial command byte to tell our peer if we compressed */ +#define SNAPPY_COMPRESS_BYTE 0x68 + +static void +snap_compress_init (struct compress_context *compctx) +{ + msg (D_INIT_MEDIUM, "Snappy compression initializing"); + ASSERT(compctx->flags & COMP_F_SWAP); +} + +static void +snap_compress_uninit (struct compress_context *compctx) +{ +} + +static void +snap_compress (struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame* frame) +{ + snappy_status status; + bool compressed = false; + + if (buf->len <= 0) + return; + + /* + * In order to attempt compression, length must be at least COMPRESS_THRESHOLD. + */ + if (buf->len >= COMPRESS_THRESHOLD) + { + const size_t ps = PAYLOAD_SIZE (frame); + size_t zlen = ps + COMP_EXTRA_BUFFER (ps); + + ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); + ASSERT (buf_safe (&work, zlen)); + + if (buf->len > ps) + { + dmsg (D_COMP_ERRORS, "Snappy compression buffer overflow"); + buf->len = 0; + return; + } + + status = snappy_compress((const char *)BPTR(buf), (size_t)BLEN(buf), (char *)BPTR(&work), &zlen); + if (status != SNAPPY_OK) + { + dmsg (D_COMP_ERRORS, "Snappy compression error: %d", status); + buf->len = 0; + return; + } + + ASSERT (buf_safe (&work, zlen)); + work.len = zlen; + compressed = true; + + dmsg (D_COMP, "Snappy compress %d -> %d", buf->len, work.len); + compctx->pre_compress += buf->len; + compctx->post_compress += work.len; + } + + /* 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 = SNAPPY_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 +snap_decompress (struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame* frame) +{ + size_t zlen = EXPANDED_SIZE (frame); + snappy_status status; + 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 == SNAPPY_COMPRESS_BYTE) /* packet was compressed */ + { + ASSERT (buf_safe (&work, zlen)); + status = snappy_uncompress((const char *)BPTR(buf), (size_t)BLEN(buf), (char *)BPTR(&work), &zlen); + if (status != SNAPPY_OK) + { + dmsg (D_COMP_ERRORS, "Snappy decompression error: %d", status); + buf->len = 0; + return; + } + + ASSERT (buf_safe (&work, zlen)); + work.len = zlen; + + dmsg (D_COMP, "Snappy decompress %d -> %d", buf->len, work.len); + compctx->pre_decompress += buf->len; + compctx->post_decompress += work.len; + + *buf = work; + } + else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */ + { + ; + } + else + { + dmsg (D_COMP_ERRORS, "Bad Snappy decompression header byte: %d", c); + buf->len = 0; + } +} + +const struct compress_alg snappy_alg = { + "snappy", + snap_compress_init, + snap_compress_uninit, + snap_compress, + snap_decompress +}; + +#else +static void dummy(void) {} +#endif /* ENABLE_SNAPPY */ diff --git a/app/openvpn/src/openvpn/snappy.h b/app/openvpn/src/openvpn/snappy.h new file mode 100644 index 00000000..361a6317 --- /dev/null +++ b/app/openvpn/src/openvpn/snappy.h @@ -0,0 +1,39 @@ +/* + * 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 + */ + +#ifndef OPENVPN_SNAPPY_H +#define OPENVPN_SNAPPY_H + +#if defined(ENABLE_SNAPPY) + +#include "buffer.h" + +extern const struct compress_alg snappy_alg; + +struct snappy_workspace +{ +}; + +#endif /* ENABLE_SNAPPY */ +#endif diff --git a/app/openvpn/src/openvpn/socket.c b/app/openvpn/src/openvpn/socket.c index 31ff6d21..9e6bd10c 100644 --- a/app/openvpn/src/openvpn/socket.c +++ b/app/openvpn/src/openvpn/socket.c @@ -39,6 +39,7 @@ #include "manage.h" #include "misc.h" #include "manage.h" +#include "openvpn.h" #include "memdbg.h" @@ -117,6 +118,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 @@ -155,7 +328,7 @@ openvpn_getaddrinfo (unsigned int flags, print_hostname = hostname; else print_hostname = "undefined"; - + if(servname) print_servname = servname; else @@ -172,11 +345,10 @@ openvpn_getaddrinfo (unsigned int flags, CLEAR(hints); hints.ai_family = ai_family; hints.ai_flags = AI_NUMERICHOST; - hints.ai_socktype = SOCK_STREAM; - + if(flags & GETADDR_PASSIVE) hints.ai_flags |= AI_PASSIVE; - + if(flags & GETADDR_DATAGRAM) hints.ai_socktype = SOCK_DGRAM; else @@ -192,7 +364,7 @@ openvpn_getaddrinfo (unsigned int flags, ((resolve_retry_seconds + 4)/ fail_wait_interval); const char *fmt; int level = 0; - + fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)"; if ((flags & GETADDR_MENTION_RESOLVE_RETRY) && !resolve_retry_seconds) @@ -276,8 +448,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 * */ } @@ -597,11 +769,14 @@ 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! */ @@ -618,17 +793,20 @@ create_socket_tcp (int af) } static socket_descriptor_t -create_socket_udp (const int af, const unsigned int flags) +create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags) { socket_descriptor_t sd; - if ((sd = socket (af, SOCK_DGRAM, IPPROTO_UDP)) < 0) + 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; - if(af == AF_INET) + if(addrinfo->ai_family == AF_INET) { #ifdef IP_PKTINFO if (setsockopt (sd, SOL_IP, IP_PKTINFO, @@ -641,8 +819,8 @@ create_socket_udp (const int af, const unsigned int flags) #else #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif - } - else if (af == AF_INET6 ) + } + else if (addrinfo->ai_family == AF_INET6 ) { #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */ if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, @@ -658,75 +836,91 @@ create_socket_udp (const int af, const unsigned int flags) return sd; } -static void -create_socket (struct link_socket *sock) +static void bind_local (struct link_socket *sock, const sa_family_t ai_family) { - /* create socket, use information carried over from getaddrinfo */ - const int ai_proto = sock->info.lsa->actual.ai_protocol; - const int ai_family = sock->info.lsa->actual.ai_family; - - ASSERT (sock->info.af == AF_UNSPEC || sock->info.af == 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); + } +} - - if (ai_proto == IPPROTO_UDP) +static void +create_socket (struct link_socket* sock, struct addrinfo* addr) +{ + if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM) { - sock->sd = create_socket_udp (ai_family, 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 (ai_family); -#endif + { + /* 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 (ai_proto == IPPROTO_TCP) + else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM) { - sock->sd = create_socket_tcp (ai_family); + 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, struct sockaddr* addr) +static void protect_fd_nonlocal (int fd, const struct sockaddr* addr) { - if (addr_local (addr)) { - msg(M_DEBUG, "Address is local, not protecting socket fd %d", fd); - return; - } - - struct user_pass up; - strcpy(up.username ,__func__); - management->connection.fdtosend = fd; - msg(M_DEBUG, "Protecting socket fd %d", fd); - management_query_user_pass(management, &up , "PROTECTFD", GET_USER_PASS_NEED_OK,(void*) 0); + /* 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(M_DEBUG, "Address is local, not protecting socket fd %d", fd); + return; + } + msg(M_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 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"); } @@ -819,7 +1013,7 @@ socket_listen_accept (socket_descriptor_t sd, int new_sd = SOCKET_UNDEFINED; CLEAR (*act); - socket_do_listen (sd, local->ai_addr, do_listen, true); + socket_do_listen (sd, local, do_listen, true); while (true) { @@ -854,7 +1048,7 @@ socket_listen_accept (socket_descriptor_t sd, if (socket_defined (new_sd)) { - struct addrinfo* ai; + struct addrinfo* ai = NULL; if(remote_dynamic) openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL, remote_verify.addr.sa.sa_family, &ai); @@ -891,7 +1085,8 @@ void socket_bind (socket_descriptor_t sd, struct addrinfo *local, int ai_family, - const char *prefix) + const char *prefix, + bool ipv6only) { struct gc_arena gc = gc_new (); @@ -901,10 +1096,12 @@ socket_bind (socket_descriptor_t sd, * For example if an address has multiple A records * What is the correct way to deal with it? */ - - ASSERT(local); + struct addrinfo* cur; - + + ASSERT(local); + + /* find the first addrinfo with correct ai_family */ for (cur = local; cur; cur=cur->ai_next) { @@ -914,7 +1111,17 @@ socket_bind (socket_descriptor_t sd, 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, &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 (); @@ -934,12 +1141,13 @@ openvpn_connect (socket_descriptor_t sd, { int status = 0; +#ifdef TARGET_ANDROID + protect_fd_nonlocal(sd, remote); +#endif + #ifdef CONNECT_NONBLOCK set_nonblock (sd); - - protect_fd_nonlocal(sd, remote); status = connect (sd, remote, af_addr_size(remote->sa_family)); - if (status) status = openvpn_errno (); if ( @@ -1015,7 +1223,7 @@ 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); @@ -1024,24 +1232,18 @@ void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai) *((struct sockaddr_in6*) ai->ai_addr); else ASSERT(0); - - /* Copy addrinfo sock parameters for socket creating */ - actual->ai_family = ai->ai_family; - actual->ai_protocol = ai->ai_protocol; - actual->ai_socktype = ai->ai_socktype; + } void -socket_connect (socket_descriptor_t *sd, - struct link_socket_addr *lsa, +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 (); - const struct sockaddr *dest = &lsa->actual.dest.addr.sa; - int status; - + #ifdef CONNECT_NONBLOCK msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", print_sockaddr (dest, &gc)); @@ -1049,14 +1251,14 @@ socket_connect (socket_descriptor_t *sd, msg (M_INFO, "Attempting to establish TCP connection with %s", print_sockaddr (dest, &gc)); #endif - + #ifdef ENABLE_MANAGEMENT if (management) management_set_state (management, - OPENVPN_STATE_TCP_CONNECT, - NULL, - (in_addr_t)0, - (in_addr_t)0); + OPENVPN_STATE_TCP_CONNECT, + NULL, + (in_addr_t)0, + (in_addr_t)0); #endif /* Set the actual address */ @@ -1139,41 +1341,34 @@ resolve_bind_local (struct link_socket *sock, const sa_family_t af) if (!sock->info.lsa->bind_local) { int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | - GETADDR_FATAL | GETADDR_PASSIVE; + GETADDR_FATAL | GETADDR_PASSIVE; int status; - + if(proto_is_dgram(sock->info.proto)) - flags |= GETADDR_DATAGRAM; - + flags |= GETADDR_DATAGRAM; + /* will return AF_{INET|INET6}from local_host */ - status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0, - NULL, af, &sock->info.lsa->bind_local); + 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)); + msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s", + sock->local_host, sock->local_port, + gai_strerror(status)); } } gc_free (&gc); } -static void bind_local (struct link_socket *sock) -{ - /* bind to local address/port */ - if (sock->bind_local) - { -#ifdef ENABLE_SOCKS - if (sock->socks_proxy && sock->info.proto == PROTO_UDP) - socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local, - sock->info.lsa->actual.ai_family, "SOCKS"); - else -#endif - socket_bind (sock->sd, sock->info.lsa->bind_local, - sock->info.lsa->actual.ai_family, "TCP/UDP"); - } -} - static void resolve_remote (struct link_socket *sock, int phase, @@ -1182,103 +1377,104 @@ resolve_remote (struct link_socket *sock, { struct gc_arena gc = gc_new (); - if (!sock->did_resolve_remote) + /* resolve remote address if undefined */ + if (!sock->info.lsa->remote_list) { - /* resolve remote address if undefined */ - if (!sock->info.lsa->remote_list) + if (sock->remote_host) { - 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; - - if (proto_is_dgram(sock->info.proto)) - flags |= GETADDR_DATAGRAM; - - if (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); + } - struct addrinfo* ai; - 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; - } + + 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; } - } } + } - /* 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, quick hack to fix persistent-remote ....*/ + /* 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); - if(sock->info.lsa->current_remote) - { - set_actual_address (&sock->info.lsa->actual, - sock->info.lsa->current_remote); - } + set_actual_address (&sock->info.lsa->actual, + sock->info.lsa->current_remote); } - - /* remember that we finished */ - sock->did_resolve_remote = true; } done: @@ -1294,61 +1490,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; } void -create_new_socket (struct link_socket* sock) -{ - if (sock->bind_local) { - resolve_bind_local (sock, sock->info.af); - } - resolve_remote (sock, 1, NULL, NULL); - /* - * In P2P or server mode we must create the socket even when resolving - * the remote site fails/is not specified. */ - - if (sock->info.af && sock->info.lsa->actual.ai_family==0 && sock->bind_local) - { - /* Copy sock parameters from bind addr */ - set_actual_address (&sock->info.lsa->actual, sock->info.lsa->bind_local); - /* clear destination set by set_actual_address */ - CLEAR(sock->info.lsa->actual.dest); - } - - /* - * Create the socket early if socket should be bound - */ - if (sock->bind_local && sock->info.lsa->actual.ai_family) - { - create_socket (sock); - - if (sock->bind_local) - bind_local(sock); - } -} - - -/* bind socket if necessary */ -void link_socket_init_phase1 (struct link_socket *sock, const char *local_host, const char *local_port, const char *remote_host, const char *remote_port, + struct cached_dns_entry *dns_cache, int proto, - sa_family_t af, + 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,15 +1531,9 @@ link_socket_init_phase1 (struct link_socket *sock, 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; @@ -1401,6 +1554,7 @@ link_socket_init_phase1 (struct link_socket *sock, 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; @@ -1412,10 +1566,9 @@ link_socket_init_phase1 (struct link_socket *sock, 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) { @@ -1430,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.af == AF_INET); ASSERT (!sock->inetd); /* the proxy server */ @@ -1446,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; @@ -1454,7 +1603,7 @@ link_socket_init_phase1 (struct link_socket *sock, } /* bind behavior for TCP server vs. client */ - if (sock->info.proto == PROTO_TCP_SERVER && sock->info.af==AF_INET) + if (sock->info.proto == PROTO_TCP_SERVER) { if (sock->mode == LS_MODE_TCP_ACCEPT_FROM) sock->bind_local = false; @@ -1471,13 +1620,16 @@ link_socket_init_phase1 (struct link_socket *sock, } else if (mode != LS_MODE_TCP_ACCEPT_FROM) { - create_new_socket (sock); + if (sock->bind_local) { + resolve_bind_local (sock, sock->info.af); + } + resolve_remote (sock, 1, NULL, NULL); } } static void phase2_inetd (struct link_socket* sock, const struct frame *frame, - const char *remote_dynamic, volatile int *signal_received) + const char *remote_dynamic, volatile int *signal_received) { bool remote_changed = false; @@ -1490,27 +1642,28 @@ void phase2_inetd (struct link_socket* sock, const struct frame *frame, 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); + 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); + 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)); + "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); + &sock->info.lsa->actual, + remote_dynamic, + sock->info.lsa->bind_local, + false, + sock->inetd == INETD_NOWAIT, + signal_received); + } ASSERT (!remote_changed); } @@ -1528,10 +1681,8 @@ phase2_set_socket_flags (struct link_socket* sock) 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); @@ -1547,171 +1698,161 @@ 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 */ - { - 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, sock->info.af, true)); - else if (sock->bind_local) - { - /* Socket is always bound on the first matching address */ - struct addrinfo *cur; - for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next) - { - if(cur->ai_family == sock->info.lsa->actual.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)); - } + 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) + 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); + &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->ai_addr, - true, - false); + 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); + &sock->info.lsa->actual, + false); if (!socket_defined (sock->sd)) - { - *signal_received = SIGTERM; - return; - } + { + *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) { -#ifdef GENERAL_PROXY_SUPPORT - bool proxy_retry = false; -#else - const bool proxy_retry = false; -#endif - do { - socket_connect (&sock->sd, - sock->info.lsa, - sock->connect_timeout, - sig_info); - - if (sig_info->signal_received) - return; - - 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, - &sig_info->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, - &sig_info->signal_received); - } -#endif - if (proxy_retry) - { - /* TODO (schwabe): This code assumes AF_INET for the proxy socket - * when retrying a connection */ - openvpn_close_socket (sock->sd); - sock->sd = create_socket_tcp (AF_INET); - } - } while (proxy_retry); + bool proxy_retry = false; + do { + socket_connect (&sock->sd, + sock->info.lsa->current_remote->ai_addr, + sock->connect_timeout, + sig_info); + + if (sig_info->signal_received) + return; + + if (false) + ; + 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, + &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); } -#ifdef ENABLE_SOCKS static void phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info) { socket_connect (&sock->ctrl_sd, - sock->info.lsa, - sock->connect_timeout, - sig_info); - + sock->info.lsa->current_remote->ai_addr, + sock->connect_timeout, + sig_info); + if (sig_info->signal_received) - return; - + return; + establish_socks_proxy_udpassoc (sock->socks_proxy, - sock->ctrl_sd, - sock->sd, - &sock->socks_relay.dest, - &sig_info->signal_received); - + sock->ctrl_sd, + sock->sd, + &sock->socks_relay.dest, + &sig_info->signal_received); + if (sig_info->signal_received) - return; - + return; + 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); if (sock->info.lsa->remote_list) - freeaddrinfo(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); - } -#endif /* finalize socket initialization */ void link_socket_init_phase2 (struct link_socket *sock, - const struct frame *frame, - struct signal_info *sig_info) + const struct frame *frame, + struct signal_info *sig_info) { const char *remote_dynamic = NULL; int sig_save = 0; @@ -1740,69 +1881,77 @@ link_socket_init_phase2 (struct link_socket *sock, { phase2_inetd (sock, frame, remote_dynamic, &sig_info->signal_received); if (sig_info && sig_info->signal_received) - goto done; + goto done; } else { /* Second chance to resolv/create socket */ resolve_remote (sock, 2, &remote_dynamic, &sig_info->signal_received); - + + /* 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); + /* If socket has not already been created create it now */ if (sock->sd == SOCKET_UNDEFINED) - { - if (sock->info.lsa->actual.ai_family) - { - create_socket (sock); - } - else - { - msg (M_WARN, "Could not determine IPv4/IPv6 protocol"); - sig_info->signal_received = SIGUSR1; - goto done; - } - - if (sock->bind_local) - bind_local(sock); - } + { + /* 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) + { + /* 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)); + + create_socket (sock, sock->info.lsa->bind_local); + } + } + + /* Socket still undefined, give a warning and abort connection */ + if (sock->sd == SOCKET_UNDEFINED) + { + msg (M_WARN, "Could not determine IPv4/IPv6 protocol"); + sig_info->signal_received = SIGUSR1; + goto done; + } - if (sig_info && sig_info->signal_received) - goto done; + goto done; if (sock->info.proto == PROTO_TCP_SERVER) - { - phase2_tcp_server (sock, remote_dynamic, - &sig_info->signal_received); - } + { + phase2_tcp_server (sock, remote_dynamic, + &sig_info->signal_received); + } else if (sock->info.proto == PROTO_TCP_CLIENT) - { - phase2_tcp_client (sock, sig_info); - - } - else if (sock->info.proto == PROTO_UDP) - { -#ifdef ENABLE_SOCKS - if (sock->info.proto == PROTO_UDP && sock->socks_proxy) - { - phase2_socks_client (sock, sig_info); -#endif - } - protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa); - } + { + phase2_tcp_client (sock, sig_info); + } + 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 && sig_info->signal_received) - goto done; + goto done; } phase2_set_socket_flags(sock); linksock_print_addr(sock); - + done: if (sig_save && sig_info) { if (!sig_info->signal_received) - sig_info->signal_received = sig_save; + sig_info->signal_received = sig_save; } } @@ -1838,14 +1987,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); @@ -2251,10 +2398,10 @@ print_sockaddr_ex (const struct sockaddr *sa, { if (separator) buf_puts (&out, separator); - + buf_puts (&out, servname); } - + return BSTR (&out); } @@ -2468,12 +2615,17 @@ struct proto_names { /* Indexed by PROTO_x */ 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}, - {"udp4", "UDPv4", AF_INET, PROTO_UDP}, - {"tcp-server", "TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER}, - {"tcp-client", "TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT}, + {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER}, + {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT}, {"tcp", "TCP", AF_UNSPEC, PROTO_TCP}, - {"tcp4", "TCPv4", AF_INET, 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}, @@ -2535,7 +2687,7 @@ proto2ascii (int proto, sa_family_t af, bool display_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(proto_names[i].proto_af == af && proto_names[i].proto == proto) { if(display_form) return proto_names[i].display_form; @@ -2562,30 +2714,6 @@ proto2ascii_all (struct gc_arena *gc) return BSTR (&out); } -int -addr_guess_family(sa_family_t af, const char *name) -{ - unsigned short ret; - if (af) - { - return af; /* 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) { @@ -2615,13 +2743,16 @@ proto_remote (int proto, bool remote) ASSERT (proto >= 0 && proto < PROTO_N); if (proto == PROTO_UDP) return "UDPv4"; - - if ( (remote && proto == PROTO_TCP_CLIENT) || proto == PROTO_TCP_SERVER) + + if ( (remote && proto == PROTO_TCP_CLIENT) || + (!remote && proto == PROTO_TCP_SERVER)) return "TCPv4_SERVER"; - if ( (remote && proto == PROTO_TCP_SERVER) || proto == PROTO_TCP_CLIENT) + if ( (remote && proto == PROTO_TCP_SERVER) || + (!remote && proto == PROTO_TCP_CLIENT)) return "TCPv4_CLIENT"; ASSERT (0); + return ""; /* Make the compiler happy */ } /* @@ -2757,7 +2888,12 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, 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 @@ -2774,7 +2910,7 @@ link_socket_read_udp_posix (struct link_socket *sock, 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) + if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO) fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from); else #endif @@ -2818,24 +2954,24 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, struct iovec iov; struct msghdr mesg; struct cmsghdr *cmsg; + union openvpn_pktinfo opi; iov.iov_base = BPTR (buf); iov.iov_len = BLEN (buf); mesg.msg_iov = &iov; mesg.msg_iovlen = 1; - switch (to->ai_family) + switch (to->dest.addr.sa.sa_family) { case AF_INET: { - struct openvpn_in4_pktinfo msgpi4; mesg.msg_name = &to->dest.addr.sa; mesg.msg_namelen = sizeof (struct sockaddr_in); - mesg.msg_control = &msgpi4; - mesg.msg_controllen = sizeof msgpi4; + mesg.msg_control = &opi; mesg.msg_flags = 0; +#ifdef HAVE_IN_PKTINFO + mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo); cmsg = CMSG_FIRSTHDR (&mesg); cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo); -#ifdef HAVE_IN_PKTINFO cmsg->cmsg_level = SOL_IP; cmsg->cmsg_type = IP_PKTINFO; { @@ -2846,6 +2982,10 @@ 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) ); + mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr)); + cmsg = CMSG_FIRSTHDR (&mesg); + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = IP_RECVDSTADDR; *(struct in_addr *) CMSG_DATA (cmsg) = to->pi.in4; @@ -2856,12 +2996,11 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, } case AF_INET6: { - struct openvpn_in6_pktinfo msgpi6; struct in6_pktinfo *pkti6; mesg.msg_name = &to->dest.addr.sa; mesg.msg_namelen = sizeof (struct sockaddr_in6); - mesg.msg_control = &msgpi6; - mesg.msg_controllen = sizeof msgpi6; + mesg.msg_control = &opi; + mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo); mesg.msg_flags = 0; cmsg = CMSG_FIRSTHDR (&mesg); cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo); @@ -2921,10 +3060,10 @@ 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 + if (sock->info.af == AF_INET) sock->reads.addrlen = sizeof (sock->reads.addr); + else + sock->reads.addrlen = sizeof (sock->reads.addr6); status = WSARecvFrom( sock->sd, wsabuf, @@ -3020,7 +3159,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 (sock->info.af == AF_INET6) { sock->writes.addr6 = to->dest.addr.in6; sock->writes.addrlen = sizeof (sock->writes.addr6); diff --git a/app/openvpn/src/openvpn/socket.h b/app/openvpn/src/openvpn/socket.h index 5b7a26a9..8e157c67 100644 --- a/app/openvpn/src/openvpn/socket.h +++ b/app/openvpn/src/openvpn/socket.h @@ -77,15 +77,21 @@ 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 */ - int ai_family; /* PF_xxx */ - int ai_socktype; /* SOCK_xxx */ - int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ - struct openvpn_sockaddr dest; #if ENABLE_IP_PKTINFO union { @@ -104,7 +110,7 @@ struct link_socket_addr { struct addrinfo* bind_local; struct addrinfo* remote_list; /* complete remote list */ - struct addrinfo* current_remote; /* remote used in the + struct addrinfo* current_remote; /* remote used in the current connection attempt */ struct link_socket_actual actual; /* reply to this address */ }; @@ -118,6 +124,7 @@ struct link_socket_info 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 */ }; @@ -165,10 +172,7 @@ 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 struct overlapped_io reads; @@ -187,6 +191,7 @@ struct link_socket const char *remote_port; const char *local_host; const char *local_port; + struct cached_dns_entry *dns_cache; bool bind_local; # define INETD_NONE 0 @@ -207,8 +212,6 @@ struct link_socket 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) @@ -222,22 +225,16 @@ struct link_socket 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; const char *proxy_dest_port; -#endif #if PASSTOS_CAPABILITY /* used to get/set TOS. */ @@ -289,13 +286,16 @@ struct link_socket *link_socket_new (void); void socket_bind (socket_descriptor_t sd, struct addrinfo *local, int af_family, - const char *prefix); + const char *prefix, + bool ipv6only); int openvpn_connect (socket_descriptor_t sd, const struct sockaddr *remote, int connect_timeout, volatile int *signal_received); + + /* * Initialize link_socket object. */ @@ -306,16 +306,14 @@ link_socket_init_phase1 (struct link_socket *sock, const char *local_port, const char *remote_host, const char *remote_port, + struct cached_dns_entry *dns_cache, int proto, - sa_family_t af, + 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 @@ -337,6 +335,8 @@ void link_socket_init_phase2 (struct link_socket *sock, const struct frame *frame, struct signal_info *sig_info); +void do_preresolve(struct context *c); + void socket_adjust_frame_parameters (struct frame *frame, int proto); void frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto); @@ -456,7 +456,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, @@ -511,6 +511,8 @@ bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int * #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, int resolve_retry_seconds, @@ -600,14 +602,14 @@ static inline bool addr_local (const struct sockaddr *addr) { if (!addr) - return false; + 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; + 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; } } @@ -641,61 +643,78 @@ link_socket_actual_defined (const struct link_socket_actual *act) static inline bool addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) { - switch(a1->addr.sa.sa_family) { - case AF_INET: - return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; - case AF_INET6: - return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); - } - ASSERT(0); - return false; + switch(a1->addr.sa.sa_family) { + case AF_INET: + return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; + case AF_INET6: + return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); + } + ASSERT(0); + 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); + 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) +{ + /* + * "public" addr returned is checked against ifconfig for + * possible clash: non sense for now given + * that we do ifconfig only IPv4 + */ + if(addr->addr.sa.sa_family != AF_INET) + return 0; + 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: + 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: + 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: + default: ASSERT(0); } } - return false; + return false; } @@ -708,7 +727,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); @@ -717,10 +736,10 @@ addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockadd static inline bool addr_match_proto (const struct openvpn_sockaddr *a1, - const struct openvpn_sockaddr *a2, - const int proto) + const struct openvpn_sockaddr *a2, + const int proto) { - return link_socket_proto_connection_oriented (proto) + return link_socket_proto_connection_oriented (proto) ? addr_match (a1, a2) : addr_port_match (a1, a2); } @@ -728,8 +747,8 @@ addr_match_proto (const struct openvpn_sockaddr *a1, static inline bool addrlist_match_proto (const struct openvpn_sockaddr *a1, - struct addrinfo *addr_list, - const int proto) + struct addrinfo *addr_list, + const int proto) { return link_socket_proto_connection_oriented (proto) ? addrlist_match (a1, addr_list) @@ -839,7 +858,7 @@ link_socket_verify_incoming_addr (struct buffer *buf, case AF_INET: if (!link_socket_actual_defined (from_addr)) return false; - if (info->remote_float || !info->lsa->remote_list) + if (info->remote_float || (!info->lsa->remote_list)) return true; if (addrlist_match_proto (&from_addr->dest, info->lsa->remote_list, info->proto)) return true; @@ -878,13 +897,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 - || !lsa->remote_list) - || addrlist_match_proto (&act->dest, lsa->remote_list, 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); @@ -1095,7 +1116,7 @@ static inline void link_socket_set_tos (struct link_socket *ls) { if (ls && ls->ptos_defined) - setsockopt (ls->sd, IPPROTO_IP, IP_TOS, &ls->ptos, sizeof (ls->ptos)); + setsockopt (ls->sd, IPPROTO_IP, IP_TOS, (const void *)&ls->ptos, sizeof (ls->ptos)); } #endif diff --git a/app/openvpn/src/openvpn/socks.c b/app/openvpn/src/openvpn/socks.c index 804c9836..72bdf550 100644 --- a/app/openvpn/src/openvpn/socks.c +++ b/app/openvpn/src/openvpn/socks.c @@ -38,8 +38,6 @@ #include "syshead.h" -#ifdef ENABLE_SOCKS - #include "common.h" #include "misc.h" #include "win32.h" @@ -189,10 +187,15 @@ socks_handshake (struct socks_proxy_info *p, char buf[2]; int len = 0; const int timeout_sec = 5; + ssize_t size; + + /* VER = 5, NMETHODS = 1, METHODS = [0 (no auth)] */ + char method_sel[3] = { 0x05, 0x01, 0x00 }; + if (p->authfile[0]) + method_sel[2] = 0x02; /* METHODS = [2 (plain login)] */ - /* VER = 5, NMETHODS = 2, METHODS = [0 (no auth), 2 (plain login)] */ - const ssize_t size = send (sd, "\x05\x02\x00\x02", 4, MSG_NOSIGNAL); - if (size != 4) + size = send (sd, method_sel, sizeof (method_sel), MSG_NOSIGNAL); + if (size != sizeof (method_sel)) { msg (D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port write failed on send()"); return false; @@ -252,6 +255,13 @@ socks_handshake (struct socks_proxy_info *p, return false; } + /* validate that the auth method returned is the one sent */ + if (buf[1] != method_sel[2]) + { + msg (D_LINK_ERRORS, "socks_handshake: Socks proxy returned unexpected auth"); + return false; + } + /* select the appropriate authentication method */ switch (buf[1]) { @@ -396,7 +406,7 @@ port_from_servname(const char* servname) port = atoi(servname); if(port >0 && port < 65536) return port; - + struct servent* service; service = getservbyname(servname, NULL); if(service) @@ -436,7 +446,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p, 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); @@ -448,7 +458,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p, goto error; } } - + /* receive reply from Socks proxy and discard */ if (!recv_socks_reply (sd, NULL, signal_received)) @@ -562,7 +572,3 @@ socks_process_outgoing_udp (struct buffer *buf, return 10; } - -#else -static void dummy(void) {} -#endif /* ENABLE_SOCKS */ diff --git a/app/openvpn/src/openvpn/socks.h b/app/openvpn/src/openvpn/socks.h index 30b957d7..2475261f 100644 --- a/app/openvpn/src/openvpn/socks.h +++ b/app/openvpn/src/openvpn/socks.h @@ -30,8 +30,6 @@ #ifndef SOCKS_H #define SOCKS_H -#ifdef ENABLE_SOCKS - #include "buffer.h" struct openvpn_sockaddr; @@ -74,4 +72,3 @@ int socks_process_outgoing_udp (struct buffer *buf, const struct link_socket_actual *to); #endif -#endif diff --git a/app/openvpn/src/openvpn/ssl.c b/app/openvpn/src/openvpn/ssl.c index 9f570b9d..95bbb277 100644 --- a/app/openvpn/src/openvpn/ssl.c +++ b/app/openvpn/src/openvpn/ssl.c @@ -7,10 +7,7 @@ * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> - * - * Additions for eurephia plugin done by: - * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2008-2009 - * + * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -38,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) @@ -51,7 +47,6 @@ #include "error.h" #include "common.h" -#include "integer.h" #include "socket.h" #include "misc.h" #include "fdmisc.h" @@ -60,8 +55,6 @@ #include "status.h" #include "gremlin.h" #include "pkcs11.h" -#include "list.h" -#include "base64.h" #include "route.h" #include "ssl.h" @@ -113,6 +106,162 @@ show_tls_performance_stats(void) #endif +/** + * SSL/TLS Cipher suite name translation table + */ +static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { + {"ADH-SEED-SHA", "TLS-DH-anon-WITH-SEED-CBC-SHA"}, + {"AES128-GCM-SHA256", "TLS-RSA-WITH-AES-128-GCM-SHA256"}, + {"AES128-SHA256", "TLS-RSA-WITH-AES-128-CBC-SHA256"}, + {"AES128-SHA", "TLS-RSA-WITH-AES-128-CBC-SHA"}, + {"AES256-GCM-SHA384", "TLS-RSA-WITH-AES-256-GCM-SHA384"}, + {"AES256-SHA256", "TLS-RSA-WITH-AES-256-CBC-SHA256"}, + {"AES256-SHA", "TLS-RSA-WITH-AES-256-CBC-SHA"}, + {"CAMELLIA128-SHA256", "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256"}, + {"CAMELLIA128-SHA", "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA"}, + {"CAMELLIA256-SHA256", "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256"}, + {"CAMELLIA256-SHA", "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA"}, + {"DES-CBC3-SHA", "TLS-RSA-WITH-3DES-EDE-CBC-SHA"}, + {"DES-CBC-SHA", "TLS-RSA-WITH-DES-CBC-SHA"}, + {"DH-DSS-SEED-SHA", "TLS-DH-DSS-WITH-SEED-CBC-SHA"}, + {"DHE-DSS-AES128-GCM-SHA256", "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256"}, + {"DHE-DSS-AES128-SHA256", "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256"}, + {"DHE-DSS-AES128-SHA", "TLS-DHE-DSS-WITH-AES-128-CBC-SHA"}, + {"DHE-DSS-AES256-GCM-SHA384", "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384"}, + {"DHE-DSS-AES256-SHA256", "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256"}, + {"DHE-DSS-AES256-SHA", "TLS-DHE-DSS-WITH-AES-256-CBC-SHA"}, + {"DHE-DSS-CAMELLIA128-SHA256", "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256"}, + {"DHE-DSS-CAMELLIA128-SHA", "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA"}, + {"DHE-DSS-CAMELLIA256-SHA256", "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256"}, + {"DHE-DSS-CAMELLIA256-SHA", "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA"}, + {"DHE-DSS-SEED-SHA", "TLS-DHE-DSS-WITH-SEED-CBC-SHA"}, + {"DHE-RSA-AES128-GCM-SHA256", "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256"}, + {"DHE-RSA-AES128-SHA256", "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256"}, + {"DHE-RSA-AES128-SHA", "TLS-DHE-RSA-WITH-AES-128-CBC-SHA"}, + {"DHE-RSA-AES256-GCM-SHA384", "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384"}, + {"DHE-RSA-AES256-SHA256", "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256"}, + {"DHE-RSA-AES256-SHA", "TLS-DHE-RSA-WITH-AES-256-CBC-SHA"}, + {"DHE-RSA-CAMELLIA128-SHA256", "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"}, + {"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-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"}, + {"ECDH-ECDSA-AES128-SHA256", "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA256"}, + {"ECDH-ECDSA-AES128-SHA", "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA"}, + {"ECDH-ECDSA-AES256-GCM-SHA384", "TLS-ECDH-ECDSA-WITH-AES-256-GCM-SHA384"}, + {"ECDH-ECDSA-AES256-SHA256", "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA256"}, + {"ECDH-ECDSA-AES256-SHA384", "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA384"}, + {"ECDH-ECDSA-AES256-SHA", "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA"}, + {"ECDH-ECDSA-CAMELLIA128-SHA256", "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"}, + {"ECDH-ECDSA-CAMELLIA128-SHA", "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA"}, + {"ECDH-ECDSA-CAMELLIA256-SHA256", "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA256"}, + {"ECDH-ECDSA-CAMELLIA256-SHA", "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA"}, + {"ECDH-ECDSA-DES-CBC3-SHA", "TLS-ECDH-ECDSA-WITH-3DES-EDE-CBC-SHA"}, + {"ECDH-ECDSA-DES-CBC-SHA", "TLS-ECDH-ECDSA-WITH-DES-CBC-SHA"}, + {"ECDH-ECDSA-RC4-SHA", "TLS-ECDH-ECDSA-WITH-RC4-128-SHA"}, + {"ECDHE-ECDSA-AES128-GCM-SHA256", "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256"}, + {"ECDHE-ECDSA-AES128-SHA256", "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256"}, + {"ECDHE-ECDSA-AES128-SHA384", "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA384"}, + {"ECDHE-ECDSA-AES128-SHA", "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA"}, + {"ECDHE-ECDSA-AES256-GCM-SHA384", "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384"}, + {"ECDHE-ECDSA-AES256-SHA256", "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA256"}, + {"ECDHE-ECDSA-AES256-SHA384", "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384"}, + {"ECDHE-ECDSA-AES256-SHA", "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA"}, + {"ECDHE-ECDSA-CAMELLIA128-SHA256", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"}, + {"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-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"}, + {"ECDHE-RSA-AES128-GCM-SHA256", "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256"}, + {"ECDHE-RSA-AES128-SHA256", "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256"}, + {"ECDHE-RSA-AES128-SHA384", "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA384"}, + {"ECDHE-RSA-AES128-SHA", "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA"}, + {"ECDHE-RSA-AES256-GCM-SHA384", "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384"}, + {"ECDHE-RSA-AES256-SHA256", "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA256"}, + {"ECDHE-RSA-AES256-SHA384", "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384"}, + {"ECDHE-RSA-AES256-SHA", "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA"}, + {"ECDHE-RSA-CAMELLIA128-SHA256", "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"}, + {"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-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"}, + {"ECDH-RSA-AES128-GCM-SHA256", "TLS-ECDH-RSA-WITH-AES-128-GCM-SHA256"}, + {"ECDH-RSA-AES128-SHA256", "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA256"}, + {"ECDH-RSA-AES128-SHA384", "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA384"}, + {"ECDH-RSA-AES128-SHA", "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA"}, + {"ECDH-RSA-AES256-GCM-SHA384", "TLS-ECDH-RSA-WITH-AES-256-GCM-SHA384"}, + {"ECDH-RSA-AES256-SHA256", "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA256"}, + {"ECDH-RSA-AES256-SHA384", "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384"}, + {"ECDH-RSA-AES256-SHA", "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA"}, + {"ECDH-RSA-CAMELLIA128-SHA256", "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA256"}, + {"ECDH-RSA-CAMELLIA128-SHA", "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA"}, + {"ECDH-RSA-CAMELLIA256-SHA256", "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA256"}, + {"ECDH-RSA-CAMELLIA256-SHA", "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA"}, + {"ECDH-RSA-DES-CBC3-SHA", "TLS-ECDH-RSA-WITH-3DES-EDE-CBC-SHA"}, + {"ECDH-RSA-DES-CBC-SHA", "TLS-ECDH-RSA-WITH-DES-CBC-SHA"}, + {"ECDH-RSA-RC4-SHA", "TLS-ECDH-RSA-WITH-RC4-128-SHA"}, + {"EDH-DSS-DES-CBC3-SHA", "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA"}, + {"EDH-DSS-DES-CBC-SHA", "TLS-DHE-DSS-WITH-DES-CBC-SHA"}, + {"EDH-RSA-DES-CBC3-SHA", "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA"}, + {"EDH-RSA-DES-CBC-SHA", "TLS-DHE-RSA-WITH-DES-CBC-SHA"}, + {"EXP-DES-CBC-SHA", "TLS-RSA-EXPORT-WITH-DES40-CBC-SHA"}, + {"EXP-EDH-DSS-DES-CBC-SHA", "TLS-DH-DSS-EXPORT-WITH-DES40-CBC-SHA"}, + {"EXP-EDH-RSA-DES-CBC-SHA", "TLS-DH-RSA-EXPORT-WITH-DES40-CBC-SHA"}, + {"EXP-RC2-CBC-MD5", "TLS-RSA-EXPORT-WITH-RC2-CBC-40-MD5"}, + {"EXP-RC4-MD5", "TLS-RSA-EXPORT-WITH-RC4-40-MD5"}, + {"NULL-MD5", "TLS-RSA-WITH-NULL-MD5"}, + {"NULL-SHA256", "TLS-RSA-WITH-NULL-SHA256"}, + {"NULL-SHA", "TLS-RSA-WITH-NULL-SHA"}, + {"PSK-3DES-EDE-CBC-SHA", "TLS-PSK-WITH-3DES-EDE-CBC-SHA"}, + {"PSK-AES128-CBC-SHA", "TLS-PSK-WITH-AES-128-CBC-SHA"}, + {"PSK-AES256-CBC-SHA", "TLS-PSK-WITH-AES-256-CBC-SHA"}, + {"PSK-RC4-SHA", "TLS-PSK-WITH-RC4-128-SHA"}, + {"RC4-MD5", "TLS-RSA-WITH-RC4-128-MD5"}, + {"RC4-SHA", "TLS-RSA-WITH-RC4-128-SHA"}, + {"SEED-SHA", "TLS-RSA-WITH-SEED-CBC-SHA"}, + {"SRP-DSS-3DES-EDE-CBC-SHA", "TLS-SRP-SHA-DSS-WITH-3DES-EDE-CBC-SHA"}, + {"SRP-DSS-AES-128-CBC-SHA", "TLS-SRP-SHA-DSS-WITH-AES-128-CBC-SHA"}, + {"SRP-DSS-AES-256-CBC-SHA", "TLS-SRP-SHA-DSS-WITH-AES-256-CBC-SHA"}, + {"SRP-RSA-3DES-EDE-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-3DES-EDE-CBC-SHA"}, + {"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 + {"DEFAULT", "DEFAULT"}, + {"ALL", "ALL"}, + {"HIGH", "HIGH"}, + {"MEDIUM", "MEDIUM"}, + {"LOW", "LOW"}, + {"ECDH", "ECDH"}, + {"ECDSA", "ECDSA"}, + {"EDH", "EDH"}, + {"EXP", "EXP"}, + {"RSA", "RSA"}, + {"SRP", "SRP"}, +#endif + {NULL, NULL} +}; + +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; + + while (pair->openssl_name != NULL) { + if ((strlen(pair->openssl_name) == len && 0 == memcmp (cipher_name, pair->openssl_name, len)) || + (strlen(pair->iana_name) == len && 0 == memcmp (cipher_name, pair->iana_name, len))) { + return pair; + } + pair++; + } + + // No entry found, return NULL + return NULL; +} /* * Max number of bytes we will add @@ -300,6 +449,27 @@ ssl_put_auth_challenge (const char *cr_str) #endif /* + * Parse a TLS version string, returning a TLS_VER_x constant. + * If version string is not recognized and extra == "or-highest", + * return tls_version_max(). + */ +int +tls_version_min_parse(const char *vstr, const char *extra) +{ + const int max_version = tls_version_max(); + if (!strcmp(vstr, "1.0") && TLS_VER_1_0 <= max_version) + return TLS_VER_1_0; + else if (!strcmp(vstr, "1.1") && TLS_VER_1_1 <= max_version) + return TLS_VER_1_1; + else if (!strcmp(vstr, "1.2") && TLS_VER_1_2 <= max_version) + return TLS_VER_1_2; + else if (extra && !strcmp(extra, "or-highest")) + return max_version; + else + return TLS_VER_BAD; +} + +/* * Initialize SSL context. * All files are in PEM format. */ @@ -348,12 +518,8 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) #ifdef MANAGMENT_EXTERNAL_KEY else if ((options->management_flags & MF_EXTERNAL_KEY) && options->cert_file) { - openvpn_x509_cert_t *my_cert = NULL; - tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline, - &my_cert); - tls_ctx_use_external_private_key(new_ctx, my_cert); - - tls_ctx_free_cert_file(my_cert); + tls_ctx_use_external_private_key(new_ctx, options->cert_file, + options->cert_file_inline); } #endif else @@ -361,7 +527,7 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) /* Load Certificate */ if (options->cert_file) { - tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline, NULL); + tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline); } /* Load Private Key */ @@ -385,11 +551,12 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_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 */ - if (options->cipher_list) - { - tls_ctx_restrict_ciphers(new_ctx, options->cipher_list); - } + tls_ctx_restrict_ciphers(new_ctx, options->cipher_list); #ifdef ENABLE_CRYPTO_POLARSSL /* Personalise the random by mixing in the certificate */ @@ -670,6 +837,25 @@ static inline void tls_session_set_self_referential_pointers (struct tls_session session->tls_auth.packet_id = &session->tls_auth_pid; } +/** + * 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 +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 + ); +} + /** @addtogroup control_processor * @{ */ @@ -959,6 +1145,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 @@ -1175,7 +1363,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]; @@ -1201,7 +1389,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); @@ -1585,7 +1772,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)); @@ -1628,7 +1814,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session) bool ret = false; #ifdef ENABLE_PUSH_PEER_INFO - if (session->opt->push_peer_info) /* write peer info */ + if (session->opt->push_peer_info_detail > 0) { struct env_set *es = session->opt->es; struct env_item *e; @@ -1651,30 +1837,34 @@ push_peer_info(struct buffer *buf, struct tls_session *session) #elif defined(TARGET_FREEBSD) buf_printf (&out, "IV_PLAT=freebsd\n"); #elif defined(TARGET_ANDROID) - buf_printf(&out, "IV_PLAT=android\n"); + buf_printf (&out, "IV_PLAT=android\n"); #elif defined(WIN32) buf_printf (&out, "IV_PLAT=win\n"); #endif - /* push mac addr */ - { - struct route_gateway_info rgi; - get_default_gateway (&rgi); - if (rgi.flags & RGI_HWADDR_DEFINED) - buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc)); - } - - /* push LZO status */ -#ifdef ENABLE_LZO_STUB - buf_printf (&out, "IV_LZO_STUB=1\n"); + /* push compression status */ +#ifdef USE_COMP + comp_generate_peer_info_string(&session->opt->comp_options, &out); #endif - /* push env vars that begin with UV_ */ + if (session->opt->push_peer_info_detail >= 2) + { + /* push mac addr */ + struct route_gateway_info rgi; + get_default_gateway (&rgi); + 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() ); + } + + /* push env vars that begin with UV_ and IV_GUI_VER */ for (e=es->list; e != NULL; e=e->next) { if (e->string) { - if (!strncmp(e->string, "UV_", 3) && buf_safe(&out, strlen(e->string)+1)) + if (((strncmp(e->string, "UV_", 3)==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); } } @@ -1699,7 +1889,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)); @@ -1783,7 +1972,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); @@ -1842,13 +2030,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); @@ -1884,15 +2072,25 @@ 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); - 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); +#endif + if (tls_session_user_pass_enabled(session)) + { + /* Perform username/password authentication */ if (!username_status || !password_status) { CLEAR (*up); @@ -1903,14 +2101,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 { @@ -1924,6 +2115,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) { diff --git a/app/openvpn/src/openvpn/ssl.h b/app/openvpn/src/openvpn/ssl.h index cd7cae2e..aaecff43 100644 --- a/app/openvpn/src/openvpn/ssl.h +++ b/app/openvpn/src/openvpn/ssl.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 */ diff --git a/app/openvpn/src/openvpn/ssl_backend.h b/app/openvpn/src/openvpn/ssl_backend.h index 203a4d26..bfd15496 100644 --- a/app/openvpn/src/openvpn/ssl_backend.h +++ b/app/openvpn/src/openvpn/ssl_backend.h @@ -36,12 +36,32 @@ #ifdef ENABLE_CRYPTO_OPENSSL #include "ssl_openssl.h" #include "ssl_verify_openssl.h" +#define SSLAPI SSLAPI_OPENSSL #endif #ifdef ENABLE_CRYPTO_POLARSSL #include "ssl_polarssl.h" #include "ssl_verify_polarssl.h" +#define SSLAPI SSLAPI_POLARSSL #endif +/* Ensure that SSLAPI got a sane value if SSL is disabled or unknown */ +#ifndef SSLAPI +#define SSLAPI SSLAPI_NONE +#endif + +/** + * prototype for struct tls_session from ssl_common.h + */ +struct tls_session; + +/** + * Get a tls_cipher_name_pair containing OpenSSL and IANA names for supplied TLS cipher name + * + * @param cipher_name Can be either OpenSSL or IANA cipher name + * @return tls_cipher_name_pair* if found, NULL otherwise + */ +typedef struct { const char *openssl_name; const char *iana_name; } tls_cipher_name_pair; +const tls_cipher_name_pair *tls_get_cipher_name_pair (const char *cipher_name, size_t len); /* * @@ -81,6 +101,29 @@ void tls_free_lib(); void tls_clear_error(); /** + * Parse a TLS version specifier + * + * @param vstr The TLS version string + * @param extra An optional extra parameter, may be NULL + * + * @return One of the TLS_VER_x constants or TLS_VER_BAD + * if a parse error should be flagged. + */ +#define TLS_VER_BAD -1 +#define TLS_VER_1_0 0 /* default */ +#define TLS_VER_1_1 1 +#define TLS_VER_1_2 2 +int tls_version_min_parse(const char *vstr, const char *extra); + +/** + * Return the maximum TLS version (as a TLS_VER_x constant) + * supported by current SSL implementation + * + * @return One of the TLS_VER_x constants (but not TLS_VER_BAD). + */ +int tls_version_max(void); + +/** * Initialise a library-specific TLS context for a server. * * @param ctx TLS context to initialise @@ -124,8 +167,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); @@ -142,6 +186,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. * @@ -172,27 +226,13 @@ void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert * Load certificate file into the given TLS context. If the given certificate * file contains a certificate chain, load the whole chain. * - * If the x509 parameter is not NULL, the certificate will be returned in it. - * * @param ctx TLS context to use * @param cert_file The file name to load the certificate from, or * "[[INLINE]]" in the case of inline files. * @param cert_file_inline A string containing the certificate - * @param x509 An optional certificate, if x509 is NULL, - * do nothing, if x509 is not NULL, *x509 will be - * allocated and filled with the loaded certificate. - * *x509 must be NULL. */ void tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline, openvpn_x509_cert_t **x509 - ); - -/** - * Free the given certificate - * - * @param x509 certificate to free - */ -void tls_ctx_free_cert_file (openvpn_x509_cert_t *x509); + const char *cert_file_inline); /** * Load private key file into the given TLS context. @@ -212,17 +252,19 @@ int tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, #ifdef MANAGMENT_EXTERNAL_KEY /** - * Tell the management interface to load the external private key matching - * the given certificate. + * Tell the management interface to load the given certificate and the external + * private key matching the given certificate. * * @param ctx TLS context to use - * @param cert The certificate file to load the private key for + * @param cert_file The file name to load the certificate from, or * "[[INLINE]]" in the case of inline files. + * @param cert_file_inline A string containing the certificate * * @return 1 if an error occurred, 0 if parsing was * successful. */ -int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, openvpn_x509_cert_t *cert); +int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline); #endif @@ -282,7 +324,7 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx); * @param session The session associated with the given key_state */ void key_state_ssl_init(struct key_state_ssl *ks_ssl, - const struct tls_root_ctx *ssl_ctx, bool is_server, void *session); + const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session); /** * Free the SSL channel part of the given key state. @@ -423,8 +465,15 @@ void print_details (struct key_state_ssl * ks_ssl, const char *prefix); /* * Show the TLS ciphers that are available for us to use in the OpenSSL * library. + * + * @param - list of allowed TLS cipher, or NULL. */ -void show_available_tls_ciphers (); +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 @@ -432,4 +481,10 @@ void show_available_tls_ciphers (); */ void get_highest_preference_tls_cipher (char *buf, int size); +/** + * return a pointer to a static memory area containing the + * name and version number of the SSL library in use + */ +const char * get_ssl_library_version(void); + #endif /* SSL_BACKEND_H_ */ diff --git a/app/openvpn/src/openvpn/ssl_common.h b/app/openvpn/src/openvpn/ssl_common.h index cb259a96..04ba7892 100644 --- a/app/openvpn/src/openvpn/ssl_common.h +++ b/app/openvpn/src/openvpn/ssl_common.h @@ -233,7 +233,7 @@ struct tls_options bool disable_occ; #endif #ifdef ENABLE_PUSH_PEER_INFO - bool push_peer_info; + int push_peer_info_detail; #endif int transition_window; int handshake_window; @@ -245,7 +245,8 @@ struct tls_options /* cert verification parms */ const char *verify_command; const char *verify_export_cert; - const char *verify_x509name; + int verify_x509_type; + const char *verify_x509_name; const char *crl_file; int ns_cert_type; unsigned remote_cert_ku[MAX_PARMS]; @@ -284,12 +285,19 @@ struct tls_options struct env_set *es; const struct plugin_list *plugins; - /* configuration file boolean options */ + /* 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_OPT_VERIFY (1<<4) # define SSLF_CRL_VERIFY_DIR (1<<5) +# define SSLF_TLS_VERSION_SHIFT 6 +# define SSLF_TLS_VERSION_MASK 0xF /* (uses bit positions 6 to 9) */ unsigned int ssl_flags; #ifdef MANAGEMENT_DEF_AUTH @@ -475,14 +483,16 @@ 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 /* diff --git a/app/openvpn/src/openvpn/ssl_openssl.c b/app/openvpn/src/openvpn/ssl_openssl.c index a727b605..c9d2d26d 100644 --- a/app/openvpn/src/openvpn/ssl_openssl.c +++ b/app/openvpn/src/openvpn/ssl_openssl.c @@ -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,33 +96,15 @@ 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) - { - msg (D_HANDSHAKE, "Generating temp (%d bit) RSA key", keylength); - rsa_tmp = RSA_generate_key (keylength, RSA_F4, NULL, NULL); - } - return (rsa_tmp); -} - void tls_ctx_server_new(struct tls_root_ctx *ctx) { ASSERT(NULL != ctx); - ctx->ctx = SSL_CTX_new (TLSv1_server_method ()); + ctx->ctx = SSL_CTX_new (SSLv23_server_method ()); if (ctx->ctx == NULL) - msg (M_SSLERR, "SSL_CTX_new TLSv1_server_method"); - - SSL_CTX_set_tmp_rsa_callback (ctx->ctx, tmp_rsa_cb); + msg (M_SSLERR, "SSL_CTX_new SSLv23_server_method"); } void @@ -127,10 +112,10 @@ tls_ctx_client_new(struct tls_root_ctx *ctx) { ASSERT(NULL != ctx); - ctx->ctx = SSL_CTX_new (TLSv1_client_method ()); + ctx->ctx = SSL_CTX_new (SSLv23_client_method ()); if (ctx->ctx == NULL) - msg (M_SSLERR, "SSL_CTX_new TLSv1_client_method"); + msg (M_SSLERR, "SSL_CTX_new SSLv23_client_method"); } void @@ -174,13 +159,49 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret) } } +/* + * Return maximum TLS version supported by local OpenSSL library. + * Assume that presence of SSL_OP_NO_TLSvX macro indicates that + * TLSvX is supported. + */ +int +tls_version_max(void) +{ +#if defined(SSL_OP_NO_TLSv1_2) + return TLS_VER_1_2; +#elif defined(SSL_OP_NO_TLSv1_1) + return TLS_VER_1_1; +#else + return TLS_VER_1_0; +#endif +} + void tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) { ASSERT(NULL != ctx); + /* process SSL options including minimum TLS version we will accept from peer */ + { + long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + const int tls_version_min = (ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK; + if (tls_version_min > TLS_VER_1_0) + sslopt |= SSL_OP_NO_TLSv1; +#ifdef SSL_OP_NO_TLSv1_1 + if (tls_version_min > TLS_VER_1_1) + sslopt |= SSL_OP_NO_TLSv1_1; +#endif +#ifdef SSL_OP_NO_TLSv1_2 + if (tls_version_min > TLS_VER_1_2) + sslopt |= SSL_OP_NO_TLSv1_2; +#endif + SSL_CTX_set_options (ctx->ctx, sslopt); + } + +#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_options (ctx->ctx, SSL_OP_SINGLE_DH_USE); SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback); /* Require peer certificate verification */ @@ -202,10 +223,80 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) { + if (ciphers == NULL) + { + /* Use sane default (disable export, and unsupported cipher modes) */ + if(!SSL_CTX_set_cipher_list(ctx->ctx, "DEFAULT:!EXP:!PSK:!SRP")) + msg(M_SSLERR, "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; + size_t current_cipher_len; + + const tls_cipher_name_pair *cipher_pair; + + char openssl_ciphers[4096]; + size_t openssl_ciphers_len = 0; + openssl_ciphers[0] = '\0'; + ASSERT(NULL != ctx); - if(!SSL_CTX_set_cipher_list(ctx->ctx, ciphers)) - msg(M_SSLERR, "Failed to set restricted TLS cipher list: %s", ciphers); + // Translate IANA cipher suite names to OpenSSL names + begin_of_cipher = end_of_cipher = 0; + for (; begin_of_cipher < strlen(ciphers); begin_of_cipher = end_of_cipher) { + end_of_cipher += strcspn(&ciphers[begin_of_cipher], ":"); + cipher_pair = tls_get_cipher_name_pair(&ciphers[begin_of_cipher], end_of_cipher - begin_of_cipher); + + if (NULL == cipher_pair) + { + // No translation found, use original + current_cipher = &ciphers[begin_of_cipher]; + current_cipher_len = end_of_cipher - begin_of_cipher; + + // 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'", + constrain_int(current_cipher_len, 0, 256), current_cipher); + } + else + { + // Use OpenSSL name + current_cipher = cipher_pair->openssl_name; + 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)) + { + // 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); + } + } + + // Make sure new cipher name fits in cipher string + if (((sizeof(openssl_ciphers)-1) - openssl_ciphers_len) < current_cipher_len) { + msg(M_SSLERR, "Failed to set restricted TLS cipher list, too long (>%d).", (int)sizeof(openssl_ciphers)-1); + } + + // Concatenate cipher name to OpenSSL cipher string + memcpy(&openssl_ciphers[openssl_ciphers_len], current_cipher, current_cipher_len); + openssl_ciphers_len += current_cipher_len; + openssl_ciphers[openssl_ciphers_len] = ':'; + openssl_ciphers_len++; + + end_of_cipher++; + } + + if (openssl_ciphers_len > 0) + openssl_ciphers[openssl_ciphers_len-1] = '\0'; + + // Set OpenSSL cipher list + if(!SSL_CTX_set_cipher_list(ctx->ctx, openssl_ciphers)) + msg(M_SSLERR, "Failed to set restricted TLS cipher list: %s", openssl_ciphers); } void @@ -244,6 +335,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)) + msg (M_SSLERR, "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, @@ -318,16 +481,34 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, /* Set Certificate Verification chain */ if (load_ca_file) { + /* Add CAs from PKCS12 to the cert store and mark them as trusted. + * They're also used to fill in the chain of intermediate certs as + * necessary. + */ if (ca && sk_X509_num(ca)) { for (i = 0; i < sk_X509_num(ca); i++) { - if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) + if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)"); if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i))) msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)"); } } + } else { + /* If trusted CA certs were loaded from a PEM file, and we ignore the + * ones in PKCS12, do load PKCS12-provided certs to the client extra + * certs chain just in case they include intermediate CAs needed to + * prove my identity to the other end. This does not make them trusted. + */ + if (ca && sk_X509_num(ca)) + { + for (i = 0; i < sk_X509_num(ca); i++) + { + if (!SSL_CTX_add_extra_chain_cert(ctx->ctx,sk_X509_value(ca, i))) + msg (M_SSLERR, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)"); + } + } } return 0; } @@ -361,9 +542,10 @@ tls_ctx_add_extra_certs (struct tls_root_ctx *ctx, BIO *bio) } } -void -tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline, X509 **x509 +/* Like tls_ctx_load_cert, but returns a copy of the certificate in **X509 */ +static void +tls_ctx_load_cert_file_and_copy (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline, X509 **x509 ) { BIO *in = NULL; @@ -418,6 +600,13 @@ end: } void +tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, + const char *cert_file_inline) +{ + tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, NULL); +} + +void tls_ctx_free_cert_file (X509 *x509) { X509_free(x509); @@ -428,7 +617,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; @@ -554,13 +742,18 @@ rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i } int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert) +tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline) { RSA *rsa = NULL; RSA *pub_rsa; RSA_METHOD *rsa_meth; + X509 *cert = NULL; ASSERT (NULL != ctx); + + tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, &cert); + ASSERT (NULL != cert); /* allocate custom RSA method object */ @@ -597,10 +790,13 @@ tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert) if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa)) goto err; + X509_free(cert); RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ return 1; err: + if (cert) + X509_free(cert); if (rsa) RSA_free(rsa); else @@ -632,7 +828,7 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, X509_STORE *store = NULL; X509_NAME *xn = NULL; BIO *in = NULL; - int i, added = 0; + int i, added = 0, prev = 0; ASSERT(NULL != ctx); @@ -659,6 +855,11 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, if (info->crl) X509_STORE_add_crl (store, info->crl); + if (tls_server && !info->x509) + { + msg (M_SSLERR, "X509 name was missing in TLS mode"); + } + if (info->x509) { X509_STORE_add_cert (store, info->x509); @@ -688,6 +889,15 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, sk_X509_NAME_push (cert_names, xn); } } + + if (tls_server) { + int cnum = sk_X509_NAME_num (cert_names); + if (cnum != (prev + 1)) { + msg (M_WARN, "Cannot load CA certificate file %s (entry %d did not validate)", np(ca_file), added); + } + prev = cnum; + } + } sk_X509_INFO_pop_free (info_stack, X509_INFO_free); } @@ -695,8 +905,15 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, if (tls_server) SSL_CTX_set_client_CA_list (ctx->ctx, cert_names); - if (!added || (tls_server && sk_X509_NAME_num (cert_names) != added)) - msg (M_SSLERR, "Cannot load CA certificate file %s", np(ca_file)); + if (!added) + msg (M_SSLERR, "Cannot load CA certificate file %s (no entries were read)", np(ca_file)); + + if (tls_server) { + int cnum = sk_X509_NAME_num (cert_names); + if (cnum != added) + msg (M_SSLERR, "Cannot load CA certificate file %s (only %d of %d entries were valid X509 names)", np(ca_file), cnum, added); + } + if (in) BIO_free (in); } @@ -709,11 +926,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 msg(M_SSLERR, "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 } } @@ -953,7 +1166,7 @@ bio_read (BIO *bio, struct buffer *buf, int maxlen, const char *desc) } void -key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, void *session) +key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) { ASSERT(NULL != ssl_ctx); ASSERT(ks_ssl); @@ -1126,29 +1339,86 @@ print_details (struct key_state_ssl * ks_ssl, const char *prefix) } void -show_available_tls_ciphers () +show_available_tls_ciphers (const char *cipher_list) { - SSL_CTX *ctx; + struct tls_root_ctx tls_ctx; SSL *ssl; const char *cipher_name; + const tls_cipher_name_pair *pair; int priority = 0; - ctx = SSL_CTX_new (TLSv1_method ()); - if (!ctx) + tls_ctx.ctx = SSL_CTX_new (SSLv23_method ()); + if (!tls_ctx.ctx) msg (M_SSLERR, "Cannot create SSL_CTX object"); - ssl = SSL_new (ctx); + ssl = SSL_new (tls_ctx.ctx); if (!ssl) msg (M_SSLERR, "Cannot create SSL object"); + tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); + printf ("Available TLS Ciphers,\n"); printf ("listed in order of preference:\n\n"); while ((cipher_name = SSL_get_cipher_list (ssl, priority++))) - printf ("%s\n", cipher_name); + { + pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name)); + + if (NULL == pair) { + // No translation found, print warning + printf ("%s (No IANA name known to OpenVPN, use OpenSSL name.)\n", cipher_name); + } else { + printf ("%s\n", pair->iana_name); + } + + } printf ("\n"); SSL_free (ssl); - SSL_CTX_free (ctx); + 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); + + curves = OPENSSL_malloc((int)(sizeof(EC_builtin_curve) * crv_len)); + + if (curves == NULL) + msg (M_SSLERR, "Cannot create EC_builtin_curve object"); + else + { + 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 + { + msg (M_SSLERR, "Cannot get list of builtin curves"); + } + OPENSSL_free(curves); + } +#else + msg (M_WARN, "Your OpenSSL library was built without elliptic curve support. " + "No curves available."); +#endif } void @@ -1158,7 +1428,7 @@ get_highest_preference_tls_cipher (char *buf, int size) SSL *ssl; const char *cipher_name; - ctx = SSL_CTX_new (TLSv1_method ()); + ctx = SSL_CTX_new (SSLv23_method ()); if (!ctx) msg (M_SSLERR, "Cannot create SSL_CTX object"); ssl = SSL_new (ctx); @@ -1172,4 +1442,10 @@ get_highest_preference_tls_cipher (char *buf, int size) SSL_CTX_free (ctx); } +const char * +get_ssl_library_version(void) +{ + return SSLeay_version(SSLEAY_VERSION); +} + #endif /* defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL) */ diff --git a/app/openvpn/src/openvpn/ssl_polarssl.c b/app/openvpn/src/openvpn/ssl_polarssl.c index 12318b33..ddccf1d9 100644 --- a/app/openvpn/src/openvpn/ssl_polarssl.c +++ b/app/openvpn/src/openvpn/ssl_polarssl.c @@ -7,6 +7,7 @@ * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2006-2010, Brainspark B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -44,11 +45,12 @@ #include "manage.h" #include "ssl_common.h" -#include <polarssl/sha2.h> #include <polarssl/havege.h> #include "ssl_verify_polarssl.h" +#include <polarssl/error.h> #include <polarssl/pem.h> +#include <polarssl/sha256.h> void tls_init_lib() @@ -65,23 +67,6 @@ tls_clear_error() { } -static int default_ciphersuites[] = -{ - SSL_EDH_RSA_AES_256_SHA, - SSL_EDH_RSA_CAMELLIA_256_SHA, - SSL_EDH_RSA_AES_128_SHA, - SSL_EDH_RSA_CAMELLIA_128_SHA, - SSL_EDH_RSA_DES_168_SHA, - SSL_RSA_AES_256_SHA, - SSL_RSA_CAMELLIA_256_SHA, - SSL_RSA_AES_128_SHA, - SSL_RSA_CAMELLIA_128_SHA, - SSL_RSA_DES_168_SHA, - SSL_RSA_RC4_128_SHA, - SSL_RSA_RC4_128_MD5, - 0 -}; - void tls_ctx_server_new(struct tls_root_ctx *ctx) { @@ -89,10 +74,10 @@ tls_ctx_server_new(struct tls_root_ctx *ctx) CLEAR(*ctx); ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context); - ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context); + ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context); - ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert); - ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert); + ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt); + ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt); ctx->endpoint = SSL_IS_SERVER; @@ -106,10 +91,10 @@ tls_ctx_client_new(struct tls_root_ctx *ctx) CLEAR(*ctx); ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context); - ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context); + ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context); - ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert); - ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert); + ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt); + ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt); ctx->endpoint = SSL_IS_CLIENT; ctx->initialised = true; @@ -120,13 +105,13 @@ tls_ctx_free(struct tls_root_ctx *ctx) { if (ctx) { - rsa_free(ctx->priv_key); + pk_free(ctx->priv_key); free(ctx->priv_key); - x509_free(ctx->ca_chain); + x509_crt_free(ctx->ca_chain); free(ctx->ca_chain); - x509_free(ctx->crt_chain); + x509_crt_free(ctx->crt_chain); free(ctx->crt_chain); dhm_free(ctx->dhm_ctx); @@ -138,6 +123,10 @@ tls_ctx_free(struct tls_root_ctx *ctx) free(ctx->priv_key_pkcs11); } #endif +#if defined(MANAGMENT_EXTERNAL_KEY) + if (ctx->external_key != NULL) + free(ctx->external_key); +#endif if (ctx->allowed_ciphers) free(ctx->allowed_ciphers); @@ -161,12 +150,36 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) { } +static const char * +tls_translate_cipher_name (const char * cipher_name) { + const tls_cipher_name_pair * pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name)); + + if (NULL == pair) + { + // No translation found, return original + return cipher_name; + } + + if (0 != strcmp(cipher_name, pair->iana_name)) + { + // Deprecated name found, notify user + msg(M_WARN, "Deprecated cipher suite name '%s', please use IANA name '%s'", pair->openssl_name, pair->iana_name); + } + + return pair->iana_name; +} + void 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); @@ -186,7 +199,8 @@ 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 (token); + ctx->allowed_ciphers[i] = ssl_get_ciphersuite_id ( + tls_translate_cipher_name (token)); if (0 != ctx->allowed_ciphers[i]) i++; token = strtok (NULL, ":"); @@ -201,12 +215,12 @@ tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file, { if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_file_inline) { - if (0 != x509parse_dhm(ctx->dhm_ctx, dh_file_inline, strlen(dh_file_inline))) + if (0 != dhm_parse_dhm(ctx->dhm_ctx, dh_file_inline, strlen(dh_file_inline))) msg (M_FATAL, "Cannot read inline DH parameters"); } else { - if (0 != x509parse_dhmfile(ctx->dhm_ctx, dh_file)) + if (0 != dhm_parse_dhmfile(ctx->dhm_ctx, dh_file)) msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file); } @@ -214,6 +228,15 @@ else (counter_type) 8 * 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: PolarSSL builds do not support specifying an ECDH " + "curve, using default curves."); +} + int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, const char *pkcs12_file_inline, @@ -234,37 +257,29 @@ tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert) void tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline, - openvpn_x509_cert_t **x509 + const char *cert_file_inline ) { ASSERT(NULL != ctx); - if (NULL != x509) - ASSERT(NULL == *x509); if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_file_inline) { - if (0 != x509parse_crt(ctx->crt_chain, cert_file_inline, + if (0 != x509_crt_parse(ctx->crt_chain, cert_file_inline, strlen(cert_file_inline))) msg (M_FATAL, "Cannot load inline certificate file"); } else { - if (0 != x509parse_crtfile(ctx->crt_chain, cert_file)) - msg (M_FATAL, "Cannot load certificate file %s", cert_file); - } - if (x509) - { - *x509 = ctx->crt_chain; + int retval = x509_crt_parse_file(ctx->crt_chain, cert_file); + if (0 != retval) + { + char errstr[128]; + polarssl_strerror(retval, errstr, sizeof(errstr)); + msg (M_FATAL, "Cannot load certificate file %s (%s)", cert_file, errstr); + } } } -void -tls_ctx_free_cert_file (openvpn_x509_cert_t *x509) -{ - x509_free(x509); -} - int tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, const char *priv_key_file_inline @@ -275,26 +290,27 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline) { - status = x509parse_key(ctx->priv_key, + status = pk_parse_key(ctx->priv_key, priv_key_file_inline, strlen(priv_key_file_inline), NULL, 0); + if (POLARSSL_ERR_PEM_PASSWORD_REQUIRED == status) { char passbuf[512] = {0}; pem_password_callback(passbuf, 512, 0, NULL); - status = x509parse_key(ctx->priv_key, + status = pk_parse_key(ctx->priv_key, priv_key_file_inline, strlen(priv_key_file_inline), - passbuf, strlen(passbuf)); + (unsigned char *) passbuf, strlen(passbuf)); } } else { - status = x509parse_keyfile(ctx->priv_key, priv_key_file, NULL); + status = pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL); if (POLARSSL_ERR_PEM_PASSWORD_REQUIRED == status) { char passbuf[512] = {0}; pem_password_callback(passbuf, 512, 0, NULL); - status = x509parse_keyfile(ctx->priv_key, priv_key_file, passbuf); + status = pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf); } } if (0 != status) @@ -319,13 +335,161 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, #ifdef MANAGMENT_EXTERNAL_KEY + +struct external_context { + size_t signature_length; +}; + int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, openvpn_x509_cert_t *cert) +tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline) { - msg(M_FATAL, "Use of management external keys not yet supported for PolarSSL."); - return false; + ASSERT(NULL != ctx); + + tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline); + + if (ctx->crt_chain == NULL) + return 0; + + /* Most of the initialization happens in key_state_ssl_init() */ + ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context); + ctx->external_key->signature_length = pk_get_len(&ctx->crt_chain->pk); + + return 1; } +/** + * external_pkcs1_sign implements a PolarSSL 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. + * @param f_rng (Unused) + * @param p_rng (Unused) + * @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). + * @param hash The digest ('hash') to sign. Should have a size + * matching the length of md_alg (if != POLARSSL_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. + */ +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, + unsigned char *sig ) +{ + struct external_context * const ctx = ctx_voidptr; + char *in_b64 = NULL; + char *out_b64 = NULL; + int rv; + unsigned char *p = sig; + size_t asn_len = 0, oid_size = 0, sig_len = 0; + const char *oid = NULL; + + if( NULL == ctx ) + return POLARSSL_ERR_RSA_BAD_INPUT_DATA; + + if( RSA_PRIVATE != mode ) + return POLARSSL_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+. + */ + if( md_alg != POLARSSL_MD_NONE ) + { + const md_info_t *md_info = md_info_from_type( md_alg ); + if( md_info == NULL ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + if( oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) + return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = 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; + + if( md_alg != POLARSSL_MD_NONE ) + { + /* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ + *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x08 + oid_size + hashlen ); + *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x04 + oid_size ); + *p++ = ASN1_OID; + *p++ = oid_size & 0xFF; + memcpy( p, oid, oid_size ); + p += oid_size; + *p++ = ASN1_NULL; + *p++ = 0x00; + *p++ = ASN1_OCTET_STRING; + *p++ = hashlen; + + /* Determine added ASN length */ + asn_len = p - sig; + } + + /* Copy the hash to be signed */ + memcpy( p, hash, hashlen ); + + /* convert 'from' to base64 */ + if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0) + { + rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA; + goto done; + } + + /* call MI for signature */ + if (management) + out_b64 = management_query_rsa_sig (management, in_b64); + if (!out_b64) + { + rv = POLARSSL_ERR_RSA_PRIVATE_FAILED; + goto done; + } + + /* decode base64 signature to binary and verify length */ + if ( openvpn_base64_decode (out_b64, sig, ctx->signature_length) != + ctx->signature_length ) + { + rv = POLARSSL_ERR_RSA_PRIVATE_FAILED; + goto done; + } + + rv = 0; + +done: + if (in_b64) + free (in_b64); + if (out_b64) + free (out_b64); + return rv; +} + +static inline size_t external_key_len(void *vctx) +{ + struct external_context * const ctx = vctx; + + return ctx->signature_length; +} #endif void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, @@ -338,14 +502,20 @@ void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline) { - if (0 != x509parse_crt(ctx->ca_chain, ca_file_inline, strlen(ca_file_inline))) + if (0 != x509_crt_parse(ctx->ca_chain, (unsigned char *) ca_file_inline, + strlen(ca_file_inline))) msg (M_FATAL, "Cannot load inline CA certificates"); } else { /* Load CA file for verifying peer supplied certificate */ - if (0 != x509parse_crtfile(ctx->ca_chain, ca_file)) - msg (M_FATAL, "Cannot load CA certificate file %s", ca_file); + int retval = x509_crt_parse_file(ctx->ca_chain, ca_file); + if (0 != retval) + { + char errstr[128]; + polarssl_strerror(retval, errstr, sizeof(errstr)); + msg (M_FATAL, "Cannot load CA certificate file %s (%s)", ca_file, errstr); + } } } @@ -358,13 +528,14 @@ tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline) { - if (0 != x509parse_crt(ctx->crt_chain, extra_certs_file_inline, + if (0 != x509_crt_parse(ctx->crt_chain, + (unsigned char *) extra_certs_file_inline, strlen(extra_certs_file_inline))) msg (M_FATAL, "Cannot load inline extra-certs file"); } else { - if (0 != x509parse_crtfile(ctx->crt_chain, extra_certs_file)) + if (0 != x509_crt_parse_file(ctx->crt_chain, extra_certs_file)) msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file); } } @@ -482,14 +653,14 @@ static void my_debug( void *ctx, int level, const char *str ) void tls_ctx_personalise_random(struct tls_root_ctx *ctx) { static char old_sha256_hash[32] = {0}; - char sha256_hash[32] = {0}; + unsigned char sha256_hash[32] = {0}; ctr_drbg_context *cd_ctx = rand_ctx_get(); if (NULL != ctx->crt_chain) { - x509_cert *cert = ctx->crt_chain; + x509_crt *cert = ctx->crt_chain; - sha2(cert->tbs.p, cert->tbs.len, sha256_hash, false); + 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); @@ -498,8 +669,20 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx) } } +int +tls_version_max(void) +{ +#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3) + return TLS_VER_1_2; +#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2) + return TLS_VER_1_1; +#else + return TLS_VER_1_0; +#endif +} + void key_state_ssl_init(struct key_state_ssl *ks_ssl, - const struct tls_root_ctx *ssl_ctx, bool is_server, void *session) + const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) { ASSERT(NULL != ssl_ctx); ASSERT(ks_ssl); @@ -514,36 +697,79 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, ssl_set_rng (ks_ssl->ctx, ctr_drbg_random, rand_ctx_get()); - ALLOC_OBJ_CLEAR (ks_ssl->ssn, ssl_session); - ssl_set_session (ks_ssl->ctx, 0, 0, ks_ssl->ssn ); if (ssl_ctx->allowed_ciphers) ssl_set_ciphersuites (ks_ssl->ctx, ssl_ctx->allowed_ciphers); - else - ssl_set_ciphersuites (ks_ssl->ctx, default_ciphersuites); /* Initialise authentication information */ if (is_server) ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx ); #if defined(ENABLE_PKCS11) if (ssl_ctx->priv_key_pkcs11 != NULL) - ssl_set_own_cert_pkcs11( ks_ssl->ctx, ssl_ctx->crt_chain, - ssl_ctx->priv_key_pkcs11 ); + ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain, + ssl_ctx->priv_key_pkcs11, ssl_pkcs11_decrypt, ssl_pkcs11_sign, + ssl_pkcs11_key_len ); + else +#endif +#if defined(MANAGMENT_EXTERNAL_KEY) + if (ssl_ctx->external_key != NULL) + ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain, + ssl_ctx->external_key, NULL, external_pkcs1_sign, + external_key_len ); else #endif ssl_set_own_cert( ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key ); /* Initialise SSL verification */ - ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED); - ssl_set_verify (ks_ssl->ctx, verify_callback, session); +#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); + } + /* TODO: PolarSSL does not currently support sending the CA chain to the client */ ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL ); + /* Initialize minimum TLS version */ + { + const int tls_version_min = (session->opt->ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK; + int polar_major; + int polar_minor; + switch (tls_version_min) + { + case TLS_VER_1_0: + default: + polar_major = SSL_MAJOR_VERSION_3; + polar_minor = SSL_MINOR_VERSION_1; + break; +#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2) + case TLS_VER_1_1: + polar_major = SSL_MAJOR_VERSION_3; + polar_minor = SSL_MINOR_VERSION_2; + break; +#endif +#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3) + case TLS_VER_1_2: + polar_major = SSL_MAJOR_VERSION_3; + polar_minor = SSL_MINOR_VERSION_3; + break; +#endif + } + ssl_set_min_version(ks_ssl->ctx, polar_major, polar_minor); + } + /* Initialise BIOs */ ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer); ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer); ssl_set_bio (ks_ssl->ctx, endless_buf_read, ks_ssl->ct_in, endless_buf_write, ks_ssl->ct_out); - } } @@ -556,8 +782,6 @@ key_state_ssl_free(struct key_state_ssl *ks_ssl) ssl_free(ks_ssl->ctx); free(ks_ssl->ctx); } - if (ks_ssl->ssn) - free(ks_ssl->ssn); if (ks_ssl->ct_in) { buf_free_entries(ks_ssl->ct_in); free(ks_ssl->ct_in); @@ -666,6 +890,7 @@ key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf, { int retval = 0; int len = 0; + char error_message[1024]; perf_push (PERF_BIO_READ_CIPHERTEXT); @@ -691,7 +916,8 @@ key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf, perf_pop (); if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) return 0; - msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error"); + error_strerror(retval, error_message, sizeof(error_message)); + msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_ciphertext error: %d %s", retval, error_message); buf->len = 0; return -1; } @@ -763,6 +989,7 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf, { int retval = 0; int len = 0; + char error_message[1024]; perf_push (PERF_BIO_READ_PLAINTEXT); @@ -787,7 +1014,8 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf, { if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) return 0; - msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error"); + error_strerror(retval, error_message, sizeof(error_message)); + msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error: %d %s", retval, error_message); buf->len = 0; perf_pop (); return -1; @@ -818,7 +1046,7 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf, void print_details (struct key_state_ssl * ks_ssl, const char *prefix) { - x509_cert *cert; + const x509_crt *cert; char s1[256]; char s2[256]; @@ -828,20 +1056,27 @@ print_details (struct key_state_ssl * ks_ssl, const char *prefix) ssl_get_version (ks_ssl->ctx), ssl_get_ciphersuite(ks_ssl->ctx)); - cert = ks_ssl->ctx->peer_cert; + cert = ssl_get_peer_cert(ks_ssl->ctx); if (cert != NULL) { - openvpn_snprintf (s2, sizeof (s2), ", " counter_format " bit RSA", (counter_type) cert->rsa.len * 8); + openvpn_snprintf (s2, sizeof (s2), ", %zu bit key", pk_get_size(&cert->pk)); } msg (D_HANDSHAKE, "%s%s", s1, s2); } void -show_available_tls_ciphers () +show_available_tls_ciphers (const char *cipher_list) { + struct tls_root_ctx tls_ctx; const int *ciphers = ssl_list_ciphersuites(); + 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"); printf ("listed in order of preference:\n\n"); @@ -853,6 +1088,25 @@ show_available_tls_ciphers () ciphers++; } printf ("\n"); + + tls_ctx_free(&tls_ctx); +} + +void +show_available_curves (void) +{ + const ecp_curve_info *pcurve = ecp_curve_list(); + + if (NULL == pcurve) + msg (M_FATAL, "Cannot retrieve curve list from PolarSSL"); + + /* Print curve list */ + printf ("Available Elliptic curves, listed in order of preference:\n\n"); + while (POLARSSL_ECP_DP_NONE != pcurve->grp_id) + { + printf("%s\n", pcurve->name); + pcurve++; + } } void @@ -867,4 +1121,14 @@ get_highest_preference_tls_cipher (char *buf, int size) 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", + (pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff ); + return polar_version; +} + #endif /* defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL) */ diff --git a/app/openvpn/src/openvpn/ssl_polarssl.h b/app/openvpn/src/openvpn/ssl_polarssl.h index 456573f5..b80a509e 100644 --- a/app/openvpn/src/openvpn/ssl_polarssl.h +++ b/app/openvpn/src/openvpn/ssl_polarssl.h @@ -30,7 +30,10 @@ #ifndef SSL_POLARSSL_H_ #define SSL_POLARSSL_H_ +#include "syshead.h" + #include <polarssl/ssl.h> +#include <polarssl/x509_crt.h> #if defined(ENABLE_PKCS11) #include <polarssl/pkcs11.h> @@ -62,18 +65,20 @@ 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_cert *crt_chain; /**< Local Certificate chain */ - x509_cert *ca_chain; /**< CA chain for remote verification */ - rsa_context *priv_key; /**< Local private key */ + x509_crt *crt_chain; /**< Local Certificate chain */ + x509_crt *ca_chain; /**< CA chain for remote verification */ + pk_context *priv_key; /**< Local private key */ #if defined(ENABLE_PKCS11) pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ #endif +#ifdef MANAGMENT_EXTERNAL_KEY + struct external_context *external_key; /**< Management external key */ +#endif int * allowed_ciphers; /**< List of allowed ciphers for this connection */ }; struct key_state_ssl { ssl_context *ctx; - ssl_session *ssn; endless_buffer *ct_in; endless_buffer *ct_out; }; diff --git a/app/openvpn/src/openvpn/ssl_verify.c b/app/openvpn/src/openvpn/ssl_verify.c index cac46e98..2d10d155 100644 --- a/app/openvpn/src/openvpn/ssl_verify.c +++ b/app/openvpn/src/openvpn/ssl_verify.c @@ -337,8 +337,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,18 +365,21 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, } } -#endif /* OPENSSL_VERSION_NUMBER */ - - /* verify X509 name or common name against --tls-remote */ - if (opt->verify_x509name && strlen (opt->verify_x509name) > 0) + /* verify X509 name or username against --verify-x509-[user]name */ + if (opt->verify_x509_type != VERIFY_X509_NONE) { - if (strcmp (opt->verify_x509name, subject) == 0 - || strncmp (opt->verify_x509name, common_name, strlen (opt->verify_x509name)) == 0) + if ( (opt->verify_x509_type == VERIFY_X509_SUBJECT_DN + && strcmp (opt->verify_x509_name, subject) == 0) + || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN + && strcmp (opt->verify_x509_name, common_name) == 0) + || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN_PREFIX + && strncmp (opt->verify_x509_name, common_name, + strlen (opt->verify_x509_name)) == 0) ) msg (D_HANDSHAKE, "VERIFY X509NAME OK: %s", subject); else { msg (D_HANDSHAKE, "VERIFY X509NAME ERROR: %s, must be %s", - subject, opt->verify_x509name); + subject, opt->verify_x509_name); return FAILURE; /* Reject connection */ } } @@ -420,7 +421,6 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert setenv_str (es, envname, common_name); #endif -#ifdef ENABLE_EUREPHIA /* export X509 cert SHA1 fingerprint */ { unsigned char *sha1_hash = x509_get_sha1_hash(peer_cert, &gc); @@ -429,13 +429,17 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert setenv_str (es, envname, format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1, ":", &gc)); } -#endif /* export serial number as environmental variable */ - serial = x509_get_serial(peer_cert, &gc); + serial = backend_x509_get_serial(peer_cert, &gc); openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", cert_depth); setenv_str (es, envname, serial); + /* export serial number in hex as environmental variable */ + serial = backend_x509_get_serial_hex(peer_cert, &gc); + openvpn_snprintf (envname, sizeof(envname), "tls_serial_hex_%d", cert_depth); + setenv_str (es, envname, serial); + gc_free(&gc); } @@ -559,7 +563,7 @@ verify_check_crl_dir(const char *crl_dir, openvpn_x509_cert_t *cert) int fd = -1; struct gc_arena gc = gc_new(); - char *serial = x509_get_serial(cert, &gc); + char *serial = backend_x509_get_serial(cert, &gc); if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", crl_dir, OS_SPECIFIC_DIRSEP, serial)) { @@ -611,7 +615,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep string_replace_leading (subject, '-', '_'); /* extract the username (default is CN) */ - if (SUCCESS != x509_get_username (common_name, TLS_USERNAME_LEN, + if (SUCCESS != backend_x509_get_username (common_name, TLS_USERNAME_LEN, opt->x509_username_field, cert)) { if (!cert_depth) @@ -1022,7 +1026,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)) diff --git a/app/openvpn/src/openvpn/ssl_verify.h b/app/openvpn/src/openvpn/ssl_verify.h index 1d201523..84554f89 100644 --- a/app/openvpn/src/openvpn/ssl_verify.h +++ b/app/openvpn/src/openvpn/ssl_verify.h @@ -30,9 +30,10 @@ #ifndef SSL_VERIFY_H_ #define SSL_VERIFY_H_ +#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) + #include "syshead.h" #include "misc.h" -#include "manage.h" #include "ssl_common.h" /* Include OpenSSL-specific code */ @@ -62,6 +63,12 @@ struct cert_hash_set { struct cert_hash *ch[MAX_CERT_DEPTH]; /**< Array of certificate hashes */ }; +#define VERIFY_X509_NONE 0 +#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 @@ -160,25 +167,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. * @@ -248,5 +236,6 @@ tls_client_reason (struct tls_multi *multi) #endif } -#endif /* SSL_VERIFY_H_ */ +#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) */ +#endif /* SSL_VERIFY_H_ */ diff --git a/app/openvpn/src/openvpn/ssl_verify_backend.h b/app/openvpn/src/openvpn/ssl_verify_backend.h index 1658cc02..4e9ad60f 100644 --- a/app/openvpn/src/openvpn/ssl_verify_backend.h +++ b/app/openvpn/src/openvpn/ssl_verify_backend.h @@ -109,20 +109,35 @@ unsigned char *x509_get_sha1_hash (openvpn_x509_cert_t *cert, struct gc_arena *g * * @return \c FAILURE, \c or SUCCESS */ -result_t x509_get_username (char *common_name, int cn_len, +result_t backend_x509_get_username (char *common_name, int cn_len, char * x509_username_field, openvpn_x509_cert_t *peer_cert); /* - * Return the certificate's serial number. + * Return the certificate's serial number in decimal string representation. * * The serial number is returned as a string, since it might be a bignum. * * @param cert Certificate to retrieve the serial number from. * @param gc Garbage collection arena to use when allocating string. * - * @return The certificate's serial number. + * @return String representation of the certificate's serial number + * in decimal notation, or NULL on error. */ -char *x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc); +char *backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc); + +/* + * Return the certificate's serial number in hex string representation. + * + * The serial number is returned as a string, since it might be a bignum. + * + * @param cert Certificate to retrieve the serial number from. + * @param gc Garbage collection arena to use when allocating string. + * + * @return String representation of the certificate's serial number + * in hex notation, or NULL on error. + */ +char *backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, + struct gc_arena *gc); /* * Save X509 fields to environment, using the naming convention: @@ -189,8 +204,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. * @@ -219,8 +232,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 * diff --git a/app/openvpn/src/openvpn/ssl_verify_openssl.c b/app/openvpn/src/openvpn/ssl_verify_openssl.c index 658f5f33..2482eaa4 100644 --- a/app/openvpn/src/openvpn/ssl_verify_openssl.c +++ b/app/openvpn/src/openvpn/ssl_verify_openssl.c @@ -37,9 +37,13 @@ #if defined(ENABLE_SSL) && 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> @@ -202,7 +206,7 @@ extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, } result_t -x509_get_username (char *common_name, int cn_len, +backend_x509_get_username (char *common_name, int cn_len, char * x509_username_field, X509 *peer_cert) { #ifdef ENABLE_X509ALTUSERNAME @@ -220,7 +224,7 @@ x509_get_username (char *common_name, int cn_len, } char * -x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) +backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) { ASN1_INTEGER *asn1_i; BIGNUM *bignum; @@ -238,10 +242,18 @@ x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) return serial; } +char * +backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc) +{ + const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert); + + 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) { - char *hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc); + unsigned char *hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc); memcpy(hash, cert->sha1_hash, SHA_DIGEST_LENGTH); return hash; } @@ -459,8 +471,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) @@ -566,8 +576,6 @@ x509_write_pem(FILE *peercert_file, X509 *peercert) return SUCCESS; } -#endif /* OPENSSL_VERSION_NUMBER */ - /* * check peer cert against CRL */ diff --git a/app/openvpn/src/openvpn/ssl_verify_polarssl.c b/app/openvpn/src/openvpn/ssl_verify_polarssl.c index a32db8df..71d38a9d 100644 --- a/app/openvpn/src/openvpn/ssl_verify_polarssl.c +++ b/app/openvpn/src/openvpn/ssl_verify_polarssl.c @@ -38,17 +38,19 @@ #if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL) #include "ssl_verify.h" +#include <polarssl/error.h> +#include <polarssl/bignum.h> +#include <polarssl/oid.h> #include <polarssl/sha1.h> #define MAX_SUBJECT_LENGTH 256 int -verify_callback (void *session_obj, x509_cert *cert, int cert_depth, - int preverify_ok) +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(); - int ret = 1; ASSERT (cert); ASSERT (session); @@ -59,31 +61,29 @@ verify_callback (void *session_obj, x509_cert *cert, int cert_depth, cert_hash_remember (session, cert_depth, x509_get_sha1_hash(cert, &gc)); /* did peer present cert which was signed by our root cert? */ - if (!preverify_ok) + if (*flags != 0) { char *subject = x509_get_subject(cert, &gc); if (subject) - msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, %s", cert_depth, 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, could not extract X509 " - "subject string from certificate", cert_depth); + msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, could not extract X509 " + "subject string from certificate", *flags, cert_depth); - goto cleanup; + /* 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; } - if (SUCCESS != verify_cert(session, cert, cert_depth)) - goto cleanup; - - ret = 0; - -cleanup: gc_free(&gc); /* - * PolarSSL expects 1 on failure, 0 on success + * PolarSSL-1.2.0+ expects 0 on anything except fatal errors. */ - return ret; + return 0; } #ifdef ENABLE_X509ALTUSERNAME @@ -91,8 +91,8 @@ cleanup: #endif result_t -x509_get_username (char *cn, int cn_len, - char *x509_username_field, x509_cert *cert) +backend_x509_get_username (char *cn, int cn_len, + char *x509_username_field, x509_crt *cert) { x509_name *name; @@ -103,7 +103,7 @@ x509_get_username (char *cn, int cn_len, /* Find common name */ while( name != NULL ) { - if( memcmp( name->oid.p, OID_CN, OID_SIZE(OID_CN) ) == 0) + if( memcmp( name->oid.p, OID_AT_CN, OID_SIZE(OID_AT_CN) ) == 0) break; name = name->next; @@ -126,23 +126,59 @@ x509_get_username (char *cn, int cn_len, } char * -x509_get_serial (x509_cert *cert, struct gc_arena *gc) +backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) +{ + char *buf = NULL; + size_t buflen = 0; + mpi serial_mpi = { 0 }; + int retval = 0; + + /* Transform asn1 integer serial into PolarSSL MPI */ + mpi_init(&serial_mpi); + retval = mpi_read_binary(&serial_mpi, cert->serial.p, cert->serial.len); + if (retval < 0) + { + char errbuf[128]; + polarssl_strerror(retval, errbuf, sizeof(errbuf)); + + msg(M_WARN, "Failed to retrieve serial from certificate: %s.", errbuf); + 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 */ + retval = mpi_write_string(&serial_mpi, 10, buf, &buflen); + if (retval < 0) + { + char errbuf[128]; + polarssl_strerror(retval, errbuf, sizeof(errbuf)); + + msg(M_WARN, "Failed to write serial to string: %s.", errbuf); + return NULL; + } + + return buf; +} + +char * +backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc) { - int ret = 0; - int i = 0; char *buf = NULL; size_t len = cert->serial.len * 3 + 1; buf = gc_malloc(len, true, gc); - if(x509parse_serial_gets(buf, len-1, &cert->serial) < 0) + if(x509_serial_gets(buf, len-1, &cert->serial) < 0) buf = NULL; return buf; } unsigned char * -x509_get_sha1_hash (x509_cert *cert, struct gc_arena *gc) +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); @@ -150,14 +186,14 @@ x509_get_sha1_hash (x509_cert *cert, struct gc_arena *gc) } char * -x509_get_subject(x509_cert *cert, struct gc_arena *gc) +x509_get_subject(x509_crt *cert, struct gc_arena *gc) { char tmp_subject[MAX_SUBJECT_LENGTH] = {0}; char *subject = NULL; int ret = 0; - ret = x509parse_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject ); + ret = x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject ); if (ret > 0) { /* Allocate the required space for the subject */ @@ -187,70 +223,28 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert) while( name != NULL ) { char name_expand[64+8]; + const char *shortname; - if( name->oid.len == 2 && memcmp( name->oid.p, OID_X520, 2 ) == 0 ) + if( 0 == oid_get_attr_short_name(&name->oid, &shortname) ) { - switch( name->oid.p[2] ) - { - case X520_COMMON_NAME: - openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_CN", - cert_depth); break; - - case X520_COUNTRY: - openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_C", - cert_depth); break; - - case X520_LOCALITY: - openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_L", - cert_depth); break; - - case X520_STATE: - openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_ST", - cert_depth); break; - - case X520_ORGANIZATION: - openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_O", - cert_depth); break; - - case X520_ORG_UNIT: - openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_OU", - cert_depth); break; - - default: - openvpn_snprintf (name_expand, sizeof(name_expand), - "X509_%d_0x%02X", cert_depth, name->oid.p[2]); - break; - } + openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s", + cert_depth, shortname); } - else if( name->oid.len == 8 && memcmp( name->oid.p, OID_PKCS9, 8 ) == 0 ) - { - switch( name->oid.p[8] ) - { - case PKCS9_EMAIL: - openvpn_snprintf (name_expand, sizeof(name_expand), - "X509_%d_emailAddress", cert_depth); break; - - default: - openvpn_snprintf (name_expand, sizeof(name_expand), - "X509_%d_0x%02X", cert_depth, name->oid.p[8]); - break; - } - } - else - { - openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?", - cert_depth); - } - - for( i = 0; i < name->val.len; i++ ) + 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; + 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; + c = name->val.p[i]; + if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) + s[i] = '?'; + else s[i] = c; } s[i] = '\0'; @@ -264,7 +258,7 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert) } result_t -x509_verify_ns_cert_type(const x509_cert *cert, const int usage) +x509_verify_ns_cert_type(const x509_crt *cert, const int usage) { if (usage == NS_CERT_CHECK_NONE) return SUCCESS; @@ -279,7 +273,7 @@ x509_verify_ns_cert_type(const x509_cert *cert, const int usage) } result_t -x509_verify_cert_ku (x509_cert *cert, const unsigned * const expected_ku, +x509_verify_cert_ku (x509_crt *cert, const unsigned * const expected_ku, int expected_len) { result_t fFound = FAILURE; @@ -312,7 +306,7 @@ x509_verify_cert_ku (x509_cert *cert, const unsigned * const expected_ku, } result_t -x509_verify_cert_eku (x509_cert *cert, const char * const expected_oid) +x509_verify_cert_eku (x509_crt *cert, const char * const expected_oid) { result_t fFound = FAILURE; @@ -362,7 +356,7 @@ x509_verify_cert_eku (x509_cert *cert, const char * const expected_oid) } result_t -x509_write_pem(FILE *peercert_file, x509_cert *peercert) +x509_write_pem(FILE *peercert_file, x509_crt *peercert) { msg (M_WARN, "PolarSSL does not support writing peer certificate in PEM format"); return FAILURE; @@ -372,12 +366,12 @@ x509_write_pem(FILE *peercert_file, x509_cert *peercert) * check peer cert against CRL */ result_t -x509_verify_crl(const char *crl_file, x509_cert *cert, const char *subject) +x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject) { result_t retval = FAILURE; x509_crl crl = {0}; - if (x509parse_crlfile(&crl, crl_file) != 0) + if (x509_crl_parse_file(&crl, crl_file) != 0) { msg (M_ERR, "CRL: cannot read CRL from file %s", crl_file); goto end; @@ -392,7 +386,7 @@ x509_verify_crl(const char *crl_file, x509_cert *cert, const char *subject) goto end; } - if (0 != x509parse_revoked(cert, &crl)) + if (0 != x509_crt_revoked(cert, &crl)) { msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED", subject); goto end; diff --git a/app/openvpn/src/openvpn/ssl_verify_polarssl.h b/app/openvpn/src/openvpn/ssl_verify_polarssl.h index fceee667..2076f2ef 100644 --- a/app/openvpn/src/openvpn/ssl_verify_polarssl.h +++ b/app/openvpn/src/openvpn/ssl_verify_polarssl.h @@ -31,13 +31,11 @@ #define SSL_VERIFY_POLARSSL_H_ #include "syshead.h" -#include "misc.h" -#include "manage.h" -#include <polarssl/x509.h> +#include <polarssl/x509_crt.h> #ifndef __OPENVPN_X509_CERT_T_DECLARED #define __OPENVPN_X509_CERT_T_DECLARED -typedef x509_cert openvpn_x509_cert_t; +typedef x509_crt openvpn_x509_cert_t; #endif /** @name Function for authenticating a new connection from a remote OpenVPN peer @@ -55,27 +53,25 @@ typedef x509_cert openvpn_x509_cert_t; * calls the PolarSSL library's \c ssl_set_verify_callback() function with \c * verify_callback() as its callback argument. * - * It checks preverify_ok, and registers the certificate hash. If these steps - * succeed, it calls the \c verify_cert() function, which performs - * OpenVPN-specific verification. + * It checks *flags and registers the certificate hash. If these steps succeed, + * it calls the \c verify_cert() function, which performs OpenVPN-specific + * verification. * * @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_depth - The depth of the current certificate in the chain, with * 0 being the actual certificate. - * @param preverify_ok - Whether the remote OpenVPN peer's certificate - * past verification. A value of 1 means it - * verified successfully, 0 means it failed. + * @param flags - Whether the remote OpenVPN peer's certificate + * passed verification. A value of 0 means it + * verified successfully, any other value means it + * failed. \c verify_callback() is considered to have + * ok'ed this certificate if flags is 0 when it returns. * - * @return The return value indicates whether the supplied certificate is - * allowed to set up a VPN tunnel. The following values can be - * returned: - * - \c 0: failure, this certificate is not allowed to connect. - * - \c 1: success, this certificate is allowed to connect. + * @return The return value is 0 unless a fatal error occurred. */ -int verify_callback (void *session_obj, x509_cert *cert, int cert_depth, - int preverify_ok); +int verify_callback (void *session_obj, x509_crt *cert, int cert_depth, + int *flags); /** @} name Function for authenticating a new connection from a remote OpenVPN peer */ diff --git a/app/openvpn/src/openvpn/status.c b/app/openvpn/src/openvpn/status.c index 5f9ab9ee..b7ff4843 100644 --- a/app/openvpn/src/openvpn/status.c +++ b/app/openvpn/src/openvpn/status.c @@ -33,6 +33,7 @@ #include "status.h" #include "perf.h" #include "misc.h" +#include "fdmisc.h" #include "memdbg.h" @@ -98,6 +99,7 @@ status_open (const char *filename, if (so->fd >= 0) { so->filename = string_alloc (filename, NULL); + set_cloexec (so->fd); /* allocate read buffer */ if (so->flags & STATUS_OUTPUT_READ) diff --git a/app/openvpn/src/openvpn/syshead.h b/app/openvpn/src/openvpn/syshead.h index 163d2bb2..771c4fc1 100644 --- a/app/openvpn/src/openvpn/syshead.h +++ b/app/openvpn/src/openvpn/syshead.h @@ -307,6 +307,10 @@ #include <netinet/ip.h> #endif +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif + #ifdef HAVE_NET_IF_TUN_H #include <net/if_tun.h> #endif @@ -422,6 +426,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 @@ -535,7 +546,7 @@ socket_defined (const socket_descriptor_t sd) /* * Enable external private key */ -#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_SSL) && !defined(ENABLE_CRYPTO_POLARSSL) +#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_SSL) #define MANAGMENT_EXTERNAL_KEY #endif @@ -575,11 +586,6 @@ socket_defined (const socket_descriptor_t sd) #endif /* - * Compile the struct buffer_list code - */ -#define ENABLE_BUFFER_LIST - -/* * Should we include OCC (options consistency check) code? */ #ifndef ENABLE_SMALL @@ -589,7 +595,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 @@ -598,20 +604,13 @@ 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) @@ -650,15 +649,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. */ @@ -704,9 +694,12 @@ socket_defined (const socket_descriptor_t sd) #endif /* - * Do we support internal client-side NAT? + * Compression support */ -#define ENABLE_CLIENT_NAT +#if defined(ENABLE_SNAPPY) || defined(ENABLE_LZO) || defined(ENABLE_LZ4) || \ + defined(ENABLE_COMP_STUB) +#define USE_COMP +#endif /* * Enable --memstats option diff --git a/app/openvpn/src/openvpn/tun.c b/app/openvpn/src/openvpn/tun.c index a0754427..482f6402 100644 --- a/app/openvpn/src/openvpn/tun.c +++ b/app/openvpn/src/openvpn/tun.c @@ -74,6 +74,14 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co #include <stropts.h> #endif +#if defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H +#include <sys/kern_control.h> +#include <net/if_utun.h> +#include <sys/sys_domain.h> +#endif + +static void clear_tuntap (struct tuntap *tuntap); + bool is_dev_type (const char *dev, const char *dev_type, const char *match_type) { @@ -299,16 +307,6 @@ warn_on_use_of_common_subnets (void) } /* - * Complain if --dev tap and --ifconfig is used on an OS for which - * we don't have a custom tap ifconfig template below. - */ -static void -no_tap_ifconfig () -{ - msg (M_FATAL, "Sorry but you cannot use --dev tap and --ifconfig together on this OS because I have not yet been programmed to understand the appropriate ifconfig syntax to use for TAP-style devices on this OS. Your best alternative is to use an --up script and do the ifconfig command manually."); -} - -/* * Return a string to be used for options compatibility check * between peers. */ @@ -468,15 +466,15 @@ init_tun (const char *dev, /* --dev option */ */ if (strict_warn) { - struct addrinfo *curele; + struct addrinfo *curele; ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology); /* * If local_public or remote_public addresses are defined, * make sure they do not clash with our virtual subnet. */ - - for(curele=remote_public;curele;curele=curele->ai_next) { + + for(curele=local_public;curele;curele=curele->ai_next) { if(curele->ai_family == AF_INET) check_addr_clash ("local", tt->type, @@ -485,14 +483,14 @@ init_tun (const char *dev, /* --dev option */ 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); - } + 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"); @@ -781,39 +779,33 @@ do_ifconfig (struct tuntap *tt, #endif /*ENABLE_IPROUTE*/ #elif defined(TARGET_ANDROID) - - - if (do_ipv6) { - struct user_pass up6; - struct buffer out6 = alloc_buf_gc (64, &gc); - buf_printf (&out6, "%s/%d", ifconfig_ipv6_local,tt->netbits_ipv6); - strcpy(up6.username, buf_bptr(&out6)); - management_query_user_pass(management, &up6 , "IFCONFIG6", GET_USER_PASS_NEED_OK,(void*) 0); - } - struct user_pass up; - 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); - strcpy(up.username, buf_bptr(&out)); - management_query_user_pass(management, &up , "IFCONFIG", GET_USER_PASS_NEED_OK,(void*) 0); + 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... @@ -917,7 +909,7 @@ do_ifconfig (struct tuntap *tt, if (!tun && tt->topology == TOP_SUBNET) { /* Add a network route for the local tun interface */ - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED | RT_METRIC_DEFINED; r.network = tt->local & tt->remote_netmask; @@ -1114,7 +1106,7 @@ do_ifconfig (struct tuntap *tt, /* Add a network route for the local tun interface */ if (!tun && tt->topology == TOP_SUBNET) { - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED; r.network = tt->local & tt->remote_netmask; @@ -1180,7 +1172,7 @@ do_ifconfig (struct tuntap *tt, /* Add a network route for the local tun interface */ if (!tun && tt->topology == TOP_SUBNET) { - struct route r; + struct route_ipv4 r; CLEAR (r); r.flags = RT_DEFINED; r.network = tt->local & tt->remote_netmask; @@ -1298,6 +1290,87 @@ open_null (struct tuntap *tt) tt->actual_name = string_alloc ("null", NULL); } + +#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H) + +/* + * OpenBSD and Mac OS X when using utun + * have a slightly incompatible TUN device from + * the rest of the world, in that it prepends a + * uint32 to the beginning of the IP header + * to designate the protocol (why not just + * look at the version field in the IP header to + * determine v4 or v6?). + * + * We strip off this field on reads and + * put it back on writes. + * + * I have not tested TAP devices on OpenBSD, + * but I have conditionalized the special + * TUN handling code described above to + * go away for TAP devices. + */ + +#include <netinet/ip.h> +#include <sys/uio.h> + +static inline int +header_modify_read_write_return (int len) +{ + if (len > 0) + return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; + else + return len; +} + +int +write_tun_header (struct tuntap* tt, uint8_t *buf, int len) +{ + if (tt->type == DEV_TYPE_TUN) + { + u_int32_t type; + struct iovec iv[2]; + struct ip *iph; + + iph = (struct ip *) buf; + + if (tt->ipv6 && iph->ip_v == 6) + type = htonl (AF_INET6); + else + type = htonl (AF_INET); + + iv[0].iov_base = &type; + iv[0].iov_len = sizeof (type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return header_modify_read_write_return (writev (tt->fd, iv, 2)); + } + else + return write (tt->fd, buf, len); +} + +int +read_tun_header (struct tuntap* tt, uint8_t *buf, int len) +{ + if (tt->type == DEV_TYPE_TUN) + { + u_int32_t type; + struct iovec iv[2]; + + iv[0].iov_base = &type; + iv[0].iov_len = sizeof (type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return header_modify_read_write_return (readv (tt->fd, iv, 2)); + } + else + return read (tt->fd, buf, len); +} +#endif + + #ifndef WIN32 static void open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, @@ -1422,33 +1495,52 @@ close_tun_generic (struct tuntap *tt) void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - int i; - struct user_pass up; - struct gc_arena gc = gc_new (); - - for (i = 0; i < tt->options.dns_len; ++i) { - strcpy(up.username, print_in_addr_t(tt->options.dns[i], 0, &gc)); - management_query_user_pass(management, &up , "DNSSERVER", GET_USER_PASS_NEED_OK,(void*) 0); - } +#define ANDROID_TUNNAME "vpnservice-tun" + int i; + struct user_pass up; + struct gc_arena gc = gc_new (); + bool opentun; + + 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)); + } + + if(tt->options.domain) + management_android_control (management, "DNSDOMAIN", tt->options.domain); + + int android_method = managment_android_persisttun_action (management); - if(tt->options.domain) { - strcpy(up.username , tt->options.domain); - management_query_user_pass(management, &up , "DNSDOMAIN", GET_USER_PASS_NEED_OK,(void*) 0); + /* Android 4.4 workaround */ + if (oldtunfd >=0 && android_method == ANDROID_OPEN_AFTER_CLOSE) + { + close(oldtunfd); + openvpn_sleep(2); } - - strcpy(up.username , dev); - management_query_user_pass(management, &up , "OPENTUN", GET_USER_PASS_NEED_OK,(void*) 0); + 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( (tt->fd < 0) || ! (strcmp("ok",up.password)==0)) { - msg (M_ERR, "ERROR: Cannot open TUN"); - } - /* Set the actual name to a dummy name to enable scripts */ - tt->actual_name = (char *) malloc(32); - strncpy(tt->actual_name, "vpnservice-tun",32); - gc_free (&gc); + } + + 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 @@ -2076,23 +2168,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) #elif defined(TARGET_OPENBSD) -/* - * OpenBSD has a slightly incompatible TUN device from - * the rest of the world, in that it prepends a - * uint32 to the beginning of the IP header - * to designate the protocol (why not just - * look at the version field in the IP header to - * determine v4 or v6?). - * - * We strip off this field on reads and - * put it back on writes. - * - * I have not tested TAP devices on OpenBSD, - * but I have conditionalized the special - * TUN handling code described above to - * go away for TAP devices. - */ - void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { @@ -2159,59 +2234,16 @@ close_tun (struct tuntap* tt) } } -static inline int -openbsd_modify_read_write_return (int len) -{ - if (len > 0) - return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; - else - return len; -} - int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; - struct ip *iph; - - iph = (struct ip *) buf; - - if (tt->ipv6 && iph->ip_v == 6) - type = htonl (AF_INET6); - else - type = htonl (AF_INET); - - iv[0].iov_base = &type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; - - return openbsd_modify_read_write_return (writev (tt->fd, iv, 2)); - } - else - return write (tt->fd, buf, len); + return write_tun_header (tt, buf, len); } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun (struct tuntap *tt, uint8_t *buf, int len) { - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; - - iv[0].iov_base = &type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; - - return openbsd_modify_read_write_return (readv (tt->fd, iv, 2)); - } - else - return read (tt->fd, buf, len); + return read_tun_header (tt, buf, len); } #elif defined(TARGET_NETBSD) @@ -2571,10 +2603,177 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) * pointing to lo0. Need to unconfigure... (observed on 10.5) */ +/* + * utun is the native Darwin tun driver present since at least 10.7 + * Thanks goes to Jonathan Levin for providing an example how to utun + * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c) + */ + +#ifdef HAVE_NET_IF_UTUN_H + +/* Helper functions that tries to open utun device + return -2 on early initialization failures (utun not supported + at all (old OS X) and -1 on initlization failure of utun + device (utun works but utunX is already used */ +static +int utun_open_helper (struct ctl_info ctlInfo, int utunnum) +{ + struct sockaddr_ctl sc; + int fd; + + fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + + if (fd < 0) + { + msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)", + strerror (errno)); + return -2; + } + + if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) + { + close (fd); + msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)", + strerror (errno)); + return -2; + } + + + sc.sc_id = ctlInfo.ctl_id; + sc.sc_len = sizeof(sc); + sc.sc_family = AF_SYSTEM; + sc.ss_sysaddr = AF_SYS_CONTROL; + + sc.sc_unit = utunnum+1; + + + /* If the connect is successful, a utun%d device will be created, where "%d" + * is (sc.sc_unit - 1) */ + + if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0) + { + msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)", + strerror (errno)); + close(fd); + return -1; + } + + set_nonblock (fd); + set_cloexec (fd); /* don't pass fd to scripts */ + + return fd; +} + +void +open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +{ + struct ctl_info ctlInfo; + int fd; + char utunname[20]; + int utunnum =-1; + socklen_t utunname_len = sizeof(utunname); + + /* dev_node is simply utun, do the normal dynamic utun + * otherwise try to parse the utun number */ + if (dev_node && !strcmp ("utun", dev_node)==0) + { + if (!sscanf (dev_node, "utun%d", &utunnum)==1) + msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'" + "to use a utun device number X", dev_node); + } + + + + CLEAR (ctlInfo); + if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >= + sizeof(ctlInfo.ctl_name)) + { + msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long"); + } + + /* try to open first available utun device if no specific utun is requested */ + if (utunnum == -1) + { + for (utunnum=0; utunnum<255; utunnum++) + { + fd = utun_open_helper (ctlInfo, utunnum); + /* Break if the fd is valid, + * or if early initalization failed (-2) */ + if (fd !=-1) + break; + } + } + else + { + fd = utun_open_helper (ctlInfo, utunnum); + } + + /* opening an utun device failed */ + tt->fd = fd; + + if (fd < 0) + return; + + /* Retrieve the assigned interface name. */ + if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len)) + msg (M_ERR | M_ERRNO, "Error retrieving utun interface name"); + + tt->actual_name = string_alloc (utunname, NULL); + + msg (M_INFO, "Opened utun device %s", utunname); + tt->is_utun = true; +} + +#endif + void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, true, tt); +#ifdef HAVE_NET_IF_UTUN_H + /* If dev_node does not start start with utun assume regular tun/tap */ + if ((!dev_node && tt->type==DEV_TYPE_TUN) || + (dev_node && !strncmp (dev_node, "utun", 4))) + { + + /* Check if user has specific dev_type tap and forced utun with + dev-node utun */ + if (tt->type!=DEV_TYPE_TUN) + msg (M_FATAL, "Cannot use utun devices with --dev-type %s", + dev_type_string (dev, dev_type)); + + /* Try utun first and fall back to normal tun if utun fails + and dev_node is not specified */ + open_darwin_utun(dev, dev_type, dev_node, tt); + + if (!tt->is_utun) + { + if (!dev_node) + { + /* No explicit utun and utun failed, try the generic way) */ + msg (M_INFO, "Failed to open utun device. Falling back to /dev/tun device"); + open_tun_generic (dev, dev_type, NULL, true, true, tt); + } + else + { + /* Specific utun device or generic utun request with no tun + fall back failed, consider this a fatal failure */ + msg (M_FATAL, "Cannot open utun device"); + } + } + } + else +#endif + { + + /* Use plain dev-node tun to select /dev/tun style + * Unset dev_node variable prior to passing to open_tun_generic to + * let open_tun_generic pick the first available tun device */ + + if (dev_node && strcmp (dev_node, "tun")==0) + dev_node=NULL; + + open_tun_generic (dev, dev_type, dev_node, true, true, tt); + } } void @@ -2607,13 +2806,23 @@ close_tun (struct tuntap* tt) int write_tun (struct tuntap* tt, uint8_t *buf, int len) { - return write (tt->fd, buf, len); +#ifdef HAVE_NET_IF_UTUN_H + if (tt->is_utun) + return write_tun_header (tt, buf, len); + else +#endif + return write (tt->fd, buf, len); } int read_tun (struct tuntap* tt, uint8_t *buf, int len) { - return read (tt->fd, buf, len); +#ifdef HAVE_NET_IF_UTUN_H + if (tt->is_utun) + return read_tun_header (tt, buf, len); + else +#endif + return read (tt->fd, buf, len); } #elif defined(WIN32) @@ -2958,9 +3167,9 @@ get_panel_reg (struct gc_arena *gc) char enum_name[256]; char connection_string[256]; HKEY connection_key; - char name_data[256]; + WCHAR name_data[256]; DWORD name_type; - const char name_string[] = "Name"; + const WCHAR name_string[] = L"Name"; len = sizeof (enum_name); status = RegEnumKeyEx( @@ -2994,12 +3203,12 @@ get_panel_reg (struct gc_arena *gc) else { len = sizeof (name_data); - status = RegQueryValueEx( + status = RegQueryValueExW( connection_key, name_string, NULL, &name_type, - name_data, + (LPBYTE) name_data, &len); if (status != ERROR_SUCCESS || name_type != REG_SZ) @@ -3007,10 +3216,15 @@ get_panel_reg (struct gc_arena *gc) NETWORK_CONNECTIONS_KEY, connection_string, name_string); else { + int n; + LPSTR name; struct panel_reg *reg; ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc); - reg->name = string_alloc (name_data, gc); + n = WideCharToMultiByte (CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL); + name = gc_malloc (n, false, gc); + WideCharToMultiByte (CP_UTF8, 0, name_data, -1, name, n, NULL, NULL); + reg->name = name; reg->guid = string_alloc (enum_name, gc); /* link into return list */ @@ -3220,7 +3434,7 @@ static void at_least_one_tap_win (const struct tap_reg *tap_reg) { if (!tap_reg) - msg (M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> " PACKAGE_NAME " -> Add a new TAP-Windows virtual ethernet adapter."); + msg (M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> TAP-Windows -> Utilities -> Add a new TAP-Windows virtual ethernet adapter."); } /* @@ -5091,10 +5305,14 @@ close_tun (struct tuntap *tt) /* 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", + "%s%sc interface ipv6 delete address %s %s store=active", get_win_sys_path(), NETSH_PATH_SUFFIX, tt->actual_name, diff --git a/app/openvpn/src/openvpn/tun.h b/app/openvpn/src/openvpn/tun.h index e7d941ab..631b53c6 100644 --- a/app/openvpn/src/openvpn/tun.h +++ b/app/openvpn/src/openvpn/tun.h @@ -181,6 +181,9 @@ struct tuntap int ip_fd; #endif +#ifdef HAVE_NET_IF_UTUN_H + bool is_utun; +#endif /* used for printing status info only */ unsigned int rwflags_debug; @@ -203,8 +206,6 @@ tuntap_defined (const struct tuntap *tt) * Function prototypes */ -static void clear_tuntap (struct tuntap *tuntap); - void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt); diff --git a/app/openvpn/src/openvpn/win32.c b/app/openvpn/src/openvpn/win32.c index 2db96a8d..7c89a5a9 100644 --- a/app/openvpn/src/openvpn/win32.c +++ b/app/openvpn/src/openvpn/win32.c @@ -517,7 +517,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; @@ -870,6 +870,9 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i WCHAR *cl = wide_cmd_line (a, &gc); WCHAR *cmd = wide_string (a->argv[0], &gc); + /* this allows console programs to run, and is ignored otherwise */ + DWORD proc_flags = CREATE_NO_WINDOW; + CLEAR (start_info); CLEAR (proc_info); @@ -879,7 +882,7 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i start_info.dwFlags = STARTF_USESHOWWINDOW; start_info.wShowWindow = SW_HIDE; - if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) + if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, proc_flags, env, NULL, &start_info, &proc_info)) { DWORD exit_status = 0; CloseHandle (proc_info.hThread); @@ -993,19 +996,27 @@ set_win_sys_path_via_env (struct env_set *es) const char * win_get_tempdir() { - static char buf[MAX_PATH]; - char *tmpdir = buf; + static char tmpdir[MAX_PATH]; + WCHAR wtmpdir[MAX_PATH]; - CLEAR(buf); + if (!GetTempPathW(_countof(wtmpdir), wtmpdir)) + { + /* Warn if we can't find a valid temporary directory, which should + * be unlikely. + */ + msg (M_WARN, "Could not find a suitable temporary directory." + " (GetTempPath() failed). Consider using --tmp-dir"); + return NULL; + } + + if (WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, NULL, 0, NULL, NULL) > sizeof (tmpdir)) + { + msg (M_WARN, "Could not get temporary directory. Path is too long." + " Consider using --tmp-dir"); + return NULL; + } - if (!GetTempPath(sizeof(buf),buf)) { - /* Warn if we can't find a valid temporary directory, which should - * be unlikely. - */ - msg (M_WARN, "Could not find a suitable temporary directory." - " (GetTempPath() failed). Consider to use --tmp-dir"); - tmpdir = NULL; - } + WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), NULL, NULL); return tmpdir; } #endif diff --git a/app/openvpn/src/plugins/auth-pam/Makefile.am b/app/openvpn/src/plugins/auth-pam/Makefile.am index 701a7497..2aef311a 100644 --- a/app/openvpn/src/plugins/auth-pam/Makefile.am +++ b/app/openvpn/src/plugins/auth-pam/Makefile.am @@ -8,8 +8,9 @@ MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in AM_CFLAGS = \ - -I$(top_srcdir)/include - $(PLUGIN_AUTH_PAM_CFLAGS) + -I$(top_srcdir)/include \ + $(PLUGIN_AUTH_PAM_CFLAGS) \ + $(OPTIONAL_CRYPTO_CFLAGS) if ENABLE_PLUGIN_AUTH_PAM plugin_LTLIBRARIES = openvpn-plugin-auth-pam.la diff --git a/app/openvpn/src/plugins/down-root/Makefile.am b/app/openvpn/src/plugins/down-root/Makefile.am index 064aa30c..7ca5a4e1 100644 --- a/app/openvpn/src/plugins/down-root/Makefile.am +++ b/app/openvpn/src/plugins/down-root/Makefile.am @@ -8,7 +8,8 @@ MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in AM_CFLAGS = \ - -I$(top_srcdir)/include + -I$(top_srcdir)/include \ + $(OPTIONAL_CRYPTO_CFLAGS) if ENABLE_PLUGIN_DOWN_ROOT plugin_LTLIBRARIES = openvpn-plugin-down-root.la diff --git a/app/openvpn/tests/t_client.rc-sample b/app/openvpn/tests/t_client.rc-sample index dcb3e4ae..6e666077 100644 --- a/app/openvpn/tests/t_client.rc-sample +++ b/app/openvpn/tests/t_client.rc-sample @@ -59,18 +59,18 @@ OPENVPN_BASE_P2P="..." RUN_TITLE_1="testing tun/udp/ipv4+ipv6" OPENVPN_CONF_1="$OPENVPN_BASE_P2MP --dev tun --proto udp --remote $REMOTE --port 51194" EXPECT_IFCONFIG4_1="10.100.50.6" -EXPECT_IFCONFIG6_1="2001:dba:a050::1:0" +EXPECT_IFCONFIG6_1="2001:db8:a050::1:0" PING4_HOSTS_1="10.100.50.1 10.100.0.1" -PING6_HOSTS_1="2001:dba::1 2001:dba:a050::1" +PING6_HOSTS_1="2001:db8::1 2001:db8:a050::1" # Test 2: TCP / p2mp tun # RUN_TITLE_2="testing tun/tcp/ipv4+ipv6" OPENVPN_CONF_2="$OPENVPN_BASE_P2MP --dev tun --proto tcp --remote $REMOTE --port 51194" EXPECT_IFCONFIG4_2="10.100.51.6" -EXPECT_IFCONFIG6_2="2001:dba:a051::1:0" +EXPECT_IFCONFIG6_2="2001:db8:a051::1:0" PING4_HOSTS_2="10.100.51.1 10.100.0.1" -PING6_HOSTS_1="2001:dba::1 2001:dba:a051::1" +PING6_HOSTS_2="2001:db8::1 2001:db8:a051::1" # Test 3: UDP / p2p tun # ... diff --git a/app/openvpn/tests/t_client.sh.in b/app/openvpn/tests/t_client.sh.in index 189eecce..52c5ed1a 100755 --- a/app/openvpn/tests/t_client.sh.in +++ b/app/openvpn/tests/t_client.sh.in @@ -24,6 +24,18 @@ else exit 77 fi +# Check for external dependencies +which fping > /dev/null +if [ $? -ne 0 ]; then + echo "$0: fping is not available in \$PATH" >&2 + exit 77 +fi +which fping6 > /dev/null +if [ $? -ne 0 ]; then + echo "$0: fping6 is not available in \$PATH" >&2 + exit 77 +fi + if [ ! -x "${top_builddir}/src/openvpn/openvpn" ] then echo "no (executable) openvpn binary in current build tree. FAIL." >&2 @@ -91,7 +103,7 @@ get_ifconfig_route() echo "-- linux iproute2 --" @IPROUTE@ addr show | grep -v valid_lft @IPROUTE@ route show - @IPROUTE@ -o -6 route show | grep -v ' cache' | sed -e 's/expires [0-9]*sec//' + @IPROUTE@ -o -6 route show | grep -v ' cache' | sed -E -e 's/ expires [0-9]*sec//' -e 's/ (mtu|hoplimit|cwnd|ssthresh) [0-9]+//g' -e 's/ (rtt|rttvar) [0-9]+ms//g' return fi @@ -209,6 +221,8 @@ SUMMARY_FAIL= for SUF in $TEST_RUN_LIST do # get config variables + eval test_prep=\"\$PREPARE_$SUF\" + eval test_cleanup=\"\$CLEANUP_$SUF\" eval test_run_title=\"\$RUN_TITLE_$SUF\" eval openvpn_conf=\"\$OPENVPN_CONF_$SUF\" eval expect_ifconfig4=\"\$EXPECT_IFCONFIG4_$SUF\" @@ -219,6 +233,11 @@ do echo -e "\n### test run $SUF: '$test_run_title' ###\n" fail_count=0 + if [ -n "$test_prep" ]; then + echo -e "running preparation: '$test_prep'" + eval $test_prep + fi + echo "save pre-openvpn ifconfig + route" get_ifconfig_route >$LOGDIR/$SUF:ifconfig_route_pre.txt @@ -304,6 +323,12 @@ do SUMMARY_FAIL="$SUMMARY_FAIL $SUF" exit_code=30 fi + + if [ -n "$test_cleanup" ]; then + echo -e "cleaning up: '$test_cleanup'" + eval $test_cleanup + fi + done if [ -z "$SUMMARY_OK" ] ; then SUMMARY_OK=" none"; fi diff --git a/app/openvpn/version.m4 b/app/openvpn/version.m4 index 1ea1c32f..376661f7 100644 --- a/app/openvpn/version.m4 +++ b/app/openvpn/version.m4 @@ -1,7 +1,7 @@ dnl define the OpenVPN version define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) -define([PRODUCT_VERSION], [2.3_master]) +define([PRODUCT_VERSION], [2.3_git]) define([PRODUCT_BUGREPORT], [openvpn-users@lists.sourceforge.net]) define([PRODUCT_VERSION_RESOURCE], [2,3,0,0]) dnl define the TAP version |