aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--.svncommitters1
-rw-r--r--ChangeLog124
-rw-r--r--ChangeLog.IPv6394
-rw-r--r--INSTALL4
-rw-r--r--INSTALL-win32.txt23
-rw-r--r--Makefile.am21
-rw-r--r--README.IPv68
-rw-r--r--README.ipv681
-rw-r--r--TODO.IPv6149
-rw-r--r--TODO.ipv630
-rw-r--r--acinclude.m4280
-rw-r--r--buffer.c26
-rw-r--r--buffer.h6
-rw-r--r--common.h2
-rw-r--r--configure.ac119
-rw-r--r--configure_h.awk39
-rw-r--r--configure_log.awk33
-rw-r--r--contrib/OCSP_check/OCSP_check.sh111
-rw-r--r--contrib/pull-resolv-conf/client.down51
-rw-r--r--contrib/pull-resolv-conf/client.up88
-rw-r--r--crypto.c3
-rw-r--r--cryptoapi.c2
-rwxr-xr-xeasy-rsa/2.0/build-ca2
-rwxr-xr-xeasy-rsa/2.0/build-dh2
-rwxr-xr-xeasy-rsa/2.0/build-inter2
-rwxr-xr-xeasy-rsa/2.0/build-key2
-rwxr-xr-xeasy-rsa/2.0/build-key-pass2
-rwxr-xr-xeasy-rsa/2.0/build-key-pkcs122
-rwxr-xr-xeasy-rsa/2.0/build-key-server2
-rwxr-xr-xeasy-rsa/2.0/build-req2
-rwxr-xr-xeasy-rsa/2.0/build-req-pass2
-rwxr-xr-xeasy-rsa/2.0/clean-all2
-rwxr-xr-xeasy-rsa/2.0/inherit-inter2
-rwxr-xr-xeasy-rsa/2.0/list-crl2
-rwxr-xr-xeasy-rsa/2.0/pkitool6
-rwxr-xr-xeasy-rsa/2.0/revoke-full2
-rwxr-xr-xeasy-rsa/2.0/sign-req2
-rw-r--r--easy-rsa/Windows/build-ca-pass.bat16
-rw-r--r--easy-rsa/Windows/build-key-pass.bat16
-rw-r--r--easy-rsa/Windows/build-key-server-pass.bat16
-rw-r--r--error.c41
-rw-r--r--error.h17
-rw-r--r--forward.c22
-rw-r--r--helper.c49
-rw-r--r--httpdigest.c286
-rw-r--r--httpdigest.h120
-rw-r--r--ieproxy.c3
-rw-r--r--init.c170
-rw-r--r--init.h1
-rwxr-xr-x[-rw-r--r--]install-win32/makeopenvpn62
-rw-r--r--install-win32/openssl/openssl097.patch48
-rw-r--r--install-win32/openssl/openssl098.patch34
-rw-r--r--list.c24
-rw-r--r--list.h33
-rw-r--r--manage.c10
-rw-r--r--mbuf.c16
-rw-r--r--mbuf.h3
-rw-r--r--misc.c104
-rw-r--r--misc.h15
-rw-r--r--mroute.c175
-rw-r--r--mroute.h17
-rw-r--r--msvc/autodefs.h.in40
-rw-r--r--msvc/config.py186
-rw-r--r--msvc/msvc.mak104
-rw-r--r--mtcp.c10
-rw-r--r--mudp.c3
-rw-r--r--multi.c253
-rw-r--r--multi.h2
-rw-r--r--occ.c2
-rw-r--r--openvpn-plugin.h246
-rw-r--r--openvpn.81825
-rw-r--r--openvpn.h11
-rw-r--r--options.c511
-rw-r--r--options.h33
-rw-r--r--otime.c2
-rw-r--r--otime.h1
-rw-r--r--perf.c6
-rw-r--r--pf.c40
-rw-r--r--ping.c2
-rw-r--r--pkcs11.c2
-rw-r--r--plugin.c52
-rw-r--r--plugin.h10
-rw-r--r--plugin/auth-pam/README2
-rw-r--r--plugin/auth-pam/auth-pam.c53
-rw-r--r--plugin/examples/log_v3.c245
-rw-r--r--pool.c75
-rw-r--r--pool.h8
-rw-r--r--proto.h15
-rw-r--r--proxy.c4
-rw-r--r--ps.c18
-rw-r--r--push.c39
-rw-r--r--reliable.c2
-rw-r--r--route.c625
-rw-r--r--route.h61
-rwxr-xr-xsample-config-files/firewall.sh2
-rwxr-xr-xsample-scripts/bridge-start2
-rwxr-xr-xsample-scripts/bridge-stop2
-rwxr-xr-xsample-scripts/openvpn.init8
-rwxr-xr-xsample-scripts/verify-cn42
-rw-r--r--schedule.c4
-rw-r--r--schedule.h8
-rw-r--r--service-win32/msvc.mak30
-rwxr-xr-xservice-win32/openvpnserv.c46
-rw-r--r--sig.c9
-rw-r--r--socket.c1194
-rw-r--r--socket.h248
-rw-r--r--socks.c163
-rw-r--r--socks.h2
-rw-r--r--ssl.c270
-rw-r--r--ssl.h16
-rw-r--r--status.c4
-rw-r--r--syshead.h39
-rw-r--r--t_client.rc-sample83
-rwxr-xr-xt_client.sh.in298
-rwxr-xr-xtap-win32/SOURCES.in3
-rwxr-xr-xtap-win32/common.h2
-rwxr-xr-xtap-win32/proto.h60
-rwxr-xr-xtap-win32/tapdrvr.c197
-rwxr-xr-xtap-win32/types.h1
-rw-r--r--thread.c156
-rw-r--r--thread.h235
-rw-r--r--tun.c718
-rw-r--r--tun.h11
-rw-r--r--version.m44
-rw-r--r--win/autodefs.h.in62
-rw-r--r--win/build.py45
-rw-r--r--win/build_all.py87
-rw-r--r--win/build_ddk.py109
-rw-r--r--win/build_exe.py30
-rw-r--r--win/config.h.in (renamed from config-win32.h)628
-rw-r--r--win/config.py39
-rw-r--r--win/config_all.py26
-rw-r--r--win/config_tap.py70
-rw-r--r--win/config_ti.py36
-rw-r--r--win/js.py20
-rw-r--r--win/make_dist.py163
-rw-r--r--win/msvc.mak.in114
-rwxr-xr-xwin/openvpn.nsi821
-rwxr-xr-xwin/setpath.nsi231
-rw-r--r--win/settings.in51
-rw-r--r--win/show.py19
-rw-r--r--win/sign.py46
-rw-r--r--win/tap_span.py258
-rw-r--r--win/wb.py537
-rw-r--r--win32.c40
-rw-r--r--win32.h10
147 files changed, 10528 insertions, 4187 deletions
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..91ff553
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1 @@
+James Yonan <james@openvpn.net> james <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
diff --git a/.svncommitters b/.svncommitters
new file mode 100644
index 0000000..0772102
--- /dev/null
+++ b/.svncommitters
@@ -0,0 +1 @@
+james = James Yonan <james@openvpn.net>
diff --git a/ChangeLog b/ChangeLog
index 5580409..93ef65f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,125 @@
OpenVPN Change Log
-Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
-
-2010.08.09 -- Version 2.1.2
+Copyright (C) 2002-2011 OpenVPN Technologies, Inc. <sales@openvpn.net>
+
+2011.03.24 -- Version 2.2-RC2
+Alon Bar-Lev (1):
+ Windows cross-compile cleanup
+
+David Sommerseth (2):
+ Open log files as text files on Windows
+ Clarify default value for the --inactive option.
+
+Gert Doering (1):
+ Implement IPv6 in TUN mode for Windows TAP driver.
+
+Samuli Seppänen (6):
+ Added support for prebuilt TAP-drivers. Automated embedding manifests.
+ Fixes to win/openvpn.nsi
+ Replaced config-win32.h with win/config.h.in
+ Updated INSTALL-win32.txt
+ Fixes to Makefile.am
+ Clarified --client-config-dir section on the man-page.
+
+Ville Skyttä (1):
+ Fix line continuation in chkconfig init script description.
+
+2011.02.28 -- Version 2.2-RC
+David Sommerseth (3):
+ Make the --x509-username-field feature an opt-in feature
+ Fix compiler warning when compiling against OpenSSL 1.0.0
+ Fix packaging of config-win32.h and service-win32/msvc.mak
+
+James Yonan (1):
+ Minor addition of logging info before and after execution of Windows net commands.
+
+Matthias Andree (1):
+ Change variadic macros to C99 style.
+
+Samuli Seppänen (15):
+ Added ENABLE_PASSWORD_SAVE to config-win32.h
+ Added a nmake makefile for openvpnserv.exe building
+ Moved TAP-driver version info to version.m4. Cleaned up win/settings.in.
+ Added helper functionality to win/wb.py
+ Added support for viewing config-win32.h paramters to win/show.py
+ Added comments and made small modifications to win/msvc.mak.in
+ Added command-line switch to win/build_all.py to skip TAP driver building
+ Added configure.h and version.m4 variable parsing to win/config.py
+ Added openvpnserv.exe building to win/build.py
+ Added comments to win/build_ddk.py
+ Several modifications to win/make_dist.py to allow building the NSI installer
+ Copied install-win32/setpath.nsi to win/setpath.nsi
+ Added first version of NSI installer script to win/openvpn.nsi
+ Changes to buildsystem patchset
+ Temporary snprintf-related fix to service-win32/openvpnserv.c
+
+2010.11.25 -- Version 2.2-beta5
+
+Samuli Seppänen (1):
+ Fixed an issue causing a build failure with MS Visual Studio 2008.
+
+2010.11.18 -- Version 2.2-beta4
+
+David Sommerseth (10):
+ Clarified --explicit-exit-notify man page entry
+ Clean-up: Remove pthread and mutex locking code
+ Clean-up: Remove more dead and inactive code paths
+ Clean-up: Removing useless code - hash related functions
+ Use stricter snprintf() formatting in socks_username_password_auth() (v3)
+ Fix compiler warnings about not used dummy() functions
+ Fixed potential misinterpretation of boolean logic
+ Only add some functions when really needed
+ Removed functions not being used anywhere
+ Merged add_bypass_address() and add_host_route_if_nonlocal()
+
+Gert Doering (3):
+ Integrate support for TAP mode on Solaris, written by Kazuyoshi Aizawa <admin2@whiteboard.ne.jp>.
+ Make "topology subnet" work on Solaris
+ Improved man page entry for script_type
+
+James Yonan (5):
+ Fixed initialization bug in route_list_add_default_gateway (Gert Doering).
+ Implement challenge/response authentication support in client mode
+ Make base64.h have the same conditional compilation expression as base64.c.
+ Fixed compiling issues when using --disable-crypto
+ In verify_callback, the subject var should be freed by OPENSSL_free, not free
+
+Jesse Young (1):
+ Remove hardcoded path to resolvconf
+
+Lars Hupel (1):
+ Add HTTP/1.1 Host header
+
+Pierre Bourdon (1):
+ Adding support for SOCKS plain text authentication
+
+Samuli Seppänen (2):
+ Added check for variable CONFIGURE_DEFINES into options.c
+ Added command-line option parser and an unsigned build option to build_all.py
+
+2010.08.21 -- Version 2.2-beta3
+
+* Attempt to fix issue where domake-win build system was not properly
+ signing drivers and .exe files.
+
+ Added win/tap_span.py for building multiple versions of the TAP driver
+ and tapinstall binaries using different DDK versions to span from Win2K
+ to Win7 and beyond.
+
+* Community patches
+ David Sommerseth (2):
+ Test framework improvment - Do not FAIL if t_client.rc is missing
+ More t_client.sh updates - exit with SKIP when we want to skip
+
+ Gert Doering (4):
+ Fix compile problems on NetBSD and OpenBSD
+ Fix <net/if.h> compile time problems on OpenBSD for good
+ full "VPN client connect" test framework for OpenVPN
+ Build t_client.sh by configure at run-time.
+
+ chantra (1):
+ Fixes openssl-1.0.0 compilation warning
+
+2010.08.16 -- Version 2.2-beta2
* Windows security issue:
Fixed potential local privilege escalation vulnerability in
diff --git a/ChangeLog.IPv6 b/ChangeLog.IPv6
new file mode 100644
index 0000000..38f4446
--- /dev/null
+++ b/ChangeLog.IPv6
@@ -0,0 +1,394 @@
+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
+
diff --git a/INSTALL b/INSTALL
index 7af6426..ab0d671 100644
--- a/INSTALL
+++ b/INSTALL
@@ -42,7 +42,7 @@ SUPPORTED PLATFORMS:
(4) Mac OS X Darwin
(5) FreeBSD
(6) NetBSD
- (7) Windows (Win 2K and higher)
+ (7) Windows (WinXP and higher)
SUPPORTED PROCESSOR ARCHITECTURES:
In general, OpenVPN is word size and endian independent, so
@@ -280,7 +280,7 @@ TUN/TAP Driver Configuration:
needs to be manually copied to /kernel/drv/sparcv9/ and then a
reconfiguration reboot. (boot -r).
-* Windows 2000/XP/2003/Vista
+* Windows XP/2003/Vista
See domake-win for building instructions.
See INSTALL-win32.txt for usage info.
diff --git a/INSTALL-win32.txt b/INSTALL-win32.txt
index cc79d72..5a0f3a9 100644
--- a/INSTALL-win32.txt
+++ b/INSTALL-win32.txt
@@ -1,4 +1,4 @@
-IMPORTANT NOTE FOR VISTA USERS
+IMPORTANT NOTE FOR WINDOWS VISTA/7 USERS
Note that on Windows Vista, you will need to run the OpenVPN
GUI with administrator privileges, so that it can add routes
@@ -9,14 +9,15 @@ desktop icon, and selecting "Run as administrator".
GENERAL QUICKSTART FOR WINDOWS
The OpenVPN Client requires a configuration file
-and key/certificate files. You should obtain
-these and save them to \Program Files\OpenVPN\config.
+and key/certificate files. You should obtain
+these and save them to OpenVPN's configuration
+directory, usually C:\Program Files\OpenVPN\config.
-To start OpenVPN, first run the OpenVPN GUI by double
-clicking on the desktop icon or start menu icon.
-
-The OpenVPN GUI is a system-tray applet, so an icon for the
-GUI will appear in 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.
+You can run OpenVPN as a Windows system service or by using
+the client GUI. To use the OpenVPN GUI, double click on the
+desktop icon or start menu icon. The OpenVPN GUI is a
+system-tray applet, so an icon for the GUI will appear in
+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.
diff --git a/Makefile.am b/Makefile.am
index 97e0971..32b40bb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,6 +6,7 @@
# packet compression.
#
# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+# Copyright (C) 2010 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
@@ -37,7 +38,7 @@ MAINTAINERCLEANFILES = \
$(srcdir)/depcomp $(srcdir)/aclocal.m4 \
$(srcdir)/config.guess $(srcdir)/config.sub \
$(srcdir)/openvpn.spec
-CLEANFILES = openvpn.8.html
+CLEANFILES = openvpn.8.html configure.h
EXTRA_DIST = \
easy-rsa \
@@ -56,22 +57,25 @@ SUBDIRS = \
service-win32 \
install-win32
-TESTS = t_lpback.sh t_cltsrv.sh
+TESTS = t_client.sh t_lpback.sh t_cltsrv.sh
sbin_PROGRAMS = openvpn
-dist_noinst_HEADERS =
+dist_doc_DATA = \
+ management/management-notes.txt
dist_noinst_SCRIPTS = \
$(TESTS) \
doclean \
domake-win \
- t_cltsrv-down.sh
+ t_cltsrv-down.sh \
+ configure_h.awk configure_log.awk
dist_noinst_DATA = \
openvpn.spec \
COPYRIGHT.GPL \
PORTS \
- INSTALL-win32.txt
+ INSTALL-win32.txt \
+ service-win32/msvc.mak
openvpn_SOURCES = \
base64.c base64.h \
@@ -138,11 +142,16 @@ openvpn_SOURCES = \
ssl.c ssl.h \
status.c status.h \
syshead.h \
- thread.c thread.h \
tun.c tun.h \
win32.h win32.c \
cryptoapi.h cryptoapi.c
+nodist_openvpn_SOURCES = configure.h
+options.$(OBJEXT): configure.h
+
+configure.h: Makefile
+ awk -f $(srcdir)/configure_h.awk config.h > $@
+ awk -f $(srcdir)/configure_log.awk config.log >> $@
dist-hook:
cd $(distdir) && for i in $(EXTRA_DIST) $(SUBDIRS) ; do find $$i -name .svn -type d -prune -exec rm -rf '{}' ';' ; rm -f `find $$i -type f | grep -E '(^|\/)\.?\#|\~$$|\.s?o$$'` ; done
diff --git a/README.IPv6 b/README.IPv6
new file mode 100644
index 0000000..ca578f2
--- /dev/null
+++ b/README.IPv6
@@ -0,0 +1,8 @@
+This is an experimentally patched version of OpenVPN 2.1 with IPv6
+payload support.
+
+Go here for release notes and documentation:
+
+ http://www.greenie.net/ipv6/openvpn.html
+
+Gert Doering, 31.12.2009
diff --git a/README.ipv6 b/README.ipv6
new file mode 100644
index 0000000..4295f85
--- /dev/null
+++ b/README.ipv6
@@ -0,0 +1,81 @@
+[ 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()
+
+* TODO: 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 ...:
diff --git a/TODO.IPv6 b/TODO.IPv6
new file mode 100644
index 0000000..092a1a3
--- /dev/null
+++ b/TODO.IPv6
@@ -0,0 +1,149 @@
+known issues for IPv6 payload support in OpenVPN
+-----------------------------------------------
+
+1.) "--topology subnet" doesn't work together with IPv6 payload on FreeBSD
+ (verified for FreeBSD server, Linux/ifconfig client, problems
+ with ICMP6 neighbor solicitations from BSD not being answered by Linux)
+
+2.) NetBSD IPv6 support doesn't work
+ ("connected" route is not auto-created, "route-ipv6" adding fails)
+
+ * fixed, 3.1.10 *
+
+3.) route deletion for IPv6 routes is not yet done
+
+ * fixed for configured routes, 3.1.10 *
+ * missing for manual-ifconfig-connected (NetBSD, Darwin, Win32)
+
+4.) do "ifconfig tun0 inet6 unplumb" or "ifconfig tun0 destroy" for
+ Solaris, *BSD, ... at program termination time, to clean up leftovers
+ (unless tunnel persistance is desired).
+
+ For Solaris, only the "ipv6 tun0" is affected, for the *BSDs all tun0
+ stay around.
+
+4a.) deconfigure IPv6 on tun interface on session termination, otherwise
+ one could end up with something like this (on NetBSD):
+
+tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
+ inet 10.9.0.18 -> 10.9.0.17 netmask 0xffffffff
+ inet6 fe80::a00:20ff:fece:d299%tun0 -> prefixlen 64 scopeid 0x3
+ inet6 2001:608:4:eff::2000:3 -> prefixlen 64
+ inet6 2001:608:4:eff::1:3 -> prefixlen 64
+
+ (pool was changed, previous address still active on tun0, breakage)
+
+ * semi-fixed for NetBSD, 28.2.10, always do tun0 destroy / tun0 create
+ before actual ifconfig -- tunnel still lingers after OpenVPN quits
+
+4b.) verify this - on FreeBSD, tun0 is auto-destroyed if created by
+ opening /dev/tun (and lingers if created by "ifconfig tun0 create")
+
+ -> use for persistant tunnels on not-linux?
+
+5.) add new option "ifconfig-ipv6-push"
+ (per-client static IPv6 assignment, -> radiusplugin, etc)
+
+ * implemented, 14.1.10 *
+
+6.) add new option "route-ipv6-gateway"
+
+7.) add "full" gateway handling for IPv6 in route.c
+ (right now, the routes are just sent down the tun interface, if the
+ operating system in questions supports that, without care for the
+ gateway address - which does not work for gateways that are supposed
+ to point elsewhere. Also, it doesn't work for TAP interfaces.
+
+8.) full IPv6 support for TAP interfaces
+ (main issue should be routes+gateway - and testing :-) )
+
+ test 2010/09/24: TAP itself works on linux/ifconfig+iproute2, but
+ route-via-tap doesn't work at all (route points to "tap0" which fails)
+
+17:51:14.075412 fe:ab:6e:c5:53:71 > 33:33:ff:00:00:01, ethertype IPv6 (0x86dd), length 86: 2001:608:4:a053::1:0 > ff02::1:ff00:1: ICMP6, neighbor solicitation, who has 2001:608:4:a001::1, length 32
+
+ how is iroute-via-tap supposed to work??
+
+9.) verify that iroute-ipv6 and route-ipv6 interact in the same way as
+ documented for iroute/route:
+
+ A's subnet, OpenVPN must push this route to all clients
+ EXCEPT for A, since the subnet is already owned by A.
+ OpenVPN accomplishes this by not
+ not pushing a route to a client
+ if it matches one of the client's iroutes.
+
+10.) extend "ifconfig-ipv6" to handle specification of /netbits, pushing
+ of /netbits, and correctly ifconfig'ing this
+ (default, if not specified: /64)
+
+11.) do not add ipv6-routes if tun-ipv6 is not set - complain instead
+
+ * done * 12.1.10
+
+12.) handle incoming [::] and [fe80:...] packets in tun-p2mp MULTI mode
+ (most likely those are DAD packets)
+ silently ignore DAD?
+ Or accept-and-forward iff (multicast && client2client)?
+ handle NS/NA
+
+13.) from Martin List-Petersen:
+
+ One thing, and I guess this requires modifications in
+ network-manager-openvpn: It also works, BUT ignores "push
+ route-ipv6-gateway" and "push route-ipv6 ...." (obviously routes pushed
+ from the server) entirely.
+
+14.) from ##openvpn-discussion:
+
+ new features should be #ifdef'ed
+
+ (check whether this is feasible at all)
+
+15.) IPv6 related environment variables
+
+ - document all of them in openvpn.8
+ - make sure that all existing IPv4 stuff has IPv6 counterparts
+
+16.) OpenBSD
+ - implement ifconfig/route for IPv6
+ - revert ifconfig/open_tun order to "normal" (separate commit!!!)
+ (openvpn-devel, Subject: OpenBSD)
+ - test
+
+17.) client-option (Elwood)
+ - ignore-v6-push-options yes/no
+ - ignore-v6-route-push ("as for IPv4 routes")
+
+18.) fail-save? "what if 'ip -6 addr add' fails" -> fail, or fallback to v4?
+ (-> recomment setting "ignore-v6-push-options yes")
+
+19.) safety check: if connecting over IPv6 (v6 transport) and the pushed
+ route-ipv6 network encompasses the server IPv6 address, make sure
+ we at least log a warning (until we can fiddle with external routing
+ to make this work correctly).
+
+20.) show "route add" / "route delete" commands for IPv6 in log file
+ (we show the "ifconfig" commands, so why not the routes?)
+
+ 2010-08-07: this is a null-feature - it's already there, but with
+ different debug level (M_INFO vs. D_ROUTE) so user
+ didn't notice
+
+21.) enable ipv6-only server operations
+ - decouple ipv6 pool handling from ipv4 pool
+ - make sure Rest of OpenVPN doesn't assume "there will always be IPv4"
+
+22.) implement --learn-address for IPv6
+
+23.) FreeBSD 8 seems to require explicit setting of the "ifconfig" IPv6
+ route, while FreeBSD 6+7 don't --> more testing, and code fix
+
+ workaround for the time being: just add
+
+ server-ipv6 2001:608:4:a051::/64
+ route-ipv6 2001:608:4:a051::/64
+
+ to the config
+
+ (problem + workaround applies both to tun and tap style devices)
diff --git a/TODO.ipv6 b/TODO.ipv6
new file mode 100644
index 0000000..966af2d
--- /dev/null
+++ b/TODO.ipv6
@@ -0,0 +1,30 @@
+[ Last updated: 11-Nov-2009. ]
+
+* All platforms:
+ o mgmt console: as currently passes straight in_addr_t bits around
+
+ 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
+
+ o use AI_PASSIVE
+
+ o the getaddr()/getaddr6() interface is not prepared for handling socktype
+ "tagging", currently I abuse the sockflags bits for getting the ai_socktype
+ downstream.
+
+ 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
+
+ o do something with multi mode learn routes, for now just ignoring
+ ipv6 addresses seems the most sensible thing to do, because there's
+ no support for intra-tunnel ipv6 stuff.
+
+* 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
+
+* N/A:
+ o this is ipv6 *endpoint* support, so don't expect "ifconfig6"-like
+ support in this patch
diff --git a/acinclude.m4 b/acinclude.m4
index f099de5..acfc01d 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -90,34 +90,30 @@ AC_DEFUN([TYPE_SOCKLEN_T],
AC_MSG_CHECKING([for socklen_t equivalent])
AC_CACHE_VAL([curl_cv_socklen_t_equiv],
[
- # Systems have either "struct sockaddr *" or
- # "void *" as the second argument to getpeername
- curl_cv_socklen_t_equiv=
- for arg2 in "struct sockaddr" void; do
- for t in int size_t unsigned long "unsigned long"; do
- AC_TRY_COMPILE([
- #ifdef _WIN32
- #include <windows.h>
- #define PREFIX1 WINSOCK_API_LINKAGE
- #define PREFIX2 PASCAL
- #else
- #include <sys/types.h>
- #include <sys/socket.h>
- #define PREFIX1
- #define PREFIX2
- #define SOCKET int
- #endif
-
- PREFIX1 int PREFIX2 getpeername (SOCKET, $arg2 *, $t *);
- ],[
- $t len;
- getpeername(0,0,&len);
- ],[
- curl_cv_socklen_t_equiv="$t"
- break
- ])
+ case "$host" in
+ *-mingw*) curl_cv_socklen_t_equiv=int ;;
+ *)
+ # Systems have either "struct sockaddr *" or
+ # "void *" as the second argument to getpeername
+ curl_cv_socklen_t_equiv=
+ for arg2 in "struct sockaddr" void; do
+ for t in int size_t unsigned long "unsigned long"; do
+ AC_TRY_COMPILE([
+ #include <sys/types.h>
+ #include <sys/socket.h>
+
+ int getpeername (int, $arg2 *, $t *);
+ ],[
+ $t len;
+ getpeername(0,0,&len);
+ ],[
+ curl_cv_socklen_t_equiv="$t"
+ break
+ ])
+ done
done
- done
+ ;;
+ esac
if test "x$curl_cv_socklen_t_equiv" = x; then
AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
@@ -127,229 +123,9 @@ AC_DEFUN([TYPE_SOCKLEN_T],
AC_DEFINE_UNQUOTED(socklen_t, $curl_cv_socklen_t_equiv,
[type to use in place of socklen_t if not defined])],
[#include <sys/types.h>
-#include <sys/socket.h>])
+#ifdef WIN32
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#endif])
])
-
-dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
-dnl
-dnl This macro figures out how to build C programs using POSIX
-dnl threads. It sets the PTHREAD_LIBS output variable to the threads
-dnl library and linker flags, and the PTHREAD_CFLAGS output variable
-dnl to any special C compiler flags that are needed. (The user can also
-dnl force certain compiler flags/libs to be tested by setting these
-dnl environment variables.)
-dnl
-dnl Also sets PTHREAD_CC to any special C compiler that is needed for
-dnl multi-threaded programs (defaults to the value of CC otherwise).
-dnl (This is necessary on AIX to use the special cc_r compiler alias.)
-dnl
-dnl If you are only building threads programs, you may wish to
-dnl use these variables in your default LIBS, CFLAGS, and CC:
-dnl
-dnl LIBS="$PTHREAD_LIBS $LIBS"
-dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-dnl CC="$PTHREAD_CC"
-dnl
-dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
-dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE
-dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
-dnl
-dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
-dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands
-dnl to run it if it is not found. If ACTION-IF-FOUND is not specified,
-dnl the default action will define HAVE_PTHREAD.
-dnl
-dnl Please let the authors know if this macro fails on any platform,
-dnl or if you have any other suggestions or comments. This macro was
-dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org)
-dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread
-dnl macros posted by AFC to the autoconf macro repository. We are also
-dnl grateful for the helpful feedback of numerous users.
-dnl
-dnl @author Steven G. Johnson <stevenj@alum.mit.edu> and Alejandro Forero Cuervo <bachue@bachue.com>
-
-AC_DEFUN([ACX_PTHREAD], [
-AC_REQUIRE([AC_CANONICAL_HOST])
-acx_pthread_ok=no
-
-# We used to check for pthread.h first, but this fails if pthread.h
-# requires special compiler flags (e.g. on True64 or Sequent).
-# It gets checked for in the link test anyway.
-
-# First of all, check if the user has set any of the PTHREAD_LIBS,
-# etcetera environment variables, and if threads linking works using
-# them:
-if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- save_LIBS="$LIBS"
- LIBS="$PTHREAD_LIBS $LIBS"
- AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
- AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
- AC_MSG_RESULT($acx_pthread_ok)
- if test x"$acx_pthread_ok" = xno; then
- PTHREAD_LIBS=""
- PTHREAD_CFLAGS=""
- fi
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
-fi
-
-# We must check for the threads library under a number of different
-# names; the ordering is very important because some systems
-# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
-# libraries is broken (non-POSIX).
-
-# Create a list of thread flags to try. Items starting with a "-" are
-# C compiler flags, and other items are library names, except for "none"
-# which indicates that we try without any flags at all.
-
-acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt"
-
-# The ordering *is* (sometimes) important. Some notes on the
-# individual items follow:
-
-# pthreads: AIX (must check this before -lpthread)
-# none: in case threads are in libc; should be tried before -Kthread and
-# other compiler flags to prevent continual compiler warnings
-# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
-# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
-# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
-# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
-# -pthreads: Solaris/gcc
-# -mthreads: Mingw32/gcc, Lynx/gcc
-# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
-# doesn't hurt to check since this sometimes defines pthreads too;
-# also defines -D_REENTRANT)
-# pthread: Linux, etcetera
-# --thread-safe: KAI C++
-
-case "$target" in
- *solaris*)
-
- # On Solaris (at least, for some versions), libc contains stubbed
- # (non-functional) versions of the pthreads routines, so link-based
- # tests will erroneously succeed. (We need to link with -pthread or
- # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
- # a function called by this macro, so we could check for that, but
- # who knows whether they'll stub that too in a future libc.) So,
- # we'll just look for -pthreads and -lpthread first:
-
- acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
- ;;
-esac
-
-if test x"$acx_pthread_ok" = xno; then
-for flag in $acx_pthread_flags; do
-
- case $flag in
- none)
- AC_MSG_CHECKING([whether pthreads work without any flags])
- ;;
-
- -*)
- AC_MSG_CHECKING([whether pthreads work with $flag])
- PTHREAD_CFLAGS="$flag"
- ;;
-
- *)
- AC_MSG_CHECKING([for the pthreads library -l$flag])
- PTHREAD_LIBS="-l$flag"
- ;;
- esac
-
- save_LIBS="$LIBS"
- save_CFLAGS="$CFLAGS"
- LIBS="$PTHREAD_LIBS $LIBS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-
- # Check for various functions. We must include pthread.h,
- # since some functions may be macros. (On the Sequent, we
- # need a special flag -Kthread to make this header compile.)
- # We check for pthread_join because it is in -lpthread on IRIX
- # while pthread_create is in libc. We check for pthread_attr_init
- # due to DEC craziness with -lpthreads. We check for
- # pthread_cleanup_push because it is one of the few pthread
- # functions on Solaris that doesn't have a non-functional libc stub.
- # We try pthread_create on general principles.
- AC_TRY_LINK([#include <pthread.h>],
- [pthread_t th; pthread_join(th, 0);
- pthread_attr_init(0); pthread_cleanup_push(0, 0);
- pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
- [acx_pthread_ok=yes])
-
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
-
- AC_MSG_RESULT($acx_pthread_ok)
- if test "x$acx_pthread_ok" = xyes; then
- break;
- fi
-
- PTHREAD_LIBS=""
- PTHREAD_CFLAGS=""
-done
-fi
-
-# Various other checks:
-if test "x$acx_pthread_ok" = xyes; then
- save_LIBS="$LIBS"
- LIBS="$PTHREAD_LIBS $LIBS"
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
-
- # Detect AIX lossage: threads are created detached by default
- # and the JOINABLE attribute has a nonstandard name (UNDETACHED).
- AC_MSG_CHECKING([for joinable pthread attribute])
- AC_TRY_LINK([#include <pthread.h>],
- [int attr=PTHREAD_CREATE_JOINABLE;],
- ok=PTHREAD_CREATE_JOINABLE, ok=unknown)
- if test x"$ok" = xunknown; then
- AC_TRY_LINK([#include <pthread.h>],
- [int attr=PTHREAD_CREATE_UNDETACHED;],
- ok=PTHREAD_CREATE_UNDETACHED, ok=unknown)
- fi
- if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then
- AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok,
- [Define to the necessary symbol if this constant
- uses a non-standard name on your system.])
- fi
- AC_MSG_RESULT(${ok})
- if test x"$ok" = xunknown; then
- AC_MSG_WARN([we do not know how to create joinable pthreads])
- fi
-
- AC_MSG_CHECKING([if more special flags are required for pthreads])
- flag=no
- case "$target" in
- *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";;
- *solaris* | alpha*-osf* | *linux*) flag="-D_REENTRANT";;
- esac
- AC_MSG_RESULT(${flag})
- if test "x$flag" != xno; then
- PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
- fi
-
- LIBS="$save_LIBS"
- CFLAGS="$save_CFLAGS"
-
- # More AIX lossage: must compile with cc_r
- AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
-else
- PTHREAD_CC="$CC"
-fi
-
-AC_SUBST(PTHREAD_LIBS)
-AC_SUBST(PTHREAD_CFLAGS)
-AC_SUBST(PTHREAD_CC)
-
-# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
-if test x"$acx_pthread_ok" = xyes; then
- ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
- :
-else
- acx_pthread_ok=no
- $2
-fi
-
-])dnl ACX_PTHREAD
diff --git a/buffer.c b/buffer.c
index 5499d99..cff2616 100644
--- a/buffer.c
+++ b/buffer.c
@@ -28,7 +28,6 @@
#include "buffer.h"
#include "error.h"
#include "mtu.h"
-#include "thread.h"
#include "memdbg.h"
@@ -215,10 +214,31 @@ buf_printf (struct buffer *buf, const char *format, ...)
return ret;
}
+bool
+buf_puts(struct buffer *buf, const char *str)
+{
+ int ret = false;
+ uint8_t *ptr = BEND (buf);
+ int cap = buf_forward_capacity (buf);
+ if (cap > 0)
+ {
+ strncpynt ((char *)ptr,str, cap);
+ *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
+ buf->len += (int) strlen ((char *)ptr);
+ ret = true;
+ }
+ return ret;
+}
+
+
/*
* This is necessary due to certain buggy implementations of snprintf,
* that don't guarantee null termination for size > 0.
+ *
* Return false on overflow.
+ *
+ * This function is duplicated into service-win32/openvpnserv.c
+ * Any modifications here should be done to the other place as well.
*/
bool openvpn_snprintf(char *str, size_t size, const char *format, ...)
@@ -300,10 +320,8 @@ gc_malloc (size_t size, bool clear, struct gc_arena *a)
#endif
check_malloc_return (e);
ret = (char *) e + sizeof (struct gc_entry);
- /*mutex_lock_static (L_GC_MALLOC);*/
e->next = a->list;
a->list = e;
- /*mutex_unlock_static (L_GC_MALLOC);*/
}
else
{
@@ -325,10 +343,8 @@ void
x_gc_free (struct gc_arena *a)
{
struct gc_entry *e;
- /*mutex_lock_static (L_GC_MALLOC);*/
e = a->list;
a->list = NULL;
- /*mutex_unlock_static (L_GC_MALLOC);*/
while (e != NULL)
{
diff --git a/buffer.h b/buffer.h
index 58273e2..1fe3c08 100644
--- a/buffer.h
+++ b/buffer.h
@@ -26,7 +26,6 @@
#define BUFFER_H
#include "basic.h"
-#include "thread.h"
#define BUF_SIZE_MAX 1000000
@@ -278,6 +277,11 @@ bool buf_printf (struct buffer *buf, const char *format, ...)
;
/*
+ * puts append to a buffer with overflow check
+ */
+bool buf_puts (struct buffer *buf, const char *str);
+
+/*
* Like snprintf but guarantees null termination for size > 0
*/
bool openvpn_snprintf(char *str, size_t size, const char *format, ...)
diff --git a/common.h b/common.h
index 0ca7323..de2d609 100644
--- a/common.h
+++ b/common.h
@@ -102,6 +102,6 @@ typedef unsigned long ptr_type;
/*
* Script security warning
*/
-#define SCRIPT_SECURITY_WARNING "openvpn_execve: 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. Use '--script-security 3 system' for backward compatibility with 2.1_rc8 and earlier. See --help text or man page for detailed info."
#endif
diff --git a/configure.ac b/configure.ac
index 729ce40..a3789d9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,7 +32,6 @@ AC_CONFIG_SRCDIR(syshead.h)
dnl Guess host type.
AC_CANONICAL_HOST
-AC_CANONICAL_SYSTEM
AM_INIT_AUTOMAKE(openvpn, [$PACKAGE_VERSION])
AC_ARG_WITH(cygwin-native,
@@ -48,7 +47,7 @@ case "${host}" in
WIN32="yes"
cross_compiling="yes"
;;
- *-cygwin*)
+ *-*-cygwin*)
AC_MSG_CHECKING([cygwin mode to use])
if test "${CYGWIN_NATIVE}" = "yes"; then
AC_MSG_RESULT([Using native win32])
@@ -87,6 +86,12 @@ AC_ARG_ENABLE(ssl,
[SSL="yes"]
)
+AC_ARG_ENABLE(x509-alt-username,
+ [ --enable-x509-alt-username Enable the --x509-username-field feature],
+ [X509ALTUSERNAME="$enableval"],
+ [X509ALTUSERNAME="no"]
+)
+
AC_ARG_ENABLE(multi,
[ --disable-multi Disable client/server support (--mode server + client mode)],
[MULTI="$enableval"],
@@ -105,6 +110,12 @@ AC_ARG_ENABLE(plugins,
[PLUGINS="yes"]
)
+AC_ARG_ENABLE(eurephia,
+ [ --disable-eurephia Disable support for the eurephia plug-in],
+ [EUREPHIA="$enableval"],
+ [EUREPHIA="yes"]
+)
+
AC_ARG_ENABLE(management,
[ --disable-management Disable management server support],
[MANAGEMENT="$enableval"],
@@ -141,6 +152,12 @@ AC_ARG_ENABLE(multihome,
[MULTIHOME="yes"]
)
+AC_ARG_ENABLE(ipv6,
+ [ --disable-ipv6 Disable UDP/IPv6 support],
+ [PF_INET6="$enableval"],
+ [PF_INET6="yes"]
+)
+
AC_ARG_ENABLE(port-share,
[ --disable-port-share Disable TCP server port-share support (--port-share)],
[PORT_SHARE="$enableval"],
@@ -159,12 +176,6 @@ AC_ARG_ENABLE(small,
[SMALL="no"]
)
-AC_ARG_ENABLE(pthread,
- [ --enable-pthread Enable pthread support (Experimental for OpenVPN 2.0)],
- [PTHREAD="$enableval"],
- [PTHREAD="no"]
-)
-
AC_ARG_ENABLE(password-save,
[ --enable-password-save Allow --askpass and --auth-user-pass passwords to be read from a file],
[PASSWORD_SAVE="$enableval"],
@@ -273,6 +284,13 @@ AC_ARG_WITH(route-path,
)
AC_DEFINE_UNQUOTED(ROUTE_PATH, "$ROUTE", [Path to route tool])
+AC_ARG_WITH(netstat-path,
+ [ --with-netstat-path=PATH Path to netstat tool],
+ [NETSTAT="$withval"],
+ [AC_PATH_PROG([NETSTAT], [netstat], [netstat], [$PATH:/usr/local/sbin:/usr/sbin:/sbin:/etc])]
+)
+AC_DEFINE_UNQUOTED(NETSTAT_PATH, "$NETSTAT", [Path to netstat tool])
+
AC_ARG_WITH(mem-check,
[ --with-mem-check=TYPE Build with debug memory checking, TYPE = dmalloc or valgrind],
[MEMCHECK="$withval"]
@@ -281,39 +299,40 @@ AC_ARG_WITH(mem-check,
dnl fix search path, to allow compilers to find syshead.h
CPPFLAGS="$CPPFLAGS -I${srcdir}"
-dnl check target OS
-openvpn_target=$target
-if test $target_alias; then
- openvpn_target=$target_alias
+dnl check host OS
+openvpn_host=$host
+if test $host_alias; then
+ openvpn_host=$host_alias
fi
-AC_DEFINE_UNQUOTED(TARGET_ALIAS, "$openvpn_target", [A string representing our target])
-case "$target" in
-*linux*)
+AC_DEFINE_UNQUOTED(TARGET_ALIAS, "$openvpn_host", [A string representing our host])
+case "$host" in
+*-*-linux*)
AC_DEFINE(TARGET_LINUX, 1, [Are we running on Linux?])
dnl RH9 SSL headers workaround
if test -z $CS_HDR_DIR && test "$CRYPTO" = "yes"; then
CPPFLAGS="$CPPFLAGS $(pkg-config --cflags openssl 2>/dev/null)"
fi
;;
-*solaris*)
+*-*-solaris*)
AC_DEFINE(TARGET_SOLARIS, 1, [Are we running on Solaris?])
;;
-*openbsd*)
+*-*-openbsd*)
AC_DEFINE(TARGET_OPENBSD, 1, [Are we running on OpenBSD?])
;;
-*freebsd*)
+*-*-freebsd*)
AC_DEFINE(TARGET_FREEBSD, 1, [Are we running on FreeBSD?])
;;
-*netbsd*)
+*-*-netbsd*)
AC_DEFINE(TARGET_NETBSD, 1, [Are we running NetBSD?])
;;
-*darwin*)
+*-*-darwin*)
dnl some Mac OS X tendering (we use vararg macros...)
AC_DEFINE(TARGET_DARWIN, 1, [Are we running on Mac OS X?])
CPPFLAGS="$CPPFLAGS -no-cpp-precomp"
;;
-*mingw*)
+*-mingw*)
AC_DEFINE(TARGET_WIN32, 1, [Are we running WIN32?])
+ CPPFLAGS="${CPPFLAGS} -DWIN32_LEAN_AND_MEAN"
OPENVPN_ADD_LIBS(-lgdi32)
OPENVPN_ADD_LIBS(-lws2_32)
OPENVPN_ADD_LIBS(-lwininet)
@@ -321,7 +340,7 @@ case "$target" in
OPENVPN_ADD_LIBS(-liphlpapi)
OPENVPN_ADD_LIBS(-lwinmm)
;;
-*dragonfly*)
+*-*-dragonfly*)
AC_DEFINE(TARGET_DRAGONFLY, 1, [Are we running on DragonFlyBSD?])
;;
@@ -375,7 +394,10 @@ if test "${WIN32}" != "yes"; then
linux/types.h sys/poll.h sys/epoll.h err.h dnl
)
AC_CHECK_HEADERS(net/if.h,,,
- [#ifdef HAVE_SYS_SOCKET_H
+ [#ifdef HAVE_SYS_TYPES_H
+ # include <sys/types.h>
+ #endif
+ #ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
])
@@ -556,6 +578,16 @@ LDFLAGS="$LDFLAGS -Wl,--fatal-warnings"
AC_CHECK_FUNC(epoll_create, AC_DEFINE(HAVE_EPOLL_CREATE, 1, [epoll_create function is defined]))
LDFLAGS="$OLDLDFLAGS"
+dnl ipv6 support
+if test "$PF_INET6" = "yes"; then
+ AC_CHECKING([for struct sockaddr_in6 for IPv6 support])
+ AC_CHECK_TYPE(
+ [struct sockaddr_in6],
+ [AC_DEFINE(USE_PF_INET6, 1, [struct sockaddr_in6 is needed for IPv6 peer support])],
+ [],
+ [#include "syshead.h"])
+fi
+
dnl
dnl check for valgrind tool
dnl
@@ -572,32 +604,6 @@ if test "$MEMCHECK" = "valgrind"; then
fi
dnl
-dnl check for pthread library
-dnl
-
-if test "$PTHREAD" = "yes"; then
- AC_CHECKING([for pthread support])
- AC_MSG_RESULT([********* WARNING: pthread support is experimental for OpenVPN 2.0])
- ACX_PTHREAD(
- [
- case "$target" in
- *openbsd*)
- AC_MSG_RESULT([WARNING: pthread support on OpenBSD is unstable!])
- CFLAGS="$CFLAGS -pthread"
- ;;
- esac
- LIBS="$PTHREAD_LIBS $LIBS"
- CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
- CC="$PTHREAD_CC"
- AC_DEFINE(USE_PTHREAD, 1, [Use pthread-based multithreading])
- ],
- [
- AC_MSG_RESULT([I don't know how to build with pthread support on this platform.])
- AC_MSG_ERROR([try ./configure --disable-pthread])
- ])
-fi
-
-dnl
dnl check for dmalloc library
dnl
@@ -606,11 +612,7 @@ if test "$MEMCHECK" = "dmalloc"; then
AC_CHECK_HEADER(dmalloc.h,
[AC_CHECK_LIB(dmalloc, malloc,
[
- if test "$PTHREAD" = "yes"; then
- OPENVPN_ADD_LIBS(-ldmallocth)
- else
- OPENVPN_ADD_LIBS(-ldmalloc)
- fi
+ OPENVPN_ADD_LIBS(-ldmalloc)
AC_DEFINE(DMALLOC, 1, [Use dmalloc memory debugging library])
],
[AC_MSG_ERROR([dmalloc library not found.])]
@@ -638,6 +640,9 @@ if test "${WIN32}" != "yes"; then
)],
[AC_MSG_RESULT([libdl headers not found.])]
)
+ if test "$EUREPHIA" = "yes"; then
+ AC_DEFINE(ENABLE_EUREPHIA, 1, [Enable support for the eurephia plug-in])
+ fi
fi
fi
@@ -780,6 +785,11 @@ dnl
fi
fi
+dnl enable --x509-username-field feature if requested
+if test "$X509ALTUSERNAME" = "yes"; then
+ AC_DEFINE(ENABLE_X509ALTUSERNAME, 1, [Enable --x509-username-field feature])
+fi
+
dnl enable pkcs11 capability
if test "$PKCS11" = "yes"; then
AC_CHECKING([for pkcs11-helper Library and Header files])
@@ -922,6 +932,7 @@ if test -z "${htmldir}"; then
fi
# end workaround
+AC_CONFIG_FILES([t_client.sh], [chmod +x t_client.sh])
AC_OUTPUT([
Makefile
openvpn.spec
diff --git a/configure_h.awk b/configure_h.awk
new file mode 100644
index 0000000..672e745
--- /dev/null
+++ b/configure_h.awk
@@ -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) 2010 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
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program (see the file COPYING included with this
+# distribution); if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# This script will build up a line which can be included into a C program.
+# The line will contain all interesting #define statements from f.ex. ./config.h
+#
+
+BEGIN {
+ printf ("#define CONFIGURE_DEFINES \"")
+}
+
+/^#define (ENABLE|DISABLE|DEPRECATED|USE)_/ {
+ printf (" %s", $2)
+}
+
+END {
+ printf ("\"\n")
+}
diff --git a/configure_log.awk b/configure_log.awk
new file mode 100644
index 0000000..099e5c4
--- /dev/null
+++ b/configure_log.awk
@@ -0,0 +1,33 @@
+#
+# 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) 2010 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
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program (see the file COPYING included with this
+# distribution); if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# This script will build up a line which can be included into a C program.
+# The line will only contain the first entry of the ./configure line from
+# ./config.log.
+#
+
+/\$ (.*)\/configure/ {
+ printf ("#define CONFIGURE_CALL \"%s\"\n", $0)
+ exit 0
+}
diff --git a/contrib/OCSP_check/OCSP_check.sh b/contrib/OCSP_check/OCSP_check.sh
new file mode 100644
index 0000000..847be45
--- /dev/null
+++ b/contrib/OCSP_check/OCSP_check.sh
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+# Sample script to perform OCSP queries with OpenSSL
+# given a certificate serial number.
+
+# If you run your own CA, you can set up a very simple
+# OCSP server using the -port option to "openssl ocsp".
+
+# Full documentation and examples:
+# http://www.openssl.org/docs/apps/ocsp.html
+
+
+# Edit the following values to suit your needs
+
+# OCSP responder URL (mandatory)
+# YOU MUST UNCOMMENT ONE OF THESE AND SET IT TO A VALID SERVER
+#ocsp_url="http://ocsp.example.com/"
+#ocsp_url="https://ocsp.secure.example.com/"
+
+# Path to issuer certificate (mandatory)
+# YOU MUST SET THIS TO THE PATH TO THE CA CERTIFICATE
+issuer="/path/to/CAcert.crt"
+
+# use a nonce in the query, set to "-no_nonce" to not use it
+nonce="-nonce"
+
+# Verify the response
+# YOU MUST SET THIS TO THE PATH TO THE RESPONSE VERIFICATION CERT
+verify="/path/to/CAcert.crt"
+
+# Depth in the certificate chain where the cert to verify is.
+# Set to -1 to run the verification at every level (NOTE that
+# in that case you need a more complex script as the various
+# parameters for the query will likely be different at each level)
+# "0" is the usual value here, where the client certificate is
+check_depth=0
+
+cur_depth=$1 # this is the *CURRENT* depth
+common_name=$2 # CN in case you need it
+
+# minimal sanity checks
+
+err=0
+if [ -z "$issuer" ] || [ ! -e "$issuer" ]; then
+ echo "Error: issuer certificate undefined or not found!" >&2
+ err=1
+fi
+
+if [ -z "$verify" ] || [ ! -e "$verify" ]; then
+ echo "Error: verification certificate undefined or not found!" >&2
+ err=1
+fi
+
+if [ -z "$ocsp_url" ]; then
+ echo "Error: OCSP server URL not defined!" >&2
+ err=1
+fi
+
+if [ $err -eq 1 ]; then
+ echo "Did you forget to customize the variables in the script?" >&2
+ exit 1
+fi
+
+# begin
+if [ $check_depth -eq -1 ] || [ $cur_depth -eq $check_depth ]; then
+
+ eval serial="\$tls_serial_${cur_depth}"
+
+ # To successfully complete, the following must happen:
+ #
+ # - 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"
+ #
+ # Everything else fails with exit status 1.
+
+ if [ -n "$serial" ]; then
+
+ # This is only an example; you are encouraged to run this command (without
+ # redirections) manually against your or your CA's OCSP server to see how
+ # it responds, and adapt accordingly.
+ # Sample output that is assumed here:
+ #
+ # Response verify OK
+ # 0x428740A5: good
+ # This Update: Apr 24 19:38:49 2010 GMT
+ # Next Update: May 2 14:23:42 2010 GMT
+ #
+ # NOTE: It is needed to check the exit code of OpenSSL explicitly. OpenSSL
+ # can in some circumstances give a "good" result if it could not
+ # reach the the OSCP server. In this case, the exit code will indicate
+ # if OpenSSL itself failed or not. If OpenSSL's exit code is not 0,
+ # don't trust the OpenSSL status.
+
+ status=$(openssl ocsp -issuer "$issuer" \
+ "$nonce" \
+ -CAfile "$verify" \
+ -url "$ocsp_url" \
+ -serial "0x${serial}" 2>/dev/null)
+
+ if [ $? -eq 0 ]; then
+ # check that it's good
+ if echo "$status" | grep -Fq "0x${serial}: good"; then
+ exit 0
+ fi
+ fi
+ fi
+ # if we get here, something was wrong
+ exit 1
+fi
diff --git a/contrib/pull-resolv-conf/client.down b/contrib/pull-resolv-conf/client.down
index 82dff54..05f2d4d 100644
--- a/contrib/pull-resolv-conf/client.down
+++ b/contrib/pull-resolv-conf/client.down
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Copyright (c) 2005-2010 OpenVPN Technologies, Inc.
# Licensed under the GPL version 2
@@ -14,7 +14,6 @@
# Place this in /etc/openvpn/client.down
# Then, add the following to your /etc/openvpn/<clientconfig>.conf:
# client
-# pull dhcp-options
# up /etc/openvpn/client.up
# down /etc/openvpn/client.down
# Next, "chmod a+x /etc/openvpn/client.down"
@@ -23,8 +22,8 @@
# Note that this script is best served with the companion "client.up"
# script.
-# Only tested on Gentoo Linux 2005.0 with OpenVPN 2.0
-# It should work with any GNU/Linux with /etc/resolv.conf
+# Tested under Debian lenny with OpenVPN 2.1_rc11
+# It should work with any UNIX with a POSIX sh, /etc/resolv.conf or resolvconf
# This runs with the context of the OpenVPN UID/GID
# at the time of execution. This generally means that
@@ -35,42 +34,14 @@
# A horrid work around, from a security perspective,
# is to run OpenVPN as root. THIS IS NOT RECOMMENDED. You have
# been WARNED.
-
-# init variables
-
-i=1
-j=1
-unset fopt
-unset dns
-unset opt
-
-# Convert ENVs to an array
-
-while fopt=foreign_option_$i; [ -n "${!fopt}" ]; do
-{
- opt[i-1]=${!fopt}
- case ${opt[i-1]} in
- *DOMAIN* ) domain=`echo ${opt[i-1]} | \
- sed -e 's/dhcp-option DOMAIN //g'` ;;
- *DNS* ) dns[j-1]=`echo ${opt[i-1]} | \
- sed -e 's/dhcp-option DNS //g'`
- let j++ ;;
- esac
- let i++
-}
-done
-
-# Now, do the work
-
-if [ -n "${dns[*]}" ]; then
- for i in "${dns[@]}"; do
- sed -i -e "/nameserver ${i}/D" /etc/resolv.conf || die
- done
-fi
-
-if [ -n "${domain}" ]; then
- sed -i -e "/search ${domain}/D" /etc/resolv.conf || die
+PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin
+
+if type resolvconf >/dev/null 2>&1; then
+ resolvconf -d "${1}" -f
+elif [ -e /etc/resolv.conf.ovpnsave ] ; then
+ # cp + rm rather than mv in case it's a symlink
+ cp /etc/resolv.conf.ovpnsave /etc/resolv.conf
+ rm -f /etc/resolv.conf.ovpnsave
fi
-# all done...
exit 0
diff --git a/contrib/pull-resolv-conf/client.up b/contrib/pull-resolv-conf/client.up
index 0eed609..b28d4d1 100644
--- a/contrib/pull-resolv-conf/client.up
+++ b/contrib/pull-resolv-conf/client.up
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Copyright (c) 2005-2010 OpenVPN Technologies, Inc.
# Licensed under the GPL version 2
@@ -14,7 +14,6 @@
# Place this in /etc/openvpn/client.up
# Then, add the following to your /etc/openvpn/<clientconfig>.conf:
# client
-# pull dhcp-options
# up /etc/openvpn/client.up
# Next, "chmod a+x /etc/openvpn/client.up"
@@ -22,8 +21,8 @@
# Note that this script is best served with the companion "client.down"
# script.
-# Only tested on Gentoo Linux 2005.0 with OpenVPN 2.0
-# It should work with any GNU/Linux with /etc/resolv.conf
+# Tested under Debian lenny with OpenVPN 2.1_rc11
+# It should work with any UNIX with a POSIX sh, /etc/resolv.conf or resolvconf
# This runs with the context of the OpenVPN UID/GID
# at the time of execution. This generally means that
@@ -34,42 +33,69 @@
# A horrid work around, from a security perspective,
# is to run OpenVPN as root. THIS IS NOT RECOMMENDED. You have
# been WARNED.
+PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin
# init variables
i=1
-j=1
-unset fopt
-unset dns
-unset opt
-
-# Convert ENVs to an array
-
-while fopt=foreign_option_$i; [ -n "${!fopt}" ]; do
-{
- opt[i-1]=${!fopt}
- case ${opt[i-1]} in
- *DOMAIN* ) domain=`echo ${opt[i-1]} | \
- sed -e 's/dhcp-option DOMAIN //g'` ;;
- *DNS* ) dns[j-1]=`echo ${opt[i-1]} | \
- sed -e 's/dhcp-option DNS //g'`
- let j++ ;;
+domains=
+fopt=
+ndoms=0
+nns=0
+nl='
+'
+
+# $foreign_option_<n> is something like
+# "dhcp-option DOMAIN example.com" (multiple allowed)
+# or
+# "dhcp-option DNS 10.10.10.10" (multiple allowed)
+
+# each DNS option becomes a "nameserver" option in resolv.con
+# if we get one DOMAIN, that becomes "domain" in resolv.conf
+# if we get multiple DOMAINS, those become "search" lines in resolv.conf
+
+while true; do
+ eval fopt=\$foreign_option_${i}
+ [ -z "${fopt}" ] && break
+
+ case ${fopt} in
+ dhcp-option\ DOMAIN\ *)
+ ndoms=$((ndoms + 1))
+ domains="${domains} ${fopt#dhcp-option DOMAIN }"
+ ;;
+ dhcp-option\ DNS\ *)
+ nns=$((nns + 1))
+ if [ $nns -le 3 ]; then
+ dns="${dns}${dns:+$nl}nameserver ${fopt#dhcp-option DNS }"
+ else
+ printf "%s\n" "Too many nameservers - ignoring after third" >&2
+ fi
+ ;;
+ *)
+ printf "%s\n" "Unknown option \"${fopt}\" - ignored" >&2
+ ;;
esac
- let i++
-}
+ i=$((i + 1))
done
-# Now, do the work
-
-if [ -n "${dns[*]}" ]; then
- for i in "${dns[@]}"; do
- sed -i -e "1,1 i nameserver ${i}" /etc/resolv.conf || die
- done
+ds=domain
+if [ $ndoms -gt 1 ]; then
+ ds=search
fi
-if [ -n "${domain}" ]; then
- sed -i -e "$j,1 i search ${domain}" /etc/resolv.conf || die
+# This is the complete file - "$domains" has a leading space already
+out="# resolv.conf autogenerated by ${0} (${1})${nl}${dns}${nl}${ds}${domains}"
+
+# use resolvconf if it's available
+if type resolvconf >/dev/null 2>&1; then
+ printf "%s\n" "${out}" | resolvconf -p -a "${1}"
+else
+ # Preserve the existing resolv.conf
+ if [ -e /etc/resolv.conf ] ; then
+ cp /etc/resolv.conf /etc/resolv.conf.ovpnsave
+ fi
+ printf "%s\n" "${out}" > /etc/resolv.conf
+ chmod 644 /etc/resolv.conf
fi
-# all done...
exit 0
diff --git a/crypto.c b/crypto.c
index d5c8c13..5cfc34a 100644
--- a/crypto.c
+++ b/crypto.c
@@ -29,7 +29,6 @@
#include "crypto.h"
#include "error.h"
#include "misc.h"
-#include "thread.h"
#include "memdbg.h"
@@ -1702,7 +1701,6 @@ prng_bytes (uint8_t *output, int len)
{
EVP_MD_CTX ctx;
const int md_size = EVP_MD_size (nonce_md);
- mutex_lock_static (L_PRNG);
while (len > 0)
{
unsigned int outlen = 0;
@@ -1716,7 +1714,6 @@ prng_bytes (uint8_t *output, int len)
output += blen;
len -= blen;
}
- mutex_unlock_static (L_PRNG);
}
else
RAND_bytes (output, len);
diff --git a/cryptoapi.c b/cryptoapi.c
index 8fb5387..3365cd7 100644
--- a/cryptoapi.c
+++ b/cryptoapi.c
@@ -470,5 +470,7 @@ int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop)
}
#else
+#ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
static void dummy (void) {}
+#endif
#endif /* WIN32 */
diff --git a/easy-rsa/2.0/build-ca b/easy-rsa/2.0/build-ca
index fb1e2ca..bce29a6 100755
--- a/easy-rsa/2.0/build-ca
+++ b/easy-rsa/2.0/build-ca
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
#
# Build a root certificate
diff --git a/easy-rsa/2.0/build-dh b/easy-rsa/2.0/build-dh
index f019222..4beb127 100755
--- a/easy-rsa/2.0/build-dh
+++ b/easy-rsa/2.0/build-dh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Build Diffie-Hellman parameters for the server side
# of an SSL/TLS connection.
diff --git a/easy-rsa/2.0/build-inter b/easy-rsa/2.0/build-inter
index f831d6f..87bf98d 100755
--- a/easy-rsa/2.0/build-inter
+++ b/easy-rsa/2.0/build-inter
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Make an intermediate CA certificate/private key pair using a locally generated
# root certificate.
diff --git a/easy-rsa/2.0/build-key b/easy-rsa/2.0/build-key
index 6196308..6c0fed8 100755
--- a/easy-rsa/2.0/build-key
+++ b/easy-rsa/2.0/build-key
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Make a certificate/private key pair using a locally generated
# root certificate.
diff --git a/easy-rsa/2.0/build-key-pass b/easy-rsa/2.0/build-key-pass
index 35543e0..8ef8307 100755
--- a/easy-rsa/2.0/build-key-pass
+++ b/easy-rsa/2.0/build-key-pass
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Similar to build-key, but protect the private key
# with a password.
diff --git a/easy-rsa/2.0/build-key-pkcs12 b/easy-rsa/2.0/build-key-pkcs12
index 5ef064f..ba90e6a 100755
--- a/easy-rsa/2.0/build-key-pkcs12
+++ b/easy-rsa/2.0/build-key-pkcs12
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Make a certificate/private key pair using a locally generated
# root certificate and convert it to a PKCS #12 file including the
diff --git a/easy-rsa/2.0/build-key-server b/easy-rsa/2.0/build-key-server
index 5502675..fee0194 100755
--- a/easy-rsa/2.0/build-key-server
+++ b/easy-rsa/2.0/build-key-server
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Make a certificate/private key pair using a locally generated
# root certificate.
diff --git a/easy-rsa/2.0/build-req b/easy-rsa/2.0/build-req
index 26587d1..559d512 100755
--- a/easy-rsa/2.0/build-req
+++ b/easy-rsa/2.0/build-req
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Build a certificate signing request and private key. Use this
# when your root certificate and key is not available locally.
diff --git a/easy-rsa/2.0/build-req-pass b/easy-rsa/2.0/build-req-pass
index 6e6c863..b73ee1b 100755
--- a/easy-rsa/2.0/build-req-pass
+++ b/easy-rsa/2.0/build-req-pass
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Like build-req, but protect your private key
# with a password.
diff --git a/easy-rsa/2.0/clean-all b/easy-rsa/2.0/clean-all
index 0576db5..cc6e3b2 100755
--- a/easy-rsa/2.0/clean-all
+++ b/easy-rsa/2.0/clean-all
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Initialize the $KEY_DIR directory.
# Note that this script does a
diff --git a/easy-rsa/2.0/inherit-inter b/easy-rsa/2.0/inherit-inter
index 2101951..aaa5168 100755
--- a/easy-rsa/2.0/inherit-inter
+++ b/easy-rsa/2.0/inherit-inter
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Build a new PKI which is rooted on an intermediate certificate generated
# by ./build-inter or ./pkitool --inter from a parent PKI. The new PKI should
diff --git a/easy-rsa/2.0/list-crl b/easy-rsa/2.0/list-crl
index afc0cd6..d1d8a69 100755
--- a/easy-rsa/2.0/list-crl
+++ b/easy-rsa/2.0/list-crl
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# list revoked certificates
diff --git a/easy-rsa/2.0/pkitool b/easy-rsa/2.0/pkitool
index 7266988..49588f5 100755
--- a/easy-rsa/2.0/pkitool
+++ b/easy-rsa/2.0/pkitool
@@ -192,6 +192,12 @@ while [ $# -gt 0 ]; do
$PKCS11TOOL --module "$PKCS11_MODULE_PATH" --list-objects --login --slot "$PKCS11_SLOT"
exit 0;;
+ --help|--usage)
+ usage
+ exit ;;
+ --version)
+ echo "$PROGNAME $VERSION"
+ exit ;;
# errors
--* ) die "$PROGNAME: unknown option: $1" ;;
* ) break ;;
diff --git a/easy-rsa/2.0/revoke-full b/easy-rsa/2.0/revoke-full
index efc94e8..4169c4c 100755
--- a/easy-rsa/2.0/revoke-full
+++ b/easy-rsa/2.0/revoke-full
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# revoke a certificate, regenerate CRL,
# and verify revocation
diff --git a/easy-rsa/2.0/sign-req b/easy-rsa/2.0/sign-req
index 38655d3..6cae7b4 100755
--- a/easy-rsa/2.0/sign-req
+++ b/easy-rsa/2.0/sign-req
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Sign a certificate signing request (a .csr file)
# with a local root certificate and key.
diff --git a/easy-rsa/Windows/build-ca-pass.bat b/easy-rsa/Windows/build-ca-pass.bat
index c0e046c..ab0b2a4 100644
--- a/easy-rsa/Windows/build-ca-pass.bat
+++ b/easy-rsa/Windows/build-ca-pass.bat
@@ -1,8 +1,8 @@
-@echo off
-cd %HOME%
-rem build a request for a cert that will be valid for ten years
-openssl req -days 3650 -new -keyout %KEY_DIR%\%1.key -out %KEY_DIR%\%1.csr -config %KEY_CONFIG%
-rem sign the cert request with our ca, creating a cert/key pair
-openssl ca -days 3650 -out %KEY_DIR%\%1.crt -in %KEY_DIR%\%1.csr -config %KEY_CONFIG%
-rem delete any .old files created in this process, to avoid future file creation errors
-del /q %KEY_DIR%\*.old
+@echo off
+cd %HOME%
+rem build a request for a cert that will be valid for ten years
+openssl req -days 3650 -new -keyout %KEY_DIR%\%1.key -out %KEY_DIR%\%1.csr -config %KEY_CONFIG%
+rem sign the cert request with our ca, creating a cert/key pair
+openssl ca -days 3650 -out %KEY_DIR%\%1.crt -in %KEY_DIR%\%1.csr -config %KEY_CONFIG%
+rem delete any .old files created in this process, to avoid future file creation errors
+del /q %KEY_DIR%\*.old
diff --git a/easy-rsa/Windows/build-key-pass.bat b/easy-rsa/Windows/build-key-pass.bat
index c0e046c..ab0b2a4 100644
--- a/easy-rsa/Windows/build-key-pass.bat
+++ b/easy-rsa/Windows/build-key-pass.bat
@@ -1,8 +1,8 @@
-@echo off
-cd %HOME%
-rem build a request for a cert that will be valid for ten years
-openssl req -days 3650 -new -keyout %KEY_DIR%\%1.key -out %KEY_DIR%\%1.csr -config %KEY_CONFIG%
-rem sign the cert request with our ca, creating a cert/key pair
-openssl ca -days 3650 -out %KEY_DIR%\%1.crt -in %KEY_DIR%\%1.csr -config %KEY_CONFIG%
-rem delete any .old files created in this process, to avoid future file creation errors
-del /q %KEY_DIR%\*.old
+@echo off
+cd %HOME%
+rem build a request for a cert that will be valid for ten years
+openssl req -days 3650 -new -keyout %KEY_DIR%\%1.key -out %KEY_DIR%\%1.csr -config %KEY_CONFIG%
+rem sign the cert request with our ca, creating a cert/key pair
+openssl ca -days 3650 -out %KEY_DIR%\%1.crt -in %KEY_DIR%\%1.csr -config %KEY_CONFIG%
+rem delete any .old files created in this process, to avoid future file creation errors
+del /q %KEY_DIR%\*.old
diff --git a/easy-rsa/Windows/build-key-server-pass.bat b/easy-rsa/Windows/build-key-server-pass.bat
index 953bc49..99ed4d3 100644
--- a/easy-rsa/Windows/build-key-server-pass.bat
+++ b/easy-rsa/Windows/build-key-server-pass.bat
@@ -1,8 +1,8 @@
-@echo off
-cd %HOME%
-rem build a request for a cert that will be valid for ten years
-openssl req -days 3650 -new -keyout %KEY_DIR%\%1.key -out %KEY_DIR%\%1.csr -config %KEY_CONFIG%
-rem sign the cert request with our ca, creating a cert/key pair
-openssl ca -days 3650 -out %KEY_DIR%\%1.crt -in %KEY_DIR%\%1.csr -extensions server -config %KEY_CONFIG%
-rem delete any .old files created in this process, to avoid future file creation errors
-del /q %KEY_DIR%\*.old
+@echo off
+cd %HOME%
+rem build a request for a cert that will be valid for ten years
+openssl req -days 3650 -new -keyout %KEY_DIR%\%1.key -out %KEY_DIR%\%1.csr -config %KEY_CONFIG%
+rem sign the cert request with our ca, creating a cert/key pair
+openssl ca -days 3650 -out %KEY_DIR%\%1.crt -in %KEY_DIR%\%1.csr -extensions server -config %KEY_CONFIG%
+rem delete any .old files created in this process, to avoid future file creation errors
+del /q %KEY_DIR%\*.old
diff --git a/error.c b/error.c
index 9cf4547..2310f96 100644
--- a/error.c
+++ b/error.c
@@ -26,7 +26,6 @@
#include "error.h"
#include "buffer.h"
-#include "thread.h"
#include "misc.h"
#include "win32.h"
#include "socket.h"
@@ -229,8 +228,6 @@ void x_msg (const unsigned int flags, const char *format, ...)
gc_init (&gc);
- mutex_lock_static (L_MSG);
-
m1 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);
m2 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc);
@@ -330,22 +327,12 @@ void x_msg (const unsigned int flags, const char *format, ...)
}
else
{
-#ifdef USE_PTHREAD
- fprintf (fp, "%s [%d] %s%s%s%s",
- time_string (0, 0, show_usec, &gc),
- (int) openvpn_thread_self (),
- prefix,
- prefix_sep,
- m1,
- (flags&M_NOLF) ? "" : "\n");
-#else
fprintf (fp, "%s %s%s%s%s",
time_string (0, 0, show_usec, &gc),
prefix,
prefix_sep,
m1,
(flags&M_NOLF) ? "" : "\n");
-#endif
}
fflush(fp);
++x_msg_line_num;
@@ -355,8 +342,6 @@ void x_msg (const unsigned int flags, const char *format, ...)
if (flags & M_FATAL)
msg (M_INFO, "Exiting due to fatal error");
- mutex_unlock_static (L_MSG);
-
if (flags & M_FATAL)
openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
@@ -521,7 +506,7 @@ redirect_stdout_stderr (const char *file, bool append)
/* open log_handle as FILE stream */
ASSERT (msgfp == NULL);
- msgfp = _fdopen (log_fd, "w");
+ msgfp = _fdopen (log_fd, "wt");
if (msgfp == NULL)
msg (M_ERR, "Error: --log redirect failed due to _fdopen");
@@ -653,10 +638,6 @@ x_check_status (int status,
*/
const char *x_msg_prefix; /* GLOBAL */
-#ifdef USE_PTHREAD
-pthread_key_t x_msg_prefix_key; /* GLOBAL */
-#endif
-
/*
* Allow MSG to be redirected through a virtual_output object
*/
@@ -664,26 +645,6 @@ pthread_key_t x_msg_prefix_key; /* GLOBAL */
const struct virtual_output *x_msg_virtual_output; /* GLOBAL */
/*
- * Init thread-local variables
- */
-
-void
-msg_thread_init (void)
-{
-#ifdef USE_PTHREAD
- ASSERT (!pthread_key_create (&x_msg_prefix_key, NULL));
-#endif
-}
-
-void
-msg_thread_uninit (void)
-{
-#ifdef USE_PTHREAD
- pthread_key_delete (x_msg_prefix_key);
-#endif
-}
-
-/*
* Exiting.
*/
diff --git a/error.h b/error.h
index 6a9adea..4be3268 100644
--- a/error.h
+++ b/error.h
@@ -26,7 +26,6 @@
#define ERROR_H
#include "basic.h"
-#include "thread.h"
/* #define ABORT_ON_ERROR */
@@ -282,34 +281,18 @@ set_check_status_error_delay (unsigned int milliseconds)
extern const char *x_msg_prefix;
-#ifdef USE_PTHREAD
-extern pthread_key_t x_msg_prefix_key;
-#endif
-
void msg_thread_init (void);
void msg_thread_uninit (void);
static inline void
msg_set_prefix (const char *prefix)
{
-#ifdef USE_PTHREAD
- if (openvpn_thread_enabled ())
- {
- ASSERT (!pthread_setspecific (x_msg_prefix_key, prefix));
- }
- else
-#endif
x_msg_prefix = prefix;
}
static inline const char *
msg_get_prefix (void)
{
-#ifdef USE_PTHREAD
- if (openvpn_thread_enabled ())
- return (const char *) pthread_getspecific (x_msg_prefix_key);
- else
-#endif
return x_msg_prefix;
}
diff --git a/forward.c b/forward.c
index 90b7d9f..b43c1c0 100644
--- a/forward.c
+++ b/forward.c
@@ -267,7 +267,8 @@ send_control_channel_string (struct context *c, const char *str, int msglevel)
static void
check_add_routes_action (struct context *c, const bool errors)
{
- do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es);
+ do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
+ c->c1.tuntap, c->plugins, c->c2.es);
update_time ();
event_timeout_clear (&c->c2.route_wakeup);
event_timeout_clear (&c->c2.route_wakeup_expire);
@@ -455,7 +456,6 @@ encrypt_sign (struct context *c, bool comp_frag)
*/
if (c->c2.tls_multi)
{
- /*tls_mutex_lock (c->c2.tls_multi);*/
tls_pre_encrypt (c->c2.tls_multi, &c->c2.buf, &c->c2.crypto_options);
}
#endif
@@ -483,7 +483,6 @@ encrypt_sign (struct context *c, bool comp_frag)
if (c->c2.tls_multi)
{
tls_post_encrypt (c->c2.tls_multi, &c->c2.buf);
- /*tls_mutex_unlock (c->c2.tls_multi);*/
}
#endif
#endif
@@ -764,7 +763,7 @@ process_incoming_link (struct context *c)
/* log incoming packet */
#ifdef LOG_RW
- if (c->c2.log_rw)
+ if (c->c2.log_rw && c->c2.buf.len > 0)
fprintf (stderr, "R");
#endif
msg (D_LINK_RW, "%s READ [%d] from %s: %s",
@@ -799,7 +798,6 @@ process_incoming_link (struct context *c)
* will load crypto_options with the correct encryption key
* and return false.
*/
- /*tls_mutex_lock (c->c2.tls_multi);*/
if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &c->c2.crypto_options))
{
interval_action (&c->c2.tmp_int);
@@ -822,13 +820,6 @@ process_incoming_link (struct context *c)
/* authenticate and decrypt the incoming packet */
decrypt_status = openvpn_decrypt (&c->c2.buf, c->c2.buffers->decrypt_buf, &c->c2.crypto_options, &c->c2.frame);
-#ifdef USE_SSL
- if (c->c2.tls_multi)
- {
- /*tls_mutex_unlock (c->c2.tls_multi);*/
- }
-#endif
-
if (!decrypt_status && link_socket_connection_oriented (c->c2.link_socket))
{
/* decryption errors are fatal in TCP mode */
@@ -972,7 +963,7 @@ process_incoming_tun (struct context *c)
c->c2.tun_read_bytes += c->c2.buf.len;
#ifdef LOG_RW
- if (c->c2.log_rw)
+ if (c->c2.log_rw && c->c2.buf.len > 0)
fprintf (stderr, "r");
#endif
@@ -1172,8 +1163,9 @@ process_outgoing_link (struct context *c)
size);
}
- /* indicate activity regarding --inactive parameter */
- register_activity (c, size);
+ /* if not a ping/control message, indicate activity regarding --inactive parameter */
+ if (c->c2.buf.len > 0 )
+ register_activity (c, size);
}
else
{
diff --git a/helper.c b/helper.c
index a9d7fd9..266b246 100644
--- a/helper.c
+++ b/helper.c
@@ -142,6 +142,55 @@ helper_client_server (struct options *o)
#if P2MP
#if P2MP_SERVER
+
+ /*
+ *
+ * HELPER DIRECTIVE for IPv6
+ *
+ * server-ipv6 2001:db8::/64
+ *
+ * EXPANDS TO:
+ *
+ * tun-ipv6
+ * push "tun-ipv6"
+ * ifconfig-ipv6 2001:db8::1 2001:db8::2
+ * if !nopool:
+ * ifconfig-ipv6-pool 2001:db8::1:0/64
+ *
+ */
+ if ( o->server_ipv6_defined )
+ {
+ if ( ! o->server_defined )
+ {
+ msg (M_USAGE, "--server-ipv6 must be used together with --server");
+ }
+ if ( o->server_flags & SF_NOPOOL )
+ {
+ msg( M_USAGE, "--server-ipv6 is incompatible with 'nopool' option" );
+ }
+ if ( o->ifconfig_ipv6_pool_defined )
+ {
+ msg( M_USAGE, "--server-ipv6 already defines an ifconfig-ipv6-pool, so you can't also specify --ifconfig-pool explicitly");
+ }
+
+ /* local ifconfig is "base address + 1" and "+2" */
+ o->ifconfig_ipv6_local =
+ print_in6_addr( add_in6_addr( o->server_network_ipv6, 1), 0, &o->gc );
+ o->ifconfig_ipv6_remote =
+ print_in6_addr( add_in6_addr( o->server_network_ipv6, 2), 0, &o->gc );
+
+ /* pool starts at "base address + 0x10000" */
+ ASSERT( o->server_netbits_ipv6 < 96 ); /* want 32 bits */
+ o->ifconfig_ipv6_pool_defined = true;
+ o->ifconfig_ipv6_pool_base =
+ add_in6_addr( o->server_network_ipv6, 0x10000 );
+ o->ifconfig_ipv6_pool_netbits = o->server_netbits_ipv6;
+
+ o->tun_ipv6 = true;
+
+ push_option( o, "tun-ipv6", M_USAGE );
+ }
+
/*
*
* HELPER DIRECTIVE:
diff --git a/httpdigest.c b/httpdigest.c
index ef77e12..90abc6a 100644
--- a/httpdigest.c
+++ b/httpdigest.c
@@ -1,143 +1,143 @@
-/*
- * OpenVPN -- An application to securely tunnel IP networks
- * over a single TCP/UDP port, with support for SSL/TLS-based
- * session authentication and key exchange,
- * packet encryption, packet authentication, and
- * packet compression.
- *
- * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "syshead.h"
-
-#if PROXY_DIGEST_AUTH
-
-#include "crypto.h"
-#include "httpdigest.h"
-
-static void
-CvtHex(
- IN HASH Bin,
- OUT HASHHEX Hex
- )
-{
- unsigned short i;
- unsigned char j;
-
- for (i = 0; i < HASHLEN; i++) {
- j = (Bin[i] >> 4) & 0xf;
- if (j <= 9)
- Hex[i*2] = (j + '0');
- else
- Hex[i*2] = (j + 'a' - 10);
- j = Bin[i] & 0xf;
- if (j <= 9)
- Hex[i*2+1] = (j + '0');
- else
- Hex[i*2+1] = (j + 'a' - 10);
- };
- Hex[HASHHEXLEN] = '\0';
-};
-
-/* calculate H(A1) as per spec */
-void
-DigestCalcHA1(
- IN char * pszAlg,
- IN char * pszUserName,
- IN char * pszRealm,
- IN char * pszPassword,
- IN char * pszNonce,
- IN char * pszCNonce,
- OUT HASHHEX SessionKey
- )
-{
- MD5_CTX Md5Ctx;
- HASH HA1;
-
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, pszUserName, strlen(pszUserName));
- MD5_Update(&Md5Ctx, ":", 1);
- MD5_Update(&Md5Ctx, pszRealm, strlen(pszRealm));
- MD5_Update(&Md5Ctx, ":", 1);
- MD5_Update(&Md5Ctx, pszPassword, strlen(pszPassword));
- MD5_Final(HA1, &Md5Ctx);
- if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)
- {
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, HA1, HASHLEN);
- MD5_Update(&Md5Ctx, ":", 1);
- MD5_Update(&Md5Ctx, pszNonce, strlen(pszNonce));
- MD5_Update(&Md5Ctx, ":", 1);
- MD5_Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
- MD5_Final(HA1, &Md5Ctx);
- };
- CvtHex(HA1, SessionKey);
-}
-
-/* calculate request-digest/response-digest as per HTTP Digest spec */
-void
-DigestCalcResponse(
- IN HASHHEX HA1, /* H(A1) */
- IN char * pszNonce, /* nonce from server */
- IN char * pszNonceCount, /* 8 hex digits */
- IN char * pszCNonce, /* client nonce */
- IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
- IN char * pszMethod, /* method from the request */
- IN char * pszDigestUri, /* requested URL */
- IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
- OUT HASHHEX Response /* request-digest or response-digest */
- )
-{
- MD5_CTX Md5Ctx;
- HASH HA2;
- HASH RespHash;
- HASHHEX HA2Hex;
-
- // calculate H(A2)
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, pszMethod, strlen(pszMethod));
- MD5_Update(&Md5Ctx, ":", 1);
- MD5_Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri));
- if (strcasecmp(pszQop, "auth-int") == 0)
- {
- MD5_Update(&Md5Ctx, ":", 1);
- MD5_Update(&Md5Ctx, HEntity, HASHHEXLEN);
- };
- MD5_Final(HA2, &Md5Ctx);
- CvtHex(HA2, HA2Hex);
-
- // calculate response
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, HA1, HASHHEXLEN);
- MD5_Update(&Md5Ctx, ":", 1);
- MD5_Update(&Md5Ctx, pszNonce, strlen(pszNonce));
- MD5_Update(&Md5Ctx, ":", 1);
- if (*pszQop)
- {
- MD5_Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount));
- MD5_Update(&Md5Ctx, ":", 1);
- MD5_Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
- MD5_Update(&Md5Ctx, ":", 1);
- MD5_Update(&Md5Ctx, pszQop, strlen(pszQop));
- MD5_Update(&Md5Ctx, ":", 1);
- };
- MD5_Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
- MD5_Final(RespHash, &Md5Ctx);
- CvtHex(RespHash, Response);
-}
-
-#endif
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "syshead.h"
+
+#if PROXY_DIGEST_AUTH
+
+#include "crypto.h"
+#include "httpdigest.h"
+
+static void
+CvtHex(
+ IN HASH Bin,
+ OUT HASHHEX Hex
+ )
+{
+ unsigned short i;
+ unsigned char j;
+
+ for (i = 0; i < HASHLEN; i++) {
+ j = (Bin[i] >> 4) & 0xf;
+ if (j <= 9)
+ Hex[i*2] = (j + '0');
+ else
+ Hex[i*2] = (j + 'a' - 10);
+ j = Bin[i] & 0xf;
+ if (j <= 9)
+ Hex[i*2+1] = (j + '0');
+ else
+ Hex[i*2+1] = (j + 'a' - 10);
+ };
+ Hex[HASHHEXLEN] = '\0';
+};
+
+/* calculate H(A1) as per spec */
+void
+DigestCalcHA1(
+ IN char * pszAlg,
+ IN char * pszUserName,
+ IN char * pszRealm,
+ IN char * pszPassword,
+ IN char * pszNonce,
+ IN char * pszCNonce,
+ OUT HASHHEX SessionKey
+ )
+{
+ MD5_CTX Md5Ctx;
+ HASH HA1;
+
+ MD5_Init(&Md5Ctx);
+ MD5_Update(&Md5Ctx, pszUserName, strlen(pszUserName));
+ MD5_Update(&Md5Ctx, ":", 1);
+ MD5_Update(&Md5Ctx, pszRealm, strlen(pszRealm));
+ MD5_Update(&Md5Ctx, ":", 1);
+ MD5_Update(&Md5Ctx, pszPassword, strlen(pszPassword));
+ MD5_Final(HA1, &Md5Ctx);
+ if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)
+ {
+ MD5_Init(&Md5Ctx);
+ MD5_Update(&Md5Ctx, HA1, HASHLEN);
+ MD5_Update(&Md5Ctx, ":", 1);
+ MD5_Update(&Md5Ctx, pszNonce, strlen(pszNonce));
+ MD5_Update(&Md5Ctx, ":", 1);
+ MD5_Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
+ MD5_Final(HA1, &Md5Ctx);
+ };
+ CvtHex(HA1, SessionKey);
+}
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void
+DigestCalcResponse(
+ IN HASHHEX HA1, /* H(A1) */
+ IN char * pszNonce, /* nonce from server */
+ IN char * pszNonceCount, /* 8 hex digits */
+ IN char * pszCNonce, /* client nonce */
+ IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
+ IN char * pszMethod, /* method from the request */
+ IN char * pszDigestUri, /* requested URL */
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ OUT HASHHEX Response /* request-digest or response-digest */
+ )
+{
+ MD5_CTX Md5Ctx;
+ HASH HA2;
+ HASH RespHash;
+ HASHHEX HA2Hex;
+
+ // calculate H(A2)
+ MD5_Init(&Md5Ctx);
+ MD5_Update(&Md5Ctx, pszMethod, strlen(pszMethod));
+ MD5_Update(&Md5Ctx, ":", 1);
+ MD5_Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri));
+ if (strcasecmp(pszQop, "auth-int") == 0)
+ {
+ MD5_Update(&Md5Ctx, ":", 1);
+ MD5_Update(&Md5Ctx, HEntity, HASHHEXLEN);
+ };
+ MD5_Final(HA2, &Md5Ctx);
+ CvtHex(HA2, HA2Hex);
+
+ // calculate response
+ MD5_Init(&Md5Ctx);
+ MD5_Update(&Md5Ctx, HA1, HASHHEXLEN);
+ MD5_Update(&Md5Ctx, ":", 1);
+ MD5_Update(&Md5Ctx, pszNonce, strlen(pszNonce));
+ MD5_Update(&Md5Ctx, ":", 1);
+ if (*pszQop)
+ {
+ MD5_Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount));
+ MD5_Update(&Md5Ctx, ":", 1);
+ MD5_Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
+ MD5_Update(&Md5Ctx, ":", 1);
+ MD5_Update(&Md5Ctx, pszQop, strlen(pszQop));
+ MD5_Update(&Md5Ctx, ":", 1);
+ };
+ MD5_Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
+ MD5_Final(RespHash, &Md5Ctx);
+ CvtHex(RespHash, Response);
+}
+
+#endif
diff --git a/httpdigest.h b/httpdigest.h
index fb6d114..8423841 100644
--- a/httpdigest.h
+++ b/httpdigest.h
@@ -1,60 +1,60 @@
-/*
- * OpenVPN -- An application to securely tunnel IP networks
- * over a single TCP/UDP port, with support for SSL/TLS-based
- * session authentication and key exchange,
- * packet encryption, packet authentication, and
- * packet compression.
- *
- * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#if PROXY_DIGEST_AUTH
-
-#define HASHLEN 16
-typedef unsigned char HASH[HASHLEN];
-#define HASHHEXLEN 32
-typedef unsigned char HASHHEX[HASHHEXLEN+1];
-#undef IN
-#undef OUT
-#define IN const
-#define OUT
-
-/* calculate H(A1) as per HTTP Digest spec */
-void DigestCalcHA1(
- IN char * pszAlg,
- IN char * pszUserName,
- IN char * pszRealm,
- IN char * pszPassword,
- IN char * pszNonce,
- IN char * pszCNonce,
- OUT HASHHEX SessionKey
- );
-
-/* calculate request-digest/response-digest as per HTTP Digest spec */
-void DigestCalcResponse(
- IN HASHHEX HA1, /* H(A1) */
- IN char * pszNonce, /* nonce from server */
- IN char * pszNonceCount, /* 8 hex digits */
- IN char * pszCNonce, /* client nonce */
- IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
- IN char * pszMethod, /* method from the request */
- IN char * pszDigestUri, /* requested URL */
- IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
- OUT HASHHEX Response /* request-digest or response-digest */
- );
-
-#endif
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if PROXY_DIGEST_AUTH
+
+#define HASHLEN 16
+typedef unsigned char HASH[HASHLEN];
+#define HASHHEXLEN 32
+typedef unsigned char HASHHEX[HASHHEXLEN+1];
+#undef IN
+#undef OUT
+#define IN const
+#define OUT
+
+/* calculate H(A1) as per HTTP Digest spec */
+void DigestCalcHA1(
+ IN char * pszAlg,
+ IN char * pszUserName,
+ IN char * pszRealm,
+ IN char * pszPassword,
+ IN char * pszNonce,
+ IN char * pszCNonce,
+ OUT HASHHEX SessionKey
+ );
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void DigestCalcResponse(
+ IN HASHHEX HA1, /* H(A1) */
+ IN char * pszNonce, /* nonce from server */
+ IN char * pszNonceCount, /* 8 hex digits */
+ IN char * pszCNonce, /* client nonce */
+ IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
+ IN char * pszMethod, /* method from the request */
+ IN char * pszDigestUri, /* requested URL */
+ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ OUT HASHHEX Response /* request-digest or response-digest */
+ );
+
+#endif
diff --git a/ieproxy.c b/ieproxy.c
index 89977a8..3099870 100644
--- a/ieproxy.c
+++ b/ieproxy.c
@@ -139,7 +139,8 @@ LPCTSTR getIeHttpProxy()
return(NULL);
}
}
-
#else
+#ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
static void dummy (void) {}
+#endif
#endif /* WIN32 */
diff --git a/init.c b/init.c
index e5ca358..4a16fba 100644
--- a/init.c
+++ b/init.c
@@ -96,7 +96,7 @@ update_options_ce_post (struct options *options)
*/
if (options->pull
&& options->ping_rec_timeout_action == PING_UNDEF
- && options->ce.proto == PROTO_UDPv4)
+ && proto_is_dgram(options->ce.proto))
{
options->ping_rec_timeout = PRE_PULL_INITIAL_PING_RESTART;
options->ping_rec_timeout_action = PING_RESTART;
@@ -410,6 +410,7 @@ init_proxy_dowork (struct context *c)
{
c->c1.socks_proxy = socks_proxy_new (c->options.ce.socks_proxy_server,
c->options.ce.socks_proxy_port,
+ c->options.ce.socks_proxy_authfile,
c->options.ce.socks_proxy_retry,
c->options.auto_proxy_info);
if (c->c1.socks_proxy)
@@ -631,7 +632,7 @@ init_static (void)
#ifdef STATUS_PRINTF_TEST
{
struct gc_arena gc = gc_new ();
- const char *tmp_file = create_temp_filename ("/tmp", "foo", &gc);
+ const char *tmp_file = create_temp_file ("/tmp", "foo", &gc);
struct status_output *so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
status_printf (so, "%s", "foo");
status_printf (so, "%s", "bar");
@@ -733,8 +734,6 @@ init_static (void)
void
uninit_static (void)
{
- openvpn_thread_cleanup ();
-
#ifdef USE_CRYPTO
free_ssl_lib ();
#endif
@@ -860,7 +859,7 @@ do_persist_tuntap (const struct options *options)
msg (M_FATAL|M_OPTERR,
"options --mktun or --rmtun should only be used together with --dev");
tuncfg (options->dev, options->dev_type, options->dev_node,
- options->tun_ipv6, options->persist_mode,
+ options->persist_mode,
options->username, options->groupname, &options->tuntap_options);
if (options->persist_mode && options->lladdr)
set_lladdr(options->dev, options->lladdr, NULL);
@@ -1083,6 +1082,8 @@ 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->options.routes_ipv6 && !c->c1.route_ipv6_list)
+ c->c1.route_ipv6_list = new_route_ipv6_list (c->options.max_routes, &c->gc);
}
@@ -1125,6 +1126,45 @@ do_init_route_list (const struct options *options,
}
}
+static void
+do_init_route_ipv6_list (const struct options *options,
+ struct route_ipv6_list *route_ipv6_list,
+ bool fatal,
+ struct env_set *es)
+{
+ const char *gw = NULL;
+ int dev = dev_type_enum (options->dev, options->dev_type);
+ int metric = 0;
+
+ if (dev != DEV_TYPE_TUN )
+ msg( M_WARN, "IPv6 routes on TAP devices are going to fail on some platforms (need gateway spec)" ); /* TODO-GERT */
+
+ gw = options->ifconfig_ipv6_remote; /* default GW = remote end */
+#if 0 /* not yet done for IPv6 - TODO!*/
+ if ( options->route_ipv6_default_gateway ) /* override? */
+ gw = options->route_ipv6_default_gateway;
+#endif
+
+ if (options->route_default_metric)
+ metric = options->route_default_metric;
+
+ if (!init_route_ipv6_list (route_ipv6_list,
+ options->routes_ipv6,
+ gw,
+ metric,
+ es))
+ {
+ if (fatal)
+ openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
+ }
+ else
+ {
+ /* copy routes to environment */
+ setenv_routes_ipv6 (es, route_ipv6_list);
+ }
+}
+
+
/*
* Called after all initialization has been completed.
*/
@@ -1167,7 +1207,12 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
const char *detail = "SUCCESS";
if (c->c1.tuntap)
tun_local = c->c1.tuntap->local;
- tun_remote = htonl (c->c1.link_socket_addr.actual.dest.sa.sin_addr.s_addr);
+ /* TODO(jjo): for ipv6 this will convert some 32bits in the ipv6 addr
+ * to a meaningless ipv4 address.
+ * In any case, is somewhat inconsistent to send local tunnel
+ * addr with remote _endpoint_ addr (?)
+ */
+ tun_remote = htonl (c->c1.link_socket_addr.actual.dest.addr.in4.sin_addr.s_addr);
if (flags & ISC_ERRORS)
detail = "ERROR";
management_set_state (management,
@@ -1188,13 +1233,14 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
void
do_route (const struct options *options,
struct route_list *route_list,
+ struct route_ipv6_list *route_ipv6_list,
const struct tuntap *tt,
const struct plugin_list *plugins,
struct env_set *es)
{
- if (!options->route_noexec && route_list)
+ if (!options->route_noexec && ( route_list || route_ipv6_list ) )
{
- add_routes (route_list, tt, ROUTE_OPTION_FLAGS (options), es);
+ add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es);
setenv_int (es, "redirect_gateway", route_list->did_redirect_default_gateway);
}
#ifdef ENABLE_MANAGEMENT
@@ -1204,7 +1250,7 @@ do_route (const struct options *options,
if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP))
{
- if (plugin_call (plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+ if (plugin_call (plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, NULL, es, -1, NULL) != OPENVPN_PLUGIN_FUNC_SUCCESS)
msg (M_WARN, "WARNING: route-up plugin call failed");
}
@@ -1213,7 +1259,7 @@ do_route (const struct options *options,
struct argv argv = argv_new ();
setenv_str (es, "script_type", "route-up");
argv_printf (&argv, "%sc", options->route_script);
- openvpn_execve_check (&argv, es, S_SCRIPT, "Route script failed");
+ openvpn_run_script (&argv, es, 0, "--route-up");
argv_reset (&argv);
}
@@ -1257,11 +1303,16 @@ do_init_tun (struct context *c)
c->options.topology,
c->options.ifconfig_local,
c->options.ifconfig_remote_netmask,
+ c->options.ifconfig_ipv6_local,
+ c->options.ifconfig_ipv6_remote,
addr_host (&c->c1.link_socket_addr.local),
addr_host (&c->c1.link_socket_addr.remote),
!c->options.ifconfig_nowarn,
c->c2.es);
+ /* flag tunnel for IPv6 config if --tun-ipv6 is set */
+ c->c1.tuntap->ipv6 = c->options.tun_ipv6;
+
init_tun_post (c->c1.tuntap,
&c->c2.frame,
&c->options.tuntap_options);
@@ -1293,6 +1344,8 @@ do_open_tun (struct context *c)
/* parse and resolve the route option list */
if (c->options.routes && c->c1.route_list && c->c2.link_socket)
do_init_route_list (&c->options, c->c1.route_list, &c->c2.link_socket->info, false, c->c2.es);
+ if (c->options.routes_ipv6 && c->c1.route_ipv6_list )
+ do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, false, c->c2.es);
/* do ifconfig */
if (!c->options.ifconfig_noexec
@@ -1309,7 +1362,7 @@ do_open_tun (struct context *c)
/* open the tun device */
open_tun (c->options.dev, c->options.dev_type, c->options.dev_node,
- c->options.tun_ipv6, c->c1.tuntap);
+ c->c1.tuntap);
/* set the hardware address */
if (c->options.lladdr)
@@ -1327,6 +1380,7 @@ do_open_tun (struct context *c)
c->plugins,
OPENVPN_PLUGIN_UP,
c->c1.tuntap->actual_name,
+ dev_type_string (c->options.dev, c->options.dev_type),
TUN_MTU_SIZE (&c->c2.frame),
EXPANDED_SIZE (&c->c2.frame),
print_in_addr_t (c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc),
@@ -1338,7 +1392,8 @@ do_open_tun (struct context *c)
/* possibly add routes */
if (!c->options.route_delay_defined)
- do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es);
+ do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
+ c->c1.tuntap, c->plugins, c->c2.es);
/*
* Did tun/tap driver give us an MTU?
@@ -1362,6 +1417,7 @@ do_open_tun (struct context *c)
c->plugins,
OPENVPN_PLUGIN_UP,
c->c1.tuntap->actual_name,
+ dev_type_string (c->options.dev, c->options.dev_type),
TUN_MTU_SIZE (&c->c2.frame),
EXPANDED_SIZE (&c->c2.frame),
print_in_addr_t (c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc),
@@ -1415,8 +1471,9 @@ do_close_tun (struct context *c, bool force)
#endif
/* delete any routes we added */
- if (c->c1.route_list)
- delete_routes (c->c1.route_list, c->c1.tuntap, ROUTE_OPTION_FLAGS (&c->options), c->c2.es);
+ if (c->c1.route_list || c->c1.route_ipv6_list )
+ delete_routes (c->c1.route_list, c->c1.route_ipv6_list,
+ c->c1.tuntap, ROUTE_OPTION_FLAGS (&c->options), c->c2.es);
/* actually close tun/tap device based on --down-pre flag */
if (!c->options.down_pre)
@@ -1428,6 +1485,7 @@ do_close_tun (struct context *c, bool force)
c->plugins,
OPENVPN_PLUGIN_DOWN,
tuntap_actual,
+ NULL,
TUN_MTU_SIZE (&c->c2.frame),
EXPANDED_SIZE (&c->c2.frame),
print_in_addr_t (local, IA_EMPTY_IF_UNDEF, &gc),
@@ -1450,6 +1508,7 @@ do_close_tun (struct context *c, bool force)
c->plugins,
OPENVPN_PLUGIN_DOWN,
tuntap_actual,
+ NULL,
TUN_MTU_SIZE (&c->c2.frame),
EXPANDED_SIZE (&c->c2.frame),
print_in_addr_t (local, IA_EMPTY_IF_UNDEF, &gc),
@@ -1591,7 +1650,7 @@ do_deferred_options (struct context *c, const unsigned int found)
#ifdef ENABLE_OCC
if (found & OPT_P_EXPLICIT_NOTIFY)
{
- if (c->options.ce.proto != PROTO_UDPv4 && c->options.explicit_exit_notification)
+ if (!proto_is_udp(c->options.ce.proto) && c->options.explicit_exit_notification)
{
msg (D_PUSH, "OPTIONS IMPORT: --explicit-exit-notify can only be used with --proto udp");
c->options.explicit_exit_notification = 0;
@@ -1686,13 +1745,22 @@ socket_restart_pause (struct context *c)
switch (c->options.ce.proto)
{
case PROTO_UDPv4:
+#ifdef USE_PF_INET6
+ case PROTO_UDPv6:
+#endif
if (proxy)
sec = c->options.ce.connect_retry_seconds;
break;
case PROTO_TCPv4_SERVER:
+#ifdef USE_PF_INET6
+ case PROTO_TCPv6_SERVER:
+#endif
sec = 1;
break;
case PROTO_TCPv4_CLIENT:
+#ifdef USE_PF_INET6
+ case PROTO_TCPv6_CLIENT:
+#endif
sec = c->options.ce.connect_retry_seconds;
break;
}
@@ -2054,6 +2122,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
#endif
to.verify_command = options->tls_verify;
+ to.verify_export_cert = options->tls_export_cert;
to.verify_x509name = options->tls_remote;
to.crl_file = options->crl_file;
to.ssl_flags = options->ssl_flags;
@@ -2842,7 +2911,7 @@ do_setup_fast_io (struct context *c)
#ifdef WIN32
msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows");
#else
- if (c->options.ce.proto != PROTO_UDPv4)
+ if (!proto_is_udp(c->options.ce.proto))
msg (M_INFO, "NOTE: --fast-io is disabled since we are not using UDP");
else
{
@@ -3118,7 +3187,11 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
/* link_socket_mode allows CM_CHILD_TCP
instances to inherit acceptable fds
from a top-level parent */
- if (c->options.ce.proto == PROTO_TCPv4_SERVER)
+ if (c->options.ce.proto == PROTO_TCPv4_SERVER
+#ifdef USE_PF_INET6
+ || c->options.ce.proto == PROTO_TCPv6_SERVER
+#endif
+ )
{
if (c->mode == CM_TOP)
link_socket_mode = LS_MODE_TCP_LISTEN;
@@ -3393,17 +3466,8 @@ inherit_context_child (struct context *dest,
{
CLEAR (*dest);
- switch (src->options.ce.proto)
- {
- case PROTO_UDPv4:
- dest->mode = CM_CHILD_UDP;
- break;
- case PROTO_TCPv4_SERVER:
- dest->mode = CM_CHILD_TCP;
- break;
- default:
- ASSERT (0);
- }
+ /* proto_is_dgram will ASSERT(0) if proto is invalid */
+ dest->mode = proto_is_dgram(src->options.ce.proto)? CM_CHILD_UDP : CM_CHILD_TCP;
dest->gc = gc_new ();
@@ -3509,7 +3573,7 @@ inherit_context_top (struct context *dest,
dest->c2.es_owned = false;
dest->c2.event_set = NULL;
- if (src->options.ce.proto == PROTO_UDPv4)
+ if (proto_is_dgram(src->options.ce.proto))
do_event_set_init (dest, false);
}
@@ -3538,23 +3602,6 @@ close_context (struct context *c, int sig, unsigned int flags)
#ifdef USE_CRYPTO
-static void
-test_malloc (void)
-{
- int i, j;
- msg (M_INFO, "Multithreaded malloc test...");
- for (i = 0; i < 25; ++i)
- {
- struct gc_arena gc = gc_new ();
- const int limit = get_random () & 0x03FF;
- for (j = 0; j < limit; ++j)
- {
- gc_malloc (get_random () & 0x03FF, false, &gc);
- }
- gc_free (&gc);
- }
-}
-
/*
* Do a loopback test
* on the crypto subsystem.
@@ -3564,50 +3611,19 @@ test_crypto_thread (void *arg)
{
struct context *c = (struct context *) arg;
const struct options *options = &c->options;
-#if defined(USE_PTHREAD)
- struct context *child = NULL;
- openvpn_thread_t child_id = 0;
-#endif
ASSERT (options->test_crypto);
init_verb_mute (c, IVM_LEVEL_1);
context_init_1 (c);
do_init_crypto_static (c, 0);
-#if defined(USE_PTHREAD)
- {
- if (c->first_time && options->n_threads > 1)
- {
- if (options->n_threads > 2)
- msg (M_FATAL, "ERROR: --test-crypto option only works with --threads set to 1 or 2");
- openvpn_thread_init ();
- ALLOC_OBJ (child, struct context);
- context_clear (child);
- child->options = *options;
- options_detach (&child->options);
- child->first_time = false;
- child_id = openvpn_thread_create (test_crypto_thread, (void *) child);
- }
- }
-#endif
frame_finalize_options (c, options);
-#if defined(USE_PTHREAD)
- if (options->n_threads == 2)
- test_malloc ();
-#endif
-
test_crypto (&c->c2.crypto_options, &c->c2.frame);
key_schedule_free (&c->c1.ks, true);
packet_id_free (&c->c2.packet_id);
-#if defined(USE_PTHREAD)
- if (c->first_time && options->n_threads > 1)
- openvpn_thread_join (child_id);
- if (child)
- free (child);
-#endif
context_gc_free (c);
return NULL;
}
diff --git a/init.h b/init.h
index cf5ca8a..5a1d1dc 100644
--- a/init.h
+++ b/init.h
@@ -63,6 +63,7 @@ void init_instance (struct context *c, const struct env_set *env, const unsigned
void do_route (const struct options *options,
struct route_list *route_list,
+ struct route_ipv6_list *route_ipv6_list,
const struct tuntap *tt,
const struct plugin_list *plugins,
struct env_set *es);
diff --git a/install-win32/makeopenvpn b/install-win32/makeopenvpn
index c1a805d..ced2a54 100644..100755
--- a/install-win32/makeopenvpn
+++ b/install-win32/makeopenvpn
@@ -2,35 +2,65 @@
H=`pwd`
-# get version.nsi definitions
-. autodefs/defs.sh
+case "`uname -o 2>/dev/null`" in
+ *inux)
-if gcc --version &>/dev/null && [ -d "$OPENSSL_DIR" ] && [ -d "$LZO_DIR" ] && [ -d "$PKCS11_HELPER_DIR" ]; then
+ # cross-compiling, make dude's life easier
+ XAUTOCONF="--host=i586-mingw32msvc --build=i386-linux $XAUTOCONF"
+ export CC=i586-mingw32msvc-gcc
+ export CXXCPP=i586-mingw32msvc-cpp
+ export CXX=i586-mingw32msvc-g++
+ # this requires the human to setup these environ vars:
+ # OPENSSL_DIR LZO_DIR PKCS11_HELPER_DIR
+ OPENSSL_INC_DIR=$OPENSSL_DIR/include
+ OPENSSL_LIB_DIR=$OPENSSL_DIR/out
+ LZO_INC_DIR=$LZO_DIR/include
+ LZO_LIB_DIR=$LZO_DIR/src/.libs
+ PKCS11_INC_DIR=$PKCS11_HELPER_DIR/include/pkcs11-helper-1.0/
+ PKCS11_LIB_DIR=$PKCS11_HELPER_DIR/lib/.libs/
+ ;;
+ *)
+ # get version.nsi definitions
+ . autodefs/defs.sh
+ XAUTOCONF=""
+ # default configuration creates relative-path environ vars:
+ OPENSSL_INC_DIR=$H/$OPENSSL_DIR/include
+ OPENSSL_LIB_DIR=$H/$OPENSSL_DIR/out
+ LZO_INC_DIR=$H/$LZO_DIR/include
+ LZO_LIB_DIR=$H/$LZO_DIR
+ PKCS11_INC_DIR=$H/$PKCS11_HELPER_DIR/usr/local/include
+ PKCS11_LIB_DIR=$H/$PKCS11_HELPER_DIR/usr/local/lib
+ ;;
+esac
+if $CC --version &>/dev/null && [ -d "$OPENSSL_DIR" ] && [ -d "$LZO_DIR" ] && [ -d "$PKCS11_HELPER_DIR" ]; then
# build OpenVPN binary
if ! [ -f Makefile ]; then
autoreconf -i -v \
- && ./configure \
+ && ./configure $XAUTOCONF \
--enable-strict \
--prefix=$H/windest \
MAN2HTML=true \
- --with-ssl-headers=$H/$OPENSSL_DIR/include \
- --with-ssl-lib=$H/$OPENSSL_DIR/out \
- --with-lzo-headers=$H/$LZO_DIR/include \
- --with-lzo-lib=$H/$LZO_DIR \
- --with-pkcs11-helper-headers=$H/$PKCS11_HELPER_DIR/usr/local/include \
- --with-pkcs11-helper-lib=$H/$PKCS11_HELPER_DIR/usr/local/lib
+ --with-ssl-headers=$OPENSSL_INC_DIR \
+ --with-ssl-lib=$OPENSSL_LIB_DIR \
+ --with-lzo-headers=$LZO_INC_DIR \
+ --with-lzo-lib=$LZO_LIB_DIR \
+ --with-pkcs11-helper-headers=$PKCS11_INC_DIR \
+ --with-pkcs11-helper-lib=$PKCS11_LIB_DIR \
+ || exit 1
fi
make -j $MAKE_JOBS && make install
+ if [ -n "$GENOOUT" ];then
# copy OpenVPN and service executables to GENOUT/bin
- mkdir -p $GENOUT/bin &>/dev/null
- cp windest/sbin/openvpn.exe $GENOUT/bin
- cp windest/sbin/openvpnserv.exe $GENOUT/bin
- if [ -z "$NO_STRIP" ]; then
- strip $GENOUT/bin/openvpn.exe
- strip $GENOUT/bin/openvpnserv.exe
+ mkdir -p $GENOUT/bin &>/dev/null
+ cp windest/sbin/openvpn.exe $GENOUT/bin
+ cp windest/sbin/openvpnserv.exe $GENOUT/bin
+ if [ -z "$NO_STRIP" ]; then
+ strip $GENOUT/bin/openvpn.exe
+ strip $GENOUT/bin/openvpnserv.exe
+ fi
fi
else
echo DID NOT BUILD openvpn.exe and openvpnserv.exe because one or more of gcc, OPENSSL_DIR, LZO_DIR, or PKCS11_HELPER_DIR directories were missing
diff --git a/install-win32/openssl/openssl097.patch b/install-win32/openssl/openssl097.patch
index 1a041cf..ccef40a 100644
--- a/install-win32/openssl/openssl097.patch
+++ b/install-win32/openssl/openssl097.patch
@@ -10,44 +10,44 @@ diff -wur openssl-0.9.7m.orig/ms/mw.bat openssl-0.9.7m/ms/mw.bat
--- openssl-0.9.7m.orig/ms/mw.bat Sat Feb 22 11:02:46 2003
+++ openssl-0.9.7m/ms/mw.bat Mon Jan 21 23:12:34 2008
@@ -1,17 +1,23 @@
- @rem OpenSSL with Mingw32
- @rem --------------------
-
+ @rem OpenSSL with Mingw32
+ @rem --------------------
+
+@rem Include MinGW, MSYS, and ActiveState Perl in path
+set PATH=c:\perl\bin;c:\MinGW\bin;c:\msys\1.0\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem
+
- @rem Makefile
- perl util\mkfiles.pl >MINFO
--perl util\mk1mf.pl Mingw32 >ms\mingw32.mak
+ @rem Makefile
+ perl util\mkfiles.pl >MINFO
+-perl util\mk1mf.pl Mingw32 >ms\mingw32.mak
+perl util\mk1mf.pl no-idea no-mdc2 no-rc5 Mingw32 >ms\mingw32.mak
+
- @rem DLL definition files
--perl util\mkdef.pl 32 libeay >ms\libeay32.def
+ @rem DLL definition files
+-perl util\mkdef.pl 32 libeay >ms\libeay32.def
+perl util\mkdef.pl no-idea no-mdc2 no-rc5 32 libeay >ms\libeay32.def
- if errorlevel 1 goto end
--perl util\mkdef.pl 32 ssleay >ms\ssleay32.def
+ if errorlevel 1 goto end
+-perl util\mkdef.pl 32 ssleay >ms\ssleay32.def
+perl util\mkdef.pl no-idea no-mdc2 no-rc5 32 ssleay >ms\ssleay32.def
- if errorlevel 1 goto end
-
- @rem Build the libraries
--make -f ms/mingw32.mak
+ if errorlevel 1 goto end
+
+ @rem Build the libraries
+-make -f ms/mingw32.mak
+
+@rem JY added --win32 flag
+make --win32 -f ms/mingw32.mak
- if errorlevel 1 goto end
-
- @rem Generate the DLLs and input libraries
+ if errorlevel 1 goto end
+
+ @rem Generate the DLLs and input libraries
@@ -20,7 +26,9 @@
- dllwrap --dllname libssl32.dll --output-lib out/libssl32.a --def ms/ssleay32.def out/libssl.a out/libeay32.a
- if errorlevel 1 goto end
-
+ dllwrap --dllname libssl32.dll --output-lib out/libssl32.a --def ms/ssleay32.def out/libssl.a out/libeay32.a
+ if errorlevel 1 goto end
+
+@rem JY added openssl.exe linked to DLL
+gcc -o openssl tmp\verify.o tmp\asn1pars.o tmp\req.o tmp\dgst.o tmp\dh.o tmp\dhparam.o tmp\enc.o tmp\passwd.o tmp\gendh.o tmp\errstr.o tmp\ca.o tmp\pkcs7.o tmp\crl2p7.o tmp\crl.o tmp\rsa.o tmp\rsautl.o tmp\dsa.o tmp\dsaparam.o tmp\x509.o tmp\genrsa.o tmp\gendsa.o tmp\s_server.o tmp\s_client.o tmp\speed.o tmp\s_time.o tmp\apps.o tmp\s_cb.o tmp\s_socket.o tmp\app_rand.o tmp\version.o tmp\sess_id.o tmp\ciphers.o tmp\nseq.o tmp\pkcs12.o tmp\pkcs8.o tmp\spkac.o tmp\smime.o tmp\rand.o tmp\engine.o tmp\ocsp.o tmp\prime.o tmp\openssl.o -leay32 -lssl32 -L. -lwsock32 -lgdi32
+
- echo Done compiling OpenSSL
-
- :end
--
+ echo Done compiling OpenSSL
+
+ :end
+-
diff -wur openssl-0.9.7m.orig/util/pl/Mingw32.pl openssl-0.9.7m/util/pl/Mingw32.pl
--- openssl-0.9.7m.orig/util/pl/Mingw32.pl Sun May 16 23:28:32 2004
+++ openssl-0.9.7m/util/pl/Mingw32.pl Mon Jan 21 17:52:36 2008
diff --git a/install-win32/openssl/openssl098.patch b/install-win32/openssl/openssl098.patch
index 085ce94..653d2fe 100644
--- a/install-win32/openssl/openssl098.patch
+++ b/install-win32/openssl/openssl098.patch
@@ -27,30 +27,30 @@ diff -urw tmp/openssl-0.9.8h/ms/mw.bat openssl-0.9.8h/ms/mw.bat
--- tmp/openssl-0.9.8h/ms/mw.bat Sat Feb 22 11:00:10 2003
+++ openssl-0.9.8h/ms/mw.bat Wed Jun 4 02:56:54 2008
@@ -1,17 +1,23 @@
- @rem OpenSSL with Mingw32
- @rem --------------------
-
+ @rem OpenSSL with Mingw32
+ @rem --------------------
+
+@rem Include MinGW, MSYS, and ActiveState Perl in path
+set PATH=c:\bin;C:\Perl\bin\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;c:\MinGW\bin;c:\msys\1.0\bin
+
- @rem Makefile
- perl util\mkfiles.pl >MINFO
--perl util\mk1mf.pl Mingw32 >ms\mingw32.mak
+ @rem Makefile
+ perl util\mkfiles.pl >MINFO
+-perl util\mk1mf.pl Mingw32 >ms\mingw32.mak
+perl util\mk1mf.pl no-idea no-mdc2 no-rc5 Mingw32 >ms\mingw32.mak
+
- @rem DLL definition files
--perl util\mkdef.pl 32 libeay >ms\libeay32.def
+ @rem DLL definition files
+-perl util\mkdef.pl 32 libeay >ms\libeay32.def
+perl util\mkdef.pl no-idea no-mdc2 no-rc5 32 libeay >ms\libeay32.def
- if errorlevel 1 goto end
--perl util\mkdef.pl 32 ssleay >ms\ssleay32.def
+ if errorlevel 1 goto end
+-perl util\mkdef.pl 32 ssleay >ms\ssleay32.def
+perl util\mkdef.pl no-idea no-mdc2 no-rc5 32 ssleay >ms\ssleay32.def
- if errorlevel 1 goto end
-
- @rem Build the libraries
--make -f ms/mingw32.mak
+ if errorlevel 1 goto end
+
+ @rem Build the libraries
+-make -f ms/mingw32.mak
+
+@rem JY added --win32
+make --win32 -f ms/mingw32.mak
- if errorlevel 1 goto end
-
- @rem Generate the DLLs and input libraries
+ if errorlevel 1 goto end
+
+ @rem Generate the DLLs and input libraries
diff --git a/list.c b/list.c
index 371c510..fb93d0a 100644
--- a/list.c
+++ b/list.c
@@ -52,7 +52,6 @@ hash_init (const int n_buckets,
{
struct hash_bucket *b = &h->buckets[i];
b->list = NULL;
- mutex_init (&b->mutex);
}
return h;
}
@@ -66,7 +65,6 @@ hash_free (struct hash *hash)
struct hash_bucket *b = &hash->buckets[i];
struct hash_element *he = b->list;
- mutex_destroy (&b->mutex);
while (he)
{
struct hash_element *next = he->next;
@@ -148,7 +146,6 @@ hash_add (struct hash *hash, const void *key, void *value, bool replace)
hv = hash_value (hash, key);
bucket = &hash->buckets[hv & hash->mask];
- mutex_lock (&bucket->mutex);
if ((he = hash_lookup_fast (hash, bucket, key, hv))) /* already exists? */
{
@@ -164,18 +161,16 @@ hash_add (struct hash *hash, const void *key, void *value, bool replace)
ret = true;
}
- mutex_unlock (&bucket->mutex);
-
return ret;
}
void
-hash_remove_by_value (struct hash *hash, void *value, bool autolock)
+hash_remove_by_value (struct hash *hash, void *value)
{
struct hash_iterator hi;
struct hash_element *he;
- hash_iterator_init (hash, &hi, autolock);
+ hash_iterator_init (hash, &hi);
while ((he = hash_iterator_next (&hi)))
{
if (he->value == value)
@@ -226,7 +221,6 @@ void_ptr_compare_function (const void *key1, const void *key2)
void
hash_iterator_init_range (struct hash *hash,
struct hash_iterator *hi,
- bool autolock,
int start_bucket,
int end_bucket)
{
@@ -238,7 +232,6 @@ hash_iterator_init_range (struct hash *hash,
hi->hash = hash;
hi->elem = NULL;
hi->bucket = NULL;
- hi->autolock = autolock;
hi->last = NULL;
hi->bucket_marked = false;
hi->bucket_index_start = start_bucket;
@@ -248,19 +241,14 @@ hash_iterator_init_range (struct hash *hash,
void
hash_iterator_init (struct hash *hash,
- struct hash_iterator *hi,
- bool autolock)
+ struct hash_iterator *hi)
{
- hash_iterator_init_range (hash, hi, autolock, 0, hash->n_buckets);
+ hash_iterator_init_range (hash, hi, 0, hash->n_buckets);
}
static inline void
hash_iterator_lock (struct hash_iterator *hi, struct hash_bucket *b)
{
- if (hi->autolock)
- {
- mutex_lock (&b->mutex);
- }
hi->bucket = b;
hi->last = NULL;
hi->bucket_marked = false;
@@ -276,10 +264,6 @@ hash_iterator_unlock (struct hash_iterator *hi)
hash_remove_marked (hi->hash, hi->bucket);
hi->bucket_marked = false;
}
- if (hi->autolock)
- {
- mutex_unlock (&hi->bucket->mutex);
- }
hi->bucket = NULL;
hi->last = NULL;
}
diff --git a/list.h b/list.h
index d72751b..adde36b 100644
--- a/list.h
+++ b/list.h
@@ -40,7 +40,6 @@
/*#define LIST_TEST*/
#include "basic.h"
-#include "thread.h"
#include "buffer.h"
#define hashsize(n) ((uint32_t)1<<(n))
@@ -56,7 +55,6 @@ struct hash_element
struct hash_bucket
{
- MUTEX_DEFINE (mutex);
struct hash_element *list;
};
@@ -90,7 +88,7 @@ bool hash_remove_fast (struct hash *hash,
const void *key,
uint32_t hv);
-void hash_remove_by_value (struct hash *hash, void *value, bool autolock);
+void hash_remove_by_value (struct hash *hash, void *value);
struct hash_iterator
{
@@ -100,18 +98,16 @@ struct hash_iterator
struct hash_element *elem;
struct hash_element *last;
bool bucket_marked;
- bool autolock;
int bucket_index_start;
int bucket_index_end;
};
void hash_iterator_init_range (struct hash *hash,
struct hash_iterator *hi,
- bool autolock,
int start_bucket,
int end_bucket);
-void hash_iterator_init (struct hash *hash, struct hash_iterator *iter, bool autolock);
+void hash_iterator_init (struct hash *hash, struct hash_iterator *iter);
struct hash_element *hash_iterator_next (struct hash_iterator *hi);
void hash_iterator_delete_element (struct hash_iterator *hi);
void hash_iterator_free (struct hash_iterator *hi);
@@ -149,40 +145,21 @@ hash_bucket (struct hash *hash, uint32_t hv)
return &hash->buckets[hv & hash->mask];
}
-static inline void
-hash_bucket_lock (struct hash_bucket *bucket)
-{
- mutex_lock (&bucket->mutex);
-}
-
-static inline void
-hash_bucket_unlock (struct hash_bucket *bucket)
-{
- mutex_unlock (&bucket->mutex);
-}
-
static inline void *
-hash_lookup_lock (struct hash *hash, const void *key, uint32_t hv)
+hash_lookup (struct hash *hash, const void *key)
{
void *ret = NULL;
struct hash_element *he;
+ uint32_t hv = hash_value (hash, key);
struct hash_bucket *bucket = &hash->buckets[hv & hash->mask];
- mutex_lock (&bucket->mutex);
he = hash_lookup_fast (hash, bucket, key, hv);
if (he)
ret = he->value;
- mutex_unlock (&bucket->mutex);
return ret;
}
-static inline void *
-hash_lookup (struct hash *hash, const void *key)
-{
- return hash_lookup_lock (hash, key, hash_value (hash, key));
-}
-
/* NOTE: assumes that key is not a duplicate */
static inline void
hash_add_fast (struct hash *hash,
@@ -211,9 +188,7 @@ hash_remove (struct hash *hash, const void *key)
hv = hash_value (hash, key);
bucket = &hash->buckets[hv & hash->mask];
- mutex_lock (&bucket->mutex);
ret = hash_remove_fast (hash, bucket, key, hv);
- mutex_unlock (&bucket->mutex);
return ret;
}
diff --git a/manage.c b/manage.c
index a79a8fd..ab425e7 100644
--- a/manage.c
+++ b/manage.c
@@ -1999,9 +1999,9 @@ man_settings_init (struct man_settings *ms,
/*
* Initialize socket address
*/
- ms->local.sa.sin_family = AF_INET;
- ms->local.sa.sin_addr.s_addr = 0;
- ms->local.sa.sin_port = htons (port);
+ ms->local.addr.in4.sin_family = AF_INET;
+ ms->local.addr.in4.sin_addr.s_addr = 0;
+ ms->local.addr.in4.sin_port = htons (port);
/*
* Run management over tunnel, or
@@ -2013,7 +2013,7 @@ man_settings_init (struct man_settings *ms,
}
else
{
- ms->local.sa.sin_addr.s_addr = getaddr
+ ms->local.addr.in4.sin_addr.s_addr = getaddr
(GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL);
}
}
@@ -2493,7 +2493,7 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i
&& man->connection.state == MS_INITIAL)
{
/* listen on our local TUN/TAP IP address */
- man->settings.local.sa.sin_addr.s_addr = htonl (tun_local_ip);
+ man->settings.local.addr.in4.sin_addr.s_addr = htonl (tun_local_ip);
man_connection_init (man);
}
diff --git a/mbuf.c b/mbuf.c
index 7e21252..0f36d3c 100644
--- a/mbuf.c
+++ b/mbuf.c
@@ -38,7 +38,6 @@ mbuf_init (unsigned int size)
{
struct mbuf_set *ret;
ALLOC_OBJ_CLEAR (ret, struct mbuf_set);
- mutex_init (&ret->mutex);
ret->capacity = adjust_power_of_2 (size);
ALLOC_ARRAY (ret->array, struct mbuf_item, ret->capacity);
return ret;
@@ -56,7 +55,6 @@ mbuf_free (struct mbuf_set *ms)
mbuf_free_buf (item->buffer);
}
free (ms->array);
- mutex_destroy (&ms->mutex);
free (ms);
}
}
@@ -89,11 +87,10 @@ void
mbuf_add_item (struct mbuf_set *ms, const struct mbuf_item *item)
{
ASSERT (ms);
- mutex_lock (&ms->mutex);
if (ms->len == ms->capacity)
{
struct mbuf_item rm;
- ASSERT (mbuf_extract_item (ms, &rm, false));
+ ASSERT (mbuf_extract_item (ms, &rm));
mbuf_free_buf (rm.buffer);
msg (D_MULTI_DROPPED, "MBUF: mbuf packet dropped");
}
@@ -104,17 +101,14 @@ mbuf_add_item (struct mbuf_set *ms, const struct mbuf_item *item)
if (++ms->len > ms->max_queued)
ms->max_queued = ms->len;
++item->buffer->refcount;
- mutex_unlock (&ms->mutex);
}
bool
-mbuf_extract_item (struct mbuf_set *ms, struct mbuf_item *item, const bool lock)
+mbuf_extract_item (struct mbuf_set *ms, struct mbuf_item *item)
{
bool ret = false;
if (ms)
{
- if (lock)
- mutex_lock (&ms->mutex);
while (ms->len)
{
*item = ms->array[ms->head];
@@ -126,8 +120,6 @@ mbuf_extract_item (struct mbuf_set *ms, struct mbuf_item *item, const bool lock)
break;
}
}
- if (lock)
- mutex_unlock (&ms->mutex);
}
return ret;
}
@@ -139,7 +131,6 @@ mbuf_peek_dowork (struct mbuf_set *ms)
if (ms)
{
int i;
- mutex_lock (&ms->mutex);
for (i = 0; i < (int) ms->len; ++i)
{
struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
@@ -149,7 +140,6 @@ mbuf_peek_dowork (struct mbuf_set *ms)
break;
}
}
- mutex_unlock (&ms->mutex);
}
return ret;
}
@@ -160,7 +150,6 @@ mbuf_dereference_instance (struct mbuf_set *ms, struct multi_instance *mi)
if (ms)
{
int i;
- mutex_lock (&ms->mutex);
for (i = 0; i < (int) ms->len; ++i)
{
struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
@@ -172,7 +161,6 @@ mbuf_dereference_instance (struct mbuf_set *ms, struct multi_instance *mi)
msg (D_MBUF, "MBUF: dereferenced queued packet");
}
}
- mutex_unlock (&ms->mutex);
}
}
diff --git a/mbuf.h b/mbuf.h
index ab7cb05..a0de679 100644
--- a/mbuf.h
+++ b/mbuf.h
@@ -58,7 +58,6 @@ struct mbuf_item
struct mbuf_set
{
- MUTEX_DEFINE (mutex);
unsigned int head;
unsigned int len;
unsigned int capacity;
@@ -74,7 +73,7 @@ void mbuf_free_buf (struct mbuf_buffer *mb);
void mbuf_add_item (struct mbuf_set *ms, const struct mbuf_item *item);
-bool mbuf_extract_item (struct mbuf_set *ms, struct mbuf_item *item, const bool lock);
+bool mbuf_extract_item (struct mbuf_set *ms, struct mbuf_item *item);
void mbuf_dereference_instance (struct mbuf_set *ms, struct multi_instance *mi);
diff --git a/misc.c b/misc.c
index 4a80004..2d6c6f3 100644
--- a/misc.c
+++ b/misc.c
@@ -29,7 +29,6 @@
#include "base64.h"
#include "tun.h"
#include "error.h"
-#include "thread.h"
#include "otime.h"
#include "plugin.h"
#include "options.h"
@@ -156,9 +155,8 @@ set_nice (int niceval)
{
#ifdef HAVE_NICE
errno = 0;
- nice (niceval);
- if (errno != 0)
- msg (M_WARN | M_ERRNO, "WARNING: nice %d failed", niceval);
+ if (nice (niceval) < 0 && errno != 0)
+ msg (M_WARN | M_ERRNO, "WARNING: nice %d failed: %s", niceval, strerror(errno));
else
msg (M_INFO, "nice %d succeeded", niceval);
#else
@@ -176,6 +174,7 @@ run_up_down (const char *command,
const struct plugin_list *plugins,
int plugin_type,
const char *arg,
+ const char *dev_type,
int tun_mtu,
int link_mtu,
const char *ifconfig_local,
@@ -193,6 +192,8 @@ run_up_down (const char *command,
setenv_int (es, "tun_mtu", tun_mtu);
setenv_int (es, "link_mtu", link_mtu);
setenv_str (es, "dev", arg);
+ if (dev_type)
+ setenv_str (es, "dev_type", dev_type);
if (!ifconfig_local)
ifconfig_local = "";
@@ -212,7 +213,7 @@ run_up_down (const char *command,
ifconfig_local, ifconfig_remote,
context);
- if (plugin_call (plugins, plugin_type, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+ if (plugin_call (plugins, plugin_type, &argv, NULL, es, -1, NULL) != OPENVPN_PLUGIN_FUNC_SUCCESS)
msg (M_FATAL, "ERROR: up/down plugin call failed");
argv_reset (&argv);
@@ -231,7 +232,7 @@ run_up_down (const char *command,
ifconfig_local, ifconfig_remote,
context);
argv_msg (M_INFO, &argv);
- openvpn_execve_check (&argv, es, S_SCRIPT|S_FATAL, "script failed");
+ openvpn_run_script (&argv, es, S_FATAL, "--up/--down");
argv_reset (&argv);
}
@@ -494,6 +495,7 @@ openvpn_execve_allowed (const unsigned int flags)
return script_security >= SSEC_BUILT_IN;
}
+
#ifndef WIN32
/*
* Run execve() inside a fork(). Designed to replicate the semantics of system() but
@@ -505,6 +507,7 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
{
struct gc_arena gc = gc_new ();
int ret = -1;
+ static bool warn_shown = false;
if (a && a->argv[0])
{
@@ -541,9 +544,10 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
ASSERT (0);
}
}
- else
+ else if (!warn_shown && (script_security < SSEC_SCRIPTS))
{
msg (M_WARN, SCRIPT_SECURITY_WARNING);
+ warn_shown = true;
}
#else
msg (M_WARN, "openvpn_execve: execve function not available");
@@ -637,9 +641,7 @@ strerror_ts (int errnum, struct gc_arena *gc)
#ifdef HAVE_STRERROR
struct buffer out = alloc_buf_gc (256, gc);
- mutex_lock_static (L_STRERR);
buf_printf (&out, "%s", openvpn_strerror (errnum, gc));
- mutex_unlock_static (L_STRERR);
return BSTR (&out);
#else
return "[error string unavailable]";
@@ -777,18 +779,15 @@ struct env_set *
env_set_create (struct gc_arena *gc)
{
struct env_set *es;
- mutex_lock_static (L_ENV_SET);
ALLOC_OBJ_CLEAR_GC (es, struct env_set, gc);
es->list = NULL;
es->gc = gc;
- mutex_unlock_static (L_ENV_SET);
return es;
}
void
env_set_destroy (struct env_set *es)
{
- mutex_lock_static (L_ENV_SET);
if (es && es->gc == NULL)
{
struct env_item *e = es->list;
@@ -801,7 +800,6 @@ env_set_destroy (struct env_set *es)
}
free (es);
}
- mutex_unlock_static (L_ENV_SET);
}
bool
@@ -810,9 +808,7 @@ env_set_del (struct env_set *es, const char *str)
bool ret;
ASSERT (es);
ASSERT (str);
- mutex_lock_static (L_ENV_SET);
ret = env_set_del_nolock (es, str);
- mutex_unlock_static (L_ENV_SET);
return ret;
}
@@ -821,9 +817,7 @@ env_set_add (struct env_set *es, const char *str)
{
ASSERT (es);
ASSERT (str);
- mutex_lock_static (L_ENV_SET);
env_set_add_nolock (es, str);
- mutex_unlock_static (L_ENV_SET);
}
void
@@ -836,7 +830,6 @@ env_set_print (int msglevel, const struct env_set *es)
if (es)
{
- mutex_lock_static (L_ENV_SET);
e = es->list;
i = 0;
@@ -847,7 +840,6 @@ env_set_print (int msglevel, const struct env_set *es)
++i;
e = e->next;
}
- mutex_unlock_static (L_ENV_SET);
}
}
}
@@ -861,14 +853,12 @@ env_set_inherit (struct env_set *es, const struct env_set *src)
if (src)
{
- mutex_lock_static (L_ENV_SET);
e = src->list;
while (e)
{
env_set_add_nolock (es, e->string);
e = e->next;
}
- mutex_unlock_static (L_ENV_SET);
}
}
@@ -880,7 +870,6 @@ env_set_add_to_environment (const struct env_set *es)
struct gc_arena gc = gc_new ();
const struct env_item *e;
- mutex_lock_static (L_ENV_SET);
e = es->list;
while (e)
@@ -893,7 +882,6 @@ env_set_add_to_environment (const struct env_set *es)
e = e->next;
}
- mutex_unlock_static (L_ENV_SET);
gc_free (&gc);
}
}
@@ -906,7 +894,6 @@ env_set_remove_from_environment (const struct env_set *es)
struct gc_arena gc = gc_new ();
const struct env_item *e;
- mutex_lock_static (L_ENV_SET);
e = es->list;
while (e)
@@ -919,7 +906,6 @@ env_set_remove_from_environment (const struct env_set *es)
e = e->next;
}
- mutex_unlock_static (L_ENV_SET);
gc_free (&gc);
}
}
@@ -1018,7 +1004,9 @@ setenv_str_ex (struct env_set *es,
{
const char *str = construct_name_value (name_tmp, val_tmp, &gc);
env_set_add (es, str);
- /*msg (M_INFO, "SETENV_ES '%s'", str);*/
+#if DEBUG_VERBOSE_SETENV
+ msg (M_INFO, "SETENV_ES '%s'", str);
+#endif
}
else
env_set_del (es, name_tmp);
@@ -1038,12 +1026,10 @@ setenv_str_ex (struct env_set *es,
char *str = construct_name_value (name_tmp, val_tmp, NULL);
int status;
- mutex_lock_static (L_PUTENV);
status = putenv (str);
/*msg (M_INFO, "PUTENV '%s'", str);*/
if (!status)
manage_env (str);
- mutex_unlock_static (L_PUTENV);
if (status)
msg (M_WARN | M_ERRNO, "putenv('%s') failed", str);
}
@@ -1166,25 +1152,55 @@ test_file (const char *filename)
/* create a temporary filename in directory */
const char *
-create_temp_filename (const char *directory, const char *prefix, struct gc_arena *gc)
+create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc)
{
static unsigned int counter;
struct buffer fname = alloc_buf_gc (256, gc);
+ int fd;
+ const char *retfname = NULL;
+ unsigned int attempts = 0;
- mutex_lock_static (L_CREATE_TEMP);
- ++counter;
- mutex_unlock_static (L_CREATE_TEMP);
-
- {
- uint8_t rndbytes[16];
- const char *rndstr;
-
- prng_bytes (rndbytes, sizeof (rndbytes));
- rndstr = format_hex_ex (rndbytes, sizeof (rndbytes), 40, 0, NULL, gc);
- buf_printf (&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr);
- }
+ do
+ {
+ uint8_t rndbytes[16];
+ const char *rndstr;
+
+ ++attempts;
+ ++counter;
+
+ prng_bytes (rndbytes, sizeof rndbytes);
+ rndstr = format_hex_ex (rndbytes, sizeof rndbytes, 40, 0, NULL, gc);
+ buf_printf (&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr);
+
+ retfname = gen_path (directory, BSTR (&fname), gc);
+ if (!retfname)
+ {
+ msg (M_FATAL, "Failed to create temporary filename and path");
+ return NULL;
+ }
+
+ /* Atomically create the file. Errors out if the file already
+ exists. */
+ fd = open (retfname, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
+ if (fd != -1)
+ {
+ close (fd);
+ return retfname;
+ }
+ else if (fd == -1 && errno != EEXIST)
+ {
+ /* Something else went wrong, no need to retry. */
+ struct gc_arena gcerr = gc_new ();
+ msg (M_FATAL, "Could not create temporary file '%s': %s",
+ retfname, strerror_ts (errno, &gcerr));
+ gc_free (&gcerr);
+ return NULL;
+ }
+ }
+ while (attempts < 6);
- return gen_path (directory, BSTR (&fname), gc);
+ msg (M_FATAL, "Failed to create temporary file after %i attempts", attempts);
+ return NULL;
}
/*
@@ -1684,14 +1700,16 @@ void
purge_user_pass (struct user_pass *up, const bool force)
{
const bool nocache = up->nocache;
+ static bool warn_shown = false;
if (nocache || force)
{
CLEAR (*up);
up->nocache = nocache;
}
- else
+ else if (!warn_shown)
{
msg (M_WARN, "WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this");
+ warn_shown = true;
}
}
diff --git a/misc.h b/misc.h
index cc6745a..7681c00 100644
--- a/misc.h
+++ b/misc.h
@@ -93,6 +93,7 @@ void run_up_down (const char *command,
const struct plugin_list *plugins,
int plugin_type,
const char *arg,
+ const char *dev_type,
int tun_mtu,
int link_mtu,
const char *ifconfig_local,
@@ -136,6 +137,15 @@ bool openvpn_execve_check (const struct argv *a, const struct env_set *es, const
bool openvpn_execve_allowed (const unsigned int flags);
int openvpn_system (const char *command, const struct env_set *es, unsigned int flags);
+static inline bool
+openvpn_run_script (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *hook)
+{
+ char msg[256];
+
+ openvpn_snprintf(msg, sizeof(msg), "WARNING: Failed running command (%s)", hook);
+ return openvpn_execve_check(a, es, flags | S_SCRIPT, msg);
+};
+
#ifdef HAVE_STRERROR
/* a thread-safe version of strerror */
const char* strerror_ts (int errnum, struct gc_arena *gc);
@@ -218,8 +228,8 @@ long int get_random(void);
/* return true if filename can be opened for read */
bool test_file (const char *filename);
-/* create a temporary filename in directory */
-const char *create_temp_filename (const char *directory, const char *prefix, struct gc_arena *gc);
+/* create a temporary file in directory, returns the filename of the created file */
+const char *create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc);
/* put a directory and filename together */
const char *gen_path (const char *directory, const char *filename, struct gc_arena *gc);
@@ -342,6 +352,7 @@ void get_user_pass_auto_userid (struct user_pass *up, const char *tag);
extern const char *iproute_path;
#endif
+/* Script security */
#define SSEC_NONE 0 /* strictly no calling of external programs */
#define SSEC_BUILT_IN 1 /* only call built-in programs such as ifconfig, route, netsh, etc.*/
#define SSEC_SCRIPTS 2 /* allow calling of built-in programs and user-defined scripts */
diff --git a/mroute.c b/mroute.c
index ad76977..c8e979a 100644
--- a/mroute.c
+++ b/mroute.c
@@ -88,12 +88,33 @@ mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int
}
}
+static inline void
+mroute_get_in6_addr (struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
+{
+ if (ma)
+ {
+ ma->type = MR_ADDR_IPV6 | mask;
+ ma->netbits = 0;
+ ma->len = 16;
+ *(struct in6_addr *)ma->addr = src;
+ }
+}
+
static inline bool
mroute_is_mcast (const in_addr_t addr)
{
return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK));
}
+/* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies
+ * the address as being a multicast address"
+ */
+static inline bool
+mroute_is_mcast_ipv6 (const struct in6_addr addr)
+{
+ return (addr.s6_addr[0] == 0xff);
+}
+
#ifdef ENABLE_PF
static unsigned int
@@ -155,10 +176,29 @@ mroute_extract_addr_ipv4 (struct mroute_addr *src,
}
break;
case 6:
- {
- msg (M_WARN, "Need IPv6 code in mroute_extract_addr_from_packet");
- break;
- }
+ if (BLEN (buf) >= (int) sizeof (struct openvpn_ipv6hdr))
+ {
+ const struct openvpn_ipv6hdr *ipv6 = (const struct openvpn_ipv6hdr *) BPTR (buf);
+#if 0 /* very basic debug */
+ struct gc_arena gc = gc_new ();
+ msg( M_INFO, "IPv6 packet! src=%s, dst=%s",
+ print_in6_addr( ipv6->saddr, 0, &gc ),
+ print_in6_addr( ipv6->daddr, 0, &gc ));
+ gc_free (&gc);
+#endif
+
+ mroute_get_in6_addr (src, ipv6->saddr, 0);
+ mroute_get_in6_addr (dest, ipv6->daddr, 0);
+
+ if (mroute_is_mcast_ipv6 (ipv6->daddr))
+ ret |= MROUTE_EXTRACT_MCAST;
+
+ ret |= MROUTE_EXTRACT_SUCCEEDED;
+ }
+ break;
+ default:
+ msg (M_WARN, "IP packet with unknown IP version=%d seen",
+ OPENVPN_IPH_GET_VER (*BPTR(buf)));
}
}
return ret;
@@ -226,25 +266,47 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
const struct openvpn_sockaddr *osaddr,
bool use_port)
{
- if (osaddr->sa.sin_family == AF_INET)
+ switch (osaddr->addr.sa.sa_family)
+ {
+ case AF_INET:
{
if (use_port)
{
addr->type = MR_ADDR_IPV4 | MR_WITH_PORT;
addr->netbits = 0;
addr->len = 6;
- memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
- memcpy (addr->addr + 4, &osaddr->sa.sin_port, 2);
+ memcpy (addr->addr, &osaddr->addr.in4.sin_addr.s_addr, 4);
+ memcpy (addr->addr + 4, &osaddr->addr.in4.sin_port, 2);
}
else
{
addr->type = MR_ADDR_IPV4;
addr->netbits = 0;
addr->len = 4;
- memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
+ memcpy (addr->addr, &osaddr->addr.in4.sin_addr.s_addr, 4);
}
return true;
}
+#ifdef USE_PF_INET6
+ case AF_INET6:
+ if (use_port)
+ {
+ addr->type = MR_ADDR_IPV6 | MR_WITH_PORT;
+ addr->netbits = 0;
+ addr->len = 18;
+ memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16);
+ memcpy (addr->addr + 16, &osaddr->addr.in6.sin6_port, 2);
+ }
+ else
+ {
+ addr->type = MR_ADDR_IPV6;
+ addr->netbits = 0;
+ addr->len = 16;
+ memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16);
+ }
+ return true;
+#endif
+ }
return false;
}
@@ -252,14 +314,36 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
* Zero off the host bits in an address, leaving
* only the network bits, using the netbits member of
* struct mroute_addr as the controlling parameter.
+ *
+ * TODO: this is called for route-lookup for every yet-unhashed
+ * destination address, so for lots of active net-iroutes, this
+ * might benefit from some "zeroize 32 bit at a time" improvements
*/
void
mroute_addr_mask_host_bits (struct mroute_addr *ma)
{
in_addr_t addr = ntohl(*(in_addr_t*)ma->addr);
- ASSERT ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4);
- addr &= netbits_to_netmask (ma->netbits);
- *(in_addr_t*)ma->addr = htonl (addr);
+ if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4)
+ {
+ addr &= netbits_to_netmask (ma->netbits);
+ *(in_addr_t*)ma->addr = htonl (addr);
+ }
+ else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6)
+ {
+ int byte = ma->len-1; /* rightmost byte in address */
+ int bits_to_clear = 128 - ma->netbits;
+
+ while( byte >= 0 && bits_to_clear > 0 )
+ {
+ if ( bits_to_clear >= 8 )
+ { ma->addr[byte--] = 0; bits_to_clear -= 8; }
+ else
+ { ma->addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; }
+ }
+ ASSERT( bits_to_clear == 0 );
+ }
+ else
+ ASSERT(0);
}
/*
@@ -337,17 +421,24 @@ mroute_addr_print_ex (const struct mroute_addr *ma,
}
break;
case MR_ADDR_IPV6:
- buf_printf (&out, "IPV6");
- break;
- default:
- buf_printf (&out, "UNKNOWN");
- break;
- }
- return BSTR (&out);
- }
- else
- return "[NULL]";
-}
+ {
+ buf_printf (&out, "%s",
+ print_in6_addr( *(struct in6_addr*)&maddr.addr, 0, gc));
+ if (maddr.type & MR_WITH_NETBITS)
+ {
+ buf_printf (&out, "/%d", maddr.netbits);
+ }
+ }
+ break;
+ default:
+ buf_printf (&out, "UNKNOWN");
+ break;
+ }
+ return BSTR (&out);
+ }
+ else
+ return "[NULL]";
+ }
/*
* mroute_helper's main job is keeping track of
@@ -360,7 +451,6 @@ mroute_helper_init (int ageable_ttl_secs)
{
struct mroute_helper *mh;
ALLOC_OBJ_CLEAR (mh, struct mroute_helper);
- /*mutex_init (&mh->mutex);*/
mh->ageable_ttl_secs = ageable_ttl_secs;
return mh;
}
@@ -398,12 +488,10 @@ mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir)
if (ir->netbits >= 0)
{
ASSERT (ir->netbits < MR_HELPER_NET_LEN);
- mroute_helper_lock (mh);
++mh->cache_generation;
++mh->net_len_refcount[ir->netbits];
if (mh->net_len_refcount[ir->netbits] == 1)
mroute_helper_regenerate (mh);
- mroute_helper_unlock (mh);
}
}
@@ -413,20 +501,51 @@ mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir)
if (ir->netbits >= 0)
{
ASSERT (ir->netbits < MR_HELPER_NET_LEN);
- mroute_helper_lock (mh);
++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);
- mroute_helper_unlock (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])
+ mroute_helper_regenerate (mh);
}
}
void
mroute_helper_free (struct mroute_helper *mh)
{
- /*mutex_destroy (&mh->mutex);*/
free (mh);
}
diff --git a/mroute.h b/mroute.h
index b3e3a1f..b72b5ff 100644
--- a/mroute.h
+++ b/mroute.h
@@ -85,13 +85,12 @@ struct mroute_addr {
/*
* Number of bits in an address. Should be raised for IPv6.
*/
-#define MR_HELPER_NET_LEN 32
+#define MR_HELPER_NET_LEN 129
/*
* Used to help maintain CIDR routing table.
*/
struct mroute_helper {
- /*MUTEX_DEFINE (mutex);*/
unsigned int cache_generation; /* incremented when route added */
int ageable_ttl_secs; /* host route cache entry time-to-live*/
int n_net_len; /* length of net_len array */
@@ -128,6 +127,8 @@ 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);
/*
* Given a raw packet in buf, return the src and dest
@@ -159,18 +160,6 @@ mroute_extract_addr_from_packet (struct mroute_addr *src,
return ret;
}
-static inline void
-mroute_helper_lock (struct mroute_helper *mh)
-{
- /*mutex_lock (&mh->mutex);*/
-}
-
-static inline void
-mroute_helper_unlock (struct mroute_helper *mh)
-{
- /*mutex_unlock (&mh->mutex);*/
-}
-
static inline bool
mroute_addr_equal (const struct mroute_addr *a1, const struct mroute_addr *a2)
{
diff --git a/msvc/autodefs.h.in b/msvc/autodefs.h.in
index 9814022..b0fa7f5 100644
--- a/msvc/autodefs.h.in
+++ b/msvc/autodefs.h.in
@@ -1,20 +1,20 @@
-/*
- * Minimum TAP-Win32 version number expected by userspace
- *
- * The TAP-Win32 version number is defined in tap-win32/SOURCES
- */
-#define TAP_ID "@PRODUCT_TAP_ID@"
-#define TAP_WIN32_MIN_MAJOR @PRODUCT_TAP_WIN32_MIN_MAJOR@
-#define TAP_WIN32_MIN_MINOR @PRODUCT_TAP_WIN32_MIN_MINOR@
-
-/* Name of package */
-#define PACKAGE "@PRODUCT_UNIX_NAME@"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "@PRODUCT_NAME@"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "@PRODUCT_UNIX_NAME@"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "@PRODUCT_VERSION@"
+/*
+ * Minimum TAP-Win32 version number expected by userspace
+ *
+ * The TAP-Win32 version number is defined in tap-win32/SOURCES
+ */
+#define TAP_ID "@PRODUCT_TAP_ID@"
+#define TAP_WIN32_MIN_MAJOR @PRODUCT_TAP_WIN32_MIN_MAJOR@
+#define TAP_WIN32_MIN_MINOR @PRODUCT_TAP_WIN32_MIN_MINOR@
+
+/* Name of package */
+#define PACKAGE "@PRODUCT_UNIX_NAME@"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "@PRODUCT_NAME@"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "@PRODUCT_UNIX_NAME@"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@PRODUCT_VERSION@"
diff --git a/msvc/config.py b/msvc/config.py
index 04ea4c5..9915cd0 100644
--- a/msvc/config.py
+++ b/msvc/config.py
@@ -1,93 +1,93 @@
-# build autodefs.h and
-
-import re
-
-autogen = "Automatically generated by config.py"
-
-def parse_version_m4(kv, version_m4):
- r = re.compile(r'^define\((\w+),\[(.*)\]\)$')
- f = open(version_m4)
- for line in f:
- line = line.rstrip()
- m = re.match(r, line)
- if m:
- g = m.groups()
- kv[g[0]] = g[1]
- f.close()
-
-def parse_settings_in(kv, settings_in):
- r = re.compile(r'^!define\s+(\w+)(?:\s+"?(.*?)"?)$')
- f = open(settings_in)
- for line in f:
- line = line.rstrip()
- m = re.match(r, line)
- if m:
- g = m.groups()
- kv[g[0]] = g[1] or ''
- f.close()
-
-def build_autodefs(kv, autodefs_in, autodefs_out):
- def repfn(m):
- var, = m.groups()
- return kv.get(var, '')
-
- r = re.compile(r'@(\w+)@')
- fin = open(autodefs_in)
- fout = open(autodefs_out, 'w')
- fout.write("/* %s */\n\n" % autogen)
- for line in fin:
- newline = re.sub(r, repfn, line)
- fout.write(newline)
- fin.close()
- fout.close()
-
-def print_key_values(kv):
- for k, v in sorted(kv.items()):
- print "%s%s%s" % (k, ' '*(32-len(k)), repr(v))
-
-def get_sources(makefile_am):
- c = set()
- h = set()
- f = open(makefile_am)
- state = False
- for line in f:
- line = line.rstrip()
- if line == 'openvpn_SOURCES = \\':
- state = True
- elif not line:
- state = False
- elif state:
- for sf in line.split():
- if sf.endswith('.c'):
- c.add(sf[:-2])
- elif sf.endswith('.h'):
- h.add(sf[:-2])
- elif sf == '\\':
- pass
- else:
- print >>sys.stderr, "Unrecognized filename:", sf
- f.close()
- return [ sorted(list(s)) for s in (c, h) ]
-
-def output_mak_list(out, title, srclist, ext):
- out.write("%s =" % (title,))
- for x in srclist:
- out.write(" \\\n\t%s.%s" % (x, ext))
- out.write('\n\n')
-
-def output_mak(makefile_am, outfile):
- c, h = get_sources(makefile_am)
- out = open(outfile, 'w')
- out.write("# %s\n\n" % autogen)
- output_mak_list(out, 'HEADERS', h, 'h')
- output_mak_list(out, 'OBJS', c, 'obj')
- out.close()
-
-def main():
- kv = {}
- parse_version_m4(kv, 'version.m4')
- parse_settings_in(kv, 'install-win32/settings.in')
- build_autodefs(kv, 'msvc/autodefs.h.in', 'autodefs.h')
- output_mak('Makefile.am', 'head_obj.mak')
-
-main()
+# build autodefs.h and
+
+import re
+
+autogen = "Automatically generated by config.py"
+
+def parse_version_m4(kv, version_m4):
+ r = re.compile(r'^define\((\w+),\[(.*)\]\)$')
+ f = open(version_m4)
+ for line in f:
+ line = line.rstrip()
+ m = re.match(r, line)
+ if m:
+ g = m.groups()
+ kv[g[0]] = g[1]
+ f.close()
+
+def parse_settings_in(kv, settings_in):
+ r = re.compile(r'^!define\s+(\w+)(?:\s+"?(.*?)"?)$')
+ f = open(settings_in)
+ for line in f:
+ line = line.rstrip()
+ m = re.match(r, line)
+ if m:
+ g = m.groups()
+ kv[g[0]] = g[1] or ''
+ f.close()
+
+def build_autodefs(kv, autodefs_in, autodefs_out):
+ def repfn(m):
+ var, = m.groups()
+ return kv.get(var, '')
+
+ r = re.compile(r'@(\w+)@')
+ fin = open(autodefs_in)
+ fout = open(autodefs_out, 'w')
+ fout.write("/* %s */\n\n" % autogen)
+ for line in fin:
+ newline = re.sub(r, repfn, line)
+ fout.write(newline)
+ fin.close()
+ fout.close()
+
+def print_key_values(kv):
+ for k, v in sorted(kv.items()):
+ print "%s%s%s" % (k, ' '*(32-len(k)), repr(v))
+
+def get_sources(makefile_am):
+ c = set()
+ h = set()
+ f = open(makefile_am)
+ state = False
+ for line in f:
+ line = line.rstrip()
+ if line == 'openvpn_SOURCES = \\':
+ state = True
+ elif not line:
+ state = False
+ elif state:
+ for sf in line.split():
+ if sf.endswith('.c'):
+ c.add(sf[:-2])
+ elif sf.endswith('.h'):
+ h.add(sf[:-2])
+ elif sf == '\\':
+ pass
+ else:
+ print >>sys.stderr, "Unrecognized filename:", sf
+ f.close()
+ return [ sorted(list(s)) for s in (c, h) ]
+
+def output_mak_list(out, title, srclist, ext):
+ out.write("%s =" % (title,))
+ for x in srclist:
+ out.write(" \\\n\t%s.%s" % (x, ext))
+ out.write('\n\n')
+
+def output_mak(makefile_am, outfile):
+ c, h = get_sources(makefile_am)
+ out = open(outfile, 'w')
+ out.write("# %s\n\n" % autogen)
+ output_mak_list(out, 'HEADERS', h, 'h')
+ output_mak_list(out, 'OBJS', c, 'obj')
+ out.close()
+
+def main():
+ kv = {}
+ parse_version_m4(kv, 'version.m4')
+ parse_settings_in(kv, 'install-win32/settings.in')
+ build_autodefs(kv, 'msvc/autodefs.h.in', 'autodefs.h')
+ output_mak('Makefile.am', 'head_obj.mak')
+
+main()
diff --git a/msvc/msvc.mak b/msvc/msvc.mak
index bca779f..2d99de7 100644
--- a/msvc/msvc.mak
+++ b/msvc/msvc.mak
@@ -1,52 +1,52 @@
-# This makefile builds the user-mode component
-# of OpenVPN for Windows in the Visual Studio 2008 environment.
-
-# To build:
-# python msvc\config.py
-# nmake /f msvc\msvc.mak
-
-# Each of the OPENSSL and LZO dirs should have 'lib' and 'include'
-# directories under them.
-
-OPENSSL = \src\openssl
-OPENSSL_DYNAMIC = libeay32.lib ssleay32.lib
-
-LZO = \src\lzo
-LZO_DYNAMIC = lzo2.lib
-
-INCLUDE_DIRS = -I$(OPENSSL)/include -I$(LZO)/include
-
-LIBS = $(OPENSSL_DYNAMIC) $(LZO_DYNAMIC) ws2_32.lib crypt32.lib iphlpapi.lib winmm.lib user32.lib gdi32.lib advapi32.lib wininet.lib
-
-LIB_DIRS = -LIBPATH:$(OPENSSL)\lib -LIBPATH:$(LZO)\lib
-
-EXE = openvpn.exe
-
-CPP=cl.exe
-CPP_ARG_COMMON=/nologo /W3 /O2 -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS -D_CRT_SECURE_NO_DEPRECATE $(INCLUDE_DIRS) /FD /c
-# release:
-CPP_PROJ=$(CPP_ARG_COMMON) /MD -DNDEBUG
-# debug:
-#CPP_PROJ=$(CPP_ARG_COMMON) /MDd /Zi /Od -D_DEBUG
-
-LINK32=link.exe
-# release:
-LINK32_FLAGS=/nologo /subsystem:console /incremental:no /out:"$(EXE)"
-# debug:
-#LINK32_FLAGS=/nologo /subsystem:console /incremental:no /debug /out:"$(EXE)"
-
-# HEADERS and OBJS definitions, automatically generated
-!INCLUDE head_obj.mak
-
-openvpn : $(OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LIB_DIRS) $(LIBS) $(OBJS)
-<<
-
-clean :
- del /Q $(OBJS) $(EXE) *.idb *.pdb
-
-.c.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
+# This makefile builds the user-mode component
+# of OpenVPN for Windows in the Visual Studio 2008 environment.
+
+# To build:
+# python msvc\config.py
+# nmake /f msvc\msvc.mak
+
+# Each of the OPENSSL and LZO dirs should have 'lib' and 'include'
+# directories under them.
+
+OPENSSL = \src\openssl
+OPENSSL_DYNAMIC = libeay32.lib ssleay32.lib
+
+LZO = \src\lzo
+LZO_DYNAMIC = lzo2.lib
+
+INCLUDE_DIRS = -I$(OPENSSL)/include -I$(LZO)/include
+
+LIBS = $(OPENSSL_DYNAMIC) $(LZO_DYNAMIC) ws2_32.lib crypt32.lib iphlpapi.lib winmm.lib user32.lib gdi32.lib advapi32.lib wininet.lib
+
+LIB_DIRS = -LIBPATH:$(OPENSSL)\lib -LIBPATH:$(LZO)\lib
+
+EXE = openvpn.exe
+
+CPP=cl.exe
+CPP_ARG_COMMON=/nologo /W3 /O2 -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS -D_CRT_SECURE_NO_DEPRECATE $(INCLUDE_DIRS) /FD /c
+# release:
+CPP_PROJ=$(CPP_ARG_COMMON) /MD -DNDEBUG
+# debug:
+#CPP_PROJ=$(CPP_ARG_COMMON) /MDd /Zi /Od -D_DEBUG
+
+LINK32=link.exe
+# release:
+LINK32_FLAGS=/nologo /subsystem:console /incremental:no /out:"$(EXE)"
+# debug:
+#LINK32_FLAGS=/nologo /subsystem:console /incremental:no /debug /out:"$(EXE)"
+
+# HEADERS and OBJS definitions, automatically generated
+!INCLUDE head_obj.mak
+
+openvpn : $(OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LIB_DIRS) $(LIBS) $(OBJS)
+<<
+
+clean :
+ del /Q $(OBJS) $(EXE) *.idb *.pdb
+
+.c.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
diff --git a/mtcp.c b/mtcp.c
index 3eca81a..ade2cfb 100644
--- a/mtcp.c
+++ b/mtcp.c
@@ -112,7 +112,6 @@ multi_create_instance_tcp (struct multi_context *m)
const uint32_t hv = hash_value (hash, &mi->real);
struct hash_bucket *bucket = hash_bucket (hash, hv);
- hash_bucket_lock (bucket);
he = hash_lookup_fast (hash, bucket, &mi->real, hv);
if (he)
@@ -128,8 +127,6 @@ multi_create_instance_tcp (struct multi_context *m)
hash_add_fast (hash, bucket, &mi->real, hv, mi);
mi->did_real_hash = true;
-
- hash_bucket_unlock (bucket);
}
#ifdef ENABLE_DEBUG
@@ -153,6 +150,11 @@ multi_tcp_instance_specific_init (struct multi_context *m, struct multi_instance
ASSERT (mi->context.c2.link_socket);
ASSERT (mi->context.c2.link_socket->info.lsa);
ASSERT (mi->context.c2.link_socket->mode == LS_MODE_TCP_ACCEPT_FROM);
+ ASSERT (mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET
+#ifdef USE_PF_INET6
+ || mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET6
+#endif
+ );
if (!mroute_extract_openvpn_sockaddr (&mi->real, &mi->context.c2.link_socket->info.lsa->actual.dest, true))
{
msg (D_MULTI_ERRORS, "MULTI TCP: TCP client address is undefined");
@@ -264,7 +266,7 @@ multi_tcp_process_outgoing_link_ready (struct multi_context *m, struct multi_ins
ASSERT (mi);
/* extract from queue */
- if (mbuf_extract_item (mi->tcp_link_out_deferred, &item, true)) /* ciphertext IP packet */
+ if (mbuf_extract_item (mi->tcp_link_out_deferred, &item)) /* ciphertext IP packet */
{
dmsg (D_MULTI_TCP, "MULTI TCP: transmitting previously deferred packet");
diff --git a/mudp.c b/mudp.c
index bf4ca3d..a478b29 100644
--- a/mudp.c
+++ b/mudp.c
@@ -51,7 +51,6 @@ multi_get_create_instance_udp (struct multi_context *m)
const uint32_t hv = hash_value (hash, &real);
struct hash_bucket *bucket = hash_bucket (hash, hv);
- hash_bucket_lock (bucket);
he = hash_lookup_fast (hash, bucket, &real, hv);
if (he)
@@ -81,8 +80,6 @@ multi_get_create_instance_udp (struct multi_context *m)
}
}
- hash_bucket_unlock (bucket);
-
#ifdef ENABLE_DEBUG
if (check_debug_level (D_MULTI_DEBUG))
{
diff --git a/multi.c b/multi.c
index 4ab1e72..15bea22 100644
--- a/multi.c
+++ b/multi.c
@@ -91,7 +91,7 @@ learn_address_script (const struct multi_context *m,
mroute_addr_print (addr, &gc));
if (mi)
argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false));
- if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+ if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es, -1, NULL) != OPENVPN_PLUGIN_FUNC_SUCCESS)
{
msg (M_WARN, "WARNING: learn-address plugin call failed");
ret = false;
@@ -109,7 +109,7 @@ learn_address_script (const struct multi_context *m,
mroute_addr_print (addr, &gc));
if (mi)
argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false));
- if (!openvpn_execve_check (&argv, es, S_SCRIPT, "WARNING: learn-address command failed"))
+ if (!openvpn_run_script (&argv, es, 0, "--learn-address"))
ret = false;
argv_reset (&argv);
}
@@ -146,7 +146,7 @@ multi_reap_range (const struct multi_context *m,
}
dmsg (D_MULTI_DEBUG, "MULTI: REAP range %d -> %d", start_bucket, end_bucket);
- hash_iterator_init_range (m->vhash, &hi, true, start_bucket, end_bucket);
+ hash_iterator_init_range (m->vhash, &hi, start_bucket, end_bucket);
while ((he = hash_iterator_next (&hi)) != NULL)
{
struct multi_route *r = (struct multi_route *) he->value;
@@ -316,25 +316,18 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
*/
if (t->options.ifconfig_pool_defined)
{
- if (dev == DEV_TYPE_TAP)
- {
- m->ifconfig_pool = ifconfig_pool_init (IFCONFIG_POOL_INDIV,
- t->options.ifconfig_pool_start,
- t->options.ifconfig_pool_end,
- t->options.duplicate_cn);
- }
- else if (dev == DEV_TYPE_TUN)
- {
- m->ifconfig_pool = ifconfig_pool_init (
- (t->options.topology == TOP_NET30) ? IFCONFIG_POOL_30NET : IFCONFIG_POOL_INDIV,
- t->options.ifconfig_pool_start,
- t->options.ifconfig_pool_end,
- t->options.duplicate_cn);
- }
- else
- {
- ASSERT (0);
- }
+ int pool_type = IFCONFIG_POOL_INDIV;
+
+ if ( dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30 )
+ pool_type = IFCONFIG_POOL_30NET;
+
+ m->ifconfig_pool = ifconfig_pool_init (pool_type,
+ t->options.ifconfig_pool_start,
+ t->options.ifconfig_pool_end,
+ t->options.duplicate_cn,
+ t->options.ifconfig_ipv6_pool_defined,
+ t->options.ifconfig_ipv6_pool_base,
+ t->options.ifconfig_ipv6_pool_netbits );
/* reload pool data from file */
if (t->c1.ifconfig_pool_persist)
@@ -429,10 +422,14 @@ multi_del_iroutes (struct multi_context *m,
struct multi_instance *mi)
{
const struct iroute *ir;
+ const struct iroute_ipv6 *ir6;
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);
+
+ for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next )
+ mroute_helper_del_iroute6 (m->route_helper, ir6);
}
}
@@ -471,7 +468,7 @@ multi_client_disconnect_script (struct multi_context *m,
if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT))
{
- if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es, -1, NULL) != OPENVPN_PLUGIN_FUNC_SUCCESS)
msg (M_WARN, "WARNING: client-disconnect plugin call failed");
}
@@ -480,7 +477,7 @@ multi_client_disconnect_script (struct multi_context *m,
struct argv argv = argv_new ();
setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script);
- openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-disconnect command failed");
+ openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect");
argv_reset (&argv);
}
#ifdef MANAGEMENT_DEF_AUTH
@@ -587,7 +584,7 @@ multi_uninit (struct multi_context *m)
struct hash_iterator hi;
struct hash_element *he;
- hash_iterator_init (m->iter, &hi, true);
+ hash_iterator_init (m->iter, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct multi_instance *mi = (struct multi_instance *) he->value;
@@ -633,7 +630,6 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real)
ALLOC_OBJ_CLEAR (mi, struct multi_instance);
- mutex_init (&mi->mutex);
mi->gc = gc_new ();
multi_instance_inc_refcount (mi);
mi->vaddr_handle = -1;
@@ -724,7 +720,7 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
status_printf (so, "OpenVPN CLIENT LIST");
status_printf (so, "Updated,%s", time_string (0, 0, false, &gc_top));
status_printf (so, "Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since");
- hash_iterator_init (m->hash, &hi, true);
+ hash_iterator_init (m->hash, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct gc_arena gc = gc_new ();
@@ -745,7 +741,7 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
status_printf (so, "ROUTING TABLE");
status_printf (so, "Virtual Address,Common Name,Real Address,Last Ref");
- hash_iterator_init (m->vhash, &hi, true);
+ hash_iterator_init (m->vhash, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct gc_arena gc = gc_new ();
@@ -788,7 +784,7 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
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)",
sep, sep, sep, sep, sep, sep, sep, sep);
- hash_iterator_init (m->hash, &hi, true);
+ hash_iterator_init (m->hash, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct gc_arena gc = gc_new ();
@@ -811,7 +807,7 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
status_printf (so, "HEADER%cROUTING_TABLE%cVirtual Address%cCommon Name%cReal Address%cLast Ref%cLast Ref (time_t)",
sep, sep, sep, sep, sep, sep);
- hash_iterator_init (m->vhash, &hi, true);
+ hash_iterator_init (m->vhash, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct gc_arena gc = gc_new ();
@@ -850,7 +846,7 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
#ifdef PACKET_TRUNCATION_CHECK
{
status_printf (so, "HEADER,ERRORS,Common Name,TUN Read Trunc,TUN Write Trunc,Pre-encrypt Trunc,Post-decrypt Trunc");
- hash_iterator_init (m->hash, &hi, true);
+ hash_iterator_init (m->hash, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct gc_arena gc = gc_new ();
@@ -896,8 +892,6 @@ multi_learn_addr (struct multi_context *m,
struct multi_route *oldroute = NULL;
struct multi_instance *owner = NULL;
- hash_bucket_lock (bucket);
-
/* if route currently exists, get the instance which owns it */
he = hash_lookup_fast (m->vhash, bucket, addr, hv);
if (he)
@@ -967,7 +961,6 @@ multi_learn_addr (struct multi_context *m,
gc_free (&gc);
}
- hash_bucket_unlock (bucket);
return owner;
}
@@ -1001,8 +994,6 @@ multi_get_instance_by_virtual_addr (struct multi_context *m,
struct mroute_addr tryaddr;
int i;
- mroute_helper_lock (rh);
-
/* cycle through each CIDR length */
for (i = 0; i < rh->n_net_len; ++i)
{
@@ -1023,8 +1014,6 @@ multi_get_instance_by_virtual_addr (struct multi_context *m,
break;
}
}
-
- mroute_helper_unlock (rh);
}
#ifdef ENABLE_DEBUG
@@ -1066,8 +1055,8 @@ multi_learn_in_addr_t (struct multi_context *m,
struct mroute_addr addr;
CLEAR (remote_si);
- remote_si.sa.sin_family = AF_INET;
- remote_si.sa.sin_addr.s_addr = htonl (a);
+ remote_si.addr.in4.sin_family = AF_INET;
+ remote_si.addr.in4.sin_addr.s_addr = htonl (a);
ASSERT (mroute_extract_openvpn_sockaddr (&addr, &remote_si, false));
if (netbits >= 0)
@@ -1086,6 +1075,37 @@ multi_learn_in_addr_t (struct multi_context *m,
}
}
+static struct multi_instance *
+multi_learn_in6_addr (struct multi_context *m,
+ struct multi_instance *mi,
+ struct in6_addr a6,
+ int netbits, /* -1 if host route, otherwise # of network bits in address */
+ bool primary)
+{
+ struct mroute_addr addr;
+
+ addr.len = 16;
+ addr.type = MR_ADDR_IPV6;
+ addr.netbits = 0;
+ memcpy( &addr.addr, &a6, sizeof(a6) );
+
+ if (netbits >= 0)
+ {
+ addr.type |= MR_WITH_NETBITS;
+ addr.netbits = (uint8_t) netbits;
+ mroute_addr_mask_host_bits( &addr );
+ }
+
+ {
+ struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0);
+#ifdef MANAGEMENT_DEF_AUTH
+ if (management && owner)
+ management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary);
+#endif
+ return owner;
+ }
+}
+
/*
* A new client has connected, add routes (server -> client)
* to internal routing table.
@@ -1096,6 +1116,7 @@ multi_add_iroutes (struct multi_context *m,
{
struct gc_arena gc = gc_new ();
const struct iroute *ir;
+ const struct iroute_ipv6 *ir6;
if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN)
{
mi->did_iroutes = true;
@@ -1115,6 +1136,22 @@ multi_add_iroutes (struct multi_context *m,
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",
+ 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);
+
+ multi_learn_in6_addr (m, mi, ir6->network, ir6->netbits, false);
+ }
}
gc_free (&gc);
}
@@ -1135,7 +1172,7 @@ multi_delete_dup (struct multi_context *m, struct multi_instance *new_mi)
struct hash_element *he;
int count = 0;
- hash_iterator_init (m->iter, &hi, true);
+ hash_iterator_init (m->iter, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct multi_instance *mi = (struct multi_instance *) he->value;
@@ -1203,21 +1240,37 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
#ifdef ENABLE_CLIENT_NAT
mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias;
#endif
+
+ /* the current implementation does not allow "static IPv4, pool IPv6",
+ * (see below) so issue a warning if that happens - don't break the
+ * session, though, as we don't even know if this client WANTS IPv6
+ */
+ if ( mi->context.c1.tuntap->ipv6 &&
+ mi->context.options.ifconfig_ipv6_pool_defined &&
+ ! mi->context.options.push_ifconfig_ipv6_defined )
+ {
+ msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." );
+ }
}
else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */
{
in_addr_t local=0, remote=0;
+ struct in6_addr remote_ipv6;
const char *cn = NULL;
if (!mi->context.options.duplicate_cn)
cn = tls_common_name (mi->context.c2.tls_multi, true);
- mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, cn);
+ mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, &remote_ipv6, cn);
if (mi->vaddr_handle >= 0)
{
const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap);
const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap);
+ msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s",
+ print_in_addr_t( remote, 0, &gc ),
+ print_in6_addr( remote_ipv6, 0, &gc ) );
+
/* set push_ifconfig_remote_netmask from pool ifconfig address(es) */
mi->context.c2.push_ifconfig_local = remote;
if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET))
@@ -1239,12 +1292,46 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
else
msg (D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s",
multi_instance_string (mi, false, &gc));
+
+ if ( mi->context.options.ifconfig_ipv6_pool_defined )
+ {
+ mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6;
+ mi->context.c2.push_ifconfig_ipv6_remote =
+ mi->context.c1.tuntap->local_ipv6;
+ mi->context.c2.push_ifconfig_ipv6_netbits =
+ mi->context.options.ifconfig_ipv6_pool_netbits;
+ mi->context.c2.push_ifconfig_ipv6_defined = true;
+ }
}
else
{
msg (D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available");
}
}
+
+ /* IPv6 push_ifconfig is a bit problematic - since IPv6 shares the
+ * pool handling with IPv4, the combination "static IPv4, dynamic IPv6"
+ * will fail (because no pool will be allocated in this case).
+ * OTOH, this doesn't make too much sense in reality - and the other
+ * way round ("dynamic IPv4, static IPv6") or "both static" makes sense
+ * -> and so it's implemented right now
+ */
+ if ( mi->context.c1.tuntap->ipv6 &&
+ mi->context.options.push_ifconfig_ipv6_defined )
+ {
+ mi->context.c2.push_ifconfig_ipv6_local =
+ mi->context.options.push_ifconfig_ipv6_local;
+ mi->context.c2.push_ifconfig_ipv6_remote =
+ mi->context.options.push_ifconfig_ipv6_remote;
+ mi->context.c2.push_ifconfig_ipv6_netbits =
+ mi->context.options.push_ifconfig_ipv6_netbits;
+ mi->context.c2.push_ifconfig_ipv6_defined = true;
+
+ msg( M_INFO, "MULTI_sva: push_ifconfig_ipv6 %s/%d",
+ print_in6_addr( mi->context.c2.push_ifconfig_ipv6_local, 0, &gc ),
+ mi->context.c2.push_ifconfig_ipv6_netbits );
+ }
+
gc_free (&gc);
}
@@ -1283,6 +1370,11 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi)
SA_SET_IF_NONZERO);
}
}
+
+ /* TODO: I'm not exactly sure what these environment variables are
+ * used for, but if we have them for IPv4, we should also have
+ * them for IPv6, no?
+ */
}
/*
@@ -1533,10 +1625,15 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT))
{
struct argv argv = argv_new ();
- const char *dc_file = create_temp_filename (mi->context.options.tmp_dir, "cc", &gc);
+ const char *dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc);
+
+ if( !dc_file ) {
+ cc_succeeded = false;
+ goto script_depr_failed;
+ }
+
argv_printf (&argv, "%s", dc_file);
- delete_file (dc_file);
- if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es, -1, NULL) != OPENVPN_PLUGIN_FUNC_SUCCESS)
{
msg (M_WARN, "WARNING: client-connect plugin call failed");
cc_succeeded = false;
@@ -1546,6 +1643,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found);
++cc_succeeded_count;
}
+ script_depr_failed:
argv_reset (&argv);
}
@@ -1556,7 +1654,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
plugin_return_init (&pr);
- if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+ if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es, -1, NULL) != OPENVPN_PLUGIN_FUNC_SUCCESS)
{
msg (M_WARN, "WARNING: client-connect-v2 plugin call failed");
cc_succeeded = false;
@@ -1581,22 +1679,24 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
setenv_str (mi->context.c2.es, "script_type", "client-connect");
- dc_file = create_temp_filename (mi->context.options.tmp_dir, "cc", &gc);
-
- delete_file (dc_file);
+ dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc);
+ if( !dc_file ) {
+ cc_succeeded = false;
+ goto script_failed;
+ }
argv_printf (&argv, "%sc %s",
mi->context.options.client_connect_script,
dc_file);
- if (openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-connect command failed"))
+ if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect"))
{
multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found);
++cc_succeeded_count;
}
else
cc_succeeded = false;
-
+ script_failed:
argv_reset (&argv);
}
@@ -1664,6 +1764,15 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc));
}
+ if (mi->context.c2.push_ifconfig_ipv6_defined)
+ {
+ multi_learn_in6_addr (m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true);
+ /* TODO: find out where addresses are "unlearned"!! */
+ msg (D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s",
+ multi_instance_string (mi, false, &gc),
+ print_in6_addr (mi->context.c2.push_ifconfig_ipv6_local, 0, &gc));
+ }
+
/* add routes locally, pointing to new client, if
--iroute options have been specified */
multi_add_iroutes (m, mi);
@@ -1776,7 +1885,7 @@ multi_bcast (struct multi_context *m,
printf ("BCAST len=%d\n", BLEN (buf));
#endif
mb = mbuf_alloc_buf (buf);
- hash_iterator_init (m->iter, &hi, true);
+ hash_iterator_init (m->iter, &hi);
while ((he = hash_iterator_next (&hi)))
{
@@ -2244,7 +2353,7 @@ multi_get_queue (struct mbuf_set *ms)
{
struct mbuf_item item;
- if (mbuf_extract_item (ms, &item, true)) /* cleartext IP packet */
+ if (mbuf_extract_item (ms, &item)) /* cleartext IP packet */
{
unsigned int pipv4_flags = PIPV4_PASSTOS;
@@ -2470,7 +2579,7 @@ management_callback_kill_by_cn (void *arg, const char *del_cn)
struct hash_element *he;
int count = 0;
- hash_iterator_init (m->iter, &hi, true);
+ hash_iterator_init (m->iter, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct multi_instance *mi = (struct multi_instance *) he->value;
@@ -2499,12 +2608,12 @@ management_callback_kill_by_addr (void *arg, const in_addr_t addr, const int por
int count = 0;
CLEAR (saddr);
- saddr.sa.sin_family = AF_INET;
- saddr.sa.sin_addr.s_addr = htonl (addr);
- saddr.sa.sin_port = htons (port);
+ saddr.addr.in4.sin_family = AF_INET;
+ saddr.addr.in4.sin_addr.s_addr = htonl (addr);
+ saddr.addr.in4.sin_port = htons (port);
if (mroute_extract_openvpn_sockaddr (&maddr, &saddr, true))
{
- hash_iterator_init (m->iter, &hi, true);
+ hash_iterator_init (m->iter, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct multi_instance *mi = (struct multi_instance *) he->value;
@@ -2679,16 +2788,24 @@ tunnel_server (struct context *top)
{
ASSERT (top->options.mode == MODE_SERVER);
- switch (top->options.ce.proto) {
- case PROTO_UDPv4:
- tunnel_server_udp (top);
- break;
- case PROTO_TCPv4_SERVER:
- tunnel_server_tcp (top);
- break;
- default:
- ASSERT (0);
- }
+#ifdef USE_PF_INET6
+ if (proto_is_dgram(top->options.ce.proto))
+ tunnel_server_udp(top);
+ else
+ tunnel_server_tcp(top);
+#else
+ switch (top->options.ce.proto)
+ {
+ case PROTO_UDPv4:
+ tunnel_server_udp (top);
+ break;
+ case PROTO_TCPv4_SERVER:
+ tunnel_server_tcp (top);
+ break;
+ default:
+ ASSERT (0);
+ }
+#endif
}
#else
diff --git a/multi.h b/multi.h
index 99436c2..08964a2 100644
--- a/multi.h
+++ b/multi.h
@@ -56,7 +56,6 @@ struct multi_reap
struct multi_instance {
struct schedule_entry se; /* this must be the first element of the structure */
struct gc_arena gc;
- MUTEX_DEFINE (mutex);
bool defined;
bool halt;
int refcount;
@@ -274,7 +273,6 @@ multi_instance_dec_refcount (struct multi_instance *mi)
if (--mi->refcount <= 0)
{
gc_free (&mi->gc);
- mutex_destroy (&mi->mutex);
free (mi);
}
}
diff --git a/occ.c b/occ.c
index b84b18d..bcf91cc 100644
--- a/occ.c
+++ b/occ.c
@@ -369,7 +369,7 @@ process_received_occ_msg (struct context *c)
c->c2.max_send_size_remote,
c->c2.max_recv_size_local);
if (!c->options.fragment
- && c->options.ce.proto == PROTO_UDPv4
+ && (proto_is_dgram(c->options.ce.proto))
&& c->c2.max_send_size_local > TUN_MTU_MIN
&& (c->c2.max_recv_size_remote < c->c2.max_send_size_local
|| c->c2.max_recv_size_local < c->c2.max_send_size_remote))
diff --git a/openvpn-plugin.h b/openvpn-plugin.h
index 56b0a70..5c82daf 100644
--- a/openvpn-plugin.h
+++ b/openvpn-plugin.h
@@ -22,7 +22,9 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define OPENVPN_PLUGIN_VERSION 2
+#include <openssl/x509v3.h>
+
+#define OPENVPN_PLUGIN_VERSION 3
/*
* Plug-in types. These types correspond to the set of script callbacks
@@ -41,6 +43,7 @@
* New Client Connection:
*
* FUNC: openvpn_plugin_client_constructor_v1
+ * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_ENABLE_PF
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_VERIFY (called once for every cert
* in the server chain)
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
@@ -72,7 +75,7 @@
* [Client session continues]
*
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_CLIENT_DISCONNECT
- * FUNC: openvpn_plugin_client_constructor_v1
+ * FUNC: openvpn_plugin_client_destructor_v1
*
* [ some time may pass ]
*
@@ -162,6 +165,133 @@ struct openvpn_plugin_string_list
char *value;
};
+
+/* openvpn_plugin_{open,func}_v3() related structs */
+
+/* Defines version of the v3 plugin argument structs
+ *
+ * Whenever one or more of these structs are modified, this constant
+ * must be updated. A changelog should be appended in this comment
+ * as well, to make it easier to see what information is available
+ * in the different versions.
+ *
+ * Version Comment
+ * 1 Initial plugin v3 structures providing the same API as
+ * the v2 plugin interface + X509 certificate information.
+ *
+ */
+#define OPENVPN_PLUGINv3_STRUCTVER 1
+
+/**
+ * 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.
+ *
+ * STRUCT MEMBERS
+ *
+ * type_mask : Set by OpenVPN to the logical OR of all script
+ * types which this version of OpenVPN supports.
+ *
+ * argv : a NULL-terminated array of options provided to the OpenVPN
+ * "plug-in" directive. argv[0] is the dynamic library pathname.
+ *
+ * envp : a NULL-terminated array of OpenVPN-set environmental
+ * variables in "name=value" format. Note that for security reasons,
+ * these variables are not actually written to the "official"
+ * environmental variable store of the process.
+ */
+struct openvpn_plugin_args_open_in
+{
+ const int type_mask;
+ const char const **argv;
+ const char const **envp;
+};
+
+
+/**
+ * Arguments used to transport variables from the plug-in back
+ * to the OpenVPN process. The struct openvpn_plugin_args_open_return
+ * is only used by the openvpn_plugin_open_v3() function.
+ *
+ * STRUCT MEMBERS
+ *
+ * *type_mask : The plug-in should set this value to the logical OR of all script
+ * types which the plug-in wants to intercept. For example, if the
+ * script wants to intercept the client-connect and client-disconnect
+ * script types:
+ *
+ * *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT)
+ * | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
+ *
+ * *handle : Pointer to a global plug-in context, created by the plug-in. This pointer
+ * is passed on to the other plug-in calls.
+ *
+ * return_list : used to return data back to OpenVPN.
+ *
+ */
+struct openvpn_plugin_args_open_return
+{
+ int type_mask;
+ openvpn_plugin_handle_t *handle;
+ struct openvpn_plugin_string_list **return_list;
+};
+
+/**
+ * Arguments used to transport variables to and from the
+ * plug-in. The struct openvpn_plugin_args_func is only used
+ * by the openvpn_plugin_func_v3() function.
+ *
+ * STRUCT MEMBERS:
+ *
+ * type : one of the PLUGIN_x types.
+ *
+ * argv : a NULL-terminated array of "command line" options which
+ * would normally be passed to the script. argv[0] is the dynamic
+ * library pathname.
+ *
+ * envp : a NULL-terminated array of OpenVPN-set environmental
+ * variables in "name=value" format. Note that for security reasons,
+ * these variables are not actually written to the "official"
+ * environmental variable store of the process.
+ *
+ * *handle : Pointer to a global plug-in context, created by the plug-in's openvpn_plugin_open_v3().
+ *
+ * *per_client_context : the per-client context pointer which was returned by
+ * openvpn_plugin_client_constructor_v1, if defined.
+ *
+ * current_cert_depth : Certificate depth of the certificate being passed over
+ *
+ * *current_cert : X509 Certificate object received from the client
+ *
+ */
+struct openvpn_plugin_args_func_in
+{
+ const int type;
+ const char const **argv;
+ const char const **envp;
+ openvpn_plugin_handle_t handle;
+ void *per_client_context;
+ int current_cert_depth;
+ X509 *current_cert;
+};
+
+
+/**
+ * Arguments used to transport variables to and from the
+ * plug-in. The struct openvpn_plugin_args_func is only used
+ * by the openvpn_plugin_func_v3() function.
+ *
+ * STRUCT MEMBERS:
+ *
+ * return_list : used to return data back to OpenVPN for further processing/usage by
+ * the OpenVPN executable.
+ *
+ */
+struct openvpn_plugin_args_func_return
+{
+ struct openvpn_plugin_string_list **return_list;
+};
+
/*
* Multiple plugin modules can be cascaded, and modules can be
* used in tandem with scripts. The order of operation is that
@@ -328,6 +458,118 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
void *per_client_context,
struct openvpn_plugin_string_list **return_list);
+
+/*
+ * FUNCTION: openvpn_plugin_open_v3
+ *
+ * REQUIRED: YES
+ *
+ * Called on initial plug-in load. OpenVPN will preserve plug-in state
+ * across SIGUSR1 restarts but not across SIGHUP restarts. A SIGHUP reset
+ * will cause the plugin to be closed and reopened.
+ *
+ * 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.
+ *
+ * arguments : Structure with all arguments available to the plug-in.
+ *
+ * retptr : used to return data back to OpenVPN.
+ *
+ * RETURN VALUE
+ *
+ * OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure
+ */
+OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v3)
+ (const int version,
+ struct openvpn_plugin_args_open_in const *arguments,
+ struct openvpn_plugin_args_open_return *retptr);
+
+/*
+ * FUNCTION: openvpn_plugin_func_v3
+ *
+ * Called to perform the work of a given script type.
+ *
+ * REQUIRED: YES
+ *
+ * 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.
+ *
+ * handle : the openvpn_plugin_handle_t value which was returned by
+ * openvpn_plugin_open.
+ *
+ * return_list : used to return data back to OpenVPN.
+ *
+ * RETURN VALUE
+ *
+ * OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure
+ *
+ * In addition, OPENVPN_PLUGIN_FUNC_DEFERRED may be returned by
+ * OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY. This enables asynchronous
+ * authentication where the plugin (or one of its agents) may indicate
+ * authentication success/failure some number of seconds after the return
+ * of the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY handler by writing a single
+ * char to the file named by auth_control_file in the environmental variable
+ * list (envp).
+ *
+ * first char of auth_control_file:
+ * '0' -- indicates auth failure
+ * '1' -- indicates auth success
+ *
+ * OpenVPN will delete the auth_control_file after it goes out of scope.
+ *
+ * If an OPENVPN_PLUGIN_ENABLE_PF handler is defined and returns success
+ * for a particular client instance, packet filtering will be enabled for that
+ * instance. OpenVPN will then attempt to read the packet filter configuration
+ * from the temporary file named by the environmental variable pf_file. This
+ * file may be generated asynchronously and may be dynamically updated during the
+ * client session, however the client will be blocked from sending or receiving
+ * VPN tunnel packets until the packet filter file has been generated. OpenVPN
+ * will periodically test the packet filter file over the life of the client
+ * instance and reload when modified. OpenVPN will delete the packet filter file
+ * when the client instance goes out of scope.
+ *
+ * Packet filter file grammar:
+ *
+ * [CLIENTS DROP|ACCEPT]
+ * {+|-}common_name1
+ * {+|-}common_name2
+ * . . .
+ * [SUBNETS DROP|ACCEPT]
+ * {+|-}subnet1
+ * {+|-}subnet2
+ * . . .
+ * [END]
+ *
+ * Subnet: IP-ADDRESS | IP-ADDRESS/NUM_NETWORK_BITS
+ *
+ * CLIENTS refers to the set of clients (by their common-name) which
+ * this instance is allowed ('+') to connect to, or is excluded ('-')
+ * from connecting to. Note that in the case of client-to-client
+ * connections, such communication must be allowed by the packet filter
+ * configuration files of both clients.
+ *
+ * SUBNETS refers to IP addresses or IP address subnets which this
+ * instance may connect to ('+') or is excluded ('-') from connecting
+ * to.
+ *
+ * DROP or ACCEPT defines default policy when there is no explicit match
+ * for a common-name or subnet. The [END] tag must exist. A special
+ * purpose tag called [KILL] will immediately kill the client instance.
+ * A given client or subnet rule applies to both incoming and outgoing
+ * packets.
+ *
+ * See plugin/defer/simple.c for an example on using asynchronous
+ * authentication and client-specific packet filtering.
+ */
+OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v3)
+ (const int version,
+ struct openvpn_plugin_args_func_in const *arguments,
+ struct openvpn_plugin_args_func_return *retptr);
+
/*
* FUNCTION: openvpn_plugin_close_v1
*
diff --git a/openvpn.8 b/openvpn.8
index 85889de..5cbf4c5 100644
--- a/openvpn.8
+++ b/openvpn.8
@@ -97,25 +97,25 @@ with a relatively lightweight footprint.
.SH OPTIONS
OpenVPN allows any option to be placed either on the command line
or in a configuration file. Though all command line options are preceded
-by a double-leading-dash ("--"), this prefix can be removed when
+by a double-leading-dash ("\-\-"), this prefix can be removed when
an option is placed in a configuration file.
.\"*********************************************************
.TP
-.B --help
+.B \-\-help
Show options.
.\"*********************************************************
.TP
-.B --config file
+.B \-\-config file
Load additional config options from
.B file
where each line corresponds to one command line option,
-but with the leading '--' removed.
+but with the leading '\-\-' removed.
If
-.B --config file
+.B \-\-config file
is the only option to the openvpn command,
the
-.B --config
+.B \-\-config
can be removed, and the command can be given as
.B openvpn file
@@ -187,25 +187,25 @@ secret static.key
.\"*********************************************************
.SS Tunnel Options:
.TP
-.B --mode m
+.B \-\-mode m
Set OpenVPN major mode. By default, OpenVPN runs in
point-to-point mode ("p2p"). OpenVPN 2.0 introduces
a new mode ("server") which implements a multi-client
server capability.
.\"*********************************************************
.TP
-.B --local host
+.B \-\-local host
Local host name or IP address for bind.
If specified, OpenVPN will bind to this address only.
If unspecified, OpenVPN will bind to all interfaces.
.\"*********************************************************
.TP
-.B --remote host [port] [proto]
+.B \-\-remote host [port] [proto]
Remote host name or IP address. On the client, multiple
-.B --remote
+.B \-\-remote
options may be specified for redundancy, each referring
to a different OpenVPN server. Specifying multiple
-.B --remote
+.B \-\-remote
options for this purpose is a special case of the more
general connection-profile feature. See the
.B <connection>
@@ -214,7 +214,7 @@ documentation below.
The OpenVPN client will try to connect to a server at
.B host:port
in the order specified by the list of
-.B --remote
+.B \-\-remote
options.
.B proto
@@ -229,18 +229,18 @@ one server.
Note that since UDP is connectionless, connection failure
is defined by the
-.B --ping
+.B \-\-ping
and
-.B --ping-restart
+.B \-\-ping-restart
options.
Note the following corner case: If you use multiple
-.B --remote
+.B \-\-remote
options, AND you are dropping root privileges on
the client with
-.B --user
+.B \-\-user
and/or
-.B --group,
+.B \-\-group,
AND the client is running a non-Windows OS, if the client needs
to switch to a different server, and that server pushes
back different TUN/TAP or route settings, the client may lack
@@ -248,7 +248,7 @@ the necessary privileges to close and reopen the TUN/TAP interface.
This could cause the client to exit with a fatal error.
If
-.B --remote
+.B \-\-remote
is unspecified, OpenVPN will listen
for packets from any IP address, but will not act on those packets unless
they pass all authentication tests. This requirement for authentication
@@ -257,7 +257,7 @@ trusted IP addresses (it is very easy to forge a source IP address on
a UDP packet).
When used in TCP mode,
-.B --remote
+.B \-\-remote
will act as a filter, rejecting connections from any host which does
not match
.B host.
@@ -270,6 +270,12 @@ chosen, providing a sort of basic load-balancing and
failover capability.
.\"*********************************************************
.TP
+.B \-\-remote-random-hostname
+Add a random string (6 characters) to first DNS label of hostname to prevent
+DNS caching. For example, "foo.bar.gov" would be modified to
+"<random-chars>.foo.bar.gov".
+.\"*********************************************************
+.TP
.B <connection>
Define a client connection
profile. Client connection profiles are groups of OpenVPN options that
@@ -283,7 +289,7 @@ and
An OpenVPN client will try each connection profile sequentially
until it achieves a successful connection.
-.B --remote-random
+.B \-\-remote-random
can be used to initially "scramble" the connection
list.
@@ -380,22 +386,22 @@ were declared in all
blocks below it.
.\"*********************************************************
.TP
-.B --proto-force p
+.B \-\-proto-force p
When iterating through connection profiles,
only consider profiles using protocol
.B p
('tcp'|'udp').
.\"*********************************************************
.TP
-.B --remote-random
+.B \-\-remote-random
When multiple
-.B --remote
+.B \-\-remote
address/ports are specified, or if connection profiles are being
used, initially randomize the order of the list
as a kind of basic load-balancing measure.
.\"*********************************************************
.TP
-.B --proto p
+.B \-\-proto p
Use protocol
.B p
for communicating with remote host.
@@ -409,17 +415,17 @@ or
The default protocol is
.B udp
when
-.B --proto
+.B \-\-proto
is not specified.
For UDP operation,
-.B --proto udp
+.B \-\-proto udp
should be specified on both peers.
For TCP operation, one peer must use
-.B --proto tcp-server
+.B \-\-proto tcp-server
and the other must use
-.B --proto tcp-client.
+.B \-\-proto tcp-client.
A peer started with
.B tcp-server
will wait indefinitely for an incoming connection. A peer
@@ -427,9 +433,9 @@ started with
.B tcp-client
will attempt to connect, and if that fails, will sleep for 5
seconds (adjustable via the
-.B --connect-retry
+.B \-\-connect-retry
option) and try again infinite or up to N retries (adjustable via the
-.B --connect-retry-max
+.B \-\-connect-retry-max
option). Both TCP client and server will simulate
a SIGUSR1 restart signal if either side resets the connection.
@@ -449,9 +455,9 @@ application-level UDP protocols, or tunneling protocols which don't
possess a built-in reliability layer.
.\"*********************************************************
.TP
-.B --connect-retry n
+.B \-\-connect-retry n
For
-.B --proto tcp-client,
+.B \-\-proto tcp-client,
take
.B n
as the
@@ -459,16 +465,24 @@ number of seconds to wait
between connection retries (default=5).
.\"*********************************************************
.TP
-.B --connect-retry-max n
+.B \-\-connect-timeout n
+For
+.B \-\-proto tcp-client,
+set connection timeout to
+.B n
+seconds (default=10).
+.\"*********************************************************
+.TP
+.B \-\-connect-retry-max n
For
-.B --proto tcp-client,
+.B \-\-proto tcp-client,
take
.B n
as the
number of retries of connection attempt (default=infinite).
.\"*********************************************************
.TP
-.B --auto-proxy
+.B \-\-auto-proxy
Try to sense HTTP or SOCKS proxy settings automatically.
If no settings are present, a direct connection will be attempted.
If both HTTP and SOCKS settings are present, HTTP will be preferred.
@@ -480,7 +494,7 @@ InternetQueryOption API.
This option exists in OpenVPN 2.1 or higher.
.\"*********************************************************
.TP
-.B --http-proxy server port [authfile|'auto'|'auto-nct'] [auth-method]
+.B \-\-http-proxy server port [authfile|'auto'|'auto-nct'] [auth-method]
Connect to remote host through an HTTP proxy at address
.B server
and port
@@ -515,32 +529,32 @@ determine the authentication method, but to reject weak
authentication protocols such as HTTP Basic Authentication.
.\"*********************************************************
.TP
-.B --http-proxy-retry
+.B \-\-http-proxy-retry
Retry indefinitely on HTTP proxy errors. If an HTTP proxy error
occurs, simulate a SIGUSR1 reset.
.\"*********************************************************
.TP
-.B --http-proxy-timeout n
+.B \-\-http-proxy-timeout n
Set proxy timeout to
.B n
seconds, default=5.
.\"*********************************************************
.TP
-.B --http-proxy-option type [parm]
+.B \-\-http-proxy-option type [parm]
Set extended HTTP proxy options.
Repeat to set multiple options.
-.B VERSION version --
+.B VERSION version \-\-
Set HTTP version number to
.B version
(default=1.0).
-.B AGENT user-agent --
+.B AGENT user-agent \-\-
Set HTTP "User-Agent" string to
.B user-agent.
.\"*********************************************************
.TP
-.B --socks-proxy server [port]
+.B \-\-socks-proxy server [port]
Connect to remote host through a Socks5 proxy at address
.B server
and port
@@ -548,14 +562,14 @@ and port
(default=1080).
.\"*********************************************************
.TP
-.B --socks-proxy-retry
+.B \-\-socks-proxy-retry
Retry indefinitely on Socks proxy errors. If a Socks proxy error
occurs, simulate a SIGUSR1 reset.
.\"*********************************************************
.TP
-.B --resolv-retry n
+.B \-\-resolv-retry n
If hostname resolve fails for
-.B --remote,
+.B \-\-remote,
retry resolve for
.B n
seconds before failing.
@@ -565,18 +579,18 @@ Set
to "infinite" to retry indefinitely.
By default,
-.B --resolv-retry infinite
+.B \-\-resolv-retry infinite
is enabled. You can disable by setting n=0.
.\"*********************************************************
.TP
-.B --float
+.B \-\-float
Allow remote peer to change its IP address and/or port number, such as due to
DHCP (this is the default if
-.B --remote
+.B \-\-remote
is not used).
-.B --float
+.B \-\-float
when specified with
-.B --remote
+.B \-\-remote
allows an OpenVPN session to initially connect to a peer
at a known address, however if packets arrive from a new
address and pass all authentication tests, the new address
@@ -585,14 +599,14 @@ you are connecting to a peer which holds a dynamic address
such as a dial-in user or DHCP client.
Essentially,
-.B --float
+.B \-\-float
tells OpenVPN to accept authenticated packets
from any address, not only the address which was specified in the
-.B --remote
+.B \-\-remote
option.
.\"*********************************************************
.TP
-.B --ipchange cmd
+.B \-\-ipchange cmd
Execute shell command
.B cmd
when our remote ip-address is initially authenticated or
@@ -603,11 +617,11 @@ Execute as:
.B cmd ip_address port_number
Don't use
-.B --ipchange
+.B \-\-ipchange
in
-.B --mode server
+.B \-\-mode server
mode. Use a
-.B --client-connect
+.B \-\-client-connect
script instead.
See the "Environmental Variables" section below for
@@ -642,41 +656,41 @@ reestablish a connection with its most recently authenticated
peer on its new IP address.
.\"*********************************************************
.TP
-.B --port port
+.B \-\-port port
TCP/UDP port number for both local and remote. The current
default of 1194 represents the official IANA port number
assignment for OpenVPN and has been used since version 2.0-beta17.
Previous versions used port 5000 as the default.
.\"*********************************************************
.TP
-.B --lport port
+.B \-\-lport port
TCP/UDP port number for bind.
.\"*********************************************************
.TP
-.B --rport port
+.B \-\-rport port
TCP/UDP port number for remote.
.\"*********************************************************
.TP
-.B --bind
+.B \-\-bind
Bind to local address and port. This is the default unless any of
-.B --proto tcp-client
+.B \-\-proto tcp-client
,
-.B --http-proxy
+.B \-\-http-proxy
or
-.B --socks-proxy
+.B \-\-socks-proxy
are used.
.\"*********************************************************
.TP
-.B --nobind
+.B \-\-nobind
Do not bind to local address and port. The IP stack will allocate
a dynamic port for returning packets. Since the value of the dynamic port
could not be known in advance by a peer, this option is only suitable for
peers which will be initiating connections by using the
-.B --remote
+.B \-\-remote
option.
.\"*********************************************************
.TP
-.B --dev tunX | tapX | null
+.B \-\-dev tunX | tapX | null
TUN/TAP virtual network device (
.B X
can be omitted for a dynamic device.)
@@ -694,7 +708,7 @@ devices encapsulate IPv4 or IPv6 (OSI Layer 3) while
devices encapsulate Ethernet 802.3 (OSI Layer 2).
.\"*********************************************************
.TP
-.B --dev-type device-type
+.B \-\-dev-type device-type
Which device type are we using?
.B device-type
should be
@@ -704,60 +718,60 @@ or
.B tap
(OSI Layer 2).
Use this option only if the TUN/TAP device used with
-.B --dev
+.B \-\-dev
does not begin with
.B tun
or
.B tap.
.\"*********************************************************
.TP
-.B --topology mode
+.B \-\-topology mode
Configure virtual addressing topology when running in
-.B --dev tun
+.B \-\-dev tun
mode. This directive has no meaning in
-.B --dev tap
+.B \-\-dev tap
mode, which always uses a
.B subnet
topology.
If you set this directive on the server, the
-.B --server
+.B \-\-server
and
-.B --server-bridge
+.B \-\-server-bridge
directives will automatically push your chosen topology setting to clients
as well. This directive can also be manually pushed to clients. Like the
-.B --dev
+.B \-\-dev
directive, this directive must always be compatible between client and server.
.B mode
can be one of:
-.B net30 --
+.B net30 \-\-
Use a point-to-point topology, by allocating one /30 subnet per client.
This is designed to allow point-to-point semantics when some
or all of the connecting clients might be Windows systems. This is the
default on OpenVPN 2.0.
-.B p2p --
+.B p2p \-\-
Use a point-to-point topology where the remote endpoint of the client's
tun interface always points to the local endpoint of the server's tun interface.
This mode allocates a single IP address per connecting client.
Only use
when none of the connecting clients are Windows systems. This mode
is functionally equivalent to the
-.B --ifconfig-pool-linear
+.B \-\-ifconfig-pool-linear
directive which is available in OpenVPN 2.0 and is now deprecated.
-.B subnet --
+.B subnet \-\-
Use a subnet rather than a point-to-point topology by
configuring the tun interface with a local IP address and subnet mask,
similar to the topology used in
-.B --dev tap
+.B \-\-dev tap
and ethernet bridging mode.
This mode allocates a single IP address per connecting client and works on
Windows as well. Only available when server and clients are OpenVPN 2.1 or
higher, or OpenVPN 2.0.x which has been manually patched with the
-.B --topology
+.B \-\-topology
directive code. When used on Windows, requires version 8.2 or higher
of the TAP-Win32 driver. When used on *nix, requires that the tun
driver supports an
@@ -767,26 +781,28 @@ command which sets a subnet instead of a remote endpoint IP address.
This option exists in OpenVPN 2.1 or higher.
.\"*********************************************************
.TP
-.B --tun-ipv6
+.B \-\-tun-ipv6
Build a tun link capable of forwarding IPv6 traffic.
Should be used in conjunction with
-.B --dev tun
+.B \-\-dev tun
or
-.B --dev tunX.
+.B \-\-dev tunX.
A warning will be displayed
if no specific IPv6 TUN support for your OS has been compiled into OpenVPN.
+
+See below for further IPv6-related configuration options.
.\"*********************************************************
.TP
-.B --dev-node node
+.B \-\-dev-node node
Explicitly set the device node rather than using
/dev/net/tun, /dev/tun, /dev/tap, etc. If OpenVPN
cannot figure out whether
.B node
is a TUN or TAP device based on the name, you should
also specify
-.B --dev-type tun
+.B \-\-dev-type tun
or
-.B --dev-type tap.
+.B \-\-dev-type tap.
On Windows systems, select the TAP-Win32 adapter which
is named
@@ -794,24 +810,24 @@ is named
in the Network Connections Control Panel or the
raw GUID of the adapter enclosed by braces.
The
-.B --show-adapters
+.B \-\-show-adapters
option under Windows can also be used
to enumerate all available TAP-Win32
adapters and will show both the network
connections control panel name and the GUID for
each TAP-Win32 adapter.
.TP
-.B --lladdr address
+.B \-\-lladdr address
Specify the link layer address, more commonly known as the MAC address.
Only applied to TAP devices.
.\"*********************************************************
.TP
-.B --iproute cmd
+.B \-\-iproute cmd
Set alternate command to execute instead of default iproute2 command.
May be used in order to execute OpenVPN in unprivileged environment.
.\"*********************************************************
.TP
-.B --ifconfig l rn
+.B \-\-ifconfig l rn
Set TUN/TAP adapter parameters.
.B l
is the IP address of the local VPN endpoint.
@@ -826,7 +842,7 @@ which is being created or connected to.
For TUN devices, which facilitate virtual
point-to-point IP connections,
the proper usage of
-.B --ifconfig
+.B \-\-ifconfig
is to use two private IP addresses
which are not a member of any
existing subnet which is in use.
@@ -840,7 +856,7 @@ you will be pinging across the VPN.
For TAP devices, which provide
the ability to create virtual
ethernet segments,
-.B --ifconfig
+.B \-\-ifconfig
is used to set an IP address and
subnet mask just as a physical
ethernet adapter would be
@@ -861,42 +877,42 @@ standard interface to the different
ifconfig implementations on different
platforms.
-.B --ifconfig
+.B \-\-ifconfig
parameters which are IP addresses can
also be specified as a DNS or /etc/hosts
file resolvable name.
For TAP devices,
-.B --ifconfig
+.B \-\-ifconfig
should not be used if the TAP interface will be
getting an IP address lease from a DHCP
server.
.\"*********************************************************
.TP
-.B --ifconfig-noexec
+.B \-\-ifconfig-noexec
Don't actually execute ifconfig/netsh commands, instead
pass
-.B --ifconfig
+.B \-\-ifconfig
parameters to scripts using environmental variables.
.\"*********************************************************
.TP
-.B --ifconfig-nowarn
+.B \-\-ifconfig-nowarn
Don't output an options consistency check warning
if the
-.B --ifconfig
+.B \-\-ifconfig
option on this side of the
connection doesn't match the remote side. This is useful
when you want to retain the overall benefits of the
options consistency check (also see
-.B --disable-occ
+.B \-\-disable-occ
option) while only disabling the ifconfig component of
the check.
For example,
if you have a configuration where the local host uses
-.B --ifconfig
+.B \-\-ifconfig
but the remote host does not, use
-.B --ifconfig-nowarn
+.B \-\-ifconfig-nowarn
on the local host.
This option will also silence warnings about potential
@@ -904,7 +920,7 @@ address conflicts which occasionally annoy more experienced
users by triggering "false positive" warnings.
.\"*********************************************************
.TP
-.B --route network/IP [netmask] [gateway] [metric]
+.B \-\-route network/IP [netmask] [gateway] [metric]
Add route to routing table after connection is established.
Multiple routes can be specified. Routes will be
automatically torn down in reverse order prior to
@@ -918,20 +934,20 @@ while at the same time providing portable semantics
across OpenVPN's platform space.
.B netmask
-default -- 255.255.255.255
+default \-\- 255.255.255.255
.B gateway
-default -- taken from
-.B --route-gateway
+default \-\- taken from
+.B \-\-route-gateway
or the second parameter to
-.B --ifconfig
+.B \-\-ifconfig
when
-.B --dev tun
+.B \-\-dev tun
is specified.
.B metric
-default -- taken from
-.B --route-metric
+default \-\- taken from
+.B \-\-route-metric
otherwise 0.
The default can be specified by leaving an option blank or setting
@@ -946,37 +962,37 @@ also be specified as a DNS or /etc/hosts
file resolvable name, or as one of three special keywords:
.B vpn_gateway
--- The remote VPN endpoint address
+\-\- The remote VPN endpoint address
(derived either from
-.B --route-gateway
+.B \-\-route-gateway
or the second parameter to
-.B --ifconfig
+.B \-\-ifconfig
when
-.B --dev tun
+.B \-\-dev tun
is specified).
.B net_gateway
--- The pre-existing IP default gateway, read from the routing
+\-\- The pre-existing IP default gateway, read from the routing
table (not supported on all OSes).
.B remote_host
--- The
-.B --remote
+\-\- The
+.B \-\-remote
address if OpenVPN is being run in client mode, and is undefined in server mode.
.\"*********************************************************
.TP
-.B --max-routes n
+.B \-\-max-routes n
Allow a maximum number of n
-.B --route
+.B \-\-route
options to be specified, either in the local configuration file,
or pulled from an OpenVPN server. By default, n=100.
.\"*********************************************************
.TP
-.B --route-gateway gw|'dhcp'
+.B \-\-route-gateway gw|'dhcp'
Specify a default gateway
.B gw
for use with
-.B --route.
+.B \-\-route.
If
.B dhcp
@@ -985,14 +1001,14 @@ the gateway address will be extracted from a DHCP
negotiation with the OpenVPN server-side LAN.
.\"*********************************************************
.TP
-.B --route-metric m
+.B \-\-route-metric m
Specify a default metric
.B m
for use with
-.B --route.
+.B \-\-route.
.\"*********************************************************
.TP
-.B --route-delay [n] [w]
+.B \-\-route-delay [n] [w]
Delay
.B n
seconds (default=0) after connection
@@ -1000,16 +1016,16 @@ establishment, before adding routes. If
.B n
is 0, routes will be added immediately upon connection
establishment. If
-.B --route-delay
+.B \-\-route-delay
is omitted, routes will be added immediately after TUN/TAP device
open and
-.B --up
+.B \-\-up
script execution, before any
-.B --user
+.B \-\-user
or
-.B --group
+.B \-\-group
privilege downgrade (or
-.B --chroot
+.B \-\-chroot
execution.)
This option is designed to be useful in scenarios where DHCP is
@@ -1018,18 +1034,18 @@ tap adapter addresses. The delay will give the DHCP handshake
time to complete before routes are added.
On Windows,
-.B --route-delay
+.B \-\-route-delay
tries to be more intelligent by waiting
.B w
seconds (w=30 by default)
for the TAP-Win32 adapter to come up before adding routes.
.\"*********************************************************
.TP
-.B --route-up cmd
+.B \-\-route-up cmd
Execute shell command
.B cmd
after routes are added, subject to
-.B --route-delay.
+.B \-\-route-delay.
See the "Environmental Variables" section below for
additional parameters passed as environmental variables.
@@ -1039,17 +1055,17 @@ Note that
can be a shell command with multiple arguments.
.\"*********************************************************
.TP
-.B --route-noexec
+.B \-\-route-noexec
Don't add or remove routes automatically. Instead pass routes to
-.B --route-up
+.B \-\-route-up
script using environmental variables.
.\"*********************************************************
.TP
-.B --route-nopull
+.B \-\-route-nopull
When used with
-.B --client
+.B \-\-client
or
-.B --pull,
+.B \-\-pull,
accept options pushed by server EXCEPT for routes.
When used on the client, this option effectively bars the
@@ -1058,16 +1074,16 @@ however note that this option still allows the server
to set the TCP/IP properties of the client's TUN/TAP interface.
.\"*********************************************************
.TP
-.B --allow-pull-fqdn
+.B \-\-allow-pull-fqdn
Allow client to pull DNS names from server (rather than being limited
to IP address) for
-.B --ifconfig,
-.B --route,
+.B \-\-ifconfig,
+.B \-\-route,
and
-.B --route-gateway.
+.B \-\-route-gateway.
.\"*********************************************************
.TP
-.B --client-nat snat|dnat network netmask alias
+.B \-\-client-nat snat|dnat network netmask alias
This pushable client option sets up a stateless one-to-one NAT
rule on packet addresses (not ports), and is useful in cases
where routes or ifconfig settings pushed to the client would
@@ -1087,12 +1103,12 @@ Use
(destination NAT) for remote resources.
Set
-.B --verb 6
+.B \-\-verb 6
for debugging info showing the transformation of src/dest
addresses in packets.
.\"*********************************************************
.TP
-.B --redirect-gateway flags...
+.B \-\-redirect-gateway flags...
(Experimental) Automatically execute routing commands to cause all outgoing IP traffic
to be redirected over the VPN.
@@ -1100,7 +1116,7 @@ This option performs three steps:
.B (1)
Create a static route for the
-.B --remote
+.B \-\-remote
address which forwards to the pre-existing default gateway.
This is done so that
.B (3)
@@ -1111,11 +1127,11 @@ Delete the default gateway route.
.B (3)
Set the new default gateway to be the VPN endpoint address (derived either from
-.B --route-gateway
+.B \-\-route-gateway
or the second parameter to
-.B --ifconfig
+.B \-\-ifconfig
when
-.B --dev tun
+.B \-\-dev tun
is specified).
When the tunnel is torn down, all of the above steps are reversed so
@@ -1123,7 +1139,7 @@ that the original default route is restored.
Option flags:
-.B local --
+.B local \-\-
Add the
.B local
flag if both OpenVPN servers are directly connected via a common subnet,
@@ -1133,19 +1149,19 @@ flag will cause step
.B 1
above to be omitted.
-.B def1 --
+.B def1 \-\-
Use this flag to override
the default gateway by using 0.0.0.0/1 and 128.0.0.0/1
rather than 0.0.0.0/0. This has the benefit of overriding
but not wiping out the original default gateway.
-.B bypass-dhcp --
+.B bypass-dhcp \-\-
Add a direct route to the DHCP server (if it is non-local) which
bypasses the tunnel
(Available on Windows clients, may not be available
on non-Windows clients).
-.B bypass-dns --
+.B bypass-dns \-\-
Add a direct route to the DNS server(s) (if they are non-local) which
bypasses the tunnel
(Available on Windows clients, may not be available
@@ -1154,13 +1170,18 @@ on non-Windows clients).
Using the def1 flag is highly recommended.
.\"*********************************************************
.TP
-.B --link-mtu n
+.B \-\-redirect-private [flags]
+Like \-\-redirect-gateway, but omit actually changing the default
+gateway. Useful when pushing private subnets.
+.\"*********************************************************
+.TP
+.B \-\-link-mtu n
Sets an upper bound on the size of UDP packets which are sent
between OpenVPN peers. It's best not to set this parameter unless
you know what you're doing.
.\"*********************************************************
.TP
-.B --tun-mtu n
+.B \-\-tun-mtu n
Take the TUN device MTU to be
.B n
and derive the link MTU
@@ -1176,17 +1197,17 @@ MTU problems often manifest themselves as connections which
hang during periods of active usage.
It's best to use the
-.B --fragment
+.B \-\-fragment
and/or
-.B --mssfix
+.B \-\-mssfix
options to deal with MTU sizing issues.
.\"*********************************************************
.TP
-.B --tun-mtu-extra n
+.B \-\-tun-mtu-extra n
Assume that the TUN/TAP device might return as many as
.B n
bytes more than the
-.B --tun-mtu
+.B \-\-tun-mtu
size on read. This parameter defaults to 0, which is sufficient for
most TUN devices. TAP devices may introduce additional overhead in excess
of the MTU size, and a setting of 32 is the default when TAP devices are used.
@@ -1194,34 +1215,34 @@ This parameter only controls internal OpenVPN buffer sizing,
so there is no transmission overhead associated with using a larger value.
.\"*********************************************************
.TP
-.B --mtu-disc type
+.B \-\-mtu-disc type
Should we do Path MTU discovery on TCP/UDP channel? Only supported on OSes such
as Linux that supports the necessary system call to set.
.B 'no'
--- Never send DF (Don't Fragment) frames
+\-\- Never send DF (Don't Fragment) frames
.br
.B 'maybe'
--- Use per-route hints
+\-\- Use per-route hints
.br
.B 'yes'
--- Always DF (Don't Fragment)
+\-\- Always DF (Don't Fragment)
.br
.\"*********************************************************
.TP
-.B --mtu-test
+.B \-\-mtu-test
To empirically measure MTU on connection startup,
add the
-.B --mtu-test
+.B \-\-mtu-test
option to your configuration.
OpenVPN will send ping packets of various sizes
to the remote peer and measure the largest packets
which were successfully received. The
-.B --mtu-test
+.B \-\-mtu-test
process normally takes about 3 minutes to complete.
.\"*********************************************************
.TP
-.B --fragment max
+.B \-\-fragment max
Enable internal datagram fragmentation so
that no UDP datagrams are sent which
are larger than
@@ -1231,24 +1252,24 @@ bytes.
The
.B max
parameter is interpreted in the same way as the
-.B --link-mtu
+.B \-\-link-mtu
parameter, i.e. the UDP packet size after encapsulation
overhead has been added in, but not including
the UDP header itself.
The
-.B --fragment
+.B \-\-fragment
option only makes sense when you are using the UDP protocol (
-.B --proto udp
+.B \-\-proto udp
).
-.B --fragment
+.B \-\-fragment
adds 4 bytes of overhead per datagram.
See the
-.B --mssfix
+.B \-\-mssfix
option below for an important related option to
-.B --fragment.
+.B \-\-fragment.
It should also be noted that this option is not meant to replace
UDP fragmentation at the IP stack level. It is only meant as a
@@ -1261,44 +1282,45 @@ internal fragmentation capability may be your only option, such
as tunneling a UDP multicast stream which requires fragmentation.
.\"*********************************************************
.TP
-.B --mssfix max
+.B \-\-mssfix max
Announce to TCP sessions running over the tunnel that they should limit
their send packet sizes such that after OpenVPN has encapsulated them,
the resulting UDP packet size that OpenVPN sends to its peer will not
exceed
.B max
-bytes.
+bytes. The default value is
+.B 1450.
The
.B max
parameter is interpreted in the same way as the
-.B --link-mtu
+.B \-\-link-mtu
parameter, i.e. the UDP packet size after encapsulation
overhead has been added in, but not including
the UDP header itself.
The
-.B --mssfix
+.B \-\-mssfix
option only makes sense when you are using the UDP protocol
for OpenVPN peer-to-peer communication, i.e.
-.B --proto udp.
+.B \-\-proto udp.
-.B --mssfix
+.B \-\-mssfix
and
-.B --fragment
+.B \-\-fragment
can be ideally used together, where
-.B --mssfix
+.B \-\-mssfix
will try to keep TCP from needing
packet fragmentation in the first place,
and if big packets come through anyhow
(from protocols other than TCP),
-.B --fragment
+.B \-\-fragment
will internally fragment them.
Both
-.B --fragment
+.B \-\-fragment
and
-.B --mssfix
+.B \-\-mssfix
are designed to work around cases where Path MTU discovery
is broken on the network path between OpenVPN peers.
@@ -1307,35 +1329,35 @@ connection which successfully starts, but then stalls
during active usage.
If
-.B --fragment
+.B \-\-fragment
and
-.B --mssfix
+.B \-\-mssfix
are used together,
-.B --mssfix
+.B \-\-mssfix
will take its default
.B max
parameter from the
-.B --fragment max
+.B \-\-fragment max
option.
Therefore, one could lower the maximum UDP packet size
to 1300 (a good first try for solving MTU-related
connection problems) with the following options:
-.B --tun-mtu 1500 --fragment 1300 --mssfix
+.B \-\-tun-mtu 1500 \-\-fragment 1300 \-\-mssfix
.\"*********************************************************
.TP
-.B --sndbuf size
+.B \-\-sndbuf size
Set the TCP/UDP socket send buffer size.
Currently defaults to 65536 bytes.
.\"*********************************************************
.TP
-.B --rcvbuf size
+.B \-\-rcvbuf size
Set the TCP/UDP socket receive buffer size.
Currently defaults to 65536 bytes.
.\"*********************************************************
.TP
-.B --socket-flags flags...
+.B \-\-socket-flags flags...
Apply the given flags to the OpenVPN transport socket.
Currently, only
.B TCP_NODELAY
@@ -1352,12 +1374,12 @@ This option is pushable from server to client, and should be used
on both client and server for maximum effect.
.\"*********************************************************
.TP
-.B --txqueuelen n
+.B \-\-txqueuelen n
(Linux only) Set the TX queue length on the TUN/TAP interface.
Currently defaults to 100.
.\"*********************************************************
.TP
-.B --shaper n
+.B \-\-shaper n
Limit bandwidth of outgoing tunnel data to
.B n
bytes per second on the TCP/UDP port.
@@ -1393,32 +1415,42 @@ OpenVPN allows
to be between 100 bytes/sec and 100 Mbytes/sec.
.\"*********************************************************
.TP
-.B --inactive n [bytes]
+.B \-\-inactive n [bytes]
Causes OpenVPN to exit after
.B n
-seconds of inactivity on the TUN/TAP device. The time length
-of inactivity is measured since the last incoming tunnel packet.
+seconds of inactivity on the TUN/TAP device. The time length of
+inactivity is measured since the last incoming or outgoing tunnel
+packet. The default value is 0 seconds, which disables this feature.
If the optional
.B bytes
parameter is included,
-exit after n seconds of activity on tun/tap device
-produces a combined in/out byte count that is less than
-.B bytes.
+exit if less than
+.B bytes
+of combined in/out traffic are produced on the tun/tap device
+in
+.B n
+seconds.
+
+In any case, OpenVPN's internal ping packets (which are just
+keepalives) and TLS control packets are not considered
+"activity", nor are they counted as traffic, as they are used
+internally by OpenVPN and are not an indication of actual user
+activity.
.\"*********************************************************
.TP
-.B --ping n
+.B \-\-ping n
Ping remote over the TCP/UDP control channel
if no packets have been sent for at least
.B n
seconds (specify
-.B --ping
+.B \-\-ping
on both peers to cause ping packets to be sent in both directions since
OpenVPN ping packets are not echoed like IP ping packets).
When used in one of OpenVPN's secure modes (where
-.B --secret, --tls-server,
+.B \-\-secret, \-\-tls-server,
or
-.B --tls-client
+.B \-\-tls-client
is specified), the ping packet
will be cryptographically secure.
@@ -1431,33 +1463,33 @@ pass will not time out.
(2) To provide a basis for the remote to test the existence
of its peer using the
-.B --ping-exit
+.B \-\-ping-exit
option.
.\"*********************************************************
.TP
-.B --ping-exit n
+.B \-\-ping-exit n
Causes OpenVPN to exit after
.B n
seconds pass without reception of a ping
or other packet from remote.
This option can be combined with
-.B --inactive, --ping,
+.B \-\-inactive, \-\-ping,
and
-.B --ping-exit
+.B \-\-ping-exit
to create a two-tiered inactivity disconnect.
For example,
-.B openvpn [options...] --inactive 3600 --ping 10 --ping-exit 60
+.B openvpn [options...] \-\-inactive 3600 \-\-ping 10 \-\-ping-exit 60
when used on both peers will cause OpenVPN to exit within 60
seconds if its peer disconnects, but will exit after one
hour if no actual tunnel data is exchanged.
.\"*********************************************************
.TP
-.B --ping-restart n
+.B \-\-ping-restart n
Similar to
-.B --ping-exit,
+.B \-\-ping-exit,
but trigger a
.B SIGUSR1
restart after
@@ -1476,13 +1508,13 @@ as
If the peer cannot be reached, a restart will be triggered, causing
the hostname used with
-.B --remote
+.B \-\-remote
to be re-resolved (if
-.B --resolv-retry
+.B \-\-resolv-retry
is also specified).
In server mode,
-.B --ping-restart, --inactive,
+.B \-\-ping-restart, \-\-inactive,
or any other type of internally generated signal will always be
applied to
individual client instance objects, never to whole server itself.
@@ -1491,14 +1523,14 @@ which would normally cause a restart, will cause the deletion
of the client instance object instead.
In client mode, the
-.B --ping-restart
+.B \-\-ping-restart
parameter is set to 120 seconds by default. This default will
hold until the client pulls a replacement value from the server, based on
the
-.B --keepalive
+.B \-\-keepalive
setting in the server configuration.
To disable the 120 second default, set
-.B --ping-restart 0
+.B \-\-ping-restart 0
on the client.
See the signals section below for more information
@@ -1508,27 +1540,27 @@ on
Note that the behavior of
.B SIGUSR1
can be modified by the
-.B --persist-tun, --persist-key, --persist-local-ip,
+.B \-\-persist-tun, \-\-persist-key, \-\-persist-local-ip,
and
-.B --persist-remote-ip
+.B \-\-persist-remote-ip
options.
Also note that
-.B --ping-exit
+.B \-\-ping-exit
and
-.B --ping-restart
+.B \-\-ping-restart
are mutually exclusive and cannot be used together.
.\"*********************************************************
.TP
-.B --keepalive n m
+.B \-\-keepalive n m
A helper directive designed to simplify the expression of
-.B --ping
+.B \-\-ping
and
-.B --ping-restart
+.B \-\-ping-restart
in server mode configurations.
For example,
-.B --keepalive 10 60
+.B \-\-keepalive 10 60
expands as follows:
.nf
@@ -1547,24 +1579,24 @@ expands as follows:
.fi
.\"*********************************************************
.TP
-.B --ping-timer-rem
+.B \-\-ping-timer-rem
Run the
-.B --ping-exit
+.B \-\-ping-exit
/
-.B --ping-restart
+.B \-\-ping-restart
timer only if we have a remote address. Use this option if you are
starting the daemon in listen mode (i.e. without an explicit
-.B --remote
+.B \-\-remote
peer), and you don't want to start clocking timeouts until a remote
peer connects.
.\"*********************************************************
.TP
-.B --persist-tun
+.B \-\-persist-tun
Don't close and reopen TUN/TAP device or run up/down scripts
across
.B SIGUSR1
or
-.B --ping-restart
+.B \-\-ping-restart
restarts.
.B SIGUSR1
@@ -1574,14 +1606,14 @@ but which offers finer-grained control over
reset options.
.\"*********************************************************
.TP
-.B --persist-key
+.B \-\-persist-key
Don't re-read key files across
.B SIGUSR1
or
-.B --ping-restart.
+.B \-\-ping-restart.
This option can be combined with
-.B --user nobody
+.B \-\-user nobody
to allow restarts triggered by the
.B SIGUSR1
signal.
@@ -1594,29 +1626,29 @@ This option solves the problem by persisting keys across
resets, so they don't need to be re-read.
.\"*********************************************************
.TP
-.B --persist-local-ip
+.B \-\-persist-local-ip
Preserve initially resolved local IP address and port number
across
.B SIGUSR1
or
-.B --ping-restart
+.B \-\-ping-restart
restarts.
.\"*********************************************************
.TP
-.B --persist-remote-ip
+.B \-\-persist-remote-ip
Preserve most recently authenticated remote IP address and port number
across
.B SIGUSR1
or
-.B --ping-restart
+.B \-\-ping-restart
restarts.
.\"*********************************************************
.TP
-.B --mlock
+.B \-\-mlock
Disable paging by calling the POSIX mlockall function.
Requires that OpenVPN be initially run as root (though
OpenVPN can subsequently downgrade its UID using the
-.B --user
+.B \-\-user
option).
Using this option ensures that key material and tunnel
@@ -1628,33 +1660,33 @@ would not be able to scan the system swap file to
recover previously used
ephemeral keys, which are used for a period of time
governed by the
-.B --reneg
+.B \-\-reneg
options (see below), then are discarded.
The downside
of using
-.B --mlock
+.B \-\-mlock
is that it will reduce the amount of physical
memory available to other applications.
.\"*********************************************************
.TP
-.B --up cmd
+.B \-\-up cmd
Shell command to run after successful TUN/TAP device open
(pre
-.B --user
+.B \-\-user
UID change). The up script is useful for specifying route
commands which route IP traffic destined for
private subnets which exist at the other
end of the VPN connection into the tunnel.
For
-.B --dev tun
+.B \-\-dev tun
execute as:
.B cmd tun_dev tun_mtu link_mtu ifconfig_local_ip ifconfig_remote_ip [ init | restart ]
For
-.B --dev tap
+.B \-\-dev tap
execute as:
.B cmd tap_dev tap_mtu link_mtu ifconfig_local_ip ifconfig_netmask [ init | restart ]
@@ -1679,62 +1711,62 @@ In this context, the last command line parameter passed to the script
will be
.I init.
If the
-.B --up-restart
+.B \-\-up-restart
option is also used, the up script will be called for restarts as
well. A restart is considered to be a partial reinitialization
of OpenVPN where the TUN/TAP instance is preserved (the
-.B --persist-tun
+.B \-\-persist-tun
option will enable such preservation). A restart
can be generated by a SIGUSR1 signal, a
-.B --ping-restart
+.B \-\-ping-restart
timeout, or a connection reset when the TCP protocol is enabled
with the
-.B --proto
+.B \-\-proto
option. If a restart occurs, and
-.B --up-restart
+.B \-\-up-restart
has been specified, the up script will be called with
.I restart
as the last parameter.
The following standalone example shows how the
-.B --up
+.B \-\-up
script can be called in both an initialization and restart context.
(NOTE: for security reasons, don't run the following example unless UDP port
9999 is blocked by your firewall. Also, the example will run indefinitely,
so you should abort with control-c).
-.B openvpn --dev tun --port 9999 --verb 4 --ping-restart 10 --up 'echo up' --down 'echo down' --persist-tun --up-restart
+.B openvpn \-\-dev tun \-\-port 9999 \-\-verb 4 \-\-ping-restart 10 \-\-up 'echo up' \-\-down 'echo down' \-\-persist-tun \-\-up-restart
Note that OpenVPN also provides the
-.B --ifconfig
+.B \-\-ifconfig
option to automatically ifconfig the TUN device,
eliminating the need to define an
-.B --up
+.B \-\-up
script, unless you also want to configure routes
in the
-.B --up
+.B \-\-up
script.
If
-.B --ifconfig
+.B \-\-ifconfig
is also specified, OpenVPN will pass the ifconfig local
and remote endpoints on the command line to the
-.B --up
+.B \-\-up
script so that they can be used to configure routes such as:
.B route add -net 10.0.0.0 netmask 255.255.255.0 gw $5
.\"*********************************************************
.TP
-.B --up-delay
+.B \-\-up-delay
Delay TUN/TAP open and possible
-.B --up
+.B \-\-up
script execution
until after TCP/UDP connection establishment with peer.
In
-.B --proto udp
+.B \-\-proto udp
mode, this option normally requires the use of
-.B --ping
+.B \-\-ping
to allow connection initiation to be sensed in the absence
of tunnel data, since UDP is a "connectionless" protocol.
@@ -1743,50 +1775,50 @@ transitioning to "connected" until connection establishment,
i.e. the receipt of the first authenticated packet from the peer.
.\"*********************************************************
.TP
-.B --down cmd
+.B \-\-down cmd
Shell command to run after TUN/TAP device close
(post
-.B --user
+.B \-\-user
UID change and/or
-.B --chroot
+.B \-\-chroot
). Called with the same parameters and environmental
variables as the
-.B --up
+.B \-\-up
option above.
Note that if you reduce privileges by using
-.B --user
+.B \-\-user
and/or
-.B --group,
+.B \-\-group,
your
-.B --down
+.B \-\-down
script will also run at reduced privilege.
.\"*********************************************************
.TP
-.B --down-pre
+.B \-\-down-pre
Call
-.B --down
+.B \-\-down
cmd/script before, rather than after, TUN/TAP close.
.\"*********************************************************
.TP
-.B --up-restart
+.B \-\-up-restart
Enable the
-.B --up
+.B \-\-up
and
-.B --down
+.B \-\-down
scripts to be called for restarts as well as initial program start.
This option is described more fully above in the
-.B --up
+.B \-\-up
option documentation.
.\"*********************************************************
.TP
-.B --setenv name value
+.B \-\-setenv name value
Set a custom environmental variable
.B name=value
to pass to script.
.\"*********************************************************
.TP
-.B --setenv FORWARD_COMPATIBLE 1
+.B \-\-setenv FORWARD_COMPATIBLE 1
Relax config file syntax checking so that unknown directives
will trigger a warning but not a fatal error,
on the assumption that a given unknown directive might be valid
@@ -1799,7 +1831,7 @@ new software features to gracefully degrade when encountered by
older software versions.
.\"*********************************************************
.TP
-.B --setenv-safe name value
+.B \-\-setenv-safe name value
Set a custom environmental variable
.B OPENVPN_name=value
to pass to script.
@@ -1810,23 +1842,23 @@ is a safety precaution to prevent a LD_PRELOAD style attack
from a malicious or compromised server.
.\"*********************************************************
.TP
-.B --script-security level [method]
+.B \-\-script-security level [method]
This directive offers policy-level control over OpenVPN's usage of external programs
and scripts. Lower
.B level
values are more restrictive, higher values are more permissive. Settings for
.B level:
-.B 0 --
+.B 0 \-\-
Strictly no calling of external programs.
.br
-.B 1 --
+.B 1 \-\-
(Default) Only call built-in executables such as ifconfig, ip, route, or netsh.
.br
-.B 2 --
+.B 2 \-\-
Allow calling of built-in executables and user-defined scripts.
.br
-.B 3 --
+.B 3 \-\-
Allow passwords to be passed to scripts via environmental variables (potentially unsafe).
The
@@ -1835,33 +1867,33 @@ parameter indicates how OpenVPN should call external commands and scripts.
Settings for
.B method:
-.B execve --
+.B execve \-\-
(default) Use execve() function on Unix family OSes and CreateProcess() on Windows.
.br
-.B system --
+.B system \-\-
Use system() function (deprecated and less safe since the external program command
line is subject to shell expansion).
The
-.B --script-security
+.B \-\-script-security
option was introduced in OpenVPN 2.1_rc9. For configuration file compatibility
with previous OpenVPN versions, use:
-.B --script-security 3 system
+.B \-\-script-security 3 system
.\"*********************************************************
.TP
-.B --disable-occ
+.B \-\-disable-occ
Don't output a warning message if option inconsistencies are detected between
peers. An example of an option inconsistency would be where one peer uses
-.B --dev tun
+.B \-\-dev tun
while the other peer uses
-.B --dev tap.
+.B \-\-dev tap.
Use of this option is discouraged, but is provided as
a temporary fix in situations where a recent version of OpenVPN must
connect to an old version.
.\"*********************************************************
.TP
-.B --user user
+.B \-\-user user
Change the user ID of the OpenVPN process to
.B user
after initialization, dropping privileges in the process.
@@ -1883,7 +1915,7 @@ you want to reset an OpenVPN daemon with a
signal
(for example in response
to a DHCP reset), you should make use of one or more of the
-.B --persist
+.B \-\-persist
options to ensure that OpenVPN doesn't need to execute any privileged
operations in order to restart (such as re-reading key files
or running
@@ -1891,16 +1923,16 @@ or running
on the TUN device).
.\"*********************************************************
.TP
-.B --group group
+.B \-\-group group
Similar to the
-.B --user
+.B \-\-user
option,
this option changes the group ID of the OpenVPN process to
.B group
after initialization.
.\"*********************************************************
.TP
-.B --cd dir
+.B \-\-cd dir
Change directory to
.B dir
prior to reading any files such as
@@ -1912,16 +1944,16 @@ to the current directory such as "." or "..".
This option is useful when you are running
OpenVPN in
-.B --daemon
+.B \-\-daemon
mode, and you want to consolidate all of
your OpenVPN control files in one location.
.\"*********************************************************
.TP
-.B --chroot dir
+.B \-\-chroot dir
Chroot to
.B dir
after initialization.
-.B --chroot
+.B \-\-chroot
essentially redefines
.B dir
as being the top
@@ -1940,22 +1972,22 @@ complications can result when scripts or restarts
are executed after the chroot operation.
.\"*********************************************************
.TP
-.B --setcon context
+.B \-\-setcon context
Apply SELinux
.B context
after initialization. This
essentially provides the ability to restrict OpenVPN's
rights to only network I/O operations, thanks to
SELinux. This goes further than
-.B --user
+.B \-\-user
and
-.B --chroot
+.B \-\-chroot
in that those two, while being great security features,
unfortunately do not protect against privilege escalation
by exploitation of a vulnerable system call. You can of
course combine all three, but please note that since
setcon requires access to /proc you will have to provide
-it inside the chroot directory (e.g. with mount --bind).
+it inside the chroot directory (e.g. with mount \-\-bind).
Since the setcon operation is delayed until after
initialization, OpenVPN can be restricted to just
@@ -1967,13 +1999,13 @@ allow many things required only during initialization.
Like with chroot, complications can result when scripts
or restarts are executed after the setcon operation,
which is why you should really consider using the
-.B --persist-key
+.B \-\-persist-key
and
-.B --persist-tun
+.B \-\-persist-tun
options.
.\"*********************************************************
.TP
-.B --daemon [progname]
+.B \-\-daemon [progname]
Become a daemon after all initialization functions are completed.
This option will cause all message and error output to
be sent to the syslog file (such as /var/log/messages),
@@ -1982,10 +2014,10 @@ ifconfig commands,
which will go to /dev/null unless otherwise redirected.
The syslog redirection occurs immediately at the point
that
-.B --daemon
+.B \-\-daemon
is parsed on the command line even though
the daemonization point occurs later. If one of the
-.B --log
+.B \-\-log
options is present, it will supercede syslog
redirection.
@@ -2001,7 +2033,7 @@ When unspecified,
defaults to "openvpn".
When OpenVPN is run with the
-.B --daemon
+.B \-\-daemon
option, it will try to delay daemonization until the majority of initialization
functions which are capable of generating fatal errors are complete. This means
that initialization scripts can test the return status of the
@@ -2011,20 +2043,20 @@ has correctly initialized and entered the packet forwarding event loop.
In OpenVPN, the vast majority of errors which occur after initialization are non-fatal.
.\"*********************************************************
.TP
-.B --syslog [progname]
+.B \-\-syslog [progname]
Direct log output to system logger, but do not become a daemon.
See
-.B --daemon
+.B \-\-daemon
directive above for description of
.B progname
parameter.
.\"*********************************************************
.TP
-.B --passtos
+.B \-\-passtos
Set the TOS field of the tunnel packet to what the payload's TOS is.
.\"*********************************************************
.TP
-.B --inetd [wait|nowait] [progname]
+.B \-\-inetd [wait|nowait] [progname]
Use this option when OpenVPN is being run from the inetd or
.BR xinetd(8)
server.
@@ -2035,7 +2067,7 @@ option must match what is specified in the inetd/xinetd
config file. The
.B nowait
mode can only be used with
-.B --proto tcp-server.
+.B \-\-proto tcp-server.
The default is
.B wait.
The
@@ -2047,16 +2079,16 @@ see the OpenVPN FAQ:
.I http://openvpn.net/faq.html#oneport
This option precludes the use of
-.B --daemon, --local,
+.B \-\-daemon, \-\-local,
or
-.B --remote.
+.B \-\-remote.
Note that this option causes message and error output to be handled in the same
way as the
-.B --daemon
+.B \-\-daemon
option. The optional
.B progname
parameter is also handled exactly as in
-.B --daemon.
+.B \-\-daemon.
Also note that in
.B wait
@@ -2066,7 +2098,7 @@ on using OpenVPN with xinetd:
.I http://openvpn.net/1xhowto.html
.\"*********************************************************
.TP
-.B --log file
+.B \-\-log file
Output logging messages to
.B file,
including output to stdout/stderr which
@@ -2077,44 +2109,44 @@ already exists it will be truncated.
This option takes effect
immediately when it is parsed in the command line
and will supercede syslog output if
-.B --daemon
+.B \-\-daemon
or
-.B --inetd
+.B \-\-inetd
is also specified.
This option is persistent over the entire course of
an OpenVPN instantiation and will not be reset by SIGHUP,
SIGUSR1, or
-.B --ping-restart.
+.B \-\-ping-restart.
Note that on Windows, when OpenVPN is started as a service,
logging occurs by default without the need to specify
this option.
.\"*********************************************************
.TP
-.B --log-append file
+.B \-\-log-append file
Append logging messages to
.B file.
If
.B file
does not exist, it will be created.
This option behaves exactly like
-.B --log
+.B \-\-log
except that it appends to rather
than truncating the log file.
.\"*********************************************************
.TP
-.B --suppress-timestamps
+.B \-\-suppress-timestamps
Avoid writing timestamps to log messages, even when they
otherwise would be prepended. In particular, this applies to
log messages sent to stdout.
.\"*********************************************************
.TP
-.B --writepid file
+.B \-\-writepid file
Write OpenVPN's main process ID to
.B file.
.\"*********************************************************
.TP
-.B --nice n
+.B \-\-nice n
Change process priority after initialization
(
.B n
@@ -2123,14 +2155,14 @@ greater than 0 is lower priority,
less than zero is higher priority).
.\"*********************************************************
.\".TP
-.\".B --nice-work n
+.\".B \-\-nice-work n
.\"Change priority of background TLS work thread. The TLS thread
.\"feature is enabled when OpenVPN is built
.\"with pthread support, and you are running OpenVPN
.\"in TLS mode (i.e. with
-.\".B --tls-client
+.\".B \-\-tls-client
.\"or
-.\".B --tls-server
+.\".B \-\-tls-server
.\"specified).
.\"
.\"Using a TLS thread offloads the CPU-intensive process of SSL/TLS-based
@@ -2140,12 +2172,12 @@ less than zero is higher priority).
.\"The parameter
.\".B n
.\"is interpreted exactly as with the
-.\".B --nice
+.\".B \-\-nice
.\"option above, but in relation to the work thread rather
.\"than the main thread.
.\"*********************************************************
.TP
-.B --fast-io
+.B \-\-fast-io
(Experimental) Optimize TUN/TAP/UDP I/O writes by avoiding
a call to poll/epoll/select prior to the write operation. The purpose
of such a call would normally be to block until the device
@@ -2156,13 +2188,13 @@ by avoiding the poll/epoll/select call, improving CPU efficiency
by 5% to 10%.
This option can only be used on non-Windows systems, when
-.B --proto udp
+.B \-\-proto udp
is specified, and when
-.B --shaper
+.B \-\-shaper
is NOT specified.
.\"*********************************************************
.TP
-.B --multihome
+.B \-\-multihome
Configure a multi-homed UDP server. This option can be used when
OpenVPN has been configured to listen on all interfaces, and will
attempt to bind client sessions to the interface on which packets
@@ -2171,13 +2203,13 @@ 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
+.B \-\-multihome
server should always use the
-.B --nobind
+.B \-\-nobind
option.
.\"*********************************************************
.TP
-.B --echo [parms...]
+.B \-\-echo [parms...]
Echo
.B parms
to log output.
@@ -2186,7 +2218,7 @@ Designed to be used to send messages to a controlling application
which is receiving the OpenVPN log output.
.\"*********************************************************
.TP
-.B --remap-usr1 signal
+.B \-\-remap-usr1 signal
Control whether internally or externally
generated SIGUSR1 signals are remapped to
SIGHUP (restart without persisting state) or
@@ -2197,20 +2229,20 @@ can be set to "SIGHUP" or "SIGTERM". By default, no remapping
occurs.
.\"*********************************************************
.TP
-.B --verb n
+.B \-\-verb n
Set output verbosity to
.B n
(default=1). Each level shows all info from the previous levels.
Level 3 is recommended if you want a good summary
of what's happening without being swamped by output.
-.B 0 --
+.B 0 \-\-
No output except fatal errors.
.br
-.B 1 to 4 --
+.B 1 to 4 \-\-
Normal usage range.
.br
-.B 5 --
+.B 5 \-\-
Output
.B R
and
@@ -2218,12 +2250,12 @@ and
characters to the console for each packet read and write, uppercase is
used for TCP/UDP packets and lowercase is used for TUN/TAP packets.
.br
-.B 6 to 11 --
+.B 6 to 11 \-\-
Debug info range (see errlevel.h for additional
information on debug levels).
.\"*********************************************************
.TP
-.B --status file [n]
+.B \-\-status file [n]
Write operational status to
.B file
every
@@ -2235,21 +2267,21 @@ Status can also be written to the syslog by sending a
signal.
.\"*********************************************************
.TP
-.B --status-version [n]
+.B \-\-status-version [n]
Choose the status file format version number. Currently
.B n
can be 1, 2, or 3 and defaults to 1.
.\"*********************************************************
.TP
-.B --mute n
+.B \-\-mute n
Log at most
.B n
consecutive messages in the same category. This is useful to
limit repetitive logging of similar message types.
.\"*********************************************************
.TP
-.B --comp-lzo [mode]
-Use fast LZO compression -- may add up to 1 byte per
+.B \-\-comp-lzo [mode]
+Use fast LZO compression \-\- may add up to 1 byte per
packet for incompressible data.
.B mode
may be "yes", "no", or "adaptive" (default).
@@ -2259,16 +2291,16 @@ compression on or off for individual clients.
First, make sure the client-side config file enables selective
compression by having at least one
-.B --comp-lzo
+.B \-\-comp-lzo
directive, such as
-.B --comp-lzo no.
+.B \-\-comp-lzo no.
This will turn off compression by default,
but allow a future directive push from the server to
dynamically change the
on/off/adaptive setting.
Next in a
-.B --client-config-dir
+.B \-\-client-config-dir
file, specify the compression setting for the client,
for example:
@@ -2287,12 +2319,12 @@ setting for the server
side of the link, the second sets the client side.
.\"*********************************************************
.TP
-.B --comp-noadapt
+.B \-\-comp-noadapt
When used in conjunction with
-.B --comp-lzo,
+.B \-\-comp-lzo,
this option will disable OpenVPN's adaptive compression algorithm.
Normally, adaptive compression is enabled with
-.B --comp-lzo.
+.B \-\-comp-lzo.
Adaptive compression tries to optimize the case where you have
compression enabled, but you are sending predominantly uncompressible
@@ -2304,7 +2336,7 @@ the compression efficiency will be very low, triggering openvpn to disable
compression for a period of time until the next re-sample test.
.\"*********************************************************
.TP
-.B --management IP port [pw-file]
+.B \-\-management IP port [pw-file]
Enable a TCP server on
.B IP:port
to handle daemon management functions.
@@ -2323,9 +2355,9 @@ and set
.B port
to 'unix'. While the default behavior is to create a unix domain socket
that may be connected to by any process, the
-.B --management-client-user
+.B \-\-management-client-user
and
-.B --management-client-group
+.B \-\-management-client-group
directives can be used to restrict access.
The management interface provides a special mode where the TCP
@@ -2352,26 +2384,33 @@ It is strongly recommended that
be set to 127.0.0.1
(localhost) to restrict accessibility of the management
server to local clients.
+.TP
+.B \-\-management-client
+Management interface will connect as a TCP client to
+.B IP:port
+specified by
+.B \-\-management
+rather than listen as a TCP server.
.\"*********************************************************
.TP
-.B --management-query-passwords
+.B \-\-management-query-passwords
Query management channel for private key password and
-.B --auth-user-pass
+.B \-\-auth-user-pass
username/password. Only query the management channel
for inputs which ordinarily would have been queried from the
console.
.\"*********************************************************
.TP
-.B --management-forget-disconnect
+.B \-\-management-forget-disconnect
Make OpenVPN forget passwords when management session
disconnects.
This directive does not affect the
-.B --http-proxy
+.B \-\-http-proxy
username/password. It is always cached.
.\"*********************************************************
.TP
-.B --management-hold
+.B \-\-management-hold
Start OpenVPN in a hibernating state, until a client
of the management interface explicitly starts it
with the
@@ -2379,50 +2418,50 @@ with the
command.
.\"*********************************************************
.TP
-.B --management-signal
+.B \-\-management-signal
Send SIGUSR1 signal to OpenVPN if management session disconnects.
This is useful when you wish to disconnect an OpenVPN session on
user logoff.
.\"*********************************************************
.TP
-.B --management-log-cache n
+.B \-\-management-log-cache n
Cache the most recent
.B n
lines of log file history for usage
by the management channel.
.\"*********************************************************
.TP
-.B --management-up-down
+.B \-\-management-up-down
Report tunnel up/down events to management interface.
.B
.\"*********************************************************
.TP
-.B --management-client-auth
+.B \-\-management-client-auth
Gives management interface client the responsibility
to authenticate clients after their client certificate
has been verified. See management-notes.txt in OpenVPN
distribution for detailed notes.
.\"*********************************************************
.TP
-.B --management-client-pf
+.B \-\-management-client-pf
Management interface clients must specify a packet
filter file for each connecting client. See management-notes.txt
in OpenVPN distribution for detailed notes.
.\"*********************************************************
.TP
-.B --management-client-user u
+.B \-\-management-client-user u
When the management interface is listening on a unix domain socket,
only allow connections from user
.B u.
.\"*********************************************************
.TP
-.B --management-client-group g
+.B \-\-management-client-group g
When the management interface is listening on a unix domain socket,
only allow connections from group
.B g.
.\"*********************************************************
.TP
-.B --plugin module-pathname [init-string]
+.B \-\-plugin module-pathname [init-string]
Load plug-in module from the file
.B module-pathname,
passing
@@ -2458,7 +2497,7 @@ the connection to be authenticated.
.SS Server Mode
Starting with OpenVPN 2.0, a multi-client TCP/UDP server mode
is supported, and can be enabled with the
-.B --mode server
+.B \-\-mode server
option. In server mode, OpenVPN will listen on a single
port for incoming client connections. All client
connections will be routed through a single tun or tap
@@ -2468,7 +2507,7 @@ on sufficiently fast hardware. SSL/TLS authentication must
be used in this mode.
.\"*********************************************************
.TP
-.B --server network netmask
+.B \-\-server network netmask
A helper directive designed to simplify the configuration
of OpenVPN's server mode. This directive will set up an
OpenVPN server which will allocate addresses to clients
@@ -2478,7 +2517,7 @@ for use as the server-side endpoint of the local
TUN/TAP interface.
For example,
-.B --server 10.8.0.0 255.255.255.0
+.B \-\-server 10.8.0.0 255.255.255.0
expands as follows:
.nf
@@ -2508,23 +2547,23 @@ expands as follows:
.fi
Don't use
-.B --server
+.B \-\-server
if you are ethernet bridging. Use
-.B --server-bridge
+.B \-\-server-bridge
instead.
.\"*********************************************************
.TP
-.B --server-bridge gateway netmask pool-start-IP pool-end-IP
+.B \-\-server-bridge gateway netmask pool-start-IP pool-end-IP
.TP
-.B --server-bridge ['nogw']
+.B \-\-server-bridge ['nogw']
A helper directive similar to
-.B --server
+.B \-\-server
which is designed to simplify the configuration
of OpenVPN's server mode in ethernet bridging configurations.
If
-.B --server-bridge
+.B \-\-server-bridge
is used without any parameters, it will enable a DHCP-proxy
mode, where connecting OpenVPN clients will receive an IP
address for their TAP adapter from the DHCP server running
@@ -2552,7 +2591,7 @@ IP/netmask on the bridge interface. The
and
.B netmask
parameters to
-.B --server-bridge
+.B \-\-server-bridge
can be set to either the IP/netmask of the
bridge interface, or the IP/netmask of the
default gateway/router on the bridged
@@ -2584,7 +2623,7 @@ push "route-gateway 10.8.0.4"
.fi
In another example,
-.B --server-bridge
+.B \-\-server-bridge
(without parameters) expands as follows:
.nf
@@ -2599,7 +2638,7 @@ push "route-gateway dhcp"
.fi
Or
-.B --server-bridge nogw
+.B \-\-server-bridge nogw
expands as follows:
.nf
@@ -2612,13 +2651,13 @@ tls-server
.fi
.\"*********************************************************
.TP
-.B --push "option"
+.B \-\-push "option"
Push a config file option back to the client for remote
execution. Note that
.B
option
must be enclosed in double quotes (""). The client must specify
-.B --pull
+.B \-\-pull
in its config file. The set of options which can be
pushed is limited by both feasibility and security.
Some options such as those which would execute scripts
@@ -2629,44 +2668,44 @@ cannot be pushed because the client needs to know
them before the connection to the server can be initiated.
This is a partial list of options which can currently be pushed:
-.B --route, --route-gateway, --route-delay, --redirect-gateway,
-.B --ip-win32, --dhcp-option,
-.B --inactive, --ping, --ping-exit, --ping-restart,
-.B --setenv,
-.B --persist-key, --persist-tun, --echo,
-.B --comp-lzo,
-.B --socket-flags,
-.B --sndbuf, --rcvbuf
+.B \-\-route, \-\-route-gateway, \-\-route-delay, \-\-redirect-gateway,
+.B \-\-ip-win32, \-\-dhcp-option,
+.B \-\-inactive, \-\-ping, \-\-ping-exit, \-\-ping-restart,
+.B \-\-setenv,
+.B \-\-persist-key, \-\-persist-tun, \-\-echo,
+.B \-\-comp-lzo,
+.B \-\-socket-flags,
+.B \-\-sndbuf, \-\-rcvbuf
.\"*********************************************************
.TP
-.B --push-reset
+.B \-\-push-reset
Don't inherit the global push list for a specific client instance.
Specify this option in a client-specific context such
as with a
-.B --client-config-dir
+.B \-\-client-config-dir
configuration file. This option will ignore
-.B --push
+.B \-\-push
options at the global config file level.
.\"*********************************************************
.TP
-.B --disable
+.B \-\-disable
Disable a particular client (based on the common name)
from connecting. Don't use this option to disable a client
due to key or password compromise. Use a CRL (certificate
revocation list) instead (see the
-.B --crl-verify
+.B \-\-crl-verify
option).
This option must be associated with a specific client instance,
which means that it must be specified either in a client
instance config file using
-.B --client-config-dir
+.B \-\-client-config-dir
or dynamically generated using a
-.B --client-connect
+.B \-\-client-connect
script.
.\"*********************************************************
.TP
-.B --ifconfig-pool start-IP end-IP [netmask]
+.B \-\-ifconfig-pool start-IP end-IP [netmask]
Set aside a pool of subnets to be
dynamically allocated to connecting clients, similar
to a DHCP server. For tun-style
@@ -2679,7 +2718,7 @@ parameter will also be pushed to clients.
.\"*********************************************************
.TP
-.B --ifconfig-pool-persist file [seconds]
+.B \-\-ifconfig-pool-persist file [seconds]
Persist/unpersist ifconfig-pool
data to
.B file,
@@ -2694,7 +2733,7 @@ IP address assigned to them from the ifconfig-pool.
Maintaining a long-term
association is good for clients because it allows them
to effectively use the
-.B --persist-tun
+.B \-\-persist-tun
option.
.B file
@@ -2715,32 +2754,32 @@ suggestions only, based on past associations between
a common name and IP address. They do not guarantee that the given common
name will always receive the given IP address. If you want guaranteed
assignment, use
-.B --ifconfig-push
+.B \-\-ifconfig-push
.\"*********************************************************
.TP
-.B --ifconfig-pool-linear
+.B \-\-ifconfig-pool-linear
Modifies the
-.B --ifconfig-pool
+.B \-\-ifconfig-pool
directive to
allocate individual TUN interface addresses for
clients rather than /30 subnets. NOTE: This option
is incompatible with Windows clients.
This option is deprecated, and should be replaced with
-.B --topology p2p
+.B \-\-topology p2p
which is functionally equivalent.
.\"*********************************************************
.TP
-.B --ifconfig-push local remote-netmask [alias]
+.B \-\-ifconfig-push local remote-netmask [alias]
Push virtual IP endpoints for client tunnel,
-overriding the --ifconfig-pool dynamic allocation.
+overriding the \-\-ifconfig-pool dynamic allocation.
The parameters
.B local
and
.B remote-netmask
are set according to the
-.B --ifconfig
+.B \-\-ifconfig
directive which you want to execute on the client machine to
configure the remote end of the tunnel. Note that the parameters
.B local
@@ -2762,13 +2801,13 @@ will refer to the client view.
This option must be associated with a specific client instance,
which means that it must be specified either in a client
instance config file using
-.B --client-config-dir
+.B \-\-client-config-dir
or dynamically generated using a
-.B --client-connect
+.B \-\-client-connect
script.
Remember also to include a
-.B --route
+.B \-\-route
directive in the main OpenVPN config file which encloses
.B local,
so that the kernel will know to route it
@@ -2778,23 +2817,23 @@ OpenVPN's internal client IP address selection algorithm works as
follows:
.B 1
--- Use
-.B --client-connect script
+\-\- Use
+.B \-\-client-connect script
generated file for static IP (first choice).
.br
.B 2
--- Use
-.B --client-config-dir
+\-\- Use
+.B \-\-client-config-dir
file for static IP (next choice).
.br
.B 3
--- Use
-.B --ifconfig-pool
+\-\- Use
+.B \-\-ifconfig-pool
allocation for dynamic IP (last choice).
.br
.\"*********************************************************
.TP
-.B --iroute network [netmask]
+.B \-\-iroute network [netmask]
Generate an internal route to a specific
client. The
.B netmask
@@ -2805,36 +2844,36 @@ the server to a particular client, regardless
of where the client is connecting from. Remember
that you must also add the route to the system
routing table as well (such as by using the
-.B --route
+.B \-\-route
directive). The reason why two routes are needed
is that the
-.B --route
+.B \-\-route
directive routes the packet from the kernel
to OpenVPN. Once in OpenVPN, the
-.B --iroute
+.B \-\-iroute
directive routes to the specific client.
This option must be specified either in a client
instance config file using
-.B --client-config-dir
+.B \-\-client-config-dir
or dynamically generated using a
-.B --client-connect
+.B \-\-client-connect
script.
The
-.B --iroute
+.B \-\-iroute
directive also has an important interaction with
-.B --push
+.B \-\-push
"route ...".
-.B --iroute
+.B \-\-iroute
essentially defines a subnet which is owned by a
particular client (we will call this client A).
If you would like other clients to be able to reach A's
subnet, you can use
-.B --push
+.B \-\-push
"route ..."
together with
-.B --client-to-client
+.B \-\-client-to-client
to effect this. In order for all clients to see
A's subnet, OpenVPN must push this route to all clients
EXCEPT for A, since the subnet is already owned by A.
@@ -2843,11 +2882,11 @@ not pushing a route to a client
if it matches one of the client's iroutes.
.\"*********************************************************
.TP
-.B --client-to-client
+.B \-\-client-to-client
Because the OpenVPN server mode handles multiple clients
through a single tun or tap interface, it is effectively
a router. The
-.B --client-to-client
+.B \-\-client-to-client
flag tells OpenVPN to internally route client-to-client
traffic rather than pushing all client-originating traffic
to the TUN/TAP interface.
@@ -2859,20 +2898,20 @@ if you want to firewall tunnel traffic using
custom, per-client rules.
.\"*********************************************************
.TP
-.B --duplicate-cn
+.B \-\-duplicate-cn
Allow multiple clients with the same common name to concurrently connect.
In the absence of this option, OpenVPN will disconnect a client instance
upon connection of a new client having the same common name.
.\"*********************************************************
.TP
-.B --client-connect script
+.B \-\-client-connect script
Run
.B script
on client connection. The script is passed the common name
and IP address of the just-authenticated client
as environmental variables (see environmental variable section
below). The script is also passed
-the pathname of a not-yet-created temporary file as $1
+the pathname of a freshly created temporary file as $1
(i.e. the first command line argument), to be used by the script
to pass dynamically generated config file directives back to OpenVPN.
@@ -2881,7 +2920,7 @@ to be applied on the server when the client connects,
it should write it to the file named by $1.
See the
-.B --client-config-dir
+.B \-\-client-config-dir
option below for options which
can be legally used in a dynamically generated config file.
@@ -2893,18 +2932,18 @@ returns a non-zero error status, it will cause the client
to be disconnected.
.\"*********************************************************
.TP
-.B --client-disconnect
+.B \-\-client-disconnect
Like
-.B --client-connect
+.B \-\-client-connect
but called on client instance shutdown. Will not be called
unless the
-.B --client-connect
+.B \-\-client-connect
script and plugins (if defined)
were previously called on this instance with
successful (0) status returns.
The exception to this rule is if the
-.B --client-disconnect
+.B \-\-client-disconnect
script or plugins are cascaded, and at least one client-connect
function succeeded, then ALL of the client-disconnect functions for
scripts and plugins will be called on client instance object deletion,
@@ -2913,7 +2952,7 @@ an error status.
.B
.\"*********************************************************
.TP
-.B --client-config-dir dir
+.B \-\-client-config-dir dir
Specify a directory
.B dir
for custom client config files. After
@@ -2923,13 +2962,15 @@ as the client's X509 common name. If a matching file
exists, it will be opened and parsed for client-specific
configuration options. If no matching file is found, OpenVPN
will instead try to open and parse a default file called
-"DEFAULT", which may be provided but is not required.
+"DEFAULT", which may be provided but is not required. Note that
+the configuration files must be readable by the OpenVPN process
+after it has dropped it's root privileges.
This file can specify a fixed IP address for a given
client using
-.B --ifconfig-push,
+.B \-\-ifconfig-push,
as well as fixed subnets owned by the client using
-.B --iroute.
+.B \-\-iroute.
One of the useful properties of this option is that it
allows client configuration files to be conveniently
@@ -2938,28 +2979,45 @@ without needing to restart the server.
The following
options are legal in a client-specific context:
-.B --push, --push-reset, --iroute, --ifconfig-push,
+.B \-\-push, \-\-push-reset, \-\-iroute, \-\-ifconfig-push,
and
-.B --config.
+.B \-\-config.
.\"*********************************************************
.TP
-.B --ccd-exclusive
+.B \-\-ccd-exclusive
Require, as a
condition of authentication, that a connecting client has a
-.B --client-config-dir
+.B \-\-client-config-dir
file.
.\"*********************************************************
.TP
-.B --tmp-dir dir
+.B \-\-tmp-dir dir
Specify a directory
.B dir
for temporary files. This directory will be used by
-.B --client-connect
+openvpn processes and script to communicate temporary
+data with openvpn main process. Note that
+the directory must be writable by the OpenVPN process
+after it has dropped it's root privileges.
+
+This directory will be used by in the following cases:
+
+*
+.B \-\-client-connect
scripts to dynamically generate client-specific
configuration files.
+
+*
+.B OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
+plugin hook to return success/failure via auth_control_file
+when using deferred auth method
+
+*
+.B OPENVPN_PLUGIN_ENABLE_PF
+plugin hook to pass filtering rules via pf_file
.\"*********************************************************
.TP
-.B --hash-size r v
+.B \-\-hash-size r v
Set the size of the real address hash table to
.B r
and the virtual address table to
@@ -2967,13 +3025,13 @@ and the virtual address table to
By default, both tables are sized at 256 buckets.
.\"*********************************************************
.TP
-.B --bcast-buffers n
+.B \-\-bcast-buffers n
Allocate
.B n
buffers for broadcast datagrams (default=256).
.\"*********************************************************
.TP
-.B --tcp-queue-limit n
+.B \-\-tcp-queue-limit n
Maximum number of output packets queued before TCP (default=64).
When OpenVPN is tunneling data from a TUN/TAP device to a
@@ -2985,7 +3043,7 @@ OpenVPN will start to drop outgoing packets directed
at this client.
.\"*********************************************************
.TP
-.B --tcp-nodelay
+.B \-\-tcp-nodelay
This macro sets the TCP_NODELAY socket flag on the server
as well as pushes it to connecting clients. The TCP_NODELAY
flag disables the Nagle algorithm on TCP sockets causing
@@ -3008,13 +3066,13 @@ The macro expands as follows:
.fi
.\"*********************************************************
.TP
-.B --max-clients n
+.B \-\-max-clients n
Limit server to a maximum of
.B n
concurrent clients.
.\"*********************************************************
.TP
-.B --max-routes-per-client n
+.B \-\-max-routes-per-client n
Allow a maximum of
.B n
internal routes per client (default=256).
@@ -3024,9 +3082,9 @@ server with packets appearing to come from many unique MAC addresses,
forcing the server to deplete
virtual memory as its internal routing table expands.
This directive can be used in a
-.B --client-config-dir
+.B \-\-client-config-dir
file or auto-generated by a
-.B --client-connect
+.B \-\-client-connect
script to override the global value for a particular client.
Note that this
@@ -3034,7 +3092,7 @@ directive affects OpenVPN's internal routing table, not the
kernel routing table.
.\"*********************************************************
.TP
-.B --connect-freq n sec
+.B \-\-connect-freq n sec
Allow a maximum of
.B n
new connections per
@@ -3048,12 +3106,12 @@ DoS scenario, legitimate connections might also be refused.
For the best protection against DoS attacks in server mode,
use
-.B --proto udp
+.B \-\-proto udp
and
-.B --tls-auth.
+.B \-\-tls-auth.
.\"*********************************************************
.TP
-.B --learn-address cmd
+.B \-\-learn-address cmd
Run script or shell command
.B cmd
to validate client virtual addresses or routes.
@@ -3061,19 +3119,19 @@ to validate client virtual addresses or routes.
.B cmd
will be executed with 3 parameters:
-.B [1] operation --
+.B [1] operation \-\-
"add", "update", or "delete" based on whether or not
the address is being added to, modified, or deleted from
OpenVPN's internal routing table.
.br
-.B [2] address --
+.B [2] address \-\-
The address being learned or unlearned. This can be
an IPv4 address such as "198.162.10.14", an IPv4 subnet
such as "198.162.10.0/24", or an ethernet MAC address (when
-.B --dev tap
+.B \-\-dev tap
is being used) such as "00:FF:01:02:03:04".
.br
-.B [3] common name --
+.B [3] common name \-\-
The common name on the certificate associated with the
client linked to this address. Only present for "add"
or "update" operations, not "delete".
@@ -3093,7 +3151,7 @@ policies with regard to the client's high-level common name,
rather than the low level client virtual addresses.
.\"*********************************************************
.TP
-.B --auth-user-pass-verify script method
+.B \-\-auth-user-pass-verify script method
Require the client to provide a username/password (possibly
in addition to a client certificate) for authentication.
@@ -3124,10 +3182,10 @@ will be passed as an argument to
and the file will be automatically deleted by OpenVPN after
the script returns. The location of the temporary file is
controlled by the
-.B --tmp-dir
+.B \-\-tmp-dir
option, and will default to the current directory if unspecified.
For security, consider setting
-.B --tmp-dir
+.B \-\-tmp-dir
to a volatile storage medium such as
.B /dev/shm
(if available) to prevent the username/password file from touching the hard drive.
@@ -3159,7 +3217,7 @@ For a sample script that performs PAM authentication, see
in the OpenVPN source distribution.
.\"*********************************************************
.TP
-.B --opt-verify
+.B \-\-opt-verify
Clients that connect with options that are incompatible
with those of the server will be disconnected.
@@ -3169,16 +3227,16 @@ comp-lzo, fragment, keydir, cipher, auth, keysize, secret,
no-replay, no-iv, tls-auth, key-method, tls-server, and tls-client.
This option requires that
-.B --disable-occ
+.B \-\-disable-occ
NOT be used.
.\"*********************************************************
.TP
-.B --auth-user-pass-optional
+.B \-\-auth-user-pass-optional
Allow connections by clients that do not specify a username/password.
Normally, when
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
or
-.B --management-client-auth
+.B \-\-management-client-auth
is specified (or an authentication plugin module), the
OpenVPN server daemon will require connecting clients to specify a
username and password. This option makes the submission of a username/password
@@ -3191,35 +3249,35 @@ to empty strings (""). The authentication module/script MUST have logic
to detect this condition and respond accordingly.
.\"*********************************************************
.TP
-.B --client-cert-not-required
+.B \-\-client-cert-not-required
Don't require client certificate, client will authenticate
using username/password only. Be aware that using this directive
is less secure than requiring certificates from all clients.
If you use this directive, the
entire responsibility of authentication will rest on your
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
script, so keep in mind that bugs in your script
could potentially compromise the security of your VPN.
If you don't use this directive, but you also specify an
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
script, then OpenVPN will perform double authentication. The
client certificate verification AND the
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
script will need to succeed in order for a client to be
authenticated and accepted onto the VPN.
.\"*********************************************************
.TP
-.B --username-as-common-name
+.B \-\-username-as-common-name
For
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
authentication, use
the authenticated username as the common name,
rather than the common name from the client cert.
.\"*********************************************************
.TP
-.B --no-name-remapping
+.B \-\-no-name-remapping
Allow Common Name, X509 Subject, and username strings to include
any printable character including space, but excluding control
characters such as tab, newline, and carriage-return.
@@ -3240,7 +3298,7 @@ disable the remapping feature. Don't use this option unless you
know what you are doing!
.\"*********************************************************
.TP
-.B --port-share host port [dir]
+.B \-\-port-share host port [dir]
When run in TCP server mode, share the OpenVPN port with
another application, such as an HTTPS server. If OpenVPN
senses a connection to its port which is using a non-OpenVPN
@@ -3265,13 +3323,13 @@ Not implemented on Windows.
.SS Client Mode
Use client mode when connecting to an OpenVPN server
which has
-.B --server, --server-bridge,
+.B \-\-server, \-\-server-bridge,
or
-.B --mode server
+.B \-\-mode server
in it's configuration.
.\"*********************************************************
.TP
-.B --client
+.B \-\-client
A helper directive designed to simplify the configuration
of OpenVPN's client mode. This directive is equivalent to:
@@ -3285,34 +3343,34 @@ of OpenVPN's client mode. This directive is equivalent to:
.fi
.\"*********************************************************
.TP
-.B --pull
+.B \-\-pull
This option must be used on a client which is connecting
to a multi-client server. It indicates to OpenVPN that it
should accept options pushed by the server, provided they
are part of the legal set of pushable options (note that the
-.B --pull
+.B \-\-pull
option is implied by
-.B --client
+.B \-\-client
).
In particular,
-.B --pull
+.B \-\-pull
allows the server to push routes to the client, so you should
not use
-.B --pull
+.B \-\-pull
or
-.B --client
+.B \-\-client
in situations where you don't trust the server to have control
over the client's routing table.
.\"*********************************************************
.TP
-.B --auth-user-pass [up]
+.B \-\-auth-user-pass [up]
Authenticate with server using username/password.
.B up
is a file containing username/password on 2 lines (Note: OpenVPN
will only read passwords from a file if it has been built
-with the --enable-password-save configure option, or on Windows
-by defining ENABLE_PASSWORD_SAVE in config-win32.h).
+with the \-\-enable-password-save configure option, or on Windows
+by defining ENABLE_PASSWORD_SAVE in win/settings.in).
If
.B up
@@ -3320,12 +3378,12 @@ is omitted, username/password will be prompted from the
console.
The server configuration must specify an
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
script to verify the username/password provided by
the client.
.\"*********************************************************
.TP
-.B --auth-retry type
+.B \-\-auth-retry type
Controls how OpenVPN responds to username/password verification
errors such as the client-side response to an AUTH_FAILED message from the server
or verification failure of the private key password.
@@ -3336,60 +3394,61 @@ of error.
An AUTH_FAILED message is generated by the server if the client
fails
-.B --auth-user-pass
+.B \-\-auth-user-pass
authentication, or if the server-side
-.B --client-connect
+.B \-\-client-connect
script returns an error status when the client
tries to connect.
.B type
can be one of:
-.B none --
+.B none \-\-
Client will exit with a fatal error (this is the default).
.br
-.B nointeract --
+.B nointeract \-\-
Client will retry the connection without requerying for an
-.B --auth-user-pass
+.B \-\-auth-user-pass
username/password. Use this option for unattended clients.
.br
-.B interact --
+.B interact \-\-
Client will requery for an
-.B --auth-user-pass
+.B \-\-auth-user-pass
username/password and/or private key password before attempting a reconnection.
Note that while this option cannot be pushed, it can be controlled
from the management interface.
.\"*********************************************************
.TP
-.B --server-poll-timeout n
+.B \-\-server-poll-timeout n
when polling possible remote servers to connect to
in a round-robin fashion, spend no more than
.B n
seconds waiting for a response before trying the next server.
.\"*********************************************************
.TP
-.B --explicit-exit-notify [n]
+.B \-\-explicit-exit-notify [n]
In UDP client mode or point-to-point mode, send server/peer an exit notification
if tunnel is restarted or OpenVPN process is exited. In client mode, on
exit/restart, this
option will tell the server to immediately close its client instance object
rather than waiting for a timeout. The
.B n
-parameter (default=1) controls the maximum number of retries that the client
-will attempt to resend the exit notification message.
+parameter (default=1) controls the maximum number of attempts that the client
+will try to resend the exit notification message. OpenVPN will not send any exit
+notifications unless this option is enabled.
.\"*********************************************************
.SS Data Channel Encryption Options:
These options are meaningful for both Static & TLS-negotiated key modes
(must be compatible between peers).
.\"*********************************************************
.TP
-.B --secret file [direction]
+.B \-\-secret file [direction]
Enable Static Key encryption mode (non-TLS).
Use pre-shared secret
.B file
which was generated with
-.B --genkey.
+.B \-\-genkey.
The optional
.B direction
@@ -3420,7 +3479,7 @@ supports the
.B direction
parameter, will also support 2048 bit key file generation
using the
-.B --genkey
+.B \-\-genkey
option.
Static key encryption mode has certain advantages,
@@ -3450,7 +3509,7 @@ would see nothing
but random-looking data.
.\"*********************************************************
.TP
-.B --auth alg
+.B \-\-auth alg
Authenticate packets with HMAC using message
digest algorithm
.B alg.
@@ -3465,7 +3524,7 @@ OpenVPN's usage of HMAC is to first encrypt a packet, then HMAC the resulting ci
In static-key encryption mode, the HMAC key
is included in the key file generated by
-.B --genkey.
+.B \-\-genkey.
In TLS mode, the HMAC key is dynamically generated and shared
between peers via the TLS control channel. If OpenVPN receives a packet with
a bad HMAC it will drop the packet.
@@ -3478,7 +3537,7 @@ For more information on HMAC see
.I http://www.cs.ucsd.edu/users/mihir/papers/hmac.html
.\"*********************************************************
.TP
-.B --cipher alg
+.B \-\-cipher alg
Encrypt packets with cipher algorithm
.B alg.
The default is
@@ -3493,7 +3552,7 @@ For more information on blowfish, see
To see other ciphers that are available with
OpenVPN, use the
-.B --show-ciphers
+.B \-\-show-ciphers
option.
OpenVPN supports the CBC, CFB, and OFB cipher modes,
@@ -3505,10 +3564,10 @@ Set
to disable encryption.
.\"*********************************************************
.TP
-.B --keysize n
+.B \-\-keysize n
Size of cipher key in bits (optional).
If unspecified, defaults to cipher-specific default. The
-.B --show-ciphers
+.B \-\-show-ciphers
option (see below) shows all available OpenSSL ciphers,
their default key sizes, and whether the key size can
be changed. Use care in changing a cipher's default
@@ -3518,7 +3577,7 @@ larger key may offer no real guarantee of greater
security, or may even reduce security.
.\"*********************************************************
.TP
-.B --prng alg [nsl]
+.B \-\-prng alg [nsl]
(Advanced) For PRNG (Pseudo-random number generator),
use digest algorithm
.B alg
@@ -3533,19 +3592,19 @@ to disable the PRNG and use the OpenSSL RAND_bytes function
instead for all of OpenVPN's pseudo-random number needs.
.\"*********************************************************
.TP
-.B --engine [engine-name]
+.B \-\-engine [engine-name]
Enable OpenSSL hardware-based crypto engine functionality.
If
.B engine-name
is specified,
use a specific crypto engine. Use the
-.B --show-engines
+.B \-\-show-engines
standalone option to list the crypto engines which are
supported by OpenSSL.
.\"*********************************************************
.TP
-.B --no-replay
+.B \-\-no-replay
(Advanced) Disable OpenVPN's protection against replay attacks.
Don't use this option unless you are prepared to make
a tradeoff of greater efficiency in exchange for less
@@ -3589,7 +3648,7 @@ algorithm used
by IPSec.
.\"*********************************************************
.TP
-.B --replay-window n [t]
+.B \-\-replay-window n [t]
Use a replay protection sliding-window of size
.B n
and a time window of
@@ -3604,9 +3663,9 @@ is 15 seconds.
This option is only relevant in UDP mode, i.e.
when either
-.B --proto udp
+.B \-\-proto udp
is specifed, or no
-.B --proto
+.B \-\-proto
option is specified.
When OpenVPN tunnels IP packets over UDP, there is the possibility that
@@ -3618,7 +3677,7 @@ the TCP/IP protocol stack, provided they satisfy several constraints.
.B (a)
The packet cannot be a replay (unless
-.B --no-replay
+.B \-\-no-replay
is specified, which disables replay protection altogether).
.B (b)
@@ -3640,7 +3699,7 @@ a larger value for
Satellite links in particular often require this.
If you run OpenVPN at
-.B --verb 4,
+.B \-\-verb 4,
you will see the message "Replay-window backtrack occurred [x]"
every time the maximum sequence number backtrack seen thus far
increases. This can be used to calibrate
@@ -3676,7 +3735,7 @@ parameters of what is to be expected from the physical IP layer. The problem
is easily fixed by simply using TCP as the VPN transport layer.
.\"*********************************************************
.TP
-.B --mute-replay-warnings
+.B \-\-mute-replay-warnings
Silence the output of replay warnings, which are a common
false alarm on WiFi networks. This option preserves
the security of the replay protection code without
@@ -3684,7 +3743,7 @@ the verbosity associated with warnings about duplicate
packets.
.\"*********************************************************
.TP
-.B --replay-persist file
+.B \-\-replay-persist file
Persist replay-protection state across sessions using
.B file
to save and reload the state.
@@ -3692,7 +3751,7 @@ to save and reload the state.
This option will strengthen protection against replay attacks,
especially when you are using OpenVPN in a dynamic context (such
as with
-.B --inetd)
+.B \-\-inetd)
when OpenVPN sessions are frequently started and stopped.
This option will keep a disk copy of the current replay protection
@@ -3703,12 +3762,12 @@ which were already received by the prior session.
This option only makes sense when replay protection is enabled
(the default) and you are using either
-.B --secret
+.B \-\-secret
(shared-secret key mode) or TLS mode with
-.B --tls-auth.
+.B \-\-tls-auth.
.\"*********************************************************
.TP
-.B --no-iv
+.B \-\-no-iv
(Advanced) Disable OpenVPN's use of IV (cipher initialization vector).
Don't use this option unless you are prepared to make
a tradeoff of greater efficiency in exchange for less
@@ -3729,24 +3788,24 @@ space-saving optimization that uses the unique identifier for
datagram replay protection as the IV.
.\"*********************************************************
.TP
-.B --test-crypto
+.B \-\-test-crypto
Do a self-test of OpenVPN's crypto options by encrypting and
decrypting test packets using the data channel encryption options
specified above. This option does not require a peer to function,
and therefore can be specified without
-.B --dev
+.B \-\-dev
or
-.B --remote.
+.B \-\-remote.
The typical usage of
-.B --test-crypto
+.B \-\-test-crypto
would be something like this:
-.B openvpn --test-crypto --secret key
+.B openvpn \-\-test-crypto \-\-secret key
or
-.B openvpn --test-crypto --secret key --verb 9
+.B openvpn \-\-test-crypto \-\-secret key \-\-verb 9
This option is very useful to test OpenVPN after it has been ported to
a new platform, or to isolate problems in the compiler, OpenSSL
@@ -3770,17 +3829,17 @@ including certificate-based authentication and Diffie Hellman forward secrecy.
To use TLS mode, each peer that runs OpenVPN should have its own local
certificate/key pair (
-.B --cert
+.B \-\-cert
and
-.B --key
+.B \-\-key
), signed by the root certificate which is specified
in
-.B --ca.
+.B \-\-ca.
When two OpenVPN peers connect, each presents its local certificate to the
other. Each peer will then check that its partner peer presented a
certificate which was signed by the master root certificate as specified in
-.B --ca.
+.B \-\-ca.
If that check on both peers succeeds, then the TLS negotiation
will succeed, both OpenVPN
@@ -3797,18 +3856,18 @@ The easy-rsa package is also rendered in web form here:
.I http://openvpn.net/easyrsa.html
.\"*********************************************************
.TP
-.B --tls-server
+.B \-\-tls-server
Enable TLS and assume server role during TLS handshake. Note that
OpenVPN is designed as a peer-to-peer application. The designation
of client or server is only for the purpose of negotiating the TLS
control channel.
.\"*********************************************************
.TP
-.B --tls-client
+.B \-\-tls-client
Enable TLS and assume client role during TLS handshake.
.\"*********************************************************
.TP
-.B --ca file
+.B \-\-ca file
Certificate authority (CA) file in .pem format, also referred to as the
.I root
certificate. This file can have multiple
@@ -3830,10 +3889,15 @@ production environment, since by virtue of the fact that
they are distributed with OpenVPN, they are totally insecure.
.\"*********************************************************
.TP
-.B --dh file
+.B \-\-capath dir
+Directory containing trusted certificates (CAs and CRLs).
+Available with OpenSSL version >= 0.9.7 dev.
+.\"*********************************************************
+.TP
+.B \-\-dh file
File containing Diffie Hellman parameters
in .pem format (required for
-.B --tls-server
+.B \-\-tls-server
only). Use
.B openssl dhparam -out dh1024.pem 1024
@@ -3843,15 +3907,15 @@ included with the OpenVPN distribution. Diffie Hellman parameters
may be considered public.
.\"*********************************************************
.TP
-.B --cert file
-Local peer's signed certificate in .pem format -- must be signed
+.B \-\-cert file
+Local peer's signed certificate in .pem format \-\- must be signed
by a certificate authority whose certificate is in
-.B --ca file.
+.B \-\-ca file.
Each peer in an OpenVPN link running in TLS mode should have its own
certificate and private key file. In addition, each certificate should
have been signed by the key of a certificate
authority whose public key resides in the
-.B --ca
+.B \-\-ca
certificate authority file.
You can easily make your own certificate authority (see above) or pay money
to use a commercial service such as thawte.com (in which case you will be
@@ -3876,7 +3940,7 @@ Note that the
command reads the location of the certificate authority key from its
configuration file such as
.B /usr/share/ssl/openssl.cnf
--- note also
+\-\- note also
that for certificate authority functions, you must set up the files
.B index.txt
(may be empty) and
@@ -3887,7 +3951,7 @@ that for certificate authority functions, you must set up the files
).
.\"*********************************************************
.TP
-.B --extra-certs file
+.B \-\-extra-certs file
Specify a
.B file
containing one or more PEM certs (concatenated together)
@@ -3903,23 +3967,23 @@ certificate, as would be the case if the certs were placed in the
file.
.\"*********************************************************
.TP
-.B --key file
+.B \-\-key file
Local peer's private key in .pem format. Use the private key which was generated
when you built your peer's certificate (see
.B -cert file
above).
.\"*********************************************************
.TP
-.B --pkcs12 file
+.B \-\-pkcs12 file
Specify a PKCS #12 file containing local private key,
local certificate, and root CA certificate.
This option can be used instead of
-.B --ca, --cert,
+.B \-\-ca, \-\-cert,
and
-.B --key.
+.B \-\-key.
.\"*********************************************************
.TP
-.B --verify-hash hash
+.B \-\-verify-hash hash
Specify SHA1 fingerprint for level-1 cert. The level-1 cert is the
CA (or intermediate cert) that signs the leaf certificate, and is
one removed from the leaf certificate in the direction of the root.
@@ -3930,74 +3994,74 @@ or certificate verification will fail. Hash is specified
as XX:XX:... For example: AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16
.\"*********************************************************
.TP
-.B --pkcs11-cert-private [0|1]...
+.B \-\-pkcs11-cert-private [0|1]...
Set if access to certificate object should be performed after login.
Every provider has its own setting.
.\"*********************************************************
.TP
-.B --pkcs11-id name
+.B \-\-pkcs11-id name
Specify the serialized certificate id to be used. The id can be gotten
by the standalone
-.B --show-pkcs11-ids
+.B \-\-show-pkcs11-ids
option.
.\"*********************************************************
.TP
-.B --pkcs11-id-management
+.B \-\-pkcs11-id-management
Acquire PKCS#11 id from management interface. In this case a NEED-STR 'pkcs11-id-request'
real-time message will be triggered, application may use pkcs11-id-count command to
retrieve available number of certificates, and pkcs11-id-get command to retrieve certificate
id and certificate body.
.\"*********************************************************
.TP
-.B --pkcs11-pin-cache seconds
+.B \-\-pkcs11-pin-cache seconds
Specify how many seconds the PIN can be cached, the default is until the token is removed.
.\"*********************************************************
.TP
-.B --pkcs11-protected-authentication [0|1]...
+.B \-\-pkcs11-protected-authentication [0|1]...
Use PKCS#11 protected authentication path, useful for biometric and external
keypad devices.
Every provider has its own setting.
.\"*********************************************************
.TP
-.B --pkcs11-providers provider...
+.B \-\-pkcs11-providers provider...
Specify a RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki) providers
to load.
This option can be used instead of
-.B --cert, --key,
+.B \-\-cert, \-\-key,
and
-.B --pkcs12.
+.B \-\-pkcs12.
.\"*********************************************************
.TP
-.B --pkcs11-private-mode mode...
+.B \-\-pkcs11-private-mode mode...
Specify which method to use in order to perform private key operations.
A different mode can be specified for each provider.
Mode is encoded as hex number, and can be a mask one of the following:
.B 0
-(default) -- Try to determind automatically.
+(default) \-\- Try to determind automatically.
.br
.B 1
--- Use sign.
+\-\- Use sign.
.br
.B 2
--- Use sign recover.
+\-\- Use sign recover.
.br
.B 4
--- Use decrypt.
+\-\- Use decrypt.
.br
.B 8
--- Use unwrap.
+\-\- Use unwrap.
.br
.\"*********************************************************
.TP
-.B --cryptoapicert select-string
+.B \-\-cryptoapicert select-string
Load the certificate and private key from the
Windows Certificate System Store (Windows Only).
Use this option instead of
-.B --cert
+.B \-\-cert
and
-.B --key.
+.B \-\-key.
This makes
it possible to use any smart card, supported by Windows, but also any
@@ -4023,7 +4087,7 @@ Certificate Store GUI.
.\"*********************************************************
.TP
-.B --key-method m
+.B \-\-key-method m
Use data channel key negotiation method
.B m.
The key method must match on both sides of the connection.
@@ -4051,16 +4115,16 @@ of keying occur:
of the connection producing certificates and verifying the certificate
(or other authentication info provided) of
the other side. The
-.B --key-method
+.B \-\-key-method
parameter has no effect on this process.
(2) After the TLS connection is established, the tunnel session keys are
separately negotiated over the existing secure TLS channel. Here,
-.B --key-method
+.B \-\-key-method
determines the derivation of the tunnel session keys.
.\"*********************************************************
.TP
-.B --tls-cipher l
+.B \-\-tls-cipher l
A list
.B l
of allowable TLS ciphers delimited by a colon (":").
@@ -4070,11 +4134,11 @@ version rollback attack where a man-in-the-middle attacker tries
to force two peers to negotiate to the lowest level
of security they both support.
Use
-.B --show-tls
+.B \-\-show-tls
to see a list of supported TLS ciphers.
.\"*********************************************************
.TP
-.B --tls-timeout n
+.B \-\-tls-timeout n
Packet retransmit timeout on TLS control channel
if no acknowledgment from remote within
.B n
@@ -4091,7 +4155,7 @@ the higher level network protocols running on top of the tunnel
such as TCP expect this role to be left to them.
.\"*********************************************************
.TP
-.B --reneg-bytes n
+.B \-\-reneg-bytes n
Renegotiate data channel key after
.B n
bytes sent or received (disabled by default).
@@ -4101,13 +4165,13 @@ a number of seconds. A key renegotiation will be forced
if any of these three criteria are met by either peer.
.\"*********************************************************
.TP
-.B --reneg-pkts n
+.B \-\-reneg-pkts n
Renegotiate data channel key after
.B n
packets sent and received (disabled by default).
.\"*********************************************************
.TP
-.B --reneg-sec n
+.B \-\-reneg-sec n
Renegotiate data channel key after
.B n
seconds (default=3600).
@@ -4118,16 +4182,16 @@ cause the end user to be challenged to reauthorize once per hour.
Also, keep in mind that this option can be used on both the client and server,
and whichever uses the lower value will be the one to trigger the renegotiation.
A common mistake is to set
-.B --reneg-sec
+.B \-\-reneg-sec
to a higher value on either the client or server, while the other side of the connection
is still using the default value of 3600 seconds, meaning that the renegotiation will
-still occur once per 3600 seconds. The solution is to increase --reneg-sec on both the
+still occur once per 3600 seconds. The solution is to increase \-\-reneg-sec on both the
client and server, or set it to 0 on one side of the connection (to disable), and to
your chosen value on the other side.
.\"*********************************************************
.TP
-.B --hand-window n
-Handshake Window -- the TLS-based key exchange must finalize within
+.B \-\-hand-window n
+Handshake Window \-\- the TLS-based key exchange must finalize within
.B n
seconds
of handshake initiation by any peer (default = 60 seconds).
@@ -4135,47 +4199,47 @@ If the handshake fails
we will attempt to reset our connection with our peer and try again.
Even in the event of handshake failure we will still use
our expiring key for up to
-.B --tran-window
+.B \-\-tran-window
seconds to maintain continuity of transmission of tunnel
data.
.\"*********************************************************
.TP
-.B --tran-window n
-Transition window -- our old key can live this many seconds
+.B \-\-tran-window n
+Transition window \-\- our old key can live this many seconds
after a new a key renegotiation begins (default = 3600 seconds).
This feature allows for a graceful transition from old to new
key, and removes the key renegotiation sequence from the critical
path of tunnel data forwarding.
.\"*********************************************************
.TP
-.B --single-session
+.B \-\-single-session
After initially connecting to a remote peer, disallow any new connections.
Using this
option means that a remote peer cannot connect, disconnect, and then
reconnect.
If the daemon is reset by a signal or
-.B --ping-restart,
+.B \-\-ping-restart,
it will allow one new connection.
-.B --single-session
+.B \-\-single-session
can be used with
-.B --ping-exit
+.B \-\-ping-exit
or
-.B --inactive
+.B \-\-inactive
to create a single dynamic session that will exit when finished.
.\"*********************************************************
.TP
-.B --tls-exit
+.B \-\-tls-exit
Exit on TLS negotiation failure.
.\"*********************************************************
.TP
-.B --tls-auth file [direction]
+.B \-\-tls-auth file [direction]
Add an additional layer of HMAC authentication on top of the TLS
control channel to protect against DoS attacks.
In a nutshell,
-.B --tls-auth
+.B \-\-tls-auth
enables a kind of "HMAC firewall" on OpenVPN's TCP/UDP port,
where TLS control channel packets
bearing an incorrect HMAC signature can be dropped immediately without
@@ -4186,7 +4250,7 @@ response.
.B (1)
An OpenVPN static key file generated by
-.B --genkey
+.B \-\-genkey
(required if
.B direction
parameter is used).
@@ -4204,19 +4268,19 @@ OpenVPN will first try format (1), and if the file fails to parse as
a static key file, format (2) will be used.
See the
-.B --secret
+.B \-\-secret
option for more information on the optional
.B direction
parameter.
-.B --tls-auth
+.B \-\-tls-auth
is recommended when you are running OpenVPN in a mode where
it is listening for packets from any IP address, such as when
-.B --remote
+.B \-\-remote
is not specified, or
-.B --remote
+.B \-\-remote
is specified with
-.B --float.
+.B \-\-float.
The rationale for
this feature is as follows. TLS requires a multi-packet exchange
@@ -4243,7 +4307,7 @@ An important rule of thumb in reducing vulnerability to DoS attacks is to
minimize the amount of resources a potential, but as yet unauthenticated,
client is able to consume.
-.B --tls-auth
+.B \-\-tls-auth
does this by signing every TLS control channel packet with an HMAC signature,
including packets which are sent before the TLS level has had a chance
to authenticate the peer.
@@ -4251,20 +4315,20 @@ The result is that packets without
the correct signature can be dropped immediately upon reception,
before they have a chance to consume additional system resources
such as by initiating a TLS handshake.
-.B --tls-auth
+.B \-\-tls-auth
can be strengthened by adding the
-.B --replay-persist
+.B \-\-replay-persist
option which will keep OpenVPN's replay protection state
in a file so that it is not lost across restarts.
It should be emphasized that this feature is optional and that the
passphrase/key file used with
-.B --tls-auth
+.B \-\-tls-auth
gives a peer nothing more than the power to initiate a TLS
handshake. It is not used to encrypt or authenticate any tunnel data.
.\"*********************************************************
.TP
-.B --askpass [file]
+.B \-\-askpass [file]
Get certificate password from console or
.B file
before we daemonize.
@@ -4273,7 +4337,7 @@ For the extremely
security conscious, it is possible to protect your private key with
a password. Of course this means that every time the OpenVPN
daemon is started you must be there to type the password. The
-.B --askpass
+.B \-\-askpass
option allows you to start OpenVPN from the command line. It will
query you for a password before it daemonizes. To protect a private
key with a password you should omit the
@@ -4290,15 +4354,15 @@ Keep in mind that storing your password in a file
to a certain extent invalidates the extra security provided by
using an encrypted key (Note: OpenVPN
will only read passwords from a file if it has been built
-with the --enable-password-save configure option, or on Windows
-by defining ENABLE_PASSWORD_SAVE in config-win32.h).
+with the \-\-enable-password-save configure option, or on Windows
+by defining ENABLE_PASSWORD_SAVE in win/settings.in).
.\"*********************************************************
.TP
-.B --auth-nocache
+.B \-\-auth-nocache
Don't cache
-.B --askpass
+.B \-\-askpass
or
-.B --auth-user-pass
+.B \-\-auth-user-pass
username/passwords in virtual memory.
If specified, this directive will cause OpenVPN to immediately
@@ -4308,28 +4372,40 @@ from stdin, which may be multiple times during the duration of an
OpenVPN session.
This directive does not affect the
-.B --http-proxy
+.B \-\-http-proxy
username/password. It is always cached.
.\"*********************************************************
.TP
-.B --tls-verify cmd
+.B \-\-tls-verify cmd
Execute shell command
.B cmd
to verify the X509 name of a
pending TLS connection that has otherwise passed all other
tests of certification (except for revocation via
-.B --crl-verify
+.B \-\-crl-verify
directive; the revocation test occurs after the
-.B --tls-verify
+.B \-\-tls-verify
test).
.B cmd
should return 0 to allow the TLS handshake to proceed, or 1 to fail.
+
+Note that
+.B cmd
+is a command line and as such may (if enclosed in quotes) contain
+whitespace separated arguments. The first word of
+.B cmd
+is the shell command to execute and the remaining words are its
+arguments.
+When
.B cmd
-is executed as
+is executed two arguments are appended, as follows:
.B cmd certificate_depth X509_NAME_oneline
+These arguments are, respectively, the current certificate depth and
+the X509 common name (cn) of the peer.
+
This feature is useful if the peer you want to trust has a certificate
which was signed by a certificate authority who also signed many
other certificates, where you don't necessarily want to trust all of them,
@@ -4343,17 +4419,17 @@ in the OpenVPN distribution.
See the "Environmental Variables" section below for
additional parameters passed as environmental variables.
-
-Note that
-.B cmd
-can be a shell command with multiple arguments, in which
-case all OpenVPN-generated arguments will be appended
-to
-.B cmd
-to build a command line which will be passed to the script.
.\"*********************************************************
.TP
-.B --tls-remote name
+.B \-\-tls-export-cert directory
+Store the certificates the clients uses upon connection to this
+directory. This will be done before \-\-tls-verify is called. The
+certificates will use a temporary name and will be deleted when
+the tls-verify script returns. The file name used for the certificate
+is available via the peer_cert environment variable.
+.\"*********************************************************
+.TP
+.B \-\-tls-remote name
Accept connections only from a host with X509 name
or common name equal to
.B name.
@@ -4370,24 +4446,24 @@ a third party, such as a commercial web CA.
Name can also be a common name prefix, for example if you
want a client to only accept connections to "Server-1",
"Server-2", etc., you can simply use
-.B --tls-remote Server
+.B \-\-tls-remote Server
Using a common 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 --tls-remote
+.B \-\-tls-remote
is a useful replacement for the
-.B --tls-verify
+.B \-\-tls-verify
option to verify the remote host, because
-.B --tls-remote
+.B \-\-tls-remote
works in a
-.B --chroot
+.B \-\-chroot
environment too.
.\"*********************************************************
.TP
-.B --x509-track attribute
+.B \-\-x509-track attribute
Save peer X509
.B attribute
value in environment for use by plugins and management interface.
@@ -4395,11 +4471,11 @@ Prepend a '+' to
.B attribute
to save values from full cert chain. Values will be encoded
as X509_<depth>_<attribute>=<value>. Multiple
-.B --x509-track
+.B \-\-x509-track
options can be defined to track multiple attributes.
.\"*********************************************************
.TP
-.B --ns-cert-type client|server
+.B \-\-ns-cert-type client|server
Require that peer certificate was signed with an explicit
.B nsCertType
designation of "client" or "server".
@@ -4414,19 +4490,19 @@ field set to "server".
If the server certificate's nsCertType field is set
to "server", then the clients can verify this with
-.B --ns-cert-type server.
+.B \-\-ns-cert-type server.
This is an important security precaution to protect against
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, \-\-tls-remote,
or
-.B --tls-verify.
+.B \-\-tls-verify.
.\"*********************************************************
.TP
-.B --remote-cert-ku v...
+.B \-\-remote-cert-ku v...
Require that peer certificate was signed with an explicit
.B key usage.
@@ -4437,7 +4513,7 @@ The key usage should be encoded in hex, more than one key
usage can be specified.
.\"*********************************************************
.TP
-.B --remote-cert-eku oid
+.B \-\-remote-cert-eku oid
Require that peer certificate was signed with an explicit
.B extended key usage.
@@ -4448,7 +4524,7 @@ The extended key usage should be encoded in oid notation, or
OpenSSL symbolic representation.
.\"*********************************************************
.TP
-.B --remote-cert-tls client|server
+.B \-\-remote-cert-tls client|server
Require that peer certificate was signed with an explicit
.B key usage
and
@@ -4459,18 +4535,18 @@ This is a useful security option for clients, to ensure that
the host they connect to is a designated server.
The
-.B --remote-cert-tls client
+.B \-\-remote-cert-tls client
option is equivalent to
.B
---remote-cert-ku 80 08 88 --remote-cert-eku "TLS Web Client Authentication"
+\-\-remote-cert-ku 80 08 88 \-\-remote-cert-eku "TLS Web Client Authentication"
The key usage is digitalSignature and/or keyAgreement.
The
-.B --remote-cert-tls server
+.B \-\-remote-cert-tls server
option is equivalent to
.B
---remote-cert-ku a0 88 --remote-cert-eku "TLS Web Server Authentication"
+\-\-remote-cert-ku a0 88 \-\-remote-cert-eku "TLS Web Server Authentication"
The key usage is digitalSignature and ( keyEncipherment or keyAgreement ).
@@ -4479,12 +4555,12 @@ 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, \-\-tls-remote,
or
-.B --tls-verify.
+.B \-\-tls-verify.
.\"*********************************************************
.TP
-.B --crl-verify crl ['dir']
+.B \-\-crl-verify crl ['dir']
Check peer certificate against the file
.B crl
in PEM format.
@@ -4514,28 +4590,28 @@ it will be rejected.
.SS SSL Library information:
.\"*********************************************************
.TP
-.B --show-ciphers
+.B \-\-show-ciphers
(Standalone)
Show all cipher algorithms to use with the
-.B --cipher
+.B \-\-cipher
option.
.\"*********************************************************
.TP
-.B --show-digests
+.B \-\-show-digests
(Standalone)
Show all message digest algorithms to use with the
-.B --auth
+.B \-\-auth
option.
.\"*********************************************************
.TP
-.B --show-tls
+.B \-\-show-tls
(Standalone)
Show all TLS ciphers (TLS used only as a control channel). The TLS
ciphers will be sorted from highest preference (most secure) to
lowest.
.\"*********************************************************
.TP
-.B --show-engines
+.B \-\-show-engines
(Standalone)
Show currently available hardware-based crypto acceleration
engines supported by the OpenSSL library.
@@ -4544,18 +4620,18 @@ engines supported by the OpenSSL library.
Used only for non-TLS static key encryption mode.
.\"*********************************************************
.TP
-.B --genkey
+.B \-\-genkey
(Standalone)
Generate a random key to be used as a shared secret,
for use with the
-.B --secret
+.B \-\-secret
option. This file must be shared with the
peer over a pre-existing secure channel such as
.BR scp (1)
.
.\"*********************************************************
.TP
-.B --secret file
+.B \-\-secret file
Write key to
.B file.
.\"*********************************************************
@@ -4564,7 +4640,7 @@ Available with linux 2.4.7+. These options comprise a standalone mode
of OpenVPN which can be used to create and delete persistent tunnels.
.\"*********************************************************
.TP
-.B --mktun
+.B \-\-mktun
(Standalone)
Create a persistent tunnel on platforms which support them such
as Linux. Normally TUN/TAP tunnels exist only for
@@ -4575,9 +4651,9 @@ only when they are deleted or the machine is rebooted.
One of the advantages of persistent tunnels is that they eliminate the
need for separate
-.B --up
+.B \-\-up
and
-.B --down
+.B \-\-down
scripts to run the appropriate
.BR ifconfig (8)
and
@@ -4589,40 +4665,40 @@ Another advantage is that open connections through the TUN/TAP-based tunnel
will not be reset if the OpenVPN peer restarts. This can be useful to
provide uninterrupted connectivity through the tunnel in the event of a DHCP
reset of the peer's public IP address (see the
-.B --ipchange
+.B \-\-ipchange
option above).
One disadvantage of persistent tunnels is that it is harder to automatically
configure their MTU value (see
-.B --link-mtu
+.B \-\-link-mtu
and
-.B --tun-mtu
+.B \-\-tun-mtu
above).
On some platforms such as Windows, TAP-Win32 tunnels are persistent by
default.
.\"*********************************************************
.TP
-.B --rmtun
+.B \-\-rmtun
(Standalone)
Remove a persistent tunnel.
.\"*********************************************************
.TP
-.B --dev tunX | tapX
+.B \-\-dev tunX | tapX
TUN/TAP device
.\"*********************************************************
.TP
-.B --user user
+.B \-\-user user
Optional user to be owner of this tunnel.
.\"*********************************************************
.TP
-.B --group group
+.B \-\-group group
Optional group to be owner of this tunnel.
.\"*********************************************************
.SS Windows-Specific Options:
.\"*********************************************************
.TP
-.B --win-sys path|'env'
+.B \-\-win-sys path|'env'
Set the Windows system directory pathname to use when looking for system
executables such as
.B route.exe
@@ -4638,23 +4714,23 @@ indicates that the pathname should be read from the
environmental variable.
.\"*********************************************************
.TP
-.B --ip-win32 method
+.B \-\-ip-win32 method
When using
-.B --ifconfig
+.B \-\-ifconfig
on Windows, set the TAP-Win32 adapter
IP address and netmask using
.B method.
Don't use this option unless you are also using
-.B --ifconfig.
+.B \-\-ifconfig.
-.B manual --
+.B manual \-\-
Don't set the IP address or netmask automatically.
Instead output a message
to the console telling the user to configure the
adapter manually and indicating the IP/netmask which
OpenVPN expects the adapter to be set to.
-.B dynamic [offset] [lease-time] --
+.B dynamic [offset] [lease-time] \-\-
Automatically set the IP address and netmask by replying to
DHCP query messages generated by the kernel. This mode is
probably the "cleanest" solution
@@ -4664,13 +4740,13 @@ this mode: (1) The TCP/IP properties for the TAP-Win32
adapter must be set to "Obtain an IP address automatically," and
(2) OpenVPN needs to claim an IP address in the subnet for use
as the virtual DHCP server address. By default in
-.B --dev tap
+.B \-\-dev tap
mode, OpenVPN will
take the normally unused first address in the subnet. For example,
if your subnet is 192.168.4.0 netmask 255.255.255.0, then
OpenVPN will take the IP address 192.168.4.0 to use as the
virtual DHCP server address. In
-.B --dev tun
+.B \-\-dev tun
mode, OpenVPN will cause the DHCP server to masquerade as if it were
coming from the remote endpoint. The optional offset parameter is
an integer which is > -256 and < 256 and which defaults to 0.
@@ -4692,13 +4768,13 @@ because it prevents routes involving the TAP-Win32 adapter from
being lost when the system goes to sleep. The default
lease time is one year.
-.B netsh --
+.B netsh \-\-
Automatically set the IP address and netmask using
the Windows command-line "netsh"
command. This method appears to work correctly on
Windows XP but not Windows 2000.
-.B ipapi --
+.B ipapi \-\-
Automatically set the IP address and netmask using the
Windows IP Helper API. This approach
does not have ideal semantics, though testing has indicated
@@ -4707,7 +4783,7 @@ it is best to leave the TCP/IP properties for the TAP-Win32
adapter in their default state, i.e. "Obtain an IP address
automatically."
-.B adaptive --
+.B adaptive \-\-
(Default) Try
.B dynamic
method initially and fail over to
@@ -4737,55 +4813,55 @@ mode to restore the TAP-Win32 adapter TCP/IP properties
to a DHCP configuration.
.\"*********************************************************
.TP
-.B --route-method m
+.B \-\-route-method m
Which method
.B m
to use for adding routes on Windows?
.B adaptive
-(default) -- Try IP helper API first. If that fails, fall
+(default) \-\- Try IP helper API first. If that fails, fall
back to the route.exe shell command.
.br
.B ipapi
--- Use IP helper API.
+\-\- Use IP helper API.
.br
.B exe
--- Call the route.exe shell command.
+\-\- Call the route.exe shell command.
.\"*********************************************************
.TP
-.B --dhcp-option type [parm]
+.B \-\-dhcp-option type [parm]
Set extended TAP-Win32 TCP/IP properties, must
be used with
-.B --ip-win32 dynamic
+.B \-\-ip-win32 dynamic
or
-.B --ip-win32 adaptive.
+.B \-\-ip-win32 adaptive.
This option can be used to set additional TCP/IP properties
on the TAP-Win32 adapter, and is particularly useful for
configuring an OpenVPN client to access a Samba server
across the VPN.
-.B DOMAIN name --
+.B DOMAIN name \-\-
Set Connection-specific DNS Suffix.
-.B DNS addr --
+.B DNS addr \-\-
Set primary domain name server address. Repeat
this option to set secondary DNS server addresses.
-.B WINS addr --
+.B WINS addr \-\-
Set primary WINS server address (NetBIOS over TCP/IP Name Server).
Repeat this option to set secondary WINS server addresses.
-.B NBDD addr --
+.B NBDD addr \-\-
Set primary NBDD server address (NetBIOS over TCP/IP Datagram Distribution Server)
Repeat this option
to set secondary NBDD server addresses.
-.B NTP addr --
+.B NTP addr \-\-
Set primary NTP server address (Network Time Protocol).
Repeat this option
to set secondary NTP server addresses.
-.B NBT type --
+.B NBT type \-\-
Set NetBIOS over TCP/IP Node type. Possible options:
.B 1
= b-node (broadcasts),
@@ -4798,7 +4874,7 @@ then query name server), and
.B 8
= h-node (query name server, then broadcast).
-.B NBS scope-id --
+.B NBS scope-id \-\-
Set NetBIOS over TCP/IP Scope. A NetBIOS Scope ID provides an extended
naming service for the NetBIOS over TCP/IP (Known as NBT) module. The
primary purpose of a NetBIOS scope ID is to isolate NetBIOS traffic on
@@ -4810,19 +4886,19 @@ computers to use the same computer name, as they have different
scope IDs. The Scope ID becomes a part of the NetBIOS name, making the name unique.
(This description of NetBIOS scopes courtesy of NeonSurge@abyss.com)
-.B DISABLE-NBT --
+.B DISABLE-NBT \-\-
Disable Netbios-over-TCP/IP.
Note that if
-.B --dhcp-option
+.B \-\-dhcp-option
is pushed via
-.B --push
+.B \-\-push
to a non-windows client, the option will be saved in the client's
environment before the up script is called, under
the name "foreign_option_{n}".
.\"*********************************************************
.TP
-.B --tap-sleep n
+.B \-\-tap-sleep n
Cause OpenVPN to sleep for
.B n
seconds immediately after the TAP-Win32 adapter state
@@ -4830,21 +4906,21 @@ is set to "connected".
This option is intended to be used to troubleshoot problems
with the
-.B --ifconfig
+.B \-\-ifconfig
and
-.B --ip-win32
+.B \-\-ip-win32
options, and is used to give
the TAP-Win32 adapter time to come up before
Windows IP Helper API operations are applied to it.
.\"*********************************************************
.TP
-.B --show-net-up
+.B \-\-show-net-up
Output OpenVPN's view of the system routing table and network
adapter list to the syslog or log file after the TUN/TAP adapter
has been brought up and any routes have been added.
.\"*********************************************************
.TP
-.B --dhcp-renew
+.B \-\-dhcp-renew
Ask Windows to renew the TAP adapter lease on startup.
This option is normally unnecessary, as Windows automatically
triggers a DHCP renegotiation on the TAP adapter when it
@@ -4853,28 +4929,28 @@ Media Status property to "Always Connected", you may need this
flag.
.\"*********************************************************
.TP
-.B --dhcp-release
+.B \-\-dhcp-release
Ask Windows to release the TAP adapter lease on shutdown.
This option has the same caveats as
-.B --dhcp-renew
+.B \-\-dhcp-renew
above.
.\"*********************************************************
.TP
-.B --register-dns
+.B \-\-register-dns
Run net stop dnscache, net start dnscache, ipconfig /flushdns
and ipconfig /registerdns on connection initiation.
This is known to kick Windows into
recognizing pushed DNS servers.
.\"*********************************************************
.TP
-.B --pause-exit
+.B \-\-pause-exit
Put up a "press any key to continue" message on the console prior
to OpenVPN program exit. This option is automatically used by the
Windows explorer when OpenVPN is run on a configuration
file using the right-click explorer menu.
.\"*********************************************************
.TP
-.B --service exit-event [0|1]
+.B \-\-service exit-event [0|1]
Should be used when OpenVPN is being automatically executed by another
program in such
a context that no interaction with the user via display or keyboard
@@ -4897,26 +4973,26 @@ parameter. In any case, the controlling process can signal
causing all such OpenVPN processes to exit.
When executing an OpenVPN process using the
-.B --service
+.B \-\-service
directive, OpenVPN will probably not have a console
window to output status/error
messages, therefore it is useful to use
-.B --log
+.B \-\-log
or
-.B --log-append
+.B \-\-log-append
to write these messages to a file.
.\"*********************************************************
.TP
-.B --show-adapters
+.B \-\-show-adapters
(Standalone)
Show available TAP-Win32 adapters which can be selected using the
-.B --dev-node
+.B \-\-dev-node
option. On non-Windows systems, the
.BR ifconfig (8)
command provides similar functionality.
.\"*********************************************************
.TP
-.B --allow-nonadmin [TAP-adapter]
+.B \-\-allow-nonadmin [TAP-adapter]
(Standalone)
Set
.B TAP-adapter
@@ -4931,10 +5007,10 @@ and reloaded.
This directive can only be used by an administrator.
.\"*********************************************************
.TP
-.B --show-valid-subnets
+.B \-\-show-valid-subnets
(Standalone)
Show valid subnets for
-.B --dev tun
+.B \-\-dev tun
emulation. Since the TAP-Win32 driver
exports an ethernet interface to Windows, and since TUN devices are
point-to-point in nature, it is necessary for the TAP-Win32 driver
@@ -4944,7 +5020,7 @@ Namely, the point-to-point endpoints used in TUN device emulation
must be the middle two addresses of a /30 subnet (netmask 255.255.255.252).
.\"*********************************************************
.TP
-.B --show-net
+.B \-\-show-net
(Standalone)
Show OpenVPN's view of the system routing table and network
adapter list.
@@ -4952,14 +5028,65 @@ adapter list.
.SS PKCS#11 Standalone Options:
.\"*********************************************************
.TP
-.B --show-pkcs11-ids provider [cert_private]
+.B \-\-show-pkcs11-ids provider [cert_private]
(Standalone)
Show PKCS#11 token object list. Specify cert_private as 1
if certificates are stored as private objects.
-.B --verb
+.B \-\-verb
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.
+.TP
+.B --ifconfig-ipv6 ipv6addr/bits ipv6remote
+configure IPv6 address
+.B ipv6addr/bits
+on the ``tun'' device. The second parameter is used as route target for
+.B --route-ipv6
+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
+.TP
+.B --server-ipv6 ipv6addr/bits
+convenience-function to enable a number of IPv6 related options at
+once, namely
+.B --ifconfig-ipv6, --ifconfig-ipv6-pool, --tun-ipv6
+and
+.B --push tun-ipv6
+Is only accepted if ``--mode server'' or ``--server'' is set.
+.TP
+.B --ifconfig-ipv6-pool ipv6addr/bits
+Specify an IPv6 address pool for dynamic assignment to clients. The
+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.
+.TP
+.B --ifconfig-ipv6-push ipv6addr/bits ipv6remote
+for ccd/ per-client static IPv6 interface configuration, see
+.B --client-config-dir
+and
+.B --ifconfig-push
+for more details.
+.TP
+.B --iroute-ipv6 ipv6addr/bits
+for ccd/ per-client static IPv6 route configuration, see
+.B --iroute
+for more details how to setup and use this, and how
+.B --iroute
+and
+.B --route
+interact.
+
+.\"*********************************************************
.SH SCRIPTING AND ENVIRONMENTAL VARIABLES
OpenVPN exports a series
of environmental variables for use by user-defined scripts.
@@ -4967,52 +5094,52 @@ of environmental variables for use by user-defined scripts.
.SS Script Order of Execution
.\"*********************************************************
.TP
-.B --up
+.B \-\-up
Executed after TCP/UDP socket bind and TUN/TAP open.
.\"*********************************************************
.TP
-.B --tls-verify
+.B \-\-tls-verify
Executed when we have a still untrusted remote peer.
.\"*********************************************************
.TP
-.B --ipchange
+.B \-\-ipchange
Executed after connection authentication, or remote IP address change.
.\"*********************************************************
.TP
-.B --client-connect
+.B \-\-client-connect
Executed in
-.B --mode server
+.B \-\-mode server
mode immediately after client authentication.
.\"*********************************************************
.TP
-.B --route-up
+.B \-\-route-up
Executed after connection authentication, either
immediately after, or some number of seconds after
as defined by the
-.B --route-delay
+.B \-\-route-delay
option.
.\"*********************************************************
.TP
-.B --client-disconnect
+.B \-\-client-disconnect
Executed in
-.B --mode server
+.B \-\-mode server
mode on client instance shutdown.
.\"*********************************************************
.TP
-.B --down
+.B \-\-down
Executed after TCP/UDP and TUN/TAP close.
.\"*********************************************************
.TP
-.B --learn-address
+.B \-\-learn-address
Executed in
-.B --mode server
+.B \-\-mode server
mode whenever an IPv4 address/route or MAC address is added to OpenVPN's
internal routing table.
.\"*********************************************************
.TP
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
Executed in
-.B --mode server
+.B \-\-mode server
mode on new client connections, when the client is
still untrusted.
.\"*********************************************************
@@ -5036,7 +5163,7 @@ Can string remapping be disabled?
.B A:
Yes, by using the
-.B --no-name-remapping
+.B \-\-no-name-remapping
option, however this should be considered an advanced option.
Here is a brief rundown of OpenVPN's current string types and the
@@ -5052,17 +5179,17 @@ true.
Alphanumeric, underbar ('_'), dash ('-'), dot ('.'), and at
('@').
-.B --auth-user-pass username:
+.B \-\-auth-user-pass username:
Same as Common Name, with one exception: starting with OpenVPN 2.0.1,
the username is passed to the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY plugin in its raw form,
without string remapping.
-.B --auth-user-pass password:
+.B \-\-auth-user-pass password:
Any "printable" character except CR or LF.
Printable is defined to be a character which will cause the C library
isprint() function to return true.
-.B --client-config-dir filename as derived from common name or username:
+.B \-\-client-config-dir filename as derived from common name or username:
Alphanumeric, underbar ('_'), dash ('-'), and dot ('.') except for "." or
".." as standalone strings. As of 2.0.1-rc6, the at ('@') character has
been added as well for compatibility with the common name character class.
@@ -5092,45 +5219,45 @@ which refer to different client instances.
.B bytes_received
Total number of bytes received from client during VPN session.
Set prior to execution of the
-.B --client-disconnect
+.B \-\-client-disconnect
script.
.\"*********************************************************
.TP
.B bytes_sent
Total number of bytes sent to client during VPN session.
Set prior to execution of the
-.B --client-disconnect
+.B \-\-client-disconnect
script.
.\"*********************************************************
.TP
.B common_name
The X509 common name of an authenticated client.
Set prior to execution of
-.B --client-connect, --client-disconnect,
+.B \-\-client-connect, \-\-client-disconnect,
and
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
scripts.
.\"*********************************************************
.TP
.B config
Name of first
-.B --config
+.B \-\-config
file.
Set on program initiation and reset on SIGHUP.
.\"*********************************************************
.TP
.B daemon
Set to "1" if the
-.B --daemon
+.B \-\-daemon
directive is specified, or "0" otherwise.
Set on program initiation and reset on SIGHUP.
.\"*********************************************************
.TP
.B daemon_log_redirect
Set to "1" if the
-.B --log
+.B \-\-log
or
-.B --log-append
+.B \-\-log-append
directives are specified, or "0" otherwise.
Set on program initiation and reset on SIGHUP.
.\"*********************************************************
@@ -5139,30 +5266,30 @@ Set on program initiation and reset on SIGHUP.
The actual name of the TUN/TAP device, including
a unit number if it exists.
Set prior to
-.B --up
+.B \-\-up
or
-.B --down
+.B \-\-down
script execution.
.\"*********************************************************
.TP
.B foreign_option_{n}
An option pushed via
-.B --push
+.B \-\-push
to a client which does not natively support it,
such as
-.B --dhcp-option
+.B \-\-dhcp-option
on a non-Windows system, will be recorded to this
environmental variable sequence prior to
-.B --up
+.B \-\-up
script execution.
.\"*********************************************************
.TP
.B ifconfig_broadcast
The broadcast address for the virtual
ethernet segment which is derived from the
-.B --ifconfig
+.B \-\-ifconfig
option when
-.B --dev tap
+.B \-\-dev tap
is used.
Set prior to OpenVPN calling the
.I ifconfig
@@ -5170,13 +5297,13 @@ or
.I netsh
(windows version of ifconfig) commands which
normally occurs prior to
-.B --up
+.B \-\-up
script execution.
.\"*********************************************************
.TP
.B ifconfig_local
The local VPN endpoint IP address specified in the
-.B --ifconfig
+.B \-\-ifconfig
option (first parameter).
Set prior to OpenVPN calling the
.I ifconfig
@@ -5184,15 +5311,15 @@ or
.I netsh
(windows version of ifconfig) commands which
normally occurs prior to
-.B --up
+.B \-\-up
script execution.
.\"*********************************************************
.TP
.B ifconfig_remote
The remote VPN endpoint IP address specified in the
-.B --ifconfig
+.B \-\-ifconfig
option (second parameter) when
-.B --dev tun
+.B \-\-dev tun
is used.
Set prior to OpenVPN calling the
.I ifconfig
@@ -5200,16 +5327,16 @@ or
.I netsh
(windows version of ifconfig) commands which
normally occurs prior to
-.B --up
+.B \-\-up
script execution.
.\"*********************************************************
.TP
.B ifconfig_netmask
The subnet mask of the virtual ethernet segment
that is specified as the second parameter to
-.B --ifconfig
+.B \-\-ifconfig
when
-.B --dev tap
+.B \-\-dev tap
is being used.
Set prior to OpenVPN calling the
.I ifconfig
@@ -5217,61 +5344,61 @@ or
.I netsh
(windows version of ifconfig) commands which
normally occurs prior to
-.B --up
+.B \-\-up
script execution.
.\"*********************************************************
.TP
.B ifconfig_pool_local_ip
The local
virtual IP address for the TUN/TAP tunnel taken from an
-.B --ifconfig-push
+.B \-\-ifconfig-push
directive if specified, or otherwise from
the ifconfig pool (controlled by the
-.B --ifconfig-pool
+.B \-\-ifconfig-pool
config file directive).
Only set for
-.B --dev tun
+.B \-\-dev tun
tunnels.
This option is set on the server prior to execution
of the
-.B --client-connect
+.B \-\-client-connect
and
-.B --client-disconnect
+.B \-\-client-disconnect
scripts.
.\"*********************************************************
.TP
.B ifconfig_pool_netmask
The
virtual IP netmask for the TUN/TAP tunnel taken from an
-.B --ifconfig-push
+.B \-\-ifconfig-push
directive if specified, or otherwise from
the ifconfig pool (controlled by the
-.B --ifconfig-pool
+.B \-\-ifconfig-pool
config file directive).
Only set for
-.B --dev tap
+.B \-\-dev tap
tunnels.
This option is set on the server prior to execution
of the
-.B --client-connect
+.B \-\-client-connect
and
-.B --client-disconnect
+.B \-\-client-disconnect
scripts.
.\"*********************************************************
.TP
.B ifconfig_pool_remote_ip
The remote
virtual IP address for the TUN/TAP tunnel taken from an
-.B --ifconfig-push
+.B \-\-ifconfig-push
directive if specified, or otherwise from
the ifconfig pool (controlled by the
-.B --ifconfig-pool
+.B \-\-ifconfig-pool
config file directive).
This option is set on the server prior to execution
of the
-.B --client-connect
+.B \-\-client-connect
and
-.B --client-disconnect
+.B \-\-client-disconnect
scripts.
.\"*********************************************************
.TP
@@ -5279,31 +5406,31 @@ scripts.
The maximum packet size (not including the IP header)
of tunnel data in UDP tunnel transport mode.
Set prior to
-.B --up
+.B \-\-up
or
-.B --down
+.B \-\-down
script execution.
.\"*********************************************************
.TP
.B local
The
-.B --local
+.B \-\-local
parameter.
Set on program initiation and reset on SIGHUP.
.\"*********************************************************
.TP
.B local_port
The local port number, specified by
-.B --port
+.B \-\-port
or
-.B --lport.
+.B \-\-lport.
Set on program initiation and reset on SIGHUP.
.\"*********************************************************
.TP
.B password
The password provided by a connecting client.
Set prior to
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
script execution only when the
.B via-env
modifier is specified, and deleted from the environment
@@ -5312,23 +5439,23 @@ after the script returns.
.TP
.B proto
The
-.B --proto
+.B \-\-proto
parameter.
Set on program initiation and reset on SIGHUP.
.\"*********************************************************
.TP
.B remote_{n}
The
-.B --remote
+.B \-\-remote
parameter.
Set on program initiation and reset on SIGHUP.
.\"*********************************************************
.TP
.B remote_port_{n}
The remote port number, specified by
-.B --port
+.B \-\-port
or
-.B --rport.
+.B \-\-rport.
Set on program initiation and reset on SIGHUP.
.\"*********************************************************
.TP
@@ -5336,29 +5463,29 @@ Set on program initiation and reset on SIGHUP.
The pre-existing default IP gateway in the system routing
table.
Set prior to
-.B --up
+.B \-\-up
script execution.
.\"*********************************************************
.TP
.B route_vpn_gateway
The default gateway used by
-.B --route
+.B \-\-route
options, as specified in either the
-.B --route-gateway
+.B \-\-route-gateway
option or the second parameter to
-.B --ifconfig
+.B \-\-ifconfig
when
-.B --dev tun
+.B \-\-dev tun
is specified.
Set prior to
-.B --up
+.B \-\-up
script execution.
.\"*********************************************************
.TP
.B route_{parm}_{n}
A set of variables which define each route to be added, and
are set prior to
-.B --up
+.B \-\-up
script execution.
.B parm
@@ -5373,35 +5500,40 @@ than their names as denoted on the command line
or configuration file.
.\"*********************************************************
.TP
+.B peer_cert
+Temporary file name containing the client certificate upon
+connection. Useful in conjunction with --tls-verify
+.\"*********************************************************
+.TP
.B script_context
Set to "init" or "restart" prior to up/down script execution.
For more information, see
documentation for
-.B --up.
+.B \-\-up.
.\"*********************************************************
.TP
.B script_type
-One of
+Prior to execution of any script, this variable is set to the type of
+script being run. It can be one of the following:
.B up, down, ipchange, route-up, tls-verify, auth-user-pass-verify,
.B client-connect, client-disconnect,
or
.B learn-address.
-Set prior to execution of any script.
.\"*********************************************************
.TP
.B signal
The reason for exit or restart. Can be one of
.B sigusr1, sighup, sigterm, sigint, inactive
(controlled by
-.B --inactive
+.B \-\-inactive
option),
.B ping-exit
(controlled by
-.B --ping-exit
+.B \-\-ping-exit
option),
.B ping-restart
(controlled by
-.B --ping-restart
+.B \-\-ping-restart
option),
.B connection-reset
(triggered on TCP connection reset),
@@ -5415,7 +5547,7 @@ or
Client connection timestamp, formatted as a human-readable
time string.
Set prior to execution of the
-.B --client-connect
+.B \-\-client-connect
script.
.\"*********************************************************
.TP
@@ -5423,7 +5555,7 @@ script.
The duration (in seconds) of the client session which is now
disconnecting.
Set prior to execution of the
-.B --client-disconnect
+.B \-\-client-disconnect
script.
.\"*********************************************************
.TP
@@ -5431,7 +5563,7 @@ script.
Client connection timestamp, formatted as a unix integer
date/time value.
Set prior to execution of the
-.B --client-connect
+.B \-\-client-connect
script.
.\"*********************************************************
.TP
@@ -5441,7 +5573,7 @@ where
.B n
is the verification level. Only set for TLS connections. Set prior
to execution of
-.B --tls-verify
+.B \-\-tls-verify
script.
.\"*********************************************************
.TP
@@ -5451,65 +5583,76 @@ where
.B n
is the verification level. Only set for TLS connections. Set prior
to execution of
-.B --tls-verify
-script.
+.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
+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 tun_mtu
The MTU of the TUN/TAP device.
Set prior to
-.B --up
+.B \-\-up
or
-.B --down
+.B \-\-down
script execution.
.\"*********************************************************
.TP
-.B trusted_ip
+.B trusted_ip (or trusted_ip6)
Actual IP address of connecting client or peer which has been authenticated.
Set prior to execution of
-.B --ipchange, --client-connect,
+.B \-\-ipchange, \-\-client-connect,
and
-.B --client-disconnect
+.B \-\-client-disconnect
scripts.
+If using ipv6 endpoints (udp6, tcp6),
+.B trusted_ip6
+will be set instead.
.\"*********************************************************
.TP
.B trusted_port
Actual port number of connecting client or peer which has been authenticated.
Set prior to execution of
-.B --ipchange, --client-connect,
+.B \-\-ipchange, \-\-client-connect,
and
-.B --client-disconnect
+.B \-\-client-disconnect
scripts.
.\"*********************************************************
.TP
-.B untrusted_ip
+.B untrusted_ip (or untrusted_ip6)
Actual IP address of connecting client or peer which has not been authenticated
yet. Sometimes used to
.B nmap
the connecting host in a
-.B --tls-verify
+.B \-\-tls-verify
script to ensure it is firewalled properly.
Set prior to execution of
-.B --tls-verify
+.B \-\-tls-verify
and
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
scripts.
+If using ipv6 endpoints (udp6, tcp6),
+.B untrusted_ip6
+will be set instead.
.\"*********************************************************
.TP
.B untrusted_port
Actual port number of connecting client or peer which has not been authenticated
yet.
Set prior to execution of
-.B --tls-verify
+.B \-\-tls-verify
and
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
scripts.
.\"*********************************************************
.TP
.B username
The username provided by a connecting client.
Set prior to
-.B --auth-user-pass-verify
+.B \-\-auth-user-pass-verify
script execution only when the
.B via-env
modifier is specified.
@@ -5521,7 +5664,7 @@ where
.B n
is the verification level. Only set for TLS connections. Set prior
to execution of
-.B --tls-verify
+.B \-\-tls-verify
script. This variable is similar to
.B tls_id_{n}
except the component X509 subject fields are broken out, and
@@ -5565,30 +5708,30 @@ Like
except don't re-read configuration file, and possibly don't close and reopen TUN/TAP
device, re-read key files, preserve local IP address/port, or preserve most recently authenticated
remote IP address/port based on
-.B --persist-tun, --persist-key, --persist-local-ip,
+.B \-\-persist-tun, \-\-persist-key, \-\-persist-local-ip,
and
-.B --persist-remote-ip
+.B \-\-persist-remote-ip
options respectively (see above).
This signal may also be internally generated by a timeout condition, governed
by the
-.B --ping-restart
+.B \-\-ping-restart
option.
This signal, when combined with
-.B --persist-remote-ip,
+.B \-\-persist-remote-ip,
may be
sent when the underlying parameters of the host's network interface change
such as when the host is a DHCP client and is assigned a new IP address.
See
-.B --ipchange
+.B \-\-ipchange
above for more information.
.\"*********************************************************
.TP
.B SIGUSR2
Causes OpenVPN to display its current statistics (to the syslog
file if
-.B --daemon
+.B \-\-daemon
is used, or stdout otherwise).
.\"*********************************************************
.TP
@@ -5643,7 +5786,7 @@ If firewalls exist between
the two machines, they should be set to forward UDP port 1194
in both directions. If you do not have control over the firewalls
between the two machines, you may still be able to use OpenVPN by adding
-.B --ping 15
+.B \-\-ping 15
to each of the
.B openvpn
commands used below in the examples (this will cause each peer to send out
@@ -5712,11 +5855,11 @@ you will get a weird feedback loop.
.LP
On may:
.IP
-.B openvpn --remote june.kg --dev tun1 --ifconfig 10.4.0.1 10.4.0.2 --verb 9
+.B openvpn \-\-remote june.kg \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-verb 9
.LP
On june:
.IP
-.B openvpn --remote may.kg --dev tun1 --ifconfig 10.4.0.2 10.4.0.1 --verb 9
+.B openvpn \-\-remote may.kg \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-verb 9
.LP
Now verify the tunnel is working by pinging across the tunnel.
.LP
@@ -5729,17 +5872,17 @@ On june:
.B ping 10.4.0.1
.LP
The
-.B --verb 9
+.B \-\-verb 9
option will produce verbose output, similar to the
.BR tcpdump (8)
program. Omit the
-.B --verb 9
+.B \-\-verb 9
option to have OpenVPN run quietly.
.\"*********************************************************
.SS Example 2: A tunnel with static-key security (i.e. using a pre-shared secret)
First build a static key on may.
.IP
-.B openvpn --genkey --secret key
+.B openvpn \-\-genkey \-\-secret key
.LP
This command will build a random key file called
.B key
@@ -5753,11 +5896,11 @@ program.
.LP
On may:
.IP
-.B openvpn --remote june.kg --dev tun1 --ifconfig 10.4.0.1 10.4.0.2 --verb 5 --secret key
+.B openvpn \-\-remote june.kg \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-verb 5 \-\-secret key
.LP
On june:
.IP
-.B openvpn --remote may.kg --dev tun1 --ifconfig 10.4.0.2 10.4.0.1 --verb 5 --secret key
+.B openvpn \-\-remote may.kg \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-verb 5 \-\-secret key
.LP
Now verify the tunnel is working by pinging across the tunnel.
.LP
@@ -5779,10 +5922,10 @@ as the TLS server.
First, build a separate certificate/key pair
for both may and june (see above where
-.B --cert
+.B \-\-cert
is discussed for more info). Then construct
Diffie Hellman parameters (see above where
-.B --dh
+.B \-\-dh
is discussed for more info). You can also use the
included test files client.crt, client.key,
server.crt, server.key and ca.crt.
@@ -5795,11 +5938,11 @@ parameters you can use the included file dh1024.pem.
.LP
On may:
.IP
-.B openvpn --remote june.kg --dev tun1 --ifconfig 10.4.0.1 10.4.0.2 --tls-client --ca ca.crt --cert client.crt --key client.key --reneg-sec 60 --verb 5
+.B openvpn \-\-remote june.kg \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-tls-client \-\-ca ca.crt \-\-cert client.crt \-\-key client.key \-\-reneg-sec 60 \-\-verb 5
.LP
On june:
.IP
-.B openvpn --remote may.kg --dev tun1 --ifconfig 10.4.0.2 10.4.0.1 --tls-server --dh dh1024.pem --ca ca.crt --cert server.crt --key server.key --reneg-sec 60 --verb 5
+.B openvpn \-\-remote may.kg \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-tls-server \-\-dh dh1024.pem \-\-ca ca.crt \-\-cert server.crt \-\-key server.key \-\-reneg-sec 60 \-\-verb 5
.LP
Now verify the tunnel is working by pinging across the tunnel.
.LP
@@ -5812,16 +5955,16 @@ On june:
.B ping 10.4.0.1
.LP
Notice the
-.B --reneg-sec 60
+.B \-\-reneg-sec 60
option we used above. That tells OpenVPN to renegotiate
the data channel keys every minute.
Since we used
-.B --verb 5
+.B \-\-verb 5
above, you will see status information on each new key negotiation.
For production operations, a key renegotiation interval of 60 seconds
is probably too frequent. Omit the
-.B --reneg-sec 60
+.B \-\-reneg-sec 60
option to use OpenVPN's default key renegotiation interval of one hour.
.\"*********************************************************
.SS Routing:
@@ -5857,7 +6000,7 @@ over the secure tunnel (or vice versa).
In a production environment, you could put the route command(s)
in a shell script and execute with the
-.B --up
+.B \-\-up
option.
.\"*********************************************************
.SH FIREWALLS
@@ -5865,7 +6008,7 @@ OpenVPN's usage of a single UDP port makes it fairly firewall-friendly.
You should add an entry to your firewall rules to allow incoming OpenVPN
packets. On Linux 2.4+:
.IP
-.B iptables -A INPUT -p udp -s 1.2.3.4 --dport 1194 -j ACCEPT
+.B iptables -A INPUT -p udp -s 1.2.3.4 \-\-dport 1194 -j ACCEPT
.LP
This will allow incoming packets on UDP port 1194 (OpenVPN's default UDP port)
from an OpenVPN peer at 1.2.3.4.
@@ -5876,7 +6019,7 @@ address can be considered optional, since HMAC packet authentication
is a much more secure method of verifying the authenticity of
a packet source. In that case:
.IP
-.B iptables -A INPUT -p udp --dport 1194 -j ACCEPT
+.B iptables -A INPUT -p udp \-\-dport 1194 -j ACCEPT
.LP
would be adequate and would not render the host inflexible with
respect to its peer having a dynamic IP address.
@@ -5885,7 +6028,7 @@ OpenVPN also works well on stateful firewalls. In some cases, you may
not need to add any static rules to the firewall list if you are
using a stateful firewall that knows how to track UDP connections.
If you specify
-.B --ping n,
+.B \-\-ping n,
OpenVPN will be guaranteed
to send a packet to its peer at least once every
.B n
diff --git a/openvpn.h b/openvpn.h
index 0ee439c..33661df 100644
--- a/openvpn.h
+++ b/openvpn.h
@@ -165,6 +165,9 @@ struct context_1
/* list of --route directives */
struct route_list *route_list;
+ /* list of --route-ipv6 directives */
+ struct route_ipv6_list *route_ipv6_list;
+
/* --status file */
struct status_output *status_output;
bool status_output_owned;
@@ -421,6 +424,11 @@ struct context_2
in_addr_t push_ifconfig_local_alias;
#endif
+ bool push_ifconfig_ipv6_defined;
+ struct in6_addr push_ifconfig_ipv6_local;
+ int push_ifconfig_ipv6_netbits;
+ struct in6_addr push_ifconfig_ipv6_remote;
+
/* client authentication state, CAS_SUCCEEDED must be 0 */
# define CAS_SUCCEEDED 0
# define CAS_PENDING 1
@@ -465,9 +473,6 @@ struct context
/* true on initial VPN iteration */
bool first_time;
- /* used by multi-client code to lock the context */
- /*MUTEX_DEFINE (mutex);*/
-
/* context modes */
# define CM_P2P 0 /* standalone point-to-point session or client */
# define CM_TOP 1 /* top level of a multi-client or point-to-multipoint server */
diff --git a/options.c b/options.c
index df7546c..f643acc 100644
--- a/options.c
+++ b/options.c
@@ -7,6 +7,9 @@
*
* 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
+ *
* 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.
@@ -46,6 +49,9 @@
#include "helper.h"
#include "manage.h"
#include "forward.h"
+#include "configure.h"
+#include "forward.h"
+#include <ctype.h>
#include "memdbg.h"
@@ -68,12 +74,19 @@ const char title_string[] =
#ifdef PRODUCT_TAP_DEBUG
" [TAPDBG]"
#endif
-#ifdef USE_PTHREAD
- " [PTHREAD]"
-#endif
#ifdef ENABLE_PKCS11
" [PKCS11]"
#endif
+#ifdef ENABLE_EUREPHIA
+ " [eurephia]"
+#endif
+#if ENABLE_IP_PKTINFO
+ " [MH]"
+#endif
+#ifdef USE_PF_INET6
+ " [PF_INET6]"
+#endif
+ " [IPv6 payload 20110424-2 (2.2RC2)]"
" built on " __DATE__
;
@@ -96,6 +109,9 @@ static const char usage_message[] =
"--proto p : Use protocol p for communicating with peer.\n"
" p = udp (default), tcp-server, or tcp-client\n"
"--proto-force p : only consider protocol p in list of connection profiles.\n"
+#ifdef USE_PF_INET6
+ " p = udp6, tcp6-server, or tcp6-client (ipv6)\n"
+#endif
"--connect-retry n : For --proto tcp-client, number of seconds to wait\n"
" between connection retries (default=%d).\n"
"--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\n"
@@ -121,8 +137,11 @@ static const char usage_message[] =
" AGENT user-agent\n"
#endif
#ifdef ENABLE_SOCKS
- "--socks-proxy s [p]: Connect to remote host through a Socks5 proxy at address\n"
- " s and port p (default port = 1080).\n"
+ "--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"
@@ -163,6 +182,8 @@ static const char usage_message[] =
" addresses outside of the subnets used by either peer.\n"
" TAP: configure device to use IP address l as a local\n"
" endpoint and rn as a subnet mask.\n"
+ "--ifconfig-ipv6 l r : configure device to use IPv6 address l as local\n"
+ " endpoint (as a /64) and r as remote endpoint\n"
"--ifconfig-noexec : Don't actually execute ifconfig/netsh command, instead\n"
" pass --ifconfig parms by environment to scripts.\n"
"--ifconfig-nowarn : Don't warn if the --ifconfig option on this side of the\n"
@@ -173,6 +194,10 @@ static const char usage_message[] =
" netmask default: 255.255.255.255\n"
" gateway default: taken from --route-gateway or --ifconfig\n"
" Specify default by leaving blank or setting to \"nil\".\n"
+ "--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"
"--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n"
@@ -292,13 +317,6 @@ static const char usage_message[] =
"--suppress-timestamps : Don't log timestamps to stdout/stderr.\n"
"--writepid file : Write main process ID to file.\n"
"--nice n : Change process priority (>0 = lower, <0 = higher).\n"
-#if 0
-#ifdef USE_PTHREAD
- "--nice-work n : Change thread priority of work thread. The work\n"
- " thread is used for background processing such as\n"
- " RSA key number crunching.\n"
-#endif
-#endif
"--echo [parms ...] : Echo parameters to log output.\n"
"--verb n : Set output verbosity to n (default=%d):\n"
" (Level 3 is recommended if you want a good summary\n"
@@ -372,6 +390,7 @@ static const char usage_message[] =
"\n"
"Multi-Client Server options (when --mode server is used):\n"
"--server network netmask : Helper option to easily configure server mode.\n"
+ "--server-ipv6 network/bits : Configure IPv6 server mode.\n"
"--server-bridge [IP netmask pool-start-IP pool-end-IP] : Helper option to\n"
" easily configure ethernet bridging server mode.\n"
"--push \"option\" : Push a config file option back to the peer for remote\n"
@@ -385,10 +404,16 @@ static const char usage_message[] =
"--ifconfig-pool-persist file [seconds] : Persist/unpersist ifconfig-pool\n"
" data to file, at seconds intervals (default=600).\n"
" If seconds=0, file will be treated as read-only.\n"
+ "--ifconfig-ipv6-pool base-IP/bits : set aside an IPv6 network block\n"
+ " to be dynamically allocated to connecting clients.\n"
"--ifconfig-push local remote-netmask : Push an ifconfig option to remote,\n"
" overrides --ifconfig-pool dynamic allocation.\n"
" Only valid in a client-specific config file.\n"
+ "--ifconfig-ipv6-push local/bits remote : Push an ifconfig-ipv6 option to\n"
+ " remote, overrides --ifconfig-ipv6-pool allocation.\n"
+ " Only valid in a client-specific config file.\n"
"--iroute network [netmask] : Route subnet to client.\n"
+ "--iroute-ipv6 network/bits : Route IPv6 subnet to client.\n"
" Sets up internal routes only.\n"
" Only valid in a client-specific config file.\n"
"--disable : Client is disabled.\n"
@@ -415,7 +440,7 @@ static const char usage_message[] =
"--client-disconnect cmd : Run script cmd on client disconnection.\n"
"--client-config-dir dir : Directory for custom client config files.\n"
"--ccd-exclusive : Refuse connection unless custom client config is found.\n"
- "--tmp-dir dir : Temporary directory, used for --client-connect return file.\n"
+ "--tmp-dir dir : Temporary directory, used for --client-connect return file and plugin communication.\n"
"--hash-size r v : Set the size of the real address hash table to r and the\n"
" virtual address table to v.\n"
"--bcast-buffers n : Allocate n broadcast buffers.\n"
@@ -511,6 +536,10 @@ static const char usage_message[] =
"--key file : Local private key in .pem format.\n"
"--pkcs12 file : PKCS#12 file containing local private key, local certificate\n"
" and optionally the root CA certificate.\n"
+#ifdef ENABLE_X509ALTUSERNAME
+ "--x509-username-field : Field used in x509 certificat to be username.\n"
+ " Default is CN.\n"
+#endif
"--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n"
#ifdef WIN32
"--cryptoapicert select-string : Load the certificate and private key from the\n"
@@ -542,6 +571,9 @@ static const char usage_message[] =
" tests of certification. cmd should return 0 to allow\n"
" TLS handshake to proceed, or 1 to fail. (cmd is\n"
" executed as 'cmd certificate_depth X509_NAME_oneline')\n"
+ "--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"
" of verification.\n"
@@ -733,9 +765,6 @@ init_options (struct options *o, const bool init_gc)
o->tuntap_options.dhcp_masq_offset = 0; /* use network address as internal DHCP server address */
o->route_method = ROUTE_METHOD_ADAPTIVE;
#endif
-#ifdef USE_PTHREAD
- o->n_threads = 1;
-#endif
#if P2MP_SERVER
o->real_hash_size = 256;
o->virtual_hash_size = 256;
@@ -767,11 +796,26 @@ init_options (struct options *o, const bool init_gc)
o->renegotiate_seconds = 3600;
o->handshake_window = 60;
o->transition_window = 3600;
+#ifdef ENABLE_X509ALTUSERNAME
+ o->x509_username_field = X509_USERNAME_FIELD_DEFAULT;
#endif
-#endif
+#endif /* USE_SSL */
+#endif /* USE_CRYPTO */
#ifdef ENABLE_PKCS11
o->pkcs11_pin_cache_period = -1;
#endif /* ENABLE_PKCS11 */
+
+ /* Set default --tmp-dir */
+#ifdef WIN32
+ /* On Windows, find temp dir via enviroment variables */
+ o->tmp_dir = win_get_tempdir();
+#else
+ /* Non-windows platforms use $TMPDIR, and if not set, default to '/tmp' */
+ o->tmp_dir = getenv("TMPDIR");
+ if( !o->tmp_dir ) {
+ o->tmp_dir = "/tmp";
+ }
+#endif /* WIN32 */
}
void
@@ -859,6 +903,78 @@ get_ip_addr (const char *ip_string, int msglevel, bool *error)
return ret;
}
+/* helper: parse a text string containing an IPv6 address + netbits
+ * in "standard format" (2001:dba::/32)
+ * "/nn" is optional, default to /64 if missing
+ *
+ * return true if parsing succeeded, modify *network and *netbits
+ * return address part without "/nn" in *printable_ipv6 (if != NULL)
+ */
+bool
+get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
+ unsigned int * netbits, char ** printable_ipv6, int msglevel )
+{
+ int rc;
+ char * sep, * endp;
+ int bits;
+ struct in6_addr t_network;
+
+ sep = strchr( prefix_str, '/' );
+ if ( sep == NULL )
+ {
+ bits = 64;
+ }
+ else
+ {
+ bits = strtol( sep+1, &endp, 10 );
+ if ( *endp != '\0' || bits < 0 || bits > 128 )
+ {
+ msg (msglevel, "IPv6 prefix '%s': invalid '/bits' spec", prefix_str);
+ return false;
+ }
+ }
+
+ /* temporary replace '/' in caller-provided string with '\0', otherwise
+ * inet_pton() will refuse prefix string
+ * (alternative would be to strncpy() the prefix to temporary buffer)
+ */
+
+ if ( sep != NULL ) *sep = '\0';
+
+ rc = inet_pton( AF_INET6, prefix_str, &t_network );
+
+ if ( rc == 1 && printable_ipv6 != NULL )
+ {
+ *printable_ipv6 = string_alloc( prefix_str, NULL );
+ }
+
+ if ( sep != NULL ) *sep = '/';
+
+ if ( rc != 1 )
+ {
+ msg (msglevel, "IPv6 prefix '%s': invalid IPv6 address", prefix_str);
+ return false;
+ }
+
+ if ( netbits != NULL )
+ {
+ *netbits = bits;
+ }
+ if ( network != NULL )
+ {
+ *network = t_network;
+ }
+ return true; /* parsing OK, values set */
+}
+
+static bool ipv6_addr_safe_hexplusbits( const char * ipv6_prefix_spec )
+{
+ struct in6_addr t_addr;
+ unsigned int t_bits;
+
+ return get_ipv6_addr( ipv6_prefix_spec, &t_addr, &t_bits, NULL, M_WARN );
+}
+
static char *
string_substitute (const char *src, int from, int to, struct gc_arena *gc)
{
@@ -884,9 +1000,6 @@ is_persist_option (const struct options *o)
|| o->persist_key
|| o->persist_local_ip
|| o->persist_remote_ip
-#ifdef USE_PTHREAD
- || o->n_threads >= 2
-#endif
;
}
@@ -1014,6 +1127,8 @@ show_p2mp_parms (const struct options *o)
#if P2MP_SERVER
msg (D_SHOW_PARMS, " server_network = %s", print_in_addr_t (o->server_network, 0, &gc));
msg (D_SHOW_PARMS, " server_netmask = %s", print_in_addr_t (o->server_netmask, 0, &gc));
+ msg (D_SHOW_PARMS, " server_network_ipv6 = %s", print_in6_addr (o->server_network_ipv6, 0, &gc) );
+ SHOW_INT (server_netbits_ipv6);
msg (D_SHOW_PARMS, " server_bridge_ip = %s", print_in_addr_t (o->server_bridge_ip, 0, &gc));
msg (D_SHOW_PARMS, " server_bridge_netmask = %s", print_in_addr_t (o->server_bridge_netmask, 0, &gc));
msg (D_SHOW_PARMS, " server_bridge_pool_start = %s", print_in_addr_t (o->server_bridge_pool_start, 0, &gc));
@@ -1034,6 +1149,9 @@ show_p2mp_parms (const struct options *o)
msg (D_SHOW_PARMS, " ifconfig_pool_netmask = %s", print_in_addr_t (o->ifconfig_pool_netmask, 0, &gc));
SHOW_STR (ifconfig_pool_persist_filename);
SHOW_INT (ifconfig_pool_persist_refresh_freq);
+ SHOW_BOOL (ifconfig_ipv6_pool_defined);
+ msg (D_SHOW_PARMS, " ifconfig_ipv6_pool_base = %s", print_in6_addr (o->ifconfig_ipv6_pool_base, 0, &gc));
+ SHOW_INT (ifconfig_ipv6_pool_netbits);
SHOW_INT (n_bcast_buf);
SHOW_INT (tcp_queue_limit);
SHOW_INT (real_hash_size);
@@ -1047,6 +1165,9 @@ show_p2mp_parms (const struct options *o)
SHOW_BOOL (push_ifconfig_defined);
msg (D_SHOW_PARMS, " push_ifconfig_local = %s", print_in_addr_t (o->push_ifconfig_local, 0, &gc));
msg (D_SHOW_PARMS, " push_ifconfig_remote_netmask = %s", print_in_addr_t (o->push_ifconfig_remote_netmask, 0, &gc));
+ SHOW_BOOL (push_ifconfig_ipv6_defined);
+ msg (D_SHOW_PARMS, " push_ifconfig_ipv6_local = %s/%d", print_in6_addr (o->push_ifconfig_ipv6_local, 0, &gc), o->push_ifconfig_ipv6_netbits );
+ msg (D_SHOW_PARMS, " push_ifconfig_ipv6_remote = %s", print_in6_addr (o->push_ifconfig_ipv6_remote, 0, &gc));
SHOW_BOOL (enable_c2c);
SHOW_BOOL (duplicate_cn);
SHOW_INT (cf_max);
@@ -1100,6 +1221,25 @@ option_iroute (struct options *o,
o->iroutes = ir;
}
+static void
+option_iroute_ipv6 (struct options *o,
+ const char *prefix_str,
+ int msglevel)
+{
+ struct iroute_ipv6 *ir;
+
+ ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc);
+
+ if ( get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, NULL, msglevel ) < 0 )
+ {
+ msg (msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification",
+ prefix_str);
+ return;
+ }
+
+ ir->next = o->iroutes_ipv6;
+ o->iroutes_ipv6 = ir;
+}
#endif /* P2MP_SERVER */
#endif /* P2MP */
@@ -1140,6 +1280,13 @@ rol_check_alloc (struct options *options)
options->routes = new_route_option_list (options->max_routes, &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);
+}
+
#ifdef ENABLE_CLIENT_NAT
static void
cnol_check_alloc (struct options *options)
@@ -1239,6 +1386,9 @@ show_settings (const struct options *o)
SHOW_STR (ifconfig_remote_netmask);
SHOW_BOOL (ifconfig_noexec);
SHOW_BOOL (ifconfig_nowarn);
+ SHOW_STR (ifconfig_ipv6_local);
+ SHOW_INT (ifconfig_ipv6_netbits);
+ SHOW_STR (ifconfig_ipv6_remote);
#ifdef HAVE_GETTIMEOFDAY
SHOW_INT (shaper);
@@ -1395,6 +1545,7 @@ show_settings (const struct options *o)
#endif
SHOW_STR (cipher_list);
SHOW_STR (tls_verify);
+ SHOW_STR (tls_export_cert);
SHOW_STR (tls_remote);
SHOW_STR (crl_file);
SHOW_INT (ns_cert_type);
@@ -1748,11 +1899,27 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
* Sanity check on TCP mode options
*/
- if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT)
- msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client");
+ if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT
+#ifdef USE_PF_INET6
+ && ce->proto != PROTO_TCPv6_CLIENT
+#endif
+ )
+ msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client"
+#ifdef USE_PF_INET6
+ " or tcp6-client"
+#endif
+ );
- if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT)
- msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with --proto tcp-client");
+ if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT
+#ifdef USE_PF_INET6
+ && ce->proto != PROTO_TCPv6_CLIENT
+#endif
+ )
+ msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with --proto tcp-client"
+#ifdef USE_PF_INET6
+ " or tcp6-client"
+#endif
+ );
/*
* Sanity check on MTU parameters
@@ -1761,7 +1928,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "only one of --tun-mtu or --link-mtu may be defined (note that --ifconfig implies --link-mtu %d)", LINK_MTU_DEFAULT);
#ifdef ENABLE_OCC
- if (ce->proto != PROTO_UDPv4 && options->mtu_test)
+ if (!proto_is_udp(ce->proto) && options->mtu_test)
msg (M_USAGE, "--mtu-test only makes sense with --proto udp");
#endif
@@ -1774,7 +1941,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
* Sanity check on --local, --remote, and --ifconfig
*/
- if (string_defined_equal (ce->local, ce->remote)
+ if (proto_is_net(ce->proto)
+ && string_defined_equal (ce->local, ce->remote)
&& ce->local_port == ce->remote_port)
msg (M_USAGE, "--remote and --local addresses are the same");
@@ -1839,16 +2007,20 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
*/
#ifdef ENABLE_FRAGMENT
- if (ce->proto != PROTO_UDPv4 && options->fragment)
+ if (!proto_is_udp(ce->proto) && options->fragment)
msg (M_USAGE, "--fragment can only be used with --proto udp");
#endif
#ifdef ENABLE_OCC
- if (ce->proto != PROTO_UDPv4 && options->explicit_exit_notification)
+ if (!proto_is_udp(ce->proto) && options->explicit_exit_notification)
msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp");
#endif
- if (!ce->remote && ce->proto == PROTO_TCPv4_CLIENT)
+ if (!ce->remote && (ce->proto == PROTO_TCPv4_CLIENT
+#ifdef USE_PF_INET6
+ || ce->proto == PROTO_TCPv6_CLIENT
+#endif
+ ))
msg (M_USAGE, "--remote MUST be used in TCP Client mode");
#ifdef ENABLE_HTTP_PROXY
@@ -1866,7 +2038,12 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode");
#endif
- if (ce->proto == PROTO_TCPv4_SERVER && connection_list_defined (options))
+ if ((ce->proto == PROTO_TCPv4_SERVER
+#ifdef USE_PF_INET6
+ || ce->proto == PROTO_TCPv6_SERVER
+#endif
+ )
+ && connection_list_defined (options))
msg (M_USAGE, "TCP server mode allows at most one --remote address");
#if P2MP_SERVER
@@ -1880,11 +2057,28 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--mode server only works with --dev tun or --dev tap");
if (options->pull)
msg (M_USAGE, "--pull cannot be used with --mode server");
- if (!(ce->proto == PROTO_UDPv4 || ce->proto == PROTO_TCPv4_SERVER))
- msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
+ if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCPv4_SERVER
+#ifdef USE_PF_INET6
+ || ce->proto == PROTO_TCPv6_SERVER
+#endif
+ ))
+ msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"
+#ifdef USE_PF_INET6
+ " or proto tcp6-server"
+#endif
+ );
#if PORT_SHARE
- if ((options->port_share_host || options->port_share_port) && ce->proto != PROTO_TCPv4_SERVER)
- msg (M_USAGE, "--port-share only works in TCP server mode (--proto tcp-server)");
+ if ((options->port_share_host || options->port_share_port) &&
+ (ce->proto != PROTO_TCPv4_SERVER
+#ifdef USE_PF_INET6
+ && ce->proto != PROTO_TCPv6_SERVER
+#endif
+ ))
+ msg (M_USAGE, "--port-share only works in TCP server mode (--proto tcp-server"
+#ifdef USE_PF_INET6
+ " or tcp6-server"
+#endif
+ ")");
#endif
if (!options->tls_server)
msg (M_USAGE, "--mode server requires --tls-server");
@@ -1904,17 +2098,27 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
if (options->connection_list)
msg (M_USAGE, "<connection> cannot be used with --mode server");
#endif
+#if 0
if (options->tun_ipv6)
msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server");
+#endif
if (options->shaper)
msg (M_USAGE, "--shaper cannot be used with --mode server");
if (options->inetd)
msg (M_USAGE, "--inetd cannot be used with --mode server");
if (options->ipchange)
msg (M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)");
- if (!(ce->proto == PROTO_UDPv4 || ce->proto == PROTO_TCPv4_SERVER))
- msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
- if (ce->proto != PROTO_UDPv4 && (options->cf_max || options->cf_per))
+ if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCPv4_SERVER
+#ifdef USE_PF_INET6
+ || ce->proto == PROTO_TCPv6_SERVER
+#endif
+ ))
+ msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server"
+#ifdef USE_PF_INET6
+ " or --proto tcp6-server"
+#endif
+ );
+ if (!proto_is_udp(ce->proto) && (options->cf_max || options->cf_per))
msg (M_USAGE, "--connect-freq only works with --mode server --proto udp. Try --max-clients instead.");
if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask)
msg (M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode");
@@ -1930,6 +2134,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--up-delay cannot be used with --mode server");
if (!options->ifconfig_pool_defined && options->ifconfig_pool_persist_filename)
msg (M_USAGE, "--ifconfig-pool-persist must be used with --ifconfig-pool");
+ if (options->ifconfig_ipv6_pool_defined && !options->ifconfig_ipv6_local )
+ msg (M_USAGE, "--ifconfig-ipv6-pool needs --ifconfig-ipv6");
+ if (options->ifconfig_ipv6_local && !options->tun_ipv6 )
+ msg (M_INFO, "Warning: --ifconfig-ipv6 without --tun-ipv6 will not do IPv6");
+
if (options->auth_user_pass_file)
msg (M_USAGE, "--auth-user-pass cannot be used with --mode server (it should be used on the client side only)");
if (options->ccd_exclusive && !options->client_config_dir)
@@ -1961,6 +2170,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
*/
if (options->ifconfig_pool_defined || options->ifconfig_pool_persist_filename)
msg (M_USAGE, "--ifconfig-pool/--ifconfig-pool-persist requires --mode server");
+ if (options->ifconfig_ipv6_pool_defined)
+ msg (M_USAGE, "--ifconfig-ipv6-pool requires --mode server");
if (options->real_hash_size != defaults.real_hash_size
|| options->virtual_hash_size != defaults.virtual_hash_size)
msg (M_USAGE, "--hash-size requires --mode server");
@@ -1970,8 +2181,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--client-connect requires --mode server");
if (options->client_disconnect_script)
msg (M_USAGE, "--client-disconnect requires --mode server");
- if (options->tmp_dir)
- msg (M_USAGE, "--tmp-dir requires --mode server");
if (options->client_config_dir || options->ccd_exclusive)
msg (M_USAGE, "--client-config-dir/--ccd-exclusive requires --mode server");
if (options->enable_c2c)
@@ -2007,7 +2216,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
/*
* Check consistency of replay options
*/
- if ((ce->proto != PROTO_UDPv4)
+ if ((!proto_is_udp(ce->proto))
&& (options->replay_window != defaults.replay_window
|| options->replay_time != defaults.replay_time))
msg (M_USAGE, "--replay-window only makes sense with --proto udp");
@@ -2124,6 +2333,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
MUST_BE_UNDEF (pkcs12_file);
MUST_BE_UNDEF (cipher_list);
MUST_BE_UNDEF (tls_verify);
+ MUST_BE_UNDEF (tls_export_cert);
MUST_BE_UNDEF (tls_remote);
MUST_BE_UNDEF (tls_timeout);
MUST_BE_UNDEF (renegotiate_bytes);
@@ -2179,6 +2389,10 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce)
{
if (ce->proto == PROTO_TCPv4)
ce->proto = PROTO_TCPv4_CLIENT;
+#ifdef USE_PF_INET6
+ else if (ce->proto == PROTO_TCPv6)
+ ce->proto = PROTO_TCPv6_CLIENT;
+#endif
}
#endif
@@ -2520,6 +2734,8 @@ options_string (const struct options *o,
o->topology,
o->ifconfig_local,
o->ifconfig_remote_netmask,
+ o->ifconfig_ipv6_local,
+ o->ifconfig_ipv6_remote,
(in_addr_t)0,
(in_addr_t)0,
false,
@@ -2987,6 +3203,14 @@ usage_version (void)
msg (M_INFO|M_NOPREFIX, "%s", title_string);
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
+#ifdef CONFIGURE_CALL
+ msg (M_INFO|M_NOPREFIX, "\n%s\n", CONFIGURE_CALL);
+#endif
+#ifdef CONFIGURE_DEFINES
+ msg (M_INFO|M_NOPREFIX, "Compile time defines: %s", CONFIGURE_DEFINES);
+#endif
+#endif
openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
}
@@ -3021,6 +3245,7 @@ positive_atoi (const char *str)
return i < 0 ? 0 : i;
}
+#ifdef WIN32 /* This function is only used when compiling on Windows */
static unsigned int
atou (const char *str)
{
@@ -3028,6 +3253,7 @@ atou (const char *str)
sscanf (str, "%u", &val);
return val;
}
+#endif
static inline bool
space (unsigned char c)
@@ -3569,6 +3795,15 @@ 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);
+ }
+}
+
+
+static void
add_option (struct options *options,
char *p[],
const char *file,
@@ -3846,6 +4081,30 @@ add_option (struct options *options,
goto err;
}
}
+ else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] )
+ {
+ unsigned int netbits;
+ char * ipv6_local;
+
+ VERIFY_PERMISSION (OPT_P_UP);
+ if ( get_ipv6_addr( p[1], NULL, &netbits, &ipv6_local, msglevel ) &&
+ ipv6_addr_safe( p[2] ) )
+ {
+ if ( netbits < 64 || netbits > 124 )
+ {
+ msg( msglevel, "ifconfig-ipv6: /netbits must be between 64 and 124, not '/%d'", netbits );
+ goto err;
+ }
+ options->ifconfig_ipv6_local = ipv6_local;
+ options->ifconfig_ipv6_netbits = netbits;
+ options->ifconfig_ipv6_remote = p[2];
+ }
+ else
+ {
+ msg (msglevel, "ifconfig-ipv6 parms '%s' and '%s' must be valid addresses", p[1], p[2]);
+ goto err;
+ }
+ }
else if (streq (p[0], "ifconfig-noexec"))
{
VERIFY_PERMISSION (OPT_P_UP);
@@ -3988,6 +4247,7 @@ 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);
}
else if (streq (p[0], "float"))
@@ -4034,6 +4294,7 @@ 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];
}
else if (streq (p[0], "down") && p[1])
@@ -4041,6 +4302,7 @@ 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->down_script, "down");
options->down_script = p[1];
}
else if (streq (p[0], "down-pre"))
@@ -4100,7 +4362,7 @@ add_option (struct options *options,
{
if (options->inetd != -1)
{
- msg (msglevel, opterr);
+ msg (msglevel, "%s", opterr);
goto err;
}
else
@@ -4110,7 +4372,7 @@ add_option (struct options *options,
{
if (options->inetd != -1)
{
- msg (msglevel, opterr);
+ msg (msglevel, "%s", opterr);
goto err;
}
else
@@ -4120,7 +4382,7 @@ add_option (struct options *options,
{
if (name != NULL)
{
- msg (msglevel, opterr);
+ msg (msglevel, "%s", opterr);
goto err;
}
name = p[z];
@@ -4296,26 +4558,6 @@ add_option (struct options *options,
goto err;
#endif
}
-#ifdef USE_PTHREAD
- else if (streq (p[0], "nice-work") && p[1])
- {
- VERIFY_PERMISSION (OPT_P_NICE);
- options->nice_work = atoi (p[1]);
- }
- else if (streq (p[0], "threads") && p[1])
- {
- int n_threads;
-
- VERIFY_PERMISSION (OPT_P_GENERAL);
- n_threads = positive_atoi (p[1]);
- if (n_threads < 1)
- {
- msg (msglevel, "--threads parameter must be at least 1");
- goto err;
- }
- options->n_threads = n_threads;
- }
-#endif
else if (streq (p[0], "shaper") && p[1])
{
#ifdef HAVE_GETTIMEOFDAY
@@ -4356,7 +4598,7 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
port = atoi (p[1]);
- if (!legal_ipv4_port (port))
+ if ((port != 0) && !legal_ipv4_port (port))
{
msg (msglevel, "Bad local port number: %s", p[1]);
goto err;
@@ -4569,6 +4811,7 @@ add_option (struct options *options,
options->ce.socks_proxy_port = 1080;
}
options->ce.socks_proxy_server = p[1];
+ options->ce.socks_proxy_authfile = p[3]; /* might be NULL */
}
else if (streq (p[0], "socks-proxy-retry"))
{
@@ -4670,6 +4913,26 @@ add_option (struct options *options,
}
add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]);
}
+ else if (streq (p[0], "route-ipv6") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_ROUTE);
+ rol6_check_alloc (options);
+ if (pull_mode)
+ {
+ if (!ipv6_addr_safe_hexplusbits (p[1]))
+ {
+ msg (msglevel, "route-ipv6 parameter network/IP '%s' must be a valid address", p[1]);
+ goto err;
+ }
+ if (p[2] && !ipv6_addr_safe (p[2]))
+ {
+ msg (msglevel, "route-ipv6 parameter gateway '%s' must be a valid address", p[2]);
+ goto err;
+ }
+ /* p[3] is metric, if present */
+ }
+ add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]);
+ }
else if (streq (p[0], "max-routes") && p[1])
{
int max_routes;
@@ -4730,6 +4993,7 @@ 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];
}
else if (streq (p[0], "route-noexec"))
@@ -4886,6 +5150,33 @@ add_option (struct options *options,
}
}
}
+ else if (streq (p[0], "server-ipv6") && p[1] )
+ {
+ const int lev = M_WARN;
+ struct in6_addr network;
+ unsigned int netbits = 0;
+
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev) )
+ {
+ msg (msglevel, "error parsing --server-ipv6 parameter");
+ goto err;
+ }
+ if ( netbits != 64 )
+ {
+ msg( msglevel, "--server-ipv6 settings: only /64 supported right now (not /%d)", netbits );
+ goto err;
+ }
+ options->server_ipv6_defined = true;
+ options->server_network_ipv6 = network;
+ options->server_netbits_ipv6 = netbits;
+
+ if (p[2]) /* no "nopool" options or similar for IPv6 */
+ {
+ msg (msglevel, "error parsing --server-ipv6: %s is not a recognized flag", p[3]);
+ goto err;
+ }
+ }
else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4])
{
const int lev = M_WARN;
@@ -4970,6 +5261,28 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
options->topology = TOP_P2P;
}
+ else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] )
+ {
+ const int lev = M_WARN;
+ struct in6_addr network;
+ unsigned int netbits = 0;
+
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev ) )
+ {
+ msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters");
+ goto err;
+ }
+ if ( netbits != 64 )
+ {
+ msg( msglevel, "--ifconfig-ipv6-pool settings: only /64 supported right now (not /%d)", netbits );
+ goto err;
+ }
+
+ options->ifconfig_ipv6_pool_defined = true;
+ options->ifconfig_ipv6_pool_base = network;
+ options->ifconfig_ipv6_pool_netbits = netbits;
+ }
else if (streq (p[0], "hash-size") && p[1] && p[2])
{
int real, virtual;
@@ -5065,6 +5378,7 @@ 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];
}
else if (streq (p[0], "client-connect") && p[1])
@@ -5072,6 +5386,7 @@ 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->client_connect_script, "client-connect");
options->client_connect_script = p[1];
}
else if (streq (p[0], "client-disconnect") && p[1])
@@ -5079,6 +5394,7 @@ 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->client_disconnect_script, "client-disconnect");
options->client_disconnect_script = p[1];
}
else if (streq (p[0], "learn-address") && p[1])
@@ -5086,6 +5402,7 @@ 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->learn_address_script, "learn-address");
options->learn_address_script = p[1];
}
else if (streq (p[0], "tmp-dir") && p[1])
@@ -5162,6 +5479,11 @@ add_option (struct options *options,
}
option_iroute (options, p[1], netmask, msglevel);
}
+ else if (streq (p[0], "iroute-ipv6") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_INSTANCE);
+ option_iroute_ipv6 (options, p[1], msglevel);
+ }
else if (streq (p[0], "ifconfig-push") && p[1] && p[2])
{
in_addr_t local, remote_netmask;
@@ -5204,6 +5526,43 @@ add_option (struct options *options,
goto err;
}
}
+ else if (streq (p[0], "ifconfig-ipv6-push") && p[1] )
+ {
+ struct in6_addr local, remote;
+ unsigned int netbits;
+
+ VERIFY_PERMISSION (OPT_P_INSTANCE);
+
+ if ( ! get_ipv6_addr( p[1], &local, &netbits, NULL, msglevel ) )
+ {
+ msg (msglevel, "cannot parse --ifconfig-ipv6-push addresses");
+ goto err;
+ }
+
+ if ( p[2] )
+ {
+ if ( !get_ipv6_addr( p[2], &remote, NULL, NULL, msglevel ) )
+ {
+ msg( msglevel, "cannot parse --ifconfig-ipv6-push addresses");
+ goto err;
+ }
+ }
+ else
+ {
+ if ( ! options->ifconfig_ipv6_local ||
+ ! get_ipv6_addr( options->ifconfig_ipv6_local, &remote,
+ NULL, NULL, msglevel ) )
+ {
+ msg( msglevel, "second argument to --ifconfig-ipv6-push missing and no global --ifconfig-ipv6 address set");
+ goto err;
+ }
+ }
+
+ options->push_ifconfig_ipv6_defined = true;
+ options->push_ifconfig_ipv6_local = local;
+ options->push_ifconfig_ipv6_netbits = netbits;
+ options->push_ifconfig_ipv6_remote = remote;
+ }
else if (streq (p[0], "disable"))
{
VERIFY_PERMISSION (OPT_P_INSTANCE);
@@ -5444,7 +5803,13 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_IPWIN32);
options->tuntap_options.register_dns = true;
}
- else if (streq (p[0], "rdns-internal")) /* standalone method for internal use */
+ else if (streq (p[0], "rdns-internal"))
+ /* standalone method for internal use
+ *
+ * (if --register-dns is set, openvpn needs to call itself in a
+ * sub-process to execute the required functions in a non-blocking
+ * way, and uses --rdns-internal to signal that to itself)
+ */
{
VERIFY_PERMISSION (OPT_P_GENERAL);
set_debug_level (options->verbosity, SDL_CONSTRAIN);
@@ -5897,8 +6262,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->tls_verify, "tls-verify");
options->tls_verify = string_substitute (p[1], ',', ' ', &options->gc);
}
+ else if (streq (p[0], "tls-export-cert") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->tls_export_cert = p[1];
+ }
else if (streq (p[0], "tls-remote") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -6024,6 +6395,16 @@ add_option (struct options *options,
}
options->key_method = key_method;
}
+#ifdef ENABLE_X509ALTUSERNAME
+ else if (streq (p[0], "x509-username-field") && p[1])
+ {
+ char *s = p[1];
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ if( strncmp ("ext:",s,4) != 0 )
+ while ((*s = toupper(*s)) != '\0') s++; /* Uppercase if necessary */
+ options->x509_username_field = p[1];
+ }
+#endif /* ENABLE_X509ALTUSERNAME */
#endif /* USE_SSL */
#endif /* USE_CRYPTO */
#ifdef ENABLE_PKCS11
diff --git a/options.h b/options.h
index 91ec6dc..a9c6a94 100644
--- a/options.h
+++ b/options.h
@@ -101,6 +101,7 @@ struct connection_entry
#ifdef ENABLE_SOCKS
const char *socks_proxy_server;
int socks_proxy_port;
+ const char *socks_proxy_authfile;
bool socks_proxy_retry;
#endif
@@ -210,6 +211,9 @@ struct options
int topology; /* one of the TOP_x values from proto.h */
const char *ifconfig_local;
const char *ifconfig_remote_netmask;
+ const char *ifconfig_ipv6_local;
+ int ifconfig_ipv6_netbits;
+ const char *ifconfig_ipv6_remote;
bool ifconfig_noexec;
bool ifconfig_nowarn;
#ifdef HAVE_GETTIMEOFDAY
@@ -331,6 +335,7 @@ struct options
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 */
@@ -364,17 +369,15 @@ struct options
struct plugin_option_list *plugin_list;
#endif
-#ifdef USE_PTHREAD
- int n_threads;
- int nice_work;
-#endif
-
#if P2MP
#if P2MP_SERVER
bool server_defined;
in_addr_t server_network;
in_addr_t server_netmask;
+ bool server_ipv6_defined; /* IPv6 */
+ struct in6_addr server_network_ipv6; /* IPv6 */
+ unsigned int server_netbits_ipv6; /* IPv6 */
# define SF_NOPOOL (1<<0)
# define SF_TCP_NODELAY_HELPER (1<<1)
@@ -396,6 +399,11 @@ struct options
in_addr_t ifconfig_pool_netmask;
const char *ifconfig_pool_persist_filename;
int ifconfig_pool_persist_refresh_freq;
+
+ bool ifconfig_ipv6_pool_defined; /* IPv6 */
+ struct in6_addr ifconfig_ipv6_pool_base; /* IPv6 */
+ int ifconfig_ipv6_pool_netbits; /* IPv6 */
+
int real_hash_size;
int virtual_hash_size;
const char *client_connect_script;
@@ -408,6 +416,7 @@ struct options
int n_bcast_buf;
int tcp_queue_limit;
struct iroute *iroutes;
+ struct iroute_ipv6 *iroutes_ipv6; /* IPv6 */
bool push_ifconfig_defined;
in_addr_t push_ifconfig_local;
in_addr_t push_ifconfig_remote_netmask;
@@ -417,6 +426,10 @@ struct options
bool push_ifconfig_constraint_defined;
in_addr_t push_ifconfig_constraint_network;
in_addr_t push_ifconfig_constraint_netmask;
+ bool push_ifconfig_ipv6_defined; /* IPv6 */
+ struct in6_addr push_ifconfig_ipv6_local; /* IPv6 */
+ int push_ifconfig_ipv6_netbits; /* IPv6 */
+ struct in6_addr push_ifconfig_ipv6_remote; /* IPv6 */
bool enable_c2c;
bool duplicate_cn;
int cf_max;
@@ -481,6 +494,7 @@ struct options
const char *pkcs12_file;
const char *cipher_list;
const char *tls_verify;
+ const char *tls_export_cert;
const char *tls_remote;
const char *crl_file;
@@ -528,6 +542,11 @@ struct options
within n seconds of handshake initiation. */
int handshake_window;
+#ifdef ENABLE_X509ALTUSERNAME
+ /* Field used to be the username in X509 cert. */
+ char *x509_username_field;
+#endif
+
/* Old key allowed to live n seconds after new key goes active */
int transition_window;
@@ -741,6 +760,10 @@ void options_string_import (struct options *options,
unsigned int *option_types_found,
struct env_set *es);
+bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
+ unsigned int * netbits, char ** printable_ipv6,
+ int msglevel );
+
/*
* inline functions
*/
diff --git a/otime.c b/otime.c
index dae0c0c..b295646 100644
--- a/otime.c
+++ b/otime.c
@@ -123,10 +123,8 @@ time_string (time_t t, int usec, bool show_usec, struct gc_arena *gc)
}
}
- mutex_lock_static (L_CTIME);
t = tv.tv_sec;
buf_printf (&out, "%s", ctime(&t));
- mutex_unlock_static (L_CTIME);
buf_rmtail (&out, '\n');
if (show_usec && tv.tv_usec)
diff --git a/otime.h b/otime.h
index 74597e3..fd73bbd 100644
--- a/otime.h
+++ b/otime.h
@@ -28,7 +28,6 @@
#include "common.h"
#include "integer.h"
#include "buffer.h"
-#include "thread.h"
struct frequency_limit
{
diff --git a/perf.c b/perf.c
index 475c699..d9dbafc 100644
--- a/perf.c
+++ b/perf.c
@@ -33,10 +33,6 @@
#include "memdbg.h"
-#ifdef USE_PTHREAD
-#error ENABLE_PERFORMANCE_METRICS is incompatible with USE_PTHREAD
-#endif
-
static const char *metric_names[] = {
"PERF_BIO_READ_PLAINTEXT",
"PERF_BIO_WRITE_PLAINTEXT",
@@ -291,5 +287,7 @@ perf_print_state (int lev)
}
#else
+#ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
static void dummy(void) {}
#endif
+#endif
diff --git a/pf.c b/pf.c
index a27de4b..8aae99c 100644
--- a/pf.c
+++ b/pf.c
@@ -109,6 +109,11 @@ add_subnet (const char *line, const char *prefix, const int line_num, struct pf_
return false;
}
netmask = netbits_to_netmask (netbits);
+ if ((network.s_addr & htonl (netmask)) != network.s_addr)
+ {
+ network.s_addr &= htonl (netmask);
+ msg (M_WARN, "WARNING: PF: %s/%d: incorrect subnet %s/%d changed to %s/%d", prefix, line_num, line, netbits, inet_ntoa (network), netbits);
+ }
}
else
{
@@ -554,24 +559,25 @@ pf_init_context (struct context *c)
#ifdef PLUGIN_PF
if (plugin_defined (c->plugins, OPENVPN_PLUGIN_ENABLE_PF))
{
- const char *pf_file = create_temp_filename (c->options.tmp_dir, "pf", &gc);
- delete_file (pf_file);
- setenv_str (c->c2.es, "pf_file", pf_file);
-
- if (plugin_call (c->plugins, OPENVPN_PLUGIN_ENABLE_PF, NULL, NULL, c->c2.es) == OPENVPN_PLUGIN_FUNC_SUCCESS)
- {
- event_timeout_init (&c->c2.pf.reload, 1, now);
- c->c2.pf.filename = string_alloc (pf_file, NULL);
- c->c2.pf.enabled = true;
+ const char *pf_file = create_temp_file (c->options.tmp_dir, "pf", &gc);
+ if( pf_file ) {
+ setenv_str (c->c2.es, "pf_file", pf_file);
+
+ if (plugin_call (c->plugins, OPENVPN_PLUGIN_ENABLE_PF, NULL, NULL, c->c2.es, -1, NULL) == OPENVPN_PLUGIN_FUNC_SUCCESS)
+ {
+ event_timeout_init (&c->c2.pf.reload, 1, now);
+ c->c2.pf.filename = string_alloc (pf_file, NULL);
+ c->c2.pf.enabled = true;
#ifdef ENABLE_DEBUG
- if (check_debug_level (D_PF_DEBUG))
- pf_context_print (&c->c2.pf, "pf_init_context#1", D_PF_DEBUG);
+ if (check_debug_level (D_PF_DEBUG))
+ pf_context_print (&c->c2.pf, "pf_init_context#1", D_PF_DEBUG);
#endif
- }
- else
- {
- msg (M_WARN, "WARNING: OPENVPN_PLUGIN_ENABLE_PF disabled");
- }
+ }
+ else
+ {
+ msg (M_WARN, "WARNING: OPENVPN_PLUGIN_ENABLE_PF disabled");
+ }
+ }
}
#endif
#ifdef MANAGEMENT_PF
@@ -638,7 +644,7 @@ pf_cn_set_print (const struct pf_cn_set *s, const int lev)
if (s->hash_table)
{
- hash_iterator_init (s->hash_table, &hi, false);
+ hash_iterator_init (s->hash_table, &hi);
while ((he = hash_iterator_next (&hi)))
{
struct pf_cn *e = (struct pf_cn *)he->value;
diff --git a/ping.c b/ping.c
index b29927d..191ad74 100644
--- a/ping.c
+++ b/ping.c
@@ -86,5 +86,7 @@ check_ping_send_dowork (struct context *c)
* encrypt, sign, etc.
*/
encrypt_sign (c, true);
+ /* Set length to 0, so it won't be counted as activity */
+ c->c2.buf.len = 0;
dmsg (D_PING, "SENT PING");
}
diff --git a/pkcs11.c b/pkcs11.c
index 974cb7d..af781e0 100644
--- a/pkcs11.c
+++ b/pkcs11.c
@@ -982,5 +982,7 @@ cleanup:
}
#else
+#ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
static void dummy (void) {}
+#endif
#endif /* ENABLE_PKCS11 */
diff --git a/plugin.c b/plugin.c
index 769de8d..56bd37f 100644
--- a/plugin.c
+++ b/plugin.c
@@ -232,8 +232,10 @@ plugin_init_item (struct plugin *p, const struct plugin_option *o)
PLUGIN_SYM (open1, "openvpn_plugin_open_v1", 0);
PLUGIN_SYM (open2, "openvpn_plugin_open_v2", 0);
+ PLUGIN_SYM (open3, "openvpn_plugin_open_v3", 0);
PLUGIN_SYM (func1, "openvpn_plugin_func_v1", 0);
PLUGIN_SYM (func2, "openvpn_plugin_func_v2", 0);
+ PLUGIN_SYM (func3, "openvpn_plugin_func_v3", 0);
PLUGIN_SYM (close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED);
PLUGIN_SYM (abort, "openvpn_plugin_abort_v1", 0);
PLUGIN_SYM (client_constructor, "openvpn_plugin_client_constructor_v1", 0);
@@ -241,10 +243,10 @@ plugin_init_item (struct plugin *p, const struct plugin_option *o)
PLUGIN_SYM (min_version_required, "openvpn_plugin_min_version_required_v1", 0);
PLUGIN_SYM (initialization_point, "openvpn_plugin_select_initialization_point_v1", 0);
- if (!p->open1 && !p->open2)
+ if (!p->open1 && !p->open2 && !p->open3)
msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname);
- if (!p->func1 && !p->func2)
+ if (!p->func1 && !p->func2 && !p->func3)
msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname);
/*
@@ -296,7 +298,21 @@ plugin_open_item (struct plugin *p,
/*
* Call the plugin initialization
*/
- if (p->open2)
+ if (p->open3) {
+ struct openvpn_plugin_args_open_in args = { .type_mask = p->plugin_type_mask,
+ .argv = o->argv,
+ .envp = envp };
+ struct openvpn_plugin_args_open_return retargs;
+
+ CLEAR(retargs);
+ if ((*p->open3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs) == OPENVPN_PLUGIN_FUNC_SUCCESS) {
+ p->plugin_type_mask = retargs.type_mask;
+ p->plugin_handle = retargs.handle;
+ retlist = retargs.return_list;
+ } else {
+ p->plugin_handle = NULL;
+ }
+ } else if (p->open2)
p->plugin_handle = (*p->open2)(&p->plugin_type_mask, o->argv, envp, retlist);
else if (p->open1)
p->plugin_handle = (*p->open1)(&p->plugin_type_mask, o->argv, envp);
@@ -329,7 +345,9 @@ plugin_call_item (const struct plugin *p,
const int type,
const struct argv *av,
struct openvpn_plugin_string_list **retlist,
- const char **envp)
+ const char **envp,
+ int certdepth,
+ X509 *current_cert)
{
int status = OPENVPN_PLUGIN_FUNC_SUCCESS;
@@ -348,7 +366,20 @@ plugin_call_item (const struct plugin *p,
/*
* Call the plugin work function
*/
- if (p->func2)
+ if (p->func3) {
+ struct openvpn_plugin_args_func_in args = { .type = type,
+ .argv = (const char **) a.argv,
+ .envp = envp,
+ .handle = p->plugin_handle,
+ .per_client_context = per_client_context,
+ .current_cert_depth = (current_cert ? certdepth : -1),
+ .current_cert = current_cert };
+ struct openvpn_plugin_args_func_return retargs;
+
+ CLEAR(retargs);
+ status = (*p->func3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs);
+ retlist = retargs.return_list;
+ } else if (p->func2)
status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist);
else if (p->func1)
status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp);
@@ -543,7 +574,9 @@ plugin_call (const struct plugin_list *pl,
const int type,
const struct argv *av,
struct plugin_return *pr,
- struct env_set *es)
+ struct env_set *es,
+ int certdepth,
+ X509 *current_cert)
{
if (pr)
plugin_return_init (pr);
@@ -558,8 +591,6 @@ plugin_call (const struct plugin_list *pl,
bool error = false;
bool deferred = false;
- mutex_lock_static (L_PLUGIN);
-
setenv_del (es, "script_type");
envp = make_env_array (es, false, &gc);
@@ -570,7 +601,8 @@ plugin_call (const struct plugin_list *pl,
type,
av,
pr ? &pr->list[i] : NULL,
- envp);
+ envp,
+ certdepth, current_cert);
switch (status)
{
case OPENVPN_PLUGIN_FUNC_SUCCESS:
@@ -588,8 +620,6 @@ plugin_call (const struct plugin_list *pl,
if (pr)
pr->n = i;
- mutex_unlock_static (L_PLUGIN);
-
gc_free (&gc);
if (type == OPENVPN_PLUGIN_ENABLE_PF && success)
diff --git a/plugin.h b/plugin.h
index 969d451..d6ff08d 100644
--- a/plugin.h
+++ b/plugin.h
@@ -61,8 +61,10 @@ struct plugin {
openvpn_plugin_open_v1 open1;
openvpn_plugin_open_v2 open2;
+ openvpn_plugin_open_v3 open3;
openvpn_plugin_func_v1 func1;
openvpn_plugin_func_v2 func2;
+ openvpn_plugin_func_v3 func3;
openvpn_plugin_close_v1 close;
openvpn_plugin_abort_v1 abort;
openvpn_plugin_client_constructor_v1 client_constructor;
@@ -118,7 +120,9 @@ int plugin_call (const struct plugin_list *pl,
const int type,
const struct argv *av,
struct plugin_return *pr,
- struct env_set *es);
+ struct env_set *es,
+ int current_cert_depth,
+ X509 *current_cert);
void plugin_list_close (struct plugin_list *pl);
bool plugin_defined (const struct plugin_list *pl, const int type);
@@ -170,7 +174,9 @@ plugin_call (const struct plugin_list *pl,
const int type,
const struct argv *av,
struct plugin_return *pr,
- struct env_set *es)
+ struct env_set *es,
+ int current_cert_depth,
+ X509 *current_cert)
{
return 0;
}
diff --git a/plugin/auth-pam/README b/plugin/auth-pam/README
index c957c02..e123690 100644
--- a/plugin/auth-pam/README
+++ b/plugin/auth-pam/README
@@ -48,7 +48,7 @@ For example, suppose you were using a PAM module called
plugin openvpn-auth-pam.so "test name USERNAME password PASSWORD"
-While "USERNAME" and "PASSWORD" are special strings which substitute
+While "USERNAME" "COMMONNAME" and "PASSWORD" are special strings which substitute
to client-supplied values, it is also possible to name literal values
to use as PAM module query responses. For example, suppose that the
login module queried for a third parameter, "domain" which
diff --git a/plugin/auth-pam/auth-pam.c b/plugin/auth-pam/auth-pam.c
index 1d811be..a06a48e 100644
--- a/plugin/auth-pam/auth-pam.c
+++ b/plugin/auth-pam/auth-pam.c
@@ -81,6 +81,7 @@ struct auth_pam_context
*
* "USERNAME" -- substitute client-supplied username
* "PASSWORD" -- substitute client-specified password
+ * "COMMONNAME" -- substitute client certificate common name
*/
#define N_NAME_VALUE 16
@@ -104,6 +105,7 @@ struct user_pass {
char username[128];
char password[128];
+ char common_name[128];
const struct name_value_list *name_value_list;
};
@@ -111,6 +113,35 @@ struct user_pass {
/* Background process function */
static void pam_server (int fd, const char *service, int verb, const struct name_value_list *name_value_list);
+/* Read 'tosearch', replace all occurences of 'searchfor' with 'replacewith' and return
+ * a pointer to the NEW string. Does not modify the input strings. Will not enter an
+ * infinite loop with clever 'searchfor' and 'replacewith' strings.
+ * Daniel Johnson - Progman2000@usa.net / djohnson@progman.us
+ */
+static char *
+searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith)
+{
+ if (!tosearch || !searchfor || !replacewith) return 0;
+ if (!strlen(tosearch) || !strlen(searchfor) || !strlen(replacewith)) return 0;
+
+ const char *searching=tosearch;
+ char *scratch;
+ char temp[strlen(tosearch)*10];
+ temp[0]=0;
+
+ scratch = strstr(searching,searchfor);
+ if (!scratch) return strdup(tosearch);
+
+ while (scratch) {
+ strncat(temp,searching,scratch-searching);
+ strcat(temp,replacewith);
+
+ searching=scratch+strlen(searchfor);
+ scratch = strstr(searching,searchfor);
+ }
+ return strdup(temp);
+}
+
/*
* Given an environmental variable name, search
* the envp array for its value, returning it
@@ -441,12 +472,14 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch
/* get username/password from envp string array */
const char *username = get_env ("username", envp);
const char *password = get_env ("password", envp);
+ const char *common_name = get_env ("common_name", envp) ? get_env ("common_name", envp) : "";
if (username && strlen (username) > 0 && password)
{
if (send_control (context->foreground_fd, COMMAND_VERIFY) == -1
|| send_string (context->foreground_fd, username) == -1
- || send_string (context->foreground_fd, password) == -1)
+ || send_string (context->foreground_fd, password) == -1
+ || send_string (context->foreground_fd, common_name) == -1)
{
fprintf (stderr, "AUTH-PAM: Error sending auth info to background process\n");
}
@@ -551,7 +584,7 @@ my_conv (int n, const struct pam_message **msg_array,
if (name_value_match (msg->msg, match_name))
{
/* found name/value match */
- const char *return_value = NULL;
+ aresp[i].resp = NULL;
if (DEBUG (up->verb))
fprintf (stderr, "AUTH-PAM: BACKGROUND: name match found, query/match-string ['%s', '%s'] = '%s'\n",
@@ -559,14 +592,15 @@ my_conv (int n, const struct pam_message **msg_array,
match_name,
match_value);
- if (!strcmp (match_value, "USERNAME"))
- return_value = up->username;
- else if (!strcmp (match_value, "PASSWORD"))
- return_value = up->password;
+ if (strstr(match_value, "USERNAME"))
+ aresp[i].resp = searchandreplace(match_value, "USERNAME", up->username);
+ else if (strstr(match_value, "PASSWORD"))
+ aresp[i].resp = searchandreplace(match_value, "PASSWORD", up->password);
+ else if (strstr(match_value, "COMMONNAME"))
+ aresp[i].resp = searchandreplace(match_value, "COMMONNAME", up->common_name);
else
- return_value = match_value;
+ aresp[i].resp = strdup (match_value);
- aresp[i].resp = strdup (return_value);
if (aresp[i].resp == NULL)
ret = PAM_CONV_ERR;
break;
@@ -709,7 +743,8 @@ pam_server (int fd, const char *service, int verb, const struct name_value_list
{
case COMMAND_VERIFY:
if (recv_string (fd, up.username, sizeof (up.username)) == -1
- || recv_string (fd, up.password, sizeof (up.password)) == -1)
+ || recv_string (fd, up.password, sizeof (up.password)) == -1
+ || recv_string (fd, up.common_name, sizeof (up.common_name)) == -1)
{
fprintf (stderr, "AUTH-PAM: BACKGROUND: read error on command channel: code=%d, exiting\n",
command);
diff --git a/plugin/examples/log_v3.c b/plugin/examples/log_v3.c
new file mode 100644
index 0000000..bf2f1dc
--- /dev/null
+++ b/plugin/examples/log_v3.c
@@ -0,0 +1,245 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2010 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
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * This plugin is similar to simple.c, except it also logs extra information
+ * to stdout for every plugin method called by OpenVPN. The only difference
+ * between this (log_v3.c) and log.c is that this module uses the v3 plug-in
+ * API.
+ *
+ * See the README file for build instructions.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "openvpn-plugin.h"
+
+/*
+ * Our context, where we keep our state.
+ */
+struct plugin_context {
+ const char *username;
+ const char *password;
+};
+
+/*
+ * Given an environmental variable name, search
+ * the envp array for its value, returning it
+ * if found or NULL otherwise.
+ */
+static const char *
+get_env (const char *name, const char *envp[])
+{
+ if (envp)
+ {
+ int i;
+ const int namelen = strlen (name);
+ for (i = 0; envp[i]; ++i)
+ {
+ if (!strncmp (envp[i], name, namelen))
+ {
+ const char *cp = envp[i] + namelen;
+ if (*cp == '=')
+ return cp + 1;
+ }
+ }
+ }
+ return NULL;
+}
+
+OPENVPN_EXPORT int
+openvpn_plugin_open_v3 (const int v3structver,
+ struct openvpn_plugin_args_open_in const *args,
+ struct openvpn_plugin_args_open_return *ret)
+{
+ struct plugin_context *context = NULL;
+
+ /* Check that we are API compatible */
+ if( v3structver != OPENVPN_PLUGINv3_STRUCTVER ) {
+ return OPENVPN_PLUGIN_FUNC_ERROR;
+ }
+
+ /* Which callbacks to intercept. */
+ ret->type_mask =
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) |
+ OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL);
+
+
+ /* Allocate our context */
+ context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context));
+
+ /* Set the username/password we will require. */
+ context->username = "foo";
+ context->password = "bar";
+
+ /* Point the global context handle to our newly created context */
+ ret->handle = (void *) context;
+
+ return OPENVPN_PLUGIN_FUNC_SUCCESS;
+}
+
+void
+show (const int type, const char *argv[], const char *envp[])
+{
+ size_t i;
+ switch (type)
+ {
+ case OPENVPN_PLUGIN_UP:
+ printf ("OPENVPN_PLUGIN_UP\n");
+ break;
+ case OPENVPN_PLUGIN_DOWN:
+ printf ("OPENVPN_PLUGIN_DOWN\n");
+ break;
+ case OPENVPN_PLUGIN_ROUTE_UP:
+ printf ("OPENVPN_PLUGIN_ROUTE_UP\n");
+ break;
+ case OPENVPN_PLUGIN_IPCHANGE:
+ printf ("OPENVPN_PLUGIN_IPCHANGE\n");
+ break;
+ case OPENVPN_PLUGIN_TLS_VERIFY:
+ printf ("OPENVPN_PLUGIN_TLS_VERIFY\n");
+ break;
+ case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
+ printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
+ break;
+ case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
+ printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
+ break;
+ case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
+ printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
+ break;
+ case OPENVPN_PLUGIN_LEARN_ADDRESS:
+ printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
+ break;
+ case OPENVPN_PLUGIN_TLS_FINAL:
+ printf ("OPENVPN_PLUGIN_TLS_FINAL\n");
+ break;
+ default:
+ printf ("OPENVPN_PLUGIN_?\n");
+ break;
+ }
+
+ printf ("ARGV\n");
+ for (i = 0; argv[i] != NULL; ++i)
+ printf ("%d '%s'\n", (int)i, argv[i]);
+
+ printf ("ENVP\n");
+ for (i = 0; envp[i] != NULL; ++i)
+ printf ("%d '%s'\n", (int)i, envp[i]);
+}
+
+static void
+x509_print_info (X509 *x509crt)
+{
+ int i, n;
+ int fn_nid;
+ ASN1_OBJECT *fn;
+ ASN1_STRING *val;
+ X509_NAME *x509_name;
+ X509_NAME_ENTRY *ent;
+ const char *objbuf;
+ unsigned char *buf;
+
+ x509_name = X509_get_subject_name (x509crt);
+ n = X509_NAME_entry_count (x509_name);
+ for (i = 0; i < n; ++i)
+ {
+ ent = X509_NAME_get_entry (x509_name, i);
+ if (!ent)
+ continue;
+ fn = X509_NAME_ENTRY_get_object (ent);
+ if (!fn)
+ continue;
+ val = X509_NAME_ENTRY_get_data (ent);
+ if (!val)
+ continue;
+ fn_nid = OBJ_obj2nid (fn);
+ if (fn_nid == NID_undef)
+ continue;
+ objbuf = OBJ_nid2sn (fn_nid);
+ if (!objbuf)
+ continue;
+ buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
+ if (ASN1_STRING_to_UTF8 (&buf, val) <= 0)
+ continue;
+
+ printf("X509 %s: %s\n", objbuf, (char *)buf);
+ OPENSSL_free (buf);
+ }
+}
+
+
+
+OPENVPN_EXPORT int
+openvpn_plugin_func_v3 (const int version,
+ struct openvpn_plugin_args_func_in const *args,
+ struct openvpn_plugin_args_func_return *retptr)
+{
+ struct plugin_context *context = (struct plugin_context *) args->handle;
+
+ printf("\nopenvpn_plugin_func_v3() :::::>> ");
+ show (args->type, args->argv, args->envp);
+
+ /* Dump some X509 information if we're in the TLS_VERIFY phase */
+ if ((args->type == OPENVPN_PLUGIN_TLS_VERIFY) && args->current_cert ) {
+ printf("---- X509 Subject information ----\n");
+ printf("Certificate depth: %i\n", args->current_cert_depth);
+ x509_print_info(args->current_cert);
+ printf("----------------------------------\n");
+ }
+
+ /* check entered username/password against what we require */
+ if (args->type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
+ {
+ /* get username/password from envp string array */
+ const char *username = get_env ("username", args->envp);
+ const char *password = get_env ("password", args->envp);
+
+ if (username && !strcmp (username, context->username)
+ && password && !strcmp (password, context->password))
+ return OPENVPN_PLUGIN_FUNC_SUCCESS;
+ else
+ return OPENVPN_PLUGIN_FUNC_ERROR;
+ }
+ else
+ return OPENVPN_PLUGIN_FUNC_SUCCESS;
+}
+
+OPENVPN_EXPORT void
+openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle)
+{
+ struct plugin_context *context = (struct plugin_context *) handle;
+ free (context);
+}
diff --git a/pool.c b/pool.c
index 84333df..60dc520 100644
--- a/pool.c
+++ b/pool.c
@@ -132,7 +132,10 @@ ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_
}
struct ifconfig_pool *
-ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn)
+ifconfig_pool_init (int type, in_addr_t start, in_addr_t end,
+ const bool duplicate_cn,
+ const bool ipv6_pool, const struct in6_addr ipv6_base,
+ const int ipv6_netbits )
{
struct gc_arena gc = gc_new ();
struct ifconfig_pool *pool = NULL;
@@ -157,11 +160,31 @@ ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplica
ASSERT (0);
}
+ /* IPv6 pools are always "INDIV" type */
+ pool->ipv6 = ipv6_pool;
+
+ if ( pool->ipv6 )
+ {
+ pool->base_ipv6 = ipv6_base;
+ pool->size_ipv6 = ipv6_netbits>96? ( 1<<(128-ipv6_netbits) )
+ : IFCONFIG_POOL_MAX;
+
+ msg( D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: (IPv4) size=%d, size_ipv6=%d, netbits=%d, base_ipv6=%s",
+ pool->size, pool->size_ipv6, ipv6_netbits,
+ print_in6_addr( pool->base_ipv6, 0, &gc ));
+
+ /* the current code is very simple and assumes that the IPv6
+ * pool is at least as big as the IPv4 pool, and we don't need
+ * to do separate math etc. for IPv6
+ */
+ ASSERT( pool->size < pool->size_ipv6 );
+ }
+
ALLOC_ARRAY_CLEAR (pool->list, struct ifconfig_pool_entry, pool->size);
- msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d",
+ msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d, ipv6=%d",
print_in_addr_t (pool->base, 0, &gc),
- pool->size);
+ pool->size, pool->ipv6 );
gc_free (&gc);
return pool;
@@ -181,7 +204,7 @@ ifconfig_pool_free (struct ifconfig_pool *pool)
}
ifconfig_pool_handle
-ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name)
+ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name)
{
int i;
@@ -214,6 +237,12 @@ ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *
default:
ASSERT (0);
}
+
+ /* IPv6 pools are always INDIV (--linear) */
+ if ( pool->ipv6 && remote_ipv6 )
+ {
+ *remote_ipv6 = add_in6_addr( pool->base_ipv6, i );
+ }
}
return i;
}
@@ -288,6 +317,19 @@ ifconfig_pool_handle_to_ip_base (const struct ifconfig_pool* pool, ifconfig_pool
return ret;
}
+static struct in6_addr
+ifconfig_pool_handle_to_ipv6_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand)
+{
+ struct in6_addr ret = in6addr_any;
+
+ /* IPv6 pools are always INDIV (--linear) */
+ if (hand >= 0 && hand < pool->size_ipv6 )
+ {
+ ret = add_in6_addr( pool->base_ipv6, hand );
+ }
+ return ret;
+}
+
static void
ifconfig_pool_set (struct ifconfig_pool* pool, const char *cn, const in_addr_t addr, const bool fixed)
{
@@ -317,9 +359,20 @@ ifconfig_pool_list (const struct ifconfig_pool* pool, struct status_output *out)
if (e->common_name)
{
const in_addr_t ip = ifconfig_pool_handle_to_ip_base (pool, i);
- status_printf (out, "%s,%s",
- e->common_name,
- print_in_addr_t (ip, 0, &gc));
+ if ( pool->ipv6 )
+ {
+ struct in6_addr ip6 = ifconfig_pool_handle_to_ipv6_base (pool, i);
+ status_printf (out, "%s,%s,%s",
+ e->common_name,
+ print_in_addr_t (ip, 0, &gc),
+ print_in6_addr (ip6, 0, &gc));
+ }
+ else
+ {
+ status_printf (out, "%s,%s",
+ e->common_name,
+ print_in_addr_t (ip, 0, &gc));
+ }
}
}
gc_free (&gc);
@@ -409,6 +462,9 @@ ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool
int c = *BSTR(&in);
if (c == '#' || c == ';')
continue;
+ msg( M_INFO, "ifconfig_pool_read(), in='%s', TODO: IPv6",
+ BSTR(&in) );
+
if (buf_parse (&in, ',', cn_buf, buf_size)
&& buf_parse (&in, ',', ip_buf, buf_size))
{
@@ -416,6 +472,7 @@ ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool
const in_addr_t addr = getaddr (GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL);
if (succeeded)
{
+ msg( M_INFO, "succeeded -> ifconfig_pool_set()");
ifconfig_pool_set (pool, cn_buf, addr, persist->fixed);
}
}
@@ -471,7 +528,7 @@ ifconfig_pool_test (in_addr_t start, in_addr_t end)
#else
cn = buf;
#endif
- h = ifconfig_pool_acquire (p, &local, &remote, cn);
+ h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn);
if (h < 0)
break;
msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s",
@@ -506,7 +563,7 @@ ifconfig_pool_test (in_addr_t start, in_addr_t end)
#else
cn = buf;
#endif
- h = ifconfig_pool_acquire (p, &local, &remote, cn);
+ h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn);
if (h < 0)
break;
msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s",
diff --git a/pool.h b/pool.h
index b37c828..fc9d6ab 100644
--- a/pool.h
+++ b/pool.h
@@ -31,7 +31,6 @@
#include "basic.h"
#include "status.h"
-#include "thread.h"
#define IFCONFIG_POOL_MAX 65536
#define IFCONFIG_POOL_MIN_NETBITS 16
@@ -53,6 +52,9 @@ struct ifconfig_pool
int size;
int type;
bool duplicate_cn;
+ bool ipv6;
+ struct in6_addr base_ipv6;
+ unsigned int size_ipv6;
struct ifconfig_pool_entry *list;
};
@@ -64,13 +66,13 @@ struct ifconfig_pool_persist
typedef int ifconfig_pool_handle;
-struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn);
+struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn, const bool ipv6_pool, const struct in6_addr ipv6_base, const int ipv6_netbits );
void ifconfig_pool_free (struct ifconfig_pool *pool);
bool ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end);
-ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name);
+ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name);
bool ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard);
diff --git a/proto.h b/proto.h
index 7e45231..8cd4ede 100644
--- a/proto.h
+++ b/proto.h
@@ -108,6 +108,21 @@ struct openvpn_iphdr {
};
/*
+ * IPv6 header
+ */
+struct openvpn_ipv6hdr {
+ uint8_t version_prio;
+ uint8_t flow_lbl[3];
+ uint16_t payload_len;
+ uint8_t nexthdr;
+ uint8_t hop_limit;
+
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+};
+
+
+/*
* UDP header
*/
struct openvpn_udphdr {
diff --git a/proxy.c b/proxy.c
index 3de2ac1..fce64a1 100644
--- a/proxy.c
+++ b/proxy.c
@@ -552,6 +552,10 @@ 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)
{
diff --git a/ps.c b/ps.c
index 4cdac3c..d5be31e 100644
--- a/ps.c
+++ b/ps.c
@@ -237,18 +237,6 @@ port_share_sendmsg (const socket_descriptor_t sd,
}
}
-static int
-pc_list_len (struct proxy_connection *pc)
-{
- int count = 0;
- while (pc)
- {
- ++count;
- pc = pc->next;
- }
- return count;
-}
-
static void
proxy_entry_close_sd (struct proxy_connection *pc, struct event_set *es)
{
@@ -383,9 +371,9 @@ sock_addr_set (struct openvpn_sockaddr *osaddr,
const int port)
{
CLEAR (*osaddr);
- osaddr->sa.sin_family = AF_INET;
- osaddr->sa.sin_addr.s_addr = htonl (addr);
- osaddr->sa.sin_port = htons (port);
+ osaddr->addr.in4.sin_family = AF_INET;
+ osaddr->addr.in4.sin_addr.s_addr = htonl (addr);
+ osaddr->addr.in4.sin_port = htons (port);
}
static inline void
diff --git a/push.c b/push.c
index 5b870ce..a8ce356 100644
--- a/push.c
+++ b/push.c
@@ -233,8 +233,27 @@ send_push_reply (struct context *c)
static char cmd[] = "PUSH_REPLY";
const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */
const int safe_cap = BCAP (&buf) - extra;
+ bool push_sent = false;
- buf_printf (&buf, cmd);
+ msg( M_INFO, "send_push_reply(): safe_cap=%d", safe_cap );
+
+ buf_printf (&buf, "%s", cmd);
+
+ if ( c->c2.push_ifconfig_ipv6_defined )
+ {
+ /* IPv6 is put into buffer first, could be lengthy */
+ /* TODO: push "/netbits" as well, to allow non-/64 subnet sizes
+ * (needs changes in options.c, options.h, and other places)
+ */
+ buf_printf( &buf, ",ifconfig-ipv6 %s %s",
+ print_in6_addr( c->c2.push_ifconfig_ipv6_local, 0, &gc),
+ print_in6_addr( c->c2.push_ifconfig_ipv6_remote, 0, &gc) );
+ if (BLEN (&buf) >= safe_cap)
+ {
+ msg (M_WARN, "--push ifconfig-ipv6 option is too long");
+ goto fail;
+ }
+ }
while (e)
{
@@ -248,9 +267,10 @@ send_push_reply (struct context *c)
const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH);
if (!status)
goto fail;
+ push_sent = true;
multi_push = true;
buf_reset_len (&buf);
- buf_printf (&buf, cmd);
+ buf_printf (&buf, "%s", cmd);
}
}
if (BLEN (&buf) + l >= safe_cap)
@@ -281,6 +301,21 @@ send_push_reply (struct context *c)
{
const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH);
if (!status)
+ goto fail;
+ push_sent = true;
+ }
+
+ /* If nothing have been pushed, send an empty push,
+ * as the client is expecting a response
+ */
+ if (!push_sent)
+ {
+ bool status = false;
+
+ buf_reset_len (&buf);
+ buf_printf (&buf, "%s", cmd);
+ status = send_control_channel_string (c, BSTR(&buf), D_PUSH);
+ if (!status)
goto fail;
}
diff --git a/reliable.c b/reliable.c
index ec03165..1f238cc 100644
--- a/reliable.c
+++ b/reliable.c
@@ -516,6 +516,7 @@ reliable_can_send (const struct reliable *rel)
return n_current > 0 && !rel->hold;
}
+#ifdef EXPONENTIAL_BACKOFF
/* return a unique point-in-time to trigger retry */
static time_t
reliable_unique_retry (struct reliable *rel, time_t retry)
@@ -535,6 +536,7 @@ reliable_unique_retry (struct reliable *rel, time_t retry)
}
return retry;
}
+#endif
/* return next buffer to send to remote */
struct buffer *
diff --git a/route.c b/route.c
index c3e4acf..cb685c3 100644
--- a/route.c
+++ b/route.c
@@ -35,10 +35,12 @@
#include "socket.h"
#include "manage.h"
#include "win32.h"
+#include "options.h"
#include "memdbg.h"
static void delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
+static void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags);
#ifdef ENABLE_DEBUG
@@ -59,26 +61,6 @@ print_bypass_addresses (const struct route_bypass *rb)
#endif
-static bool
-add_bypass_address (struct route_bypass *rb, const in_addr_t a)
-{
- int i;
- for (i = 0; i < rb->n_bypass; ++i)
- {
- if (a == rb->bypass[i]) /* avoid duplicates */
- return true;
- }
- if (rb->n_bypass < N_ROUTE_BYPASS)
- {
- rb->bypass[rb->n_bypass++] = a;
- return true;
- }
- else
- {
- return false;
- }
-}
-
struct route_option_list *
new_route_option_list (const int max_routes, struct gc_arena *a)
{
@@ -88,6 +70,15 @@ new_route_option_list (const int max_routes, struct gc_arena *a)
return ret;
}
+struct route_ipv6_option_list *
+new_route_ipv6_option_list (const int max_routes, 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;
+ return ret;
+}
+
struct route_option_list *
clone_route_option_list (const struct route_option_list *src, struct gc_arena *a)
{
@@ -115,6 +106,15 @@ new_route_list (const int max_routes, struct gc_arena *a)
return ret;
}
+struct route_ipv6_list *
+new_route_ipv6_list (const int max_routes, struct gc_arena *a)
+{
+ struct route_ipv6_list *ret;
+ ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_list, struct route_ipv6, max_routes, a);
+ ret->capacity = max_routes;
+ return ret;
+}
+
static const char *
route_string (const struct route *r, struct gc_arena *gc)
{
@@ -331,6 +331,68 @@ init_route (struct route *r,
return false;
}
+static bool
+init_route_ipv6 (struct route_ipv6 *r6,
+ const struct route_ipv6_option *r6o,
+ const struct route_ipv6_list *rl6 )
+{
+ r6->option = r6o;
+ r6->defined = false;
+
+ if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, NULL, M_WARN ))
+ goto fail;
+
+ /* gateway */
+ if (is_route_parm_defined (r6o->gateway))
+ {
+ if ( inet_pton( AF_INET6, r6o->gateway, &r6->gateway ) != 1 )
+ {
+ msg( M_WARN, PACKAGE_NAME "ROUTE6: cannot parse gateway spec '%s'", r6o->gateway );
+ }
+ }
+ else if (rl6->remote_endpoint_defined)
+ {
+ r6->gateway = rl6->remote_endpoint_ipv6;
+ }
+ else
+ {
+ msg (M_WARN, PACKAGE_NAME " ROUTE6: " PACKAGE_NAME " needs a gateway parameter for a --route-ipv6 option and no default was specified by either --route-ipv6-gateway or --ifconfig-ipv6 options");
+ goto fail;
+ }
+
+ /* metric */
+
+ r6->metric_defined = false;
+ r6->metric = 0;
+ if (is_route_parm_defined (r6o->metric))
+ {
+ r6->metric = atoi (r6o->metric);
+ if (r6->metric < 0)
+ {
+ msg (M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0",
+ r6o->prefix,
+ r6o->metric);
+ goto fail;
+ }
+ r6->metric_defined = true;
+ }
+ else if (rl6->default_metric_defined)
+ {
+ r6->metric = rl6->default_metric;
+ r6->metric_defined = true;
+ }
+
+ r6->defined = true;
+
+ return true;
+
+ fail:
+ msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s",
+ r6o->prefix);
+ r6->defined = false;
+ return false;
+}
+
void
add_route_to_option_list (struct route_option_list *l,
const char *network,
@@ -351,6 +413,23 @@ add_route_to_option_list (struct route_option_list *l,
}
void
+add_route_ipv6_to_option_list (struct route_ipv6_option_list *l,
+ const char *prefix,
+ const char *gateway,
+ 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];
+ ro->prefix = prefix;
+ ro->gateway = gateway;
+ ro->metric = metric;
+ ++l->n;
+}
+
+void
clear_route_list (struct route_list *rl)
{
const int capacity = rl->capacity;
@@ -360,6 +439,15 @@ clear_route_list (struct route_list *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;
+}
+
+void
route_list_add_default_gateway (struct route_list *rl,
struct env_set *es,
const in_addr_t addr)
@@ -489,6 +577,72 @@ init_route_list (struct route_list *rl,
return ret;
}
+bool
+init_route_ipv6_list (struct route_ipv6_list *rl6,
+ const struct route_ipv6_option_list *opt6,
+ const char *remote_endpoint,
+ int default_metric,
+ struct env_set *es)
+{
+ struct gc_arena gc = gc_new ();
+ bool ret = true;
+
+ clear_route_ipv6_list (rl6);
+
+ rl6->flags = opt6->flags;
+
+ if (default_metric)
+ {
+ rl6->default_metric = default_metric;
+ rl6->default_metric_defined = true;
+ }
+
+ /* "default_gateway" is stuff for "redirect-gateway", which we don't
+ * do for IPv6 yet -> TODO
+ */
+ {
+ dmsg (D_ROUTE, "ROUTE6: default_gateway=UNDEF");
+ }
+
+ if ( is_route_parm_defined( remote_endpoint ))
+ {
+ if ( inet_pton( AF_INET6, remote_endpoint,
+ &rl6->remote_endpoint_ipv6) == 1 )
+ {
+ rl6->remote_endpoint_defined = true;
+ }
+ else
+ {
+ msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve default gateway: %s", remote_endpoint);
+ ret = false;
+ }
+ }
+ else
+ 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 */
+ {
+ int i, j = 0;
+ for (i = 0; i < opt6->n; ++i)
+ {
+ if (!init_route_ipv6 (&rl6->routes_ipv6[j],
+ &opt6->routes_ipv6[i],
+ rl6 ))
+ ret = false;
+ else
+ ++j;
+ }
+ rl6->n = j;
+ }
+
+ gc_free (&gc);
+ return ret;
+}
+
static void
add_route3 (in_addr_t network,
in_addr_t netmask,
@@ -601,13 +755,23 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u
if (!local)
{
/* route remote host to original default gateway */
- add_route3 (rl->spec.remote_host,
- ~0,
- rl->spec.net_gateway,
- tt,
- flags,
- es);
- rl->did_local = true;
+#ifdef USE_PF_INET6
+ /* if remote_host is not ipv4 (ie: ipv6), just skip
+ * adding this special /32 route */
+ if (rl->spec.remote_host != IPV4_INVALID_ADDR) {
+#endif
+ add_route3 (rl->spec.remote_host,
+ ~0,
+ rl->spec.net_gateway,
+ tt,
+ flags,
+ es);
+ rl->did_local = true;
+#ifdef USE_PF_INET6
+ } else {
+ dmsg (D_ROUTE, "ROUTE remote_host protocol differs from tunneled");
+ }
+#endif
}
/* route DHCP/DNS server traffic through original default gateway */
@@ -724,10 +888,13 @@ undo_redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *
}
void
-add_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
+add_routes (struct route_list *rl, struct route_ipv6_list *rl6,
+ const struct tuntap *tt, unsigned int flags, const struct env_set *es)
{
- redirect_default_route_to_vpn (rl, tt, flags, es);
- if (!rl->routes_added)
+ if (rl)
+ redirect_default_route_to_vpn (rl, tt, flags, es);
+
+ if (rl && !rl->routes_added)
{
int i;
@@ -752,12 +919,27 @@ add_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags,
}
rl->routes_added = true;
}
+
+ if (rl6 && !rl6->routes_added)
+ {
+ int i;
+
+ for (i = 0; i < rl6->n; ++i)
+ {
+ struct route_ipv6 *r = &rl6->routes_ipv6[i];
+ if (flags & ROUTE_DELETE_FIRST)
+ delete_route_ipv6 (r, tt, flags, es);
+ add_route_ipv6 (r, tt, flags, es);
+ }
+ rl6->routes_added = true;
+ }
}
void
-delete_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
+delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
+ const struct tuntap *tt, unsigned int flags, const struct env_set *es)
{
- if (rl->routes_added)
+ if (rl && rl->routes_added)
{
int i;
for (i = rl->n - 1; i >= 0; --i)
@@ -767,9 +949,28 @@ delete_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flag
}
rl->routes_added = false;
}
- undo_redirect_default_route_to_vpn (rl, tt, flags, es);
- clear_route_list (rl);
+ if ( rl )
+ {
+ undo_redirect_default_route_to_vpn (rl, tt, flags, es);
+ clear_route_list (rl);
+ }
+
+ if ( rl6 && rl6->routes_added )
+ {
+ int i;
+ for (i = rl6->n - 1; i >= 0; --i)
+ {
+ const struct route_ipv6 *r6 = &rl6->routes_ipv6[i];
+ delete_route_ipv6 (r6, tt, flags, es);
+ }
+ rl6->routes_added = false;
+ }
+
+ if ( rl6 )
+ {
+ clear_route_ipv6_list (rl6);
+ }
}
#ifdef ENABLE_DEBUG
@@ -852,6 +1053,34 @@ setenv_routes (struct env_set *es, const struct route_list *rl)
setenv_route (es, &rl->routes[i], i + 1);
}
+static void
+setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i)
+{
+ struct gc_arena gc = gc_new ();
+ if (r6->defined)
+ {
+ struct buffer name1 = alloc_buf_gc( 256, &gc );
+ struct buffer val = alloc_buf_gc( 256, &gc );
+ struct buffer name2 = alloc_buf_gc( 256, &gc );
+
+ buf_printf( &name1, "route_ipv6_network_%d", i );
+ buf_printf( &val, "%s/%d", print_in6_addr( r6->network, 0, &gc ),
+ r6->netbits );
+ setenv_str( es, BSTR(&name1), BSTR(&val) );
+
+ buf_printf( &name2, "route_ipv6_gateway_%d", i );
+ setenv_str( es, BSTR(&name2), print_in6_addr( r6->gateway, 0, &gc ));
+ }
+ gc_free (&gc);
+}
+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);
+}
+
void
add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
{
@@ -952,16 +1181,14 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
argv_printf (&argv, "%s add",
ROUTE_PATH);
-#if 0
- if (r->metric_defined)
- argv_printf_cat (&argv, "-rtt %d", r->metric);
-#endif
-
argv_printf_cat (&argv, "%s -netmask %s %s",
network,
netmask,
gateway);
+ if (r->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");
@@ -1047,6 +1274,176 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
gc_free (&gc);
}
+void
+add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
+{
+ struct gc_arena gc;
+ struct argv argv;
+
+ const char *network;
+ const char *gateway;
+ bool status = false;
+ const char *device = tt->actual_name;
+ int byte, bits_to_clear;
+ struct in6_addr network_copy = r6->network;
+
+ if (!r6->defined)
+ return;
+
+ gc_init (&gc);
+ argv_init (&argv);
+
+ /* clear host bit parts of route
+ * (needed if routes are specified improperly, or if we need to
+ * explicitely setup the "connected" network routes on some OSes)
+ */
+ byte = 15;
+ bits_to_clear = 128 - r6->netbits;
+
+ while( byte >= 0 && bits_to_clear > 0 )
+ {
+ if ( bits_to_clear >= 8 )
+ { network_copy.s6_addr[byte--] = 0; bits_to_clear -= 8; }
+ else
+ { network_copy.s6_addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; }
+ }
+
+ network = print_in6_addr( network_copy, 0, &gc);
+ gateway = print_in6_addr( r6->gateway, 0, &gc);
+
+ if ( !tt->ipv6 )
+ {
+ msg( M_INFO, "add_route_ipv6(): not adding %s/%d, no IPv6 on if %s",
+ network, r6->netbits, device );
+ return;
+ }
+
+ msg( M_INFO, "add_route_ipv6(%s/%d -> %s metric %d) dev %s",
+ network, r6->netbits, gateway, r6->metric, device );
+
+ /*
+ * Filter out routes which are essentially no-ops
+ * (not currently done for IPv6)
+ */
+
+#if defined(TARGET_LINUX)
+#ifdef CONFIG_FEATURE_IPROUTE
+ argv_printf (&argv, "%s -6 route add %s/%d dev %s",
+ iproute_path,
+ network,
+ r6->netbits,
+ device);
+ if (r6->metric_defined)
+ argv_printf_cat (&argv, " metric %d", r6->metric);
+
+#else
+ argv_printf (&argv, "%s -A inet6 add %s/%d dev %s",
+ ROUTE_PATH,
+ network,
+ r6->netbits,
+ device);
+ if (r6->metric_defined)
+ argv_printf_cat (&argv, " metric %d", r6->metric);
+#endif /*CONFIG_FEATURE_IPROUTE*/
+ argv_msg (D_ROUTE, &argv);
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 add command failed");
+
+#elif defined (WIN32)
+
+ /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
+ argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ network,
+ r6->netbits,
+ device);
+
+ /* next-hop depends on TUN or TAP mode:
+ * - in TAP mode, we use the "real" next-hop
+ * - in TUN mode we use a special-case link-local address that the tapdrvr
+ * knows about and will answer ND (neighbor discovery) packets for
+ */
+ if ( tt->type == DEV_TYPE_TUN )
+ argv_printf_cat( &argv, " %s", "fe80::8" );
+ else
+ argv_printf_cat( &argv, " %s", gateway );
+
+#if 0
+ if (r->metric_defined)
+ argv_printf_cat (&argv, " METRIC %d", r->metric);
+#endif
+
+ argv_msg (D_ROUTE, &argv);
+
+ netcmd_semaphore_lock ();
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed");
+ netcmd_semaphore_release ();
+
+#elif defined (TARGET_SOLARIS)
+
+ /* example: route add -inet6 2001:db8::/32 somegateway 0 */
+
+ /* for some weird reason, this does not work for me unless I set
+ * "metric 0" - otherwise, the routes will be nicely installed, but
+ * packets will just disappear somewhere. So we use "0" now...
+ */
+
+ argv_printf (&argv, "%s add -inet6 %s/%d %s 0",
+ ROUTE_PATH,
+ network,
+ r6->netbits,
+ gateway );
+
+ argv_msg (D_ROUTE, &argv);
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add -inet6 command failed");
+
+#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
+
+ argv_printf (&argv, "%s add -inet6 %s/%d -iface %s",
+ ROUTE_PATH,
+ network,
+ r6->netbits,
+ device );
+
+ argv_msg (D_ROUTE, &argv);
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route add -inet6 command failed");
+
+#elif defined(TARGET_DARWIN)
+
+ argv_printf (&argv, "%s add -inet6 %s -prefixlen %d -iface %s",
+ ROUTE_PATH,
+ network, r6->netbits, device );
+
+ argv_msg (D_ROUTE, &argv);
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: MacOS X route add -inet6 command failed");
+
+#elif defined(TARGET_OPENBSD)
+
+ argv_printf (&argv, "%s add -inet6 %s -prefixlen %d %s",
+ ROUTE_PATH,
+ network, r6->netbits, gateway );
+
+ argv_msg (D_ROUTE, &argv);
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD route add -inet6 command failed");
+
+#elif defined(TARGET_NETBSD)
+
+ argv_printf (&argv, "%s add -inet6 %s/%d %s",
+ ROUTE_PATH,
+ network, r6->netbits, gateway );
+
+ argv_msg (D_ROUTE, &argv);
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route add -inet6 command failed");
+
+#else
+ msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-up script");
+#endif
+
+ r6->defined = status;
+ argv_reset (&argv);
+ gc_free (&gc);
+}
+
static void
delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
{
@@ -1186,6 +1583,142 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags
gc_free (&gc);
}
+static void
+delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
+{
+ struct gc_arena gc;
+ struct argv argv;
+ const char *network;
+ const char *gateway;
+ const char *device = tt->actual_name;
+
+ if (!r6->defined)
+ return;
+
+ gc_init (&gc);
+ argv_init (&argv);
+
+ network = print_in6_addr( r6->network, 0, &gc);
+ gateway = print_in6_addr( r6->gateway, 0, &gc);
+
+ if ( !tt->ipv6 )
+ {
+ msg( M_INFO, "delete_route_ipv6(): not deleting %s/%d, no IPv6 on if %s",
+ network, r6->netbits, device );
+ return;
+ }
+
+ msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits );
+
+#if defined(TARGET_LINUX)
+#ifdef CONFIG_FEATURE_IPROUTE
+ argv_printf (&argv, "%s -6 route del %s/%d dev %s",
+ iproute_path,
+ network,
+ r6->netbits,
+ device);
+#else
+ argv_printf (&argv, "%s -A inet6 del %s/%d dev %s",
+ ROUTE_PATH,
+ network,
+ r6->netbits,
+ device);
+#endif /*CONFIG_FEATURE_IPROUTE*/
+ argv_msg (D_ROUTE, &argv);
+ openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 del command failed");
+
+#elif defined (WIN32)
+
+ /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
+ argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ network,
+ r6->netbits,
+ device);
+
+ /* next-hop depends on TUN or TAP mode:
+ * - in TAP mode, we use the "real" next-hop
+ * - in TUN mode we use a special-case link-local address that the tapdrvr
+ * knows about and will answer ND (neighbor discovery) packets for
+ * (and "route deletion without specifying next-hop" does not work...)
+ */
+ if ( tt->type == DEV_TYPE_TUN )
+ argv_printf_cat( &argv, " %s", "fe80::8" );
+ else
+ argv_printf_cat( &argv, " %s", gateway );
+
+#if 0
+ if (r->metric_defined)
+ argv_printf_cat (&argv, "METRIC %d", r->metric);
+#endif
+
+ argv_msg (D_ROUTE, &argv);
+
+ netcmd_semaphore_lock ();
+ openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed");
+ netcmd_semaphore_release ();
+
+#elif defined (TARGET_SOLARIS)
+
+ /* example: route delete -inet6 2001:db8::/32 somegateway */
+ /* GERT-TODO: this is untested, but should work */
+
+ argv_printf (&argv, "%s delete -inet6 %s/%d %s",
+ ROUTE_PATH,
+ network,
+ r6->netbits,
+ gateway );
+
+ argv_msg (D_ROUTE, &argv);
+ openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route delete -inet6 command failed");
+
+#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY)
+
+ argv_printf (&argv, "%s delete -inet6 %s/%d -iface %s",
+ ROUTE_PATH,
+ network,
+ r6->netbits,
+ device );
+
+ argv_msg (D_ROUTE, &argv);
+ openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed");
+
+#elif defined(TARGET_DARWIN)
+
+ argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d -iface %s",
+ ROUTE_PATH,
+ network, r6->netbits, device );
+
+ argv_msg (D_ROUTE, &argv);
+ openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed");
+
+#elif defined(TARGET_OPENBSD)
+
+ argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d %s",
+ ROUTE_PATH,
+ network, r6->netbits, gateway );
+
+ argv_msg (D_ROUTE, &argv);
+ openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD route delete -inet6 command failed");
+
+#elif defined(TARGET_NETBSD)
+
+ argv_printf (&argv, "%s delete -inet6 %s/%d %s",
+ ROUTE_PATH,
+ network, r6->netbits, gateway );
+
+ argv_msg (D_ROUTE, &argv);
+ openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route delete -inet6 command failed");
+
+#else
+ msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-down script");
+#endif
+
+ argv_reset (&argv);
+ gc_free (&gc);
+}
+
/*
* The --redirect-gateway option requires OS-specific code below
* to get the current default gateway.
@@ -2133,8 +2666,18 @@ netmask_to_netbits (const in_addr_t network, const in_addr_t netmask, int *netbi
static void
add_host_route_if_nonlocal (struct route_bypass *rb, const in_addr_t addr)
{
- if (test_local_addr(addr) == TLA_NONLOCAL && addr != 0 && addr != ~0)
- add_bypass_address (rb, addr);
+ if (test_local_addr(addr) == TLA_NONLOCAL && addr != 0 && addr != ~0) {
+ int i;
+ for (i = 0; i < rb->n_bypass; ++i)
+ {
+ if (addr == rb->bypass[i]) /* avoid duplicates */
+ return;
+ }
+ if (rb->n_bypass < N_ROUTE_BYPASS)
+ {
+ rb->bypass[rb->n_bypass++] = addr;
+ }
+ }
}
static void
diff --git a/route.h b/route.h
index c5cbb7c..739d12d 100644
--- a/route.h
+++ b/route.h
@@ -92,6 +92,19 @@ struct route_option_list {
struct route_option routes[EMPTY_ARRAY_SIZE];
};
+struct route_ipv6_option {
+ const char *prefix; /* e.g. "2001:db8:1::/64" */
+ const char *gateway; /* e.g. "2001:db8:0::2" */
+ const char *metric; /* e.g. "5" */
+};
+
+struct route_ipv6_option_list {
+ unsigned int flags;
+ int capacity;
+ int n;
+ struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE];
+};
+
struct route {
bool defined;
const struct route_option *option;
@@ -113,6 +126,31 @@ struct route_list {
struct route routes[EMPTY_ARRAY_SIZE];
};
+struct route_ipv6 {
+ bool defined;
+ const struct route_ipv6_option *option;
+ struct in6_addr network;
+ unsigned int netbits;
+ struct in6_addr gateway;
+ bool metric_defined;
+ int metric;
+};
+
+struct route_ipv6_list {
+ bool routes_added;
+ unsigned int flags;
+ int default_metric;
+ bool default_metric_defined;
+ struct in6_addr remote_endpoint_ipv6;
+ bool remote_endpoint_defined;
+ bool did_redirect_default_gateway; /* TODO (?) */
+ bool did_local; /* TODO (?) */
+ int capacity;
+ int n;
+ struct route_ipv6 routes_ipv6[EMPTY_ARRAY_SIZE];
+};
+
+
#if P2MP
/* internal OpenVPN route */
struct iroute {
@@ -120,15 +158,24 @@ struct iroute {
int netbits;
struct iroute *next;
};
+
+struct iroute_ipv6 {
+ struct in6_addr network;
+ unsigned int netbits;
+ struct iroute_ipv6 *next;
+};
#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 *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a);
void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src);
struct route_list *new_route_list (const int max_routes, struct gc_arena *a);
+struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_arena *a);
void add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
+void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
void add_route_to_option_list (struct route_option_list *l,
const char *network,
@@ -136,6 +183,11 @@ void add_route_to_option_list (struct route_option_list *l,
const char *gateway,
const char *metric);
+void add_route_ipv6_to_option_list (struct route_ipv6_option_list *l,
+ const char *prefix,
+ const char *gateway,
+ const char *metric);
+
bool init_route_list (struct route_list *rl,
const struct route_option_list *opt,
const char *remote_endpoint,
@@ -143,21 +195,30 @@ bool init_route_list (struct route_list *rl,
in_addr_t remote_host,
struct env_set *es);
+bool init_route_ipv6_list (struct route_ipv6_list *rl6,
+ const struct route_ipv6_option_list *opt6,
+ const char *remote_endpoint,
+ int default_metric,
+ struct env_set *es);
+
void route_list_add_default_gateway (struct route_list *rl,
struct env_set *es,
const in_addr_t addr);
void add_routes (struct route_list *rl,
+ struct route_ipv6_list *rl6,
const struct tuntap *tt,
unsigned int flags,
const struct env_set *es);
void delete_routes (struct route_list *rl,
+ struct route_ipv6_list *rl6,
const struct tuntap *tt,
unsigned int flags,
const struct env_set *es);
void setenv_routes (struct env_set *es, const struct route_list *rl);
+void setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6);
bool is_special_addr (const char *addr_str);
diff --git a/sample-config-files/firewall.sh b/sample-config-files/firewall.sh
index f0db806..19d75ee 100755
--- a/sample-config-files/firewall.sh
+++ b/sample-config-files/firewall.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# A Sample OpenVPN-aware firewall.
diff --git a/sample-scripts/bridge-start b/sample-scripts/bridge-start
index bfbbdc5..d20a260 100755
--- a/sample-scripts/bridge-start
+++ b/sample-scripts/bridge-start
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
#################################
# Set up Ethernet bridge on Linux
diff --git a/sample-scripts/bridge-stop b/sample-scripts/bridge-stop
index d452893..8192779 100755
--- a/sample-scripts/bridge-stop
+++ b/sample-scripts/bridge-stop
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
####################################
# Tear Down Ethernet bridge on Linux
diff --git a/sample-scripts/openvpn.init b/sample-scripts/openvpn.init
index 6c699cc..821abd5 100755
--- a/sample-scripts/openvpn.init
+++ b/sample-scripts/openvpn.init
@@ -5,10 +5,10 @@
#
# chkconfig: 345 24 76
#
-# description: OpenVPN is a robust and highly flexible tunneling application that
-# uses all of the encryption, authentication, and certification features
-# of the OpenSSL library to securely tunnel IP networks over a single
-# UDP port.
+# description: OpenVPN is a robust and highly flexible tunneling application \
+# that uses all of the encryption, authentication, and \
+# certification features of the OpenSSL library to securely \
+# tunnel IP networks over a single UDP port.
#
# Contributed to the OpenVPN project by
diff --git a/sample-scripts/verify-cn b/sample-scripts/verify-cn
index 5d56d95..f9fea0f 100755
--- a/sample-scripts/verify-cn
+++ b/sample-scripts/verify-cn
@@ -7,24 +7,28 @@
#
# For example in OpenVPN, you could use the directive:
#
-# tls-verify "./verify-cn Test-Client"
+# tls-verify "./verify-cn /etc/openvpn/allowed_clients"
#
# This would cause the connection to be dropped unless
-# the client common name is "Test-Client"
+# the client common name is listed on a line in the
+# allowed_clients file.
-die "usage: verify-cn cn certificate_depth X509_NAME_oneline" if (@ARGV != 3);
+die "usage: verify-cn cnfile certificate_depth X509_NAME_oneline" if (@ARGV != 3);
# Parse out arguments:
-# cn -- The common name which the client is required to have,
-# taken from the argument to the tls-verify directive
-# in the OpenVPN config file.
-# depth -- The current certificate chain depth. In a typical
-# bi-level chain, the root certificate will be at level
-# 1 and the client certificate will be at level 0.
-# This script will be called separately for each level.
-# x509 -- the X509 subject string as extracted by OpenVPN from
-# the client's provided certificate.
-($cn, $depth, $x509) = @ARGV;
+# cnfile -- The file containing the list of common names, one per
+# line, which the client is required to have,
+# taken from the argument to the tls-verify directive
+# in the OpenVPN config file.
+# The file can have blank lines and comment lines that begin
+# with the # character.
+# depth -- The current certificate chain depth. In a typical
+# bi-level chain, the root certificate will be at level
+# 1 and the client certificate will be at level 0.
+# This script will be called separately for each level.
+# x509 -- the X509 subject string as extracted by OpenVPN from
+# the client's provided certificate.
+($cnfile, $depth, $x509) = @ARGV;
if ($depth == 0) {
# If depth is zero, we know that this is the final
@@ -34,11 +38,19 @@ if ($depth == 0) {
# the X509 subject string.
if ($x509 =~ /\/CN=([^\/]+)/) {
+ $cn = $1;
# Accept the connection if the X509 common name
# string matches the passed cn argument.
- if ($cn eq $1) {
- exit 0;
+ open(FH, '<', $cnfile) or exit 1; # can't open, nobody authenticates!
+ while (defined($line = <FH>)) {
+ if ($line !~ /^[[:space:]]*(#|$)/o) {
+ chop($line);
+ if ($line eq $cn) {
+ exit 0;
+ }
+ }
}
+ close(FH);
}
# Authentication failed -- Either we could not parse
diff --git a/schedule.c b/schedule.c
index 8a53031..f0482ab 100644
--- a/schedule.c
+++ b/schedule.c
@@ -363,24 +363,20 @@ schedule_init (void)
struct schedule *s;
ALLOC_OBJ_CLEAR (s, struct schedule);
- mutex_init (&s->mutex);
return s;
}
void
schedule_free (struct schedule *s)
{
- mutex_destroy (&s->mutex);
free (s);
}
void
schedule_remove_entry (struct schedule *s, struct schedule_entry *e)
{
- mutex_lock (&s->mutex);
s->earliest_wakeup = NULL; /* invalidate cache */
schedule_remove_node (s, e);
- mutex_unlock (&s->mutex);
}
/*
diff --git a/schedule.h b/schedule.h
index 1a6d219..71c6d8c 100644
--- a/schedule.h
+++ b/schedule.h
@@ -42,7 +42,6 @@
/*#define SCHEDULE_TEST*/
#include "otime.h"
-#include "thread.h"
#include "error.h"
struct schedule_entry
@@ -56,7 +55,6 @@ struct schedule_entry
struct schedule
{
- MUTEX_DEFINE (mutex);
struct schedule_entry *earliest_wakeup; /* cached earliest wakeup */
struct schedule_entry *root; /* the root of the treap (btree) */
};
@@ -100,14 +98,12 @@ schedule_add_entry (struct schedule *s,
const struct timeval *tv,
unsigned int sigma)
{
- mutex_lock (&s->mutex);
if (!IN_TREE (e) || !sigma || !tv_within_sigma (tv, &e->tv, sigma))
{
e->tv = *tv;
schedule_add_modify (s, e);
s->earliest_wakeup = NULL; /* invalidate cache */
}
- mutex_unlock (&s->mutex);
}
/*
@@ -122,8 +118,6 @@ schedule_get_earliest_wakeup (struct schedule *s,
{
struct schedule_entry *ret;
- mutex_lock (&s->mutex);
-
/* cache result */
if (!s->earliest_wakeup)
s->earliest_wakeup = schedule_find_least (s->root);
@@ -131,8 +125,6 @@ schedule_get_earliest_wakeup (struct schedule *s,
if (ret)
*wakeup = ret->tv;
- mutex_unlock (&s->mutex);
-
return ret;
}
diff --git a/service-win32/msvc.mak b/service-win32/msvc.mak
new file mode 100644
index 0000000..ba4bab7
--- /dev/null
+++ b/service-win32/msvc.mak
@@ -0,0 +1,30 @@
+# This makefile builds the OpenVPN service wrapper for Windows in the
+# Visual Studio 2008 environment.
+
+# Some of these libs may not be needed
+LIBS = ws2_32.lib crypt32.lib iphlpapi.lib winmm.lib user32.lib gdi32.lib advapi32.lib wininet.lib
+EXE = openvpnserv.exe
+
+CPP=cl.exe
+CPP_ARG_COMMON=/nologo /W3 -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS -D_CRT_SECURE_NO_DEPRECATE /FD /c -I".."
+CPP_PROJ=$(CPP_ARG_COMMON) /O2 /MD -DNDEBUG
+
+LINK32=link.exe
+LINK32_FLAGS=/nologo /subsystem:console /incremental:no
+
+OBJS = \
+ openvpnserv.obj \
+ service.obj
+
+openvpnserv : $(OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) "/out:$(EXE)" $(LIBS) $(OBJS)
+<<
+
+clean :
+ del /Q $(OBJS) $(EXE) *.idb *.pdb
+
+.c.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
diff --git a/service-win32/openvpnserv.c b/service-win32/openvpnserv.c
index 6c9ff1e..0993064 100755
--- a/service-win32/openvpnserv.c
+++ b/service-win32/openvpnserv.c
@@ -33,14 +33,11 @@
* This code is designed to be built with the mingw compiler.
*/
-#ifdef _MSC_VER
-#include "config-win32.h"
-#else
#include "config.h"
-#endif
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
+#include <stdarg.h>
#include <process.h>
#include "service.h"
@@ -83,13 +80,6 @@ static HANDLE exit_event = NULL;
/* clear an object */
#define CLEAR(x) memset(&(x), 0, sizeof(x))
-/* snprintf with guaranteed null termination */
-#define mysnprintf(out, args...) \
- { \
- snprintf (out, sizeof(out), args); \
- out [sizeof (out) - 1] = '\0'; \
- }
-
/*
* Message handling
*/
@@ -98,10 +88,10 @@ static HANDLE exit_event = NULL;
#define M_ERR (MSG_FLAGS_ERROR) // error
/* write error to event log */
-#define MSG(flags, args...) \
+#define MSG(flags, ...) \
{ \
char x_msg[256]; \
- mysnprintf (x_msg, args); \
+ openvpn_snprintf (x_msg, sizeof(x_msg), __VA_ARGS__); \
AddToMessageLog ((flags), x_msg); \
}
@@ -133,6 +123,28 @@ static HANDLE exit_event = NULL;
} \
}
+/*
+ * This is necessary due to certain buggy implementations of snprintf,
+ * that don't guarantee null termination for size > 0.
+ * (copied from ../buffer.c, line 217)
+ * (git: 100644 blob e2f8caab0a5b2a870092c6cd508a1a50c21c3ba3 buffer.c)
+ */
+
+int openvpn_snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list arglist;
+ int len = -1;
+ if (size > 0)
+ {
+ va_start (arglist, format);
+ len = vsnprintf (str, size, format, arglist);
+ va_end (arglist);
+ str[size - 1] = 0;
+ }
+ return (len >= 0 && len < size);
+}
+
+
bool
init_security_attributes_allow_all (struct security_attributes *obj)
{
@@ -275,7 +287,6 @@ VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
LONG status;
DWORD len;
DWORD type;
- char error_string[256];
static const char error_format_str[] =
"Error querying registry key of type REG_SZ: HKLM\\" REG_KEY "\\%s";
@@ -358,7 +369,7 @@ VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
BOOL more_files;
char find_string[MAX_PATH];
- mysnprintf (find_string, "%s\\*", config_dir);
+ openvpn_snprintf (find_string, MAX_PATH, "%s\\*", config_dir);
find_handle = FindFirstFile (find_string, &find_obj);
if (find_handle == INVALID_HANDLE_VALUE)
@@ -400,10 +411,11 @@ VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv)
FindClose (find_handle);
goto finish;
}
- mysnprintf (log_path, "%s\\%s", log_dir, log_file);
+ openvpn_snprintf (log_path, sizeof(log_path),
+ "%s\\%s", log_dir, log_file);
/* construct command line */
- mysnprintf (command_line, PACKAGE " --service %s 1 --config \"%s\"",
+ openvpn_snprintf (command_line, sizeof(command_line), PACKAGE " --service %s 1 --config \"%s\"",
EXIT_EVENT_NAME,
find_obj.cFileName);
diff --git a/sig.c b/sig.c
index aeac739..d73525f 100644
--- a/sig.c
+++ b/sig.c
@@ -185,15 +185,6 @@ signal_handler (const int signum)
signal (signum, signal_handler);
}
-/* temporary signal handler, before we are fully initialized */
-static void
-signal_handler_exit (const int signum)
-{
- msg (M_FATAL,
- "Signal %d (%s) received during initialization, exiting",
- signum, signal_description (signum, NULL));
-}
-
#endif
/* set handlers for unix signals */
diff --git a/socket.c b/socket.c
index 8e58250..6b855c0 100644
--- a/socket.c
+++ b/socket.c
@@ -26,7 +26,6 @@
#include "socket.h"
#include "fdmisc.h"
-#include "thread.h"
#include "misc.h"
#include "gremlin.h"
#include "plugin.h"
@@ -37,10 +36,16 @@
#include "memdbg.h"
const int proto_overhead[] = { /* indexed by PROTO_x */
- IPv4_UDP_HEADER_SIZE,
+ 0,
+ IPv4_UDP_HEADER_SIZE, /* IPv4 */
IPv4_TCP_HEADER_SIZE,
IPv4_TCP_HEADER_SIZE,
- IPv4_TCP_HEADER_SIZE
+#ifdef USE_PF_INET6
+ IPv6_UDP_HEADER_SIZE, /* IPv6 */
+ IPv6_TCP_HEADER_SIZE,
+ IPv6_TCP_HEADER_SIZE,
+ IPv6_TCP_HEADER_SIZE,
+#endif
};
/*
@@ -277,6 +282,201 @@ getaddr_multi (unsigned int flags,
return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr;
}
+#ifdef USE_PF_INET6
+/*
+ * Translate IPv6 addr or hostname into struct addrinfo
+ * If resolve error, try again for
+ * resolve_retry_seconds seconds.
+ */
+bool
+getaddr6 (unsigned int flags,
+ const char *hostname,
+ int resolve_retry_seconds,
+ volatile int *signal_received,
+ int *gai_err,
+ struct sockaddr_in6 *in6)
+{
+ bool success;
+ struct addrinfo hints, *ai;
+ int status;
+ int sigrec = 0;
+ int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
+ struct gc_arena gc = gc_new ();
+
+ ASSERT(in6);
+
+ if (!hostname)
+ hostname = "::";
+
+ if (flags & GETADDR_RANDOMIZE)
+ hostname = hostname_randomize(hostname, &gc);
+
+ if (flags & GETADDR_MSG_VIRT_OUT)
+ msglevel |= M_MSG_VIRT_OUT;
+
+ CLEAR (ai);
+ success = false;
+
+ if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))
+ && !signal_received)
+ signal_received = &sigrec;
+
+ /* try numeric ipv6 addr first */
+ CLEAR(hints);
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_NUMERICHOST;
+ if ((status = getaddrinfo(hostname, NULL, &hints, &ai))==0)
+ {
+ *in6 = *((struct sockaddr_in6 *)(ai->ai_addr));
+ freeaddrinfo(ai);
+ ai = NULL;
+ }
+ if (gai_err)
+ *gai_err = status;
+
+
+ if (status != 0) /* parse as IPv6 address failed? */
+ {
+ const int fail_wait_interval = 5; /* seconds */
+ int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : (resolve_retry_seconds / fail_wait_interval);
+ const char *fmt;
+ int level = 0;
+ int err;
+
+ ai = NULL;
+
+ fmt = "RESOLVE: Cannot resolve host address: %s: %s";
+ if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
+ && !resolve_retry_seconds)
+ fmt = "RESOLVE: Cannot resolve host address: %s: %s (I would have retried this name query if you had specified the --resolv-retry option.)";
+
+ if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
+ {
+ msg (msglevel, "RESOLVE: Cannot parse IPv6 address: %s", hostname);
+ goto done;
+ }
+
+#ifdef ENABLE_MANAGEMENT
+ if (flags & GETADDR_UPDATE_MANAGEMENT_STATE)
+ {
+ if (management)
+ management_set_state (management,
+ OPENVPN_STATE_RESOLVE,
+ NULL,
+ (in_addr_t)0,
+ (in_addr_t)0);
+ }
+#endif
+
+ /*
+ * Resolve hostname
+ */
+ while (true)
+ {
+ /* try hostname lookup */
+ hints.ai_flags = 0;
+ hints.ai_socktype = dnsflags_to_socktype(flags);
+ dmsg (D_SOCKET_DEBUG, "GETADDR6 flags=0x%04x ai_family=%d ai_socktype=%d",
+ flags, hints.ai_family, hints.ai_socktype);
+ err = getaddrinfo(hostname, NULL, &hints, &ai);
+
+ if (gai_err)
+ *gai_err = err;
+
+ if (signal_received)
+ {
+ get_signal (signal_received);
+ if (*signal_received) /* were we interrupted by a signal? */
+ {
+ if (0 == err) {
+ ASSERT(ai);
+ freeaddrinfo(ai);
+ ai = NULL;
+ }
+ if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */
+ {
+ msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt");
+ *signal_received = 0;
+ }
+ else
+ goto done;
+ }
+ }
+
+ /* success? */
+ if (0 == err)
+ break;
+
+ /* resolve lookup failed, should we
+ continue or fail? */
+
+ level = msglevel;
+ if (resolve_retries > 0)
+ level = D_RESOLVE_ERRORS;
+
+ msg (level,
+ fmt,
+ hostname,
+ gai_strerror(err));
+
+ if (--resolve_retries <= 0)
+ goto done;
+
+ openvpn_sleep (fail_wait_interval);
+ }
+
+ ASSERT(ai);
+
+ if (!ai->ai_next)
+ *in6 = *((struct sockaddr_in6*)(ai->ai_addr));
+ else
+ /* more than one address returned */
+ {
+ struct addrinfo *ai_cursor;
+ int n = 0;
+ /* count address list */
+ for (ai_cursor = ai; ai_cursor; ai_cursor = ai_cursor->ai_next) n++;
+ ASSERT (n >= 2);
+
+ msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d ipv6 addresses, choosing one by random",
+ hostname,
+ n);
+
+ /* choose address randomly, for basic load-balancing capability */
+ n--;
+ n %= get_random();
+ for (ai_cursor = ai; n; ai_cursor = ai_cursor->ai_next) n--;
+ *in6 = *((struct sockaddr_in6*)(ai_cursor->ai_addr));
+ }
+
+ freeaddrinfo(ai);
+ ai = NULL;
+
+ /* hostname resolve succeeded */
+ success = true;
+ }
+ else
+ {
+ /* IP address parse succeeded */
+ success = true;
+ }
+
+ done:
+ if (signal_received && *signal_received)
+ {
+ int level = 0;
+ if (flags & GETADDR_FATAL_ON_SIGNAL)
+ level = M_FATAL;
+ else if (flags & GETADDR_WARN_ON_SIGNAL)
+ level = M_WARN;
+ msg (level, "RESOLVE: signal received during DNS resolution attempt");
+ }
+
+ gc_free (&gc);
+ return success;
+}
+#endif /* USE_PF_INET6 */
+
/*
* We do our own inet_aton because the glibc function
* isn't very good about error checking.
@@ -343,6 +543,24 @@ ip_addr_dotted_quad_safe (const char *dotted_quad)
}
}
+bool
+ipv6_addr_safe (const char *ipv6_text_addr)
+{
+ /* verify non-NULL */
+ if (!ipv6_text_addr)
+ return false;
+
+ /* verify length is within limits */
+ if (strlen (ipv6_text_addr) > INET6_ADDRSTRLEN )
+ return false;
+
+ /* verify that string will convert to IPv6 address */
+ {
+ struct in6_addr a6;
+ return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1;
+ }
+}
+
static bool
dns_addr_safe (const char *addr)
{
@@ -411,20 +629,53 @@ update_remote (const char* host,
bool *changed,
const unsigned int sockflags)
{
- if (host && addr)
+ switch(addr->addr.sa.sa_family)
{
- const in_addr_t new_addr = getaddr (
- sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags),
- host,
- 1,
- NULL,
- NULL);
- if (new_addr && addr->sa.sin_addr.s_addr != new_addr)
+ case AF_INET:
+ if (host && addr)
{
- addr->sa.sin_addr.s_addr = new_addr;
- *changed = true;
+ const in_addr_t new_addr = getaddr (
+ sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags),
+ host,
+ 1,
+ NULL,
+ NULL);
+ if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr)
+ {
+ addr->addr.in4.sin_addr.s_addr = new_addr;
+ *changed = true;
+ }
}
- }
+ break;
+#ifdef USE_PF_INET6
+ case AF_INET6:
+ if (host && addr)
+ {
+ struct sockaddr_in6 sin6;
+ CLEAR(sin6);
+ int success = getaddr6 (
+ sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags),
+ host,
+ 1,
+ NULL,
+ NULL,
+ &sin6);
+ if ( success )
+ {
+ if (!IN6_ARE_ADDR_EQUAL(&sin6.sin6_addr, &addr->addr.in6.sin6_addr))
+ {
+ int port = addr->addr.in6.sin6_port;
+ /* ipv6 requires also eg. sin6_scope_id => easier to fully copy and override port */
+ addr->addr.in6 = sin6;
+ addr->addr.in6.sin6_port = port;
+ }
+ }
+ }
+ break;
+#endif
+ default:
+ ASSERT(0);
+ }
}
static int
@@ -611,12 +862,62 @@ create_socket_udp (const unsigned int flags)
else if (flags & SF_USE_IP_PKTINFO)
{
int pad = 1;
- setsockopt (sd, SOL_IP, IP_PKTINFO, (void*)&pad, sizeof(pad));
+#ifdef IP_PKTINFO
+ if (setsockopt (sd, SOL_IP, IP_PKTINFO,
+ (void*)&pad, sizeof(pad)) < 0)
+ msg(M_SOCKERR, "UDP: failed setsockopt for IP_PKTINFO");
+#elif defined(IP_RECVDSTADDR)
+ if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR,
+ (void*)&pad, sizeof(pad)) < 0)
+ msg(M_SOCKERR, "UDP: failed setsockopt for IP_RECVDSTADDR");
+#else
+#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
+#endif
+ }
+#endif
+ return sd;
+}
+
+#ifdef USE_PF_INET6
+static socket_descriptor_t
+create_socket_udp6 (const unsigned int flags)
+{
+ socket_descriptor_t sd;
+
+ if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ msg (M_SOCKERR, "UDP: Cannot create UDP6 socket");
+#if ENABLE_IP_PKTINFO
+ else if (flags & SF_USE_IP_PKTINFO)
+ {
+ int pad = 1;
+ if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (void*)&pad, sizeof(pad)) < 0)
+ msg(M_SOCKERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");
}
#endif
return sd;
}
+static socket_descriptor_t
+create_socket_tcp6 (void)
+{
+ socket_descriptor_t sd;
+
+ if ((sd = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ msg (M_SOCKERR, "Cannot create TCP6 socket");
+
+ /* set SO_REUSEADDR on socket */
+ {
+ int on = 1;
+ if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR,
+ (void *) &on, sizeof (on)) < 0)
+ msg (M_SOCKERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP6 socket");
+ }
+
+ return sd;
+}
+
+#endif
static void
create_socket (struct link_socket *sock)
{
@@ -624,6 +925,7 @@ create_socket (struct link_socket *sock)
if (sock->info.proto == PROTO_UDPv4)
{
sock->sd = create_socket_udp (sock->sockflags);
+ sock->sockflags |= SF_GETADDRINFO_DGRAM;
#ifdef ENABLE_SOCKS
if (sock->socks_proxy)
@@ -635,6 +937,18 @@ create_socket (struct link_socket *sock)
{
sock->sd = create_socket_tcp ();
}
+#ifdef USE_PF_INET6
+ else if (sock->info.proto == PROTO_TCPv6_SERVER
+ || sock->info.proto == PROTO_TCPv6_CLIENT)
+ {
+ sock->sd = create_socket_tcp6 ();
+ }
+ else if (sock->info.proto == PROTO_UDPv6)
+ {
+ sock->sd = create_socket_udp6 (sock->sockflags);
+ sock->sockflags |= SF_GETADDRINFO_DGRAM;
+ }
+#endif
else
{
ASSERT (0);
@@ -672,7 +986,12 @@ socket_do_accept (socket_descriptor_t sd,
struct link_socket_actual *act,
const bool nowait)
{
- socklen_t remote_len = sizeof (act->dest.sa);
+ /* af_addr_size WILL return 0 in this case if AFs other than AF_INET
+ * are compiled because act is empty here.
+ * could use getsockname() to support later remote_len check
+ */
+ socklen_t remote_len_af = af_addr_size(act->dest.addr.sa.sa_family);
+ socklen_t remote_len = sizeof(act->dest.addr);
socket_descriptor_t new_sd = SOCKET_UNDEFINED;
CLEAR (*act);
@@ -680,7 +999,7 @@ socket_do_accept (socket_descriptor_t sd,
#ifdef HAVE_GETPEERNAME
if (nowait)
{
- new_sd = getpeername (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
+ new_sd = getpeername (sd, &act->dest.addr.sa, &remote_len);
if (!socket_defined (new_sd))
msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed");
@@ -693,7 +1012,7 @@ socket_do_accept (socket_descriptor_t sd,
#endif
else
{
- new_sd = accept (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
+ new_sd = accept (sd, &act->dest.addr.sa, &remote_len);
}
#if 0 /* For debugging only, test the effect of accept() failures */
@@ -709,7 +1028,8 @@ socket_do_accept (socket_descriptor_t sd,
{
msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept(%d) failed", sd);
}
- else if (remote_len != sizeof (act->dest.sa))
+ /* only valid if we have remote_len_af!=0 */
+ else if (remote_len_af && remote_len != remote_len_af)
{
msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len);
openvpn_close_socket (new_sd);
@@ -810,7 +1130,7 @@ socket_bind (socket_descriptor_t sd,
{
struct gc_arena gc = gc_new ();
- if (bind (sd, (struct sockaddr *) &local->sa, sizeof (local->sa)))
+ if (bind (sd, &local->addr.sa, af_addr_size(local->addr.sa.sa_family)))
{
const int errnum = openvpn_errno_socket ();
msg (M_FATAL, "%s: Socket bind failed on local address %s: %s",
@@ -831,7 +1151,7 @@ openvpn_connect (socket_descriptor_t sd,
#ifdef CONNECT_NONBLOCK
set_nonblock (sd);
- status = connect (sd, (struct sockaddr *) &remote->sa, sizeof (remote->sa));
+ status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family));
if (status)
status = openvpn_errno_socket ();
if (status == EINPROGRESS)
@@ -889,7 +1209,7 @@ openvpn_connect (socket_descriptor_t sd,
}
}
#else
- status = connect (sd, (struct sockaddr *) &remote->sa, sizeof (remote->sa));
+ status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family));
if (status)
status = openvpn_errno_socket ();
#endif
@@ -967,7 +1287,20 @@ socket_connect (socket_descriptor_t *sd,
if (*signal_received)
goto done;
- *sd = create_socket_tcp ();
+#ifdef USE_PF_INET6
+ switch(local->addr.sa.sa_family)
+ {
+ case PF_INET6:
+ *sd = create_socket_tcp6 ();
+ break;
+ case PF_INET:
+#endif
+ *sd = create_socket_tcp ();
+#ifdef USE_PF_INET6
+ break;
+ }
+#endif
+
if (bind_local)
socket_bind (*sd, local, "TCP Client");
update_remote (remote_dynamic, remote, remote_changed, sockflags);
@@ -1032,15 +1365,54 @@ resolve_bind_local (struct link_socket *sock)
/* resolve local address if undefined */
if (!addr_defined (&sock->info.lsa->local))
{
- sock->info.lsa->local.sa.sin_family = AF_INET;
- sock->info.lsa->local.sa.sin_addr.s_addr =
- (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
+#ifdef USE_PF_INET6
+ /* may return AF_{INET|INET6} guessed from local_host */
+ switch(addr_guess_family(sock->info.proto, sock->local_host))
+ {
+ case AF_INET:
+#endif
+ sock->info.lsa->local.addr.in4.sin_family = AF_INET;
+ sock->info.lsa->local.addr.in4.sin_addr.s_addr =
+ (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
+ sock->local_host,
+ 0,
+ NULL,
+ NULL)
+ : htonl (INADDR_ANY));
+ sock->info.lsa->local.addr.in4.sin_port = htons (sock->local_port);
+#ifdef USE_PF_INET6
+ break;
+ case AF_INET6:
+ {
+ int success;
+ int err;
+ CLEAR(sock->info.lsa->local.addr.in6);
+ if (sock->local_host)
+ {
+ success = getaddr6(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
sock->local_host,
0,
NULL,
- NULL)
- : htonl (INADDR_ANY));
- sock->info.lsa->local.sa.sin_port = htons (sock->local_port);
+ &err,
+ &sock->info.lsa->local.addr.in6);
+ }
+ else
+ {
+ sock->info.lsa->local.addr.in6.sin6_family = AF_INET6;
+ sock->info.lsa->local.addr.in6.sin6_addr = in6addr_any;
+ success = true;
+ }
+ if (!success)
+ {
+ msg (M_FATAL, "getaddr6() failed for local \"%s\": %s",
+ sock->local_host,
+ gai_strerror(err));
+ }
+ sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port);
+ }
+ break;
+ }
+#endif /* USE_PF_INET6 */
}
/* bind to local address/port */
@@ -1063,14 +1435,32 @@ resolve_remote (struct link_socket *sock,
volatile int *signal_received)
{
struct gc_arena gc = gc_new ();
+#ifdef USE_PF_INET6
+ int af;
+#endif
if (!sock->did_resolve_remote)
{
/* resolve remote address if undefined */
if (!addr_defined (&sock->info.lsa->remote))
{
- sock->info.lsa->remote.sa.sin_family = AF_INET;
- sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
+#ifdef USE_PF_INET6
+ af = addr_guess_family(sock->info.proto, sock->remote_host);
+ switch(af)
+ {
+ case AF_INET:
+#endif
+ sock->info.lsa->remote.addr.in4.sin_family = AF_INET;
+ sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0;
+#ifdef USE_PF_INET6
+ break;
+ case AF_INET6:
+ CLEAR(sock->info.lsa->remote.addr.in6);
+ sock->info.lsa->remote.addr.in6.sin6_family = AF_INET6;
+ sock->info.lsa->remote.addr.in6.sin6_addr = in6addr_any;
+ break;
+ }
+#endif
if (sock->remote_host)
{
@@ -1113,13 +1503,31 @@ resolve_remote (struct link_socket *sock,
ASSERT (0);
}
- sock->info.lsa->remote.sa.sin_addr.s_addr = getaddr (
- flags,
- sock->remote_host,
- retry,
- &status,
- signal_received);
-
+#ifdef USE_PF_INET6
+ switch(af)
+ {
+ case AF_INET:
+#endif
+ sock->info.lsa->remote.addr.in4.sin_addr.s_addr = getaddr (
+ flags,
+ sock->remote_host,
+ retry,
+ &status,
+ signal_received);
+#ifdef USE_PF_INET6
+ break;
+ case AF_INET6:
+ status = getaddr6 (
+ flags,
+ sock->remote_host,
+ retry,
+ signal_received,
+ NULL,
+ &sock->info.lsa->remote.addr.in6);
+ break;
+ }
+#endif
+
dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
flags,
phase,
@@ -1139,8 +1547,19 @@ resolve_remote (struct link_socket *sock,
goto done;
}
}
-
- sock->info.lsa->remote.sa.sin_port = htons (sock->remote_port);
+#ifdef USE_PF_INET6
+ switch(af)
+ {
+ case AF_INET:
+#endif
+ sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port);
+#ifdef USE_PF_INET6
+ break;
+ case AF_INET6:
+ sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port);
+ break;
+ }
+#endif
}
/* should we re-use previous active remote address? */
@@ -1257,7 +1676,11 @@ link_socket_init_phase1 (struct link_socket *sock,
if (mode == LS_MODE_TCP_ACCEPT_FROM)
{
ASSERT (accept_from);
- ASSERT (sock->info.proto == PROTO_TCPv4_SERVER);
+ ASSERT (sock->info.proto == PROTO_TCPv4_SERVER
+#ifdef USE_PF_INET6
+ || sock->info.proto == PROTO_TCPv6_SERVER
+#endif
+ );
ASSERT (!sock->inetd);
sock->sd = accept_from->sd;
}
@@ -1314,7 +1737,11 @@ link_socket_init_phase1 (struct link_socket *sock,
/* were we started by inetd or xinetd? */
if (sock->inetd)
{
- ASSERT (sock->info.proto != PROTO_TCPv4_CLIENT);
+ ASSERT (sock->info.proto != PROTO_TCPv4_CLIENT
+#ifdef USE_PF_INET6
+ && sock->info.proto != PROTO_TCPv6_CLIENT
+#endif
+ );
ASSERT (socket_defined (inetd_socket_descriptor));
sock->sd = inetd_socket_descriptor;
}
@@ -1363,7 +1790,34 @@ link_socket_init_phase2 (struct link_socket *sock,
/* were we started by inetd or xinetd? */
if (sock->inetd)
{
- if (sock->info.proto == PROTO_TCPv4_SERVER)
+ if (sock->info.proto == PROTO_TCPv4_SERVER
+#ifdef USE_PF_INET6
+ || sock->info.proto == PROTO_TCPv6_SERVER
+#endif
+ ) {
+ /* AF_INET as default (and fallback) for inetd */
+ sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET;
+#ifdef USE_PF_INET6
+#ifdef HAVE_GETSOCKNAME
+ {
+ /* inetd: hint family type for dest = local's */
+ struct openvpn_sockaddr local_addr;
+ socklen_t addrlen = sizeof(local_addr);
+ if (getsockname (sock->sd, (struct sockaddr *)&local_addr, &addrlen) == 0) {
+ sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family;
+ dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)",
+ proto2ascii(sock->info.proto, false), local_addr.addr.sa.sa_family,
+ sock->sd);
+ } else
+ msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
+ proto2ascii(sock->info.proto, false), sock->sd);
+ }
+#else
+ msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() "
+ "function, using AF_INET",
+ proto2ascii(sock->info.proto, false));
+#endif
+#endif
sock->sd =
socket_listen_accept (sock->sd,
&sock->info.lsa->actual,
@@ -1373,6 +1827,7 @@ link_socket_init_phase2 (struct link_socket *sock,
false,
sock->inetd == INETD_NOWAIT,
signal_received);
+ }
ASSERT (!remote_changed);
if (*signal_received)
goto done;
@@ -1385,7 +1840,11 @@ link_socket_init_phase2 (struct link_socket *sock,
goto done;
/* TCP client/server */
- if (sock->info.proto == PROTO_TCPv4_SERVER)
+ if (sock->info.proto == PROTO_TCPv4_SERVER
+#ifdef USE_PF_INET6
+ ||sock->info.proto == PROTO_TCPv6_SERVER
+#endif
+ )
{
switch (sock->mode)
{
@@ -1420,7 +1879,11 @@ link_socket_init_phase2 (struct link_socket *sock,
ASSERT (0);
}
}
- else if (sock->info.proto == PROTO_TCPv4_CLIENT)
+ else if (sock->info.proto == PROTO_TCPv4_CLIENT
+#ifdef USE_PF_INET6
+ ||sock->info.proto == PROTO_TCPv6_CLIENT
+#endif
+ )
{
#ifdef GENERAL_PROXY_SUPPORT
@@ -1507,8 +1970,8 @@ link_socket_init_phase2 (struct link_socket *sock,
sock->remote_port = sock->proxy_dest_port;
sock->did_resolve_remote = false;
- sock->info.lsa->actual.dest.sa.sin_addr.s_addr = 0;
- sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
+ addr_zero_host(&sock->info.lsa->actual.dest);
+ addr_zero_host(&sock->info.lsa->remote);
resolve_remote (sock, 1, NULL, signal_received);
@@ -1523,7 +1986,7 @@ link_socket_init_phase2 (struct link_socket *sock,
if (remote_changed)
{
msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment");
- sock->info.lsa->remote.sa.sin_addr.s_addr = sock->info.lsa->actual.dest.sa.sin_addr.s_addr;
+ addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest);
}
}
@@ -1688,7 +2151,7 @@ link_socket_connection_initiated (const struct buffer *buf,
{
struct argv argv = argv_new ();
ipchange_fmt (false, &argv, info, &gc);
- if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+ if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es, -1, NULL) != OPENVPN_PLUGIN_FUNC_SUCCESS)
msg (M_WARN, "WARNING: ipchange plugin call failed");
argv_reset (&argv);
}
@@ -1699,7 +2162,7 @@ link_socket_connection_initiated (const struct buffer *buf,
struct argv argv = argv_new ();
setenv_str (es, "script_type", "ipchange");
ipchange_fmt (true, &argv, info, &gc);
- openvpn_execve_check (&argv, es, S_SCRIPT, "ip-change command failed");
+ openvpn_run_script (&argv, es, 0, "--ipchange");
argv_reset (&argv);
}
@@ -1713,13 +2176,20 @@ link_socket_bad_incoming_addr (struct buffer *buf,
{
struct gc_arena gc = gc_new ();
- msg (D_LINK_ERRORS,
- "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",
- print_link_socket_actual (from_addr, &gc),
- (int)from_addr->dest.sa.sin_family,
- print_sockaddr (&info->lsa->remote, &gc));
+ switch(from_addr->dest.addr.sa.sa_family)
+ {
+ case AF_INET:
+#ifdef USE_PF_INET6
+ case AF_INET6:
+#endif
+ msg (D_LINK_ERRORS,
+ "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",
+ print_link_socket_actual (from_addr, &gc),
+ (int)from_addr->dest.addr.sa.sa_family,
+ print_sockaddr (&info->lsa->remote, &gc));
+ break;
+ }
buf->len = 0;
-
gc_free (&gc);
}
@@ -1734,10 +2204,25 @@ link_socket_current_remote (const struct link_socket_info *info)
{
const struct link_socket_addr *lsa = info->lsa;
+/*
+ * This logic supports "redirect-gateway" semantic, which
+ * makes sense only for PF_INET routes over PF_INET endpoints
+ *
+ * Maybe in the future consider PF_INET6 endpoints also ...
+ * by now just ignore it
+ *
+ */
+#ifdef USE_PF_INET6
+ if (lsa->actual.dest.addr.sa.sa_family != AF_INET)
+ return IPV4_INVALID_ADDR;
+#else
+ ASSERT (lsa->actual.dest.addr.sa.sa_family == AF_INET);
+#endif
+
if (link_socket_actual_defined (&lsa->actual))
- return ntohl (lsa->actual.dest.sa.sin_addr.s_addr);
+ return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr);
else if (addr_defined (&lsa->remote))
- return ntohl (lsa->remote.sa.sin_addr.s_addr);
+ return ntohl (lsa->remote.addr.in4.sin_addr.s_addr);
else
return 0;
}
@@ -1898,7 +2383,7 @@ stream_buf_added (struct stream_buf *sb,
if (sb->len < 1 || sb->len > sb->maxlen)
{
- msg (M_WARN, "WARNING: Bad encapsulated packet length from peer (%d), which must be > 0 and <= %d -- please ensure that --tun-mtu or --link-mtu is equal on both peers -- this condition could also indicate a possible active attack on the TCP link -- [Attemping restart...]", sb->len, sb->maxlen);
+ msg (M_WARN, "WARNING: Bad encapsulated packet length from peer (%d), which must be > 0 and <= %d -- please ensure that --tun-mtu or --link-mtu is equal on both peers -- this condition could also indicate a possible active attack on the TCP link -- [Attempting restart...]", sb->len, sb->maxlen);
stream_buf_reset (sb);
sb->error = true;
return false;
@@ -1964,28 +2449,61 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr,
const unsigned int flags,
struct gc_arena *gc)
{
- if (addr)
+ struct buffer out = alloc_buf_gc (128, gc);
+ bool addr_is_defined;
+ addr_is_defined = addr_defined (addr);
+ if (!addr_is_defined) {
+ return "[undef]";
+ }
+#ifdef USE_PF_INET6
+ switch(addr->addr.sa.sa_family)
{
- struct buffer out = alloc_buf_gc (64, gc);
- const int port = ntohs (addr->sa.sin_port);
+ case AF_INET:
+#endif
+ {
+ const int port= ntohs (addr->addr.in4.sin_port);
+ buf_puts (&out, "[AF_INET]");
- mutex_lock_static (L_INET_NTOA);
- if (!(flags & PS_DONT_SHOW_ADDR))
- buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]"));
- mutex_unlock_static (L_INET_NTOA);
+ if (!(flags & PS_DONT_SHOW_ADDR))
+ buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]"));
+
+ if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
+ && port)
+ {
+ if (separator)
+ buf_printf (&out, "%s", separator);
- if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
- && port)
+ buf_printf (&out, "%d", port);
+ }
+ }
+#ifdef USE_PF_INET6
+ break;
+ case AF_INET6:
{
- if (separator)
- buf_printf (&out, "%s", separator);
+ const int port= ntohs (addr->addr.in6.sin6_port);
+ char buf[INET6_ADDRSTRLEN] = "";
+ buf_puts (&out, "[AF_INET6]");
+ if (addr_is_defined)
+ {
+ getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
+ buf, sizeof (buf), NULL, 0, NI_NUMERICHOST);
+ buf_puts (&out, buf);
+ }
+ if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED)))
+ && port)
+ {
+ if (separator)
+ buf_puts (&out, separator);
- buf_printf (&out, "%d", port);
+ buf_printf (&out, "%d", port);
+ }
}
- return BSTR (&out);
+ break;
+ default:
+ ASSERT(0);
}
- else
- return "[NULL]";
+#endif
+ return BSTR (&out);
}
const char *
@@ -1994,6 +2512,10 @@ print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena
return print_link_socket_actual_ex (act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc);
}
+#ifndef IF_NAMESIZE
+#define IF_NAMESIZE 16
+#endif
+
const char *
print_link_socket_actual_ex (const struct link_socket_actual *act,
const char *separator,
@@ -2002,15 +2524,54 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,
{
if (act)
{
+ char ifname[IF_NAMESIZE] = "[undef]";
struct buffer out = alloc_buf_gc (128, gc);
buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc));
#if ENABLE_IP_PKTINFO
- if ((flags & PS_SHOW_PKTINFO) && act->pi.ipi_spec_dst.s_addr)
+ if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
{
- struct openvpn_sockaddr sa;
- CLEAR (sa);
- sa.sa.sin_addr = act->pi.ipi_spec_dst;
- buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc));
+#ifdef USE_PF_INET6
+ switch(act->dest.addr.sa.sa_family)
+ {
+ case AF_INET:
+#endif
+ {
+ struct openvpn_sockaddr sa;
+ CLEAR (sa);
+ sa.addr.in4.sin_family = AF_INET;
+#ifdef IP_PKTINFO
+ sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
+ if_indextoname(act->pi.in4.ipi_ifindex, ifname);
+#elif defined(IP_RECVDSTADDR)
+ sa.addr.in4.sin_addr = act->pi.in4;
+ ifname[0]=0;
+#else
+#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
+#endif
+ buf_printf (&out, " (via %s%%%s)",
+ print_sockaddr_ex (&sa, separator, 0, gc),
+ ifname);
+ }
+#ifdef USE_PF_INET6
+ break;
+ case AF_INET6:
+ {
+ struct sockaddr_in6 sin6;
+ char buf[INET6_ADDRSTRLEN] = "[undef]";
+ CLEAR(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = act->pi.in6.ipi6_addr;
+ if_indextoname(act->pi.in6.ipi6_ifindex, ifname);
+ if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6),
+ buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) == 0)
+ buf_printf (&out, " (via %s%%%s)", buf, ifname);
+ else
+ buf_printf (&out, " (via [getnameinfo() err]%%%s)", ifname);
+ }
+ break;
+ }
+#endif /* USE_PF_INET6 */
+
}
#endif
return BSTR (&out);
@@ -2034,33 +2595,100 @@ print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc)
CLEAR (ia);
ia.s_addr = (flags & IA_NET_ORDER) ? addr : htonl (addr);
- mutex_lock_static (L_INET_NTOA);
buf_printf (&out, "%s", inet_ntoa (ia));
- mutex_unlock_static (L_INET_NTOA);
}
return BSTR (&out);
}
+/*
+ * Convert an in6_addr in host byte order
+ * to an ascii representation of an IPv6 address
+ */
+const char *
+print_in6_addr (struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
+{
+ struct buffer out = alloc_buf_gc (64, gc);
+ char tmp_out_buf[64]; /* inet_ntop wants pointer to buffer */
+
+ if ( memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 ||
+ !(flags & IA_EMPTY_IF_UNDEF))
+ {
+ inet_ntop (AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1);
+ buf_printf (&out, "%s", tmp_out_buf );
+ }
+ return BSTR (&out);
+}
+
+/* add some offset to an ipv6 address
+ * (add in steps of 32 bits, taking overflow into next round)
+ */
+#ifndef s6_addr32
+# ifdef TARGET_SOLARIS
+# define s6_addr32 _S6_un._S6_u32
+# else
+# define s6_addr32 __u6_addr.__u6_addr32
+# endif
+#endif
+#ifndef UINT32_MAX
+# define UINT32_MAX (4294967295U)
+#endif
+struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add )
+{
+ int i;
+ uint32_t h;
+
+ for( i=3; i>=0 && add > 0 ; i-- )
+ {
+ h = ntohl( base.s6_addr32[i] );
+ base.s6_addr32[i] = htonl( (h+add) & UINT32_MAX );
+ /* 32-bit overrun?
+ * caveat: can't do "h+add > UINT32_MAX" with 32bit math!
+ */
+ add = ( h > UINT32_MAX - add )? 1: 0;
+ }
+ return base;
+}
+
/* set environmental variables for ip/port in *addr */
void
setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags)
{
char name_buf[256];
- if (flags & SA_IP_PORT)
- openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix);
- else
- openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix);
+#ifdef USE_PF_INET6
+ char buf[128];
+ switch(addr->addr.sa.sa_family)
+ {
+ case AF_INET:
+#endif
+ if (flags & SA_IP_PORT)
+ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix);
+ else
+ openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix);
- mutex_lock_static (L_INET_NTOA);
- setenv_str (es, name_buf, inet_ntoa (addr->sa.sin_addr));
- mutex_unlock_static (L_INET_NTOA);
+ setenv_str (es, name_buf, inet_ntoa (addr->addr.in4.sin_addr));
- if ((flags & SA_IP_PORT) && addr->sa.sin_port)
- {
- openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
- setenv_int (es, name_buf, ntohs (addr->sa.sin_port));
+ if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port)
+ {
+ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
+ setenv_int (es, name_buf, ntohs (addr->addr.in4.sin_port));
+ }
+#ifdef USE_PF_INET6
+ break;
+ case AF_INET6:
+ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix);
+ getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
+ buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+ setenv_str (es, name_buf, buf);
+
+ if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port)
+ {
+ openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
+ setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port));
+ }
+ break;
}
+#endif
}
void
@@ -2070,7 +2698,8 @@ setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, c
{
struct openvpn_sockaddr si;
CLEAR (si);
- si.sa.sin_addr.s_addr = htonl (addr);
+ si.addr.in4.sin_family = AF_INET;
+ si.addr.in4.sin_addr.s_addr = htonl (addr);
setenv_sockaddr (es, name_prefix, &si, flags);
}
}
@@ -2091,16 +2720,63 @@ setenv_link_socket_actual (struct env_set *es,
struct proto_names {
const char *short_form;
const char *display_form;
+ bool is_dgram;
+ bool is_net;
+ unsigned short proto_af;
};
/* Indexed by PROTO_x */
-static const struct proto_names proto_names[] = {
- {"udp", "UDPv4"},
- {"tcp-server", "TCPv4_SERVER"},
- {"tcp-client", "TCPv4_CLIENT"},
- {"tcp", "TCPv4"}
+static const struct proto_names proto_names[PROTO_N] = {
+ {"proto-uninitialized", "proto-NONE",0,0, AF_UNSPEC},
+ {"udp", "UDPv4",1,1, AF_INET},
+ {"tcp-server", "TCPv4_SERVER",0,1, AF_INET},
+ {"tcp-client", "TCPv4_CLIENT",0,1, AF_INET},
+ {"tcp", "TCPv4",0,1, AF_INET},
+#ifdef USE_PF_INET6
+ {"udp6" ,"UDPv6",1,1, AF_INET6},
+ {"tcp6-server","TCPv6_SERVER",0,1, AF_INET6},
+ {"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6},
+ {"tcp6" ,"TCPv6",0,1, AF_INET6},
+#endif
};
+bool
+proto_is_net(int proto)
+{
+ if (proto < 0 || proto >= PROTO_N)
+ ASSERT(0);
+ return proto_names[proto].is_net;
+}
+bool
+proto_is_dgram(int proto)
+{
+ if (proto < 0 || proto >= PROTO_N)
+ ASSERT(0);
+ return proto_names[proto].is_dgram;
+}
+bool
+proto_is_udp(int proto)
+{
+ if (proto < 0 || proto >= PROTO_N)
+ ASSERT(0);
+ return proto_names[proto].is_dgram&&proto_names[proto].is_net;
+}
+bool
+proto_is_tcp(int proto)
+{
+ if (proto < 0 || proto >= PROTO_N)
+ ASSERT(0);
+ return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net;
+}
+
+unsigned short
+proto_sa_family(int proto)
+{
+ if (proto < 0 || proto >= PROTO_N)
+ ASSERT(0);
+ return proto_names[proto].proto_af;
+}
+
int
ascii2proto (const char* proto_name)
{
@@ -2140,6 +2816,45 @@ proto2ascii_all (struct gc_arena *gc)
return BSTR (&out);
}
+int
+addr_guess_family(int proto, const char *name)
+{
+#ifdef USE_PF_INET6
+ unsigned short ret;
+#endif
+ if (proto)
+ {
+ return proto_sa_family(proto); /* already stamped */
+ }
+#ifdef USE_PF_INET6
+ 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;
+ }
+ }
+#endif
+ return AF_INET; /* default */
+}
+const char *
+addr_family_name (int af)
+{
+ switch (af)
+ {
+ case AF_INET: return "AF_INET";
+ case AF_INET6: return "AF_INET6";
+ }
+ return "AF_UNSPEC";
+}
+
/*
* Given a local proto, return local proto
* if !remote, or compatible remote proto
@@ -2154,10 +2869,15 @@ proto_remote (int proto, bool remote)
ASSERT (proto >= 0 && proto < PROTO_N);
if (remote)
{
- if (proto == PROTO_TCPv4_SERVER)
- return PROTO_TCPv4_CLIENT;
- if (proto == PROTO_TCPv4_CLIENT)
- return PROTO_TCPv4_SERVER;
+ switch (proto)
+ {
+ case PROTO_TCPv4_SERVER: return PROTO_TCPv4_CLIENT;
+ case PROTO_TCPv4_CLIENT: return PROTO_TCPv4_SERVER;
+#ifdef USE_PF_INET6
+ case PROTO_TCPv6_SERVER: return PROTO_TCPv6_CLIENT;
+ case PROTO_TCPv6_CLIENT: return PROTO_TCPv6_SERVER;
+#endif
+ }
}
return proto;
}
@@ -2216,10 +2936,29 @@ link_socket_read_tcp (struct link_socket *sock,
#if ENABLE_IP_PKTINFO
#pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */
-struct openvpn_pktinfo
+struct openvpn_in4_pktinfo
{
struct cmsghdr cmsghdr;
- struct in_pktinfo in_pktinfo;
+#ifdef HAVE_IN_PKTINFO
+ struct in_pktinfo pi4;
+#endif
+#ifdef IP_RECVDSTADDR
+ struct in_addr pi4;
+#endif
+};
+#ifdef USE_PF_INET6
+struct openvpn_in6_pktinfo
+{
+ struct cmsghdr cmsghdr;
+ struct in6_pktinfo pi6;
+};
+#endif
+
+union openvpn_pktinfo {
+ struct openvpn_in4_pktinfo msgpi4;
+#ifdef USE_PF_INET6
+ struct openvpn_in6_pktinfo msgpi6;
+#endif
};
#pragma pack()
@@ -2230,18 +2969,18 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
struct link_socket_actual *from)
{
struct iovec iov;
- struct openvpn_pktinfo opi;
+ union openvpn_pktinfo opi;
struct msghdr mesg;
- socklen_t fromlen = sizeof (from->dest.sa);
+ socklen_t fromlen = sizeof (from->dest.addr);
iov.iov_base = BPTR (buf);
iov.iov_len = maxsize;
mesg.msg_iov = &iov;
mesg.msg_iovlen = 1;
- mesg.msg_name = &from->dest.sa;
+ mesg.msg_name = &from->dest.addr;
mesg.msg_namelen = fromlen;
mesg.msg_control = &opi;
- mesg.msg_controllen = sizeof (opi);
+ mesg.msg_controllen = sizeof opi;
buf->len = recvmsg (sock->sd, &mesg, 0);
if (buf->len >= 0)
{
@@ -2250,14 +2989,39 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
cmsg = CMSG_FIRSTHDR (&mesg);
if (cmsg != NULL
&& CMSG_NXTHDR (&mesg, cmsg) == NULL
+#ifdef IP_PKTINFO
&& cmsg->cmsg_level == SOL_IP
&& cmsg->cmsg_type == IP_PKTINFO
- && cmsg->cmsg_len >= sizeof (opi))
+#elif defined(IP_RECVDSTADDR)
+ && cmsg->cmsg_level == IPPROTO_IP
+ && cmsg->cmsg_type == IP_RECVDSTADDR
+#else
+#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
+#endif
+ && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo))
{
+#ifdef IP_PKTINFO
struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
- from->pi.ipi_ifindex = pkti->ipi_ifindex;
- from->pi.ipi_spec_dst = pkti->ipi_spec_dst;
+ from->pi.in4.ipi_ifindex = pkti->ipi_ifindex;
+ from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst;
+#elif defined(IP_RECVDSTADDR)
+ from->pi.in4 = *(struct in_addr*) CMSG_DATA (cmsg);
+#else
+#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
+#endif
+ }
+#ifdef USE_PF_INET6
+ else if (cmsg != NULL
+ && CMSG_NXTHDR (&mesg, cmsg) == NULL
+ && cmsg->cmsg_level == IPPROTO_IPV6
+ && cmsg->cmsg_type == IPV6_PKTINFO
+ && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo))
+ {
+ struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
+ from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex;
+ from->pi.in6.ipi6_addr = pkti6->ipi6_addr;
}
+#endif
}
return fromlen;
}
@@ -2269,18 +3033,20 @@ link_socket_read_udp_posix (struct link_socket *sock,
int maxsize,
struct link_socket_actual *from)
{
- socklen_t fromlen = sizeof (from->dest.sa);
- from->dest.sa.sin_addr.s_addr = 0;
+ socklen_t fromlen = sizeof (from->dest.addr);
+ socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto));
+ addr_zero_host(&from->dest);
ASSERT (buf_safe (buf, maxsize));
#if ENABLE_IP_PKTINFO
- if (sock->sockflags & SF_USE_IP_PKTINFO)
+ /* Both PROTO_UDPv4 and PROTO_UDPv6 */
+ if (proto_is_udp(sock->info.proto) && sock->sockflags & SF_USE_IP_PKTINFO)
fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from);
else
#endif
buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0,
- (struct sockaddr *) &from->dest.sa, &fromlen);
- if (fromlen != sizeof (from->dest.sa))
- bad_address_length (fromlen, sizeof (from->dest.sa));
+ &from->dest.addr.sa, &fromlen);
+ if (buf->len >= 0 && expectedlen && fromlen != expectedlen)
+ bad_address_length (fromlen, expectedlen);
return buf->len;
}
@@ -2317,26 +3083,64 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct iovec iov;
struct msghdr mesg;
struct cmsghdr *cmsg;
- struct in_pktinfo *pkti;
- struct openvpn_pktinfo opi;
iov.iov_base = BPTR (buf);
iov.iov_len = BLEN (buf);
mesg.msg_iov = &iov;
mesg.msg_iovlen = 1;
- mesg.msg_name = &to->dest.sa;
- mesg.msg_namelen = sizeof (to->dest.sa);
- mesg.msg_control = &opi;
- mesg.msg_controllen = sizeof (opi);
- mesg.msg_flags = 0;
- cmsg = CMSG_FIRSTHDR (&mesg);
- cmsg->cmsg_len = sizeof (opi);
- cmsg->cmsg_level = SOL_IP;
- cmsg->cmsg_type = IP_PKTINFO;
- pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
- pkti->ipi_ifindex = to->pi.ipi_ifindex;
- pkti->ipi_spec_dst = to->pi.ipi_spec_dst;
- pkti->ipi_addr.s_addr = 0;
+ switch (sock->info.lsa->remote.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_flags = 0;
+ 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;
+ {
+ struct in_pktinfo *pkti;
+ pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
+ pkti->ipi_ifindex = to->pi.in4.ipi_ifindex;
+ pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst;
+ pkti->ipi_addr.s_addr = 0;
+ }
+#elif defined(IP_RECVDSTADDR)
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_RECVDSTADDR;
+ *(struct in_addr *) CMSG_DATA (cmsg) = to->pi.in4;
+#else
+#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
+#endif
+ break;
+ }
+#ifdef USE_PF_INET6
+ 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_flags = 0;
+ cmsg = CMSG_FIRSTHDR (&mesg);
+ cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo);
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
+ pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex;
+ pkti6->ipi6_addr = to->pi.in6.ipi6_addr;
+ break;
+ }
+#endif
+ default: ASSERT(0);
+ }
return sendmsg (sock->sd, &mesg, 0);
}
@@ -2348,6 +3152,58 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
#ifdef WIN32
+/*
+ * inet_ntop() and inet_pton() wrap-implementations using
+ * WSAAddressToString() and WSAStringToAddress() functions
+ */
+const char *
+inet_ntop(int af, const void *src, char *dst, socklen_t size)
+{
+ struct sockaddr_storage ss;
+ unsigned long s = size;
+
+ CLEAR(ss);
+ ss.ss_family = af;
+
+ switch(af) {
+ case AF_INET:
+ ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
+ break;
+ default:
+ ASSERT (0);
+ }
+ // cannot direclty use &size because of strict aliasing rules
+ return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)?
+ dst : NULL;
+}
+
+int
+inet_pton(int af, const char *src, void *dst)
+{
+ struct sockaddr_storage ss;
+ int size = sizeof(ss);
+ char src_copy[INET6_ADDRSTRLEN+1];
+
+ CLEAR(ss);
+ // stupid non-const API
+ strncpynt(src_copy, src, INET6_ADDRSTRLEN+1);
+
+ if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) {
+ switch(af) {
+ case AF_INET:
+ *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
+ return 1;
+ case AF_INET6:
+ *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
+ return 1;
+ }
+ }
+ return 0;
+}
+
int
socket_recv_queue (struct link_socket *sock, int maxsize)
{
@@ -2357,11 +3213,11 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
int status;
/* reset buf to its initial state */
- if (sock->info.proto == PROTO_UDPv4)
+ if (proto_is_udp(sock->info.proto))
{
sock->reads.buf = sock->reads.buf_init;
}
- else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER)
+ else if (proto_is_tcp(sock->info.proto))
{
stream_buf_get_next (&sock->stream_buf, &sock->reads.buf);
}
@@ -2381,10 +3237,15 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
ASSERT (ResetEvent (sock->reads.overlapped.hEvent));
sock->reads.flags = 0;
- if (sock->info.proto == PROTO_UDPv4)
+ if (proto_is_udp(sock->info.proto))
{
sock->reads.addr_defined = true;
- sock->reads.addrlen = sizeof (sock->reads.addr);
+#ifdef USE_PF_INET6
+ if (sock->info.proto == PROTO_UDPv6)
+ sock->reads.addrlen = sizeof (sock->reads.addr6);
+ else
+#endif
+ sock->reads.addrlen = sizeof (sock->reads.addr);
status = WSARecvFrom(
sock->sd,
wsabuf,
@@ -2396,7 +3257,7 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
&sock->reads.overlapped,
NULL);
}
- else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER)
+ else if (proto_is_tcp(sock->info.proto))
{
sock->reads.addr_defined = false;
status = WSARecv(
@@ -2416,8 +3277,14 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
if (!status) /* operation completed immediately? */
{
+#ifdef USE_PF_INET6
+ int addrlen = af_addr_size(sock->info.lsa->local.addr.sa.sa_family);
+ if (sock->reads.addr_defined && sock->reads.addrlen != addrlen)
+ bad_address_length (sock->reads.addrlen, addrlen);
+#else
if (sock->reads.addr_defined && sock->reads.addrlen != sizeof (sock->reads.addr))
bad_address_length (sock->reads.addrlen, sizeof (sock->reads.addr));
+#endif
sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
@@ -2476,12 +3343,22 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li
ASSERT (ResetEvent (sock->writes.overlapped.hEvent));
sock->writes.flags = 0;
- if (sock->info.proto == PROTO_UDPv4)
+ if (proto_is_udp(sock->info.proto))
{
/* set destination address for UDP writes */
sock->writes.addr_defined = true;
- sock->writes.addr = to->dest.sa;
- sock->writes.addrlen = sizeof (sock->writes.addr);
+#ifdef USE_PF_INET6
+ if (sock->info.proto == PROTO_UDPv6)
+ {
+ sock->writes.addr6 = to->dest.addr.in6;
+ sock->writes.addrlen = sizeof (sock->writes.addr6);
+ }
+ else
+#endif
+ {
+ sock->writes.addr = to->dest.addr.in4;
+ sock->writes.addrlen = sizeof (sock->writes.addr);
+ }
status = WSASendTo(
sock->sd,
@@ -2494,7 +3371,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li
&sock->writes.overlapped,
NULL);
}
- else if (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_TCPv4_SERVER)
+ else if (proto_is_tcp(sock->info.proto))
{
/* destination address for TCP writes was established on connection initiation */
sock->writes.addr_defined = false;
@@ -2633,13 +3510,44 @@ socket_finalize (SOCKET s,
if (from)
{
if (ret >= 0 && io->addr_defined)
+#ifdef USE_PF_INET6
+ {
+ /* TODO(jjo): streamline this mess */
+ /* in this func we dont have relevant info about the PF_ of this
+ * endpoint, as link_socket_actual will be zero for the 1st received packet
+ *
+ * Test for inets PF_ possible sizes
+ */
+ switch (io->addrlen)
+ {
+ case sizeof(struct sockaddr_in):
+ case sizeof(struct sockaddr_in6):
+ /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6 */
+ case sizeof(struct sockaddr_in6)-4:
+ break;
+ default:
+ bad_address_length (io->addrlen, af_addr_size(io->addr.sin_family));
+ }
+
+ switch (io->addr.sin_family)
+ {
+ case AF_INET:
+ from->dest.addr.in4 = io->addr;
+ break;
+ case AF_INET6:
+ from->dest.addr.in6 = io->addr6;
+ break;
+ }
+ }
+#else
{
if (io->addrlen != sizeof (io->addr))
bad_address_length (io->addrlen, sizeof (io->addr));
- from->dest.sa = io->addr;
+ from->dest.addr.in4 = io->addr;
}
+#endif
else
- CLEAR (from->dest.sa);
+ CLEAR (from->dest.addr);
}
if (buf)
diff --git a/socket.h b/socket.h
index eef98d1..33da53c 100644
--- a/socket.h
+++ b/socket.h
@@ -70,7 +70,13 @@ typedef uint16_t packet_size_type;
struct openvpn_sockaddr
{
/*int dummy;*/ /* add offset to force a bug if sa not explicitly dereferenced */
- struct sockaddr_in sa;
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in in4;
+#ifdef USE_PF_INET6
+ struct sockaddr_in6 in6;
+#endif
+ } addr;
};
/* actual address of remote, based on source address of received packets */
@@ -79,7 +85,17 @@ struct link_socket_actual
/*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */
struct openvpn_sockaddr dest;
#if ENABLE_IP_PKTINFO
- struct in_pktinfo pi;
+ union {
+#ifdef HAVE_IN_PKTINFO
+ struct in_pktinfo in4;
+#endif
+#ifdef IP_RECVDSTADDR
+ struct in_addr in4;
+#endif
+#ifdef USE_PF_INET6
+ struct in6_pktinfo in6;
+#endif
+ } pi;
#endif
};
@@ -199,6 +215,7 @@ struct link_socket
# define SF_TCP_NODELAY (1<<1)
# define SF_PORT_SHARE (1<<2)
# define SF_HOST_RANDOMIZE (1<<3)
+# define SF_GETADDRINFO_DGRAM (1<<4)
unsigned int sockflags;
/* for stream sockets */
@@ -351,6 +368,8 @@ const char *print_link_socket_actual (const struct link_socket_actual *act,
#define IA_EMPTY_IF_UNDEF (1<<0)
#define IA_NET_ORDER (1<<1)
const char *print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc);
+const char *print_in6_addr (struct in6_addr addr6, unsigned int flags, struct gc_arena *gc);
+struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add );
#define SA_IP_PORT (1<<0)
#define SA_SET_IF_NONZERO (1<<1)
@@ -371,6 +390,12 @@ void setenv_link_socket_actual (struct env_set *es,
void bad_address_length (int actual, int expected);
+#ifdef USE_PF_INET6
+/* IPV4_INVALID_ADDR: returned by link_socket_current_remote()
+ * to ease redirect-gateway logic for ipv4 tunnels on ipv6 endpoints
+ */
+#define IPV4_INVALID_ADDR 0xffffffff
+#endif
in_addr_t link_socket_current_remote (const struct link_socket_info *info);
void link_socket_connection_initiated (const struct buffer *buf,
@@ -404,12 +429,21 @@ int openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr);
bool ip_addr_dotted_quad_safe (const char *dotted_quad);
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 (void);
socket_descriptor_t socket_do_accept (socket_descriptor_t sd,
struct link_socket_actual *act,
const bool nowait);
+/*
+ * proto related
+ */
+bool proto_is_net(int proto);
+bool proto_is_dgram(int proto);
+bool proto_is_udp(int proto);
+bool proto_is_tcp(int proto);
+
#if UNIX_SOCK_SUPPORT
@@ -455,6 +489,11 @@ struct resolve_list {
#define GETADDR_UPDATE_MANAGEMENT_STATE (1<<8)
#define GETADDR_RANDOMIZE (1<<9)
+/* [ab]use flags bits to get socktype info downstream */
+/* TODO(jjo): resolve tradeoff between hackiness|args-overhead */
+#define GETADDR_DGRAM (1<<10)
+#define dnsflags_to_socktype(flags) ((flags & GETADDR_DGRAM) ? SOCK_DGRAM : SOCK_STREAM)
+
in_addr_t getaddr (unsigned int flags,
const char *hostname,
int resolve_retry_seconds,
@@ -472,23 +511,38 @@ in_addr_t getaddr_multi (unsigned int flags,
* Transport protocol naming and other details.
*/
-#define PROTO_UDPv4 0
-#define PROTO_TCPv4_SERVER 1
-#define PROTO_TCPv4_CLIENT 2
-#define PROTO_TCPv4 3
-#define PROTO_N 4
+/*
+ * Use enum's instead of #define to allow for easier
+ * optional proto support
+ */
+enum proto_num {
+ PROTO_NONE, /* catch for uninitialized */
+ PROTO_UDPv4,
+ PROTO_TCPv4_SERVER,
+ PROTO_TCPv4_CLIENT,
+ PROTO_TCPv4,
+#ifdef USE_PF_INET6
+ PROTO_UDPv6,
+ PROTO_TCPv6_SERVER,
+ PROTO_TCPv6_CLIENT,
+ PROTO_TCPv6,
+#endif
+ PROTO_N
+};
int ascii2proto (const char* proto_name);
const char *proto2ascii (int proto, bool display_form);
const char *proto2ascii_all (struct gc_arena *gc);
int proto_remote (int proto, bool remote);
+const char *addr_family_name(int af);
/*
* Overhead added to packets by various protocols.
*/
#define IPv4_UDP_HEADER_SIZE 28
#define IPv4_TCP_HEADER_SIZE 40
-#define IPv6_UDP_HEADER_SIZE 40
+#define IPv6_UDP_HEADER_SIZE 48
+#define IPv6_TCP_HEADER_SIZE 60
extern const int proto_overhead[];
@@ -518,7 +572,7 @@ is_proto_tcp(const int p)
static inline bool
link_socket_proto_connection_oriented (int proto)
{
- return proto == PROTO_TCPv4_SERVER || proto == PROTO_TCPv4_CLIENT;
+ return !proto_is_dgram(proto);
}
static inline bool
@@ -533,7 +587,36 @@ link_socket_connection_oriented (const struct link_socket *sock)
static inline bool
addr_defined (const struct openvpn_sockaddr *addr)
{
- return addr->sa.sin_addr.s_addr != 0;
+ if (!addr) return 0;
+ switch (addr->addr.sa.sa_family) {
+ case AF_INET: return addr->addr.in4.sin_addr.s_addr != 0;
+#ifdef USE_PF_INET6
+ case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6.sin6_addr);
+#endif
+ default: return 0;
+ }
+}
+static inline bool
+addr_defined_ipi (const struct link_socket_actual *lsa)
+{
+#if ENABLE_IP_PKTINFO
+ if (!lsa) return 0;
+ switch (lsa->dest.addr.sa.sa_family) {
+#ifdef HAVE_IN_PKTINFO
+ case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0;
+#endif
+#ifdef IP_RECVDSTADDR
+ case AF_INET: return lsa->pi.in4.s_addr != 0;
+#endif
+#ifdef USE_PF_INET6
+ case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&lsa->pi.in6.ipi6_addr);
+#endif
+ default: return 0;
+ }
+#else
+ ASSERT(0);
+#endif
+ return false;
}
static inline bool
@@ -545,20 +628,50 @@ 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)
{
- return a1->sa.sin_addr.s_addr == a2->sa.sin_addr.s_addr;
+ switch(a1->addr.sa.sa_family) {
+ case AF_INET:
+ return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr;
+#ifdef USE_PF_INET6
+ case AF_INET6:
+ return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr);
+#endif
+ }
+ ASSERT(0);
+ return false;
}
static inline in_addr_t
-addr_host (const struct openvpn_sockaddr *s)
+addr_host (const struct openvpn_sockaddr *addr)
{
- return ntohl (s->sa.sin_addr.s_addr);
+ /*
+ * "public" addr returned is checked against ifconfig for
+ * possible clash: non sense for now given
+ * that we do ifconfig only IPv4
+ */
+#if defined(USE_PF_INET6)
+ if(addr->addr.sa.sa_family != AF_INET)
+ return 0;
+#else
+ ASSERT(addr->addr.sa.sa_family == AF_INET);
+#endif
+ return ntohl (addr->addr.in4.sin_addr.s_addr);
}
static inline bool
addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
{
- return a1->sa.sin_addr.s_addr == a2->sa.sin_addr.s_addr
- && a1->sa.sin_port == a2->sa.sin_port;
+ switch(a1->addr.sa.sa_family) {
+ case AF_INET:
+ 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;
+#ifdef USE_PF_INET6
+ case AF_INET6:
+ 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;
+#endif
+ }
+ ASSERT(0);
+ return false;
}
static inline bool
@@ -571,6 +684,74 @@ addr_match_proto (const struct openvpn_sockaddr *a1,
: addr_port_match (a1, a2);
}
+static inline void
+addr_zero_host(struct openvpn_sockaddr *addr)
+{
+ switch(addr->addr.sa.sa_family) {
+ case AF_INET:
+ addr->addr.in4.sin_addr.s_addr = 0;
+ break;
+#ifdef USE_PF_INET6
+ case AF_INET6:
+ memset(&addr->addr.in6.sin6_addr, 0, sizeof (struct in6_addr));
+ break;
+#endif
+ }
+}
+
+static inline void
+addr_copy_sa(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src)
+{
+ dst->addr = src->addr;
+}
+
+static inline void
+addr_copy_host(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src)
+{
+ switch(src->addr.sa.sa_family) {
+ case AF_INET:
+ dst->addr.in4.sin_addr.s_addr = src->addr.in4.sin_addr.s_addr;
+ break;
+#ifdef USE_PF_INET6
+ case AF_INET6:
+ dst->addr.in6.sin6_addr = src->addr.in6.sin6_addr;
+ break;
+#endif
+ }
+}
+
+static inline bool
+addr_inet4or6(struct sockaddr *addr)
+{
+ return addr->sa_family == AF_INET || addr->sa_family == AF_INET6;
+}
+
+int addr_guess_family(int proto, const char *name);
+static inline int
+af_addr_size(unsigned short af)
+{
+#if defined(USE_PF_INET6) || defined (USE_PF_UNIX)
+ switch(af) {
+ case AF_INET: return sizeof (struct sockaddr_in);
+#ifdef USE_PF_UNIX
+ case AF_UNIX: return sizeof (struct sockaddr_un);
+#endif
+#ifdef USE_PF_INET6
+ case AF_INET6: return sizeof (struct sockaddr_in6);
+#endif
+ default:
+#if 0
+ /* could be called from socket_do_accept() with empty addr */
+ msg (M_ERR, "Bad address family: %d\n", af);
+ ASSERT(0);
+#endif
+ return 0;
+ }
+#else /* only AF_INET */
+ return sizeof(struct sockaddr_in);
+#endif
+}
+
static inline bool
link_socket_actual_match (const struct link_socket_actual *a1, const struct link_socket_actual *a2)
{
@@ -627,14 +808,18 @@ link_socket_verify_incoming_addr (struct buffer *buf,
{
if (buf->len > 0)
{
- if (from_addr->dest.sa.sin_family != AF_INET)
- return false;
- if (!link_socket_actual_defined (from_addr))
- return false;
- if (info->remote_float || !addr_defined (&info->lsa->remote))
- return true;
- if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto))
- return true;
+ switch (from_addr->dest.addr.sa.sa_family) {
+#ifdef USE_PF_INET6
+ case AF_INET6:
+#endif
+ case AF_INET:
+ if (!link_socket_actual_defined (from_addr))
+ return false;
+ if (info->remote_float || !addr_defined (&info->lsa->remote))
+ return true;
+ if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto))
+ return true;
+ }
}
return false;
}
@@ -740,7 +925,7 @@ link_socket_read (struct link_socket *sock,
int maxsize,
struct link_socket_actual *from)
{
- if (sock->info.proto == PROTO_UDPv4)
+ if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */
{
int res;
@@ -751,10 +936,10 @@ link_socket_read (struct link_socket *sock,
#endif
return res;
}
- else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT)
+ else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */
{
/* from address was returned by accept */
- from->dest.sa = sock->info.lsa->actual.dest.sa;
+ addr_copy_sa(&from->dest, &sock->info.lsa->actual.dest);
return link_socket_read_tcp (sock, buf);
}
else
@@ -809,13 +994,14 @@ link_socket_write_udp_posix (struct link_socket *sock,
struct buffer *buf,
struct link_socket_actual *to);
- if (sock->sockflags & SF_USE_IP_PKTINFO)
+ if (proto_is_udp(sock->info.proto) && (sock->sockflags & SF_USE_IP_PKTINFO)
+ && addr_defined_ipi(to))
return link_socket_write_udp_posix_sendmsg (sock, buf, to);
else
#endif
return sendto (sock->sd, BPTR (buf), BLEN (buf), 0,
- (struct sockaddr *) &to->dest.sa,
- (socklen_t) sizeof (to->dest.sa));
+ (struct sockaddr *) &to->dest.addr.sa,
+ (socklen_t) af_addr_size(to->dest.addr.sa.sa_family));
}
static inline int
@@ -846,11 +1032,11 @@ link_socket_write (struct link_socket *sock,
struct buffer *buf,
struct link_socket_actual *to)
{
- if (sock->info.proto == PROTO_UDPv4)
+ if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */
{
return link_socket_write_udp (sock, buf, to);
}
- else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT)
+ else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */
{
return link_socket_write_tcp (sock, buf, to);
}
diff --git a/socks.c b/socks.c
index 0c1bb3e..949d256 100644
--- a/socks.c
+++ b/socks.c
@@ -23,10 +23,11 @@
*/
/*
- * 2004-01-30: Added Socks5 proxy support
+ * 2004-01-30: Added Socks5 proxy support, see RFC 1928
* (Christof Meerwald, http://cmeerw.org)
*
- * see RFC 1928, only supports "no authentication"
+ * 2010-10-10: Added Socks5 plain text authentication support (RFC 1929)
+ * (Pierre Bourdon <delroth@gmail.com>)
*/
#include "syshead.h"
@@ -38,10 +39,12 @@
#include "win32.h"
#include "socket.h"
#include "fdmisc.h"
+#include "misc.h"
#include "proxy.h"
#include "memdbg.h"
+#define UP_TYPE_SOCKS "SOCKS Proxy"
void
socks_adjust_frame_parameters (struct frame *frame, int proto)
@@ -53,6 +56,7 @@ socks_adjust_frame_parameters (struct frame *frame, int proto)
struct socks_proxy_info *
socks_proxy_new (const char *server,
int port,
+ const char *authfile,
bool retry,
struct auto_proxy_info *auto_proxy_info)
{
@@ -77,6 +81,12 @@ socks_proxy_new (const char *server,
strncpynt (p->server, server, sizeof (p->server));
p->port = port;
+
+ if (authfile)
+ strncpynt (p->authfile, authfile, sizeof (p->authfile));
+ else
+ p->authfile[0] = 0;
+
p->retry = retry;
p->defined = true;
@@ -90,15 +100,106 @@ socks_proxy_close (struct socks_proxy_info *sp)
}
static bool
-socks_handshake (socket_descriptor_t sd, volatile int *signal_received)
+socks_username_password_auth (struct socks_proxy_info *p,
+ socket_descriptor_t sd,
+ volatile int *signal_received)
{
+ char to_send[516];
char buf[2];
int len = 0;
const int timeout_sec = 5;
+ struct user_pass creds;
+ ssize_t size;
+
+ creds.defined = 0;
+ get_user_pass (&creds, p->authfile, UP_TYPE_SOCKS, GET_USER_PASS_MANAGEMENT);
+
+ if( !creds.username || (strlen(creds.username) > 255)
+ || !creds.password || (strlen(creds.password) > 255) ) {
+ msg (M_NONFATAL,
+ "SOCKS username and/or password exceeds 255 characters. "
+ "Authentication not possible.");
+ return false;
+ }
+ openvpn_snprintf (to_send, sizeof (to_send), "\x01%c%s%c%s", (int) strlen(creds.username),
+ creds.username, (int) strlen(creds.password), creds.password);
+ size = send (sd, to_send, strlen(to_send), MSG_NOSIGNAL);
+
+ if (size != strlen (to_send))
+ {
+ msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_username_password_auth: TCP port write failed on send()");
+ return false;
+ }
- /* VER = 5, NMETHODS = 1, METHODS = [0] */
- const ssize_t size = send (sd, "\x05\x01\x00", 3, MSG_NOSIGNAL);
- if (size != 3)
+ while (len < 2)
+ {
+ int status;
+ ssize_t size;
+ fd_set reads;
+ struct timeval tv;
+ char c;
+
+ FD_ZERO (&reads);
+ FD_SET (sd, &reads);
+ tv.tv_sec = timeout_sec;
+ tv.tv_usec = 0;
+
+ status = select (sd + 1, &reads, NULL, NULL, &tv);
+
+ get_signal (signal_received);
+ if (*signal_received)
+ return false;
+
+ /* timeout? */
+ if (status == 0)
+ {
+ msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_username_password_auth: TCP port read timeout expired");
+ return false;
+ }
+
+ /* error */
+ if (status < 0)
+ {
+ msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_username_password_auth: TCP port read failed on select()");
+ return false;
+ }
+
+ /* read single char */
+ size = recv(sd, &c, 1, MSG_NOSIGNAL);
+
+ /* error? */
+ if (size != 1)
+ {
+ msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_username_password_auth: TCP port read failed on recv()");
+ return false;
+ }
+
+ /* store char in buffer */
+ buf[len++] = c;
+ }
+
+ /* VER = 5, SUCCESS = 0 --> auth success */
+ if (buf[0] != 5 && buf[1] != 0)
+ {
+ msg (D_LINK_ERRORS, "socks_username_password_auth: server refused the authentication");
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+socks_handshake (struct socks_proxy_info *p,
+ socket_descriptor_t sd,
+ volatile int *signal_received)
+{
+ char buf[2];
+ int len = 0;
+ const int timeout_sec = 5;
+
+ /* 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)
{
msg (D_LINK_ERRORS | M_ERRNO_SOCK, "socks_handshake: TCP port write failed on send()");
return false;
@@ -151,13 +252,37 @@ socks_handshake (socket_descriptor_t sd, volatile int *signal_received)
buf[len++] = c;
}
- /* VER == 5 && METHOD == 0 */
- if (buf[0] != '\x05' || buf[1] != '\x00')
+ /* VER == 5 */
+ if (buf[0] != '\x05')
{
msg (D_LINK_ERRORS, "socks_handshake: Socks proxy returned bad status");
return false;
}
+ /* select the appropriate authentication method */
+ switch (buf[1])
+ {
+ case 0: /* no authentication */
+ break;
+
+ case 2: /* login/password */
+ if (!p->authfile[0])
+ {
+ msg(D_LINK_ERRORS, "socks_handshake: server asked for username/login auth but we were "
+ "not provided any credentials");
+ return false;
+ }
+
+ if (!socks_username_password_auth(p, sd, signal_received))
+ return false;
+
+ break;
+
+ default: /* unknown auth method */
+ msg(D_LINK_ERRORS, "socks_handshake: unknown SOCKS auth method");
+ return false;
+ }
+
return true;
}
@@ -174,9 +299,9 @@ recv_socks_reply (socket_descriptor_t sd,
if (addr != NULL)
{
- addr->sa.sin_family = AF_INET;
- addr->sa.sin_addr.s_addr = htonl (INADDR_ANY);
- addr->sa.sin_port = htons (0);
+ addr->addr.in4.sin_family = AF_INET;
+ addr->addr.in4.sin_addr.s_addr = htonl (INADDR_ANY);
+ addr->addr.in4.sin_port = htons (0);
}
while (len < 4 + alen + 2)
@@ -263,8 +388,8 @@ recv_socks_reply (socket_descriptor_t sd,
/* ATYP == 1 (IP V4 address) */
if (atyp == '\x01' && addr != NULL)
{
- memcpy (&addr->sa.sin_addr, buf + 4, sizeof (addr->sa.sin_addr));
- memcpy (&addr->sa.sin_port, buf + 8, sizeof (addr->sa.sin_port));
+ memcpy (&addr->addr.in4.sin_addr, buf + 4, sizeof (addr->addr.in4.sin_addr));
+ memcpy (&addr->addr.in4.sin_port, buf + 8, sizeof (addr->addr.in4.sin_port));
}
@@ -281,7 +406,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p,
char buf[128];
size_t len;
- if (!socks_handshake (sd, signal_received))
+ if (!socks_handshake (p, sd, signal_received))
goto error;
/* format Socks CONNECT message */
@@ -328,7 +453,7 @@ establish_socks_proxy_udpassoc (struct socks_proxy_info *p,
struct openvpn_sockaddr *relay_addr,
volatile int *signal_received)
{
- if (!socks_handshake (ctrl_sd, signal_received))
+ if (!socks_handshake (p, ctrl_sd, signal_received))
goto error;
{
@@ -382,8 +507,8 @@ socks_process_incoming_udp (struct buffer *buf,
if (atyp != 1) /* ATYP == 1 (IP V4) */
goto error;
- buf_read (buf, &from->dest.sa.sin_addr, sizeof (from->dest.sa.sin_addr));
- buf_read (buf, &from->dest.sa.sin_port, sizeof (from->dest.sa.sin_port));
+ buf_read (buf, &from->dest.addr.in4.sin_addr, sizeof (from->dest.addr.in4.sin_addr));
+ buf_read (buf, &from->dest.addr.in4.sin_port, sizeof (from->dest.addr.in4.sin_port));
return;
@@ -415,8 +540,8 @@ socks_process_outgoing_udp (struct buffer *buf,
buf_write_u16 (&head, 0); /* RSV = 0 */
buf_write_u8 (&head, 0); /* FRAG = 0 */
buf_write_u8 (&head, '\x01'); /* ATYP = 1 (IP V4) */
- buf_write (&head, &to->dest.sa.sin_addr, sizeof (to->dest.sa.sin_addr));
- buf_write (&head, &to->dest.sa.sin_port, sizeof (to->dest.sa.sin_port));
+ buf_write (&head, &to->dest.addr.in4.sin_addr, sizeof (to->dest.addr.in4.sin_addr));
+ buf_write (&head, &to->dest.addr.in4.sin_port, sizeof (to->dest.addr.in4.sin_port));
return 10;
}
diff --git a/socks.h b/socks.h
index 702aa06..b748bb3 100644
--- a/socks.h
+++ b/socks.h
@@ -43,12 +43,14 @@ struct socks_proxy_info {
char server[128];
int port;
+ char authfile[256];
};
void socks_adjust_frame_parameters (struct frame *frame, int proto);
struct socks_proxy_info *socks_proxy_new (const char *server,
int port,
+ const char *authfile,
bool retry,
struct auto_proxy_info *auto_proxy_info);
diff --git a/ssl.c b/ssl.c
index df237cc..a2b5b18 100644
--- a/ssl.c
+++ b/ssl.c
@@ -7,6 +7,10 @@
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
*
+ * Additions for eurephia plugin done by:
+ * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2008-2009
+ *
+ *
* 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.
@@ -39,7 +43,6 @@
#include "common.h"
#include "integer.h"
#include "socket.h"
-#include "thread.h"
#include "misc.h"
#include "fdmisc.h"
#include "interval.h"
@@ -530,6 +533,58 @@ extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, int
}
}
+#ifdef ENABLE_X509ALTUSERNAME
+static
+bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size)
+{
+ bool retval = false;
+ X509_EXTENSION *pExt;
+ char *buf = 0;
+ int length = 0;
+ GENERAL_NAMES *extensions;
+ int nid = OBJ_txt2nid(fieldname);
+
+ extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL);
+ if ( extensions )
+ {
+ int numalts;
+ int i;
+ /* get amount of alternatives,
+ * RFC2459 claims there MUST be at least
+ * one, but we don't depend on it...
+ */
+
+ numalts = sk_GENERAL_NAME_num(extensions);
+
+ /* loop through all alternatives */
+ for (i=0; i<numalts; i++)
+ {
+ /* get a handle to alternative name number i */
+ const GENERAL_NAME *name = sk_GENERAL_NAME_value (extensions, i );
+
+ switch (name->type)
+ {
+ case GEN_EMAIL:
+ ASN1_STRING_to_UTF8((unsigned char**)&buf, name->d.ia5);
+ if ( strlen (buf) != name->d.ia5->length )
+ {
+ msg (D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero");
+ OPENSSL_free (buf);
+ } else {
+ strncpynt(out, buf, size);
+ OPENSSL_free(buf);
+ retval = true;
+ }
+ break;
+ default:
+ msg (D_TLS_ERRORS, "ASN1 ERROR: can not handle field type %i",
+ name->type);
+ break;
+ }
+ }
+ sk_GENERAL_NAME_free (extensions);
+ }
+ return retval;
#ifdef ENABLE_X509_TRACK
/*
* setenv_x509_track function -- save X509 fields to environment,
@@ -820,6 +875,51 @@ string_mod_sslname (char *str, const unsigned int restrictive_flags, const unsig
string_mod (str, restrictive_flags, 0, '_');
}
+/* Get peer cert and store it in pem format in a temporary file
+ * in tmp_dir
+ */
+
+const char *
+get_peer_cert(X509_STORE_CTX *ctx, const char *tmp_dir, struct gc_arena *gc)
+{
+ X509 *peercert;
+ FILE *peercert_file;
+ const char *peercert_filename="";
+
+ if(!tmp_dir)
+ return NULL;
+
+ /* get peer cert */
+ peercert = X509_STORE_CTX_get_current_cert(ctx);
+ if(!peercert)
+ {
+ msg (M_ERR, "Unable to get peer certificate from current context");
+ return NULL;
+ }
+
+ /* create tmp file to store peer cert */
+ peercert_filename = create_temp_file (tmp_dir, "pcf", gc);
+
+ /* write peer-cert in tmp-file */
+ peercert_file = fopen(peercert_filename, "w+");
+ if(!peercert_file)
+ {
+ msg (M_ERR, "Failed to open temporary file : %s", peercert_filename);
+ return NULL;
+ }
+ if(PEM_write_X509(peercert_file,peercert)<0)
+ {
+ msg (M_ERR, "Failed to write peer certificate in PEM format");
+ fclose(peercert_file);
+ return NULL;
+ }
+
+ fclose(peercert_file);
+ return peercert_filename;
+}
+
+char * x509_username_field; /* GLOBAL */
+
/*
* Our verify callback function -- check
* that an incoming peer certificate is good.
@@ -830,7 +930,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
{
char *subject = NULL;
char envname[64];
- char common_name[TLS_CN_LEN];
+ char common_name[TLS_USERNAME_LEN];
SSL *ssl;
struct tls_session *session;
const struct tls_options *opt;
@@ -868,18 +968,34 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
string_mod_sslname (subject, X509_NAME_CHAR_CLASS, opt->ssl_flags);
string_replace_leading (subject, '-', '_');
- /* extract the common name */
- if (!extract_x509_field_ssl (X509_get_subject_name (ctx->current_cert), "CN", common_name, TLS_CN_LEN))
+ /* extract the username (default is CN) */
+#ifdef ENABLE_X509ALTUSERNAME
+ if (strncmp("ext:",x509_username_field,4) == 0)
+ {
+ if (!extract_x509_extension (ctx->current_cert, x509_username_field+4, common_name, sizeof(common_name)))
+ {
+ msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract %s extension from X509 subject string ('%s') "
+ "-- note that the username length is limited to %d characters",
+ x509_username_field+4,
+ subject,
+ TLS_USERNAME_LEN);
+ goto err;
+ }
+ } else
+#endif
+ if (!extract_x509_field_ssl (X509_get_subject_name (ctx->current_cert), x509_username_field, common_name, sizeof(common_name)))
{
if (!ctx->error_depth)
- {
- msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract Common Name from X509 subject string ('%s') -- note that the Common Name length is limited to %d characters",
- subject,
- TLS_CN_LEN);
- goto err;
- }
+ {
+ msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract %s from X509 subject string ('%s') -- note that the username length is limited to %d characters",
+ x509_username_field,
+ subject,
+ TLS_USERNAME_LEN);
+ goto err;
+ }
}
+
string_mod_sslname (common_name, COMMON_NAME_CHAR_CLASS, opt->ssl_flags);
cert_hash_remember (session, ctx->error_depth, ctx->current_cert->sha1_hash);
@@ -929,6 +1045,16 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
openvpn_snprintf (envname, sizeof(envname), "tls_id_%d", ctx->error_depth);
setenv_str (opt->es, envname, subject);
+#ifdef ENABLE_EUREPHIA
+ /* export X509 cert SHA1 fingerprint */
+ {
+ struct gc_arena gc = gc_new ();
+ openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", ctx->error_depth);
+ setenv_str (opt->es, envname,
+ format_hex_ex(ctx->current_cert->sha1_hash, SHA_DIGEST_LENGTH, 0, 1, ":", &gc));
+ gc_free(&gc);
+ }
+#endif
#if 0
/* export common name string as environmental variable */
openvpn_snprintf (envname, sizeof(envname), "tls_common_name_%d", ctx->error_depth);
@@ -1022,7 +1148,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
ctx->error_depth,
subject);
- ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, opt->es);
+ ret = plugin_call (opt->plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, opt->es, ctx->error_depth, ctx->current_cert);
if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS)
{
@@ -1040,32 +1166,48 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
/* run --tls-verify script */
if (opt->verify_command)
{
+ const char *tmp_file = NULL;
+ struct gc_arena gc;
int ret;
setenv_str (opt->es, "script_type", "tls-verify");
+ if (opt->verify_export_cert)
+ {
+ gc = gc_new();
+ if ((tmp_file=get_peer_cert(ctx, opt->verify_export_cert,&gc)))
+ {
+ setenv_str(opt->es, "peer_cert", tmp_file);
+ }
+ }
+
argv_printf (&argv, "%sc %d %s",
opt->verify_command,
ctx->error_depth,
subject);
argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command");
- ret = openvpn_execve (&argv, opt->es, S_SCRIPT);
+ ret = openvpn_run_script (&argv, opt->es, 0, "--tls-verify script");
+
+ if (opt->verify_export_cert)
+ {
+ if (tmp_file)
+ delete_file(tmp_file);
+ gc_free(&gc);
+ }
- if (system_ok (ret))
+ if (ret)
{
msg (D_HANDSHAKE, "VERIFY SCRIPT OK: depth=%d, %s",
ctx->error_depth, subject);
}
else
{
- if (!system_executed (ret))
- argv_msg_prefix (M_ERR, &argv, "Verify command failed to execute");
msg (D_HANDSHAKE, "VERIFY SCRIPT ERROR: depth=%d, %s",
ctx->error_depth, subject);
goto err; /* Reject connection */
}
}
-
+
/* check peer cert against CRL */
if (opt->crl_file)
{
@@ -1115,15 +1257,15 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
goto end;
}
- n = sk_num(X509_CRL_get_REVOKED(crl));
+ n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
- for (i = 0; i < n; i++) {
- revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i);
- if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
- msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
- goto end;
- }
- }
+ for (i = 0; i < n; i++) {
+ revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
+ if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(ctx->current_cert)) == 0) {
+ msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
+ goto end;
+ }
+ }
retval = 1;
msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
@@ -1296,10 +1438,11 @@ key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options
const char *acf;
key_state_rm_auth_control_file (ks);
- acf = create_temp_filename (opt->tmp_dir, "acf", &gc);
- ks->auth_control_file = string_alloc (acf, NULL);
- setenv_str (opt->es, "auth_control_file", ks->auth_control_file);
-
+ acf = create_temp_file (opt->tmp_dir, "acf", &gc);
+ if( acf ) {
+ ks->auth_control_file = string_alloc (acf, NULL);
+ setenv_str (opt->es, "auth_control_file", ks->auth_control_file);
+ } /* FIXME: Should have better error handling? */
gc_free (&gc);
}
@@ -1979,7 +2122,7 @@ init_ssl (const struct options *options)
/* Set Certificate Verification chain */
if (!options->ca_file)
{
- if (ca && sk_num(ca))
+ if (ca && sk_X509_num(ca))
{
for (i = 0; i < sk_X509_num(ca); i++)
{
@@ -2189,8 +2332,15 @@ init_ssl (const struct options *options)
}
else
#endif
- SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
- verify_callback);
+ {
+#ifdef ENABLE_X509ALTUSERNAME
+ x509_username_field = (char *) options->x509_username_field;
+#else
+ x509_username_field = X509_USERNAME_FIELD_DEFAULT;
+#endif
+ SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ verify_callback);
+ }
/* Connection information callback */
SSL_CTX_set_info_callback (ctx, info_callback);
@@ -2223,7 +2373,7 @@ init_ssl (const struct options *options)
static void
print_details (SSL * c_ssl, const char *prefix)
{
- SSL_CIPHER *ciph;
+ const SSL_CIPHER *ciph;
X509 *cert;
char s1[256];
char s2[256];
@@ -3650,7 +3800,6 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
struct gc_arena gc = gc_new ();
struct argv argv = argv_new ();
const char *tmp_file = "";
- int retval;
bool ret = false;
/* Is username defined? */
@@ -3663,17 +3812,22 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
{
struct status_output *so;
- tmp_file = create_temp_filename (session->opt->tmp_dir, "up", &gc);
- so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
- status_printf (so, "%s", up->username);
- status_printf (so, "%s", up->password);
- if (!status_close (so))
- {
- msg (D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s",
- tmp_file);
- goto done;
- }
- }
+ tmp_file = create_temp_file (session->opt->tmp_dir, "up", &gc);
+ if( tmp_file ) {
+ so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE);
+ status_printf (so, "%s", up->username);
+ status_printf (so, "%s", up->password);
+ if (!status_close (so))
+ {
+ msg (D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s",
+ tmp_file);
+ goto done;
+ }
+ } else {
+ msg (D_TLS_ERRORS, "TLS Auth Error: could not create write "
+ "username/password to temp file");
+ }
+ }
else
{
setenv_str (session->opt->es, "username", up->username);
@@ -3688,16 +3842,11 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
/* format command line */
argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
-
+
/* call command */
- retval = openvpn_execve (&argv, session->opt->es, S_SCRIPT);
+ ret = openvpn_run_script (&argv, session->opt->es, 0,
+ "--auth-user-pass-verify");
- /* test return status of command */
- if (system_ok (retval))
- ret = true;
- else if (!system_executed (retval))
- argv_msg_prefix (D_TLS_ERRORS, &argv, "TLS Auth Error: user-pass-verify script failed to execute");
-
if (!session->opt->auth_user_pass_verify_script_via_file)
setenv_del (session->opt->es, "password");
}
@@ -3707,7 +3856,7 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
}
done:
- if (strlen (tmp_file) > 0)
+ if (tmp_file && strlen (tmp_file) > 0)
delete_file (tmp_file);
argv_reset (&argv);
@@ -3739,7 +3888,7 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up
#endif
/* call command */
- retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es);
+ retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es, -1, NULL);
#ifdef PLUGIN_DEF_AUTH
/* purge auth control filename (and file itself) for non-deferred returns */
@@ -4148,9 +4297,9 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
s2 = verify_user_pass_script (session, up);
/* check sizing of username if it will become our common name */
- if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_CN_LEN)
+ if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_USERNAME_LEN)
{
- msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_CN_LEN);
+ msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN);
s1 = OPENVPN_PLUGIN_FUNC_ERROR;
}
@@ -4273,7 +4422,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
*/
if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL))
{
- if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS)
+ if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es, -1, NULL) != OPENVPN_PLUGIN_FUNC_SUCCESS)
ks->authenticated = false;
}
@@ -4354,7 +4503,8 @@ tls_process (struct tls_multi *multi,
&& ks->n_packets >= session->opt->renegotiate_packets)
|| (packet_id_close_to_wrapping (&ks->packet_id.send))))
{
- msg (D_TLS_DEBUG_LOW, "TLS: soft reset sec=%d bytes=%d/%d pkts=%d/%d",
+ msg (D_TLS_DEBUG_LOW,
+ "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" counter_format "/%d",
(int)(ks->established + session->opt->renegotiate_seconds - now),
ks->n_bytes, session->opt->renegotiate_bytes,
ks->n_packets, session->opt->renegotiate_packets);
@@ -4367,8 +4517,6 @@ tls_process (struct tls_multi *multi,
msg (D_TLS_DEBUG_LOW, "TLS: tls_process: killed expiring key");
}
- /*mutex_cycle (multi->mutex);*/
-
do
{
update_time ();
@@ -4655,7 +4803,6 @@ tls_process (struct tls_multi *multi,
}
}
}
- /*mutex_cycle (multi->mutex);*/
}
while (state_change);
@@ -4809,7 +4956,6 @@ tls_multi_process (struct tls_multi *multi,
reset_session (multi, session);
}
}
- /*mutex_cycle (multi->mutex);*/
}
update_time ();
diff --git a/ssl.h b/ssl.h
index 1b23d7d..790a57e 100644
--- a/ssl.h
+++ b/ssl.h
@@ -42,7 +42,6 @@
#include "reliable.h"
#include "socket.h"
#include "mtu.h"
-#include "thread.h"
#include "options.h"
#include "plugin.h"
@@ -278,8 +277,8 @@
* Buffer sizes (also see mtu.h).
*/
-/* Maximum length of common name */
-#define TLS_CN_LEN 64
+/* Maximum length of the username in cert */
+#define TLS_USERNAME_LEN 64
/* Legal characters in an X509 or common name */
#define X509_NAME_CHAR_CLASS (CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT|CC_COLON|CC_SLASH|CC_EQUAL)
@@ -288,6 +287,9 @@
/* Maximum length of OCC options string passed as part of auth handshake */
#define TLS_OPTIONS_LEN 512
+/* Default field in X509 to be username */
+#define X509_USERNAME_FIELD_DEFAULT "CN"
+
/*
* Range of key exchange methods
*/
@@ -378,8 +380,8 @@ struct key_state
struct buffer_list *paybuf;
- int n_bytes; /* how many bytes sent/recvd since last key exchange */
- int n_packets; /* how many packets sent/recvd since last key exchange */
+ counter_type n_bytes; /* how many bytes sent/recvd since last key exchange */
+ counter_type n_packets; /* how many packets sent/recvd since last key exchange */
/*
* If bad username/password, TLS connection will come up but 'authenticated' will be false.
@@ -461,6 +463,7 @@ struct tls_options
/* cert verification parms */
const char *verify_command;
+ const char *verify_export_cert;
const char *verify_x509name;
const char *crl_file;
int ns_cert_type;
@@ -597,9 +600,6 @@ struct tls_session
*/
struct tls_multi
{
- /* used to coordinate access between main thread and TLS thread */
- /*MUTEX_PTR_DEFINE (mutex);*/
-
/* const options and config info */
struct tls_options opt;
diff --git a/status.c b/status.c
index 92fc7bc..4bbea28 100644
--- a/status.c
+++ b/status.c
@@ -168,7 +168,9 @@ status_flush (struct status_output *so)
#if defined(HAVE_FTRUNCATE)
{
const off_t off = lseek (so->fd, (off_t)0, SEEK_CUR);
- ftruncate (so->fd, off);
+ if (ftruncate (so->fd, off) != 0) {
+ msg (M_WARN, "Failed to truncate status file: %s", strerror(errno));
+ }
}
#elif defined(HAVE_CHSIZE)
{
diff --git a/syshead.h b/syshead.h
index 0da1fc2..5b86cad 100644
--- a/syshead.h
+++ b/syshead.h
@@ -28,13 +28,13 @@
/*
* Only include if not during configure
*/
+#ifdef WIN32
+/* USE_PF_INET6: win32 ipv6 exists only after 0x0501 (XP) */
+#define WINVER 0x0501
+#endif
#ifndef PACKAGE_NAME
-#ifdef _MSC_VER
-#include "config-win32.h"
-#else
#include "config.h"
#endif
-#endif
/* branch prediction hints */
#if defined(__GNUC__)
@@ -51,6 +51,7 @@
#ifdef WIN32
#include <windows.h>
+#include <winsock2.h>
#define sleep(x) Sleep((x)*1000)
#define random rand
#define srandom srand
@@ -85,6 +86,10 @@
#endif
#ifdef HAVE_SYS_SOCKET_H
+# if defined(TARGET_LINUX) && !defined(_GNU_SOURCE)
+ /* needed for peercred support on glibc-2.8 */
+# define _GNU_SOURCE
+# endif
#include <sys/socket.h>
#endif
@@ -338,6 +343,9 @@
#ifdef WIN32
#include <iphlpapi.h>
#include <wininet.h>
+/* The following two headers are needed of USE_PF_INET6 */
+#include <winsock2.h>
+#include <ws2tcpip.h>
#endif
#ifdef HAVE_SYS_MMAN_H
@@ -382,9 +390,10 @@
#endif
/*
- * Does this platform support linux-style IP_PKTINFO?
+ * Does this platform support linux-style IP_PKTINFO
+ * or bsd-style IP_RECVDSTADDR ?
*/
-#if defined(ENABLE_MULTIHOME) && defined(HAVE_IN_PKTINFO) && defined(IP_PKTINFO) && defined(HAVE_MSGHDR) && defined(HAVE_CMSGHDR) && defined(HAVE_IOVEC) && defined(CMSG_FIRSTHDR) && defined(CMSG_NXTHDR) && defined(HAVE_RECVMSG) && defined(HAVE_SENDMSG)
+#if defined(ENABLE_MULTIHOME) && ((defined(HAVE_IN_PKTINFO)&&defined(IP_PKTINFO)) || defined(IP_RECVDSTADDR)) && defined(HAVE_MSGHDR) && defined(HAVE_CMSGHDR) && defined(HAVE_IOVEC) && defined(CMSG_FIRSTHDR) && defined(CMSG_NXTHDR) && defined(HAVE_RECVMSG) && defined(HAVE_SENDMSG)
#define ENABLE_IP_PKTINFO 1
#else
#define ENABLE_IP_PKTINFO 0
@@ -551,24 +560,6 @@ socket_defined (const socket_descriptor_t sd)
#define ENABLE_BUFFER_LIST
/*
- * Do we have pthread capability?
- */
-#ifdef USE_PTHREAD
-#if defined(USE_CRYPTO) && defined(USE_SSL) && P2MP
-#include <pthread.h>
-#else
-#undef USE_PTHREAD
-#endif
-#endif
-
-/*
- * Pthread support is currently experimental (and quite unfinished).
- */
-#if 1 /* JYFIXME -- if defined, disable pthread */
-#undef USE_PTHREAD
-#endif
-
-/*
* Should we include OCC (options consistency check) code?
*/
#ifndef ENABLE_SMALL
diff --git a/t_client.rc-sample b/t_client.rc-sample
new file mode 100644
index 0000000..ca59c68
--- /dev/null
+++ b/t_client.rc-sample
@@ -0,0 +1,83 @@
+#
+# this is sourced from t_client.sh and defines which openvpn client tests
+# to run
+#
+# (sample config, copy to t_client.rc and adapt to your environment)
+#
+#
+# define these - if empty, no tests will run
+#
+CA_CERT="/home/openvpn-test-ca/keys/ca.crt"
+CLIENT_KEY="/home/openvpn-test-ca/keys/client-test.key"
+CLIENT_CERT="/home/openvpn-test-ca/keys/client-test.crt"
+#
+# remote host (used as macro below)
+#
+REMOTE=mytestserver
+#
+# tests to run (list suffixes for config stanzas below)
+#
+TEST_RUN_LIST="1 2"
+
+#
+# base confic that is the same for all the p2mp test runs
+#
+OPENVPN_BASE_P2MP="--client --ca $CA_CERT \
+ --cert $CLIENT_CERT --key $CLIENT_KEY \
+ --ns-cert-type server --nobind --comp-lzo --verb 3"
+
+# base config for p2p tests
+#
+OPENVPN_BASE_P2P="..."
+
+#
+#
+# now define the individual tests - all variables suffixed with _1, _2 etc
+# will be used in test run "1", "2", etc.
+#
+# if something is not defined here, the corresponding test is not run
+#
+# possible test options:
+#
+# OPENVPN_CONF_x = "how to call ./openvpn" [mandatory]
+# EXPECT_IFCONFIG4_x = "this IPv4 address needs to show up in ifconfig"
+# EXPECT_IFCONFIG6_x = "this IPv6 address needs to show up in ifconfig"
+# PING4_HOSTS_x = "these hosts musts ping when openvpn is up (IPv4 fping)"
+# PING6_HOSTS_x = "these hosts musts ping when openvpn is up (IPv6 fping6)"
+#
+# Test 1: UDP / p2mp tun
+# specify IPv4+IPv6 addresses expected from server and ping targets
+#
+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"
+PING4_HOSTS_1="10.100.50.1 10.100.0.1"
+PING6_HOSTS_1="2001:dba::1 2001:dba:a050::1"
+
+# Test 2: TCP / p2mp tun
+#
+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"
+PING4_HOSTS_2="10.100.51.1 10.100.0.1"
+PING6_HOSTS_1="2001:dba::1 2001:dba:a051::1"
+
+# Test 3: UDP / p2p tun
+# ...
+
+# Test 4: TCP / p2p tun
+# ...
+
+# Test 5: UDP / p2mp tap
+# ...
+
+# Test 6: TCP / p2mp tun
+# ...
+
+# Test 7: UDP / p2p tap
+# ...
+
+# Test 8: TCP / p2p tap
+# ...
+
+# Test 9: whatever you want to test... :-)
diff --git a/t_client.sh.in b/t_client.sh.in
new file mode 100755
index 0000000..b273964
--- /dev/null
+++ b/t_client.sh.in
@@ -0,0 +1,298 @@
+#!@SHELL@
+#
+# run OpenVPN client against ``test reference'' server
+# - check that ping, http, ... via tunnel works
+# - check that interface config / routes are properly cleaned after test end
+#
+# prerequisites:
+# - openvpn binary in current directory
+# - writable current directory to create subdir for logs
+# - t_client.rc in current directory OR source dir that specifies tests
+# - for "ping4" checks: fping binary in $PATH
+# - for "ping6" checks: fping6 binary in $PATH
+#
+
+if [ -r ./t_client.rc ] ; then
+ . ./t_client.rc
+elif [ -r "${srcdir}"/t_client.rc ] ; then
+ . "${srcdir}"/t_client.rc
+else
+ echo "$0: cannot find 't_client.rc' in current directory or" >&2
+ echo "$0: source dir ('${srcdir}'). SKIPPING TEST." >&2
+ exit 77
+fi
+
+if [ ! -x ./openvpn ]
+then
+ echo "no (executable) openvpn binary in current directory. FAIL." >&2
+ exit 1
+fi
+
+if [ ! -w . ]
+then
+ echo "current directory is not writable (required for logging). FAIL." >&2
+ exit 1
+fi
+
+if [ -z "$CA_CERT" ] ; then
+ echo "CA_CERT not defined in 't_client.rc'. SKIP test." >&2
+ exit 77
+fi
+
+if [ -z "$TEST_RUN_LIST" ] ; then
+ echo "TEST_RUN_LIST empty, no tests defined. SKIP test." >&2
+ exit 77
+fi
+
+# make sure we have permissions to run ifconfig/route from OpenVPN
+# can't use "id -u" here - doesn't work on Solaris
+ID=`id`
+if expr "$ID" : "uid=0" >/dev/null
+then :
+else
+ echo "$0: this test must run be as root. SKIP." >&2
+ exit 77
+fi
+
+LOGDIR=t_client-`hostname`-`date +%Y%m%d-%H%M%S`
+if mkdir $LOGDIR
+then :
+else
+ echo "can't create log directory '$LOGDIR'. FAIL." >&2
+ exit 1
+fi
+
+exit_code=0
+
+# ----------------------------------------------------------
+# helper functions
+# ----------------------------------------------------------
+# print failure message, increase FAIL counter
+fail()
+{
+ echo ""
+ echo "FAIL: $@" >&2
+ fail_count=$(( $fail_count + 1 ))
+}
+
+# print "all interface IP addresses" + "all routes"
+# this is higly system dependent...
+get_ifconfig_route()
+{
+ # linux / iproute2? (-> if configure got a path)
+ if [ "@IPROUTE@" != "ip" ]
+ then
+ echo "-- linux iproute2 --"
+ @IPROUTE@ addr show | grep -v valid_lft
+ @IPROUTE@ route show
+ @IPROUTE@ -6 route show | sed -e 's/expires [0-9]*sec //'
+ return
+ fi
+
+ # try uname
+ case `uname -s` in
+ Linux)
+ echo "-- linux / ifconfig --"
+ LANG=C @IFCONFIG@ -a |egrep "( addr:|encap:)"
+ LANG=C @NETSTAT@ -rn -4 -6
+ return
+ ;;
+ FreeBSD|NetBSD|Darwin)
+ echo "-- FreeBSD/NetBSD/Darwin [MacOS X] --"
+ @IFCONFIG@ -a | egrep "(flags=|inet)"
+ @NETSTAT@ -rn | awk '$3 !~ /^UHL/ { print $1,$2,$3,$NF }'
+ return
+ ;;
+ OpenBSD)
+ echo "-- OpenBSD --"
+ @IFCONFIG@ -a | egrep "(flags=|inet)" | \
+ sed -e 's/pltime [0-9]*//' -e 's/vltime [0-9]*//'
+ @NETSTAT@ -rn | awk '$3 !~ /^UHL/ { print $1,$2,$3,$NF }'
+ return
+ ;;
+ SunOS)
+ echo "-- Solaris --"
+ @IFCONFIG@ -a | egrep "(flags=|inet)"
+ @NETSTAT@ -rn | awk '$3 !~ /^UHL/ { print $1,$2,$3,$6 }'
+ return
+ ;;
+ esac
+
+ echo "get_ifconfig_route(): no idea how to get info on your OS. FAIL." >&2
+ exit 20
+}
+
+# ----------------------------------------------------------
+# check ifconfig
+# arg1: "4" or "6" -> for message
+# arg2: IPv4/IPv6 address that must show up in out of "get_ifconfig_route"
+check_ifconfig()
+{
+ proto=$1 ; shift
+ expect_list="$@"
+
+ if [ -z "$expect_list" ] ; then return ; fi
+
+ for expect in $expect_list
+ do
+ if get_ifconfig_route | fgrep "$expect" >/dev/null
+ then :
+ else
+ fail "check_ifconfig(): expected IPv$proto address '$expect' not found in ifconfig output."
+ fi
+ done
+}
+
+# ----------------------------------------------------------
+# run pings
+# arg1: "4" or "6" -> fping/fing6
+# arg2: "want_ok" or "want_fail" (expected ping result)
+# arg3... -> fping arguments (host list)
+run_ping_tests()
+{
+ proto=$1 ; want=$2 ; shift ; shift
+ targetlist="$@"
+
+ # "no targets" is fine
+ if [ -z "$targetlist" ] ; then return ; fi
+
+ case $proto in
+ 4) cmd=fping ;;
+ 6) cmd=fping6 ;;
+ *) echo "internal error in run_ping_tests arg 1: '$proto'" >&2
+ exit 1 ;;
+ esac
+
+ case $want in
+ want_ok) sizes_list="64 1440 3000" ;;
+ want_fail) sizes_list="64" ;;
+ esac
+
+ for bytes in $sizes_list
+ do
+ echo "run IPv$proto ping tests ($want), $bytes byte packets..."
+
+ echo "$cmd -b $bytes -C 20 -p 250 -q $targetlist" >>$LOGDIR/$SUF:fping.out
+ $cmd -b $bytes -C 20 -p 250 -q $targetlist >>$LOGDIR/$SUF:fping.out 2>&1
+
+ # while OpenVPN is running, pings must succeed (want='want_ok')
+ # before OpenVPN is up, pings must NOT succeed (want='want_fail')
+
+ rc=$?
+ if [ $rc = 0 ] # all ping OK
+ then
+ if [ $want = "want_fail" ] # not what we want
+ then
+ fail "IPv$proto ping test succeeded, but needs to *fail*."
+ fi
+ else # ping failed
+ if [ $want = "want_ok" ] # not what we wanted
+ then
+ fail "IPv$proto ping test ($bytes bytes) failed, but should succeed."
+ fi
+ fi
+ done
+}
+
+# ----------------------------------------------------------
+# main test loop
+# ----------------------------------------------------------
+for SUF in $TEST_RUN_LIST
+do
+ echo -e "\n### test run $SUF ###\n"
+ fail_count=0
+
+ echo "save pre-openvpn ifconfig + route"
+ get_ifconfig_route >$LOGDIR/$SUF:ifconfig_route_pre.txt
+
+ # get config variables
+ eval openvpn_conf=\"\$OPENVPN_CONF_$SUF\"
+ eval expect_ifconfig4=\"\$EXPECT_IFCONFIG4_$SUF\"
+ eval expect_ifconfig6=\"\$EXPECT_IFCONFIG6_$SUF\"
+ eval ping4_hosts=\"\$PING4_HOSTS_$SUF\"
+ eval ping6_hosts=\"\$PING6_HOSTS_$SUF\"
+
+ echo -e "\nrun pre-openvpn ping tests - targets must not be reachable..."
+ run_ping_tests 4 want_fail "$ping4_hosts"
+ run_ping_tests 6 want_fail "$ping6_hosts"
+ if [ "$fail_count" = 0 ] ; then
+ echo -e "OK.\n"
+ else
+ echo -e "FAIL: make sure that ping hosts are ONLY reachable via VPN, SKIP test $SUF".
+ exit_code=31
+ continue
+ fi
+
+ echo " run ./openvpn $openvpn_conf"
+ ./openvpn $openvpn_conf >$LOGDIR/$SUF:openvpn.log &
+ opid=$!
+
+ # make sure openvpn client is terminated in case shell exits
+ trap "kill $opid" 0
+ trap "kill $opid ; trap - 0 ; exit 1" 1 2 3 15
+
+ echo "wait for connection to establish..."
+ sleep 10
+
+ # test whether OpenVPN process is still there
+ if kill -0 $opid
+ then :
+ else
+ echo -e "OpenVPN process has failed to start up, check log ($LOGDIR/$SUF:openvpn.log). FAIL.\ntail of logfile follows:\n..." >&2
+ tail $LOGDIR/$SUF:openvpn.log >&2
+ trap - 0 1 2 3 15
+ exit 10
+ fi
+
+ # compare whether anything changed in ifconfig/route setup?
+ echo "save ifconfig+route"
+ get_ifconfig_route >$LOGDIR/$SUF:ifconfig_route.txt
+
+ echo -n "compare pre-openvpn ifconfig+route with current values..."
+ if diff $LOGDIR/$SUF:ifconfig_route_pre.txt \
+ $LOGDIR/$SUF:ifconfig_route.txt >/dev/null
+ then
+ fail "no differences between ifconfig/route before OpenVPN start and now."
+ else
+ echo -e " OK!\n"
+ fi
+
+ # expected ifconfig values in there?
+ check_ifconfig 4 "$expect_ifconfig4"
+ check_ifconfig 6 "$expect_ifconfig6"
+
+ run_ping_tests 4 want_ok "$ping4_hosts"
+ run_ping_tests 6 want_ok "$ping6_hosts"
+ echo -e "ping tests done.\n"
+
+ echo "stopping OpenVPN"
+ kill $opid
+ wait $!
+ rc=$?
+ if [ $rc != 0 ] ; then
+ fail "OpenVPN return code $rc, expect 0"
+ fi
+
+ echo -e "\nsave post-openvpn ifconfig + route..."
+ get_ifconfig_route >$LOGDIR/$SUF:ifconfig_route_post.txt
+
+ echo -n "compare pre- and post-openvpn ifconfig + route..."
+ if diff $LOGDIR/$SUF:ifconfig_route_pre.txt \
+ $LOGDIR/$SUF:ifconfig_route_post.txt >$LOGDIR/$SUF:ifconfig_route_diff.txt
+ then
+ echo -e " OK.\n"
+ else
+ cat $LOGDIR/$SUF:ifconfig_route_diff.txt >&2
+ fail "differences between pre- and post-ifconfig/route"
+ fi
+ if [ "$fail_count" = 0 ] ; then
+ echo -e "test run $SUF: all tests OK.\n"
+ else
+ echo -e "test run $SUF: $fail_count test failures. FAIL.\n";
+ exit_code=30
+ fi
+done
+
+# remove trap handler
+trap - 0 1 2 3 15
+exit $exit_code
diff --git a/tap-win32/SOURCES.in b/tap-win32/SOURCES.in
index b7f0e18..cf030f4 100755
--- a/tap-win32/SOURCES.in
+++ b/tap-win32/SOURCES.in
@@ -11,8 +11,7 @@ TARGETLIBS=$(DDK_LIB_PATH)\ndis.lib $(DDK_LIB_PATH)\ntstrsafe.lib
INCLUDES=$(DDK_INCLUDE_PATH) ..
# The TAP version numbers here must be >=
-# TAP_WIN32_MIN_x values defined in
-# config-win32.h
+# PRODUCT_TAP_WIN32_MIN_x values defined in version.m4
C_DEFINES=
C_DEFINES=$(C_DEFINES) -DTAP_DRIVER_MAJOR_VERSION=@@PRODUCT_TAP_MAJOR_VER@@
C_DEFINES=$(C_DEFINES) -DTAP_DRIVER_MINOR_VERSION=@@PRODUCT_TAP_MINOR_VER@@
diff --git a/tap-win32/common.h b/tap-win32/common.h
index 6785a33..bb8ab90 100755
--- a/tap-win32/common.h
+++ b/tap-win32/common.h
@@ -28,7 +28,9 @@
// common to both.
//===============================================
+#ifndef HAVE_CONFIG_H
#include "autodefs.h"
+#endif
//=============
// TAP IOCTLs
diff --git a/tap-win32/proto.h b/tap-win32/proto.h
index 0390b08..894a37f 100755
--- a/tap-win32/proto.h
+++ b/tap-win32/proto.h
@@ -29,9 +29,11 @@
#pragma pack(1)
#define IP_HEADER_SIZE 20
+#define IPV6_HEADER_SIZE 40
typedef unsigned char MACADDR [6];
typedef unsigned long IPADDR;
+typedef unsigned char IPV6ADDR [16];
//-----------------
// Ethernet address
@@ -55,6 +57,7 @@ typedef struct
MACADDR src; /* source ether addr */
# define ETH_P_IP 0x0800 /* IPv4 protocol */
+# define ETH_P_IPV6 0x86DD /* IPv6 protocol */
# define ETH_P_ARP 0x0806 /* ARP protocol */
USHORT proto; /* packet type ID field */
} ETH_HEADER, *PETH_HEADER;
@@ -161,4 +164,61 @@ typedef struct {
#define TCPOPT_MAXSEG 2
#define TCPOLEN_MAXSEG 4
+//------------
+// IPv6 Header
+//------------
+
+typedef struct {
+ UCHAR version_prio;
+ UCHAR flow_lbl[3];
+ USHORT payload_len;
+# define IPPROTO_ICMPV6 0x3a /* ICMP protocol v6 */
+ UCHAR nexthdr;
+ UCHAR hop_limit;
+ IPV6ADDR saddr;
+ IPV6ADDR daddr;
+} IPV6HDR;
+
+//--------------------------------------------
+// IPCMPv6 NS/NA Packets (RFC4443 and RFC4861)
+//--------------------------------------------
+
+// Neighbor Solictiation - RFC 4861, 4.3
+// (this is just the ICMPv6 part of the packet)
+typedef struct {
+ UCHAR type;
+# define ICMPV6_TYPE_NS 135 // neighbour solicitation
+ UCHAR code;
+# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA
+ USHORT checksum;
+ ULONG reserved;
+ IPV6ADDR target_addr;
+} ICMPV6_NS;
+
+// Neighbor Advertisement - RFC 4861, 4.4 + 4.6/4.6.1
+// (this is just the ICMPv6 payload)
+typedef struct {
+ UCHAR type;
+# define ICMPV6_TYPE_NA 136 // neighbour advertisement
+ UCHAR code;
+# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA
+ USHORT checksum;
+ UCHAR rso_bits; // Router(0), Solicited(2), Ovrrd(4)
+ UCHAR reserved[3];
+ IPV6ADDR target_addr;
+// always include "Target Link-layer Address" option (RFC 4861 4.6.1)
+ UCHAR opt_type;
+#define ICMPV6_OPTION_TLLA 2
+ UCHAR opt_length;
+#define ICMPV6_LENGTH_TLLA 1 // multiplied by 8 -> 1 = 8 bytes
+ MACADDR target_macaddr;
+} ICMPV6_NA;
+
+// this is the complete packet with Ethernet and IPv6 headers
+typedef struct {
+ ETH_HEADER eth;
+ IPV6HDR ipv6;
+ ICMPV6_NA icmpv6;
+} ICMPV6_NA_PKT;
+
#pragma pack()
diff --git a/tap-win32/tapdrvr.c b/tap-win32/tapdrvr.c
index 506f1f6..7ab3916 100755
--- a/tap-win32/tapdrvr.c
+++ b/tap-win32/tapdrvr.c
@@ -1430,6 +1430,158 @@ NDIS_STATUS AdapterModify
return l_Status;
}
+// checksum code for ICMPv6 packet, taken from dhcp.c / udp_checksum
+// see RFC 4443, 2.3, and RFC 2460, 8.1
+USHORT
+icmpv6_checksum (const UCHAR *buf,
+ const int len_icmpv6,
+ const UCHAR *saddr6,
+ const UCHAR *daddr6)
+{
+ USHORT word16;
+ ULONG sum = 0;
+ int i;
+
+ // make 16 bit words out of every two adjacent 8 bit words and
+ // calculate the sum of all 16 bit words
+ for (i = 0; i < len_icmpv6; i += 2){
+ word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_icmpv6) ? (buf[i+1] & 0xFF) : 0);
+ sum += word16;
+ }
+
+ // add the IPv6 pseudo header which contains the IP source and destination addresses
+ for (i = 0; i < 16; i += 2){
+ word16 =((saddr6[i] << 8) & 0xFF00) + (saddr6[i+1] & 0xFF);
+ sum += word16;
+ }
+ for (i = 0; i < 16; i += 2){
+ word16 =((daddr6[i] << 8) & 0xFF00) + (daddr6[i+1] & 0xFF);
+ sum += word16;
+ }
+
+ // the next-header number and the length of the ICMPv6 packet
+ sum += (USHORT) IPPROTO_ICMPV6 + (USHORT) len_icmpv6;
+
+ // keep only the last 16 bits of the 32 bit calculated sum and add the carries
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ // Take the one's complement of sum
+ return ((USHORT) ~sum);
+}
+
+// check IPv6 packet for "is this an IPv6 Neighbor Solicitation that
+// the tap driver needs to answer?"
+// see RFC 4861 4.3 for the different cases
+static IPV6ADDR IPV6_NS_TARGET_MCAST =
+ { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x08 };
+static IPV6ADDR IPV6_NS_TARGET_UNICAST =
+ { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 };
+
+BOOLEAN
+HandleIPv6NeighborDiscovery( TapAdapterPointer p_Adapter, UCHAR * m_Data )
+{
+ const ETH_HEADER * e = (ETH_HEADER *) m_Data;
+ const IPV6HDR *ipv6 = (IPV6HDR *) (m_Data + sizeof (ETH_HEADER));
+ const ICMPV6_NS * icmpv6_ns = (ICMPV6_NS *) (m_Data + sizeof (ETH_HEADER) + sizeof (IPV6HDR));
+ ICMPV6_NA_PKT *na;
+ USHORT icmpv6_len, icmpv6_csum;
+
+ // we don't really care about the destination MAC address here
+ // - it's either a multicast MAC, or the userland destination MAC
+ // but since the TAP driver is point-to-point, all packets are "for us"
+
+ // IPv6 target address must be ff02::1::ff00:8 (multicast for
+ // initial NS) or fe80::1 (unicast for recurrent NUD)
+ if ( memcmp( ipv6->daddr, IPV6_NS_TARGET_MCAST,
+ sizeof(IPV6ADDR) ) != 0 &&
+ memcmp( ipv6->daddr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) ) != 0 )
+ {
+ return FALSE; // wrong target address
+ }
+
+ // IPv6 Next-Header must be ICMPv6
+ if ( ipv6->nexthdr != IPPROTO_ICMPV6 )
+ {
+ return FALSE; // wrong next-header
+ }
+
+ // ICMPv6 type+code must be 135/0 for NS
+ if ( icmpv6_ns->type != ICMPV6_TYPE_NS ||
+ icmpv6_ns->code != ICMPV6_CODE_0 )
+ {
+ return FALSE; // wrong ICMPv6 type
+ }
+
+ // ICMPv6 target address must be fe80::8 (magic)
+ if ( memcmp( icmpv6_ns->target_addr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) ) != 0 )
+ {
+ return FALSE; // not for us
+ }
+
+ // packet identified, build magic response packet
+
+ na = (ICMPV6_NA_PKT *) MemAlloc (sizeof (ICMPV6_NA_PKT), TRUE);
+ if ( !na ) return FALSE;
+
+ //------------------------------------------------
+ // Initialize Neighbour Advertisement reply packet
+ //------------------------------------------------
+
+ // ethernet header
+ na->eth.proto = htons(ETH_P_IPV6);
+ COPY_MAC(na->eth.dest, p_Adapter->m_MAC);
+ COPY_MAC(na->eth.src, p_Adapter->m_TapToUser.dest);
+
+ // IPv6 header
+ na->ipv6.version_prio = ipv6->version_prio;
+ NdisMoveMemory( na->ipv6.flow_lbl, ipv6->flow_lbl,
+ sizeof(na->ipv6.flow_lbl) );
+ icmpv6_len = sizeof(ICMPV6_NA_PKT) - sizeof(ETH_HEADER) - sizeof(IPV6HDR);
+ na->ipv6.payload_len = htons(icmpv6_len);
+ na->ipv6.nexthdr = IPPROTO_ICMPV6;
+ na->ipv6.hop_limit = 255;
+ NdisMoveMemory( na->ipv6.saddr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) );
+ NdisMoveMemory( na->ipv6.daddr, ipv6->saddr,
+ sizeof(IPV6ADDR) );
+
+ // ICMPv6
+ na->icmpv6.type = ICMPV6_TYPE_NA;
+ na->icmpv6.code = ICMPV6_CODE_0;
+ na->icmpv6.checksum = 0;
+ na->icmpv6.rso_bits = 0x60; // Solicited + Override
+ NdisZeroMemory( na->icmpv6.reserved, sizeof(na->icmpv6.reserved) );
+ NdisMoveMemory( na->icmpv6.target_addr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) );
+
+ // ICMPv6 option "Target Link Layer Address"
+ na->icmpv6.opt_type = ICMPV6_OPTION_TLLA;
+ na->icmpv6.opt_length = ICMPV6_LENGTH_TLLA;
+ COPY_MAC( na->icmpv6.target_macaddr, p_Adapter->m_TapToUser.dest );
+
+ // calculate and set checksum
+ icmpv6_csum = icmpv6_checksum ( (UCHAR*) &(na->icmpv6),
+ icmpv6_len,
+ na->ipv6.saddr,
+ na->ipv6.daddr );
+ na->icmpv6.checksum = htons( icmpv6_csum );
+
+ DUMP_PACKET ("HandleIPv6NeighborDiscovery",
+ (unsigned char *) na,
+ sizeof (ICMPV6_NA_PKT));
+
+ InjectPacketDeferred (p_Adapter, (UCHAR *) na, sizeof (ICMPV6_NA_PKT));
+
+ MemFree (na, sizeof (ICMPV6_NA_PKT));
+
+ return TRUE; // all fine
+}
+
//====================================================================
// Adapter Transmission
//====================================================================
@@ -1566,7 +1718,10 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
//===============================================
// In Point-To-Point mode, check to see whether
- // packet is ARP or IPv4 (if neither, then drop).
+ // packet is ARP (handled) or IPv4 (sent to app).
+ // IPv6 packets are inspected for neighbour discovery
+ // (to be handled locally), and the rest is forwarded
+ // all other protocols are dropped
//===============================================
if (l_Adapter->m_tun)
{
@@ -1611,6 +1766,27 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
// Packet looks like IPv4, queue it.
l_PacketBuffer->m_SizeFlags |= TP_TUN;
+
+ case ETH_P_IPV6:
+ // make sure that packet is large
+ // enough to be IPv6
+ if (l_PacketLength
+ < ETHERNET_HEADER_SIZE + IPV6_HEADER_SIZE)
+ goto no_queue;
+
+ // broadcasts and multicasts are handled specially
+ // (to be implemented)
+
+ // neighbor discovery packets to fe80::8 are special
+ // OpenVPN sets this next-hop to signal "handled by tapdrv"
+ if ( HandleIPv6NeighborDiscovery( l_Adapter,
+ l_PacketBuffer->m_Data ))
+ {
+ goto no_queue;
+ }
+
+ // Packet looks like IPv6, queue it :-)
+ l_PacketBuffer->m_SizeFlags |= TP_TUN;
}
}
@@ -1902,6 +2078,8 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
+ l_Adapter->m_UserToTap_IPv6 = l_Adapter->m_UserToTap;
+ l_Adapter->m_UserToTap_IPv6.proto = htons(ETH_P_IPV6);
l_Adapter->m_tun = TRUE;
@@ -1939,6 +2117,8 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
+ l_Adapter->m_UserToTap_IPv6 = l_Adapter->m_UserToTap;
+ l_Adapter->m_UserToTap_IPv6.proto = htons(ETH_P_IPV6);
l_Adapter->m_tun = TRUE;
@@ -2236,10 +2416,18 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
{
__try
{
+ ETH_HEADER * p_UserToTap = &l_Adapter->m_UserToTap;
+
+ // for IPv6, need to use ethernet header with IPv6 proto
+ if ( IPH_GET_VER( ((IPHDR*) p_IRP->AssociatedIrp.SystemBuffer)->version_len) == 6 )
+ {
+ p_UserToTap = &l_Adapter->m_UserToTap_IPv6;
+ }
+
p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length;
DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
- &l_Adapter->m_UserToTap,
+ p_UserToTap,
(unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
l_IrpSp->Parameters.Write.Length);
@@ -2258,8 +2446,8 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
NdisMEthIndicateReceive
(l_Adapter->m_MiniportAdapterHandle,
(NDIS_HANDLE) l_Adapter,
- (unsigned char *) &l_Adapter->m_UserToTap,
- sizeof (l_Adapter->m_UserToTap),
+ (unsigned char *) p_UserToTap,
+ sizeof (ETH_HEADER),
(unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
l_IrpSp->Parameters.Write.Length,
l_IrpSp->Parameters.Write.Length);
@@ -2820,6 +3008,7 @@ VOID ResetTapAdapterState (TapAdapterPointer p_Adapter)
p_Adapter->m_remoteNetmask = 0;
NdisZeroMemory (&p_Adapter->m_TapToUser, sizeof (p_Adapter->m_TapToUser));
NdisZeroMemory (&p_Adapter->m_UserToTap, sizeof (p_Adapter->m_UserToTap));
+ NdisZeroMemory (&p_Adapter->m_UserToTap_IPv6, sizeof (p_Adapter->m_UserToTap_IPv6));
// DHCP Masq
p_Adapter->m_dhcp_enabled = FALSE;
diff --git a/tap-win32/types.h b/tap-win32/types.h
index 9406252..bdc08e7 100755
--- a/tap-win32/types.h
+++ b/tap-win32/types.h
@@ -143,6 +143,7 @@ typedef struct _TapAdapter
IPADDR m_remoteNetmask;
ETH_HEADER m_TapToUser;
ETH_HEADER m_UserToTap;
+ ETH_HEADER m_UserToTap_IPv6; // same as UserToTap but proto=ipv6
MACADDR m_MAC_Broadcast;
// Used for DHCP server masquerade
diff --git a/thread.c b/thread.c
deleted file mode 100644
index efe911b..0000000
--- a/thread.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "syshead.h"
-
-#ifdef USE_PTHREAD
-
-#include "thread.h"
-#include "buffer.h"
-#include "common.h"
-#include "error.h"
-#include "crypto.h"
-
-#include "memdbg.h"
-
-static struct sparse_mutex *ssl_mutex; /* GLOBAL */
-
-static void
-ssl_pthreads_locking_callback (int mode, int type, char *file, int line)
-{
- dmsg (D_OPENSSL_LOCK, "SSL LOCK thread=%4lu mode=%s lock=%s %s:%d",
- CRYPTO_thread_id (),
- (mode & CRYPTO_LOCK) ? "l" : "u",
- (type & CRYPTO_READ) ? "r" : "w", file, line);
-
- if (mode & CRYPTO_LOCK)
- pthread_mutex_lock (&ssl_mutex[type].mutex);
- else
- pthread_mutex_unlock (&ssl_mutex[type].mutex);
-}
-
-static unsigned long
-ssl_pthreads_thread_id (void)
-{
- unsigned long ret;
-
- ret = (unsigned long) pthread_self ();
- return ret;
-}
-
-static void
-ssl_thread_setup (void)
-{
- int i;
-
-#error L_MSG needs to be initialized as a recursive mutex
-
- ssl_mutex = OPENSSL_malloc (CRYPTO_num_locks () * sizeof (struct sparse_mutex));
- for (i = 0; i < CRYPTO_num_locks (); i++)
- pthread_mutex_init (&ssl_mutex[i].mutex, NULL);
-
- CRYPTO_set_id_callback ((unsigned long (*)(void)) ssl_pthreads_thread_id);
- CRYPTO_set_locking_callback ((void (*)(int, int, const char*, int)) ssl_pthreads_locking_callback);
-}
-
-static void
-ssl_thread_cleanup (void)
-{
- int i;
-
- dmsg (D_OPENSSL_LOCK, "SSL LOCK cleanup");
- CRYPTO_set_locking_callback (NULL);
- for (i = 0; i < CRYPTO_num_locks (); i++)
- pthread_mutex_destroy (&ssl_mutex[i].mutex);
- OPENSSL_free (ssl_mutex);
-}
-
-struct sparse_mutex mutex_array[N_MUTEXES]; /* GLOBAL */
-bool pthread_initialized; /* GLOBAL */
-
-openvpn_thread_t
-openvpn_thread_create (void *(*start_routine) (void *), void* arg)
-{
- openvpn_thread_t ret;
- ASSERT (pthread_initialized);
- ASSERT (!pthread_create (&ret, NULL, start_routine, arg));
- dmsg (D_THREAD_DEBUG, "CREATE THREAD ID=%lu", (unsigned long)ret);
- return ret;
-}
-
-void
-openvpn_thread_join (openvpn_thread_t id)
-{
- ASSERT (pthread_initialized);
- pthread_join (id, NULL);
-}
-
-void
-openvpn_thread_init ()
-{
- int i;
-
- ASSERT (!pthread_initialized);
-
- msg (M_INFO, "PTHREAD support initialized");
-
- /* initialize OpenSSL library locking */
-#if defined(USE_CRYPTO) && defined(USE_SSL)
- ssl_thread_setup();
-#endif
-
- /* initialize static mutexes */
- for (i = 0; i < N_MUTEXES; i++)
- ASSERT (!pthread_mutex_init (&mutex_array[i].mutex, NULL));
-
- msg_thread_init ();
-
- pthread_initialized = true;
-}
-
-void
-openvpn_thread_cleanup ()
-{
- if (pthread_initialized)
- {
- int i;
-
- pthread_initialized = false;
-
- /* cleanup OpenSSL library locking */
-#if defined(USE_CRYPTO) && defined(USE_SSL)
- ssl_thread_cleanup();
-#endif
-
- /* destroy static mutexes */
- for (i = 0; i < N_MUTEXES; i++)
- ASSERT (!pthread_mutex_destroy (&mutex_array[i].mutex));
-
- msg_thread_uninit ();
- }
-}
-
-#else
-static void dummy(void) {}
-#endif
diff --git a/thread.h b/thread.h
deleted file mode 100644
index 427237b..0000000
--- a/thread.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef THREAD_H
-#define THREAD_H
-
-#include "basic.h"
-#include "common.h"
-
-/*
- * OpenVPN static mutex locks, by mutex type
- */
-#define L_UNUSED 0
-#define L_CTIME 1
-#define L_INET_NTOA 2
-#define L_MSG 3
-#define L_STRERR 4
-#define L_PUTENV 5
-#define L_PRNG 6
-#define L_GETTIMEOFDAY 7
-#define L_ENV_SET 8
-#define L_SYSTEM 9
-#define L_CREATE_TEMP 10
-#define L_PLUGIN 11
-#define N_MUTEXES 12
-
-#ifdef USE_PTHREAD
-
-#define MAX_THREADS 50
-
-#define CACHE_LINE_SIZE 128
-
-/*
- * Improve SMP performance by making sure that each
- * mutex resides in its own cache line.
- */
-struct sparse_mutex
-{
- pthread_mutex_t mutex;
- uint8_t dummy [CACHE_LINE_SIZE - sizeof (pthread_mutex_t)];
-};
-
-typedef pthread_t openvpn_thread_t;
-
-extern bool pthread_initialized;
-
-extern struct sparse_mutex mutex_array[N_MUTEXES];
-
-#define MUTEX_DEFINE(lock) pthread_mutex_t lock
-#define MUTEX_PTR_DEFINE(lock) pthread_mutex_t *lock
-
-static inline bool
-openvpn_thread_enabled (void)
-{
- return pthread_initialized;
-}
-
-static inline openvpn_thread_t
-openvpn_thread_self (void)
-{
- return pthread_initialized ? pthread_self() : 0;
-}
-
-static inline void
-mutex_init (pthread_mutex_t *mutex)
-{
- if (mutex)
- pthread_mutex_init (mutex, NULL);
-}
-
-static inline void
-mutex_destroy (pthread_mutex_t *mutex)
-{
- if (mutex)
- pthread_mutex_destroy (mutex);
-}
-
-static inline void
-mutex_lock (pthread_mutex_t *mutex)
-{
- if (pthread_initialized && mutex)
- pthread_mutex_lock (mutex);
-}
-
-static inline bool
-mutex_trylock (pthread_mutex_t *mutex)
-{
- if (pthread_initialized && mutex)
- return pthread_mutex_trylock (mutex) == 0;
- else
- return true;
-}
-
-static inline void
-mutex_unlock (pthread_mutex_t *mutex)
-{
- if (pthread_initialized && mutex)
- {
- pthread_mutex_unlock (mutex);
-#if 1 /* JYFIXME: if race conditions exist, make them more likely to occur */
- sleep (0);
-#endif
- }
-}
-
-static inline void
-mutex_cycle (pthread_mutex_t *mutex)
-{
- if (pthread_initialized && mutex)
- {
- pthread_mutex_unlock (mutex);
- sleep (0);
- pthread_mutex_lock (mutex);
- }
-}
-
-static inline void
-mutex_lock_static (int type)
-{
- mutex_lock (&mutex_array[type].mutex);
-}
-
-static inline void
-mutex_unlock_static (int type)
-{
- mutex_unlock (&mutex_array[type].mutex);
-}
-
-static inline void
-mutex_cycle_static (int type)
-{
- mutex_cycle (&mutex_array[type].mutex);
-}
-
-void openvpn_thread_init (void);
-void openvpn_thread_cleanup (void);
-
-openvpn_thread_t openvpn_thread_create (void *(*start_routine) (void *), void* arg);
-void openvpn_thread_join (openvpn_thread_t id);
-
-#else /* USE_PTHREAD */
-
-typedef int openvpn_thread_t;
-
-#if defined(_MSC_VER) || PEDANTIC
-
-#define MUTEX_DEFINE(lock) int eat_semicolon
-#define MUTEX_PTR_DEFINE(lock) int eat_semicolon
-
-#else
-
-#define MUTEX_DEFINE(lock)
-#define MUTEX_PTR_DEFINE(lock)
-
-#endif
-
-#define mutex_init(m)
-#define mutex_destroy(m)
-#define mutex_lock(m)
-#define mutex_trylock(m) (true)
-#define mutex_unlock(m)
-#define mutex_cycle(m)
-
-static inline bool
-openvpn_thread_enabled (void)
-{
- return false;
-}
-
-static inline openvpn_thread_t
-openvpn_thread_self (void)
-{
- return 0;
-}
-
-static inline void
-openvpn_thread_init (void)
-{
-}
-
-static inline void
-openvpn_thread_cleanup (void)
-{
-}
-
-static inline openvpn_thread_t
-openvpn_thread_create (void *(*start_routine) (void *), void* arg)
-{
- return 0;
-}
-
-static inline void
-work_thread_join (openvpn_thread_t id)
-{
-}
-
-static inline void
-mutex_lock_static (int type)
-{
-}
-
-static inline void
-mutex_unlock_static (int type)
-{
-}
-
-static inline void
-mutex_cycle_static (int type)
-{
-}
-
-#endif /* USE_PTHREAD */
-
-#endif /* THREAD_H */
diff --git a/tun.c b/tun.c
index f1b132c..5a41cdf 100644
--- a/tun.c
+++ b/tun.c
@@ -56,13 +56,15 @@ static void netsh_ifconfig (const struct tuntap_options *to,
const in_addr_t ip,
const in_addr_t netmask,
const unsigned int flags);
+static void netsh_command (const struct argv *a, int n);
static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc);
#endif
#ifdef TARGET_SOLARIS
-static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual);
+static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual, bool unplumb_inet6);
+#include <stropts.h>
#endif
bool
@@ -128,30 +130,6 @@ guess_tuntap_dev (const char *dev,
return dev;
}
-/*
- * Called by the open_tun function of OSes to check if we
- * explicitly support IPv6.
- *
- * In this context, explicit means that the OS expects us to
- * do something special to the tun socket in order to support
- * IPv6, i.e. it is not transparent.
- *
- * ipv6_explicitly_supported should be set to false if we don't
- * have any explicit IPv6 code in the tun device handler.
- *
- * If ipv6_explicitly_supported is true, then we have explicit
- * OS-specific tun dev code for handling IPv6. If so, tt->ipv6
- * is set according to the --tun-ipv6 command line option.
- */
-static void
-ipv6_support (bool ipv6, bool ipv6_explicitly_supported, struct tuntap* tt)
-{
- tt->ipv6 = false;
- if (ipv6_explicitly_supported)
- tt->ipv6 = ipv6;
- else if (ipv6)
- msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
-}
/* --ifconfig-nowarn disables some options sanity checking */
static const char ifconfig_warn_how_to_silence[] = "(silence this warning with --ifconfig-nowarn)";
@@ -422,6 +400,8 @@ init_tun (const char *dev, /* --dev option */
int topology, /* one of the TOP_x values */
const char *ifconfig_local_parm, /* --ifconfig parm 1 */
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
+ const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 IPv6 */
+ const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 IPv6 */
in_addr_t local_public,
in_addr_t remote_public,
const bool strict_warn,
@@ -536,6 +516,40 @@ init_tun (const char *dev, /* --dev option */
tt->did_ifconfig_setup = true;
}
+
+ if (ifconfig_ipv6_local_parm && ifconfig_ipv6_remote_parm)
+ {
+ const char *ifconfig_ipv6_local = NULL;
+ const char *ifconfig_ipv6_remote = NULL;
+
+ /*
+ * Convert arguments to binary IPv6 addresses.
+ */
+
+ if ( inet_pton( AF_INET6, ifconfig_ipv6_local_parm, &tt->local_ipv6 ) != 1 ||
+ inet_pton( AF_INET6, ifconfig_ipv6_remote_parm, &tt->remote_ipv6 ) != 1 )
+ {
+ msg( M_FATAL, "init_tun: problem converting IPv6 ifconfig addresses %s and %s to binary", ifconfig_ipv6_local_parm, ifconfig_ipv6_remote_parm );
+ }
+ tt->netbits_ipv6 = 64;
+
+ /*
+ * Set ifconfig parameters
+ */
+ ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
+ ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc);
+
+ /*
+ * Set environmental variables with ifconfig parameters.
+ */
+ if (es)
+ {
+ setenv_str (es, "ifconfig_ipv6_local", ifconfig_ipv6_local);
+ setenv_str (es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote);
+ }
+ tt->did_ifconfig_ipv6_setup = true;
+ }
+
gc_free (&gc);
return tt;
}
@@ -558,6 +572,28 @@ init_tun_post (struct tuntap *tt,
#endif
}
+#if defined(TARGET_WIN32) || \
+ defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD)
+
+/* some of the platforms will auto-add a "network route" pointing
+ * to the interface on "ifconfig tunX 2001:db8::1/64", others need
+ * an extra call to "route add..."
+ * -> helper function to simplify code below
+ */
+void add_route_connected_v6_net(struct tuntap * tt,
+ const struct env_set *es)
+{
+ struct route_ipv6 r6;
+
+ r6.defined = true;
+ r6.network = tt->local_ipv6;
+ r6.netbits = tt->netbits_ipv6;
+ r6.gateway = tt->local_ipv6;
+ add_route_ipv6 (&r6, tt, 0, es);
+}
+#endif
+
+
/* execute the ifconfig command through the shell */
void
do_ifconfig (struct tuntap *tt,
@@ -573,10 +609,16 @@ do_ifconfig (struct tuntap *tt,
const char *ifconfig_local = NULL;
const char *ifconfig_remote_netmask = NULL;
const char *ifconfig_broadcast = NULL;
+ const char *ifconfig_ipv6_local = NULL;
+ const char *ifconfig_ipv6_remote = NULL;
+ bool do_ipv6 = false;
struct argv argv;
argv_init (&argv);
+ msg( M_INFO, "do_ifconfig, tt->ipv6=%d, tt->did_ifconfig_ipv6_setup=%d",
+ tt->ipv6, tt->did_ifconfig_ipv6_setup );
+
/*
* We only handle TUN/TAP devices here, not --dev null devices.
*/
@@ -588,6 +630,13 @@ do_ifconfig (struct tuntap *tt,
ifconfig_local = print_in_addr_t (tt->local, 0, &gc);
ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc);
+ if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
+ {
+ ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
+ ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc);
+ do_ipv6 = true;
+ }
+
/*
* If TAP-style device, generate broadcast address.
*/
@@ -646,7 +695,19 @@ do_ifconfig (struct tuntap *tt,
argv_msg (M_INFO, &argv);
openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed");
}
- tt->did_ifconfig = true;
+ if ( do_ipv6 )
+ {
+ argv_printf( &argv,
+ "%s -6 addr add %s/%d dev %s",
+ iproute_path,
+ ifconfig_ipv6_local,
+ tt->netbits_ipv6,
+ actual
+ );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ip -6 addr add failed");
+ }
+ tt->did_ifconfig = true;
#else
if (tun)
argv_printf (&argv,
@@ -669,6 +730,18 @@ do_ifconfig (struct tuntap *tt,
);
argv_msg (M_INFO, &argv);
openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig failed");
+ if ( do_ipv6 )
+ {
+ argv_printf (&argv,
+ "%s %s inet6 add %s/%d",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_ipv6_local,
+ tt->netbits_ipv6
+ );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig inet6 failed");
+ }
tt->did_ifconfig = true;
#endif /*CONFIG_FEATURE_IPROUTE*/
@@ -692,7 +765,7 @@ do_ifconfig (struct tuntap *tt,
argv_msg (M_INFO, &argv);
if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-1 failed"))
- solaris_error_close (tt, es, actual);
+ solaris_error_close (tt, es, actual, false);
argv_printf (&argv,
"%s %s netmask 255.255.255.255",
@@ -701,11 +774,90 @@ do_ifconfig (struct tuntap *tt,
);
}
else
- no_tap_ifconfig ();
+ if (tt->topology == TOP_SUBNET)
+ {
+ argv_printf (&argv,
+ "%s %s %s %s netmask %s mtu %d up",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_local,
+ ifconfig_local,
+ ifconfig_remote_netmask,
+ tun_mtu
+ );
+ }
+ else
+ argv_printf (&argv,
+ " %s %s %s netmask %s broadcast + up",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_local,
+ ifconfig_remote_netmask
+ );
argv_msg (M_INFO, &argv);
if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed"))
- solaris_error_close (tt, es, actual);
+ solaris_error_close (tt, es, actual, false);
+
+ if ( do_ipv6 )
+ {
+ argv_printf (&argv, "%s %s inet6 unplumb",
+ IFCONFIG_PATH, actual );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, 0, NULL);
+
+ if ( tt->type == DEV_TYPE_TUN )
+ {
+ argv_printf (&argv,
+ "%s %s inet6 plumb %s/%d %s up",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_ipv6_local,
+ tt->netbits_ipv6,
+ ifconfig_ipv6_remote
+ );
+ }
+ else /* tap mode */
+ {
+ /* base IPv6 tap interface needs to be brought up first
+ */
+ argv_printf (&argv, "%s %s inet6 plumb up",
+ IFCONFIG_PATH, actual );
+ argv_msg (M_INFO, &argv);
+ if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 (prepare) failed"))
+ solaris_error_close (tt, es, actual, true);
+
+ /* we might need to do "ifconfig %s inet6 auto-dhcp drop"
+ * after the system has noticed the interface and fired up
+ * the DHCPv6 client - but this takes quite a while, and the
+ * server will ignore the DHCPv6 packets anyway. So we don't.
+ */
+
+ /* static IPv6 addresses need to go to a subinterface (tap0:1)
+ */
+ argv_printf (&argv,
+ "%s %s inet6 addif %s/%d up",
+ IFCONFIG_PATH, actual,
+ ifconfig_ipv6_local, tt->netbits_ipv6 );
+ }
+ argv_msg (M_INFO, &argv);
+ if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 failed"))
+ solaris_error_close (tt, es, actual, true);
+ }
+
+ if (!tun && tt->topology == TOP_SUBNET)
+ {
+ /* Add a network route for the local tun interface */
+ struct route r;
+ CLEAR (r);
+ r.defined = true;
+ r.network = tt->local & tt->remote_netmask;
+ r.netmask = tt->remote_netmask;
+ r.gateway = tt->local;
+ r.metric_defined = true;
+ r.metric = 0;
+ add_route (&r, tt, 0, es);
+ }
tt->did_ifconfig = true;
@@ -753,10 +905,42 @@ do_ifconfig (struct tuntap *tt,
);
argv_msg (M_INFO, &argv);
openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed");
+ if ( do_ipv6 )
+ {
+ argv_printf (&argv,
+ "%s %s inet6 %s/%d",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_ipv6_local,
+ tt->netbits_ipv6
+ );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig inet6 failed");
+
+ /* and, hooray, we explicitely need to add a route... */
+ add_route_connected_v6_net(tt, es);
+ }
tt->did_ifconfig = true;
#elif defined(TARGET_NETBSD)
+/* whether or not NetBSD can do IPv6 can be seen by the availability of
+ * the TUNSIFHEAD ioctl() - see next TARGET_NETBSD block for more details
+ */
+#ifdef TUNSIFHEAD
+# define NETBSD_MULTI_AF
+#endif
+
+ /* as on OpenBSD and Darwin, destroy and re-create tun<x> interface
+ */
+ argv_printf (&argv, "%s %s destroy", IFCONFIG_PATH, actual );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, 0, "NetBSD ifconfig destroy failed");
+
+ argv_printf (&argv, "%s %s create", IFCONFIG_PATH, actual );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig create failed");
+
if (tun)
argv_printf (&argv,
"%s %s %s %s mtu %d netmask 255.255.255.255 up",
@@ -783,6 +967,27 @@ do_ifconfig (struct tuntap *tt,
);
argv_msg (M_INFO, &argv);
openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed");
+
+ if ( do_ipv6 )
+ {
+#ifdef NETBSD_MULTI_AF
+ argv_printf (&argv,
+ "%s %s inet6 %s/%d",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_ipv6_local,
+ tt->netbits_ipv6
+ );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig inet6 failed");
+
+ /* and, hooray, we explicitely need to add a route... */
+ add_route_connected_v6_net(tt, es);
+#else
+ msg( M_INFO, "no IPv6 support for tun interfaces on NetBSD before 4.0 (if your system is newer, recompile openvpn)" );
+ tt->ipv6 = false;
+#endif
+ }
tt->did_ifconfig = true;
#elif defined(TARGET_DARWIN)
@@ -848,6 +1053,22 @@ do_ifconfig (struct tuntap *tt,
add_route (&r, tt, 0, es);
}
+ if ( do_ipv6 )
+ {
+ argv_printf (&argv,
+ "%s %s inet6 %s/%d",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_ipv6_local,
+ tt->netbits_ipv6
+ );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, S_FATAL, "MacOS X ifconfig inet6 failed");
+
+ /* and, hooray, we explicitely need to add a route... */
+ add_route_connected_v6_net(tt, es);
+ }
+
#elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)
/* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */
@@ -860,26 +1081,15 @@ do_ifconfig (struct tuntap *tt,
ifconfig_remote_netmask,
tun_mtu
);
- else {
- if (tt->topology == TOP_SUBNET)
- argv_printf (&argv,
- "%s %s %s netmask %s mtu %d up",
+ else
+ argv_printf (&argv,
+ "%s %s %s netmask %s mtu %d up",
IFCONFIG_PATH,
actual,
ifconfig_local,
ifconfig_remote_netmask,
tun_mtu
);
- else
- argv_printf (&argv,
- "%s %s %s netmask %s mtu %d up",
- IFCONFIG_PATH,
- actual,
- ifconfig_local,
- ifconfig_remote_netmask,
- tun_mtu
- );
- }
argv_msg (M_INFO, &argv);
openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig failed");
@@ -897,6 +1107,19 @@ do_ifconfig (struct tuntap *tt,
add_route (&r, tt, 0, es);
}
+ if ( do_ipv6 )
+ {
+ argv_printf (&argv,
+ "%s %s inet6 %s/%d",
+ IFCONFIG_PATH,
+ actual,
+ ifconfig_ipv6_local,
+ tt->netbits_ipv6
+ );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed");
+ }
+
#elif defined (WIN32)
{
/*
@@ -936,6 +1159,34 @@ do_ifconfig (struct tuntap *tt,
tt->did_ifconfig = true;
}
+ /* IPv6 always uses "netsh" interface */
+ if ( do_ipv6 )
+ {
+ char * saved_actual;
+
+ if (!strcmp (actual, "NULL"))
+ msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than one TAP-Win32 adapter, you must also specify --dev-node");
+
+ /* example: netsh interface ipv6 add address MyTap 2001:608:8003::d */
+ argv_printf (&argv,
+ "%s%sc interface ipv6 add address %s %s",
+ get_win_sys_path(),
+ NETSH_PATH_SUFFIX,
+ actual,
+ ifconfig_ipv6_local );
+
+ netsh_command (&argv, 4);
+
+ /* explicit route needed */
+ /* on windows, OpenVPN does ifconfig first, open_tun later, so
+ * tt->actual_name might not yet be initialized, but routing code
+ * needs to know interface name - point to "actual", restore later
+ */
+ saved_actual = tt->actual_name;
+ tt->actual_name = (char*) actual;
+ add_route_connected_v6_net(tt, es);
+ tt->actual_name = saved_actual;
+ }
#else
msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script.");
#endif
@@ -968,14 +1219,16 @@ open_null (struct tuntap *tt)
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
- bool ipv6, bool ipv6_explicitly_supported, bool dynamic,
+ bool ipv6_explicitly_supported, bool dynamic,
struct tuntap *tt)
{
char tunname[256];
char dynamic_name[256];
bool dynamic_opened = false;
- ipv6_support (ipv6, ipv6_explicitly_supported, tt);
+
+ if ( tt->ipv6 && ! ipv6_explicitly_supported )
+ msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
if (tt->type == DEV_TYPE_NULL)
{
@@ -1071,16 +1324,16 @@ close_tun_generic (struct tuntap *tt)
#if !PEDANTIC
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
struct ifreq ifr;
- /*
- * Set tt->ipv6 to true if
- * (a) we have the capability of supporting --tun-ipv6, and
- * (b) --tun-ipv6 was specified.
+ /* warn if a very old linux version is used & --tun-ipv6 set
*/
- ipv6_support (ipv6, LINUX_IPV6, tt);
+#if LINUX_IPV6 == 0
+ if ( tt->ipv6 )
+ msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
+#endif
/*
* We handle --dev null specially, we do not open /dev/null for this.
@@ -1192,13 +1445,13 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
close (tt->fd);
tt->fd = -1;
}
- open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt);
+ open_tun_generic (dev, dev_type, dev_node, false, true, tt);
}
#else
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
ASSERT (0);
}
@@ -1208,9 +1461,9 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
#else
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt);
+ open_tun_generic (dev, dev_type, dev_node, false, true, tt);
}
#endif /* HAVE_LINUX_IF_TUN_H */
@@ -1230,7 +1483,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
#endif
void
-tuncfg (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options)
+tuncfg (const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options)
{
struct tuntap *tt;
@@ -1238,7 +1491,7 @@ tuncfg (const char *dev, const char *dev_type, const char *dev_node, bool ipv6,
clear_tuntap (tt);
tt->type = dev_type_enum (dev, dev_type);
tt->options = *options;
- open_tun (dev, dev_type, dev_node, ipv6, tt);
+ open_tun (dev, dev_type, dev_node, tt);
if (ioctl (tt->fd, TUNSETPERSIST, persist_mode) < 0)
msg (M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev);
if (username != NULL)
@@ -1381,17 +1634,22 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#endif
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- int if_fd, muxid, ppa = -1;
- struct ifreq ifr;
+ int if_fd, ip_muxid, arp_muxid, arp_fd, ppa = -1;
+ struct lifreq ifr;
const char *ptr;
- const char *ip_node;
+ const char *ip_node, *arp_node;
const char *dev_tuntap_type;
int link_type;
bool is_tun;
+ struct strioctl strioc_if, strioc_ppa;
- ipv6_support (ipv6, false, tt);
+ /* improved generic TUN/TAP driver from
+ * http://www.whiteboard.ne.jp/~admin2/tuntap/
+ * has IPv6 support
+ */
+ memset(&ifr, 0x0, sizeof(ifr));
if (tt->type == DEV_TYPE_NULL)
{
@@ -1410,9 +1668,10 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
}
else if (tt->type == DEV_TYPE_TAP)
{
- ip_node = "/dev/ip";
+ ip_node = "/dev/udp";
if (!dev_node)
dev_node = "/dev/tap";
+ arp_node = dev_node;
dev_tuntap_type = "tap";
link_type = I_PLINK; /* was: I_LINK */
is_tun = false;
@@ -1439,7 +1698,11 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
msg (M_ERR, "Can't open %s", dev_node);
/* Assign a new PPA and get its unit number. */
- if ((ppa = ioctl (tt->fd, TUNNEWPPA, ppa)) < 0)
+ strioc_ppa.ic_cmd = TUNNEWPPA;
+ strioc_ppa.ic_timout = 0;
+ strioc_ppa.ic_len = sizeof(ppa);
+ strioc_ppa.ic_dp = (char *)&ppa;
+ if ((ppa = ioctl (tt->fd, I_STR, &strioc_ppa)) < 0)
msg (M_ERR, "Can't assign new interface");
if ((if_fd = open (dev_node, O_RDWR, 0)) < 0)
@@ -1448,27 +1711,83 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
if (ioctl (if_fd, I_PUSH, "ip") < 0)
msg (M_ERR, "Can't push IP module");
+ if (tt->type == DEV_TYPE_TUN)
+ {
/* Assign ppa according to the unit number returned by tun device */
if (ioctl (if_fd, IF_UNITSEL, (char *) &ppa) < 0)
msg (M_ERR, "Can't set PPA %d", ppa);
-
- if ((muxid = ioctl (tt->ip_fd, link_type, if_fd)) < 0)
- msg (M_ERR, "Can't link %s device to IP", dev_tuntap_type);
-
- close (if_fd);
+ }
tt->actual_name = (char *) malloc (32);
check_malloc_return (tt->actual_name);
openvpn_snprintf (tt->actual_name, 32, "%s%d", dev_tuntap_type, ppa);
+ if (tt->type == DEV_TYPE_TAP)
+ {
+ if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
+ msg (M_ERR, "Can't get flags\n");
+ strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name));
+ ifr.lifr_ppa = ppa;
+ /* Assign ppa according to the unit number returned by tun device */
+ if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
+ msg (M_ERR, "Can't set PPA %d", ppa);
+ if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
+ msg (M_ERR, "Can't get flags\n");
+ /* Push arp module to if_fd */
+ if (ioctl (if_fd, I_PUSH, "arp") < 0)
+ msg (M_ERR, "Can't push ARP module");
+
+ /* Pop any modules on the stream */
+ while (true)
+ {
+ if (ioctl (tt->ip_fd, I_POP, NULL) < 0)
+ break;
+ }
+ /* Push arp module to ip_fd */
+ if (ioctl (tt->ip_fd, I_PUSH, "arp") < 0)
+ msg (M_ERR, "Can't push ARP module\n");
+
+ /* Open arp_fd */
+ if ((arp_fd = open (arp_node, O_RDWR, 0)) < 0)
+ msg (M_ERR, "Can't open %s\n", arp_node);
+ /* Push arp module to arp_fd */
+ if (ioctl (arp_fd, I_PUSH, "arp") < 0)
+ msg (M_ERR, "Can't push ARP module\n");
+
+ /* Set ifname to arp */
+ strioc_if.ic_cmd = SIOCSLIFNAME;
+ strioc_if.ic_timout = 0;
+ strioc_if.ic_len = sizeof(ifr);
+ strioc_if.ic_dp = (char *)&ifr;
+ if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
+ msg (M_ERR, "Can't set ifname to arp\n");
+ }
+ }
+
+ if ((ip_muxid = ioctl (tt->ip_fd, link_type, if_fd)) < 0)
+ msg (M_ERR, "Can't link %s device to IP", dev_tuntap_type);
+
+ if (tt->type == DEV_TYPE_TAP) {
+ if ((arp_muxid = ioctl (tt->ip_fd, link_type, arp_fd)) < 0)
+ msg (M_ERR, "Can't link %s device to ARP", dev_tuntap_type);
+ close (arp_fd);
+ }
+
CLEAR (ifr);
- strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name));
- ifr.ifr_ip_muxid = muxid;
+ strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name));
+ ifr.lifr_ip_muxid = ip_muxid;
+ if (tt->type == DEV_TYPE_TAP) {
+ ifr.lifr_arp_muxid = arp_muxid;
+ }
- if (ioctl (tt->ip_fd, SIOCSIFMUXID, &ifr) < 0)
+ if (ioctl (tt->ip_fd, SIOCSLIFMUXID, &ifr) < 0)
{
- ioctl (tt->ip_fd, I_PUNLINK, muxid);
+ if (tt->type == DEV_TYPE_TAP)
+ {
+ ioctl (tt->ip_fd, I_PUNLINK , arp_muxid);
+ }
+ ioctl (tt->ip_fd, I_PUNLINK, ip_muxid);
msg (M_ERR, "Can't set multiplexor id");
}
@@ -1484,20 +1803,38 @@ solaris_close_tun (struct tuntap *tt)
{
if (tt)
{
+ /* IPv6 interfaces need to be 'manually' de-configured */
+ if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
+ {
+ struct argv argv;
+ argv_init (&argv);
+ argv_printf( &argv, "%s %s inet6 unplumb",
+ IFCONFIG_PATH, tt->actual_name );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed");
+ argv_reset (&argv);
+ }
+
if (tt->ip_fd >= 0)
{
- struct ifreq ifr;
+ struct lifreq ifr;
CLEAR (ifr);
- strncpynt (ifr.ifr_name, tt->actual_name, sizeof (ifr.ifr_name));
+ strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name));
- if (ioctl (tt->ip_fd, SIOCGIFFLAGS, &ifr) < 0)
+ if (ioctl (tt->ip_fd, SIOCGLIFFLAGS, &ifr) < 0)
msg (M_WARN | M_ERRNO, "Can't get iface flags");
- if (ioctl (tt->ip_fd, SIOCGIFMUXID, &ifr) < 0)
+ if (ioctl (tt->ip_fd, SIOCGLIFMUXID, &ifr) < 0)
msg (M_WARN | M_ERRNO, "Can't get multiplexor id");
- if (ioctl (tt->ip_fd, I_PUNLINK, ifr.ifr_ip_muxid) < 0)
- msg (M_WARN | M_ERRNO, "Can't unlink interface");
+ if (tt->type == DEV_TYPE_TAP)
+ {
+ if (ioctl (tt->ip_fd, I_PUNLINK, ifr.lifr_arp_muxid) < 0)
+ msg (M_WARN | M_ERRNO, "Can't unlink interface(arp)");
+ }
+
+ if (ioctl (tt->ip_fd, I_PUNLINK, ifr.lifr_ip_muxid) < 0)
+ msg (M_WARN | M_ERRNO, "Can't unlink interface(ip)");
close (tt->ip_fd);
tt->ip_fd = -1;
@@ -1530,11 +1867,20 @@ close_tun (struct tuntap *tt)
}
static void
-solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual)
+solaris_error_close (struct tuntap *tt, const struct env_set *es,
+ const char *actual, bool unplumb_inet6 )
{
struct argv argv;
argv_init (&argv);
+ if (unplumb_inet6)
+ {
+ argv_printf( &argv, "%s %s inet6 unplumb",
+ IFCONFIG_PATH, actual );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, es, 0, "Solaris ifconfig inet6 unplumb failed");
+ }
+
argv_printf (&argv,
"%s %s unplumb",
IFCONFIG_PATH,
@@ -1591,9 +1937,9 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
*/
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt);
+ open_tun_generic (dev, dev_type, dev_node, true, true, tt);
/* Enable multicast on the interface */
if (tt->fd >= 0)
@@ -1605,7 +1951,9 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
strerror(errno));
}
+#ifdef IFF_MULTICAST /* openbsd 4.x doesn't have this */
info.flags |= IFF_MULTICAST;
+#endif
if (ioctl (tt->fd, TUNSIFINFO, &info) < 0) {
msg (M_WARN | M_ERRNO, "Can't set interface info: %s",
@@ -1614,12 +1962,31 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
}
}
+/* the current way OpenVPN handles tun devices on OpenBSD leads to
+ * lingering tunX interfaces after close -> for a full cleanup, they
+ * need to be explicitely destroyed
+ */
+
void
close_tun (struct tuntap* tt)
{
if (tt)
{
+ struct gc_arena gc = gc_new ();
+ struct argv argv;
+
+ /* setup command, close tun dev (clears tt->actual_name!), run command
+ */
+
+ argv_init (&argv);
+ argv_printf (&argv, "%s %s destroy",
+ IFCONFIG_PATH, tt->actual_name);
+
close_tun_generic (tt);
+
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, NULL, 0, "OpenBSD 'destroy tun interface' failed (non-critical)");
+
free (tt);
}
}
@@ -1682,33 +2049,51 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_NETBSD)
/*
- * NetBSD does not support IPv6 on tun out of the box,
- * but there exists a patch. When this patch is applied,
- * only two things are left to openvpn:
- * 1. Activate multicasting (this has already been done
- * before by the kernel, but we make sure that nobody
- * has deactivated multicasting inbetween.
- * 2. Deactivate "link layer mode" (otherwise NetBSD
- * prepends the address family to the packet, and we
- * would run into the same trouble as with OpenBSD.
+ * NetBSD before 4.0 does not support IPv6 on tun out of the box,
+ * but there exists a patch (sys/net/if_tun.c, 1.79->1.80, see PR 32944).
+ *
+ * NetBSD 4.0 and up do, but we need to put the tun interface into
+ * "multi_af" mode, which will prepend the address family to all packets
+ * (same as OpenBSD and FreeBSD). If this is not enabled, the kernel
+ * silently drops all IPv6 packets on output and gets confused on input.
+ *
+ * On earlier versions, multi_af is not available at all, so we have
+ * two different NetBSD code variants here :-(
+ *
*/
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt);
+#ifdef NETBSD_MULTI_AF
+ open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+#else
+ open_tun_generic (dev, dev_type, dev_node, false, true, tt);
+#endif
+
if (tt->fd >= 0)
{
int i = IFF_POINTOPOINT|IFF_MULTICAST;
ioctl (tt->fd, TUNSIFMODE, &i); /* multicast on */
i = 0;
ioctl (tt->fd, TUNSLMODE, &i); /* link layer mode off */
+
+#ifdef NETBSD_MULTI_AF
+ i = 1;
+ if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0) /* multi-af mode on */
+ {
+ msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
+ }
+#endif
}
}
void
close_tun (struct tuntap *tt)
{
+ /* TODO: we really should cleanup non-persistant tunX with
+ * "ifconfig tunX destroy" here...
+ */
if (tt)
{
close_tun_generic (tt);
@@ -1716,18 +2101,78 @@ close_tun (struct tuntap *tt)
}
}
+#ifdef NETBSD_MULTI_AF
+
+static inline int
+netbsd_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)
{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct openvpn_iphdr *iph;
+
+ iph = (struct openvpn_iphdr *) buf;
+
+ if (tt->ipv6 && OPENVPN_IPH_GET_VER(iph->version_len) == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = (char *)&type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return netbsd_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
return write (tt->fd, buf, len);
}
int
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 = (char *)&type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return netbsd_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
return read (tt->fd, buf, len);
}
+#else /* not NETBSD_MULTI_AF -> older code, IPv4 only */
+
+int
+write_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+ return read (tt->fd, buf, len);
+}
+#endif /* NETBSD_MULTI_AF */
+
#elif defined(TARGET_FREEBSD)
static inline int
@@ -1740,9 +2185,9 @@ freebsd_modify_read_write_return (int len)
}
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt);
+ open_tun_generic (dev, dev_type, dev_node, true, true, tt);
if (tt->fd >= 0 && tt->type == DEV_TYPE_TUN)
{
@@ -1828,9 +2273,9 @@ dragonfly_modify_read_write_return (int len)
}
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt);
+ open_tun_generic (dev, dev_type, dev_node, true, true, tt);
if (tt->fd >= 0)
{
@@ -1899,6 +2344,61 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
return read (tt->fd, buf, len);
}
+#elif defined(TARGET_DARWIN)
+
+/* Darwin (MacOS X) is mostly "just use the generic stuff", but there
+ * is always one caveat...:
+ *
+ * If IPv6 is configured, and the tun device is closed, the IPv6 address
+ * configured to the tun interface changes to a lingering /128 route
+ * pointing to lo0. Need to unconfigure... (observed on 10.5)
+ */
+
+void
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ open_tun_generic (dev, dev_type, dev_node, false, true, tt);
+}
+
+void
+close_tun (struct tuntap* tt)
+{
+ if (tt)
+ {
+ struct gc_arena gc = gc_new ();
+ struct argv argv;
+ argv_init (&argv);
+
+ if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
+ {
+ const char * ifconfig_ipv6_local =
+ print_in6_addr (tt->local_ipv6, 0, &gc);
+
+ argv_printf (&argv, "%s delete -inet6 %s",
+ ROUTE_PATH, ifconfig_ipv6_local );
+ argv_msg (M_INFO, &argv);
+ openvpn_execve_check (&argv, NULL, 0, "MacOS X 'remove inet6 route' failed (non-critical)");
+ }
+
+ close_tun_generic (tt);
+ free (tt);
+ argv_reset (&argv);
+ gc_free (&gc);
+ }
+}
+
+int
+write_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun (struct tuntap* tt, uint8_t *buf, int len)
+{
+ return read (tt->fd, buf, len);
+}
+
#elif defined(WIN32)
int
@@ -3884,7 +4384,7 @@ fork_register_dns_action (struct tuntap *tt)
}
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
struct gc_arena gc = gc_new ();
char device_path[256];
@@ -3895,7 +4395,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
/*netcmd_semaphore_lock ();*/
- ipv6_support (ipv6, false, tt);
+ msg( M_INFO, "open_tun, tt->ipv6=%d", tt->ipv6 );
if (tt->type == DEV_TYPE_NULL)
{
@@ -4017,6 +4517,16 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
msg (M_FATAL, "ERROR: This version of " PACKAGE_NAME " requires a TAP-Win32 driver that is at least version %d.%d -- If you recently upgraded your " PACKAGE_NAME " distribution, a reboot is probably required at this point to get Windows to see the new driver.",
TAP_WIN32_MIN_MAJOR,
TAP_WIN32_MIN_MINOR);
+
+ /* usage of numeric constants is ugly, but this is really tied to
+ * *this* version of the driver
+ */
+ if ( tt->ipv6 && tt->type == DEV_TYPE_TUN &&
+ info[0] == 9 && info[1] < 8)
+ {
+ msg( M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will be disabled. Upgrade to Tap-Win32 9.8 (2.2-beta3 release or later) or use TAP mode to get IPv6", (int) info[0], (int) info[1] );
+ tt->ipv6 = false;
+ }
}
/* get driver MTU */
@@ -4341,6 +4851,12 @@ close_tun (struct tuntap *tt)
if (tt)
{
+ if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
+ {
+ /* netsh interface ipv6 delete address \"%s\" %s */
+ const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
+ msg( M_WARN, "TODO: remove IPv6 address %s", ifconfig_ipv6_local );
+ }
#if 1
if (tt->ipapi_context_defined)
{
@@ -4444,9 +4960,9 @@ ipset2ascii_all (struct gc_arena *gc)
#else /* generic */
void
-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt);
+ open_tun_generic (dev, dev_type, dev_node, false, true, tt);
}
void
diff --git a/tun.h b/tun.h
index 011ab54..f28b8d8 100644
--- a/tun.h
+++ b/tun.h
@@ -130,6 +130,7 @@ struct tuntap
int topology; /* one of the TOP_x values */
bool did_ifconfig_setup;
+ bool did_ifconfig_ipv6_setup;
bool did_ifconfig;
bool ipv6;
@@ -146,6 +147,10 @@ struct tuntap
in_addr_t remote_netmask;
in_addr_t broadcast;
+ struct in6_addr local_ipv6;
+ struct in6_addr remote_ipv6;
+ int netbits_ipv6;
+
#ifdef WIN32
HANDLE hand;
struct overlapped_io reads;
@@ -197,7 +202,7 @@ tuntap_defined (const struct tuntap *tt)
void clear_tuntap (struct tuntap *tuntap);
void open_tun (const char *dev, const char *dev_type, const char *dev_node,
- bool ipv6, struct tuntap *tt);
+ struct tuntap *tt);
void close_tun (struct tuntap *tt);
@@ -206,7 +211,7 @@ int write_tun (struct tuntap* tt, uint8_t *buf, int len);
int read_tun (struct tuntap* tt, uint8_t *buf, int len);
void tuncfg (const char *dev, const char *dev_type, const char *dev_node,
- bool ipv6, int persist_mode, const char *username,
+ int persist_mode, const char *username,
const char *groupname, const struct tuntap_options *options);
const char *guess_tuntap_dev (const char *dev,
@@ -219,6 +224,8 @@ struct tuntap *init_tun (const char *dev, /* --dev option */
int topology, /* one of the TOP_x values */
const char *ifconfig_local_parm, /* --ifconfig parm 1 */
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
+ const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 / IPv6 */
+ const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 / IPv6 */
in_addr_t local_public,
in_addr_t remote_public,
const bool strict_warn,
diff --git a/version.m4 b/version.m4
index 77e4950..78e69aa 100644
--- a/version.m4
+++ b/version.m4
@@ -1,6 +1,6 @@
dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1.3w])
+define(PRODUCT_VERSION,[2.x-master])
dnl define the TAP version
define(PRODUCT_TAP_ID,[tap0901])
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])
-define(PRODUCT_TAP_WIN32_MIN_MINOR,[1])
+define(PRODUCT_TAP_WIN32_MIN_MINOR,[8])
diff --git a/win/autodefs.h.in b/win/autodefs.h.in
index 2edd9b6..ad0af19 100644
--- a/win/autodefs.h.in
+++ b/win/autodefs.h.in
@@ -1,31 +1,31 @@
-#ifndef AUTODEFS_H
-#define AUTODEFS_H
-
-/*
- * Minimum TAP-Win32 version number expected by userspace
- *
- * The TAP-Win32 version number is defined in tap-win32/SOURCES
- */
-#define TAP_ID "@PRODUCT_TAP_ID@"
-#define TAP_WIN32_MIN_MAJOR @PRODUCT_TAP_WIN32_MIN_MAJOR@
-#define TAP_WIN32_MIN_MINOR @PRODUCT_TAP_WIN32_MIN_MINOR@
-
-/* Friendly name for TAP driver */
-#define PRODUCT_TAP_DEVICE_DESCRIPTION "@PRODUCT_TAP_DEVICE_DESCRIPTION@"
-
-/* Version number of DDK/WDK used to build TAP driver */
-#define DDKVER_MAJOR @DDKVER_MAJOR@
-
-/* Name of package */
-#define PACKAGE "@PRODUCT_UNIX_NAME@"
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME "@PRODUCT_NAME@"
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "@PRODUCT_UNIX_NAME@"
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION "@PRODUCT_VERSION@"
-
-#endif
+#ifndef AUTODEFS_H
+#define AUTODEFS_H
+
+/*
+ * Minimum TAP-Win32 version number expected by userspace
+ *
+ * The TAP-Win32 version number is defined in tap-win32/SOURCES
+ */
+#define TAP_ID "@PRODUCT_TAP_ID@"
+#define TAP_WIN32_MIN_MAJOR @PRODUCT_TAP_WIN32_MIN_MAJOR@
+#define TAP_WIN32_MIN_MINOR @PRODUCT_TAP_WIN32_MIN_MINOR@
+
+/* Friendly name for TAP driver */
+#define PRODUCT_TAP_DEVICE_DESCRIPTION "@PRODUCT_TAP_DEVICE_DESCRIPTION@"
+
+/* Version number of DDK/WDK used to build TAP driver */
+#define DDKVER_MAJOR @DDKVER_MAJOR@
+
+/* Name of package */
+#define PACKAGE "@PRODUCT_UNIX_NAME@"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "@PRODUCT_NAME@"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "@PRODUCT_UNIX_NAME@"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "@PRODUCT_VERSION@"
+
+#endif
diff --git a/win/build.py b/win/build.py
index 3a9fbc7..69137f2 100644
--- a/win/build.py
+++ b/win/build.py
@@ -1,22 +1,23 @@
-import os, sys
-from wb import system, config, home_fn, cd_home
-
-os.environ['PATH'] += ";%s\\VC" % (os.path.normpath(config['MSVC']),)
-
-def build_vc(cmd):
- system('cmd /c "vcvarsall.bat x86 && %s"' % (cmd,))
-
-def main():
- cd_home()
- build_vc("nmake /f %s" % (home_fn('msvc.mak'),))
-
-def clean():
- cd_home()
- build_vc("nmake /f %s clean" % (home_fn('msvc.mak'),))
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- if len(sys.argv) == 2 and sys.argv[1] == 'clean':
- clean()
- else:
- main()
+import os, sys
+from wb import system, config, home_fn, cd_home, cd_service_win32, run_in_vs_shell
+
+def main():
+ """Build openvpn.exe and openvpnserv.exe"""
+ cd_home()
+ run_in_vs_shell("nmake /f %s" % (home_fn('msvc.mak'),))
+ cd_service_win32()
+ run_in_vs_shell("nmake /f %s" % ('msvc.mak'))
+
+def clean():
+ """Clean up after openvpn.exe and openvpnserv.exe build"""
+ cd_home()
+ run_in_vs_shell("nmake /f %s clean" % (home_fn('msvc.mak'),))
+ os.chdir("service-win32")
+ run_in_vs_shell("nmake /f %s clean" % ('msvc.mak'))
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ if len(sys.argv) == 2 and sys.argv[1] == 'clean':
+ clean()
+ else:
+ main()
diff --git a/win/build_all.py b/win/build_all.py
index 92d2bf4..47716a1 100644
--- a/win/build_all.py
+++ b/win/build_all.py
@@ -1,18 +1,69 @@
-from config_all import main as config_all
-from build import main as build_openvpn
-from build_ddk import main as build_ddk
-from sign import main as sign
-from make_dist import main as make_dist
-
-def main(config):
- config_all(config)
- build_openvpn()
- build_ddk(config, 'tap', 'all')
- build_ddk(config, 'tapinstall', 'all')
- sign(config, 'all')
- make_dist(config)
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- from wb import config
- main(config)
+import getopt, sys
+from config_all import main as config_all
+from build import main as build_openvpn
+from build_ddk import main as build_ddk
+from make_dist import main as make_dist
+
+def Usage():
+ '''Show usage information'''
+ print "Usage: build_all.py [OPTIONS]..."
+ print "Build OpenVPN using Visual Studio tools"
+ print
+ print " -h, --help Show this help"
+ print " -u, --unsigned Do not sign the TAP drivers"
+ print " -n, --notap Don't build the TAP driver"
+ sys.exit(1)
+
+def main(config):
+
+ # Do a signed build by default
+ signedBuild=True
+
+ # Build the TAP driver by default
+ tap=True
+
+ # Parse the command line argument(s)
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "hun", ["help", "unsigned", "notap"])
+ except getopt.GetoptError:
+ Usage()
+
+ for o, a in opts:
+ if o in ("-h","--help"):
+ Usage()
+ if o in ("-u", "--unsigned"):
+ signedBuild=False
+ if o in ("-n", "--notap"):
+ tap=False
+
+ # Check if the SignTool module is present. This avoids ImportErrors popping
+ # up annoyingly _after_ the build.
+ if signedBuild:
+ try:
+ from signtool import SignTool
+ except (ImportError):
+ print "ERROR: SignTool python module not found! Can't do a signed build."
+ sys.exit(1)
+ else:
+ print "Doing an unsigned build as requested"
+
+ # Start the build
+ config_all(config)
+ build_openvpn()
+
+ if tap:
+ build_ddk(config, 'tap', 'all')
+ build_ddk(config, 'tapinstall', 'all')
+ if signedBuild:
+ sign(config, 'all')
+ make_dist(config,tap=True)
+
+ else:
+ if 'TAP_PREBUILT' in config:
+ print "Using prebuilt TAP driver"
+ make_dist(config,tap=False)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/build_ddk.py b/win/build_ddk.py
index 1a0cf82..a197bf5 100644
--- a/win/build_ddk.py
+++ b/win/build_ddk.py
@@ -1,54 +1,55 @@
-import os
-from wb import system, home_fn, choose_arch
-
-def build_ddk(config, dir, x64):
- ddk_path = config['DDK_PATH']
- ddk_major = int(config['DDKVER_MAJOR'])
- debug = 'PRODUCT_TAP_DEBUG' in config
- return build_tap(ddk_path, ddk_major, debug, dir, x64)
-
-def build_tap(ddk_path, ddk_major, debug, dir, x64):
- setenv_bat = os.path.realpath(os.path.join(ddk_path, 'bin/setenv.bat'))
- target = 'chk' if debug else 'fre'
- if x64:
- target += ' x64'
- else:
- target += ' x86'
- if ddk_major >= 7600:
- if x64:
- target += ' wlh' # vista
- else:
- target += ' wnet' # server 2003
- else:
- if x64:
- target += ' wnet' # server 2003
- else:
- target += ' w2k' # 2000
-
- system('cmd /c "%s %s %s && cd %s && build -cef"' % (
- setenv_bat,
- os.path.realpath(ddk_path),
- target,
- dir
- ))
-
-def main(config, proj, arch):
- if proj == 'tap':
- dir = home_fn('tap-win32')
- elif proj == 'tapinstall':
- dir = home_fn('tapinstall')
- else:
- raise ValueError("unknown project: %s" % (proj,))
-
- for x64 in choose_arch(arch):
- build_ddk(config, dir, x64)
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- import sys
- from wb import config
- if len(sys.argv) >= 3:
- main(config, sys.argv[1], sys.argv[2])
- else:
- print "usage: build <tap|tapinstall> <x64|x86|all>"
- sys.exit(2)
+import os
+from wb import system, home_fn, choose_arch
+
+def build_ddk(config, dir, x64):
+ ddk_path = config['DDK_PATH']
+ ddk_major = int(config['DDKVER_MAJOR'])
+ debug = 'PRODUCT_TAP_DEBUG' in config
+ return build_tap(ddk_path, ddk_major, debug, dir, x64)
+
+def build_tap(ddk_path, ddk_major, debug, dir, x64):
+ """Build drivers using WinDDK tools"""
+ setenv_bat = os.path.realpath(os.path.join(ddk_path, 'bin/setenv.bat'))
+ target = 'chk' if debug else 'fre'
+ if x64:
+ target += ' x64'
+ else:
+ target += ' x86'
+ if ddk_major >= 7600:
+ if x64:
+ target += ' wlh' # vista
+ else:
+ target += ' wnet' # server 2003
+ else:
+ if x64:
+ target += ' wnet' # server 2003
+ else:
+ target += ' w2k' # 2000
+
+ system('cmd /c "%s %s %s && cd %s && build -cef"' % (
+ setenv_bat,
+ os.path.realpath(ddk_path),
+ target,
+ dir
+ ))
+
+def main(config, proj, arch):
+ if proj == 'tap':
+ dir = home_fn('tap-win32')
+ elif proj == 'tapinstall':
+ dir = home_fn('tapinstall')
+ else:
+ raise ValueError("unknown project: %s" % (proj,))
+
+ for x64 in choose_arch(arch):
+ build_ddk(config, dir, x64)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ import sys
+ from wb import config
+ if len(sys.argv) >= 3:
+ main(config, sys.argv[1], sys.argv[2])
+ else:
+ print "usage: build <tap|tapinstall> <x64|x86|all>"
+ sys.exit(2)
diff --git a/win/build_exe.py b/win/build_exe.py
index 087f9a3..dae4825 100644
--- a/win/build_exe.py
+++ b/win/build_exe.py
@@ -1,15 +1,15 @@
-from config import main as config_main
-from build import main as build_openvpn
-from build_ddk import main as build_ddk
-from sign import main as sign
-from make_dist import main as make_dist
-
-def main(config):
- config_main(config)
- build_openvpn()
- make_dist(config, tap=False)
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- from wb import config
- main(config)
+from config import main as config_main
+from build import main as build_openvpn
+from build_ddk import main as build_ddk
+from sign import main as sign
+from make_dist import main as make_dist
+
+def main(config):
+ config_main(config)
+ build_openvpn()
+ make_dist(config, tap=False)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/config-win32.h b/win/config.h.in
index be0b320..82344a0 100644
--- a/config-win32.h
+++ b/win/config.h.in
@@ -1,305 +1,323 @@
-/*
- * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program (see the file COPYING included with this
- * distribution); if not, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- * Configuration header for Win32 using the MSVC environment.
- */
-
-#include <windows.h>
-#include <winsock2.h>
-#include "autodefs.h" /* machine generated */
-
-//#define sleep(x) Sleep((x)*1000)
-
-//#define random rand
-//#define srandom srand
-
-typedef unsigned long in_addr_t;
-
-#ifndef _SSIZE_T_
-#define _SSIZE_T_
- typedef unsigned int ssize_t;
-#endif
-
-/* Append a label to program startup title */
-/*#define DEBUG_LABEL "DEBUG1"*/
-
-/* Should we print debug info from driver? */
-#ifdef PRODUCT_TAP_DEBUG
-#define TAP_WIN32_DEBUG
-#endif
-
-/* Enable client/server capability */
-#define ENABLE_CLIENT_SERVER 1
-
-/* Enable client capability only */
-#define ENABLE_CLIENT_ONLY
-
-/* Enable management server capability */
-#define ENABLE_MANAGEMENT 1
-
-/* Enable PKCS#11 support */
-/* #define USE_PKCS11 1 */
-
-/* Enable HTTP proxy support */
-#define ENABLE_HTTP_PROXY 1
-
-/* Enable Socks proxy support */
-#define ENABLE_SOCKS 1
-
-/* Enable internal fragmentation support */
-#define ENABLE_FRAGMENT 1
-
-/* Enable smaller executable size */
-/* #undef ENABLE_SMALL */
-
-/* Enable debugging support */
-#define ENABLE_DEBUG 1
-
-/* if defined, will allow usage of the --plugin directive */
-#define USE_LOAD_LIBRARY
-
-/* Dimension size to use for empty array declaration */
-#define EMPTY_ARRAY_SIZE 0
-
-/* Define to 1 if you have the `getsockname' function. */
-#define HAVE_GETSOCKNAME 1
-
-/* Define to 1 if you have the <openssl/engine.h> header file. */
-#define HAVE_OPENSSL_ENGINE_H 1
-
-/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
-#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
-
-/* Define to 1 if you have the `ENGINE_register_all_complete' function. */
-#define HAVE_ENGINE_REGISTER_ALL_COMPLETE 1
-
-/* Define to 1 if you have the `ENGINE_cleanup' function. */
-#define HAVE_ENGINE_CLEANUP 1
-
-/* gettimeofday() is implemented in otime.c for Windows */
-#define HAVE_GETTIMEOFDAY 1
-
-/* Define to 1 if you have the 'chsize' function. */
-#define HAVE_CHSIZE 1
-
-/* Define to 1 if you have the `chdir' function. */
-#define HAVE_CHDIR 1
-
-/* Define to 1 if your compiler supports GNU GCC-style variadic macros */
-#ifndef _MSC_VER /* Defines MSFT compiler version. Defined as 1200 for MSVC++ 6.0. */
-#define HAVE_CPP_VARARG_MACRO_GCC 1
-#endif
-
-/* Define to 1 if you have the <ctype.h> header file. */
-#define HAVE_CTYPE_H 1
-
-/* Define to 1 if you have the <errno.h> header file. */
-#define HAVE_ERRNO_H 1
-
-/* Define to 1 if you have the `EVP_CIPHER_CTX_set_key_length' function. */
-#define HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH 1
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define to 1 if you have the `getsockopt' function. */
-#define HAVE_GETSOCKOPT 1
-
-/* Define to 1 if you have the `inet_ntoa' function. */
-#define HAVE_INET_NTOA 1
-
-/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
- to 0 otherwise. */
-#define HAVE_MALLOC 1
-
-/* Define to 1 if you have the `memset' function. */
-#define HAVE_MEMSET 1
-
-/* Define to 1 if you have the `setsockopt' function. */
-#define HAVE_SETSOCKOPT 1
-
-/* Define to 1 if you have the `socket' function. */
-#define HAVE_SOCKET 1
-
-/* Define to 1 if you have the <stdarg.h> header file. */
-#define HAVE_STDARG_H 1
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#ifndef _MSC_VER
-#define HAVE_STDINT_H 1
-#endif
-
-/* Define to 1 if you have the <stdio.h> header file. */
-#define HAVE_STDIO_H 1
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the `strerror' function. */
-#define HAVE_STRERROR 1
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the `system' function. */
-#define HAVE_SYSTEM 1
-
-/* Define to 1 if you have the <sys/file.h> header file. */
-#ifndef _MSC_VER
-#define HAVE_SYS_FILE_H 1
-#endif
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#ifndef _MSC_VER
-#define HAVE_SYS_TIME_H 1
-#endif
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the `time' function. */
-#define HAVE_TIME 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#ifndef _MSC_VER
-#define HAVE_UNISTD_H 1
-#endif
-
-/* Define to 1 if you have the `vsnprintf' function. */
-#define HAVE_VSNPRINTF 1
-
-/* Special Windows version of getpass() defined in io.c */
-#define HAVE_GETPASS 1
-
-/* Define to the address where bug reports for this package should be sent. */
-//#define PACKAGE_BUGREPORT "openvpn-users@lists.sourceforge.net"
-
-/* Define to the full name and version of this package. */
-#ifdef DEBUG_LABEL
-#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION " " DEBUG_LABEL
-#else
-#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION
-#endif
-
-/* Define as the return type of signal handlers (`int' or `void'). */
-#define RETSIGTYPE void
-
-/* The size of a `unsigned int', as computed by sizeof. */
-#define SIZEOF_UNSIGNED_INT 4
-
-/* The size of a `unsigned long', as computed by sizeof. */
-#define SIZEOF_UNSIGNED_LONG 4
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* A string representing our target */
-#ifdef _MSC_VER
-#define TARGET_ALIAS "Win32-MSVC++"
-#else
-#define TARGET_ALIAS "Win32-MinGW"
-#endif
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#ifndef _MSC_VER
-#define TIME_WITH_SYS_TIME 1
-#endif
-
-/* Use OpenSSL crypto library */
-#define USE_CRYPTO 1
-
-/* Use LZO compression library */
-#define USE_LZO 1
-
-/* LZO version number */
-#define LZO_VERSION_NUM "2"
-
-/* Use lzo/ directory prefix for LZO header files (for LZO 2.0) */
-#define LZO_HEADER_DIR 1
-
-/* Use OpenSSL SSL library */
-#define USE_SSL 1
-
-/* Version number of package */
-#define VERSION PACKAGE_VERSION
-
-/* Define as `__inline' if that's what the C compiler calls it, or to nothing
- if it is not supported. */
-#define inline __inline
-
-/* type to use in place of socklen_t if not defined */
-#define socklen_t unsigned int
-
-/* 32-bit unsigned type */
-#define uint32_t unsigned int
-
-/* 16-bit unsigned type */
-#define uint16_t unsigned short
-
-/* 8-bit unsigned type */
-#define uint8_t unsigned char
-
-/* Route command */
-#define ROUTE_PATH "route"
-
-/* Windows doesn't support PTHREAD yet */
-#ifdef USE_PTHREAD
-#error The Windows version of OpenVPN does not support PTHREAD yet
-#endif
-
-#ifdef _MSC_VER
-/* MSVC++ hacks */
-#pragma warning(disable:4244) // conversion from 'foo' to 'bar', possible loss of data
-#pragma warning(disable:4018) // signed/unsigned mismatch
-#include <io.h>
-#include <direct.h>
-//#define vsnprintf _vsnprintf
-//#define vsnwprintf _vsnwprintf
-#define snwprintf _snwprintf
-#define write _write
-#define open _open
-#define read _read
-#define close _close
-#define lseek _lseek
-#define chdir _chdir
-#define strdup _strdup
-#define strcasecmp _stricmp
-#define chsize _chsize
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define TV_SEC_CAST (long)
-#define TV_USEC_CAST (long)
-typedef int intptr_t;
-/* Visual Studio 2005 supports vararg macros */
-#if _MSC_VER >= 1400
-#define HAVE_CPP_VARARG_MACRO_ISO 1
-#endif
-#endif
+/*
+ * 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-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Configuration header for Win32 using the MSVC environment.
+ */
+
+#ifndef OPENVPN_CONFIG_H
+#define OPENVPN_CONFIG_H
+
+#include <windows.h>
+#include <winsock2.h>
+#include "autodefs.h" /* machine generated */
+
+//#define sleep(x) Sleep((x)*1000)
+
+//#define random rand
+//#define srandom srand
+
+typedef unsigned long in_addr_t;
+
+#ifndef _SSIZE_T_
+#define _SSIZE_T_
+ typedef unsigned int ssize_t;
+#endif
+
+/* Append a label to program startup title */
+/*#define DEBUG_LABEL "DEBUG1"*/
+
+/* Should we print debug info from driver? */
+#ifdef PRODUCT_TAP_DEBUG
+#define TAP_WIN32_DEBUG
+#endif
+
+/* Enable reading credentials from a file */
+#if @ENABLE_PASSWORD_SAVE@ != 0
+#define ENABLE_PASSWORD_SAVE @ENABLE_PASSWORD_SAVE@
+#endif
+
+/* Enable client/server capability */
+#if @ENABLE_CLIENT_SERVER@ != 0
+#define ENABLE_CLIENT_SERVER @ENABLE_CLIENT_SERVER@
+#endif
+
+/* Enable client capability only */
+#if @ENABLE_CLIENT_ONLY@ != 0
+#define ENABLE_CLIENT_ONLY @ENABLE_CLIENT_ONLY@
+#endif
+
+/* Enable management server capability */
+#if @ENABLE_MANAGEMENT@ != 0
+#define ENABLE_MANAGEMENT @ENABLE_MANAGEMENT@
+#endif
+
+/* Enable PKCS#11 support */
+/* #define USE_PKCS11 1 */
+
+/* Enable HTTP proxy support */
+#if @ENABLE_HTTP_PROXY@ != 0
+#define ENABLE_HTTP_PROXY @ENABLE_HTTP_PROXY@
+#endif
+
+/* Enable Socks proxy support */
+#if @ENABLE_SOCKS@ != 0
+#define ENABLE_SOCKS @ENABLE_SOCKS@
+#endif
+
+/* Enable internal fragmentation support */
+#if @ENABLE_FRAGMENT@ != 0
+#define ENABLE_FRAGMENT @ENABLE_FRAGMENT@
+#endif
+
+/* Enable smaller executable size */
+/* #undef ENABLE_SMALL */
+
+/* Enable debugging support */
+#if @ENABLE_DEBUG@ != 0
+#define ENABLE_DEBUG @ENABLE_DEBUG@
+#endif
+
+/* if defined, will allow usage of the --plugin directive */
+#define USE_LOAD_LIBRARY
+
+/* Dimension size to use for empty array declaration */
+#define EMPTY_ARRAY_SIZE 0
+
+/* Define to 1 if you have the `getsockname' function. */
+#define HAVE_GETSOCKNAME 1
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+#define HAVE_OPENSSL_ENGINE_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
+
+/* Define to 1 if you have the `ENGINE_register_all_complete' function. */
+#define HAVE_ENGINE_REGISTER_ALL_COMPLETE 1
+
+/* Define to 1 if you have the `ENGINE_cleanup' function. */
+#define HAVE_ENGINE_CLEANUP 1
+
+/* gettimeofday() is implemented in otime.c for Windows */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the 'chsize' function. */
+#define HAVE_CHSIZE 1
+
+/* Define to 1 if you have the `chdir' function. */
+#define HAVE_CHDIR 1
+
+/* Define to 1 if your compiler supports GNU GCC-style variadic macros */
+#ifndef _MSC_VER /* Defines MSFT compiler version. Defined as 1200 for MSVC++ 6.0. */
+#define HAVE_CPP_VARARG_MACRO_GCC 1
+#endif
+
+/* Define to 1 if you have the <ctype.h> header file. */
+#define HAVE_CTYPE_H 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the `EVP_CIPHER_CTX_set_key_length' function. */
+#define HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getsockopt' function. */
+#define HAVE_GETSOCKOPT 1
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#define HAVE_INET_NTOA 1
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the `setsockopt' function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#ifndef _MSC_VER
+#define HAVE_STDINT_H 1
+#endif
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `system' function. */
+#define HAVE_SYSTEM 1
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#ifndef _MSC_VER
+#define HAVE_SYS_FILE_H 1
+#endif
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#ifndef _MSC_VER
+#define HAVE_SYS_TIME_H 1
+#endif
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `time' function. */
+#define HAVE_TIME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#ifndef _MSC_VER
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Special Windows version of getpass() defined in io.c */
+#define HAVE_GETPASS 1
+
+/* Define to the full name and version of this package. */
+#ifdef DEBUG_LABEL
+#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION " " DEBUG_LABEL
+#else
+#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION
+#endif
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The size of a `unsigned int', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_INT 4
+
+/* The size of a `unsigned long', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_LONG 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* A string representing our target */
+#ifdef _MSC_VER
+#define TARGET_ALIAS "Win32-MSVC++"
+#else
+#define TARGET_ALIAS "Win32-MinGW"
+#endif
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#ifndef _MSC_VER
+#define TIME_WITH_SYS_TIME 1
+#endif
+
+/* Use OpenSSL crypto library */
+#define USE_CRYPTO 1
+
+/* Use LZO compression library */
+#define USE_LZO 1
+
+/* LZO version number */
+#define LZO_VERSION_NUM "2"
+
+/* Use lzo/ directory prefix for LZO header files (for LZO 2.0) */
+#define LZO_HEADER_DIR 1
+
+/* Use OpenSSL SSL library */
+#define USE_SSL 1
+
+/* Version number of package */
+#define VERSION PACKAGE_VERSION
+
+/* Define as `__inline' if that's what the C compiler calls it, or to nothing
+ if it is not supported. */
+#define inline __inline
+
+/* type to use in place of socklen_t if not defined */
+#define socklen_t unsigned int
+
+#ifndef __MINGW32__
+/* 32-bit unsigned type */
+#define uint32_t unsigned int
+
+/* 16-bit unsigned type */
+#define uint16_t unsigned short
+
+/* 8-bit unsigned type */
+#define uint8_t unsigned char
+#endif /* __MINGW32__ */
+
+/* Route command */
+#define ROUTE_PATH "route"
+
+#ifdef _MSC_VER
+/* MSVC++ hacks */
+#pragma warning(disable:4244) // conversion from 'foo' to 'bar', possible loss of data
+#pragma warning(disable:4018) // signed/unsigned mismatch
+#include <io.h>
+#include <direct.h>
+//#define vsnprintf _vsnprintf
+//#define vsnwprintf _vsnwprintf
+#define snwprintf _snwprintf
+#define write _write
+#define open _open
+#define read _read
+#define close _close
+#define lseek _lseek
+#define chdir _chdir
+#define strdup _strdup
+#define strcasecmp _stricmp
+#define chsize _chsize
+#define S_IRUSR 0
+#define S_IWUSR 0
+#define TV_SEC_CAST (long)
+#define TV_USEC_CAST (long)
+typedef int intptr_t;
+/* Visual Studio 2005 supports vararg macros */
+#if _MSC_VER >= 1400
+#define HAVE_CPP_VARARG_MACRO_ISO 1
+#endif
+#endif
+
+#endif /* OPENVPN_CONFIG_H */
diff --git a/win/config.py b/win/config.py
index cf38cac..b820510 100644
--- a/win/config.py
+++ b/win/config.py
@@ -1,18 +1,21 @@
-from wb import preprocess, autogen, mod_fn, home_fn, build_autodefs, make_headers_objs, dict_def
-
-def main(config):
- build_autodefs(config, mod_fn('autodefs.h.in'), home_fn('autodefs.h'))
- ho = make_headers_objs(home_fn('Makefile.am'))
-
- preprocess(dict_def(config, [('HEADERS_OBJS', ho)]),
- in_fn=mod_fn('msvc.mak.in'),
- out_fn=home_fn('msvc.mak'),
- quote_begin='@',
- quote_end='@',
- if_prefix='!',
- head_comment='# %s\n\n' % autogen)
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- from wb import config
- main(config)
+from wb import preprocess, autogen, mod_fn, home_fn, build_config_h, build_configure_h, build_version_m4_vars, build_autodefs, make_headers_objs, dict_def
+
+def main(config):
+ build_config_h(config)
+ build_configure_h(config, mod_fn(home_fn('configure.h')), head_comment='/* %s */\n\n' % autogen)
+ build_version_m4_vars(mod_fn(mod_fn('version_m4_vars.tmp')), head_comment='/* %s */\n\n' % autogen)
+ build_autodefs(config, mod_fn('autodefs.h.in'), home_fn('autodefs.h'))
+ ho = make_headers_objs(home_fn('Makefile.am'))
+
+ preprocess(dict_def(config, [('HEADERS_OBJS', ho)]),
+ in_fn=mod_fn('msvc.mak.in'),
+ out_fn=home_fn('msvc.mak'),
+ quote_begin='@',
+ quote_end='@',
+ if_prefix='!',
+ head_comment='# %s\n\n' % autogen)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/config_all.py b/win/config_all.py
index 2686780..ba6affe 100644
--- a/win/config_all.py
+++ b/win/config_all.py
@@ -1,13 +1,13 @@
-from config import main as config_main
-from config_tap import main as config_tap
-from config_ti import main as config_ti
-
-def main(config):
- config_main(config)
- config_tap(config)
- config_ti(config)
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- from wb import config
- main(config)
+from config import main as config_main
+from config_tap import main as config_tap
+from config_ti import main as config_ti
+
+def main(config):
+ config_main(config)
+ config_tap(config)
+ config_ti(config)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/config_tap.py b/win/config_tap.py
index e69ee9b..a5b1d6c 100644
--- a/win/config_tap.py
+++ b/win/config_tap.py
@@ -1,35 +1,35 @@
-import os
-from wb import preprocess, home_fn, autogen, dict_def
-
-def main(config):
- preprocess(config,
- in_fn=home_fn('tap-win32/SOURCES.in'),
- out_fn=home_fn('tap-win32/SOURCES'),
- quote_begin='@@',
- quote_end='@@',
- head_comment='# %s\n\n' % autogen)
-
- preprocess(config,
- in_fn=home_fn('tap-win32/i386/OemWin2k.inf.in'),
- out_fn=home_fn('tap-win32/i386/OemWin2k.inf'),
- quote_begin='@@',
- quote_end='@@',
- if_prefix='!',
- head_comment='; %s\n\n' % autogen)
-
- try:
- os.mkdir(home_fn('tap-win32/amd64'))
- except:
- pass
- preprocess(dict_def(config, [('AMD64', '1')]),
- in_fn=home_fn('tap-win32/i386/OemWin2k.inf.in'),
- out_fn=home_fn('tap-win32/amd64/OemWin2k.inf'),
- quote_begin='@@',
- quote_end='@@',
- if_prefix='!',
- head_comment='; %s\n\n' % autogen)
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- from wb import config
- main(config)
+import os
+from wb import preprocess, home_fn, autogen, dict_def
+
+def main(config):
+ preprocess(config,
+ in_fn=home_fn('tap-win32/SOURCES.in'),
+ out_fn=home_fn('tap-win32/SOURCES'),
+ quote_begin='@@',
+ quote_end='@@',
+ head_comment='# %s\n\n' % autogen)
+
+ preprocess(config,
+ in_fn=home_fn('tap-win32/i386/OemWin2k.inf.in'),
+ out_fn=home_fn('tap-win32/i386/OemWin2k.inf'),
+ quote_begin='@@',
+ quote_end='@@',
+ if_prefix='!',
+ head_comment='; %s\n\n' % autogen)
+
+ try:
+ os.mkdir(home_fn('tap-win32/amd64'))
+ except:
+ pass
+ preprocess(dict_def(config, [('AMD64', '1')]),
+ in_fn=home_fn('tap-win32/i386/OemWin2k.inf.in'),
+ out_fn=home_fn('tap-win32/amd64/OemWin2k.inf'),
+ quote_begin='@@',
+ quote_end='@@',
+ if_prefix='!',
+ head_comment='; %s\n\n' % autogen)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/config_ti.py b/win/config_ti.py
index 4facaff..8742caa 100644
--- a/win/config_ti.py
+++ b/win/config_ti.py
@@ -1,18 +1,18 @@
-import os, shutil
-from wb import preprocess, home_fn, autogen
-
-def main(config):
- src = os.path.join(home_fn(config['TISRC']), config['DDKVER_MAJOR'])
- dest = home_fn('tapinstall')
- shutil.rmtree(dest, ignore_errors=True)
- shutil.copytree(src, dest)
- preprocess(config,
- in_fn=os.path.join(dest, 'sources.in'),
- out_fn=os.path.join(dest, 'sources'),
- if_prefix='!',
- head_comment='# %s\n\n' % autogen)
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- from wb import config
- main(config)
+import os, shutil
+from wb import preprocess, home_fn, autogen
+
+def main(config):
+ src = os.path.join(home_fn(config['TISRC']), config['DDKVER_MAJOR'])
+ dest = home_fn('tapinstall')
+ shutil.rmtree(dest, ignore_errors=True)
+ shutil.copytree(src, dest)
+ preprocess(config,
+ in_fn=os.path.join(src, 'sources'),
+ out_fn=os.path.join(dest, 'sources'),
+ if_prefix='!',
+ head_comment='# %s\n\n' % autogen)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/js.py b/win/js.py
index c515824..d1d4db3 100644
--- a/win/js.py
+++ b/win/js.py
@@ -1,10 +1,10 @@
-import json
-
-# usage:
-# print JSON().encode(kv)
-
-class JSON(json.JSONEncoder):
- def __init__(self, **kwargs):
- args = dict(sort_keys=True, indent=2)
- args.update(kwargs)
- json.JSONEncoder.__init__(self, **args)
+import json
+
+# usage:
+# print JSON().encode(kv)
+
+class JSON(json.JSONEncoder):
+ def __init__(self, **kwargs):
+ args = dict(sort_keys=True, indent=2)
+ args.update(kwargs)
+ json.JSONEncoder.__init__(self, **args)
diff --git a/win/make_dist.py b/win/make_dist.py
index a6a0563..edb0e6a 100644
--- a/win/make_dist.py
+++ b/win/make_dist.py
@@ -1,56 +1,107 @@
-import os
-from wb import home_fn, rm_rf, mkdir, cp_a, cp
-
-def main(config, tap=True):
- dist = config['DIST']
- assert dist
- dist = home_fn(dist)
- bin = os.path.join(dist, 'bin')
- i386 = os.path.join(dist, 'i386')
- amd64 = os.path.join(dist, 'amd64')
-
- # build dist and subdirectories
- rm_rf(dist)
- mkdir(dist)
- mkdir(bin)
- if tap:
- mkdir(i386)
- mkdir(amd64)
-
- # copy openvpn.exe and manifest
- cp(home_fn('openvpn.exe'), bin)
- cp(home_fn('openvpn.exe.manifest'), bin)
-
- # copy DLL dependencies
- cp(home_fn(config['LZO_DIR']+'/bin/lzo2.dll'), bin)
- cp(home_fn(config['OPENSSL_DIR']+'/bin/libeay32.dll'), bin)
- cp(home_fn(config['OPENSSL_DIR']+'/bin/ssleay32.dll'), bin)
-
- # copy MSVC CRT
- cp_a(home_fn(config['MSVC_CRT']), bin)
-
- if tap:
- # copy TAP drivers
- for dir_name, dest in (('amd64', amd64), ('i386', i386)):
- dir = home_fn(os.path.join('tap-win32', dir_name))
- for dirpath, dirnames, filenames in os.walk(dir):
- for f in filenames:
- root, ext = os.path.splitext(f)
- if ext in ('.inf', '.cat', '.sys'):
- cp(os.path.join(dir, f), dest)
- break
-
- # copy tapinstall
- dest = {'amd64' : amd64, 'i386' : i386}
- for dirpath, dirnames, filenames in os.walk(home_fn('tapinstall')):
- for f in filenames:
- if f == 'tapinstall.exe':
- dir_name = os.path.basename(dirpath)
- src = os.path.join(dirpath, f)
- if dir_name in dest:
- cp(src, dest[dir_name])
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- from wb import config
- main(config)
+import os
+from wb import home_fn, rm_rf, mkdir, cp_a, cp, rename, run_in_vs_shell
+
+def main(config, tap=True):
+ dist = config['DIST']
+ assert dist
+ dist = home_fn(dist)
+ bin = os.path.join(dist, 'bin')
+ i386 = os.path.join(dist, 'i386')
+ amd64 = os.path.join(dist, 'amd64')
+ samples = os.path.join(dist, 'samples')
+
+ # build dist and subdirectories
+ rm_rf(dist)
+ mkdir(dist)
+ mkdir(bin)
+ mkdir(i386)
+ mkdir(amd64)
+ mkdir(samples)
+
+ # copy openvpn.exe, openvpnserv.exe and their manifests
+ cp(home_fn('openvpn.exe'), bin)
+ cp(home_fn('openvpn.exe.manifest'), bin)
+ cp(home_fn('service-win32/openvpnserv.exe'), bin)
+ cp(home_fn('service-win32/openvpnserv.exe.manifest'), bin)
+
+ # copy openvpn-gui
+ cp(home_fn(config['OPENVPN_GUI_DIR']+"/"+config['OPENVPN_GUI']), bin)
+
+ # copy DLL dependencies
+ cp(home_fn(config['LZO_DIR']+'/bin/lzo2.dll'), bin)
+ cp(home_fn(config['LZO_DIR']+'/bin/lzo2.dll.manifest'), bin)
+ cp(home_fn(config['OPENSSL_DIR']+'/bin/libeay32.dll'), bin)
+ cp(home_fn(config['OPENSSL_DIR']+'/bin/ssleay32.dll'), bin)
+ cp(home_fn(config['PKCS11_HELPER_DIR']+'/lib/libpkcs11-helper-1.dll'), bin)
+ cp(home_fn(config['PKCS11_HELPER_DIR']+'/lib/libpkcs11-helper-1.dll.manifest'), bin)
+
+ # copy OpenSSL utilities (=openvpn.exe)
+ cp(home_fn(config['OPENSSL_DIR']+'/bin/openssl.exe'), bin)
+
+ # copy sample config files; renaming is necessary due to openvpn.nsi script
+ cp(home_fn('install-win32/sample.ovpn'), samples)
+ cp(home_fn('sample-config-files/client.conf'), samples)
+ cp(home_fn('sample-config-files/server.conf'), samples)
+ rename(os.path.join(samples,'client.conf'), os.path.join(samples, 'client.ovpn'))
+ rename(os.path.join(samples,'server.conf'), os.path.join(samples, 'server.ovpn'))
+
+ # embed manifests to executables and DLLs
+ for f in [ "openvpn.exe", "openvpnserv.exe", "lzo2.dll", "libpkcs11-helper-1.dll" ]:
+
+ outputresource = os.path.join(bin,f)
+ manifest = outputresource+".manifest"
+
+ # EXEs and DLLs require slightly different treatment
+ if f.endswith(".exe"):
+ type = "1"
+ elif f.endswith(".dll"):
+ type = "2"
+ else:
+ print "ERROR: Could not embed manifest to "+outputresouce+", bailing out."
+ sys.exit(1)
+
+ # Embed the manifest
+ run_in_vs_shell('mt.exe -manifest %s -outputresource:%s;%s' % (manifest, outputresource, type))
+
+ # copy MSVC CRT
+ cp_a(home_fn(config['MSVC_CRT']), bin)
+
+ # TAP-driver and tapinstall.exe were built, so copy those over
+ if tap:
+ drv_dir = 'tap-win32'
+ ti_dir = 'tapinstall'
+
+ # we're using prebuilt TAP-driver and tapinstall.exe
+ elif 'TAP_PREBUILT' in config:
+ drv_dir = config['TAP_PREBUILT']
+ ti_dir = config['TAP_PREBUILT']
+
+ else:
+ print "ERROR: Could not find prebuilt TAP-drivers or tapinstall.exe. Please check win/settings.in"
+ sys.exit(1)
+
+ # copy TAP drivers
+ for dir_name, dest in (('amd64', amd64), ('i386', i386)):
+ dir = home_fn(os.path.join(drv_dir, dir_name))
+ for dirpath, dirnames, filenames in os.walk(dir):
+ for f in filenames:
+ root, ext = os.path.splitext(f)
+ if ext in ('.inf', '.cat', '.sys'):
+ cp(os.path.join(dir, f), dest)
+ break
+
+ # Copy tapinstall.exe (usually known as devcon.exe)
+ dest = {'amd64' : amd64, 'i386' : i386}
+ for dirpath, dirnames, filenames in os.walk(home_fn(ti_dir)):
+ for f in filenames:
+ if f in ( 'devcon.exe', 'tapinstall.exe' ):
+ dir_name = os.path.basename(dirpath)
+ src = os.path.join(dirpath, f)
+ dst = os.path.join(dest[dir_name],'tapinstall.exe')
+ if dir_name in dest:
+ cp(src, dst, dest_is_dir=False)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/msvc.mak.in b/win/msvc.mak.in
index 5d94a6e..ac17ae9 100644
--- a/win/msvc.mak.in
+++ b/win/msvc.mak.in
@@ -1,57 +1,57 @@
-# This makefile builds the user-mode component
-# of OpenVPN for Windows in the Visual Studio 2008 environment.
-
-# To build:
-# python win\config.py
-# nmake /f msvc.mak
-
-# Each of the OPENSSL and LZO dirs should have 'lib' and 'include'
-# directories under them.
-
-OPENSSL = @OPENSSL_DIR@
-OPENSSL_DYNAMIC = libeay32.lib ssleay32.lib
-
-LZO = @LZO_DIR@
-LZO_DYNAMIC = lzo2.lib
-
-INCLUDE_DIRS = -I$(OPENSSL)/include -I$(LZO)/include
-
-LIBS = $(OPENSSL_DYNAMIC) $(LZO_DYNAMIC) ws2_32.lib crypt32.lib iphlpapi.lib winmm.lib user32.lib gdi32.lib advapi32.lib wininet.lib
-
-LIB_DIRS = -LIBPATH:$(OPENSSL)\lib -LIBPATH:$(LZO)\lib
-
-EXE = openvpn.exe
-
-CPP=cl.exe
-CPP_ARG_COMMON=/nologo /W3 -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS -D_CRT_SECURE_NO_DEPRECATE $(INCLUDE_DIRS) /FD /c
-
-LINK32=link.exe
-
-!ifdef PRODUCT_OPENVPN_DEBUG
-# debug:
-CPP_PROJ=$(CPP_ARG_COMMON) /MD /Z7
-LINK32_FLAGS=/nologo /subsystem:console /incremental:no /opt:ref /opt:icf /debug /out:"$(EXE)"
-# old debug:
-#CPP_PROJ=$(CPP_ARG_COMMON) /MDd /Zi /Od -D_DEBUG
-#LINK32_FLAGS=/nologo /subsystem:console /incremental:no /debug /out:"$(EXE)"
-!else
-# release:
-CPP_PROJ=$(CPP_ARG_COMMON) /O2 /MD -DNDEBUG
-LINK32_FLAGS=/nologo /subsystem:console /incremental:no /out:"$(EXE)"
-!endif
-
-# HEADERS and OBJS definitions, automatically generated
-@HEADERS_OBJS@
-
-openvpn : $(OBJS)
- $(LINK32) @<<
- $(LINK32_FLAGS) $(LIB_DIRS) $(LIBS) $(OBJS)
-<<
-
-clean :
- del /Q $(OBJS) $(EXE) *.idb *.pdb
-
-.c.obj::
- $(CPP) @<<
- $(CPP_PROJ) $<
-<<
+# This makefile builds the user-mode component of OpenVPN for Windows in the
+# Visual Studio 2008 environment. Note that this file is basis for the real
+# makefile (..\msvc.mak) but unusable as is. The real makefile is automatically
+# generated during the build process by the Python build scripts.
+#
+# A few details are in order:
+#
+# - Everything between @<< and << is inserted into a s.c. "in-line file". This
+# file drives the linker (link.exe).
+# - HEADERS_OBJS is expanded to all all header and source files listed in
+# ..\Makefile.am
+# - OPENSSL_DIR and LZO_DIR are dynamically created from settings.in
+
+OPENSSL = @OPENSSL_DIR@
+OPENSSL_DYNAMIC = libeay32.lib ssleay32.lib
+
+LZO = @LZO_DIR@
+LZO_DYNAMIC = lzo2.lib
+
+INCLUDE_DIRS = -I$(OPENSSL)/include -I$(LZO)/include
+
+LIBS = $(OPENSSL_DYNAMIC) $(LZO_DYNAMIC) ws2_32.lib crypt32.lib iphlpapi.lib winmm.lib user32.lib gdi32.lib advapi32.lib wininet.lib
+
+LIB_DIRS = -LIBPATH:$(OPENSSL)\lib -LIBPATH:$(LZO)\lib
+
+EXE = openvpn.exe
+
+CPP=cl.exe
+CPP_ARG_COMMON=/nologo /W3 -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS -D_CRT_SECURE_NO_DEPRECATE $(INCLUDE_DIRS) /FD /c
+
+LINK32=link.exe
+
+!ifdef PRODUCT_OPENVPN_DEBUG
+# debug:
+CPP_PROJ=$(CPP_ARG_COMMON) /MD /Z7
+LINK32_FLAGS=/nologo /subsystem:console /incremental:no /opt:ref /opt:icf /debug
+!else
+# release:
+CPP_PROJ=$(CPP_ARG_COMMON) /O2 /MD -DNDEBUG
+LINK32_FLAGS=/nologo /subsystem:console /incremental:no
+!endif
+
+# HEADERS and OBJS definitions, automatically generated from ../Makefile.am
+@HEADERS_OBJS@
+
+openvpn : $(OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) "/out:$(EXE)" $(LIB_DIRS) $(LIBS) $(OBJS)
+<<
+
+clean :
+ del /Q $(OBJS) $(EXE) *.idb *.pdb
+
+.c.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
diff --git a/win/openvpn.nsi b/win/openvpn.nsi
new file mode 100755
index 0000000..d3f80d0
--- /dev/null
+++ b/win/openvpn.nsi
@@ -0,0 +1,821 @@
+; ****************************************************************************
+; * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. *
+; * This program is free software; you can redistribute it and/or modify *
+; * it under the terms of the GNU General Public License version 2 *
+; * as published by the Free Software Foundation. *
+; ****************************************************************************
+
+; OpenVPN install script for Windows, using NSIS
+
+; Start menu entries don't get uninstalled properly on Windows Vista/7 unless we
+; explicitly state that the installer requires admin privileges. This is
+; caused by backwards compatibility tricks used on those platforms. For details,
+; see http://nsis.sourceforge.net/Shortcuts_removal_fails_on_Windows_Vista
+RequestExecutionLevel admin
+
+SetCompressor lzma
+
+!include "MUI.nsh"
+
+# Include basic build settings
+!include "settings.in"
+
+# Include variables generated dynamically from version.m4 by wb.py
+!include "version_m4_vars.tmp"
+
+;!include "guidefs.nsi"
+!include "setpath.nsi"
+
+!ifdef EXTRACT_FILES
+!include "MultiFileExtract.nsi"
+!endif
+
+!define GEN "..\dist"
+!define BIN "${GEN}\bin"
+!define EASYRSA "..\easy-rsa"
+
+!define PRODUCT_ICON "icon.ico"
+
+!ifdef PRODUCT_TAP_DEBUG
+!define DBG_POSTFIX "-DBG"
+!else
+!define DBG_POSTFIX ""
+!endif
+
+!define VERSION "${PRODUCT_VERSION}${DBG_POSTFIX}"
+
+!define TAP "${PRODUCT_TAP_ID}"
+!define TAPDRV "${TAP}.sys"
+
+; Default service settings
+!define SERV_CONFIG_DIR "$INSTDIR\config"
+!define SERV_CONFIG_EXT "${PRODUCT_FILE_EXT}"
+!define SERV_EXE_PATH "$INSTDIR\bin\${PRODUCT_UNIX_NAME}.exe"
+!define SERV_LOG_DIR "$INSTDIR\log"
+!define SERV_PRIORITY "NORMAL_PRIORITY_CLASS"
+!define SERV_LOG_APPEND "0"
+
+;--------------------------------
+;Configuration
+
+ ;General
+
+ OutFile "${GEN}\${PRODUCT_UNIX_NAME}-${VERSION}${OUTFILE_LABEL}-install.exe"
+
+ ShowInstDetails show
+ ShowUninstDetails show
+
+ ;Folder selection page
+ InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
+
+ ;Remember install folder
+ InstallDirRegKey HKCU "Software\${PRODUCT_NAME}" ""
+
+;--------------------------------
+;Modern UI Configuration
+
+ Name "${PRODUCT_NAME} ${VERSION} ${TITLE_LABEL}"
+
+ !define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of ${PRODUCT_NAME}, an Open Source VPN package by James Yonan.\r\n\r\nNote that the Windows version of ${PRODUCT_NAME} only runs on XP, or higher.\r\n\r\n\r\n"
+
+ !define MUI_COMPONENTSPAGE_TEXT_TOP "Select the components to install/upgrade. Stop any ${PRODUCT_NAME} processes or the ${PRODUCT_NAME} service if it is running. All DLLs are installed locally."
+
+ !define MUI_COMPONENTSPAGE_SMALLDESC
+ !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\INSTALL-win32.txt"
+ !define MUI_FINISHPAGE_NOAUTOCLOSE
+ !define MUI_ABORTWARNING
+ !define MUI_ICON "..\images\${PRODUCT_ICON}"
+ !define MUI_UNICON "..\images\${PRODUCT_ICON}"
+ !define MUI_HEADERIMAGE
+ !define MUI_HEADERIMAGE_BITMAP "..\images\install-whirl.bmp"
+ !define MUI_UNFINISHPAGE_NOAUTOCLOSE
+
+ !insertmacro MUI_PAGE_WELCOME
+ !insertmacro MUI_PAGE_LICENSE "..\COPYRIGHT.GPL"
+ !insertmacro MUI_PAGE_COMPONENTS
+ !insertmacro MUI_PAGE_DIRECTORY
+ !insertmacro MUI_PAGE_INSTFILES
+ !insertmacro MUI_PAGE_FINISH
+
+ !insertmacro MUI_UNPAGE_CONFIRM
+ !insertmacro MUI_UNPAGE_INSTFILES
+ !insertmacro MUI_UNPAGE_FINISH
+
+
+;--------------------------------
+;Languages
+
+ !insertmacro MUI_LANGUAGE "English"
+
+;--------------------------------
+;Language Strings
+
+ LangString DESC_SecOpenVPNUserSpace ${LANG_ENGLISH} "Install ${PRODUCT_NAME} user-space components, including ${PRODUCT_UNIX_NAME}.exe."
+
+!ifdef USE_GUI
+ LangString DESC_SecOpenVPNGUI ${LANG_ENGLISH} "Install ${PRODUCT_NAME} GUI by Mathias Sundman"
+!endif
+
+ LangString DESC_SecOpenVPNEasyRSA ${LANG_ENGLISH} "Install ${PRODUCT_NAME} RSA scripts for X509 certificate management."
+
+ LangString DESC_SecOpenSSLDLLs ${LANG_ENGLISH} "Install OpenSSL DLLs locally (may be omitted if DLLs are already installed globally)."
+
+ LangString DESC_SecPKCS11DLLs ${LANG_ENGLISH} "Install PKCS#11 helper DLLs locally (may be omitted if DLLs are already installed globally)."
+
+ LangString DESC_SecLZO2DLLs ${LANG_ENGLISH} "Install LZO2 DLLs locally (may be omitted if DLLs are already installed globally)."
+
+ LangString DESC_SecMSVCR90DLL ${LANG_ENGLISH} "Install Microsoft Visual C 9.0 Runtime (may be omitted if it is already installed globally)."
+
+ LangString DESC_SecTAP ${LANG_ENGLISH} "Install/Upgrade the TAP virtual device driver. Will not interfere with CIPE."
+
+ LangString DESC_SecService ${LANG_ENGLISH} "Install the ${PRODUCT_NAME} service wrapper (${PRODUCT_UNIX_NAME}serv.exe)"
+
+ LangString DESC_SecOpenSSLUtilities ${LANG_ENGLISH} "Install the OpenSSL Utilities (used for generating public/private key pairs)."
+
+ LangString DESC_SecAddPath ${LANG_ENGLISH} "Add ${PRODUCT_NAME} executable directory to the current user's PATH."
+
+ LangString DESC_SecAddShortcuts ${LANG_ENGLISH} "Add ${PRODUCT_NAME} shortcuts to the current user's Start Menu."
+
+ LangString DESC_SecFileAssociation ${LANG_ENGLISH} "Register ${PRODUCT_NAME} config file association (*.${SERV_CONFIG_EXT})"
+
+;--------------------------------
+;Reserve Files
+
+ ;Things that need to be extracted on first (keep these lines before any File command!)
+ ;Only useful for BZIP2 compression
+
+ ReserveFile "..\images\install-whirl.bmp"
+
+;--------------------------------
+;Macros
+
+!macro WriteRegStringIfUndef ROOT SUBKEY KEY VALUE
+Push $R0
+ReadRegStr $R0 "${ROOT}" "${SUBKEY}" "${KEY}"
+StrCmp $R0 "" +1 +2
+WriteRegStr "${ROOT}" "${SUBKEY}" "${KEY}" '${VALUE}'
+Pop $R0
+!macroend
+
+!macro DelRegStringIfUnchanged ROOT SUBKEY KEY VALUE
+Push $R0
+ReadRegStr $R0 "${ROOT}" "${SUBKEY}" "${KEY}"
+StrCmp $R0 '${VALUE}' +1 +2
+DeleteRegValue "${ROOT}" "${SUBKEY}" "${KEY}"
+Pop $R0
+!macroend
+
+!macro DelRegKeyIfUnchanged ROOT SUBKEY VALUE
+Push $R0
+ReadRegStr $R0 "${ROOT}" "${SUBKEY}" ""
+StrCmp $R0 '${VALUE}' +1 +2
+DeleteRegKey "${ROOT}" "${SUBKEY}"
+Pop $R0
+!macroend
+
+!macro DelRegKeyIfEmpty ROOT SUBKEY
+Push $R0
+EnumRegValue $R0 "${ROOT}" "${SUBKEY}" 1
+StrCmp $R0 "" +1 +2
+DeleteRegKey /ifempty "${ROOT}" "${SUBKEY}"
+Pop $R0
+!macroend
+
+;------------------------------------------
+;Set reboot flag based on tapinstall return
+
+Function CheckReboot
+ IntCmp $R0 1 "" noreboot noreboot
+ IntOp $R0 0 & 0
+ SetRebootFlag true
+ DetailPrint "REBOOT flag set"
+ noreboot:
+FunctionEnd
+
+;--------------------------------
+;Installer Sections
+
+Function .onInit
+ ClearErrors
+
+# Verify that user has admin privs
+ UserInfo::GetName
+ IfErrors ok
+ Pop $R0
+ UserInfo::GetAccountType
+ Pop $R1
+ StrCmp $R1 "Admin" ok
+ Messagebox MB_OK "Administrator privileges required to install ${PRODUCT_NAME} [$R0/$R1]"
+ Abort
+ ok:
+
+# Delete previous start menu
+ RMDir /r $SMPROGRAMS\${PRODUCT_NAME}
+
+# FIXME: reimplement Windows version checking code that was located here, but
+# disabled intentionally to avoid Windows 7 issues. This should do it:
+#
+# http://nsis.sourceforge.net/Get_Windows_version
+#
+# Blacklisting should be safer than whitelisting used originally.
+
+FunctionEnd
+
+!ifndef SF_SELECTED
+!define SF_SELECTED 1
+!endif
+
+;--------------------
+;Pre-install section
+
+Section -pre
+
+ ; Stop OpenVPN if currently running
+ DetailPrint "Previous Service REMOVE (if exists)"
+ nsExec::ExecToLog '"$INSTDIR\bin\${PRODUCT_UNIX_NAME}serv.exe" -remove'
+ Pop $R0 # return value/error/timeout
+
+ Sleep 3000
+
+ # Fix for Trac ticket 120. Remove after 2.3 has been released.
+ !ifdef USE_GUI
+ SetShellVarContext current
+ Delete "$DESKTOP\${PRODUCT_NAME} GUI.lnk"
+ !endif
+
+SectionEnd
+
+Section "${PRODUCT_NAME} User-Space Components" SecOpenVPNUserSpace
+
+ SetOverwrite on
+ SetOutPath "$INSTDIR\bin"
+
+ File "${BIN}\${PRODUCT_UNIX_NAME}.exe"
+
+SectionEnd
+
+!ifdef USE_GUI
+Section "${PRODUCT_NAME} GUI" SecOpenVPNGUI
+
+ SetOverwrite on
+ SetOutPath "$INSTDIR\bin"
+
+ File "${BIN}\${OPENVPN_GUI}"
+
+SectionEnd
+!endif
+
+Section "${PRODUCT_NAME} RSA Certificate Management Scripts" SecOpenVPNEasyRSA
+
+ SetOverwrite on
+ SetOutPath "$INSTDIR\easy-rsa"
+
+ # FIXME: the easy-rsa directory would need cleaning up
+
+ # Original nsi script looked for openssl.cnf.sample
+ File "${EASYRSA}\2.0\openssl.cnf"
+
+ File "${EASYRSA}\Windows\vars.bat.sample"
+
+ File "${EASYRSA}\Windows\init-config.bat"
+
+ File "${EASYRSA}\Windows\README.txt"
+ File "${EASYRSA}\Windows\build-ca.bat"
+ File "${EASYRSA}\Windows\build-dh.bat"
+ File "${EASYRSA}\Windows\build-key-server.bat"
+ File "${EASYRSA}\Windows\build-key.bat"
+ File "${EASYRSA}\Windows\build-key-pkcs12.bat"
+ File "${EASYRSA}\Windows\clean-all.bat"
+ File "${EASYRSA}\Windows\index.txt.start"
+ File "${EASYRSA}\Windows\revoke-full.bat"
+ File "${EASYRSA}\Windows\serial.start"
+
+SectionEnd
+
+Section "${PRODUCT_NAME} Service" SecService
+
+ SetOverwrite on
+
+ SetOutPath "$INSTDIR\bin"
+ File "${BIN}\${PRODUCT_UNIX_NAME}serv.exe"
+
+ SetOutPath "$INSTDIR\config"
+
+ FileOpen $R0 "$INSTDIR\config\README.txt" w
+ FileWrite $R0 "This directory should contain ${PRODUCT_NAME} configuration files$\r$\n"
+ FileWrite $R0 "each having an extension of .${SERV_CONFIG_EXT}$\r$\n"
+ FileWrite $R0 "$\r$\n"
+ FileWrite $R0 "When ${PRODUCT_NAME} is started as a service, a separate ${PRODUCT_NAME}$\r$\n"
+ FileWrite $R0 "process will be instantiated for each configuration file.$\r$\n"
+ FileClose $R0
+
+ SetOutPath "$INSTDIR\sample-config"
+ File "${GEN}\samples\sample.${SERV_CONFIG_EXT}"
+ File "${GEN}\samples\client.${SERV_CONFIG_EXT}"
+ File "${GEN}\samples\server.${SERV_CONFIG_EXT}"
+
+ CreateDirectory "$INSTDIR\log"
+ FileOpen $R0 "$INSTDIR\log\README.txt" w
+ FileWrite $R0 "This directory will contain the log files for ${PRODUCT_NAME}$\r$\n"
+ FileWrite $R0 "sessions which are being run as a service.$\r$\n"
+ FileClose $R0
+
+SectionEnd
+
+Section "${PRODUCT_NAME} File Associations" SecFileAssociation
+SectionEnd
+
+Section "OpenSSL DLLs" SecOpenSSLDLLs
+
+ SetOverwrite on
+ SetOutPath "$INSTDIR\bin"
+ File "${BIN}\libeay32.dll"
+ File "${BIN}\ssleay32.dll"
+
+SectionEnd
+
+Section "OpenSSL Utilities" SecOpenSSLUtilities
+
+ SetOverwrite on
+ SetOutPath "$INSTDIR\bin"
+ File "${BIN}\openssl.exe"
+
+SectionEnd
+
+Section "PKCS#11 DLLs" SecPKCS11DLLs
+
+ SetOverwrite on
+ SetOutPath "$INSTDIR\bin"
+ File "${BIN}\libpkcs11-helper-1.dll"
+
+SectionEnd
+
+Section "LZO2 DLLs" SecLZO2DLLs
+
+ SetOverwrite on
+ SetOutPath "$INSTDIR\bin"
+ File "${BIN}\lzo2.dll"
+
+SectionEnd
+
+Section "Microsoft Visual C 9.0 Runtime DLL" SecMSVCR90DLL
+
+ SetOverwrite on
+ SetOutPath "$INSTDIR\bin"
+ File "${BIN}\Microsoft.VC90.CRT\msvcr90.dll"
+ File "${BIN}\Microsoft.VC90.CRT\Microsoft.VC90.CRT.manifest"
+
+SectionEnd
+
+
+
+
+Section "TAP Virtual Ethernet Adapter" SecTAP
+
+ SetOverwrite on
+
+ # Generate TAP driver install script dynamically
+ FileOpen $R0 "$INSTDIR\bin\addtap.bat" w
+ FileWrite $R0 "rem Add a new TAP virtual ethernet adapter$\r$\n"
+ FileWrite $R0 '"$INSTDIR\bin\tapinstall.exe" install "$INSTDIR\driver\OemWin2k.inf" ${TAP}$\r$\n'
+ FileWrite $R0 "pause$\r$\n"
+ FileClose $R0
+
+ # Generate TAP driver removal script dynamically
+ FileOpen $R0 "$INSTDIR\bin\deltapall.bat" w
+ FileWrite $R0 "echo WARNING: this script will delete ALL TAP virtual adapters (use the device manager to delete adapters one at a time)$\r$\n"
+ FileWrite $R0 "pause$\r$\n"
+ FileWrite $R0 '"$INSTDIR\bin\tapinstall.exe" remove ${TAP}$\r$\n'
+ FileWrite $R0 "pause$\r$\n"
+ FileClose $R0
+
+ ; Check if we are running on a 64 bit system.
+ System::Call "kernel32::GetCurrentProcess() i .s"
+ System::Call "kernel32::IsWow64Process(i s, *i .r0)"
+ IntCmp $0 0 tap-32bit
+
+; tap-64bit:
+
+ DetailPrint "We are running on a 64-bit system."
+
+ SetOutPath "$INSTDIR\bin"
+
+ File "${GEN}\amd64\tapinstall.exe"
+
+ SetOutPath "$INSTDIR\driver"
+
+ File "${GEN}\amd64\OemWin2k.inf"
+ File "${GEN}\amd64\${TAPDRV}"
+
+ # Don't try to install TAP driver signature if it does not exist.
+ File /nonfatal "${GEN}\amd64\${PRODUCT_TAP_ID}.cat"
+
+goto tapend
+
+tap-32bit:
+
+ DetailPrint "We are running on a 32-bit system."
+
+ SetOutPath "$INSTDIR\bin"
+ File "${GEN}\i386\tapinstall.exe"
+
+ SetOutPath "$INSTDIR\driver"
+ File "${GEN}\i386\OemWin2k.inf"
+ File "${GEN}\i386\${TAPDRV}"
+
+ # Don't try to install TAP driver signature if it does not exist.
+ File /nonfatal "${GEN}\i386\${PRODUCT_TAP_ID}.cat"
+
+ tapend:
+
+SectionEnd
+
+Section "Add ${PRODUCT_NAME} to PATH" SecAddPath
+
+ ; remove previously set path (if any)
+ Push "$INSTDIR\bin"
+ Call RemoveFromPath
+
+ ; append our bin directory to end of current user path
+ Push "$INSTDIR\bin"
+ Call AddToPath
+
+SectionEnd
+
+Section "Add Shortcuts to Start Menu" SecAddShortcuts
+
+ ; Required to handle shortcuts properly on Vista/7
+ SetShellVarContext all
+ SetOverwrite on
+ CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}"
+ CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}\Documentation"
+ WriteINIStr "$SMPROGRAMS\${PRODUCT_NAME}\Documentation\${PRODUCT_NAME} Windows Notes.url" "InternetShortcut" "URL" "http://openvpn.net/INSTALL-win32.html"
+ WriteINIStr "$SMPROGRAMS\${PRODUCT_NAME}\Documentation\${PRODUCT_NAME} Manual Page.url" "InternetShortcut" "URL" "http://openvpn.net/man.html"
+ WriteINIStr "$SMPROGRAMS\${PRODUCT_NAME}\Documentation\${PRODUCT_NAME} HOWTO.url" "InternetShortcut" "URL" "http://openvpn.net/howto.html"
+ WriteINIStr "$SMPROGRAMS\${PRODUCT_NAME}\Documentation\${PRODUCT_NAME} Web Site.url" "InternetShortcut" "URL" "http://openvpn.net/"
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall ${PRODUCT_NAME}.lnk" "$INSTDIR\Uninstall.exe"
+
+SectionEnd
+
+;--------------------
+;Post-install section
+
+Section -post
+
+ SetOverwrite on
+
+ ; delete old tapinstall.exe
+ ;Delete "$INSTDIR\bin\tapinstall.exe"
+
+ ; Store README, license, icon
+ SetOverwrite on
+ SetOutPath $INSTDIR
+ File "..\INSTALL-win32.txt"
+ File "..\COPYRIGHT.GPL"
+ File "..\images\${PRODUCT_ICON}"
+
+ ; store sample config files
+ !ifdef SAMPCONF_DIR
+ SetOverwrite on
+ SetOutPath "$INSTDIR\config"
+ !ifdef SAMPCONF_CONF
+ File "${GEN}\conf\${SAMPCONF_CONF}"
+ !endif
+ !ifdef SAMPCONF_CONF2
+ File "${GEN}\conf\${SAMPCONF_CONF2}"
+ !endif
+ !ifdef SAMPCONF_P12
+ File "${GEN}\conf\${SAMPCONF_P12}"
+ !endif
+ !ifdef SAMPCONF_TA
+ File "${GEN}\conf\${SAMPCONF_TA}"
+ !endif
+ !ifdef SAMPCONF_CA
+ File "${GEN}\conf\${SAMPCONF_CA}"
+ !endif
+ !ifdef SAMPCONF_CRT
+ File "${GEN}\conf\${SAMPCONF_CRT}"
+ !endif
+ !ifdef SAMPCONF_KEY
+ File "${GEN}\conf\${SAMPCONF_KEY}"
+ !endif
+ !ifdef SAMPCONF_DH
+ File "${GEN}\conf\${SAMPCONF_DH}"
+ !endif
+ !endif
+
+ ; Try to extract files if present
+ !ifdef EXTRACT_FILES
+ Push "$INSTDIR"
+ Call MultiFileExtract
+ Pop $R0
+ IntCmp $R0 0 +3 +1 +1
+ DetailPrint "MultiFileExtract Failed status=$R0"
+ goto +2
+ DetailPrint "MultiFileExtract Succeeded"
+ !endif
+
+ ;
+ ; install/upgrade TAP driver if selected, using tapinstall.exe
+ ;
+ SectionGetFlags ${SecTAP} $R0
+ IntOp $R0 $R0 & ${SF_SELECTED}
+ IntCmp $R0 ${SF_SELECTED} "" notap notap
+ ; TAP install/update was selected.
+ ; Should we install or update?
+ ; If tapinstall error occurred, $5 will
+ ; be nonzero.
+ IntOp $5 0 & 0
+ nsExec::ExecToStack '"$INSTDIR\bin\tapinstall.exe" hwids ${TAP}'
+ Pop $R0 # return value/error/timeout
+ IntOp $5 $5 | $R0
+ DetailPrint "tapinstall hwids returned: $R0"
+
+ ; If tapinstall output string contains "${TAP}" we assume
+ ; that TAP device has been previously installed,
+ ; therefore we will update, not install.
+ Push "${TAP}"
+ Call StrStr
+ Pop $R0
+
+ IntCmp $5 0 "" tapinstall_check_error tapinstall_check_error
+ IntCmp $R0 -1 tapinstall
+
+ ;tapupdate:
+ DetailPrint "TAP UPDATE"
+ nsExec::ExecToLog '"$INSTDIR\bin\tapinstall.exe" update "$INSTDIR\driver\OemWin2k.inf" ${TAP}'
+ Pop $R0 # return value/error/timeout
+ Call CheckReboot
+ IntOp $5 $5 | $R0
+ DetailPrint "tapinstall update returned: $R0"
+ Goto tapinstall_check_error
+
+ tapinstall:
+ DetailPrint "TAP REMOVE OLD TAP"
+
+ nsExec::ExecToLog '"$INSTDIR\bin\tapinstall.exe" remove TAP0801'
+ Pop $R0 # return value/error/timeout
+ DetailPrint "tapinstall remove TAP0801 returned: $R0"
+
+ DetailPrint "TAP INSTALL (${TAP})"
+ nsExec::ExecToLog '"$INSTDIR\bin\tapinstall.exe" install "$INSTDIR\driver\OemWin2k.inf" ${TAP}'
+ Pop $R0 # return value/error/timeout
+ Call CheckReboot
+ IntOp $5 $5 | $R0
+ DetailPrint "tapinstall install returned: $R0"
+
+ tapinstall_check_error:
+ DetailPrint "tapinstall cumulative status: $5"
+ IntCmp $5 0 notap
+ MessageBox MB_OK "An error occurred installing the TAP device driver."
+
+ notap:
+
+ ; Store install folder in registry
+ WriteRegStr HKLM SOFTWARE\${PRODUCT_NAME} "" $INSTDIR
+
+ ; install as a service if requested
+ SectionGetFlags ${SecService} $R0
+ IntOp $R0 $R0 & ${SF_SELECTED}
+ IntCmp $R0 ${SF_SELECTED} "" noserv noserv
+
+ ; set registry parameters for openvpnserv
+ !insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\${PRODUCT_NAME}" "config_dir" "${SERV_CONFIG_DIR}"
+ !insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\${PRODUCT_NAME}" "config_ext" "${SERV_CONFIG_EXT}"
+ !insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\${PRODUCT_NAME}" "exe_path" "${SERV_EXE_PATH}"
+ !insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\${PRODUCT_NAME}" "log_dir" "${SERV_LOG_DIR}"
+ !insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\${PRODUCT_NAME}" "priority" "${SERV_PRIORITY}"
+ !insertmacro WriteRegStringIfUndef HKLM "SOFTWARE\${PRODUCT_NAME}" "log_append" "${SERV_LOG_APPEND}"
+
+ ; install openvpnserv as a service (to be started manually from service control manager)
+ DetailPrint "Service INSTALL"
+ nsExec::ExecToLog '"$INSTDIR\bin\${PRODUCT_UNIX_NAME}serv.exe" -install'
+ Pop $R0 # return value/error/timeout
+
+ noserv:
+
+ ; Create file association if requested
+ fileass:
+ SectionGetFlags ${SecFileAssociation} $R0
+ IntOp $R0 $R0 & ${SF_SELECTED}
+ IntCmp $R0 ${SF_SELECTED} "" noass noass
+ WriteRegStr HKCR ".${SERV_CONFIG_EXT}" "" "${PRODUCT_NAME}File"
+ WriteRegStr HKCR "${PRODUCT_NAME}File" "" "${PRODUCT_NAME} Config File"
+ WriteRegStr HKCR "${PRODUCT_NAME}File\shell" "" "open"
+ WriteRegStr HKCR "${PRODUCT_NAME}File\DefaultIcon" "" "$INSTDIR\${PRODUCT_ICON},0"
+ WriteRegStr HKCR "${PRODUCT_NAME}File\shell\open\command" "" 'notepad.exe "%1"'
+ WriteRegStr HKCR "${PRODUCT_NAME}File\shell\run" "" "Start ${PRODUCT_NAME} on this config file"
+ WriteRegStr HKCR "${PRODUCT_NAME}File\shell\run\command" "" '"$INSTDIR\bin\${PRODUCT_UNIX_NAME}.exe" --pause-exit --config "%1"'
+
+ ; Create start menu folders
+ noass:
+ CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}\Utilities"
+ CreateDirectory "$SMPROGRAMS\${PRODUCT_NAME}\Shortcuts"
+
+ ; Create start menu and desktop shortcuts to OpenVPN GUI
+ !ifdef USE_GUI
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME} GUI.lnk" "$INSTDIR\bin\${OPENVPN_GUI}" ""
+ CreateShortcut "$DESKTOP\${PRODUCT_NAME} GUI.lnk" "$INSTDIR\bin\${OPENVPN_GUI}"
+ !endif
+
+ ; Create start menu shortcuts to addtap.bat and deltapall.bat
+ tryaddtap:
+ IfFileExists "$INSTDIR\bin\addtap.bat" "" trydeltap
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Utilities\Add a new TAP virtual ethernet adapter.lnk" "$INSTDIR\bin\addtap.bat" ""
+
+ trydeltap:
+ IfFileExists "$INSTDIR\bin\deltapall.bat" "" config_shortcut
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Utilities\Delete ALL TAP virtual ethernet adapters.lnk" "$INSTDIR\bin\deltapall.bat" ""
+
+ ; Create start menu shortcuts for config and log directories
+ config_shortcut:
+ IfFileExists "$INSTDIR\config" "" log_shortcut
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Shortcuts\${PRODUCT_NAME} configuration file directory.lnk" "$INSTDIR\config" ""
+
+ log_shortcut:
+ IfFileExists "$INSTDIR\log" "" samp_shortcut
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Shortcuts\${PRODUCT_NAME} log file directory.lnk" "$INSTDIR\log" ""
+
+ samp_shortcut:
+ IfFileExists "$INSTDIR\sample-config" "" genkey_shortcut
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Shortcuts\${PRODUCT_NAME} Sample Configuration Files.lnk" "$INSTDIR\sample-config" ""
+
+ genkey_shortcut:
+ IfFileExists "$INSTDIR\bin\${PRODUCT_UNIX_NAME}.exe" "" noshortcuts
+ IfFileExists "$INSTDIR\config" "" noshortcuts
+ CreateShortCut "$SMPROGRAMS\${PRODUCT_NAME}\Utilities\Generate a static ${PRODUCT_NAME} key.lnk" "$INSTDIR\bin\${PRODUCT_UNIX_NAME}.exe" '--pause-exit --verb 3 --genkey --secret "$INSTDIR\config\key.txt"' "$INSTDIR\${PRODUCT_ICON}" 0
+
+ noshortcuts:
+ ; Create uninstaller
+ WriteUninstaller "$INSTDIR\Uninstall.exe"
+
+ ; Show up in Add/Remove programs
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayName" "${PRODUCT_NAME} ${VERSION}"
+ WriteRegExpandStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayIcon" "$INSTDIR\${PRODUCT_ICON}"
+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" "DisplayVersion" "${VERSION}"
+
+ ; Advise a reboot
+ ;Messagebox MB_OK "IMPORTANT: Rebooting the system is advised in order to finalize TAP driver installation/upgrade (this is an informational message only, pressing OK will not reboot)."
+
+SectionEnd
+
+;--------------------------------
+;Descriptions
+
+!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecOpenVPNUserSpace} $(DESC_SecOpenVPNUserSpace)
+ !ifdef USE_GUI
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecOpenVPNGUI} $(DESC_SecOpenVPNGUI)
+ !endif
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecOpenVPNEasyRSA} $(DESC_SecOpenVPNEasyRSA)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecTAP} $(DESC_SecTAP)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecOpenSSLUtilities} $(DESC_SecOpenSSLUtilities)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecOpenSSLDLLs} $(DESC_SecOpenSSLDLLs)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecPKCS11DLLs} $(DESC_SecPKCS11DLLs)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecLZO2DLLs} $(DESC_SecLZO2DLLs)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecMSVCR90DLL} $(DESC_SecMSVCR90DLL)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecAddPath} $(DESC_SecAddPath)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecAddShortcuts} $(DESC_SecAddShortcuts)
+
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecService} $(DESC_SecService)
+ !insertmacro MUI_DESCRIPTION_TEXT ${SecFileAssociation} $(DESC_SecFileAssociation)
+!insertmacro MUI_FUNCTION_DESCRIPTION_END
+
+;--------------------------------
+;Uninstaller Section
+
+Function un.onInit
+ ClearErrors
+ UserInfo::GetName
+ IfErrors ok
+ Pop $R0
+ UserInfo::GetAccountType
+ Pop $R1
+ StrCmp $R1 "Admin" ok
+ Messagebox MB_OK "Administrator privileges required to uninstall ${PRODUCT_NAME} [$R0/$R1]"
+ Abort
+ ok:
+FunctionEnd
+
+Section "Uninstall"
+
+ ; Required to handle shortcuts properly on Vista/7
+ SetShellVarContext all
+
+ ; Stop OpenVPN if currently running
+
+ DetailPrint "Service REMOVE"
+ nsExec::ExecToLog '"$INSTDIR\bin\${PRODUCT_UNIX_NAME}serv.exe" -remove'
+ Pop $R0 # return value/error/timeout
+
+ Sleep 3000
+
+ DetailPrint "TAP REMOVE"
+ nsExec::ExecToLog '"$INSTDIR\bin\tapinstall.exe" remove ${TAP}'
+ Pop $R0 # return value/error/timeout
+ DetailPrint "tapinstall remove returned: $R0"
+
+ Push "$INSTDIR\bin"
+ Call un.RemoveFromPath
+
+ RMDir /r $SMPROGRAMS\${PRODUCT_NAME}
+
+ ; delete sample config files
+ !ifdef SAMPCONF_DIR
+ !ifdef SAMPCONF_CONF
+ Delete "$INSTDIR\config\${SAMPCONF_CONF}"
+ !endif
+ !ifdef SAMPCONF_CONF2
+ Delete "$INSTDIR\config\${SAMPCONF_CONF2}"
+ !endif
+ !ifdef SAMPCONF_P12
+ Delete "$INSTDIR\config\${SAMPCONF_P12}"
+ !endif
+ !ifdef SAMPCONF_TA
+ Delete "$INSTDIR\config\${SAMPCONF_TA}"
+ !endif
+ !ifdef SAMPCONF_CA
+ Delete "$INSTDIR\config\${SAMPCONF_CA}"
+ !endif
+ !ifdef SAMPCONF_CRT
+ Delete "$INSTDIR\config\${SAMPCONF_CRT}"
+ !endif
+ !ifdef SAMPCONF_KEY
+ Delete "$INSTDIR\config\${SAMPCONF_KEY}"
+ !endif
+ !ifdef SAMPCONF_DH
+ Delete "$INSTDIR\config\${SAMPCONF_DH}"
+ !endif
+ !endif
+
+ !ifdef USE_GUI
+ Delete "$INSTDIR\bin\${OPENVPN_GUI}"
+ Delete "$DESKTOP\${PRODUCT_NAME} GUI.lnk"
+ !endif
+
+ # Files installed by openvpn-2.2-beta5 and earlier
+ Delete "$INSTDIR\easy-rsa\openssl.cnf.sample"
+ Delete "$INSTDIR\license"
+ Delete "$INSTDIR\bin\libssl32.dll"
+
+ Delete "$INSTDIR\bin\${PRODUCT_UNIX_NAME}.exe"
+ Delete "$INSTDIR\bin\${PRODUCT_UNIX_NAME}serv.exe"
+ Delete "$INSTDIR\bin\libeay32.dll"
+ Delete "$INSTDIR\bin\ssleay32.dll"
+ Delete "$INSTDIR\bin\libpkcs11-helper-1.dll"
+ Delete "$INSTDIR\bin\lzo2.dll"
+ Delete "$INSTDIR\bin\msvcr90.dll"
+ Delete "$INSTDIR\bin\Microsoft.VC90.CRT.manifest"
+ Delete "$INSTDIR\bin\tapinstall.exe"
+ Delete "$INSTDIR\bin\addtap.bat"
+ Delete "$INSTDIR\bin\deltapall.bat"
+
+ Delete "$INSTDIR\config\README.txt"
+ Delete "$INSTDIR\config\sample.${SERV_CONFIG_EXT}.txt"
+
+ Delete "$INSTDIR\log\README.txt"
+
+ Delete "$INSTDIR\driver\OemWin2k.inf"
+ Delete "$INSTDIR\driver\${PRODUCT_TAP_ID}.cat"
+ Delete "$INSTDIR\driver\${TAPDRV}"
+
+ Delete "$INSTDIR\bin\openssl.exe"
+
+ Delete "$INSTDIR\INSTALL-win32.txt"
+ Delete "$INSTDIR\${PRODUCT_ICON}"
+ Delete "$INSTDIR\COPYRIGHT.GPL"
+ Delete "$INSTDIR\Uninstall.exe"
+
+ Delete "$INSTDIR\easy-rsa\openssl.cnf"
+ Delete "$INSTDIR\easy-rsa\vars.bat.sample"
+ Delete "$INSTDIR\easy-rsa\init-config.bat"
+ Delete "$INSTDIR\easy-rsa\README.txt"
+ Delete "$INSTDIR\easy-rsa\build-ca.bat"
+ Delete "$INSTDIR\easy-rsa\build-dh.bat"
+ Delete "$INSTDIR\easy-rsa\build-key-server.bat"
+ Delete "$INSTDIR\easy-rsa\build-key.bat"
+ Delete "$INSTDIR\easy-rsa\build-key-pkcs12.bat"
+ Delete "$INSTDIR\easy-rsa\clean-all.bat"
+ Delete "$INSTDIR\easy-rsa\index.txt.start"
+ Delete "$INSTDIR\easy-rsa\revoke-key.bat"
+ Delete "$INSTDIR\easy-rsa\revoke-full.bat"
+ Delete "$INSTDIR\easy-rsa\serial.start"
+
+ Delete "$INSTDIR\sample-config\*.${PRODUCT_FILE_EXT}"
+
+ RMDir "$INSTDIR\bin"
+ RMDir "$INSTDIR\config"
+ RMDir "$INSTDIR\driver"
+ RMDir "$INSTDIR\easy-rsa"
+ RMDir "$INSTDIR\sample-config"
+ RMDir /r "$INSTDIR\log"
+ RMDir "$INSTDIR"
+
+ !insertmacro DelRegKeyIfUnchanged HKCR ".${SERV_CONFIG_EXT}" "${PRODUCT_NAME}File"
+ DeleteRegKey HKCR "${PRODUCT_NAME}File"
+ DeleteRegKey HKLM SOFTWARE\${PRODUCT_NAME}
+ DeleteRegKey HKCU "Software\${PRODUCT_NAME}"
+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
+
+SectionEnd
diff --git a/win/setpath.nsi b/win/setpath.nsi
new file mode 100755
index 0000000..a9626c3
--- /dev/null
+++ b/win/setpath.nsi
@@ -0,0 +1,231 @@
+; Modify the user's PATH variable.
+;
+; Modified by JY to have both a RemoveFromPath
+; and an un.RemoveFromPath which are basically
+; copies of each other. Why does NSIS demand
+; this nonsense?
+;
+; Modified Feb 14, 2005 by Mathias Sundman:
+; Added code to remove the semicolon at the end of the path
+; when uninstalling.
+;
+; Added code to make sure we don't insert an extra semicolon
+; before our path if there already exist one at the end of
+; the original path.
+;
+; Removed duplicated "un. and install" functions and made
+; macros to duplicate the code instead.
+
+; example usage
+;
+;Section "Add to path"
+; Push $INSTDIR
+; Call AddToPath
+;SectionEnd
+;
+;# ...
+;
+;Section "uninstall"
+; # ...
+; Push $INSTDIR
+; Call un.RemoveFromPath
+; # ...
+;SectionEnd
+
+!verbose 3
+!include "WinMessages.NSH"
+!verbose 4
+
+;====================================================
+; AddToPath - Adds the given dir to the search path.
+; Input - head of the stack
+; Note - Win9x systems requires reboot
+;====================================================
+Function AddToPath
+ Exch $0
+ Push $1
+ Push $2
+
+ Call IsNT
+ Pop $1
+ StrCmp $1 1 AddToPath_NT
+ ; Not on NT
+ StrCpy $1 $WINDIR 2
+ FileOpen $1 "$1\autoexec.bat" a
+ FileSeek $1 0 END
+ GetFullPathName /SHORT $0 $0
+ FileWrite $1 "$\r$\nSET PATH=%PATH%;$0$\r$\n"
+ FileClose $1
+ Goto AddToPath_done
+
+ AddToPath_NT:
+ ReadRegStr $1 HKCU "Environment" "PATH"
+ StrCpy $2 $1 1 -1 # copy last char
+ StrCmp $2 ";" 0 +2 # if last char == ;
+ StrCpy $1 $1 -1 # remove last char
+
+ StrCmp $1 "" AddToPath_NTdoIt
+ StrCpy $0 "$1;$0"
+ Goto AddToPath_NTdoIt
+ AddToPath_NTdoIt:
+ WriteRegExpandStr HKCU "Environment" "PATH" $0
+ SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+
+ AddToPath_done:
+ Pop $2
+ Pop $1
+ Pop $0
+FunctionEnd
+
+;====================================================
+; RemoveFromPath - Remove a given dir from the path
+; Input: head of the stack
+;====================================================
+!macro RemoveFromPath un
+Function ${un}RemoveFromPath
+ Exch $0
+ Push $1
+ Push $2
+ Push $3
+ Push $4
+ Push $5
+
+ Call ${un}IsNT
+ Pop $1
+ StrCmp $1 1 RemoveFromPath_NT
+ ; Not on NT
+ StrCpy $1 $WINDIR 2
+ FileOpen $1 "$1\autoexec.bat" r
+ GetTempFileName $4
+ FileOpen $2 $4 w
+ GetFullPathName /SHORT $0 $0
+ StrCpy $0 "SET PATH=%PATH%;$0"
+ SetRebootFlag true
+ Goto RemoveFromPath_dosLoop
+
+ RemoveFromPath_dosLoop:
+ FileRead $1 $3
+ StrCmp $3 "$0$\r$\n" RemoveFromPath_dosLoop
+ StrCmp $3 "$0$\n" RemoveFromPath_dosLoop
+ StrCmp $3 "$0" RemoveFromPath_dosLoop
+ StrCmp $3 "" RemoveFromPath_dosLoopEnd
+ FileWrite $2 $3
+ Goto RemoveFromPath_dosLoop
+
+ RemoveFromPath_dosLoopEnd:
+ FileClose $2
+ FileClose $1
+ StrCpy $1 $WINDIR 2
+ Delete "$1\autoexec.bat"
+ CopyFiles /SILENT $4 "$1\autoexec.bat"
+ Delete $4
+ Goto RemoveFromPath_done
+
+ RemoveFromPath_NT:
+ StrLen $2 $0
+ ReadRegStr $1 HKCU "Environment" "PATH"
+ Push $1
+ Push $0
+ Call ${un}StrStr ; Find $0 in $1
+ Pop $0 ; pos of our dir
+ IntCmp $0 -1 RemoveFromPath_done
+ ; else, it is in path
+ StrCpy $3 $1 $0 ; $3 now has the part of the path before our dir
+ IntOp $2 $2 + $0 ; $2 now contains the pos after our dir in the path (';')
+ IntOp $2 $2 + 1 ; $2 now containts the pos after our dir and the semicolon.
+ StrLen $0 $1
+ StrCpy $1 $1 $0 $2
+ StrCpy $3 "$3$1"
+
+ StrCpy $5 $3 1 -1 # copy last char
+ StrCmp $5 ";" 0 +2 # if last char == ;
+ StrCpy $3 $3 -1 # remove last char
+
+ WriteRegExpandStr HKCU "Environment" "PATH" $3
+ SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
+
+ RemoveFromPath_done:
+ Pop $5
+ Pop $4
+ Pop $3
+ Pop $2
+ Pop $1
+ Pop $0
+FunctionEnd
+!macroend
+!insertmacro RemoveFromPath ""
+!insertmacro RemoveFromPath "un."
+
+
+;====================================================
+; StrStr - Finds a given string in another given string.
+; Returns -1 if not found and the pos if found.
+; Input: head of the stack - string to find
+; second in the stack - string to find in
+; Output: head of the stack
+;====================================================
+!macro StrStr un
+Function ${un}StrStr
+ Push $0
+ Exch
+ Pop $0 ; $0 now have the string to find
+ Push $1
+ Exch 2
+ Pop $1 ; $1 now have the string to find in
+ Exch
+ Push $2
+ Push $3
+ Push $4
+ Push $5
+
+ StrCpy $2 -1
+ StrLen $3 $0
+ StrLen $4 $1
+ IntOp $4 $4 - $3
+
+ StrStr_loop:
+ IntOp $2 $2 + 1
+ IntCmp $2 $4 0 0 StrStrReturn_notFound
+ StrCpy $5 $1 $3 $2
+ StrCmp $5 $0 StrStr_done StrStr_loop
+
+ StrStrReturn_notFound:
+ StrCpy $2 -1
+
+ StrStr_done:
+ Pop $5
+ Pop $4
+ Pop $3
+ Exch $2
+ Exch 2
+ Pop $0
+ Pop $1
+FunctionEnd
+!macroend
+!insertmacro StrStr ""
+!insertmacro StrStr "un."
+
+;====================================================
+; IsNT - Returns 1 if the current system is NT, 0
+; otherwise.
+; Output: head of the stack
+;====================================================
+!macro IsNT un
+Function ${un}IsNT
+ Push $0
+ ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
+ StrCmp $0 "" 0 IsNT_yes
+ ; we are not NT.
+ Pop $0
+ Push 0
+ Return
+
+ IsNT_yes:
+ ; NT!!!
+ Pop $0
+ Push 1
+FunctionEnd
+!macroend
+!insertmacro IsNT ""
+!insertmacro IsNT "un."
+
diff --git a/win/settings.in b/win/settings.in
index f8eeb20..10c7926 100644
--- a/win/settings.in
+++ b/win/settings.in
@@ -1,42 +1,58 @@
# Version numbers, settings, and dependencies
# for Windows OpenVPN installer.
+#
+# Note that some variables are parsed by wb.py from version.m4 and are not
+# stored in this file. This is done to allow using the old and new Windows build
+# systems side-by-side
+
+# Features to include. DO NOT comment these out, use 1 to enable and 0 to
+# disable.
+!define ENABLE_PASSWORD_SAVE 1
+
+# ENABLE_CLIENT_SERVER enables the point-to-multipoint support. Normally you
+# want to have this enabled.
+!define ENABLE_CLIENT_SERVER 1
+
+# ENABLE_CLIENT_ONLY removes server-side point-to-multipoint features. This
+# depends on ENABLE_CLIENT_SERVER being set to 1.
+!define ENABLE_CLIENT_ONLY 0
+
+!define ENABLE_MANAGEMENT 1
+!define ENABLE_HTTP_PROXY 1
+!define ENABLE_SOCKS 1
+!define ENABLE_FRAGMENT 1
+!define ENABLE_DEBUG 1
# Branding
!define PRODUCT_NAME "OpenVPN"
!define PRODUCT_UNIX_NAME "openvpn"
!define PRODUCT_FILE_EXT "ovpn"
-# Allow --askpass and --auth-user-pass passwords to be read from a file
-;!define ENABLE_PASSWORD_SAVE
-
-# Include the OpenVPN GUI exe in the installer.
-# May be undefined.
+# Include the OpenVPN GUI exe in the installer. Comment out USE_GUI to disable.
+!define USE_GUI
!define OPENVPN_GUI_DIR "../openvpn-gui"
!define OPENVPN_GUI "openvpn-gui-1.0.3.exe"
# Prebuilt libraries. DMALLOC is optional.
!define OPENSSL_DIR "../openssl"
!define LZO_DIR "../lzo"
+!define PKCS11_HELPER_DIR "../pkcs11-helper"
# write output files here
!define DIST "dist"
-# tapinstall.exe source code.
-# Not needed if DRVBINSRC is defined
-# (or if using pre-built mode).
+# tapinstall.exe (a.k.a. devcon.exe) source code. Not needed if DRVBINSRC is
+# defined (or if using pre-built mode).
!define TISRC "../tapinstall"
-# TAP Adapter parameters. Note that PRODUCT_TAP_ID is
-# defined in version.m4.
-!define PRODUCT_TAP_DEVICE_DESCRIPTION "TAP-Win32 Adapter V9"
-!define PRODUCT_TAP_PROVIDER "TAP-Win32 Provider V9"
-!define PRODUCT_TAP_MAJOR_VER 9
-!define PRODUCT_TAP_MINOR_VER 7
-!define PRODUCT_TAP_RELDATE "04/19/2010"
-
# TAP adapter icon -- visible=0x81 or hidden=0x89
!define PRODUCT_TAP_CHARACTERISTICS 0x81
+# TAP adapter metadata. Version information in ../version.m4.
+!define PRODUCT_TAP_RELDATE "04/19/2010"
+!define PRODUCT_TAP_DEVICE_DESCRIPTION "TAP-Win32 Adapter V9"
+!define PRODUCT_TAP_PROVIDER "TAP-Win32 Provider V9"
+
# Build debugging version of TAP driver
;!define PRODUCT_TAP_DEBUG
@@ -61,6 +77,9 @@
!define SIGNTOOL "../signtool"
!define PRODUCT_SIGN_CN "openvpn"
+# Directory with prebuilt TAP drivers and tapinstall.exes
+!define TAP_PREBUILT "../tap-prebuilt"
+
; DEBUGGING -- set to something like "-DBG2"
!define OUTFILE_LABEL ""
diff --git a/win/show.py b/win/show.py
index 9558c87..ac56e98 100644
--- a/win/show.py
+++ b/win/show.py
@@ -1,10 +1,9 @@
-from wb import get_config
-from js import JSON
-
-def main():
- kv = get_config()
- print JSON().encode(kv)
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- main()
+from wb import get_config
+from js import JSON
+
+def main():
+ print JSON().encode(get_config())
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ main()
diff --git a/win/sign.py b/win/sign.py
index 9376951..a80bf98 100644
--- a/win/sign.py
+++ b/win/sign.py
@@ -1,23 +1,23 @@
-import sys
-from wb import config, choose_arch, home_fn
-
-if 'SIGNTOOL' in config:
- sys.path.append(home_fn(config['SIGNTOOL']))
-
-def main(conf, arch, tap_dir):
- from signtool import SignTool
- st = SignTool(conf, tap_dir)
- for x64 in choose_arch(arch):
- st.sign_verify(x64=x64)
-
-# if we are run directly, and not loaded as a module
-if __name__ == "__main__":
- if len(sys.argv) >= 2:
- if len(sys.argv) >= 3:
- tap_dir = home_fn(sys.argv[2])
- else:
- tap_dir = None
- main(config, sys.argv[1], tap_dir)
- else:
- print "usage: sign <x64|x86|all> [tap-dir]"
- sys.exit(2)
+import sys
+from wb import config, choose_arch, home_fn
+
+if 'SIGNTOOL' in config:
+ sys.path.append(home_fn(config['SIGNTOOL']))
+
+def main(conf, arch, tap_dir):
+ from signtool import SignTool
+ st = SignTool(conf, tap_dir)
+ for x64 in choose_arch(arch):
+ st.sign_verify(x64=x64)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ if len(sys.argv) >= 2:
+ if len(sys.argv) >= 3:
+ tap_dir = home_fn(sys.argv[2])
+ else:
+ tap_dir = None
+ main(config, sys.argv[1], tap_dir)
+ else:
+ print "usage: sign <x64|x86|all> [tap-dir]"
+ sys.exit(2)
diff --git a/win/tap_span.py b/win/tap_span.py
index 9cd127b..749f6f3 100644
--- a/win/tap_span.py
+++ b/win/tap_span.py
@@ -1,129 +1,129 @@
-import sys, os, shutil
-from wb import config, home_fn, mod_fn, preprocess, autogen, dict_def, build_autodefs, rm_rf, mkdir_silent, cp
-if 'SIGNTOOL' in config:
- sys.path.append(home_fn(config['SIGNTOOL']))
-from signtool import SignTool
-from build_ddk import build_tap
-
-ti_dir = "c:/src/tapinstall"
-hi = ("c:/winddk/7600.16385.1", 7600, 7600, ("i386", "amd64"))
-low = ("c:/winddk/6001.18002", 6001, 5600, ("win2k",))
-dest_top = home_fn('tap_build')
-dist = home_fn(config['TAP_DIST'])
-
-def copy_tap(src, dest, x64):
- dir = os.path.join(src, { False : 'i386', True: 'amd64' }[x64])
- mkdir_silent(dest)
- for dirpath, dirnames, filenames in os.walk(dir):
- for f in filenames:
- root, ext = os.path.splitext(f)
- if ext in ('.inf', '.cat', '.sys'):
- cp(os.path.join(dir, f), dest)
- break
-
-def copy_tapinstall(src, dest, x64):
- base = { False : 'i386', True: 'amd64' }[x64]
- mkdir_silent(dest)
- for dirpath, dirnames, filenames in os.walk(home_fn(src)):
- for f in filenames:
- if f == 'tapinstall.exe':
- dir_name = os.path.basename(dirpath)
- s = os.path.join(dirpath, f)
- if dir_name == base:
- cp(s, dest)
-
-def main():
- rm_rf(dest_top)
- os.mkdir(dest_top)
-
- rm_rf(dist)
- os.mkdir(dist)
-
- for ver in hi, low:
- top = os.path.join(dest_top, str(ver[1]))
- os.mkdir(top)
- tap_dest = os.path.join(top, "tap-win32")
- ti_dest = os.path.join(top, "tapinstall")
- ti_src = os.path.join(ti_dir, str(ver[2]))
- shutil.copytree(home_fn("tap-win32"), tap_dest)
- shutil.copytree(ti_src, ti_dest)
-
- i386 = os.path.join(tap_dest, "i386")
- amd64 = os.path.join(tap_dest, "amd64")
-
- build_amd64 = (len(ver[3]) >= 2)
-
- build_autodefs(config, mod_fn('autodefs.h.in'), os.path.join(top, 'autodefs.h'))
-
- st = SignTool(config, tap_dest)
-
- preprocess(config,
- in_fn=os.path.join(tap_dest, 'SOURCES.in'),
- out_fn=os.path.join(tap_dest, 'SOURCES'),
- quote_begin='@@',
- quote_end='@@',
- head_comment='# %s\n\n' % autogen)
-
- preprocess(config,
- in_fn=os.path.join(i386, 'OemWin2k.inf.in'),
- out_fn=os.path.join(i386, 'OemWin2k.inf'),
- quote_begin='@@',
- quote_end='@@',
- if_prefix='!',
- head_comment='; %s\n\n' % autogen)
-
- preprocess(config,
- in_fn=os.path.join(ti_dest, 'sources.in'),
- out_fn=os.path.join(ti_dest, 'sources'),
- if_prefix='!',
- head_comment='# %s\n\n' % autogen)
-
- build_tap(ddk_path=ver[0],
- ddk_major=ver[1],
- debug=False,
- dir=tap_dest,
- x64=False)
-
- st.sign_verify(x64=False)
-
- build_tap(ddk_path=ver[0],
- ddk_major=ver[1],
- debug=False,
- dir=ti_dest,
- x64=False)
-
- tap_dist = os.path.join(dist, ver[3][0])
-
- copy_tap(tap_dest, tap_dist, x64=False)
- copy_tapinstall(ti_dest, tap_dist, x64=False)
-
- if build_amd64:
- os.mkdir(amd64)
- preprocess(dict_def(config, [('AMD64', '1')]),
- in_fn=os.path.join(i386, 'OemWin2k.inf.in'),
- out_fn=os.path.join(amd64, 'OemWin2k.inf'),
- quote_begin='@@',
- quote_end='@@',
- if_prefix='!',
- head_comment='; %s\n\n' % autogen)
-
- build_tap(ddk_path=ver[0],
- ddk_major=ver[1],
- debug=False,
- dir=tap_dest,
- x64=True)
-
- build_tap(ddk_path=ver[0],
- ddk_major=ver[1],
- debug=False,
- dir=ti_dest,
- x64=True)
-
- st.sign_verify(x64=True)
-
- tap_dist_x64 = os.path.join(dist, ver[3][1])
-
- copy_tap(tap_dest, tap_dist_x64, x64=True)
- copy_tapinstall(ti_dest, tap_dist_x64, x64=True)
-
-main()
+import sys, os, shutil
+from wb import config, home_fn, mod_fn, preprocess, autogen, dict_def, build_autodefs, rm_rf, mkdir_silent, cp
+if 'SIGNTOOL' in config:
+ sys.path.append(home_fn(config['SIGNTOOL']))
+from signtool import SignTool
+from build_ddk import build_tap
+
+ti_dir = "c:/src/tapinstall"
+hi = ("c:/winddk/7600.16385.1", 7600, 7600, ("i386", "amd64"))
+low = ("c:/winddk/6001.18002", 6001, 5600, ("win2k",))
+dest_top = home_fn('tap_build')
+dist = home_fn(config['TAP_DIST'])
+
+def copy_tap(src, dest, x64):
+ dir = os.path.join(src, { False : 'i386', True: 'amd64' }[x64])
+ mkdir_silent(dest)
+ for dirpath, dirnames, filenames in os.walk(dir):
+ for f in filenames:
+ root, ext = os.path.splitext(f)
+ if ext in ('.inf', '.cat', '.sys'):
+ cp(os.path.join(dir, f), dest)
+ break
+
+def copy_tapinstall(src, dest, x64):
+ base = { False : 'i386', True: 'amd64' }[x64]
+ mkdir_silent(dest)
+ for dirpath, dirnames, filenames in os.walk(home_fn(src)):
+ for f in filenames:
+ if f == 'devcon.exe':
+ dir_name = os.path.basename(dirpath)
+ s = os.path.join(dirpath, f)
+ if dir_name == base:
+ cp(s, dest)
+
+def main():
+ rm_rf(dest_top)
+ os.mkdir(dest_top)
+
+ rm_rf(dist)
+ os.mkdir(dist)
+
+ for ver in hi, low:
+ top = os.path.join(dest_top, str(ver[1]))
+ os.mkdir(top)
+ tap_dest = os.path.join(top, "tap-win32")
+ ti_dest = os.path.join(top, "tapinstall")
+ ti_src = os.path.join(ti_dir, str(ver[2]))
+ shutil.copytree(home_fn("tap-win32"), tap_dest)
+ shutil.copytree(ti_src, ti_dest)
+
+ i386 = os.path.join(tap_dest, "i386")
+ amd64 = os.path.join(tap_dest, "amd64")
+
+ build_amd64 = (len(ver[3]) >= 2)
+
+ build_autodefs(config, mod_fn('autodefs.h.in'), os.path.join(top, 'autodefs.h'))
+
+ st = SignTool(config, tap_dest)
+
+ preprocess(config,
+ in_fn=os.path.join(tap_dest, 'SOURCES.in'),
+ out_fn=os.path.join(tap_dest, 'SOURCES'),
+ quote_begin='@@',
+ quote_end='@@',
+ head_comment='# %s\n\n' % autogen)
+
+ preprocess(config,
+ in_fn=os.path.join(i386, 'OemWin2k.inf.in'),
+ out_fn=os.path.join(i386, 'OemWin2k.inf'),
+ quote_begin='@@',
+ quote_end='@@',
+ if_prefix='!',
+ head_comment='; %s\n\n' % autogen)
+
+ preprocess(config,
+ in_fn=os.path.join(ti_dest, 'sources.in'),
+ out_fn=os.path.join(ti_dest, 'sources'),
+ if_prefix='!',
+ head_comment='# %s\n\n' % autogen)
+
+ build_tap(ddk_path=ver[0],
+ ddk_major=ver[1],
+ debug=False,
+ dir=tap_dest,
+ x64=False)
+
+ st.sign_verify(x64=False)
+
+ build_tap(ddk_path=ver[0],
+ ddk_major=ver[1],
+ debug=False,
+ dir=ti_dest,
+ x64=False)
+
+ tap_dist = os.path.join(dist, ver[3][0])
+
+ copy_tap(tap_dest, tap_dist, x64=False)
+ copy_tapinstall(ti_dest, tap_dist, x64=False)
+
+ if build_amd64:
+ os.mkdir(amd64)
+ preprocess(dict_def(config, [('AMD64', '1')]),
+ in_fn=os.path.join(i386, 'OemWin2k.inf.in'),
+ out_fn=os.path.join(amd64, 'OemWin2k.inf'),
+ quote_begin='@@',
+ quote_end='@@',
+ if_prefix='!',
+ head_comment='; %s\n\n' % autogen)
+
+ build_tap(ddk_path=ver[0],
+ ddk_major=ver[1],
+ debug=False,
+ dir=tap_dest,
+ x64=True)
+
+ build_tap(ddk_path=ver[0],
+ ddk_major=ver[1],
+ debug=False,
+ dir=ti_dest,
+ x64=True)
+
+ st.sign_verify(x64=True)
+
+ tap_dist_x64 = os.path.join(dist, ver[3][1])
+
+ copy_tap(tap_dest, tap_dist_x64, x64=True)
+ copy_tapinstall(ti_dest, tap_dist_x64, x64=True)
+
+main()
diff --git a/win/wb.py b/win/wb.py
index 8e23684..39eadec 100644
--- a/win/wb.py
+++ b/win/wb.py
@@ -1,215 +1,322 @@
-# Python module containing general build functions
-# for OpenVPN on Windows
-
-import os, re, shutil, stat
-
-autogen = "Automatically generated by OpenVPN Windows build system"
-
-def get_config():
- kv = {}
- parse_version_m4(kv, home_fn('version.m4'))
- parse_settings_in(kv, mod_fn('settings.in'))
-
- # config fixups
- kv['DDKVER'] = os.path.basename(kv['DDK_PATH'])
- kv['DDKVER_MAJOR'] = re.match(r'^(\d+)\.', kv['DDKVER']).groups()[0]
-
- if 'VERSION_SUFFIX' in kv:
- kv['PRODUCT_VERSION'] += kv['VERSION_SUFFIX']
-
- return kv
-
-def mod_fn(fn, src=__file__, real=True):
- p = os.path.join(os.path.dirname(src), os.path.normpath(fn))
- if real:
- p = os.path.realpath(p)
- return p
-
-def home_fn(fn, real=True):
- return mod_fn(os.path.join('..', fn), real=real)
-
-def cd_home():
- os.chdir(os.path.join(os.path.dirname(__file__), '..'))
-
-def system(cmd):
- print "RUN:", cmd
- os.system(cmd)
-
-def parse_version_m4(kv, version_m4):
- r = re.compile(r'^define\((\w+),\[(.*)\]\)$')
- f = open(version_m4)
- for line in f:
- line = line.rstrip()
- m = re.match(r, line)
- if m:
- g = m.groups()
- kv[g[0]] = g[1]
- f.close()
-
-def parse_settings_in(kv, settings_in):
- r = re.compile(r'^!define\s+(\w+)(?:\s+"?(.*?)"?)?$')
- f = open(settings_in)
- for line in f:
- line = line.rstrip()
- m = re.match(r, line)
- if m:
- g = m.groups()
- kv[g[0]] = g[1] or ''
- f.close()
-
-def dict_def(dict, newdefs):
- ret = dict.copy()
- ret.update(newdefs)
- return ret
-
-def build_autodefs(kv, autodefs_in, autodefs_out):
- preprocess(kv,
- in_fn=autodefs_in,
- out_fn=autodefs_out,
- quote_begin='@',
- quote_end='@',
- head_comment='/* %s */\n\n' % autogen)
-
-def preprocess(kv, in_fn, out_fn, quote_begin=None, quote_end=None, if_prefix=None, head_comment=None):
- def repfn(m):
- var, = m.groups()
- return kv.get(var, '')
-
- re_macro = re_ifdef = None
-
- if quote_begin and quote_end:
- re_macro = re.compile(r'%s(\w+)%s' % (re.escape(quote_begin), re.escape(quote_end)))
-
- if if_prefix:
- re_ifdef = re.compile(r'^\s*%sifdef\s+(\w+)\b' % (re.escape(if_prefix),))
- re_else = re.compile(r'^\s*%selse\b' % (re.escape(if_prefix),))
- re_endif = re.compile(r'^\s*%sendif\b' % (re.escape(if_prefix),))
-
- if_stack = []
- fin = open(in_fn)
- fout = open(out_fn, 'w')
- if head_comment:
- fout.write(head_comment)
- for line in fin:
- if re_ifdef:
- m = re.match(re_ifdef, line)
- if m:
- var, = m.groups()
- if_stack.append(int(var in kv))
- continue
- elif re.match(re_else, line):
- if_stack[-1] ^= 1
- continue
- elif re.match(re_endif, line):
- if_stack.pop()
- continue
- if not if_stack or min(if_stack):
- if re_macro:
- line = re.sub(re_macro, repfn, line)
- fout.write(line)
- assert not if_stack
- fin.close()
- fout.close()
-
-def print_key_values(kv):
- for k, v in sorted(kv.items()):
- print "%s%s%s" % (k, ' '*(32-len(k)), repr(v))
-
-def get_sources(makefile_am):
- c = set()
- h = set()
- f = open(makefile_am)
- state = False
- for line in f:
- line = line.rstrip()
- if line == 'openvpn_SOURCES = \\':
- state = True
- elif not line:
- state = False
- elif state:
- for sf in line.split():
- if sf.endswith('.c'):
- c.add(sf[:-2])
- elif sf.endswith('.h'):
- h.add(sf[:-2])
- elif sf == '\\':
- pass
- else:
- print >>sys.stderr, "Unrecognized filename:", sf
- f.close()
- return [ sorted(list(s)) for s in (c, h) ]
-
-def output_mak_list(title, srclist, ext):
- ret = "%s =" % (title,)
- for x in srclist:
- ret += " \\\n\t%s.%s" % (x, ext)
- ret += '\n\n'
- return ret
-
-def make_headers_objs(makefile_am):
- c, h = get_sources(makefile_am)
- ret = output_mak_list('HEADERS', h, 'h')
- ret += output_mak_list('OBJS', c, 'obj')
- return ret
-
-def choose_arch(arch_name):
- if arch_name == 'x64':
- return (True,)
- elif arch_name == 'x86':
- return (False,)
- elif arch_name == 'all':
- return (True, False)
- else:
- raise ValueError("architecture ('%s') must be x86, x64, or all" % (arch_name,))
-
-def rm_rf(dir):
- print "REMOVE", dir
- shutil.rmtree(dir, ignore_errors=True)
-
-def mkdir(dir):
- print "MKDIR", dir
- os.mkdir(dir)
-
-def cp_a(src, dest, dest_is_dir=True):
- if dest_is_dir:
- dest = os.path.join(dest, os.path.basename(src))
- print "COPY_DIR %s %s" % (src, dest)
- shutil.copytree(src, dest)
-
-def cp(src, dest, dest_is_dir=True):
- if dest_is_dir:
- dest = os.path.join(dest, os.path.basename(src))
- print "COPY %s %s" % (src, dest)
- shutil.copyfile(src, dest)
-
-def rm_rf(path):
- try:
- shutil.rmtree(path, onerror=onerror)
- except:
- pass
-
-def onerror(func, path, exc_info):
- """
- Error handler for ``shutil.rmtree``.
-
- If the error is due to an access error (read only file)
- it attempts to add write permission and then retries.
-
- If the error is for another reason it re-raises the error.
-
- Usage : ``shutil.rmtree(path, onerror=onerror)``
- """
- if not os.access(path, os.W_OK):
- # Is the error an access error ?
- os.chmod(path, stat.S_IWUSR)
- func(path)
- else:
- raise
-
-def mkdir_silent(dir):
- try:
- os.mkdir(dir)
- except:
- pass
-
-config = get_config()
+# Python module containing general build functions
+# for OpenVPN on Windows
+
+import os, re, shutil, stat
+
+autogen = "Automatically generated by OpenVPN Windows build system"
+
+def get_config():
+ kv = {}
+ parse_version_m4(kv, home_fn('version.m4'))
+ parse_settings_in(kv, mod_fn('settings.in'))
+
+ # config fixups
+ kv['DDKVER'] = os.path.basename(kv['DDK_PATH'])
+ kv['DDKVER_MAJOR'] = re.match(r'^(\d+)\.', kv['DDKVER']).groups()[0]
+
+ if 'VERSION_SUFFIX' in kv:
+ kv['PRODUCT_VERSION'] += kv['VERSION_SUFFIX']
+
+ return kv
+
+def get_build_params():
+ kv = {}
+ parse_build_params(kv,mod_fn('settings.in'))
+
+ return kv
+
+def mod_fn(fn, src=__file__, real=True):
+ p = os.path.join(os.path.dirname(src), os.path.normpath(fn))
+ if real:
+ p = os.path.realpath(p)
+ return p
+
+def home_fn(fn, real=True):
+ return mod_fn(os.path.join('..', fn), real=real)
+
+def cd_home():
+ os.chdir(os.path.join(os.path.dirname(__file__), '..'))
+
+def cd_service_win32():
+ os.chdir(os.path.join(os.path.dirname(__file__), '../service-win32'))
+
+def system(cmd):
+ print "RUN:", cmd
+ os.system(cmd)
+
+def run_in_vs_shell(cmd):
+ """Make sure environment variables are setup before running command"""
+ os.environ['PATH'] += ";%s\\VC" % (os.path.normpath(config['MSVC']),)
+ system('cmd /c "vcvarsall.bat x86 && %s"' % (cmd,))
+
+def parse_version_m4(kv, version_m4):
+ '''Parse define lines in version.m4'''
+ r = re.compile(r'^define\((\w+),\[(.*)\]\)$')
+ f = open(version_m4)
+ for line in f:
+ line = line.rstrip()
+ m = re.match(r, line)
+
+ if m:
+ g = m.groups()
+
+ # If we encounter PRODUCT_TAP_WIN32_MIN_MAJOR or
+ # PRODUCT_TAP_WIN32_MIN_MAJOR then we need to generate extra
+ # variables, PRODUCT_TAP_MAJOR_VER and PRODUCT_TAP_MINOR_VER with
+ # the same contents. This is necessary because tap-win32/tapdrv.c
+ # build depends on those.
+ if g[0] == 'PRODUCT_TAP_WIN32_MIN_MAJOR':
+ kv['PRODUCT_TAP_MAJOR_VER'] = g[1]
+ elif g[0] == 'PRODUCT_TAP_WIN32_MIN_MINOR':
+ kv['PRODUCT_TAP_MINOR_VER'] = g[1]
+
+ # Add the variable to build configuration
+ kv[g[0]] = g[1]
+ f.close()
+
+def parse_settings_in(kv, settings_in):
+ r = re.compile(r'^!define\s+(\w+)(?:\s+"?(.*?)"?)?$')
+ f = open(settings_in)
+ for line in f:
+ line = line.rstrip()
+ m = re.match(r, line)
+ if m:
+ g = m.groups()
+ kv[g[0]] = g[1] or ''
+ f.close()
+
+def parse_build_params(kv, settings_in):
+ r = re.compile(r'^!define\s+(ENABLE_\w+)\s+(\w+)')
+
+ f = open(settings_in)
+
+ for line in f:
+ line = line.rstrip()
+
+ # Check if this is a #define line starts with ENABLE_
+ m = re.match(r, line)
+
+ if m:
+ g = m.groups()
+ kv[g[0]] = g[1] or ''
+ f.close()
+
+def dict_def(dict, newdefs):
+ ret = dict.copy()
+ ret.update(newdefs)
+ return ret
+
+def build_autodefs(kv, autodefs_in, autodefs_out):
+ preprocess(kv,
+ in_fn=autodefs_in,
+ out_fn=autodefs_out,
+ quote_begin='@',
+ quote_end='@',
+ head_comment='/* %s */\n\n' % autogen)
+
+def build_config_h(kv):
+ """Generate static win/config.h to config.h to mimic autotools behavior"""
+ preprocess(kv,
+ in_fn=mod_fn('config.h.in'),
+ out_fn=home_fn('config.h'),
+ quote_begin='@',
+ quote_end='@',
+ head_comment='/* %s */\n\n' % autogen)
+
+def build_configure_h(kv, configure_h_out, head_comment):
+ """Generate a configure.h dynamically"""
+ fout = open(configure_h_out, 'w')
+
+ # These two variables are required to view build parameters during runtime
+ configure_defines='#define CONFIGURE_DEFINES \"'
+ configure_call='#define CONFIGURE_CALL \" config_all.py \"'
+
+ # Initialize the list of enabled features
+ features = ''
+
+ # Write the header
+ fout.write(head_comment)
+
+ dict = get_build_params()
+
+ for key, value in dict.iteritems():
+ # Add enabled features
+ features = features + "#define " + key + " " + value + "\n"
+
+ # Add each enabled feature to CONFIGURE_DEFINES list
+ configure_defines = configure_defines + " " + key + "=" + value + ","
+
+ configure_defines = configure_defines + "\"" + "\n"
+
+ fout.write(features)
+ fout.write(configure_defines)
+ fout.write(configure_call)
+
+
+ fout.close()
+
+def build_version_m4_vars(version_m4_vars_out, head_comment):
+ """Generate a temporary file containing variables from version.m4 in
+win/settings.in format. This done to allow importing them in win/openvpn.nsi"""
+
+ fout = open(version_m4_vars_out, 'w')
+ fout.write(head_comment)
+
+ kv = {}
+ parse_version_m4(kv, home_fn('version.m4'))
+
+ for key, value in kv.iteritems():
+ line = "!define " + key + "\t" + "\"" + value + "\"" + "\n"
+ fout.write(line)
+
+ fout.close()
+
+def preprocess(kv, in_fn, out_fn, quote_begin=None, quote_end=None, if_prefix=None, head_comment=None):
+ def repfn(m):
+ var, = m.groups()
+ return kv.get(var, '')
+
+ re_macro = re_ifdef = None
+
+ if quote_begin and quote_end:
+ re_macro = re.compile(r'%s(\w+)%s' % (re.escape(quote_begin), re.escape(quote_end)))
+
+ if if_prefix:
+ re_ifdef = re.compile(r'^\s*%sifdef\s+(\w+)\b' % (re.escape(if_prefix),))
+ re_else = re.compile(r'^\s*%selse\b' % (re.escape(if_prefix),))
+ re_endif = re.compile(r'^\s*%sendif\b' % (re.escape(if_prefix),))
+
+ if_stack = []
+ fin = open(in_fn)
+ fout = open(out_fn, 'w')
+ if head_comment:
+ fout.write(head_comment)
+ for line in fin:
+ if re_ifdef:
+ m = re.match(re_ifdef, line)
+ if m:
+ var, = m.groups()
+ if_stack.append(int(var in kv))
+ continue
+ elif re.match(re_else, line):
+ if_stack[-1] ^= 1
+ continue
+ elif re.match(re_endif, line):
+ if_stack.pop()
+ continue
+ if not if_stack or min(if_stack):
+ if re_macro:
+ line = re.sub(re_macro, repfn, line)
+ fout.write(line)
+ assert not if_stack
+ fin.close()
+ fout.close()
+
+def print_key_values(kv):
+ for k, v in sorted(kv.items()):
+ print "%s%s%s" % (k, ' '*(32-len(k)), repr(v))
+
+def get_sources(makefile_am):
+ """Parse ../Makefile.am to obtain a list of .h and .c files"""
+ c = set()
+ h = set()
+ f = open(makefile_am)
+ state = False
+ for line in f:
+ line = line.rstrip()
+ if line == 'openvpn_SOURCES = \\':
+ state = True
+ elif not line:
+ state = False
+ elif state:
+ for sf in line.split():
+ if sf.endswith('.c'):
+ c.add(sf[:-2])
+ elif sf.endswith('.h'):
+ h.add(sf[:-2])
+ elif sf == '\\':
+ pass
+ else:
+ print >>sys.stderr, "Unrecognized filename:", sf
+ f.close()
+ return [ sorted(list(s)) for s in (c, h) ]
+
+def output_mak_list(title, srclist, ext):
+ ret = "%s =" % (title,)
+ for x in srclist:
+ ret += " \\\n\t%s.%s" % (x, ext)
+ ret += '\n\n'
+ return ret
+
+def make_headers_objs(makefile_am):
+ """Generate HEADER and OBJS entries dynamically from ../Makefile.am"""
+ c, h = get_sources(makefile_am)
+ ret = output_mak_list('HEADERS', h, 'h')
+ ret += output_mak_list('OBJS', c, 'obj')
+ return ret
+
+def choose_arch(arch_name):
+ if arch_name == 'x64':
+ return (True,)
+ elif arch_name == 'x86':
+ return (False,)
+ elif arch_name == 'all':
+ return (True, False)
+ else:
+ raise ValueError("architecture ('%s') must be x86, x64, or all" % (arch_name,))
+
+def rm_rf(dir):
+ print "REMOVE", dir
+ shutil.rmtree(dir, ignore_errors=True)
+
+def mkdir(dir):
+ print "MKDIR", dir
+ os.mkdir(dir)
+
+def cp_a(src, dest, dest_is_dir=True):
+ if dest_is_dir:
+ dest = os.path.join(dest, os.path.basename(src))
+ print "COPY_DIR %s %s" % (src, dest)
+ shutil.copytree(src, dest)
+
+def cp(src, dest, dest_is_dir=True):
+ if dest_is_dir:
+ dest = os.path.join(dest, os.path.basename(src))
+ print "COPY %s %s" % (src, dest)
+ shutil.copyfile(src, dest)
+
+def rename(src, dest):
+ print "RENAME %s %s" % (src, dest)
+ shutil.move(src, dest)
+
+def rm_rf(path):
+ try:
+ shutil.rmtree(path, onerror=onerror)
+ except:
+ pass
+
+def onerror(func, path, exc_info):
+ """
+ Error handler for ``shutil.rmtree``.
+
+ If the error is due to an access error (read only file)
+ it attempts to add write permission and then retries.
+
+ If the error is for another reason it re-raises the error.
+
+ Usage : ``shutil.rmtree(path, onerror=onerror)``
+ """
+ if not os.access(path, os.W_OK):
+ # Is the error an access error ?
+ os.chmod(path, stat.S_IWUSR)
+ func(path)
+ else:
+ raise
+
+def mkdir_silent(dir):
+ try:
+ os.mkdir(dir)
+ except:
+ pass
+
+config = get_config()
diff --git a/win32.c b/win32.c
index 2a3350d..cf6cc2d 100644
--- a/win32.c
+++ b/win32.c
@@ -874,16 +874,21 @@ win_safe_filename (const char *fn)
static char *
env_block (const struct env_set *es)
{
+ char * force_path = "PATH=C:\\Windows\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem";
+
if (es)
{
struct env_item *e;
char *ret;
char *p;
size_t nchars = 1;
+ bool path_seen = false;
for (e = es->list; e != NULL; e = e->next)
nchars += strlen (e->string) + 1;
+ nchars += strlen(force_path)+1;
+
ret = (char *) malloc (nchars);
check_malloc_return (ret);
@@ -895,7 +900,18 @@ env_block (const struct env_set *es)
strcpy (p, e->string);
p += strlen (e->string) + 1;
}
+ if ( strncmp(e->string, "PATH=", 5 ) == 0 )
+ path_seen = true;
+ }
+
+ /* make sure PATH is set */
+ if ( !path_seen )
+ {
+ msg( M_INFO, "env_block: add %s", force_path );
+ strcpy( p, force_path );
+ p += strlen(force_path) + 1;
}
+
*p = '\0';
return ret;
}
@@ -952,6 +968,8 @@ int
openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags)
{
int ret = -1;
+ static bool exec_warn = false;
+
if (a && a->argv[0])
{
if (openvpn_execve_allowed (flags))
@@ -1002,9 +1020,10 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
ASSERT (0);
}
}
- else
+ else if (!exec_warn && (script_security < SSEC_SCRIPTS))
{
msg (M_WARN, SCRIPT_SECURITY_WARNING);
+ exec_warn = true;
}
}
else
@@ -1090,4 +1109,23 @@ env_set_add_win32 (struct env_set *es)
set_win_sys_path (DEFAULT_WIN_SYS_PATH, es);
}
+
+const char *
+win_get_tempdir()
+{
+ static char buf[MAX_PATH];
+ char *tmpdir = buf;
+
+ CLEAR(buf);
+
+ 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;
+ }
+ return tmpdir;
+}
#endif
diff --git a/win32.h b/win32.h
index fcc3062..d0ecc85 100644
--- a/win32.h
+++ b/win32.h
@@ -195,7 +195,10 @@ struct overlapped_io {
DWORD flags;
int status;
bool addr_defined;
- struct sockaddr_in addr;
+ union {
+ struct sockaddr_in addr;
+ struct sockaddr_in6 addr6;
+ };
int addrlen;
struct buffer buf_init;
struct buffer buf;
@@ -269,6 +272,11 @@ char *get_win_sys_path (void);
/* call self in a subprocess */
void fork_to_self (const char *cmdline);
+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
+int inet_pton(int af, const char *src, void *st);
+
+/* Find temporary directory */
+const char *win_get_tempdir();
#endif
#endif