From ec5b4540d6f163861c6d639e5aba853e8702aae1 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 2 Feb 2014 18:00:31 +0100 Subject: Update openvpn, implement redirect-private unblock-local, remove redirect-gateway gateway redirection --- openvpn/src/openvpn/error.h | 2 +- openvpn/src/openvpn/manage.c | 6 +- openvpn/src/openvpn/options.c | 4 + openvpn/src/openvpn/ps.c | 2 +- openvpn/src/openvpn/route.c | 48 +++++++++++ openvpn/src/openvpn/route.h | 1 + openvpn/src/openvpn/socket.c | 185 +++++++++++++++++++++--------------------- openvpn/src/openvpn/socket.h | 6 +- 8 files changed, 150 insertions(+), 104 deletions(-) (limited to 'openvpn/src') diff --git a/openvpn/src/openvpn/error.h b/openvpn/src/openvpn/error.h index 5571bfdb..1e1f2acf 100644 --- a/openvpn/src/openvpn/error.h +++ b/openvpn/src/openvpn/error.h @@ -194,7 +194,7 @@ void error_reset (void); void errors_to_stderr (void); void set_suppress_timestamps (bool suppressed); -void set_parsable_output (bool parsable); +void set_machine_readable_output (bool parsable); #define SDL_CONSTRAIN (1<<0) diff --git a/openvpn/src/openvpn/manage.c b/openvpn/src/openvpn/manage.c index 06965ad2..561c252b 100644 --- a/openvpn/src/openvpn/manage.c +++ b/openvpn/src/openvpn/manage.c @@ -1568,9 +1568,9 @@ man_listen (struct management *man) else #endif { - man->connection.sd_top = create_socket_tcp (man->settings.local->ai_family); + man->connection.sd_top = create_socket_tcp (man->settings.local); socket_bind (man->connection.sd_top, man->settings.local, - man->settings.local->ai_family, "MANAGEMENT", false); + man->settings.local->ai_family, "MANAGEMENT", false); } /* @@ -1635,7 +1635,7 @@ man_connect (struct management *man) else #endif { - man->connection.sd_cli = create_socket_tcp (AF_INET); + man->connection.sd_cli = create_socket_tcp (man->settings.local); status = openvpn_connect (man->connection.sd_cli, man->settings.local->ai_addr, 5, diff --git a/openvpn/src/openvpn/options.c b/openvpn/src/openvpn/options.c index 52c6c239..9393c0aa 100644 --- a/openvpn/src/openvpn/options.c +++ b/openvpn/src/openvpn/options.c @@ -2076,6 +2076,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #endif if (options->routes && (options->routes->flags & RG_ENABLE)) msg (M_USAGE, "--redirect-gateway cannot be used with --mode server (however --push \"redirect-gateway\" is fine)"); + if (options->routes && ((options->routes->flags & RG_BLOCK_LOCAL) && (options->routes->flags & RG_BLOCK_LOCAL))) + msg (M_USAGE, "unblock-local and block-local options of redirect-gateway/redirect-private are mutatlly exclusive"); if (options->route_delay_defined) msg (M_USAGE, "--route-delay cannot be used with --mode server"); if (options->up_delay) @@ -5363,6 +5365,8 @@ add_option (struct options *options, options->routes->flags |= RG_BYPASS_DNS; else if (streq (p[j], "block-local")) options->routes->flags |= RG_BLOCK_LOCAL; + else if (streq (p[j], "unblock-local")) + options->routes->flags |= RG_UNBLOCK_LOCAL; else { msg (msglevel, "unknown --%s flag: %s", p[0], p[j]); diff --git a/openvpn/src/openvpn/ps.c b/openvpn/src/openvpn/ps.c index 901a094f..6807aac0 100644 --- a/openvpn/src/openvpn/ps.c +++ b/openvpn/src/openvpn/ps.c @@ -803,7 +803,7 @@ port_share_open (const char *host, * Get host's IP address */ - status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, + status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_FATAL, host, port, 0, NULL, AF_INET, &ai); ASSERT (status==0); hostaddr = *((struct sockaddr_in*) ai->ai_addr); diff --git a/openvpn/src/openvpn/route.c b/openvpn/src/openvpn/route.c index fa8221d4..25eeb77c 100644 --- a/openvpn/src/openvpn/route.c +++ b/openvpn/src/openvpn/route.c @@ -535,6 +535,46 @@ add_block_local_item (struct route_list *rl, } } +static void +add_unblock_local (struct route_list *rl) +{ + const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED); + + if (rl->flags & RG_UNBLOCK_LOCAL && rl->n+1 < rl->capacity + && (rl->rgi.flags & rgi_needed) == rgi_needed) + { + /* unblock access to local subnet */ + struct route_ipv4 r; + int i; + + CLEAR(r); + r.flags = RT_DEFINED; + r.network = rl->rgi.gateway.addr & rl->rgi.gateway.netmask; + r.netmask = rl->rgi.gateway.netmask; + r.gateway = rl->rgi.gateway.addr; + rl->routes[rl->n++] = r; + + /* Additional local networks */ + for (i = 0; i < rl->rgi.n_addrs; ++i) + { + const struct route_gateway_address *gwa = &rl->rgi.addrs[i]; + + /* omit the add/subnet in &rl->rgi which we processed above */ + if ((!((rl->rgi.gateway.addr & rl->rgi.gateway.netmask) == (gwa->addr & gwa->netmask) + && rl->rgi.gateway.netmask == gwa->netmask)) && rl->n+1 < rl->capacity) + { + CLEAR(r); + r.flags = RT_DEFINED; + r.network = gwa->addr & gwa->netmask; + r.netmask = gwa->netmask; + r.gateway = gwa->addr; + rl->routes[rl->n++] = r; + } + } + } +} + + static void add_block_local (struct route_list *rl) { @@ -546,8 +586,10 @@ add_block_local (struct route_list *rl) { size_t i; +#ifndef TARGET_ANDROID /* add bypass for gateway addr */ add_bypass_address (&rl->spec.bypass, rl->rgi.gateway.addr); +#endif /* block access to local subnet */ add_block_local_item (rl, &rl->rgi.gateway, rl->spec.remote_endpoint); @@ -564,6 +606,8 @@ add_block_local (struct route_list *rl) } } + + bool init_route_list (struct route_list *rl, const struct route_option_list *opt, @@ -632,6 +676,8 @@ init_route_list (struct route_list *rl, } } + + add_unblock_local (rl); if (rl->flags & RG_ENABLE) { add_block_local (rl); @@ -852,6 +898,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u } else { +#ifndef TARGET_ANDROID bool local = BOOL_CAST(rl->flags & RG_LOCAL); if (rl->flags & RG_AUTO_LOCAL) { const int tla = rl->spec.remote_host_local; @@ -884,6 +931,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u dmsg (D_ROUTE, "ROUTE remote_host protocol differs from tunneled"); } } +#endif /* route DHCP/DNS server traffic through original default gateway */ add_bypass_routes (&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, &rl->rgi, es); diff --git a/openvpn/src/openvpn/route.h b/openvpn/src/openvpn/route.h index fe9b4616..c5e2c1e4 100644 --- a/openvpn/src/openvpn/route.h +++ b/openvpn/src/openvpn/route.h @@ -89,6 +89,7 @@ struct route_option { #define RG_REROUTE_GW (1<<5) #define RG_AUTO_LOCAL (1<<6) #define RG_BLOCK_LOCAL (1<<7) +#define RG_UNBLOCK_LOCAL (1<<8) struct route_option_list { unsigned int flags; /* RG_x flags */ diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c index 97f67563..4b86d439 100644 --- a/openvpn/src/openvpn/socket.c +++ b/openvpn/src/openvpn/socket.c @@ -766,11 +766,15 @@ link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf) */ socket_descriptor_t -create_socket_tcp (int af) +create_socket_tcp (struct addrinfo* addrinfo) { socket_descriptor_t sd; - if ((sd = socket (af, SOCK_STREAM, IPPROTO_TCP)) < 0) + ASSERT (addrinfo); + ASSERT (addrinfo->ai_socktype == SOCK_STREAM); + ASSERT (addrinfo->ai_protocol == IPPROTO_TCP); + + if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) msg (M_ERR, "Cannot create TCP socket"); #ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */ @@ -787,17 +791,21 @@ create_socket_tcp (int af) } static socket_descriptor_t -create_socket_udp (const int af, const unsigned int flags) +create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags) { socket_descriptor_t sd; - if ((sd = socket (af, SOCK_DGRAM, IPPROTO_UDP)) < 0) + ASSERT (addrinfo); + ASSERT (addrinfo->ai_socktype == SOCK_DGRAM); + ASSERT (addrinfo->ai_protocol == IPPROTO_UDP); + + if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket"); #if ENABLE_IP_PKTINFO else if (flags & SF_USE_IP_PKTINFO) { int pad = 1; - if(af == AF_INET) + if(addrinfo->ai_family == AF_INET) { #ifdef IP_PKTINFO if (setsockopt (sd, SOL_IP, IP_PKTINFO, @@ -811,7 +819,7 @@ create_socket_udp (const int af, const unsigned int flags) #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif } - else if (af == AF_INET6 ) + else if (addrinfo->ai_family == AF_INET6 ) { #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */ if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, @@ -827,28 +835,48 @@ create_socket_udp (const int af, const unsigned int flags) return sd; } -static void -create_socket (struct link_socket *sock) +static void bind_local (struct link_socket *sock, const sa_family_t ai_family) { - /* create socket, use information carried over from getaddrinfo */ - const int ai_proto = sock->info.lsa->actual.ai_protocol; - int ai_family = sock->info.lsa->actual.ai_family; - - ASSERT (sock->info.af == AF_UNSPEC || sock->info.af == ai_family); + /* bind to local address/port */ + if (sock->bind_local) + { +#ifdef ENABLE_SOCKS + if (sock->socks_proxy && sock->info.proto == PROTO_UDP) + socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local, + ai_family, "SOCKS", false); + else +#endif + socket_bind (sock->sd, sock->info.lsa->bind_local, + ai_family, + "TCP/UDP", sock->info.bind_ipv6_only); + } +} - if (ai_proto == IPPROTO_UDP) +static void +create_socket (struct link_socket* sock, struct addrinfo* addr) +{ + if (addr->ai_protocol == IPPROTO_UDP) { - sock->sd = create_socket_udp (ai_family, sock->sockflags); + sock->sd = create_socket_udp (addr, sock->sockflags); sock->sockflags |= SF_GETADDRINFO_DGRAM; #ifdef ENABLE_SOCKS + /* Assume that control socket and data socket to the socks proxy + * are using the same IP family */ if (sock->socks_proxy) - sock->ctrl_sd = create_socket_tcp (ai_family); + { + /* Construct a temporary addrinfo to create the socket, + * currently resolve two remote addresses is not supported, + * TODO: Rewrite the whole resolve_remote */ + struct addrinfo addrinfo_tmp = *addr; + addr->ai_protocol = IPPROTO_TCP; + sock->ctrl_sd = create_socket_tcp (&addrinfo_tmp); + } #endif } - else if (ai_proto == IPPROTO_TCP) + else if (addr->ai_protocol == IPPROTO_TCP) { - sock->sd = create_socket_tcp (ai_family); + sock->sd = create_socket_tcp (addr); } else { @@ -859,6 +887,8 @@ create_socket (struct link_socket *sock) /* set socket to --mark packets with given value */ socket_set_mark (sock->sd, sock->mark); + + bind_local (sock, addr->ai_family); } #ifdef TARGET_ANDROID @@ -1204,21 +1234,15 @@ void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai) else ASSERT(0); - /* Copy addrinfo sock parameters for socket creating */ - actual->ai_family = ai->ai_family; - actual->ai_protocol = ai->ai_protocol; - actual->ai_socktype = ai->ai_socktype; } void -socket_connect (socket_descriptor_t *sd, - struct link_socket_addr *lsa, +socket_connect (socket_descriptor_t* sd, + const struct sockaddr* dest, const int connect_timeout, struct signal_info* sig_info) { struct gc_arena gc = gc_new (); - const struct sockaddr *dest = &lsa->actual.dest.addr.sa; - int status; #ifdef CONNECT_NONBLOCK @@ -1346,23 +1370,6 @@ resolve_bind_local (struct link_socket *sock, const sa_family_t af) gc_free (&gc); } -static void bind_local (struct link_socket *sock) -{ - /* bind to local address/port */ - if (sock->bind_local) - { -#ifdef ENABLE_SOCKS - if (sock->socks_proxy && sock->info.proto == PROTO_UDP) - socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local, - sock->info.lsa->actual.ai_family, "SOCKS", false); - else -#endif - socket_bind (sock->sd, sock->info.lsa->bind_local, - sock->info.lsa->actual.ai_family, - "TCP/UDP", sock->info.bind_ipv6_only); - } -} - static void resolve_remote (struct link_socket *sock, int phase, @@ -1490,30 +1497,6 @@ link_socket_new (void) return sock; } -void -create_new_socket (struct link_socket* sock) -{ - if (sock->bind_local) { - resolve_bind_local (sock, sock->info.af); - } - resolve_remote (sock, 1, NULL, NULL); - - /* - * In P2P or server mode we must create the socket even when resolving - * the remote site fails/is not specified. */ - - if (sock->info.lsa->actual.ai_family==0 && sock->bind_local) - { - /* Copy sock parameters from bind addr */ - set_actual_address (&sock->info.lsa->actual, sock->info.lsa->bind_local); - /* clear destination set by set_actual_address */ - CLEAR(sock->info.lsa->actual.dest); - } -} - - - -/* bind socket if necessary */ void link_socket_init_phase1 (struct link_socket *sock, const char *local_host, @@ -1655,7 +1638,10 @@ link_socket_init_phase1 (struct link_socket *sock, } else if (mode != LS_MODE_TCP_ACCEPT_FROM) { - create_new_socket (sock); + if (sock->bind_local) { + resolve_bind_local (sock, sock->info.af); + } + resolve_remote (sock, 1, NULL, NULL); } } @@ -1739,11 +1725,14 @@ linksock_print_addr (struct link_socket *sock) msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true)); else if (sock->bind_local) { - /* Socket is always bound on the first matching address */ + sa_family_t ai_family = sock->info.lsa->actual.dest.addr.sa.sa_family; + /* Socket is always bound on the first matching address, + * For bound sockets with no remote addr this is the element of + * the list */ struct addrinfo *cur; for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next) { - if(cur->ai_family == sock->info.lsa->actual.ai_family) + if(!ai_family || ai_family == cur->ai_family) break; } ASSERT (cur); @@ -1812,8 +1801,9 @@ phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info) const bool proxy_retry = false; #endif do { + ASSERT (sock->info.lsa->current_remote->ai_protocol == IPPROTO_TCP); socket_connect (&sock->sd, - sock->info.lsa, + sock->info.lsa->current_remote->ai_addr, sock->connect_timeout, sig_info); @@ -1848,7 +1838,7 @@ phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info) /* TODO (schwabe): This code assumes AF_INET for the proxy socket * when retrying a connection */ openvpn_close_socket (sock->sd); - sock->sd = create_socket_tcp (AF_INET); + sock->sd = create_socket_tcp (sock->info.lsa->current_remote); } } while (proxy_retry); @@ -1860,7 +1850,7 @@ static void phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info) { socket_connect (&sock->ctrl_sd, - sock->info.lsa, + sock->info.lsa->current_remote->ai_addr, sock->connect_timeout, sig_info); @@ -1932,33 +1922,34 @@ link_socket_init_phase2 (struct link_socket *sock, /* Second chance to resolv/create socket */ resolve_remote (sock, 2, &remote_dynamic, &sig_info->signal_received); + /* If a valid remote has been found, create the socket with its addrinfo */ + if (sock->info.lsa->current_remote) + create_socket (sock, sock->info.lsa->current_remote); + /* If socket has not already been created create it now */ if (sock->sd == SOCKET_UNDEFINED) { - /* If we have no --remote and have still not figured out the - * protocol family to use we will use the first of the bind */ - if (sock->bind_local && sock->info.lsa->bind_local - && !sock->info.lsa->actual.ai_family && !sock->remote_host) - { - msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s", - addr_family_name(sock->info.lsa->bind_local->ai_family)); - set_actual_address(&sock->info.lsa->actual, sock->info.lsa->bind_local); - - } + /* If we have no --remote and have still not figured out the + * protocol family to use we will use the first of the bind */ - if (sock->info.lsa->actual.ai_family) - { - create_socket (sock); - } - else + if (sock->bind_local && !sock->remote_host && sock->info.lsa->bind_local) { - msg (M_WARN, "Could not determine IPv4/IPv6 protocol"); - sig_info->signal_received = SIGUSR1; - goto done; + /* Warn if this is because neither v4 or v6 was specified + * and we should not connect a remote */ + if (sock->info.af == AF_UNSPEC) + msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s", + addr_family_name(sock->info.lsa->bind_local->ai_family)); + + create_socket (sock, sock->info.lsa->bind_local); } + } - if (sock->bind_local) - bind_local(sock); + /* Socket still undefined, give a warning and abort connection */ + if (sock->sd == SOCKET_UNDEFINED) + { + msg (M_WARN, "Could not determine IPv4/IPv6 protocol"); + sig_info->signal_received = SIGUSR1; + goto done; } if (sig_info && sig_info->signal_received) @@ -2798,6 +2789,7 @@ proto_remote (int proto, bool remote) return "TCPv4_CLIENT"; ASSERT (0); + return ""; /* Make the compiler happy */ } /* @@ -2933,7 +2925,12 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex; from->pi.in6.ipi6_addr = pkti6->ipi6_addr; } + else if (cmsg != NULL) + { + msg(M_WARN, "CMSG received that cannot be parsed"); + } } + return fromlen; } #endif @@ -3000,7 +2997,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, iov.iov_len = BLEN (buf); mesg.msg_iov = &iov; mesg.msg_iovlen = 1; - switch (to->ai_family) + switch (to->dest.addr.sa.sa_family) { case AF_INET: { diff --git a/openvpn/src/openvpn/socket.h b/openvpn/src/openvpn/socket.h index 8d4316ba..51329534 100644 --- a/openvpn/src/openvpn/socket.h +++ b/openvpn/src/openvpn/socket.h @@ -91,10 +91,6 @@ struct cached_dns_entry { struct link_socket_actual { /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */ - int ai_family; /* PF_xxx */ - int ai_socktype; /* SOCK_xxx */ - int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ - struct openvpn_sockaddr dest; #if ENABLE_IP_PKTINFO @@ -473,7 +469,7 @@ bool ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn); bool mac_addr_safe (const char *mac_addr); bool ipv6_addr_safe (const char *ipv6_text_addr); -socket_descriptor_t create_socket_tcp (int af); +socket_descriptor_t create_socket_tcp (struct addrinfo*); socket_descriptor_t socket_do_accept (socket_descriptor_t sd, struct link_socket_actual *act, -- cgit v1.2.3