| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,189 @@ |
| 0 |
+Do 31. Dez 15:32:40 CET 2009 Gert Doering |
|
| 1 |
+ |
|
| 2 |
+ * Basic IPv6 p2mp functionality implemented |
|
| 3 |
+ |
|
| 4 |
+ * new options: |
|
| 5 |
+ - server-ipv6 |
|
| 6 |
+ - ifconfig-ipv6 |
|
| 7 |
+ - ifconfig-ipv6-pool |
|
| 8 |
+ - route-ipv6 |
|
| 9 |
+ - iroute-ipv6 |
|
| 10 |
+ |
|
| 11 |
+ * modules touched: |
|
| 12 |
+ - init.c: init & setup IPv6 route list & add/delete IPv6 routes |
|
| 13 |
+ - tun.c: add "ifconfig" and "route" handling for IPv6 |
|
| 14 |
+ - multi.c: IPv6 ifconfig-pool assignments |
|
| 15 |
+ put to route-hash table |
|
| 16 |
+ push to client |
|
| 17 |
+ - pool.c: extend pools to handle IPv4+IPv6, and also return IPv6 address |
|
| 18 |
+ IPv6 address saved to file if ifconfig-pool-persist is set |
|
| 19 |
+ (but ignored on read due to the way pools work) |
|
| 20 |
+ - mroute.c: handle reading src/dst addresses from IPv6 packets |
|
| 21 |
+ (so multi.c can check against route-hash table) |
|
| 22 |
+ handle printing of IPv6 mroute_addr structure |
|
| 23 |
+ - helper.c: implement "server-ipv6" macro (->ifconfig-ipv6, pool, ...) |
|
| 24 |
+ - options.c: implement all the new options |
|
| 25 |
+ add helper functions for IPv6 address handling |
|
| 26 |
+ - forward.c: tell do_route() about IPv6 routes |
|
| 27 |
+ - route.c: handle IPv6 route lists + route option lists |
|
| 28 |
+ extend add_routes() to do IPv4 + IPv6 route lists |
|
| 29 |
+ extend delete_routes() to do IPv4 + IPv6 route lists |
|
| 30 |
+ implement add_route_ipv6(), delete_route_ipv6() to call |
|
| 31 |
+ system-dependend external program to do the work |
|
| 32 |
+ - push.c: handle pushing of "ifconfig-ipv6" option |
|
| 33 |
+ - socket.c: helper function to check & print IPv6 address strings |
|
| 34 |
+ |
|
| 35 |
+ * known issues: |
|
| 36 |
+ - operating system support on all but Linux (ifconfig, route) |
|
| 37 |
+ - route-ipv6 gateway handling |
|
| 38 |
+ - iroute-ipv6 not implemented |
|
| 39 |
+ - TAP support: ifconfig, routing (route needs gateway!) |
|
| 40 |
+ |
|
| 41 |
+ * release as patch 20091231-1 |
|
| 42 |
+ |
|
| 43 |
+Thu Dec 31 17:02:08 CET 2009 |
|
| 44 |
+ |
|
| 45 |
+ * NetBSD port (NetBSD 3.1 on Sparc64) |
|
| 46 |
+ |
|
| 47 |
+ * mroute.c, socket.c: make byte/word access to in6_addr more portable |
|
| 48 |
+ |
|
| 49 |
+ * tun.c: fix IPv6 ifconfig arguments on NetBSD |
|
| 50 |
+ |
|
| 51 |
+ still doesn't work on NetBSD 3.1, "ifconfig tun0 inet6..." errors with |
|
| 52 |
+ |
|
| 53 |
+ ifconfig: SIOCAIFADDR: Address family not supported by protocol family |
|
| 54 |
+ |
|
| 55 |
+ (sys/net/if_tun.c, needs to be revision 1.80 or later, NetBSD PR 32944, |
|
| 56 |
+ included in NetBSD 4.0 and up) |
|
| 57 |
+ |
|
| 58 |
+ |
|
| 59 |
+Fri Jan 1 14:07:15 CET 2010 |
|
| 60 |
+ |
|
| 61 |
+ * FreeBSD port (FreeBSD 6.3-p12 on i386) |
|
| 62 |
+ |
|
| 63 |
+ * tun.c: implement IPv6 ifconfig setting for FreeBSD |
|
| 64 |
+ |
|
| 65 |
+ * route.c: fix %s/%s argument to IPv6 route add/delete command for *BSD |
|
| 66 |
+ |
|
| 67 |
+ * TEST SUCCESS: FreeBSD 6.3-p12, server-ipv6, route-ipv6, ccd/iroute-ipv6 |
|
| 68 |
+ |
|
| 69 |
+ * multi.c: implement setting and deleting of iroute-ipv6 |
|
| 70 |
+ (multi_add_iroutes(), multi_del_iroutes()) |
|
| 71 |
+ * mroute.c: add mroute_helper_add_iroute6(), mroute_helper_del_iroute6() |
|
| 72 |
+ * mroute.h: add prototypes, increase MR_HELPER_NET_LEN to 129 (/0.../128) |
|
| 73 |
+ * multi.c: zeroize host part of IPv6 iroutes in multi_learn_in6_addr() |
|
| 74 |
+ * mroute.c: implement mroute_addr_mask_host_bits() for IPv6 |
|
| 75 |
+ |
|
| 76 |
+ * TEST SUCCESS: Linux 2.6.30 (Gentoo)/iproute2, server-ipv6, ccd/iroute-ipv6 |
|
| 77 |
+ |
|
| 78 |
+ * TEST SUCCESS: Linux 2.6.30 (Gentoo)/ifconfig, client-ipv6 |
|
| 79 |
+ |
|
| 80 |
+ * TEST FAIL: NetBSD 5.0, IPv6 client |
|
| 81 |
+ - "ifconfig tun0 .../64" does not create a "connected" route |
|
| 82 |
+ - adding routes fails |
|
| 83 |
+ |
|
| 84 |
+ --> more work to do here. |
|
| 85 |
+ |
|
| 86 |
+ * release as patch 20100101-1 |
|
| 87 |
+ |
|
| 88 |
+ * TEST FAIL: |
|
| 89 |
+ FreeBSD 6.3-p12 server "--topology subnet" |
|
| 90 |
+ Linux/ifconfig client |
|
| 91 |
+ - BSD sends ICMP6 neighbor solicitations, which are ignored by Linux |
|
| 92 |
+ - server tun interface is not in p2p mode, client tun interface *is* |
|
| 93 |
+ |
|
| 94 |
+ * TEST SUCCESS: non-ipv6 enabled client -> "--server-ipv6" server |
|
| 95 |
+ (warnings in the log file, but no malfunctions) |
|
| 96 |
+ |
|
| 97 |
+ |
|
| 98 |
+Sat Jan 2 19:48:35 CET 2010 |
|
| 99 |
+ |
|
| 100 |
+ * tun.c: change "ipv6_support()", do not turn off tt->ipv6 unconditionally |
|
| 101 |
+ if we don't know about OS IPv6 support - just log warning |
|
| 102 |
+ |
|
| 103 |
+ * tun.c: implement "ifconfig inet6" setting for MacOS X / Darwin |
|
| 104 |
+ |
|
| 105 |
+ * route.c: split *BSD system dependent part of add/delete_route_ipv6() |
|
| 106 |
+ into FreeBSD/Dragonfly and NetBSD/Darwin/OpenBSD variants |
|
| 107 |
+ ("2001:db8::/64" vs. "2001:db8:: --prefixlen 64").
|
|
| 108 |
+ |
|
| 109 |
+ * tun.c: on MacOS X, NetBSD and OpenBSD, explicitely set on-link route |
|
| 110 |
+ |
|
| 111 |
+ * TEST SUCCESS: MacOS X, client-ipv6 with route-ipv6 |
|
| 112 |
+ |
|
| 113 |
+ |
|
| 114 |
+Sun Jan 3 10:55:31 CET 2010 |
|
| 115 |
+ |
|
| 116 |
+ * route.c: NetBSD fails with "-iface tun0", needs gateway address |
|
| 117 |
+ (assume that the same syntax is needed for OpenBSD) |
|
| 118 |
+ |
|
| 119 |
+ * route.h: introduce "remote_endpoint_ipv6" into "struct route_ipv6_list" |
|
| 120 |
+ |
|
| 121 |
+ * init.c: pass "ifconfig_ipv6_remote" as gateway to init_route_ipv6_list() |
|
| 122 |
+ |
|
| 123 |
+ * route.c: |
|
| 124 |
+ - init_route_ipv6(): use "remote_endpoint_ipv6" as IPv6 gateway address |
|
| 125 |
+ if no gateway was specified explicitely |
|
| 126 |
+ |
|
| 127 |
+ - init_route_ipv6_list(): fill in "remote_endpoint_ipv6", if parseable |
|
| 128 |
+ |
|
| 129 |
+ - get rid of "GATEWAY-LESS ROUTE6" warning |
|
| 130 |
+ |
|
| 131 |
+ * route.c, add_route_ipv6() |
|
| 132 |
+ - explicitely clear host bits of base address, to be able to more |
|
| 133 |
+ easily set up "connected" /64 routes on NetBSD+Darwin |
|
| 134 |
+ |
|
| 135 |
+ - split system-dependent part between Darwin and NetBSD/OpenBSD |
|
| 136 |
+ (Darwin can use "-iface tun0", NetBSD/OpenBSD get gateway address) |
|
| 137 |
+ |
|
| 138 |
+ - change Solaris comments from "known-broken" to "unknown" |
|
| 139 |
+ |
|
| 140 |
+ * tun.c: rework NetBSD tunnel initialization and tun_read() / tun_write() |
|
| 141 |
+ to work the same way OpenBSD and NetBSD do - tunnel is put into |
|
| 142 |
+ "multi-af" mode, and all packet read/write activity is prepended by |
|
| 143 |
+ a 32 bit value specifying the address family. |
|
| 144 |
+ |
|
| 145 |
+ * TEST SUCCESS: NetBSD 5.0/Sparc64: client-ipv6 with route-ipv6 |
|
| 146 |
+ |
|
| 147 |
+ * TEST SUCCESS: MacOS X 10.5: client-ipv6 with route-ipv6 |
|
| 148 |
+ |
|
| 149 |
+ * (RE-)TEST SUCCESS: Linux/iproute2: server-ipv6 |
|
| 150 |
+ Linux/ifconfig: client-ipv6 |
|
| 151 |
+ FreeBSD 6.3: server-ipv6 |
|
| 152 |
+ |
|
| 153 |
+ * release as patch 20100103-1 |
|
| 154 |
+ |
|
| 155 |
+ * options.c: document all new options in "--help" |
|
| 156 |
+ |
|
| 157 |
+ * tun.c: fix typo in Solaris-specific section |
|
| 158 |
+ |
|
| 159 |
+ * socket.h, socket.c: change u_int32_t to uint32_t |
|
| 160 |
+ (Solaris - and all the rest of the code uses "uintNN" anyway) |
|
| 161 |
+ |
|
| 162 |
+Mon Jan 4 17:46:58 CET 2010 |
|
| 163 |
+ |
|
| 164 |
+ * socket.c: rework add_in6_addr() to use 32-bit access to struct in6_addr |
|
| 165 |
+ (Solaris has no 16-bit values in union, but this is more elegant as well) |
|
| 166 |
+ |
|
| 167 |
+ * tun.c: fix "ifconfig inet6" command for Solaris |
|
| 168 |
+ |
|
| 169 |
+ * tun.c: make sure "tun0 inet6" is unplumbed first, cleanup leftovers |
|
| 170 |
+ |
|
| 171 |
+ * route.c: add routes with "metric 0" on solaris, otherwise they just |
|
| 172 |
+ don't work (someone who understands Solaris might want to fix this). |
|
| 173 |
+ |
|
| 174 |
+ * Solaris "sort of" works now - ifconfig works, route add does not give |
|
| 175 |
+ errors, "netstat -rn" looks right, but packets are discarded unless |
|
| 176 |
+ the routes are installed with "metric 0". So we just use "metric 0"... |
|
| 177 |
+ |
|
| 178 |
+ * CAVEAT: Solaris "ifconfig ... preferred" interferes with source address |
|
| 179 |
+ selection. So if there are any active IPv6 interfaces configured with |
|
| 180 |
+ "preferred", packets leaving out the tunnel will use the wrong source |
|
| 181 |
+ IPv6 address. Not fixable from within OpenVPN. |
|
| 182 |
+ |
|
| 183 |
+ * CAVEAT2: Solaris insists on doing DHCPv6 on tun0 interfaces by default, |
|
| 184 |
+ so DHCPv6 solicitation packets will be seen. Since the server end has |
|
| 185 |
+ no idea what to do with them, they are a harmless nuisance. Fixable |
|
| 186 |
+ on the Solaris side via "ndpd.conf" (see ``man ifconfig''). |
|
| 187 |
+ |
|
| 188 |
+ * release as patch 20100104-1 |
| 0 | 189 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,180 @@ |
| 0 |
+TODO: |
|
| 1 |
+ |
|
| 2 |
+ * tun.c -> init_tun() |
|
| 3 |
+ [ifconfig-Parameter vorbereiten] |
|
| 4 |
+ |
|
| 5 |
+ init.c -> do_open_tun() -> init.c::do_init_tun() -> tun.c::init_tun() |
|
| 6 |
+ -> do_ifconfig() |
|
| 7 |
+ |
|
| 8 |
+ o tun.c -> do_ifconfig() |
|
| 9 |
+ [ifconfig/ip aufrufen] |
|
| 10 |
+ |
|
| 11 |
+ * Linux / ifconfig |
|
| 12 |
+ / Linux / iproute2 ** TESTEN ** |
|
| 13 |
+ o FreeBSD |
|
| 14 |
+ / NetBSD ("needs patch", googlen) ** TESTEN **
|
|
| 15 |
+ / Solaris ** TESTEN ** |
|
| 16 |
+ o OpenBSD |
|
| 17 |
+ o MacOS X |
|
| 18 |
+ |
|
| 19 |
+ o tun.c (?) -> interface cleanup ("ip addr del dev tun0 ...")
|
|
| 20 |
+ |
|
| 21 |
+ o TAP mode und IPv6? Fehlermeldung? |
|
| 22 |
+ o einfach confen |
|
| 23 |
+ |
|
| 24 |
+ o ifconfig_ipv6_remote -> kann eigentlich ersatzlos wegfallen |
|
| 25 |
+ [tun.c, init.c, options.c, options.h] |
|
| 26 |
+ o [kann nicht, braucht man als default-gateway auf Solaris :( ] |
|
| 27 |
+ |
|
| 28 |
+ * push ifconfig-ipv6 |
|
| 29 |
+ push::send_push_reply() -> c->c2.push_ifconfig_local |
|
| 30 |
+ |
|
| 31 |
+ ** wo wird das gesetzt? ** multi.c (und ggf. options.c / ifconfig-push) |
|
| 32 |
+ |
|
| 33 |
+ o /netbits pushen (push.c) -> options.c "ifconfig-ipv6" muss auch |
|
| 34 |
+ damit zurecht kommen, tut es derzeit aber nicht |
|
| 35 |
+ |
|
| 36 |
+ * ifconfig_pool_write() -> IPv6 "wenn pool IPv6 hat" |
|
| 37 |
+ |
|
| 38 |
+ * multi::multi_init() -> ifconfig_pool_init() |
|
| 39 |
+ |
|
| 40 |
+ |
|
| 41 |
+ * "route-ipv6"-Option und "push route-ipv6" |
|
| 42 |
+ o "gateway" |
|
| 43 |
+ o "metric" |
|
| 44 |
+ o "route-gateway-ipv6"-Option |
|
| 45 |
+ o "ifconfig-ipv6-push"-Option |
|
| 46 |
+ options.c -> options.push_ifconfig_... |
|
| 47 |
+ multi.c |
|
| 48 |
+ mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; |
|
| 49 |
+ |
|
| 50 |
+ |
|
| 51 |
+ o "server-ipv6"-Option |
|
| 52 |
+ |
|
| 53 |
+ o options.c, add_option() -> wird fuer "lokale" und "push"-Options |
|
| 54 |
+ aufgerufen |
|
| 55 |
+ no_more_than_n_args() |
|
| 56 |
+ struct options [options.h] |
|
| 57 |
+ |
|
| 58 |
+ * add_route_to_option_list() |
|
| 59 |
+ [route.c -> add_route_ipv6_to_option_list] |
|
| 60 |
+ [options.h -> options->routes_ipv6] |
|
| 61 |
+ |
|
| 62 |
+ o was passiert danach damit? |
|
| 63 |
+ |
|
| 64 |
+ * socket.c: ip_or_dns_addr_safe() |
|
| 65 |
+ --> ipv6_addr_safe() |
|
| 66 |
+ --> ipv6_addr_safe_hexplusbits() |
|
| 67 |
+ |
|
| 68 |
+ * Makro? helper.c -> helper_client_server() ****** |
|
| 69 |
+ * Fehler, wenn options->mode != MODE_SERVER |
|
| 70 |
+ * "tun-ipv6" auto-enablen |
|
| 71 |
+ |
|
| 72 |
+ * if (options->tun_ipv6) |
|
| 73 |
+ msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server"); |
|
| 74 |
+ [options.c, 1710] |
|
| 75 |
+ [raus] |
|
| 76 |
+ |
|
| 77 |
+ o struct tuntap->ipv6 = true, wenn "ipv6" und "system kann das" |
|
| 78 |
+ o Fehler, wenn System kein IPv6 kann |
|
| 79 |
+ ("NetBSD needs patch" -> googlen)
|
|
| 80 |
+ |
|
| 81 |
+ o Adress-Allokation an Clients (/128 aus ifconfig-ipv6-pool /64 erstmal nur) |
|
| 82 |
+ o hash aus Client-Key als host part? |
|
| 83 |
+ (nein, wir nehmen einfach "den gleichen Offset wie bei IPv4" und |
|
| 84 |
+ add_in6_addr()) |
|
| 85 |
+ |
|
| 86 |
+ o "iroute-ipv6"-Option |
|
| 87 |
+ o "ifconfig-ipv6" |
|
| 88 |
+ o "ifconfig-ipv6-pool" |
|
| 89 |
+ o "ifconfig-pool-persist-ipv6"-Option |
|
| 90 |
+ |
|
| 91 |
+ o was tut #define LINUX_IPV6? |
|
| 92 |
+ o was tut bestehender Code mit "ipv6"? |
|
| 93 |
+ |
|
| 94 |
+ |
|
| 95 |
+ o Routing-/Forwarding-Funktion |
|
| 96 |
+ read_tun() --> ?? |
|
| 97 |
+ ?? --> write_tun() |
|
| 98 |
+ |
|
| 99 | ||
| 100 |
+ server-seite anzupassen] |
|
| 101 |
+ |
|
| 102 |
+ o ICMP |
|
| 103 |
+ |
|
| 104 |
+ o Optionen dokumentieren (-> berniv6) |
|
| 105 |
+ o server-ipv6 |
|
| 106 |
+ o ifconfig-ipv6 |
|
| 107 |
+ o ifconfig-ipv6-pool |
|
| 108 |
+ o ifconfig-pool-persist (v4+v6, Formataenderung im File) |
|
| 109 |
+ o iroute-ipv6 |
|
| 110 |
+ o route-ipv6 |
|
| 111 |
+ o tun-ipv6 |
|
| 112 |
+ |
|
| 113 |
+ * http://www.greenie.net/ipv6/openvpn.html - DONE |
|
| 114 |
+ o man pages, --help |
|
| 115 |
+ |
|
| 116 |
+ * options.c |
|
| 117 |
+ - get_ip_addr() --> socket.c getaddr() |
|
| 118 |
+ - openvpn_inet_aton -> OIA_IP "ist IP" |
|
| 119 |
+ |
|
| 120 |
+ * options.c, show_p2mp_parms() |
|
| 121 |
+ |
|
| 122 |
+ * socket.c, print_in_addr_t() --> print_in6_addr() |
|
| 123 |
+ |
|
| 124 |
+ o forward_compatible? |
|
| 125 |
+ |
|
| 126 |
+ o ifconfig_ipv6_pool_persist --> einfach ifconfig_pool_persist mitbenutzen? |
|
| 127 |
+ Entscheidung: JA |
|
| 128 |
+ o to be implemented: pool.c |
|
| 129 |
+ |
|
| 130 |
+ o route.c: |
|
| 131 |
+ clone_route_option_list(), copy_route_option_list(), |
|
| 132 |
+ new_route_list(), add_route(), init_route_list(), ... |
|
| 133 |
+ add_routes(), delete_routes(), setenv_routes(), |
|
| 134 |
+ |
|
| 135 |
+ -> wo werden die aufgerufen, wofuer verwendet, IPv6-Anpassung? |
|
| 136 |
+ |
|
| 137 |
+ * add_route() ruft "/sbin/route add..." auf |
|
| 138 |
+ o div. (redirect gateway related) -> route.c::add_route3() -> add_route() |
|
| 139 |
+ o init.c::do_route() -> route.c::add_routes() -> add_route() |
|
| 140 |
+ o init.c::do_open_tun() -> do_route() |
|
| 141 |
+ o forward.c::check_add_routes_action() -> do_route() |
|
| 142 |
+ o init.c::do_open_tun() -> init.c::do_init_route_list() -> |
|
| 143 |
+ route.c::init_route_list() |
|
| 144 |
+ * init.c::do_open_tun() -> do_alloc_route_list() -> new_route_ipv6_list() |
|
| 145 |
+ |
|
| 146 |
+ o add_route_ipv6() - implementieren und testen |
|
| 147 |
+ * Linux / ifconfig |
|
| 148 |
+ * Linux / iproute2 |
|
| 149 |
+ i FreeBSD |
|
| 150 |
+ i NetBSD ("needs patch", googlen)
|
|
| 151 |
+ i Solaris *braucht Gateway* |
|
| 152 |
+ i OpenBSD |
|
| 153 |
+ i MacOS X |
|
| 154 |
+ |
|
| 155 |
+ o delete_route_ipv6() - implementieren und testen |
|
| 156 |
+ * Linux / ifconfig |
|
| 157 |
+ * Linux / iproute2 |
|
| 158 |
+ i FreeBSD |
|
| 159 |
+ i NetBSD ("needs patch", googlen)
|
|
| 160 |
+ i Solaris |
|
| 161 |
+ i OpenBSD |
|
| 162 |
+ i MacOS X |
|
| 163 |
+ |
|
| 164 | ||
| 165 |
+ aus ifconfig-ipv6 $remote") |
|
| 166 |
+ |
|
| 167 |
+ o IPv6 TCPMSS oder "fragmentation required"? |
|
| 168 |
+ o IPv6 MTU auf Interface setzen? |
|
| 169 |
+ o sysdep! |
|
| 170 |
+ |
|
| 171 |
+ |
|
| 172 |
+TESTEN |
|
| 173 |
+ * ipv6_addr_safe() [--ifconfig-ipv6 null/zu lang/invalid] |
|
| 174 |
+ o ipv6_addr_safe_hexplusbits() [--route-ipv6 ...] |
|
| 175 |
+ * get_ipv6_addr() [--server-ipv6 ...] |
|
| 176 |
+ |
|
| 177 |
+ o unmodifizierter 2.1-client -> 2.1+ipv6-Server? |
|
| 178 |
+ o unmodifizierter 2.0-client -> 2.1+ipv6-Server? |
|
| 179 |
+ o wie kann der Server das erkennen, und "kein v6" schicken? |
| 0 | 8 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,37 @@ |
| 0 |
+known issues for IPv6 payload support in OpenVPN |
|
| 1 |
+----------------------------------------------- |
|
| 2 |
+ |
|
| 3 |
+1.) "--topology subnet" doesn't work together with IPv6 payload |
|
| 4 |
+ (verified for FreeBSD server, Linux/ifconfig client, problems |
|
| 5 |
+ with ICMP6 neighbor solicitations from BSD not being answered by Linux) |
|
| 6 |
+ |
|
| 7 |
+2.) NetBSD IPv6 support doesn't work |
|
| 8 |
+ ("connected" route is not auto-created, "route-ipv6" adding fails)
|
|
| 9 |
+ |
|
| 10 |
+ * fixed, 3.1.10 * |
|
| 11 |
+ |
|
| 12 |
+3.) route deletion for IPv6 routes is not yet done |
|
| 13 |
+ |
|
| 14 |
+ * fixed for configured routes, 3.1.10 * |
|
| 15 |
+ * missing for manual-ifconfig-connected (NetBSD, Darwin) |
|
| 16 |
+ |
|
| 17 |
+4.) do "ifconfig tun0 inet6 unplumb" or "ifconfig tun0 destroy" for |
|
| 18 |
+ Solaris, *BSD, ... at program termination time, to clean up leftovers |
|
| 19 |
+ (unless tunnel persistance is desired). |
|
| 20 |
+ |
|
| 21 |
+ For Solaris, only the "ipv6 tun0" is affected, for the *BSDs all tun0 |
|
| 22 |
+ stay around. |
|
| 23 |
+ |
|
| 24 |
+5.) add new option "ifconfig-ipv6-push" |
|
| 25 |
+ (per-client static IPv6 assignment, -> radiusplugin, etc) |
|
| 26 |
+ |
|
| 27 |
+6.) add new option "route-ipv6-gateway" |
|
| 28 |
+ |
|
| 29 |
+7.) add "full" gateway handling for IPv6 in route.c |
|
| 30 |
+ (right now, the routes are just sent down the tun interface, if the |
|
| 31 |
+ operating system in questions supports that, without care for the |
|
| 32 |
+ gateway address - which does not work for gateways that are supposed |
|
| 33 |
+ to point elsewhere. Also, it doesn't work for TAP interfaces. |
|
| 34 |
+ |
|
| 35 |
+8.) full IPv6 support for TAP interfaces |
|
| 36 |
+ (main issue should be routes+gateway - and testing :-) ) |
| ... | ... |
@@ -259,7 +259,8 @@ send_control_channel_string (struct context *c, const char *str, int msglevel) |
| 259 | 259 |
static void |
| 260 | 260 |
check_add_routes_action (struct context *c, const bool errors) |
| 261 | 261 |
{
|
| 262 |
- do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es); |
|
| 262 |
+ do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, |
|
| 263 |
+ c->c1.tuntap, c->plugins, c->c2.es); |
|
| 263 | 264 |
update_time (); |
| 264 | 265 |
event_timeout_clear (&c->c2.route_wakeup); |
| 265 | 266 |
event_timeout_clear (&c->c2.route_wakeup_expire); |
| ... | ... |
@@ -142,6 +142,55 @@ helper_client_server (struct options *o) |
| 142 | 142 |
|
| 143 | 143 |
#if P2MP |
| 144 | 144 |
#if P2MP_SERVER |
| 145 |
+ |
|
| 146 |
+ /* |
|
| 147 |
+ * |
|
| 148 |
+ * HELPER DIRECTIVE for IPv6 |
|
| 149 |
+ * |
|
| 150 |
+ * server-ipv6 2001:db8::/64 |
|
| 151 |
+ * |
|
| 152 |
+ * EXPANDS TO: |
|
| 153 |
+ * |
|
| 154 |
+ * tun-ipv6 |
|
| 155 |
+ * push "tun-ipv6" |
|
| 156 |
+ * ifconfig-ipv6 2001:db8::1 2001:db8::2 |
|
| 157 |
+ * if !nopool: |
|
| 158 |
+ * ifconfig-ipv6-pool 2001:db8::1:0/64 |
|
| 159 |
+ * |
|
| 160 |
+ */ |
|
| 161 |
+ if ( o->server_ipv6_defined ) |
|
| 162 |
+ {
|
|
| 163 |
+ if ( ! o->server_defined ) |
|
| 164 |
+ {
|
|
| 165 |
+ msg (M_USAGE, "--server-ipv6 must be used together with --server"); |
|
| 166 |
+ } |
|
| 167 |
+ if ( o->server_flags & SF_NOPOOL ) |
|
| 168 |
+ {
|
|
| 169 |
+ msg( M_USAGE, "--server-ipv6 is incompatible with 'nopool' option" ); |
|
| 170 |
+ } |
|
| 171 |
+ if ( o->ifconfig_ipv6_pool_defined ) |
|
| 172 |
+ {
|
|
| 173 |
+ msg( M_USAGE, "--server-ipv6 already defines an ifconfig-ipv6-pool, so you can't also specify --ifconfig-pool explicitly"); |
|
| 174 |
+ } |
|
| 175 |
+ |
|
| 176 |
+ /* local ifconfig is "base address + 1" and "+2" */ |
|
| 177 |
+ o->ifconfig_ipv6_local = |
|
| 178 |
+ print_in6_addr( add_in6_addr( o->server_network_ipv6, 1), 0, &o->gc ); |
|
| 179 |
+ o->ifconfig_ipv6_remote = |
|
| 180 |
+ print_in6_addr( add_in6_addr( o->server_network_ipv6, 2), 0, &o->gc ); |
|
| 181 |
+ |
|
| 182 |
+ /* pool starts at "base address + 0x10000" */ |
|
| 183 |
+ ASSERT( o->server_netbits_ipv6 < 96 ); /* want 32 bits */ |
|
| 184 |
+ o->ifconfig_ipv6_pool_defined = true; |
|
| 185 |
+ o->ifconfig_ipv6_pool_base = |
|
| 186 |
+ add_in6_addr( o->server_network_ipv6, 0x10000 ); |
|
| 187 |
+ o->ifconfig_ipv6_pool_netbits = o->server_netbits_ipv6; |
|
| 188 |
+ |
|
| 189 |
+ o->tun_ipv6 = true; |
|
| 190 |
+ |
|
| 191 |
+ push_option( o, "tun-ipv6", M_USAGE ); |
|
| 192 |
+ } |
|
| 193 |
+ |
|
| 145 | 194 |
/* |
| 146 | 195 |
* |
| 147 | 196 |
* HELPER DIRECTIVE: |
| ... | ... |
@@ -1066,6 +1066,8 @@ do_alloc_route_list (struct context *c) |
| 1066 | 1066 |
{
|
| 1067 | 1067 |
if (c->options.routes && !c->c1.route_list) |
| 1068 | 1068 |
c->c1.route_list = new_route_list (c->options.max_routes, &c->gc); |
| 1069 |
+ if (c->options.routes_ipv6 && !c->c1.route_ipv6_list) |
|
| 1070 |
+ c->c1.route_ipv6_list = new_route_ipv6_list (c->options.max_routes, &c->gc); |
|
| 1069 | 1071 |
} |
| 1070 | 1072 |
|
| 1071 | 1073 |
|
| ... | ... |
@@ -1108,6 +1110,45 @@ do_init_route_list (const struct options *options, |
| 1108 | 1108 |
} |
| 1109 | 1109 |
} |
| 1110 | 1110 |
|
| 1111 |
+static void |
|
| 1112 |
+do_init_route_ipv6_list (const struct options *options, |
|
| 1113 |
+ struct route_ipv6_list *route_ipv6_list, |
|
| 1114 |
+ bool fatal, |
|
| 1115 |
+ struct env_set *es) |
|
| 1116 |
+{
|
|
| 1117 |
+ const char *gw = NULL; |
|
| 1118 |
+ int dev = dev_type_enum (options->dev, options->dev_type); |
|
| 1119 |
+ int metric = 0; |
|
| 1120 |
+ |
|
| 1121 |
+ if (dev != DEV_TYPE_TUN ) |
|
| 1122 |
+ msg( M_WARN, "IPv6 routes on TAP devices are going to fail on some platforms (need gateway spec)" ); /* TODO-GERT */ |
|
| 1123 |
+ |
|
| 1124 |
+ gw = options->ifconfig_ipv6_remote; /* default GW = remote end */ |
|
| 1125 |
+#if 0 /* not yet done for IPv6 - TODO!*/ |
|
| 1126 |
+ if ( options->route_ipv6_default_gateway ) /* override? */ |
|
| 1127 |
+ gw = options->route_ipv6_default_gateway; |
|
| 1128 |
+#endif |
|
| 1129 |
+ |
|
| 1130 |
+ if (options->route_default_metric) |
|
| 1131 |
+ metric = options->route_default_metric; |
|
| 1132 |
+ |
|
| 1133 |
+ if (!init_route_ipv6_list (route_ipv6_list, |
|
| 1134 |
+ options->routes_ipv6, |
|
| 1135 |
+ gw, |
|
| 1136 |
+ metric, |
|
| 1137 |
+ es)) |
|
| 1138 |
+ {
|
|
| 1139 |
+ if (fatal) |
|
| 1140 |
+ openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */ |
|
| 1141 |
+ } |
|
| 1142 |
+ else |
|
| 1143 |
+ {
|
|
| 1144 |
+ /* copy routes to environment */ |
|
| 1145 |
+ setenv_routes_ipv6 (es, route_ipv6_list); |
|
| 1146 |
+ } |
|
| 1147 |
+} |
|
| 1148 |
+ |
|
| 1149 |
+ |
|
| 1111 | 1150 |
/* |
| 1112 | 1151 |
* Called after all initialization has been completed. |
| 1113 | 1152 |
*/ |
| ... | ... |
@@ -1171,12 +1212,13 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) |
| 1171 | 1171 |
void |
| 1172 | 1172 |
do_route (const struct options *options, |
| 1173 | 1173 |
struct route_list *route_list, |
| 1174 |
+ struct route_ipv6_list *route_ipv6_list, |
|
| 1174 | 1175 |
const struct tuntap *tt, |
| 1175 | 1176 |
const struct plugin_list *plugins, |
| 1176 | 1177 |
struct env_set *es) |
| 1177 | 1178 |
{
|
| 1178 |
- if (!options->route_noexec && route_list) |
|
| 1179 |
- add_routes (route_list, tt, ROUTE_OPTION_FLAGS (options), es); |
|
| 1179 |
+ if (!options->route_noexec && ( route_list || route_ipv6_list ) ) |
|
| 1180 |
+ add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es); |
|
| 1180 | 1181 |
|
| 1181 | 1182 |
if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP)) |
| 1182 | 1183 |
{
|
| ... | ... |
@@ -1233,6 +1275,8 @@ do_init_tun (struct context *c) |
| 1233 | 1233 |
c->options.topology, |
| 1234 | 1234 |
c->options.ifconfig_local, |
| 1235 | 1235 |
c->options.ifconfig_remote_netmask, |
| 1236 |
+ c->options.ifconfig_ipv6_local, |
|
| 1237 |
+ c->options.ifconfig_ipv6_remote, |
|
| 1236 | 1238 |
addr_host (&c->c1.link_socket_addr.local), |
| 1237 | 1239 |
addr_host (&c->c1.link_socket_addr.remote), |
| 1238 | 1240 |
!c->options.ifconfig_nowarn, |
| ... | ... |
@@ -1269,6 +1313,8 @@ do_open_tun (struct context *c) |
| 1269 | 1269 |
/* parse and resolve the route option list */ |
| 1270 | 1270 |
if (c->options.routes && c->c1.route_list && c->c2.link_socket) |
| 1271 | 1271 |
do_init_route_list (&c->options, c->c1.route_list, &c->c2.link_socket->info, false, c->c2.es); |
| 1272 |
+ if (c->options.routes_ipv6 && c->c1.route_ipv6_list ) |
|
| 1273 |
+ do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, false, c->c2.es); |
|
| 1272 | 1274 |
|
| 1273 | 1275 |
/* do ifconfig */ |
| 1274 | 1276 |
if (!c->options.ifconfig_noexec |
| ... | ... |
@@ -1315,7 +1361,8 @@ do_open_tun (struct context *c) |
| 1315 | 1315 |
|
| 1316 | 1316 |
/* possibly add routes */ |
| 1317 | 1317 |
if (!c->options.route_delay_defined) |
| 1318 |
- do_route (&c->options, c->c1.route_list, c->c1.tuntap, c->plugins, c->c2.es); |
|
| 1318 |
+ do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, |
|
| 1319 |
+ c->c1.tuntap, c->plugins, c->c2.es); |
|
| 1319 | 1320 |
|
| 1320 | 1321 |
/* |
| 1321 | 1322 |
* Did tun/tap driver give us an MTU? |
| ... | ... |
@@ -1390,8 +1437,9 @@ do_close_tun (struct context *c, bool force) |
| 1390 | 1390 |
#endif |
| 1391 | 1391 |
|
| 1392 | 1392 |
/* delete any routes we added */ |
| 1393 |
- if (c->c1.route_list) |
|
| 1394 |
- delete_routes (c->c1.route_list, c->c1.tuntap, ROUTE_OPTION_FLAGS (&c->options), c->c2.es); |
|
| 1393 |
+ if (c->c1.route_list || c->c1.route_ipv6_list ) |
|
| 1394 |
+ delete_routes (c->c1.route_list, c->c1.route_ipv6_list, |
|
| 1395 |
+ c->c1.tuntap, ROUTE_OPTION_FLAGS (&c->options), c->c2.es); |
|
| 1395 | 1396 |
|
| 1396 | 1397 |
/* actually close tun/tap device based on --down-pre flag */ |
| 1397 | 1398 |
if (!c->options.down_pre) |
| ... | ... |
@@ -63,6 +63,7 @@ void init_instance (struct context *c, const struct env_set *env, const unsigned |
| 63 | 63 |
|
| 64 | 64 |
void do_route (const struct options *options, |
| 65 | 65 |
struct route_list *route_list, |
| 66 |
+ struct route_ipv6_list *route_ipv6_list, |
|
| 66 | 67 |
const struct tuntap *tt, |
| 67 | 68 |
const struct plugin_list *plugins, |
| 68 | 69 |
struct env_set *es); |
| ... | ... |
@@ -1004,7 +1004,7 @@ setenv_str_ex (struct env_set *es, |
| 1004 | 1004 |
{
|
| 1005 | 1005 |
const char *str = construct_name_value (name_tmp, val_tmp, &gc); |
| 1006 | 1006 |
env_set_add (es, str); |
| 1007 |
- /*msg (M_INFO, "SETENV_ES '%s'", str);*/ |
|
| 1007 |
+ msg (M_INFO, "SETENV_ES '%s'", str);/**/ |
|
| 1008 | 1008 |
} |
| 1009 | 1009 |
else |
| 1010 | 1010 |
env_set_del (es, name_tmp); |
| ... | ... |
@@ -88,12 +88,33 @@ mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int |
| 88 | 88 |
} |
| 89 | 89 |
} |
| 90 | 90 |
|
| 91 |
+static inline void |
|
| 92 |
+mroute_get_in6_addr (struct mroute_addr *ma, const struct in6_addr src, unsigned int mask) |
|
| 93 |
+{
|
|
| 94 |
+ if (ma) |
|
| 95 |
+ {
|
|
| 96 |
+ ma->type = MR_ADDR_IPV6 | mask; |
|
| 97 |
+ ma->netbits = 0; |
|
| 98 |
+ ma->len = 16; |
|
| 99 |
+ *(struct in6_addr *)ma->addr = src; |
|
| 100 |
+ } |
|
| 101 |
+} |
|
| 102 |
+ |
|
| 91 | 103 |
static inline bool |
| 92 | 104 |
mroute_is_mcast (const in_addr_t addr) |
| 93 | 105 |
{
|
| 94 | 106 |
return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK)); |
| 95 | 107 |
} |
| 96 | 108 |
|
| 109 |
+/* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies |
|
| 110 |
+ * the address as being a multicast address" |
|
| 111 |
+ */ |
|
| 112 |
+static inline bool |
|
| 113 |
+mroute_is_mcast_ipv6 (const struct in6_addr addr) |
|
| 114 |
+{
|
|
| 115 |
+ return (addr.s6_addr[0] == 0xff); |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 97 | 118 |
#ifdef ENABLE_PF |
| 98 | 119 |
|
| 99 | 120 |
static unsigned int |
| ... | ... |
@@ -155,10 +176,29 @@ mroute_extract_addr_ipv4 (struct mroute_addr *src, |
| 155 | 155 |
} |
| 156 | 156 |
break; |
| 157 | 157 |
case 6: |
| 158 |
- {
|
|
| 159 |
- msg (M_WARN, "Need IPv6 code in mroute_extract_addr_from_packet"); |
|
| 160 |
- break; |
|
| 161 |
- } |
|
| 158 |
+ if (BLEN (buf) >= (int) sizeof (struct openvpn_ipv6hdr)) |
|
| 159 |
+ {
|
|
| 160 |
+ const struct openvpn_ipv6hdr *ipv6 = (const struct openvpn_ipv6hdr *) BPTR (buf); |
|
| 161 |
+#if 0 /* very basic debug */ |
|
| 162 |
+ struct gc_arena gc = gc_new (); |
|
| 163 |
+ msg( M_INFO, "IPv6 packet! src=%s, dst=%s", |
|
| 164 |
+ print_in6_addr( ipv6->saddr, 0, &gc ), |
|
| 165 |
+ print_in6_addr( ipv6->daddr, 0, &gc )); |
|
| 166 |
+ gc_free (&gc); |
|
| 167 |
+#endif |
|
| 168 |
+ |
|
| 169 |
+ mroute_get_in6_addr (src, ipv6->saddr, 0); |
|
| 170 |
+ mroute_get_in6_addr (dest, ipv6->daddr, 0); |
|
| 171 |
+ |
|
| 172 |
+ if (mroute_is_mcast_ipv6 (ipv6->daddr)) |
|
| 173 |
+ ret |= MROUTE_EXTRACT_MCAST; |
|
| 174 |
+ |
|
| 175 |
+ ret |= MROUTE_EXTRACT_SUCCEEDED; |
|
| 176 |
+ } |
|
| 177 |
+ break; |
|
| 178 |
+ default: |
|
| 179 |
+ msg (M_WARN, "IP packet with unknown IP version=%d seen", |
|
| 180 |
+ OPENVPN_IPH_GET_VER (*BPTR(buf))); |
|
| 162 | 181 |
} |
| 163 | 182 |
} |
| 164 | 183 |
return ret; |
| ... | ... |
@@ -252,14 +292,36 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr, |
| 252 | 252 |
* Zero off the host bits in an address, leaving |
| 253 | 253 |
* only the network bits, using the netbits member of |
| 254 | 254 |
* struct mroute_addr as the controlling parameter. |
| 255 |
+ * |
|
| 256 |
+ * TODO: this is called for route-lookup for every yet-unhashed |
|
| 257 |
+ * destination address, so for lots of active net-iroutes, this |
|
| 258 |
+ * might benefit from some "zeroize 32 bit at a time" improvements |
|
| 255 | 259 |
*/ |
| 256 | 260 |
void |
| 257 | 261 |
mroute_addr_mask_host_bits (struct mroute_addr *ma) |
| 258 | 262 |
{
|
| 259 | 263 |
in_addr_t addr = ntohl(*(in_addr_t*)ma->addr); |
| 260 |
- ASSERT ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4); |
|
| 261 |
- addr &= netbits_to_netmask (ma->netbits); |
|
| 262 |
- *(in_addr_t*)ma->addr = htonl (addr); |
|
| 264 |
+ if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4) |
|
| 265 |
+ {
|
|
| 266 |
+ addr &= netbits_to_netmask (ma->netbits); |
|
| 267 |
+ *(in_addr_t*)ma->addr = htonl (addr); |
|
| 268 |
+ } |
|
| 269 |
+ else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6) |
|
| 270 |
+ {
|
|
| 271 |
+ int byte = ma->len-1; /* rightmost byte in address */ |
|
| 272 |
+ int bits_to_clear = 128 - ma->netbits; |
|
| 273 |
+ |
|
| 274 |
+ while( byte >= 0 && bits_to_clear > 0 ) |
|
| 275 |
+ {
|
|
| 276 |
+ if ( bits_to_clear >= 8 ) |
|
| 277 |
+ { ma->addr[byte--] = 0; bits_to_clear -= 8; }
|
|
| 278 |
+ else |
|
| 279 |
+ { ma->addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; }
|
|
| 280 |
+ } |
|
| 281 |
+ ASSERT( bits_to_clear == 0 ); |
|
| 282 |
+ } |
|
| 283 |
+ else |
|
| 284 |
+ ASSERT(0); |
|
| 263 | 285 |
} |
| 264 | 286 |
|
| 265 | 287 |
/* |
| ... | ... |
@@ -337,17 +399,24 @@ mroute_addr_print_ex (const struct mroute_addr *ma, |
| 337 | 337 |
} |
| 338 | 338 |
break; |
| 339 | 339 |
case MR_ADDR_IPV6: |
| 340 |
- buf_printf (&out, "IPV6"); |
|
| 341 |
- break; |
|
| 342 |
- default: |
|
| 343 |
- buf_printf (&out, "UNKNOWN"); |
|
| 344 |
- break; |
|
| 345 |
- } |
|
| 346 |
- return BSTR (&out); |
|
| 347 |
- } |
|
| 348 |
- else |
|
| 349 |
- return "[NULL]"; |
|
| 350 |
-} |
|
| 340 |
+ {
|
|
| 341 |
+ buf_printf (&out, "%s", |
|
| 342 |
+ print_in6_addr( *(struct in6_addr*)&maddr.addr, 0, gc)); |
|
| 343 |
+ if (maddr.type & MR_WITH_NETBITS) |
|
| 344 |
+ {
|
|
| 345 |
+ buf_printf (&out, "/%d", maddr.netbits); |
|
| 346 |
+ } |
|
| 347 |
+ } |
|
| 348 |
+ break; |
|
| 349 |
+ default: |
|
| 350 |
+ buf_printf (&out, "UNKNOWN"); |
|
| 351 |
+ break; |
|
| 352 |
+ } |
|
| 353 |
+ return BSTR (&out); |
|
| 354 |
+ } |
|
| 355 |
+ else |
|
| 356 |
+ return "[NULL]"; |
|
| 357 |
+ } |
|
| 351 | 358 |
|
| 352 | 359 |
/* |
| 353 | 360 |
* 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) |
| 418 | 418 |
} |
| 419 | 419 |
} |
| 420 | 420 |
|
| 421 |
+/* this is a bit inelegant, we really should have a helper to that |
|
| 422 |
+ * is only passed the netbits value, and not the whole struct iroute * |
|
| 423 |
+ * - thus one helper could do IPv4 and IPv6. For the sake of "not change |
|
| 424 |
+ * code unrelated to IPv4" this is left for later cleanup, for now. |
|
| 425 |
+ */ |
|
| 426 |
+void |
|
| 427 |
+mroute_helper_add_iroute6 (struct mroute_helper *mh, |
|
| 428 |
+ const struct iroute_ipv6 *ir6) |
|
| 429 |
+{
|
|
| 430 |
+ if (ir6->netbits >= 0) |
|
| 431 |
+ {
|
|
| 432 |
+ ASSERT (ir6->netbits < MR_HELPER_NET_LEN); |
|
| 433 |
+ mroute_helper_lock (mh); |
|
| 434 |
+ ++mh->cache_generation; |
|
| 435 |
+ ++mh->net_len_refcount[ir6->netbits]; |
|
| 436 |
+ if (mh->net_len_refcount[ir6->netbits] == 1) |
|
| 437 |
+ mroute_helper_regenerate (mh); |
|
| 438 |
+ mroute_helper_unlock (mh); |
|
| 439 |
+ } |
|
| 440 |
+} |
|
| 441 |
+ |
|
| 442 |
+void |
|
| 443 |
+mroute_helper_del_iroute6 (struct mroute_helper *mh, |
|
| 444 |
+ const struct iroute_ipv6 *ir6) |
|
| 445 |
+{
|
|
| 446 |
+ if (ir6->netbits >= 0) |
|
| 447 |
+ {
|
|
| 448 |
+ ASSERT (ir6->netbits < MR_HELPER_NET_LEN); |
|
| 449 |
+ mroute_helper_lock (mh); |
|
| 450 |
+ ++mh->cache_generation; |
|
| 451 |
+ --mh->net_len_refcount[ir6->netbits]; |
|
| 452 |
+ ASSERT (mh->net_len_refcount[ir6->netbits] >= 0); |
|
| 453 |
+ if (!mh->net_len_refcount[ir6->netbits]) |
|
| 454 |
+ mroute_helper_regenerate (mh); |
|
| 455 |
+ mroute_helper_unlock (mh); |
|
| 456 |
+ } |
|
| 457 |
+} |
|
| 458 |
+ |
|
| 421 | 459 |
void |
| 422 | 460 |
mroute_helper_free (struct mroute_helper *mh) |
| 423 | 461 |
{
|
| ... | ... |
@@ -85,7 +85,7 @@ struct mroute_addr {
|
| 85 | 85 |
/* |
| 86 | 86 |
* Number of bits in an address. Should be raised for IPv6. |
| 87 | 87 |
*/ |
| 88 |
-#define MR_HELPER_NET_LEN 32 |
|
| 88 |
+#define MR_HELPER_NET_LEN 129 |
|
| 89 | 89 |
|
| 90 | 90 |
/* |
| 91 | 91 |
* Used to help maintain CIDR routing table. |
| ... | ... |
@@ -127,6 +127,8 @@ struct mroute_helper *mroute_helper_init (int ageable_ttl_secs); |
| 127 | 127 |
void mroute_helper_free (struct mroute_helper *mh); |
| 128 | 128 |
void mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir); |
| 129 | 129 |
void mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir); |
| 130 |
+void mroute_helper_add_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6); |
|
| 131 |
+void mroute_helper_del_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6); |
|
| 130 | 132 |
|
| 131 | 133 |
/* |
| 132 | 134 |
* Given a raw packet in buf, return the src and dest |
| ... | ... |
@@ -316,25 +316,18 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa |
| 316 | 316 |
*/ |
| 317 | 317 |
if (t->options.ifconfig_pool_defined) |
| 318 | 318 |
{
|
| 319 |
- if (dev == DEV_TYPE_TAP) |
|
| 320 |
- {
|
|
| 321 |
- m->ifconfig_pool = ifconfig_pool_init (IFCONFIG_POOL_INDIV, |
|
| 322 |
- t->options.ifconfig_pool_start, |
|
| 323 |
- t->options.ifconfig_pool_end, |
|
| 324 |
- t->options.duplicate_cn); |
|
| 325 |
- } |
|
| 326 |
- else if (dev == DEV_TYPE_TUN) |
|
| 327 |
- {
|
|
| 328 |
- m->ifconfig_pool = ifconfig_pool_init ( |
|
| 329 |
- (t->options.topology == TOP_NET30) ? IFCONFIG_POOL_30NET : IFCONFIG_POOL_INDIV, |
|
| 330 |
- t->options.ifconfig_pool_start, |
|
| 331 |
- t->options.ifconfig_pool_end, |
|
| 332 |
- t->options.duplicate_cn); |
|
| 333 |
- } |
|
| 334 |
- else |
|
| 335 |
- {
|
|
| 336 |
- ASSERT (0); |
|
| 337 |
- } |
|
| 319 |
+ int pool_type = IFCONFIG_POOL_INDIV; |
|
| 320 |
+ |
|
| 321 |
+ if ( dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30 ) |
|
| 322 |
+ pool_type = IFCONFIG_POOL_30NET; |
|
| 323 |
+ |
|
| 324 |
+ m->ifconfig_pool = ifconfig_pool_init (pool_type, |
|
| 325 |
+ t->options.ifconfig_pool_start, |
|
| 326 |
+ t->options.ifconfig_pool_end, |
|
| 327 |
+ t->options.duplicate_cn, |
|
| 328 |
+ t->options.ifconfig_ipv6_pool_defined, |
|
| 329 |
+ t->options.ifconfig_ipv6_pool_base, |
|
| 330 |
+ t->options.ifconfig_ipv6_pool_netbits ); |
|
| 338 | 331 |
|
| 339 | 332 |
/* reload pool data from file */ |
| 340 | 333 |
if (t->c1.ifconfig_pool_persist) |
| ... | ... |
@@ -429,10 +422,14 @@ multi_del_iroutes (struct multi_context *m, |
| 429 | 429 |
struct multi_instance *mi) |
| 430 | 430 |
{
|
| 431 | 431 |
const struct iroute *ir; |
| 432 |
+ const struct iroute_ipv6 *ir6; |
|
| 432 | 433 |
if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) |
| 433 | 434 |
{
|
| 434 | 435 |
for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) |
| 435 | 436 |
mroute_helper_del_iroute (m->route_helper, ir); |
| 437 |
+ |
|
| 438 |
+ for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next ) |
|
| 439 |
+ mroute_helper_del_iroute6 (m->route_helper, ir6); |
|
| 436 | 440 |
} |
| 437 | 441 |
} |
| 438 | 442 |
|
| ... | ... |
@@ -1078,6 +1075,37 @@ multi_learn_in_addr_t (struct multi_context *m, |
| 1078 | 1078 |
} |
| 1079 | 1079 |
} |
| 1080 | 1080 |
|
| 1081 |
+static struct multi_instance * |
|
| 1082 |
+multi_learn_in6_addr (struct multi_context *m, |
|
| 1083 |
+ struct multi_instance *mi, |
|
| 1084 |
+ struct in6_addr a6, |
|
| 1085 |
+ int netbits, /* -1 if host route, otherwise # of network bits in address */ |
|
| 1086 |
+ bool primary) |
|
| 1087 |
+{
|
|
| 1088 |
+ struct mroute_addr addr; |
|
| 1089 |
+ |
|
| 1090 |
+ addr.len = 16; |
|
| 1091 |
+ addr.type = MR_ADDR_IPV6; |
|
| 1092 |
+ addr.netbits = 0; |
|
| 1093 |
+ memcpy( &addr.addr, &a6, sizeof(a6) ); |
|
| 1094 |
+ |
|
| 1095 |
+ if (netbits >= 0) |
|
| 1096 |
+ {
|
|
| 1097 |
+ addr.type |= MR_WITH_NETBITS; |
|
| 1098 |
+ addr.netbits = (uint8_t) netbits; |
|
| 1099 |
+ mroute_addr_mask_host_bits( &addr ); |
|
| 1100 |
+ } |
|
| 1101 |
+ |
|
| 1102 |
+ {
|
|
| 1103 |
+ struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0); |
|
| 1104 |
+#ifdef MANAGEMENT_DEF_AUTH |
|
| 1105 |
+ if (management && owner) |
|
| 1106 |
+ management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary); |
|
| 1107 |
+#endif |
|
| 1108 |
+ return owner; |
|
| 1109 |
+ } |
|
| 1110 |
+} |
|
| 1111 |
+ |
|
| 1081 | 1112 |
/* |
| 1082 | 1113 |
* A new client has connected, add routes (server -> client) |
| 1083 | 1114 |
* to internal routing table. |
| ... | ... |
@@ -1088,6 +1116,7 @@ multi_add_iroutes (struct multi_context *m, |
| 1088 | 1088 |
{
|
| 1089 | 1089 |
struct gc_arena gc = gc_new (); |
| 1090 | 1090 |
const struct iroute *ir; |
| 1091 |
+ const struct iroute_ipv6 *ir6; |
|
| 1091 | 1092 |
if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) |
| 1092 | 1093 |
{
|
| 1093 | 1094 |
mi->did_iroutes = true; |
| ... | ... |
@@ -1107,6 +1136,22 @@ multi_add_iroutes (struct multi_context *m, |
| 1107 | 1107 |
|
| 1108 | 1108 |
multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false); |
| 1109 | 1109 |
} |
| 1110 |
+ for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next ) |
|
| 1111 |
+ {
|
|
| 1112 |
+ if (ir6->netbits >= 0) |
|
| 1113 |
+ msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", |
|
| 1114 |
+ print_in6_addr (ir6->network, 0, &gc), |
|
| 1115 |
+ ir6->netbits, |
|
| 1116 |
+ multi_instance_string (mi, false, &gc)); |
|
| 1117 |
+ else |
|
| 1118 |
+ msg (D_MULTI_LOW, "MULTI: internal route %s -> %s", |
|
| 1119 |
+ print_in6_addr (ir6->network, 0, &gc), |
|
| 1120 |
+ multi_instance_string (mi, false, &gc)); |
|
| 1121 |
+ |
|
| 1122 |
+ mroute_helper_add_iroute6 (m->route_helper, ir6); |
|
| 1123 |
+ |
|
| 1124 |
+ multi_learn_in6_addr (m, mi, ir6->network, ir6->netbits, false); |
|
| 1125 |
+ } |
|
| 1110 | 1126 |
} |
| 1111 | 1127 |
gc_free (&gc); |
| 1112 | 1128 |
} |
| ... | ... |
@@ -1196,17 +1241,22 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) |
| 1196 | 1196 |
else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */ |
| 1197 | 1197 |
{
|
| 1198 | 1198 |
in_addr_t local=0, remote=0; |
| 1199 |
+ struct in6_addr remote_ipv6; |
|
| 1199 | 1200 |
const char *cn = NULL; |
| 1200 | 1201 |
|
| 1201 | 1202 |
if (!mi->context.options.duplicate_cn) |
| 1202 | 1203 |
cn = tls_common_name (mi->context.c2.tls_multi, true); |
| 1203 | 1204 |
|
| 1204 |
- mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, cn); |
|
| 1205 |
+ mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, &remote_ipv6, cn); |
|
| 1205 | 1206 |
if (mi->vaddr_handle >= 0) |
| 1206 | 1207 |
{
|
| 1207 | 1208 |
const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap); |
| 1208 | 1209 |
const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap); |
| 1209 | 1210 |
|
| 1211 |
+ msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s", |
|
| 1212 |
+ print_in_addr_t( remote, 0, &gc ), |
|
| 1213 |
+ print_in6_addr( remote_ipv6, 0, &gc ) ); |
|
| 1214 |
+ |
|
| 1210 | 1215 |
/* set push_ifconfig_remote_netmask from pool ifconfig address(es) */ |
| 1211 | 1216 |
mi->context.c2.push_ifconfig_local = remote; |
| 1212 | 1217 |
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) |
| 1228 | 1228 |
else |
| 1229 | 1229 |
msg (D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s", |
| 1230 | 1230 |
multi_instance_string (mi, false, &gc)); |
| 1231 |
+ |
|
| 1232 |
+ if ( mi->context.options.ifconfig_ipv6_pool_defined ) |
|
| 1233 |
+ {
|
|
| 1234 |
+ mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6; |
|
| 1235 |
+ mi->context.c2.push_ifconfig_ipv6_remote = |
|
| 1236 |
+ mi->context.c1.tuntap->local_ipv6; |
|
| 1237 |
+ mi->context.c2.push_ifconfig_ipv6_netbits = |
|
| 1238 |
+ mi->context.options.ifconfig_ipv6_pool_netbits; |
|
| 1239 |
+ mi->context.c2.push_ifconfig_ipv6_defined = true; |
|
| 1240 |
+ } |
|
| 1231 | 1241 |
} |
| 1232 | 1242 |
else |
| 1233 | 1243 |
{
|
| ... | ... |
@@ -1272,6 +1332,11 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi) |
| 1272 | 1272 |
SA_SET_IF_NONZERO); |
| 1273 | 1273 |
} |
| 1274 | 1274 |
} |
| 1275 |
+ |
|
| 1276 |
+ /* TODO: I'm not exactly sure what these environment variables are |
|
| 1277 |
+ * used for, but if we have them for IPv4, we should also have |
|
| 1278 |
+ * them for IPv6, no? |
|
| 1279 |
+ */ |
|
| 1275 | 1280 |
} |
| 1276 | 1281 |
|
| 1277 | 1282 |
/* |
| ... | ... |
@@ -1661,6 +1726,15 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi |
| 1661 | 1661 |
print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc)); |
| 1662 | 1662 |
} |
| 1663 | 1663 |
|
| 1664 |
+ if (mi->context.c2.push_ifconfig_ipv6_defined) |
|
| 1665 |
+ {
|
|
| 1666 |
+ multi_learn_in6_addr (m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true); |
|
| 1667 |
+ /* TODO: find out where addresses are "unlearned"!! */ |
|
| 1668 |
+ msg (D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", |
|
| 1669 |
+ multi_instance_string (mi, false, &gc), |
|
| 1670 |
+ print_in6_addr (mi->context.c2.push_ifconfig_ipv6_local, 0, &gc)); |
|
| 1671 |
+ } |
|
| 1672 |
+ |
|
| 1664 | 1673 |
/* add routes locally, pointing to new client, if |
| 1665 | 1674 |
--iroute options have been specified */ |
| 1666 | 1675 |
multi_add_iroutes (m, mi); |
| ... | ... |
@@ -165,6 +165,9 @@ struct context_1 |
| 165 | 165 |
/* list of --route directives */ |
| 166 | 166 |
struct route_list *route_list; |
| 167 | 167 |
|
| 168 |
+ /* list of --route-ipv6 directives */ |
|
| 169 |
+ struct route_ipv6_list *route_ipv6_list; |
|
| 170 |
+ |
|
| 168 | 171 |
/* --status file */ |
| 169 | 172 |
struct status_output *status_output; |
| 170 | 173 |
bool status_output_owned; |
| ... | ... |
@@ -417,6 +420,11 @@ struct context_2 |
| 417 | 417 |
in_addr_t push_ifconfig_local; |
| 418 | 418 |
in_addr_t push_ifconfig_remote_netmask; |
| 419 | 419 |
|
| 420 |
+ bool push_ifconfig_ipv6_defined; |
|
| 421 |
+ struct in6_addr push_ifconfig_ipv6_local; |
|
| 422 |
+ int push_ifconfig_ipv6_netbits; |
|
| 423 |
+ struct in6_addr push_ifconfig_ipv6_remote; |
|
| 424 |
+ |
|
| 420 | 425 |
/* client authentication state, CAS_SUCCEEDED must be 0 */ |
| 421 | 426 |
# define CAS_SUCCEEDED 0 |
| 422 | 427 |
# define CAS_PENDING 1 |
| ... | ... |
@@ -172,6 +172,8 @@ static const char usage_message[] = |
| 172 | 172 |
" addresses outside of the subnets used by either peer.\n" |
| 173 | 173 |
" TAP: configure device to use IP address l as a local\n" |
| 174 | 174 |
" endpoint and rn as a subnet mask.\n" |
| 175 |
+ "--ifconfig-ipv6 l r : configure device to use IPv6 address l as local\n" |
|
| 176 |
+ " endpoint (as a /64) and r as remote endpoint\n" |
|
| 175 | 177 |
"--ifconfig-noexec : Don't actually execute ifconfig/netsh command, instead\n" |
| 176 | 178 |
" pass --ifconfig parms by environment to scripts.\n" |
| 177 | 179 |
"--ifconfig-nowarn : Don't warn if the --ifconfig option on this side of the\n" |
| ... | ... |
@@ -182,6 +184,10 @@ static const char usage_message[] = |
| 182 | 182 |
" netmask default: 255.255.255.255\n" |
| 183 | 183 |
" gateway default: taken from --route-gateway or --ifconfig\n" |
| 184 | 184 |
" Specify default by leaving blank or setting to \"nil\".\n" |
| 185 |
+ "--route-ipv6 network/bits [gateway] [metric] :\n" |
|
| 186 |
+ " Add IPv6 route to routing table after connection\n" |
|
| 187 |
+ " is established. Multiple routes can be specified.\n" |
|
| 188 |
+ " gateway default: taken from --route-ipv6-gateway or --ifconfig\n" |
|
| 185 | 189 |
"--max-routes n : Specify the maximum number of routes that may be defined\n" |
| 186 | 190 |
" or pulled from a server.\n" |
| 187 | 191 |
"--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n" |
| ... | ... |
@@ -370,6 +376,7 @@ static const char usage_message[] = |
| 370 | 370 |
"\n" |
| 371 | 371 |
"Multi-Client Server options (when --mode server is used):\n" |
| 372 | 372 |
"--server network netmask : Helper option to easily configure server mode.\n" |
| 373 |
+ "--server-ipv6 network/bits : Configure IPv6 server mode.\n" |
|
| 373 | 374 |
"--server-bridge [IP netmask pool-start-IP pool-end-IP] : Helper option to\n" |
| 374 | 375 |
" easily configure ethernet bridging server mode.\n" |
| 375 | 376 |
"--push \"option\" : Push a config file option back to the peer for remote\n" |
| ... | ... |
@@ -383,10 +390,13 @@ static const char usage_message[] = |
| 383 | 383 |
"--ifconfig-pool-persist file [seconds] : Persist/unpersist ifconfig-pool\n" |
| 384 | 384 |
" data to file, at seconds intervals (default=600).\n" |
| 385 | 385 |
" If seconds=0, file will be treated as read-only.\n" |
| 386 |
+ "--ifconfig-ipv6-pool base-IP/bits : set aside an IPv6 network block\n" |
|
| 387 |
+ " to be dynamically allocated to connecting clients.\n" |
|
| 386 | 388 |
"--ifconfig-push local remote-netmask : Push an ifconfig option to remote,\n" |
| 387 | 389 |
" overrides --ifconfig-pool dynamic allocation.\n" |
| 388 | 390 |
" Only valid in a client-specific config file.\n" |
| 389 | 391 |
"--iroute network [netmask] : Route subnet to client.\n" |
| 392 |
+ "--iroute-ipv6 network/bits : Route IPv6 subnet to client.\n" |
|
| 390 | 393 |
" Sets up internal routes only.\n" |
| 391 | 394 |
" Only valid in a client-specific config file.\n" |
| 392 | 395 |
"--disable : Client is disabled.\n" |
| ... | ... |
@@ -871,6 +881,58 @@ get_ip_addr (const char *ip_string, int msglevel, bool *error) |
| 871 | 871 |
return ret; |
| 872 | 872 |
} |
| 873 | 873 |
|
| 874 |
+/* parse a text string containing an IPv6 address + netbits |
|
| 875 |
+ * in "standard format" (2001:dba::/32) |
|
| 876 |
+ * return true if parsing succeeded, modify *network and *netbits |
|
| 877 |
+ */ |
|
| 878 |
+bool |
|
| 879 |
+get_ipv6_addr( const char * prefix_str, struct in6_addr *network, |
|
| 880 |
+ unsigned int * netbits, int msglevel ) |
|
| 881 |
+{
|
|
| 882 |
+ int rc; |
|
| 883 |
+ char * sep, * endp; |
|
| 884 |
+ int bits; |
|
| 885 |
+ |
|
| 886 |
+ sep = strchr( prefix_str, '/' ); |
|
| 887 |
+ if ( sep == NULL ) |
|
| 888 |
+ {
|
|
| 889 |
+ msg (msglevel, "IPv6 prefix '%s': missing '/'", prefix_str); |
|
| 890 |
+ return false; |
|
| 891 |
+ } |
|
| 892 |
+ |
|
| 893 |
+ bits = strtol( sep+1, &endp, 10 ); |
|
| 894 |
+ if ( *endp != '\0' || bits < 0 || bits > 128 ) |
|
| 895 |
+ {
|
|
| 896 |
+ msg (msglevel, "IPv6 prefix '%s': invalid '/bits' spec", prefix_str); |
|
| 897 |
+ return false; |
|
| 898 |
+ } |
|
| 899 |
+ |
|
| 900 |
+ /* temporary replace '/' in caller-provided string with '\0', otherwise |
|
| 901 |
+ * inet_pton() will refuse prefix string |
|
| 902 |
+ * (alternative would be to strncpy() the prefix to temporary buffer) |
|
| 903 |
+ */ |
|
| 904 |
+ |
|
| 905 |
+ *sep = '\0'; |
|
| 906 |
+ rc = inet_pton( AF_INET6, prefix_str, network ); |
|
| 907 |
+ *sep = '/'; |
|
| 908 |
+ |
|
| 909 |
+ if ( rc != 1 ) |
|
| 910 |
+ {
|
|
| 911 |
+ msg (msglevel, "IPv6 prefix '%s': invalid network part", prefix_str); |
|
| 912 |
+ return false; |
|
| 913 |
+ } |
|
| 914 |
+ *netbits = bits; |
|
| 915 |
+ return true; /* parsing OK, values set */ |
|
| 916 |
+} |
|
| 917 |
+ |
|
| 918 |
+static bool ipv6_addr_safe_hexplusbits( const char * ipv6_prefix_spec ) |
|
| 919 |
+{
|
|
| 920 |
+ struct in6_addr t_addr; |
|
| 921 |
+ unsigned int t_bits; |
|
| 922 |
+ |
|
| 923 |
+ return get_ipv6_addr( ipv6_prefix_spec, &t_addr, &t_bits, M_WARN ); |
|
| 924 |
+} |
|
| 925 |
+ |
|
| 874 | 926 |
static char * |
| 875 | 927 |
string_substitute (const char *src, int from, int to, struct gc_arena *gc) |
| 876 | 928 |
{
|
| ... | ... |
@@ -989,6 +1051,8 @@ show_p2mp_parms (const struct options *o) |
| 989 | 989 |
#if P2MP_SERVER |
| 990 | 990 |
msg (D_SHOW_PARMS, " server_network = %s", print_in_addr_t (o->server_network, 0, &gc)); |
| 991 | 991 |
msg (D_SHOW_PARMS, " server_netmask = %s", print_in_addr_t (o->server_netmask, 0, &gc)); |
| 992 |
+ msg (D_SHOW_PARMS, " server_network_ipv6 = %s", print_in6_addr (o->server_network_ipv6, 0, &gc) ); |
|
| 993 |
+ SHOW_INT (server_netbits_ipv6); |
|
| 992 | 994 |
msg (D_SHOW_PARMS, " server_bridge_ip = %s", print_in_addr_t (o->server_bridge_ip, 0, &gc)); |
| 993 | 995 |
msg (D_SHOW_PARMS, " server_bridge_netmask = %s", print_in_addr_t (o->server_bridge_netmask, 0, &gc)); |
| 994 | 996 |
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) |
| 1009 | 1009 |
msg (D_SHOW_PARMS, " ifconfig_pool_netmask = %s", print_in_addr_t (o->ifconfig_pool_netmask, 0, &gc)); |
| 1010 | 1010 |
SHOW_STR (ifconfig_pool_persist_filename); |
| 1011 | 1011 |
SHOW_INT (ifconfig_pool_persist_refresh_freq); |
| 1012 |
+ msg (D_SHOW_PARMS, " ifconfig_ipv6_pool_base = %s", print_in6_addr (o->ifconfig_ipv6_pool_base, 0, &gc)); |
|
| 1013 |
+ SHOW_INT (ifconfig_ipv6_pool_netbits); |
|
| 1012 | 1014 |
SHOW_INT (n_bcast_buf); |
| 1013 | 1015 |
SHOW_INT (tcp_queue_limit); |
| 1014 | 1016 |
SHOW_INT (real_hash_size); |
| ... | ... |
@@ -1076,6 +1142,25 @@ option_iroute (struct options *o, |
| 1076 | 1076 |
o->iroutes = ir; |
| 1077 | 1077 |
} |
| 1078 | 1078 |
|
| 1079 |
+static void |
|
| 1080 |
+option_iroute_ipv6 (struct options *o, |
|
| 1081 |
+ const char *prefix_str, |
|
| 1082 |
+ int msglevel) |
|
| 1083 |
+{
|
|
| 1084 |
+ struct iroute_ipv6 *ir; |
|
| 1085 |
+ |
|
| 1086 |
+ ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc); |
|
| 1087 |
+ |
|
| 1088 |
+ if ( get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, msglevel ) < 0 ) |
|
| 1089 |
+ {
|
|
| 1090 |
+ msg (msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification", |
|
| 1091 |
+ prefix_str); |
|
| 1092 |
+ return; |
|
| 1093 |
+ } |
|
| 1094 |
+ |
|
| 1095 |
+ ir->next = o->iroutes_ipv6; |
|
| 1096 |
+ o->iroutes_ipv6 = ir; |
|
| 1097 |
+} |
|
| 1079 | 1098 |
#endif /* P2MP_SERVER */ |
| 1080 | 1099 |
#endif /* P2MP */ |
| 1081 | 1100 |
|
| ... | ... |
@@ -1113,6 +1198,13 @@ rol_check_alloc (struct options *options) |
| 1113 | 1113 |
options->routes = new_route_option_list (options->max_routes, &options->gc); |
| 1114 | 1114 |
} |
| 1115 | 1115 |
|
| 1116 |
+void |
|
| 1117 |
+rol6_check_alloc (struct options *options) |
|
| 1118 |
+{
|
|
| 1119 |
+ if (!options->routes_ipv6) |
|
| 1120 |
+ options->routes_ipv6 = new_route_ipv6_option_list (options->max_routes, &options->gc); |
|
| 1121 |
+} |
|
| 1122 |
+ |
|
| 1116 | 1123 |
#ifdef ENABLE_DEBUG |
| 1117 | 1124 |
static void |
| 1118 | 1125 |
show_connection_entry (const struct connection_entry *o) |
| ... | ... |
@@ -1203,6 +1295,8 @@ show_settings (const struct options *o) |
| 1203 | 1203 |
SHOW_STR (ifconfig_remote_netmask); |
| 1204 | 1204 |
SHOW_BOOL (ifconfig_noexec); |
| 1205 | 1205 |
SHOW_BOOL (ifconfig_nowarn); |
| 1206 |
+ SHOW_STR (ifconfig_ipv6_local); |
|
| 1207 |
+ SHOW_STR (ifconfig_ipv6_remote); |
|
| 1206 | 1208 |
|
| 1207 | 1209 |
#ifdef HAVE_GETTIMEOFDAY |
| 1208 | 1210 |
SHOW_INT (shaper); |
| ... | ... |
@@ -1863,8 +1957,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne |
| 1863 | 1863 |
if (options->connection_list) |
| 1864 | 1864 |
msg (M_USAGE, "<connection> cannot be used with --mode server"); |
| 1865 | 1865 |
#endif |
| 1866 |
+#if 0 |
|
| 1866 | 1867 |
if (options->tun_ipv6) |
| 1867 | 1868 |
msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server"); |
| 1869 |
+#endif |
|
| 1868 | 1870 |
if (options->shaper) |
| 1869 | 1871 |
msg (M_USAGE, "--shaper cannot be used with --mode server"); |
| 1870 | 1872 |
if (options->inetd) |
| ... | ... |
@@ -2461,6 +2557,8 @@ options_string (const struct options *o, |
| 2461 | 2461 |
o->topology, |
| 2462 | 2462 |
o->ifconfig_local, |
| 2463 | 2463 |
o->ifconfig_remote_netmask, |
| 2464 |
+ o->ifconfig_ipv6_local, |
|
| 2465 |
+ o->ifconfig_ipv6_remote, |
|
| 2464 | 2466 |
(in_addr_t)0, |
| 2465 | 2467 |
(in_addr_t)0, |
| 2466 | 2468 |
false, |
| ... | ... |
@@ -3794,6 +3892,21 @@ add_option (struct options *options, |
| 3794 | 3794 |
goto err; |
| 3795 | 3795 |
} |
| 3796 | 3796 |
} |
| 3797 |
+ else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] ) |
|
| 3798 |
+ {
|
|
| 3799 |
+ VERIFY_PERMISSION (OPT_P_UP); |
|
| 3800 |
+ /* TODO: should we accept address + netbits (2001:db8::1/64) here? */ |
|
| 3801 |
+ if ( ipv6_addr_safe( p[1] ) && ipv6_addr_safe( p[2] ) ) |
|
| 3802 |
+ {
|
|
| 3803 |
+ options->ifconfig_ipv6_local = p[1]; |
|
| 3804 |
+ options->ifconfig_ipv6_remote = p[2]; |
|
| 3805 |
+ } |
|
| 3806 |
+ else |
|
| 3807 |
+ {
|
|
| 3808 |
+ msg (msglevel, "ifconfig-ipv6 parms '%s' and '%s' must be valid addresses", p[1], p[2]); |
|
| 3809 |
+ goto err; |
|
| 3810 |
+ } |
|
| 3811 |
+ } |
|
| 3797 | 3812 |
else if (streq (p[0], "ifconfig-noexec")) |
| 3798 | 3813 |
{
|
| 3799 | 3814 |
VERIFY_PERMISSION (OPT_P_UP); |
| ... | ... |
@@ -4594,6 +4707,26 @@ add_option (struct options *options, |
| 4594 | 4594 |
} |
| 4595 | 4595 |
add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]); |
| 4596 | 4596 |
} |
| 4597 |
+ else if (streq (p[0], "route-ipv6") && p[1]) |
|
| 4598 |
+ {
|
|
| 4599 |
+ VERIFY_PERMISSION (OPT_P_ROUTE); |
|
| 4600 |
+ rol6_check_alloc (options); |
|
| 4601 |
+ if (pull_mode) |
|
| 4602 |
+ {
|
|
| 4603 |
+ if (!ipv6_addr_safe_hexplusbits (p[1])) |
|
| 4604 |
+ {
|
|
| 4605 |
+ msg (msglevel, "route-ipv6 parameter network/IP '%s' must be a valid address", p[1]); |
|
| 4606 |
+ goto err; |
|
| 4607 |
+ } |
|
| 4608 |
+ if (p[2] && !ipv6_addr_safe (p[2])) |
|
| 4609 |
+ {
|
|
| 4610 |
+ msg (msglevel, "route-ipv6 parameter gateway '%s' must be a valid address", p[2]); |
|
| 4611 |
+ goto err; |
|
| 4612 |
+ } |
|
| 4613 |
+ /* p[3] is metric, if present */ |
|
| 4614 |
+ } |
|
| 4615 |
+ add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]); |
|
| 4616 |
+ } |
|
| 4597 | 4617 |
else if (streq (p[0], "max-routes") && p[1]) |
| 4598 | 4618 |
{
|
| 4599 | 4619 |
int max_routes; |
| ... | ... |
@@ -4805,6 +4938,33 @@ add_option (struct options *options, |
| 4805 | 4805 |
} |
| 4806 | 4806 |
} |
| 4807 | 4807 |
} |
| 4808 |
+ else if (streq (p[0], "server-ipv6") && p[1] ) |
|
| 4809 |
+ {
|
|
| 4810 |
+ const int lev = M_WARN; |
|
| 4811 |
+ struct in6_addr network; |
|
| 4812 |
+ unsigned int netbits = 0; |
|
| 4813 |
+ |
|
| 4814 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
| 4815 |
+ if ( ! get_ipv6_addr (p[1], &network, &netbits, lev) ) |
|
| 4816 |
+ {
|
|
| 4817 |
+ msg (msglevel, "error parsing --server-ipv6 parameter"); |
|
| 4818 |
+ goto err; |
|
| 4819 |
+ } |
|
| 4820 |
+ if ( netbits != 64 ) |
|
| 4821 |
+ {
|
|
| 4822 |
+ msg( msglevel, "--server-ipv6 settings: only /64 supported right now (not /%d)", netbits ); |
|
| 4823 |
+ goto err; |
|
| 4824 |
+ } |
|
| 4825 |
+ options->server_ipv6_defined = true; |
|
| 4826 |
+ options->server_network_ipv6 = network; |
|
| 4827 |
+ options->server_netbits_ipv6 = netbits; |
|
| 4828 |
+ |
|
| 4829 |
+ if (p[2]) /* no "nopool" options or similar for IPv6 */ |
|
| 4830 |
+ {
|
|
| 4831 |
+ msg (msglevel, "error parsing --server: %s is not a recognized flag", p[3]); |
|
| 4832 |
+ goto err; |
|
| 4833 |
+ } |
|
| 4834 |
+ } |
|
| 4808 | 4835 |
else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4]) |
| 4809 | 4836 |
{
|
| 4810 | 4837 |
const int lev = M_WARN; |
| ... | ... |
@@ -4889,6 +5049,28 @@ add_option (struct options *options, |
| 4889 | 4889 |
VERIFY_PERMISSION (OPT_P_GENERAL); |
| 4890 | 4890 |
options->topology = TOP_P2P; |
| 4891 | 4891 |
} |
| 4892 |
+ else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] ) |
|
| 4893 |
+ {
|
|
| 4894 |
+ const int lev = M_WARN; |
|
| 4895 |
+ struct in6_addr network; |
|
| 4896 |
+ unsigned int netbits = 0; |
|
| 4897 |
+ |
|
| 4898 |
+ VERIFY_PERMISSION (OPT_P_GENERAL); |
|
| 4899 |
+ if ( ! get_ipv6_addr (p[1], &network, &netbits, lev ) ) |
|
| 4900 |
+ {
|
|
| 4901 |
+ msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters"); |
|
| 4902 |
+ goto err; |
|
| 4903 |
+ } |
|
| 4904 |
+ if ( netbits != 64 ) |
|
| 4905 |
+ {
|
|
| 4906 |
+ msg( msglevel, "--ifconfig-ipv6-pool settings: only /64 supported right now (not /%d)", netbits ); |
|
| 4907 |
+ goto err; |
|
| 4908 |
+ } |
|
| 4909 |
+ |
|
| 4910 |
+ options->ifconfig_ipv6_pool_defined = true; |
|
| 4911 |
+ options->ifconfig_ipv6_pool_base = network; |
|
| 4912 |
+ options->ifconfig_ipv6_pool_netbits = netbits; |
|
| 4913 |
+ } |
|
| 4892 | 4914 |
else if (streq (p[0], "hash-size") && p[1] && p[2]) |
| 4893 | 4915 |
{
|
| 4894 | 4916 |
int real, virtual; |
| ... | ... |
@@ -5084,6 +5266,11 @@ add_option (struct options *options, |
| 5084 | 5084 |
} |
| 5085 | 5085 |
option_iroute (options, p[1], netmask, msglevel); |
| 5086 | 5086 |
} |
| 5087 |
+ else if (streq (p[0], "iroute-ipv6") && p[1]) |
|
| 5088 |
+ {
|
|
| 5089 |
+ VERIFY_PERMISSION (OPT_P_INSTANCE); |
|
| 5090 |
+ option_iroute_ipv6 (options, p[1], msglevel); |
|
| 5091 |
+ } |
|
| 5087 | 5092 |
else if (streq (p[0], "ifconfig-push") && p[1] && p[2]) |
| 5088 | 5093 |
{
|
| 5089 | 5094 |
in_addr_t local, remote_netmask; |
| ... | ... |
@@ -205,6 +205,8 @@ struct options |
| 205 | 205 |
int topology; /* one of the TOP_x values from proto.h */ |
| 206 | 206 |
const char *ifconfig_local; |
| 207 | 207 |
const char *ifconfig_remote_netmask; |
| 208 |
+ const char *ifconfig_ipv6_local; |
|
| 209 |
+ const char *ifconfig_ipv6_remote; |
|
| 208 | 210 |
bool ifconfig_noexec; |
| 209 | 211 |
bool ifconfig_nowarn; |
| 210 | 212 |
#ifdef HAVE_GETTIMEOFDAY |
| ... | ... |
@@ -326,6 +328,7 @@ struct options |
| 326 | 326 |
bool route_delay_defined; |
| 327 | 327 |
int max_routes; |
| 328 | 328 |
struct route_option_list *routes; |
| 329 |
+ struct route_ipv6_option_list *routes_ipv6; /* IPv6 */ |
|
| 329 | 330 |
bool route_nopull; |
| 330 | 331 |
bool route_gateway_via_dhcp; |
| 331 | 332 |
bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */ |
| ... | ... |
@@ -361,6 +364,9 @@ struct options |
| 361 | 361 |
bool server_defined; |
| 362 | 362 |
in_addr_t server_network; |
| 363 | 363 |
in_addr_t server_netmask; |
| 364 |
+ bool server_ipv6_defined; /* IPv6 */ |
|
| 365 |
+ struct in6_addr server_network_ipv6; /* IPv6 */ |
|
| 366 |
+ unsigned int server_netbits_ipv6; /* IPv6 */ |
|
| 364 | 367 |
|
| 365 | 368 |
# define SF_NOPOOL (1<<0) |
| 366 | 369 |
# define SF_TCP_NODELAY_HELPER (1<<1) |
| ... | ... |
@@ -382,6 +388,11 @@ struct options |
| 382 | 382 |
in_addr_t ifconfig_pool_netmask; |
| 383 | 383 |
const char *ifconfig_pool_persist_filename; |
| 384 | 384 |
int ifconfig_pool_persist_refresh_freq; |
| 385 |
+ |
|
| 386 |
+ bool ifconfig_ipv6_pool_defined; /* IPv6 */ |
|
| 387 |
+ struct in6_addr ifconfig_ipv6_pool_base; /* IPv6 */ |
|
| 388 |
+ int ifconfig_ipv6_pool_netbits; /* IPv6 */ |
|
| 389 |
+ |
|
| 385 | 390 |
int real_hash_size; |
| 386 | 391 |
int virtual_hash_size; |
| 387 | 392 |
const char *client_connect_script; |
| ... | ... |
@@ -394,6 +405,7 @@ struct options |
| 394 | 394 |
int n_bcast_buf; |
| 395 | 395 |
int tcp_queue_limit; |
| 396 | 396 |
struct iroute *iroutes; |
| 397 |
+ struct iroute_ipv6 *iroutes_ipv6; /* IPv6 */ |
|
| 397 | 398 |
bool push_ifconfig_defined; |
| 398 | 399 |
in_addr_t push_ifconfig_local; |
| 399 | 400 |
in_addr_t push_ifconfig_remote_netmask; |
| ... | ... |
@@ -722,6 +734,9 @@ void options_string_import (struct options *options, |
| 722 | 722 |
unsigned int *option_types_found, |
| 723 | 723 |
struct env_set *es); |
| 724 | 724 |
|
| 725 |
+bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network, |
|
| 726 |
+ unsigned int * netbits, int msglevel ); |
|
| 727 |
+ |
|
| 725 | 728 |
/* |
| 726 | 729 |
* inline functions |
| 727 | 730 |
*/ |
| ... | ... |
@@ -132,7 +132,10 @@ ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_ |
| 132 | 132 |
} |
| 133 | 133 |
|
| 134 | 134 |
struct ifconfig_pool * |
| 135 |
-ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn) |
|
| 135 |
+ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, |
|
| 136 |
+ const bool duplicate_cn, |
|
| 137 |
+ const bool ipv6_pool, const struct in6_addr ipv6_base, |
|
| 138 |
+ const int ipv6_netbits ) |
|
| 136 | 139 |
{
|
| 137 | 140 |
struct gc_arena gc = gc_new (); |
| 138 | 141 |
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 |
| 157 | 157 |
ASSERT (0); |
| 158 | 158 |
} |
| 159 | 159 |
|
| 160 |
+ /* IPv6 pools are always "INDIV" type */ |
|
| 161 |
+ pool->ipv6 = ipv6_pool; |
|
| 162 |
+ |
|
| 163 |
+ if ( pool->ipv6 ) |
|
| 164 |
+ {
|
|
| 165 |
+ pool->base_ipv6 = ipv6_base; |
|
| 166 |
+ pool->size_ipv6 = ipv6_netbits>96? ( 1<<(128-ipv6_netbits) ) |
|
| 167 |
+ : IFCONFIG_POOL_MAX; |
|
| 168 |
+ |
|
| 169 |
+ msg( D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: (IPv4) size=%d, size_ipv6=%d, netbits=%d, base_ipv6=%s", |
|
| 170 |
+ pool->size, pool->size_ipv6, ipv6_netbits, |
|
| 171 |
+ print_in6_addr( pool->base_ipv6, 0, &gc )); |
|
| 172 |
+ |
|
| 173 |
+ /* the current code is very simple and assumes that the IPv6 |
|
| 174 |
+ * pool is at least as big as the IPv4 pool, and we don't need |
|
| 175 |
+ * to do separate math etc. for IPv6 |
|
| 176 |
+ */ |
|
| 177 |
+ ASSERT( pool->size < pool->size_ipv6 ); |
|
| 178 |
+ } |
|
| 179 |
+ |
|
| 160 | 180 |
ALLOC_ARRAY_CLEAR (pool->list, struct ifconfig_pool_entry, pool->size); |
| 161 | 181 |
|
| 162 |
- msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d", |
|
| 182 |
+ msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d, ipv6=%d", |
|
| 163 | 183 |
print_in_addr_t (pool->base, 0, &gc), |
| 164 |
- pool->size); |
|
| 184 |
+ pool->size, pool->ipv6 ); |
|
| 165 | 185 |
|
| 166 | 186 |
gc_free (&gc); |
| 167 | 187 |
return pool; |
| ... | ... |
@@ -181,7 +204,7 @@ ifconfig_pool_free (struct ifconfig_pool *pool) |
| 181 | 181 |
} |
| 182 | 182 |
|
| 183 | 183 |
ifconfig_pool_handle |
| 184 |
-ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name) |
|
| 184 |
+ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name) |
|
| 185 | 185 |
{
|
| 186 | 186 |
int i; |
| 187 | 187 |
|
| ... | ... |
@@ -214,6 +237,12 @@ ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t * |
| 214 | 214 |
default: |
| 215 | 215 |
ASSERT (0); |
| 216 | 216 |
} |
| 217 |
+ |
|
| 218 |
+ /* IPv6 pools are always INDIV (--linear) */ |
|
| 219 |
+ if ( pool->ipv6 && remote_ipv6 ) |
|
| 220 |
+ {
|
|
| 221 |
+ *remote_ipv6 = add_in6_addr( pool->base_ipv6, i ); |
|
| 222 |
+ } |
|
| 217 | 223 |
} |
| 218 | 224 |
return i; |
| 219 | 225 |
} |
| ... | ... |
@@ -288,6 +317,19 @@ ifconfig_pool_handle_to_ip_base (const struct ifconfig_pool* pool, ifconfig_pool |
| 288 | 288 |
return ret; |
| 289 | 289 |
} |
| 290 | 290 |
|
| 291 |
+static struct in6_addr |
|
| 292 |
+ifconfig_pool_handle_to_ipv6_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand) |
|
| 293 |
+{
|
|
| 294 |
+ struct in6_addr ret = in6addr_any; |
|
| 295 |
+ |
|
| 296 |
+ /* IPv6 pools are always INDIV (--linear) */ |
|
| 297 |
+ if (hand >= 0 && hand < pool->size_ipv6 ) |
|
| 298 |
+ {
|
|
| 299 |
+ ret = add_in6_addr( pool->base_ipv6, hand ); |
|
| 300 |
+ } |
|
| 301 |
+ return ret; |
|
| 302 |
+} |
|
| 303 |
+ |
|
| 291 | 304 |
static void |
| 292 | 305 |
ifconfig_pool_set (struct ifconfig_pool* pool, const char *cn, const in_addr_t addr, const bool fixed) |
| 293 | 306 |
{
|
| ... | ... |
@@ -317,9 +359,20 @@ ifconfig_pool_list (const struct ifconfig_pool* pool, struct status_output *out) |
| 317 | 317 |
if (e->common_name) |
| 318 | 318 |
{
|
| 319 | 319 |
const in_addr_t ip = ifconfig_pool_handle_to_ip_base (pool, i); |
| 320 |
- status_printf (out, "%s,%s", |
|
| 321 |
- e->common_name, |
|
| 322 |
- print_in_addr_t (ip, 0, &gc)); |
|
| 320 |
+ if ( pool->ipv6 ) |
|
| 321 |
+ {
|
|
| 322 |
+ struct in6_addr ip6 = ifconfig_pool_handle_to_ipv6_base (pool, i); |
|
| 323 |
+ status_printf (out, "%s,%s,%s", |
|
| 324 |
+ e->common_name, |
|
| 325 |
+ print_in_addr_t (ip, 0, &gc), |
|
| 326 |
+ print_in6_addr (ip6, 0, &gc)); |
|
| 327 |
+ } |
|
| 328 |
+ else |
|
| 329 |
+ {
|
|
| 330 |
+ status_printf (out, "%s,%s", |
|
| 331 |
+ e->common_name, |
|
| 332 |
+ print_in_addr_t (ip, 0, &gc)); |
|
| 333 |
+ } |
|
| 323 | 334 |
} |
| 324 | 335 |
} |
| 325 | 336 |
gc_free (&gc); |
| ... | ... |
@@ -409,6 +462,9 @@ ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool |
| 409 | 409 |
int c = *BSTR(&in); |
| 410 | 410 |
if (c == '#' || c == ';') |
| 411 | 411 |
continue; |
| 412 |
+ msg( M_INFO, "ifconfig_pool_read(), in='%s', TODO: IPv6", |
|
| 413 |
+ BSTR(&in) ); |
|
| 414 |
+ |
|
| 412 | 415 |
if (buf_parse (&in, ',', cn_buf, buf_size) |
| 413 | 416 |
&& buf_parse (&in, ',', ip_buf, buf_size)) |
| 414 | 417 |
{
|
| ... | ... |
@@ -416,6 +472,7 @@ ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool |
| 416 | 416 |
const in_addr_t addr = getaddr (GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL); |
| 417 | 417 |
if (succeeded) |
| 418 | 418 |
{
|
| 419 |
+ msg( M_INFO, "succeeded -> ifconfig_pool_set()"); |
|
| 419 | 420 |
ifconfig_pool_set (pool, cn_buf, addr, persist->fixed); |
| 420 | 421 |
} |
| 421 | 422 |
} |
| ... | ... |
@@ -471,7 +528,7 @@ ifconfig_pool_test (in_addr_t start, in_addr_t end) |
| 471 | 471 |
#else |
| 472 | 472 |
cn = buf; |
| 473 | 473 |
#endif |
| 474 |
- h = ifconfig_pool_acquire (p, &local, &remote, cn); |
|
| 474 |
+ h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn); |
|
| 475 | 475 |
if (h < 0) |
| 476 | 476 |
break; |
| 477 | 477 |
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) |
| 506 | 506 |
#else |
| 507 | 507 |
cn = buf; |
| 508 | 508 |
#endif |
| 509 |
- h = ifconfig_pool_acquire (p, &local, &remote, cn); |
|
| 509 |
+ h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn); |
|
| 510 | 510 |
if (h < 0) |
| 511 | 511 |
break; |
| 512 | 512 |
msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s", |
| ... | ... |
@@ -52,6 +52,9 @@ struct ifconfig_pool |
| 52 | 52 |
int size; |
| 53 | 53 |
int type; |
| 54 | 54 |
bool duplicate_cn; |
| 55 |
+ bool ipv6; |
|
| 56 |
+ struct in6_addr base_ipv6; |
|
| 57 |
+ unsigned int size_ipv6; |
|
| 55 | 58 |
struct ifconfig_pool_entry *list; |
| 56 | 59 |
}; |
| 57 | 60 |
|
| ... | ... |
@@ -63,13 +66,13 @@ struct ifconfig_pool_persist |
| 63 | 63 |
|
| 64 | 64 |
typedef int ifconfig_pool_handle; |
| 65 | 65 |
|
| 66 |
-struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn); |
|
| 66 |
+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 ); |
|
| 67 | 67 |
|
| 68 | 68 |
void ifconfig_pool_free (struct ifconfig_pool *pool); |
| 69 | 69 |
|
| 70 | 70 |
bool ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end); |
| 71 | 71 |
|
| 72 |
-ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name); |
|
| 72 |
+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); |
|
| 73 | 73 |
|
| 74 | 74 |
bool ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard); |
| 75 | 75 |
|
| ... | ... |
@@ -108,6 +108,21 @@ struct openvpn_iphdr {
|
| 108 | 108 |
}; |
| 109 | 109 |
|
| 110 | 110 |
/* |
| 111 |
+ * IPv6 header |
|
| 112 |
+ */ |
|
| 113 |
+struct openvpn_ipv6hdr {
|
|
| 114 |
+ uint8_t version_prio; |
|
| 115 |
+ uint8_t flow_lbl[3]; |
|
| 116 |
+ uint16_t payload_len; |
|
| 117 |
+ uint8_t nexthdr; |
|
| 118 |
+ uint8_t hop_limit; |
|
| 119 |
+ |
|
| 120 |
+ struct in6_addr saddr; |
|
| 121 |
+ struct in6_addr daddr; |
|
| 122 |
+}; |
|
| 123 |
+ |
|
| 124 |
+ |
|
| 125 |
+/* |
|
| 111 | 126 |
* UDP header |
| 112 | 127 |
*/ |
| 113 | 128 |
struct openvpn_udphdr {
|
| ... | ... |
@@ -191,6 +191,22 @@ send_push_reply (struct context *c) |
| 191 | 191 |
|
| 192 | 192 |
buf_printf (&buf, "%s", cmd); |
| 193 | 193 |
|
| 194 |
+ if ( c->c2.push_ifconfig_ipv6_defined ) |
|
| 195 |
+ {
|
|
| 196 |
+ /* IPv6 is put into buffer first, could be lengthy */ |
|
| 197 |
+ /* TODO: push "/netbits" as well, to allow non-/64 subnet sizes |
|
| 198 |
+ * (needs changes in options.c, options.h, and other places) |
|
| 199 |
+ */ |
|
| 200 |
+ buf_printf( &buf, ",ifconfig-ipv6 %s %s", |
|
| 201 |
+ print_in6_addr( c->c2.push_ifconfig_ipv6_local, 0, &gc), |
|
| 202 |
+ print_in6_addr( c->c2.push_ifconfig_ipv6_remote, 0, &gc) ); |
|
| 203 |
+ if (BLEN (&buf) >= safe_cap) |
|
| 204 |
+ {
|
|
| 205 |
+ msg (M_WARN, "--push ifconfig-ipv6 option is too long"); |
|
| 206 |
+ goto fail; |
|
| 207 |
+ } |
|
| 208 |
+ } |
|
| 209 |
+ |
|
| 194 | 210 |
while (e) |
| 195 | 211 |
{
|
| 196 | 212 |
if (e->enable) |
| ... | ... |
@@ -39,6 +39,7 @@ |
| 39 | 39 |
#include "memdbg.h" |
| 40 | 40 |
|
| 41 | 41 |
static void delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); |
| 42 |
+static void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); |
|
| 42 | 43 |
static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags); |
| 43 | 44 |
|
| 44 | 45 |
#ifdef ENABLE_DEBUG |
| ... | ... |
@@ -68,6 +69,15 @@ new_route_option_list (const int max_routes, struct gc_arena *a) |
| 68 | 68 |
return ret; |
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 |
+struct route_ipv6_option_list * |
|
| 72 |
+new_route_ipv6_option_list (const int max_routes, struct gc_arena *a) |
|
| 73 |
+{
|
|
| 74 |
+ struct route_ipv6_option_list *ret; |
|
| 75 |
+ ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_option_list, struct route_ipv6_option, max_routes, a); |
|
| 76 |
+ ret->capacity = max_routes; |
|
| 77 |
+ return ret; |
|
| 78 |
+} |
|
| 79 |
+ |
|
| 71 | 80 |
struct route_option_list * |
| 72 | 81 |
clone_route_option_list (const struct route_option_list *src, struct gc_arena *a) |
| 73 | 82 |
{
|
| ... | ... |
@@ -95,6 +105,15 @@ new_route_list (const int max_routes, struct gc_arena *a) |
| 95 | 95 |
return ret; |
| 96 | 96 |
} |
| 97 | 97 |
|
| 98 |
+struct route_ipv6_list * |
|
| 99 |
+new_route_ipv6_list (const int max_routes, struct gc_arena *a) |
|
| 100 |
+{
|
|
| 101 |
+ struct route_ipv6_list *ret; |
|
| 102 |
+ ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_list, struct route_ipv6, max_routes, a); |
|
| 103 |
+ ret->capacity = max_routes; |
|
| 104 |
+ return ret; |
|
| 105 |
+} |
|
| 106 |
+ |
|
| 98 | 107 |
static const char * |
| 99 | 108 |
route_string (const struct route *r, struct gc_arena *gc) |
| 100 | 109 |
{
|
| ... | ... |
@@ -311,6 +330,68 @@ init_route (struct route *r, |
| 311 | 311 |
return false; |
| 312 | 312 |
} |
| 313 | 313 |
|
| 314 |
+static bool |
|
| 315 |
+init_route_ipv6 (struct route_ipv6 *r6, |
|
| 316 |
+ const struct route_ipv6_option *r6o, |
|
| 317 |
+ const struct route_ipv6_list *rl6 ) |
|
| 318 |
+{
|
|
| 319 |
+ r6->option = r6o; |
|
| 320 |
+ r6->defined = false; |
|
| 321 |
+ |
|
| 322 |
+ if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, M_WARN )) |
|
| 323 |
+ goto fail; |
|
| 324 |
+ |
|
| 325 |
+ /* gateway */ |
|
| 326 |
+ if (is_route_parm_defined (r6o->gateway)) |
|
| 327 |
+ {
|
|
| 328 |
+ if ( inet_pton( AF_INET6, r6o->gateway, &r6->gateway ) != 1 ) |
|
| 329 |
+ {
|
|
| 330 |
+ msg( M_WARN, PACKAGE_NAME "ROUTE6: cannot parse gateway spec '%s'", r6o->gateway ); |
|
| 331 |
+ } |
|
| 332 |
+ } |
|
| 333 |
+ else if (rl6->remote_endpoint_defined) |
|
| 334 |
+ {
|
|
| 335 |
+ r6->gateway = rl6->remote_endpoint_ipv6; |
|
| 336 |
+ } |
|
| 337 |
+ else |
|
| 338 |
+ {
|
|
| 339 |
+ 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"); |
|
| 340 |
+ goto fail; |
|
| 341 |
+ } |
|
| 342 |
+ |
|
| 343 |
+ /* metric */ |
|
| 344 |
+ |
|
| 345 |
+ r6->metric_defined = false; |
|
| 346 |
+ r6->metric = 0; |
|
| 347 |
+ if (is_route_parm_defined (r6o->metric)) |
|
| 348 |
+ {
|
|
| 349 |
+ r6->metric = atoi (r6o->metric); |
|
| 350 |
+ if (r6->metric < 0) |
|
| 351 |
+ {
|
|
| 352 |
+ msg (M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0", |
|
| 353 |
+ r6o->prefix, |
|
| 354 |
+ r6o->metric); |
|
| 355 |
+ goto fail; |
|
| 356 |
+ } |
|
| 357 |
+ r6->metric_defined = true; |
|
| 358 |
+ } |
|
| 359 |
+ else if (rl6->default_metric_defined) |
|
| 360 |
+ {
|
|
| 361 |
+ r6->metric = rl6->default_metric; |
|
| 362 |
+ r6->metric_defined = true; |
|
| 363 |
+ } |
|
| 364 |
+ |
|
| 365 |
+ r6->defined = true; |
|
| 366 |
+ |
|
| 367 |
+ return true; |
|
| 368 |
+ |
|
| 369 |
+ fail: |
|
| 370 |
+ msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s", |
|
| 371 |
+ r6o->prefix); |
|
| 372 |
+ r6->defined = false; |
|
| 373 |
+ return false; |
|
| 374 |
+} |
|
| 375 |
+ |
|
| 314 | 376 |
void |
| 315 | 377 |
add_route_to_option_list (struct route_option_list *l, |
| 316 | 378 |
const char *network, |
| ... | ... |
@@ -331,6 +412,23 @@ add_route_to_option_list (struct route_option_list *l, |
| 331 | 331 |
} |
| 332 | 332 |
|
| 333 | 333 |
void |
| 334 |
+add_route_ipv6_to_option_list (struct route_ipv6_option_list *l, |
|
| 335 |
+ const char *prefix, |
|
| 336 |
+ const char *gateway, |
|
| 337 |
+ const char *metric) |
|
| 338 |
+{
|
|
| 339 |
+ struct route_ipv6_option *ro; |
|
| 340 |
+ if (l->n >= l->capacity) |
|
| 341 |
+ msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d IPv6 routes -- please increase the max-routes option in the client configuration file", |
|
| 342 |
+ l->capacity); |
|
| 343 |
+ ro = &l->routes_ipv6[l->n]; |
|
| 344 |
+ ro->prefix = prefix; |
|
| 345 |
+ ro->gateway = gateway; |
|
| 346 |
+ ro->metric = metric; |
|
| 347 |
+ ++l->n; |
|
| 348 |
+} |
|
| 349 |
+ |
|
| 350 |
+void |
|
| 334 | 351 |
clear_route_list (struct route_list *rl) |
| 335 | 352 |
{
|
| 336 | 353 |
const int capacity = rl->capacity; |
| ... | ... |
@@ -340,6 +438,15 @@ clear_route_list (struct route_list *rl) |
| 340 | 340 |
} |
| 341 | 341 |
|
| 342 | 342 |
void |
| 343 |
+clear_route_ipv6_list (struct route_ipv6_list *rl6) |
|
| 344 |
+{
|
|
| 345 |
+ const int capacity = rl6->capacity; |
|
| 346 |
+ const size_t rl6_size = array_mult_safe (sizeof(struct route_ipv6), capacity, sizeof(struct route_ipv6_list)); |
|
| 347 |
+ memset(rl6, 0, rl6_size); |
|
| 348 |
+ rl6->capacity = capacity; |
|
| 349 |
+} |
|
| 350 |
+ |
|
| 351 |
+void |
|
| 343 | 352 |
route_list_add_default_gateway (struct route_list *rl, |
| 344 | 353 |
struct env_set *es, |
| 345 | 354 |
const in_addr_t addr) |
| ... | ... |
@@ -469,6 +576,72 @@ init_route_list (struct route_list *rl, |
| 469 | 469 |
return ret; |
| 470 | 470 |
} |
| 471 | 471 |
|
| 472 |
+bool |
|
| 473 |
+init_route_ipv6_list (struct route_ipv6_list *rl6, |
|
| 474 |
+ const struct route_ipv6_option_list *opt6, |
|
| 475 |
+ const char *remote_endpoint, |
|
| 476 |
+ int default_metric, |
|
| 477 |
+ struct env_set *es) |
|
| 478 |
+{
|
|
| 479 |
+ struct gc_arena gc = gc_new (); |
|
| 480 |
+ bool ret = true; |
|
| 481 |
+ |
|
| 482 |
+ clear_route_ipv6_list (rl6); |
|
| 483 |
+ |
|
| 484 |
+ rl6->flags = opt6->flags; |
|
| 485 |
+ |
|
| 486 |
+ if (default_metric) |
|
| 487 |
+ {
|
|
| 488 |
+ rl6->default_metric = default_metric; |
|
| 489 |
+ rl6->default_metric_defined = true; |
|
| 490 |
+ } |
|
| 491 |
+ |
|
| 492 |
+ /* "default_gateway" is stuff for "redirect-gateway", which we don't |
|
| 493 |
+ * do for IPv6 yet -> TODO |
|
| 494 |
+ */ |
|
| 495 |
+ {
|
|
| 496 |
+ dmsg (D_ROUTE, "ROUTE6: default_gateway=UNDEF"); |
|
| 497 |
+ } |
|
| 498 |
+ |
|
| 499 |
+ if ( is_route_parm_defined( remote_endpoint )) |
|
| 500 |
+ {
|
|
| 501 |
+ if ( inet_pton( AF_INET6, remote_endpoint, |
|
| 502 |
+ &rl6->remote_endpoint_ipv6) == 1 ) |
|
| 503 |
+ {
|
|
| 504 |
+ rl6->remote_endpoint_defined = true; |
|
| 505 |
+ } |
|
| 506 |
+ else |
|
| 507 |
+ {
|
|
| 508 |
+ msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve default gateway: %s", remote_endpoint); |
|
| 509 |
+ ret = false; |
|
| 510 |
+ } |
|
| 511 |
+ } |
|
| 512 |
+ else |
|
| 513 |
+ rl6->remote_endpoint_defined = false; |
|
| 514 |
+ |
|
| 515 |
+ |
|
| 516 |
+ if (!(opt6->n >= 0 && opt6->n <= rl6->capacity)) |
|
| 517 |
+ msg (M_FATAL, PACKAGE_NAME " ROUTE6: (init) number of route options (%d) is greater than route list capacity (%d)", opt6->n, rl6->capacity); |
|
| 518 |
+ |
|
| 519 |
+ /* parse the routes from opt to rl6 */ |
|
| 520 |
+ {
|
|
| 521 |
+ int i, j = 0; |
|
| 522 |
+ for (i = 0; i < opt6->n; ++i) |
|
| 523 |
+ {
|
|
| 524 |
+ if (!init_route_ipv6 (&rl6->routes_ipv6[j], |
|
| 525 |
+ &opt6->routes_ipv6[i], |
|
| 526 |
+ rl6 )) |
|
| 527 |
+ ret = false; |
|
| 528 |
+ else |
|
| 529 |
+ ++j; |
|
| 530 |
+ } |
|
| 531 |
+ rl6->n = j; |
|
| 532 |
+ } |
|
| 533 |
+ |
|
| 534 |
+ gc_free (&gc); |
|
| 535 |
+ return ret; |
|
| 536 |
+} |
|
| 537 |
+ |
|
| 472 | 538 |
static void |
| 473 | 539 |
add_route3 (in_addr_t network, |
| 474 | 540 |
in_addr_t netmask, |
| ... | ... |
@@ -704,10 +877,13 @@ undo_redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap * |
| 704 | 704 |
} |
| 705 | 705 |
|
| 706 | 706 |
void |
| 707 |
-add_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
|
| 707 |
+add_routes (struct route_list *rl, struct route_ipv6_list *rl6, |
|
| 708 |
+ const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
|
| 708 | 709 |
{
|
| 709 |
- redirect_default_route_to_vpn (rl, tt, flags, es); |
|
| 710 |
- if (!rl->routes_added) |
|
| 710 |
+ if (rl) |
|
| 711 |
+ redirect_default_route_to_vpn (rl, tt, flags, es); |
|
| 712 |
+ |
|
| 713 |
+ if (rl && !rl->routes_added) |
|
| 711 | 714 |
{
|
| 712 | 715 |
int i; |
| 713 | 716 |
|
| ... | ... |
@@ -732,12 +908,27 @@ add_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, |
| 732 | 732 |
} |
| 733 | 733 |
rl->routes_added = true; |
| 734 | 734 |
} |
| 735 |
+ |
|
| 736 |
+ if (rl6 && !rl6->routes_added) |
|
| 737 |
+ {
|
|
| 738 |
+ int i; |
|
| 739 |
+ |
|
| 740 |
+ for (i = 0; i < rl6->n; ++i) |
|
| 741 |
+ {
|
|
| 742 |
+ struct route_ipv6 *r = &rl6->routes_ipv6[i]; |
|
| 743 |
+ if (flags & ROUTE_DELETE_FIRST) |
|
| 744 |
+ delete_route_ipv6 (r, tt, flags, es); |
|
| 745 |
+ add_route_ipv6 (r, tt, flags, es); |
|
| 746 |
+ } |
|
| 747 |
+ rl6->routes_added = true; |
|
| 748 |
+ } |
|
| 735 | 749 |
} |
| 736 | 750 |
|
| 737 | 751 |
void |
| 738 |
-delete_routes (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
|
| 752 |
+delete_routes (struct route_list *rl, struct route_ipv6_list *rl6, |
|
| 753 |
+ const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
|
| 739 | 754 |
{
|
| 740 |
- if (rl->routes_added) |
|
| 755 |
+ if (rl && rl->routes_added) |
|
| 741 | 756 |
{
|
| 742 | 757 |
int i; |
| 743 | 758 |
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 |
| 747 | 747 |
} |
| 748 | 748 |
rl->routes_added = false; |
| 749 | 749 |
} |
| 750 |
- undo_redirect_default_route_to_vpn (rl, tt, flags, es); |
|
| 751 | 750 |
|
| 752 |
- clear_route_list (rl); |
|
| 751 |
+ if ( rl ) |
|
| 752 |
+ {
|
|
| 753 |
+ undo_redirect_default_route_to_vpn (rl, tt, flags, es); |
|
| 754 |
+ clear_route_list (rl); |
|
| 755 |
+ } |
|
| 756 |
+ |
|
| 757 |
+ if ( rl6 && rl6->routes_added ) |
|
| 758 |
+ {
|
|
| 759 |
+ int i; |
|
| 760 |
+ for (i = rl6->n - 1; i >= 0; --i) |
|
| 761 |
+ {
|
|
| 762 |
+ const struct route_ipv6 *r6 = &rl6->routes_ipv6[i]; |
|
| 763 |
+ delete_route_ipv6 (r6, tt, flags, es); |
|
| 764 |
+ } |
|
| 765 |
+ rl6->routes_added = false; |
|
| 766 |
+ } |
|
| 767 |
+ |
|
| 768 |
+ if ( rl6 ) |
|
| 769 |
+ {
|
|
| 770 |
+ clear_route_ipv6_list (rl6); |
|
| 771 |
+ } |
|
| 753 | 772 |
} |
| 754 | 773 |
|
| 755 | 774 |
#ifdef ENABLE_DEBUG |
| ... | ... |
@@ -832,6 +1042,34 @@ setenv_routes (struct env_set *es, const struct route_list *rl) |
| 832 | 832 |
setenv_route (es, &rl->routes[i], i + 1); |
| 833 | 833 |
} |
| 834 | 834 |
|
| 835 |
+static void |
|
| 836 |
+setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i) |
|
| 837 |
+{
|
|
| 838 |
+ struct gc_arena gc = gc_new (); |
|
| 839 |
+ if (r6->defined) |
|
| 840 |
+ {
|
|
| 841 |
+ struct buffer name1 = alloc_buf_gc( 256, &gc ); |
|
| 842 |
+ struct buffer val = alloc_buf_gc( 256, &gc ); |
|
| 843 |
+ struct buffer name2 = alloc_buf_gc( 256, &gc ); |
|
| 844 |
+ |
|
| 845 |
+ buf_printf( &name1, "route_ipv6_network_%d", i ); |
|
| 846 |
+ buf_printf( &val, "%s/%d", print_in6_addr( r6->network, 0, &gc ), |
|
| 847 |
+ r6->netbits ); |
|
| 848 |
+ setenv_str( es, BSTR(&name1), BSTR(&val) ); |
|
| 849 |
+ |
|
| 850 |
+ buf_printf( &name2, "route_ipv6_gateway_%d", i ); |
|
| 851 |
+ setenv_str( es, BSTR(&name2), print_in6_addr( r6->gateway, 0, &gc )); |
|
| 852 |
+ } |
|
| 853 |
+ gc_free (&gc); |
|
| 854 |
+} |
|
| 855 |
+void |
|
| 856 |
+setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6) |
|
| 857 |
+{
|
|
| 858 |
+ int i; |
|
| 859 |
+ for (i = 0; i < rl6->n; ++i) |
|
| 860 |
+ setenv_route_ipv6 (es, &rl6->routes_ipv6[i], i + 1); |
|
| 861 |
+} |
|
| 862 |
+ |
|
| 835 | 863 |
void |
| 836 | 864 |
add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
| 837 | 865 |
{
|
| ... | ... |
@@ -1025,6 +1263,136 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s |
| 1025 | 1025 |
gc_free (&gc); |
| 1026 | 1026 |
} |
| 1027 | 1027 |
|
| 1028 |
+void |
|
| 1029 |
+add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
|
| 1030 |
+{
|
|
| 1031 |
+ struct gc_arena gc; |
|
| 1032 |
+ struct argv argv; |
|
| 1033 |
+ |
|
| 1034 |
+ const char *network; |
|
| 1035 |
+ const char *gateway; |
|
| 1036 |
+ bool status = false; |
|
| 1037 |
+ const char *device = tt->actual_name; |
|
| 1038 |
+ int byte, bits_to_clear; |
|
| 1039 |
+ struct in6_addr network_copy = r6->network; |
|
| 1040 |
+ |
|
| 1041 |
+ if (!r6->defined) |
|
| 1042 |
+ return; |
|
| 1043 |
+ |
|
| 1044 |
+ gc_init (&gc); |
|
| 1045 |
+ argv_init (&argv); |
|
| 1046 |
+ |
|
| 1047 |
+ /* clear host bit parts of route |
|
| 1048 |
+ * (needed if routes are specified improperly, or if we need to |
|
| 1049 |
+ * explicitely setup the "connected" network routes on some OSes) |
|
| 1050 |
+ */ |
|
| 1051 |
+ byte = 15; |
|
| 1052 |
+ bits_to_clear = 128 - r6->netbits; |
|
| 1053 |
+ |
|
| 1054 |
+ while( byte >= 0 && bits_to_clear > 0 ) |
|
| 1055 |
+ {
|
|
| 1056 |
+ if ( bits_to_clear >= 8 ) |
|
| 1057 |
+ { network_copy.s6_addr[byte--] = 0; bits_to_clear -= 8; }
|
|
| 1058 |
+ else |
|
| 1059 |
+ { network_copy.s6_addr[byte--] &= (~0 << bits_to_clear); bits_to_clear = 0; }
|
|
| 1060 |
+ } |
|
| 1061 |
+ |
|
| 1062 |
+ network = print_in6_addr( network_copy, 0, &gc); |
|
| 1063 |
+ gateway = print_in6_addr( r6->gateway, 0, &gc); |
|
| 1064 |
+ |
|
| 1065 |
+ msg( M_INFO, "add_route_ipv6(%s/%d -> %s metric %d) dev %s", |
|
| 1066 |
+ network, r6->netbits, gateway, r6->metric, device ); |
|
| 1067 |
+ |
|
| 1068 |
+ /* |
|
| 1069 |
+ * Filter out routes which are essentially no-ops |
|
| 1070 |
+ * (not currently done for IPv6) |
|
| 1071 |
+ */ |
|
| 1072 |
+ |
|
| 1073 |
+#if defined(TARGET_LINUX) |
|
| 1074 |
+#ifdef CONFIG_FEATURE_IPROUTE |
|
| 1075 |
+ argv_printf (&argv, "%s -6 route add %s/%d dev %s", |
|
| 1076 |
+ iproute_path, |
|
| 1077 |
+ network, |
|
| 1078 |
+ r6->netbits, |
|
| 1079 |
+ device); |
|
| 1080 |
+ if (r6->metric_defined) |
|
| 1081 |
+ argv_printf_cat (&argv, " metric %d", r6->metric); |
|
| 1082 |
+ |
|
| 1083 |
+#else |
|
| 1084 |
+ argv_printf (&argv, "%s -A inet6 add %s/%d dev %s", |
|
| 1085 |
+ ROUTE_PATH, |
|
| 1086 |
+ network, |
|
| 1087 |
+ r6->netbits, |
|
| 1088 |
+ device); |
|
| 1089 |
+ if (r6->metric_defined) |
|
| 1090 |
+ argv_printf_cat (&argv, " metric %d", r6->metric); |
|
| 1091 |
+#endif /*CONFIG_FEATURE_IPROUTE*/ |
|
| 1092 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1093 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 add command failed"); |
|
| 1094 |
+ |
|
| 1095 |
+#elif defined (WIN32) |
|
| 1096 |
+ |
|
| 1097 |
+ msg( M_FATAL, "no idea how to set IPv6 routes on windows (unimplemented)" ); |
|
| 1098 |
+ |
|
| 1099 |
+#elif defined (TARGET_SOLARIS) |
|
| 1100 |
+ |
|
| 1101 |
+ /* example: route add -inet6 2001:db8::/32 somegateway 0 */ |
|
| 1102 |
+ |
|
| 1103 |
+ /* for some weird reason, this does not work for me unless I set |
|
| 1104 |
+ * "metric 0" - otherwise, the routes will be nicely installed, but |
|
| 1105 |
+ * packets will just disappear somewhere. So we use "0" now... |
|
| 1106 |
+ */ |
|
| 1107 |
+ |
|
| 1108 |
+ argv_printf (&argv, "%s add -inet6 %s/%d %s 0", |
|
| 1109 |
+ ROUTE_PATH, |
|
| 1110 |
+ network, |
|
| 1111 |
+ r6->netbits, |
|
| 1112 |
+ gateway ); |
|
| 1113 |
+ |
|
| 1114 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1115 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add -inet6 command failed"); |
|
| 1116 |
+ |
|
| 1117 |
+#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) |
|
| 1118 |
+ |
|
| 1119 |
+ argv_printf (&argv, "%s add -inet6 %s/%d -iface %s", |
|
| 1120 |
+ ROUTE_PATH, |
|
| 1121 |
+ network, |
|
| 1122 |
+ r6->netbits, |
|
| 1123 |
+ device ); |
|
| 1124 |
+ |
|
| 1125 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1126 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route add -inet6 command failed"); |
|
| 1127 |
+ |
|
| 1128 |
+#elif defined(TARGET_DARWIN) |
|
| 1129 |
+ |
|
| 1130 |
+ argv_printf (&argv, "%s add -inet6 %s -prefixlen %d -iface %s", |
|
| 1131 |
+ ROUTE_PATH, |
|
| 1132 |
+ network, r6->netbits, device ); |
|
| 1133 |
+ |
|
| 1134 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1135 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: MacOS X route add -inet6 command failed"); |
|
| 1136 |
+ |
|
| 1137 |
+#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) |
|
| 1138 |
+ |
|
| 1139 |
+ /* GERT-TODO: this needs real-world testing on OpenBSD, but it should work |
|
| 1140 |
+ */ |
|
| 1141 |
+ |
|
| 1142 |
+ argv_printf (&argv, "%s add -inet6 %s/%d %s", |
|
| 1143 |
+ ROUTE_PATH, |
|
| 1144 |
+ network, r6->netbits, gateway ); |
|
| 1145 |
+ |
|
| 1146 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1147 |
+ status = openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD/OpenBSD route add -inet6 command failed"); |
|
| 1148 |
+ |
|
| 1149 |
+#else |
|
| 1150 |
+ 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"); |
|
| 1151 |
+#endif |
|
| 1152 |
+ |
|
| 1153 |
+ r6->defined = status; |
|
| 1154 |
+ argv_reset (&argv); |
|
| 1155 |
+ gc_free (&gc); |
|
| 1156 |
+} |
|
| 1157 |
+ |
|
| 1028 | 1158 |
static void |
| 1029 | 1159 |
delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
| 1030 | 1160 |
{
|
| ... | ... |
@@ -1164,6 +1532,101 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags |
| 1164 | 1164 |
gc_free (&gc); |
| 1165 | 1165 |
} |
| 1166 | 1166 |
|
| 1167 |
+static void |
|
| 1168 |
+delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) |
|
| 1169 |
+{
|
|
| 1170 |
+ struct gc_arena gc; |
|
| 1171 |
+ struct argv argv; |
|
| 1172 |
+ const char *network; |
|
| 1173 |
+ const char *gateway; |
|
| 1174 |
+ const char *device = tt->actual_name; |
|
| 1175 |
+ |
|
| 1176 |
+ if (!r6->defined) |
|
| 1177 |
+ return; |
|
| 1178 |
+ |
|
| 1179 |
+ gc_init (&gc); |
|
| 1180 |
+ argv_init (&argv); |
|
| 1181 |
+ |
|
| 1182 |
+ network = print_in6_addr( r6->network, 0, &gc); |
|
| 1183 |
+ gateway = print_in6_addr( r6->gateway, 0, &gc); |
|
| 1184 |
+ |
|
| 1185 |
+ msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits ); |
|
| 1186 |
+ |
|
| 1187 |
+#if defined(TARGET_LINUX) |
|
| 1188 |
+#ifdef CONFIG_FEATURE_IPROUTE |
|
| 1189 |
+ argv_printf (&argv, "%s -6 route del %s/%d dev %s", |
|
| 1190 |
+ iproute_path, |
|
| 1191 |
+ network, |
|
| 1192 |
+ r6->netbits, |
|
| 1193 |
+ device); |
|
| 1194 |
+#else |
|
| 1195 |
+ argv_printf (&argv, "%s -A inet6 del %s/%d dev %s", |
|
| 1196 |
+ ROUTE_PATH, |
|
| 1197 |
+ network, |
|
| 1198 |
+ r6->netbits, |
|
| 1199 |
+ device); |
|
| 1200 |
+#endif /*CONFIG_FEATURE_IPROUTE*/ |
|
| 1201 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1202 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 del command failed"); |
|
| 1203 |
+ |
|
| 1204 |
+#elif defined (WIN32) |
|
| 1205 |
+ |
|
| 1206 |
+ msg( M_FATAL, "no idea how to delete IPv6 routes on windows (unimplemented)" ); |
|
| 1207 |
+ |
|
| 1208 |
+#elif defined (TARGET_SOLARIS) |
|
| 1209 |
+ |
|
| 1210 |
+ /* example: route delete -inet6 2001:db8::/32 somegateway */ |
|
| 1211 |
+ /* GERT-TODO: this is untested, but should work */ |
|
| 1212 |
+ |
|
| 1213 |
+ argv_printf (&argv, "%s delete -inet6 %s/%d %s", |
|
| 1214 |
+ ROUTE_PATH, |
|
| 1215 |
+ network, |
|
| 1216 |
+ r6->netbits, |
|
| 1217 |
+ gateway ); |
|
| 1218 |
+ |
|
| 1219 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1220 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route delete -inet6 command failed"); |
|
| 1221 |
+ |
|
| 1222 |
+#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) |
|
| 1223 |
+ |
|
| 1224 |
+ argv_printf (&argv, "%s delete -inet6 %s/%d -iface %s", |
|
| 1225 |
+ ROUTE_PATH, |
|
| 1226 |
+ network, |
|
| 1227 |
+ r6->netbits, |
|
| 1228 |
+ device ); |
|
| 1229 |
+ |
|
| 1230 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1231 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed"); |
|
| 1232 |
+ |
|
| 1233 |
+#elif defined(TARGET_DARWIN) |
|
| 1234 |
+ |
|
| 1235 |
+ argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d -iface %s", |
|
| 1236 |
+ ROUTE_PATH, |
|
| 1237 |
+ network, r6->netbits, device ); |
|
| 1238 |
+ |
|
| 1239 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1240 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed"); |
|
| 1241 |
+ |
|
| 1242 |
+#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) |
|
| 1243 |
+ |
|
| 1244 |
+ /* GERT-TODO: this needs real-world testing on OpenBSD, but it should work |
|
| 1245 |
+ */ |
|
| 1246 |
+ |
|
| 1247 |
+ argv_printf (&argv, "%s delete -inet6 %s/%d %s", |
|
| 1248 |
+ ROUTE_PATH, |
|
| 1249 |
+ network, r6->netbits, gateway ); |
|
| 1250 |
+ |
|
| 1251 |
+ argv_msg (D_ROUTE, &argv); |
|
| 1252 |
+ openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD/OpenBSD route delete -inet6 command failed"); |
|
| 1253 |
+ |
|
| 1254 |
+#else |
|
| 1255 |
+ 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"); |
|
| 1256 |
+#endif |
|
| 1257 |
+ |
|
| 1258 |
+ argv_reset (&argv); |
|
| 1259 |
+ gc_free (&gc); |
|
| 1260 |
+} |
|
| 1261 |
+ |
|
| 1167 | 1262 |
/* |
| 1168 | 1263 |
* The --redirect-gateway option requires OS-specific code below |
| 1169 | 1264 |
* to get the current default gateway. |
| ... | ... |
@@ -92,6 +92,19 @@ struct route_option_list {
|
| 92 | 92 |
struct route_option routes[EMPTY_ARRAY_SIZE]; |
| 93 | 93 |
}; |
| 94 | 94 |
|
| 95 |
+struct route_ipv6_option {
|
|
| 96 |
+ const char *prefix; /* e.g. "2001:db8:1::/64" */ |
|
| 97 |
+ const char *gateway; /* e.g. "2001:db8:0::2" */ |
|
| 98 |
+ const char *metric; /* e.g. "5" */ |
|
| 99 |
+}; |
|
| 100 |
+ |
|
| 101 |
+struct route_ipv6_option_list {
|
|
| 102 |
+ unsigned int flags; |
|
| 103 |
+ int capacity; |
|
| 104 |
+ int n; |
|
| 105 |
+ struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE]; |
|
| 106 |
+}; |
|
| 107 |
+ |
|
| 95 | 108 |
struct route {
|
| 96 | 109 |
bool defined; |
| 97 | 110 |
const struct route_option *option; |
| ... | ... |
@@ -113,6 +126,31 @@ struct route_list {
|
| 113 | 113 |
struct route routes[EMPTY_ARRAY_SIZE]; |
| 114 | 114 |
}; |
| 115 | 115 |
|
| 116 |
+struct route_ipv6 {
|
|
| 117 |
+ bool defined; |
|
| 118 |
+ const struct route_ipv6_option *option; |
|
| 119 |
+ struct in6_addr network; |
|
| 120 |
+ int netbits; |
|
| 121 |
+ struct in6_addr gateway; |
|
| 122 |
+ bool metric_defined; |
|
| 123 |
+ int metric; |
|
| 124 |
+}; |
|
| 125 |
+ |
|
| 126 |
+struct route_ipv6_list {
|
|
| 127 |
+ bool routes_added; |
|
| 128 |
+ unsigned int flags; |
|
| 129 |
+ int default_metric; |
|
| 130 |
+ bool default_metric_defined; |
|
| 131 |
+ struct in6_addr remote_endpoint_ipv6; |
|
| 132 |
+ bool remote_endpoint_defined; |
|
| 133 |
+ bool did_redirect_default_gateway; /* TODO (?) */ |
|
| 134 |
+ bool did_local; /* TODO (?) */ |
|
| 135 |
+ int capacity; |
|
| 136 |
+ int n; |
|
| 137 |
+ struct route_ipv6 routes_ipv6[EMPTY_ARRAY_SIZE]; |
|
| 138 |
+}; |
|
| 139 |
+ |
|
| 140 |
+ |
|
| 116 | 141 |
#if P2MP |
| 117 | 142 |
/* internal OpenVPN route */ |
| 118 | 143 |
struct iroute {
|
| ... | ... |
@@ -120,15 +158,24 @@ struct iroute {
|
| 120 | 120 |
int netbits; |
| 121 | 121 |
struct iroute *next; |
| 122 | 122 |
}; |
| 123 |
+ |
|
| 124 |
+struct iroute_ipv6 {
|
|
| 125 |
+ struct in6_addr network; |
|
| 126 |
+ unsigned int netbits; |
|
| 127 |
+ struct iroute_ipv6 *next; |
|
| 128 |
+}; |
|
| 123 | 129 |
#endif |
| 124 | 130 |
|
| 125 | 131 |
struct route_option_list *new_route_option_list (const int max_routes, struct gc_arena *a); |
| 132 |
+struct route_ipv6_option_list *new_route_ipv6_option_list (const int max_routes, struct gc_arena *a); |
|
| 126 | 133 |
struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a); |
| 127 | 134 |
void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src); |
| 128 | 135 |
|
| 129 | 136 |
struct route_list *new_route_list (const int max_routes, struct gc_arena *a); |
| 137 |
+struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_arena *a); |
|
| 130 | 138 |
|
| 131 | 139 |
void add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); |
| 140 |
+void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); |
|
| 132 | 141 |
|
| 133 | 142 |
void add_route_to_option_list (struct route_option_list *l, |
| 134 | 143 |
const char *network, |
| ... | ... |
@@ -136,6 +183,11 @@ void add_route_to_option_list (struct route_option_list *l, |
| 136 | 136 |
const char *gateway, |
| 137 | 137 |
const char *metric); |
| 138 | 138 |
|
| 139 |
+void add_route_ipv6_to_option_list (struct route_ipv6_option_list *l, |
|
| 140 |
+ const char *prefix, |
|
| 141 |
+ const char *gateway, |
|
| 142 |
+ const char *metric); |
|
| 143 |
+ |
|
| 139 | 144 |
bool init_route_list (struct route_list *rl, |
| 140 | 145 |
const struct route_option_list *opt, |
| 141 | 146 |
const char *remote_endpoint, |
| ... | ... |
@@ -143,21 +195,30 @@ bool init_route_list (struct route_list *rl, |
| 143 | 143 |
in_addr_t remote_host, |
| 144 | 144 |
struct env_set *es); |
| 145 | 145 |
|
| 146 |
+bool init_route_ipv6_list (struct route_ipv6_list *rl6, |
|
| 147 |
+ const struct route_ipv6_option_list *opt6, |
|
| 148 |
+ const char *remote_endpoint, |
|
| 149 |
+ int default_metric, |
|
| 150 |
+ struct env_set *es); |
|
| 151 |
+ |
|
| 146 | 152 |
void route_list_add_default_gateway (struct route_list *rl, |
| 147 | 153 |
struct env_set *es, |
| 148 | 154 |
const in_addr_t addr); |
| 149 | 155 |
|
| 150 | 156 |
void add_routes (struct route_list *rl, |
| 157 |
+ struct route_ipv6_list *rl6, |
|
| 151 | 158 |
const struct tuntap *tt, |
| 152 | 159 |
unsigned int flags, |
| 153 | 160 |
const struct env_set *es); |
| 154 | 161 |
|
| 155 | 162 |
void delete_routes (struct route_list *rl, |
| 163 |
+ struct route_ipv6_list *rl6, |
|
| 156 | 164 |
const struct tuntap *tt, |
| 157 | 165 |
unsigned int flags, |
| 158 | 166 |
const struct env_set *es); |
| 159 | 167 |
|
| 160 | 168 |
void setenv_routes (struct env_set *es, const struct route_list *rl); |
| 169 |
+void setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6); |
|
| 161 | 170 |
|
| 162 | 171 |
bool is_special_addr (const char *addr_str); |
| 163 | 172 |
|
| ... | ... |
@@ -342,6 +342,24 @@ ip_addr_dotted_quad_safe (const char *dotted_quad) |
| 342 | 342 |
} |
| 343 | 343 |
} |
| 344 | 344 |
|
| 345 |
+bool |
|
| 346 |
+ipv6_addr_safe (const char *ipv6_text_addr) |
|
| 347 |
+{
|
|
| 348 |
+ /* verify non-NULL */ |
|
| 349 |
+ if (!ipv6_text_addr) |
|
| 350 |
+ return false; |
|
| 351 |
+ |
|
| 352 |
+ /* verify length is within limits */ |
|
| 353 |
+ if (strlen (ipv6_text_addr) > INET6_ADDRSTRLEN ) |
|
| 354 |
+ return false; |
|
| 355 |
+ |
|
| 356 |
+ /* verify that string will convert to IPv6 address */ |
|
| 357 |
+ {
|
|
| 358 |
+ struct in6_addr a6; |
|
| 359 |
+ return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1; |
|
| 360 |
+ } |
|
| 361 |
+} |
|
| 362 |
+ |
|
| 345 | 363 |
static bool |
| 346 | 364 |
dns_addr_safe (const char *addr) |
| 347 | 365 |
{
|
| ... | ... |
@@ -2032,6 +2050,58 @@ print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc) |
| 2032 | 2032 |
return BSTR (&out); |
| 2033 | 2033 |
} |
| 2034 | 2034 |
|
| 2035 |
+/* |
|
| 2036 |
+ * Convert an in6_addr in host byte order |
|
| 2037 |
+ * to an ascii representation of an IPv6 address |
|
| 2038 |
+ * (we reuse the L_INET_NTOA mutex, no contention here) |
|
| 2039 |
+ */ |
|
| 2040 |
+const char * |
|
| 2041 |
+print_in6_addr (struct in6_addr a6, unsigned int flags, struct gc_arena *gc) |
|
| 2042 |
+{
|
|
| 2043 |
+ struct buffer out = alloc_buf_gc (64, gc); |
|
| 2044 |
+ char tmp_out_buf[64]; /* inet_ntop wants pointer to buffer */ |
|
| 2045 |
+ |
|
| 2046 |
+ if ( memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 || |
|
| 2047 |
+ !(flags & IA_EMPTY_IF_UNDEF)) |
|
| 2048 |
+ {
|
|
| 2049 |
+ mutex_lock_static (L_INET_NTOA); |
|
| 2050 |
+ inet_ntop (AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1); |
|
| 2051 |
+ buf_printf (&out, "%s", tmp_out_buf ); |
|
| 2052 |
+ mutex_unlock_static (L_INET_NTOA); |
|
| 2053 |
+ } |
|
| 2054 |
+ return BSTR (&out); |
|
| 2055 |
+} |
|
| 2056 |
+ |
|
| 2057 |
+/* add some offset to an ipv6 address |
|
| 2058 |
+ * (add in steps of 32 bits, taking overflow into next round) |
|
| 2059 |
+ */ |
|
| 2060 |
+#ifndef s6_addr32 |
|
| 2061 |
+# ifdef TARGET_SOLARIS |
|
| 2062 |
+# define s6_addr32 _S6_un._S6_u32 |
|
| 2063 |
+# else |
|
| 2064 |
+# define s6_addr32 __u6_addr.__u6_addr32 |
|
| 2065 |
+# endif |
|
| 2066 |
+#endif |
|
| 2067 |
+#ifndef UINT32_MAX |
|
| 2068 |
+# define UINT32_MAX (4294967295U) |
|
| 2069 |
+#endif |
|
| 2070 |
+struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add ) |
|
| 2071 |
+{
|
|
| 2072 |
+ int i; |
|
| 2073 |
+ uint32_t h; |
|
| 2074 |
+ |
|
| 2075 |
+ for( i=3; i>=0 && add > 0 ; i-- ) |
|
| 2076 |
+ {
|
|
| 2077 |
+ h = ntohl( base.s6_addr32[i] ); |
|
| 2078 |
+ base.s6_addr32[i] = htonl( (h+add) & UINT32_MAX ); |
|
| 2079 |
+ /* 32-bit overrun? |
|
| 2080 |
+ * caveat: can't do "h+add > UINT32_MAX" with 32bit math! |
|
| 2081 |
+ */ |
|
| 2082 |
+ add = ( h > UINT32_MAX - add )? 1: 0; |
|
| 2083 |
+ } |
|
| 2084 |
+ return base; |
|
| 2085 |
+} |
|
| 2086 |
+ |
|
| 2035 | 2087 |
/* set environmental variables for ip/port in *addr */ |
| 2036 | 2088 |
void |
| 2037 | 2089 |
setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags) |
| ... | ... |
@@ -351,6 +351,8 @@ const char *print_link_socket_actual (const struct link_socket_actual *act, |
| 351 | 351 |
#define IA_EMPTY_IF_UNDEF (1<<0) |
| 352 | 352 |
#define IA_NET_ORDER (1<<1) |
| 353 | 353 |
const char *print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc); |
| 354 |
+const char *print_in6_addr (struct in6_addr addr6, unsigned int flags, struct gc_arena *gc); |
|
| 355 |
+struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add ); |
|
| 354 | 356 |
|
| 355 | 357 |
#define SA_IP_PORT (1<<0) |
| 356 | 358 |
#define SA_SET_IF_NONZERO (1<<1) |
| ... | ... |
@@ -404,6 +406,7 @@ int openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr); |
| 404 | 404 |
bool ip_addr_dotted_quad_safe (const char *dotted_quad); |
| 405 | 405 |
bool ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn); |
| 406 | 406 |
bool mac_addr_safe (const char *mac_addr); |
| 407 |
+bool ipv6_addr_safe (const char *ipv6_text_addr); |
|
| 407 | 408 |
|
| 408 | 409 |
socket_descriptor_t create_socket_tcp (void); |
| 409 | 410 |
|
| ... | ... |
@@ -62,7 +62,7 @@ static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc); |
| 62 | 62 |
#endif |
| 63 | 63 |
|
| 64 | 64 |
#ifdef TARGET_SOLARIS |
| 65 |
-static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual); |
|
| 65 |
+static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual, bool unplumb_inet6); |
|
| 66 | 66 |
#include <stropts.h> |
| 67 | 67 |
#endif |
| 68 | 68 |
|
| ... | ... |
@@ -143,14 +143,15 @@ guess_tuntap_dev (const char *dev, |
| 143 | 143 |
* If ipv6_explicitly_supported is true, then we have explicit |
| 144 | 144 |
* OS-specific tun dev code for handling IPv6. If so, tt->ipv6 |
| 145 | 145 |
* is set according to the --tun-ipv6 command line option. |
| 146 |
+ * |
|
| 147 |
+ * (enabling IPv6 on tun devices might work anyway, but since |
|
| 148 |
+ * we don't know, we log a warning) |
|
| 146 | 149 |
*/ |
| 147 | 150 |
static void |
| 148 | 151 |
ipv6_support (bool ipv6, bool ipv6_explicitly_supported, struct tuntap* tt) |
| 149 | 152 |
{
|
| 150 |
- tt->ipv6 = false; |
|
| 151 |
- if (ipv6_explicitly_supported) |
|
| 152 |
- tt->ipv6 = ipv6; |
|
| 153 |
- else if (ipv6) |
|
| 153 |
+ tt->ipv6 = ipv6; |
|
| 154 |
+ if (ipv6 && !ipv6_explicitly_supported) |
|
| 154 | 155 |
msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS"); |
| 155 | 156 |
} |
| 156 | 157 |
|
| ... | ... |
@@ -423,6 +424,8 @@ init_tun (const char *dev, /* --dev option */ |
| 423 | 423 |
int topology, /* one of the TOP_x values */ |
| 424 | 424 |
const char *ifconfig_local_parm, /* --ifconfig parm 1 */ |
| 425 | 425 |
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */ |
| 426 |
+ const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 IPv6 */ |
|
| 427 |
+ const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 IPv6 */ |
|
| 426 | 428 |
in_addr_t local_public, |
| 427 | 429 |
in_addr_t remote_public, |
| 428 | 430 |
const bool strict_warn, |
| ... | ... |
@@ -430,6 +433,7 @@ init_tun (const char *dev, /* --dev option */ |
| 430 | 430 |
{
|
| 431 | 431 |
struct gc_arena gc = gc_new (); |
| 432 | 432 |
struct tuntap *tt; |
| 433 |
+ bool tun; |
|
| 433 | 434 |
|
| 434 | 435 |
ALLOC_OBJ (tt, struct tuntap); |
| 435 | 436 |
clear_tuntap (tt); |
| ... | ... |
@@ -437,19 +441,18 @@ init_tun (const char *dev, /* --dev option */ |
| 437 | 437 |
tt->type = dev_type_enum (dev, dev_type); |
| 438 | 438 |
tt->topology = topology; |
| 439 | 439 |
|
| 440 |
+ /* |
|
| 441 |
+ * We only handle TUN/TAP devices here, not --dev null devices. |
|
| 442 |
+ */ |
|
| 443 |
+ tun = is_tun_p2p (tt); |
|
| 444 |
+ |
|
| 440 | 445 |
if (ifconfig_local_parm && ifconfig_remote_netmask_parm) |
| 441 | 446 |
{
|
| 442 |
- bool tun = false; |
|
| 443 | 447 |
const char *ifconfig_local = NULL; |
| 444 | 448 |
const char *ifconfig_remote_netmask = NULL; |
| 445 | 449 |
const char *ifconfig_broadcast = NULL; |
| 446 | 450 |
|
| 447 | 451 |
/* |
| 448 |
- * We only handle TUN/TAP devices here, not --dev null devices. |
|
| 449 |
- */ |
|
| 450 |
- tun = is_tun_p2p (tt); |
|
| 451 |
- |
|
| 452 |
- /* |
|
| 453 | 452 |
* Convert arguments to binary IPv4 addresses. |
| 454 | 453 |
*/ |
| 455 | 454 |
|
| ... | ... |
@@ -537,6 +540,40 @@ init_tun (const char *dev, /* --dev option */ |
| 537 | 537 |
|
| 538 | 538 |
tt->did_ifconfig_setup = true; |
| 539 | 539 |
} |
| 540 |
+ |
|
| 541 |
+ if (ifconfig_ipv6_local_parm && ifconfig_ipv6_remote_parm) |
|
| 542 |
+ {
|
|
| 543 |
+ const char *ifconfig_ipv6_local = NULL; |
|
| 544 |
+ const char *ifconfig_ipv6_remote = NULL; |
|
| 545 |
+ |
|
| 546 |
+ /* |
|
| 547 |
+ * Convert arguments to binary IPv6 addresses. |
|
| 548 |
+ */ |
|
| 549 |
+ |
|
| 550 |
+ if ( inet_pton( AF_INET6, ifconfig_ipv6_local_parm, &tt->local_ipv6 ) != 1 || |
|
| 551 |
+ inet_pton( AF_INET6, ifconfig_ipv6_remote_parm, &tt->remote_ipv6 ) != 1 ) |
|
| 552 |
+ {
|
|
| 553 |
+ msg( M_FATAL, "init_tun: problem converting IPv6 ifconfig addresses %s and %s to binary", ifconfig_ipv6_local_parm, ifconfig_ipv6_remote_parm ); |
|
| 554 |
+ } |
|
| 555 |
+ tt->netbits_ipv6 = 64; |
|
| 556 |
+ |
|
| 557 |
+ /* |
|
| 558 |
+ * Set ifconfig parameters |
|
| 559 |
+ */ |
|
| 560 |
+ ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); |
|
| 561 |
+ ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); |
|
| 562 |
+ |
|
| 563 |
+ /* |
|
| 564 |
+ * Set environmental variables with ifconfig parameters. |
|
| 565 |
+ */ |
|
| 566 |
+ if (es) |
|
| 567 |
+ {
|
|
| 568 |
+ setenv_str (es, "ifconfig_ipv6_local", ifconfig_ipv6_local); |
|
| 569 |
+ setenv_str (es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote); |
|
| 570 |
+ } |
|
| 571 |
+ tt->did_ifconfig_ipv6_setup = true; |
|
| 572 |
+ } |
|
| 573 |
+ |
|
| 540 | 574 |
gc_free (&gc); |
| 541 | 575 |
return tt; |
| 542 | 576 |
} |
| ... | ... |
@@ -574,10 +611,15 @@ do_ifconfig (struct tuntap *tt, |
| 574 | 574 |
const char *ifconfig_local = NULL; |
| 575 | 575 |
const char *ifconfig_remote_netmask = NULL; |
| 576 | 576 |
const char *ifconfig_broadcast = NULL; |
| 577 |
+ const char *ifconfig_ipv6_local = NULL; |
|
| 578 |
+ const char *ifconfig_ipv6_remote = NULL; |
|
| 579 |
+ bool do_ipv6 = false; |
|
| 577 | 580 |
struct argv argv; |
| 578 | 581 |
|
| 579 | 582 |
argv_init (&argv); |
| 580 | 583 |
|
| 584 |
+ msg( M_INFO, "do_ifconfig, ipv6=%d", tt->ipv6 ); |
|
| 585 |
+ |
|
| 581 | 586 |
/* |
| 582 | 587 |
* We only handle TUN/TAP devices here, not --dev null devices. |
| 583 | 588 |
*/ |
| ... | ... |
@@ -589,6 +631,13 @@ do_ifconfig (struct tuntap *tt, |
| 589 | 589 |
ifconfig_local = print_in_addr_t (tt->local, 0, &gc); |
| 590 | 590 |
ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc); |
| 591 | 591 |
|
| 592 |
+ if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) |
|
| 593 |
+ {
|
|
| 594 |
+ ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); |
|
| 595 |
+ ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); |
|
| 596 |
+ do_ipv6 = true; |
|
| 597 |
+ } |
|
| 598 |
+ |
|
| 592 | 599 |
/* |
| 593 | 600 |
* If TAP-style device, generate broadcast address. |
| 594 | 601 |
*/ |
| ... | ... |
@@ -635,6 +684,18 @@ do_ifconfig (struct tuntap *tt, |
| 635 | 635 |
); |
| 636 | 636 |
argv_msg (M_INFO, &argv); |
| 637 | 637 |
openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed"); |
| 638 |
+ if ( do_ipv6 ) /* GERT-TODO: yet UNTESTED! */ |
|
| 639 |
+ {
|
|
| 640 |
+ argv_printf( &argv, |
|
| 641 |
+ "%s -6 addr add %s/%d dev %s", |
|
| 642 |
+ iproute_path, |
|
| 643 |
+ ifconfig_ipv6_local, |
|
| 644 |
+ tt->netbits_ipv6, |
|
| 645 |
+ actual |
|
| 646 |
+ ); |
|
| 647 |
+ argv_msg (M_INFO, &argv); |
|
| 648 |
+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ip -6 addr add failed"); |
|
| 649 |
+ } |
|
| 638 | 650 |
} else {
|
| 639 | 651 |
argv_printf (&argv, |
| 640 | 652 |
"%s addr add dev %s %s/%d broadcast %s", |
| ... | ... |
@@ -670,6 +731,18 @@ do_ifconfig (struct tuntap *tt, |
| 670 | 670 |
); |
| 671 | 671 |
argv_msg (M_INFO, &argv); |
| 672 | 672 |
openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig failed"); |
| 673 |
+ if ( do_ipv6 ) |
|
| 674 |
+ {
|
|
| 675 |
+ argv_printf (&argv, |
|
| 676 |
+ "%s %s inet6 add %s/%d", |
|
| 677 |
+ IFCONFIG_PATH, |
|
| 678 |
+ actual, |
|
| 679 |
+ ifconfig_ipv6_local, |
|
| 680 |
+ tt->netbits_ipv6 |
|
| 681 |
+ ); |
|
| 682 |
+ argv_msg (M_INFO, &argv); |
|
| 683 |
+ openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig inet6 failed"); |
|
| 684 |
+ } |
|
| 673 | 685 |
tt->did_ifconfig = true; |
| 674 | 686 |
|
| 675 | 687 |
#endif /*CONFIG_FEATURE_IPROUTE*/ |
| ... | ... |
@@ -693,7 +766,7 @@ do_ifconfig (struct tuntap *tt, |
| 693 | 693 |
|
| 694 | 694 |
argv_msg (M_INFO, &argv); |
| 695 | 695 |
if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-1 failed")) |
| 696 |
- solaris_error_close (tt, es, actual); |
|
| 696 |
+ solaris_error_close (tt, es, actual, false); |
|
| 697 | 697 |
|
| 698 | 698 |
argv_printf (&argv, |
| 699 | 699 |
"%s %s netmask 255.255.255.255", |
| ... | ... |
@@ -725,7 +798,27 @@ do_ifconfig (struct tuntap *tt, |
| 725 | 725 |
|
| 726 | 726 |
argv_msg (M_INFO, &argv); |
| 727 | 727 |
if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed")) |
| 728 |
- solaris_error_close (tt, es, actual); |
|
| 728 |
+ solaris_error_close (tt, es, actual, false); |
|
| 729 |
+ |
|
| 730 |
+ if ( do_ipv6 ) /* GERT-TODO: UNTESTED */ |
|
| 731 |
+ {
|
|
| 732 |
+ argv_printf (&argv, "%s %s inet6 unplumb", |
|
| 733 |
+ IFCONFIG_PATH, actual ); |
|
| 734 |
+ argv_msg (M_INFO, &argv); |
|
| 735 |
+ openvpn_execve_check (&argv, es, 0, NULL); |
|
| 736 |
+ |
|
| 737 |
+ argv_printf (&argv, |
|
| 738 |
+ "%s %s inet6 plumb %s/%d %s up", |
|
| 739 |
+ IFCONFIG_PATH, |
|
| 740 |
+ actual, |
|
| 741 |
+ ifconfig_ipv6_local, |
|
| 742 |
+ tt->netbits_ipv6, |
|
| 743 |
+ ifconfig_ipv6_remote |
|
| 744 |
+ ); |
|
| 745 |
+ argv_msg (M_INFO, &argv); |
|
| 746 |
+ if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 failed")) |
|
| 747 |
+ solaris_error_close (tt, es, actual, true); |
|
| 748 |
+ } |
|
| 729 | 749 |
|
| 730 | 750 |
if (!tun && tt->topology == TOP_SUBNET) |
| 731 | 751 |
{
|
| ... | ... |
@@ -787,10 +880,19 @@ do_ifconfig (struct tuntap *tt, |
| 787 | 787 |
); |
| 788 | 788 |
argv_msg (M_INFO, &argv); |
| 789 | 789 |
openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed"); |
| 790 |
+ if ( do_ipv6 ) |
|
| 791 |
+ {
|
|
| 792 |
+ msg( M_FATAL, "can't configure IPv6 on OpenBSD yet - unimplemented" ); |
|
| 793 |
+ } |
|
| 790 | 794 |
tt->did_ifconfig = true; |
| 791 | 795 |
|
| 792 | 796 |
#elif defined(TARGET_NETBSD) |
| 793 | 797 |
|
| 798 |
+ /* as on OpenBSD and Darwin, destroy and re-create tun0 interface |
|
| 799 |
+ */ |
|
| 800 |
+ argv_printf (&argv, "%s %s destroy", IFCONFIG_PATH, actual ); |
|
| 801 |
+ argv_msg (M_INFO, &argv); |
|
| 802 |
+ |
|
| 794 | 803 |
if (tun) |
| 795 | 804 |
argv_printf (&argv, |
| 796 | 805 |
"%s %s %s %s mtu %d netmask 255.255.255.255 up", |
| ... | ... |
@@ -817,6 +919,27 @@ do_ifconfig (struct tuntap *tt, |
| 817 | 817 |
); |
| 818 | 818 |
argv_msg (M_INFO, &argv); |
| 819 | 819 |
openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed"); |
| 820 |
+ |
|
| 821 |
+ if ( do_ipv6 ) |
|
| 822 |
+ {
|
|
| 823 |
+ struct route_ipv6 r6; |
|
| 824 |
+ argv_printf (&argv, |
|
| 825 |
+ "%s %s inet6 %s/%d", |
|
| 826 |
+ IFCONFIG_PATH, |
|
| 827 |
+ actual, |
|
| 828 |
+ ifconfig_ipv6_local, |
|
| 829 |
+ tt->netbits_ipv6 |
|
| 830 |
+ ); |
|
| 831 |
+ argv_msg (M_INFO, &argv); |
|
| 832 |
+ openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed"); |
|
| 833 |
+ |
|
| 834 |
+ /* and, hooray, we explicitely need to add a route... */ |
|
| 835 |
+ r6.defined = true; |
|
| 836 |
+ r6.network = tt->local_ipv6; |
|
| 837 |
+ r6.netbits = tt->netbits_ipv6; |
|
| 838 |
+ r6.gateway = tt->local_ipv6; |
|
| 839 |
+ add_route_ipv6 (&r6, tt, 0, es); |
|
| 840 |
+ } |
|
| 820 | 841 |
tt->did_ifconfig = true; |
| 821 | 842 |
|
| 822 | 843 |
#elif defined(TARGET_DARWIN) |
| ... | ... |
@@ -882,6 +1005,27 @@ do_ifconfig (struct tuntap *tt, |
| 882 | 882 |
add_route (&r, tt, 0, es); |
| 883 | 883 |
} |
| 884 | 884 |
|
| 885 |
+ if ( do_ipv6 ) |
|
| 886 |
+ {
|
|
| 887 |
+ struct route_ipv6 r6; |
|
| 888 |
+ argv_printf (&argv, |
|
| 889 |
+ "%s %s inet6 %s/%d", |
|
| 890 |
+ IFCONFIG_PATH, |
|
| 891 |
+ actual, |
|
| 892 |
+ ifconfig_ipv6_local, |
|
| 893 |
+ tt->netbits_ipv6 |
|
| 894 |
+ ); |
|
| 895 |
+ argv_msg (M_INFO, &argv); |
|
| 896 |
+ openvpn_execve_check (&argv, es, S_FATAL, "MacOS X ifconfig inet6 failed"); |
|
| 897 |
+ |
|
| 898 |
+ /* and, hooray, we explicitely need to add a route... */ |
|
| 899 |
+ r6.defined = true; |
|
| 900 |
+ r6.network = tt->local_ipv6; |
|
| 901 |
+ r6.netbits = tt->netbits_ipv6; |
|
| 902 |
+ r6.gateway = tt->local_ipv6; |
|
| 903 |
+ add_route_ipv6 (&r6, tt, 0, es); |
|
| 904 |
+ } |
|
| 905 |
+ |
|
| 885 | 906 |
#elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY) |
| 886 | 907 |
|
| 887 | 908 |
/* 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, |
| 920 | 920 |
add_route (&r, tt, 0, es); |
| 921 | 921 |
} |
| 922 | 922 |
|
| 923 |
+ if ( do_ipv6 ) |
|
| 924 |
+ {
|
|
| 925 |
+ argv_printf (&argv, |
|
| 926 |
+ "%s %s inet6 %s/%d", |
|
| 927 |
+ IFCONFIG_PATH, |
|
| 928 |
+ actual, |
|
| 929 |
+ ifconfig_ipv6_local, |
|
| 930 |
+ tt->netbits_ipv6 |
|
| 931 |
+ ); |
|
| 932 |
+ argv_msg (M_INFO, &argv); |
|
| 933 |
+ openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed"); |
|
| 934 |
+ } |
|
| 935 |
+ |
|
| 923 | 936 |
#elif defined (WIN32) |
| 924 | 937 |
{
|
| 925 | 938 |
/* |
| ... | ... |
@@ -959,6 +1116,10 @@ do_ifconfig (struct tuntap *tt, |
| 959 | 959 |
tt->did_ifconfig = true; |
| 960 | 960 |
} |
| 961 | 961 |
|
| 962 |
+ if ( do_ipv6 ) |
|
| 963 |
+ {
|
|
| 964 |
+ msg( M_FATAL, "can't configure IPv6 on Win32 yet - unimplemented" ); |
|
| 965 |
+ } |
|
| 962 | 966 |
#else |
| 963 | 967 |
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."); |
| 964 | 968 |
#endif |
| ... | ... |
@@ -1415,6 +1576,10 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 |
| 1415 | 1415 |
bool is_tun; |
| 1416 | 1416 |
struct strioctl strioc_if, strioc_ppa; |
| 1417 | 1417 |
|
| 1418 |
+ /* improved generic TUN/TAP driver from |
|
| 1419 |
+ * http://www.whiteboard.ne.jp/~admin2/tuntap/ |
|
| 1420 |
+ * has IPv6 support |
|
| 1421 |
+ */ |
|
| 1418 | 1422 |
ipv6_support (ipv6, true, tt); |
| 1419 | 1423 |
memset(&ifr, 0x0, sizeof(ifr)); |
| 1420 | 1424 |
|
| ... | ... |
@@ -1622,11 +1787,20 @@ close_tun (struct tuntap *tt) |
| 1622 | 1622 |
} |
| 1623 | 1623 |
|
| 1624 | 1624 |
static void |
| 1625 |
-solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual) |
|
| 1625 |
+solaris_error_close (struct tuntap *tt, const struct env_set *es, |
|
| 1626 |
+ const char *actual, bool unplumb_inet6 ) |
|
| 1626 | 1627 |
{
|
| 1627 | 1628 |
struct argv argv; |
| 1628 | 1629 |
argv_init (&argv); |
| 1629 | 1630 |
|
| 1631 |
+ if (unplumb_inet6) |
|
| 1632 |
+ {
|
|
| 1633 |
+ argv_printf( &argv, "%s %s inet6 unplumb", |
|
| 1634 |
+ IFCONFIG_PATH, actual ); |
|
| 1635 |
+ argv_msg (M_INFO, &argv); |
|
| 1636 |
+ openvpn_execve_check (&argv, es, 0, "Solaris ifconfig inet6 unplumb failed"); |
|
| 1637 |
+ } |
|
| 1638 |
+ |
|
| 1630 | 1639 |
argv_printf (&argv, |
| 1631 | 1640 |
"%s %s unplumb", |
| 1632 | 1641 |
IFCONFIG_PATH, |
| ... | ... |
@@ -1774,17 +1948,34 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) |
| 1774 | 1774 |
#elif defined(TARGET_NETBSD) |
| 1775 | 1775 |
|
| 1776 | 1776 |
/* |
| 1777 |
- * NetBSD does not support IPv6 on tun out of the box, |
|
| 1778 |
- * but there exists a patch. When this patch is applied, |
|
| 1779 |
- * only two things are left to openvpn: |
|
| 1777 |
+ * NetBSD before 4.0 does not support IPv6 on tun out of the box, |
|
| 1778 |
+ * but there exists a patch (sys/net/if_tun.c, 1.79->1.80, see PR 32944). |
|
| 1779 |
+ * |
|
| 1780 |
+ * When this patch is applied, only two things are left to openvpn: |
|
| 1780 | 1781 |
* 1. Activate multicasting (this has already been done |
| 1781 | 1782 |
* before by the kernel, but we make sure that nobody |
| 1782 | 1783 |
* has deactivated multicasting inbetween. |
| 1783 | 1784 |
* 2. Deactivate "link layer mode" (otherwise NetBSD |
| 1784 | 1785 |
* prepends the address family to the packet, and we |
| 1785 | 1786 |
* would run into the same trouble as with OpenBSD. |
| 1787 |
+ * |
|
| 1788 |
+ * ... unfortunately, it doesn't work that way. If TUN_IFHEAD is disabled |
|
| 1789 |
+ * ("no prepending of the AF"), then the kernel code just drops IPv6 packets
|
|
| 1790 |
+ * on output, and gets confused on input. |
|
| 1791 |
+ * |
|
| 1792 |
+ * So we have to do it the same way as FreeBSD and OpenBSD do it |
|
| 1793 |
+ * (and we really should merge FreeBSD, NetBSD and OpenBSD together) |
|
| 1786 | 1794 |
*/ |
| 1787 | 1795 |
|
| 1796 |
+static inline int |
|
| 1797 |
+netbsd_modify_read_write_return (int len) |
|
| 1798 |
+{
|
|
| 1799 |
+ if (len > 0) |
|
| 1800 |
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; |
|
| 1801 |
+ else |
|
| 1802 |
+ return len; |
|
| 1803 |
+} |
|
| 1804 |
+ |
|
| 1788 | 1805 |
void |
| 1789 | 1806 |
open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, struct tuntap *tt) |
| 1790 | 1807 |
{
|
| ... | ... |
@@ -1795,12 +1986,20 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6 |
| 1795 | 1795 |
ioctl (tt->fd, TUNSIFMODE, &i); /* multicast on */ |
| 1796 | 1796 |
i = 0; |
| 1797 | 1797 |
ioctl (tt->fd, TUNSLMODE, &i); /* link layer mode off */ |
| 1798 |
+ i = 1; |
|
| 1799 |
+ if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0) /* multi-af mode on */ |
|
| 1800 |
+ {
|
|
| 1801 |
+ msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); |
|
| 1802 |
+ } |
|
| 1798 | 1803 |
} |
| 1799 | 1804 |
} |
| 1800 | 1805 |
|
| 1801 | 1806 |
void |
| 1802 | 1807 |
close_tun (struct tuntap *tt) |
| 1803 | 1808 |
{
|
| 1809 |
+ /* TODO: we really should cleanup non-persistant tunX with |
|
| 1810 |
+ * "ifconfig tunX destroy" here... |
|
| 1811 |
+ */ |
|
| 1804 | 1812 |
if (tt) |
| 1805 | 1813 |
{
|
| 1806 | 1814 |
close_tun_generic (tt); |
| ... | ... |
@@ -1811,12 +2010,46 @@ close_tun (struct tuntap *tt) |
| 1811 | 1811 |
int |
| 1812 | 1812 |
write_tun (struct tuntap* tt, uint8_t *buf, int len) |
| 1813 | 1813 |
{
|
| 1814 |
+ if (tt->type == DEV_TYPE_TUN) |
|
| 1815 |
+ {
|
|
| 1816 |
+ u_int32_t type; |
|
| 1817 |
+ struct iovec iv[2]; |
|
| 1818 |
+ struct openvpn_iphdr *iph; |
|
| 1819 |
+ |
|
| 1820 |
+ iph = (struct openvpn_iphdr *) buf; |
|
| 1821 |
+ |
|
| 1822 |
+ if (tt->ipv6 && OPENVPN_IPH_GET_VER(iph->version_len) == 6) |
|
| 1823 |
+ type = htonl (AF_INET6); |
|
| 1824 |
+ else |
|
| 1825 |
+ type = htonl (AF_INET); |
|
| 1826 |
+ |
|
| 1827 |
+ iv[0].iov_base = (char *)&type; |
|
| 1828 |
+ iv[0].iov_len = sizeof (type); |
|
| 1829 |
+ iv[1].iov_base = buf; |
|
| 1830 |
+ iv[1].iov_len = len; |
|
| 1831 |
+ |
|
| 1832 |
+ return netbsd_modify_read_write_return (writev (tt->fd, iv, 2)); |
|
| 1833 |
+ } |
|
| 1834 |
+ else |
|
| 1814 | 1835 |
return write (tt->fd, buf, len); |
| 1815 | 1836 |
} |
| 1816 | 1837 |
|
| 1817 | 1838 |
int |
| 1818 | 1839 |
read_tun (struct tuntap* tt, uint8_t *buf, int len) |
| 1819 | 1840 |
{
|
| 1841 |
+ if (tt->type == DEV_TYPE_TUN) |
|
| 1842 |
+ {
|
|
| 1843 |
+ u_int32_t type; |
|
| 1844 |
+ struct iovec iv[2]; |
|
| 1845 |
+ |
|
| 1846 |
+ iv[0].iov_base = (char *)&type; |
|
| 1847 |
+ iv[0].iov_len = sizeof (type); |
|
| 1848 |
+ iv[1].iov_base = buf; |
|
| 1849 |
+ iv[1].iov_len = len; |
|
| 1850 |
+ |
|
| 1851 |
+ return netbsd_modify_read_write_return (readv (tt->fd, iv, 2)); |
|
| 1852 |
+ } |
|
| 1853 |
+ else |
|
| 1820 | 1854 |
return read (tt->fd, buf, len); |
| 1821 | 1855 |
} |
| 1822 | 1856 |
|
| ... | ... |
@@ -130,6 +130,7 @@ struct tuntap |
| 130 | 130 |
int topology; /* one of the TOP_x values */ |
| 131 | 131 |
|
| 132 | 132 |
bool did_ifconfig_setup; |
| 133 |
+ bool did_ifconfig_ipv6_setup; |
|
| 133 | 134 |
bool did_ifconfig; |
| 134 | 135 |
|
| 135 | 136 |
bool ipv6; |
| ... | ... |
@@ -146,6 +147,10 @@ struct tuntap |
| 146 | 146 |
in_addr_t remote_netmask; |
| 147 | 147 |
in_addr_t broadcast; |
| 148 | 148 |
|
| 149 |
+ struct in6_addr local_ipv6; |
|
| 150 |
+ struct in6_addr remote_ipv6; |
|
| 151 |
+ int netbits_ipv6; |
|
| 152 |
+ |
|
| 149 | 153 |
#ifdef WIN32 |
| 150 | 154 |
HANDLE hand; |
| 151 | 155 |
struct overlapped_io reads; |
| ... | ... |
@@ -219,6 +224,8 @@ struct tuntap *init_tun (const char *dev, /* --dev option */ |
| 219 | 219 |
int topology, /* one of the TOP_x values */ |
| 220 | 220 |
const char *ifconfig_local_parm, /* --ifconfig parm 1 */ |
| 221 | 221 |
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */ |
| 222 |
+ const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 / IPv6 */ |
|
| 223 |
+ const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 / IPv6 */ |
|
| 222 | 224 |
in_addr_t local_public, |
| 223 | 225 |
in_addr_t remote_public, |
| 224 | 226 |
const bool strict_warn, |