diff options
Diffstat (limited to 'src/openvpn')
-rw-r--r-- | src/openvpn/errlevel.h | 1 | ||||
-rw-r--r-- | src/openvpn/init.c | 14 | ||||
-rw-r--r-- | src/openvpn/manage.c | 30 | ||||
-rw-r--r-- | src/openvpn/networking_iproute2.c | 2 | ||||
-rw-r--r-- | src/openvpn/networking_sitnl.c | 44 | ||||
-rw-r--r-- | src/openvpn/openvpn.vcxproj | 4 | ||||
-rw-r--r-- | src/openvpn/options.c | 86 | ||||
-rw-r--r-- | src/openvpn/otime.h | 1 | ||||
-rw-r--r-- | src/openvpn/pool.c | 18 | ||||
-rw-r--r-- | src/openvpn/route.c | 62 | ||||
-rw-r--r-- | src/openvpn/socket.c | 71 | ||||
-rw-r--r-- | src/openvpn/socks.c | 9 | ||||
-rw-r--r-- | src/openvpn/ssl.c | 8 | ||||
-rw-r--r-- | src/openvpn/ssl_ncp.c | 18 | ||||
-rw-r--r-- | src/openvpn/ssl_verify.c | 177 | ||||
-rw-r--r-- | src/openvpn/tun.c | 233 |
16 files changed, 518 insertions, 260 deletions
diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h index e448fc3..5663f84 100644 --- a/src/openvpn/errlevel.h +++ b/src/openvpn/errlevel.h @@ -91,6 +91,7 @@ #define D_OSBUF LOGLEV(3, 43, 0) /* show socket/tun/tap buffer sizes */ #define D_PS_PROXY LOGLEV(3, 44, 0) /* messages related to --port-share option */ #define D_PF_INFO LOGLEV(3, 45, 0) /* packet filter informational messages */ +#define D_IFCONFIG LOGLEV(3, 0, 0) /* show ifconfig info (don't mute) */ #define D_SHOW_PARMS LOGLEV(4, 50, 0) /* show all parameters on program initiation */ #define D_SHOW_OCC LOGLEV(4, 51, 0) /* show options compatibility string */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index a785934..31ecadc 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -500,6 +500,17 @@ next_connection_entry(struct context *c) */ if (!c->options.persist_remote_ip) { + /* Connection entry addrinfo objects might have been + * resolved earlier but the entry itself might have been + * skipped by management on the previous loop. + * If so, clear the addrinfo objects as close_instance does + */ + if (c->c1.link_socket_addr.remote_list) + { + clear_remote_addrlist(&c->c1.link_socket_addr, + !c->options.resolve_in_advance); + } + /* close_instance should have cleared the addrinfo objects */ ASSERT(c->c1.link_socket_addr.current_remote == NULL); ASSERT(c->c1.link_socket_addr.remote_list == NULL); @@ -3635,7 +3646,8 @@ do_close_link_socket(struct context *c) && ( (c->options.persist_remote_ip) || ( c->sig->source != SIG_SOURCE_HARD - && ((c->c1.link_socket_addr.current_remote && c->c1.link_socket_addr.current_remote->ai_next) + && ((c->c1.link_socket_addr.current_remote + && c->c1.link_socket_addr.current_remote->ai_next) || c->options.no_advance)) ))) { diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 898cb3b..ac14217 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -3310,12 +3310,17 @@ man_block(struct management *man, volatile int *signal_received, const time_t ex if (man_standalone_ok(man)) { + /* expire time can be already overdue, for this case init zero + * timeout to avoid waiting first time and exit loop early with + * either obtained event or timeout. + */ + tv.tv_usec = 0; + tv.tv_sec = 0; + while (true) { event_reset(man->connection.es); management_socket_set(man, man->connection.es, NULL, NULL); - tv.tv_usec = 0; - tv.tv_sec = 1; if (man_check_for_signals(signal_received)) { status = -1; @@ -3343,6 +3348,10 @@ man_block(struct management *man, volatile int *signal_received, const time_t ex } break; } + + /* wait one second more */ + tv.tv_sec = 1; + tv.tv_usec = 0; } } return status; @@ -3444,7 +3453,7 @@ management_event_loop_n_seconds(struct management *man, int sec) /* set expire time */ update_time(); - if (sec) + if (sec >= 0) { expire = now + sec; } @@ -3474,7 +3483,7 @@ management_event_loop_n_seconds(struct management *man, int sec) /* revert state */ man->persist.standalone_disabled = standalone_disabled_save; } - else + else if (sec > 0) { sleep(sec); } @@ -4117,11 +4126,15 @@ log_history_ref(const struct log_history *h, const int index) void management_sleep(const int n) { - if (management) + if (n < 0) + { + return; + } + else if (management) { management_event_loop_n_seconds(management, n); } - else + else if (n > 0) { sleep(n); } @@ -4132,7 +4145,10 @@ management_sleep(const int n) void management_sleep(const int n) { - sleep(n); + if (n > 0) + { + sleep(n); + } } #endif /* ENABLE_MANAGEMENT */ diff --git a/src/openvpn/networking_iproute2.c b/src/openvpn/networking_iproute2.c index f3b9c61..3b46052 100644 --- a/src/openvpn/networking_iproute2.c +++ b/src/openvpn/networking_iproute2.c @@ -88,6 +88,8 @@ net_iface_mtu_set(openvpn_net_ctx_t *ctx, const char *iface, uint32_t mtu) argv_msg(M_INFO, &argv); openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link set failed"); + argv_free(&argv); + return 0; } diff --git a/src/openvpn/networking_sitnl.c b/src/openvpn/networking_sitnl.c index 713a213..2bc70a5 100644 --- a/src/openvpn/networking_sitnl.c +++ b/src/openvpn/networking_sitnl.c @@ -345,6 +345,13 @@ sitnl_send(struct nlmsghdr *payload, pid_t peer, unsigned int groups, * continue; * } */ + + if (h->nlmsg_type == NLMSG_DONE) + { + ret = 0; + goto out; + } + if (h->nlmsg_type == NLMSG_ERROR) { err = (struct nlmsgerr *)NLMSG_DATA(h); @@ -360,7 +367,11 @@ sitnl_send(struct nlmsghdr *payload, pid_t peer, unsigned int groups, ret = 0; if (cb) { - ret = cb(h, arg_cb); + int r = cb(h, arg_cb); + if (r <= 0) + { + ret = r; + } } } else @@ -375,8 +386,12 @@ sitnl_send(struct nlmsghdr *payload, pid_t peer, unsigned int groups, if (cb) { - ret = cb(h, arg_cb); - goto out; + int r = cb(h, arg_cb); + if (r <= 0) + { + ret = r; + goto out; + } } else { @@ -410,6 +425,7 @@ typedef struct { int addr_size; inet_address_t gw; char iface[IFNAMSIZ]; + bool default_only; } route_res_t; static int @@ -421,6 +437,12 @@ sitnl_route_save(struct nlmsghdr *n, void *arg) int len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)); unsigned int ifindex = 0; + /* filter-out non-zero dst prefixes */ + if (res->default_only && r->rtm_dst_len != 0) + { + return 1; + } + while (RTA_OK(rta, len)) { switch (rta->rta_type) @@ -477,11 +499,25 @@ sitnl_route_best_gw(sa_family_t af_family, const inet_address_t *dst, { case AF_INET: res.addr_size = sizeof(in_addr_t); - req.n.nlmsg_flags |= NLM_F_DUMP; + /* + * kernel can't return 0.0.0.0/8 host route, dump all + * the routes and filter for 0.0.0.0/0 in cb() + */ + if (!dst || !dst->ipv4) + { + req.n.nlmsg_flags |= NLM_F_DUMP; + res.default_only = true; + } + else + { + req.r.rtm_dst_len = 32; + } break; case AF_INET6: res.addr_size = sizeof(struct in6_addr); + /* kernel can return ::/128 host route */ + req.r.rtm_dst_len = 128; break; default: diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 5367979..3863854 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -92,7 +92,7 @@ </ClCompile> <ResourceCompile /> <Link> - <AdditionalDependencies>legacy_stdio_definitions.lib;Ncrypt.lib;libssl.lib;libcrypto.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>legacy_stdio_definitions.lib;Ncrypt.lib;libssl.lib;libcrypto.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <SubSystem>Console</SubSystem> </Link> @@ -122,7 +122,7 @@ </ClCompile> <ResourceCompile /> <Link> - <AdditionalDependencies>legacy_stdio_definitions.lib;Ncrypt.lib;libssl.lib;libcrypto.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalDependencies>legacy_stdio_definitions.lib;Ncrypt.lib;libssl.lib;libcrypto.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <SubSystem>Console</SubSystem> </Link> diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 8bf82c5..658ca53 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1983,7 +1983,8 @@ connection_entry_load_re(struct connection_entry *ce, const struct remote_entry } static void -options_postprocess_verify_ce(const struct options *options, const struct connection_entry *ce) +options_postprocess_verify_ce(const struct options *options, + const struct connection_entry *ce) { struct options defaults; int dev = DEV_TYPE_UNDEF; @@ -2011,7 +2012,9 @@ options_postprocess_verify_ce(const struct options *options, const struct connec */ if (ce->proto == PROTO_TCP) { - msg(M_USAGE, "--proto tcp is ambiguous in this context. Please specify --proto tcp-server or --proto tcp-client"); + msg(M_USAGE, + "--proto tcp is ambiguous in this context. Please specify " + "--proto tcp-server or --proto tcp-client"); } /* @@ -2051,8 +2054,9 @@ options_postprocess_verify_ce(const struct options *options, const struct connec if (options->inetd) { - msg(M_WARN, "DEPRECATED OPTION: --inetd mode is deprecated " - "and will be removed in OpenVPN 2.6"); + msg(M_WARN, + "DEPRECATED OPTION: --inetd mode is deprecated and will be removed " + "in OpenVPN 2.6"); } if (options->lladdr && dev != DEV_TYPE_TAP) @@ -2065,7 +2069,9 @@ options_postprocess_verify_ce(const struct options *options, const struct connec */ if (options->ce.tun_mtu_defined && options->ce.link_mtu_defined) { - msg(M_USAGE, "only one of --tun-mtu or --link-mtu may be defined (note that --ifconfig implies --link-mtu %d)", LINK_MTU_DEFAULT); + msg(M_USAGE, + "only one of --tun-mtu or --link-mtu may be defined (note that " + "--ifconfig implies --link-mtu %d)", LINK_MTU_DEFAULT); } if (!proto_is_udp(ce->proto) && options->mtu_test) @@ -2092,18 +2098,23 @@ options_postprocess_verify_ce(const struct options *options, const struct connec if (string_defined_equal(ce->remote, options->ifconfig_local) || string_defined_equal(ce->remote, options->ifconfig_remote_netmask)) { - msg(M_USAGE, "--local and --remote addresses must be distinct from --ifconfig addresses"); + msg(M_USAGE, + "--local and --remote addresses must be distinct from --ifconfig " + "addresses"); } if (string_defined_equal(ce->local, options->ifconfig_local) || string_defined_equal(ce->local, options->ifconfig_remote_netmask)) { - msg(M_USAGE, "--local addresses must be distinct from --ifconfig addresses"); + msg(M_USAGE, + "--local addresses must be distinct from --ifconfig addresses"); } - if (string_defined_equal(options->ifconfig_local, options->ifconfig_remote_netmask)) + if (string_defined_equal(options->ifconfig_local, + options->ifconfig_remote_netmask)) { - msg(M_USAGE, "local and remote/netmask --ifconfig addresses must be different"); + msg(M_USAGE, + "local and remote/netmask --ifconfig addresses must be different"); } if (ce->bind_defined && !ce->bind_local) @@ -2113,12 +2124,14 @@ options_postprocess_verify_ce(const struct options *options, const struct connec if (ce->local && !ce->bind_local) { - msg(M_USAGE, "--local and --nobind don't make sense when used together"); + msg(M_USAGE, + "--local and --nobind don't make sense when used together"); } if (ce->local_port_defined && !ce->bind_local) { - msg(M_USAGE, "--lport and --nobind don't make sense when used together"); + msg(M_USAGE, + "--lport and --nobind don't make sense when used together"); } if (!ce->remote && !ce->bind_local) @@ -2181,10 +2194,11 @@ options_postprocess_verify_ce(const struct options *options, const struct connec } if (options->tuntap_options.dhcp_options + && options->windows_driver != WINDOWS_DRIVER_WINTUN && options->tuntap_options.ip_win32_type != IPW32_SET_DHCP_MASQ && options->tuntap_options.ip_win32_type != IPW32_SET_ADAPTIVE) { - msg(M_USAGE, "--dhcp-options requires --ip-win32 dynamic or adaptive"); + msg(M_USAGE, "--dhcp-option requires --ip-win32 dynamic or adaptive"); } if (options->windows_driver == WINDOWS_DRIVER_WINTUN && dev != DEV_TYPE_TUN) @@ -2206,7 +2220,8 @@ options_postprocess_verify_ce(const struct options *options, const struct connec if (!proto_is_udp(ce->proto) && ce->explicit_exit_notification) { - msg(M_USAGE, "--explicit-exit-notify can only be used with --proto udp"); + msg(M_USAGE, + "--explicit-exit-notify can only be used with --proto udp"); } if (!ce->remote && ce->proto == PROTO_TCP_CLIENT) @@ -2216,16 +2231,21 @@ options_postprocess_verify_ce(const struct options *options, const struct connec if ((ce->http_proxy_options) && ce->proto != PROTO_TCP_CLIENT) { - msg(M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)"); + msg(M_USAGE, + "--http-proxy MUST be used in TCP Client mode (i.e. --proto " + "tcp-client)"); } + if ((ce->http_proxy_options) && !ce->http_proxy_options->server) { - msg(M_USAGE, "--http-proxy not specified but other http proxy options present"); + msg(M_USAGE, + "--http-proxy not specified but other http proxy options present"); } if (ce->http_proxy_options && ce->socks_proxy_server) { - msg(M_USAGE, "--http-proxy can not be used together with --socks-proxy"); + msg(M_USAGE, + "--http-proxy can not be used together with --socks-proxy"); } if (ce->socks_proxy_server && ce->proto == PROTO_TCP_SERVER) @@ -2291,8 +2311,9 @@ options_postprocess_verify_ce(const struct options *options, const struct connec { msg(M_USAGE, "--socks-proxy cannot be used with --mode server"); } - /* <connection> blocks force to have a remote embedded, so we check for the - * --remote and bail out if it is present */ + /* <connection> blocks force to have a remote embedded, so we check + * for the --remote and bail out if it is present + */ if (options->connection_list->len >1 || options->connection_list->array[0]->remote) { @@ -2309,12 +2330,15 @@ options_postprocess_verify_ce(const struct options *options, const struct connec } if (options->ipchange) { - msg(M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)"); + msg(M_USAGE, + "--ipchange cannot be used with --mode server (use " + "--client-connect instead)"); } if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCP_SERVER)) { - msg(M_USAGE, "--mode server currently only supports " - "--proto udp or --proto tcp-server or --proto tcp6-server"); + msg(M_USAGE, + "--mode server currently only supports --proto udp or --proto " + "tcp-server or --proto tcp6-server"); } if (!proto_is_udp(ce->proto) && (options->cf_max || options->cf_per)) { @@ -2816,12 +2840,14 @@ options_postprocess_mutate_ce(struct options *o, struct connection_entry *ce) } #endif - if (ce->proto == PROTO_TCP_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined) + if (ce->proto == PROTO_TCP_CLIENT && !ce->local + && !ce->local_port_defined && !ce->bind_defined) { ce->bind_local = false; } - if (ce->proto == PROTO_UDP && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined) + if (ce->proto == PROTO_UDP && ce->socks_proxy_server && !ce->local + && !ce->local_port_defined && !ce->bind_defined) { ce->bind_local = false; } @@ -2831,7 +2857,9 @@ options_postprocess_mutate_ce(struct options *o, struct connection_entry *ce) ce->local_port = NULL; } - /* if protocol forcing is enabled, disable all protocols except for the forced one */ + /* if protocol forcing is enabled, disable all protocols + * except for the forced one + */ if (o->proto_force >= 0 && o->proto_force != ce->proto) { ce->flags |= CE_DISABLED; @@ -5689,7 +5717,9 @@ add_option(struct options *options, const sa_family_t af = ascii2af(p[3]); if (proto < 0) { - msg(msglevel, "remote: bad protocol associated with host %s: '%s'", p[1], p[3]); + msg(msglevel, + "remote: bad protocol associated with host %s: '%s'", + p[1], p[3]); goto err; } re.proto = proto; @@ -6209,7 +6239,8 @@ add_option(struct options *options, af = ascii2af(p[1]); if (proto < 0) { - msg(msglevel, "Bad protocol: '%s'. Allowed protocols with --proto option: %s", + msg(msglevel, + "Bad protocol: '%s'. Allowed protocols with --proto option: %s", p[1], proto2ascii_all(&gc)); goto err; @@ -7439,7 +7470,8 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_IPWIN32); bool ipv6dns = false; - if (streq(p[1], "DOMAIN") && p[2]) + if ((streq(p[1], "DOMAIN") || streq(p[1], "ADAPTER_DOMAIN_SUFFIX")) + && p[2]) { o->domain = p[2]; } diff --git a/src/openvpn/otime.h b/src/openvpn/otime.h index a6f7ec2..78d20ba 100644 --- a/src/openvpn/otime.h +++ b/src/openvpn/otime.h @@ -84,6 +84,7 @@ update_time(void) openvpn_gettimeofday(&tv, NULL); #else update_now(time(NULL)); + now_usec = 0; #endif } diff --git a/src/openvpn/pool.c b/src/openvpn/pool.c index 1f74ac5..ece0784 100644 --- a/src/openvpn/pool.c +++ b/src/openvpn/pool.c @@ -224,6 +224,24 @@ ifconfig_pool_init(const bool ipv4_pool, enum pool_type type, in_addr_t start, } pool->ipv6.base = ipv6_base; + + /* if a pool starts at a base address that has all-zero in the + * host part, that first IPv6 address must not be assigned to + * clients because it is not usable (subnet anycast address). + * Start with 1, then. + * + * NOTE: this will also (mis-)fire for something like + * ifconfig-ipv6-pool 2001:db8:0:1:1234::0/64 + * as we only check the rightmost 32 bits of the host part. So be it. + */ + if (base == 0) + { + msg(D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: incrementing pool start " + "to avoid ::0 assignment"); + base++; + pool->ipv6.base.s6_addr[15]++; + } + pool_ipv6_size = ipv6_netbits >= 112 ? (1 << (128 - ipv6_netbits)) - base : IFCONFIG_POOL_MAX; diff --git a/src/openvpn/route.c b/src/openvpn/route.c index f127a90..5e1dca6 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -49,6 +49,10 @@ #include <linux/rtnetlink.h> /* RTM_GETROUTE etc. */ #endif +#if defined(TARGET_NETBSD) +#include <net/route.h> /* RT_ROUNDUP(), RT_ADVANCE() */ +#endif + #ifdef _WIN32 #include "openvpn-msg.h" @@ -323,6 +327,10 @@ init_route(struct route_ipv4 *r, if (get_special_addr(rl, ro->network, (in_addr_t *) &special.s_addr, &status)) { + if (!status) + { + goto fail; + } special.s_addr = htonl(special.s_addr); ret = openvpn_getaddrinfo(0, inet_ntoa(special), NULL, 0, NULL, AF_INET, network_list); @@ -619,7 +627,7 @@ init_route_list(struct route_list *rl, rl->flags = opt->flags; - if (remote_host) + if (remote_host != IPV4_INVALID_ADDR) { rl->spec.remote_host = remote_host; rl->spec.flags |= RTSA_REMOTE_HOST; @@ -1003,14 +1011,10 @@ redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *tt, * - we are connecting to a non-IPv4 remote host (i.e. we use IPv6) */ else if (!(rl->rgi.flags & RGI_ADDR_DEFINED) && !local - && (rl->spec.remote_host != IPV4_INVALID_ADDR)) + && (rl->spec.flags & RTSA_REMOTE_HOST)) { msg(M_WARN, "%s Cannot read current default gateway from system", err); } - else if (!(rl->spec.flags & RTSA_REMOTE_HOST)) - { - msg(M_WARN, "%s Cannot obtain current remote host address", err); - } else { #ifndef TARGET_ANDROID @@ -1033,7 +1037,8 @@ redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *tt, /* route remote host to original default gateway */ /* if remote_host is not ipv4 (ie: ipv6), just skip * adding this special /32 route */ - if (rl->spec.remote_host != IPV4_INVALID_ADDR) + if ((rl->spec.flags & RTSA_REMOTE_HOST) + && rl->spec.remote_host != IPV4_INVALID_ADDR) { add_route3(rl->spec.remote_host, IPV4_NETMASK_HOST, @@ -1471,6 +1476,13 @@ setenv_route_ipv6(struct env_set *es, const struct route_ipv6 *r6, int i) buf_printf( &name2, "route_ipv6_gateway_%d", i ); setenv_str( es, BSTR(&name2), print_in6_addr( r6->gateway, 0, &gc )); + + if (r6->flags & RT_METRIC_DEFINED) + { + struct buffer name3 = alloc_buf_gc( 256, &gc ); + buf_printf( &name3, "route_ipv6_metric_%d", i) ; + setenv_int( es, BSTR(&name3), r6->metric); + } } gc_free(&gc); } @@ -1979,25 +1991,24 @@ add_route_ipv6(struct route_ipv6 *r6, const struct tuntap *tt, } else { - struct buffer out = alloc_buf_gc(64, &gc); + DWORD adapter_index; if (r6->adapter_index) /* vpn server special route */ { - buf_printf(&out, "interface=%lu", r6->adapter_index ); + adapter_index = r6->adapter_index; gateway_needed = true; } else { - buf_printf(&out, "interface=%lu", tt->adapter_index ); + adapter_index = tt->adapter_index; } - device = buf_bptr(&out); - /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */ - argv_printf(&argv, "%s%s interface ipv6 add route %s/%d %s", + /* netsh interface ipv6 add route 2001:db8::/32 42 */ + argv_printf(&argv, "%s%s interface ipv6 add route %s/%d %lu", get_win_sys_path(), NETSH_PATH_SUFFIX, network, r6->netbits, - device); + adapter_index); /* next-hop depends on TUN or TAP mode: * - in TAP mode, we use the "real" next-hop @@ -2423,25 +2434,24 @@ delete_route_ipv6(const struct route_ipv6 *r6, const struct tuntap *tt, } else { - struct buffer out = alloc_buf_gc(64, &gc); + DWORD adapter_index; if (r6->adapter_index) /* vpn server special route */ { - buf_printf(&out, "interface=%lu", r6->adapter_index ); + adapter_index = r6->adapter_index; gateway_needed = true; } else { - buf_printf(&out, "interface=%lu", tt->adapter_index ); + adapter_index = tt->adapter_index; } - device = buf_bptr(&out); - /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */ - argv_printf(&argv, "%s%s interface ipv6 delete route %s/%d %s", + /* netsh interface ipv6 delete route 2001:db8::/32 42 */ + argv_printf(&argv, "%s%s interface ipv6 delete route %s/%d %lu", get_win_sys_path(), NETSH_PATH_SUFFIX, network, r6->netbits, - device); + adapter_index); /* next-hop depends on TUN or TAP mode: * - in TAP mode, we use the "real" next-hop @@ -3408,11 +3418,15 @@ struct rtmsg { /* the route socket code is identical for all 4 supported BSDs and for * MacOS X (Darwin), with one crucial difference: when going from - * 32 bit to 64 bit, the BSDs increased the structure size but kept + * 32 bit to 64 bit, FreeBSD/OpenBSD increased the structure size but kept * source code compatibility by keeping the use of "long", while * MacOS X decided to keep binary compatibility by *changing* the API * to use "uint32_t", thus 32 bit on all OS X variants * + * NetBSD does the MacOS way of "fixed number of bits, no matter if + * 32 or 64 bit OS", but chose uint64_t. For maximum portability, we + * just use the OS RT_ROUNDUP() macro, which is guaranteed to be correct. + * * We used to have a large amount of duplicate code here which really * differed only in this (long) vs. (uint32_t) - IMHO, worse than * having a combined block for all BSDs with this single #ifdef inside @@ -3421,6 +3435,8 @@ struct rtmsg { #if defined(TARGET_DARWIN) #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t)) +#elif defined(TARGET_NETBSD) +#define ROUNDUP(a) RT_ROUNDUP(a) #else #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) @@ -3729,7 +3745,7 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, } if (write(sockfd, (char *)&m_rtmsg, l) < 0) { - msg(M_WARN, "GDG6: problem writing to routing socket"); + msg(M_WARN|M_ERRNO, "GDG6: problem writing to routing socket"); goto done; } diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index c486327..9775068 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -378,7 +378,8 @@ do_preresolve(struct context *c) /* HTTP remote hostname does not need to be resolved */ if (!ce->http_proxy_options) { - status = do_preresolve_host(c, remote, ce->remote_port, ce->af, flags); + status = do_preresolve_host(c, remote, ce->remote_port, + ce->af, flags); if (status != 0) { goto err; @@ -417,7 +418,8 @@ do_preresolve(struct context *c) { flags |= GETADDR_PASSIVE; flags &= ~GETADDR_RANDOMIZE; - status = do_preresolve_host(c, ce->local, ce->local_port, ce->af, flags); + status = do_preresolve_host(c, ce->local, ce->local_port, + ce->af, flags); if (status != 0) { goto err; @@ -526,7 +528,9 @@ openvpn_getaddrinfo(unsigned int flags, if ((flags & GETADDR_MENTION_RESOLVE_RETRY) && !resolve_retry_seconds) { - fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) (I would have retried this name query if you had specified the --resolv-retry option.)"; + fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) " + "(I would have retried this name query if you had " + "specified the --resolv-retry option.)"; } if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL) @@ -558,11 +562,13 @@ openvpn_getaddrinfo(unsigned int flags, while (true) { #ifndef _WIN32 + /* force resolv.conf reload */ res_init(); #endif /* try hostname lookup */ hints.ai_flags &= ~AI_NUMERICHOST; - dmsg(D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d", + dmsg(D_SOCKET_DEBUG, + "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d", flags, hints.ai_family, hints.ai_socktype); status = getaddrinfo(hostname, servname, &hints, res); @@ -573,7 +579,9 @@ openvpn_getaddrinfo(unsigned int flags, { if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ { - msg(level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); + msg(level, + "RESOLVE: Ignored SIGUSR1 signal received during " + "DNS resolution attempt"); *signal_received = 0; } else @@ -634,7 +642,9 @@ openvpn_getaddrinfo(unsigned int flags, /* IP address parse succeeded */ if (flags & GETADDR_RANDOMIZE) { - msg(M_WARN, "WARNING: ignoring --remote-random-hostname because the hostname is an IP address"); + msg(M_WARN, + "WARNING: ignoring --remote-random-hostname because the " + "hostname is an IP address"); } } @@ -1141,8 +1151,8 @@ create_socket(struct link_socket *sock, struct addrinfo *addr) #if defined(TARGET_LINUX) if (sock->bind_dev) { - msg (M_INFO, "Using bind-dev %s", sock->bind_dev); - if (setsockopt (sock->sd, SOL_SOCKET, SO_BINDTODEVICE, sock->bind_dev, strlen (sock->bind_dev) + 1) != 0) + msg(M_INFO, "Using bind-dev %s", sock->bind_dev); + if (setsockopt(sock->sd, SOL_SOCKET, SO_BINDTODEVICE, sock->bind_dev, strlen(sock->bind_dev) + 1) != 0) { msg(M_WARN|M_ERRNO, "WARN: setsockopt SO_BINDTODEVICE=%s failed", sock->bind_dev); } @@ -1470,14 +1480,14 @@ openvpn_connect(socket_descriptor_t sd, struct pollfd fds[1]; fds[0].fd = sd; fds[0].events = POLLOUT; - status = poll(fds, 1, 0); + status = poll(fds, 1, (connect_timeout > 0) ? 1000 : 0); #else fd_set writes; struct timeval tv; FD_ZERO(&writes); openvpn_fd_set(sd, &writes); - tv.tv_sec = 0; + tv.tv_sec = (connect_timeout > 0) ? 1 : 0; tv.tv_usec = 0; status = select(sd + 1, NULL, &writes, NULL, &tv); @@ -1507,7 +1517,7 @@ openvpn_connect(socket_descriptor_t sd, #endif break; } - management_sleep(1); + management_sleep(0); continue; } @@ -1802,7 +1812,8 @@ resolve_remote(struct link_socket *sock, sock->info.lsa->remote_list = ai; sock->info.lsa->current_remote = ai; - dmsg(D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", + dmsg(D_SOCKET_DEBUG, + "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", flags, phase, retry, @@ -2030,8 +2041,14 @@ phase2_inetd(struct link_socket *sock, const struct frame *frame, } else { - msg(M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", + int saved_errno = errno; + msg(M_WARN|M_ERRNO, "inetd(%s): getsockname(%d) failed, using AF_INET", proto2ascii(sock->info.proto, sock->info.af, false), (int)sock->sd); + /* if not called with a socket on stdin, --inetd cannot work */ + if (saved_errno == ENOTSOCK) + { + msg(M_FATAL, "ERROR: socket required for --inetd operation"); + } } } #else /* ifdef HAVE_GETSOCKNAME */ @@ -2047,7 +2064,6 @@ phase2_inetd(struct link_socket *sock, const struct frame *frame, false, sock->inetd == INETD_NOWAIT, signal_received); - } ASSERT(!remote_changed); } @@ -3150,22 +3166,22 @@ struct proto_names { /* Indexed by PROTO_x */ static const struct proto_names proto_names[] = { - {"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE}, + {"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE}, /* try IPv4 and IPv6 (client), bind dual-stack (server) */ - {"udp", "UDP", AF_UNSPEC, PROTO_UDP}, - {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER}, - {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT}, - {"tcp", "TCP", AF_UNSPEC, PROTO_TCP}, + {"udp", "UDP", AF_UNSPEC, PROTO_UDP}, + {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER}, + {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT}, + {"tcp", "TCP", AF_UNSPEC, PROTO_TCP}, /* force IPv4 */ - {"udp4", "UDPv4", AF_INET, PROTO_UDP}, - {"tcp4-server","TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER}, - {"tcp4-client","TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT}, - {"tcp4", "TCPv4", AF_INET, PROTO_TCP}, + {"udp4", "UDPv4", AF_INET, PROTO_UDP}, + {"tcp4-server", "TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER}, + {"tcp4-client", "TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT}, + {"tcp4", "TCPv4", AF_INET, PROTO_TCP}, /* force IPv6 */ - {"udp6","UDPv6", AF_INET6, PROTO_UDP}, - {"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER}, - {"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT}, - {"tcp6","TCPv6", AF_INET6, PROTO_TCP}, + {"udp6", "UDPv6", AF_INET6, PROTO_UDP}, + {"tcp6-server", "TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER}, + {"tcp6-client", "TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT}, + {"tcp6", "TCPv6", AF_INET6, PROTO_TCP}, }; bool @@ -3177,6 +3193,7 @@ proto_is_net(int proto) } return proto != PROTO_NONE; } + bool proto_is_dgram(int proto) { diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c index 57f0cee..36df747 100644 --- a/src/openvpn/socks.c +++ b/src/openvpn/socks.c @@ -312,7 +312,7 @@ recv_socks_reply(socket_descriptor_t sd, char atyp = '\0'; int alen = 0; int len = 0; - char buf[22]; + char buf[270]; /* 4 + alen(max 256) + 2 */ const int timeout_sec = 5; if (addr != NULL) @@ -381,7 +381,10 @@ recv_socks_reply(socket_descriptor_t sd, break; case '\x03': /* DOMAINNAME */ - alen = (unsigned char) c; + /* RFC 1928, section 5: 1 byte length, <n> bytes name, + * so the total "address length" is (length+1) + */ + alen = (unsigned char) c + 1; break; case '\x04': /* IP V6 */ @@ -451,7 +454,7 @@ establish_socks_proxy_passthru(struct socks_proxy_info *p, const char *servname, /* openvpn server port */ volatile int *signal_received) { - char buf[128]; + char buf[270]; size_t len; if (!socks_handshake(p, sd, signal_received)) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index f16114c..c6ba812 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2484,6 +2484,14 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio multi->remote_ciphername = options_string_extract_option(options, "cipher", NULL); + /* In OCC we send '[null-cipher]' instead 'none' */ + if (multi->remote_ciphername + && strcmp(multi->remote_ciphername, "[null-cipher]") == 0) + { + free(multi->remote_ciphername); + multi->remote_ciphername = string_alloc("none", NULL); + } + if (tls_session_user_pass_enabled(session)) { /* Perform username/password authentication */ diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c index 5549639..45bddbe 100644 --- a/src/openvpn/ssl_ncp.c +++ b/src/openvpn/ssl_ncp.c @@ -110,7 +110,15 @@ mutate_ncp_cipher_list(const char *list, struct gc_arena *gc) * e.g. replacing AeS-128-gCm with AES-128-GCM */ const cipher_kt_t *ktc = cipher_kt_get(token); - if (!ktc) + if (strcmp(token, "none") == 0) + { + msg(M_WARN, "WARNING: cipher 'none' specified for --data-ciphers. " + "This allows negotiation of NO encryption and " + "tunnelled data WILL then be transmitted in clear text " + "over the network! " + "PLEASE DO RECONSIDER THIS SETTING!"); + } + if (!ktc && strcmp(token, "none") != 0) { msg(M_WARN, "Unsupported cipher in --data-ciphers: %s", token); error_found = true; @@ -118,6 +126,12 @@ mutate_ncp_cipher_list(const char *list, struct gc_arena *gc) else { const char *ovpn_cipher_name = cipher_kt_name(ktc); + if (ktc == NULL) + { + /* NULL resolves to [null-cipher] but we need none for + * data-ciphers */ + ovpn_cipher_name = "none"; + } if (buf_len(&new_list)> 0) { @@ -325,4 +339,4 @@ check_pull_client_ncp(struct context *c, const int found) "to this server."); return false; } -}
\ No newline at end of file +} diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 97ccb93..33115eb 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -1068,69 +1068,51 @@ verify_user_pass_script(struct tls_session *session, struct tls_multi *multi, const char *tmp_file = ""; bool ret = false; - /* Is username defined? */ - if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen(up->username)) + /* Set environmental variables prior to calling script */ + setenv_str(session->opt->es, "script_type", "user-pass-verify"); + + /* format command line */ + argv_parse_cmd(&argv, session->opt->auth_user_pass_verify_script); + + if (session->opt->auth_user_pass_verify_script_via_file) { - /* Set environmental variables prior to calling script */ - setenv_str(session->opt->es, "script_type", "user-pass-verify"); + struct status_output *so; - if (session->opt->auth_user_pass_verify_script_via_file) + tmp_file = platform_create_temp_file(session->opt->tmp_dir, "up", + &gc); + if (tmp_file) { - struct status_output *so; - - tmp_file = platform_create_temp_file(session->opt->tmp_dir, "up", - &gc); - if (tmp_file) - { - so = status_open(tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE); - status_printf(so, "%s", up->username); - status_printf(so, "%s", up->password); - if (!status_close(so)) - { - msg(D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s", - tmp_file); - goto done; - } - } - else + so = status_open(tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE); + status_printf(so, "%s", up->username); + status_printf(so, "%s", up->password); + if (!status_close(so)) { - msg(D_TLS_ERRORS, "TLS Auth Error: could not create write " - "username/password to temp file"); + msg(D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s", + tmp_file); + goto done; } + /* pass temp file name to script */ + argv_printf_cat(&argv, "%s", tmp_file); } else { - setenv_str(session->opt->es, "username", up->username); - setenv_str(session->opt->es, "password", up->password); - } - - /* setenv incoming cert common name for script */ - setenv_str(session->opt->es, "common_name", session->common_name); - - /* setenv client real IP address */ - setenv_untrusted(session); - - /* add auth-token environment */ - add_session_token_env(session, multi, up); - - /* format command line */ - argv_parse_cmd(&argv, session->opt->auth_user_pass_verify_script); - argv_printf_cat(&argv, "%s", tmp_file); - - /* call command */ - ret = openvpn_run_script(&argv, session->opt->es, 0, - "--auth-user-pass-verify"); - - if (!session->opt->auth_user_pass_verify_script_via_file) - { - setenv_del(session->opt->es, "password"); + msg(D_TLS_ERRORS, "TLS Auth Error: could not create write " + "username/password to temp file"); } } else { - msg(D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username"); + setenv_str(session->opt->es, "password", up->password); } + /* call command */ + ret = openvpn_run_script(&argv, session->opt->es, 0, + "--auth-user-pass-verify"); + + if (!session->opt->auth_user_pass_verify_script_via_file) + { + setenv_del(session->opt->es, "password"); + } done: if (tmp_file && strlen(tmp_file) > 0) { @@ -1154,48 +1136,31 @@ verify_user_pass_plugin(struct tls_session *session, struct tls_multi *multi, struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ #endif - /* Is username defined? */ - if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen(up->username)) - { - /* set username/password in private env space */ - setenv_str(session->opt->es, "username", up->username); - setenv_str(session->opt->es, "password", up->password); - - /* setenv incoming cert common name for script */ - setenv_str(session->opt->es, "common_name", session->common_name); + /* set password in private env space */ + setenv_str(session->opt->es, "password", up->password); - /* setenv client real IP address */ - setenv_untrusted(session); - - /* add auth-token environment */ - add_session_token_env(session, multi, up); #ifdef PLUGIN_DEF_AUTH - /* generate filename for deferred auth control file */ - if (!key_state_gen_auth_control_file(ks, session->opt)) - { - msg(D_TLS_ERRORS, "TLS Auth Error (%s): " - "could not create deferred auth control file", __func__); - return retval; - } + /* generate filename for deferred auth control file */ + if (!key_state_gen_auth_control_file(ks, session->opt)) + { + msg(D_TLS_ERRORS, "TLS Auth Error (%s): " + "could not create deferred auth control file", __func__); + return retval; + } #endif - /* call command */ - retval = plugin_call(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es); + /* call command */ + retval = plugin_call(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es); #ifdef PLUGIN_DEF_AUTH - /* purge auth control filename (and file itself) for non-deferred returns */ - if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED) - { - key_state_rm_auth_control_file(ks); - } -#endif - - setenv_del(session->opt->es, "password"); - } - else + /* purge auth control filename (and file itself) for non-deferred returns */ + if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED) { - msg(D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_plugin): peer provided a blank username"); + key_state_rm_auth_control_file(ks); } +#endif + + setenv_del(session->opt->es, "password"); return retval; } @@ -1218,12 +1183,30 @@ verify_user_pass_management(struct tls_session *session, int retval = KMDA_ERROR; struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + /* set username/password in private env space */ + setenv_str(session->opt->es, "password", up->password); + + if (management) + { + management_notify_client_needing_auth(management, ks->mda_key_id, session->opt->mda_context, session->opt->es); + } + + setenv_del(session->opt->es, "password"); + + retval = KMDA_SUCCESS; + + return retval; +} +#endif /* ifdef MANAGEMENT_DEF_AUTH */ + +static bool +set_verify_user_pass_env(struct user_pass *up, struct tls_multi *multi, + struct tls_session *session) +{ /* Is username defined? */ if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen(up->username)) { - /* set username/password in private env space */ setenv_str(session->opt->es, "username", up->username); - setenv_str(session->opt->es, "password", up->password); /* setenv incoming cert common name for script */ setenv_str(session->opt->es, "common_name", session->common_name); @@ -1236,24 +1219,14 @@ verify_user_pass_management(struct tls_session *session, * allow the management to figure out if it is a new session or a continued one */ add_session_token_env(session, multi, up); - if (management) - { - management_notify_client_needing_auth(management, ks->mda_key_id, session->opt->mda_context, session->opt->es); - } - - setenv_del(session->opt->es, "password"); - - retval = KMDA_SUCCESS; + return true; } else { - msg(D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_management): peer provided a blank username"); + msg(D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username"); + return false; } - - return retval; } -#endif /* ifdef MANAGEMENT_DEF_AUTH */ - /* * Main username/password verification entry point @@ -1325,6 +1298,14 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, return; } } + + /* Set the environment variables used by all auth variants */ + if (!set_verify_user_pass_env(up, multi, session)) + { + skip_auth = true; + s1 = OPENVPN_PLUGIN_FUNC_ERROR; + } + /* call plugin(s) and/or script */ if (!skip_auth) { diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 923131a..8315a42 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -68,7 +68,7 @@ const static GUID GUID_DEVINTERFACE_NET = { 0xcac88484, 0x7515, 0x4c03, { 0x82, #define NI_OPTIONS (1<<2) static void netsh_ifconfig(const struct tuntap_options *to, - const char *flex_name, + DWORD adapter_index, const in_addr_t ip, const in_addr_t netmask, const unsigned int flags); @@ -79,7 +79,7 @@ static void windows_set_mtu(const int iface_index, static void netsh_set_dns6_servers(const struct in6_addr *addr_list, const int addr_len, - const char *flex_name); + DWORD adapter_index); static void netsh_command(const struct argv *a, int n, int msglevel); @@ -115,11 +115,17 @@ do_address_service(const bool add, const short family, const struct tuntap *tt) { addr.address.ipv4.s_addr = htonl(tt->local); addr.prefix_len = netmask_to_netbits2(tt->adapter_netmask); + msg(D_IFCONFIG, "INET address service: %s %s/%d", + add ? "add" : "remove", + print_in_addr_t(tt->local, 0, &gc), addr.prefix_len); } else { addr.address.ipv6 = tt->local_ipv6; - addr.prefix_len = tt->netbits_ipv6; + addr.prefix_len = (tt->type == DEV_TYPE_TUN) ? 128 : tt->netbits_ipv6; + msg(D_IFCONFIG, "INET6 address service: %s %s/%d", + add ? "add" : "remove", + print_in6_addr(tt->local_ipv6, 0, &gc), addr.prefix_len); } if (!send_msg_iservice(pipe, &addr, sizeof(addr), &ack, "TUN")) @@ -143,6 +149,61 @@ out: } static bool +do_dns_domain_service(bool add, const struct tuntap *tt) +{ + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new(); + HANDLE pipe = tt->options.msg_channel; + + if (!tt->options.domain) /* no domain to add or delete */ + { + return true; + } + + /* Use dns_cfg_msg with addr_len = 0 for setting only the DOMAIN */ + dns_cfg_message_t dns = { + .header = { + (add ? msg_add_dns_cfg : msg_del_dns_cfg), + sizeof(dns_cfg_message_t), + 0 + }, + .iface = { .index = tt->adapter_index, .name = "" }, + .domains = "", /* set below */ + .family = AF_INET, /* unused */ + .addr_len = 0 /* add/delete only the domain, not DNS servers */ + }; + + strncpynt(dns.iface.name, tt->actual_name, sizeof(dns.iface.name)); + strncpynt(dns.domains, tt->options.domain, sizeof(dns.domains)); + /* truncation of domain name is not checked as it can't happen + * with 512 bytes room in dns.domains. + */ + + msg(D_LOW, "%s dns domain on '%s' (if_index = %d) using service", + (add ? "Setting" : "Deleting"), dns.iface.name, dns.iface.index); + if (!send_msg_iservice(pipe, &dns, sizeof(dns), &ack, "TUN")) + { + goto out; + } + + if (ack.error_number != NO_ERROR) + { + msg(M_WARN, "TUN: %s dns domain failed using service: %s [status=%u if_name=%s]", + (add ? "adding" : "deleting"), strerror_win32(ack.error_number, &gc), + ack.error_number, dns.iface.name); + goto out; + } + + msg(M_INFO, "DNS domain %s using service", (add ? "set" : "deleted")); + ret = true; + +out: + gc_free(&gc); + return ret; +} + +static bool do_dns_service(bool add, const short family, const struct tuntap *tt) { bool ret = false; @@ -158,6 +219,7 @@ do_dns_service(bool add, const short family, const struct tuntap *tt) return true; } + /* Use dns_cfg_msg with domain = "" for setting only the DNS servers */ dns_cfg_message_t dns = { .header = { (add ? msg_add_dns_cfg : msg_del_dns_cfg), @@ -1088,26 +1150,40 @@ do_ifconfig_ipv6(struct tuntap *tt, const char *ifname, int tun_mtu, else if (tt->options.msg_channel) { do_address_service(true, AF_INET6, tt); - add_route_connected_v6_net(tt, es); + if (tt->type == DEV_TYPE_TUN) + { + add_route_connected_v6_net(tt, es); + } do_dns_service(true, AF_INET6, tt); do_set_mtu_service(tt, AF_INET6, tun_mtu); + /* If IPv4 is not enabled, set DNS domain here */ + if (!tt->did_ifconfig_setup) + { + do_dns_domain_service(true, tt); + } } else { - /* example: netsh interface ipv6 set address interface=42 - * 2001:608:8003::d store=active + /* example: netsh interface ipv6 set address 42 + * 2001:608:8003::d/bits store=active + */ + + /* in TUN mode, we only simulate a subnet, so the interface + * is configured with /128 + a route to fe80::8. In TAP mode, + * the correct netbits must be set, and no on-link route */ - char iface[64]; + int netbits = (tt->type == DEV_TYPE_TUN) ? 128 : tt->netbits_ipv6; - openvpn_snprintf(iface, sizeof(iface), "interface=%lu", - tt->adapter_index); - argv_printf(&argv, "%s%s interface ipv6 set address %s %s store=active", - get_win_sys_path(), NETSH_PATH_SUFFIX, iface, - ifconfig_ipv6_local); + argv_printf(&argv, "%s%s interface ipv6 set address %lu %s/%d store=active", + get_win_sys_path(), NETSH_PATH_SUFFIX, tt->adapter_index, + ifconfig_ipv6_local, netbits); netsh_command(&argv, 4, M_FATAL); - add_route_connected_v6_net(tt, es); + if (tt->type == DEV_TYPE_TUN) + { + add_route_connected_v6_net(tt, es); + } /* set ipv6 dns servers if any are specified */ - netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, ifname); + netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, tt->adapter_index); windows_set_mtu(tt->adapter_index, AF_INET6, tun_mtu); } #else /* platforms we have no IPv6 code for */ @@ -1224,7 +1300,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, argv_printf(&argv, "%s %s netmask 255.255.255.255", IFCONFIG_PATH, ifname); } - else if (tt->topology == TOP_SUBNET) + else if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up", IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_local, @@ -1243,7 +1319,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, solaris_error_close(tt, es, ifname, false); } - if (!tun && tt->topology == TOP_SUBNET) + if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { /* Add a network route for the local tun interface */ struct route_ipv4 r; @@ -1274,7 +1350,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_remote_netmask, tun_mtu); } - else if (tt->topology == TOP_SUBNET) + else if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { remote_end = create_arbitrary_remote( tt ); argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up -link0", @@ -1292,7 +1368,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig failed"); /* Add a network route for the local tun interface */ - if (!tun && tt->topology == TOP_SUBNET) + if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { struct route_ipv4 r; CLEAR(r); @@ -1312,7 +1388,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_remote_netmask, tun_mtu); } - else if (tt->topology == TOP_SUBNET) + else if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { remote_end = create_arbitrary_remote(tt); argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up", IFCONFIG_PATH, @@ -1334,7 +1410,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig failed"); /* Add a network route for the local tun interface */ - if (!tun && tt->topology == TOP_SUBNET) + if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { struct route_ipv4 r; CLEAR(r); @@ -1366,7 +1442,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, } else { - if (tt->topology == TOP_SUBNET) + if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up", IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_local, @@ -1384,7 +1460,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, openvpn_execve_check(&argv, es, S_FATAL, "Mac OS X ifconfig failed"); /* Add a network route for the local tun interface */ - if (!tun && tt->topology == TOP_SUBNET) + if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { struct route_ipv4 r; CLEAR(r); @@ -1406,7 +1482,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_remote_netmask, tun_mtu); } - else if (tt->topology == TOP_SUBNET) + else if (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { remote_end = create_arbitrary_remote( tt ); argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up", IFCONFIG_PATH, @@ -1423,7 +1499,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, openvpn_execve_check(&argv, es, S_FATAL, "FreeBSD ifconfig failed"); /* Add a network route for the local tun interface */ - if (!tun && tt->topology == TOP_SUBNET) + if (!tun && tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) { struct route_ipv4 r; CLEAR(r); @@ -1455,8 +1531,6 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, env_set_destroy(aix_es); } #elif defined (_WIN32) - ASSERT(ifname != NULL); - if (tt->options.ip_win32_type == IPW32_SET_MANUAL) { msg(M_INFO, @@ -1472,10 +1546,11 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu, { do_address_service(true, AF_INET, tt); do_dns_service(true, AF_INET, tt); + do_dns_domain_service(true, tt); } else if (tt->options.ip_win32_type == IPW32_SET_NETSH) { - netsh_ifconfig(&tt->options, ifname, tt->local, + netsh_ifconfig(&tt->options, tt->adapter_index, tt->local, tt->adapter_netmask, NI_IP_NETMASK|NI_OPTIONS); } if (tt->options.msg_channel) @@ -1993,6 +2068,11 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun #ifdef ENABLE_FEATURE_TUN_PERSIST +/* TUNSETGROUP appeared in 2.6.23 */ +#ifndef TUNSETGROUP +# define TUNSETGROUP _IOW('T', 206, int) +#endif + void tuncfg(const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, @@ -2032,7 +2112,7 @@ tuncfg(const char *dev, const char *dev_type, const char *dev_node, } else if (ioctl(tt->fd, TUNSETGROUP, platform_state_group.gr->gr_gid) < 0) { - msg(M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", groupname, dev); + msg(M_ERR, "Cannot ioctl TUNSETGROUP(%s) %s", groupname, dev); } } close_tun(tt, ctx); @@ -5263,23 +5343,29 @@ ip_addr_member_of(const in_addr_t addr, const IP_ADDR_STRING *ias) * Set the ipv6 dns servers on the specified interface. * The list of dns servers currently set on the interface * are cleared first. - * No action is taken if number of addresses (addr_len) < 1. */ static void netsh_set_dns6_servers(const struct in6_addr *addr_list, const int addr_len, - const char *flex_name) + DWORD adapter_index) { struct gc_arena gc = gc_new(); struct argv argv = argv_new(); + /* delete existing DNS settings from TAP interface */ + argv_printf(&argv, "%s%s interface ipv6 delete dns %lu all", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + adapter_index); + netsh_command(&argv, 2, M_FATAL); + for (int i = 0; i < addr_len; ++i) { const char *fmt = (i == 0) ? - "%s%s interface ipv6 set dns %s static %s" - : "%s%s interface ipv6 add dns %s %s"; + "%s%s interface ipv6 set dns %lu static %s" + : "%s%s interface ipv6 add dns %lu %s"; argv_printf(&argv, fmt, get_win_sys_path(), - NETSH_PATH_SUFFIX, flex_name, + NETSH_PATH_SUFFIX, adapter_index, print_in6_addr(addr_list[i], 0, &gc)); /* disable slow address validation on Windows 7 and higher */ @@ -5301,7 +5387,7 @@ netsh_ifconfig_options(const char *type, const in_addr_t *addr_list, const int addr_len, const IP_ADDR_STRING *current, - const char *flex_name, + DWORD adapter_index, const bool test_first) { struct gc_arena gc = gc_new(); @@ -5325,11 +5411,11 @@ netsh_ifconfig_options(const char *type, /* delete existing DNS/WINS settings from TAP interface */ if (delete_first) { - argv_printf(&argv, "%s%s interface ip delete %s %s all", + argv_printf(&argv, "%s%s interface ip delete %s %lu all", get_win_sys_path(), NETSH_PATH_SUFFIX, type, - flex_name); + adapter_index); netsh_command(&argv, 2, M_FATAL); } @@ -5342,14 +5428,14 @@ netsh_ifconfig_options(const char *type, if (delete_first || !test_first || !ip_addr_member_of(addr_list[i], current)) { const char *fmt = count ? - "%s%s interface ip add %s %s %s" - : "%s%s interface ip set %s %s static %s"; + "%s%s interface ip add %s %lu %s" + : "%s%s interface ip set %s %lu static %s"; argv_printf(&argv, fmt, get_win_sys_path(), NETSH_PATH_SUFFIX, type, - flex_name, + adapter_index, print_in_addr_t(addr_list[i], 0, &gc)); /* disable slow address validation on Windows 7 and higher */ @@ -5365,8 +5451,8 @@ netsh_ifconfig_options(const char *type, } else { - msg(M_INFO, "NETSH: \"%s\" %s %s [already set]", - flex_name, + msg(M_INFO, "NETSH: %lu %s %s [already set]", + adapter_index, type, print_in_addr_t(addr_list[i], 0, &gc)); } @@ -5397,7 +5483,7 @@ init_ip_addr_string2(IP_ADDR_STRING *dest, const IP_ADDR_STRING *src1, const IP_ static void netsh_ifconfig(const struct tuntap_options *to, - const char *flex_name, + DWORD adapter_index, const in_addr_t ip, const in_addr_t netmask, const unsigned int flags) @@ -5410,27 +5496,26 @@ netsh_ifconfig(const struct tuntap_options *to, if (flags & NI_TEST_FIRST) { const IP_ADAPTER_INFO *list = get_adapter_info_list(&gc); - const int index = get_adapter_index_flexible(flex_name); - ai = get_adapter(list, index); - pai = get_per_adapter_info(index, &gc); + ai = get_adapter(list, adapter_index); + pai = get_per_adapter_info(adapter_index, &gc); } if (flags & NI_IP_NETMASK) { if (test_adapter_ip_netmask(ai, ip, netmask)) { - msg(M_INFO, "NETSH: \"%s\" %s/%s [already set]", - flex_name, + msg(M_INFO, "NETSH: %lu %s/%s [already set]", + adapter_index, print_in_addr_t(ip, 0, &gc), print_in_addr_t(netmask, 0, &gc)); } else { - /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */ - argv_printf(&argv, "%s%s interface ip set address %s static %s %s", + /* example: netsh interface ip set address 42 static 10.3.0.1 255.255.255.0 */ + argv_printf(&argv, "%s%s interface ip set address %lu static %s %s", get_win_sys_path(), NETSH_PATH_SUFFIX, - flex_name, + adapter_index, print_in_addr_t(ip, 0, &gc), print_in_addr_t(netmask, 0, &gc)); @@ -5449,7 +5534,7 @@ netsh_ifconfig(const struct tuntap_options *to, to->dns, to->dns_len, pai ? &pai->DnsServerList : NULL, - flex_name, + adapter_index, BOOL_CAST(flags & NI_TEST_FIRST)); if (ai && ai->HaveWins) { @@ -5460,7 +5545,7 @@ netsh_ifconfig(const struct tuntap_options *to, to->wins, to->wins_len, ai ? wins : NULL, - flex_name, + adapter_index, BOOL_CAST(flags & NI_TEST_FIRST)); } @@ -5469,16 +5554,16 @@ netsh_ifconfig(const struct tuntap_options *to, } static void -netsh_enable_dhcp(const char *actual_name) +netsh_enable_dhcp(DWORD adapter_index) { struct argv argv = argv_new(); - /* example: netsh interface ip set address my-tap dhcp */ + /* example: netsh interface ip set address 42 dhcp */ argv_printf(&argv, - "%s%s interface ip set address %s dhcp", + "%s%s interface ip set address %lu dhcp", get_win_sys_path(), NETSH_PATH_SUFFIX, - actual_name); + adapter_index); netsh_command(&argv, 4, M_FATAL); @@ -5624,7 +5709,7 @@ tun_standby(struct tuntap *tt) { msg(M_INFO, "NOTE: now trying netsh (this may take some time)"); netsh_ifconfig(&tt->options, - tt->actual_name, + tt->adapter_index, tt->local, tt->adapter_netmask, NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS); @@ -6486,7 +6571,7 @@ tun_open_device(struct tuntap *tt, const char *dev_node, const char **device_gui if (!*device_guid) { - msg(M_FATAL, "All %s adapters on this system are currently in use.", print_windows_driver(tt->windows_driver)); + msg(M_FATAL, "All %s adapters on this system are currently in use or disabled.", print_windows_driver(tt->windows_driver)); } if (tt->windows_driver != windows_driver) @@ -6529,7 +6614,7 @@ tuntap_set_ip_props(const struct tuntap *tt, bool *dhcp_masq, bool *dhcp_masq_po } else { - netsh_enable_dhcp(tt->actual_name); + netsh_enable_dhcp(tt->adapter_index); } } *dhcp_masq = true; @@ -6543,7 +6628,7 @@ tuntap_set_ip_props(const struct tuntap *tt, bool *dhcp_masq, bool *dhcp_masq_po if (dhcp_status(tt->adapter_index) != DHCP_STATUS_ENABLED) { netsh_ifconfig(&tt->options, - tt->actual_name, + tt->adapter_index, tt->local, tt->adapter_netmask, NI_TEST_FIRST | NI_IP_NETMASK | NI_OPTIONS); @@ -6675,15 +6760,25 @@ netsh_delete_address_dns(const struct tuntap *tt, bool ipv6, struct gc_arena *gc if (len > 0) { argv_printf(&argv, - "%s%s interface %s delete dns %s all", + "%s%s interface %s delete dns %lu all", get_win_sys_path(), NETSH_PATH_SUFFIX, ipv6 ? "ipv6" : "ipv4", - tt->actual_name); + tt->adapter_index); netsh_command(&argv, 1, M_WARN); } - if (ipv6) + if (!ipv6 && tt->options.wins_len > 0) + { + argv_printf(&argv, + "%s%s interface ipv4 delete winsservers %lu all", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + tt->adapter_index); + netsh_command(&argv, 1, M_WARN); + } + + if (ipv6 && tt->type == DEV_TYPE_TUN) { delete_route_connected_v6_net(tt); } @@ -6692,7 +6787,7 @@ netsh_delete_address_dns(const struct tuntap *tt, bool ipv6, struct gc_arena *gc * address we added (pointed out by Cedric Tabary). */ - /* netsh interface ipvX delete address \"%s\" %s */ + /* netsh interface ipvX delete address %lu %s */ if (ipv6) { ifconfig_ip_local = print_in6_addr(tt->local_ipv6, 0, gc); @@ -6702,11 +6797,11 @@ netsh_delete_address_dns(const struct tuntap *tt, bool ipv6, struct gc_arena *gc ifconfig_ip_local = print_in_addr_t(tt->local, 0, gc); } argv_printf(&argv, - "%s%s interface %s delete address %s %s store=active", + "%s%s interface %s delete address %lu %s store=active", get_win_sys_path(), NETSH_PATH_SUFFIX, ipv6 ? "ipv6" : "ipv4", - tt->actual_name, + tt->adapter_index, ifconfig_ip_local); netsh_command(&argv, 1, M_WARN); @@ -6728,6 +6823,11 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) } else if (tt->options.msg_channel) { + /* If IPv4 is not enabled, delete DNS domain here */ + if (!tt->did_ifconfig_setup) + { + do_dns_domain_service(false, tt); + } if (tt->options.dns6_len > 0) { do_dns_service(false, AF_INET6, tt); @@ -6753,6 +6853,7 @@ close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx) } else if (tt->options.msg_channel) { + do_dns_domain_service(false, tt); do_dns_service(false, AF_INET, tt); do_address_service(false, AF_INET, tt); } |