diff options
159 files changed, 11024 insertions, 4301 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> @@ -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..283fe6e --- /dev/null +++ b/ChangeLog.IPv6 @@ -0,0 +1,440 @@ +Do 31. Dez 15:32:40 CET 2009 Gert Doering + + * Basic IPv6 p2mp functionality implemented + + * new options: + - server-ipv6 + - ifconfig-ipv6 + - ifconfig-ipv6-pool + - route-ipv6 + - iroute-ipv6 + + * modules touched: + - init.c: init & setup IPv6 route list & add/delete IPv6 routes + - tun.c: add "ifconfig" and "route" handling for IPv6 + - multi.c: IPv6 ifconfig-pool assignments + put to route-hash table + push to client + - pool.c: extend pools to handle IPv4+IPv6, and also return IPv6 address + IPv6 address saved to file if ifconfig-pool-persist is set + (but ignored on read due to the way pools work) + - mroute.c: handle reading src/dst addresses from IPv6 packets + (so multi.c can check against route-hash table) + handle printing of IPv6 mroute_addr structure + - helper.c: implement "server-ipv6" macro (->ifconfig-ipv6, pool, ...) + - options.c: implement all the new options + add helper functions for IPv6 address handling + - forward.c: tell do_route() about IPv6 routes + - route.c: handle IPv6 route lists + route option lists + extend add_routes() to do IPv4 + IPv6 route lists + extend delete_routes() to do IPv4 + IPv6 route lists + implement add_route_ipv6(), delete_route_ipv6() to call + system-dependend external program to do the work + - push.c: handle pushing of "ifconfig-ipv6" option + - socket.c: helper function to check & print IPv6 address strings + + * known issues: + - operating system support on all but Linux (ifconfig, route) + - route-ipv6 gateway handling + - iroute-ipv6 not implemented + - TAP support: ifconfig, routing (route needs gateway!) + + * release as patch 20091231-1 + +Thu Dec 31 17:02:08 CET 2009 + + * NetBSD port (NetBSD 3.1 on Sparc64) + + * mroute.c, socket.c: make byte/word access to in6_addr more portable + + * tun.c: fix IPv6 ifconfig arguments on NetBSD + + still doesn't work on NetBSD 3.1, "ifconfig tun0 inet6..." errors with + + ifconfig: SIOCAIFADDR: Address family not supported by protocol family + + (sys/net/if_tun.c, needs to be revision 1.80 or later, NetBSD PR 32944, + included in NetBSD 4.0 and up) + + +Fri Jan 1 14:07:15 CET 2010 + + * FreeBSD port (FreeBSD 6.3-p12 on i386) + + * tun.c: implement IPv6 ifconfig setting for FreeBSD + + * route.c: fix %s/%s argument to IPv6 route add/delete command for *BSD + + * TEST SUCCESS: FreeBSD 6.3-p12, server-ipv6, route-ipv6, ccd/iroute-ipv6 + + * multi.c: implement setting and deleting of iroute-ipv6 + (multi_add_iroutes(), multi_del_iroutes()) + * mroute.c: add mroute_helper_add_iroute6(), mroute_helper_del_iroute6() + * mroute.h: add prototypes, increase MR_HELPER_NET_LEN to 129 (/0.../128) + * multi.c: zeroize host part of IPv6 iroutes in multi_learn_in6_addr() + * mroute.c: implement mroute_addr_mask_host_bits() for IPv6 + + * TEST SUCCESS: Linux 2.6.30 (Gentoo)/iproute2, server-ipv6, ccd/iroute-ipv6 + + * TEST SUCCESS: Linux 2.6.30 (Gentoo)/ifconfig, client-ipv6 + + * TEST FAIL: NetBSD 5.0, IPv6 client + - "ifconfig tun0 .../64" does not create a "connected" route + - adding routes fails + + --> more work to do here. + + * release as patch 20100101-1 + + * TEST FAIL: + FreeBSD 6.3-p12 server "--topology subnet" + Linux/ifconfig client + - BSD sends ICMP6 neighbor solicitations, which are ignored by Linux + - server tun interface is not in p2p mode, client tun interface *is* + + * TEST SUCCESS: non-ipv6 enabled client -> "--server-ipv6" server + (warnings in the log file, but no malfunctions) + + +Sat Jan 2 19:48:35 CET 2010 + + * tun.c: change "ipv6_support()", do not turn off tt->ipv6 unconditionally + if we don't know about OS IPv6 support - just log warning + + * tun.c: implement "ifconfig inet6" setting for MacOS X / Darwin + + * route.c: split *BSD system dependent part of add/delete_route_ipv6() + into FreeBSD/Dragonfly and NetBSD/Darwin/OpenBSD variants + ("2001:db8::/64" vs. "2001:db8:: --prefixlen 64"). + + * tun.c: on MacOS X, NetBSD and OpenBSD, explicitely set on-link route + + * TEST SUCCESS: MacOS X, client-ipv6 with route-ipv6 + + +Sun Jan 3 10:55:31 CET 2010 + + * route.c: NetBSD fails with "-iface tun0", needs gateway address + (assume that the same syntax is needed for OpenBSD) + + * route.h: introduce "remote_endpoint_ipv6" into "struct route_ipv6_list" + + * init.c: pass "ifconfig_ipv6_remote" as gateway to init_route_ipv6_list() + + * route.c: + - init_route_ipv6(): use "remote_endpoint_ipv6" as IPv6 gateway address + if no gateway was specified explicitely + + - init_route_ipv6_list(): fill in "remote_endpoint_ipv6", if parseable + + - get rid of "GATEWAY-LESS ROUTE6" warning + + * route.c, add_route_ipv6() + - explicitely clear host bits of base address, to be able to more + easily set up "connected" /64 routes on NetBSD+Darwin + + - split system-dependent part between Darwin and NetBSD/OpenBSD + (Darwin can use "-iface tun0", NetBSD/OpenBSD get gateway address) + + - change Solaris comments from "known-broken" to "unknown" + + * tun.c: rework NetBSD tunnel initialization and tun_read() / tun_write() + to work the same way OpenBSD and NetBSD do - tunnel is put into + "multi-af" mode, and all packet read/write activity is prepended by + a 32 bit value specifying the address family. + + * TEST SUCCESS: NetBSD 5.0/Sparc64: client-ipv6 with route-ipv6 + + * TEST SUCCESS: MacOS X 10.5: client-ipv6 with route-ipv6 + + * (RE-)TEST SUCCESS: Linux/iproute2: server-ipv6 + Linux/ifconfig: client-ipv6 + FreeBSD 6.3: server-ipv6 + + * release as patch 20100103-1 + + * options.c: document all new options in "--help" + + * tun.c: fix typo in Solaris-specific section + + * socket.h, socket.c: change u_int32_t to uint32_t + (Solaris - and all the rest of the code uses "uintNN" anyway) + +Mon Jan 4 17:46:58 CET 2010 + + * socket.c: rework add_in6_addr() to use 32-bit access to struct in6_addr + (Solaris has no 16-bit values in union, but this is more elegant as well) + + * tun.c: fix "ifconfig inet6" command for Solaris + + * tun.c: make sure "tun0 inet6" is unplumbed first, cleanup leftovers + + * route.c: add routes with "metric 0" on solaris, otherwise they just + don't work (someone who understands Solaris might want to fix this). + + * Solaris "sort of" works now - ifconfig works, route add does not give + errors, "netstat -rn" looks right, but packets are discarded unless + the routes are installed with "metric 0". So we just use "metric 0"... + + * CAVEAT: Solaris "ifconfig ... preferred" interferes with source address + selection. So if there are any active IPv6 interfaces configured with + "preferred", packets leaving out the tunnel will use the wrong source + IPv6 address. Not fixable from within OpenVPN. + + * CAVEAT2: Solaris insists on doing DHCPv6 on tun0 interfaces by default, + so DHCPv6 solicitation packets will be seen. Since the server end has + no idea what to do with them, they are a harmless nuisance. Fixable + on the Solaris side via "ndpd.conf" (see ``man ifconfig''). + + * release as patch 20100104-1 + +Fri Jan 8 10:00:50 CET 2010 + + * import into git repository + + * options.c: add sanity checks for most typical error cases + (--ifconfig-ipv6-pool configured with no --ifconfig-ipv6, etc) + + * options.c: modify get_ipv6_addr() to be more flexible about netbits + (optional now, default to /64) and to return the address-without-netbits + string now (-> for options that want the IPv6 address in printable + form, but without /nn) + + * options.c: modify --ifconfig-ipv6 to optionally accept /netbits, + you can do now "ifconfig-ipv6 2001:df8::1/64 2001:df8::2" or just + "ifconfig-ipv6 2001:df8::5 2001:df8::7", defaulting to /64 + + * options.h: add necessary structure elements for --ifconfig-ipv6-push + + * options.c: implement "parse options" side of --ifconfig-ipv6-push + +Tue Jan 12 22:42:09 CET 2010 + + * tun.c: in TARGET_NETBSD #ifdef, distinguish between "old" code + (IPv4 only, but unmodified read/write) and "new" code (multi-af, + extra 32 bit AF on read/write of the tun interface) - pre-4.0 + NetBSD systems don't have TUNSIFHEAD, no way to have common code. + + * TEST SUCCESS: NetBSD 5.0/Sparc64: client-ipv6 with route-ipv6 (v4+v6) + + * TEST SUCCESS: NetBSD 3.1/Sparc64: client-ipv6 with route-ipv6 (v4-only) + +Thu Jan 14 15:41:50 CET 2010 + + * multi.c: if "--ifconfig-push" is used together with "--ifconfig-ipv6-pool" + and no "--ifconfig-ipv6-push" is seen, issue warning - the current + implementation of pools has IPv6 tied to IPv4, so if v4 does not use + the pool, it breaks for IPv6. Not a *big* problem (since there is + enough v6, just give those users a static v6 address as well), but needs + to be pointed out clearly. + + * release as patch 20100114-1 + +Tue Feb 16 14:43:28 CET 2010 + + * options.c: print "IPv6 payload patch" release date in "--version" + + * tun.c: undo change to init_tun() (moving "bool tun" and call to + "is_tun_p2p()" further up) - it wasn't needed and breaks "make check" + + * git stuff: rebase on David Sommerseth's openvpn-testing git tree + + * release as patch 20100216-1 + +Fri Feb 26 19:59:01 CET 2010 + + * init.c: initialize tuntap->ipv6 in do_init_tun() (to make sure it's + always initialized early-enough, independent of the sequence of + do_ifconfig()/open_tun() [see ifconfig_order() in tun.h]) + + * tun.c, init.c: remove "bool ipv6" argument to tuncfg(), open_tun() + and open_tun_generic() - obsoleted by previous change + + * tun.c: remove ipv6_support() - original purpose was unclear, and all + current platforms (except linux-very-old) fully support IPv6 now :-) + + * tun.c: initial implementation of "netsh" IPv6-ifconfig for Win32 + + * RE-TEST SUCCESS: Linux/i386/ifconfig, client-tun/net30, v4+v6 + +Sun Feb 28 17:05:57 CET 2010 + + * tun.c: NetBSD dependent part: correct destroying/re-creation of tun dev + + * tun.c: move adding of "connected" IPv6 prefix to new helper function, + add_route_connected_v6_net() + + * RE-TEST SUCCESS: NetBSD 5.0/Sparc64, client-tun/net30, v4+v6 + + * RE-TEST SUCCESS: NetBSD 3.1/Sparc64: client-tun/net30, v4-only + + * RE-TEST SUCCESS: Linux/i386/iproute2: server-tun/net30, v4+v6 + + * tun.c: add #ifdef TARGET_DARWIN block for *_tun() functions, to + be able to modify close_tun() for unconfiguring IPv6 + + * tun.c: on close_tun() on MacOS X, need to de-configure "lo0" route for + configured IPv6 address + + * RE-TEST SUCCESS: MacOS X (10.5)/i386: client-tun/net30, v4+v6 + + * route.c: implement ipv6 route adding / deletion via "netsh" for WIN32 + + * TEST FAIL: Windows XP fails, because the tun/tap driver does not + forward IPv6 frames kernel->userland if in "tun" mode + + * options.c: set IPv6 version to 20100228-1 + + * release as patch 20100228-1 + +Sun Mar 7 19:17:33 CET 2010 + + * options.c: set IPv6 version to 20100307-1 + + * TODO.IPv6: add note about OpenBSD TODO (#16) + + * route.c: set (and remove) "magic next hop" fe80::8 for IPv6 routes on + Win32 + + * install-win32/settings.in: bump TAP driver version from 9.6 to 9.7 + and TAP_RELDATE to "07/03/2010" + + * tap-win32/proto.h: add data types and definitions needed for IPv6 + + * tap-win32/types.h: add m_UserToTap_IPv6 ethernet header for IPv6 packets + + * tap-win32/tapdrvr.c: implement support for IPv6 in TUN mode: + - IPv6 packets User->OS need correct ether type + - IPv6 packets OS->User get correctly forwarded + - IPv6 neighbour discovery packets for "fe80::8" (magic address + installed as route-nexthop by OpenVPN.exe) get answered locally + + * TEST SUCCESS: WindowsXP/32bit: client-tun/net30, v4+v6 + + * tun.c: if IPv6 requested in TUN mode, and TUN/TAP driver version + is older than 9.7, log warning and disable IPv6 (won't work anyway). + + * release as patch 20100307-1 + +Sat Jul 10 14:37:52 CEST 2010 + + * TEST SUCCESS: point-to-point tun mode with --ifconfig-ipv6 between + Solaris10/sparc and Linux (Michal Ludvig) + (using the whiteboard tun driver on Solaris, otherwise "no IPv6") + +Sun Aug 8 12:30:44 CEST 2010 + + * route.c: split NetBSD and OpenBSD parts of add_route_ipv6() and + delete_route_ipv6(), implement OpenBSD variant + (needs "-prefixlen nn" while NetBSD uses "/nn") + + * tun.c: implement IPv6 ifconfig for OpenBSD + + * tun.c: destroy tunX interface at tun_close() on OpenBSD (cleanup) + + * TEST SUCCESS: OpenBSD 4.7: client-tun/net30, v4+v6 + +Thu Sep 2 21:18:32 CEST 2010 + + * tun.c: the TAP binary in 2.2-beta3 has the IPv6 related changes, but + the version number is 9.8 now -> check for 9.8, not 9.7 + +Wed Sep 22 22:20:37 CEST 2010 + + * tun.c: bugfix for Linux/iproute2/"topology subnet". Works :-) + + * TEST SUCCESS: Linux/ifconfig: client-tun/net30+subnet, v4+v6 + + * TEST SUCCESS: Linux/iproute2: client-tun/net30+subnet, v4+v6 + + * options.c: tag as 20100922-1 so "allmerged" users can see IPv6 change + +Fri Sep 24 17:57:41 CEST 2010 + + * TEST SUCCESS: Linux/<both>: client-tap, v4+v6, ping6 on connected addr + + * TEST FAIL: Linux/<both>: client-tap, v6, route6 (gateway missing) + +Do 21. Okt 19:36:49 CEST 2010 + + * t_client.sh.in: cherrypick commit f25fe91a40aa3f and 6f1e61b41be52 + (proper exit codes to signal "SKIP" if we do not want to run) + +So 16. Jan 17:25:23 CET 2011 + + * tun.c, route.c: cherrypick 121755c2cb4891f and f0eac1a5979096c67 + (TAP driver and "topology subnet" support for Solaris) + + * tun.c: add IPv6 configuration for TAP interfaces (<device>:1 inet6) + + * tun.c: on close_tun on Solaris, unplumb IPv6 TUN or TAP interfaces + + * TEST SUCCESS: OpenSolaris: client-tun, v4+v6 + TEST SUCCESS: OpenSolaris: client-tap, v4+v6, ping6 on connected addr + TEST FAIL: OpenSolaris: client-tap, v6, route6 (gateway missing) + +So 24. Apr 16:51:45 CEST 2011 + + * rebase to "beta2.2" branch (at 2.2RC2 tag) + + * mroute.c: remove mroute_helper_lock/_unlock() calls for IPv6 + * socket.c: remove locking with L_INET_NTOA mutex + (all the threading stuff got removed by David Sommerseth for 2.2) + + * mroute.c: remove duplicate mroute_helper_add_iroute6() and + mroute_helper_del_iroute6() - "git rebase" artefact + + * ChangeLog.IPv6 and TODO.IPv6: add to commit + + * options.c: tag as 20110424-2 (2.2RC2) + + * TEST SUCCESS: Linux/ifconfig: client-tun/net30+subnet, v4+v6 + + * TEST SUCCESS: Linux/iproute2: client-tun/net30+subnet, v4+v6 + +Thu Apr 28 19:10:01 CEST 2011 + + * rebase to "origin/release/2.2" branch (at v2.2.0 tag) + +Thu May 19 20:51:12 CEST 2011 + + * include Windows "netsh add" -> "netsh set ... store=active" patch from + Seth Mos, to fix restart problems on Windows due to persistant addresses + + * TEST SUCCESS: Windows XP SP3: client-tun/net30, v4+v6 + +Sat May 21 17:03:20 CEST 2011 + + * tun.c: Solaris cleanup (use CLEAR() to zero-out "ifr") + + * tun.c: Windows cleanup: remove route and IPv6 address on disconnect + + * route.c, route.h: remove "static" from delete_route_ipv6(), needed + for ipv6-route cleanup on disconnect + + * TEST SUCCESS: Windows XP SP3: client-tun/net30, v4+v6 + + * TEST SUCCESS: Windows 7 Home Premium: client-tun/net30, v4+v6 + +So 22. Mai 14:46:12 CEST 2011 + + * Tony Lim: removing routes fails on windows if certain bits are set + in the "host part" (others are silently ignored) --> + + * route.c: create print_in6_addr_netbits_only() helper, call from + add_route_ipv6() and delete_route_ipv6() to get only network part + of route-to-be-modified + + * route.c: set 'store=active' on adding routes on WIN32 as well (Tony Lim) + + * options.c: bump IPv6 release to 20110522-1 + + * TEST SUCCESS: Linux/iproute2: client-tun/net30+subnet, v4+v6 + + * TEST SUCCESS: Windows XP SP3: client-tun/net30, v4+v6 + + * TEST SUCCESS: Windows 7 Home Premium: client-tun/net30, v4+v6 + + * TEST SUCCESS: OpenBSD 4.7: client-tun/net30, v4+v6 + TEST FAIL: OpenBSD 4.7: client-tun/subnet, v4 + (seems to be due to "topology subnet has just not been implemented yet") @@ -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 @@ -41,7 +41,6 @@ static char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - /* * base64 encode input data of length size to malloced * buffer which is returned as *str. Returns string @@ -120,7 +119,6 @@ token_decode(const char *token) return DECODE_ERROR; return (marker << 24) | val; } - /* * Decode base64 str, outputting data to buffer * at data of length size. Return length of @@ -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) { @@ -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, ...) @@ -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 @@ -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/Makefile b/easy-rsa/2.0/Makefile index 125ac51..8000cc5 100644 --- a/easy-rsa/2.0/Makefile +++ b/easy-rsa/2.0/Makefile @@ -10,4 +10,4 @@ install: install -d "${DESTDIR}/${PREFIX}" install -m 0755 build-* "${DESTDIR}/${PREFIX}" install -m 0755 clean-all list-crl inherit-inter pkitool revoke-full sign-req whichopensslcnf "${DESTDIR}/${PREFIX}" - install -m 0644 openssl-0.9.6.cnf openssl.cnf README vars "${DESTDIR}/${PREFIX}" + install -m 0644 openssl-0.9.6.cnf openssl-0.9.8.cnf openssl-1.0.0.cnf README vars "${DESTDIR}/${PREFIX}" diff --git a/easy-rsa/2.0/README b/easy-rsa/2.0/README index bde0d8c..6f5395c 100644 --- a/easy-rsa/2.0/README +++ b/easy-rsa/2.0/README @@ -74,8 +74,8 @@ Release Notes for easy-rsa-2.0 INSTALL easy-rsa 1. Edit vars. -2. Set KEY_CONFIG to point to the openssl.cnf file - included in this distribution. +2. Set KEY_CONFIG to point to the correct openssl-<version>.cnf + file included in this distribution. 3. Set KEY_DIR to point to a directory which will contain all keys, certificates, etc. This directory need not exist, and if it does, 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/openssl.cnf b/easy-rsa/2.0/openssl-0.9.8.cnf index 3e4d3b3..340b8af 100755 --- a/easy-rsa/2.0/openssl.cnf +++ b/easy-rsa/2.0/openssl-0.9.8.cnf @@ -20,7 +20,7 @@ engines = engine_section # To use this configuration file with the "-extfile" option of the # "openssl x509" utility, name here the section containing the # X.509v3 extensions to use: -# extensions = +# extensions = # (Alternatively, use a configuration file that has only # X.509v3 extensions in its main [= default] section.) @@ -102,7 +102,7 @@ x509_extensions = v3_ca # The extentions to add to the self signed cert # input_password = secret # output_password = secret -# This sets a mask for permitted string types. There are several options. +# This sets a mask for permitted string types. There are several options. # default: PrintableString, T61String, BMPString. # pkix : PrintableString, BMPString. # utf8only: only UTF8Strings. @@ -288,4 +288,3 @@ dynamic_path = /usr/lib/engines/engine_pkcs11.so MODULE_PATH = $ENV::PKCS11_MODULE_PATH PIN = $ENV::PKCS11_PIN init = 0 - diff --git a/easy-rsa/2.0/openssl-1.0.0.cnf b/easy-rsa/2.0/openssl-1.0.0.cnf new file mode 100755 index 0000000..fa258a5 --- /dev/null +++ b/easy-rsa/2.0/openssl-1.0.0.cnf @@ -0,0 +1,285 @@ +# For use with easy-rsa version 2.0 and OpenSSL 1.0.0* + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd +openssl_conf = openssl_init + +[ openssl_init ] +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids +engines = engine_section + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = $ENV::KEY_DIR # Where everything is kept +certs = $dir # Where the issued certs are kept +crl_dir = $dir # Where the issued crl are kept +database = $dir/index.txt # database index file. +new_certs_dir = $dir # default place for new certs. + +certificate = $dir/ca.crt # The CA certificate +serial = $dir/serial # The current serial number +crl = $dir/crl.pem # The current CRL +private_key = $dir/ca.key # The private key +RANDFILE = $dir/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 3650 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = md5 # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_anything + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +name = optional +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +name = optional +emailAddress = optional + +#################################################################### +[ req ] +default_bits = $ENV::KEY_SIZE +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation after 2004). +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +string_mask = nombstr + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = $ENV::KEY_COUNTRY +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = $ENV::KEY_PROVINCE + +localityName = Locality Name (eg, city) +localityName_default = $ENV::KEY_CITY + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = $ENV::KEY_ORG + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (eg, your name or your server\'s hostname) +commonName_max = 64 + +name = Name +name_max = 64 + +emailAddress = Email Address +emailAddress_default = $ENV::KEY_EMAIL +emailAddress_max = 40 + +# JY -- added for batch mode +organizationalUnitName_default = $ENV::KEY_OU +commonName_default = $ENV::KEY_CN +name_default = $ENV::KEY_NAME + + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "Easy-RSA Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always +extendedKeyUsage=clientAuth +keyUsage = digitalSignature + + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ server ] + +# JY ADDED -- Make a cert with nsCertType set to "server" +basicConstraints=CA:FALSE +nsCertType = server +nsComment = "Easy-RSA Generated Server Certificate" +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always +extendedKeyUsage=serverAuth +keyUsage = digitalSignature, keyEncipherment + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ engine_section ] +# +# If you are using PKCS#11 +# Install engine_pkcs11 of opensc (www.opensc.org) +# And uncomment the following +# verify that dynamic_path points to the correct location +# +#pkcs11 = pkcs11_section + +[ pkcs11_section ] +engine_id = pkcs11 +dynamic_path = /usr/lib/engines/engine_pkcs11.so +MODULE_PATH = $ENV::PKCS11_MODULE_PATH +PIN = $ENV::PKCS11_PIN +init = 0 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/2.0/vars b/easy-rsa/2.0/vars index cded885..2ea1ced 100755 --- a/easy-rsa/2.0/vars +++ b/easy-rsa/2.0/vars @@ -66,3 +66,9 @@ export KEY_PROVINCE="CA" export KEY_CITY="SanFrancisco" export KEY_ORG="Fort-Funston" export KEY_EMAIL="me@myhost.mydomain" +export KEY_EMAIL=mail@host.domain +export KEY_CN=changeme +export KEY_NAME=changeme +export KEY_OU=changeme +export PKCS11_MODULE_PATH=changeme +export PKCS11_PIN=1234 diff --git a/easy-rsa/2.0/whichopensslcnf b/easy-rsa/2.0/whichopensslcnf index 2260aa8..2226a8e 100755 --- a/easy-rsa/2.0/whichopensslcnf +++ b/easy-rsa/2.0/whichopensslcnf @@ -1,13 +1,26 @@ #!/bin/sh +cnf="$1/openssl.cnf" + if [ "$OPENSSL" ]; then - if $OPENSSL version | grep 0.9.6 > /dev/null; then - echo "$1/openssl-0.9.6.cnf" + if $OPENSSL version | grep -E "0\.9\.6[[:alnum:]]" > /dev/null; then + cnf="$1/openssl-0.9.6.cnf" + elif $OPENSSL version | grep -E "0\.9\.8[[:alnum:]]" > /dev/null; then + cnf="$1/openssl-0.9.8.cnf" + elif $OPENSSL version | grep -E "1\.0\.([[:digit:]][[:alnum:]])" > /dev/null; then + cnf="$1/openssl-1.0.0.cnf" else - echo "$1/openssl.cnf" + cnf="$1/openssl.cnf" fi -else - echo "$1/openssl.cnf" +fi + +echo $cnf + +if [ ! -r $cnf ]; then + echo "**************************************************************" >&2 + echo " No $cnf file could be found" >&2 + echo " Further invocations will fail" >&2 + echo "**************************************************************" >&2 fi exit 0 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/easy-rsa/Windows/init-config.bat b/easy-rsa/Windows/init-config.bat index 048d558..12e6d78 100755 --- a/easy-rsa/Windows/init-config.bat +++ b/easy-rsa/Windows/init-config.bat @@ -1,2 +1 @@ copy vars.bat.sample vars.bat -copy openssl.cnf.sample openssl.cnf diff --git a/easy-rsa/Windows/vars.bat.sample b/easy-rsa/Windows/vars.bat.sample index 3c4b607..36e6f71 100644 --- a/easy-rsa/Windows/vars.bat.sample +++ b/easy-rsa/Windows/vars.bat.sample @@ -4,7 +4,7 @@ rem the openssl.cnf file included rem with easy-rsa. set HOME=%ProgramFiles%\OpenVPN\easy-rsa -set KEY_CONFIG=openssl.cnf +set KEY_CONFIG=openssl-1.0.0.cnf rem Edit this variable to point to rem your soon-to-be-created key @@ -33,3 +33,8 @@ set KEY_PROVINCE=CA set KEY_CITY=SanFrancisco set KEY_ORG=OpenVPN set KEY_EMAIL=mail@host.domain +set KEY_CN=changeme +set KEY_NAME=changeme +set KEY_OU=changeme +set PKCS11_MODULE_PATH=changeme +set PKCS11_PIN=1234 @@ -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. */ @@ -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; } @@ -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 { @@ -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 @@ -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 */ @@ -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; @@ -509,6 +509,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) @@ -718,7 +719,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"); @@ -820,8 +821,6 @@ init_static (void) void uninit_static (void) { - openvpn_thread_cleanup (); - #ifdef USE_CRYPTO free_ssl_lib (); #endif @@ -947,7 +946,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); @@ -1170,6 +1169,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); } @@ -1212,6 +1213,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. */ @@ -1254,7 +1294,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, @@ -1275,13 +1320,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_did_redirect_default_gateway(route_list)); } #ifdef ENABLE_MANAGEMENT @@ -1291,7 +1337,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"); } @@ -1300,7 +1346,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); } @@ -1344,11 +1390,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); @@ -1380,6 +1431,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 @@ -1396,7 +1449,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) @@ -1414,6 +1467,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), @@ -1425,7 +1479,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? @@ -1449,6 +1504,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), @@ -1502,8 +1558,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) @@ -1515,6 +1572,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), @@ -1537,6 +1595,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), @@ -1678,7 +1737,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; @@ -1773,13 +1832,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; } @@ -2141,6 +2209,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; @@ -2933,7 +3002,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 { @@ -3206,23 +3275,17 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int goto sig; } - /* should we disable paging? */ - if (c->first_time && options->mlock) - do_mlockall (true); - -#if P2MP - /* get passwords if undefined */ - if (auth_retry_get () == AR_INTERACT) - init_query_passwords (c); -#endif - /* map in current connection entry */ next_connection_entry (c); /* link_socket_mode allows CM_CHILD_TCP instances to inherit acceptable fds from a top-level parent */ - if (c->options.ce.proto == PROTO_TCPv4_SERVER) + 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; @@ -3230,6 +3293,16 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int link_socket_mode = LS_MODE_TCP_ACCEPT_FROM; } + /* should we disable paging? */ + if (c->first_time && options->mlock) + do_mlockall (true); + +#if P2MP + /* get passwords if undefined */ + if (auth_retry_get () == AR_INTERACT) + init_query_passwords (c); +#endif + /* initialize context level 2 --verb/--mute parms */ init_verb_mute (c, IVM_LEVEL_2); @@ -3487,17 +3560,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 (); @@ -3603,7 +3667,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); } @@ -3632,23 +3696,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. @@ -3658,50 +3705,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; } @@ -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/Makefile.am b/install-win32/Makefile.am index 7211de2..75932fe 100644 --- a/install-win32/Makefile.am +++ b/install-win32/Makefile.am @@ -57,7 +57,7 @@ nodist_doc_DATA = tmp/license.txt confdir = $(win32datadir)/config nodist_conf_DATA = \ - tmp/openssl.cnf.sample \ + tmp/openssl-1.0.0.cnf \ tmp/client.ovpn \ tmp/server.ovpn dist_conf_DATA = \ @@ -83,8 +83,8 @@ tmp/server.ovpn: tmp $(top_srcdir)/sample-config-files/server.conf tmp/license.txt: tmp $(top_srcdir)/COPYING $(top_srcdir)/COPYRIGHT.GPL cat $(top_srcdir)/COPYING $(top_srcdir)/COPYRIGHT.GPL > tmp/license.txt -tmp/openssl.cnf.sample: tmp $(top_srcdir)/easy-rsa/2.0/openssl.cnf - cp $(top_srcdir)/easy-rsa/2.0/openssl.cnf tmp/openssl.cnf.sample +tmp/openssl-1.0.0.cnf: tmp $(top_srcdir)/easy-rsa/2.0/openssl-1.0.0.cnf + cp $(top_srcdir)/easy-rsa/2.0/openssl-1.0.0.cnf tmp/openssl-1.0.0.cnf clean-local: -rm -fr tmp 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/install-win32/openvpn.nsi b/install-win32/openvpn.nsi index b6e4a07..f06c5aa 100755 --- a/install-win32/openvpn.nsi +++ b/install-win32/openvpn.nsi @@ -333,7 +333,7 @@ Section "${PRODUCT_NAME} RSA Certificate Management Scripts" SecOpenVPNEasyRSA SetOverwrite on SetOutPath "$INSTDIR\easy-rsa" - File "${GEN}\easy-rsa\openssl.cnf.sample" + File "${GEN}\easy-rsa\openssl-1.0.0.cnf" File "${GEN}\easy-rsa\vars.bat.sample" File "${GEN}\easy-rsa\init-config.bat" @@ -850,7 +850,7 @@ Section "Uninstall" Delete "$INSTDIR\license.txt" Delete "$INSTDIR\Uninstall.exe" - Delete "$INSTDIR\easy-rsa\openssl.cnf.sample" + Delete "$INSTDIR\easy-rsa\openssl-1.0.0.cnf" Delete "$INSTDIR\easy-rsa\vars.bat.sample" Delete "$INSTDIR\easy-rsa\init-config.bat" Delete "$INSTDIR\easy-rsa\README.txt" @@ -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; } @@ -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; } @@ -2029,9 +2029,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 @@ -2043,7 +2043,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); } } @@ -2529,7 +2529,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/management/management-notes.txt b/management/management-notes.txt index 90643ea..785eb88 100644 --- a/management/management-notes.txt +++ b/management/management-notes.txt @@ -687,7 +687,7 @@ the 10.0.0.0/8 netblock is allowed: 10.10.0.1. Also, the client may not interact with external IP addresses using an "unknown" protocol (i.e. one that is not IPv4 or ARP). -COMMAND -- remote (OpenVPN 2.1.5 or higher) +COMMAND -- remote (OpenVPN AS 2.1.5/OpenVPN 2.3 or higher) -------------------------------------------- Provide remote host/port in response to a >REMOTE notification @@ -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); } } @@ -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); @@ -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; } /* @@ -1678,14 +1694,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; } } @@ -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); @@ -357,6 +367,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 */ @@ -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); } @@ -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) $< +<< @@ -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 @@ -264,7 +261,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"); @@ -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)) { @@ -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 @@ -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); } } @@ -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..24aa36c 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 * @@ -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,12 @@ InternetQueryOption API. This option exists in OpenVPN 2.1 or higher. .\"********************************************************* .TP -.B --http-proxy server port [authfile|'auto'|'auto-nct'] [auth-method] +.B \-\-show-proxy-settings +Show sensed HTTP or SOCKS proxy settings. Currently, only Windows clients +support this option. +.\"********************************************************* +.TP +.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 +534,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 +567,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 +584,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 +604,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 +622,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 +661,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 +713,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 +723,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 +786,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 +815,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 +847,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 +861,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 +882,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 +925,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 +939,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 +967,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 +1006,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 +1021,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 +1039,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 +1060,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 +1079,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 +1108,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... Automatically execute routing commands to cause all outgoing IP traffic to be redirected over the VPN. This is a client-side option. @@ -1100,7 +1121,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 +1132,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,52 +1144,58 @@ that the original default route is restored. Option flags: -.B local -- +.B local \-\- Add the .B local -flag if both OpenVPN nodes are directly connected via a common subnet, +flag if both OpenVPN servers are directly connected via a common subnet, such as with wireless. The .B local flag will cause step .B 1 above to be omitted. -.B autolocal -- +.B autolocal \-\- Try to automatically determine whether to enable .B local flag above. -.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 on non-Windows clients). -.B block-local -- +.B block-local \-\- Block access to local LAN when the tunnel is active, except for the LAN gateway itself. This is accomplished by routing the local LAN (except for the LAN gateway address) into the tunnel. .\"********************************************************* .TP -.B --link-mtu n +.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 \-\-redirect-private [flags] +Like \-\-redirect-gateway, but omit actually changing the default +gateway. Useful when pushing private subnets. +.\"********************************************************* +.TP +.B \-\-tun-mtu n Take the TUN device MTU to be .B n and derive the link MTU @@ -1184,17 +1211,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. @@ -1202,34 +1229,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 @@ -1239,24 +1266,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 @@ -1269,44 +1296,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. @@ -1315,35 +1343,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 @@ -1360,12 +1388,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. @@ -1401,32 +1429,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. @@ -1439,33 +1477,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 @@ -1484,13 +1522,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. @@ -1499,14 +1537,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 @@ -1516,27 +1554,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 @@ -1555,24 +1593,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 @@ -1582,14 +1620,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. @@ -1602,29 +1640,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 @@ -1636,33 +1674,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 ] @@ -1687,62 +1725,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. @@ -1751,50 +1789,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 @@ -1807,7 +1845,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. @@ -1818,23 +1856,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 @@ -1843,33 +1881,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. @@ -1891,7 +1929,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 @@ -1899,16 +1937,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 @@ -1920,16 +1958,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 @@ -1948,22 +1986,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 @@ -1975,13 +2013,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), @@ -1990,10 +2028,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. @@ -2009,7 +2047,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 @@ -2019,20 +2057,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. @@ -2043,7 +2081,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 @@ -2055,16 +2093,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 @@ -2074,7 +2112,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 @@ -2085,44 +2123,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 @@ -2131,14 +2169,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 @@ -2148,12 +2186,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 @@ -2164,13 +2202,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 @@ -2179,13 +2217,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. @@ -2194,7 +2232,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 @@ -2205,20 +2243,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 @@ -2226,12 +2264,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 @@ -2243,21 +2281,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). @@ -2267,16 +2305,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: @@ -2295,12 +2333,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 @@ -2312,7 +2350,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. @@ -2331,9 +2369,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 @@ -2360,32 +2398,39 @@ 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-query-remote +.B \-\-management-query-remote Allow management interface to override -.B --remote +.B \-\-remote directives (client-only). .\"********************************************************* .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 @@ -2393,50 +2438,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 @@ -2472,7 +2517,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 @@ -2482,7 +2527,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 @@ -2492,7 +2537,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 @@ -2522,23 +2567,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 @@ -2566,7 +2611,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 @@ -2598,7 +2643,7 @@ push "route-gateway 10.8.0.4" .fi In another example, -.B --server-bridge +.B \-\-server-bridge (without parameters) expands as follows: .nf @@ -2613,7 +2658,7 @@ push "route-gateway dhcp" .fi Or -.B --server-bridge nogw +.B \-\-server-bridge nogw expands as follows: .nf @@ -2626,13 +2671,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 @@ -2643,44 +2688,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 @@ -2693,7 +2738,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, @@ -2708,7 +2753,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 @@ -2729,32 +2774,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 @@ -2776,13 +2821,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 @@ -2792,23 +2837,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 @@ -2819,36 +2864,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. @@ -2857,11 +2902,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. @@ -2873,20 +2918,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. @@ -2895,7 +2940,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. @@ -2907,18 +2952,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, @@ -2927,7 +2972,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 @@ -2937,13 +2982,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 @@ -2952,28 +2999,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 @@ -2981,13 +3045,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 @@ -2999,7 +3063,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 @@ -3022,13 +3086,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). @@ -3038,9 +3102,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 @@ -3048,7 +3112,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 @@ -3062,12 +3126,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. @@ -3075,19 +3139,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". @@ -3107,7 +3171,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. @@ -3138,10 +3202,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. @@ -3173,7 +3237,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. @@ -3183,16 +3247,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 @@ -3205,35 +3269,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. @@ -3254,7 +3318,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 @@ -3279,13 +3343,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: @@ -3299,34 +3363,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 @@ -3334,12 +3398,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. @@ -3350,26 +3414,26 @@ 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 @@ -3391,34 +3455,35 @@ See management\-notes.txt in the OpenVPN distribution for a description of the OpenVPN challenge/response protocol. .\"********************************************************* .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 @@ -3449,7 +3514,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, @@ -3479,7 +3544,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. @@ -3494,7 +3559,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. @@ -3507,7 +3572,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 @@ -3522,7 +3587,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, @@ -3534,10 +3599,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 @@ -3547,7 +3612,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 @@ -3562,19 +3627,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 @@ -3618,7 +3683,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 @@ -3633,9 +3698,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 @@ -3647,7 +3712,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) @@ -3669,7 +3734,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 @@ -3705,7 +3770,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 @@ -3713,7 +3778,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. @@ -3721,7 +3786,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 @@ -3732,12 +3797,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 @@ -3758,24 +3823,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 @@ -3799,17 +3864,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 @@ -3826,18 +3891,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 @@ -3859,10 +3924,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 @@ -3872,15 +3942,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 @@ -3905,7 +3975,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 @@ -3916,7 +3986,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) @@ -3932,23 +4002,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. @@ -3959,74 +4029,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 @@ -4052,7 +4122,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. @@ -4080,16 +4150,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 (":"). @@ -4099,11 +4169,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 @@ -4120,7 +4190,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). @@ -4130,13 +4200,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). @@ -4147,16 +4217,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). @@ -4164,47 +4234,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 @@ -4215,7 +4285,7 @@ response. .B (1) An OpenVPN static key file generated by -.B --genkey +.B \-\-genkey (required if .B direction parameter is used). @@ -4233,19 +4303,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 @@ -4272,7 +4342,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. @@ -4280,20 +4350,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. @@ -4302,7 +4372,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 @@ -4319,15 +4389,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 @@ -4337,28 +4407,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 executed as +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 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, @@ -4372,17 +4454,25 @@ 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 \-\-x509-username-field fieldname +Field in x509 certificate subject to be used as username (default=CN). +.B Fieldname +will be uppercased before matching. When this option is used, the +--tls-remote option will match against the chosen fieldname instead +of the CN. +.\"********************************************************* +.TP +.B \-\-tls-remote name Accept connections only from a host with X509 name or common name equal to .B name. @@ -4399,24 +4489,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. @@ -4424,11 +4514,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". @@ -4443,19 +4533,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. @@ -4466,7 +4556,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. @@ -4477,7 +4567,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 @@ -4488,18 +4578,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 ). @@ -4508,12 +4598,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. @@ -4543,28 +4633,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. @@ -4573,18 +4663,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. .\"********************************************************* @@ -4593,7 +4683,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 @@ -4604,9 +4694,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 @@ -4618,40 +4708,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 @@ -4667,23 +4757,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 @@ -4693,13 +4783,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. @@ -4721,13 +4811,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 @@ -4736,7 +4826,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 @@ -4766,55 +4856,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), @@ -4827,7 +4917,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 @@ -4839,19 +4929,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 @@ -4859,21 +4949,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 @@ -4882,28 +4972,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 @@ -4926,26 +5016,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 @@ -4960,10 +5050,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 @@ -4973,7 +5063,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. @@ -4981,14 +5071,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. @@ -4996,52 +5137,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. .\"********************************************************* @@ -5065,7 +5206,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 @@ -5081,17 +5222,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. @@ -5121,45 +5262,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. .\"********************************************************* @@ -5168,30 +5309,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 @@ -5199,13 +5340,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 @@ -5213,15 +5354,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 @@ -5229,16 +5370,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 @@ -5246,61 +5387,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 @@ -5308,31 +5449,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 @@ -5341,23 +5482,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 @@ -5365,29 +5506,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 @@ -5402,15 +5543,21 @@ 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 @@ -5422,15 +5569,15 @@ Set prior to execution of any script. 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), @@ -5444,7 +5591,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 @@ -5452,7 +5599,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 @@ -5460,7 +5607,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 @@ -5470,7 +5617,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 @@ -5480,65 +5627,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. @@ -5550,7 +5708,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 @@ -5594,30 +5752,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 @@ -5633,11 +5791,6 @@ Make device: Load driver: .B modprobe tun - -If you have Linux 2.2 or earlier, you should obtain version 1.1 of the -TUN/TAP driver from -.I http://vtun.sourceforge.net/tun/ -and follow the installation instructions. .\"********************************************************* .SH EXAMPLES Prior to running these examples, you should have OpenVPN installed on two @@ -5658,10 +5811,7 @@ If you installed from RPM, the .B mknod step may be omitted, because the RPM install does that for you. -If you have Linux 2.2, you should obtain version 1.1 of the -TUN/TAP driver from -.I http://vtun.sourceforge.net/tun/ -and follow the installation instructions. +Only Linux 2.4 and newer are supported. For other platforms, consult the INSTALL file at .I http://openvpn.net/install.html @@ -5672,7 +5822,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 @@ -5741,11 +5891,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 @@ -5758,17 +5908,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 @@ -5782,11 +5932,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 @@ -5808,10 +5958,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. @@ -5824,11 +5974,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 @@ -5841,16 +5991,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: @@ -5886,7 +6036,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 @@ -5894,7 +6044,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. @@ -5905,7 +6055,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. @@ -5914,7 +6064,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 @@ -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 */ @@ -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 20110522-1 (2.2.0)]" " built on " __DATE__ ; @@ -96,12 +109,16 @@ 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" "--connect-retry-max n : Maximum connection attempt retries, default infinite.\n" #ifdef GENERAL_PROXY_SUPPORT "--auto-proxy : Try to sense proxy settings (or lack thereof) automatically.\n" + "--show-proxy-settings : Show sensed proxy settings.\n" #endif #ifdef ENABLE_HTTP_PROXY "--http-proxy s p [up] [auth] : Connect to remote host\n" @@ -121,8 +138,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 +183,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 +195,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 +318,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" @@ -375,6 +394,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" @@ -388,10 +408,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" @@ -418,7 +444,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" @@ -516,6 +542,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 certificate 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" @@ -547,6 +577,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" @@ -741,9 +774,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; @@ -775,11 +805,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 @@ -867,6 +912,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) { @@ -892,9 +1009,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 ; } @@ -1022,6 +1136,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)); @@ -1042,6 +1158,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); @@ -1055,6 +1174,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); @@ -1108,6 +1230,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 */ @@ -1148,6 +1289,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) @@ -1247,6 +1395,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); @@ -1403,6 +1554,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); @@ -1756,11 +1908,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 @@ -1769,7 +1937,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 @@ -1782,7 +1950,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"); @@ -1847,16 +2016,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 @@ -1874,7 +2047,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 @@ -1888,11 +2066,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"); @@ -1912,17 +2107,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"); @@ -1938,6 +2143,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) @@ -1969,6 +2179,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"); @@ -1978,8 +2190,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) @@ -2015,7 +2225,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"); @@ -2132,6 +2342,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); @@ -2187,6 +2398,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 @@ -2528,6 +2743,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, @@ -2995,6 +3212,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 */ } @@ -3029,6 +3254,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) { @@ -3036,6 +3262,7 @@ atou (const char *str) sscanf (str, "%u", &val); return val; } +#endif static inline bool space (unsigned char c) @@ -3577,6 +3804,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, @@ -3869,6 +4105,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); @@ -4011,6 +4271,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")) @@ -4057,6 +4318,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]) @@ -4064,6 +4326,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")) @@ -4123,7 +4386,7 @@ add_option (struct options *options, { if (options->inetd != -1) { - msg (msglevel, opterr); + msg (msglevel, "%s", opterr); goto err; } else @@ -4133,7 +4396,7 @@ add_option (struct options *options, { if (options->inetd != -1) { - msg (msglevel, opterr); + msg (msglevel, "%s", opterr); goto err; } else @@ -4143,7 +4406,7 @@ add_option (struct options *options, { if (name != NULL) { - msg (msglevel, opterr); + msg (msglevel, "%s", opterr); goto err; } name = p[z]; @@ -4319,26 +4582,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 @@ -4379,7 +4622,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; @@ -4592,6 +4835,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")) { @@ -4693,6 +4937,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; @@ -4753,6 +5017,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")) @@ -4911,6 +5176,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; @@ -4995,6 +5287,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; @@ -5090,6 +5404,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]) @@ -5097,6 +5412,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]) @@ -5104,6 +5420,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]) @@ -5111,6 +5428,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]) @@ -5187,6 +5505,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; @@ -5229,6 +5552,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); @@ -5478,7 +5838,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); @@ -5931,8 +6297,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); @@ -6058,6 +6430,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 @@ -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 @@ -230,6 +231,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 @@ -351,6 +355,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 */ @@ -384,10 +389,7 @@ struct options struct plugin_option_list *plugin_list; #endif -#ifdef USE_PTHREAD - int n_threads; - int nice_work; -#endif + const char *tmp_dir; #if P2MP @@ -395,6 +397,9 @@ struct options 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) @@ -416,18 +421,23 @@ 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; const char *client_disconnect_script; const char *learn_address_script; - const char *tmp_dir; const char *client_config_dir; bool ccd_exclusive; bool disable; 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; @@ -437,6 +447,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; @@ -504,6 +518,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; @@ -551,6 +566,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; @@ -764,6 +784,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 */ @@ -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) @@ -28,7 +28,6 @@ #include "common.h" #include "integer.h" #include "buffer.h" -#include "thread.h" struct frequency_limit { @@ -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 @@ -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; @@ -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"); } @@ -33,6 +33,8 @@ #include "manage.h" #include "base64.h" #include "pkcs11.h" +#include "misc.h" +#include "otime.h" static time_t @@ -982,5 +984,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 */ @@ -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) @@ -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..e52f632 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) +{ + const char *searching=tosearch; + char *scratch; + char temp[strlen(tosearch)*10]; + temp[0]=0; + + if (!tosearch || !searchfor || !replacewith) return 0; + if (!strlen(tosearch) || !strlen(searchfor) || !strlen(replacewith)) return 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); +} @@ -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", @@ -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); @@ -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 { @@ -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) { @@ -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) { @@ -331,10 +319,10 @@ journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_ char *jfn; int fd; - slen = sizeof(from.sa); - dlen = sizeof(to.sa); - if (!getpeername (pc->sd, (struct sockaddr *) &from.sa, &slen) - && !getsockname (cp->sd, (struct sockaddr *) &to.sa, &dlen)) + slen = sizeof(from.addr.sa); + dlen = sizeof(to.addr.sa); + if (!getpeername (pc->sd, (struct sockaddr *) &from.addr.sa, &slen) + && !getsockname (cp->sd, (struct sockaddr *) &to.addr.sa, &dlen)) { const char *f = print_sockaddr_ex (&from, ":", PS_SHOW_PORT, &gc); const char *t = print_sockaddr_ex (&to, ":", PS_SHOW_PORT, &gc); @@ -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 @@ -872,8 +860,10 @@ port_share_open (const char *host, /* Let msg know that we forked */ msg_forked (); +#ifdef ENABLE_MANAGEMENT /* Don't interact with management interface */ management = NULL; +#endif /* close all parent fds except our socket back to parent */ close_fds_except (fd[1]); @@ -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; } @@ -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 * @@ -35,10 +35,12 @@ #include "socket.h" #include "manage.h" #include "win32.h" +#include "options.h" #include "memdbg.h" static void delete_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es); + static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags); #ifdef ENABLE_DEBUG @@ -88,6 +90,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 +126,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) { @@ -329,6 +349,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, @@ -349,6 +431,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; @@ -358,6 +457,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_vpn_gateway (struct route_list *rl, struct env_set *es, const in_addr_t addr) @@ -549,6 +657,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, @@ -667,14 +841,24 @@ 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->rgi.gateway.addr, - tt, - flags, - &rl->rgi, - es); - rl->iflags |= RL_DID_LOCAL; +#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->rgi.gateway.addr, + tt, + flags, + &rl->rgi, + es); + rl->iflags |= RL_DID_LOCAL; +#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 */ @@ -800,7 +984,7 @@ 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->iflags & RL_ROUTES_ADDED)) @@ -828,24 +1012,54 @@ add_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, } rl->iflags |= RL_ROUTES_ADDED; } + 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->iflags & RL_ROUTES_ADDED) { int i; for (i = rl->n - 1; i >= 0; --i) { - struct route *r = &rl->routes[i]; + const struct route *r = &rl->routes[i]; delete_route (r, tt, flags, &rl->rgi, es); } rl->iflags &= ~RL_ROUTES_ADDED; } - undo_redirect_default_route_to_vpn (rl, tt, flags, es); - clear_route_list (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 @@ -953,6 +1167,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); +} + /* * local_route() determines whether the gateway of a provided host * route is on the same interface that owns the default gateway. @@ -964,7 +1206,7 @@ setenv_routes (struct env_set *es, const struct route_list *rl) * gateway interface as the route destination. For example, here * is an example on Linux that uses LR_MATCH: * - * route add -net 10.10.0.1 netmask 255.255.255.255 dev eth0 + * route add -net 10.10.0.1 netmask 255.255.255.255 dev eth0 * * This capability is needed by the "default-gateway block-local" * directive, to allow client access to the local subnet to be @@ -1184,7 +1426,7 @@ add_route (struct route *r, if (rgi && is_local_route == LR_MATCH) { - /* Mac OS X route syntax for LR_MATCH: + /* Mac OS X route syntax for LR_MATCH: route add -cloning -net 10.10.0.1 -netmask 255.255.255.255 -interface en0 */ argv_printf_cat (&argv, "-cloning -net %s -netmask %s -interface %s", network, @@ -1235,6 +1477,187 @@ add_route (struct route *r, gc_free (&gc); } + +static const char * +print_in6_addr_netbits_only( struct in6_addr network_copy, int netbits, + struct gc_arena * gc) +{ + /* clear host bit parts of route + * (needed if routes are specified improperly, or if we need to + * explicitely setup/clear the "connected" network routes on some OSes) + */ + int byte = 15; + int bits_to_clear = 128 - netbits; + + 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; } + } + + return print_in6_addr( network_copy, 0, gc); +} + +void +add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) +{ + struct gc_arena gc; + struct argv argv; + + const char *network; + const char *gateway; + bool status = false; + const char *device = tt->actual_name; + + if (!r6->defined) + return; + + gc_init (&gc); + argv_init (&argv); + + network = print_in6_addr_netbits_only( r6->network, r6->netbits, &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 + + /* in some versions of Windows, routes are persistent across reboots by + * default, unless "store=active" is set (pointed out by Tony Lim, thanks) + */ + argv_printf_cat( &argv, " store=active" ); + + argv_msg (D_ROUTE, &argv); + + 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 (struct route *r, const struct tuntap *tt, @@ -1395,6 +1818,142 @@ delete_route (struct route *r, gc_free (&gc); } +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_netbits_only( r6->network, r6->netbits, &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. @@ -1884,7 +2443,7 @@ get_default_gateway (struct route_gateway_info *rgi) strncpynt (rgi->iface, ifreq.ifr_name, sizeof(rgi->iface)); rgi->gateway.netmask = netmask; rgi->flags |= (RGI_IFACE_DEFINED|RGI_NETMASK_DEFINED); - + /* now get the hardware address. */ memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr)); if (ioctl (sd, SIOCGIFHWADDR, &ifreq) < 0) @@ -2144,7 +2703,7 @@ get_default_gateway (struct route_gateway_info *rgi) } do { l = read(sockfd, (char *)&m_rtmsg, sizeof(m_rtmsg)); - } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); + } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); close(sockfd); sockfd = -1; @@ -96,6 +96,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 { # define RT_DEFINED (1<<0) # define RT_ADDED (1<<1) @@ -108,6 +121,31 @@ struct route { int metric; }; +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]; +}; + + struct route_gateway_address { in_addr_t addr; in_addr_t netmask; @@ -161,13 +199,25 @@ 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_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); +void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); void add_route (struct route *r, const struct tuntap *tt, @@ -181,6 +231,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, @@ -188,21 +243,32 @@ 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_vpn_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 @@ -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); } /* @@ -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); @@ -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 */ @@ -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) @@ -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); } @@ -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; } @@ -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); @@ -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" @@ -303,25 +306,25 @@ auth_user_pass_setup (const char *auth_file, const struct static_challenge_info #else # ifdef ENABLE_CLIENT_CR if (auth_challenge) /* dynamic challenge/response */ - get_user_pass_cr (&auth_user_pass, - auth_file, - UP_TYPE_AUTH, - GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_DYNAMIC_CHALLENGE, - auth_challenge); + get_user_pass_cr (&auth_user_pass, + auth_file, + UP_TYPE_AUTH, + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_DYNAMIC_CHALLENGE, + auth_challenge); else if (sci) /* static challenge response */ - { - int flags = GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_STATIC_CHALLENGE; - if (sci->flags & SC_ECHO) - flags |= GET_USER_PASS_STATIC_CHALLENGE_ECHO; - get_user_pass_cr (&auth_user_pass, - auth_file, - UP_TYPE_AUTH, - flags, - sci->challenge_text); - } + { + int flags = GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_STATIC_CHALLENGE; + if (sci->flags & SC_ECHO) + flags |= GET_USER_PASS_STATIC_CHALLENGE_ECHO; + get_user_pass_cr (&auth_user_pass, + auth_file, + UP_TYPE_AUTH, + flags, + sci->challenge_text); + } else # endif - get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE); + get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE); #endif } } @@ -549,6 +552,61 @@ 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; +} +#endif /* ENABLE_X509ALTUSERNAME */ + #ifdef ENABLE_X509_TRACK /* * setenv_x509_track function -- save X509 fields to environment, @@ -589,73 +647,52 @@ setenv_x509_track (const struct x509_track *xt, struct env_set *es, const int de { X509_NAME *x509_name = X509_get_subject_name (x509); const char nullc = '\0'; + int i; while (xt) { if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) { - switch (xt->nid) + i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); + if (i >= 0) { - case NID_sha1: - { - int i; - char hash_str[SHA_DIGEST_LENGTH*3+1]; - char *hs = hash_str; - const unsigned char *src = x509->sha1_hash; - for (i = 0; i < SHA_DIGEST_LENGTH; ++i) - { - openvpn_snprintf(hs, 4, "%02X:", src[i]); - hs += 3; - } - --hs; /* wipe the trailing ':' */ - *hs = '\0'; - do_setenv_x509(es, xt->name, hash_str, depth); - } - break; - default: - { - int i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); - if (i >= 0) - { - X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); - if (ent) - { - ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent); - unsigned char *buf; - buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8 (&buf, val) > 0) - { - do_setenv_x509(es, xt->name, (char *)buf, depth); - OPENSSL_free (buf); - } - } - } - else - { - i = X509_get_ext_by_NID(x509, xt->nid, -1); - if (i >= 0) - { - X509_EXTENSION *ext = X509_get_ext(x509, i); - if (ext) - { - BIO *bio = BIO_new(BIO_s_mem()); - if (bio) - { - if (X509V3_EXT_print(bio, ext, 0, 0)) - { - if (BIO_write(bio, &nullc, 1) == 1) - { - char *str; - BIO_get_mem_data(bio, &str); - do_setenv_x509(es, xt->name, str, depth); - } - } - BIO_free(bio); - } - } - } - } - } + X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); + if (ent) + { + ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent); + unsigned char *buf; + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + if (ASN1_STRING_to_UTF8 (&buf, val) > 0) + { + do_setenv_x509(es, xt->name, (char *)buf, depth); + OPENSSL_free (buf); + } + } + } + else + { + i = X509_get_ext_by_NID(x509, xt->nid, -1); + if (i >= 0) + { + X509_EXTENSION *ext = X509_get_ext(x509, i); + if (ext) + { + BIO *bio = BIO_new(BIO_s_mem()); + if (bio) + { + if (X509V3_EXT_print(bio, ext, 0, 0)) + { + if (BIO_write(bio, &nullc, 1) == 1) + { + char *str; + BIO_get_mem_data(bio, &str); + do_setenv_x509(es, xt->name, str, depth); + } + } + BIO_free(bio); + } + } + } } } xt = xt->next; @@ -860,6 +897,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. @@ -870,7 +952,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; @@ -908,18 +990,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); @@ -969,6 +1067,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); @@ -1062,7 +1170,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) { @@ -1080,32 +1188,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) { @@ -1155,15 +1279,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); @@ -1336,10 +1460,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); } @@ -2019,7 +2144,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++) { @@ -2229,8 +2354,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); @@ -2263,7 +2395,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]; @@ -3690,7 +3822,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? */ @@ -3703,17 +3834,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); @@ -3728,16 +3864,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"); } @@ -3747,7 +3878,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); @@ -3779,7 +3910,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 */ @@ -4192,9 +4323,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; } @@ -4317,7 +4448,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; } @@ -4398,7 +4529,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); @@ -4411,8 +4543,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 (); @@ -4699,7 +4829,6 @@ tls_process (struct tls_multi *multi, } } } - /*mutex_cycle (multi->mutex);*/ } while (state_change); @@ -4853,7 +4982,6 @@ tls_multi_process (struct tls_multi *multi, reset_session (multi, session); } } - /*mutex_cycle (multi->mutex);*/ } update_time (); @@ -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; @@ -601,9 +604,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; @@ -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) { @@ -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 @@ -699,7 +690,9 @@ socket_defined (const socket_descriptor_t sd) /* * Do we support pushing peer info? */ +#if defined(USE_CRYPTO) && defined(USE_SSL) #define ENABLE_PUSH_PEER_INFO +#endif /* * Do we support internal client-side NAT? 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 */ @@ -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)"; @@ -306,7 +284,7 @@ warn_on_use_of_common_subnets (void) get_default_gateway (&rgi); if ((rgi.flags & needed) == needed) { - const in_addr_t lan_network = rgi.gateway.addr & rgi.gateway.netmask; + const in_addr_t lan_network = rgi.gateway.addr & rgi.gateway.netmask; if (lan_network == 0xC0A80000 || lan_network == 0xC0A80100) msg (M_WARN, "NOTE: your local LAN uses the extremely common subnet address 192.168.0.x or 192.168.1.x. Be aware that this might create routing conflicts if you connect to the VPN server from public locations such as internet cafes that use the same subnet."); } @@ -425,6 +403,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, @@ -539,6 +519,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; } @@ -561,6 +575,40 @@ 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); +} + +void delete_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; + delete_route_ipv6 (&r6, tt, 0, es); +} +#endif + + /* execute the ifconfig command through the shell */ void do_ifconfig (struct tuntap *tt, @@ -576,10 +624,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. */ @@ -591,6 +645,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. */ @@ -649,7 +710,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, @@ -672,6 +745,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*/ @@ -695,7 +780,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", @@ -704,11 +789,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; @@ -756,10 +920,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", @@ -786,6 +982,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) @@ -844,11 +1061,27 @@ do_ifconfig (struct tuntap *tt, { struct route r; CLEAR (r); - r.flags = RT_DEFINED; + r.defined = true; r.network = tt->local & tt->remote_netmask; r.netmask = tt->remote_netmask; r.gateway = tt->local; - add_route (&r, tt, 0, NULL, es); + 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) @@ -863,26 +1096,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"); @@ -900,6 +1122,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) { /* @@ -939,6 +1174,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 set address MyTap 2001:608:8003::d store=active */ + argv_printf (&argv, + "%s%sc interface ipv6 set address %s %s store=active", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + 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 @@ -971,14 +1234,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) { @@ -1074,16 +1339,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. @@ -1107,7 +1372,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 if ((tt->fd = open (node, O_RDWR)) < 0) { msg (M_WARN | M_ERRNO, "Note: Cannot open TUN/TAP dev %s", node); - goto linux_2_2_fallback; + return; } /* @@ -1151,7 +1416,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 if (ioctl (tt->fd, TUNSETIFF, (void *) &ifr) < 0) { msg (M_WARN | M_ERRNO, "Note: Cannot ioctl TUNSETIFF %s", dev); - goto linux_2_2_fallback; + return; } msg (M_INFO, "TUN/TAP device %s opened", ifr.ifr_name); @@ -1187,21 +1452,12 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 tt->actual_name = string_alloc (ifr.ifr_name, NULL); } return; - - linux_2_2_fallback: - msg (M_INFO, "Note: Attempting fallback to kernel 2.2 TUN/TAP interface"); - if (tt->fd >= 0) - { - close (tt->fd); - tt->fd = -1; - } - open_tun_generic (dev, dev_type, dev_node, ipv6, 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); } @@ -1211,9 +1467,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 */ @@ -1233,7 +1489,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; @@ -1241,7 +1497,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) @@ -1384,17 +1640,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 + */ + CLEAR(ifr); if (tt->type == DEV_TYPE_NULL) { @@ -1413,9 +1674,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; @@ -1442,7 +1704,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) @@ -1451,27 +1717,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 *)𝔦 + 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"); } @@ -1487,20 +1809,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; @@ -1533,11 +1873,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, @@ -1594,9 +1943,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) @@ -1608,7 +1957,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", @@ -1617,12 +1968,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); } } @@ -1685,33 +2055,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); @@ -1719,18 +2107,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 @@ -1743,9 +2191,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) { @@ -1831,9 +2279,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) { @@ -1902,6 +2350,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 @@ -3887,7 +4390,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]; @@ -3898,7 +4401,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) { @@ -4020,6 +4523,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 */ @@ -4344,6 +4857,26 @@ close_tun (struct tuntap *tt) if (tt) { + if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) + { + struct argv argv; + argv_init (&argv); + + /* remove route pointing to interface */ + delete_route_connected_v6_net(tt, NULL); + + /* netsh interface ipv6 delete address \"%s\" %s */ + const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); + argv_printf (&argv, + "%s%sc interface ipv6 delete address %s %s", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + tt->actual_name, + ifconfig_ipv6_local ); + + netsh_command (&argv, 1); + argv_reset (&argv); + } #if 1 if (tt->ipapi_context_defined) { @@ -4447,9 +4980,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 @@ -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, @@ -1,6 +1,6 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1.6]) +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) @@ -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..29d34f1 --- /dev/null +++ b/win/openvpn.nsi @@ -0,0 +1,822 @@ +; **************************************************************************** +; * 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 ${EASYRSA}\2.0\openssl.cnf.sample. A newer + # openssl.cnf is needed on OpenVPN 2.2+. + File "${EASYRSA}\2.0\openssl-1.0.0.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() @@ -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() @@ -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 @@ -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 |