diff options
Diffstat (limited to 'openvpn')
50 files changed, 1638 insertions, 1514 deletions
diff --git a/openvpn/.gitignore b/openvpn/.gitignore index f762089d..a04afff7 100644 --- a/openvpn/.gitignore +++ b/openvpn/.gitignore @@ -37,6 +37,7 @@ stamp-h1 install-sh missing ltmain.sh +libtool m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 @@ -50,5 +51,6 @@ config-msvc-version.h doc/openvpn.8.html distro/rpm/openvpn.spec tests/t_client.sh +tests/t_client-*-20??????-??????/ src/openvpn/openvpn config-version.h diff --git a/openvpn/Android.mk b/openvpn/Android.mk index b27ef794..c68bcccf 100644 --- a/openvpn/Android.mk +++ b/openvpn/Android.mk @@ -1,17 +1,21 @@ -# Android openvpn JNI LOCAL_PATH:= $(call my-dir)/ include $(CLEAR_VARS) LOCAL_LDLIBS := -lz -LOCAL_C_INCLUDES := openssl/include lzo/include openssl/crypto openssl openvpn/src/compat openvpn/src/openvpn openvpn/include +LOCAL_C_INCLUDES := openssl/include lzo/include openssl/crypto openssl openvpn/src/compat openvpn/src/openvpn openvpn/include google-breakpad/src google-breakpad/src/common/android/include LOCAL_SHARED_LIBRARIES := libssl libcrypto #LOCAL_STATIC_LIBRARIES := libssl_static libcrypto_static liblzo-static + +LOCAL_CFLAGS= -DHAVE_CONFIG_H -DTARGET_ABI=\"${TARGET_ABI}\" LOCAL_STATIC_LIBRARIES := liblzo-static +ifneq ($(TARGET_ARCH),mips) +LOCAL_STATIC_LIBRARIES += breakpad_client +LOCAL_CFLAGS += -DGOOGLE_BREAKPAD=1 +endif -LOCAL_CFLAGS= -DHAVE_CONFIG_H -DTARGET_ABI=\"${TARGET_ABI}\" LOCAL_MODULE = openvpn LOCAL_SRC_FILES:= \ @@ -85,7 +89,12 @@ LOCAL_SRC_FILES:= \ src/openvpn/ssl_verify_openssl.c \ src/openvpn/ssl_verify_polarssl.c \ src/openvpn/status.c \ - src/openvpn/tun.c + src/openvpn/tun.c +ifneq ($(TARGET_ARCH),mips) +LOCAL_SRC_FILES+=src/openvpn/breakpad.cpp +endif + + include $(BUILD_SHARED_LIBRARY) #include $(BUILD_EXECUTABLE) diff --git a/openvpn/config.h b/openvpn/config.h index 6684f70d..0d86c1d9 100644 --- a/openvpn/config.h +++ b/openvpn/config.h @@ -450,7 +450,7 @@ #define PACKAGE_NAME "OpenVPN" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "OpenVPN 2.3_beta1" +#define PACKAGE_STRING "OpenVPN 2.3_rc1+dspatch3" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "openvpn" diff --git a/openvpn/configure.ac b/openvpn/configure.ac index d3d974dc..2f780b7a 100644 --- a/openvpn/configure.ac +++ b/openvpn/configure.ac @@ -934,7 +934,7 @@ if test "${enable_ssl}" = "yes"; then fi if test "${enable_crypto}" = "yes"; then - test "${have_crypto_crypto}" != "yes" && AC_MSG_ERROR([${with_crypto_library} crytpo is required but missing]) + test "${have_crypto_crypto}" != "yes" && AC_MSG_ERROR([${with_crypto_library} crypto is required but missing]) OPTIONAL_CRYPTO_CFLAGS="${OPTIONAL_CRYPTO_CFLAGS} ${CRYPTO_CRYPTO_CFLAGS}" OPTIONAL_CRYPTO_LIBS="${OPTIONAL_CRYPTO_LIBS} ${CRYPTO_CRYPTO_LIBS}" AC_DEFINE([ENABLE_CRYPTO], [1], [Enable crypto library]) diff --git a/openvpn/doc/management-notes.txt b/openvpn/doc/management-notes.txt index a07a5142..ef39b855 100644 --- a/openvpn/doc/management-notes.txt +++ b/openvpn/doc/management-notes.txt @@ -750,6 +750,34 @@ To accept connecting to the host and port directly, use this command: proxy NONE +COMMAND -- rsa-sig (OpenVPN 2.3 or higher) +------------------------------------------ +Provides support for external storage of the private key. Requires the +--management-external-key option. This option can be used instead of "key" +in client mode, and allows the client to run without the need to load the +actual private key. When the SSL protocol needs to perform an RSA sign +operation, the data to be signed will be sent to the management interface +via a notification as follows: + +>RSA_SIGN:[BASE64_DATA] + +The management interface client should then sign BASE64_DATA +using the private key and return the SSL signature as follows: + +rsa-sig +[BASE64_SIG_LINE] +. +. +. +END + +Base64 encoded output of RSA_sign(NID_md5_sha1,... will provide a +correct signature. + +This capability is intended to allow the use of arbitrary cryptographic +service providers with OpenVPN via the management interface. + + OUTPUT FORMAT ------------- diff --git a/openvpn/doc/openvpn.8 b/openvpn/doc/openvpn.8 index da1c0f9e..d66bd665 100644 --- a/openvpn/doc/openvpn.8 +++ b/openvpn/doc/openvpn.8 @@ -456,13 +456,9 @@ possess a built-in reliability layer. .\"********************************************************* .TP .B \-\-connect-retry n -For -.B \-\-proto tcp-client, -take +Wait .B n -as the -number of seconds to wait -between connection retries (default=5). +seconds between connection attempts (default=5). .\"********************************************************* .TP .B \-\-connect-timeout n @@ -474,12 +470,15 @@ seconds (default=10). .\"********************************************************* .TP .B \-\-connect-retry-max n -For -.B \-\-proto tcp-client, -take .B n -as the -number of retries of connection attempt (default=infinite). +specifies the number of times all +.B \-\-remote +respectively +.B <connection> +statements are tried. Specifiying +.B n +as one would try each entry exactly once. A sucessful connection +resets the counter. (default=umlimited). .\"********************************************************* .TP .B \-\-show-proxy-settings @@ -651,18 +650,18 @@ peer on its new IP address. .\"********************************************************* .TP .B \-\-port port -TCP/UDP port number for both local and remote. The current +TCP/UDP port number or port name for both local and remote. The current default of 1194 represents the official IANA port number assignment for OpenVPN and has been used since version 2.0-beta17. Previous versions used port 5000 as the default. .\"********************************************************* .TP .B \-\-lport port -TCP/UDP port number for bind. +TCP/UDP port number or name for bind. .\"********************************************************* .TP .B \-\-rport port -TCP/UDP port number for remote. +TCP/UDP port number or name for remote. .\"********************************************************* .TP .B \-\-bind @@ -1886,7 +1885,7 @@ is a safety precaution to prevent a LD_PRELOAD style attack from a malicious or compromised server. .\"********************************************************* .TP -.B \-\-script-security level [method] +.B \-\-script-security level This directive offers policy-level control over OpenVPN's usage of external programs and scripts. Lower .B level @@ -1905,24 +1904,40 @@ Allow calling of built-in executables and user-defined scripts. .B 3 \-\- Allow passwords to be passed to scripts via environmental variables (potentially unsafe). -The +OpenVPN releases before v2.3 also supported a .B method -parameter indicates how OpenVPN should call external commands and scripts. -Settings for -.B method: +flag which indicated how OpenVPN should call external commands and scripts. This +could be either +.B execve +or +.B system. +As of OpenVPN v2.3, this flag is no longer accepted. In most *nix environments the execve() +approach has been used without any issues. + +To run scripts in Windows in earlier OpenVPN +versions you needed to either add a full path to the script interpreter which can parse the +script or use the +.B system +flag to run these scripts. As of OpenVPN v2.3 it is now a strict requirement to have +full path to the script interpreter when running non-executables files. +This is not needed for executable files, such as .exe, .com, .bat or .cmd files. For +example, if you have a Visual Basic script, you must use this syntax now: -.B execve \-\- -(default) Use execve() function on Unix family OSes and CreateProcess() on Windows. -.br -.B system \-\- -Use system() function (deprecated and less safe since the external program command -line is subject to shell expansion). +.nf +.ft 3 +.in +4 +\-\-up 'C:\\\\Windows\\\\System32\\\\wscript.exe C:\\\\Program\\ Files\\\\OpenVPN\\\\config\\\\my-up-script.vbs' +.in -4 +.ft +.fi -The -.B \-\-script-security -option was introduced in OpenVPN 2.1_rc9. For configuration file compatibility -with previous OpenVPN versions, use: -.B \-\-script-security 3 system +Please note the single quote marks and the escaping of the backslashes (\\) and +the space character. + +The reason the support for the +.B system +flag was removed is due to the security implications with shell expansions +when executing scripts via the system() call. .\"********************************************************* .TP .B \-\-disable-occ @@ -2464,6 +2479,11 @@ Allow management interface to override .B \-\-remote directives (client-only). .\"********************************************************* +.B \-\-management-external-key +Allows usage for external private key file instead of +.B \-\-key +option (client-only). +.\"********************************************************* .TP .B \-\-management-forget-disconnect Make OpenVPN forget passwords when management session @@ -5675,7 +5695,7 @@ Set on program initiation and reset on SIGHUP. .\"********************************************************* .TP .B local_port -The local port number, specified by +The local port number or name, specified by .B \-\-port or .B \-\-lport. diff --git a/openvpn/src/openvpn/breakpad.cpp b/openvpn/src/openvpn/breakpad.cpp new file mode 100644 index 00000000..cfcc10a8 --- /dev/null +++ b/openvpn/src/openvpn/breakpad.cpp @@ -0,0 +1,29 @@ + +#include "breakpad.h" +#include "client/linux/handler/exception_handler.h" + + +static +bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, + void* context, + bool succeeded) { + printf("Dump path: %s\n", descriptor.path()); + fflush(stdout); + fflush(stderr); + return succeeded; +} + +static google_breakpad::MinidumpDescriptor* desc; +static google_breakpad::ExceptionHandler* eh; + +void breakpad_setup(void) +{ + printf("Initializing Google Breakpad!\n"); + desc = new google_breakpad::MinidumpDescriptor("/data/data/de.blinkt.openvpn/cache"); + eh = new google_breakpad::ExceptionHandler(*desc, NULL, DumpCallback, NULL, true,-1); +} + +void breakpad_dodump(void) +{ + eh->WriteMinidump(); +} diff --git a/openvpn/src/openvpn/breakpad.h b/openvpn/src/openvpn/breakpad.h new file mode 100644 index 00000000..84df62ab --- /dev/null +++ b/openvpn/src/openvpn/breakpad.h @@ -0,0 +1,13 @@ +#ifndef BUFFER_H +#define BUFFER_H + +#ifdef __cplusplus +extern "C" { +#endif + void breakpad_setup(void); + void breakpad_dodump(void); +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openvpn/src/openvpn/buffer.c b/openvpn/src/openvpn/buffer.c index 5eee3ee4..56d14b1a 100644 --- a/openvpn/src/openvpn/buffer.c +++ b/openvpn/src/openvpn/buffer.c @@ -782,6 +782,16 @@ char_class (const unsigned char c, const unsigned int flags) return true; if ((flags & CC_EQUAL) && c == '=') return true; + if ((flags & CC_LESS_THAN) && c == '<') + return true; + if ((flags & CC_GREATER_THAN) && c == '>') + return true; + if ((flags & CC_PIPE) && c == '|') + return true; + if ((flags & CC_QUESTION_MARK) && c == '?') + return true; + if ((flags & CC_ASTERISK) && c == '*') + return true; return false; } diff --git a/openvpn/src/openvpn/buffer.h b/openvpn/src/openvpn/buffer.h index 9bc33dba..5e11de05 100644 --- a/openvpn/src/openvpn/buffer.h +++ b/openvpn/src/openvpn/buffer.h @@ -736,6 +736,11 @@ const char *np (const char *str); #define CC_REVERSE_QUOTE (1<<23) #define CC_AT (1<<24) #define CC_EQUAL (1<<25) +#define CC_LESS_THAN (1<<26) +#define CC_GREATER_THAN (1<<27) +#define CC_PIPE (1<<28) +#define CC_QUESTION_MARK (1<<29) +#define CC_ASTERISK (1<<30) /* macro classes */ #define CC_NAME (CC_ALNUM|CC_UNDERBAR) diff --git a/openvpn/src/openvpn/error.c b/openvpn/src/openvpn/error.c index 6848425e..98611a1b 100644 --- a/openvpn/src/openvpn/error.c +++ b/openvpn/src/openvpn/error.c @@ -57,6 +57,10 @@ #endif #endif +#ifdef GOOGLE_BREAKPAD +#include "breakpad.h" +#endif + /* Globals */ unsigned int x_debug_level; /* GLOBAL */ @@ -259,7 +263,7 @@ void x_msg_va (const unsigned int flags, const char *format, va_list arglist) if (flags & M_SSL) { int nerrs = 0; - int err; + size_t err; while ((err = ERR_get_error ())) { openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s", @@ -399,6 +403,9 @@ dont_mute (unsigned int flags) void assert_failed (const char *filename, int line) { +#ifdef GOOGLE_BREAKPAD + breakpad_dodump(); +#endif msg (M_FATAL, "Assertion failed at %s:%d", filename, line); } @@ -602,7 +609,7 @@ x_check_status (int status, const char *extended_msg = NULL; msg (x_cs_verbose_level, "%s %s returned %d", - sock ? proto2ascii (sock->info.proto, true) : "", + sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "", description, status); @@ -630,14 +637,14 @@ x_check_status (int status, if (extended_msg) msg (x_cs_info_level, "%s %s [%s]: %s (code=%d)", description, - sock ? proto2ascii (sock->info.proto, true) : "", + sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "", extended_msg, strerror_ts (my_errno, &gc), my_errno); else msg (x_cs_info_level, "%s %s: %s (code=%d)", description, - sock ? proto2ascii (sock->info.proto, true) : "", + sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "", strerror_ts (my_errno, &gc), my_errno); diff --git a/openvpn/src/openvpn/forward-inline.h b/openvpn/src/openvpn/forward-inline.h index 5853ce29..7eb480dd 100644 --- a/openvpn/src/openvpn/forward-inline.h +++ b/openvpn/src/openvpn/forward-inline.h @@ -228,6 +228,7 @@ 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/forward.c b/openvpn/src/openvpn/forward.c index 57c78462..9e9c406c 100644 --- a/openvpn/src/openvpn/forward.c +++ b/openvpn/src/openvpn/forward.c @@ -620,7 +620,7 @@ check_timeout_random_component (struct context *c) static inline void socks_postprocess_incoming_link (struct context *c) { - if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4) + if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP) socks_process_incoming_udp (&c->c2.buf, &c->c2.from); } @@ -629,7 +629,7 @@ socks_preprocess_outgoing_link (struct context *c, struct link_socket_actual **to_addr, int *size_delta) { - if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4) + if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP) { *size_delta += socks_process_outgoing_udp (&c->c2.to_link, c->c2.to_link_addr); *to_addr = &c->c2.link_socket->socks_relay; @@ -778,7 +778,7 @@ process_incoming_link (struct context *c) fprintf (stderr, "R"); #endif msg (D_LINK_RW, "%s READ [%d] from %s: %s", - proto2ascii (lsi->proto, true), + proto2ascii (lsi->proto, lsi->af, true), BLEN (&c->c2.buf), print_link_socket_actual (&c->c2.from, &gc), PROTO_DUMP (&c->c2.buf, &gc)); @@ -985,9 +985,9 @@ process_incoming_tun (struct context *c) { /* * The --passtos and --mssfix options require - * us to examine the IPv4 header. + * us to examine the IP header (IPv4 or IPv6). */ - process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf); + process_ip_header (c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf); #ifdef PACKET_TRUNCATION_CHECK /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ @@ -1009,10 +1009,10 @@ process_incoming_tun (struct context *c) } void -process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf) +process_ip_header (struct context *c, unsigned int flags, struct buffer *buf) { if (!c->options.ce.mssfix) - flags &= ~PIPV4_MSSFIX; + flags &= ~PIP_MSSFIX; #if PASSTOS_CAPABILITY if (!c->options.passtos) flags &= ~PIPV4_PASSTOS; @@ -1027,9 +1027,9 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf) * us to examine the IPv4 header. */ #if PASSTOS_CAPABILITY - if (flags & (PIPV4_PASSTOS|PIPV4_MSSFIX)) + if (flags & (PIPV4_PASSTOS|PIP_MSSFIX)) #else - if (flags & PIPV4_MSSFIX) + if (flags & PIP_MSSFIX) #endif { struct buffer ipbuf = *buf; @@ -1042,8 +1042,8 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf) #endif /* possibly alter the TCP MSS */ - if (flags & PIPV4_MSSFIX) - mss_fixup (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame))); + if (flags & PIP_MSSFIX) + mss_fixup_ipv4 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame))); #ifdef ENABLE_CLIENT_NAT /* possibly do NAT on packet */ @@ -1061,6 +1061,12 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf) route_list_add_vpn_gateway (c->c1.route_list, c->c2.es, dhcp_router); } } + else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf)) + { + /* possibly alter the TCP MSS */ + if (flags & PIP_MSSFIX) + mss_fixup_ipv6 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame))); + } } } } @@ -1116,7 +1122,7 @@ process_outgoing_link (struct context *c) fprintf (stderr, "W"); #endif msg (D_LINK_RW, "%s WRITE [%d] to %s: %s", - proto2ascii (c->c2.link_socket->info.proto, true), + proto2ascii (c->c2.link_socket->info.proto, c->c2.link_socket->info.proto, true), BLEN (&c->c2.to_link), print_link_socket_actual (c->c2.to_link_addr, &gc), PROTO_DUMP (&c->c2.to_link, &gc)); @@ -1217,9 +1223,9 @@ process_outgoing_tun (struct context *c) /* * The --mssfix option requires - * us to examine the IPv4 header. + * us to examine the IP header (IPv4 or IPv6). */ - process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun); + process_ip_header (c, PIP_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun); if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame)) { diff --git a/openvpn/src/openvpn/forward.h b/openvpn/src/openvpn/forward.h index 0f829bde..1830a00b 100644 --- a/openvpn/src/openvpn/forward.h +++ b/openvpn/src/openvpn/forward.h @@ -228,12 +228,12 @@ void process_outgoing_tun (struct context *c); bool send_control_channel_string (struct context *c, const char *str, int msglevel); #define PIPV4_PASSTOS (1<<0) -#define PIPV4_MSSFIX (1<<1) +#define PIP_MSSFIX (1<<1) /* v4 and v6 */ #define PIPV4_OUTGOING (1<<2) #define PIPV4_EXTRACT_DHCP_ROUTER (1<<3) #define PIPV4_CLIENT_NAT (1<<4) -void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf); +void process_ip_header (struct context *c, unsigned int flags, struct buffer *buf); #if P2MP void schedule_exit (struct context *c, const int n_seconds, const int signal); diff --git a/openvpn/src/openvpn/init.c b/openvpn/src/openvpn/init.c index 1f06eaa5..b3125282 100644 --- a/openvpn/src/openvpn/init.c +++ b/openvpn/src/openvpn/init.c @@ -125,28 +125,19 @@ management_callback_proxy_cmd (void *arg, const char **p) ret = true; else if (p[2] && p[3]) { - const int port = atoi(p[3]); - if (!legal_ipv4_port (port)) - { - msg (M_WARN, "Bad proxy port number: %s", p[3]); - return false; - } - if (streq (p[1], "HTTP")) { #ifndef ENABLE_HTTP_PROXY msg (M_WARN, "HTTP proxy support is not available"); #else struct http_proxy_options *ho; - if (ce->proto != PROTO_TCPv4 && ce->proto != PROTO_TCPv4_CLIENT && - ce->proto != PROTO_TCPv6 && ce->proto != PROTO_TCPv6_CLIENT) - { + if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT ) { msg (M_WARN, "HTTP proxy support only works for TCP based connections"); return false; } ho = init_http_proxy_options_once (&ce->http_proxy_options, gc); ho->server = string_alloc (p[2], gc); - ho->port = port; + ho->port = string_alloc (p[3], gc); ho->retry = true; ho->auth_retry = (p[4] && streq (p[4], "nct") ? PAR_NCT : PAR_ALL); ret = true; @@ -158,7 +149,7 @@ management_callback_proxy_cmd (void *arg, const char **p) msg (M_WARN, "SOCKS proxy support is not available"); #else ce->socks_proxy_server = string_alloc (p[2], gc); - ce->socks_proxy_port = port; + ce->socks_proxy_port = p[3]; ret = true; #endif } @@ -225,8 +216,7 @@ management_callback_remote_cmd (void *arg, const char **p) } else if (!strcmp(p[1], "MOD") && p[2] && p[3]) { - const int port = atoi(p[3]); - if (strlen(p[2]) < RH_HOST_LEN && legal_ipv4_port(port)) + if (strlen(p[2]) < RH_HOST_LEN && strlen(p[3]) < RH_PORT_LEN) { struct remote_host_store *rhs = c->options.rh_store; if (!rhs) @@ -235,8 +225,10 @@ management_callback_remote_cmd (void *arg, const char **p) c->options.rh_store = rhs; } strncpynt(rhs->host, p[2], RH_HOST_LEN); + strncpynt(rhs->port, p[3], RH_PORT_LEN); + ce->remote = rhs->host; - ce->remote_port = port; + ce->remote_port = rhs->port; flags = CE_MAN_QUERY_REMOTE_MOD; ret = true; } @@ -251,7 +243,7 @@ management_callback_remote_cmd (void *arg, const char **p) } static bool -ce_management_query_remote (struct context *c, const char *remote_ip_hint) +ce_management_query_remote (struct context *c) { struct gc_arena gc = gc_new (); volatile struct connection_entry *ce = &c->options.ce; @@ -260,7 +252,7 @@ ce_management_query_remote (struct context *c, const char *remote_ip_hint) if (management) { struct buffer out = alloc_buf_gc (256, &gc); - buf_printf (&out, ">REMOTE:%s,%d,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, false)); + buf_printf (&out, ">REMOTE:%s,%s,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, ce->af, false)); management_notify_generic(management, BSTR (&out)); ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<<CE_MAN_QUERY_REMOTE_SHIFT); ce->flags |= (CE_MAN_QUERY_REMOTE_QUERY<<CE_MAN_QUERY_REMOTE_SHIFT); @@ -276,8 +268,6 @@ ce_management_query_remote (struct context *c, const char *remote_ip_hint) } { const int flags = ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK); - if (flags == CE_MAN_QUERY_REMOTE_ACCEPT && remote_ip_hint) - ce->remote = remote_ip_hint; ret = (flags != CE_MAN_QUERY_REMOTE_SKIP); } gc_free (&gc); @@ -292,95 +282,126 @@ static void init_connection_list (struct context *c) { struct connection_list *l = c->options.connection_list; - if (l) + l->current = -1; + if (c->options.remote_random) { - l->current = -1; - if (c->options.remote_random) - { - int i; - for (i = 0; i < l->len; ++i) - { - const int j = get_random () % l->len; - if (i != j) - { - struct connection_entry *tmp; - tmp = l->array[i]; - l->array[i] = l->array[j]; - l->array[j] = tmp; - } - } - } + int i; + for (i = 0; i < l->len; ++i) + { + const int j = get_random () % l->len; + if (i != j) + { + struct connection_entry *tmp; + tmp = l->array[i]; + l->array[i] = l->array[j]; + l->array[j] = tmp; + } + } } } /* + * Clear the remote address list + */ +static void clear_remote_addrlist (struct link_socket_addr *lsa) +{ + if (lsa->remote_list) { + freeaddrinfo(lsa->remote_list); + } + lsa->remote_list = NULL; + lsa->current_remote = NULL; +} + +/* * Increment to next connection entry */ static void next_connection_entry (struct context *c) { struct connection_list *l = c->options.connection_list; - if (l) - { - bool ce_defined; - struct connection_entry *ce; - int n_cycles = 0; - - do { - const char *remote_ip_hint = NULL; - bool newcycle = false; - - ce_defined = true; - if (l->no_advance && l->current >= 0) - { - l->no_advance = false; - } - else - { - if (++l->current >= l->len) - { - l->current = 0; - ++l->n_cycles; - if (++n_cycles >= 2) - msg (M_FATAL, "No usable connection profiles are present"); - } - - if (l->current == 0) - newcycle = true; - } - - ce = l->array[l->current]; + bool ce_defined; + struct connection_entry *ce; + int n_cycles = 0; + + do { + ce_defined = true; + if (c->options.no_advance && l->current >= 0) + { + c->options.no_advance = false; + } + else + { + /* Check if there is another resolved address to try for + * the current connection */ + if (c->c1.link_socket_addr.current_remote && + c->c1.link_socket_addr.current_remote->ai_next) + { + c->c1.link_socket_addr.current_remote = + c->c1.link_socket_addr.current_remote->ai_next; + } + else + { + /* FIXME (schwabe) fix the persist-remote-ip option for real, + * this is broken probably ever since connection lists and multiple + * remote existed + */ + + if (!c->options.persist_remote_ip) + clear_remote_addrlist (&c->c1.link_socket_addr); + else + c->c1.link_socket_addr.current_remote = + c->c1.link_socket_addr.remote_list; + + /* + * Increase the number of connection attempts + * If this is connect-retry-max * size(l) + * OpenVPN will quit + */ + + c->options.unsuccessful_attempts++; + + if (++l->current >= l->len) + { + + l->current = 0; + if (++n_cycles >= 2) + msg (M_FATAL, "No usable connection profiles are present"); + } + } + } - if (c->options.remote_ip_hint && !l->n_cycles) - remote_ip_hint = c->options.remote_ip_hint; + ce = l->array[l->current]; - if (ce->flags & CE_DISABLED) - ce_defined = false; + if (ce->flags & CE_DISABLED) + ce_defined = false; - c->options.ce = *ce; + c->options.ce = *ce; #ifdef ENABLE_MANAGEMENT - if (ce_defined && management && management_query_remote_enabled(management)) - { - /* allow management interface to override connection entry details */ - ce_defined = ce_management_query_remote(c, remote_ip_hint); - if (IS_SIG (c)) - break; - } - else + if (ce_defined && management && management_query_remote_enabled(management)) + { + /* allow management interface to override connection entry details */ + ce_defined = ce_management_query_remote(c); + if (IS_SIG (c)) + break; + } + else #endif - if (remote_ip_hint) - c->options.ce.remote = remote_ip_hint; #ifdef ENABLE_MANAGEMENT - if (ce_defined && management && management_query_proxy_enabled (management)) - { - ce_defined = ce_management_query_proxy (c); - if (IS_SIG (c)) - break; - } + if (ce_defined && management && management_query_proxy_enabled (management)) + { + ce_defined = ce_management_query_proxy (c); + if (IS_SIG (c)) + break; + } #endif - } while (!ce_defined); - } + } while (!ce_defined); + + /* Check if this connection attempt would bring us over the limit */ + if (c->options.connect_retry_max > 0 && + c->options.unsuccessful_attempts > (l->len * c->options.connect_retry_max)) + msg(M_FATAL, "All connections have been connect-retry-max (%d) times unsuccessful, exiting", + c->options.connect_retry_max); update_options_ce_post (&c->options); } @@ -415,12 +436,6 @@ init_query_passwords (struct context *c) #ifdef GENERAL_PROXY_SUPPORT -static int -proxy_scope (struct context *c) -{ - return connection_list_defined (&c->options) ? 2 : 1; -} - static void uninit_proxy_dowork (struct context *c) { @@ -482,17 +497,15 @@ init_proxy_dowork (struct context *c) } static void -init_proxy (struct context *c, const int scope) +init_proxy (struct context *c) { - if (scope == proxy_scope (c)) - init_proxy_dowork (c); + init_proxy_dowork (c); } static void uninit_proxy (struct context *c) { - if (c->sig->signal_received != SIGUSR1 || proxy_scope (c) == 2) - uninit_proxy_dowork (c); + uninit_proxy_dowork (c); } #else @@ -544,8 +557,6 @@ context_init_1 (struct context *c) } #endif - /* initialize HTTP or SOCKS proxy object at scope level 1 */ - init_proxy (c, 1); } void @@ -1240,6 +1251,9 @@ void initialization_sequence_completed (struct context *c, const unsigned int flags) { static const char message[] = "Initialization Sequence Completed"; + + /* Reset the unsuccessful connection counter on complete initialisation */ + c->options.unsuccessful_attempts=0; /* If we delayed UID/GID downgrade or chroot, do it now */ do_uid_gid_chroot (c, true); @@ -1258,9 +1272,9 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) else msg (M_INFO, "%s", message); - /* Flag connection_list that we initialized */ - if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0 && connection_list_defined (&c->options)) - connection_list_set_no_advance (&c->options); + /* Flag that we initialized */ + if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0) + c->options.no_advance=true; #ifdef WIN32 fork_register_dns_action (c->c1.tuntap); @@ -1374,8 +1388,8 @@ do_init_tun (struct context *c) c->options.ifconfig_ipv6_local, c->options.ifconfig_ipv6_netbits, c->options.ifconfig_ipv6_remote, - addr_host (&c->c1.link_socket_addr.local), - addr_host (&c->c1.link_socket_addr.remote), + c->c1.link_socket_addr.bind_local, + c->c1.link_socket_addr.remote_list, !c->options.ifconfig_nowarn, c->c2.es); @@ -1853,17 +1867,11 @@ socket_restart_pause (struct context *c) switch (c->options.ce.proto) { - case PROTO_UDPv4: - case PROTO_UDPv6: - if (proxy) - sec = c->options.ce.connect_retry_seconds; - break; - case PROTO_TCPv4_SERVER: - case PROTO_TCPv6_SERVER: + case PROTO_TCP_SERVER: sec = 1; break; - case PROTO_TCPv4_CLIENT: - case PROTO_TCPv6_CLIENT: + case PROTO_UDP: + case PROTO_TCP_CLIENT: sec = c->options.ce.connect_retry_seconds; break; } @@ -2219,7 +2227,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) /* should we not xmit any packets until we get an initial response from client? */ - if (to.server && options->ce.proto == PROTO_TCPv4_SERVER) + if (to.server && options->ce.proto == PROTO_TCP_SERVER) to.xmit_hold = true; #ifdef ENABLE_OCC @@ -2504,8 +2512,6 @@ do_option_warnings (struct context *c) msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS"); #endif - if (script_method == SM_SYSTEM) - msg (M_WARN, "NOTE: --script-security method='system' is deprecated due to the fact that passed parameters will be subject to shell expansion"); } static void @@ -2628,12 +2634,12 @@ do_init_socket_1 (struct context *c, const int mode) #endif link_socket_init_phase1 (c->c2.link_socket, - connection_list_defined (&c->options), c->options.ce.local, c->options.ce.local_port, c->options.ce.remote, c->options.ce.remote_port, c->options.ce.proto, + c->options.ce.af, mode, c->c2.accept_from, #ifdef ENABLE_HTTP_PROXY @@ -2652,9 +2658,7 @@ do_init_socket_1 (struct context *c, const int mode) c->options.ipchange, c->plugins, c->options.resolve_retry_seconds, - c->options.ce.connect_retry_seconds, c->options.ce.connect_timeout, - c->options.ce.connect_retry_max, c->options.ce.mtu_discover_type, c->options.rcvbuf, c->options.sndbuf, @@ -2669,7 +2673,7 @@ static void do_init_socket_2 (struct context *c) { link_socket_init_phase2 (c->c2.link_socket, &c->c2.frame, - &c->sig->signal_received); + c->sig); } /* @@ -2841,14 +2845,30 @@ do_close_link_socket (struct context *c) c->c2.link_socket = NULL; } - if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip)) - { - CLEAR (c->c1.link_socket_addr.remote); + + /* Preserve the resolved list of remote if the user request to or if we want + * reconnect to the same host again or there are still addresses that need + * to be tried */ + if (!(c->sig->signal_received == SIGUSR1 && + ( (c->options.persist_remote_ip) + || + ( c->sig->source != SIG_SOURCE_HARD && + ((c->c1.link_socket_addr.current_remote && c->c1.link_socket_addr.current_remote->ai_next) + || c->options.no_advance)) + ))) + { + clear_remote_addrlist(&c->c1.link_socket_addr); + } + + /* Clear the remote actual address when persist_remote_ip is not in use */ + if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip)) CLEAR (c->c1.link_socket_addr.actual); - } - if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) - CLEAR (c->c1.link_socket_addr.local); + if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) { + if (c->c1.link_socket_addr.bind_local) + freeaddrinfo(c->c1.link_socket_addr.bind_local); + c->c1.link_socket_addr.bind_local=NULL; + } } /* @@ -3271,7 +3291,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int /* signals caught here will abort */ c->sig->signal_received = 0; c->sig->signal_text = NULL; - c->sig->hard = false; + c->sig->source = SIG_SOURCE_SOFT; if (c->mode == CM_P2P) init_management_callback_p2p (c); @@ -3290,8 +3310,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int /* link_socket_mode allows CM_CHILD_TCP instances to inherit acceptable fds from a top-level parent */ - if (c->options.ce.proto == PROTO_TCPv4_SERVER - || c->options.ce.proto == PROTO_TCPv6_SERVER) + if (c->options.ce.proto == PROTO_TCP_SERVER) { if (c->mode == CM_TOP) link_socket_mode = LS_MODE_TCP_LISTEN; @@ -3358,7 +3377,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int do_event_set_init (c, false); /* initialize HTTP or SOCKS proxy object at scope level 2 */ - init_proxy (c, 2); + init_proxy (c); /* allocate our socket object */ if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) @@ -3689,8 +3708,11 @@ close_context (struct context *c, int sig, unsigned int flags) if (c->sig->signal_received == SIGUSR1) { if ((flags & CC_USR1_TO_HUP) - || (c->sig->hard && (flags & CC_HARD_USR1_TO_HUP))) - c->sig->signal_received = SIGHUP; + || (c->sig->source == SIG_SOURCE_HARD && (flags & CC_HARD_USR1_TO_HUP))) + { + c->sig->signal_received = SIGHUP; + c->sig->signal_text = "close_context usr1 to hup"; + } } if (!(flags & CC_NO_CLOSE)) diff --git a/openvpn/src/openvpn/manage.c b/openvpn/src/openvpn/manage.c index 45e0bd43..c4e834b2 100644 --- a/openvpn/src/openvpn/manage.c +++ b/openvpn/src/openvpn/manage.c @@ -287,13 +287,13 @@ virtual_output_callback_func (void *arg, const unsigned int flags, const char *s # define AF_DID_PUSH (1<<0) # define AF_DID_RESET (1<<1) - unsigned int action_flags = 0; if (!recursive_level) /* don't allow recursion */ { struct gc_arena gc = gc_new (); struct log_entry e; const char *out = NULL; + unsigned int action_flags = 0; ++recursive_level; @@ -334,14 +334,15 @@ virtual_output_callback_func (void *arg, const unsigned int flags, const char *s } } - --recursive_level; gc_free (&gc); - } - if (action_flags & AF_DID_PUSH) - man_output_list_push_finalize (man); - if (action_flags & AF_DID_RESET) - man_reset_client_socket (man, true); + if (action_flags & AF_DID_PUSH) + man_output_list_push_finalize (man); + if (action_flags & AF_DID_RESET) + man_reset_client_socket (man, true); + + --recursive_level; + } } /* @@ -1460,7 +1461,7 @@ man_new_connection_post (struct management *man, const char *description) #endif msg (D_MANAGEMENT, "MANAGEMENT: %s %s", description, - print_sockaddr (&man->settings.local, &gc)); + print_sockaddr (man->settings.local->ai_addr, &gc)); buffer_list_reset (man->connection.out); @@ -1568,7 +1569,8 @@ man_listen (struct management *man) #endif { man->connection.sd_top = create_socket_tcp (AF_INET); - socket_bind (man->connection.sd_top, &man->settings.local, "MANAGEMENT"); + socket_bind (man->connection.sd_top, man->settings.local, + AF_INET, "MANAGEMENT"); } /* @@ -1592,7 +1594,7 @@ man_listen (struct management *man) else #endif msg (D_MANAGEMENT, "MANAGEMENT: TCP Socket listening on %s", - print_sockaddr (&man->settings.local, &gc)); + print_sockaddr (man->settings.local->ai_addr, &gc)); } #ifdef WIN32 @@ -1635,7 +1637,7 @@ man_connect (struct management *man) { man->connection.sd_cli = create_socket_tcp (AF_INET); status = openvpn_connect (man->connection.sd_cli, - &man->settings.local, + man->settings.local->ai_addr, 5, &signal_received); } @@ -1660,7 +1662,7 @@ man_connect (struct management *man) #endif msg (D_LINK_ERRORS, "MANAGEMENT: connect to %s failed: %s", - print_sockaddr (&man->settings.local, &gc), + print_sockaddr (man->settings.local->ai_addr, &gc), strerror_ts (status, &gc)); throw_signal_soft (SIGTERM, "management-connect-failed"); goto done; @@ -2044,7 +2046,7 @@ man_persist_close (struct man_persist *mp) static void man_settings_init (struct man_settings *ms, const char *addr, - const int port, + const char *port, const char *pass_file, const char *client_user, const char *client_group, @@ -2097,12 +2099,6 @@ man_settings_init (struct man_settings *ms, else #endif { - /* - * Initialize socket address - */ - ms->local.addr.in4.sin_family = AF_INET; - ms->local.addr.in4.sin_addr.s_addr = 0; - ms->local.addr.in4.sin_port = htons (port); /* * Run management over tunnel, or @@ -2114,8 +2110,9 @@ man_settings_init (struct man_settings *ms, } else { - ms->local.addr.in4.sin_addr.s_addr = getaddr - (GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL); + int status = openvpn_getaddrinfo(GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, + addr, port, 0, NULL, AF_INET, &ms->local); + ASSERT(status==0); } } @@ -2234,7 +2231,7 @@ management_init (void) bool management_open (struct management *man, const char *addr, - const int port, + const char *port, const char *pass_file, const char *client_user, const char *client_group, @@ -2600,7 +2597,13 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i && man->connection.state == MS_INITIAL) { /* listen on our local TUN/TAP IP address */ - man->settings.local.addr.in4.sin_addr.s_addr = htonl (tun_local_ip); + struct in_addr ia; + int ret; + + ia.s_addr = htonl(tun_local_ip); + ret = openvpn_getaddrinfo(0, inet_ntoa(ia), NULL, 0, NULL, + AF_INET, &man->settings.local); + ASSERT (ret==0); man_connection_init (man); } diff --git a/openvpn/src/openvpn/manage.h b/openvpn/src/openvpn/manage.h index eec24a2e..d2790dd4 100644 --- a/openvpn/src/openvpn/manage.h +++ b/openvpn/src/openvpn/manage.h @@ -212,7 +212,7 @@ struct man_persist { struct man_settings { bool defined; unsigned int flags; /* MF_x flags */ - struct openvpn_sockaddr local; + struct addrinfo* local; #if UNIX_SOCK_SUPPORT struct sockaddr_un local_unix; #endif @@ -341,7 +341,7 @@ struct management *management_init (void); bool management_open (struct management *man, const char *addr, - const int port, + const char *port, const char *pass_file, const char *client_user, const char *client_group, diff --git a/openvpn/src/openvpn/misc.c b/openvpn/src/openvpn/misc.c index d2882d81..fcc85526 100644 --- a/openvpn/src/openvpn/misc.c +++ b/openvpn/src/openvpn/misc.c @@ -53,9 +53,6 @@ const char *iproute_path = IPROUTE_PATH; /* GLOBAL */ /* contains an SSEC_x value defined in misc.h */ int script_security = SSEC_BUILT_IN; /* GLOBAL */ -/* contains SM_x value defined in misc.h */ -int script_method = SM_EXECVE; /* GLOBAL */ - /* * Pass tunnel endpoint and MTU parms to a user-supplied script. * Used to execute the up/down script/plugins. @@ -303,36 +300,25 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i #if defined(ENABLE_FEATURE_EXECVE) if (openvpn_execve_allowed (flags)) { - if (script_method == SM_EXECVE) - { - const char *cmd = a->argv[0]; - char *const *argv = a->argv; - char *const *envp = (char *const *)make_env_array (es, true, &gc); - pid_t pid; - - pid = fork (); - if (pid == (pid_t)0) /* child side */ - { - execve (cmd, argv, envp); - exit (127); - } - else if (pid < (pid_t)0) /* fork failed */ - msg (M_ERR, "openvpn_execve: unable to fork"); - else /* parent side */ - { - if (waitpid (pid, &ret, 0) != pid) - ret = -1; - } - } - else if (script_method == SM_SYSTEM) - { - ret = openvpn_system (argv_system_str (a), es, flags); - } - else - { - ASSERT (0); - } - } + const char *cmd = a->argv[0]; + char *const *argv = a->argv; + char *const *envp = (char *const *)make_env_array (es, true, &gc); + pid_t pid; + + pid = fork (); + if (pid == (pid_t)0) /* child side */ + { + execve (cmd, argv, envp); + exit (127); + } + else if (pid < (pid_t)0) /* fork failed */ + msg (M_ERR, "openvpn_execve: unable to fork"); + else /* parent side */ + { + if (waitpid (pid, &ret, 0) != pid) + ret = -1; + } + } else if (!warn_shown && (script_security < SSEC_SCRIPTS)) { msg (M_WARN, SCRIPT_SECURITY_WARNING); @@ -353,52 +339,6 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i #endif /* - * Wrapper around the system() call. - */ -int -openvpn_system (const char *command, const struct env_set *es, unsigned int flags) -{ -#ifdef HAVE_SYSTEM - int ret; - - perf_push (PERF_SCRIPT); - - /* - * add env_set to environment. - */ - if (flags & S_SCRIPT) - env_set_add_to_environment (es); - - - /* debugging */ - dmsg (D_SCRIPT, "SYSTEM[%u] '%s'", flags, command); - if (flags & S_SCRIPT) - env_set_print (D_SCRIPT, es); - - /* - * execute the command - */ - ret = platform_system(command); - - /* debugging */ - dmsg (D_SCRIPT, "SYSTEM return=%u", ret); - - /* - * remove env_set from environment - */ - if (flags & S_SCRIPT) - env_set_remove_from_environment (es); - - perf_pop (); - return ret; - -#else - msg (M_FATAL, "Sorry but I can't execute the shell command '%s' because this operating system doesn't appear to support the system() call", command); - return -1; /* NOTREACHED */ -#endif -} - -/* * Run execve() inside a fork(), duping stdout. Designed to replicate the semantics of popen() but * in a safer way that doesn't require the invocation of a shell or the risks * assocated with formatting and parsing a command line. @@ -1056,7 +996,13 @@ hostname_randomize(const char *hostname, struct gc_arena *gc) const char * gen_path (const char *directory, const char *filename, struct gc_arena *gc) { - const char *safe_filename = string_mod_const (filename, CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT, 0, '_', gc); +#if WIN32 + const int CC_PATH_RESERVED = CC_LESS_THAN|CC_GREATER_THAN|CC_COLON| + CC_DOUBLE_QUOTE|CC_SLASH|CC_BACKSLASH|CC_PIPE|CC_QUESTION_MARK|CC_ASTERISK; +#else + const int CC_PATH_RESERVED = CC_SLASH; +#endif + const char *safe_filename = string_mod_const (filename, CC_PRINT, CC_PATH_RESERVED, '_', gc); if (safe_filename && strcmp (safe_filename, ".") diff --git a/openvpn/src/openvpn/misc.h b/openvpn/src/openvpn/misc.h index b6da3f4b..183898e3 100644 --- a/openvpn/src/openvpn/misc.h +++ b/openvpn/src/openvpn/misc.h @@ -96,7 +96,6 @@ int openvpn_popen (const struct argv *a, const struct env_set *es); int openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags); bool openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message); bool openvpn_execve_allowed (const unsigned int flags); -int openvpn_system (const char *command, const struct env_set *es, unsigned int flags); static inline bool openvpn_run_script (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *hook) @@ -322,10 +321,6 @@ extern const char *iproute_path; #define SSEC_PW_ENV 3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */ extern int script_security; /* GLOBAL */ -#define SM_EXECVE 0 /* call external programs with execve() or CreateProcess() */ -#define SM_SYSTEM 1 /* call external programs with system() */ -extern int script_method; /* GLOBAL */ - /* return the next largest power of 2 */ size_t adjust_power_of_2 (size_t u); diff --git a/openvpn/src/openvpn/mss.c b/openvpn/src/openvpn/mss.c index 8981badc..64fd722f 100644 --- a/openvpn/src/openvpn/mss.c +++ b/openvpn/src/openvpn/mss.c @@ -38,8 +38,13 @@ * problems which arise from protocol * encapsulation. */ + +/* + * IPv4 packet: find TCP header, check flags for "SYN" + * if yes, hand to mss_fixup_dowork() + */ void -mss_fixup (struct buffer *buf, int maxmss) +mss_fixup_ipv4 (struct buffer *buf, int maxmss) { const struct openvpn_iphdr *pip; int hlen; @@ -69,6 +74,56 @@ mss_fixup (struct buffer *buf, int maxmss) } } +/* + * IPv6 packet: find TCP header, check flags for "SYN" + * if yes, hand to mss_fixup_dowork() + * (IPv6 header structure is sufficiently different from IPv4...) + */ +void +mss_fixup_ipv6 (struct buffer *buf, int maxmss) +{ + const struct openvpn_ipv6hdr *pip6; + struct buffer newbuf; + + if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr)) + return; + + verify_align_4 (buf); + pip6 = (struct openvpn_ipv6hdr *) BPTR (buf); + + /* do we have the full IPv6 packet? + * "payload_len" does not include IPv6 header (+40 bytes) + */ + if (BLEN (buf) != (int) ntohs(pip6->payload_len)+40 ) + return; + + /* follow header chain until we reach final header, then check for TCP + * + * An IPv6 packet could, theoretically, have a chain of multiple headers + * before the final header (TCP, UDP, ...), so we'd need to walk that + * chain (see RFC 2460 and RFC 6564 for details). + * + * In practice, "most typically used" extention headers (AH, routing, + * fragment, mobility) are very unlikely to be seen inside an OpenVPN + * tun, so for now, we only handle the case of "single next header = TCP" + */ + if ( pip6->nexthdr != OPENVPN_IPPROTO_TCP ) + return; + + newbuf = *buf; + if ( buf_advance( &newbuf, 40 ) ) + { + struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR (&newbuf); + if (tc->flags & OPENVPN_TCPH_SYN_MASK) + mss_fixup_dowork (&newbuf, (uint16_t) maxmss-20); + } +} + +/* + * change TCP MSS option in SYN/SYN-ACK packets, if present + * this is generic for IPv4 and IPv6, as the TCP header is the same + */ + void mss_fixup_dowork (struct buffer *buf, uint16_t maxmss) { diff --git a/openvpn/src/openvpn/mss.h b/openvpn/src/openvpn/mss.h index 0b290c36..0d329432 100644 --- a/openvpn/src/openvpn/mss.h +++ b/openvpn/src/openvpn/mss.h @@ -28,7 +28,8 @@ #include "proto.h" #include "error.h" -void mss_fixup (struct buffer *buf, int maxmss); +void mss_fixup_ipv4 (struct buffer *buf, int maxmss); +void mss_fixup_ipv6 (struct buffer *buf, int maxmss); void mss_fixup_dowork (struct buffer *buf, uint16_t maxmss); #endif diff --git a/openvpn/src/openvpn/multi.c b/openvpn/src/openvpn/multi.c index 9876b80a..ab3f10cb 100644 --- a/openvpn/src/openvpn/multi.c +++ b/openvpn/src/openvpn/multi.c @@ -2411,13 +2411,13 @@ multi_get_queue (struct mbuf_set *ms) if (mbuf_extract_item (ms, &item)) /* cleartext IP packet */ { - unsigned int pipv4_flags = PIPV4_PASSTOS; + unsigned int pip_flags = PIPV4_PASSTOS; set_prefix (item.instance); item.instance->context.c2.buf = item.buffer->buf; if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */ - pipv4_flags |= PIPV4_MSSFIX; - process_ipv4_header (&item.instance->context, pipv4_flags, &item.instance->context.c2.buf); + pip_flags |= PIP_MSSFIX; + process_ip_header (&item.instance->context, pip_flags, &item.instance->context.c2.buf); encrypt_sign (&item.instance->context, true); mbuf_free_buf (item.buffer); diff --git a/openvpn/src/openvpn/openvpn.c b/openvpn/src/openvpn/openvpn.c index 104c9e93..a177d9e8 100644 --- a/openvpn/src/openvpn/openvpn.c +++ b/openvpn/src/openvpn/openvpn.c @@ -41,6 +41,10 @@ #define P2P_CHECK_SIG() EVENT_LOOP_CHECK_SIGNAL (c, process_signal_p2p, c); +#ifdef GOOGLE_BREAKPAD +#include "breakpad.h" +#endif + static bool process_signal_p2p (struct context *c) { @@ -321,6 +325,10 @@ wmain (int argc, wchar_t *wargv[]) { #else int main (int argc, char *argv[]) { +#ifdef GOOGLE_BREAKPAD + breakpad_setup(); +#endif + return openvpn_main(argc, argv); } #endif diff --git a/openvpn/src/openvpn/openvpn.h b/openvpn/src/openvpn/openvpn.h index 7abfb087..bdfa6852 100644 --- a/openvpn/src/openvpn/openvpn.h +++ b/openvpn/src/openvpn/openvpn.h @@ -474,6 +474,7 @@ struct context_2 bool did_pre_pull_restore; /* hash of pulled options, so we can compare when options change */ + bool pulled_options_md5_init_done; struct md5_state pulled_options_state; struct md5_digest pulled_options_digest; diff --git a/openvpn/src/openvpn/options.c b/openvpn/src/openvpn/options.c index 47aaffcb..64c81cf2 100644 --- a/openvpn/src/openvpn/options.c +++ b/openvpn/src/openvpn/options.c @@ -167,8 +167,8 @@ static const char usage_message[] = "--ipchange cmd : Run command cmd on remote ip address initial\n" " setting or change -- execute as: cmd ip-address port#\n" "--port port : TCP/UDP port # for both local and remote.\n" - "--lport port : TCP/UDP port # for local (default=%d). Implies --bind.\n" - "--rport port : TCP/UDP port # for remote (default=%d).\n" + "--lport port : TCP/UDP port # for local (default=%s). Implies --bind.\n" + "--rport port : TCP/UDP port # for remote (default=%s).\n" "--bind : Bind to local address and port. (This is the default unless\n" " --proto tcp-client" #ifdef ENABLE_HTTP_PROXY @@ -248,7 +248,7 @@ static const char usage_message[] = "--setenv name value : Set a custom environmental variable to pass to script.\n" "--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n" " directives for future OpenVPN versions to be ignored.\n" - "--script-security level mode : mode='execve' (default) or 'system', level=\n" + "--script-security level: Where level can be:\n" " 0 -- strictly no calling of external programs\n" " 1 -- (default) only call built-ins such as ifconfig\n" " 2 -- allow calling of built-ins and scripts\n" @@ -767,10 +767,11 @@ init_options (struct options *o, const bool init_gc) } o->mode = MODE_POINT_TO_POINT; o->topology = TOP_NET30; - o->ce.proto = PROTO_UDPv4; + o->ce.proto = PROTO_UDP; + o->ce.af = AF_UNSPEC; o->ce.connect_retry_seconds = 5; o->ce.connect_timeout = 10; - o->ce.connect_retry_max = 0; + o->connect_retry_max = 0; o->ce.local_port = o->ce.remote_port = OPENVPN_PORT; o->verbosity = 1; o->status_file_update_freq = 60; @@ -897,24 +898,24 @@ setenv_connection_entry (struct env_set *es, const struct connection_entry *e, const int i) { - setenv_str_i (es, "proto", proto2ascii (e->proto, false), i); + setenv_str_i (es, "proto", proto2ascii (e->proto, e->af, false), i); setenv_str_i (es, "local", e->local, i); - setenv_int_i (es, "local_port", e->local_port, i); + setenv_str_i (es, "local_port", e->local_port, i); setenv_str_i (es, "remote", e->remote, i); - setenv_int_i (es, "remote_port", e->remote_port, i); + setenv_str_i (es, "remote_port", e->remote_port, i); #ifdef ENABLE_HTTP_PROXY if (e->http_proxy_options) { setenv_str_i (es, "http_proxy_server", e->http_proxy_options->server, i); - setenv_int_i (es, "http_proxy_port", e->http_proxy_options->port, i); + setenv_str_i (es, "http_proxy_port", e->http_proxy_options->port, i); } #endif #ifdef ENABLE_SOCKS if (e->socks_proxy_server) { setenv_str_i (es, "socks_proxy_server", e->socks_proxy_server, i); - setenv_int_i (es, "socks_proxy_port", e->socks_proxy_port, i); + setenv_str_i (es, "socks_proxy_port", e->socks_proxy_port, i); } #endif } @@ -1216,7 +1217,7 @@ show_p2mp_parms (const struct options *o) SHOW_BOOL (auth_user_pass_verify_script_via_file); #if PORT_SHARE SHOW_STR (port_share_host); - SHOW_INT (port_share_port); + SHOW_STR (port_share_port); #endif #endif /* P2MP_SERVER */ @@ -1287,7 +1288,7 @@ show_http_proxy_options (const struct http_proxy_options *o) { msg (D_SHOW_PARMS, "BEGIN http_proxy"); SHOW_STR (server); - SHOW_INT (port); + SHOW_STR (port); SHOW_STR (auth_method_string); SHOW_STR (auth_file); SHOW_BOOL (retry); @@ -1338,17 +1339,16 @@ cnol_check_alloc (struct options *options) static void show_connection_entry (const struct connection_entry *o) { - msg (D_SHOW_PARMS, " proto = %s", proto2ascii (o->proto, false)); + msg (D_SHOW_PARMS, " proto = %s", proto2ascii (o->proto, o->af, false)); SHOW_STR (local); - SHOW_INT (local_port); + SHOW_STR (local_port); SHOW_STR (remote); - SHOW_INT (remote_port); + SHOW_STR (remote_port); SHOW_BOOL (remote_float); SHOW_BOOL (bind_defined); SHOW_BOOL (bind_local); SHOW_INT (connect_retry_seconds); SHOW_INT (connect_timeout); - SHOW_INT (connect_retry_max); #ifdef ENABLE_HTTP_PROXY if (o->http_proxy_options) @@ -1356,7 +1356,7 @@ show_connection_entry (const struct connection_entry *o) #endif #ifdef ENABLE_SOCKS SHOW_STR (socks_proxy_server); - SHOW_INT (socks_proxy_port); + SHOW_STR (socks_proxy_port); SHOW_BOOL (socks_proxy_retry); #endif SHOW_INT (tun_mtu); @@ -1425,6 +1425,7 @@ show_settings (const struct options *o) #endif #endif + SHOW_INT (connect_retry_max); show_connection_entries (o); SHOW_BOOL (remote_random); @@ -1536,7 +1537,7 @@ show_settings (const struct options *o) #ifdef ENABLE_MANAGEMENT SHOW_STR (management_addr); - SHOW_INT (management_port); + SHOW_STR (management_port); SHOW_STR (management_user_pass); SHOW_INT (management_log_history_cache); SHOW_INT (management_echo_buffer_size); @@ -1683,17 +1684,9 @@ parse_http_proxy_override (const char *server, if (server && port) { struct http_proxy_options *ho; - const int int_port = atoi(port); - - if (!legal_ipv4_port (int_port)) - { - msg (msglevel, "Bad http-proxy port number: %s", port); - return NULL; - } - ALLOC_OBJ_CLEAR_GC (ho, struct http_proxy_options, gc); ho->server = string_alloc(server, gc); - ho->port = int_port; + ho->port = port; ho->retry = true; ho->timeout = 5; if (flags && !strcmp(flags, "nct")) @@ -1712,32 +1705,31 @@ void options_postprocess_http_proxy_override (struct options *o) { const struct connection_list *l = o->connection_list; - if (l) + int i; + bool succeed = false; + for (i = 0; i < l->len; ++i) + { + struct connection_entry *ce = l->array[i]; + if (ce->proto == PROTO_TCP_CLIENT || ce->proto == PROTO_TCP) + { + ce->http_proxy_options = o->http_proxy_override; + succeed = true; + } + } + if (succeed) { - int i; - bool succeed = false; for (i = 0; i < l->len; ++i) - { - struct connection_entry *ce = l->array[i]; - if (ce->proto == PROTO_TCPv4_CLIENT || ce->proto == PROTO_TCPv4) - { - ce->http_proxy_options = o->http_proxy_override; - succeed = true; - } - } - if (succeed) - { - for (i = 0; i < l->len; ++i) - { - struct connection_entry *ce = l->array[i]; - if (ce->proto == PROTO_UDPv4) - { - ce->flags |= CE_DISABLED; - } - } - } - else - msg (M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined"); + { + struct connection_entry *ce = l->array[i]; + if (ce->proto == PROTO_UDP) + { + ce->flags |= CE_DISABLED; + } + } + } + else + { + msg (M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined"); } } @@ -1796,10 +1788,12 @@ connection_entry_load_re (struct connection_entry *ce, const struct remote_entry { if (re->remote) ce->remote = re->remote; - if (re->remote_port >= 0) + if (re->remote_port) ce->remote_port = re->remote_port; if (re->proto >= 0) ce->proto = re->proto; + if (re->af > 0) + ce->af = re->af; } static void @@ -1829,7 +1823,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne * If "proto tcp" is specified, make sure we know whether it is * tcp-client or tcp-server. */ - if (ce->proto == PROTO_TCPv4) + if (ce->proto == PROTO_TCP) msg (M_USAGE, "--proto tcp is ambiguous in this context. Please specify --proto tcp-server or --proto tcp-client"); /* @@ -1842,10 +1836,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne if (options->inetd && (ce->local || ce->remote)) msg (M_USAGE, "--local or --remote cannot be used with --inetd"); - if (options->inetd && ce->proto == PROTO_TCPv4_CLIENT) + if (options->inetd && ce->proto == PROTO_TCP_CLIENT) msg (M_USAGE, "--proto tcp-client cannot be used with --inetd"); - if (options->inetd == INETD_NOWAIT && ce->proto != PROTO_TCPv4_SERVER) + if (options->inetd == INETD_NOWAIT && ce->proto != PROTO_TCP_SERVER) msg (M_USAGE, "--inetd nowait can only be used with --proto tcp-server"); if (options->inetd == INETD_NOWAIT @@ -1865,14 +1859,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne /* * Sanity check on TCP mode options */ - - if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT - && ce->proto != PROTO_TCPv6_CLIENT) - msg (M_USAGE, "--connect-retry doesn't make sense unless also used with " - "--proto tcp-client or tcp6-client"); - - if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT - && ce->proto != PROTO_TCPv6_CLIENT) + if (ce->connect_timeout_defined && ce->proto != PROTO_TCP_CLIENT) msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with " "--proto tcp-client or tcp6-client"); @@ -1898,7 +1885,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne if (proto_is_net(ce->proto) && string_defined_equal (ce->local, ce->remote) - && ce->local_port == ce->remote_port) + && string_defined_equal (ce->local_port, ce->remote_port)) msg (M_USAGE, "--remote and --local addresses are the same"); if (string_defined_equal (ce->remote, options->ifconfig_local) @@ -1971,12 +1958,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp"); #endif - if (!ce->remote && (ce->proto == PROTO_TCPv4_CLIENT - || ce->proto == PROTO_TCPv6_CLIENT)) + if (!ce->remote && ce->proto == PROTO_TCP_CLIENT) msg (M_USAGE, "--remote MUST be used in TCP Client mode"); #ifdef ENABLE_HTTP_PROXY - if ((ce->http_proxy_options) && ce->proto != PROTO_TCPv4_CLIENT) + if ((ce->http_proxy_options) && ce->proto != PROTO_TCP_CLIENT) msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)"); #endif @@ -1986,12 +1972,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #endif #ifdef ENABLE_SOCKS - if (ce->socks_proxy_server && ce->proto == PROTO_TCPv4_SERVER) + if (ce->socks_proxy_server && ce->proto == PROTO_TCP_SERVER) msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode"); #endif - if ((ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_SERVER) - && connection_list_defined (options)) + if (ce->proto == PROTO_TCP_SERVER && (options->connection_list->len > 1)) msg (M_USAGE, "TCP server mode allows at most one --remote address"); #if P2MP_SERVER @@ -2005,13 +1990,12 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--mode server only works with --dev tun or --dev tap"); if (options->pull) msg (M_USAGE, "--pull cannot be used with --mode server"); - if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCPv4_SERVER - || ce->proto == PROTO_TCPv6_SERVER)) + if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCP_SERVER)) msg (M_USAGE, "--mode server currently only supports " "--proto udp or --proto tcp-server or proto tcp6-server"); #if PORT_SHARE if ((options->port_share_host || options->port_share_port) && - (ce->proto != PROTO_TCPv4_SERVER && ce->proto != PROTO_TCPv6_SERVER)) + (ce->proto != PROTO_TCP_SERVER)) msg (M_USAGE, "--port-share only works in TCP server mode " "(--proto tcp-server or tcp6-server)"); #endif @@ -2041,8 +2025,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--inetd cannot be used with --mode server"); if (options->ipchange) msg (M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)"); - if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCPv4_SERVER - || ce->proto == PROTO_TCPv6_SERVER)) + if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCP_SERVER)) msg (M_USAGE, "--mode server currently only supports " "--proto udp or --proto tcp-server or --proto tcp6-server"); if (!proto_is_udp(ce->proto) && (options->cf_max || options->cf_per)) @@ -2194,13 +2177,15 @@ options_postprocess_verify_ce (const struct options *options, const struct conne } else #endif -#ifdef ENABLE_CRYPTOAPI #ifdef MANAGMENT_EXTERNAL_KEY if((options->management_flags & MF_EXTERNAL_KEY) && options->priv_key_file) - msg (M_USAGE, "--key and --management-external-key are mutually exclusive"); + { + msg (M_USAGE, "--key and --management-external-key are mutually exclusive"); + } + else #endif - - if (options->cryptoapi_cert) +#ifdef ENABLE_CRYPTOAPI + if (options->cryptoapi_cert) { if ((!(options->ca_file)) && (!(options->ca_path))) msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)"); @@ -2274,7 +2259,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne { notnull (options->cert_file, "certificate file (--cert) or PKCS#12 file (--pkcs12)"); #ifdef MANAGMENT_EXTERNAL_KEY - if (!options->management_flags & MF_EXTERNAL_KEY) + if (!(options->management_flags & MF_EXTERNAL_KEY)) #endif notnull (options->priv_key_file, "private key file (--key) or PKCS#12 file (--pkcs12)"); } @@ -2350,35 +2335,33 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce) #if P2MP_SERVER if (o->server_defined || o->server_bridge_defined || o->server_bridge_proxy_dhcp) { - if (ce->proto == PROTO_TCPv4) - ce->proto = PROTO_TCPv4_SERVER; + if (ce->proto == PROTO_TCP) + ce->proto = PROTO_TCP_SERVER; } #endif #if P2MP if (o->client) { - if (ce->proto == PROTO_TCPv4) - ce->proto = PROTO_TCPv4_CLIENT; - else if (ce->proto == PROTO_TCPv6) - ce->proto = PROTO_TCPv6_CLIENT; + if (ce->proto == PROTO_TCP) + ce->proto = PROTO_TCP_CLIENT; } #endif - if (ce->proto == PROTO_TCPv4_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined) + if (ce->proto == PROTO_TCP_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined) ce->bind_local = false; #ifdef ENABLE_SOCKS - if (ce->proto == PROTO_UDPv4 && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined) + if (ce->proto == PROTO_UDP && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined) ce->bind_local = false; #endif if (!ce->bind_local) - ce->local_port = 0; + ce->local_port = NULL; /* if protocol forcing is enabled, disable all protocols except for the forced one */ - if (o->proto_force >= 0 && proto_is_tcp(o->proto_force) != proto_is_tcp(ce->proto)) + if (o->proto_force >= 0 && o->proto_force != ce->proto) ce->flags |= CE_DISABLED; - + /* * If --mssfix is supplied without a parameter, default * it to --fragment value, if --fragment is specified. @@ -2488,48 +2471,40 @@ options_postprocess_mutate (struct options *o) if (o->remote_list && !o->connection_list) { /* - * For compatibility with 2.0.x, map multiple --remote options - * into connection list (connection lists added in 2.1). + * Convert remotes into connection list */ - if (o->remote_list->len > 1 || o->force_connection_list) - { - const struct remote_list *rl = o->remote_list; - int i; - for (i = 0; i < rl->len; ++i) - { - const struct remote_entry *re = rl->array[i]; - struct connection_entry ce = o->ce; - struct connection_entry *ace; - - ASSERT (re->remote); - connection_entry_load_re (&ce, re); - ace = alloc_connection_entry (o, M_USAGE); - ASSERT (ace); - *ace = ce; - } - } - else if (o->remote_list->len == 1) /* one --remote option specified */ - { - connection_entry_load_re (&o->ce, o->remote_list->array[0]); - } - else - { - ASSERT (0); - } + const struct remote_list *rl = o->remote_list; + int i; + for (i = 0; i < rl->len; ++i) + { + const struct remote_entry *re = rl->array[i]; + struct connection_entry ce = o->ce; + struct connection_entry *ace; + + ASSERT (re->remote); + connection_entry_load_re (&ce, re); + ace = alloc_connection_entry (o, M_USAGE); + ASSERT (ace); + *ace = ce; + } } - if (o->connection_list) + else if(!o->remote_list && !o->connection_list) { - int i; - for (i = 0; i < o->connection_list->len; ++i) - options_postprocess_mutate_ce (o, o->connection_list->array[i]); + struct connection_entry *ace; + ace = alloc_connection_entry (o, M_USAGE); + ASSERT (ace); + *ace = o->ce; + } + ASSERT (o->connection_list); + int i; + for (i = 0; i < o->connection_list->len; ++i) + options_postprocess_mutate_ce (o, o->connection_list->array[i]); + #if HTTP_PROXY_OVERRIDE - if (o->http_proxy_override) + if (o->http_proxy_override) options_postprocess_http_proxy_override(o); #endif - } - else - options_postprocess_mutate_ce (o, &o->ce); #if P2MP /* @@ -2666,7 +2641,7 @@ options_postprocess_filechecks (struct options *options) errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->extra_certs_file, R_OK, "--extra-certs"); #ifdef MANAGMENT_EXTERNAL_KEY - if(!options->management_flags & MF_EXTERNAL_KEY) + if(!(options->management_flags & MF_EXTERNAL_KEY)) #endif errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->priv_key_file, R_OK, "--key"); @@ -2916,8 +2891,12 @@ options_string (const struct options *o, buf_printf (&out, ",dev-type %s", dev_type_string (o->dev, o->dev_type)); buf_printf (&out, ",link-mtu %d", EXPANDED_SIZE (frame)); buf_printf (&out, ",tun-mtu %d", PAYLOAD_SIZE (frame)); - buf_printf (&out, ",proto %s", proto2ascii (proto_remote (o->ce.proto, remote), true)); - if (o->tun_ipv6) + buf_printf (&out, ",proto %s", proto_remote (o->ce.proto, remote)); + + /* send tun_ipv6 only in peer2peer mode - in client/server mode, it + * is usually pushed by the server, triggering a non-helpful warning + */ + if (o->tun_ipv6 && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o)) buf_printf (&out, ",tun-ipv6"); /* @@ -3097,6 +3076,15 @@ options_warning_safe_scan2 (const int msglevel, const char *b1_name, const char *b2_name) { + /* we will stop sending 'proto xxx' in OCC in a future version + * (because it's not useful), and to reduce questions when + * interoperating, we start not-printing a warning about it today + */ + if (strncmp(p1, "proto ", 6) == 0 ) + { + return; + } + if (strlen (p1) > 0) { struct gc_arena gc = gc_new (); @@ -4096,8 +4084,6 @@ add_option (struct options *options, #ifdef ENABLE_MANAGEMENT else if (streq (p[0], "management") && p[1] && p[2]) { - int port = 0; - VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[2], "unix")) { @@ -4108,18 +4094,9 @@ add_option (struct options *options, goto err; #endif } - else - { - port = atoi (p[2]); - if (!legal_ipv4_port (port)) - { - msg (msglevel, "port number associated with --management directive is out of range"); - goto err; - } - } options->management_addr = p[1]; - options->management_port = port; + options->management_port = p[2]; if (p[3]) { options->management_user_pass = p[3]; @@ -4149,7 +4126,6 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_QUERY_PROXY; - options->force_connection_list = true; } else if (streq (p[0], "management-hold")) { @@ -4378,11 +4354,6 @@ add_option (struct options *options, uninit_options (&sub); } } - else if (streq (p[0], "remote-ip-hint") && p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->remote_ip_hint = p[1]; - } #if HTTP_PROXY_OVERRIDE else if (streq (p[0], "http-proxy-override") && p[1] && p[2]) { @@ -4390,35 +4361,31 @@ add_option (struct options *options, options->http_proxy_override = parse_http_proxy_override(p[1], p[2], p[3], msglevel, &options->gc); if (!options->http_proxy_override) goto err; - options->force_connection_list = true; } #endif else if (streq (p[0], "remote") && p[1]) { struct remote_entry re; - re.remote = NULL; - re.remote_port = re.proto = -1; + re.remote = re.remote_port= NULL; + re.proto = -1; + re.af=0; VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); re.remote = p[1]; if (p[2]) { - const int port = atoi (p[2]); - if (!legal_ipv4_port (port)) - { - msg (msglevel, "remote: port number associated with host %s is out of range", p[1]); - goto err; - } - re.remote_port = port; + re.remote_port = p[2]; if (p[3]) { const int proto = ascii2proto (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; } } if (permission_mask & OPT_P_GENERAL) @@ -4445,7 +4412,6 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.connect_retry_seconds = positive_atoi (p[1]); - options->ce.connect_retry_defined = true; } else if (streq (p[0], "connect-timeout") && p[1]) { @@ -4456,7 +4422,7 @@ add_option (struct options *options, else if (streq (p[0], "connect-retry-max") && p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.connect_retry_max = positive_atoi (p[1]); + options->connect_retry_max = positive_atoi (p[1]); } else if (streq (p[0], "ipchange") && p[1]) { @@ -4811,43 +4777,19 @@ add_option (struct options *options, } else if (streq (p[0], "port") && p[1]) { - int port; - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - port = atoi (p[1]); - if (!legal_ipv4_port (port)) - { - msg (msglevel, "Bad port number: %s", p[1]); - goto err; - } - options->ce.local_port = options->ce.remote_port = port; + options->ce.local_port = options->ce.remote_port = p[1]; } else if (streq (p[0], "lport") && p[1]) { - int port; - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - port = atoi (p[1]); - if ((port != 0) && !legal_ipv4_port (port)) - { - msg (msglevel, "Bad local port number: %s", p[1]); - goto err; - } options->ce.local_port_defined = true; - options->ce.local_port = port; + options->ce.local_port = p[1]; } else if (streq (p[0], "rport") && p[1]) { - int port; - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - port = atoi (p[1]); - if (!legal_ipv4_port (port)) - { - msg (msglevel, "Bad remote port number: %s", p[1]); - goto err; - } - options->ce.remote_port = port; + options->ce.remote_port = p[1]; } else if (streq (p[0], "bind")) { @@ -4874,8 +4816,10 @@ add_option (struct options *options, else if (streq (p[0], "proto") && p[1]) { int proto; + sa_family_t af; VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); proto = ascii2proto (p[1]); + af = ascii2af(p[1]); if (proto < 0) { msg (msglevel, "Bad protocol: '%s'. Allowed protocols with --proto option: %s", @@ -4884,6 +4828,7 @@ add_option (struct options *options, goto err; } options->ce.proto = proto; + options->ce.af = af; } else if (streq (p[0], "proto-force") && p[1]) { @@ -4896,7 +4841,6 @@ add_option (struct options *options, goto err; } options->proto_force = proto_force; - options->force_connection_list = true; } #ifdef ENABLE_HTTP_PROXY else if (streq (p[0], "http-proxy") && p[1]) @@ -4906,23 +4850,16 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); { - int port; if (!p[2]) { msg (msglevel, "http-proxy port number not defined"); goto err; } - port = atoi (p[2]); - if (!legal_ipv4_port (port)) - { - msg (msglevel, "Bad http-proxy port number: %s", p[2]); - goto err; - } ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); ho->server = p[1]; - ho->port = port; + ho->port = p[2]; } if (p[3]) @@ -4992,19 +4929,12 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); if (p[2]) - { - int port; - port = atoi (p[2]); - if (!legal_ipv4_port (port)) - { - msg (msglevel, "Bad socks-proxy port number: %s", p[2]); - goto err; - } - options->ce.socks_proxy_port = port; + { + options->ce.socks_proxy_port = p[2]; } else { - options->ce.socks_proxy_port = 1080; + options->ce.socks_proxy_port = "1080"; } options->ce.socks_proxy_server = p[1]; options->ce.socks_proxy_authfile = p[3]; /* might be NULL */ @@ -5141,6 +5071,11 @@ add_option (struct options *options, msg (msglevel, "--max-routes parameter is out of range"); goto err; } + if (options->routes || options->routes_ipv6) + { + msg (msglevel, "--max-routes must to be specifed before any route/route-ipv6/redirect-gateway option"); + goto err; + } options->max_routes = max_routes; } else if (streq (p[0], "route-gateway") && p[1]) @@ -5293,20 +5228,6 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL); script_security = atoi (p[1]); - if (p[2]) - { - if (streq (p[2], "execve")) - script_method = SM_EXECVE; - else if (streq (p[2], "system")) - script_method = SM_SYSTEM; - else - { - msg (msglevel, "unknown --script-security method: %s", p[2]); - goto err; - } - } - else - script_method = SM_EXECVE; } else if (streq (p[0], "mssfix")) { @@ -5652,18 +5573,9 @@ add_option (struct options *options, #if PORT_SHARE else if (streq (p[0], "port-share") && p[1] && p[2]) { - int port; - VERIFY_PERMISSION (OPT_P_GENERAL); - port = atoi (p[2]); - if (!legal_ipv4_port (port)) - { - msg (msglevel, "port number associated with --port-share directive is out of range"); - goto err; - } - options->port_share_host = p[1]; - options->port_share_port = port; + options->port_share_port = p[2]; options->port_share_journal_dir = p[3]; } #endif diff --git a/openvpn/src/openvpn/options.h b/openvpn/src/openvpn/options.h index 306520b0..909cb38a 100644 --- a/openvpn/src/openvpn/options.h +++ b/openvpn/src/openvpn/options.h @@ -87,17 +87,16 @@ struct options_pre_pull struct connection_entry { int proto; - int local_port; + sa_family_t af; + const char* local_port; bool local_port_defined; - int remote_port; + const char* remote_port; const char *local; const char *remote; bool remote_float; bool bind_defined; bool bind_local; int connect_retry_seconds; - bool connect_retry_defined; - int connect_retry_max; int connect_timeout; bool connect_timeout_defined; #ifdef ENABLE_HTTP_PROXY @@ -105,7 +104,7 @@ struct connection_entry #endif #ifdef ENABLE_SOCKS const char *socks_proxy_server; - int socks_proxy_port; + const char *socks_proxy_port; const char *socks_proxy_authfile; bool socks_proxy_retry; #endif @@ -143,8 +142,9 @@ struct connection_entry struct remote_entry { const char *remote; - int remote_port; + const char *remote_port; int proto; + sa_family_t af; }; #define CONNECTION_LIST_SIZE 64 @@ -153,8 +153,6 @@ struct connection_list { int len; int current; - int n_cycles; - bool no_advance; struct connection_entry *array[CONNECTION_LIST_SIZE]; }; @@ -168,6 +166,8 @@ struct remote_host_store { # define RH_HOST_LEN 80 char host[RH_HOST_LEN]; +#define RH_PORT_LEN 20 + char port[RH_PORT_LEN]; }; /* Command line options */ @@ -203,11 +203,15 @@ struct options #endif /* Networking parms */ + int connect_retry_max; struct connection_entry ce; - char *remote_ip_hint; struct connection_list *connection_list; + struct remote_list *remote_list; - bool force_connection_list; + /* Do not advanced the connection or remote addr list*/ + bool no_advance; + /* Counts the number of unsuccessful connection attempts */ + unsigned int unsuccessful_attempts; #if HTTP_PROXY_OVERRIDE struct http_proxy_options *http_proxy_override; @@ -354,7 +358,7 @@ struct options #ifdef ENABLE_MANAGEMENT const char *management_addr; - int management_port; + const char *management_port; const char *management_user_pass; int management_log_history_cache; int management_echo_buffer_size; @@ -449,7 +453,7 @@ struct options bool auth_user_pass_verify_script_via_file; #if PORT_SHARE char *port_share_host; - int port_share_port; + char *port_share_port; const char *port_share_journal_dir; #endif #endif @@ -769,20 +773,5 @@ bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network, unsigned int * netbits, char ** printable_ipv6, int msglevel ); -/* - * inline functions - */ -static inline bool -connection_list_defined (const struct options *o) -{ - return o->connection_list != NULL; -} - -static inline void -connection_list_set_no_advance (struct options *o) -{ - if (o->connection_list) - o->connection_list->no_advance = true; -} #endif diff --git a/openvpn/src/openvpn/pf.c b/openvpn/src/openvpn/pf.c index 3c468019..aafe9ff0 100644 --- a/openvpn/src/openvpn/pf.c +++ b/openvpn/src/openvpn/pf.c @@ -606,7 +606,6 @@ pf_destroy_context (struct pf_context *pfc) if (pfc->filename) { platform_unlink (pfc->filename); - free (pfc->filename); } #endif if (pfc->pfs) diff --git a/openvpn/src/openvpn/pkcs11.c b/openvpn/src/openvpn/pkcs11.c index 645f1f48..3a15ef68 100644 --- a/openvpn/src/openvpn/pkcs11.c +++ b/openvpn/src/openvpn/pkcs11.c @@ -887,7 +887,7 @@ show_pkcs11_ids ( (dn = pkcs11_certificate_dn ( certificate, &gc - )) + )) == NULL ) { goto cleanup1; } diff --git a/openvpn/src/openvpn/platform.c b/openvpn/src/openvpn/platform.c index c79f6807..e79de7a7 100644 --- a/openvpn/src/openvpn/platform.c +++ b/openvpn/src/openvpn/platform.c @@ -205,7 +205,7 @@ platform_chdir (const char* dir) } /* - * convert system() return into a success/failure value + * convert execve() return into a success/failure value */ bool platform_system_ok (int stat) @@ -217,19 +217,6 @@ platform_system_ok (int stat) #endif } -/* - * did system() call execute the given command? - */ -bool -platform_system_executed (int stat) -{ -#ifdef WIN32 - return stat != -1; -#else - return stat != -1 && WEXITSTATUS (stat) != 127; -#endif -} - int platform_access (const char *path, int mode) { @@ -288,18 +275,6 @@ platform_unlink (const char *filename) #endif } -int platform_system(const char *command) { - int ret; -#ifdef WIN32 - struct gc_arena gc = gc_new (); - ret = _wsystem (wide_string (command, &gc)); - gc_free (&gc); -#else - ret = system (command); -#endif - return ret; -} - int platform_putenv(char *string) { int status; diff --git a/openvpn/src/openvpn/platform.h b/openvpn/src/openvpn/platform.h index 7bd20671..7c0a4d72 100644 --- a/openvpn/src/openvpn/platform.h +++ b/openvpn/src/openvpn/platform.h @@ -113,10 +113,8 @@ void platform_mlockall (bool print_msg); /* Disable paging */ int platform_chdir (const char* dir); -/* interpret the status code returned by system()/execve() */ +/* interpret the status code returned by execve() */ bool platform_system_ok (int stat); -bool platform_system_executed (int stat); -int platform_system(const char *command); int platform_access (const char *path, int mode); diff --git a/openvpn/src/openvpn/plugin.c b/openvpn/src/openvpn/plugin.c index d785daec..83f79e4f 100644 --- a/openvpn/src/openvpn/plugin.c +++ b/openvpn/src/openvpn/plugin.c @@ -98,7 +98,9 @@ plugin_type_name (const int type) case OPENVPN_PLUGIN_TLS_FINAL: return "PLUGIN_TLS_FINAL"; case OPENVPN_PLUGIN_ENABLE_PF: - return "OPENVPN_PLUGIN_ENABLE_PF"; + return "PLUGIN_ENABLE_PF"; + case OPENVPN_PLUGIN_ROUTE_PREDOWN: + return "PLUGIN_ROUTE_PREDOWN"; default: return "PLUGIN_???"; } @@ -376,10 +378,10 @@ plugin_open_item (struct plugin *p, struct openvpn_plugin_args_open_return retargs; CLEAR(retargs); + retargs.return_list = retlist; if ((*p->open3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs) == OPENVPN_PLUGIN_FUNC_SUCCESS) { p->plugin_type_mask = retargs.type_mask; p->plugin_handle = retargs.handle; - retlist = retargs.return_list; } else { p->plugin_handle = NULL; } @@ -458,8 +460,8 @@ plugin_call_item (const struct plugin *p, struct openvpn_plugin_args_func_return retargs; CLEAR(retargs); + retargs.return_list = retlist; status = (*p->func3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs); - retlist = retargs.return_list; } else if (p->func2) status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist); else if (p->func1) diff --git a/openvpn/src/openvpn/proto.c b/openvpn/src/openvpn/proto.c index 2cf8314b..b437f1ad 100644 --- a/openvpn/src/openvpn/proto.c +++ b/openvpn/src/openvpn/proto.c @@ -36,11 +36,12 @@ #include "memdbg.h" /* - * If raw tunnel packet is IPv4, return true and increment + * If raw tunnel packet is IPv<X>, return true and increment * buffer offset to start of IP header. */ +static bool -is_ipv4 (int tunnel_type, struct buffer *buf) +is_ipv_X ( int tunnel_type, struct buffer *buf, int ip_ver ) { int offset; const struct openvpn_iphdr *ih; @@ -68,12 +69,24 @@ is_ipv4 (int tunnel_type, struct buffer *buf) ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset); - if (OPENVPN_IPH_GET_VER (ih->version_len) == 4) + /* IP version is stored in the same bits for IPv4 or IPv6 header */ + if (OPENVPN_IPH_GET_VER (ih->version_len) == ip_ver) return buf_advance (buf, offset); else return false; } +bool +is_ipv4 (int tunnel_type, struct buffer *buf) +{ + return is_ipv_X( tunnel_type, buf, 4 ); +} +bool +is_ipv6 (int tunnel_type, struct buffer *buf) +{ + return is_ipv_X( tunnel_type, buf, 6 ); +} + #ifdef PACKET_TRUNCATION_CHECK void diff --git a/openvpn/src/openvpn/proto.h b/openvpn/src/openvpn/proto.h index 8cd4edec..f91e787e 100644 --- a/openvpn/src/openvpn/proto.h +++ b/openvpn/src/openvpn/proto.h @@ -219,10 +219,11 @@ struct ip_tcp_udp_hdr { - sizeof(struct openvpn_tcphdr)) /* - * If raw tunnel packet is IPv4, return true and increment + * If raw tunnel packet is IPv4 or IPv6, return true and increment * buffer offset to start of IP header. */ bool is_ipv4 (int tunnel_type, struct buffer *buf); +bool is_ipv6 (int tunnel_type, struct buffer *buf); #ifdef PACKET_TRUNCATION_CHECK void ipv4_packet_size_verify (const uint8_t *data, diff --git a/openvpn/src/openvpn/proxy.c b/openvpn/src/openvpn/proxy.c index 363d8a73..17748504 100644 --- a/openvpn/src/openvpn/proxy.c +++ b/openvpn/src/openvpn/proxy.c @@ -444,7 +444,7 @@ http_proxy_new (const struct http_proxy_options *o) if (!o || !o->server) msg (M_FATAL, "HTTP_PROXY: server not specified"); - ASSERT (legal_ipv4_port (o->port)); + ASSERT ( o->port); ALLOC_OBJ_CLEAR (p, struct http_proxy_info); p->options = *o; @@ -493,7 +493,7 @@ bool establish_http_proxy_passthru (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ - const int port, /* openvpn server port */ + const char *port, /* openvpn server port */ struct buffer *lookahead, volatile int *signal_received) { @@ -521,7 +521,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, else { /* format HTTP CONNECT message */ - openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", + openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%s HTTP/%s", host, port, p->options.http_version); @@ -642,7 +642,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, /* now send the phase 3 reply */ /* format HTTP CONNECT message */ - openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", + openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%s HTTP/%s", host, port, p->options.http_version); @@ -730,7 +730,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, /* build the digest response */ - openvpn_snprintf (uri, sizeof(uri), "%s:%d", + openvpn_snprintf (uri, sizeof(uri), "%s:%s", host, port); diff --git a/openvpn/src/openvpn/proxy.h b/openvpn/src/openvpn/proxy.h index 5e476f16..9d75e063 100644 --- a/openvpn/src/openvpn/proxy.h +++ b/openvpn/src/openvpn/proxy.h @@ -40,7 +40,7 @@ struct http_proxy_options { const char *server; - int port; + const char *port; bool retry; int timeout; @@ -57,7 +57,7 @@ struct http_proxy_options { struct http_proxy_options_simple { const char *server; - int port; + const char *port; int auth_retry; }; @@ -80,7 +80,7 @@ void http_proxy_close (struct http_proxy_info *hp); bool establish_http_proxy_passthru (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ - const int port, /* openvpn server port */ + const char *port, /* openvpn server port */ struct buffer *lookahead, volatile int *signal_received); diff --git a/openvpn/src/openvpn/ps.c b/openvpn/src/openvpn/ps.c index 6495dc71..c1868642 100644 --- a/openvpn/src/openvpn/ps.c +++ b/openvpn/src/openvpn/ps.c @@ -330,8 +330,8 @@ journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_ if (!getpeername (pc->sd, (struct sockaddr *) &from.addr.sa, &slen) && !getsockname (cp->sd, (struct sockaddr *) &to.addr.sa, &dlen)) { - const char *f = print_sockaddr_ex (&from, ":", PS_SHOW_PORT, &gc); - const char *t = print_sockaddr_ex (&to, ":", PS_SHOW_PORT, &gc); + const char *f = print_openvpn_sockaddr (&from, &gc); + const char *t = print_openvpn_sockaddr (&to, &gc); fnlen = strlen(journal_dir) + strlen(t) + 2; jfn = (char *) malloc(fnlen); check_malloc_return (jfn); @@ -403,8 +403,7 @@ proxy_connection_io_requeue (struct proxy_connection *pc, const int rwflags_new, static bool proxy_entry_new (struct proxy_connection **list, struct event_set *es, - const in_addr_t server_addr, - const int server_port, + const struct sockaddr_in server_addr, const socket_descriptor_t sd_client, struct buffer *initial_data, const char *journal_dir) @@ -416,7 +415,7 @@ proxy_entry_new (struct proxy_connection **list, struct proxy_connection *cp; /* connect to port share server */ - sock_addr_set (&osaddr, server_addr, server_port); + 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"); @@ -482,8 +481,7 @@ static bool control_message_from_parent (const socket_descriptor_t sd_control, struct proxy_connection **list, struct event_set *es, - const in_addr_t server_addr, - const int server_port, + const struct sockaddr_in server_addr, const int max_initial_buf, const char *journal_dir) { @@ -539,7 +537,6 @@ control_message_from_parent (const socket_descriptor_t sd_control, if (proxy_entry_new (list, es, server_addr, - server_port, received_fd, &buf, journal_dir)) @@ -716,8 +713,7 @@ proxy_connection_io_dispatch (struct proxy_connection *pc, * This is the main function for the port share proxy background process. */ static void -port_share_proxy (const in_addr_t hostaddr, - const int port, +port_share_proxy (const struct sockaddr_in hostaddr, const socket_descriptor_t sd_control, const int max_initial_buf, const char *journal_dir) @@ -754,7 +750,7 @@ port_share_proxy (const in_addr_t hostaddr, const struct event_set_return *e = &esr[i]; if (e->arg == sd_control_marker) { - if (!control_message_from_parent (sd_control, &list, es, hostaddr, port, max_initial_buf, journal_dir)) + if (!control_message_from_parent (sd_control, &list, es, hostaddr, max_initial_buf, journal_dir)) goto done; } else @@ -789,14 +785,16 @@ port_share_proxy (const in_addr_t hostaddr, */ struct port_share * port_share_open (const char *host, - const int port, + const char *port, const int max_initial_buf, const char *journal_dir) { pid_t pid; socket_descriptor_t fd[2]; - in_addr_t hostaddr; + struct sockaddr_in hostaddr; struct port_share *ps; + int status; + struct addrinfo* ai; ALLOC_OBJ_CLEAR (ps, struct port_share); ps->foreground_fd = -1; @@ -805,7 +803,12 @@ port_share_open (const char *host, /* * Get host's IP address */ - hostaddr = getaddr (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, host, 0, NULL, NULL); + + status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, + host, port, 0, NULL, AF_INET, &ai); + ASSERT (status==0); + hostaddr = *((struct sockaddr_in*) ai->ai_addr); + freeaddrinfo(ai); /* * Make a socket for foreground and background processes @@ -881,7 +884,7 @@ port_share_open (const char *host, prng_init (NULL, 0); /* execute the event loop */ - port_share_proxy (hostaddr, port, fd[1], max_initial_buf, journal_dir); + port_share_proxy (hostaddr, fd[1], max_initial_buf, journal_dir); openvpn_close_socket (fd[1]); diff --git a/openvpn/src/openvpn/ps.h b/openvpn/src/openvpn/ps.h index 4280635d..e8919d48 100644 --- a/openvpn/src/openvpn/ps.h +++ b/openvpn/src/openvpn/ps.h @@ -44,7 +44,7 @@ struct port_share { extern struct port_share *port_share; struct port_share *port_share_open (const char *host, - const int port, + const char *port, const int max_initial_buf, const char *journal_dir); diff --git a/openvpn/src/openvpn/push.c b/openvpn/src/openvpn/push.c index 05a38e0d..994b7ba7 100644 --- a/openvpn/src/openvpn/push.c +++ b/openvpn/src/openvpn/push.c @@ -49,7 +49,7 @@ void receive_auth_failed (struct context *c, const struct buffer *buffer) { msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); - connection_list_set_no_advance(&c->options); + c->options.no_advance=true; if (c->options.pull) { switch (auth_retry_get ()) @@ -446,10 +446,14 @@ process_incoming_push_msg (struct context *c, if (ch == ',') { struct buffer buf_orig = buf; + if (!c->c2.pulled_options_md5_init_done) + { + md5_state_init (&c->c2.pulled_options_state); + c->c2.pulled_options_md5_init_done = true; + } if (!c->c2.did_pre_pull_restore) { pre_pull_restore (&c->options); - md5_state_init (&c->c2.pulled_options_state); c->c2.did_pre_pull_restore = true; } if (apply_push_options (&c->options, @@ -463,6 +467,7 @@ process_incoming_push_msg (struct context *c, case 1: md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); md5_state_final (&c->c2.pulled_options_state, &c->c2.pulled_options_digest); + c->c2.pulled_options_md5_init_done = false; ret = PUSH_MSG_REPLY; break; case 2: diff --git a/openvpn/src/openvpn/route.c b/openvpn/src/openvpn/route.c index caa2459b..8a778884 100644 --- a/openvpn/src/openvpn/route.c +++ b/openvpn/src/openvpn/route.c @@ -294,12 +294,12 @@ init_route (struct route *r, if(get_special_addr (rl, ro->network, &special.s_addr, &status)) { special.s_addr = htonl(special.s_addr); - ret = openvpn_getaddrinfo(0, inet_ntoa(special), 0, NULL, + ret = openvpn_getaddrinfo(0, inet_ntoa(special), NULL, 0, NULL, AF_INET, network_list); } else ret = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL, - ro->network, 0, NULL, AF_INET, network_list); + ro->network, NULL, 0, NULL, AF_INET, network_list); status = (ret == 0); @@ -2722,7 +2722,7 @@ get_default_gateway (struct route_gateway_info *rgi) if (write(s, (char *)&m_rtmsg, l) < 0) { - warn("writing to routing socket"); + msg(M_WARN|M_ERRNO, "Could not retrieve default gateway from route socket:"); gc_free (&gc); close(s); return; @@ -3088,7 +3088,7 @@ get_default_gateway (struct route_gateway_info *rgi) if (write(s, (char *)&m_rtmsg, l) < 0) { - warn("writing to routing socket"); + msg(M_WARN|M_ERRNO, "Could not retrieve default gateway from route socket:"); gc_free (&gc); close(s); return; diff --git a/openvpn/src/openvpn/sig.c b/openvpn/src/openvpn/sig.c index 0ebde245..7ddfd0ed 100644 --- a/openvpn/src/openvpn/sig.c +++ b/openvpn/src/openvpn/sig.c @@ -97,14 +97,14 @@ void throw_signal (const int signum) { siginfo_static.signal_received = signum; - siginfo_static.hard = true; + siginfo_static.source = SIG_SOURCE_HARD; } void throw_signal_soft (const int signum, const char *signal_text) { siginfo_static.signal_received = signum; - siginfo_static.hard = false; + siginfo_static.source = SIG_SOURCE_SOFT; siginfo_static.signal_text = signal_text; } @@ -115,7 +115,7 @@ signal_reset (struct signal_info *si) { si->signal_received = 0; si->signal_text = NULL; - si->hard = false; + si->source = SIG_SOURCE_SOFT; } } @@ -124,9 +124,23 @@ print_signal (const struct signal_info *si, const char *title, int msglevel) { if (si) { - const char *hs = (si->hard ? "hard" : "soft"); const char *type = (si->signal_text ? si->signal_text : ""); const char *t = (title ? title : "process"); + const char *hs; + switch (si->source) + { + case SIG_SOURCE_SOFT: + hs= "soft"; + break; + case SIG_SOURCE_HARD: + hs = "hard"; + break; + case SIG_SOURCE_CONNECTION_FAILED: + hs = "connection failed(soft)"; + break; + default: + ASSERT(0); + } switch (si->signal_received) { diff --git a/openvpn/src/openvpn/sig.h b/openvpn/src/openvpn/sig.h index 987efef5..c2c7b54e 100644 --- a/openvpn/src/openvpn/sig.h +++ b/openvpn/src/openvpn/sig.h @@ -28,6 +28,15 @@ #include "status.h" #include "win32.h" + + +#define SIG_SOURCE_SOFT 0 +#define SIG_SOURCE_HARD 1 +/* CONNECTION_FAILED is also a "soft" status, + * It is thrown if a connection attempt fails + */ +#define SIG_SOURCE_CONNECTION_FAILED 2 + /* * Signal information, including signal code * and descriptive text. @@ -35,7 +44,7 @@ struct signal_info { volatile int signal_received; - volatile bool hard; + volatile int source; const char *signal_text; }; diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c index 1e38e82c..9a33197c 100644 --- a/openvpn/src/openvpn/socket.c +++ b/openvpn/src/openvpn/socket.c @@ -101,8 +101,8 @@ getaddr (unsigned int flags, { struct addrinfo *ai; int status; - status = openvpn_getaddrinfo(flags, hostname, resolve_retry_seconds, - signal_received, AF_INET, &ai); + status = openvpn_getaddrinfo (flags & ~GETADDR_HOST_ORDER, hostname, NULL, + resolve_retry_seconds, signal_received, AF_INET, &ai); if(status==0) { struct in_addr ia; if(succeeded) @@ -125,6 +125,7 @@ getaddr (unsigned int flags, int openvpn_getaddrinfo (unsigned int flags, const char *hostname, + const char *servname, int resolve_retry_seconds, volatile int *signal_received, int ai_family, @@ -135,6 +136,8 @@ openvpn_getaddrinfo (unsigned int flags, 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); @@ -142,8 +145,19 @@ openvpn_getaddrinfo (unsigned int flags, res_init (); #endif - if (!hostname) - hostname = "::"; + ASSERT (hostname || servname); + ASSERT (!(flags & GETADDR_HOST_ORDER)); + + if(hostname) + print_hostname = hostname; + else + print_hostname = "undefined"; + + if(servname) + print_servname = servname; + else + print_servname = ""; + if (flags & GETADDR_RANDOMIZE) hostname = hostname_randomize(hostname, &gc); @@ -159,25 +173,36 @@ openvpn_getaddrinfo (unsigned int flags, CLEAR(hints); hints.ai_family = ai_family; hints.ai_flags = AI_NUMERICHOST; - hints.ai_socktype = dnsflags_to_socktype(flags); + hints.ai_socktype = SOCK_STREAM; + + 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, NULL, &hints, res); + status = getaddrinfo(hostname, servname, &hints, res); if (status != 0) /* parse as numeric address failed? */ { const int fail_wait_interval = 5; /* seconds */ - int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : (resolve_retry_seconds / fail_wait_interval); + /* 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; - - fmt = "RESOLVE: Cannot resolve host address: %s: %s"; + + 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 (I would have retried this name query if you had specified the --resolv-retry option.)"; + fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) (I would have retried this name query if you had specified the --resolv-retry option.)"; if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL) { - msg (msglevel, "RESOLVE: Cannot parse IP address: %s", hostname); + msg (msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)", + print_hostname,print_servname, gai_strerror(status)); goto done; } @@ -199,28 +224,30 @@ openvpn_getaddrinfo (unsigned int flags, while (true) { /* try hostname lookup */ - hints.ai_flags = 0; + 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, NULL, &hints, res); + status = getaddrinfo(hostname, servname, &hints, res); if (signal_received) { get_signal (signal_received); if (*signal_received) /* were we interrupted by a signal? */ { - if (0 == status) { - ASSERT(res); - freeaddrinfo(*res); - res = NULL; - } if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ { msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); *signal_received = 0; } else - goto done; + { + if (0 == status) { + ASSERT(res); + freeaddrinfo(*res); + res = NULL; + } + goto done; + } } } @@ -236,7 +263,8 @@ openvpn_getaddrinfo (unsigned int flags, msg (level, fmt, - hostname, + print_hostname, + print_servname, gai_strerror(status)); if (--resolve_retries <= 0) @@ -249,7 +277,8 @@ openvpn_getaddrinfo (unsigned int flags, /* hostname resolve succeeded */ - /* Do not chose an IP Addresse by random or change the order * + /* + * Do not chose an IP Addresse by random or change the order * * of IP addresses, doing so will break RFC 3484 address selection * */ } @@ -419,59 +448,6 @@ mac_addr_safe (const char *mac_addr) return true; } -static void -update_remote (const char* host, - struct openvpn_sockaddr *addr, - bool *changed, - const unsigned int sockflags) -{ - switch(addr->addr.sa.sa_family) - { - case AF_INET: - if (host && addr) - { - const in_addr_t new_addr = getaddr ( - sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), - host, - 1, - NULL, - NULL); - if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr) - { - addr->addr.in4.sin_addr.s_addr = new_addr; - *changed = true; - } - } - break; - case AF_INET6: - if (host && addr) - { - int status; - struct addrinfo* ai; - - status = openvpn_getaddrinfo(sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), host, 1, NULL, AF_INET6, &ai); - - if ( status ==0 ) - { - struct sockaddr_in6 sin6; - CLEAR(sin6); - sin6 = *((struct sockaddr_in6*)ai->ai_addr); - if (!IN6_ARE_ADDR_EQUAL(&sin6.sin6_addr, &addr->addr.in6.sin6_addr)) - { - int port = addr->addr.in6.sin6_port; - /* ipv6 requires also eg. sin6_scope_id => easier to fully copy and override port */ - addr->addr.in6 = sin6; - addr->addr.in6.sin6_port = port; - } - freeaddrinfo(ai); - } - } - break; - default: - ASSERT(0); - } -} - static int socket_get_sndbuf (int sd) { @@ -643,51 +619,41 @@ create_socket_tcp (int af) } static socket_descriptor_t -create_socket_udp (const unsigned int flags) +create_socket_udp (const int af, const unsigned int flags) { socket_descriptor_t sd; - if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - msg (M_ERR, "UDP: Cannot create UDP socket"); + if ((sd = socket (af, SOCK_DGRAM, IPPROTO_UDP)) < 0) + msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket"); #if ENABLE_IP_PKTINFO else if (flags & SF_USE_IP_PKTINFO) { int pad = 1; + if(af == AF_INET) + { #ifdef IP_PKTINFO - if (setsockopt (sd, SOL_IP, IP_PKTINFO, - (void*)&pad, sizeof(pad)) < 0) - msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO"); + 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"); + if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR, + (void*)&pad, sizeof(pad)) < 0) + msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR"); #else #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif - } -#endif - return sd; -} - -static socket_descriptor_t -create_socket_udp6 (const unsigned int flags) -{ - socket_descriptor_t sd; - - if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) - msg (M_ERR, "UDP: Cannot create UDP6 socket"); -#if ENABLE_IP_PKTINFO - else if (flags & SF_USE_IP_PKTINFO) - { - int pad = 1; + } + else if (af == AF_INET6 ) + { #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */ - if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, - (void*)&pad, sizeof(pad)) < 0) + 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) + if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + (void*)&pad, sizeof(pad)) < 0) #endif - msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO"); + msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO"); + } } #endif return sd; @@ -696,36 +662,37 @@ create_socket_udp6 (const unsigned int flags) static void create_socket (struct link_socket *sock) { - /* create socket */ - if (sock->info.proto == PROTO_UDPv4) + /* 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); + + + if (ai_proto == IPPROTO_UDP) { - sock->sd = create_socket_udp (sock->sockflags); + sock->sd = create_socket_udp (ai_family, sock->sockflags); sock->sockflags |= SF_GETADDRINFO_DGRAM; #ifdef ENABLE_SOCKS if (sock->socks_proxy) - sock->ctrl_sd = create_socket_tcp (AF_INET); + sock->ctrl_sd = create_socket_tcp (ai_family); #endif } - else if (sock->info.proto == PROTO_TCPv4_SERVER - || sock->info.proto == PROTO_TCPv4_CLIENT) - { - sock->sd = create_socket_tcp (AF_INET); - } - else if (sock->info.proto == PROTO_TCPv6_SERVER - || sock->info.proto == PROTO_TCPv6_CLIENT) + else if (ai_proto == IPPROTO_TCP) { - sock->sd = create_socket_tcp (AF_INET6); - } - else if (sock->info.proto == PROTO_UDPv6) - { - sock->sd = create_socket_udp6 (sock->sockflags); - sock->sockflags |= SF_GETADDRINFO_DGRAM; + sock->sd = create_socket_tcp (ai_family); } 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); + #ifdef TARGET_ANDROID struct user_pass up; strcpy(up.username ,__func__); @@ -740,10 +707,9 @@ create_socket (struct link_socket *sock) /* * Functions used for establishing a TCP stream connection. */ - static void socket_do_listen (socket_descriptor_t sd, - const struct openvpn_sockaddr *local, + const struct sockaddr *local, bool do_listen, bool do_set_nonblock) { @@ -833,8 +799,7 @@ static int socket_listen_accept (socket_descriptor_t sd, struct link_socket_actual *act, const char *remote_dynamic, - bool *remote_changed, - const struct openvpn_sockaddr *local, + const struct addrinfo *local, bool do_listen, bool nowait, volatile int *signal_received) @@ -845,7 +810,7 @@ socket_listen_accept (socket_descriptor_t sd, int new_sd = SOCKET_UNDEFINED; CLEAR (*act); - socket_do_listen (sd, local, do_listen, true); + socket_do_listen (sd, local->ai_addr, do_listen, true); while (true) { @@ -880,18 +845,26 @@ socket_listen_accept (socket_descriptor_t sd, if (socket_defined (new_sd)) { - update_remote (remote_dynamic, &remote_verify, remote_changed, 0); - if (addr_defined (&remote_verify) - && !addr_match (&remote_verify, &act->dest)) - { - 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)"); - } + struct addrinfo* ai; + 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 - break; + { + if(ai) + freeaddrinfo(ai); + break; + } } openvpn_sleep (1); } @@ -907,17 +880,38 @@ socket_listen_accept (socket_descriptor_t sd, void socket_bind (socket_descriptor_t sd, - struct openvpn_sockaddr *local, + struct addrinfo *local, + int ai_family, const char *prefix) { struct gc_arena gc = gc_new (); - if (bind (sd, &local->addr.sa, af_addr_size(local->addr.sa.sa_family))) + /* 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? + */ + + ASSERT(local); + struct addrinfo* cur; + + /* 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 (bind (sd, cur->ai_addr, cur->ai_addrlen)) { const int errnum = openvpn_errno (); msg (M_FATAL, "%s: Socket bind failed on local address %s: %s", prefix, - print_sockaddr (local, &gc), + print_sockaddr_ex (local->ai_addr, ":", PS_SHOW_PORT, &gc), strerror_ts (errnum, &gc)); } gc_free (&gc); @@ -925,7 +919,7 @@ socket_bind (socket_descriptor_t sd, int openvpn_connect (socket_descriptor_t sd, - struct openvpn_sockaddr *remote, + const struct sockaddr *remote, int connect_timeout, volatile int *signal_received) { @@ -933,7 +927,7 @@ openvpn_connect (socket_descriptor_t sd, #ifdef CONNECT_NONBLOCK set_nonblock (sd); - status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family)); + status = connect (sd, remote, af_addr_size(remote->sa_family)); if (status) status = openvpn_errno (); if ( @@ -1005,85 +999,76 @@ openvpn_connect (socket_descriptor_t sd, 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); + + /* Copy addrinfo sock parameters for socket creating */ + actual->ai_family = ai->ai_family; + actual->ai_protocol = ai->ai_protocol; + actual->ai_socktype = ai->ai_socktype; +} + void socket_connect (socket_descriptor_t *sd, - struct openvpn_sockaddr *local, - bool bind_local, - struct openvpn_sockaddr *remote, - const bool connection_profiles_defined, - const char *remote_dynamic, - bool *remote_changed, - const int connect_retry_seconds, - const int connect_timeout, - const int connect_retry_max, - const unsigned int sockflags, - volatile int *signal_received) + struct link_socket_addr *lsa, + const int connect_timeout, + struct signal_info* sig_info) { struct gc_arena gc = gc_new (); - int retry = 0; - + const struct sockaddr *dest = &lsa->actual.dest.addr.sa; + + int status; + #ifdef CONNECT_NONBLOCK - msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", - print_sockaddr (remote, &gc)); + 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 (remote, &gc)); + msg (M_INFO, "Attempting to establish TCP connection with %s", + print_sockaddr (dest, &gc)); #endif - - while (true) - { - int status; - + #ifdef ENABLE_MANAGEMENT - if (management) + if (management) management_set_state (management, - OPENVPN_STATE_TCP_CONNECT, - NULL, - (in_addr_t)0, - (in_addr_t)0); + OPENVPN_STATE_TCP_CONNECT, + NULL, + (in_addr_t)0, + (in_addr_t)0); #endif - status = openvpn_connect (*sd, remote, connect_timeout, signal_received); + /* Set the actual address */ + status = openvpn_connect (*sd, dest, connect_timeout, &sig_info->signal_received); - get_signal (signal_received); - if (*signal_received) + get_signal (&sig_info->signal_received); + if (sig_info->signal_received) goto done; - if (!status) - break; - - msg (D_LINK_ERRORS, - "TCP: connect to %s failed, will try again in %d seconds: %s", - print_sockaddr (remote, &gc), - connect_retry_seconds, - strerror_ts (status, &gc)); - - gc_reset (&gc); - - openvpn_close_socket (*sd); - *sd = SOCKET_UNDEFINED; - - if ((connect_retry_max > 0 && ++retry >= connect_retry_max) || connection_profiles_defined) - { - *signal_received = SIGUSR1; - goto done; - } + if (status) { - openvpn_sleep (connect_retry_seconds); + msg (D_LINK_ERRORS, + "TCP: connect to %s failed: %s", + print_sockaddr (dest, &gc), + strerror_ts (status, &gc)); - get_signal (signal_received); - if (*signal_received) - goto done; - - *sd = create_socket_tcp (local->addr.sa.sa_family); - - if (bind_local) - socket_bind (*sd, local, "TCP Client"); - update_remote (remote_dynamic, remote, remote_changed, sockflags); - } - - msg (M_INFO, "TCP connection established with %s", - print_sockaddr (remote, &gc)); + 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); @@ -1134,72 +1119,47 @@ frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto) } static void -resolve_bind_local (struct link_socket *sock) +resolve_bind_local (struct link_socket *sock, const sa_family_t af) { struct gc_arena gc = gc_new (); /* resolve local address if undefined */ - if (!addr_defined (&sock->info.lsa->local)) + if (!sock->info.lsa->bind_local) { - /* may return AF_{INET|INET6} guessed from local_host */ - switch(addr_guess_family(sock->info.proto, sock->local_host)) - { - case AF_INET: - sock->info.lsa->local.addr.in4.sin_family = AF_INET; - sock->info.lsa->local.addr.in4.sin_addr.s_addr = - (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, - sock->local_host, - 0, - NULL, - NULL) - : htonl (INADDR_ANY)); - sock->info.lsa->local.addr.in4.sin_port = htons (sock->local_port); - break; - case AF_INET6: - { - int status; - int err; - CLEAR(sock->info.lsa->local.addr.in6); - if (sock->local_host) - { - struct addrinfo *ai; - - status = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, - sock->local_host, 0, NULL, AF_INET6, &ai); - if(status ==0) { - sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); - freeaddrinfo(ai); - } - } - else - { - sock->info.lsa->local.addr.in6.sin6_family = AF_INET6; - sock->info.lsa->local.addr.in6.sin6_addr = in6addr_any; - status = 0; - } - if (!status == 0) - { - msg (M_FATAL, "getaddr6() failed for local \"%s\": %s", - sock->local_host, - gai_strerror(err)); - } - sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port); - } - break; - } + 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 = 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)); + } } - - /* bind to local address/port */ - if (sock->bind_local) - { + + gc_free (&gc); +} + +static void bind_local (struct link_socket *sock) +{ + /* bind to local address/port */ + if (sock->bind_local) + { #ifdef ENABLE_SOCKS - if (sock->socks_proxy && sock->info.proto == PROTO_UDPv4) - socket_bind (sock->ctrl_sd, &sock->info.lsa->local, "SOCKS"); - else + 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"); + else #endif - socket_bind (sock->sd, &sock->info.lsa->local, "TCP/UDP"); - } - gc_free (&gc); + socket_bind (sock->sd, sock->info.lsa->bind_local, + sock->info.lsa->actual.ai_family, "TCP/UDP"); + } } static void @@ -1209,34 +1169,22 @@ resolve_remote (struct link_socket *sock, volatile int *signal_received) { struct gc_arena gc = gc_new (); - int af; if (!sock->did_resolve_remote) { /* resolve remote address if undefined */ - if (!addr_defined (&sock->info.lsa->remote)) + if (!sock->info.lsa->remote_list) { - af = addr_guess_family(sock->info.proto, sock->remote_host); - switch(af) - { - case AF_INET: - sock->info.lsa->remote.addr.in4.sin_family = AF_INET; - sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0; - break; - case AF_INET6: - CLEAR(sock->info.lsa->remote.addr.in6); - sock->info.lsa->remote.addr.in6.sin6_family = AF_INET6; - sock->info.lsa->remote.addr.in6.sin6_addr = in6addr_any; - break; - } - if (sock->remote_host) { unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); int retry = 0; int status = -1; + + if (proto_is_dgram(sock->info.proto)) + flags |= GETADDR_DATAGRAM; - if (sock->connection_profiles_defined && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) + if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) { if (phase == 2) flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); @@ -1272,12 +1220,11 @@ resolve_remote (struct link_socket *sock, } struct addrinfo* ai; - /* Temporary fix, this need to be changed for dual stack */ - status = openvpn_getaddrinfo(flags, sock->remote_host, retry, - signal_received, af, &ai); + status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port, + retry, signal_received, sock->info.af, &ai); if(status == 0) { - sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); - freeaddrinfo(ai); + 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, @@ -1298,15 +1245,6 @@ resolve_remote (struct link_socket *sock, goto done; } } - switch(af) - { - case AF_INET: - sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port); - break; - case AF_INET6: - sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port); - break; - } } /* should we re-use previous active remote address? */ @@ -1317,10 +1255,14 @@ resolve_remote (struct link_socket *sock, if (remote_dynamic) *remote_dynamic = NULL; } - else + /* else, quick hack to fix persistent-remote ....*/ { - CLEAR (sock->info.lsa->actual); - sock->info.lsa->actual.dest = sock->info.lsa->remote; + CLEAR (sock->info.lsa->actual); + if(sock->info.lsa->current_remote) + { + set_actual_address (&sock->info.lsa->actual, + sock->info.lsa->current_remote); + } } /* remember that we finished */ @@ -1331,6 +1273,8 @@ resolve_remote (struct link_socket *sock, gc_free (&gc); } + + struct link_socket * link_socket_new (void) { @@ -1344,15 +1288,47 @@ link_socket_new (void) return sock; } +void +create_new_socket (struct link_socket* sock) +{ + if (sock->bind_local) { + resolve_bind_local (sock, sock->info.af); + } + resolve_remote (sock, 1, NULL, NULL); + /* + * In P2P or server mode we must create the socket even when resolving + * the remote site fails/is not specified. */ + + if (sock->info.af && sock->info.lsa->actual.ai_family==0 && sock->bind_local) + { + /* Copy sock parameters from bind addr */ + set_actual_address (&sock->info.lsa->actual, sock->info.lsa->bind_local); + /* clear destination set by set_actual_address */ + CLEAR(sock->info.lsa->actual.dest); + } + + /* + * Create the socket early if socket should be bound + */ + if (sock->bind_local && sock->info.lsa->actual.ai_family) + { + create_socket (sock); + + if (sock->bind_local) + bind_local(sock); + } +} + + /* bind socket if necessary */ void link_socket_init_phase1 (struct link_socket *sock, - const bool connection_profiles_defined, const char *local_host, - int local_port, + const char *local_port, const char *remote_host, - int remote_port, + const char *remote_port, int proto, + sa_family_t af, int mode, const struct link_socket *accept_from, #ifdef ENABLE_HTTP_PROXY @@ -1371,9 +1347,7 @@ link_socket_init_phase1 (struct link_socket *sock, const char *ipchange_command, const struct plugin_list *plugins, int resolve_retry_seconds, - int connect_retry_seconds, int connect_timeout, - int connect_retry_max, int mtu_discover_type, int rcvbuf, int sndbuf, @@ -1382,8 +1356,6 @@ link_socket_init_phase1 (struct link_socket *sock, { ASSERT (sock); - sock->connection_profiles_defined = connection_profiles_defined; - sock->local_host = local_host; sock->local_port = local_port; sock->remote_host = remote_host; @@ -1400,9 +1372,7 @@ link_socket_init_phase1 (struct link_socket *sock, sock->bind_local = bind_local; sock->inetd = inetd; sock->resolve_retry_seconds = resolve_retry_seconds; - sock->connect_retry_seconds = connect_retry_seconds; sock->connect_timeout = connect_timeout; - sock->connect_retry_max = connect_retry_max; sock->mtu_discover_type = mtu_discover_type; #ifdef ENABLE_DEBUG @@ -1413,8 +1383,10 @@ link_socket_init_phase1 (struct link_socket *sock, 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.ipchange_command = ipchange_command; @@ -1424,20 +1396,18 @@ link_socket_init_phase1 (struct link_socket *sock, if (mode == LS_MODE_TCP_ACCEPT_FROM) { ASSERT (accept_from); - ASSERT (sock->info.proto == PROTO_TCPv4_SERVER - || sock->info.proto == PROTO_TCPv6_SERVER - ); + ASSERT (sock->info.proto == PROTO_TCP_SERVER); ASSERT (!sock->inetd); sock->sd = accept_from->sd; } - + if (false) ; #ifdef ENABLE_HTTP_PROXY /* are we running in HTTP proxy mode? */ else if (sock->http_proxy) { - ASSERT (sock->info.proto == PROTO_TCPv4_CLIENT); + ASSERT (sock->info.proto == PROTO_TCP_CLIENT); ASSERT (!sock->inetd); /* the proxy server */ @@ -1453,7 +1423,7 @@ link_socket_init_phase1 (struct link_socket *sock, /* or in Socks proxy mode? */ else if (sock->socks_proxy) { - ASSERT (sock->info.proto == PROTO_TCPv4_CLIENT || sock->info.proto == PROTO_UDPv4); + ASSERT (sock->info.af == AF_INET); ASSERT (!sock->inetd); /* the proxy server */ @@ -1472,7 +1442,7 @@ link_socket_init_phase1 (struct link_socket *sock, } /* bind behavior for TCP server vs. client */ - if (sock->info.proto == PROTO_TCPv4_SERVER) + if (sock->info.proto == PROTO_TCP_SERVER && sock->info.af==AF_INET) { if (sock->mode == LS_MODE_TCP_ACCEPT_FROM) sock->bind_local = false; @@ -1483,248 +1453,59 @@ link_socket_init_phase1 (struct link_socket *sock, /* were we started by inetd or xinetd? */ if (sock->inetd) { - ASSERT (sock->info.proto != PROTO_TCPv4_CLIENT - && sock->info.proto != PROTO_TCPv6_CLIENT); + ASSERT (sock->info.proto != PROTO_TCP_CLIENT); ASSERT (socket_defined (inetd_socket_descriptor)); sock->sd = inetd_socket_descriptor; } else if (mode != LS_MODE_TCP_ACCEPT_FROM) { - create_socket (sock); - - /* 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, mark); - - resolve_bind_local (sock); - resolve_remote (sock, 1, NULL, NULL); + create_new_socket (sock); } } -/* finalize socket initialization */ -void -link_socket_init_phase2 (struct link_socket *sock, - const struct frame *frame, - volatile int *signal_received) +static +void phase2_inetd (struct link_socket* sock, const struct frame *frame, + const char *remote_dynamic, volatile int *signal_received) { - struct gc_arena gc = gc_new (); - const char *remote_dynamic = NULL; bool remote_changed = false; - int sig_save = 0; - - ASSERT (sock); - - if (signal_received && *signal_received) - { - sig_save = *signal_received; - *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) - { - if (sock->info.proto == PROTO_TCPv4_SERVER - || sock->info.proto == PROTO_TCPv6_SERVER) { - /* AF_INET as default (and fallback) for inetd */ - sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET; + 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, (struct sockaddr *)&local_addr, &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, 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, 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)); -#endif - sock->sd = - socket_listen_accept (sock->sd, - &sock->info.lsa->actual, - remote_dynamic, - &remote_changed, - &sock->info.lsa->local, - false, - sock->inetd == INETD_NOWAIT, - signal_received); - } - ASSERT (!remote_changed); - if (*signal_received) - goto done; - } - else { - resolve_remote (sock, 2, &remote_dynamic, signal_received); - - if (*signal_received) - goto done; - - /* TCP client/server */ - if (sock->info.proto == PROTO_TCPv4_SERVER - ||sock->info.proto == PROTO_TCPv6_SERVER) - { - switch (sock->mode) - { - case LS_MODE_DEFAULT: - sock->sd = socket_listen_accept (sock->sd, - &sock->info.lsa->actual, - remote_dynamic, - &remote_changed, - &sock->info.lsa->local, - true, - false, - signal_received); - break; - case LS_MODE_TCP_LISTEN: - socket_do_listen (sock->sd, - &sock->info.lsa->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; - goto done; - } - tcp_connection_established (&sock->info.lsa->actual); - break; - default: - ASSERT (0); - } - } - else if (sock->info.proto == PROTO_TCPv4_CLIENT - ||sock->info.proto == PROTO_TCPv6_CLIENT) - { - -#ifdef GENERAL_PROXY_SUPPORT - bool proxy_retry = false; -#else - const bool proxy_retry = false; -#endif - do { - socket_connect (&sock->sd, - &sock->info.lsa->local, - sock->bind_local, - &sock->info.lsa->actual.dest, - sock->connection_profiles_defined, - remote_dynamic, - &remote_changed, - sock->connect_retry_seconds, - sock->connect_timeout, - sock->connect_retry_max, - sock->sockflags, - signal_received); - - if (*signal_received) - goto done; - - 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, - 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, - signal_received); - } -#endif - if (proxy_retry) - { - openvpn_close_socket (sock->sd); - sock->sd = create_socket_tcp (AF_INET); - } - } while (proxy_retry); - } -#ifdef ENABLE_SOCKS - else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy) - { - socket_connect (&sock->ctrl_sd, - &sock->info.lsa->local, - sock->bind_local, - &sock->info.lsa->actual.dest, - sock->connection_profiles_defined, - remote_dynamic, - &remote_changed, - sock->connect_retry_seconds, - sock->connect_timeout, - sock->connect_retry_max, - sock->sockflags, - signal_received); - - if (*signal_received) - goto done; - - establish_socks_proxy_udpassoc (sock->socks_proxy, - sock->ctrl_sd, - sock->sd, - &sock->socks_relay.dest, - signal_received); - - if (*signal_received) - goto done; - - 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); - addr_zero_host(&sock->info.lsa->remote); - - resolve_remote (sock, 1, NULL, signal_received); - - if (*signal_received) - goto done; - } -#endif - - if (*signal_received) - goto done; - - if (remote_changed) - { - msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment"); - addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest); - } + /* 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, + sock->sd); + } else + 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)); +#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); + } + ASSERT (!remote_changed); +} +static void +phase2_set_socket_flags (struct link_socket* sock) +{ /* set misc socket parameters */ socket_set_flags (sock->sd, sock->sockflags); @@ -1747,35 +1528,265 @@ link_socket_init_phase2 (struct link_socket *sock, /* 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 (); /* 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, true)); + 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)); + } else - msg (msglevel, "%s link local%s: %s", - proto2ascii (sock->info.proto, true), - (sock->bind_local ? " (bound)" : ""), - print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc)); - + 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, 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) +{ + 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->ai_addr, + 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) +{ +#ifdef GENERAL_PROXY_SUPPORT + 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) + ; +#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); + } +#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); + } +#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); + +} + +#ifdef ENABLE_SOCKS +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); + + 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; + 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); + + 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 char *remote_dynamic = NULL; + int sig_save = 0; + + ASSERT (sock); + if (sig_info && 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 && sig_info->signal_received) + 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 (sig_info && 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); + + } +#ifdef ENABLE_SOCKS + else if (sock->info.proto == PROTO_UDP && sock->socks_proxy && sock->info.af == AF_INET) + { + phase2_socks_client (sock, sig_info); +#endif + } + if (sig_info && sig_info->signal_received) + goto done; + } + + phase2_set_socket_flags(sock); + linksock_print_addr(sock); + done: - if (sig_save && signal_received) + if (sig_save && sig_info) { - if (!*signal_received) - *signal_received = sig_save; + if (!sig_info->signal_received) + sig_info->signal_received = sig_save; } - gc_free (&gc); } void @@ -1843,17 +1854,14 @@ setenv_trusted (struct env_set *es, const struct link_socket_info *info) static void ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc) { - const char *ip = print_sockaddr_ex (&info->lsa->actual.dest, NULL, 0, gc); - const char *port = print_sockaddr_ex (&info->lsa->actual.dest, NULL, PS_DONT_SHOW_ADDR|PS_SHOW_PORT, gc); + const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc); if (include_cmd) - argv_printf (argv, "%sc %s %s", + argv_printf (argv, "%sc %s", info->ipchange_command, - ip, - port); + host); else - argv_printf (argv, "%s %s", - ip, - port); + argv_printf (argv, "%s", host); + } void @@ -1910,6 +1918,7 @@ link_socket_bad_incoming_addr (struct buffer *buf, const struct link_socket_actual *from_addr) { struct gc_arena gc = gc_new (); + struct addrinfo* ai; switch(from_addr->dest.addr.sa.sa_family) { @@ -1919,7 +1928,12 @@ link_socket_bad_incoming_addr (struct buffer *buf, "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 (&info->lsa->remote, &gc)); + 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; @@ -1944,14 +1958,17 @@ link_socket_current_remote (const struct link_socket_info *info) * 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 (addr_defined (&lsa->remote)) - return ntohl (lsa->remote.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; } @@ -2018,7 +2035,7 @@ stream_buf_init (struct stream_buf *sb, sb->residual = alloc_buf (sb->maxlen); sb->error = false; #if PORT_SHARE - sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCPv4_SERVER)) + sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER)) ? PS_ENABLED : PS_DISABLED; #endif @@ -2167,67 +2184,60 @@ socket_listen_event_handle (struct link_socket *s) */ const char * -print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc) -{ - return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc); -} - -const char * -print_sockaddr_ex (const struct openvpn_sockaddr *addr, - const char* separator, - const unsigned int flags, - struct gc_arena *gc) +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; - addr_is_defined = addr_defined (addr); - if (!addr_is_defined) { - return "[undef]"; - } - switch(addr->addr.sa.sa_family) + char hostaddr[NI_MAXHOST] = ""; + char servname[NI_MAXSERV] = ""; + int status; + + socklen_t salen; + switch(sa->sa_family) { case AF_INET: - { - const int port= ntohs (addr->addr.in4.sin_port); - buf_puts (&out, "[AF_INET]"); - - if (!(flags & PS_DONT_SHOW_ADDR)) - buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]")); - - if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED))) - && port) - { - if (separator) - buf_printf (&out, "%s", separator); - - buf_printf (&out, "%d", port); - } - } + 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: - { - const int port= ntohs (addr->addr.in6.sin6_port); - char buf[INET6_ADDRSTRLEN] = ""; - buf_puts (&out, "[AF_INET6]"); - if (addr_is_defined) - { - getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), - buf, sizeof (buf), NULL, 0, NI_NUMERICHOST); - buf_puts (&out, buf); - } - if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED))) - && port) - { - if (separator) - buf_puts (&out, separator); - - buf_printf (&out, "%d", port); - } - } + 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: + return "[AF_UNSPEC]"; 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); } @@ -2251,7 +2261,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, { char ifname[IF_NAMESIZE] = "[undef]"; struct buffer out = alloc_buf_gc (128, gc); - buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, 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)) { @@ -2272,7 +2282,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, #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, separator, 0, gc), + print_sockaddr_ex (&sa.addr.sa, separator, 0, gc), ifname); } break; @@ -2434,22 +2444,23 @@ setenv_link_socket_actual (struct env_set *es, struct proto_names { const char *short_form; const char *display_form; - bool is_dgram; - bool is_net; - unsigned short proto_af; + sa_family_t proto_af; + int proto; }; /* Indexed by PROTO_x */ -static const struct proto_names proto_names[PROTO_N] = { - {"proto-uninitialized", "proto-NONE",0,0, AF_UNSPEC}, - {"udp", "UDPv4",1,1, AF_INET}, - {"tcp-server", "TCPv4_SERVER",0,1, AF_INET}, - {"tcp-client", "TCPv4_CLIENT",0,1, AF_INET}, - {"tcp", "TCPv4",0,1, AF_INET}, - {"udp6" ,"UDPv6",1,1, AF_INET6}, - {"tcp6-server","TCPv6_SERVER",0,1, AF_INET6}, - {"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6}, - {"tcp6" ,"TCPv6",0,1, AF_INET6}, +static const struct proto_names proto_names[] = { + {"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE}, + {"udp", "UDP", AF_UNSPEC, PROTO_UDP}, + {"udp4", "UDPv4", AF_INET, PROTO_UDP}, + {"tcp-server", "TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER}, + {"tcp-client", "TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT}, + {"tcp", "TCP", AF_UNSPEC, PROTO_TCP}, + {"tcp4", "TCPv4", AF_INET, PROTO_TCP}, + {"udp6" ,"UDPv6", AF_INET6, PROTO_UDP}, + {"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER}, + {"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT}, + {"tcp6" ,"TCPv6", AF_INET6, PROTO_TCP}, }; bool @@ -2457,59 +2468,66 @@ proto_is_net(int proto) { if (proto < 0 || proto >= PROTO_N) ASSERT(0); - return proto_names[proto].is_net; + return proto != PROTO_NONE; } bool proto_is_dgram(int proto) { - if (proto < 0 || proto >= PROTO_N) - ASSERT(0); - return proto_names[proto].is_dgram; + return proto_is_udp(proto); } + bool proto_is_udp(int proto) { if (proto < 0 || proto >= PROTO_N) ASSERT(0); - return proto_names[proto].is_dgram&&proto_names[proto].is_net; + return proto == PROTO_UDP; } + bool proto_is_tcp(int proto) { if (proto < 0 || proto >= PROTO_N) ASSERT(0); - return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net; -} - -unsigned short -proto_sa_family(int proto) -{ - if (proto < 0 || proto >= PROTO_N) - ASSERT(0); - return proto_names[proto].proto_af; + return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER || proto == PROTO_TCP_CLIENT; } int ascii2proto (const char* proto_name) { int i; - ASSERT (PROTO_N == SIZE (proto_names)); - for (i = 0; i < PROTO_N; ++i) + for (i = 0; i < SIZE (proto_names); ++i) if (!strcmp (proto_name, proto_names[i].short_form)) - return i; + return proto_names[i].proto; return -1; } +sa_family_t +ascii2af (const char* proto_name) +{ + int i; + for (i = 0; i < SIZE (proto_names); ++i) + if (!strcmp (proto_name, proto_names[i].short_form)) + return proto_names[i].proto_af; + return 0; +} + const char * -proto2ascii (int proto, bool display_form) +proto2ascii (int proto, sa_family_t af, bool display_form) { - ASSERT (PROTO_N == SIZE (proto_names)); - if (proto < 0 || proto >= PROTO_N) - return "[unknown protocol]"; - else if (display_form) - return proto_names[proto].display_form; - else - return proto_names[proto].short_form; + unsigned int i; + for (i = 0; i < SIZE (proto_names); ++i) + { + if(proto_names[i].proto_af == af && proto_names[i].proto == proto) + { + if(display_form) + return proto_names[i].display_form; + else + return proto_names[i].short_form; + } + } + + return "[unknown protocol]"; } const char * @@ -2518,23 +2536,22 @@ proto2ascii_all (struct gc_arena *gc) struct buffer out = alloc_buf_gc (256, gc); int i; - ASSERT (PROTO_N == SIZE (proto_names)); - for (i = 0; i < PROTO_N; ++i) + for (i = 0; i < SIZE (proto_names); ++i) { if (i) buf_printf(&out, " "); - buf_printf(&out, "[%s]", proto2ascii(i, false)); + buf_printf(&out, "[%s]", proto_names[i].short_form); } return BSTR (&out); } int -addr_guess_family(int proto, const char *name) +addr_guess_family(sa_family_t af, const char *name) { unsigned short ret; - if (proto) + if (af) { - return proto_sa_family(proto); /* already stamped */ + return af; /* already stamped */ } else { @@ -2570,22 +2587,24 @@ addr_family_name (int af) * * This is used for options compatibility * checking. + * + * IPv6 and IPv4 protocols are comptabile but OpenVPN + * has always sent UDPv4, TCPv4 over the wire. Keep these + * strings for backward compatbility */ -int +const char* proto_remote (int proto, bool remote) { ASSERT (proto >= 0 && proto < PROTO_N); - if (remote) - { - switch (proto) - { - case PROTO_TCPv4_SERVER: return PROTO_TCPv4_CLIENT; - case PROTO_TCPv4_CLIENT: return PROTO_TCPv4_SERVER; - case PROTO_TCPv6_SERVER: return PROTO_TCPv6_CLIENT; - case PROTO_TCPv6_CLIENT: return PROTO_TCPv6_SERVER; - } - } - return proto; + if (proto == PROTO_UDP) + return "UDPv4"; + + if ( (remote && proto == PROTO_TCP_CLIENT) || proto == PROTO_TCP_SERVER) + return "TCPv4_SERVER"; + if ( (remote && proto == PROTO_TCP_SERVER) || proto == PROTO_TCP_CLIENT) + return "TCPv4_CLIENT"; + + ASSERT (0); } /* @@ -2733,7 +2752,7 @@ link_socket_read_udp_posix (struct link_socket *sock, struct link_socket_actual *from) { socklen_t fromlen = sizeof (from->dest.addr); - socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto)); + socklen_t expectedlen = af_addr_size(sock->info.af); addr_zero_host(&from->dest); ASSERT (buf_safe (buf, maxsize)); #if ENABLE_IP_PKTINFO @@ -2774,7 +2793,7 @@ link_socket_write_tcp (struct link_socket *sock, #if ENABLE_IP_PKTINFO -int +size_t link_socket_write_udp_posix_sendmsg (struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to) @@ -2787,7 +2806,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, iov.iov_len = BLEN (buf); mesg.msg_iov = &iov; mesg.msg_iovlen = 1; - switch (sock->info.lsa->remote.addr.sa.sa_family) + switch (to->ai_family) { case AF_INET: { diff --git a/openvpn/src/openvpn/socket.h b/openvpn/src/openvpn/socket.h index 44f1098b..b30a1bc7 100644 --- a/openvpn/src/openvpn/socket.h +++ b/openvpn/src/openvpn/socket.h @@ -39,7 +39,7 @@ /* * OpenVPN's default port number as assigned by IANA. */ -#define OPENVPN_PORT 1194 +#define OPENVPN_PORT "1194" /* * Maximum size passed passed to setsockopt SNDBUF/RCVBUF @@ -81,6 +81,11 @@ struct openvpn_sockaddr struct link_socket_actual { /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + + struct openvpn_sockaddr dest; #if ENABLE_IP_PKTINFO union { @@ -97,8 +102,10 @@ struct link_socket_actual /* IP addresses which are persistant across SIGUSR1s */ struct link_socket_addr { - struct openvpn_sockaddr local; - struct openvpn_sockaddr remote; /* initial remote */ + struct addrinfo* bind_local; + struct addrinfo* remote_list; /* complete remote list */ + struct addrinfo* current_remote; /* remote used in the + current connection attempt */ struct link_socket_actual actual; /* reply to this address */ }; @@ -110,6 +117,7 @@ struct link_socket_info const struct plugin_list *plugins; bool remote_float; int proto; /* Protocol (PROTO_x defined below) */ + sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/ int mtu_changed; /* Set to true when mtu value is changed */ }; @@ -175,13 +183,10 @@ struct link_socket /* used for long-term queueing of pre-accepted socket listen */ bool listen_persistent_queued; - /* Does config file contain any <connection> ... </connection> blocks? */ - bool connection_profiles_defined; - const char *remote_host; - int remote_port; + const char *remote_port; const char *local_host; - int local_port; + const char *local_port; bool bind_local; # define INETD_NONE 0 @@ -195,9 +200,7 @@ struct link_socket int mode; int resolve_retry_seconds; - int connect_retry_seconds; int connect_timeout; - int connect_retry_max; int mtu_discover_type; struct socket_buffer_size socket_buffer_sizes; @@ -212,6 +215,7 @@ struct link_socket # define SF_HOST_RANDOMIZE (1<<3) # define SF_GETADDRINFO_DGRAM (1<<4) unsigned int sockflags; + int mark; /* for stream sockets */ struct stream_buf stream_buf; @@ -232,7 +236,7 @@ struct link_socket #if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS) /* The OpenVPN server we will use the proxy to connect to */ const char *proxy_dest_host; - int proxy_dest_port; + const char *proxy_dest_port; #endif #if PASSTOS_CAPABILITY @@ -279,11 +283,12 @@ int socket_finalize ( struct link_socket *link_socket_new (void); void socket_bind (socket_descriptor_t sd, - struct openvpn_sockaddr *local, + struct addrinfo *local, + int af_family, const char *prefix); int openvpn_connect (socket_descriptor_t sd, - struct openvpn_sockaddr *remote, + const struct sockaddr *remote, int connect_timeout, volatile int *signal_received); @@ -293,12 +298,12 @@ int openvpn_connect (socket_descriptor_t sd, void link_socket_init_phase1 (struct link_socket *sock, - const bool connection_profiles_defined, const char *local_host, - int local_port, + const char *local_port, const char *remote_host, - int remote_port, + const char *remote_port, int proto, + sa_family_t af, int mode, const struct link_socket *accept_from, #ifdef ENABLE_HTTP_PROXY @@ -317,9 +322,7 @@ link_socket_init_phase1 (struct link_socket *sock, const char *ipchange_command, const struct plugin_list *plugins, int resolve_retry_seconds, - int connect_retry_seconds, int connect_timeout, - int connect_retry_max, int mtu_discover_type, int rcvbuf, int sndbuf, @@ -328,7 +331,7 @@ link_socket_init_phase1 (struct link_socket *sock, void link_socket_init_phase2 (struct link_socket *sock, const struct frame *frame, - volatile int *signal_received); + struct signal_info *sig_info); void socket_adjust_frame_parameters (struct frame *frame, int proto); @@ -343,14 +346,35 @@ void sd_close (socket_descriptor_t *sd); #define PS_SHOW_PKTINFO (1<<2) #define PS_DONT_SHOW_ADDR (1<<3) -const char *print_sockaddr_ex (const struct openvpn_sockaddr *addr, +const char *print_sockaddr_ex (const struct sockaddr *addr, const char* separator, const unsigned int flags, struct gc_arena *gc); +static inline +const char *print_openvpn_sockaddr_ex (const struct openvpn_sockaddr *addr, + const char* separator, + const unsigned int flags, + struct gc_arena *gc) +{ + return print_sockaddr_ex(&addr->addr.sa, separator, flags, gc); +} + +static inline +const char *print_openvpn_sockaddr (const struct openvpn_sockaddr *addr, + struct gc_arena *gc) +{ + return print_sockaddr_ex (&addr->addr.sa, ":", PS_SHOW_PORT, gc); +} + +static inline +const char *print_sockaddr (const struct sockaddr *addr, + struct gc_arena *gc) +{ + return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc); +} + -const char *print_sockaddr (const struct openvpn_sockaddr *addr, - struct gc_arena *gc); const char *print_link_socket_actual_ex (const struct link_socket_actual *act, const char* separator, @@ -402,6 +426,9 @@ void link_socket_bad_incoming_addr (struct buffer *buf, const struct link_socket_info *info, const struct link_socket_actual *from_addr); +void set_actual_address (struct link_socket_actual* actual, + struct addrinfo* ai); + void link_socket_bad_outgoing_addr (void); void setenv_trusted (struct env_set *es, const struct link_socket_info *info); @@ -477,11 +504,8 @@ bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int * #define GETADDR_TRY_ONCE (1<<7) #define GETADDR_UPDATE_MANAGEMENT_STATE (1<<8) #define GETADDR_RANDOMIZE (1<<9) - -/* [ab]use flags bits to get socktype info downstream */ -/* TODO(jjo): resolve tradeoff between hackiness|args-overhead */ -#define GETADDR_DGRAM (1<<10) -#define dnsflags_to_socktype(flags) ((flags & GETADDR_DGRAM) ? SOCK_DGRAM : SOCK_STREAM) +#define GETADDR_PASSIVE (1<<10) +#define GETADDR_DATAGRAM (1<<11) in_addr_t getaddr (unsigned int flags, const char *hostname, @@ -491,6 +515,7 @@ in_addr_t getaddr (unsigned int flags, int openvpn_getaddrinfo (unsigned int flags, const char *hostname, + const char *servname, int resolve_retry_seconds, volatile int *signal_received, int ai_family, @@ -506,21 +531,18 @@ int openvpn_getaddrinfo (unsigned int flags, */ enum proto_num { PROTO_NONE, /* catch for uninitialized */ - PROTO_UDPv4, - PROTO_TCPv4_SERVER, - PROTO_TCPv4_CLIENT, - PROTO_TCPv4, - PROTO_UDPv6, - PROTO_TCPv6_SERVER, - PROTO_TCPv6_CLIENT, - PROTO_TCPv6, + PROTO_UDP, + PROTO_TCP, + PROTO_TCP_SERVER, + PROTO_TCP_CLIENT, PROTO_N }; int ascii2proto (const char* proto_name); -const char *proto2ascii (int proto, bool display_form); +sa_family_t ascii2af (const char* proto_name); +const char *proto2ascii (int proto, sa_family_t af, bool display_form); const char *proto2ascii_all (struct gc_arena *gc); -int proto_remote (int proto, bool remote); +const char *proto_remote (int proto, bool remote); const char *addr_family_name(int af); /* @@ -545,12 +567,6 @@ datagram_overhead (int proto) */ static inline bool -legal_ipv4_port (int port) -{ - return port > 0 && port < 65536; -} - -static inline bool link_socket_proto_connection_oriented (int proto) { return !proto_is_dgram(proto); @@ -604,29 +620,65 @@ link_socket_actual_defined (const struct link_socket_actual *act) static inline bool addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) { - switch(a1->addr.sa.sa_family) { + switch(a1->addr.sa.sa_family) { + case AF_INET: + return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; + case AF_INET6: + return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); + } + ASSERT(0); + return false; +} + +static inline bool +addrlist_match (const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist) +{ + const struct addrinfo *curele; + for (curele = addrlist; curele; curele=curele->ai_next) { + + switch(a1->addr.sa.sa_family) { case AF_INET: - return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; + if (a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr) + return true; + break; case AF_INET6: - return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); + if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr)) + return true; + break; + default: + ASSERT(0); + } } - ASSERT(0); return false; } -static inline in_addr_t -addr_host (const struct openvpn_sockaddr *addr) +static inline bool +addrlist_port_match (const struct openvpn_sockaddr *a1, const struct addrinfo *a2) { - /* - * "public" addr returned is checked against ifconfig for - * possible clash: non sense for now given - * that we do ifconfig only IPv4 - */ - if(addr->addr.sa.sa_family != AF_INET) - return 0; - return ntohl (addr->addr.in4.sin_addr.s_addr); + const struct addrinfo *curele; + for(curele=a2;curele;curele = curele->ai_next) { + switch(a1->addr.sa.sa_family) { + case AF_INET: + if (curele->ai_family == AF_INET + && a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr + && a1->addr.in4.sin_port == ((struct sockaddr_in*)curele->ai_addr)->sin_port) + return true; + break; + case AF_INET6: + if (curele->ai_family == AF_INET6 + && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr) + && a1->addr.in6.sin6_port == ((struct sockaddr_in6*) curele->ai_addr)->sin6_port) + return true; + break; + default: + ASSERT(0); + } + } + return false; } + + static inline bool addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) { @@ -644,14 +696,25 @@ addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockadd static inline bool addr_match_proto (const struct openvpn_sockaddr *a1, - const struct openvpn_sockaddr *a2, - const int proto) + const struct openvpn_sockaddr *a2, + const int proto) { - return link_socket_proto_connection_oriented (proto) + return link_socket_proto_connection_oriented (proto) ? addr_match (a1, a2) : addr_port_match (a1, a2); } + +static inline bool +addrlist_match_proto (const struct openvpn_sockaddr *a1, + struct addrinfo *addr_list, + const int proto) +{ + return link_socket_proto_connection_oriented (proto) + ? addrlist_match (a1, addr_list) + : addrlist_port_match (a1, addr_list); +} + static inline void addr_zero_host(struct openvpn_sockaddr *addr) { @@ -671,28 +734,15 @@ addr_copy_sa(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src) dst->addr = src->addr; } -static inline void -addr_copy_host(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src) -{ - switch(src->addr.sa.sa_family) { - case AF_INET: - dst->addr.in4.sin_addr.s_addr = src->addr.in4.sin_addr.s_addr; - break; - case AF_INET6: - dst->addr.in6.sin6_addr = src->addr.in6.sin6_addr; - break; - } -} - static inline bool addr_inet4or6(struct sockaddr *addr) { return addr->sa_family == AF_INET || addr->sa_family == AF_INET6; } -int addr_guess_family(int proto, const char *name); +int addr_guess_family(sa_family_t af,const char *name); static inline int -af_addr_size(unsigned short af) +af_addr_size(sa_family_t af) { switch(af) { case AF_INET: return sizeof (struct sockaddr_in); @@ -768,9 +818,9 @@ link_socket_verify_incoming_addr (struct buffer *buf, case AF_INET: if (!link_socket_actual_defined (from_addr)) return false; - if (info->remote_float || !addr_defined (&info->lsa->remote)) + if (info->remote_float || !info->lsa->remote_list) return true; - if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto)) + if (addrlist_match_proto (&from_addr->dest, info->lsa->remote_list, info->proto)) return true; } } @@ -812,8 +862,8 @@ link_socket_set_outgoing_addr (const struct buffer *buf, || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto)) /* address undef or address == remote or --float */ && (info->remote_float - || !addr_defined (&lsa->remote) - || addr_match_proto (&act->dest, &lsa->remote, info->proto)) + || !lsa->remote_list) + || addrlist_match_proto (&act->dest, lsa->remote_list, info->proto) ) { link_socket_connection_initiated (buf, info, act, common_name, es); @@ -937,13 +987,13 @@ link_socket_write_win32 (struct link_socket *sock, #else -static inline int +static inline size_t link_socket_write_udp_posix (struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to) { #if ENABLE_IP_PKTINFO - int link_socket_write_udp_posix_sendmsg (struct link_socket *sock, + size_t link_socket_write_udp_posix_sendmsg (struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to); @@ -957,7 +1007,7 @@ link_socket_write_udp_posix (struct link_socket *sock, (socklen_t) af_addr_size(to->dest.addr.sa.sa_family)); } -static inline int +static inline size_t link_socket_write_tcp_posix (struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to) @@ -967,7 +1017,7 @@ link_socket_write_tcp_posix (struct link_socket *sock, #endif -static inline int +static inline size_t link_socket_write_udp (struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to) diff --git a/openvpn/src/openvpn/socks.c b/openvpn/src/openvpn/socks.c index 235982e4..804c9836 100644 --- a/openvpn/src/openvpn/socks.c +++ b/openvpn/src/openvpn/socks.c @@ -55,13 +55,13 @@ void socks_adjust_frame_parameters (struct frame *frame, int proto) { - if (proto == PROTO_UDPv4) + if (proto == PROTO_UDP) frame_add_to_extra_link (frame, 10); } struct socks_proxy_info * socks_proxy_new (const char *server, - int port, + const char *port, const char *authfile, bool retry) { @@ -70,7 +70,7 @@ socks_proxy_new (const char *server, ALLOC_OBJ_CLEAR (p, struct socks_proxy_info); ASSERT (server); - ASSERT (legal_ipv4_port (port)); + ASSERT (port); strncpynt (p->server, server, sizeof (p->server)); p->port = port; @@ -389,11 +389,27 @@ recv_socks_reply (socket_descriptor_t sd, return true; } +static int +port_from_servname(const char* servname) +{ + int port =0; + port = atoi(servname); + if(port >0 && port < 65536) + return port; + + struct servent* service; + service = getservbyname(servname, NULL); + if(service) + return service->s_port; + + return 0; +} + void establish_socks_proxy_passthru (struct socks_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ - const int port, /* openvpn server port */ + const char *servname, /* openvpn server port */ volatile int *signal_received) { char buf[128]; @@ -414,6 +430,13 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p, buf[4] = (char) len; memcpy(buf + 5, host, len); + int port = port_from_servname (servname); + if (port ==0) + { + msg (D_LINK_ERRORS, "establish_socks_proxy_passthrough: Cannot convert %s to port number", servname); + goto error; + } + buf[5 + len] = (char) (port >> 8); buf[5 + len + 1] = (char) (port & 0xff); @@ -425,6 +448,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p, goto error; } } + /* receive reply from Socks proxy and discard */ if (!recv_socks_reply (sd, NULL, signal_received)) diff --git a/openvpn/src/openvpn/socks.h b/openvpn/src/openvpn/socks.h index b55ff6fb..30b957d7 100644 --- a/openvpn/src/openvpn/socks.h +++ b/openvpn/src/openvpn/socks.h @@ -42,14 +42,14 @@ struct socks_proxy_info { bool retry; char server[128]; - int port; + const char *port; char authfile[256]; }; void socks_adjust_frame_parameters (struct frame *frame, int proto); struct socks_proxy_info *socks_proxy_new (const char *server, - int port, + const char *port, const char *authfile, bool retry); @@ -58,7 +58,7 @@ void socks_proxy_close (struct socks_proxy_info *sp); void establish_socks_proxy_passthru (struct socks_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ - const int port, /* openvpn server port */ + const char *servname, /* openvpn server port */ volatile int *signal_received); void establish_socks_proxy_udpassoc (struct socks_proxy_info *p, diff --git a/openvpn/src/openvpn/ssl_polarssl.c b/openvpn/src/openvpn/ssl_polarssl.c index 6995958b..12318b33 100644 --- a/openvpn/src/openvpn/ssl_polarssl.c +++ b/openvpn/src/openvpn/ssl_polarssl.c @@ -338,7 +338,7 @@ void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline) { - if (0 != x509parse_crt(ctx->ca_chain, ca_file_inline, strlen(ca_file_inline))); + if (0 != x509parse_crt(ctx->ca_chain, ca_file_inline, strlen(ca_file_inline))) msg (M_FATAL, "Cannot load inline CA certificates"); } else diff --git a/openvpn/src/openvpn/tun.c b/openvpn/src/openvpn/tun.c index 1b2e5822..a0754427 100644 --- a/openvpn/src/openvpn/tun.c +++ b/openvpn/src/openvpn/tun.c @@ -413,8 +413,8 @@ init_tun (const char *dev, /* --dev option */ const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 IPv6 */ int ifconfig_ipv6_netbits_parm, const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 IPv6 */ - in_addr_t local_public, - in_addr_t remote_public, + struct addrinfo *local_public, + struct addrinfo *remote_public, const bool strict_warn, struct env_set *es) { @@ -468,24 +468,31 @@ init_tun (const char *dev, /* --dev option */ */ if (strict_warn) { + struct addrinfo *curele; ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology); /* * If local_public or remote_public addresses are defined, * make sure they do not clash with our virtual subnet. */ - - check_addr_clash ("local", + + for(curele=remote_public;curele;curele=curele->ai_next) { + if(curele->ai_family == AF_INET) + check_addr_clash ("local", tt->type, - local_public, + ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr, tt->local, tt->remote_netmask); + } - check_addr_clash ("remote", - tt->type, - remote_public, - 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"); @@ -1405,7 +1412,7 @@ close_tun_generic (struct tuntap *tt) if (tt->fd >= 0) close (tt->fd); if (tt->actual_name) - free (tt->actual_name); + free (tt->actual_name); clear_tuntap (tt); } @@ -1439,8 +1446,8 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu msg (M_ERR, "ERROR: Cannot open TUN"); } /* Set the actual name to a dummy name to enable scripts */ - tt->actual_name = (char *) malloc(32); - strncpy(tt->actual_name, "vpnservice-tun",32); + tt->actual_name = (char *) malloc(32); + strncpy(tt->actual_name, "vpnservice-tun",32); gc_free (&gc); } diff --git a/openvpn/src/openvpn/tun.h b/openvpn/src/openvpn/tun.h index c31ac001..e7d941ab 100644 --- a/openvpn/src/openvpn/tun.h +++ b/openvpn/src/openvpn/tun.h @@ -231,8 +231,8 @@ struct tuntap *init_tun (const char *dev, /* --dev option */ const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 / IPv6 */ int ifconfig_ipv6_netbits_parm, /* --ifconfig parm 1 / bits */ const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 / IPv6 */ - in_addr_t local_public, - in_addr_t remote_public, + struct addrinfo *local_public, + struct addrinfo *remote_public, const bool strict_warn, struct env_set *es); diff --git a/openvpn/src/openvpn/win32.c b/openvpn/src/openvpn/win32.c index d00088eb..2db96a8d 100644 --- a/openvpn/src/openvpn/win32.c +++ b/openvpn/src/openvpn/win32.c @@ -82,51 +82,6 @@ struct semaphore netcmd_semaphore; /* GLOBAL */ */ static char *win_sys_path = NULL; /* GLOBAL */ -/* - * Configure PATH. On Windows, sometimes PATH is not set correctly - * by default. - */ -static void -configure_win_path (void) -{ - static bool done = false; /* GLOBAL */ - if (!done) - { - FILE *fp; - fp = fopen ("c:\\windows\\system32\\route.exe", "rb"); - if (fp) - { - const int bufsiz = 4096; - struct gc_arena gc = gc_new (); - struct buffer oldpath = alloc_buf_gc (bufsiz, &gc); - struct buffer newpath = alloc_buf_gc (bufsiz, &gc); - const char* delim = ";"; - DWORD status; - fclose (fp); - status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath)); -#if 0 - status = 0; -#endif - if (!status) - { - *BPTR(&oldpath) = '\0'; - delim = ""; - } - buf_printf (&newpath, "C:\\WINDOWS\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem%s%s", - delim, - BSTR(&oldpath)); - SetEnvironmentVariable ("PATH", BSTR(&newpath)); -#if 0 - status = GetEnvironmentVariable ("PATH", BPTR(&oldpath), (DWORD)BCAP(&oldpath)); - if (status > 0) - printf ("PATH: %s\n", BSTR(&oldpath)); -#endif - gc_free (&gc); - done = true; - } - } -} - void init_win32 (void) { @@ -907,53 +862,41 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i { if (openvpn_execve_allowed (flags)) { - if (script_method == SM_EXECVE) - { - struct gc_arena gc = gc_new (); - STARTUPINFOW start_info; - PROCESS_INFORMATION proc_info; - - char *env = env_block (es); - WCHAR *cl = wide_cmd_line (a, &gc); - WCHAR *cmd = wide_string (a->argv[0], &gc); - - CLEAR (start_info); - CLEAR (proc_info); - - /* fill in STARTUPINFO struct */ - GetStartupInfoW(&start_info); - start_info.cb = sizeof(start_info); - start_info.dwFlags = STARTF_USESHOWWINDOW; - start_info.wShowWindow = SW_HIDE; - - if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) - { - DWORD exit_status = 0; - CloseHandle (proc_info.hThread); - WaitForSingleObject (proc_info.hProcess, INFINITE); - if (GetExitCodeProcess (proc_info.hProcess, &exit_status)) - ret = (int)exit_status; - else - msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %S failed", cmd); - CloseHandle (proc_info.hProcess); - } - else - { - msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %S failed", cmd); - } - free (env); - gc_free (&gc); - } - else if (script_method == SM_SYSTEM) - { - configure_win_path (); - ret = openvpn_system (argv_system_str (a), es, flags); - } - else - { - ASSERT (0); - } - } + struct gc_arena gc = gc_new (); + STARTUPINFOW start_info; + PROCESS_INFORMATION proc_info; + + char *env = env_block (es); + WCHAR *cl = wide_cmd_line (a, &gc); + WCHAR *cmd = wide_string (a->argv[0], &gc); + + CLEAR (start_info); + CLEAR (proc_info); + + /* fill in STARTUPINFO struct */ + GetStartupInfoW(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = STARTF_USESHOWWINDOW; + start_info.wShowWindow = SW_HIDE; + + if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info)) + { + DWORD exit_status = 0; + CloseHandle (proc_info.hThread); + WaitForSingleObject (proc_info.hProcess, INFINITE); + if (GetExitCodeProcess (proc_info.hProcess, &exit_status)) + ret = (int)exit_status; + else + msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %S failed", cmd); + CloseHandle (proc_info.hProcess); + } + else + { + msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %S failed", cmd); + } + free (env); + gc_free (&gc); + } else if (!exec_warn && (script_security < SSEC_SCRIPTS)) { msg (M_WARN, SCRIPT_SECURITY_WARNING); diff --git a/openvpn/version.m4 b/openvpn/version.m4 index 161462e5..1ea1c32f 100644 --- a/openvpn/version.m4 +++ b/openvpn/version.m4 @@ -1,7 +1,7 @@ dnl define the OpenVPN version define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) -define([PRODUCT_VERSION], [2.3_beta1]) +define([PRODUCT_VERSION], [2.3_master]) define([PRODUCT_BUGREPORT], [openvpn-users@lists.sourceforge.net]) define([PRODUCT_VERSION_RESOURCE], [2,3,0,0]) dnl define the TAP version |