[packages/openvpn] Up to 2.7.6; dropped obsolete patches

arekm arekm at pld-linux.org
Mon Aug 10 09:43:14 CEST 2026


commit a369078e50c97d328dd89c06b4e052d9534eb8e2
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Mon Aug 10 09:39:00 2026 +0200

    Up to 2.7.6; dropped obsolete patches

 openvpn-ipv6_payload.patch | 10435 -------------------------------------------
 openvpn-pam.patch          |    12 -
 openvpn.spec               |     6 +-
 3 files changed, 2 insertions(+), 10451 deletions(-)
---
diff --git a/openvpn.spec b/openvpn.spec
index ecacf56..02b232d 100644
--- a/openvpn.spec
+++ b/openvpn.spec
@@ -9,12 +9,12 @@
 Summary:	VPN Daemon
 Summary(pl.UTF-8):	Serwer VPN
 Name:		openvpn
-Version:	2.7.5
+Version:	2.7.6
 Release:	1
 License:	GPL v2
 Group:		Networking/Daemons
 Source0:	https://swupdate.openvpn.org/community/releases/%{name}-%{version}.tar.gz
-# Source0-md5:	163f1c2c946b32d15c9971219a5bff45
+# Source0-md5:	58ec432379200175e4c15894527121c9
 Source1:	%{name}.init
 Source2:	%{name}.sysconfig
 Source3:	%{name}.tmpfiles
@@ -22,7 +22,6 @@ Source4:	%{name}-service-generator
 Source5:	%{name}.target
 Source6:	%{name}@.service
 Source7:	%{name}-update-resolv-conf
-Patch0:		%{name}-pam.patch
 URL:		https://www.openvpn.net/
 BuildRequires:	autoconf >= 2.60
 BuildRequires:	automake >= 1:1.9
@@ -147,7 +146,6 @@ Ten pakiet zawiera pliki nagłówkowe do tworzenia wtyczek OpenVPN.
 
 %prep
 %setup -q
-%patch -P0 -p1
 
 %{__sed} -e 's,/''usr/lib/openvpn,%{_libexecdir}/%{name},' %{SOURCE7} > contrib/update-resolv-conf
 
diff --git a/openvpn-ipv6_payload.patch b/openvpn-ipv6_payload.patch
deleted file mode 100644
index 977e5c9..0000000
--- a/openvpn-ipv6_payload.patch
+++ /dev/null
@@ -1,10435 +0,0 @@
-diff -durN openvpn-2.2.2.orig/ChangeLog.IPv6 openvpn-2.2.2/ChangeLog.IPv6
---- openvpn-2.2.2.orig/ChangeLog.IPv6	1970-01-01 01:00:00.000000000 +0100
-+++ openvpn-2.2.2/ChangeLog.IPv6	2012-06-01 10:40:28.000000000 +0200
-@@ -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")
-diff -durN openvpn-2.2.2.orig/README.IPv6 openvpn-2.2.2/README.IPv6
---- openvpn-2.2.2.orig/README.IPv6	1970-01-01 01:00:00.000000000 +0100
-+++ openvpn-2.2.2/README.IPv6	2012-06-01 10:40:28.000000000 +0200
-@@ -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 -durN openvpn-2.2.2.orig/TODO.IPv6 openvpn-2.2.2/TODO.IPv6
---- openvpn-2.2.2.orig/TODO.IPv6	1970-01-01 01:00:00.000000000 +0100
-+++ openvpn-2.2.2/TODO.IPv6	2012-06-01 10:40:28.000000000 +0200
-@@ -0,0 +1,153 @@
-+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)
-+      * fixed for Win32, 22.5.2011
-+
-+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)
-+
-+24.) implement link-local IPv6 addresses
-+     (OSPFv3 over TUN/multipoint does not work right now)
-diff -durN openvpn-2.2.2.orig/forward.c openvpn-2.2.2/forward.c
---- openvpn-2.2.2.orig/forward.c	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/forward.c	2012-06-01 10:40:28.000000000 +0200
-@@ -262,7 +262,8 @@
- 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);
-diff -durN openvpn-2.2.2.orig/helper.c openvpn-2.2.2/helper.c
---- openvpn-2.2.2.orig/helper.c	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/helper.c	2012-06-01 10:40:28.000000000 +0200
-@@ -142,6 +142,55 @@
- 
- #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 -durN openvpn-2.2.2.orig/init.c openvpn-2.2.2/init.c
---- openvpn-2.2.2.orig/init.c	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/init.c	2012-06-01 10:40:28.000000000 +0200
-@@ -843,7 +843,7 @@
- 	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);
-@@ -1066,6 +1066,8 @@
- {
-   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);
- }
- 
- 
-@@ -1108,6 +1110,45 @@
-     }
- }
- 
-+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.
-  */
-@@ -1172,12 +1213,13 @@
- 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)
--    add_routes (route_list, tt, ROUTE_OPTION_FLAGS (options), es);
-+  if (!options->route_noexec && ( route_list || route_ipv6_list ) )
-+    add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es);
- 
-   if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP))
-     {
-@@ -1234,11 +1276,16 @@
- 			   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);
-@@ -1270,6 +1317,8 @@
-       /* 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
-@@ -1286,7 +1335,7 @@
- 
-       /* 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)
-@@ -1315,7 +1364,8 @@
- 
-       /* 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?
-@@ -1389,8 +1439,9 @@
- #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)
-diff -durN openvpn-2.2.2.orig/init.h openvpn-2.2.2/init.h
---- openvpn-2.2.2.orig/init.h	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/init.h	2012-06-01 10:40:28.000000000 +0200
-@@ -63,6 +63,7 @@
- 
- 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 -durN openvpn-2.2.2.orig/misc.c openvpn-2.2.2/misc.c
---- openvpn-2.2.2.orig/misc.c	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/misc.c	2012-06-01 10:40:28.000000000 +0200
-@@ -1001,7 +1001,9 @@
- 	{
- 	  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);
-diff -durN openvpn-2.2.2.orig/mroute.c openvpn-2.2.2/mroute.c
---- openvpn-2.2.2.orig/mroute.c	2011-12-13 21:17:06.000000000 +0100
-+++ openvpn-2.2.2/mroute.c	2012-06-01 10:42:51.000000000 +0200
-@@ -88,12 +88,33 @@
-     }
- }
- 
-+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
-@@ -157,13 +178,29 @@
- 	    }
- 	  break;
- 	case 6:
--	  {
--            if( !ipv6warned ) {
--              msg (M_WARN, "IPv6 in tun mode is not supported in OpenVPN 2.2");
--              ipv6warned = true;
--            }
--	    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;
-@@ -257,14 +294,36 @@
-  * 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);
- }
- 
- /*
-@@ -342,17 +401,24 @@
- 	  }
- 	  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
-@@ -422,6 +488,40 @@
- 	mroute_helper_regenerate (mh);
-     }
- }
-+
-+/* this is a bit inelegant, we really should have a helper to that 
-+ * is only passed the netbits value, and not the whole struct iroute *
-+ * - thus one helper could do IPv4 and IPv6.  For the sake of "not change
-+ * code unrelated to IPv4" this is left for later cleanup, for now.
-+ */
-+void
-+mroute_helper_add_iroute6 (struct mroute_helper *mh, 
-+                           const struct iroute_ipv6 *ir6)
-+{
-+  if (ir6->netbits >= 0)
-+    {
-+      ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
-+      ++mh->cache_generation;
-+      ++mh->net_len_refcount[ir6->netbits];
-+      if (mh->net_len_refcount[ir6->netbits] == 1)
-+	mroute_helper_regenerate (mh);
-+    }
-+}
-+
-+void
-+mroute_helper_del_iroute6 (struct mroute_helper *mh, 
-+			   const struct iroute_ipv6 *ir6)
-+{
-+  if (ir6->netbits >= 0)
-+    {
-+      ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
-+      ++mh->cache_generation;
-+      --mh->net_len_refcount[ir6->netbits];
-+      ASSERT (mh->net_len_refcount[ir6->netbits] >= 0);
-+      if (!mh->net_len_refcount[ir6->netbits])
-+	mroute_helper_regenerate (mh);
-+    }
-+}
- 
- void
- mroute_helper_free (struct mroute_helper *mh)
-diff -durN openvpn-2.2.2.orig/mroute.c~ openvpn-2.2.2/mroute.c~
---- openvpn-2.2.2.orig/mroute.c~	1970-01-01 01:00:00.000000000 +0100
-+++ openvpn-2.2.2/mroute.c~	2012-06-01 10:40:28.000000000 +0200
-@@ -0,0 +1,518 @@
-+/*
-+ *  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 at 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 P2MP_SERVER
-+
-+#include "mroute.h"
-+#include "proto.h"
-+#include "error.h"
-+#include "socket.h"
-+
-+#include "memdbg.h"
-+
-+void
-+mroute_addr_init (struct mroute_addr *addr)
-+{
-+  CLEAR (*addr);
-+}
-+
-+/*
-+ * Ethernet multicast addresses.
-+ */
-+
-+static inline bool
-+is_mac_mcast_addr (const uint8_t *mac)
-+{
-+  return (bool) mac[0] & 1;
-+}
-+
-+static inline bool
-+is_mac_mcast_maddr (const struct mroute_addr *addr)
-+{
-+  return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER && is_mac_mcast_addr (addr->addr); 
-+}
-+
-+/*
-+ * Don't learn certain addresses.
-+ */
-+bool
-+mroute_learnable_address (const struct mroute_addr *addr)
-+{
-+  int i;
-+  bool not_all_zeros = false;
-+  bool not_all_ones = false;
-+
-+  for (i = 0; i < addr->len; ++i)
-+    {
-+      int b = addr->addr[i];
-+      if (b != 0x00)
-+	not_all_zeros = true;
-+      if (b != 0xFF)
-+	not_all_ones = true;
-+    }
-+  return not_all_zeros && not_all_ones && !is_mac_mcast_maddr (addr);
-+}
-+
-+static inline void
-+mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int mask)
-+{
-+  if (ma)
-+    {
-+      ma->type = MR_ADDR_IPV4 | mask;
-+      ma->netbits = 0;
-+      ma->len = 4;
-+      *(in_addr_t*)ma->addr = src;
-+    }
-+}
-+
-+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
-+mroute_extract_addr_arp (struct mroute_addr *src,
-+			 struct mroute_addr *dest,
-+			 const struct buffer *buf)
-+{
-+  unsigned int ret = 0;
-+  if (BLEN (buf) >= (int) sizeof (struct openvpn_arp))
-+    {
-+      const struct openvpn_arp *arp = (const struct openvpn_arp *) BPTR (buf);
-+      if (arp->mac_addr_type == htons(0x0001)
-+	  && arp->proto_addr_type == htons(0x0800)
-+	  && arp->mac_addr_size == 0x06
-+	  && arp->proto_addr_size == 0x04)
-+	{
-+	  mroute_get_in_addr_t (src, arp->ip_src, MR_ARP);
-+	  mroute_get_in_addr_t (dest, arp->ip_dest, MR_ARP);
-+
-+	  /* multicast packet? */
-+	  if (mroute_is_mcast (arp->ip_dest))
-+	    ret |= MROUTE_EXTRACT_MCAST;
-+
-+	  ret |= MROUTE_EXTRACT_SUCCEEDED;
-+	}
-+    }
-+  return ret;
-+}
-+
-+#endif
-+
-+unsigned int
-+mroute_extract_addr_ipv4 (struct mroute_addr *src,
-+			  struct mroute_addr *dest,
-+			  const struct buffer *buf)
-+{
-+  unsigned int ret = 0;
-+  static bool ipv6warned = false;
-+
-+  if (BLEN (buf) >= 1)
-+    {
-+      switch (OPENVPN_IPH_GET_VER (*BPTR(buf)))
-+	{
-+	case 4:
-+	  if (BLEN (buf) >= (int) sizeof (struct openvpn_iphdr))
-+	    {
-+	      const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR (buf);
-+
-+	      mroute_get_in_addr_t (src, ip->saddr, 0);
-+	      mroute_get_in_addr_t (dest, ip->daddr, 0);
-+
-+	      /* multicast packet? */
-+	      if (mroute_is_mcast (ip->daddr))
-+		ret |= MROUTE_EXTRACT_MCAST;
-+
-+	      /* IGMP message? */
-+	      if (ip->protocol == OPENVPN_IPPROTO_IGMP)
-+		ret |= MROUTE_EXTRACT_IGMP;
-+
-+	      ret |= MROUTE_EXTRACT_SUCCEEDED;
-+	    }
-+	  break;
-+	case 6:
-+	  {
-+            if( !ipv6warned ) {
-+              msg (M_WARN, "IPv6 in tun mode is not supported in OpenVPN 2.2");
-+              ipv6warned = true;
-+            }
-+	    break;
-+	  }
-+	}
-+    }
-+  return ret;
-+}
-+
-+unsigned int
-+mroute_extract_addr_ether (struct mroute_addr *src,
-+			   struct mroute_addr *dest,
-+			   struct mroute_addr *esrc,
-+			   struct mroute_addr *edest,
-+			   const struct buffer *buf)
-+{
-+  unsigned int ret = 0;
-+  if (BLEN (buf) >= (int) sizeof (struct openvpn_ethhdr))
-+    {
-+      const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR (buf);
-+      if (src)
-+	{
-+	  src->type = MR_ADDR_ETHER;
-+	  src->netbits = 0;
-+	  src->len = 6;
-+	  memcpy (src->addr, eth->source, 6);
-+	}
-+      if (dest)
-+	{
-+	  dest->type = MR_ADDR_ETHER;
-+	  dest->netbits = 0;
-+	  dest->len = 6;
-+	  memcpy (dest->addr, eth->dest, 6);
-+
-+	  /* ethernet broadcast/multicast packet? */
-+	  if (is_mac_mcast_addr (eth->dest))
-+	    ret |= MROUTE_EXTRACT_BCAST;
-+	}
-+	  
-+      ret |= MROUTE_EXTRACT_SUCCEEDED;
-+
-+#ifdef ENABLE_PF
-+      if (esrc || edest)
-+	{
-+	  struct buffer b = *buf;
-+	  if (buf_advance (&b, sizeof (struct openvpn_ethhdr)))
-+	    {
-+	      switch (ntohs (eth->proto))
-+		{
-+		case OPENVPN_ETH_P_IPV4:
-+		  ret |= (mroute_extract_addr_ipv4 (esrc, edest, &b) << MROUTE_SEC_SHIFT);
-+		  break;
-+		case OPENVPN_ETH_P_ARP:
-+		  ret |= (mroute_extract_addr_arp (esrc, edest, &b) << MROUTE_SEC_SHIFT);
-+		  break;
-+		}
-+	    }
-+	}
-+#endif
-+    }
-+  return ret;
-+}
-+
-+/*
-+ * Translate a struct openvpn_sockaddr (osaddr)
-+ * to a struct mroute_addr (addr).
-+ */
-+bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
-+				      const struct openvpn_sockaddr *osaddr,
-+				      bool use_port)
-+{
-+  if (osaddr->sa.sin_family == 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);
-+	}
-+      else
-+	{
-+	  addr->type = MR_ADDR_IPV4;
-+	  addr->netbits = 0;
-+	  addr->len = 4;
-+	  memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
-+	}
-+      return true;
-+    }
-+  return false;
-+}
-+
-+/*
-+ * 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);
-+  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);
-+}
-+
-+/*
-+ * The mroute_addr hash function takes into account the
-+ * address type, number of bits in the network address,
-+ * and the actual address.
-+ */
-+uint32_t
-+mroute_addr_hash_function (const void *key, uint32_t iv)
-+{
-+  return hash_func (mroute_addr_hash_ptr ((const struct mroute_addr *) key),
-+		    mroute_addr_hash_len ((const struct mroute_addr *) key),
-+		    iv);
-+}
-+
-+bool
-+mroute_addr_compare_function (const void *key1, const void *key2)
-+{
-+  return mroute_addr_equal ((const struct mroute_addr *) key1,
-+			    (const struct mroute_addr *) key2);
-+}
-+
-+const char *
-+mroute_addr_print (const struct mroute_addr *ma,
-+		   struct gc_arena *gc)
-+{
-+  return mroute_addr_print_ex (ma, MAPF_IA_EMPTY_IF_UNDEF, gc);
-+}
-+
-+const char *
-+mroute_addr_print_ex (const struct mroute_addr *ma,
-+		      const unsigned int flags,
-+		      struct gc_arena *gc)
-+{
-+  struct buffer out = alloc_buf_gc (64, gc);
-+  if (ma)
-+    {
-+      struct mroute_addr maddr = *ma;
-+
-+      switch (maddr.type & MR_ADDR_MASK)
-+	{
-+	case MR_ADDR_ETHER:
-+	  buf_printf (&out, "%s", format_hex_ex (ma->addr, 6, 0, 1, ":", gc)); 
-+	  break;
-+	case MR_ADDR_IPV4:
-+	  {
-+	    struct buffer buf;
-+	    in_addr_t addr;
-+	    int port;
-+	    bool status;
-+	    buf_set_read (&buf, maddr.addr, maddr.len);
-+	    addr = buf_read_u32 (&buf, &status);
-+	    if (status)
-+	      {
-+		if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP))
-+		  buf_printf (&out, "ARP/");
-+		buf_printf (&out, "%s", print_in_addr_t (addr, (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc));
-+		if (maddr.type & MR_WITH_NETBITS)
-+		  {
-+		    if (flags & MAPF_SUBNET)
-+		      {
-+			const in_addr_t netmask = netbits_to_netmask (maddr.netbits);
-+			buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc));
-+		      }
-+		    else
-+		      buf_printf (&out, "/%d", maddr.netbits);
-+		  }
-+	      }
-+	    if (maddr.type & MR_WITH_PORT)
-+	      {
-+		port = buf_read_u16 (&buf);
-+		if (port >= 0)
-+		  buf_printf (&out, ":%d", port);
-+	      }
-+	  }
-+	  break;
-+	case MR_ADDR_IPV6:
-+	  {
-+	    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
-+ * currently used CIDR netlengths, so we don't
-+ * have to cycle through all 33.
-+ */
-+
-+struct mroute_helper *
-+mroute_helper_init (int ageable_ttl_secs)
-+{
-+  struct mroute_helper *mh;
-+  ALLOC_OBJ_CLEAR (mh, struct mroute_helper);
-+  mh->ageable_ttl_secs = ageable_ttl_secs;
-+  return mh;
-+}
-+
-+static void
-+mroute_helper_regenerate (struct mroute_helper *mh)
-+{
-+  int i, j = 0;
-+  for (i = MR_HELPER_NET_LEN - 1; i >= 0; --i)
-+    {
-+      if (mh->net_len_refcount[i] > 0)
-+	mh->net_len[j++] = (uint8_t) i;
-+    }
-+  mh->n_net_len = j;
-+
-+#ifdef ENABLE_DEBUG
-+  if (check_debug_level (D_MULTI_DEBUG))
-+    {
-+      struct gc_arena gc = gc_new ();
-+      struct buffer out = alloc_buf_gc (256, &gc);
-+      buf_printf (&out, "MROUTE CIDR netlen:");
-+      for (i = 0; i < mh->n_net_len; ++i)
-+	{
-+	  buf_printf (&out, " /%d", mh->net_len[i]);
-+	}
-+      dmsg (D_MULTI_DEBUG, "%s", BSTR (&out));
-+      gc_free (&gc);
-+    }
-+#endif
-+}
-+
-+void
-+mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir)
-+{
-+  if (ir->netbits >= 0)
-+    {
-+      ASSERT (ir->netbits < MR_HELPER_NET_LEN);
-+      ++mh->cache_generation;
-+      ++mh->net_len_refcount[ir->netbits];
-+      if (mh->net_len_refcount[ir->netbits] == 1)
-+	mroute_helper_regenerate (mh);
-+    }
-+}
-+
-+void
-+mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir)
-+{
-+  if (ir->netbits >= 0)
-+    {
-+      ASSERT (ir->netbits < MR_HELPER_NET_LEN);
-+      ++mh->cache_generation;
-+      --mh->net_len_refcount[ir->netbits];
-+      ASSERT (mh->net_len_refcount[ir->netbits] >= 0);
-+      if (!mh->net_len_refcount[ir->netbits])
-+	mroute_helper_regenerate (mh);
-+    }
-+}
-+
-+/* this is a bit inelegant, we really should have a helper to that 
-+ * is only passed the netbits value, and not the whole struct iroute *
-+ * - thus one helper could do IPv4 and IPv6.  For the sake of "not change
-+ * code unrelated to IPv4" this is left for later cleanup, for now.
-+ */
-+void
-+mroute_helper_add_iroute6 (struct mroute_helper *mh, 
-+                           const struct iroute_ipv6 *ir6)
-+{
-+  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)
-+{
-+  free (mh);
-+}
-+
-+#else
-+static void dummy(void) {}
-+#endif /* P2MP_SERVER */
-diff -durN openvpn-2.2.2.orig/mroute.h openvpn-2.2.2/mroute.h
---- openvpn-2.2.2.orig/mroute.h	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/mroute.h	2012-06-01 10:40:28.000000000 +0200
-@@ -85,7 +85,7 @@
- /*
-  * 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.
-@@ -127,6 +127,8 @@
- 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
-diff -durN openvpn-2.2.2.orig/multi.c openvpn-2.2.2/multi.c
---- openvpn-2.2.2.orig/multi.c	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/multi.c	2012-06-01 10:40:28.000000000 +0200
-@@ -316,25 +316,18 @@
-    */
-   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 @@
- 		   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);
-     }
- }
- 
-@@ -1078,6 +1075,37 @@
-   }
- }
- 
-+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.
-@@ -1088,6 +1116,7 @@
- {
-   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;
-@@ -1107,6 +1136,22 @@
-       
- 	  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);
- }
-@@ -1192,21 +1237,37 @@
-       mi->context.c2.push_ifconfig_defined = true;
-       mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local;
-       mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask;
-+
-+      /* 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))
-@@ -1228,12 +1289,46 @@
- 	  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);
- }
- 
-@@ -1272,6 +1367,11 @@
- 			    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?
-+     */
- }
- 
- /*
-@@ -1661,6 +1761,15 @@
- 		       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);
-diff -durN openvpn-2.2.2.orig/openvpn.8 openvpn-2.2.2/openvpn.8
---- openvpn-2.2.2.orig/openvpn.8	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/openvpn.8	2012-06-01 10:40:28.000000000 +0200
-@@ -794,6 +794,8 @@
- .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
-@@ -4949,6 +4951,57 @@
- .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.
-diff -durN openvpn-2.2.2.orig/openvpn.h openvpn-2.2.2/openvpn.h
---- openvpn-2.2.2.orig/openvpn.h	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/openvpn.h	2012-06-01 10:40:28.000000000 +0200
-@@ -165,6 +165,9 @@
-   /* 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;
-@@ -417,6 +420,11 @@
-   in_addr_t push_ifconfig_local;
-   in_addr_t push_ifconfig_remote_netmask;
- 
-+  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
-diff -durN openvpn-2.2.2.orig/options.c openvpn-2.2.2/options.c
---- openvpn-2.2.2.orig/options.c	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/options.c	2012-06-01 10:40:28.000000000 +0200
-@@ -79,6 +79,7 @@
- #ifdef ENABLE_EUREPHIA
-   " [eurephia]"
- #endif
-+  " [IPv6 payload 20110522-1 (2.2.0)]"
-   " built on " __DATE__
- ;
- 
-@@ -172,6 +173,8 @@
-   "                  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"
-@@ -182,6 +185,10 @@
-   "                  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"
-@@ -370,6 +377,7 @@
-   "\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"
-@@ -383,10 +391,16 @@
-   "--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"
-@@ -871,6 +885,78 @@
-   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)
- {
-@@ -989,6 +1075,8 @@
- #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));
-@@ -1009,6 +1097,9 @@
-   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);
-@@ -1022,6 +1113,9 @@
-   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);
-@@ -1076,6 +1170,25 @@
-   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 */
- 
-@@ -1113,6 +1226,13 @@
-     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_DEBUG
- static void
- show_connection_entry (const struct connection_entry *o)
-@@ -1203,6 +1323,9 @@
-   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);
-@@ -1863,8 +1986,10 @@
-       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)
-@@ -1889,6 +2014,11 @@
- 	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)
-@@ -1920,6 +2050,8 @@
-        */
-       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");
-@@ -2461,6 +2593,8 @@
- 		     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,
-@@ -3786,6 +3920,30 @@
- 	  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);
-@@ -4586,6 +4744,26 @@
- 	}
-       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;
-@@ -4797,6 +4975,33 @@
- 	    }
- 	}
-     }
-+  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;
-@@ -4881,6 +5086,28 @@
-       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;
-@@ -5076,6 +5303,11 @@
- 	}
-       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;
-@@ -5114,6 +5346,43 @@
- 	  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);
-diff -durN openvpn-2.2.2.orig/options.h openvpn-2.2.2/options.h
---- openvpn-2.2.2.orig/options.h	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/options.h	2012-06-01 10:44:37.000000000 +0200
-@@ -205,6 +205,9 @@
-   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
-@@ -326,6 +329,7 @@
-   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 */
-@@ -363,6 +367,9 @@
-   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)
-@@ -384,6 +391,11 @@
-   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;
-@@ -395,12 +407,17 @@
-   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;
-   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;
-@@ -723,6 +740,10 @@
- 			    unsigned int *option_types_found,
- 			    struct env_set *es);
- 
-+bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
-+		    unsigned int * netbits, char ** printable_ipv6, 
-+		    int msglevel );
-+
- /*
-  * inline functions
-  */
-diff -durN openvpn-2.2.2.orig/options.h~ openvpn-2.2.2/options.h~
---- openvpn-2.2.2.orig/options.h~	1970-01-01 01:00:00.000000000 +0100
-+++ openvpn-2.2.2/options.h~	2012-06-01 10:44:29.000000000 +0200
-@@ -0,0 +1,780 @@
-+/*
-+ *  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 at 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
-+ */
-+
-+/*
-+ * 2004-01-28: Added Socks5 proxy support
-+ *   (Christof Meerwald, http://cmeerw.org)
-+ */
-+
-+#ifndef OPTIONS_H
-+#define OPTIONS_H
-+
-+#include "basic.h"
-+#include "common.h"
-+#include "mtu.h"
-+#include "route.h"
-+#include "tun.h"
-+#include "socket.h"
-+#include "plugin.h"
-+#include "manage.h"
-+#include "proxy.h"
-+#include "lzo.h"
-+#include "pushlist.h"
-+
-+/*
-+ * Maximum number of parameters associated with an option,
-+ * including the option name itself.
-+ */
-+#define MAX_PARMS 16
-+
-+/*
-+ * Max size of options line and parameter.
-+ */
-+#define OPTION_PARM_SIZE 256
-+#define OPTION_LINE_SIZE 256
-+
-+extern const char title_string[];
-+
-+#if P2MP
-+
-+/* certain options are saved before --pull modifications are applied */
-+struct options_pre_pull
-+{
-+  bool tuntap_options_defined;
-+  struct tuntap_options tuntap_options;
-+
-+  bool routes_defined;
-+  struct route_option_list *routes;
-+
-+  int foreign_option_index;
-+};
-+
-+#endif
-+
-+struct connection_entry
-+{
-+  int proto;
-+  int local_port;
-+  bool local_port_defined;
-+  int remote_port;
-+  bool port_option_used;
-+  const char *local;
-+  const char *remote;
-+  bool remote_float;
-+  bool bind_defined;
-+  bool bind_local;
-+  int connect_retry_seconds;
-+  bool connect_retry_defined;
-+  int connect_retry_max;
-+  int connect_timeout;
-+  bool connect_timeout_defined;
-+#ifdef ENABLE_HTTP_PROXY
-+  struct http_proxy_options *http_proxy_options;
-+#endif  
-+#ifdef ENABLE_SOCKS
-+  const char *socks_proxy_server;
-+  int socks_proxy_port;
-+  const char *socks_proxy_authfile;
-+  bool socks_proxy_retry;
-+#endif
-+
-+# define CE_DISABLED (1<<0)
-+#if HTTP_PROXY_FALLBACK
-+# define CE_HTTP_PROXY_FALLBACK (1<<1)
-+  time_t ce_http_proxy_fallback_timestamp; /* time when fallback http_proxy_options was last updated */
-+#endif
-+
-+  unsigned int flags;
-+};
-+
-+struct remote_entry
-+{
-+  const char *remote;
-+  int remote_port;
-+  int proto;
-+};
-+
-+#ifdef ENABLE_CONNECTION
-+
-+#define CONNECTION_LIST_SIZE 64
-+
-+struct connection_list
-+{
-+  int len;
-+  int current;
-+  int n_cycles;
-+  bool no_advance;
-+  struct connection_entry *array[CONNECTION_LIST_SIZE];
-+};
-+
-+struct remote_list
-+{
-+  int len;
-+  struct remote_entry *array[CONNECTION_LIST_SIZE];
-+};
-+
-+#endif
-+
-+#if HTTP_PROXY_FALLBACK
-+struct hpo_store
-+{
-+  struct http_proxy_options hpo;
-+  char server[80];
-+};
-+#endif
-+
-+/* Command line options */
-+struct options
-+{
-+  struct gc_arena gc;
-+  bool gc_owned;
-+
-+  /* first config file */
-+  const char *config;
-+
-+  /* major mode */
-+# define MODE_POINT_TO_POINT 0
-+# define MODE_SERVER         1
-+  int mode;
-+
-+  /* enable forward compatibility for post-2.1 features */
-+  bool forward_compatible;
-+
-+  /* persist parms */
-+  bool persist_config;
-+  int persist_mode;
-+
-+#ifdef USE_CRYPTO
-+  const char *key_pass_file;
-+  bool show_ciphers;
-+  bool show_digests;
-+  bool show_engines;
-+#ifdef USE_SSL
-+  bool show_tls_ciphers;
-+#endif
-+  bool genkey;
-+#endif
-+
-+  /* Networking parms */
-+  struct connection_entry ce;
-+
-+#ifdef ENABLE_CONNECTION
-+  char *remote_ip_hint;
-+  struct connection_list *connection_list;
-+  struct remote_list *remote_list;
-+  bool force_connection_list;
-+#endif
-+
-+#ifdef GENERAL_PROXY_SUPPORT
-+  struct auto_proxy_info *auto_proxy_info;
-+#endif
-+
-+#if HTTP_PROXY_FALLBACK
-+  bool http_proxy_fallback;
-+  struct http_proxy_options *http_proxy_override;
-+  struct hpo_store *hpo_store; /* used to store dynamic proxy info given by management interface */
-+#endif
-+
-+  bool remote_random;
-+  const char *ipchange;
-+  const char *dev;
-+  const char *dev_type;
-+  const char *dev_node;
-+  const char *lladdr;
-+  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
-+  int shaper;
-+#endif
-+  int tun_mtu;           /* MTU of tun device */
-+  int tun_mtu_extra;
-+  bool tun_mtu_extra_defined;
-+  int link_mtu;          /* MTU of device over which tunnel packets pass via TCP/UDP */
-+  bool tun_mtu_defined;  /* true if user overriding parm with command line option */
-+  bool link_mtu_defined; /* true if user overriding parm with command line option */
-+
-+  int proto_force;
-+
-+  /* Advanced MTU negotiation and datagram fragmentation options */
-+  int mtu_discover_type; /* used if OS supports setting Path MTU discovery options on socket */
-+
-+#ifdef ENABLE_OCC
-+  bool mtu_test;
-+#endif
-+
-+  int fragment;                 /* internal fragmentation size */
-+
-+  bool mlock;
-+
-+  int keepalive_ping;           /* a proxy for ping/ping-restart */
-+  int keepalive_timeout;
-+
-+  int inactivity_timeout;       /* --inactive */
-+  int inactivity_minimum_bytes;
-+
-+  int ping_send_timeout;        /* Send a TCP/UDP ping to remote every n seconds */
-+  int ping_rec_timeout;         /* Expect a TCP/UDP ping from remote at least once every n seconds */
-+  bool ping_timer_remote;       /* Run ping timer only if we have a remote address */
-+  bool tun_ipv6;                /* Build tun dev that supports IPv6 */
-+
-+# define PING_UNDEF   0
-+# define PING_EXIT    1
-+# define PING_RESTART 2
-+  int ping_rec_timeout_action;  /* What action to take on ping_rec_timeout (exit or restart)? */
-+
-+#ifdef ENABLE_OCC
-+  int explicit_exit_notification;  /* Explicitly tell peer when we are exiting via OCC_EXIT message */
-+#endif
-+
-+  bool persist_tun;             /* Don't close/reopen TUN/TAP dev on SIGUSR1 or PING_RESTART */
-+  bool persist_local_ip;        /* Don't re-resolve local address on SIGUSR1 or PING_RESTART */
-+  bool persist_remote_ip;       /* Don't re-resolve remote address on SIGUSR1 or PING_RESTART */
-+  bool persist_key;             /* Don't re-read key files on SIGUSR1 or PING_RESTART */
-+
-+  int mssfix;                   /* Upper bound on TCP MSS */
-+  bool mssfix_default;          /* true if --mssfix was supplied without a parameter */
-+
-+#if PASSTOS_CAPABILITY
-+  bool passtos;                  
-+#endif
-+
-+  int resolve_retry_seconds;    /* If hostname resolve fails, retry for n seconds */
-+
-+  struct tuntap_options tuntap_options;
-+
-+  /* Misc parms */
-+  const char *username;
-+  const char *groupname;
-+  const char *chroot_dir;
-+  const char *cd_dir;
-+#ifdef HAVE_SETCON
-+  char *selinux_context;
-+#endif
-+  const char *writepid;
-+  const char *up_script;
-+  const char *down_script;
-+  bool down_pre;
-+  bool up_delay;
-+  bool up_restart;
-+  bool daemon;
-+
-+  int remap_sigusr1;
-+
-+  /* inetd modes defined in socket.h */
-+  int inetd;
-+
-+  bool log;
-+  bool suppress_timestamps;
-+  int nice;
-+  int verbosity;
-+  int mute;
-+
-+#ifdef ENABLE_DEBUG
-+  int gremlin;
-+#endif
-+
-+  const char *status_file;
-+  int status_file_version;
-+  int status_file_update_freq;
-+
-+  /* optimize TUN/TAP/UDP writes */
-+  bool fast_io;
-+
-+#ifdef USE_LZO
-+  /* LZO_x flags from lzo.h */
-+  unsigned int lzo;
-+#endif
-+
-+  /* buffer sizes */
-+  int rcvbuf;
-+  int sndbuf;
-+
-+  /* socket flags */
-+  unsigned int sockflags;
-+
-+  /* route management */
-+  const char *route_script;
-+  const char *route_default_gateway;
-+  int route_default_metric;
-+  bool route_noexec;
-+  int route_delay;
-+  int route_delay_window;
-+  bool route_delay_defined;
-+  int max_routes;
-+  struct route_option_list *routes;
-+  struct route_ipv6_option_list *routes_ipv6;			/* IPv6 */
-+  bool route_nopull;
-+  bool route_gateway_via_dhcp;
-+  bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */
-+
-+#ifdef ENABLE_OCC
-+  /* Enable options consistency check between peers */
-+  bool occ;
-+#endif
-+
-+#ifdef ENABLE_MANAGEMENT
-+  const char *management_addr;
-+  int management_port;
-+  const char *management_user_pass;
-+  int management_log_history_cache;
-+  int management_echo_buffer_size;
-+  int management_state_buffer_size;
-+  const char *management_write_peer_info_file;
-+
-+  const char *management_client_user;
-+  const char *management_client_group;
-+
-+  /* Mask of MF_ values of manage.h */
-+  unsigned int management_flags;
-+#endif
-+
-+#ifdef ENABLE_PLUGIN
-+  struct plugin_option_list *plugin_list;
-+#endif
-+
-+  const char *tmp_dir;
-+
-+#if P2MP
-+
-+#if P2MP_SERVER
-+  bool server_defined;
-+  in_addr_t server_network;
-+  in_addr_t server_netmask;
-+  bool server_ipv6_defined;				/* IPv6 */
-+  struct in6_addr server_network_ipv6;			/* IPv6 */
-+  unsigned int    server_netbits_ipv6;			/* IPv6 */
-+
-+# define SF_NOPOOL (1<<0)
-+# define SF_TCP_NODELAY_HELPER (1<<1)
-+# define SF_NO_PUSH_ROUTE_GATEWAY (1<<2)
-+  unsigned int server_flags;
-+
-+  bool server_bridge_proxy_dhcp;
-+
-+  bool server_bridge_defined;
-+  in_addr_t server_bridge_ip;
-+  in_addr_t server_bridge_netmask;
-+  in_addr_t server_bridge_pool_start;
-+  in_addr_t server_bridge_pool_end;
-+
-+  struct push_list push_list;
-+  bool ifconfig_pool_defined;
-+  in_addr_t ifconfig_pool_start;
-+  in_addr_t ifconfig_pool_end;
-+  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 *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;
-+  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;
-+  int cf_per;
-+  int max_clients;
-+  int max_routes_per_client;
-+
-+  const char *auth_user_pass_verify_script;
-+  bool auth_user_pass_verify_script_via_file;
-+  unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */
-+#if PORT_SHARE
-+  char *port_share_host;
-+  int port_share_port;
-+#endif
-+#endif
-+
-+  bool client;
-+  bool pull; /* client pull of config options from server */
-+  int push_continuation;
-+  const char *auth_user_pass_file;
-+  struct options_pre_pull *pre_pull;
-+
-+  int server_poll_timeout;
-+
-+  int scheduled_exit_interval;
-+
-+#endif
-+
-+#ifdef USE_CRYPTO
-+  /* Cipher parms */
-+  const char *shared_secret_file;
-+#if ENABLE_INLINE_FILES
-+  const char *shared_secret_file_inline;
-+#endif
-+  int key_direction;
-+  bool ciphername_defined;
-+  const char *ciphername;
-+  bool authname_defined;
-+  const char *authname;
-+  int keysize;
-+  const char *prng_hash;
-+  int prng_nonce_secret_len;
-+  const char *engine;
-+  bool replay;
-+  bool mute_replay_warnings;
-+  int replay_window;
-+  int replay_time;
-+  const char *packet_id_file;
-+  bool use_iv;
-+  bool test_crypto;
-+
-+#ifdef USE_SSL
-+  /* TLS (control channel) parms */
-+  bool tls_server;
-+  bool tls_client;
-+  const char *ca_file;
-+  const char *ca_path;
-+  const char *dh_file;
-+  const char *cert_file;
-+  const char *priv_key_file;
-+  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;
-+
-+#if ENABLE_INLINE_FILES
-+  const char *ca_file_inline;
-+  const char *cert_file_inline;
-+  char *priv_key_file_inline;
-+  const char *dh_file_inline;
-+  const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */
-+#endif
-+
-+  int ns_cert_type; /* set to 0, NS_SSL_SERVER, or NS_SSL_CLIENT */
-+  unsigned remote_cert_ku[MAX_PARMS];
-+  const char *remote_cert_eku;
-+
-+#ifdef ENABLE_PKCS11
-+  const char *pkcs11_providers[MAX_PARMS];
-+  unsigned pkcs11_private_mode[MAX_PARMS];
-+  bool pkcs11_protected_authentication[MAX_PARMS];
-+  bool pkcs11_cert_private[MAX_PARMS];
-+  int pkcs11_pin_cache_period;
-+  const char *pkcs11_id;
-+  bool pkcs11_id_management;
-+#endif
-+
-+#ifdef WIN32
-+  const char *cryptoapi_cert;
-+#endif
-+
-+  /* data channel key exchange method */
-+  int key_method;
-+
-+  /* Per-packet timeout on control channel */
-+  int tls_timeout;
-+
-+  /* Data channel key renegotiation parameters */
-+  int renegotiate_bytes;
-+  int renegotiate_packets;
-+  int renegotiate_seconds;
-+
-+  /* Data channel key handshake must finalize
-+     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;
-+
-+  /* Special authentication MAC for TLS control channel */
-+  const char *tls_auth_file;		/* shared secret */
-+#if ENABLE_INLINE_FILES
-+  const char *tls_auth_file_inline;
-+#endif
-+
-+  /* Allow only one session */
-+  bool single_session;
-+
-+#ifdef ENABLE_PUSH_PEER_INFO
-+  bool push_peer_info;
-+#endif
-+
-+  bool tls_exit;
-+
-+#endif /* USE_SSL */
-+#endif /* USE_CRYPTO */
-+
-+  /* special state parms */
-+  int foreign_option_index;
-+
-+#ifdef WIN32
-+  const char *exit_event_name;
-+  bool exit_event_initial_state;
-+  bool show_net_up;
-+  int route_method;
-+#endif
-+};
-+
-+#define streq(x, y) (!strcmp((x), (y)))
-+
-+/*
-+ * Option classes.
-+ */
-+#define OPT_P_GENERAL         (1<<0)
-+#define OPT_P_UP              (1<<1)
-+#define OPT_P_ROUTE           (1<<2)
-+#define OPT_P_IPWIN32         (1<<3)
-+#define OPT_P_SCRIPT          (1<<4)
-+#define OPT_P_SETENV          (1<<5)
-+#define OPT_P_SHAPER          (1<<6)
-+#define OPT_P_TIMER           (1<<7)
-+#define OPT_P_PERSIST         (1<<8)
-+#define OPT_P_PERSIST_IP      (1<<9)
-+#define OPT_P_COMP            (1<<10) /* TODO */
-+#define OPT_P_MESSAGES        (1<<11)
-+#define OPT_P_CRYPTO          (1<<12) /* TODO */
-+#define OPT_P_TLS_PARMS       (1<<13) /* TODO */
-+#define OPT_P_MTU             (1<<14) /* TODO */
-+#define OPT_P_NICE            (1<<15)
-+#define OPT_P_PUSH            (1<<16)
-+#define OPT_P_INSTANCE        (1<<17)
-+#define OPT_P_CONFIG          (1<<18)
-+#define OPT_P_EXPLICIT_NOTIFY (1<<19)
-+#define OPT_P_ECHO            (1<<20)
-+#define OPT_P_INHERIT         (1<<21)
-+#define OPT_P_ROUTE_EXTRAS    (1<<22)
-+#define OPT_P_PULL_MODE       (1<<23)
-+#define OPT_P_PLUGIN          (1<<24)
-+#define OPT_P_SOCKBUF         (1<<25)
-+#define OPT_P_SOCKFLAGS       (1<<26)
-+#define OPT_P_CONNECTION      (1<<27)
-+
-+#define OPT_P_DEFAULT   (~(OPT_P_INSTANCE|OPT_P_PULL_MODE))
-+
-+#if P2MP
-+#define PULL_DEFINED(opt) ((opt)->pull)
-+#if P2MP_SERVER
-+#define PUSH_DEFINED(opt) ((opt)->push_list)
-+#endif
-+#endif
-+
-+#ifndef PULL_DEFINED
-+#define PULL_DEFINED(opt) (false)
-+#endif
-+
-+#ifndef PUSH_DEFINED
-+#define PUSH_DEFINED(opt) (false)
-+#endif
-+
-+#ifdef WIN32
-+#define ROUTE_OPTION_FLAGS(o) ((o)->route_method & ROUTE_METHOD_MASK)
-+#else
-+#define ROUTE_OPTION_FLAGS(o) (0)
-+#endif
-+
-+#ifdef HAVE_GETTIMEOFDAY
-+#define SHAPER_DEFINED(opt) ((opt)->shaper)
-+#else
-+#define SHAPER_DEFINED(opt) (false)
-+#endif
-+
-+#ifdef ENABLE_PLUGIN
-+#define PLUGIN_OPTION_LIST(opt) ((opt)->plugin_list)
-+#else
-+#define PLUGIN_OPTION_LIST(opt) (NULL)
-+#endif
-+
-+#ifdef MANAGEMENT_DEF_AUTH
-+#define MAN_CLIENT_AUTH_ENABLED(opt) ((opt)->management_flags & MF_CLIENT_AUTH)
-+#else
-+#define MAN_CLIENT_AUTH_ENABLED(opt) (false)
-+#endif
-+
-+void parse_argv (struct options *options,
-+		 const int argc,
-+		 char *argv[],
-+		 const int msglevel,
-+		 const unsigned int permission_mask,
-+		 unsigned int *option_types_found,
-+		 struct env_set *es);
-+
-+void notnull (const char *arg, const char *description);
-+
-+void usage_small (void);
-+
-+void init_options (struct options *o, const bool init_gc);
-+void uninit_options (struct options *o);
-+
-+void setenv_settings (struct env_set *es, const struct options *o);
-+void show_settings (const struct options *o);
-+
-+bool string_defined_equal (const char *s1, const char *s2);
-+
-+#ifdef ENABLE_OCC
-+
-+const char *options_string_version (const char* s, struct gc_arena *gc);
-+
-+char *options_string (const struct options *o,
-+		      const struct frame *frame,
-+		      struct tuntap *tt,
-+		      bool remote,
-+		      struct gc_arena *gc);
-+
-+bool options_cmp_equal_safe (char *actual, const char *expected, size_t actual_n);
-+void options_warning_safe (char *actual, const char *expected, size_t actual_n);
-+bool options_cmp_equal (char *actual, const char *expected);
-+void options_warning (char *actual, const char *expected);
-+
-+#endif
-+
-+void options_postprocess (struct options *options);
-+
-+void pre_pull_save (struct options *o);
-+void pre_pull_restore (struct options *o);
-+
-+bool apply_push_options (struct options *options,
-+			 struct buffer *buf,
-+			 unsigned int permission_mask,
-+			 unsigned int *option_types_found,
-+			 struct env_set *es);
-+
-+bool is_persist_option (const struct options *o);
-+bool is_stateful_restart (const struct options *o);
-+
-+void options_detach (struct options *o);
-+
-+void options_server_import (struct options *o,
-+			    const char *filename,
-+			    int msglevel,
-+			    unsigned int permission_mask,
-+			    unsigned int *option_types_found,
-+			    struct env_set *es);
-+
-+void pre_pull_default (struct options *o);
-+
-+void rol_check_alloc (struct options *options);
-+
-+int parse_line (const char *line,
-+		char *p[],
-+		const int n,
-+		const char *file,
-+		const int line_num,
-+		int msglevel,
-+		struct gc_arena *gc);
-+
-+/*
-+ * parse/print topology coding
-+ */
-+
-+int parse_topology (const char *str, const int msglevel);
-+const char *print_topology (const int topology);
-+
-+/*
-+ * Manage auth-retry variable
-+ */
-+
-+#if P2MP
-+
-+#define AR_NONE       0
-+#define AR_INTERACT   1
-+#define AR_NOINTERACT 2
-+
-+int auth_retry_get (void);
-+bool auth_retry_set (const int msglevel, const char *option);
-+const char *auth_retry_print (void);
-+
-+#endif
-+
-+void options_string_import (struct options *options,
-+			    const char *config,
-+			    const int msglevel,
-+			    const unsigned int permission_mask,
-+			    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
-+ */
-+static inline bool
-+connection_list_defined (const struct options *o)
-+{
-+#ifdef ENABLE_CONNECTION
-+  return o->connection_list != NULL;
-+#else
-+  return false;
-+#endif
-+}
-+
-+static inline void
-+connection_list_set_no_advance (struct options *o)
-+{
-+#ifdef ENABLE_CONNECTION
-+  if (o->connection_list)
-+    o->connection_list->no_advance = true;
-+#endif
-+}
-+
-+#if HTTP_PROXY_FALLBACK
-+
-+struct http_proxy_options *
-+parse_http_proxy_fallback (struct context *c,
-+			   const char *server,
-+			   const char *port,
-+			   const char *flags,
-+			   const int msglevel);
-+
-+#endif /* HTTP_PROXY_FALLBACK */
-+
-+#endif
-diff -durN openvpn-2.2.2.orig/pool.c openvpn-2.2.2/pool.c
---- openvpn-2.2.2.orig/pool.c	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/pool.c	2012-06-01 10:40:28.000000000 +0200
-@@ -132,7 +132,10 @@
- }
- 
- 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 @@
-       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_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 @@
- 	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 @@
-   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 @@
- 	  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 @@
- 	      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 @@
- 		  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 @@
- #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 @@
- #else
-       cn = buf;
- #endif
--      h = ifconfig_pool_acquire (p, &local, &remote, cn);
-+      h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn);
-       if (h < 0)
- 	break;
-       msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s",
-diff -durN openvpn-2.2.2.orig/pool.h openvpn-2.2.2/pool.h
---- openvpn-2.2.2.orig/pool.h	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/pool.h	2012-06-01 10:40:28.000000000 +0200
-@@ -52,6 +52,9 @@
-   int size;
-   int type;
-   bool duplicate_cn;
-+  bool ipv6;
-+  struct in6_addr base_ipv6;
-+  unsigned int size_ipv6;
-   struct ifconfig_pool_entry *list;
- };
- 
-@@ -63,13 +66,13 @@
- 
- typedef int ifconfig_pool_handle;
- 
--struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn);
-+struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn, const bool ipv6_pool, const struct in6_addr ipv6_base, const int ipv6_netbits );
- 
- void ifconfig_pool_free (struct ifconfig_pool *pool);
- 
- bool ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end);
- 
--ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name);
-+ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name);
- 
- bool ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard);
- 
-diff -durN openvpn-2.2.2.orig/proto.h openvpn-2.2.2/proto.h
---- openvpn-2.2.2.orig/proto.h	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/proto.h	2012-06-01 10:40:28.000000000 +0200
-@@ -108,6 +108,21 @@
- };
- 
- /*
-+ * IPv6 header
-+ */
-+struct openvpn_ipv6hdr {
-+        uint8_t		version_prio;
-+        uint8_t		flow_lbl[3];
-+        uint16_t	payload_len;
-+        uint8_t		nexthdr;
-+        uint8_t		hop_limit;
-+
-+        struct  in6_addr        saddr;
-+        struct  in6_addr        daddr;
-+};
-+
-+
-+/*
-  * UDP header
-  */
- struct openvpn_udphdr {
-diff -durN openvpn-2.2.2.orig/push.c openvpn-2.2.2/push.c
---- openvpn-2.2.2.orig/push.c	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/push.c	2012-06-01 10:40:28.000000000 +0200
-@@ -189,8 +189,26 @@
-   const int safe_cap = BCAP (&buf) - extra;
-   bool push_sent = false;
- 
-+  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)
-     {
-       if (e->enable)
-diff -durN openvpn-2.2.2.orig/route.c openvpn-2.2.2/route.c
---- openvpn-2.2.2.orig/route.c	2011-12-13 17:58:56.000000000 +0100
-+++ openvpn-2.2.2/route.c	2012-06-01 10:40:28.000000000 +0200
-@@ -35,6 +35,7 @@
- #include "socket.h"
- #include "manage.h"
- #include "win32.h"
-+#include "options.h"
- 
- #include "memdbg.h"
- 
-@@ -68,6 +69,15 @@
-   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)
- {
-@@ -95,6 +105,15 @@
-   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)
- {
-@@ -311,6 +330,68 @@
-   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,
-@@ -331,6 +412,23 @@
- }
- 
- 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;
-@@ -340,6 +438,15 @@
- }
- 
- void
-+clear_route_ipv6_list (struct route_ipv6_list *rl6)
-+{
-+  const int capacity = rl6->capacity;
-+  const size_t rl6_size = array_mult_safe (sizeof(struct route_ipv6), capacity, sizeof(struct route_ipv6_list));
-+  memset(rl6, 0, rl6_size);
-+  rl6->capacity = capacity;
-+}
-+
-+void
- route_list_add_default_gateway (struct route_list *rl,
- 				struct env_set *es,
- 				const in_addr_t addr)
-@@ -469,6 +576,72 @@
-   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,
-@@ -704,10 +877,13 @@
- }
- 
- void
--add_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
-+add_routes (struct route_list *rl, struct route_ipv6_list *rl6,
-+	    const struct tuntap *tt, unsigned int flags, const struct env_set *es)
- {
--  redirect_default_route_to_vpn (rl, tt, flags, es);
--  if (!rl->routes_added)
-+  if (rl) 
-+      redirect_default_route_to_vpn (rl, tt, flags, es);
-+
-+  if (rl && !rl->routes_added)
-     {
-       int i;
- 
-@@ -732,12 +908,27 @@
- 	}
-       rl->routes_added = true;
-     }
-+
-+  if (rl6 && !rl6->routes_added)
-+    {
-+      int i;
-+
-+      for (i = 0; i < rl6->n; ++i)
-+	{
-+	  struct route_ipv6 *r = &rl6->routes_ipv6[i];
-+	  if (flags & ROUTE_DELETE_FIRST)
-+	    delete_route_ipv6 (r, tt, flags, es);
-+	  add_route_ipv6 (r, tt, flags, es);
-+	}
-+      rl6->routes_added = true;
-+    }
- }
- 
- void
--delete_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
-+delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
-+	       const struct tuntap *tt, unsigned int flags, const struct env_set *es)
- {
--  if (rl->routes_added)
-+  if (rl && rl->routes_added)
-     {
-       int i;
-       for (i = rl->n - 1; i >= 0; --i)
-@@ -747,9 +938,28 @@
- 	}
-       rl->routes_added = false;
-     }
--  undo_redirect_default_route_to_vpn (rl, tt, flags, es);
- 
--  clear_route_list (rl);
-+  if ( rl )
-+    {
-+      undo_redirect_default_route_to_vpn (rl, tt, flags, es);
-+      clear_route_list (rl);
-+    }
-+
-+  if ( rl6 && rl6->routes_added )
-+    {
-+      int i;
-+      for (i = rl6->n - 1; i >= 0; --i)
-+	{
-+	  const struct route_ipv6 *r6 = &rl6->routes_ipv6[i];
-+	  delete_route_ipv6 (r6, tt, flags, es);
-+	}
-+      rl6->routes_added = false;
-+    }
-+
-+  if ( rl6 )
-+    {
-+      clear_route_ipv6_list (rl6);
-+    }
- }
- 
- #ifdef ENABLE_DEBUG
-@@ -832,6 +1042,34 @@
-     setenv_route (es, &rl->routes[i], i + 1);
- }
- 
-+static void
-+setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i)
-+{
-+  struct gc_arena gc = gc_new ();
-+  if (r6->defined)
-+    {
-+      struct buffer name1 = alloc_buf_gc( 256, &gc );
-+      struct buffer val = alloc_buf_gc( 256, &gc );
-+      struct buffer name2 = alloc_buf_gc( 256, &gc );
-+
-+      buf_printf( &name1, "route_ipv6_network_%d", i );
-+      buf_printf( &val, "%s/%d", print_in6_addr( r6->network, 0, &gc ),
-+				 r6->netbits );
-+      setenv_str( es, BSTR(&name1), BSTR(&val) );
-+
-+      buf_printf( &name2, "route_ipv6_gateway_%d", i );
-+      setenv_str( es, BSTR(&name2), print_in6_addr( r6->gateway, 0, &gc ));
-+    }
-+  gc_free (&gc);
-+}
-+void
-+setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6)
-+{
-+  int i;
-+  for (i = 0; i < rl6->n; ++i)
-+    setenv_route_ipv6 (es, &rl6->routes_ipv6[i], i + 1);
-+}
-+
- void
- add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
- {
-@@ -1025,6 +1263,187 @@
-   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 );
<Skipped 6519 lines>
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/openvpn.git/commitdiff/a369078e50c97d328dd89c06b4e052d9534eb8e2



More information about the pld-cvs-commit mailing list