mirror of
https://github.com/OpenVPN/openvpn.git
synced 2026-06-11 09:50:26 -04:00
Enable IPv6 Payload in OpenVPN p2mp tun server mode. 20100104-1 release.
(cherry picked from commit ec9dce6387afd198881493bfebf13bb121e8a56b)
This commit is contained in:
parent
285252d1a1
commit
512cda46b0
25 changed files with 1915 additions and 81 deletions
189
ChangeLog.IPv6
Normal file
189
ChangeLog.IPv6
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
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
|
||||
180
NOTES
Normal file
180
NOTES
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
TODO:
|
||||
|
||||
* tun.c -> init_tun()
|
||||
[ifconfig-Parameter vorbereiten]
|
||||
|
||||
init.c -> do_open_tun() -> init.c::do_init_tun() -> tun.c::init_tun()
|
||||
-> do_ifconfig()
|
||||
|
||||
o tun.c -> do_ifconfig()
|
||||
[ifconfig/ip aufrufen]
|
||||
|
||||
* Linux / ifconfig
|
||||
/ Linux / iproute2 ** TESTEN **
|
||||
o FreeBSD
|
||||
/ NetBSD ("needs patch", googlen) ** TESTEN **
|
||||
/ Solaris ** TESTEN **
|
||||
o OpenBSD
|
||||
o MacOS X
|
||||
|
||||
o tun.c (?) -> interface cleanup ("ip addr del dev tun0 ...")
|
||||
|
||||
o TAP mode und IPv6? Fehlermeldung?
|
||||
o einfach confen
|
||||
|
||||
o ifconfig_ipv6_remote -> kann eigentlich ersatzlos wegfallen
|
||||
[tun.c, init.c, options.c, options.h]
|
||||
o [kann nicht, braucht man als default-gateway auf Solaris :( ]
|
||||
|
||||
* push ifconfig-ipv6
|
||||
push::send_push_reply() -> c->c2.push_ifconfig_local
|
||||
|
||||
** wo wird das gesetzt? ** multi.c (und ggf. options.c / ifconfig-push)
|
||||
|
||||
o /netbits pushen (push.c) -> options.c "ifconfig-ipv6" muss auch
|
||||
damit zurecht kommen, tut es derzeit aber nicht
|
||||
|
||||
* ifconfig_pool_write() -> IPv6 "wenn pool IPv6 hat"
|
||||
|
||||
* multi::multi_init() -> ifconfig_pool_init()
|
||||
|
||||
|
||||
* "route-ipv6"-Option und "push route-ipv6"
|
||||
o "gateway"
|
||||
o "metric"
|
||||
o "route-gateway-ipv6"-Option
|
||||
o "ifconfig-ipv6-push"-Option
|
||||
options.c -> options.push_ifconfig_...
|
||||
multi.c
|
||||
mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local;
|
||||
|
||||
|
||||
o "server-ipv6"-Option
|
||||
|
||||
o options.c, add_option() -> wird fuer "lokale" und "push"-Options
|
||||
aufgerufen
|
||||
no_more_than_n_args()
|
||||
struct options [options.h]
|
||||
|
||||
* add_route_to_option_list()
|
||||
[route.c -> add_route_ipv6_to_option_list]
|
||||
[options.h -> options->routes_ipv6]
|
||||
|
||||
o was passiert danach damit?
|
||||
|
||||
* socket.c: ip_or_dns_addr_safe()
|
||||
--> ipv6_addr_safe()
|
||||
--> ipv6_addr_safe_hexplusbits()
|
||||
|
||||
* Makro? helper.c -> helper_client_server() ******
|
||||
* Fehler, wenn options->mode != MODE_SERVER
|
||||
* "tun-ipv6" auto-enablen
|
||||
|
||||
* if (options->tun_ipv6)
|
||||
msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server");
|
||||
[options.c, 1710]
|
||||
[raus]
|
||||
|
||||
o struct tuntap->ipv6 = true, wenn "ipv6" und "system kann das"
|
||||
o Fehler, wenn System kein IPv6 kann
|
||||
("NetBSD needs patch" -> googlen)
|
||||
|
||||
o Adress-Allokation an Clients (/128 aus ifconfig-ipv6-pool /64 erstmal nur)
|
||||
o hash aus Client-Key als host part?
|
||||
(nein, wir nehmen einfach "den gleichen Offset wie bei IPv4" und
|
||||
add_in6_addr())
|
||||
|
||||
o "iroute-ipv6"-Option
|
||||
o "ifconfig-ipv6"
|
||||
o "ifconfig-ipv6-pool"
|
||||
o "ifconfig-pool-persist-ipv6"-Option
|
||||
|
||||
o was tut #define LINUX_IPV6?
|
||||
o was tut bestehender Code mit "ipv6"?
|
||||
|
||||
|
||||
o Routing-/Forwarding-Funktion
|
||||
read_tun() --> ??
|
||||
?? --> write_tun()
|
||||
|
||||
[muss für p2p schon funktionieren, d.h. vermutlich ist nur die
|
||||
server-seite anzupassen]
|
||||
|
||||
o ICMP
|
||||
|
||||
o Optionen dokumentieren (-> berniv6)
|
||||
o server-ipv6
|
||||
o ifconfig-ipv6
|
||||
o ifconfig-ipv6-pool
|
||||
o ifconfig-pool-persist (v4+v6, Formataenderung im File)
|
||||
o iroute-ipv6
|
||||
o route-ipv6
|
||||
o tun-ipv6
|
||||
|
||||
* http://www.greenie.net/ipv6/openvpn.html - DONE
|
||||
o man pages, --help
|
||||
|
||||
* options.c
|
||||
- get_ip_addr() --> socket.c getaddr()
|
||||
- openvpn_inet_aton -> OIA_IP "ist IP"
|
||||
|
||||
* options.c, show_p2mp_parms()
|
||||
|
||||
* socket.c, print_in_addr_t() --> print_in6_addr()
|
||||
|
||||
o forward_compatible?
|
||||
|
||||
o ifconfig_ipv6_pool_persist --> einfach ifconfig_pool_persist mitbenutzen?
|
||||
Entscheidung: JA
|
||||
o to be implemented: pool.c
|
||||
|
||||
o route.c:
|
||||
clone_route_option_list(), copy_route_option_list(),
|
||||
new_route_list(), add_route(), init_route_list(), ...
|
||||
add_routes(), delete_routes(), setenv_routes(),
|
||||
|
||||
-> wo werden die aufgerufen, wofuer verwendet, IPv6-Anpassung?
|
||||
|
||||
* add_route() ruft "/sbin/route add..." auf
|
||||
o div. (redirect gateway related) -> route.c::add_route3() -> add_route()
|
||||
o init.c::do_route() -> route.c::add_routes() -> add_route()
|
||||
o init.c::do_open_tun() -> do_route()
|
||||
o forward.c::check_add_routes_action() -> do_route()
|
||||
o init.c::do_open_tun() -> init.c::do_init_route_list() ->
|
||||
route.c::init_route_list()
|
||||
* init.c::do_open_tun() -> do_alloc_route_list() -> new_route_ipv6_list()
|
||||
|
||||
o add_route_ipv6() - implementieren und testen
|
||||
* Linux / ifconfig
|
||||
* Linux / iproute2
|
||||
i FreeBSD
|
||||
i NetBSD ("needs patch", googlen)
|
||||
i Solaris *braucht Gateway*
|
||||
i OpenBSD
|
||||
i MacOS X
|
||||
|
||||
o delete_route_ipv6() - implementieren und testen
|
||||
* Linux / ifconfig
|
||||
* Linux / iproute2
|
||||
i FreeBSD
|
||||
i NetBSD ("needs patch", googlen)
|
||||
i Solaris
|
||||
i OpenBSD
|
||||
i MacOS X
|
||||
|
||||
o Gateway-Logik für IPv6-Routen mitschleifen ("explizit angeben oder
|
||||
aus ifconfig-ipv6 $remote")
|
||||
|
||||
o IPv6 TCPMSS oder "fragmentation required"?
|
||||
o IPv6 MTU auf Interface setzen?
|
||||
o sysdep!
|
||||
|
||||
|
||||
TESTEN
|
||||
* ipv6_addr_safe() [--ifconfig-ipv6 null/zu lang/invalid]
|
||||
o ipv6_addr_safe_hexplusbits() [--route-ipv6 ...]
|
||||
* get_ipv6_addr() [--server-ipv6 ...]
|
||||
|
||||
o unmodifizierter 2.1-client -> 2.1+ipv6-Server?
|
||||
o unmodifizierter 2.0-client -> 2.1+ipv6-Server?
|
||||
o wie kann der Server das erkennen, und "kein v6" schicken?
|
||||
8
README.IPv6
Normal file
8
README.IPv6
Normal file
|
|
@ -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
|
||||
37
TODO.IPv6
Normal file
37
TODO.IPv6
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
known issues for IPv6 payload support in OpenVPN
|
||||
-----------------------------------------------
|
||||
|
||||
1.) "--topology subnet" doesn't work together with IPv6 payload
|
||||
(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)
|
||||
|
||||
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.
|
||||
|
||||
5.) add new option "ifconfig-ipv6-push"
|
||||
(per-client static IPv6 assignment, -> radiusplugin, etc)
|
||||
|
||||
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 :-) )
|
||||
|
|
@ -259,7 +259,8 @@ send_control_channel_string (struct context *c, const char *str, int msglevel)
|
|||
static void
|
||||
check_add_routes_action (struct context *c, const bool errors)
|
||||
{
|
||||
do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es);
|
||||
do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
|
||||
c->c1.tuntap, c->plugins, c->c2.es);
|
||||
update_time ();
|
||||
event_timeout_clear (&c->c2.route_wakeup);
|
||||
event_timeout_clear (&c->c2.route_wakeup_expire);
|
||||
|
|
|
|||
49
helper.c
49
helper.c
|
|
@ -142,6 +142,55 @@ helper_client_server (struct options *o)
|
|||
|
||||
#if P2MP
|
||||
#if P2MP_SERVER
|
||||
|
||||
/*
|
||||
*
|
||||
* HELPER DIRECTIVE for IPv6
|
||||
*
|
||||
* server-ipv6 2001:db8::/64
|
||||
*
|
||||
* EXPANDS TO:
|
||||
*
|
||||
* tun-ipv6
|
||||
* push "tun-ipv6"
|
||||
* ifconfig-ipv6 2001:db8::1 2001:db8::2
|
||||
* if !nopool:
|
||||
* ifconfig-ipv6-pool 2001:db8::1:0/64
|
||||
*
|
||||
*/
|
||||
if ( o->server_ipv6_defined )
|
||||
{
|
||||
if ( ! o->server_defined )
|
||||
{
|
||||
msg (M_USAGE, "--server-ipv6 must be used together with --server");
|
||||
}
|
||||
if ( o->server_flags & SF_NOPOOL )
|
||||
{
|
||||
msg( M_USAGE, "--server-ipv6 is incompatible with 'nopool' option" );
|
||||
}
|
||||
if ( o->ifconfig_ipv6_pool_defined )
|
||||
{
|
||||
msg( M_USAGE, "--server-ipv6 already defines an ifconfig-ipv6-pool, so you can't also specify --ifconfig-pool explicitly");
|
||||
}
|
||||
|
||||
/* local ifconfig is "base address + 1" and "+2" */
|
||||
o->ifconfig_ipv6_local =
|
||||
print_in6_addr( add_in6_addr( o->server_network_ipv6, 1), 0, &o->gc );
|
||||
o->ifconfig_ipv6_remote =
|
||||
print_in6_addr( add_in6_addr( o->server_network_ipv6, 2), 0, &o->gc );
|
||||
|
||||
/* pool starts at "base address + 0x10000" */
|
||||
ASSERT( o->server_netbits_ipv6 < 96 ); /* want 32 bits */
|
||||
o->ifconfig_ipv6_pool_defined = true;
|
||||
o->ifconfig_ipv6_pool_base =
|
||||
add_in6_addr( o->server_network_ipv6, 0x10000 );
|
||||
o->ifconfig_ipv6_pool_netbits = o->server_netbits_ipv6;
|
||||
|
||||
o->tun_ipv6 = true;
|
||||
|
||||
push_option( o, "tun-ipv6", M_USAGE );
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* HELPER DIRECTIVE:
|
||||
|
|
|
|||
58
init.c
58
init.c
|
|
@ -1066,6 +1066,8 @@ do_alloc_route_list (struct context *c)
|
|||
{
|
||||
if (c->options.routes && !c->c1.route_list)
|
||||
c->c1.route_list = new_route_list (c->options.max_routes, &c->gc);
|
||||
if (c->options.routes_ipv6 && !c->c1.route_ipv6_list)
|
||||
c->c1.route_ipv6_list = new_route_ipv6_list (c->options.max_routes, &c->gc);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1108,6 +1110,45 @@ do_init_route_list (const struct options *options,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_init_route_ipv6_list (const struct options *options,
|
||||
struct route_ipv6_list *route_ipv6_list,
|
||||
bool fatal,
|
||||
struct env_set *es)
|
||||
{
|
||||
const char *gw = NULL;
|
||||
int dev = dev_type_enum (options->dev, options->dev_type);
|
||||
int metric = 0;
|
||||
|
||||
if (dev != DEV_TYPE_TUN )
|
||||
msg( M_WARN, "IPv6 routes on TAP devices are going to fail on some platforms (need gateway spec)" ); /* TODO-GERT */
|
||||
|
||||
gw = options->ifconfig_ipv6_remote; /* default GW = remote end */
|
||||
#if 0 /* not yet done for IPv6 - TODO!*/
|
||||
if ( options->route_ipv6_default_gateway ) /* override? */
|
||||
gw = options->route_ipv6_default_gateway;
|
||||
#endif
|
||||
|
||||
if (options->route_default_metric)
|
||||
metric = options->route_default_metric;
|
||||
|
||||
if (!init_route_ipv6_list (route_ipv6_list,
|
||||
options->routes_ipv6,
|
||||
gw,
|
||||
metric,
|
||||
es))
|
||||
{
|
||||
if (fatal)
|
||||
openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* copy routes to environment */
|
||||
setenv_routes_ipv6 (es, route_ipv6_list);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called after all initialization has been completed.
|
||||
*/
|
||||
|
|
@ -1171,12 +1212,13 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
|
|||
void
|
||||
do_route (const struct options *options,
|
||||
struct route_list *route_list,
|
||||
struct route_ipv6_list *route_ipv6_list,
|
||||
const struct tuntap *tt,
|
||||
const struct plugin_list *plugins,
|
||||
struct env_set *es)
|
||||
{
|
||||
if (!options->route_noexec && route_list)
|
||||
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))
|
||||
{
|
||||
|
|
@ -1233,6 +1275,8 @@ do_init_tun (struct context *c)
|
|||
c->options.topology,
|
||||
c->options.ifconfig_local,
|
||||
c->options.ifconfig_remote_netmask,
|
||||
c->options.ifconfig_ipv6_local,
|
||||
c->options.ifconfig_ipv6_remote,
|
||||
addr_host (&c->c1.link_socket_addr.local),
|
||||
addr_host (&c->c1.link_socket_addr.remote),
|
||||
!c->options.ifconfig_nowarn,
|
||||
|
|
@ -1269,6 +1313,8 @@ do_open_tun (struct context *c)
|
|||
/* parse and resolve the route option list */
|
||||
if (c->options.routes && c->c1.route_list && c->c2.link_socket)
|
||||
do_init_route_list (&c->options, c->c1.route_list, &c->c2.link_socket->info, false, c->c2.es);
|
||||
if (c->options.routes_ipv6 && c->c1.route_ipv6_list )
|
||||
do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, false, c->c2.es);
|
||||
|
||||
/* do ifconfig */
|
||||
if (!c->options.ifconfig_noexec
|
||||
|
|
@ -1315,7 +1361,8 @@ do_open_tun (struct context *c)
|
|||
|
||||
/* possibly add routes */
|
||||
if (!c->options.route_delay_defined)
|
||||
do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es);
|
||||
do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
|
||||
c->c1.tuntap, c->plugins, c->c2.es);
|
||||
|
||||
/*
|
||||
* Did tun/tap driver give us an MTU?
|
||||
|
|
@ -1390,8 +1437,9 @@ do_close_tun (struct context *c, bool force)
|
|||
#endif
|
||||
|
||||
/* delete any routes we added */
|
||||
if (c->c1.route_list)
|
||||
delete_routes (c->c1.route_list, c->c1.tuntap, ROUTE_OPTION_FLAGS (&c->options), c->c2.es);
|
||||
if (c->c1.route_list || c->c1.route_ipv6_list )
|
||||
delete_routes (c->c1.route_list, c->c1.route_ipv6_list,
|
||||
c->c1.tuntap, ROUTE_OPTION_FLAGS (&c->options), c->c2.es);
|
||||
|
||||
/* actually close tun/tap device based on --down-pre flag */
|
||||
if (!c->options.down_pre)
|
||||
|
|
|
|||
1
init.h
1
init.h
|
|
@ -63,6 +63,7 @@ void init_instance (struct context *c, const struct env_set *env, const unsigned
|
|||
|
||||
void do_route (const struct options *options,
|
||||
struct route_list *route_list,
|
||||
struct route_ipv6_list *route_ipv6_list,
|
||||
const struct tuntap *tt,
|
||||
const struct plugin_list *plugins,
|
||||
struct env_set *es);
|
||||
|
|
|
|||
2
misc.c
2
misc.c
|
|
@ -1004,7 +1004,7 @@ setenv_str_ex (struct env_set *es,
|
|||
{
|
||||
const char *str = construct_name_value (name_tmp, val_tmp, &gc);
|
||||
env_set_add (es, str);
|
||||
/*msg (M_INFO, "SETENV_ES '%s'", str);*/
|
||||
msg (M_INFO, "SETENV_ES '%s'", str);/**/
|
||||
}
|
||||
else
|
||||
env_set_del (es, name_tmp);
|
||||
|
|
|
|||
143
mroute.c
143
mroute.c
|
|
@ -88,12 +88,33 @@ mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int
|
|||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
mroute_get_in6_addr (struct mroute_addr *ma, const struct in6_addr src, unsigned int mask)
|
||||
{
|
||||
if (ma)
|
||||
{
|
||||
ma->type = MR_ADDR_IPV6 | mask;
|
||||
ma->netbits = 0;
|
||||
ma->len = 16;
|
||||
*(struct in6_addr *)ma->addr = src;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
mroute_is_mcast (const in_addr_t addr)
|
||||
{
|
||||
return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK));
|
||||
}
|
||||
|
||||
/* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies
|
||||
* the address as being a multicast address"
|
||||
*/
|
||||
static inline bool
|
||||
mroute_is_mcast_ipv6 (const struct in6_addr addr)
|
||||
{
|
||||
return (addr.s6_addr[0] == 0xff);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PF
|
||||
|
||||
static unsigned int
|
||||
|
|
@ -155,10 +176,29 @@ mroute_extract_addr_ipv4 (struct mroute_addr *src,
|
|||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
msg (M_WARN, "Need IPv6 code in mroute_extract_addr_from_packet");
|
||||
break;
|
||||
}
|
||||
if (BLEN (buf) >= (int) sizeof (struct openvpn_ipv6hdr))
|
||||
{
|
||||
const struct openvpn_ipv6hdr *ipv6 = (const struct openvpn_ipv6hdr *) BPTR (buf);
|
||||
#if 0 /* very basic debug */
|
||||
struct gc_arena gc = gc_new ();
|
||||
msg( M_INFO, "IPv6 packet! src=%s, dst=%s",
|
||||
print_in6_addr( ipv6->saddr, 0, &gc ),
|
||||
print_in6_addr( ipv6->daddr, 0, &gc ));
|
||||
gc_free (&gc);
|
||||
#endif
|
||||
|
||||
mroute_get_in6_addr (src, ipv6->saddr, 0);
|
||||
mroute_get_in6_addr (dest, ipv6->daddr, 0);
|
||||
|
||||
if (mroute_is_mcast_ipv6 (ipv6->daddr))
|
||||
ret |= MROUTE_EXTRACT_MCAST;
|
||||
|
||||
ret |= MROUTE_EXTRACT_SUCCEEDED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msg (M_WARN, "IP packet with unknown IP version=%d seen",
|
||||
OPENVPN_IPH_GET_VER (*BPTR(buf)));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
|
@ -252,14 +292,36 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
|
|||
* Zero off the host bits in an address, leaving
|
||||
* only the network bits, using the netbits member of
|
||||
* struct mroute_addr as the controlling parameter.
|
||||
*
|
||||
* TODO: this is called for route-lookup for every yet-unhashed
|
||||
* destination address, so for lots of active net-iroutes, this
|
||||
* might benefit from some "zeroize 32 bit at a time" improvements
|
||||
*/
|
||||
void
|
||||
mroute_addr_mask_host_bits (struct mroute_addr *ma)
|
||||
{
|
||||
in_addr_t addr = ntohl(*(in_addr_t*)ma->addr);
|
||||
ASSERT ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4);
|
||||
addr &= netbits_to_netmask (ma->netbits);
|
||||
*(in_addr_t*)ma->addr = htonl (addr);
|
||||
if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4)
|
||||
{
|
||||
addr &= netbits_to_netmask (ma->netbits);
|
||||
*(in_addr_t*)ma->addr = htonl (addr);
|
||||
}
|
||||
else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6)
|
||||
{
|
||||
int byte = ma->len-1; /* rightmost byte in address */
|
||||
int bits_to_clear = 128 - ma->netbits;
|
||||
|
||||
while( byte >= 0 && bits_to_clear > 0 )
|
||||
{
|
||||
if ( bits_to_clear >= 8 )
|
||||
{ ma->addr[byte--] = 0; bits_to_clear -= 8; }
|
||||
else
|
||||
{ ma->addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; }
|
||||
}
|
||||
ASSERT( bits_to_clear == 0 );
|
||||
}
|
||||
else
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -337,17 +399,24 @@ mroute_addr_print_ex (const struct mroute_addr *ma,
|
|||
}
|
||||
break;
|
||||
case MR_ADDR_IPV6:
|
||||
buf_printf (&out, "IPV6");
|
||||
break;
|
||||
default:
|
||||
buf_printf (&out, "UNKNOWN");
|
||||
break;
|
||||
}
|
||||
return BSTR (&out);
|
||||
}
|
||||
else
|
||||
return "[NULL]";
|
||||
}
|
||||
{
|
||||
buf_printf (&out, "%s",
|
||||
print_in6_addr( *(struct in6_addr*)&maddr.addr, 0, gc));
|
||||
if (maddr.type & MR_WITH_NETBITS)
|
||||
{
|
||||
buf_printf (&out, "/%d", maddr.netbits);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
buf_printf (&out, "UNKNOWN");
|
||||
break;
|
||||
}
|
||||
return BSTR (&out);
|
||||
}
|
||||
else
|
||||
return "[NULL]";
|
||||
}
|
||||
|
||||
/*
|
||||
* mroute_helper's main job is keeping track of
|
||||
|
|
@ -418,6 +487,44 @@ mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
mroute_helper_lock (mh);
|
||||
++mh->cache_generation;
|
||||
++mh->net_len_refcount[ir6->netbits];
|
||||
if (mh->net_len_refcount[ir6->netbits] == 1)
|
||||
mroute_helper_regenerate (mh);
|
||||
mroute_helper_unlock (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);
|
||||
mroute_helper_lock (mh);
|
||||
++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);
|
||||
mroute_helper_unlock (mh);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mroute_helper_free (struct mroute_helper *mh)
|
||||
{
|
||||
|
|
|
|||
4
mroute.h
4
mroute.h
|
|
@ -85,7 +85,7 @@ struct mroute_addr {
|
|||
/*
|
||||
* Number of bits in an address. Should be raised for IPv6.
|
||||
*/
|
||||
#define MR_HELPER_NET_LEN 32
|
||||
#define MR_HELPER_NET_LEN 129
|
||||
|
||||
/*
|
||||
* Used to help maintain CIDR routing table.
|
||||
|
|
@ -127,6 +127,8 @@ struct mroute_helper *mroute_helper_init (int ageable_ttl_secs);
|
|||
void mroute_helper_free (struct mroute_helper *mh);
|
||||
void mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir);
|
||||
void mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir);
|
||||
void mroute_helper_add_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6);
|
||||
void mroute_helper_del_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6);
|
||||
|
||||
/*
|
||||
* Given a raw packet in buf, return the src and dest
|
||||
|
|
|
|||
114
multi.c
114
multi.c
|
|
@ -316,25 +316,18 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa
|
|||
*/
|
||||
if (t->options.ifconfig_pool_defined)
|
||||
{
|
||||
if (dev == DEV_TYPE_TAP)
|
||||
{
|
||||
m->ifconfig_pool = ifconfig_pool_init (IFCONFIG_POOL_INDIV,
|
||||
t->options.ifconfig_pool_start,
|
||||
t->options.ifconfig_pool_end,
|
||||
t->options.duplicate_cn);
|
||||
}
|
||||
else if (dev == DEV_TYPE_TUN)
|
||||
{
|
||||
m->ifconfig_pool = ifconfig_pool_init (
|
||||
(t->options.topology == TOP_NET30) ? IFCONFIG_POOL_30NET : IFCONFIG_POOL_INDIV,
|
||||
t->options.ifconfig_pool_start,
|
||||
t->options.ifconfig_pool_end,
|
||||
t->options.duplicate_cn);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT (0);
|
||||
}
|
||||
int pool_type = IFCONFIG_POOL_INDIV;
|
||||
|
||||
if ( dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30 )
|
||||
pool_type = IFCONFIG_POOL_30NET;
|
||||
|
||||
m->ifconfig_pool = ifconfig_pool_init (pool_type,
|
||||
t->options.ifconfig_pool_start,
|
||||
t->options.ifconfig_pool_end,
|
||||
t->options.duplicate_cn,
|
||||
t->options.ifconfig_ipv6_pool_defined,
|
||||
t->options.ifconfig_ipv6_pool_base,
|
||||
t->options.ifconfig_ipv6_pool_netbits );
|
||||
|
||||
/* reload pool data from file */
|
||||
if (t->c1.ifconfig_pool_persist)
|
||||
|
|
@ -429,10 +422,14 @@ multi_del_iroutes (struct multi_context *m,
|
|||
struct multi_instance *mi)
|
||||
{
|
||||
const struct iroute *ir;
|
||||
const struct iroute_ipv6 *ir6;
|
||||
if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN)
|
||||
{
|
||||
for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next)
|
||||
mroute_helper_del_iroute (m->route_helper, ir);
|
||||
|
||||
for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next )
|
||||
mroute_helper_del_iroute6 (m->route_helper, ir6);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1078,6 +1075,37 @@ multi_learn_in_addr_t (struct multi_context *m,
|
|||
}
|
||||
}
|
||||
|
||||
static struct multi_instance *
|
||||
multi_learn_in6_addr (struct multi_context *m,
|
||||
struct multi_instance *mi,
|
||||
struct in6_addr a6,
|
||||
int netbits, /* -1 if host route, otherwise # of network bits in address */
|
||||
bool primary)
|
||||
{
|
||||
struct mroute_addr addr;
|
||||
|
||||
addr.len = 16;
|
||||
addr.type = MR_ADDR_IPV6;
|
||||
addr.netbits = 0;
|
||||
memcpy( &addr.addr, &a6, sizeof(a6) );
|
||||
|
||||
if (netbits >= 0)
|
||||
{
|
||||
addr.type |= MR_WITH_NETBITS;
|
||||
addr.netbits = (uint8_t) netbits;
|
||||
mroute_addr_mask_host_bits( &addr );
|
||||
}
|
||||
|
||||
{
|
||||
struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0);
|
||||
#ifdef MANAGEMENT_DEF_AUTH
|
||||
if (management && owner)
|
||||
management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary);
|
||||
#endif
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A new client has connected, add routes (server -> client)
|
||||
* to internal routing table.
|
||||
|
|
@ -1088,6 +1116,7 @@ multi_add_iroutes (struct multi_context *m,
|
|||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
const struct iroute *ir;
|
||||
const struct iroute_ipv6 *ir6;
|
||||
if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN)
|
||||
{
|
||||
mi->did_iroutes = true;
|
||||
|
|
@ -1107,6 +1136,22 @@ multi_add_iroutes (struct multi_context *m,
|
|||
|
||||
multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false);
|
||||
}
|
||||
for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next )
|
||||
{
|
||||
if (ir6->netbits >= 0)
|
||||
msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s",
|
||||
print_in6_addr (ir6->network, 0, &gc),
|
||||
ir6->netbits,
|
||||
multi_instance_string (mi, false, &gc));
|
||||
else
|
||||
msg (D_MULTI_LOW, "MULTI: internal route %s -> %s",
|
||||
print_in6_addr (ir6->network, 0, &gc),
|
||||
multi_instance_string (mi, false, &gc));
|
||||
|
||||
mroute_helper_add_iroute6 (m->route_helper, ir6);
|
||||
|
||||
multi_learn_in6_addr (m, mi, ir6->network, ir6->netbits, false);
|
||||
}
|
||||
}
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
|
@ -1196,17 +1241,22 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
|
|||
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,6 +1278,16 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
|
|||
else
|
||||
msg (D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s",
|
||||
multi_instance_string (mi, false, &gc));
|
||||
|
||||
if ( mi->context.options.ifconfig_ipv6_pool_defined )
|
||||
{
|
||||
mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6;
|
||||
mi->context.c2.push_ifconfig_ipv6_remote =
|
||||
mi->context.c1.tuntap->local_ipv6;
|
||||
mi->context.c2.push_ifconfig_ipv6_netbits =
|
||||
mi->context.options.ifconfig_ipv6_pool_netbits;
|
||||
mi->context.c2.push_ifconfig_ipv6_defined = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1272,6 +1332,11 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi)
|
|||
SA_SET_IF_NONZERO);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: I'm not exactly sure what these environment variables are
|
||||
* used for, but if we have them for IPv4, we should also have
|
||||
* them for IPv6, no?
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1661,6 +1726,15 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
|
|||
print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc));
|
||||
}
|
||||
|
||||
if (mi->context.c2.push_ifconfig_ipv6_defined)
|
||||
{
|
||||
multi_learn_in6_addr (m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true);
|
||||
/* TODO: find out where addresses are "unlearned"!! */
|
||||
msg (D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s",
|
||||
multi_instance_string (mi, false, &gc),
|
||||
print_in6_addr (mi->context.c2.push_ifconfig_ipv6_local, 0, &gc));
|
||||
}
|
||||
|
||||
/* add routes locally, pointing to new client, if
|
||||
--iroute options have been specified */
|
||||
multi_add_iroutes (m, mi);
|
||||
|
|
|
|||
|
|
@ -165,6 +165,9 @@ struct context_1
|
|||
/* list of --route directives */
|
||||
struct route_list *route_list;
|
||||
|
||||
/* list of --route-ipv6 directives */
|
||||
struct route_ipv6_list *route_ipv6_list;
|
||||
|
||||
/* --status file */
|
||||
struct status_output *status_output;
|
||||
bool status_output_owned;
|
||||
|
|
@ -417,6 +420,11 @@ struct context_2
|
|||
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
|
||||
|
|
|
|||
187
options.c
187
options.c
|
|
@ -172,6 +172,8 @@ static const char usage_message[] =
|
|||
" addresses outside of the subnets used by either peer.\n"
|
||||
" TAP: configure device to use IP address l as a local\n"
|
||||
" endpoint and rn as a subnet mask.\n"
|
||||
"--ifconfig-ipv6 l r : configure device to use IPv6 address l as local\n"
|
||||
" endpoint (as a /64) and r as remote endpoint\n"
|
||||
"--ifconfig-noexec : Don't actually execute ifconfig/netsh command, instead\n"
|
||||
" pass --ifconfig parms by environment to scripts.\n"
|
||||
"--ifconfig-nowarn : Don't warn if the --ifconfig option on this side of the\n"
|
||||
|
|
@ -182,6 +184,10 @@ static const char usage_message[] =
|
|||
" netmask default: 255.255.255.255\n"
|
||||
" gateway default: taken from --route-gateway or --ifconfig\n"
|
||||
" Specify default by leaving blank or setting to \"nil\".\n"
|
||||
"--route-ipv6 network/bits [gateway] [metric] :\n"
|
||||
" Add IPv6 route to routing table after connection\n"
|
||||
" is established. Multiple routes can be specified.\n"
|
||||
" gateway default: taken from --route-ipv6-gateway or --ifconfig\n"
|
||||
"--max-routes n : Specify the maximum number of routes that may be defined\n"
|
||||
" or pulled from a server.\n"
|
||||
"--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n"
|
||||
|
|
@ -370,6 +376,7 @@ static const char usage_message[] =
|
|||
"\n"
|
||||
"Multi-Client Server options (when --mode server is used):\n"
|
||||
"--server network netmask : Helper option to easily configure server mode.\n"
|
||||
"--server-ipv6 network/bits : Configure IPv6 server mode.\n"
|
||||
"--server-bridge [IP netmask pool-start-IP pool-end-IP] : Helper option to\n"
|
||||
" easily configure ethernet bridging server mode.\n"
|
||||
"--push \"option\" : Push a config file option back to the peer for remote\n"
|
||||
|
|
@ -383,10 +390,13 @@ static const char usage_message[] =
|
|||
"--ifconfig-pool-persist file [seconds] : Persist/unpersist ifconfig-pool\n"
|
||||
" data to file, at seconds intervals (default=600).\n"
|
||||
" If seconds=0, file will be treated as read-only.\n"
|
||||
"--ifconfig-ipv6-pool base-IP/bits : set aside an IPv6 network block\n"
|
||||
" to be dynamically allocated to connecting clients.\n"
|
||||
"--ifconfig-push local remote-netmask : Push an ifconfig option to remote,\n"
|
||||
" overrides --ifconfig-pool dynamic allocation.\n"
|
||||
" Only valid in a client-specific config file.\n"
|
||||
"--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 +881,58 @@ get_ip_addr (const char *ip_string, int msglevel, bool *error)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* parse a text string containing an IPv6 address + netbits
|
||||
* in "standard format" (2001:dba::/32)
|
||||
* return true if parsing succeeded, modify *network and *netbits
|
||||
*/
|
||||
bool
|
||||
get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
|
||||
unsigned int * netbits, int msglevel )
|
||||
{
|
||||
int rc;
|
||||
char * sep, * endp;
|
||||
int bits;
|
||||
|
||||
sep = strchr( prefix_str, '/' );
|
||||
if ( sep == NULL )
|
||||
{
|
||||
msg (msglevel, "IPv6 prefix '%s': missing '/'", prefix_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
*/
|
||||
|
||||
*sep = '\0';
|
||||
rc = inet_pton( AF_INET6, prefix_str, network );
|
||||
*sep = '/';
|
||||
|
||||
if ( rc != 1 )
|
||||
{
|
||||
msg (msglevel, "IPv6 prefix '%s': invalid network part", prefix_str);
|
||||
return false;
|
||||
}
|
||||
*netbits = bits;
|
||||
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, M_WARN );
|
||||
}
|
||||
|
||||
static char *
|
||||
string_substitute (const char *src, int from, int to, struct gc_arena *gc)
|
||||
{
|
||||
|
|
@ -989,6 +1051,8 @@ show_p2mp_parms (const struct options *o)
|
|||
#if P2MP_SERVER
|
||||
msg (D_SHOW_PARMS, " server_network = %s", print_in_addr_t (o->server_network, 0, &gc));
|
||||
msg (D_SHOW_PARMS, " server_netmask = %s", print_in_addr_t (o->server_netmask, 0, &gc));
|
||||
msg (D_SHOW_PARMS, " server_network_ipv6 = %s", print_in6_addr (o->server_network_ipv6, 0, &gc) );
|
||||
SHOW_INT (server_netbits_ipv6);
|
||||
msg (D_SHOW_PARMS, " server_bridge_ip = %s", print_in_addr_t (o->server_bridge_ip, 0, &gc));
|
||||
msg (D_SHOW_PARMS, " server_bridge_netmask = %s", print_in_addr_t (o->server_bridge_netmask, 0, &gc));
|
||||
msg (D_SHOW_PARMS, " server_bridge_pool_start = %s", print_in_addr_t (o->server_bridge_pool_start, 0, &gc));
|
||||
|
|
@ -1009,6 +1073,8 @@ show_p2mp_parms (const struct options *o)
|
|||
msg (D_SHOW_PARMS, " ifconfig_pool_netmask = %s", print_in_addr_t (o->ifconfig_pool_netmask, 0, &gc));
|
||||
SHOW_STR (ifconfig_pool_persist_filename);
|
||||
SHOW_INT (ifconfig_pool_persist_refresh_freq);
|
||||
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);
|
||||
|
|
@ -1076,6 +1142,25 @@ option_iroute (struct options *o,
|
|||
o->iroutes = ir;
|
||||
}
|
||||
|
||||
static void
|
||||
option_iroute_ipv6 (struct options *o,
|
||||
const char *prefix_str,
|
||||
int msglevel)
|
||||
{
|
||||
struct iroute_ipv6 *ir;
|
||||
|
||||
ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc);
|
||||
|
||||
if ( get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, 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 +1198,13 @@ rol_check_alloc (struct options *options)
|
|||
options->routes = new_route_option_list (options->max_routes, &options->gc);
|
||||
}
|
||||
|
||||
void
|
||||
rol6_check_alloc (struct options *options)
|
||||
{
|
||||
if (!options->routes_ipv6)
|
||||
options->routes_ipv6 = new_route_ipv6_option_list (options->max_routes, &options->gc);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
static void
|
||||
show_connection_entry (const struct connection_entry *o)
|
||||
|
|
@ -1203,6 +1295,8 @@ show_settings (const struct options *o)
|
|||
SHOW_STR (ifconfig_remote_netmask);
|
||||
SHOW_BOOL (ifconfig_noexec);
|
||||
SHOW_BOOL (ifconfig_nowarn);
|
||||
SHOW_STR (ifconfig_ipv6_local);
|
||||
SHOW_STR (ifconfig_ipv6_remote);
|
||||
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
SHOW_INT (shaper);
|
||||
|
|
@ -1863,8 +1957,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
|
|||
if (options->connection_list)
|
||||
msg (M_USAGE, "<connection> cannot be used with --mode server");
|
||||
#endif
|
||||
#if 0
|
||||
if (options->tun_ipv6)
|
||||
msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server");
|
||||
#endif
|
||||
if (options->shaper)
|
||||
msg (M_USAGE, "--shaper cannot be used with --mode server");
|
||||
if (options->inetd)
|
||||
|
|
@ -2461,6 +2557,8 @@ options_string (const struct options *o,
|
|||
o->topology,
|
||||
o->ifconfig_local,
|
||||
o->ifconfig_remote_netmask,
|
||||
o->ifconfig_ipv6_local,
|
||||
o->ifconfig_ipv6_remote,
|
||||
(in_addr_t)0,
|
||||
(in_addr_t)0,
|
||||
false,
|
||||
|
|
@ -3794,6 +3892,21 @@ add_option (struct options *options,
|
|||
goto err;
|
||||
}
|
||||
}
|
||||
else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] )
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_UP);
|
||||
/* TODO: should we accept address + netbits (2001:db8::1/64) here? */
|
||||
if ( ipv6_addr_safe( p[1] ) && ipv6_addr_safe( p[2] ) )
|
||||
{
|
||||
options->ifconfig_ipv6_local = p[1];
|
||||
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);
|
||||
|
|
@ -4594,6 +4707,26 @@ add_option (struct options *options,
|
|||
}
|
||||
add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]);
|
||||
}
|
||||
else if (streq (p[0], "route-ipv6") && p[1])
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_ROUTE);
|
||||
rol6_check_alloc (options);
|
||||
if (pull_mode)
|
||||
{
|
||||
if (!ipv6_addr_safe_hexplusbits (p[1]))
|
||||
{
|
||||
msg (msglevel, "route-ipv6 parameter network/IP '%s' must be a valid address", p[1]);
|
||||
goto err;
|
||||
}
|
||||
if (p[2] && !ipv6_addr_safe (p[2]))
|
||||
{
|
||||
msg (msglevel, "route-ipv6 parameter gateway '%s' must be a valid address", p[2]);
|
||||
goto err;
|
||||
}
|
||||
/* p[3] is metric, if present */
|
||||
}
|
||||
add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]);
|
||||
}
|
||||
else if (streq (p[0], "max-routes") && p[1])
|
||||
{
|
||||
int max_routes;
|
||||
|
|
@ -4805,6 +4938,33 @@ add_option (struct options *options,
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (streq (p[0], "server-ipv6") && p[1] )
|
||||
{
|
||||
const int lev = M_WARN;
|
||||
struct in6_addr network;
|
||||
unsigned int netbits = 0;
|
||||
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
if ( ! get_ipv6_addr (p[1], &network, &netbits, 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: %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;
|
||||
|
|
@ -4889,6 +5049,28 @@ add_option (struct options *options,
|
|||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->topology = TOP_P2P;
|
||||
}
|
||||
else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] )
|
||||
{
|
||||
const int lev = M_WARN;
|
||||
struct in6_addr network;
|
||||
unsigned int netbits = 0;
|
||||
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
if ( ! get_ipv6_addr (p[1], &network, &netbits, 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;
|
||||
|
|
@ -5084,6 +5266,11 @@ add_option (struct options *options,
|
|||
}
|
||||
option_iroute (options, p[1], netmask, msglevel);
|
||||
}
|
||||
else if (streq (p[0], "iroute-ipv6") && p[1])
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_INSTANCE);
|
||||
option_iroute_ipv6 (options, p[1], msglevel);
|
||||
}
|
||||
else if (streq (p[0], "ifconfig-push") && p[1] && p[2])
|
||||
{
|
||||
in_addr_t local, remote_netmask;
|
||||
|
|
|
|||
15
options.h
15
options.h
|
|
@ -205,6 +205,8 @@ struct options
|
|||
int topology; /* one of the TOP_x values from proto.h */
|
||||
const char *ifconfig_local;
|
||||
const char *ifconfig_remote_netmask;
|
||||
const char *ifconfig_ipv6_local;
|
||||
const char *ifconfig_ipv6_remote;
|
||||
bool ifconfig_noexec;
|
||||
bool ifconfig_nowarn;
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
|
|
@ -326,6 +328,7 @@ struct options
|
|||
bool route_delay_defined;
|
||||
int max_routes;
|
||||
struct route_option_list *routes;
|
||||
struct route_ipv6_option_list *routes_ipv6; /* IPv6 */
|
||||
bool route_nopull;
|
||||
bool route_gateway_via_dhcp;
|
||||
bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */
|
||||
|
|
@ -361,6 +364,9 @@ struct options
|
|||
bool server_defined;
|
||||
in_addr_t server_network;
|
||||
in_addr_t server_netmask;
|
||||
bool server_ipv6_defined; /* IPv6 */
|
||||
struct in6_addr server_network_ipv6; /* IPv6 */
|
||||
unsigned int server_netbits_ipv6; /* IPv6 */
|
||||
|
||||
# define SF_NOPOOL (1<<0)
|
||||
# define SF_TCP_NODELAY_HELPER (1<<1)
|
||||
|
|
@ -382,6 +388,11 @@ struct options
|
|||
in_addr_t ifconfig_pool_netmask;
|
||||
const char *ifconfig_pool_persist_filename;
|
||||
int ifconfig_pool_persist_refresh_freq;
|
||||
|
||||
bool ifconfig_ipv6_pool_defined; /* IPv6 */
|
||||
struct in6_addr ifconfig_ipv6_pool_base; /* IPv6 */
|
||||
int ifconfig_ipv6_pool_netbits; /* IPv6 */
|
||||
|
||||
int real_hash_size;
|
||||
int virtual_hash_size;
|
||||
const char *client_connect_script;
|
||||
|
|
@ -394,6 +405,7 @@ struct options
|
|||
int n_bcast_buf;
|
||||
int tcp_queue_limit;
|
||||
struct iroute *iroutes;
|
||||
struct iroute_ipv6 *iroutes_ipv6; /* IPv6 */
|
||||
bool push_ifconfig_defined;
|
||||
in_addr_t push_ifconfig_local;
|
||||
in_addr_t push_ifconfig_remote_netmask;
|
||||
|
|
@ -722,6 +734,9 @@ void options_string_import (struct options *options,
|
|||
unsigned int *option_types_found,
|
||||
struct env_set *es);
|
||||
|
||||
bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
|
||||
unsigned int * netbits, int msglevel );
|
||||
|
||||
/*
|
||||
* inline functions
|
||||
*/
|
||||
|
|
|
|||
75
pool.c
75
pool.c
|
|
@ -132,7 +132,10 @@ ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_
|
|||
}
|
||||
|
||||
struct ifconfig_pool *
|
||||
ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn)
|
||||
ifconfig_pool_init (int type, in_addr_t start, in_addr_t end,
|
||||
const bool duplicate_cn,
|
||||
const bool ipv6_pool, const struct in6_addr ipv6_base,
|
||||
const int ipv6_netbits )
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
struct ifconfig_pool *pool = NULL;
|
||||
|
|
@ -157,11 +160,31 @@ ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplica
|
|||
ASSERT (0);
|
||||
}
|
||||
|
||||
/* IPv6 pools are always "INDIV" type */
|
||||
pool->ipv6 = ipv6_pool;
|
||||
|
||||
if ( pool->ipv6 )
|
||||
{
|
||||
pool->base_ipv6 = ipv6_base;
|
||||
pool->size_ipv6 = ipv6_netbits>96? ( 1<<(128-ipv6_netbits) )
|
||||
: IFCONFIG_POOL_MAX;
|
||||
|
||||
msg( D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: (IPv4) size=%d, size_ipv6=%d, netbits=%d, base_ipv6=%s",
|
||||
pool->size, pool->size_ipv6, ipv6_netbits,
|
||||
print_in6_addr( pool->base_ipv6, 0, &gc ));
|
||||
|
||||
/* the current code is very simple and assumes that the IPv6
|
||||
* pool is at least as big as the IPv4 pool, and we don't need
|
||||
* to do separate math etc. for IPv6
|
||||
*/
|
||||
ASSERT( pool->size < pool->size_ipv6 );
|
||||
}
|
||||
|
||||
ALLOC_ARRAY_CLEAR (pool->list, struct ifconfig_pool_entry, pool->size);
|
||||
|
||||
msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d",
|
||||
msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d, ipv6=%d",
|
||||
print_in_addr_t (pool->base, 0, &gc),
|
||||
pool->size);
|
||||
pool->size, pool->ipv6 );
|
||||
|
||||
gc_free (&gc);
|
||||
return pool;
|
||||
|
|
@ -181,7 +204,7 @@ ifconfig_pool_free (struct ifconfig_pool *pool)
|
|||
}
|
||||
|
||||
ifconfig_pool_handle
|
||||
ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name)
|
||||
ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -214,6 +237,12 @@ ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *
|
|||
default:
|
||||
ASSERT (0);
|
||||
}
|
||||
|
||||
/* IPv6 pools are always INDIV (--linear) */
|
||||
if ( pool->ipv6 && remote_ipv6 )
|
||||
{
|
||||
*remote_ipv6 = add_in6_addr( pool->base_ipv6, i );
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
|
@ -288,6 +317,19 @@ ifconfig_pool_handle_to_ip_base (const struct ifconfig_pool* pool, ifconfig_pool
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct in6_addr
|
||||
ifconfig_pool_handle_to_ipv6_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand)
|
||||
{
|
||||
struct in6_addr ret = in6addr_any;
|
||||
|
||||
/* IPv6 pools are always INDIV (--linear) */
|
||||
if (hand >= 0 && hand < pool->size_ipv6 )
|
||||
{
|
||||
ret = add_in6_addr( pool->base_ipv6, hand );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
ifconfig_pool_set (struct ifconfig_pool* pool, const char *cn, const in_addr_t addr, const bool fixed)
|
||||
{
|
||||
|
|
@ -317,9 +359,20 @@ ifconfig_pool_list (const struct ifconfig_pool* pool, struct status_output *out)
|
|||
if (e->common_name)
|
||||
{
|
||||
const in_addr_t ip = ifconfig_pool_handle_to_ip_base (pool, i);
|
||||
status_printf (out, "%s,%s",
|
||||
e->common_name,
|
||||
print_in_addr_t (ip, 0, &gc));
|
||||
if ( pool->ipv6 )
|
||||
{
|
||||
struct in6_addr ip6 = ifconfig_pool_handle_to_ipv6_base (pool, i);
|
||||
status_printf (out, "%s,%s,%s",
|
||||
e->common_name,
|
||||
print_in_addr_t (ip, 0, &gc),
|
||||
print_in6_addr (ip6, 0, &gc));
|
||||
}
|
||||
else
|
||||
{
|
||||
status_printf (out, "%s,%s",
|
||||
e->common_name,
|
||||
print_in_addr_t (ip, 0, &gc));
|
||||
}
|
||||
}
|
||||
}
|
||||
gc_free (&gc);
|
||||
|
|
@ -409,6 +462,9 @@ ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool
|
|||
int c = *BSTR(&in);
|
||||
if (c == '#' || c == ';')
|
||||
continue;
|
||||
msg( M_INFO, "ifconfig_pool_read(), in='%s', TODO: IPv6",
|
||||
BSTR(&in) );
|
||||
|
||||
if (buf_parse (&in, ',', cn_buf, buf_size)
|
||||
&& buf_parse (&in, ',', ip_buf, buf_size))
|
||||
{
|
||||
|
|
@ -416,6 +472,7 @@ ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool
|
|||
const in_addr_t addr = getaddr (GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL);
|
||||
if (succeeded)
|
||||
{
|
||||
msg( M_INFO, "succeeded -> ifconfig_pool_set()");
|
||||
ifconfig_pool_set (pool, cn_buf, addr, persist->fixed);
|
||||
}
|
||||
}
|
||||
|
|
@ -471,7 +528,7 @@ ifconfig_pool_test (in_addr_t start, in_addr_t end)
|
|||
#else
|
||||
cn = buf;
|
||||
#endif
|
||||
h = ifconfig_pool_acquire (p, &local, &remote, cn);
|
||||
h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn);
|
||||
if (h < 0)
|
||||
break;
|
||||
msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s",
|
||||
|
|
@ -506,7 +563,7 @@ ifconfig_pool_test (in_addr_t start, in_addr_t end)
|
|||
#else
|
||||
cn = buf;
|
||||
#endif
|
||||
h = ifconfig_pool_acquire (p, &local, &remote, cn);
|
||||
h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn);
|
||||
if (h < 0)
|
||||
break;
|
||||
msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s",
|
||||
|
|
|
|||
7
pool.h
7
pool.h
|
|
@ -52,6 +52,9 @@ struct ifconfig_pool
|
|||
int size;
|
||||
int type;
|
||||
bool duplicate_cn;
|
||||
bool ipv6;
|
||||
struct in6_addr base_ipv6;
|
||||
unsigned int size_ipv6;
|
||||
struct ifconfig_pool_entry *list;
|
||||
};
|
||||
|
||||
|
|
@ -63,13 +66,13 @@ struct ifconfig_pool_persist
|
|||
|
||||
typedef int ifconfig_pool_handle;
|
||||
|
||||
struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn);
|
||||
struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn, const bool ipv6_pool, const struct in6_addr ipv6_base, const int ipv6_netbits );
|
||||
|
||||
void ifconfig_pool_free (struct ifconfig_pool *pool);
|
||||
|
||||
bool ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end);
|
||||
|
||||
ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name);
|
||||
ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name);
|
||||
|
||||
bool ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard);
|
||||
|
||||
|
|
|
|||
15
proto.h
15
proto.h
|
|
@ -107,6 +107,21 @@ struct openvpn_iphdr {
|
|||
/*The options start here. */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
|
|
|||
16
push.c
16
push.c
|
|
@ -191,6 +191,22 @@ send_push_reply (struct context *c)
|
|||
|
||||
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)
|
||||
|
|
|
|||
477
route.c
477
route.c
|
|
@ -39,6 +39,7 @@
|
|||
#include "memdbg.h"
|
||||
|
||||
static void delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
|
||||
static void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
|
||||
static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags);
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
|
|
@ -68,6 +69,15 @@ new_route_option_list (const int max_routes, struct gc_arena *a)
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct route_ipv6_option_list *
|
||||
new_route_ipv6_option_list (const int max_routes, struct gc_arena *a)
|
||||
{
|
||||
struct route_ipv6_option_list *ret;
|
||||
ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_option_list, struct route_ipv6_option, max_routes, a);
|
||||
ret->capacity = max_routes;
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct route_option_list *
|
||||
clone_route_option_list (const struct route_option_list *src, struct gc_arena *a)
|
||||
{
|
||||
|
|
@ -95,6 +105,15 @@ new_route_list (const int max_routes, struct gc_arena *a)
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct route_ipv6_list *
|
||||
new_route_ipv6_list (const int max_routes, struct gc_arena *a)
|
||||
{
|
||||
struct route_ipv6_list *ret;
|
||||
ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_list, struct route_ipv6, max_routes, a);
|
||||
ret->capacity = max_routes;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
route_string (const struct route *r, struct gc_arena *gc)
|
||||
{
|
||||
|
|
@ -311,6 +330,68 @@ init_route (struct route *r,
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
init_route_ipv6 (struct route_ipv6 *r6,
|
||||
const struct route_ipv6_option *r6o,
|
||||
const struct route_ipv6_list *rl6 )
|
||||
{
|
||||
r6->option = r6o;
|
||||
r6->defined = false;
|
||||
|
||||
if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, 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,
|
||||
|
|
@ -330,6 +411,23 @@ add_route_to_option_list (struct route_option_list *l,
|
|||
++l->n;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -339,6 +437,15 @@ clear_route_list (struct route_list *rl)
|
|||
rl->capacity = capacity;
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
@ -469,6 +576,72 @@ init_route_list (struct route_list *rl,
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
init_route_ipv6_list (struct route_ipv6_list *rl6,
|
||||
const struct route_ipv6_option_list *opt6,
|
||||
const char *remote_endpoint,
|
||||
int default_metric,
|
||||
struct env_set *es)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
bool ret = true;
|
||||
|
||||
clear_route_ipv6_list (rl6);
|
||||
|
||||
rl6->flags = opt6->flags;
|
||||
|
||||
if (default_metric)
|
||||
{
|
||||
rl6->default_metric = default_metric;
|
||||
rl6->default_metric_defined = true;
|
||||
}
|
||||
|
||||
/* "default_gateway" is stuff for "redirect-gateway", which we don't
|
||||
* do for IPv6 yet -> TODO
|
||||
*/
|
||||
{
|
||||
dmsg (D_ROUTE, "ROUTE6: default_gateway=UNDEF");
|
||||
}
|
||||
|
||||
if ( is_route_parm_defined( remote_endpoint ))
|
||||
{
|
||||
if ( inet_pton( AF_INET6, remote_endpoint,
|
||||
&rl6->remote_endpoint_ipv6) == 1 )
|
||||
{
|
||||
rl6->remote_endpoint_defined = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve default gateway: %s", remote_endpoint);
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
rl6->remote_endpoint_defined = false;
|
||||
|
||||
|
||||
if (!(opt6->n >= 0 && opt6->n <= rl6->capacity))
|
||||
msg (M_FATAL, PACKAGE_NAME " ROUTE6: (init) number of route options (%d) is greater than route list capacity (%d)", opt6->n, rl6->capacity);
|
||||
|
||||
/* parse the routes from opt to rl6 */
|
||||
{
|
||||
int i, j = 0;
|
||||
for (i = 0; i < opt6->n; ++i)
|
||||
{
|
||||
if (!init_route_ipv6 (&rl6->routes_ipv6[j],
|
||||
&opt6->routes_ipv6[i],
|
||||
rl6 ))
|
||||
ret = false;
|
||||
else
|
||||
++j;
|
||||
}
|
||||
rl6->n = j;
|
||||
}
|
||||
|
||||
gc_free (&gc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
add_route3 (in_addr_t network,
|
||||
in_addr_t netmask,
|
||||
|
|
@ -704,10 +877,13 @@ undo_redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *
|
|||
}
|
||||
|
||||
void
|
||||
add_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
|
||||
add_routes (struct route_list *rl, struct route_ipv6_list *rl6,
|
||||
const struct tuntap *tt, unsigned int flags, const struct env_set *es)
|
||||
{
|
||||
redirect_default_route_to_vpn (rl, tt, flags, es);
|
||||
if (!rl->routes_added)
|
||||
if (rl)
|
||||
redirect_default_route_to_vpn (rl, tt, flags, es);
|
||||
|
||||
if (rl && !rl->routes_added)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
|
@ -732,12 +908,27 @@ add_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags,
|
|||
}
|
||||
rl->routes_added = true;
|
||||
}
|
||||
|
||||
if (rl6 && !rl6->routes_added)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rl6->n; ++i)
|
||||
{
|
||||
struct route_ipv6 *r = &rl6->routes_ipv6[i];
|
||||
if (flags & ROUTE_DELETE_FIRST)
|
||||
delete_route_ipv6 (r, tt, flags, es);
|
||||
add_route_ipv6 (r, tt, flags, es);
|
||||
}
|
||||
rl6->routes_added = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
delete_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
|
||||
delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
|
||||
const struct tuntap *tt, unsigned int flags, const struct env_set *es)
|
||||
{
|
||||
if (rl->routes_added)
|
||||
if (rl && rl->routes_added)
|
||||
{
|
||||
int i;
|
||||
for (i = rl->n - 1; i >= 0; --i)
|
||||
|
|
@ -747,9 +938,28 @@ delete_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flag
|
|||
}
|
||||
rl->routes_added = false;
|
||||
}
|
||||
undo_redirect_default_route_to_vpn (rl, tt, flags, es);
|
||||
|
||||
clear_route_list (rl);
|
||||
if ( rl )
|
||||
{
|
||||
undo_redirect_default_route_to_vpn (rl, tt, flags, es);
|
||||
clear_route_list (rl);
|
||||
}
|
||||
|
||||
if ( rl6 && rl6->routes_added )
|
||||
{
|
||||
int i;
|
||||
for (i = rl6->n - 1; i >= 0; --i)
|
||||
{
|
||||
const struct route_ipv6 *r6 = &rl6->routes_ipv6[i];
|
||||
delete_route_ipv6 (r6, tt, flags, es);
|
||||
}
|
||||
rl6->routes_added = false;
|
||||
}
|
||||
|
||||
if ( rl6 )
|
||||
{
|
||||
clear_route_ipv6_list (rl6);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DEBUG
|
||||
|
|
@ -832,6 +1042,34 @@ setenv_routes (struct env_set *es, const struct route_list *rl)
|
|||
setenv_route (es, &rl->routes[i], i + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
if (r6->defined)
|
||||
{
|
||||
struct buffer name1 = alloc_buf_gc( 256, &gc );
|
||||
struct buffer val = alloc_buf_gc( 256, &gc );
|
||||
struct buffer name2 = alloc_buf_gc( 256, &gc );
|
||||
|
||||
buf_printf( &name1, "route_ipv6_network_%d", i );
|
||||
buf_printf( &val, "%s/%d", print_in6_addr( r6->network, 0, &gc ),
|
||||
r6->netbits );
|
||||
setenv_str( es, BSTR(&name1), BSTR(&val) );
|
||||
|
||||
buf_printf( &name2, "route_ipv6_gateway_%d", i );
|
||||
setenv_str( es, BSTR(&name2), print_in6_addr( r6->gateway, 0, &gc ));
|
||||
}
|
||||
gc_free (&gc);
|
||||
}
|
||||
void
|
||||
setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < rl6->n; ++i)
|
||||
setenv_route_ipv6 (es, &rl6->routes_ipv6[i], i + 1);
|
||||
}
|
||||
|
||||
void
|
||||
add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
|
||||
{
|
||||
|
|
@ -1025,6 +1263,136 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
|
|||
gc_free (&gc);
|
||||
}
|
||||
|
||||
void
|
||||
add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
|
||||
{
|
||||
struct gc_arena gc;
|
||||
struct argv argv;
|
||||
|
||||
const char *network;
|
||||
const char *gateway;
|
||||
bool status = false;
|
||||
const char *device = tt->actual_name;
|
||||
int byte, bits_to_clear;
|
||||
struct in6_addr network_copy = r6->network;
|
||||
|
||||
if (!r6->defined)
|
||||
return;
|
||||
|
||||
gc_init (&gc);
|
||||
argv_init (&argv);
|
||||
|
||||
/* clear host bit parts of route
|
||||
* (needed if routes are specified improperly, or if we need to
|
||||
* explicitely setup the "connected" network routes on some OSes)
|
||||
*/
|
||||
byte = 15;
|
||||
bits_to_clear = 128 - r6->netbits;
|
||||
|
||||
while( byte >= 0 && bits_to_clear > 0 )
|
||||
{
|
||||
if ( bits_to_clear >= 8 )
|
||||
{ network_copy.s6_addr[byte--] = 0; bits_to_clear -= 8; }
|
||||
else
|
||||
{ network_copy.s6_addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; }
|
||||
}
|
||||
|
||||
network = print_in6_addr( network_copy, 0, &gc);
|
||||
gateway = print_in6_addr( r6->gateway, 0, &gc);
|
||||
|
||||
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)
|
||||
|
||||
msg( M_FATAL, "no idea how to set IPv6 routes on windows (unimplemented)" );
|
||||
|
||||
#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) || defined(TARGET_NETBSD)
|
||||
|
||||
/* GERT-TODO: this needs real-world testing on OpenBSD, but it should work
|
||||
*/
|
||||
|
||||
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/OpenBSD 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)
|
||||
{
|
||||
|
|
@ -1164,6 +1532,101 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags
|
|||
gc_free (&gc);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es)
|
||||
{
|
||||
struct gc_arena gc;
|
||||
struct argv argv;
|
||||
const char *network;
|
||||
const char *gateway;
|
||||
const char *device = tt->actual_name;
|
||||
|
||||
if (!r6->defined)
|
||||
return;
|
||||
|
||||
gc_init (&gc);
|
||||
argv_init (&argv);
|
||||
|
||||
network = print_in6_addr( r6->network, 0, &gc);
|
||||
gateway = print_in6_addr( r6->gateway, 0, &gc);
|
||||
|
||||
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)
|
||||
|
||||
msg( M_FATAL, "no idea how to delete IPv6 routes on windows (unimplemented)" );
|
||||
|
||||
#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) || defined(TARGET_NETBSD)
|
||||
|
||||
/* GERT-TODO: this needs real-world testing on OpenBSD, but it 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: NetBSD/OpenBSD route delete -inet6 command failed");
|
||||
|
||||
#else
|
||||
msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-down script");
|
||||
#endif
|
||||
|
||||
argv_reset (&argv);
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
/*
|
||||
* The --redirect-gateway option requires OS-specific code below
|
||||
* to get the current default gateway.
|
||||
|
|
|
|||
61
route.h
61
route.h
|
|
@ -92,6 +92,19 @@ struct route_option_list {
|
|||
struct route_option routes[EMPTY_ARRAY_SIZE];
|
||||
};
|
||||
|
||||
struct route_ipv6_option {
|
||||
const char *prefix; /* e.g. "2001:db8:1::/64" */
|
||||
const char *gateway; /* e.g. "2001:db8:0::2" */
|
||||
const char *metric; /* e.g. "5" */
|
||||
};
|
||||
|
||||
struct route_ipv6_option_list {
|
||||
unsigned int flags;
|
||||
int capacity;
|
||||
int n;
|
||||
struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE];
|
||||
};
|
||||
|
||||
struct route {
|
||||
bool defined;
|
||||
const struct route_option *option;
|
||||
|
|
@ -113,6 +126,31 @@ struct route_list {
|
|||
struct route routes[EMPTY_ARRAY_SIZE];
|
||||
};
|
||||
|
||||
struct route_ipv6 {
|
||||
bool defined;
|
||||
const struct route_ipv6_option *option;
|
||||
struct in6_addr network;
|
||||
int netbits;
|
||||
struct in6_addr gateway;
|
||||
bool metric_defined;
|
||||
int metric;
|
||||
};
|
||||
|
||||
struct route_ipv6_list {
|
||||
bool routes_added;
|
||||
unsigned int flags;
|
||||
int default_metric;
|
||||
bool default_metric_defined;
|
||||
struct in6_addr remote_endpoint_ipv6;
|
||||
bool remote_endpoint_defined;
|
||||
bool did_redirect_default_gateway; /* TODO (?) */
|
||||
bool did_local; /* TODO (?) */
|
||||
int capacity;
|
||||
int n;
|
||||
struct route_ipv6 routes_ipv6[EMPTY_ARRAY_SIZE];
|
||||
};
|
||||
|
||||
|
||||
#if P2MP
|
||||
/* internal OpenVPN route */
|
||||
struct iroute {
|
||||
|
|
@ -120,15 +158,24 @@ struct iroute {
|
|||
int netbits;
|
||||
struct iroute *next;
|
||||
};
|
||||
|
||||
struct iroute_ipv6 {
|
||||
struct in6_addr network;
|
||||
unsigned int netbits;
|
||||
struct iroute_ipv6 *next;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct route_option_list *new_route_option_list (const int max_routes, struct gc_arena *a);
|
||||
struct route_ipv6_option_list *new_route_ipv6_option_list (const int max_routes, struct gc_arena *a);
|
||||
struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a);
|
||||
void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src);
|
||||
|
||||
struct route_list *new_route_list (const int max_routes, struct gc_arena *a);
|
||||
struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_arena *a);
|
||||
|
||||
void add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
|
||||
void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
|
||||
|
||||
void add_route_to_option_list (struct route_option_list *l,
|
||||
const char *network,
|
||||
|
|
@ -136,6 +183,11 @@ void add_route_to_option_list (struct route_option_list *l,
|
|||
const char *gateway,
|
||||
const char *metric);
|
||||
|
||||
void add_route_ipv6_to_option_list (struct route_ipv6_option_list *l,
|
||||
const char *prefix,
|
||||
const char *gateway,
|
||||
const char *metric);
|
||||
|
||||
bool init_route_list (struct route_list *rl,
|
||||
const struct route_option_list *opt,
|
||||
const char *remote_endpoint,
|
||||
|
|
@ -143,21 +195,30 @@ bool init_route_list (struct route_list *rl,
|
|||
in_addr_t remote_host,
|
||||
struct env_set *es);
|
||||
|
||||
bool init_route_ipv6_list (struct route_ipv6_list *rl6,
|
||||
const struct route_ipv6_option_list *opt6,
|
||||
const char *remote_endpoint,
|
||||
int default_metric,
|
||||
struct env_set *es);
|
||||
|
||||
void route_list_add_default_gateway (struct route_list *rl,
|
||||
struct env_set *es,
|
||||
const in_addr_t addr);
|
||||
|
||||
void add_routes (struct route_list *rl,
|
||||
struct route_ipv6_list *rl6,
|
||||
const struct tuntap *tt,
|
||||
unsigned int flags,
|
||||
const struct env_set *es);
|
||||
|
||||
void delete_routes (struct route_list *rl,
|
||||
struct route_ipv6_list *rl6,
|
||||
const struct tuntap *tt,
|
||||
unsigned int flags,
|
||||
const struct env_set *es);
|
||||
|
||||
void setenv_routes (struct env_set *es, const struct route_list *rl);
|
||||
void setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6);
|
||||
|
||||
bool is_special_addr (const char *addr_str);
|
||||
|
||||
|
|
|
|||
70
socket.c
70
socket.c
|
|
@ -342,6 +342,24 @@ ip_addr_dotted_quad_safe (const char *dotted_quad)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ipv6_addr_safe (const char *ipv6_text_addr)
|
||||
{
|
||||
/* verify non-NULL */
|
||||
if (!ipv6_text_addr)
|
||||
return false;
|
||||
|
||||
/* verify length is within limits */
|
||||
if (strlen (ipv6_text_addr) > INET6_ADDRSTRLEN )
|
||||
return false;
|
||||
|
||||
/* verify that string will convert to IPv6 address */
|
||||
{
|
||||
struct in6_addr a6;
|
||||
return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
dns_addr_safe (const char *addr)
|
||||
{
|
||||
|
|
@ -2032,6 +2050,58 @@ print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc)
|
|||
return BSTR (&out);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an in6_addr in host byte order
|
||||
* to an ascii representation of an IPv6 address
|
||||
* (we reuse the L_INET_NTOA mutex, no contention here)
|
||||
*/
|
||||
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))
|
||||
{
|
||||
mutex_lock_static (L_INET_NTOA);
|
||||
inet_ntop (AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1);
|
||||
buf_printf (&out, "%s", tmp_out_buf );
|
||||
mutex_unlock_static (L_INET_NTOA);
|
||||
}
|
||||
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)
|
||||
|
|
|
|||
3
socket.h
3
socket.h
|
|
@ -351,6 +351,8 @@ const char *print_link_socket_actual (const struct link_socket_actual *act,
|
|||
#define IA_EMPTY_IF_UNDEF (1<<0)
|
||||
#define IA_NET_ORDER (1<<1)
|
||||
const char *print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc);
|
||||
const char *print_in6_addr (struct in6_addr addr6, unsigned int flags, struct gc_arena *gc);
|
||||
struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add );
|
||||
|
||||
#define SA_IP_PORT (1<<0)
|
||||
#define SA_SET_IF_NONZERO (1<<1)
|
||||
|
|
@ -404,6 +406,7 @@ int openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr);
|
|||
bool ip_addr_dotted_quad_safe (const char *dotted_quad);
|
||||
bool ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn);
|
||||
bool mac_addr_safe (const char *mac_addr);
|
||||
bool ipv6_addr_safe (const char *ipv6_text_addr);
|
||||
|
||||
socket_descriptor_t create_socket_tcp (void);
|
||||
|
||||
|
|
|
|||
267
tun.c
267
tun.c
|
|
@ -62,7 +62,7 @@ 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
|
||||
|
||||
|
|
@ -143,14 +143,15 @@ guess_tuntap_dev (const char *dev,
|
|||
* 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.
|
||||
*
|
||||
* (enabling IPv6 on tun devices might work anyway, but since
|
||||
* we don't know, we log a warning)
|
||||
*/
|
||||
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)
|
||||
tt->ipv6 = ipv6;
|
||||
if (ipv6 && !ipv6_explicitly_supported)
|
||||
msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");
|
||||
}
|
||||
|
||||
|
|
@ -423,6 +424,8 @@ init_tun (const char *dev, /* --dev option */
|
|||
int topology, /* one of the TOP_x values */
|
||||
const char *ifconfig_local_parm, /* --ifconfig parm 1 */
|
||||
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
|
||||
const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 IPv6 */
|
||||
const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 IPv6 */
|
||||
in_addr_t local_public,
|
||||
in_addr_t remote_public,
|
||||
const bool strict_warn,
|
||||
|
|
@ -430,6 +433,7 @@ init_tun (const char *dev, /* --dev option */
|
|||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
struct tuntap *tt;
|
||||
bool tun;
|
||||
|
||||
ALLOC_OBJ (tt, struct tuntap);
|
||||
clear_tuntap (tt);
|
||||
|
|
@ -437,18 +441,17 @@ init_tun (const char *dev, /* --dev option */
|
|||
tt->type = dev_type_enum (dev, dev_type);
|
||||
tt->topology = topology;
|
||||
|
||||
/*
|
||||
* We only handle TUN/TAP devices here, not --dev null devices.
|
||||
*/
|
||||
tun = is_tun_p2p (tt);
|
||||
|
||||
if (ifconfig_local_parm && ifconfig_remote_netmask_parm)
|
||||
{
|
||||
bool tun = false;
|
||||
const char *ifconfig_local = NULL;
|
||||
const char *ifconfig_remote_netmask = NULL;
|
||||
const char *ifconfig_broadcast = NULL;
|
||||
|
||||
/*
|
||||
* We only handle TUN/TAP devices here, not --dev null devices.
|
||||
*/
|
||||
tun = is_tun_p2p (tt);
|
||||
|
||||
/*
|
||||
* Convert arguments to binary IPv4 addresses.
|
||||
*/
|
||||
|
|
@ -537,6 +540,40 @@ init_tun (const char *dev, /* --dev option */
|
|||
|
||||
tt->did_ifconfig_setup = true;
|
||||
}
|
||||
|
||||
if (ifconfig_ipv6_local_parm && ifconfig_ipv6_remote_parm)
|
||||
{
|
||||
const char *ifconfig_ipv6_local = NULL;
|
||||
const char *ifconfig_ipv6_remote = NULL;
|
||||
|
||||
/*
|
||||
* Convert arguments to binary IPv6 addresses.
|
||||
*/
|
||||
|
||||
if ( inet_pton( AF_INET6, ifconfig_ipv6_local_parm, &tt->local_ipv6 ) != 1 ||
|
||||
inet_pton( AF_INET6, ifconfig_ipv6_remote_parm, &tt->remote_ipv6 ) != 1 )
|
||||
{
|
||||
msg( M_FATAL, "init_tun: problem converting IPv6 ifconfig addresses %s and %s to binary", ifconfig_ipv6_local_parm, ifconfig_ipv6_remote_parm );
|
||||
}
|
||||
tt->netbits_ipv6 = 64;
|
||||
|
||||
/*
|
||||
* Set ifconfig parameters
|
||||
*/
|
||||
ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
|
||||
ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc);
|
||||
|
||||
/*
|
||||
* Set environmental variables with ifconfig parameters.
|
||||
*/
|
||||
if (es)
|
||||
{
|
||||
setenv_str (es, "ifconfig_ipv6_local", ifconfig_ipv6_local);
|
||||
setenv_str (es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote);
|
||||
}
|
||||
tt->did_ifconfig_ipv6_setup = true;
|
||||
}
|
||||
|
||||
gc_free (&gc);
|
||||
return tt;
|
||||
}
|
||||
|
|
@ -574,10 +611,15 @@ do_ifconfig (struct tuntap *tt,
|
|||
const char *ifconfig_local = NULL;
|
||||
const char *ifconfig_remote_netmask = NULL;
|
||||
const char *ifconfig_broadcast = NULL;
|
||||
const char *ifconfig_ipv6_local = NULL;
|
||||
const char *ifconfig_ipv6_remote = NULL;
|
||||
bool do_ipv6 = false;
|
||||
struct argv argv;
|
||||
|
||||
argv_init (&argv);
|
||||
|
||||
msg( M_INFO, "do_ifconfig, ipv6=%d", tt->ipv6 );
|
||||
|
||||
/*
|
||||
* We only handle TUN/TAP devices here, not --dev null devices.
|
||||
*/
|
||||
|
|
@ -589,6 +631,13 @@ do_ifconfig (struct tuntap *tt,
|
|||
ifconfig_local = print_in_addr_t (tt->local, 0, &gc);
|
||||
ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc);
|
||||
|
||||
if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup )
|
||||
{
|
||||
ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
|
||||
ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc);
|
||||
do_ipv6 = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If TAP-style device, generate broadcast address.
|
||||
*/
|
||||
|
|
@ -635,6 +684,18 @@ do_ifconfig (struct tuntap *tt,
|
|||
);
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed");
|
||||
if ( do_ipv6 ) /* GERT-TODO: yet UNTESTED! */
|
||||
{
|
||||
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");
|
||||
}
|
||||
} else {
|
||||
argv_printf (&argv,
|
||||
"%s addr add dev %s %s/%d broadcast %s",
|
||||
|
|
@ -670,6 +731,18 @@ do_ifconfig (struct tuntap *tt,
|
|||
);
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig failed");
|
||||
if ( do_ipv6 )
|
||||
{
|
||||
argv_printf (&argv,
|
||||
"%s %s inet6 add %s/%d",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_ipv6_local,
|
||||
tt->netbits_ipv6
|
||||
);
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig inet6 failed");
|
||||
}
|
||||
tt->did_ifconfig = true;
|
||||
|
||||
#endif /*CONFIG_FEATURE_IPROUTE*/
|
||||
|
|
@ -693,7 +766,7 @@ do_ifconfig (struct tuntap *tt,
|
|||
|
||||
argv_msg (M_INFO, &argv);
|
||||
if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-1 failed"))
|
||||
solaris_error_close (tt, es, actual);
|
||||
solaris_error_close (tt, es, actual, false);
|
||||
|
||||
argv_printf (&argv,
|
||||
"%s %s netmask 255.255.255.255",
|
||||
|
|
@ -725,7 +798,27 @@ do_ifconfig (struct tuntap *tt,
|
|||
|
||||
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 ) /* GERT-TODO: UNTESTED */
|
||||
{
|
||||
argv_printf (&argv, "%s %s inet6 unplumb",
|
||||
IFCONFIG_PATH, actual );
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, NULL);
|
||||
|
||||
argv_printf (&argv,
|
||||
"%s %s inet6 plumb %s/%d %s up",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_ipv6_local,
|
||||
tt->netbits_ipv6,
|
||||
ifconfig_ipv6_remote
|
||||
);
|
||||
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 +880,19 @@ do_ifconfig (struct tuntap *tt,
|
|||
);
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed");
|
||||
if ( do_ipv6 )
|
||||
{
|
||||
msg( M_FATAL, "can't configure IPv6 on OpenBSD yet - unimplemented" );
|
||||
}
|
||||
tt->did_ifconfig = true;
|
||||
|
||||
#elif defined(TARGET_NETBSD)
|
||||
|
||||
/* as on OpenBSD and Darwin, destroy and re-create tun0 interface
|
||||
*/
|
||||
argv_printf (&argv, "%s %s destroy", IFCONFIG_PATH, actual );
|
||||
argv_msg (M_INFO, &argv);
|
||||
|
||||
if (tun)
|
||||
argv_printf (&argv,
|
||||
"%s %s %s %s mtu %d netmask 255.255.255.255 up",
|
||||
|
|
@ -817,6 +919,27 @@ do_ifconfig (struct tuntap *tt,
|
|||
);
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed");
|
||||
|
||||
if ( do_ipv6 )
|
||||
{
|
||||
struct route_ipv6 r6;
|
||||
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 failed");
|
||||
|
||||
/* and, hooray, we explicitely need to add a route... */
|
||||
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);
|
||||
}
|
||||
tt->did_ifconfig = true;
|
||||
|
||||
#elif defined(TARGET_DARWIN)
|
||||
|
|
@ -882,6 +1005,27 @@ do_ifconfig (struct tuntap *tt,
|
|||
add_route (&r, tt, 0, es);
|
||||
}
|
||||
|
||||
if ( do_ipv6 )
|
||||
{
|
||||
struct route_ipv6 r6;
|
||||
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... */
|
||||
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);
|
||||
}
|
||||
|
||||
#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 +1064,19 @@ do_ifconfig (struct tuntap *tt,
|
|||
add_route (&r, tt, 0, es);
|
||||
}
|
||||
|
||||
if ( do_ipv6 )
|
||||
{
|
||||
argv_printf (&argv,
|
||||
"%s %s inet6 %s/%d",
|
||||
IFCONFIG_PATH,
|
||||
actual,
|
||||
ifconfig_ipv6_local,
|
||||
tt->netbits_ipv6
|
||||
);
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed");
|
||||
}
|
||||
|
||||
#elif defined (WIN32)
|
||||
{
|
||||
/*
|
||||
|
|
@ -959,6 +1116,10 @@ do_ifconfig (struct tuntap *tt,
|
|||
tt->did_ifconfig = true;
|
||||
}
|
||||
|
||||
if ( do_ipv6 )
|
||||
{
|
||||
msg( M_FATAL, "can't configure IPv6 on Win32 yet - unimplemented" );
|
||||
}
|
||||
#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
|
||||
|
|
@ -1415,6 +1576,10 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
|
|||
bool is_tun;
|
||||
struct strioctl strioc_if, strioc_ppa;
|
||||
|
||||
/* improved generic TUN/TAP driver from
|
||||
* http://www.whiteboard.ne.jp/~admin2/tuntap/
|
||||
* has IPv6 support
|
||||
*/
|
||||
ipv6_support (ipv6, true, tt);
|
||||
memset(&ifr, 0x0, sizeof(ifr));
|
||||
|
||||
|
|
@ -1622,11 +1787,20 @@ close_tun (struct tuntap *tt)
|
|||
}
|
||||
|
||||
static void
|
||||
solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual)
|
||||
solaris_error_close (struct tuntap *tt, const struct env_set *es,
|
||||
const char *actual, bool unplumb_inet6 )
|
||||
{
|
||||
struct argv argv;
|
||||
argv_init (&argv);
|
||||
|
||||
if (unplumb_inet6)
|
||||
{
|
||||
argv_printf( &argv, "%s %s inet6 unplumb",
|
||||
IFCONFIG_PATH, actual );
|
||||
argv_msg (M_INFO, &argv);
|
||||
openvpn_execve_check (&argv, es, 0, "Solaris ifconfig inet6 unplumb failed");
|
||||
}
|
||||
|
||||
argv_printf (&argv,
|
||||
"%s %s unplumb",
|
||||
IFCONFIG_PATH,
|
||||
|
|
@ -1774,17 +1948,34 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
|
|||
#elif defined(TARGET_NETBSD)
|
||||
|
||||
/*
|
||||
* NetBSD does not support IPv6 on tun out of the box,
|
||||
* but there exists a patch. When this patch is applied,
|
||||
* only two things are left to openvpn:
|
||||
* 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).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ... unfortunately, it doesn't work that way. If TUN_IFHEAD is disabled
|
||||
* ("no prepending of the AF"), then the kernel code just drops IPv6 packets
|
||||
* on output, and gets confused on input.
|
||||
*
|
||||
* So we have to do it the same way as FreeBSD and OpenBSD do it
|
||||
* (and we really should merge FreeBSD, NetBSD and OpenBSD together)
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt)
|
||||
{
|
||||
|
|
@ -1795,12 +1986,20 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
|
|||
ioctl (tt->fd, TUNSIFMODE, &i); /* multicast on */
|
||||
i = 0;
|
||||
ioctl (tt->fd, TUNSLMODE, &i); /* link layer mode off */
|
||||
i = 1;
|
||||
if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0) /* multi-af mode on */
|
||||
{
|
||||
msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
@ -1811,12 +2010,46 @@ close_tun (struct tuntap *tt)
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
7
tun.h
7
tun.h
|
|
@ -130,6 +130,7 @@ struct tuntap
|
|||
int topology; /* one of the TOP_x values */
|
||||
|
||||
bool did_ifconfig_setup;
|
||||
bool did_ifconfig_ipv6_setup;
|
||||
bool did_ifconfig;
|
||||
|
||||
bool ipv6;
|
||||
|
|
@ -146,6 +147,10 @@ struct tuntap
|
|||
in_addr_t remote_netmask;
|
||||
in_addr_t broadcast;
|
||||
|
||||
struct in6_addr local_ipv6;
|
||||
struct in6_addr remote_ipv6;
|
||||
int netbits_ipv6;
|
||||
|
||||
#ifdef WIN32
|
||||
HANDLE hand;
|
||||
struct overlapped_io reads;
|
||||
|
|
@ -219,6 +224,8 @@ struct tuntap *init_tun (const char *dev, /* --dev option */
|
|||
int topology, /* one of the TOP_x values */
|
||||
const char *ifconfig_local_parm, /* --ifconfig parm 1 */
|
||||
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
|
||||
const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 / IPv6 */
|
||||
const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 / IPv6 */
|
||||
in_addr_t local_public,
|
||||
in_addr_t remote_public,
|
||||
const bool strict_warn,
|
||||
|
|
|
|||
Loading…
Reference in a new issue