From bf13e848dc3de1b5cf0143d823f8a86a53ac71b8 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 19 Nov 2013 15:43:11 +0100 Subject: Update dual stack patch set, workaround for Android 4.4 --- openvpn/.gitignore | 1 + openvpn/configure.ac | 8 +- openvpn/doc/openvpn.8 | 20 +- openvpn/src/openvpn/forward-inline.h | 1 - openvpn/src/openvpn/init.c | 20 +- openvpn/src/openvpn/manage.c | 27 ++- openvpn/src/openvpn/manage.h | 5 + openvpn/src/openvpn/options.c | 26 ++- openvpn/src/openvpn/options.h | 1 + openvpn/src/openvpn/proxy.c | 86 ++++----- openvpn/src/openvpn/ps.c | 4 +- openvpn/src/openvpn/socket.c | 347 ++++++++++++++++++----------------- openvpn/src/openvpn/socket.h | 36 ++-- openvpn/src/openvpn/ssl.c | 3 +- openvpn/src/openvpn/ssl_openssl.c | 27 ++- openvpn/src/openvpn/tun.c | 64 +++++-- 16 files changed, 390 insertions(+), 286 deletions(-) diff --git a/openvpn/.gitignore b/openvpn/.gitignore index a04afff7..3a2f3842 100644 --- a/openvpn/.gitignore +++ b/openvpn/.gitignore @@ -54,3 +54,4 @@ tests/t_client.sh tests/t_client-*-20??????-??????/ src/openvpn/openvpn config-version.h +nbproject diff --git a/openvpn/configure.ac b/openvpn/configure.ac index 65c639c5..b181f6d6 100644 --- a/openvpn/configure.ac +++ b/openvpn/configure.ac @@ -754,7 +754,9 @@ PKG_CHECK_MODULES( [ have_openssl_ssl="yes" OPENSSL_SSL_LIBS="-lssl" - ] + ], + [], + [-lcrypto] )] ) @@ -812,13 +814,13 @@ if test "${with_crypto_library}" = "polarssl" ; then #include ]], [[ -#if POLARSSL_VERSION_NUMBER < 0x01020500 +#if POLARSSL_VERSION_NUMBER < 0x01020A00 || POLARSSL_VERSION_NUMBER >= 0x01030000 #error invalid version #endif ]] )], [AC_MSG_RESULT([ok])], - [AC_MSG_ERROR([PolarSSL 1.2.5 or newer required])] + [AC_MSG_ERROR([PolarSSL 1.2.x required and must be 1.2.10 or later])] ) polarssl_with_pkcs11="no" diff --git a/openvpn/doc/openvpn.8 b/openvpn/doc/openvpn.8 index 55152c1c..fba477ba 100644 --- a/openvpn/doc/openvpn.8 +++ b/openvpn/doc/openvpn.8 @@ -221,6 +221,9 @@ options. indicates the protocol to use when connecting with the remote, and may be "tcp" or "udp". +For forcing IPv4 or IPv6 connection suffix tcp or udp +with 4/6 like udp4/udp6/tcp4/tcp6. + The client will move on to the next host in the list, in the event of connection failure. Note that at any given time, the OpenVPN client @@ -553,19 +556,22 @@ Set HTTP "User-Agent" string to .B user-agent. .B CUSTOM\-HEADER name content \-\- -Adds the custom Header with +Adds the custom Header with .B name -as name and +as name and .B content as the content of the custom HTTP header. .\"********************************************************* .TP -.B \-\-socks-proxy server [port] +.B \-\-socks-proxy server [port] [authfile] Connect to remote host through a Socks5 proxy at address .B server and port .B port (default=1080). +.B authfile +(optional) is a file containing a username and password on 2 lines, or +"stdin" to prompt from console. .\"********************************************************* .TP .B \-\-socks-proxy-retry @@ -678,7 +684,7 @@ TCP/UDP port number or name for bind. TCP/UDP port number or name for remote. .\"********************************************************* .TP -.B \-\-bind +.B \-\-bind [ipv6only] Bind to local address and port. This is the default unless any of .B \-\-proto tcp-client , @@ -686,6 +692,12 @@ Bind to local address and port. This is the default unless any of or .B \-\-socks-proxy are used. + +If the +.B \-\-ipv6only +keyword is present OpenVPN will bind only to IPv6 (as oposed +to IPv6 and IPv4) when a IPv6 socket is opened. + .\"********************************************************* .TP .B \-\-nobind diff --git a/openvpn/src/openvpn/forward-inline.h b/openvpn/src/openvpn/forward-inline.h index 7eb480dd..5853ce29 100644 --- a/openvpn/src/openvpn/forward-inline.h +++ b/openvpn/src/openvpn/forward-inline.h @@ -228,7 +228,6 @@ context_reschedule_sec (struct context *c, int sec) static inline struct link_socket_info * get_link_socket_info (struct context *c) { - if (c->c2.link_socket_info) return c->c2.link_socket_info; else diff --git a/openvpn/src/openvpn/init.c b/openvpn/src/openvpn/init.c index 8cd136d5..7c9bf048 100644 --- a/openvpn/src/openvpn/init.c +++ b/openvpn/src/openvpn/init.c @@ -284,6 +284,7 @@ static void init_connection_list (struct context *c) { struct connection_list *l = c->options.connection_list; + l->current = -1; if (c->options.remote_random) { @@ -1425,10 +1426,10 @@ do_open_tun (struct context *c) #ifdef TARGET_ANDROID /* If we emulate persist-tun on android we still have to open a new tun and - then close the old */ + * then close the old */ int oldtunfd=-1; if (c->c1.tuntap) - oldtunfd = c->c1.tuntap->fd; + oldtunfd = c->c1.tuntap->fd; #endif /* initialize (but do not open) tun/tap object */ @@ -1462,14 +1463,14 @@ do_open_tun (struct context *c) do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, c->c1.tuntap, c->plugins, c->c2.es); } - +#ifdef TARGET_ANDROID + /* Store the old fd inside the fd so open_tun can use it */ + c->c1.tuntap->fd = oldtunfd; +#endif /* open the tun device */ open_tun (c->options.dev, c->options.dev_type, c->options.dev_node, c->c1.tuntap); -#ifdef TARGET_ANDROID - if (oldtunfd>=0) - close(oldtunfd); -#endif + /* set the hardware address */ if (c->options.lladdr) set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es); @@ -1580,7 +1581,7 @@ do_close_tun (struct context *c, bool force) /* delete any routes we added */ if (c->c1.route_list || c->c1.route_ipv6_list ) - { + { run_up_down (c->options.route_predown_script, c->plugins, OPENVPN_PLUGIN_ROUTE_PREDOWN, @@ -2688,7 +2689,8 @@ do_init_socket_1 (struct context *c, const int mode) c->options.ce.remote, c->options.ce.remote_port, c->options.ce.proto, - c->options.ce.af, + c->options.ce.af, + c->options.ce.bind_ipv6_only, mode, c->c2.accept_from, #ifdef ENABLE_HTTP_PROXY diff --git a/openvpn/src/openvpn/manage.c b/openvpn/src/openvpn/manage.c index 23e76527..8217ead2 100644 --- a/openvpn/src/openvpn/manage.c +++ b/openvpn/src/openvpn/manage.c @@ -1570,7 +1570,7 @@ man_listen (struct management *man) { man->connection.sd_top = create_socket_tcp (AF_INET); socket_bind (man->connection.sd_top, man->settings.local, - AF_INET, "MANAGEMENT"); + AF_INET, "MANAGEMENT", true); } /* @@ -1864,6 +1864,31 @@ bool management_android_control (struct management *man, const char *command, co management_query_user_pass(management, &up , command, GET_USER_PASS_NEED_OK,(void*) 0); return strcmp ("ok", up.password)==0; } + +/* + * In Android 4.4 it is not possible to open a new tun device and then close the + * old tun device without breaking the whole VPNService stack until the device + * is reported. This management method ask the UI what method should be taken to + * ensure the optimal solution for the situation + */ +int managment_android_persisttun_action (struct management *man) +{ + struct user_pass up; + CLEAR(up); + strcpy(up.username,"tunmethod"); + management_query_user_pass(management, &up , "PERSIST_TUN_ACTION", + GET_USER_PASS_NEED_OK,(void*) 0); + if (!strcmp("NOACTION", up.password)) + return ANDROID_KEEP_OLD_TUN; + else if (!strcmp ("OPEN_AFTER_CLOSE", up.password)) + return ANDROID_OPEN_AFTER_CLOSE; + else if (!strcmp ("OPEN_BEFORE_CLOSE", up.password)) + return ANDROID_OPEN_BEFORE_CLOSE; + else + ASSERT (0); +} + + #endif static int diff --git a/openvpn/src/openvpn/manage.h b/openvpn/src/openvpn/manage.h index dc3ade10..f5a621b7 100644 --- a/openvpn/src/openvpn/manage.h +++ b/openvpn/src/openvpn/manage.h @@ -378,6 +378,11 @@ bool management_query_user_pass (struct management *man, #ifdef TARGET_ANDROID bool management_android_control (struct management *man, const char *command, const char *msg); + +#define ANDROID_KEEP_OLD_TUN 1 +#define ANDROID_OPEN_AFTER_CLOSE 2 +#define ANDROID_OPEN_BEFORE_CLOSE 3 +int managment_android_persisttun_action (struct management *man); #endif bool management_should_daemonize (struct management *man); diff --git a/openvpn/src/openvpn/options.c b/openvpn/src/openvpn/options.c index 66fb8962..89a5888d 100644 --- a/openvpn/src/openvpn/options.c +++ b/openvpn/src/openvpn/options.c @@ -780,6 +780,7 @@ init_options (struct options *o, const bool init_gc) o->topology = TOP_NET30; o->ce.proto = PROTO_UDP; o->ce.af = AF_UNSPEC; + o->ce.bind_local=false; o->ce.connect_retry_seconds = 5; o->ce.connect_timeout = 10; o->connect_retry_max = 0; @@ -2037,8 +2038,12 @@ options_postprocess_verify_ce (const struct options *options, const struct conne if (ce->socks_proxy_server) msg (M_USAGE, "--socks-proxy cannot be used with --mode server"); #endif - if (options->connection_list) - msg (M_USAGE, " cannot be used with --mode server"); + /* blocks force to have a remote embedded, so we check for the + * --remote and bail out if it is present */ + if (options->connection_list->len >1 || + options->connection_list->array[0]->remote) + msg (M_USAGE, " cannot be used with --mode server"); + #if 0 if (options->tun_ipv6) msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server"); @@ -4446,14 +4451,14 @@ add_option (struct options *options, if (p[3]) { const int proto = ascii2proto (p[3]); - const sa_family_t af = ascii2af (p[3]); + const sa_family_t af = ascii2af (p[3]); if (proto < 0) { msg (msglevel, "remote: bad protocol associated with host %s: '%s'", p[1], p[3]); goto err; } re.proto = proto; - re.af = af; + re.af = af; } } if (permission_mask & OPT_P_GENERAL) @@ -4875,6 +4880,9 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.bind_defined = true; + if (p[1] && streq (p[1], "ipv6only")) + options->ce.bind_ipv6_only=true; + } else if (streq (p[0], "nobind")) { @@ -5000,10 +5008,10 @@ add_option (struct options *options, else if ((streq (p[1], "EXT1") || streq(p[1], "EXT2") || streq(p[1], "CUSTOM-HEADER")) && p[2]) { - /* In the wild patched versions use both EXT1/2 and CUSTOM-HEADER with either two - * argument or one */ + /* In the wild patched versions use both EXT1/2 and CUSTOM-HEADER + * with either two argument or one */ - struct http_custom_header *custom_header =NULL; + struct http_custom_header *custom_header = NULL; int i; /* Find the first free header */ for (i=0; i < MAX_CUSTOM_HTTP_HEADER; i++) { @@ -5014,11 +5022,11 @@ add_option (struct options *options, } if (!custom_header) { - msg (msglevel, "Cannot use more than %d http-proxy-option CUSTOM-HEAER : '%s'", MAX_CUSTOM_HTTP_HEADER, p[1]); + msg (msglevel, "Cannot use more than %d http-proxy-option CUSTOM-HEADER : '%s'", MAX_CUSTOM_HTTP_HEADER, p[1]); } else { - /* We will save p[2] and p[3], the proxy code will detect if + /* We will save p[2] and p[3], the proxy code will detect if * p[3] is NULL */ custom_header->name = p[2]; custom_header->content = p[3]; diff --git a/openvpn/src/openvpn/options.h b/openvpn/src/openvpn/options.h index 99877da7..4e97a192 100644 --- a/openvpn/src/openvpn/options.h +++ b/openvpn/src/openvpn/options.h @@ -95,6 +95,7 @@ struct connection_entry const char *remote; bool remote_float; bool bind_defined; + bool bind_ipv6_only; bool bind_local; int connect_retry_seconds; int connect_timeout; diff --git a/openvpn/src/openvpn/proxy.c b/openvpn/src/openvpn/proxy.c index db26994c..f7f06487 100644 --- a/openvpn/src/openvpn/proxy.c +++ b/openvpn/src/openvpn/proxy.c @@ -489,37 +489,50 @@ http_proxy_close (struct http_proxy_info *hp) } bool -add_proxy_header (struct http_proxy_info *p, +add_proxy_headers (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ - const char *port /* openvpn server port */ + const char* port /* openvpn server port */ ) { char buf[512]; int i; - bool hostheadercustom=false; - - /* Check if any of the custom headers already provides Host: */ - i=0; + bool host_header_sent=false; + + /* + * Send custom headers if provided + * If content is NULL the whole header is in name + * Also remember if we already sent a Host: header + */ for (i=0; i < MAX_CUSTOM_HTTP_HEADER && p->options.custom_headers[i].name;i++) { - if( - ((!strcasecmp(p->options.custom_headers[i].name, "Host")) && - (p->options.custom_headers[i].content)) - || - ((!strncasecmp(p->options.custom_headers[i].name, "Host:", 5)) && - p->options.custom_headers[i].content == NULL) - ) - hostheadercustom=true; - i++; + if (p->options.custom_headers[i].content) + { + openvpn_snprintf (buf, sizeof(buf), "%s: %s", + p->options.custom_headers[i].name, + p->options.custom_headers[i].content); + if (!strcasecmp(p->options.custom_headers[i].name, "Host")) + host_header_sent=true; + } + else + { + openvpn_snprintf (buf, sizeof(buf), "%s", + p->options.custom_headers[i].name); + if (!strncasecmp(p->options.custom_headers[i].name, "Host:", 5)) + host_header_sent=true; + } + + msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); + if (!send_line_crlf (sd, buf)) + return false; } - if (!hostheadercustom) + if (!host_header_sent) { - openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf(sd, buf)) - return false; + openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); + msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); + if (!send_line_crlf(sd, buf)) + return false; } /* send User-Agent string if provided */ @@ -532,26 +545,6 @@ add_proxy_header (struct http_proxy_info *p, return false; } - /* - * Send custom headers if provided - * If content is NULL whole header is in name - */ - for (i=0; i < MAX_CUSTOM_HTTP_HEADER && p->options.custom_headers[i].name;i++) - { - if (p->options.custom_headers[i].content) - openvpn_snprintf (buf, sizeof(buf), "%s: %s", - p->options.custom_headers[i].name, - p->options.custom_headers[i].content); - else - openvpn_snprintf (buf, sizeof(buf), "%s", - p->options.custom_headers[i].name); - - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - return false; - i++; - } - return true; } @@ -598,9 +591,9 @@ establish_http_proxy_passthru (struct http_proxy_info *p, /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; - - if(!add_proxy_header (p, sd, host, port)) - goto error; + + if (!add_proxy_headers (p, sd, host, port)) + goto error; /* auth specified? */ switch (p->auth_method) @@ -715,9 +708,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p, if (!send_line_crlf (sd, buf)) goto error; - /* send HOST etc, */ - if(!add_proxy_header (p, sd, host, port)) + if (!add_proxy_headers (p, sd, host, port)) goto error; msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); @@ -826,8 +818,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p, goto error; /* send HOST etc, */ - if(!add_proxy_header (p, sd, host, port)) - goto error; + if (!add_proxy_headers (p, sd, host, port)) + goto error; /* send digest response */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s", diff --git a/openvpn/src/openvpn/ps.c b/openvpn/src/openvpn/ps.c index c1868642..a57ac547 100644 --- a/openvpn/src/openvpn/ps.c +++ b/openvpn/src/openvpn/ps.c @@ -408,20 +408,18 @@ proxy_entry_new (struct proxy_connection **list, struct buffer *initial_data, const char *journal_dir) { - struct openvpn_sockaddr osaddr; socket_descriptor_t sd_server; int status; struct proxy_connection *pc; struct proxy_connection *cp; /* connect to port share server */ - osaddr.addr.in4 = server_addr; if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { msg (M_WARN|M_ERRNO, "PORT SHARE PROXY: cannot create socket"); return false; } - status = openvpn_connect (sd_server, &osaddr, 5, NULL); + status = openvpn_connect (sd_server,(const struct sockaddr*) &server_addr, 5, NULL); if (status) { msg (M_WARN, "PORT SHARE PROXY: connect to port-share server failed"); diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c index 0898babe..c5f085f8 100644 --- a/openvpn/src/openvpn/socket.c +++ b/openvpn/src/openvpn/socket.c @@ -663,10 +663,9 @@ create_socket (struct link_socket *sock) { /* create socket, use information carried over from getaddrinfo */ const int ai_proto = sock->info.lsa->actual.ai_protocol; - const int ai_family = sock->info.lsa->actual.ai_family; - - ASSERT (sock->info.af == AF_UNSPEC || sock->info.af == ai_family); + int ai_family = sock->info.lsa->actual.ai_family; + ASSERT (sock->info.af == AF_UNSPEC || sock->info.af == ai_family); if (ai_proto == IPPROTO_UDP) { @@ -889,7 +888,8 @@ void socket_bind (socket_descriptor_t sd, struct addrinfo *local, int ai_family, - const char *prefix) + const char *prefix, + bool ipv6only) { struct gc_arena gc = gc_new (); @@ -900,8 +900,11 @@ socket_bind (socket_descriptor_t sd, * What is the correct way to deal with it? */ - ASSERT(local); struct addrinfo* cur; + int v6only= ipv6only ? 0: 1; + + ASSERT(local); + /* find the first addrinfo with correct ai_family */ for (cur = local; cur; cur=cur->ai_next) @@ -912,7 +915,14 @@ socket_bind (socket_descriptor_t sd, 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) + { + if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only))) + { + msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY failed"); + } + } if (bind (sd, cur->ai_addr, cur->ai_addrlen)) { const int errnum = openvpn_errno (); @@ -1138,19 +1148,20 @@ resolve_bind_local (struct link_socket *sock, const sa_family_t af) if (!sock->info.lsa->bind_local) { int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | - GETADDR_FATAL | GETADDR_PASSIVE; + GETADDR_FATAL | GETADDR_PASSIVE; int status; - + if(proto_is_dgram(sock->info.proto)) - flags |= GETADDR_DATAGRAM; - + flags |= GETADDR_DATAGRAM; + /* will return AF_{INET|INET6}from local_host */ status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0, - NULL, af, &sock->info.lsa->bind_local); + 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)); + msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s", + sock->local_host, sock->local_port, + gai_strerror(status)); } } @@ -1165,11 +1176,12 @@ static void bind_local (struct link_socket *sock) #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"); + 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.lsa->actual.ai_family, + "TCP/UDP", sock->info.bind_ipv6_only); } } @@ -1306,11 +1318,12 @@ create_new_socket (struct link_socket* sock) 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.af && sock->info.lsa->actual.ai_family==0 && sock->bind_local) + 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); @@ -1321,7 +1334,7 @@ create_new_socket (struct link_socket* sock) /* * Create the socket early if socket should be bound */ - if (sock->bind_local && sock->info.lsa->actual.ai_family) + if (sock->bind_local) { create_socket (sock); @@ -1339,7 +1352,8 @@ link_socket_init_phase1 (struct link_socket *sock, const char *remote_host, const char *remote_port, int proto, - sa_family_t af, + sa_family_t af, + bool bind_ipv6_only, int mode, const struct link_socket *accept_from, #ifdef ENABLE_HTTP_PROXY @@ -1400,6 +1414,7 @@ link_socket_init_phase1 (struct link_socket *sock, 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; @@ -1452,7 +1467,7 @@ link_socket_init_phase1 (struct link_socket *sock, } /* bind behavior for TCP server vs. client */ - if (sock->info.proto == PROTO_TCP_SERVER && sock->info.af==AF_INET) + if (sock->info.proto == PROTO_TCP_SERVER) { if (sock->mode == LS_MODE_TCP_ACCEPT_FROM) sock->bind_local = false; @@ -1475,7 +1490,7 @@ link_socket_init_phase1 (struct link_socket *sock, static void phase2_inetd (struct link_socket* sock, const struct frame *frame, - const char *remote_dynamic, volatile int *signal_received) + const char *remote_dynamic, volatile int *signal_received) { bool remote_changed = false; @@ -1488,27 +1503,28 @@ void phase2_inetd (struct link_socket* sock, const struct frame *frame, 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, - sock->sd); + 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, sock->sd); } else - msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", - proto2ascii(sock->info.proto, sock->info.af, false), sock->sd); + msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", + proto2ascii(sock->info.proto, sock->info.af, false), sock->sd); } #else msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() " - "function, using AF_INET", - proto2ascii(sock->info.proto, false)); + "function, using AF_INET", + proto2ascii(sock->info.proto, false)); #endif 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); + &sock->info.lsa->actual, + remote_dynamic, + sock->info.lsa->bind_local, + false, + sock->inetd == INETD_NOWAIT, + signal_received); + } ASSERT (!remote_changed); } @@ -1549,68 +1565,68 @@ linksock_print_addr (struct link_socket *sock) /* print local address */ { const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO; - + if (sock->inetd) 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 */ - 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) - break; - } - ASSERT (cur); - msg (msglevel, "%s link local (bound): %s", - proto2ascii (sock->info.proto, sock->info.af, true), - print_sockaddr(cur->ai_addr,&gc)); + /* Socket is always bound on the first matching address */ + 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) + 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)); - + 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)); + 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) + 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); + &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->ai_addr, - true, - false); + sock->info.lsa->bind_local->ai_addr, + true, + false); break; case LS_MODE_TCP_ACCEPT_FROM: sock->sd = socket_do_accept (sock->sd, - &sock->info.lsa->actual, - false); + &sock->info.lsa->actual, + false); if (!socket_defined (sock->sd)) - { - *signal_received = SIGTERM; - return; - } + { + *signal_received = SIGTERM; + return; + } tcp_connection_established (&sock->info.lsa->actual); break; default: @@ -1624,50 +1640,51 @@ static void phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info) { #ifdef GENERAL_PROXY_SUPPORT - bool proxy_retry = false; + bool proxy_retry = false; #else - const bool proxy_retry = false; -#endif - do { - socket_connect (&sock->sd, - sock->info.lsa, - sock->connect_timeout, - sig_info); - - if (sig_info->signal_received) - return; - - if (false) - ; + const bool proxy_retry = false; +#endif + do { + socket_connect (&sock->sd, + sock->info.lsa, + sock->connect_timeout, + sig_info); + + if (sig_info->signal_received) + return; + + if (false) + ; #ifdef ENABLE_HTTP_PROXY - else if (sock->http_proxy) - { - proxy_retry = establish_http_proxy_passthru (sock->http_proxy, - sock->sd, - sock->proxy_dest_host, - sock->proxy_dest_port, - &sock->stream_buf.residual, - &sig_info->signal_received); - } + else if (sock->http_proxy) + { + proxy_retry = establish_http_proxy_passthru (sock->http_proxy, + sock->sd, + sock->proxy_dest_host, + sock->proxy_dest_port, + &sock->stream_buf.residual, + &sig_info->signal_received); + } #endif #ifdef ENABLE_SOCKS - 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); - } + 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); + } #endif - if (proxy_retry) - { - /* 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); - } - } while (proxy_retry); + if (proxy_retry) + { + /* 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); + } + + } while (proxy_retry); } @@ -1676,44 +1693,43 @@ static void phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info) { socket_connect (&sock->ctrl_sd, - sock->info.lsa, - sock->connect_timeout, - sig_info); - + sock->info.lsa, + sock->connect_timeout, + sig_info); + if (sig_info->signal_received) - return; - + return; + establish_socks_proxy_udpassoc (sock->socks_proxy, - sock->ctrl_sd, - sock->sd, - &sock->socks_relay.dest, - &sig_info->signal_received); - + sock->ctrl_sd, + sock->sd, + &sock->socks_relay.dest, + &sig_info->signal_received); + if (sig_info->signal_received) - return; - + return; + sock->remote_host = sock->proxy_dest_host; sock->remote_port = sock->proxy_dest_port; sock->did_resolve_remote = false; - + addr_zero_host(&sock->info.lsa->actual.dest); if (sock->info.lsa->remote_list) { - freeaddrinfo(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); - } #endif /* finalize socket initialization */ void link_socket_init_phase2 (struct link_socket *sock, - const struct frame *frame, - struct signal_info *sig_info) + const struct frame *frame, + struct signal_info *sig_info) { const char *remote_dynamic = NULL; int sig_save = 0; @@ -1742,71 +1758,66 @@ link_socket_init_phase2 (struct link_socket *sock, { phase2_inetd (sock, frame, remote_dynamic, &sig_info->signal_received); if (sig_info && sig_info->signal_received) - goto done; + goto done; } else { /* Second chance to resolv/create socket */ resolve_remote (sock, 2, &remote_dynamic, &sig_info->signal_received); - + /* If socket has not already been created create it now */ if (sock->sd == SOCKET_UNDEFINED) - { - if (sock->info.lsa->actual.ai_family) - { - create_socket (sock); - } - else - { - msg (M_WARN, "Could not determine IPv4/IPv6 protocol"); - sig_info->signal_received = SIGUSR1; - goto done; - } - - if (sock->bind_local) - bind_local(sock); - } + { + if (sock->info.lsa->actual.ai_family) + { + create_socket (sock); + } + else + { + msg (M_WARN, "Could not determine IPv4/IPv6 protocol"); + sig_info->signal_received = SIGUSR1; + goto done; + } + + if (sock->bind_local) + bind_local(sock); + } - if (sig_info && sig_info->signal_received) - goto done; + goto done; if (sock->info.proto == PROTO_TCP_SERVER) - { - phase2_tcp_server (sock, remote_dynamic, - &sig_info->signal_received); - } + { + 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) - { + { + phase2_tcp_client (sock, sig_info); + + } #ifdef ENABLE_SOCKS - if (sock->info.proto == PROTO_UDP && sock->socks_proxy) - { - phase2_socks_client (sock, sig_info); + else if (sock->info.proto == PROTO_UDP && sock->socks_proxy) + { + phase2_socks_client (sock, sig_info); #endif - } + } #ifdef TARGET_ANDROID - protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa); + protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa); #endif - } - if (sig_info && sig_info->signal_received) - goto done; + goto done; } phase2_set_socket_flags(sock); linksock_print_addr(sock); - + done: if (sig_save && sig_info) { if (!sig_info->signal_received) - sig_info->signal_received = sig_save; + sig_info->signal_received = sig_save; } } diff --git a/openvpn/src/openvpn/socket.h b/openvpn/src/openvpn/socket.h index d077a153..4c18b740 100644 --- a/openvpn/src/openvpn/socket.h +++ b/openvpn/src/openvpn/socket.h @@ -118,6 +118,7 @@ struct link_socket_info bool remote_float; int proto; /* Protocol (PROTO_x defined below) */ sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/ + bool bind_ipv6_only; int mtu_changed; /* Set to true when mtu value is changed */ }; @@ -289,7 +290,8 @@ struct link_socket *link_socket_new (void); void socket_bind (socket_descriptor_t sd, struct addrinfo *local, int af_family, - const char *prefix); + const char *prefix, + bool ipv6only); int openvpn_connect (socket_descriptor_t sd, const struct sockaddr *remote, @@ -308,6 +310,7 @@ link_socket_init_phase1 (struct link_socket *sock, const char *remote_port, int proto, sa_family_t af, + bool bind_ipv6_only, int mode, const struct link_socket *accept_from, #ifdef ENABLE_HTTP_PROXY @@ -600,14 +603,14 @@ static inline bool addr_local (const struct sockaddr *addr) { if (!addr) - return false; + return false; switch (addr->sa_family) { - case AF_INET: - return ((const struct sockaddr_in*)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK); - case AF_INET6: - return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6*)addr)->sin6_addr); - default: - return false; + case AF_INET: + return ((const struct sockaddr_in*)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK); + case AF_INET6: + return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6*)addr)->sin6_addr); + default: + return false; } } @@ -853,7 +856,7 @@ link_socket_verify_incoming_addr (struct buffer *buf, case AF_INET: if (!link_socket_actual_defined (from_addr)) return false; - if (info->remote_float || !info->lsa->remote_list) + if (info->remote_float || (!info->lsa->remote_list)) return true; if (addrlist_match_proto (&from_addr->dest, info->lsa->remote_list, info->proto)) return true; @@ -892,13 +895,14 @@ link_socket_set_outgoing_addr (const struct buffer *buf, { struct link_socket_addr *lsa = info->lsa; if ( - /* new or changed address? */ - (!info->connection_established - || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto)) - /* address undef or address == remote or --float */ - && (info->remote_float - || !lsa->remote_list) - || addrlist_match_proto (&act->dest, lsa->remote_list, info->proto) + ( + /* new or changed address? */ + (!info->connection_established + || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto)) + /* address undef or address == remote or --float */ + && (info->remote_float + || !lsa->remote_list)) + || addrlist_match_proto (&act->dest, lsa->remote_list, info->proto) ) { link_socket_connection_initiated (buf, info, act, common_name, es); diff --git a/openvpn/src/openvpn/ssl.c b/openvpn/src/openvpn/ssl.c index 60f5f67f..58ba2384 100644 --- a/openvpn/src/openvpn/ssl.c +++ b/openvpn/src/openvpn/ssl.c @@ -64,7 +64,6 @@ #include "ssl.h" #include "ssl_verify.h" #include "ssl_backend.h" -#include "multi.h" #include "memdbg.h" @@ -1837,7 +1836,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session) buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc)); } - /* push env vars that begin with UV_ and IV_OPENVPN_GUI_VERSION*/ + /* push env vars that begin with UV_ and IV_OPENVPN_GUI_VERSION */ for (e=es->list; e != NULL; e=e->next) { if (e->string) diff --git a/openvpn/src/openvpn/ssl_openssl.c b/openvpn/src/openvpn/ssl_openssl.c index f64177a8..e3926914 100644 --- a/openvpn/src/openvpn/ssl_openssl.c +++ b/openvpn/src/openvpn/ssl_openssl.c @@ -743,7 +743,7 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, X509_STORE *store = NULL; X509_NAME *xn = NULL; BIO *in = NULL; - int i, added = 0; + int i, added = 0, prev = 0; ASSERT(NULL != ctx); @@ -770,6 +770,11 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, if (info->crl) X509_STORE_add_crl (store, info->crl); + if (tls_server && !info->x509) + { + msg (M_SSLERR, "X509 name was missing in TLS mode"); + } + if (info->x509) { X509_STORE_add_cert (store, info->x509); @@ -799,6 +804,15 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, sk_X509_NAME_push (cert_names, xn); } } + + if (tls_server) { + int cnum = sk_X509_NAME_num (cert_names); + if (cnum != (prev + 1)) { + msg (M_WARN, "Cannot load CA certificate file %s (entry %d did not validate)", np(ca_file), added); + } + prev = cnum; + } + } sk_X509_INFO_pop_free (info_stack, X509_INFO_free); } @@ -806,8 +820,15 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, if (tls_server) SSL_CTX_set_client_CA_list (ctx->ctx, cert_names); - if (!added || (tls_server && sk_X509_NAME_num (cert_names) != added)) - msg (M_SSLERR, "Cannot load CA certificate file %s", np(ca_file)); + if (!added) + msg (M_SSLERR, "Cannot load CA certificate file %s (no entries were read)", np(ca_file)); + + if (tls_server) { + int cnum = sk_X509_NAME_num (cert_names); + if (cnum != added) + msg (M_SSLERR, "Cannot load CA certificate file %s (only %d of %d entries were valid X509 names)", np(ca_file), cnum, added); + } + if (in) BIO_free (in); } diff --git a/openvpn/src/openvpn/tun.c b/openvpn/src/openvpn/tun.c index bd62b392..c1dcc5e2 100644 --- a/openvpn/src/openvpn/tun.c +++ b/openvpn/src/openvpn/tun.c @@ -466,7 +466,7 @@ init_tun (const char *dev, /* --dev option */ */ if (strict_warn) { - struct addrinfo *curele; + struct addrinfo *curele; ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology); /* @@ -483,14 +483,14 @@ init_tun (const char *dev, /* --dev option */ tt->remote_netmask); } - for(curele=remote_public;curele;curele=curele->ai_next) { - if(curele->ai_family == AF_INET) - check_addr_clash ("remote", - tt->type, - ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr, - tt->local, - tt->remote_netmask); - } + for (curele=remote_public;curele;curele=curele->ai_next) { + if (curele->ai_family == AF_INET) + check_addr_clash ("remote", + tt->type, + ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr, + tt->local, + tt->remote_netmask); + } if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) check_subnet_conflict (tt->local, tt->remote_netmask, "TUN/TAP adapter"); @@ -1501,19 +1501,38 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu struct gc_arena gc = gc_new (); bool opentun; + int oldtunfd = tt->fd; + for (i = 0; i < tt->options.dns_len; ++i) { management_android_control (management, "DNSSERVER", - print_in_addr_t(tt->options.dns[i], 0, &gc)); + print_in_addr_t(tt->options.dns[i], 0, &gc)); } if(tt->options.domain) management_android_control (management, "DNSDOMAIN", tt->options.domain); - opentun = management_android_control (management, "OPENTUN", dev); + int android_method = managment_android_persisttun_action (management); + + /* Android 4.4 workaround */ + if (oldtunfd >=0 && android_method == ANDROID_OPEN_AFTER_CLOSE) + { + close(oldtunfd); + openvpn_sleep(2); + } - /* Pick up the fd from management interface after calling the OPENTUN command */ - tt->fd = management->connection.lastfdreceived; - management->connection.lastfdreceived=-1; + if (oldtunfd >=0 && android_method == ANDROID_KEEP_OLD_TUN) { + /* keep the old fd */ + opentun = true; + } else { + opentun = management_android_control (management, "OPENTUN", dev); + /* Pick up the fd from management interface after calling the + * OPENTUN command */ + tt->fd = management->connection.lastfdreceived; + management->connection.lastfdreceived=-1; + } + + if (oldtunfd>=0 && android_method == ANDROID_OPEN_BEFORE_CLOSE) + close(oldtunfd); /* Set the actual name to a dummy name */ tt->actual_name = string_alloc (ANDROID_TUNNAME, NULL); @@ -3148,9 +3167,9 @@ get_panel_reg (struct gc_arena *gc) char enum_name[256]; char connection_string[256]; HKEY connection_key; - char name_data[256]; + WCHAR name_data[256]; DWORD name_type; - const char name_string[] = "Name"; + const WCHAR name_string[] = L"Name"; len = sizeof (enum_name); status = RegEnumKeyEx( @@ -3184,12 +3203,12 @@ get_panel_reg (struct gc_arena *gc) else { len = sizeof (name_data); - status = RegQueryValueEx( + status = RegQueryValueExW( connection_key, name_string, NULL, &name_type, - name_data, + (LPBYTE) name_data, &len); if (status != ERROR_SUCCESS || name_type != REG_SZ) @@ -3197,10 +3216,15 @@ get_panel_reg (struct gc_arena *gc) NETWORK_CONNECTIONS_KEY, connection_string, name_string); else { + int n; + LPSTR name; struct panel_reg *reg; ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc); - reg->name = string_alloc (name_data, gc); + n = WideCharToMultiByte (CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL); + name = gc_malloc (n, false, gc); + WideCharToMultiByte (CP_UTF8, 0, name_data, -1, name, n, NULL, NULL); + reg->name = name; reg->guid = string_alloc (enum_name, gc); /* link into return list */ @@ -3410,7 +3434,7 @@ static void at_least_one_tap_win (const struct tap_reg *tap_reg) { if (!tap_reg) - msg (M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> " PACKAGE_NAME " -> Add a new TAP-Windows virtual ethernet adapter."); + msg (M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> TAP-Windows -> Utilities -> Add a new TAP-Windows virtual ethernet adapter."); } /* -- cgit v1.2.3