diff options
Diffstat (limited to 'openvpn/src')
43 files changed, 1541 insertions, 1476 deletions
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); |