From cddff731a04d261c638e19b5d37c7ee15d81c19e Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 7 Jan 2010 14:51:40 +0100 Subject: [PATCH] Enable IPv6 Payload in OpenVPN p2mp tun server mode. 20100104-1 release. (cherry picked from commit ec9dce6387afd198881493bfebf13bb121e8a56b) --- NOTES | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ mroute.c | 38 ++++++++++++ push.c | 2 + tun.c | 55 +++++++++++++++-- 4 files changed, 269 insertions(+), 6 deletions(-) create mode 100644 NOTES diff --git a/NOTES b/NOTES new file mode 100644 index 00000000..d4940733 --- /dev/null +++ b/NOTES @@ -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? diff --git a/mroute.c b/mroute.c index af00c1e2..5ef07b22 100644 --- a/mroute.c +++ b/mroute.c @@ -525,6 +525,44 @@ mroute_helper_del_iroute6 (struct mroute_helper *mh, } } +/* this is a bit inelegant, we really should have a helper to that + * is only passed the netbits value, and not the whole struct iroute * + * - thus one helper could do IPv4 and IPv6. For the sake of "not change + * code unrelated to IPv4" this is left for later cleanup, for now. + */ +void +mroute_helper_add_iroute6 (struct mroute_helper *mh, + const struct iroute_ipv6 *ir6) +{ + if (ir6->netbits >= 0) + { + ASSERT (ir6->netbits < MR_HELPER_NET_LEN); + 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) { diff --git a/push.c b/push.c index e2a91827..1fd8bea3 100644 --- a/push.c +++ b/push.c @@ -189,6 +189,8 @@ send_push_reply (struct context *c) const int safe_cap = BCAP (&buf) - extra; bool push_sent = false; + msg( M_INFO, "send_push_reply(): safe_cap=%d", safe_cap ); + buf_printf (&buf, "%s", cmd); if ( c->c2.push_ifconfig_ipv6_defined ) diff --git a/tun.c b/tun.c index 9dcd9e6f..88e1f0fe 100644 --- a/tun.c +++ b/tun.c @@ -433,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); @@ -440,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. */ @@ -1973,6 +1973,15 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) * */ +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) { @@ -2074,12 +2083,46 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) int write_tun (struct tuntap* tt, uint8_t *buf, int len) { + if (tt->type == DEV_TYPE_TUN) + { + u_int32_t type; + struct iovec iv[2]; + struct openvpn_iphdr *iph; + + iph = (struct openvpn_iphdr *) buf; + + if (tt->ipv6 && OPENVPN_IPH_GET_VER(iph->version_len) == 6) + type = htonl (AF_INET6); + else + type = htonl (AF_INET); + + iv[0].iov_base = (char *)&type; + iv[0].iov_len = sizeof (type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return netbsd_modify_read_write_return (writev (tt->fd, iv, 2)); + } + else return write (tt->fd, buf, len); } int read_tun (struct tuntap* tt, uint8_t *buf, int len) { + if (tt->type == DEV_TYPE_TUN) + { + u_int32_t type; + struct iovec iv[2]; + + iv[0].iov_base = (char *)&type; + iv[0].iov_len = sizeof (type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return netbsd_modify_read_write_return (readv (tt->fd, iv, 2)); + } + else return read (tt->fd, buf, len); } #endif /* NETBSD_MULTI_AF */