| /* |
| * OpenVPN -- An application to securely tunnel IP networks |
| * over a single TCP/UDP port, with support for SSL/TLS-based |
| * session authentication and key exchange, |
| * packet encryption, packet authentication, and |
| * packet compression. |
| * |
| * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 |
| * as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #elif defined(_MSC_VER) |
| #include "config-msvc.h" |
| #endif |
| |
| #include "syshead.h" |
| |
| #include "socket.h" |
| #include "fdmisc.h" |
| #include "misc.h" |
| #include "gremlin.h" |
| #include "plugin.h" |
| #include "ps.h" |
| #include "manage.h" |
| #include "misc.h" |
| #include "manage.h" |
| #include "openvpn.h" |
| #include "forward.h" |
| |
| #include "memdbg.h" |
| |
| const int proto_overhead[] = { /* indexed by PROTO_x */ |
| 0, |
| IPv4_UDP_HEADER_SIZE, /* IPv4 */ |
| IPv4_TCP_HEADER_SIZE, |
| IPv4_TCP_HEADER_SIZE, |
| IPv6_UDP_HEADER_SIZE, /* IPv6 */ |
| IPv6_TCP_HEADER_SIZE, |
| IPv6_TCP_HEADER_SIZE, |
| IPv6_TCP_HEADER_SIZE, |
| }; |
| |
| /* |
| * Convert sockflags/getaddr_flags into getaddr_flags |
| */ |
| static unsigned int |
| sf2gaf(const unsigned int getaddr_flags, |
| const unsigned int sockflags) |
| { |
| if (sockflags & SF_HOST_RANDOMIZE) |
| { |
| return getaddr_flags | GETADDR_RANDOMIZE; |
| } |
| else |
| { |
| return getaddr_flags; |
| } |
| } |
| |
| /* |
| * Functions related to the translation of DNS names to IP addresses. |
| */ |
| static int |
| get_addr_generic(sa_family_t af, unsigned int flags, const char *hostname, |
| void *network, unsigned int *netbits, |
| int resolve_retry_seconds, volatile int *signal_received, |
| int msglevel) |
| { |
| char *endp, *sep, *var_host = NULL; |
| struct addrinfo *ai = NULL; |
| unsigned long bits; |
| uint8_t max_bits; |
| int ret = -1; |
| |
| if (!hostname) |
| { |
| msg(M_NONFATAL, "Can't resolve null hostname!"); |
| goto out; |
| } |
| |
| /* assign family specific default values */ |
| switch (af) |
| { |
| case AF_INET: |
| bits = 0; |
| max_bits = sizeof(in_addr_t) * 8; |
| break; |
| case AF_INET6: |
| bits = 64; |
| max_bits = sizeof(struct in6_addr) * 8; |
| break; |
| default: |
| msg(M_WARN, |
| "Unsupported AF family passed to getaddrinfo for %s (%d)", |
| hostname, af); |
| goto out; |
| } |
| |
| /* we need to modify the hostname received as input, but we don't want to |
| * touch it directly as it might be a constant string. |
| * |
| * Therefore, we clone the string here and free it at the end of the |
| * function */ |
| var_host = strdup(hostname); |
| if (!var_host) |
| { |
| msg(M_NONFATAL | M_ERRNO, |
| "Can't allocate hostname buffer for getaddrinfo"); |
| goto out; |
| } |
| |
| /* check if this hostname has a /bits suffix */ |
| sep = strchr(var_host , '/'); |
| if (sep) |
| { |
| bits = strtoul(sep + 1, &endp, 10); |
| if ((*endp != '\0') || (bits > max_bits)) |
| { |
| msg(msglevel, "IP prefix '%s': invalid '/bits' spec (%s)", hostname, |
| sep + 1); |
| goto out; |
| } |
| *sep = '\0'; |
| } |
| |
| ret = openvpn_getaddrinfo(flags & ~GETADDR_HOST_ORDER, var_host, NULL, |
| resolve_retry_seconds, signal_received, af, &ai); |
| if ((ret == 0) && network) |
| { |
| struct in6_addr *ip6; |
| in_addr_t *ip4; |
| |
| switch (af) |
| { |
| case AF_INET: |
| ip4 = network; |
| *ip4 = ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr; |
| |
| if (flags & GETADDR_HOST_ORDER) |
| { |
| *ip4 = ntohl(*ip4); |
| } |
| break; |
| case AF_INET6: |
| ip6 = network; |
| *ip6 = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr; |
| break; |
| default: |
| /* can't get here because 'af' was previously checked */ |
| msg(M_WARN, |
| "Unsupported AF family for %s (%d)", var_host, af); |
| goto out; |
| } |
| } |
| |
| if (netbits) |
| { |
| *netbits = bits; |
| } |
| |
| /* restore '/' separator, if any */ |
| if (sep) |
| { |
| *sep = '/'; |
| } |
| out: |
| freeaddrinfo(ai); |
| free(var_host); |
| |
| return ret; |
| } |
| |
| in_addr_t |
| getaddr(unsigned int flags, |
| const char *hostname, |
| int resolve_retry_seconds, |
| bool *succeeded, |
| volatile int *signal_received) |
| { |
| in_addr_t addr; |
| int status; |
| |
| status = get_addr_generic(AF_INET, flags, hostname, &addr, NULL, |
| resolve_retry_seconds, signal_received, |
| M_WARN); |
| if (status==0) |
| { |
| if (succeeded) |
| { |
| *succeeded = true; |
| } |
| return addr; |
| } |
| else |
| { |
| if (succeeded) |
| { |
| *succeeded = false; |
| } |
| return 0; |
| } |
| } |
| |
| bool |
| get_ipv6_addr(const char *hostname, struct in6_addr *network, |
| unsigned int *netbits, int msglevel) |
| { |
| if (get_addr_generic(AF_INET6, GETADDR_RESOLVE, hostname, network, netbits, |
| 0, NULL, msglevel) < 0) |
| { |
| return false; |
| } |
| |
| return true; /* parsing OK, values set */ |
| } |
| |
| static inline bool |
| streqnull(const char *a, const char *b) |
| { |
| if (a == NULL && b == NULL) |
| { |
| return true; |
| } |
| else if (a == NULL || b == NULL) |
| { |
| return false; |
| } |
| else |
| { |
| return streq(a, b); |
| } |
| } |
| |
| /* |
| * get_cached_dns_entry return 0 on success and -1 |
| * otherwise. (like getaddrinfo) |
| */ |
| static int |
| get_cached_dns_entry(struct cached_dns_entry *dns_cache, |
| const char *hostname, |
| const char *servname, |
| int ai_family, |
| int resolve_flags, |
| struct addrinfo **ai) |
| { |
| struct cached_dns_entry *ph; |
| int flags; |
| |
| /* Only use flags that are relevant for the structure */ |
| flags = resolve_flags & GETADDR_CACHE_MASK; |
| |
| for (ph = dns_cache; ph; ph = ph->next) |
| { |
| if (streqnull(ph->hostname, hostname) |
| && streqnull(ph->servname, servname) |
| && ph->ai_family == ai_family |
| && ph->flags == flags) |
| { |
| *ai = ph->ai; |
| return 0; |
| } |
| } |
| return -1; |
| } |
| |
| |
| static int |
| do_preresolve_host(struct context *c, |
| const char *hostname, |
| const char *servname, |
| const int af, |
| const int flags) |
| { |
| struct addrinfo *ai; |
| int status; |
| |
| if (get_cached_dns_entry(c->c1.dns_cache, |
| hostname, |
| servname, |
| af, |
| flags, |
| &ai) == 0) |
| { |
| /* entry already cached, return success */ |
| return 0; |
| } |
| |
| status = openvpn_getaddrinfo(flags, hostname, servname, |
| c->options.resolve_retry_seconds, NULL, |
| af, &ai); |
| if (status == 0) |
| { |
| struct cached_dns_entry *ph; |
| |
| ALLOC_OBJ_CLEAR_GC(ph, struct cached_dns_entry, &c->gc); |
| ph->ai = ai; |
| ph->hostname = hostname; |
| ph->servname = servname; |
| ph->flags = flags & GETADDR_CACHE_MASK; |
| |
| if (!c->c1.dns_cache) |
| { |
| c->c1.dns_cache = ph; |
| } |
| else |
| { |
| struct cached_dns_entry *prev = c->c1.dns_cache; |
| while (prev->next) |
| { |
| prev = prev->next; |
| } |
| prev->next = ph; |
| } |
| |
| gc_addspecial(ai, &gc_freeaddrinfo_callback, &c->gc); |
| |
| } |
| return status; |
| } |
| |
| void |
| do_preresolve(struct context *c) |
| { |
| int i; |
| struct connection_list *l = c->options.connection_list; |
| const unsigned int preresolve_flags = GETADDR_RESOLVE |
| |GETADDR_UPDATE_MANAGEMENT_STATE |
| |GETADDR_MENTION_RESOLVE_RETRY |
| |GETADDR_FATAL; |
| |
| |
| for (i = 0; i < l->len; ++i) |
| { |
| int status; |
| const char *remote; |
| int flags = preresolve_flags; |
| |
| struct connection_entry *ce = c->options.connection_list->array[i]; |
| |
| if (proto_is_dgram(ce->proto)) |
| { |
| flags |= GETADDR_DATAGRAM; |
| } |
| |
| if (c->options.sockflags & SF_HOST_RANDOMIZE) |
| { |
| flags |= GETADDR_RANDOMIZE; |
| } |
| |
| if (c->options.ip_remote_hint) |
| { |
| remote = c->options.ip_remote_hint; |
| } |
| else |
| { |
| remote = ce->remote; |
| } |
| |
| /* 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); |
| if (status != 0) |
| { |
| goto err; |
| } |
| } |
| |
| /* Preresolve proxy */ |
| if (ce->http_proxy_options) |
| { |
| status = do_preresolve_host(c, |
| ce->http_proxy_options->server, |
| ce->http_proxy_options->port, |
| ce->af, |
| preresolve_flags); |
| |
| if (status != 0) |
| { |
| goto err; |
| } |
| } |
| |
| if (ce->socks_proxy_server) |
| { |
| status = do_preresolve_host(c, |
| ce->socks_proxy_server, |
| ce->socks_proxy_port, |
| ce->af, |
| flags); |
| if (status != 0) |
| { |
| goto err; |
| } |
| } |
| |
| if (ce->bind_local) |
| { |
| flags |= GETADDR_PASSIVE; |
| flags &= ~GETADDR_RANDOMIZE; |
| status = do_preresolve_host(c, ce->local, ce->local_port, ce->af, flags); |
| if (status != 0) |
| { |
| goto err; |
| } |
| |
| } |
| |
| } |
| return; |
| |
| err: |
| throw_signal_soft(SIGHUP, "Preresolving failed"); |
| } |
| |
| /* |
| * Translate IPv4/IPv6 addr or hostname into struct addrinfo |
| * If resolve error, try again for resolve_retry_seconds seconds. |
| */ |
| int |
| openvpn_getaddrinfo(unsigned int flags, |
| const char *hostname, |
| const char *servname, |
| int resolve_retry_seconds, |
| volatile int *signal_received, |
| int ai_family, |
| struct addrinfo **res) |
| { |
| struct addrinfo hints; |
| int status; |
| int sigrec = 0; |
| int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS; |
| struct gc_arena gc = gc_new(); |
| const char *print_hostname; |
| const char *print_servname; |
| |
| ASSERT(res); |
| |
| ASSERT(hostname || servname); |
| ASSERT(!(flags & GETADDR_HOST_ORDER)); |
| |
| if (servname) |
| { |
| print_servname = servname; |
| } |
| else |
| { |
| print_servname = ""; |
| } |
| |
| if (flags & GETADDR_MSG_VIRT_OUT) |
| { |
| msglevel |= M_MSG_VIRT_OUT; |
| } |
| |
| if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL)) |
| && !signal_received) |
| { |
| signal_received = &sigrec; |
| } |
| |
| /* try numeric ipv6 addr first */ |
| CLEAR(hints); |
| hints.ai_family = ai_family; |
| hints.ai_flags = AI_NUMERICHOST; |
| |
| if (flags & GETADDR_PASSIVE) |
| { |
| hints.ai_flags |= AI_PASSIVE; |
| } |
| |
| if (flags & GETADDR_DATAGRAM) |
| { |
| hints.ai_socktype = SOCK_DGRAM; |
| } |
| else |
| { |
| hints.ai_socktype = SOCK_STREAM; |
| } |
| |
| status = getaddrinfo(hostname, servname, &hints, res); |
| |
| if (status != 0) /* parse as numeric address failed? */ |
| { |
| const int fail_wait_interval = 5; /* seconds */ |
| /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */ |
| int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : |
| ((resolve_retry_seconds + 4)/ fail_wait_interval); |
| const char *fmt; |
| int level = 0; |
| |
| if (hostname && (flags & GETADDR_RANDOMIZE)) |
| { |
| hostname = hostname_randomize(hostname, &gc); |
| } |
| |
| if (hostname) |
| { |
| print_hostname = hostname; |
| } |
| else |
| { |
| print_hostname = "undefined"; |
| } |
| |
| fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)"; |
| 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.)"; |
| } |
| |
| if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL) |
| { |
| msg(msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)", |
| print_hostname,print_servname, gai_strerror(status)); |
| goto done; |
| } |
| |
| #ifdef ENABLE_MANAGEMENT |
| if (flags & GETADDR_UPDATE_MANAGEMENT_STATE) |
| { |
| if (management) |
| { |
| management_set_state(management, |
| OPENVPN_STATE_RESOLVE, |
| NULL, |
| NULL, |
| NULL, |
| NULL, |
| NULL); |
| } |
| } |
| #endif |
| |
| /* |
| * Resolve hostname |
| */ |
| while (true) |
| { |
| #ifndef _WIN32 |
| 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", |
| flags, hints.ai_family, hints.ai_socktype); |
| status = getaddrinfo(hostname, servname, &hints, res); |
| |
| if (signal_received) |
| { |
| get_signal(signal_received); |
| if (*signal_received) /* were we interrupted by a signal? */ |
| { |
| if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ |
| { |
| msg(level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); |
| *signal_received = 0; |
| } |
| else |
| { |
| /* turn success into failure (interrupted syscall) */ |
| if (0 == status) |
| { |
| ASSERT(res); |
| freeaddrinfo(*res); |
| *res = NULL; |
| status = EAI_AGAIN; /* = temporary failure */ |
| errno = EINTR; |
| } |
| goto done; |
| } |
| } |
| } |
| |
| /* success? */ |
| if (0 == status) |
| { |
| break; |
| } |
| |
| /* resolve lookup failed, should we |
| * continue or fail? */ |
| level = msglevel; |
| if (resolve_retries > 0) |
| { |
| level = D_RESOLVE_ERRORS; |
| } |
| |
| msg(level, |
| fmt, |
| print_hostname, |
| print_servname, |
| gai_strerror(status)); |
| |
| if (--resolve_retries <= 0) |
| { |
| goto done; |
| } |
| |
| management_sleep(fail_wait_interval); |
| } |
| |
| ASSERT(res); |
| |
| /* hostname resolve succeeded */ |
| |
| /* |
| * Do not choose an IP Addresse by random or change the order * |
| * of IP addresses, doing so will break RFC 3484 address selection * |
| */ |
| } |
| else |
| { |
| /* IP address parse succeeded */ |
| if (flags & GETADDR_RANDOMIZE) |
| { |
| msg(M_WARN, "WARNING: ignoring --remote-random-hostname because the hostname is an IP address"); |
| } |
| } |
| |
| done: |
| if (signal_received && *signal_received) |
| { |
| int level = 0; |
| if (flags & GETADDR_FATAL_ON_SIGNAL) |
| { |
| level = M_FATAL; |
| } |
| else if (flags & GETADDR_WARN_ON_SIGNAL) |
| { |
| level = M_WARN; |
| } |
| msg(level, "RESOLVE: signal received during DNS resolution attempt"); |
| } |
| |
| gc_free(&gc); |
| return status; |
| } |
| |
| /* |
| * We do our own inet_aton because the glibc function |
| * isn't very good about error checking. |
| */ |
| int |
| openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr) |
| { |
| unsigned int a, b, c, d; |
| |
| CLEAR(*addr); |
| if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) |
| { |
| if (a < 256 && b < 256 && c < 256 && d < 256) |
| { |
| addr->s_addr = htonl(a<<24 | b<<16 | c<<8 | d); |
| return OIA_IP; /* good dotted quad */ |
| } |
| } |
| if (string_class(dotted_quad, CC_DIGIT|CC_DOT, 0)) |
| { |
| return OIA_ERROR; /* probably a badly formatted dotted quad */ |
| } |
| else |
| { |
| return OIA_HOSTNAME; /* probably a hostname */ |
| } |
| } |
| |
| bool |
| ip_addr_dotted_quad_safe(const char *dotted_quad) |
| { |
| /* verify non-NULL */ |
| if (!dotted_quad) |
| { |
| return false; |
| } |
| |
| /* verify length is within limits */ |
| if (strlen(dotted_quad) > 15) |
| { |
| return false; |
| } |
| |
| /* verify that all chars are either numeric or '.' and that no numeric |
| * substring is greater than 3 chars */ |
| { |
| int nnum = 0; |
| const char *p = dotted_quad; |
| int c; |
| |
| while ((c = *p++)) |
| { |
| if (c >= '0' && c <= '9') |
| { |
| ++nnum; |
| if (nnum > 3) |
| { |
| return false; |
| } |
| } |
| else if (c == '.') |
| { |
| nnum = 0; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| } |
| |
| /* verify that string will convert to IP address */ |
| { |
| struct in_addr a; |
| return openvpn_inet_aton(dotted_quad, &a) == OIA_IP; |
| } |
| } |
| |
| bool |
| ipv6_addr_safe(const char *ipv6_text_addr) |
| { |
| /* verify non-NULL */ |
| if (!ipv6_text_addr) |
| { |
| return false; |
| } |
| |
| /* verify length is within limits */ |
| if (strlen(ipv6_text_addr) > INET6_ADDRSTRLEN) |
| { |
| return false; |
| } |
| |
| /* verify that string will convert to IPv6 address */ |
| { |
| struct in6_addr a6; |
| return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1; |
| } |
| } |
| |
| static bool |
| dns_addr_safe(const char *addr) |
| { |
| if (addr) |
| { |
| const size_t len = strlen(addr); |
| return len > 0 && len <= 255 && string_class(addr, CC_ALNUM|CC_DASH|CC_DOT, 0); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| bool |
| ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn) |
| { |
| if (ip_addr_dotted_quad_safe(addr)) |
| { |
| return true; |
| } |
| else if (allow_fqdn) |
| { |
| return dns_addr_safe(addr); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| bool |
| mac_addr_safe(const char *mac_addr) |
| { |
| /* verify non-NULL */ |
| if (!mac_addr) |
| { |
| return false; |
| } |
| |
| /* verify length is within limits */ |
| if (strlen(mac_addr) > 17) |
| { |
| return false; |
| } |
| |
| /* verify that all chars are either alphanumeric or ':' and that no |
| * alphanumeric substring is greater than 2 chars */ |
| { |
| int nnum = 0; |
| const char *p = mac_addr; |
| int c; |
| |
| while ((c = *p++)) |
| { |
| if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) |
| { |
| ++nnum; |
| if (nnum > 2) |
| { |
| return false; |
| } |
| } |
| else if (c == ':') |
| { |
| nnum = 0; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| } |
| |
| /* error-checking is left to script invoked in lladdr.c */ |
| return true; |
| } |
| |
| static int |
| socket_get_sndbuf(int sd) |
| { |
| #if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF) |
| int val; |
| socklen_t len; |
| |
| len = sizeof(val); |
| if (getsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &val, &len) == 0 |
| && len == sizeof(val)) |
| { |
| return val; |
| } |
| #endif |
| return 0; |
| } |
| |
| static void |
| socket_set_sndbuf(int sd, int size) |
| { |
| #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF) |
| if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof(size)) != 0) |
| { |
| msg(M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size); |
| } |
| #endif |
| } |
| |
| static int |
| socket_get_rcvbuf(int sd) |
| { |
| #if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF) |
| int val; |
| socklen_t len; |
| |
| len = sizeof(val); |
| if (getsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &val, &len) == 0 |
| && len == sizeof(val)) |
| { |
| return val; |
| } |
| #endif |
| return 0; |
| } |
| |
| static bool |
| socket_set_rcvbuf(int sd, int size) |
| { |
| #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF) |
| if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof(size)) != 0) |
| { |
| msg(M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size); |
| return false; |
| } |
| return true; |
| #endif |
| } |
| |
| static void |
| socket_set_buffers(int fd, const struct socket_buffer_size *sbs) |
| { |
| if (sbs) |
| { |
| const int sndbuf_old = socket_get_sndbuf(fd); |
| const int rcvbuf_old = socket_get_rcvbuf(fd); |
| |
| if (sbs->sndbuf) |
| { |
| socket_set_sndbuf(fd, sbs->sndbuf); |
| } |
| |
| if (sbs->rcvbuf) |
| { |
| socket_set_rcvbuf(fd, sbs->rcvbuf); |
| } |
| |
| msg(D_OSBUF, "Socket Buffers: R=[%d->%d] S=[%d->%d]", |
| rcvbuf_old, |
| socket_get_rcvbuf(fd), |
| sndbuf_old, |
| socket_get_sndbuf(fd)); |
| } |
| } |
| |
| /* |
| * Set other socket options |
| */ |
| |
| static bool |
| socket_set_tcp_nodelay(int sd, int state) |
| { |
| #if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) |
| if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof(state)) != 0) |
| { |
| msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state); |
| return false; |
| } |
| else |
| { |
| dmsg(D_OSBUF, "Socket flags: TCP_NODELAY=%d succeeded", state); |
| return true; |
| } |
| #else /* if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) */ |
| msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed (No kernel support)", state); |
| return false; |
| #endif |
| } |
| |
| static inline void |
| socket_set_mark(int sd, int mark) |
| { |
| #if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK |
| if (mark && setsockopt(sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof(mark)) != 0) |
| { |
| msg(M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark); |
| } |
| #endif |
| } |
| |
| static bool |
| socket_set_flags(int sd, unsigned int sockflags) |
| { |
| if (sockflags & SF_TCP_NODELAY) |
| { |
| return socket_set_tcp_nodelay(sd, 1); |
| } |
| else |
| { |
| return true; |
| } |
| } |
| |
| bool |
| link_socket_update_flags(struct link_socket *ls, unsigned int sockflags) |
| { |
| if (ls && socket_defined(ls->sd)) |
| { |
| return socket_set_flags(ls->sd, ls->sockflags = sockflags); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| void |
| link_socket_update_buffer_sizes(struct link_socket *ls, int rcvbuf, int sndbuf) |
| { |
| if (ls && socket_defined(ls->sd)) |
| { |
| ls->socket_buffer_sizes.sndbuf = sndbuf; |
| ls->socket_buffer_sizes.rcvbuf = rcvbuf; |
| socket_set_buffers(ls->sd, &ls->socket_buffer_sizes); |
| } |
| } |
| |
| /* |
| * SOCKET INITALIZATION CODE. |
| * Create a TCP/UDP socket |
| */ |
| |
| socket_descriptor_t |
| create_socket_tcp(struct addrinfo *addrinfo) |
| { |
| socket_descriptor_t sd; |
| |
| ASSERT(addrinfo); |
| ASSERT(addrinfo->ai_socktype == SOCK_STREAM); |
| |
| 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! */ |
| /* set SO_REUSEADDR on socket */ |
| { |
| int on = 1; |
| if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, |
| (void *) &on, sizeof(on)) < 0) |
| { |
| msg(M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP socket"); |
| } |
| } |
| #endif |
| |
| /* set socket file descriptor to not pass across execs, so that |
| * scripts don't have access to it */ |
| set_cloexec(sd); |
| |
| return sd; |
| } |
| |
| static socket_descriptor_t |
| create_socket_udp(struct addrinfo *addrinfo, const unsigned int flags) |
| { |
| socket_descriptor_t sd; |
| |
| ASSERT(addrinfo); |
| ASSERT(addrinfo->ai_socktype == SOCK_DGRAM); |
| |
| 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 (addrinfo->ai_family == AF_INET) |
| { |
| #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) |
| if (setsockopt(sd, SOL_IP, IP_PKTINFO, |
| (void *)&pad, sizeof(pad)) < 0) |
| { |
| msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO"); |
| } |
| #elif defined(IP_RECVDSTADDR) |
| if (setsockopt(sd, IPPROTO_IP, IP_RECVDSTADDR, |
| (void *)&pad, sizeof(pad)) < 0) |
| { |
| msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR"); |
| } |
| #else /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */ |
| #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) |
| #endif |
| } |
| else if (addrinfo->ai_family == AF_INET6) |
| { |
| #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */ |
| if (setsockopt(sd, IPPROTO_IPV6, IPV6_PKTINFO, |
| (void *)&pad, sizeof(pad)) < 0) |
| #else |
| if (setsockopt(sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, |
| (void *)&pad, sizeof(pad)) < 0) |
| #endif |
| { msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");} |
| } |
| } |
| #endif /* if ENABLE_IP_PKTINFO */ |
| |
| /* set socket file descriptor to not pass across execs, so that |
| * scripts don't have access to it */ |
| set_cloexec(sd); |
| |
| return sd; |
| } |
| |
| static void |
| bind_local(struct link_socket *sock, const sa_family_t ai_family) |
| { |
| /* bind to local address/port */ |
| if (sock->bind_local) |
| { |
| if (sock->socks_proxy && sock->info.proto == PROTO_UDP) |
| { |
| socket_bind(sock->ctrl_sd, sock->info.lsa->bind_local, |
| ai_family, "SOCKS", false); |
| } |
| else |
| { |
| socket_bind(sock->sd, sock->info.lsa->bind_local, |
| ai_family, |
| "TCP/UDP", sock->info.bind_ipv6_only); |
| } |
| } |
| } |
| |
| static void |
| create_socket(struct link_socket *sock, struct addrinfo *addr) |
| { |
| if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM) |
| { |
| sock->sd = create_socket_udp(addr, sock->sockflags); |
| sock->sockflags |= SF_GETADDRINFO_DGRAM; |
| |
| /* Assume that control socket and data socket to the socks proxy |
| * are using the same IP family */ |
| if (sock->socks_proxy) |
| { |
| /* 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; |
| addrinfo_tmp.ai_socktype = SOCK_STREAM; |
| addrinfo_tmp.ai_protocol = IPPROTO_TCP; |
| sock->ctrl_sd = create_socket_tcp(&addrinfo_tmp); |
| } |
| } |
| else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM) |
| { |
| sock->sd = create_socket_tcp(addr); |
| } |
| else |
| { |
| ASSERT(0); |
| } |
| /* set socket buffers based on --sndbuf and --rcvbuf options */ |
| socket_set_buffers(sock->sd, &sock->socket_buffer_sizes); |
| |
| /* set socket to --mark packets with given value */ |
| socket_set_mark(sock->sd, sock->mark); |
| |
| bind_local(sock, addr->ai_family); |
| } |
| |
| #ifdef TARGET_ANDROID |
| static void |
| protect_fd_nonlocal(int fd, const struct sockaddr *addr) |
| { |
| /* pass socket FD to management interface to pass on to VPNService API |
| * as "protected socket" (exempt from being routed into tunnel) |
| */ |
| if (addr_local(addr)) |
| { |
| msg(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd); |
| return; |
| } |
| |
| msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd); |
| management->connection.fdtosend = fd; |
| management_android_control(management, "PROTECTFD", __func__); |
| } |
| #endif |
| |
| /* |
| * Functions used for establishing a TCP stream connection. |
| */ |
| static void |
| socket_do_listen(socket_descriptor_t sd, |
| const struct addrinfo *local, |
| bool do_listen, |
| bool do_set_nonblock) |
| { |
| struct gc_arena gc = gc_new(); |
| if (do_listen) |
| { |
| ASSERT(local); |
| msg(M_INFO, "Listening for incoming TCP connection on %s", |
| print_sockaddr(local->ai_addr, &gc)); |
| if (listen(sd, 32)) |
| { |
| msg(M_ERR, "TCP: listen() failed"); |
| } |
| } |
| |
| /* set socket to non-blocking mode */ |
| if (do_set_nonblock) |
| { |
| set_nonblock(sd); |
| } |
| |
| gc_free(&gc); |
| } |
| |
| socket_descriptor_t |
| socket_do_accept(socket_descriptor_t sd, |
| struct link_socket_actual *act, |
| const bool nowait) |
| { |
| /* af_addr_size WILL return 0 in this case if AFs other than AF_INET |
| * are compiled because act is empty here. |
| * could use getsockname() to support later remote_len check |
| */ |
| socklen_t remote_len_af = af_addr_size(act->dest.addr.sa.sa_family); |
| socklen_t remote_len = sizeof(act->dest.addr); |
| socket_descriptor_t new_sd = SOCKET_UNDEFINED; |
| |
| CLEAR(*act); |
| |
| #ifdef HAVE_GETPEERNAME |
| if (nowait) |
| { |
| new_sd = getpeername(sd, &act->dest.addr.sa, &remote_len); |
| |
| if (!socket_defined(new_sd)) |
| { |
| msg(D_LINK_ERRORS | M_ERRNO, "TCP: getpeername() failed"); |
| } |
| else |
| { |
| new_sd = sd; |
| } |
| } |
| #else /* ifdef HAVE_GETPEERNAME */ |
| if (nowait) |
| { |
| msg(M_WARN, "TCP: this OS does not provide the getpeername() function"); |
| } |
| #endif |
| else |
| { |
| new_sd = accept(sd, &act->dest.addr.sa, &remote_len); |
| } |
| |
| #if 0 /* For debugging only, test the effect of accept() failures */ |
| { |
| static int foo = 0; |
| ++foo; |
| if (foo & 1) |
| { |
| new_sd = -1; |
| } |
| } |
| #endif |
| |
| if (!socket_defined(new_sd)) |
| { |
| msg(D_LINK_ERRORS | M_ERRNO, "TCP: accept(%d) failed", (int)sd); |
| } |
| /* only valid if we have remote_len_af!=0 */ |
| else if (remote_len_af && remote_len != remote_len_af) |
| { |
| msg(D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len); |
| openvpn_close_socket(new_sd); |
| new_sd = SOCKET_UNDEFINED; |
| } |
| else |
| { |
| /* set socket file descriptor to not pass across execs, so that |
| * scripts don't have access to it */ |
| set_cloexec(sd); |
| } |
| return new_sd; |
| } |
| |
| static void |
| tcp_connection_established(const struct link_socket_actual *act) |
| { |
| struct gc_arena gc = gc_new(); |
| msg(M_INFO, "TCP connection established with %s", |
| print_link_socket_actual(act, &gc)); |
| gc_free(&gc); |
| } |
| |
| static socket_descriptor_t |
| socket_listen_accept(socket_descriptor_t sd, |
| struct link_socket_actual *act, |
| const char *remote_dynamic, |
| const struct addrinfo *local, |
| bool do_listen, |
| bool nowait, |
| volatile int *signal_received) |
| { |
| struct gc_arena gc = gc_new(); |
| /* struct openvpn_sockaddr *remote = &act->dest; */ |
| struct openvpn_sockaddr remote_verify = act->dest; |
| socket_descriptor_t new_sd = SOCKET_UNDEFINED; |
| |
| CLEAR(*act); |
| socket_do_listen(sd, local, do_listen, true); |
| |
| while (true) |
| { |
| int status; |
| fd_set reads; |
| struct timeval tv; |
| |
| FD_ZERO(&reads); |
| openvpn_fd_set(sd, &reads); |
| tv.tv_sec = 0; |
| tv.tv_usec = 0; |
| |
| status = select(sd + 1, &reads, NULL, NULL, &tv); |
| |
| get_signal(signal_received); |
| if (*signal_received) |
| { |
| gc_free(&gc); |
| return sd; |
| } |
| |
| if (status < 0) |
| { |
| msg(D_LINK_ERRORS | M_ERRNO, "TCP: select() failed"); |
| } |
| |
| if (status <= 0) |
| { |
| management_sleep(1); |
| continue; |
| } |
| |
| new_sd = socket_do_accept(sd, act, nowait); |
| |
| if (socket_defined(new_sd)) |
| { |
| struct addrinfo *ai = NULL; |
| if (remote_dynamic) |
| { |
| openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL, |
| remote_verify.addr.sa.sa_family, &ai); |
| } |
| |
| if (ai && !addrlist_match(&remote_verify, ai)) |
| { |
| msg(M_WARN, |
| "TCP NOTE: Rejected connection attempt from %s due to --remote setting", |
| print_link_socket_actual(act, &gc)); |
| if (openvpn_close_socket(new_sd)) |
| { |
| msg(M_ERR, "TCP: close socket failed (new_sd)"); |
| } |
| freeaddrinfo(ai); |
| } |
| else |
| { |
| if (ai) |
| { |
| freeaddrinfo(ai); |
| } |
| break; |
| } |
| } |
| management_sleep(1); |
| } |
| |
| if (!nowait && openvpn_close_socket(sd)) |
| { |
| msg(M_ERR, "TCP: close socket failed (sd)"); |
| } |
| |
| tcp_connection_established(act); |
| |
| gc_free(&gc); |
| return new_sd; |
| } |
| |
| /* older mingw versions and WinXP do not have this define, |
| * but Vista and up support the functionality - just define it here |
| */ |
| #ifdef _WIN32 |
| #ifndef IPV6_V6ONLY |
| #define IPV6_V6ONLY 27 |
| #endif |
| #endif |
| void |
| socket_bind(socket_descriptor_t sd, |
| struct addrinfo *local, |
| int ai_family, |
| const char *prefix, |
| bool ipv6only) |
| { |
| struct gc_arena gc = gc_new(); |
| |
| /* FIXME (schwabe) |
| * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6 |
| * entries for the requested protocol. |
| * For example if an address has multiple A records |
| * What is the correct way to deal with it? |
| */ |
| |
| struct addrinfo *cur; |
| |
| ASSERT(local); |
| |
| |
| /* find the first addrinfo with correct ai_family */ |
| for (cur = local; cur; cur = cur->ai_next) |
| { |
| if (cur->ai_family == ai_family) |
| { |
| break; |
| } |
| } |
| if (!cur) |
| { |
| msg(M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record", |
| prefix, addr_family_name(ai_family)); |
| } |
| |
| if (ai_family == AF_INET6) |
| { |
| int v6only = ipv6only ? 1 : 0; /* setsockopt must have an "int" */ |
| |
| msg(M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only); |
| if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only))) |
| { |
| msg(M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only); |
| } |
| } |
| if (bind(sd, cur->ai_addr, cur->ai_addrlen)) |
| { |
| msg(M_FATAL | M_ERRNO, "%s: Socket bind failed on local address %s", |
| prefix, |
| print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc)); |
| } |
| gc_free(&gc); |
| } |
| |
| int |
| openvpn_connect(socket_descriptor_t sd, |
| const struct sockaddr *remote, |
| int connect_timeout, |
| volatile int *signal_received) |
| { |
| int status = 0; |
| |
| #ifdef TARGET_ANDROID |
| protect_fd_nonlocal(sd, remote); |
| #endif |
| |
| #ifdef CONNECT_NONBLOCK |
| set_nonblock(sd); |
| status = connect(sd, remote, af_addr_size(remote->sa_family)); |
| if (status) |
| { |
| status = openvpn_errno(); |
| } |
| if ( |
| #ifdef _WIN32 |
| status == WSAEWOULDBLOCK |
| #else |
| status == EINPROGRESS |
| #endif |
| ) |
| { |
| while (true) |
| { |
| #if POLL |
| struct pollfd fds[1]; |
| fds[0].fd = sd; |
| fds[0].events = POLLOUT; |
| status = poll(fds, 1, 0); |
| #else |
| fd_set writes; |
| struct timeval tv; |
| |
| FD_ZERO(&writes); |
| openvpn_fd_set(sd, &writes); |
| tv.tv_sec = 0; |
| tv.tv_usec = 0; |
| |
| status = select(sd + 1, NULL, &writes, NULL, &tv); |
| #endif |
| if (signal_received) |
| { |
| get_signal(signal_received); |
| if (*signal_received) |
| { |
| status = 0; |
| break; |
| } |
| } |
| if (status < 0) |
| { |
| status = openvpn_errno(); |
| break; |
| } |
| if (status <= 0) |
| { |
| if (--connect_timeout < 0) |
| { |
| #ifdef _WIN32 |
| status = WSAETIMEDOUT; |
| #else |
| status = ETIMEDOUT; |
| #endif |
| break; |
| } |
| management_sleep(1); |
| continue; |
| } |
| |
| /* got it */ |
| { |
| int val = 0; |
| socklen_t len; |
| |
| len = sizeof(val); |
| if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (void *) &val, &len) == 0 |
| && len == sizeof(val)) |
| { |
| status = val; |
| } |
| else |
| { |
| status = openvpn_errno(); |
| } |
| break; |
| } |
| } |
| } |
| #else /* ifdef CONNECT_NONBLOCK */ |
| status = connect(sd, remote, af_addr_size(remote->sa_family)); |
| if (status) |
| { |
| status = openvpn_errno(); |
| } |
| #endif /* ifdef CONNECT_NONBLOCK */ |
| |
| return status; |
| } |
| |
| void |
| set_actual_address(struct link_socket_actual *actual, struct addrinfo *ai) |
| { |
| CLEAR(*actual); |
| ASSERT(ai); |
| |
| if (ai->ai_family == AF_INET) |
| { |
| actual->dest.addr.in4 = |
| *((struct sockaddr_in *) ai->ai_addr); |
| } |
| else if (ai->ai_family == AF_INET6) |
| { |
| actual->dest.addr.in6 = |
| *((struct sockaddr_in6 *) ai->ai_addr); |
| } |
| else |
| { |
| ASSERT(0); |
| } |
| |
| } |
| |
| static void |
| 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(); |
| int status; |
| |
| #ifdef CONNECT_NONBLOCK |
| msg(M_INFO, "Attempting to establish TCP connection with %s [nonblock]", |
| print_sockaddr(dest, &gc)); |
| #else |
| msg(M_INFO, "Attempting to establish TCP connection with %s", |
| print_sockaddr(dest, &gc)); |
| #endif |
| |
| #ifdef ENABLE_MANAGEMENT |
| if (management) |
| { |
| management_set_state(management, |
| OPENVPN_STATE_TCP_CONNECT, |
| NULL, |
| NULL, |
| NULL, |
| NULL, |
| NULL); |
| } |
| #endif |
| |
| /* Set the actual address */ |
| status = openvpn_connect(*sd, dest, connect_timeout, &sig_info->signal_received); |
| |
| get_signal(&sig_info->signal_received); |
| if (sig_info->signal_received) |
| { |
| goto done; |
| } |
| |
| if (status) |
| { |
| |
| msg(D_LINK_ERRORS, "TCP: connect to %s failed: %s", |
| print_sockaddr(dest, &gc), strerror(status)); |
| |
| openvpn_close_socket(*sd); |
| *sd = SOCKET_UNDEFINED; |
| sig_info->signal_received = SIGUSR1; |
| sig_info->source = SIG_SOURCE_CONNECTION_FAILED; |
| } |
| else |
| { |
| msg(M_INFO, "TCP connection established with %s", |
| print_sockaddr(dest, &gc)); |
| } |
| |
| done: |
| gc_free(&gc); |
| } |
| |
| /* For stream protocols, allocate a buffer to build up packet. |
| * Called after frame has been finalized. */ |
| |
| static void |
| socket_frame_init(const struct frame *frame, struct link_socket *sock) |
| { |
| #ifdef _WIN32 |
| overlapped_io_init(&sock->reads, frame, FALSE, false); |
| overlapped_io_init(&sock->writes, frame, TRUE, false); |
| sock->rw_handle.read = sock->reads.overlapped.hEvent; |
| sock->rw_handle.write = sock->writes.overlapped.hEvent; |
| #endif |
| |
| if (link_socket_connection_oriented(sock)) |
| { |
| #ifdef _WIN32 |
| stream_buf_init(&sock->stream_buf, |
| &sock->reads.buf_init, |
| sock->sockflags, |
| sock->info.proto); |
| #else |
| alloc_buf_sock_tun(&sock->stream_buf_data, |
| frame, |
| false, |
| FRAME_HEADROOM_MARKER_READ_STREAM); |
| |
| stream_buf_init(&sock->stream_buf, |
| &sock->stream_buf_data, |
| sock->sockflags, |
| sock->info.proto); |
| #endif |
| } |
| } |
| |
| /* |
| * Adjust frame structure based on a Path MTU value given |
| * to us by the OS. |
| */ |
| void |
| frame_adjust_path_mtu(struct frame *frame, int pmtu, int proto) |
| { |
| frame_set_mtu_dynamic(frame, pmtu - datagram_overhead(proto), SET_MTU_UPPER_BOUND); |
| } |
| |
| static void |
| resolve_bind_local(struct link_socket *sock, const sa_family_t af) |
| { |
| struct gc_arena gc = gc_new(); |
| |
| /* resolve local address if undefined */ |
| if (!sock->info.lsa->bind_local) |
| { |
| int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL |
| |GETADDR_FATAL | GETADDR_PASSIVE; |
| int status; |
| |
| if (proto_is_dgram(sock->info.proto)) |
| { |
| flags |= GETADDR_DATAGRAM; |
| } |
| |
| /* will return AF_{INET|INET6}from local_host */ |
| status = get_cached_dns_entry(sock->dns_cache, |
| sock->local_host, |
| sock->local_port, |
| af, |
| flags, |
| &sock->info.lsa->bind_local); |
| |
| if (status) |
| { |
| status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0, |
| NULL, af, &sock->info.lsa->bind_local); |
| } |
| |
| if (status !=0) |
| { |
| msg(M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s", |
| sock->local_host, sock->local_port, |
| gai_strerror(status)); |
| } |
| } |
| |
| gc_free(&gc); |
| } |
| |
| static void |
| resolve_remote(struct link_socket *sock, |
| int phase, |
| const char **remote_dynamic, |
| volatile int *signal_received) |
| { |
| struct gc_arena gc = gc_new(); |
| |
| /* resolve remote address if undefined */ |
| if (!sock->info.lsa->remote_list) |
| { |
| if (sock->remote_host) |
| { |
| unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); |
| int retry = 0; |
| int status = -1; |
| struct addrinfo *ai; |
| if (proto_is_dgram(sock->info.proto)) |
| { |
| flags |= GETADDR_DATAGRAM; |
| } |
| |
| if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) |
| { |
| if (phase == 2) |
| { |
| flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); |
| } |
| retry = 0; |
| } |
| else if (phase == 1) |
| { |
| if (sock->resolve_retry_seconds) |
| { |
| retry = 0; |
| } |
| else |
| { |
| flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY); |
| retry = 0; |
| } |
| } |
| else if (phase == 2) |
| { |
| if (sock->resolve_retry_seconds) |
| { |
| flags |= GETADDR_FATAL; |
| retry = sock->resolve_retry_seconds; |
| } |
| else |
| { |
| ASSERT(0); |
| } |
| } |
| else |
| { |
| ASSERT(0); |
| } |
| |
| |
| status = get_cached_dns_entry(sock->dns_cache, |
| sock->remote_host, |
| sock->remote_port, |
| sock->info.af, |
| flags, &ai); |
| if (status) |
| { |
| status = openvpn_getaddrinfo(flags, sock->remote_host, sock->remote_port, |
| retry, signal_received, sock->info.af, &ai); |
| } |
| |
| if (status == 0) |
| { |
| 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", |
| flags, |
| phase, |
| retry, |
| signal_received ? *signal_received : -1, |
| status); |
| } |
| if (signal_received) |
| { |
| if (*signal_received) |
| { |
| goto done; |
| } |
| } |
| if (status!=0) |
| { |
| if (signal_received) |
| { |
| *signal_received = SIGUSR1; |
| } |
| goto done; |
| } |
| } |
| } |
| |
| /* should we re-use previous active remote address? */ |
| if (link_socket_actual_defined(&sock->info.lsa->actual)) |
| { |
| msg(M_INFO, "TCP/UDP: Preserving recently used remote address: %s", |
| print_link_socket_actual(&sock->info.lsa->actual, &gc)); |
| if (remote_dynamic) |
| { |
| *remote_dynamic = NULL; |
| } |
| } |
| else |
| { |
| CLEAR(sock->info.lsa->actual); |
| if (sock->info.lsa->current_remote) |
| { |
| set_actual_address(&sock->info.lsa->actual, |
| sock->info.lsa->current_remote); |
| } |
| } |
| |
| done: |
| gc_free(&gc); |
| } |
| |
| |
| |
| struct link_socket * |
| link_socket_new(void) |
| { |
| struct link_socket *sock; |
| |
| ALLOC_OBJ_CLEAR(sock, struct link_socket); |
| sock->sd = SOCKET_UNDEFINED; |
| sock->ctrl_sd = SOCKET_UNDEFINED; |
| return sock; |
| } |
| |
| void |
| link_socket_init_phase1(struct link_socket *sock, |
| const char *local_host, |
| const char *local_port, |
| const char *remote_host, |
| const char *remote_port, |
| struct cached_dns_entry *dns_cache, |
| int proto, |
| sa_family_t af, |
| bool bind_ipv6_only, |
| int mode, |
| const struct link_socket *accept_from, |
| struct http_proxy_info *http_proxy, |
| struct socks_proxy_info *socks_proxy, |
| #ifdef ENABLE_DEBUG |
| int gremlin, |
| #endif |
| bool bind_local, |
| bool remote_float, |
| int inetd, |
| struct link_socket_addr *lsa, |
| const char *ipchange_command, |
| const struct plugin_list *plugins, |
| int resolve_retry_seconds, |
| int mtu_discover_type, |
| int rcvbuf, |
| int sndbuf, |
| int mark, |
| struct event_timeout *server_poll_timeout, |
| unsigned int sockflags) |
| { |
| ASSERT(sock); |
| |
| sock->local_host = local_host; |
| sock->local_port = local_port; |
| sock->remote_host = remote_host; |
| sock->remote_port = remote_port; |
| sock->dns_cache = dns_cache; |
| sock->http_proxy = http_proxy; |
| sock->socks_proxy = socks_proxy; |
| sock->bind_local = bind_local; |
| sock->inetd = inetd; |
| sock->resolve_retry_seconds = resolve_retry_seconds; |
| sock->mtu_discover_type = mtu_discover_type; |
| |
| #ifdef ENABLE_DEBUG |
| sock->gremlin = gremlin; |
| #endif |
| |
| sock->socket_buffer_sizes.rcvbuf = rcvbuf; |
| sock->socket_buffer_sizes.sndbuf = sndbuf; |
| |
| sock->sockflags = sockflags; |
| sock->mark = mark; |
| |
| sock->info.proto = proto; |
| sock->info.af = af; |
| sock->info.remote_float = remote_float; |
| sock->info.lsa = lsa; |
| sock->info.bind_ipv6_only = bind_ipv6_only; |
| sock->info.ipchange_command = ipchange_command; |
| sock->info.plugins = plugins; |
| sock->server_poll_timeout = server_poll_timeout; |
| |
| sock->mode = mode; |
| if (mode == LS_MODE_TCP_ACCEPT_FROM) |
| { |
| ASSERT(accept_from); |
| ASSERT(sock->info.proto == PROTO_TCP_SERVER); |
| ASSERT(!sock->inetd); |
| sock->sd = accept_from->sd; |
| /* inherit (possibly guessed) info AF from parent context */ |
| sock->info.af = accept_from->info.af; |
| } |
| |
| /* are we running in HTTP proxy mode? */ |
| if (sock->http_proxy) |
| { |
| ASSERT(sock->info.proto == PROTO_TCP_CLIENT); |
| ASSERT(!sock->inetd); |
| |
| /* the proxy server */ |
| sock->remote_host = http_proxy->options.server; |
| sock->remote_port = http_proxy->options.port; |
| |
| /* the OpenVPN server we will use the proxy to connect to */ |
| sock->proxy_dest_host = remote_host; |
| sock->proxy_dest_port = remote_port; |
| } |
| /* or in Socks proxy mode? */ |
| else if (sock->socks_proxy) |
| { |
| ASSERT(!sock->inetd); |
| |
| /* the proxy server */ |
| sock->remote_host = socks_proxy->server; |
| sock->remote_port = socks_proxy->port; |
| |
| /* the OpenVPN server we will use the proxy to connect to */ |
| sock->proxy_dest_host = remote_host; |
| sock->proxy_dest_port = remote_port; |
| } |
| else |
| { |
| sock->remote_host = remote_host; |
| sock->remote_port = remote_port; |
| } |
| |
| /* bind behavior for TCP server vs. client */ |
| if (sock->info.proto == PROTO_TCP_SERVER) |
| { |
| if (sock->mode == LS_MODE_TCP_ACCEPT_FROM) |
| { |
| sock->bind_local = false; |
| } |
| else |
| { |
| sock->bind_local = true; |
| } |
| } |
| |
| /* were we started by inetd or xinetd? */ |
| if (sock->inetd) |
| { |
| ASSERT(sock->info.proto != PROTO_TCP_CLIENT); |
| ASSERT(socket_defined(inetd_socket_descriptor)); |
| sock->sd = inetd_socket_descriptor; |
| set_cloexec(sock->sd); /* not created by create_socket*() */ |
| } |
| else if (mode != LS_MODE_TCP_ACCEPT_FROM) |
| { |
| if (sock->bind_local) |
| { |
| resolve_bind_local(sock, sock->info.af); |
| } |
| resolve_remote(sock, 1, NULL, NULL); |
| } |
| } |
| |
| static |
| void |
| phase2_inetd(struct link_socket *sock, const struct frame *frame, |
| const char *remote_dynamic, volatile int *signal_received) |
| { |
| bool remote_changed = false; |
| |
| if (sock->info.proto == PROTO_TCP_SERVER) |
| { |
| /* AF_INET as default (and fallback) for inetd */ |
| sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET; |
| #ifdef HAVE_GETSOCKNAME |
| { |
| /* inetd: hint family type for dest = local's */ |
| struct openvpn_sockaddr local_addr; |
| socklen_t addrlen = sizeof(local_addr); |
| if (getsockname(sock->sd, &local_addr.addr.sa, &addrlen) == 0) |
| { |
| sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family; |
| dmsg(D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)", |
| proto2ascii(sock->info.proto, sock->info.af, false), |
| local_addr.addr.sa.sa_family, (int)sock->sd); |
| } |
| else |
| { |
| msg(M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", |
| proto2ascii(sock->info.proto, sock->info.af, false), (int)sock->sd); |
| } |
| } |
| #else /* ifdef HAVE_GETSOCKNAME */ |
| msg(M_WARN, "inetd(%s): this OS does not provide the getsockname() " |
| "function, using AF_INET", |
| proto2ascii(sock->info.proto, false)); |
| #endif /* ifdef HAVE_GETSOCKNAME */ |
| sock->sd = |
| socket_listen_accept(sock->sd, |
| &sock->info.lsa->actual, |
| remote_dynamic, |
| sock->info.lsa->bind_local, |
| false, |
| sock->inetd == INETD_NOWAIT, |
| signal_received); |
| |
| } |
| ASSERT(!remote_changed); |
| } |
| |
| static void |
| phase2_set_socket_flags(struct link_socket *sock) |
| { |
| /* set misc socket parameters */ |
| socket_set_flags(sock->sd, sock->sockflags); |
| |
| /* set socket to non-blocking mode */ |
| set_nonblock(sock->sd); |
| |
| /* set Path MTU discovery options on the socket */ |
| set_mtu_discover_type(sock->sd, sock->mtu_discover_type, sock->info.af); |
| |
| #if EXTENDED_SOCKET_ERROR_CAPABILITY |
| /* if the OS supports it, enable extended error passing on the socket */ |
| set_sock_extended_error_passing(sock->sd); |
| #endif |
| } |
| |
| |
| static void |
| linksock_print_addr(struct link_socket *sock) |
| { |
| struct gc_arena gc = gc_new(); |
| const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO; |
| |
| /* print local address */ |
| if (sock->inetd) |
| { |
| msg(msglevel, "%s link local: [inetd]", proto2ascii(sock->info.proto, sock->info.af, true)); |
| } |
| else if (sock->bind_local) |
| { |
| 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 (!ai_family || ai_family == cur->ai_family) |
| { |
| break; |
| } |
| } |
| ASSERT(cur); |
| msg(msglevel, "%s link local (bound): %s", |
| proto2ascii(sock->info.proto, sock->info.af, true), |
| print_sockaddr(cur->ai_addr,&gc)); |
| } |
| else |
| { |
| msg(msglevel, "%s link local: (not bound)", |
| proto2ascii(sock->info.proto, sock->info.af, true)); |
| } |
| |
| /* print active remote address */ |
| msg(msglevel, "%s link remote: %s", |
| proto2ascii(sock->info.proto, sock->info.af, true), |
| print_link_socket_actual_ex(&sock->info.lsa->actual, |
| ":", |
| PS_SHOW_PORT_IF_DEFINED, |
| &gc)); |
| gc_free(&gc); |
| } |
| |
| static void |
| phase2_tcp_server(struct link_socket *sock, const char *remote_dynamic, |
| volatile int *signal_received) |
| { |
| switch (sock->mode) |
| { |
| case LS_MODE_DEFAULT: |
| sock->sd = socket_listen_accept(sock->sd, |
| &sock->info.lsa->actual, |
| remote_dynamic, |
| sock->info.lsa->bind_local, |
| true, |
| false, |
| signal_received); |
| break; |
| |
| case LS_MODE_TCP_LISTEN: |
| socket_do_listen(sock->sd, |
| sock->info.lsa->bind_local, |
| true, |
| false); |
| break; |
| |
| case LS_MODE_TCP_ACCEPT_FROM: |
| sock->sd = socket_do_accept(sock->sd, |
| &sock->info.lsa->actual, |
| false); |
| if (!socket_defined(sock->sd)) |
| { |
| *signal_received = SIGTERM; |
| return; |
| } |
| tcp_connection_established(&sock->info.lsa->actual); |
| break; |
| |
| default: |
| ASSERT(0); |
| } |
| } |
| |
| |
| static void |
| phase2_tcp_client(struct link_socket *sock, struct signal_info *sig_info) |
| { |
| bool proxy_retry = false; |
| do |
| { |
| socket_connect(&sock->sd, |
| sock->info.lsa->current_remote->ai_addr, |
| get_server_poll_remaining_time(sock->server_poll_timeout), |
| sig_info); |
| |
| if (sig_info->signal_received) |
| { |
| return; |
| } |
| |
| if (sock->http_proxy) |
| { |
| proxy_retry = establish_http_proxy_passthru(sock->http_proxy, |
| sock->sd, |
| sock->proxy_dest_host, |
| sock->proxy_dest_port, |
| sock->server_poll_timeout, |
| &sock->stream_buf.residual, |
| &sig_info->signal_received); |
| } |
| else if (sock->socks_proxy) |
| { |
| establish_socks_proxy_passthru(sock->socks_proxy, |
| sock->sd, |
| sock->proxy_dest_host, |
| sock->proxy_dest_port, |
| &sig_info->signal_received); |
| } |
| if (proxy_retry) |
| { |
| openvpn_close_socket(sock->sd); |
| sock->sd = create_socket_tcp(sock->info.lsa->current_remote); |
| } |
| |
| } while (proxy_retry); |
| |
| } |
| |
| static void |
| phase2_socks_client(struct link_socket *sock, struct signal_info *sig_info) |
| { |
| socket_connect(&sock->ctrl_sd, |
| sock->info.lsa->current_remote->ai_addr, |
| get_server_poll_remaining_time(sock->server_poll_timeout), |
| sig_info); |
| |
| if (sig_info->signal_received) |
| { |
| return; |
| } |
| |
| establish_socks_proxy_udpassoc(sock->socks_proxy, |
| sock->ctrl_sd, |
| sock->sd, |
| &sock->socks_relay.dest, |
| &sig_info->signal_received); |
| |
| if (sig_info->signal_received) |
| { |
| return; |
| } |
| |
| sock->remote_host = sock->proxy_dest_host; |
| sock->remote_port = sock->proxy_dest_port; |
| |
| addr_zero_host(&sock->info.lsa->actual.dest); |
| if (sock->info.lsa->remote_list) |
| { |
| freeaddrinfo(sock->info.lsa->remote_list); |
| sock->info.lsa->current_remote = NULL; |
| sock->info.lsa->remote_list = NULL; |
| } |
| |
| resolve_remote(sock, 1, NULL, &sig_info->signal_received); |
| } |
| |
| /* finalize socket initialization */ |
| void |
| link_socket_init_phase2(struct link_socket *sock, |
| const struct frame *frame, |
| struct signal_info *sig_info) |
| { |
| const char *remote_dynamic = NULL; |
| int sig_save = 0; |
| |
| ASSERT(sock); |
| ASSERT(sig_info); |
| |
| if (sig_info->signal_received) |
| { |
| sig_save = sig_info->signal_received; |
| sig_info->signal_received = 0; |
| } |
| |
| /* initialize buffers */ |
| socket_frame_init(frame, sock); |
| |
| /* |
| * Pass a remote name to connect/accept so that |
| * they can test for dynamic IP address changes |
| * and throw a SIGUSR1 if appropriate. |
| */ |
| if (sock->resolve_retry_seconds) |
| { |
| remote_dynamic = sock->remote_host; |
| } |
| |
| /* were we started by inetd or xinetd? */ |
| if (sock->inetd) |
| { |
| phase2_inetd(sock, frame, remote_dynamic, &sig_info->signal_received); |
| if (sig_info->signal_received) |
| { |
| goto done; |
| } |
| |
| } |
| else |
| { |
| /* 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->remote_host && sock->info.lsa->bind_local) |
| { |
| /* 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)); |
| sock->info.af = sock->info.lsa->bind_local->ai_family; |
| } |
| |
| create_socket(sock, sock->info.lsa->bind_local); |
| } |
| } |
| |
| /* 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->signal_received) |
| { |
| goto done; |
| } |
| |
| if (sock->info.proto == PROTO_TCP_SERVER) |
| { |
| phase2_tcp_server(sock, remote_dynamic, |
| &sig_info->signal_received); |
| } |
| else if (sock->info.proto == PROTO_TCP_CLIENT) |
| { |
| phase2_tcp_client(sock, sig_info); |
| |
| } |
| else if (sock->info.proto == PROTO_UDP && sock->socks_proxy) |
| { |
| phase2_socks_client(sock, sig_info); |
| } |
| #ifdef TARGET_ANDROID |
| if (sock->sd != -1) |
| { |
| protect_fd_nonlocal(sock->sd, &sock->info.lsa->actual.dest.addr.sa); |
| } |
| #endif |
| if (sig_info->signal_received) |
| { |
| goto done; |
| } |
| } |
| |
| phase2_set_socket_flags(sock); |
| linksock_print_addr(sock); |
| |
| done: |
| if (sig_save) |
| { |
| if (!sig_info->signal_received) |
| { |
| sig_info->signal_received = sig_save; |
| } |
| } |
| } |
| |
| void |
| link_socket_close(struct link_socket *sock) |
| { |
| if (sock) |
| { |
| #ifdef ENABLE_DEBUG |
| const int gremlin = GREMLIN_CONNECTION_FLOOD_LEVEL(sock->gremlin); |
| #else |
| const int gremlin = 0; |
| #endif |
| |
| if (socket_defined(sock->sd)) |
| { |
| #ifdef _WIN32 |
| close_net_event_win32(&sock->listen_handle, sock->sd, 0); |
| #endif |
| if (!gremlin) |
| { |
| msg(D_LOW, "TCP/UDP: Closing socket"); |
| if (openvpn_close_socket(sock->sd)) |
| { |
| msg(M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed"); |
| } |
| } |
| sock->sd = SOCKET_UNDEFINED; |
| #ifdef _WIN32 |
| if (!gremlin) |
| { |
| overlapped_io_close(&sock->reads); |
| overlapped_io_close(&sock->writes); |
| } |
| #endif |
| } |
| |
| if (socket_defined(sock->ctrl_sd)) |
| { |
| if (openvpn_close_socket(sock->ctrl_sd)) |
| { |
| msg(M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed"); |
| } |
| sock->ctrl_sd = SOCKET_UNDEFINED; |
| } |
| |
| stream_buf_close(&sock->stream_buf); |
| free_buf(&sock->stream_buf_data); |
| if (!gremlin) |
| { |
| free(sock); |
| } |
| } |
| } |
| |
| /* for stream protocols, allow for packet length prefix */ |
| void |
| socket_adjust_frame_parameters(struct frame *frame, int proto) |
| { |
| if (link_socket_proto_connection_oriented(proto)) |
| { |
| frame_add_to_extra_frame(frame, sizeof(packet_size_type)); |
| } |
| } |
| |
| void |
| setenv_trusted(struct env_set *es, const struct link_socket_info *info) |
| { |
| setenv_link_socket_actual(es, "trusted", &info->lsa->actual, SA_IP_PORT); |
| } |
| |
| static void |
| ipchange_fmt(const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc) |
| { |
| const char *host = print_sockaddr_ex(&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT, gc); |
| if (include_cmd) |
| { |
| argv_parse_cmd(argv, info->ipchange_command); |
| argv_printf_cat(argv, "%s", host); |
| } |
| else |
| { |
| argv_printf(argv, "%s", host); |
| } |
| |
| } |
| |
| void |
| link_socket_connection_initiated(const struct buffer *buf, |
| struct link_socket_info *info, |
| const struct link_socket_actual *act, |
| const char *common_name, |
| struct env_set *es) |
| { |
| struct gc_arena gc = gc_new(); |
| |
| info->lsa->actual = *act; /* Note: skip this line for --force-dest */ |
| setenv_trusted(es, info); |
| info->connection_established = true; |
| |
| /* Print connection initiated message, with common name if available */ |
| { |
| struct buffer out = alloc_buf_gc(256, &gc); |
| if (common_name) |
| { |
| buf_printf(&out, "[%s] ", common_name); |
| } |
| buf_printf(&out, "Peer Connection Initiated with %s", print_link_socket_actual(&info->lsa->actual, &gc)); |
| msg(M_INFO, "%s", BSTR(&out)); |
| } |
| |
| /* set environmental vars */ |
| setenv_str(es, "common_name", common_name); |
| |
| /* Process --ipchange plugin */ |
| if (plugin_defined(info->plugins, OPENVPN_PLUGIN_IPCHANGE)) |
| { |
| struct argv argv = argv_new(); |
| ipchange_fmt(false, &argv, info, &gc); |
| if (plugin_call(info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) |
| { |
| msg(M_WARN, "WARNING: ipchange plugin call failed"); |
| } |
| argv_reset(&argv); |
| } |
| |
| /* Process --ipchange option */ |
| if (info->ipchange_command) |
| { |
| struct argv argv = argv_new(); |
| setenv_str(es, "script_type", "ipchange"); |
| ipchange_fmt(true, &argv, info, &gc); |
| openvpn_run_script(&argv, es, 0, "--ipchange"); |
| argv_reset(&argv); |
| } |
| |
| gc_free(&gc); |
| } |
| |
| void |
| link_socket_bad_incoming_addr(struct buffer *buf, |
| const struct link_socket_info *info, |
| const struct link_socket_actual *from_addr) |
| { |
| struct gc_arena gc = gc_new(); |
| struct addrinfo *ai; |
| |
| switch (from_addr->dest.addr.sa.sa_family) |
| { |
| case AF_INET: |
| case AF_INET6: |
| msg(D_LINK_ERRORS, |
| "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)", |
| print_link_socket_actual(from_addr, &gc), |
| (int)from_addr->dest.addr.sa.sa_family, |
| print_sockaddr_ex(info->lsa->remote_list->ai_addr,":",PS_SHOW_PORT, &gc)); |
| /* print additional remote addresses */ |
| for (ai = info->lsa->remote_list->ai_next; ai; ai = ai->ai_next) |
| { |
| msg(D_LINK_ERRORS,"or from peer address: %s", |
| print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc)); |
| } |
| break; |
| } |
| buf->len = 0; |
| gc_free(&gc); |
| } |
| |
| void |
| link_socket_bad_outgoing_addr(void) |
| { |
| dmsg(D_READ_WRITE, "TCP/UDP: No outgoing address to send packet"); |
| } |
| |
| in_addr_t |
| link_socket_current_remote(const struct link_socket_info *info) |
| { |
| const struct link_socket_addr *lsa = info->lsa; |
| |
| /* |
| * This logic supports "redirect-gateway" semantic, which |
| * makes sense only for PF_INET routes over PF_INET endpoints |
| * |
| * Maybe in the future consider PF_INET6 endpoints also ... |
| * by now just ignore it |
| * |
| * For --remote entries with multiple addresses this |
| * only return the actual endpoint we have sucessfully connected to |
| */ |
| if (lsa->actual.dest.addr.sa.sa_family != AF_INET) |
| { |
| return IPV4_INVALID_ADDR; |
| } |
| |
| if (link_socket_actual_defined(&lsa->actual)) |
| { |
| return ntohl(lsa->actual.dest.addr.in4.sin_addr.s_addr); |
| } |
| else if (lsa->current_remote) |
| { |
| return ntohl(((struct sockaddr_in *)lsa->current_remote->ai_addr) |
| ->sin_addr.s_addr); |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| const struct in6_addr * |
| link_socket_current_remote_ipv6(const struct link_socket_info *info) |
| { |
| const struct link_socket_addr *lsa = info->lsa; |
| |
| /* This logic supports "redirect-gateway" semantic, |
| * for PF_INET6 routes over PF_INET6 endpoints |
| * |
| * For --remote entries with multiple addresses this |
| * only return the actual endpoint we have sucessfully connected to |
| */ |
| if (lsa->actual.dest.addr.sa.sa_family != AF_INET6) |
| { |
| return NULL; |
| } |
| |
| if (link_socket_actual_defined(&lsa->actual)) |
| { |
| return &(lsa->actual.dest.addr.in6.sin6_addr); |
| } |
| else if (lsa->current_remote) |
| { |
| return &(((struct sockaddr_in6 *)lsa->current_remote->ai_addr)->sin6_addr); |
| } |
| else |
| { |
| return NULL; |
| } |
| } |
| |
| /* |
| * Return a status string describing socket state. |
| */ |
| const char * |
| socket_stat(const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc) |
| { |
| struct buffer out = alloc_buf_gc(64, gc); |
| if (s) |
| { |
| if (rwflags & EVENT_READ) |
| { |
| buf_printf(&out, "S%s", |
| (s->rwflags_debug & EVENT_READ) ? "R" : "r"); |
| #ifdef _WIN32 |
| buf_printf(&out, "%s", |
| overlapped_io_state_ascii(&s->reads)); |
| #endif |
| } |
| if (rwflags & EVENT_WRITE) |
| { |
| buf_printf(&out, "S%s", |
| (s->rwflags_debug & EVENT_WRITE) ? "W" : "w"); |
| #ifdef _WIN32 |
| buf_printf(&out, "%s", |
| overlapped_io_state_ascii(&s->writes)); |
| #endif |
| } |
| } |
| else |
| { |
| buf_printf(&out, "S?"); |
| } |
| return BSTR(&out); |
| } |
| |
| /* |
| * Stream buffer functions, used to packetize a TCP |
| * stream connection. |
| */ |
| |
| static inline void |
| stream_buf_reset(struct stream_buf *sb) |
| { |
| dmsg(D_STREAM_DEBUG, "STREAM: RESET"); |
| sb->residual_fully_formed = false; |
| sb->buf = sb->buf_init; |
| buf_reset(&sb->next); |
| sb->len = -1; |
| } |
| |
| void |
| stream_buf_init(struct stream_buf *sb, |
| struct buffer *buf, |
| const unsigned int sockflags, |
| const int proto) |
| { |
| sb->buf_init = *buf; |
| sb->maxlen = sb->buf_init.len; |
| sb->buf_init.len = 0; |
| sb->residual = alloc_buf(sb->maxlen); |
| sb->error = false; |
| #if PORT_SHARE |
| sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER)) |
| ? PS_ENABLED |
| : PS_DISABLED; |
| #endif |
| stream_buf_reset(sb); |
| |
| dmsg(D_STREAM_DEBUG, "STREAM: INIT maxlen=%d", sb->maxlen); |
| } |
| |
| static inline void |
| stream_buf_set_next(struct stream_buf *sb) |
| { |
| /* set up 'next' for next i/o read */ |
| sb->next = sb->buf; |
| sb->next.offset = sb->buf.offset + sb->buf.len; |
| sb->next.len = (sb->len >= 0 ? sb->len : sb->maxlen) - sb->buf.len; |
| dmsg(D_STREAM_DEBUG, "STREAM: SET NEXT, buf=[%d,%d] next=[%d,%d] len=%d maxlen=%d", |
| sb->buf.offset, sb->buf.len, |
| sb->next.offset, sb->next.len, |
| sb->len, sb->maxlen); |
| ASSERT(sb->next.len > 0); |
| ASSERT(buf_safe(&sb->buf, sb->next.len)); |
| } |
| |
| static inline void |
| stream_buf_get_final(struct stream_buf *sb, struct buffer *buf) |
| { |
| dmsg(D_STREAM_DEBUG, "STREAM: GET FINAL len=%d", |
| buf_defined(&sb->buf) ? sb->buf.len : -1); |
| ASSERT(buf_defined(&sb->buf)); |
| *buf = sb->buf; |
| } |
| |
| static inline void |
| stream_buf_get_next(struct stream_buf *sb, struct buffer *buf) |
| { |
| dmsg(D_STREAM_DEBUG, "STREAM: GET NEXT len=%d", |
| buf_defined(&sb->next) ? sb->next.len : -1); |
| ASSERT(buf_defined(&sb->next)); |
| *buf = sb->next; |
| } |
| |
| bool |
| stream_buf_read_setup_dowork(struct link_socket *sock) |
| { |
| if (sock->stream_buf.residual.len && !sock->stream_buf.residual_fully_formed) |
| { |
| ASSERT(buf_copy(&sock->stream_buf.buf, &sock->stream_buf.residual)); |
| ASSERT(buf_init(&sock->stream_buf.residual, 0)); |
| sock->stream_buf.residual_fully_formed = stream_buf_added(&sock->stream_buf, 0); |
| dmsg(D_STREAM_DEBUG, "STREAM: RESIDUAL FULLY FORMED [%s], len=%d", |
| sock->stream_buf.residual_fully_formed ? "YES" : "NO", |
| sock->stream_buf.residual.len); |
| } |
| |
| if (!sock->stream_buf.residual_fully_formed) |
| { |
| stream_buf_set_next(&sock->stream_buf); |
| } |
| return !sock->stream_buf.residual_fully_formed; |
| } |
| |
| bool |
| stream_buf_added(struct stream_buf *sb, |
| int length_added) |
| { |
| dmsg(D_STREAM_DEBUG, "STREAM: ADD length_added=%d", length_added); |
| if (length_added > 0) |
| { |
| sb->buf.len += length_added; |
| } |
| |
| /* if length unknown, see if we can get the length prefix from |
| * the head of the buffer */ |
| if (sb->len < 0 && sb->buf.len >= (int) sizeof(packet_size_type)) |
| { |
| packet_size_type net_size; |
| |
| #if PORT_SHARE |
| if (sb->port_share_state == PS_ENABLED) |
| { |
| if (!is_openvpn_protocol(&sb->buf)) |
| { |
| msg(D_STREAM_ERRORS, "Non-OpenVPN client protocol detected"); |
| sb->port_share_state = PS_FOREIGN; |
| sb->error = true; |
| return false; |
| } |
| else |
| { |
| sb->port_share_state = PS_DISABLED; |
| } |
| } |
| #endif |
| |
| ASSERT(buf_read(&sb->buf, &net_size, sizeof(net_size))); |
| sb->len = ntohps(net_size); |
| |
| if (sb->len < 1 || sb->len > sb->maxlen) |
| { |
| msg(M_WARN, "WARNING: Bad encapsulated packet length from peer (%d), which must be > 0 and <= %d -- please ensure that --tun-mtu or --link-mtu is equal on both peers -- this condition could also indicate a possible active attack on the TCP link -- [Attempting restart...]", sb->len, sb->maxlen); |
| stream_buf_reset(sb); |
| sb->error = true; |
| return false; |
| } |
| } |
| |
| /* is our incoming packet fully read? */ |
| if (sb->len > 0 && sb->buf.len >= sb->len) |
| { |
| /* save any residual data that's part of the next packet */ |
| ASSERT(buf_init(&sb->residual, 0)); |
| if (sb->buf.len > sb->len) |
| { |
| ASSERT(buf_copy_excess(&sb->residual, &sb->buf, sb->len)); |
| } |
| dmsg(D_STREAM_DEBUG, "STREAM: ADD returned TRUE, buf_len=%d, residual_len=%d", |
| BLEN(&sb->buf), |
| BLEN(&sb->residual)); |
| return true; |
| } |
| else |
| { |
| dmsg(D_STREAM_DEBUG, "STREAM: ADD returned FALSE (have=%d need=%d)", sb->buf.len, sb->len); |
| stream_buf_set_next(sb); |
| return false; |
| } |
| } |
| |
| void |
| stream_buf_close(struct stream_buf *sb) |
| { |
| free_buf(&sb->residual); |
| } |
| |
| /* |
| * The listen event is a special event whose sole purpose is |
| * to tell us that there's a new incoming connection on a |
| * TCP socket, for use in server mode. |
| */ |
| event_t |
| socket_listen_event_handle(struct link_socket *s) |
| { |
| #ifdef _WIN32 |
| if (!defined_net_event_win32(&s->listen_handle)) |
| { |
| init_net_event_win32(&s->listen_handle, FD_ACCEPT, s->sd, 0); |
| } |
| return &s->listen_handle; |
| #else /* ifdef _WIN32 */ |
| return s->sd; |
| #endif |
| } |
| |
| /* |
| * Format IP addresses in ascii |
| */ |
| |
| const char * |
| print_sockaddr_ex(const struct sockaddr *sa, |
| const char *separator, |
| const unsigned int flags, |
| struct gc_arena *gc) |
| { |
| struct buffer out = alloc_buf_gc(128, gc); |
| bool addr_is_defined = false; |
| char hostaddr[NI_MAXHOST] = ""; |
| char servname[NI_MAXSERV] = ""; |
| int status; |
| |
| socklen_t salen = 0; |
| switch (sa->sa_family) |
| { |
| case AF_INET: |
| if (!(flags & PS_DONT_SHOW_FAMILY)) |
| { |
| buf_puts(&out, "[AF_INET]"); |
| } |
| salen = sizeof(struct sockaddr_in); |
| addr_is_defined = ((struct sockaddr_in *) sa)->sin_addr.s_addr != 0; |
| break; |
| |
| case AF_INET6: |
| if (!(flags & PS_DONT_SHOW_FAMILY)) |
| { |
| buf_puts(&out, "[AF_INET6]"); |
| } |
| salen = sizeof(struct sockaddr_in6); |
| addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) sa)->sin6_addr); |
| break; |
| |
| case AF_UNSPEC: |
| if (!(flags & PS_DONT_SHOW_FAMILY)) |
| { |
| return "[AF_UNSPEC]"; |
| } |
| else |
| { |
| return ""; |
| } |
| |
| default: |
| ASSERT(0); |
| } |
| |
| status = getnameinfo(sa, salen, hostaddr, sizeof(hostaddr), |
| servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV); |
| |
| if (status!=0) |
| { |
| buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status)); |
| return BSTR(&out); |
| } |
| |
| if (!(flags & PS_DONT_SHOW_ADDR)) |
| { |
| if (addr_is_defined) |
| { |
| buf_puts(&out, hostaddr); |
| } |
| else |
| { |
| buf_puts(&out, "[undef]"); |
| } |
| } |
| |
| if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED)) |
| { |
| if (separator) |
| { |
| buf_puts(&out, separator); |
| } |
| |
| buf_puts(&out, servname); |
| } |
| |
| return BSTR(&out); |
| } |
| |
| const char * |
| print_link_socket_actual(const struct link_socket_actual *act, struct gc_arena *gc) |
| { |
| return print_link_socket_actual_ex(act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc); |
| } |
| |
| #ifndef IF_NAMESIZE |
| #define IF_NAMESIZE 16 |
| #endif |
| |
| const char * |
| print_link_socket_actual_ex(const struct link_socket_actual *act, |
| const char *separator, |
| const unsigned int flags, |
| struct gc_arena *gc) |
| { |
| if (act) |
| { |
| char ifname[IF_NAMESIZE] = "[undef]"; |
| struct buffer out = alloc_buf_gc(128, gc); |
| buf_printf(&out, "%s", print_sockaddr_ex(&act->dest.addr.sa, separator, flags, gc)); |
| #if ENABLE_IP_PKTINFO |
| if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act)) |
| { |
| switch (act->dest.addr.sa.sa_family) |
| { |
| case AF_INET: |
| { |
| struct openvpn_sockaddr sa; |
| CLEAR(sa); |
| sa.addr.in4.sin_family = AF_INET; |
| #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) |
| sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst; |
| if_indextoname(act->pi.in4.ipi_ifindex, ifname); |
| #elif defined(IP_RECVDSTADDR) |
| sa.addr.in4.sin_addr = act->pi.in4; |
| ifname[0] = 0; |
| #else /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */ |
| #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) |
| #endif |
| buf_printf(&out, " (via %s%%%s)", |
| print_sockaddr_ex(&sa.addr.sa, separator, 0, gc), |
| ifname); |
| } |
| break; |
| |
| case AF_INET6: |
| { |
| struct sockaddr_in6 sin6; |
| char buf[INET6_ADDRSTRLEN] = "[undef]"; |
| CLEAR(sin6); |
| sin6.sin6_family = AF_INET6; |
| sin6.sin6_addr = act->pi.in6.ipi6_addr; |
| if_indextoname(act->pi.in6.ipi6_ifindex, ifname); |
| if (getnameinfo((struct sockaddr *)&sin6, sizeof(struct sockaddr_in6), |
| buf, sizeof(buf), NULL, 0, NI_NUMERICHOST) == 0) |
| { |
| buf_printf(&out, " (via %s%%%s)", buf, ifname); |
| } |
| else |
| { |
| buf_printf(&out, " (via [getnameinfo() err]%%%s)", ifname); |
| } |
| } |
| break; |
| } |
| } |
| #endif /* if ENABLE_IP_PKTINFO */ |
| return BSTR(&out); |
| } |
| else |
| { |
| return "[NULL]"; |
| } |
| } |
| |
| /* |
| * Convert an in_addr_t in host byte order |
| * to an ascii dotted quad. |
| */ |
| const char * |
| print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc) |
| { |
| struct in_addr ia; |
| struct buffer out = alloc_buf_gc(64, gc); |
| |
| if (addr || !(flags & IA_EMPTY_IF_UNDEF)) |
| { |
| CLEAR(ia); |
| ia.s_addr = (flags & IA_NET_ORDER) ? addr : htonl(addr); |
| |
| buf_printf(&out, "%s", inet_ntoa(ia)); |
| } |
| return BSTR(&out); |
| } |
| |
| /* |
| * Convert an in6_addr in host byte order |
| * to an ascii representation of an IPv6 address |
| */ |
| const char * |
| print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc) |
| { |
| struct buffer out = alloc_buf_gc(64, gc); |
| char tmp_out_buf[64]; /* inet_ntop wants pointer to buffer */ |
| |
| if (memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 |
| || !(flags & IA_EMPTY_IF_UNDEF)) |
| { |
| inet_ntop(AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1); |
| buf_printf(&out, "%s", tmp_out_buf ); |
| } |
| return BSTR(&out); |
| } |
| |
| #ifndef UINT8_MAX |
| #define UINT8_MAX 0xff |
| #endif |
| |
| /* add some offset to an ipv6 address |
| * (add in steps of 8 bits, taking overflow into next round) |
| */ |
| struct in6_addr |
| add_in6_addr( struct in6_addr base, uint32_t add ) |
| { |
| int i; |
| |
| for (i = 15; i>=0 && add > 0; i--) |
| { |
| register int carry; |
| register uint32_t h; |
| |
| h = (unsigned char) base.s6_addr[i]; |
| base.s6_addr[i] = (h+add) & UINT8_MAX; |
| |
| /* using explicit carry for the 8-bit additions will catch |
| * 8-bit and(!) 32-bit overruns nicely |
| */ |
| carry = ((h & 0xff) + (add & 0xff)) >> 8; |
| add = (add>>8) + carry; |
| } |
| return base; |
| } |
| |
| /* set environmental variables for ip/port in *addr */ |
| void |
| setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const unsigned int flags) |
| { |
| char name_buf[256]; |
| |
| char buf[128]; |
| switch (addr->addr.sa.sa_family) |
| { |
| case AF_INET: |
| if (flags & SA_IP_PORT) |
| { |
| openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix); |
| } |
| else |
| { |
| openvpn_snprintf(name_buf, sizeof(name_buf), "%s", name_prefix); |
| } |
| |
| setenv_str(es, name_buf, inet_ntoa(addr->addr.in4.sin_addr)); |
| |
| if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port) |
| { |
| openvpn_snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix); |
| setenv_int(es, name_buf, ntohs(addr->addr.in4.sin_port)); |
| } |
| break; |
| |
| case AF_INET6: |
| if (IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr )) |
| { |
| struct in_addr ia; |
| memcpy(&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12], |
| sizeof(ia.s_addr)); |
| openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix); |
| openvpn_snprintf(buf, sizeof(buf), "%s", inet_ntoa(ia) ); |
| } |
| else |
| { |
| openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip6", name_prefix); |
| getnameinfo(&addr->addr.sa, sizeof(struct sockaddr_in6), |
| buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); |
| } |
| setenv_str(es, name_buf, buf); |
| |
| if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port) |
| { |
| openvpn_snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix); |
| setenv_int(es, name_buf, ntohs(addr->addr.in6.sin6_port)); |
| } |
| break; |
| } |
| } |
| |
| void |
| setenv_in_addr_t(struct env_set *es, const char *name_prefix, in_addr_t addr, const unsigned int flags) |
| { |
| if (addr || !(flags & SA_SET_IF_NONZERO)) |
| { |
| struct openvpn_sockaddr si; |
| CLEAR(si); |
| si.addr.in4.sin_family = AF_INET; |
| si.addr.in4.sin_addr.s_addr = htonl(addr); |
| setenv_sockaddr(es, name_prefix, &si, flags); |
| } |
| } |
| |
| void |
| setenv_in6_addr(struct env_set *es, |
| const char *name_prefix, |
| const struct in6_addr *addr, |
| const unsigned int flags) |
| { |
| if (!IN6_IS_ADDR_UNSPECIFIED(addr) || !(flags & SA_SET_IF_NONZERO)) |
| { |
| struct openvpn_sockaddr si; |
| CLEAR(si); |
| si.addr.in6.sin6_family = AF_INET6; |
| si.addr.in6.sin6_addr = *addr; |
| setenv_sockaddr(es, name_prefix, &si, flags); |
| } |
| } |
| |
| void |
| setenv_link_socket_actual(struct env_set *es, |
| const char *name_prefix, |
| const struct link_socket_actual *act, |
| const unsigned int flags) |
| { |
| setenv_sockaddr(es, name_prefix, &act->dest, flags); |
| } |
| |
| /* |
| * Convert protocol names between index and ascii form. |
| */ |
| |
| struct proto_names { |
| const char *short_form; |
| const char *display_form; |
| sa_family_t proto_af; |
| int proto; |
| }; |
| |
| /* Indexed by PROTO_x */ |
| static const struct proto_names proto_names[] = { |
| {"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}, |
| /* 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}, |
| /* 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}, |
| }; |
| |
| bool |
| proto_is_net(int proto) |
| { |
| if (proto < 0 || proto >= PROTO_N) |
| { |
| ASSERT(0); |
| } |
| return proto != PROTO_NONE; |
| } |
| bool |
| proto_is_dgram(int proto) |
| { |
| return proto_is_udp(proto); |
| } |
| |
| bool |
| proto_is_udp(int proto) |
| { |
| if (proto < 0 || proto >= PROTO_N) |
| { |
|