Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 303393 Details for
Bug 405937
net-misc/openvpn-2.2.2 - re-add IPv6 payload patch
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
openvpn-2.2.2-ipv6-payload.patch
openvpn-2.2.2-ipv6-payload.patch (text/plain), 129.30 KB, created by
Marcel Pennewiß
on 2012-02-26 17:48:36 UTC
(
hide
)
Description:
openvpn-2.2.2-ipv6-payload.patch
Filename:
MIME Type:
Creator:
Marcel Pennewiß
Created:
2012-02-26 17:48:36 UTC
Size:
129.30 KB
patch
obsolete
>diff -Naur openvpn-2.2.2_unpatched//ChangeLog.IPv6 openvpn-2.2.2/ChangeLog.IPv6 >--- openvpn-2.2.2_unpatched//ChangeLog.IPv6 1970-01-01 01:00:00.000000000 +0100 >+++ openvpn-2.2.2/ChangeLog.IPv6 2012-02-26 18:02:09.639865797 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//README.IPv6 openvpn-2.2.2/README.IPv6 >--- openvpn-2.2.2_unpatched//README.IPv6 1970-01-01 01:00:00.000000000 +0100 >+++ openvpn-2.2.2/README.IPv6 2012-02-26 18:02:09.686532841 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//TODO.IPv6 openvpn-2.2.2/TODO.IPv6 >--- openvpn-2.2.2_unpatched//TODO.IPv6 1970-01-01 01:00:00.000000000 +0100 >+++ openvpn-2.2.2/TODO.IPv6 2012-02-26 18:02:09.686532841 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//forward.c openvpn-2.2.2/forward.c >--- openvpn-2.2.2_unpatched//forward.c 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/forward.c 2012-02-26 18:02:09.686532841 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//helper.c openvpn-2.2.2/helper.c >--- openvpn-2.2.2_unpatched//helper.c 2012-02-26 18:02:05.953169291 +0100 >+++ openvpn-2.2.2/helper.c 2012-02-26 18:02:09.686532841 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//init.c openvpn-2.2.2/init.c >--- openvpn-2.2.2_unpatched//init.c 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/init.c 2012-02-26 18:02:09.689866201 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//init.h openvpn-2.2.2/init.h >--- openvpn-2.2.2_unpatched//init.h 2012-02-26 18:02:05.959836011 +0100 >+++ openvpn-2.2.2/init.h 2012-02-26 18:02:09.689866201 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//misc.c openvpn-2.2.2/misc.c >--- openvpn-2.2.2_unpatched//misc.c 2012-02-26 18:02:05.953169291 +0100 >+++ openvpn-2.2.2/misc.c 2012-02-26 18:02:09.693199561 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//mroute.c openvpn-2.2.2/mroute.c >--- openvpn-2.2.2_unpatched//mroute.c 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/mroute.c 2012-02-26 18:04:08.424160547 +0100 >@@ -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; >+ 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; >- } >+ 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 -Naur openvpn-2.2.2_unpatched//mroute.h openvpn-2.2.2/mroute.h >--- openvpn-2.2.2_unpatched//mroute.h 2012-02-26 18:02:05.953169291 +0100 >+++ openvpn-2.2.2/mroute.h 2012-02-26 18:02:09.693199561 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//multi.c openvpn-2.2.2/multi.c >--- openvpn-2.2.2_unpatched//multi.c 2012-02-26 18:02:05.953169291 +0100 >+++ openvpn-2.2.2/multi.c 2012-02-26 18:02:09.693199561 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//openvpn.8 openvpn-2.2.2/openvpn.8 >--- openvpn-2.2.2_unpatched//openvpn.8 2012-02-26 18:02:05.953169291 +0100 >+++ openvpn-2.2.2/openvpn.8 2012-02-26 18:02:09.696532922 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//openvpn.h openvpn-2.2.2/openvpn.h >--- openvpn-2.2.2_unpatched//openvpn.h 2012-02-26 18:02:05.953169291 +0100 >+++ openvpn-2.2.2/openvpn.h 2012-02-26 18:02:09.699866283 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//options.c openvpn-2.2.2/options.c >--- openvpn-2.2.2_unpatched//options.c 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/options.c 2012-02-26 18:02:09.703199644 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//options.h openvpn-2.2.2/options.h >--- openvpn-2.2.2_unpatched//options.h 2012-02-26 18:02:05.959836011 +0100 >+++ openvpn-2.2.2/options.h 2012-02-26 18:32:07.373515779 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//pool.c openvpn-2.2.2/pool.c >--- openvpn-2.2.2_unpatched//pool.c 2012-02-26 18:02:05.959836011 +0100 >+++ openvpn-2.2.2/pool.c 2012-02-26 18:02:09.706533004 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//pool.h openvpn-2.2.2/pool.h >--- openvpn-2.2.2_unpatched//pool.h 2012-02-26 18:02:05.959836011 +0100 >+++ openvpn-2.2.2/pool.h 2012-02-26 18:02:09.709866364 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//proto.h openvpn-2.2.2/proto.h >--- openvpn-2.2.2_unpatched//proto.h 2012-02-26 18:02:05.953169291 +0100 >+++ openvpn-2.2.2/proto.h 2012-02-26 18:02:09.709866364 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//push.c openvpn-2.2.2/push.c >--- openvpn-2.2.2_unpatched//push.c 2012-02-26 18:02:05.959836011 +0100 >+++ openvpn-2.2.2/push.c 2012-02-26 18:02:09.709866364 +0100 >@@ -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 -Naur openvpn-2.2.2_unpatched//route.c openvpn-2.2.2/route.c >--- openvpn-2.2.2_unpatched//route.c 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/route.c 2012-02-26 18:02:09.709866364 +0100 >@@ -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 ); >+ >+ argv_msg (D_ROUTE, &argv); >+ status = openvpn_execve_check (&argv, es, 0, "ERROR: MacOS X route add -inet6 command failed"); >+ >+#elif defined(TARGET_OPENBSD) >+ >+ argv_printf (&argv, "%s add -inet6 %s -prefixlen %d %s", >+ ROUTE_PATH, >+ network, r6->netbits, gateway ); >+ >+ argv_msg (D_ROUTE, &argv); >+ status = openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD route add -inet6 command failed"); >+ >+#elif defined(TARGET_NETBSD) >+ >+ argv_printf (&argv, "%s add -inet6 %s/%d %s", >+ ROUTE_PATH, >+ network, r6->netbits, gateway ); >+ >+ argv_msg (D_ROUTE, &argv); >+ status = openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route add -inet6 command failed"); >+ >+#else >+ msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-up script"); >+#endif >+ >+ r6->defined = status; >+ argv_reset (&argv); >+ gc_free (&gc); >+} >+ > static void > delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es) > { >@@ -1161,6 +1580,142 @@ > #endif > > argv_reset (&argv); >+ gc_free (&gc); >+} >+ >+void >+delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) >+{ >+ struct gc_arena gc; >+ struct argv argv; >+ const char *network; >+ const char *gateway; >+ const char *device = tt->actual_name; >+ >+ if (!r6->defined) >+ return; >+ >+ gc_init (&gc); >+ argv_init (&argv); >+ >+ network = print_in6_addr_netbits_only( r6->network, r6->netbits, &gc); >+ gateway = print_in6_addr( r6->gateway, 0, &gc); >+ >+ if ( !tt->ipv6 ) >+ { >+ msg( M_INFO, "delete_route_ipv6(): not deleting %s/%d, no IPv6 on if %s", >+ network, r6->netbits, device ); >+ return; >+ } >+ >+ msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits ); >+ >+#if defined(TARGET_LINUX) >+#ifdef CONFIG_FEATURE_IPROUTE >+ argv_printf (&argv, "%s -6 route del %s/%d dev %s", >+ iproute_path, >+ network, >+ r6->netbits, >+ device); >+#else >+ argv_printf (&argv, "%s -A inet6 del %s/%d dev %s", >+ ROUTE_PATH, >+ network, >+ r6->netbits, >+ device); >+#endif /*CONFIG_FEATURE_IPROUTE*/ >+ argv_msg (D_ROUTE, &argv); >+ openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 del command failed"); >+ >+#elif defined (WIN32) >+ >+ /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */ >+ argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s", >+ get_win_sys_path(), >+ NETSH_PATH_SUFFIX, >+ network, >+ r6->netbits, >+ device); >+ >+ /* next-hop depends on TUN or TAP mode: >+ * - in TAP mode, we use the "real" next-hop >+ * - in TUN mode we use a special-case link-local address that the tapdrvr >+ * knows about and will answer ND (neighbor discovery) packets for >+ * (and "route deletion without specifying next-hop" does not work...) >+ */ >+ if ( tt->type == DEV_TYPE_TUN ) >+ argv_printf_cat( &argv, " %s", "fe80::8" ); >+ else >+ argv_printf_cat( &argv, " %s", gateway ); >+ >+#if 0 >+ if (r->metric_defined) >+ argv_printf_cat (&argv, "METRIC %d", r->metric); >+#endif >+ >+ argv_msg (D_ROUTE, &argv); >+ >+ netcmd_semaphore_lock (); >+ openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed"); >+ netcmd_semaphore_release (); >+ >+#elif defined (TARGET_SOLARIS) >+ >+ /* example: route delete -inet6 2001:db8::/32 somegateway */ >+ /* GERT-TODO: this is untested, but should work */ >+ >+ argv_printf (&argv, "%s delete -inet6 %s/%d %s", >+ ROUTE_PATH, >+ network, >+ r6->netbits, >+ gateway ); >+ >+ argv_msg (D_ROUTE, &argv); >+ openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route delete -inet6 command failed"); >+ >+#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) >+ >+ argv_printf (&argv, "%s delete -inet6 %s/%d -iface %s", >+ ROUTE_PATH, >+ network, >+ r6->netbits, >+ device ); >+ >+ argv_msg (D_ROUTE, &argv); >+ openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed"); >+ >+#elif defined(TARGET_DARWIN) >+ >+ argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d -iface %s", >+ ROUTE_PATH, >+ network, r6->netbits, device ); >+ >+ argv_msg (D_ROUTE, &argv); >+ openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed"); >+ >+#elif defined(TARGET_OPENBSD) >+ >+ argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d %s", >+ ROUTE_PATH, >+ network, r6->netbits, gateway ); >+ >+ argv_msg (D_ROUTE, &argv); >+ openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD route delete -inet6 command failed"); >+ >+#elif defined(TARGET_NETBSD) >+ >+ argv_printf (&argv, "%s delete -inet6 %s/%d %s", >+ ROUTE_PATH, >+ network, r6->netbits, gateway ); >+ >+ argv_msg (D_ROUTE, &argv); >+ openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route delete -inet6 command failed"); >+ >+#else >+ msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-down script"); >+#endif >+ >+ argv_reset (&argv); > gc_free (&gc); > } > >diff -Naur openvpn-2.2.2_unpatched//route.h openvpn-2.2.2/route.h >--- openvpn-2.2.2_unpatched//route.h 2012-02-26 18:02:05.959836011 +0100 >+++ openvpn-2.2.2/route.h 2012-02-26 18:02:09.713199724 +0100 >@@ -92,6 +92,19 @@ > struct route_option routes[EMPTY_ARRAY_SIZE]; > }; > >+struct route_ipv6_option { >+ const char *prefix; /* e.g. "2001:db8:1::/64" */ >+ const char *gateway; /* e.g. "2001:db8:0::2" */ >+ const char *metric; /* e.g. "5" */ >+}; >+ >+struct route_ipv6_option_list { >+ unsigned int flags; >+ int capacity; >+ int n; >+ struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE]; >+}; >+ > struct route { > bool defined; > const struct route_option *option; >@@ -113,6 +126,31 @@ > struct route routes[EMPTY_ARRAY_SIZE]; > }; > >+struct route_ipv6 { >+ bool defined; >+ const struct route_ipv6_option *option; >+ struct in6_addr network; >+ unsigned int netbits; >+ struct in6_addr gateway; >+ bool metric_defined; >+ int metric; >+}; >+ >+struct route_ipv6_list { >+ bool routes_added; >+ unsigned int flags; >+ int default_metric; >+ bool default_metric_defined; >+ struct in6_addr remote_endpoint_ipv6; >+ bool remote_endpoint_defined; >+ bool did_redirect_default_gateway; /* TODO (?) */ >+ bool did_local; /* TODO (?) */ >+ int capacity; >+ int n; >+ struct route_ipv6 routes_ipv6[EMPTY_ARRAY_SIZE]; >+}; >+ >+ > #if P2MP > /* internal OpenVPN route */ > struct iroute { >@@ -120,15 +158,25 @@ > int netbits; > struct iroute *next; > }; >+ >+struct iroute_ipv6 { >+ struct in6_addr network; >+ unsigned int netbits; >+ struct iroute_ipv6 *next; >+}; > #endif > > struct route_option_list *new_route_option_list (const int max_routes, struct gc_arena *a); >+struct route_ipv6_option_list *new_route_ipv6_option_list (const int max_routes, struct gc_arena *a); > struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a); > void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src); > > struct route_list *new_route_list (const int max_routes, struct gc_arena *a); >+struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_arena *a); > > void add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); >+void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); >+void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); > > void add_route_to_option_list (struct route_option_list *l, > const char *network, >@@ -136,6 +184,11 @@ > const char *gateway, > const char *metric); > >+void add_route_ipv6_to_option_list (struct route_ipv6_option_list *l, >+ const char *prefix, >+ const char *gateway, >+ const char *metric); >+ > bool init_route_list (struct route_list *rl, > const struct route_option_list *opt, > const char *remote_endpoint, >@@ -143,21 +196,30 @@ > in_addr_t remote_host, > struct env_set *es); > >+bool init_route_ipv6_list (struct route_ipv6_list *rl6, >+ const struct route_ipv6_option_list *opt6, >+ const char *remote_endpoint, >+ int default_metric, >+ struct env_set *es); >+ > void route_list_add_default_gateway (struct route_list *rl, > struct env_set *es, > const in_addr_t addr); > > void add_routes (struct route_list *rl, >+ struct route_ipv6_list *rl6, > const struct tuntap *tt, > unsigned int flags, > const struct env_set *es); > > void delete_routes (struct route_list *rl, >+ struct route_ipv6_list *rl6, > const struct tuntap *tt, > unsigned int flags, > const struct env_set *es); > > void setenv_routes (struct env_set *es, const struct route_list *rl); >+void setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6); > > bool is_special_addr (const char *addr_str); > >diff -Naur openvpn-2.2.2_unpatched//socket.c openvpn-2.2.2/socket.c >--- openvpn-2.2.2_unpatched//socket.c 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/socket.c 2012-02-26 18:02:09.713199724 +0100 >@@ -342,6 +342,24 @@ > } > } > >+bool >+ipv6_addr_safe (const char *ipv6_text_addr) >+{ >+ /* verify non-NULL */ >+ if (!ipv6_text_addr) >+ return false; >+ >+ /* verify length is within limits */ >+ if (strlen (ipv6_text_addr) > INET6_ADDRSTRLEN ) >+ return false; >+ >+ /* verify that string will convert to IPv6 address */ >+ { >+ struct in6_addr a6; >+ return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1; >+ } >+} >+ > static bool > dns_addr_safe (const char *addr) > { >@@ -2032,6 +2050,55 @@ > return BSTR (&out); > } > >+/* >+ * Convert an in6_addr in host byte order >+ * to an ascii representation of an IPv6 address >+ */ >+const char * >+print_in6_addr (struct in6_addr a6, unsigned int flags, struct gc_arena *gc) >+{ >+ struct buffer out = alloc_buf_gc (64, gc); >+ char tmp_out_buf[64]; /* inet_ntop wants pointer to buffer */ >+ >+ if ( memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 || >+ !(flags & IA_EMPTY_IF_UNDEF)) >+ { >+ inet_ntop (AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1); >+ buf_printf (&out, "%s", tmp_out_buf ); >+ } >+ return BSTR (&out); >+} >+ >+/* add some offset to an ipv6 address >+ * (add in steps of 32 bits, taking overflow into next round) >+ */ >+#ifndef s6_addr32 >+# ifdef TARGET_SOLARIS >+# define s6_addr32 _S6_un._S6_u32 >+# else >+# define s6_addr32 __u6_addr.__u6_addr32 >+# endif >+#endif >+#ifndef UINT32_MAX >+# define UINT32_MAX (4294967295U) >+#endif >+struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add ) >+{ >+ int i; >+ uint32_t h; >+ >+ for( i=3; i>=0 && add > 0 ; i-- ) >+ { >+ h = ntohl( base.s6_addr32[i] ); >+ base.s6_addr32[i] = htonl( (h+add) & UINT32_MAX ); >+ /* 32-bit overrun? >+ * caveat: can't do "h+add > UINT32_MAX" with 32bit math! >+ */ >+ add = ( h > UINT32_MAX - add )? 1: 0; >+ } >+ return base; >+} >+ > /* set environmental variables for ip/port in *addr */ > void > setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags) >@@ -2337,6 +2404,58 @@ > > #ifdef WIN32 > >+/* >+ * inet_ntop() and inet_pton() wrap-implementations using >+ * WSAAddressToString() and WSAStringToAddress() functions >+ */ >+const char * >+inet_ntop(int af, const void *src, char *dst, socklen_t size) >+{ >+ struct sockaddr_storage ss; >+ unsigned long s = size; >+ >+ CLEAR(ss); >+ ss.ss_family = af; >+ >+ switch(af) { >+ case AF_INET: >+ ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src; >+ break; >+ case AF_INET6: >+ ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src; >+ break; >+ default: >+ ASSERT (0); >+ } >+ // cannot direclty use &size because of strict aliasing rules >+ return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)? >+ dst : NULL; >+} >+ >+int >+inet_pton(int af, const char *src, void *dst) >+{ >+ struct sockaddr_storage ss; >+ int size = sizeof(ss); >+ char src_copy[INET6_ADDRSTRLEN+1]; >+ >+ CLEAR(ss); >+ // stupid non-const API >+ strncpynt(src_copy, src, INET6_ADDRSTRLEN+1); >+ >+ if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) { >+ switch(af) { >+ case AF_INET: >+ *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr; >+ return 1; >+ case AF_INET6: >+ *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr; >+ return 1; >+ } >+ } >+ return 0; >+} >+ > int > socket_recv_queue (struct link_socket *sock, int maxsize) > { >diff -Naur openvpn-2.2.2_unpatched//socket.h openvpn-2.2.2/socket.h >--- openvpn-2.2.2_unpatched//socket.h 2012-02-26 18:02:05.953169291 +0100 >+++ openvpn-2.2.2/socket.h 2012-02-26 18:02:09.713199724 +0100 >@@ -351,6 +351,8 @@ > #define IA_EMPTY_IF_UNDEF (1<<0) > #define IA_NET_ORDER (1<<1) > const char *print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc); >+const char *print_in6_addr (struct in6_addr addr6, unsigned int flags, struct gc_arena *gc); >+struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add ); > > #define SA_IP_PORT (1<<0) > #define SA_SET_IF_NONZERO (1<<1) >@@ -404,6 +406,7 @@ > bool ip_addr_dotted_quad_safe (const char *dotted_quad); > bool ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn); > bool mac_addr_safe (const char *mac_addr); >+bool ipv6_addr_safe (const char *ipv6_text_addr); > > socket_descriptor_t create_socket_tcp (void); > >diff -Naur openvpn-2.2.2_unpatched//syshead.h openvpn-2.2.2/syshead.h >--- openvpn-2.2.2_unpatched//syshead.h 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/syshead.h 2012-02-26 18:02:09.716533084 +0100 >@@ -28,6 +28,10 @@ > /* > * Only include if not during configure > */ >+#ifdef WIN32 >+/* USE_PF_INET6: win32 ipv6 exists only after 0x0501 (XP) */ >+#define WINVER 0x0501 >+#endif > #ifndef PACKAGE_NAME > #include "config.h" > #endif >@@ -339,6 +343,9 @@ > #ifdef WIN32 > #include <iphlpapi.h> > #include <wininet.h> >+/* The following two headers are needed of USE_PF_INET6 */ >+#include <winsock2.h> >+#include <ws2tcpip.h> > #endif > > #ifdef HAVE_SYS_MMAN_H >diff -Naur openvpn-2.2.2_unpatched//tun.c openvpn-2.2.2/tun.c >--- openvpn-2.2.2_unpatched//tun.c 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/tun.c 2012-02-26 18:20:37.172163299 +0100 >@@ -56,13 +56,14 @@ > const in_addr_t ip, > const in_addr_t netmask, > const unsigned int flags); >+static void netsh_command (const struct argv *a, int n); > > static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc); > > #endif > > #ifdef TARGET_SOLARIS >-static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual); >+static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual, bool unplumb_inet6); > #include <stropts.h> > #endif > >@@ -129,30 +130,6 @@ > return dev; > } > >-/* >- * Called by the open_tun function of OSes to check if we >- * explicitly support IPv6. >- * >- * In this context, explicit means that the OS expects us to >- * do something special to the tun socket in order to support >- * IPv6, i.e. it is not transparent. >- * >- * ipv6_explicitly_supported should be set to false if we don't >- * have any explicit IPv6 code in the tun device handler. >- * >- * If ipv6_explicitly_supported is true, then we have explicit >- * OS-specific tun dev code for handling IPv6. If so, tt->ipv6 >- * is set according to the --tun-ipv6 command line option. >- */ >-static void >-ipv6_support (bool ipv6, bool ipv6_explicitly_supported, struct tuntap* tt) >-{ >- tt->ipv6 = false; >- if (ipv6_explicitly_supported) >- tt->ipv6 = ipv6; >- else if (ipv6) >- msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS"); >-} > > /* --ifconfig-nowarn disables some options sanity checking */ > static const char ifconfig_warn_how_to_silence[] = "(silence this warning with --ifconfig-nowarn)"; >@@ -423,6 +400,8 @@ > int topology, /* one of the TOP_x values */ > const char *ifconfig_local_parm, /* --ifconfig parm 1 */ > const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */ >+ const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 IPv6 */ >+ const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 IPv6 */ > in_addr_t local_public, > in_addr_t remote_public, > const bool strict_warn, >@@ -537,6 +516,40 @@ > > tt->did_ifconfig_setup = true; > } >+ >+ if (ifconfig_ipv6_local_parm && ifconfig_ipv6_remote_parm) >+ { >+ const char *ifconfig_ipv6_local = NULL; >+ const char *ifconfig_ipv6_remote = NULL; >+ >+ /* >+ * Convert arguments to binary IPv6 addresses. >+ */ >+ >+ if ( inet_pton( AF_INET6, ifconfig_ipv6_local_parm, &tt->local_ipv6 ) != 1 || >+ inet_pton( AF_INET6, ifconfig_ipv6_remote_parm, &tt->remote_ipv6 ) != 1 ) >+ { >+ msg( M_FATAL, "init_tun: problem converting IPv6 ifconfig addresses %s and %s to binary", ifconfig_ipv6_local_parm, ifconfig_ipv6_remote_parm ); >+ } >+ tt->netbits_ipv6 = 64; >+ >+ /* >+ * Set ifconfig parameters >+ */ >+ ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); >+ ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); >+ >+ /* >+ * Set environmental variables with ifconfig parameters. >+ */ >+ if (es) >+ { >+ setenv_str (es, "ifconfig_ipv6_local", ifconfig_ipv6_local); >+ setenv_str (es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote); >+ } >+ tt->did_ifconfig_ipv6_setup = true; >+ } >+ > gc_free (&gc); > return tt; > } >@@ -559,6 +572,40 @@ > #endif > } > >+#if defined(TARGET_WIN32) || \ >+ defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) >+ >+/* some of the platforms will auto-add a "network route" pointing >+ * to the interface on "ifconfig tunX 2001:db8::1/64", others need >+ * an extra call to "route add..." >+ * -> helper function to simplify code below >+ */ >+void add_route_connected_v6_net(struct tuntap * tt, >+ const struct env_set *es) >+{ >+ struct route_ipv6 r6; >+ >+ r6.defined = true; >+ r6.network = tt->local_ipv6; >+ r6.netbits = tt->netbits_ipv6; >+ r6.gateway = tt->local_ipv6; >+ add_route_ipv6 (&r6, tt, 0, es); >+} >+ >+void delete_route_connected_v6_net(struct tuntap * tt, >+ const struct env_set *es) >+{ >+ struct route_ipv6 r6; >+ >+ r6.defined = true; >+ r6.network = tt->local_ipv6; >+ r6.netbits = tt->netbits_ipv6; >+ r6.gateway = tt->local_ipv6; >+ delete_route_ipv6 (&r6, tt, 0, es); >+} >+#endif >+ >+ > /* execute the ifconfig command through the shell */ > void > do_ifconfig (struct tuntap *tt, >@@ -574,10 +621,16 @@ > const char *ifconfig_local = NULL; > const char *ifconfig_remote_netmask = NULL; > const char *ifconfig_broadcast = NULL; >+ const char *ifconfig_ipv6_local = NULL; >+ const char *ifconfig_ipv6_remote = NULL; >+ bool do_ipv6 = false; > struct argv argv; > > argv_init (&argv); > >+ msg( M_INFO, "do_ifconfig, tt->ipv6=%d, tt->did_ifconfig_ipv6_setup=%d", >+ tt->ipv6, tt->did_ifconfig_ipv6_setup ); >+ > /* > * We only handle TUN/TAP devices here, not --dev null devices. > */ >@@ -589,6 +642,13 @@ > ifconfig_local = print_in_addr_t (tt->local, 0, &gc); > ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc); > >+ if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) >+ { >+ ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); >+ ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); >+ do_ipv6 = true; >+ } >+ > /* > * If TAP-style device, generate broadcast address. > */ >@@ -647,7 +707,19 @@ > argv_msg (M_INFO, &argv); > openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed"); > } >- tt->did_ifconfig = true; >+ if ( do_ipv6 ) >+ { >+ argv_printf( &argv, >+ "%s -6 addr add %s/%d dev %s", >+ iproute_path, >+ ifconfig_ipv6_local, >+ tt->netbits_ipv6, >+ actual >+ ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ip -6 addr add failed"); >+ } >+ tt->did_ifconfig = true; > #else > if (tun) > argv_printf (&argv, >@@ -670,6 +742,18 @@ > ); > argv_msg (M_INFO, &argv); > openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig failed"); >+ if ( do_ipv6 ) >+ { >+ argv_printf (&argv, >+ "%s %s inet6 add %s/%d", >+ IFCONFIG_PATH, >+ actual, >+ ifconfig_ipv6_local, >+ tt->netbits_ipv6 >+ ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig inet6 failed"); >+ } > tt->did_ifconfig = true; > > #endif /*CONFIG_FEATURE_IPROUTE*/ >@@ -693,7 +777,7 @@ > > argv_msg (M_INFO, &argv); > if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-1 failed")) >- solaris_error_close (tt, es, actual); >+ solaris_error_close (tt, es, actual, false); > > argv_printf (&argv, > "%s %s netmask 255.255.255.255", >@@ -725,7 +809,53 @@ > > argv_msg (M_INFO, &argv); > if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed")) >- solaris_error_close (tt, es, actual); >+ solaris_error_close (tt, es, actual, false); >+ >+ if ( do_ipv6 ) >+ { >+ argv_printf (&argv, "%s %s inet6 unplumb", >+ IFCONFIG_PATH, actual ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, 0, NULL); >+ >+ if ( tt->type == DEV_TYPE_TUN ) >+ { >+ argv_printf (&argv, >+ "%s %s inet6 plumb %s/%d %s up", >+ IFCONFIG_PATH, >+ actual, >+ ifconfig_ipv6_local, >+ tt->netbits_ipv6, >+ ifconfig_ipv6_remote >+ ); >+ } >+ else /* tap mode */ >+ { >+ /* base IPv6 tap interface needs to be brought up first >+ */ >+ argv_printf (&argv, "%s %s inet6 plumb up", >+ IFCONFIG_PATH, actual ); >+ argv_msg (M_INFO, &argv); >+ if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 (prepare) failed")) >+ solaris_error_close (tt, es, actual, true); >+ >+ /* we might need to do "ifconfig %s inet6 auto-dhcp drop" >+ * after the system has noticed the interface and fired up >+ * the DHCPv6 client - but this takes quite a while, and the >+ * server will ignore the DHCPv6 packets anyway. So we don't. >+ */ >+ >+ /* static IPv6 addresses need to go to a subinterface (tap0:1) >+ */ >+ argv_printf (&argv, >+ "%s %s inet6 addif %s/%d up", >+ IFCONFIG_PATH, actual, >+ ifconfig_ipv6_local, tt->netbits_ipv6 ); >+ } >+ argv_msg (M_INFO, &argv); >+ if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 failed")) >+ solaris_error_close (tt, es, actual, true); >+ } > > if (!tun && tt->topology == TOP_SUBNET) > { >@@ -787,10 +917,42 @@ > ); > argv_msg (M_INFO, &argv); > openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed"); >+ if ( do_ipv6 ) >+ { >+ argv_printf (&argv, >+ "%s %s inet6 %s/%d", >+ IFCONFIG_PATH, >+ actual, >+ ifconfig_ipv6_local, >+ tt->netbits_ipv6 >+ ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig inet6 failed"); >+ >+ /* and, hooray, we explicitely need to add a route... */ >+ add_route_connected_v6_net(tt, es); >+ } > tt->did_ifconfig = true; > > #elif defined(TARGET_NETBSD) > >+/* whether or not NetBSD can do IPv6 can be seen by the availability of >+ * the TUNSIFHEAD ioctl() - see next TARGET_NETBSD block for more details >+ */ >+#ifdef TUNSIFHEAD >+# define NETBSD_MULTI_AF >+#endif >+ >+ /* as on OpenBSD and Darwin, destroy and re-create tun<x> interface >+ */ >+ argv_printf (&argv, "%s %s destroy", IFCONFIG_PATH, actual ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, 0, "NetBSD ifconfig destroy failed"); >+ >+ argv_printf (&argv, "%s %s create", IFCONFIG_PATH, actual ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig create failed"); >+ > if (tun) > argv_printf (&argv, > "%s %s %s %s mtu %d netmask 255.255.255.255 up", >@@ -817,6 +979,27 @@ > ); > argv_msg (M_INFO, &argv); > openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed"); >+ >+ if ( do_ipv6 ) >+ { >+#ifdef NETBSD_MULTI_AF >+ argv_printf (&argv, >+ "%s %s inet6 %s/%d", >+ IFCONFIG_PATH, >+ actual, >+ ifconfig_ipv6_local, >+ tt->netbits_ipv6 >+ ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig inet6 failed"); >+ >+ /* and, hooray, we explicitely need to add a route... */ >+ add_route_connected_v6_net(tt, es); >+#else >+ msg( M_INFO, "no IPv6 support for tun interfaces on NetBSD before 4.0 (if your system is newer, recompile openvpn)" ); >+ tt->ipv6 = false; >+#endif >+ } > tt->did_ifconfig = true; > > #elif defined(TARGET_DARWIN) >@@ -882,6 +1065,22 @@ > add_route (&r, tt, 0, es); > } > >+ if ( do_ipv6 ) >+ { >+ argv_printf (&argv, >+ "%s %s inet6 %s/%d", >+ IFCONFIG_PATH, >+ actual, >+ ifconfig_ipv6_local, >+ tt->netbits_ipv6 >+ ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, S_FATAL, "MacOS X ifconfig inet6 failed"); >+ >+ /* and, hooray, we explicitely need to add a route... */ >+ add_route_connected_v6_net(tt, es); >+ } >+ > #elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY) > > /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ >@@ -920,6 +1119,19 @@ > add_route (&r, tt, 0, es); > } > >+ if ( do_ipv6 ) >+ { >+ argv_printf (&argv, >+ "%s %s inet6 %s/%d", >+ IFCONFIG_PATH, >+ actual, >+ ifconfig_ipv6_local, >+ tt->netbits_ipv6 >+ ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed"); >+ } >+ > #elif defined (WIN32) > { > /* >@@ -959,6 +1171,34 @@ > tt->did_ifconfig = true; > } > >+ /* IPv6 always uses "netsh" interface */ >+ if ( do_ipv6 ) >+ { >+ char * saved_actual; >+ >+ if (!strcmp (actual, "NULL")) >+ msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than one TAP-Win32 adapter, you must also specify --dev-node"); >+ >+ /* example: netsh interface ipv6 set address MyTap 2001:608:8003::d store=active */ >+ argv_printf (&argv, >+ "%s%sc interface ipv6 set address %s %s store=active", >+ get_win_sys_path(), >+ NETSH_PATH_SUFFIX, >+ actual, >+ ifconfig_ipv6_local ); >+ >+ netsh_command (&argv, 4); >+ >+ /* explicit route needed */ >+ /* on windows, OpenVPN does ifconfig first, open_tun later, so >+ * tt->actual_name might not yet be initialized, but routing code >+ * needs to know interface name - point to "actual", restore later >+ */ >+ saved_actual = tt->actual_name; >+ tt->actual_name = (char*) actual; >+ add_route_connected_v6_net(tt, es); >+ tt->actual_name = saved_actual; >+ } > #else > msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script."); > #endif >@@ -991,14 +1231,16 @@ > #ifndef WIN32 > static void > open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, >- bool ipv6, bool ipv6_explicitly_supported, bool dynamic, >+ bool ipv6_explicitly_supported, bool dynamic, > struct tuntap *tt) > { > char tunname[256]; > char dynamic_name[256]; > bool dynamic_opened = false; > >- ipv6_support (ipv6, ipv6_explicitly_supported, tt); >+ >+ if ( tt->ipv6 && ! ipv6_explicitly_supported ) >+ msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS"); > > if (tt->type == DEV_TYPE_NULL) > { >@@ -1094,16 +1336,16 @@ > #if !PEDANTIC > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { > struct ifreq ifr; > >- /* >- * Set tt->ipv6 to true if >- * (a) we have the capability of supporting --tun-ipv6, and >- * (b) --tun-ipv6 was specified. >+ /* warn if a very old linux version is used & --tun-ipv6 set > */ >- ipv6_support (ipv6, LINUX_IPV6, tt); >+#if LINUX_IPV6 == 0 >+ if ( tt->ipv6 ) >+ msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS"); >+#endif > > /* > * We handle --dev null specially, we do not open /dev/null for this. >@@ -1212,7 +1454,7 @@ > #else > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { > ASSERT (0); > } >@@ -1222,9 +1464,9 @@ > #else > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { >- open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt); >+ open_tun_generic (dev, dev_type, dev_node, false, true, tt); > } > > #endif /* HAVE_LINUX_IF_TUN_H */ >@@ -1244,7 +1486,7 @@ > #endif > > void >-tuncfg (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options) >+tuncfg (const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options) > { > struct tuntap *tt; > >@@ -1252,7 +1494,7 @@ > clear_tuntap (tt); > tt->type = dev_type_enum (dev, dev_type); > tt->options = *options; >- open_tun (dev, dev_type, dev_node, ipv6, tt); >+ open_tun (dev, dev_type, dev_node, tt); > if (ioctl (tt->fd, TUNSETPERSIST, persist_mode) < 0) > msg (M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev); > if (username != NULL) >@@ -1395,7 +1637,7 @@ > #endif > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { > int if_fd, ip_muxid, arp_muxid, arp_fd, ppa = -1; > struct lifreq ifr; >@@ -1406,8 +1648,11 @@ > bool is_tun; > struct strioctl strioc_if, strioc_ppa; > >- ipv6_support (ipv6, true, tt); >- memset(&ifr, 0x0, sizeof(ifr)); >+ /* improved generic TUN/TAP driver from >+ * http://www.whiteboard.ne.jp/~admin2/tuntap/ >+ * has IPv6 support >+ */ >+ CLEAR(ifr); > > if (tt->type == DEV_TYPE_NULL) > { >@@ -1561,6 +1806,18 @@ > { > if (tt) > { >+ /* IPv6 interfaces need to be 'manually' de-configured */ >+ if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) >+ { >+ struct argv argv; >+ argv_init (&argv); >+ argv_printf( &argv, "%s %s inet6 unplumb", >+ IFCONFIG_PATH, tt->actual_name ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed"); >+ argv_reset (&argv); >+ } >+ > if (tt->ip_fd >= 0) > { > struct lifreq ifr; >@@ -1613,11 +1870,20 @@ > } > > static void >-solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual) >+solaris_error_close (struct tuntap *tt, const struct env_set *es, >+ const char *actual, bool unplumb_inet6 ) > { > struct argv argv; > argv_init (&argv); > >+ if (unplumb_inet6) >+ { >+ argv_printf( &argv, "%s %s inet6 unplumb", >+ IFCONFIG_PATH, actual ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, es, 0, "Solaris ifconfig inet6 unplumb failed"); >+ } >+ > argv_printf (&argv, > "%s %s unplumb", > IFCONFIG_PATH, >@@ -1674,9 +1940,9 @@ > */ > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { >- open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); >+ open_tun_generic (dev, dev_type, dev_node, true, true, tt); > > /* Enable multicast on the interface */ > if (tt->fd >= 0) >@@ -1697,12 +1963,31 @@ > } > } > >+/* the current way OpenVPN handles tun devices on OpenBSD leads to >+ * lingering tunX interfaces after close -> for a full cleanup, they >+ * need to be explicitely destroyed >+ */ >+ > void > close_tun (struct tuntap* tt) > { > if (tt) > { >+ struct gc_arena gc = gc_new (); >+ struct argv argv; >+ >+ /* setup command, close tun dev (clears tt->actual_name!), run command >+ */ >+ >+ argv_init (&argv); >+ argv_printf (&argv, "%s %s destroy", >+ IFCONFIG_PATH, tt->actual_name); >+ > close_tun_generic (tt); >+ >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, NULL, 0, "OpenBSD 'destroy tun interface' failed (non-critical)"); >+ > free (tt); > } > } >@@ -1765,33 +2050,51 @@ > #elif defined(TARGET_NETBSD) > > /* >- * NetBSD does not support IPv6 on tun out of the box, >- * but there exists a patch. When this patch is applied, >- * only two things are left to openvpn: >- * 1. Activate multicasting (this has already been done >- * before by the kernel, but we make sure that nobody >- * has deactivated multicasting inbetween. >- * 2. Deactivate "link layer mode" (otherwise NetBSD >- * prepends the address family to the packet, and we >- * would run into the same trouble as with OpenBSD. >+ * NetBSD before 4.0 does not support IPv6 on tun out of the box, >+ * but there exists a patch (sys/net/if_tun.c, 1.79->1.80, see PR 32944). >+ * >+ * NetBSD 4.0 and up do, but we need to put the tun interface into >+ * "multi_af" mode, which will prepend the address family to all packets >+ * (same as OpenBSD and FreeBSD). If this is not enabled, the kernel >+ * silently drops all IPv6 packets on output and gets confused on input. >+ * >+ * On earlier versions, multi_af is not available at all, so we have >+ * two different NetBSD code variants here :-( >+ * > */ > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { >- open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); >+#ifdef NETBSD_MULTI_AF >+ open_tun_generic (dev, dev_type, dev_node, true, true, tt); >+#else >+ open_tun_generic (dev, dev_type, dev_node, false, true, tt); >+#endif >+ > if (tt->fd >= 0) > { > int i = IFF_POINTOPOINT|IFF_MULTICAST; > ioctl (tt->fd, TUNSIFMODE, &i); /* multicast on */ > i = 0; > ioctl (tt->fd, TUNSLMODE, &i); /* link layer mode off */ >+ >+#ifdef NETBSD_MULTI_AF >+ i = 1; >+ if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0) /* multi-af mode on */ >+ { >+ msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); >+ } >+#endif > } > } > > void > close_tun (struct tuntap *tt) > { >+ /* TODO: we really should cleanup non-persistant tunX with >+ * "ifconfig tunX destroy" here... >+ */ > if (tt) > { > close_tun_generic (tt); >@@ -1799,6 +2102,65 @@ > } > } > >+#ifdef NETBSD_MULTI_AF >+ >+static inline int >+netbsd_modify_read_write_return (int len) >+{ >+ if (len > 0) >+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; >+ else >+ return len; >+} >+ >+int >+write_tun (struct tuntap* tt, uint8_t *buf, int len) >+{ >+ if (tt->type == DEV_TYPE_TUN) >+ { >+ u_int32_t type; >+ struct iovec iv[2]; >+ struct openvpn_iphdr *iph; >+ >+ iph = (struct openvpn_iphdr *) buf; >+ >+ if (tt->ipv6 && OPENVPN_IPH_GET_VER(iph->version_len) == 6) >+ type = htonl (AF_INET6); >+ else >+ type = htonl (AF_INET); >+ >+ iv[0].iov_base = (char *)&type; >+ iv[0].iov_len = sizeof (type); >+ iv[1].iov_base = buf; >+ iv[1].iov_len = len; >+ >+ return netbsd_modify_read_write_return (writev (tt->fd, iv, 2)); >+ } >+ else >+ return write (tt->fd, buf, len); >+} >+ >+int >+read_tun (struct tuntap* tt, uint8_t *buf, int len) >+{ >+ if (tt->type == DEV_TYPE_TUN) >+ { >+ u_int32_t type; >+ struct iovec iv[2]; >+ >+ iv[0].iov_base = (char *)&type; >+ iv[0].iov_len = sizeof (type); >+ iv[1].iov_base = buf; >+ iv[1].iov_len = len; >+ >+ return netbsd_modify_read_write_return (readv (tt->fd, iv, 2)); >+ } >+ else >+ return read (tt->fd, buf, len); >+} >+ >+#else /* not NETBSD_MULTI_AF -> older code, IPv4 only */ >+ > int > write_tun (struct tuntap* tt, uint8_t *buf, int len) > { >@@ -1810,6 +2172,7 @@ > { > return read (tt->fd, buf, len); > } >+#endif /* NETBSD_MULTI_AF */ > > #elif defined(TARGET_FREEBSD) > >@@ -1823,9 +2186,9 @@ > } > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { >- open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); >+ open_tun_generic (dev, dev_type, dev_node, true, true, tt); > > if (tt->fd >= 0 && tt->type == DEV_TYPE_TUN) > { >@@ -1911,9 +2274,9 @@ > } > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { >- open_tun_generic (dev, dev_type, dev_node, ipv6, true, true, tt); >+ open_tun_generic (dev, dev_type, dev_node, true, true, tt); > > if (tt->fd >= 0) > { >@@ -1982,6 +2345,61 @@ > return read (tt->fd, buf, len); > } > >+#elif defined(TARGET_DARWIN) >+ >+/* Darwin (MacOS X) is mostly "just use the generic stuff", but there >+ * is always one caveat...: >+ * >+ * If IPv6 is configured, and the tun device is closed, the IPv6 address >+ * configured to the tun interface changes to a lingering /128 route >+ * pointing to lo0. Need to unconfigure... (observed on 10.5) >+ */ >+ >+void >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) >+{ >+ open_tun_generic (dev, dev_type, dev_node, false, true, tt); >+} >+ >+void >+close_tun (struct tuntap* tt) >+{ >+ if (tt) >+ { >+ struct gc_arena gc = gc_new (); >+ struct argv argv; >+ argv_init (&argv); >+ >+ if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) >+ { >+ const char * ifconfig_ipv6_local = >+ print_in6_addr (tt->local_ipv6, 0, &gc); >+ >+ argv_printf (&argv, "%s delete -inet6 %s", >+ ROUTE_PATH, ifconfig_ipv6_local ); >+ argv_msg (M_INFO, &argv); >+ openvpn_execve_check (&argv, NULL, 0, "MacOS X 'remove inet6 route' failed (non-critical)"); >+ } >+ >+ close_tun_generic (tt); >+ free (tt); >+ argv_reset (&argv); >+ gc_free (&gc); >+ } >+} >+ >+int >+write_tun (struct tuntap* tt, uint8_t *buf, int len) >+{ >+ return write (tt->fd, buf, len); >+} >+ >+int >+read_tun (struct tuntap* tt, uint8_t *buf, int len) >+{ >+ return read (tt->fd, buf, len); >+} >+ > #elif defined(WIN32) > > int >@@ -3967,7 +4385,7 @@ > } > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { > struct gc_arena gc = gc_new (); > char device_path[256]; >@@ -3978,7 +4396,7 @@ > > /*netcmd_semaphore_lock ();*/ > >- ipv6_support (ipv6, false, tt); >+ msg( M_INFO, "open_tun, tt->ipv6=%d", tt->ipv6 ); > > if (tt->type == DEV_TYPE_NULL) > { >@@ -4101,6 +4519,16 @@ > TAP_WIN32_MIN_MAJOR, > TAP_WIN32_MIN_MINOR); > >+ /* usage of numeric constants is ugly, but this is really tied to >+ * *this* version of the driver >+ */ >+ if ( tt->ipv6 && tt->type == DEV_TYPE_TUN && >+ info[0] == 9 && info[1] < 8) >+ { >+ msg( M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will be disabled. Upgrade to Tap-Win32 9.8 (2.2-beta3 release or later) or use TAP mode to get IPv6", (int) info[0], (int) info[1] ); >+ tt->ipv6 = false; >+ } >+ > /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy > */ > if ( tt->type == DEV_TYPE_TUN && >@@ -4432,6 +4860,26 @@ > > if (tt) > { >+ if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) >+ { >+ struct argv argv; >+ argv_init (&argv); >+ >+ /* remove route pointing to interface */ >+ delete_route_connected_v6_net(tt, NULL); >+ >+ /* netsh interface ipv6 delete address \"%s\" %s */ >+ const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); >+ argv_printf (&argv, >+ "%s%sc interface ipv6 delete address %s %s", >+ get_win_sys_path(), >+ NETSH_PATH_SUFFIX, >+ tt->actual_name, >+ ifconfig_ipv6_local ); >+ >+ netsh_command (&argv, 1); >+ argv_reset (&argv); >+ } > #if 1 > if (tt->ipapi_context_defined) > { >@@ -4535,9 +4983,9 @@ > #else /* generic */ > > void >-open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) >+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) > { >- open_tun_generic (dev, dev_type, dev_node, ipv6, false, true, tt); >+ open_tun_generic (dev, dev_type, dev_node, false, true, tt); > } > > void >diff -Naur openvpn-2.2.2_unpatched//tun.h openvpn-2.2.2/tun.h >--- openvpn-2.2.2_unpatched//tun.h 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/tun.h 2012-02-26 18:02:09.719866444 +0100 >@@ -130,6 +130,7 @@ > int topology; /* one of the TOP_x values */ > > bool did_ifconfig_setup; >+ bool did_ifconfig_ipv6_setup; > bool did_ifconfig; > > bool ipv6; >@@ -146,6 +147,10 @@ > in_addr_t remote_netmask; > in_addr_t broadcast; > >+ struct in6_addr local_ipv6; >+ struct in6_addr remote_ipv6; >+ int netbits_ipv6; >+ > #ifdef WIN32 > HANDLE hand; > struct overlapped_io reads; >@@ -197,7 +202,7 @@ > void clear_tuntap (struct tuntap *tuntap); > > void open_tun (const char *dev, const char *dev_type, const char *dev_node, >- bool ipv6, struct tuntap *tt); >+ struct tuntap *tt); > > void close_tun (struct tuntap *tt); > >@@ -206,7 +211,7 @@ > int read_tun (struct tuntap* tt, uint8_t *buf, int len); > > void tuncfg (const char *dev, const char *dev_type, const char *dev_node, >- bool ipv6, int persist_mode, const char *username, >+ int persist_mode, const char *username, > const char *groupname, const struct tuntap_options *options); > > const char *guess_tuntap_dev (const char *dev, >@@ -219,6 +224,8 @@ > int topology, /* one of the TOP_x values */ > const char *ifconfig_local_parm, /* --ifconfig parm 1 */ > const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */ >+ const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 / IPv6 */ >+ const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 / IPv6 */ > in_addr_t local_public, > in_addr_t remote_public, > const bool strict_warn, >diff -Naur openvpn-2.2.2_unpatched//win32.c openvpn-2.2.2/win32.c >--- openvpn-2.2.2_unpatched//win32.c 2012-02-26 18:02:05.956502651 +0100 >+++ openvpn-2.2.2/win32.c 2012-02-26 18:02:09.719866444 +0100 >@@ -874,16 +874,21 @@ > static char * > env_block (const struct env_set *es) > { >+ char * force_path = "PATH=C:\\Windows\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem"; >+ > if (es) > { > struct env_item *e; > char *ret; > char *p; > size_t nchars = 1; >+ bool path_seen = false; > > for (e = es->list; e != NULL; e = e->next) > nchars += strlen (e->string) + 1; > >+ nchars += strlen(force_path)+1; >+ > ret = (char *) malloc (nchars); > check_malloc_return (ret); > >@@ -895,7 +900,18 @@ > strcpy (p, e->string); > p += strlen (e->string) + 1; > } >+ if ( strncmp(e->string, "PATH=", 5 ) == 0 ) >+ path_seen = true; >+ } >+ >+ /* make sure PATH is set */ >+ if ( !path_seen ) >+ { >+ msg( M_INFO, "env_block: add %s", force_path ); >+ strcpy( p, force_path ); >+ p += strlen(force_path) + 1; > } >+ > *p = '\0'; > return ret; > } >diff -Naur openvpn-2.2.2_unpatched//win32.h openvpn-2.2.2/win32.h >--- openvpn-2.2.2_unpatched//win32.h 2012-02-26 18:02:05.959836011 +0100 >+++ openvpn-2.2.2/win32.h 2012-02-26 18:02:09.723199804 +0100 >@@ -269,6 +269,8 @@ > > /* call self in a subprocess */ > void fork_to_self (const char *cmdline); >+const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); >+int inet_pton(int af, const char *src, void *st); > > /* Find temporary directory */ > const char *win_get_tempdir();
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 405937
:
303391
| 303393