From 191b7ecd2b1f6012ee9cba9e619de4805e7a058b Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 10 Sep 2012 16:21:36 +0200 Subject: Update openvpn version. Matches github.com/schwabe/openvpn --- openvpn/doc/openvpn.8 | 49 ++- openvpn/include/openvpn-plugin.h | 61 +++- openvpn/src/openvpn/error.c | 11 +- openvpn/src/openvpn/error.h | 2 + openvpn/src/openvpn/init.c | 7 + openvpn/src/openvpn/manage.c | 4 +- openvpn/src/openvpn/options.c | 25 +- openvpn/src/openvpn/plugin.c | 62 +++- openvpn/src/openvpn/route.c | 45 ++- openvpn/src/openvpn/socket.c | 548 ++++++++----------------------- openvpn/src/openvpn/socket.h | 19 +- openvpn/src/openvpn/ssl_common.h | 1 - openvpn/src/openvpn/ssl_verify_openssl.h | 2 - openvpn/src/openvpn/tun.c | 22 +- openvpn/src/openvpn/tun.h | 4 +- openvpn/tests/t_client.sh.in | 3 +- 16 files changed, 396 insertions(+), 469 deletions(-) diff --git a/openvpn/doc/openvpn.8 b/openvpn/doc/openvpn.8 index 56be29ec..f586744e 100644 --- a/openvpn/doc/openvpn.8 +++ b/openvpn/doc/openvpn.8 @@ -2431,11 +2431,14 @@ be set to 127.0.0.1 server to local clients. .TP .B \-\-management-client -Management interface will connect as a TCP client to +Management interface will connect as a TCP/unix domain client to .B IP:port specified by .B \-\-management -rather than listen as a TCP server. +rather than listen as a TCP server or on a unix domain socket. + +If the client connection fails to connect or is disconnected, +a SIGTERM signal will be generated causing OpenVPN to quit. .\"********************************************************* .TP .B \-\-management-query-passwords @@ -2478,7 +2481,8 @@ command. .B \-\-management-signal Send SIGUSR1 signal to OpenVPN if management session disconnects. This is useful when you wish to disconnect an OpenVPN session on -user logoff. +user logoff. For --management-client this option is not needed since +a disconnect will always generate a SIGTERM. .\"********************************************************* .TP .B \-\-management-log-cache n @@ -3621,6 +3625,14 @@ would see nothing but random-looking data. .\"********************************************************* .TP +.B \-\-key-direction +Alternative way of specifying the optional direction parameter for the +.B \-\-tls-auth +and +.B \-\-secret +options. Useful when using inline files (See section on inline files). +.\"********************************************************* +.TP .B \-\-auth alg Authenticate packets with HMAC using message digest algorithm @@ -5901,6 +5913,37 @@ X509_1_C=KG .ft .fi .\"********************************************************* +.SH INLINE FILE SUPPORT +OpenVPN allows including files in the main configuration for the +.B \-\-ca, \-\-cert, \-\-dh, \-\-extra-certs, \-\-key, \-\-pkcs12, \-\-secret +and +.B \-\-tls-auth +options. + +Each inline file started by the line +.B + +Here is an example of an inline file usage + +.nf +.ft 3 +.in +4 + +-----BEGIN CERTIFICATE----- +[...] +-----END CERTIFICATE----- + +.in -4 +.ft +.fi + +When using the inline file feature with +.B \-\-pkcs12 +the inline file has to be base64 encoded. Encoding of a .p12 file into base64 can be done for example with OpenSSL by running +.B openssl base64 -in input.p12 + .SH SIGNALS .TP .B SIGHUP diff --git a/openvpn/include/openvpn-plugin.h b/openvpn/include/openvpn-plugin.h index 1c80eec3..0879f490 100644 --- a/openvpn/include/openvpn-plugin.h +++ b/openvpn/include/openvpn-plugin.h @@ -43,6 +43,8 @@ typedef X509 openvpn_x509_cert_t; #endif #endif +#include + #ifdef __cplusplus extern "C" { #endif @@ -145,7 +147,7 @@ typedef void *openvpn_plugin_handle_t; /* * For Windows (needs to be modified for MSVC) */ -#if defined(__MINGW32_VERSION) && !defined(OPENVPN_PLUGIN_H) +#if defined(WIN32) && !defined(OPENVPN_PLUGIN_H) # define OPENVPN_EXPORT __declspec(dllexport) #else # define OPENVPN_EXPORT @@ -204,6 +206,59 @@ struct openvpn_plugin_string_list */ #define OPENVPN_PLUGINv3_STRUCTVER 1 +/** + * Definitions needed for the plug-in callback functions. + */ +typedef enum +{ + PLOG_ERR = (1 << 0), /* Error condition message */ + PLOG_WARN = (1 << 1), /* General warning message */ + PLOG_NOTE = (1 << 2), /* Informational message */ + PLOG_DEBUG = (1 << 3), /* Debug message, displayed if verb >= 7 */ + + PLOG_ERRNO = (1 << 8), /* Add error description to message */ + PLOG_NOMUTE = (1 << 9), /* Mute setting does not apply for message */ + +} openvpn_plugin_log_flags_t; + + +#ifdef __GNUC__ +#if __USE_MINGW_ANSI_STDIO +# define _ovpn_chk_fmt(a, b) __attribute__ ((format(gnu_printf, (a), (b)))) +#else +# define _ovpn_chk_fmt(a, b) __attribute__ ((format(__printf__, (a), (b)))) +#endif +#else +# define _ovpn_chk_fmt(a, b) +#endif + +typedef void (*plugin_log_t) (openvpn_plugin_log_flags_t flags, + const char *plugin_name, + const char *format, ...) _ovpn_chk_fmt(3, 4); + +typedef void (*plugin_vlog_t) (openvpn_plugin_log_flags_t flags, + const char *plugin_name, + const char *format, + va_list arglist) _ovpn_chk_fmt(3, 0); + +#undef _ovpn_chk_fmt + +/** + * Used by the openvpn_plugin_open_v3() function to pass callback + * function pointers to the plug-in. + * + * plugin_log + * plugin_vlog : Use these functions to add information to the OpenVPN log file. + * Messages will only be displayed if the plugin_name parameter + * is set. PLOG_DEBUG messages will only be displayed with plug-in + * debug log verbosity (at the time of writing that's verb >= 7). + */ +struct openvpn_plugin_callbacks +{ + plugin_log_t plugin_log; + plugin_vlog_t plugin_vlog; +}; + /** * Arguments used to transport variables to the plug-in. * The struct openvpn_plugin_args_open_in is only used @@ -221,12 +276,16 @@ struct openvpn_plugin_string_list * variables in "name=value" format. Note that for security reasons, * these variables are not actually written to the "official" * environmental variable store of the process. + * + * callbacks : a pointer to the plug-in callback function struct. + * */ struct openvpn_plugin_args_open_in { const int type_mask; const char ** const argv; const char ** const envp; + struct openvpn_plugin_callbacks *callbacks; }; diff --git a/openvpn/src/openvpn/error.c b/openvpn/src/openvpn/error.c index 8396fe01..6848425e 100644 --- a/openvpn/src/openvpn/error.c +++ b/openvpn/src/openvpn/error.c @@ -201,8 +201,15 @@ int x_msg_line_num; /* GLOBAL */ void x_msg (const unsigned int flags, const char *format, ...) { - struct gc_arena gc; va_list arglist; + va_start (arglist, format); + x_msg_va (flags, format, arglist); + va_end (arglist); +} + +void x_msg_va (const unsigned int flags, const char *format, va_list arglist) +{ + struct gc_arena gc; #if SYSLOG_CAPABILITY int level; #endif @@ -237,9 +244,7 @@ void x_msg (const unsigned int flags, const char *format, ...) m1 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc); m2 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc); - va_start (arglist, format); vsnprintf (m1, ERR_BUF_SIZE, format, arglist); - va_end (arglist); m1[ERR_BUF_SIZE - 1] = 0; /* windows vsnprintf needs this */ if ((flags & M_ERRNO) && e) diff --git a/openvpn/src/openvpn/error.h b/openvpn/src/openvpn/error.h index aedb7c37..27c48b69 100644 --- a/openvpn/src/openvpn/error.h +++ b/openvpn/src/openvpn/error.h @@ -182,6 +182,8 @@ void x_msg (const unsigned int flags, const char *format, ...) #endif ; /* should be called via msg above */ +void x_msg_va (const unsigned int flags, const char *format, va_list arglist); + /* * Function prototypes */ diff --git a/openvpn/src/openvpn/init.c b/openvpn/src/openvpn/init.c index b2013923..cd5ebd3d 100644 --- a/openvpn/src/openvpn/init.c +++ b/openvpn/src/openvpn/init.c @@ -2488,6 +2488,13 @@ do_option_warnings (struct context *c) msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS"); #endif + if (script_security >= SSEC_SCRIPTS) + msg (M_WARN, "NOTE: the current --script-security setting may allow this configuration to call user-defined scripts"); + else if (script_security >= SSEC_PW_ENV) + msg (M_WARN, "WARNING: the current --script-security setting may allow passwords to be passed to scripts via environmental variables"); + else + msg (M_WARN, "NOTE: " PACKAGE_NAME " 2.1 requires '--script-security 2' or higher to call user-defined scripts or executables"); + 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"); } diff --git a/openvpn/src/openvpn/manage.c b/openvpn/src/openvpn/manage.c index 77d40833..45e0bd43 100644 --- a/openvpn/src/openvpn/manage.c +++ b/openvpn/src/openvpn/manage.c @@ -1567,7 +1567,7 @@ man_listen (struct management *man) else #endif { - man->connection.sd_top = create_socket_tcp (); + man->connection.sd_top = create_socket_tcp (AF_INET); socket_bind (man->connection.sd_top, &man->settings.local, "MANAGEMENT"); } @@ -1633,7 +1633,7 @@ man_connect (struct management *man) else #endif { - man->connection.sd_cli = create_socket_tcp (); + man->connection.sd_cli = create_socket_tcp (AF_INET); status = openvpn_connect (man->connection.sd_cli, &man->settings.local, 5, diff --git a/openvpn/src/openvpn/options.c b/openvpn/src/openvpn/options.c index a3029fc2..528583fe 100644 --- a/openvpn/src/openvpn/options.c +++ b/openvpn/src/openvpn/options.c @@ -62,6 +62,10 @@ #include "memdbg.h" +#ifdef MANAGMENT_EXTERNAL_KEY +#define EXTERNAL_KEY_STRING "EXTERNAL_PRIVATE_KEY" +#endif + const char title_string[] = PACKAGE_STRING " " TARGET_ALIAS @@ -106,8 +110,7 @@ const char title_string[] = #if ENABLE_IP_PKTINFO " [MH]" #endif - " [PF_INET6]" - " [IPv6 payload 20110522-1 (2.2.0)]" + " [IPv6]" " built on " __DATE__ ; @@ -2183,6 +2186,11 @@ 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) && !strcmp(options->priv_key_file,EXTERNAL_KEY_STRING)==0) + msg (M_USAGE, "--key and --management-external-key are mutually exclusive"); +#endif + if (options->cryptoapi_cert) { if ((!(options->ca_file)) && (!(options->ca_path))) @@ -2357,14 +2365,6 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce) #endif } -#ifdef MANAGMENT_EXTERNAL_KEY - if(o->management_flags & MF_EXTERNAL_KEY) { - if(o->priv_key_file) - msg (M_USAGE, "--key and --management-external-key are mutually exclusive"); - /* set a filename for nicer output in the logs */ - o->priv_key_file = "EXTERNAL_PRIVATE_KEY"; - } -#endif /* * Set MTU defaults */ @@ -2640,7 +2640,7 @@ options_postprocess_filechecks (struct options *options) #ifdef MANAGMENT_EXTERNAL_KEY if(!options->management_flags & MF_EXTERNAL_KEY) #endif - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->priv_key_file, R_OK, + errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->priv_key_file, R_OK, "--key"); errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->pkcs12_file, R_OK, "--pkcs12"); @@ -4154,6 +4154,9 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_EXTERNAL_KEY; + /* Set priv key file name only if not defined, so --key and this option can be checked later */ + if(!options->priv_key_file) + options->priv_key_file = EXTERNAL_KEY_STRING; } #endif #ifdef MANAGEMENT_DEF_AUTH diff --git a/openvpn/src/openvpn/plugin.c b/openvpn/src/openvpn/plugin.c index 7ce2f5e7..d785daec 100644 --- a/openvpn/src/openvpn/plugin.c +++ b/openvpn/src/openvpn/plugin.c @@ -286,6 +286,65 @@ plugin_init_item (struct plugin *p, const struct plugin_option *o) gc_free (&gc); } +static void +plugin_vlog (openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist) +{ + unsigned int msg_flags; + + if (!format) + return; + + if (!name || name[0] == '\0') + { + msg (D_PLUGIN_DEBUG, "PLUGIN: suppressed log message from plugin with unknown name"); + return; + } + + if (flags & PLOG_ERR) + msg_flags = M_INFO | M_NONFATAL; + else if (flags & PLOG_WARN) + msg_flags = M_INFO | M_WARN; + else if (flags & PLOG_NOTE) + msg_flags = M_INFO; + else if (flags & PLOG_DEBUG) + msg_flags = D_PLUGIN_DEBUG; + + if (flags & PLOG_ERRNO) + msg_flags |= M_ERRNO; + if (flags & PLOG_NOMUTE) + msg_flags |= M_NOMUTE; + + if (MSG_TEST (msg_flags)) + { + struct gc_arena gc; + char* msg_fmt; + + /* Never add instance prefix; not thread safe */ + msg_flags |= M_NOIPREFIX; + + gc_init (&gc); + msg_fmt = gc_malloc (ERR_BUF_SIZE, false, &gc); + openvpn_snprintf (msg_fmt, ERR_BUF_SIZE, "PLUGIN %s: %s", name, format); + x_msg_va (msg_flags, msg_fmt, arglist); + + gc_free (&gc); + } +} + +static void +plugin_log (openvpn_plugin_log_flags_t flags, const char *name, const char *format, ...) +{ + va_list arglist; + va_start (arglist, format); + plugin_vlog (flags, name, format, arglist); + va_end (arglist); +} + +static struct openvpn_plugin_callbacks callbacks = { + plugin_log, + plugin_vlog +}; + static void plugin_open_item (struct plugin *p, const struct plugin_option *o, @@ -312,7 +371,8 @@ plugin_open_item (struct plugin *p, if (p->open3) { struct openvpn_plugin_args_open_in args = { p->plugin_type_mask, (const char ** const) o->argv, - (const char ** const) envp }; + (const char ** const) envp, + &callbacks }; struct openvpn_plugin_args_open_return retargs; CLEAR(retargs); diff --git a/openvpn/src/openvpn/route.c b/openvpn/src/openvpn/route.c index e908be99..caa2459b 100644 --- a/openvpn/src/openvpn/route.c +++ b/openvpn/src/openvpn/route.c @@ -268,12 +268,14 @@ is_special_addr (const char *addr_str) static bool init_route (struct route *r, - struct resolve_list *network_list, + struct addrinfo **network_list, const struct route_option *ro, const struct route_list *rl) { const in_addr_t default_netmask = IPV4_NETMASK_HOST; bool status; + int ret; + struct in_addr special; CLEAR (*r); r->option = ro; @@ -284,19 +286,22 @@ init_route (struct route *r, { goto fail; } - - if (!get_special_addr (rl, ro->network, &r->network, &status)) + + + /* get_special_addr replaces specialaddr with a special ip addr + like gw. getaddrinfo is called to convert a a addrinfo struct */ + + if(get_special_addr (rl, ro->network, &special.s_addr, &status)) { - r->network = getaddr_multi ( - GETADDR_RESOLVE - | GETADDR_HOST_ORDER - | GETADDR_WARN_ON_SIGNAL, - ro->network, - 0, - &status, - NULL, - network_list); + special.s_addr = htonl(special.s_addr); + ret = openvpn_getaddrinfo(0, inet_ntoa(special), 0, NULL, + AF_INET, network_list); } + else + ret = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL, + ro->network, 0, NULL, AF_INET, network_list); + + status = (ret == 0); if (!status) goto fail; @@ -642,11 +647,8 @@ init_route_list (struct route_list *rl, bool warned = false; for (i = 0; i < opt->n; ++i) { - struct resolve_list netlist; + struct addrinfo* netlist; struct route r; - int k; - - CLEAR(netlist); /* init_route() will not always init this */ if (!init_route (&r, &netlist, @@ -655,16 +657,12 @@ init_route_list (struct route_list *rl, ret = false; else { - if (!netlist.len) - { - netlist.data[0] = r.network; - netlist.len = 1; - } - for (k = 0; k < netlist.len; ++k) + struct addrinfo* curele; + for (curele = netlist; curele; curele = curele->ai_next) { if (j < rl->capacity) { - r.network = netlist.data[k]; + r.network = ntohl(((struct sockaddr_in*)(curele)->ai_addr)->sin_addr.s_addr); rl->routes[j++] = r; } else @@ -676,6 +674,7 @@ init_route_list (struct route_list *rl, } } } + freeaddrinfo(netlist); } } rl->n = j; diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c index 339470b0..bb973bc9 100644 --- a/openvpn/src/openvpn/socket.c +++ b/openvpn/src/openvpn/socket.c @@ -94,220 +94,53 @@ h_errno_msg(int h_errno_err) */ in_addr_t getaddr (unsigned int flags, - const char *hostname, - int resolve_retry_seconds, - bool *succeeded, - volatile int *signal_received) + const char *hostname, + int resolve_retry_seconds, + bool *succeeded, + volatile int *signal_received) { - return getaddr_multi (flags, hostname, resolve_retry_seconds, succeeded, signal_received, NULL); -} - -in_addr_t -getaddr_multi (unsigned int flags, - const char *hostname, - int resolve_retry_seconds, - bool *succeeded, - volatile int *signal_received, - struct resolve_list *reslist) -{ - struct in_addr ia; + struct addrinfo *ai; int status; - int sigrec = 0; - int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS; - struct gc_arena gc = gc_new (); - - if (reslist) - reslist->len = 0; - - if (flags & GETADDR_RANDOMIZE) - hostname = hostname_randomize(hostname, &gc); - - if (flags & GETADDR_MSG_VIRT_OUT) - msglevel |= M_MSG_VIRT_OUT; - - CLEAR (ia); - if (succeeded) - *succeeded = false; - - if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL)) - && !signal_received) - signal_received = &sigrec; - - status = openvpn_inet_aton (hostname, &ia); /* parse ascii IP address */ - - if (status != OIA_IP) /* parse as IP address failed? */ - { - const int fail_wait_interval = 5; /* seconds */ - int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : (resolve_retry_seconds / fail_wait_interval); - struct hostent *h; - const char *fmt; - int level = 0; - - CLEAR (ia); - - fmt = "RESOLVE: Cannot resolve host address: %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.)"; - - if (!(flags & GETADDR_RESOLVE) || status == OIA_ERROR) - { - msg (msglevel, "RESOLVE: Cannot parse IP address: %s", hostname); - goto done; - } - -#ifdef ENABLE_MANAGEMENT - if (flags & GETADDR_UPDATE_MANAGEMENT_STATE) - { - if (management) - management_set_state (management, - OPENVPN_STATE_RESOLVE, - NULL, - (in_addr_t)0, - (in_addr_t)0); - } -#endif - - /* - * Resolve hostname - */ - while (true) - { - /* try hostname lookup */ -#if defined(HAVE_RES_INIT) - res_init (); -#endif - h = gethostbyname (hostname); - - if (signal_received) - { - get_signal (signal_received); - if (*signal_received) /* were we interrupted by a signal? */ - { - h = NULL; - if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ - { - msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); - *signal_received = 0; - } - else - goto done; - } - } - - /* success? */ - if (h) - break; - - /* resolve lookup failed, should we - continue or fail? */ - - level = msglevel; - if (resolve_retries > 0) - level = D_RESOLVE_ERRORS; - - msg (level, - fmt, - hostname, - h_errno_msg (h_errno)); - - if (--resolve_retries <= 0) - goto done; - - openvpn_sleep (fail_wait_interval); - } - - if (h->h_addrtype != AF_INET || h->h_length != 4) - { - msg (msglevel, "RESOLVE: Sorry, but we only accept IPv4 DNS names: %s", hostname); - goto done; - } - - ia.s_addr = *(in_addr_t *) (h->h_addr_list[0]); - - if (ia.s_addr) - { - if (h->h_addr_list[1]) /* more than one address returned */ - { - int n = 0; - - /* count address list */ - while (h->h_addr_list[n]) - ++n; - ASSERT (n >= 2); - - msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d addresses", - hostname, - n); - - /* choose address randomly, for basic load-balancing capability */ - /*ia.s_addr = *(in_addr_t *) (h->h_addr_list[get_random () % n]);*/ - - /* choose first address */ - ia.s_addr = *(in_addr_t *) (h->h_addr_list[0]); - - if (reslist) - { - int i; - for (i = 0; i < n && i < SIZE(reslist->data); ++i) - { - in_addr_t a = *(in_addr_t *) (h->h_addr_list[i]); - if (flags & GETADDR_HOST_ORDER) - a = ntohl(a); - reslist->data[i] = a; - } - reslist->len = i; - } - } - } - - /* hostname resolve succeeded */ - if (succeeded) - *succeeded = true; - } - else - { - /* IP address parse succeeded */ - if (succeeded) - *succeeded = true; - } - - done: - if (signal_received && *signal_received) - { - int level = 0; - if (flags & GETADDR_FATAL_ON_SIGNAL) - level = M_FATAL; - else if (flags & GETADDR_WARN_ON_SIGNAL) - level = M_WARN; - msg (level, "RESOLVE: signal received during DNS resolution attempt"); - } - - gc_free (&gc); - return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr; + status = openvpn_getaddrinfo(flags, hostname, resolve_retry_seconds, + signal_received, AF_INET, &ai); + if(status==0) { + struct in_addr ia; + if(succeeded) + *succeeded=true; + ia = ((struct sockaddr_in*)ai->ai_addr)->sin_addr; + freeaddrinfo(ai); + return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr; + } else { + if(succeeded) + *succeeded =false; + return 0; + } } + /* - * Translate IPv6 addr or hostname into struct addrinfo - * If resolve error, try again for - * resolve_retry_seconds seconds. + * Translate IPv4/IPv6 addr or hostname into struct addrinfo + * If resolve error, try again for resolve_retry_seconds seconds. */ -bool -getaddr6 (unsigned int flags, - const char *hostname, - int resolve_retry_seconds, - volatile int *signal_received, - int *gai_err, - struct sockaddr_in6 *in6) -{ - bool success; - struct addrinfo hints, *ai; +int +openvpn_getaddrinfo (unsigned int flags, + const char *hostname, + int resolve_retry_seconds, + volatile int *signal_received, + int ai_family, + struct addrinfo **res) +{ + struct addrinfo hints; int status; int sigrec = 0; int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS; struct gc_arena gc = gc_new (); - ASSERT(in6); + ASSERT(res); + +#if defined(HAVE_RES_INIT) + res_init (); +#endif if (!hostname) hostname = "::"; @@ -318,151 +151,111 @@ getaddr6 (unsigned int flags, if (flags & GETADDR_MSG_VIRT_OUT) msglevel |= M_MSG_VIRT_OUT; - CLEAR (ai); - success = false; - if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL)) && !signal_received) signal_received = &sigrec; /* try numeric ipv6 addr first */ CLEAR(hints); - hints.ai_family = AF_INET6; + hints.ai_family = ai_family; hints.ai_flags = AI_NUMERICHOST; - if ((status = getaddrinfo(hostname, NULL, &hints, &ai))==0) - { - *in6 = *((struct sockaddr_in6 *)(ai->ai_addr)); - freeaddrinfo(ai); - ai = NULL; - } - if (gai_err) - *gai_err = status; + hints.ai_socktype = dnsflags_to_socktype(flags); + status = getaddrinfo(hostname, NULL, &hints, res); - if (status != 0) /* parse as IPv6 address failed? */ + 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); const char *fmt; int level = 0; - int err; - - ai = NULL; fmt = "RESOLVE: Cannot resolve host address: %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.)"; + && !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.)"; if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL) - { - msg (msglevel, "RESOLVE: Cannot parse IPv6 address: %s", hostname); - goto done; - } + { + msg (msglevel, "RESOLVE: Cannot parse IP address: %s", hostname); + goto done; + } #ifdef ENABLE_MANAGEMENT if (flags & GETADDR_UPDATE_MANAGEMENT_STATE) - { - if (management) - management_set_state (management, - OPENVPN_STATE_RESOLVE, - NULL, - (in_addr_t)0, - (in_addr_t)0); - } + { + if (management) + management_set_state (management, + OPENVPN_STATE_RESOLVE, + NULL, + (in_addr_t)0, + (in_addr_t)0); + } #endif /* * Resolve hostname */ while (true) - { - /* try hostname lookup */ + { + /* try hostname lookup */ hints.ai_flags = 0; - hints.ai_socktype = dnsflags_to_socktype(flags); - dmsg (D_SOCKET_DEBUG, "GETADDR6 flags=0x%04x ai_family=%d ai_socktype=%d", - flags, hints.ai_family, hints.ai_socktype); - err = getaddrinfo(hostname, NULL, &hints, &ai); + 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); - if (gai_err) - *gai_err = err; - - if (signal_received) - { - get_signal (signal_received); - if (*signal_received) /* were we interrupted by a signal? */ - { - if (0 == err) { - ASSERT(ai); - freeaddrinfo(ai); - ai = NULL; + 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; - } - } - - /* success? */ - if (0 == err) - break; - - /* resolve lookup failed, should we - continue or fail? */ - - level = msglevel; - if (resolve_retries > 0) - level = D_RESOLVE_ERRORS; - - msg (level, - fmt, - hostname, - gai_strerror(err)); - - if (--resolve_retries <= 0) - goto done; - - openvpn_sleep (fail_wait_interval); - } + if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ + { + msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); + *signal_received = 0; + } + else + goto done; + } + } - ASSERT(ai); + /* success? */ + if (0 == status) + break; - if (!ai->ai_next) - *in6 = *((struct sockaddr_in6*)(ai->ai_addr)); - else - /* more than one address returned */ - { - struct addrinfo *ai_cursor; - int n = 0; - /* count address list */ - for (ai_cursor = ai; ai_cursor; ai_cursor = ai_cursor->ai_next) n++; - ASSERT (n >= 2); + /* resolve lookup failed, should we + continue or fail? */ + level = msglevel; + if (resolve_retries > 0) + level = D_RESOLVE_ERRORS; - msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d ipv6 addresses, choosing one by random", + msg (level, + fmt, hostname, - n); + gai_strerror(status)); + + if (--resolve_retries <= 0) + goto done; - /* choose address randomly, for basic load-balancing capability */ - n--; - n %= get_random(); - for (ai_cursor = ai; n; ai_cursor = ai_cursor->ai_next) n--; - *in6 = *((struct sockaddr_in6*)(ai_cursor->ai_addr)); + openvpn_sleep (fail_wait_interval); } - freeaddrinfo(ai); - ai = NULL; + ASSERT(res); /* hostname resolve succeeded */ - success = true; + + /* Do not chose an IP Addresse by random or change the order * + * of IP addresses, doing so will break RFC 3484 address selection * + */ } else { /* IP address parse succeeded */ - success = true; } done: @@ -470,14 +263,14 @@ getaddr6 (unsigned int flags, { int level = 0; if (flags & GETADDR_FATAL_ON_SIGNAL) - level = M_FATAL; + level = M_FATAL; else if (flags & GETADDR_WARN_ON_SIGNAL) - level = M_WARN; + level = M_WARN; msg (level, "RESOLVE: signal received during DNS resolution attempt"); } gc_free (&gc); - return success; + return status; } /* @@ -653,18 +446,16 @@ update_remote (const char* host, case AF_INET6: if (host && addr) { - struct sockaddr_in6 sin6; - int success; - CLEAR(sin6); - success = getaddr6 ( - sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sockflags), - host, - 1, - NULL, - NULL, - &sin6); - if ( success ) + 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; @@ -672,6 +463,7 @@ update_remote (const char* host, addr->addr.in6 = sin6; addr->addr.in6.sin6_port = port; } + freeaddrinfo(ai); } } break; @@ -830,11 +622,11 @@ link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf) */ socket_descriptor_t -create_socket_tcp (void) +create_socket_tcp (int af) { socket_descriptor_t sd; - if ((sd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + if ((sd = socket (af, SOCK_STREAM, IPPROTO_TCP)) < 0) msg (M_ERR, "Cannot create TCP socket"); #ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */ @@ -847,18 +639,6 @@ create_socket_tcp (void) } #endif -#if 0 - /* set socket linger options */ - { - struct linger linger; - linger.l_onoff = 1; - linger.l_linger = 2; - if (setsockopt (sd, SOL_SOCKET, SO_LINGER, - (void *) &linger, sizeof (linger)) < 0) - msg (M_ERR, "TCP: Cannot setsockopt SO_LINGER on TCP socket"); - } -#endif - return sd; } @@ -913,25 +693,6 @@ create_socket_udp6 (const unsigned int flags) return sd; } -static socket_descriptor_t -create_socket_tcp6 (void) -{ - socket_descriptor_t sd; - - if ((sd = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) - msg (M_ERR, "Cannot create TCP6 socket"); - - /* set SO_REUSEADDR on socket */ - { - int on = 1; - if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, - (void *) &on, sizeof (on)) < 0) - msg (M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP6 socket"); - } - - return sd; -} - static void create_socket (struct link_socket *sock) { @@ -943,18 +704,18 @@ create_socket (struct link_socket *sock) #ifdef ENABLE_SOCKS if (sock->socks_proxy) - sock->ctrl_sd = create_socket_tcp (); + sock->ctrl_sd = create_socket_tcp (AF_INET); #endif } else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT) { - sock->sd = create_socket_tcp (); + sock->sd = create_socket_tcp (AF_INET); } else if (sock->info.proto == PROTO_TCPv6_SERVER || sock->info.proto == PROTO_TCPv6_CLIENT) { - sock->sd = create_socket_tcp6 (); + sock->sd = create_socket_tcp (AF_INET6); } else if (sock->info.proto == PROTO_UDPv6) { @@ -1314,15 +1075,7 @@ socket_connect (socket_descriptor_t *sd, if (*signal_received) goto done; - switch(local->addr.sa.sa_family) - { - case PF_INET6: - *sd = create_socket_tcp6 (); - break; - case PF_INET: - *sd = create_socket_tcp (); - break; - } + *sd = create_socket_tcp (local->addr.sa.sa_family); if (bind_local) socket_bind (*sd, local, "TCP Client"); @@ -1404,25 +1157,27 @@ resolve_bind_local (struct link_socket *sock) break; case AF_INET6: { - int success; + int status; int err; CLEAR(sock->info.lsa->local.addr.in6); if (sock->local_host) { - success = getaddr6(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL, - sock->local_host, - 0, - NULL, - &err, - &sock->info.lsa->local.addr.in6); + 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; - success = true; + status = 0; } - if (!success) + if (!status == 0) { msg (M_FATAL, "getaddr6() failed for local \"%s\": %s", sock->local_host, @@ -1479,7 +1234,7 @@ resolve_remote (struct link_socket *sock, { unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); int retry = 0; - bool status = false; + int status = -1; if (sock->connection_profiles_defined && sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) { @@ -1516,40 +1271,27 @@ resolve_remote (struct link_socket *sock, ASSERT (0); } - switch(af) - { - case AF_INET: - sock->info.lsa->remote.addr.in4.sin_addr.s_addr = getaddr ( - flags, - sock->remote_host, - retry, - &status, - signal_received); - break; - case AF_INET6: - status = getaddr6 ( - flags, - sock->remote_host, - retry, - signal_received, - NULL, - &sock->info.lsa->remote.addr.in6); - break; - } - - dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", - flags, - phase, - retry, - signal_received ? *signal_received : -1, - status); - + 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); + if(status == 0) { + sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); + freeaddrinfo(ai); + + dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", + flags, + phase, + retry, + signal_received ? *signal_received : -1, + status); + } if (signal_received) { if (*signal_received) goto done; } - if (!status) + if (status!=0) { if (signal_received) *signal_received = SIGUSR1; @@ -1927,7 +1669,7 @@ link_socket_init_phase2 (struct link_socket *sock, if (proxy_retry) { openvpn_close_socket (sock->sd); - sock->sd = create_socket_tcp (); + sock->sd = create_socket_tcp (AF_INET); } } while (proxy_retry); } diff --git a/openvpn/src/openvpn/socket.h b/openvpn/src/openvpn/socket.h index 47c6e8eb..44f1098b 100644 --- a/openvpn/src/openvpn/socket.h +++ b/openvpn/src/openvpn/socket.h @@ -425,7 +425,7 @@ bool ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn); bool mac_addr_safe (const char *mac_addr); bool ipv6_addr_safe (const char *ipv6_text_addr); -socket_descriptor_t create_socket_tcp (void); +socket_descriptor_t create_socket_tcp (int af); socket_descriptor_t socket_do_accept (socket_descriptor_t sd, struct link_socket_actual *act, @@ -467,11 +467,6 @@ bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int * * DNS resolution */ -struct resolve_list { - int len; - in_addr_t data[16]; -}; - #define GETADDR_RESOLVE (1<<0) #define GETADDR_FATAL (1<<1) #define GETADDR_HOST_ORDER (1<<2) @@ -494,12 +489,12 @@ in_addr_t getaddr (unsigned int flags, bool *succeeded, volatile int *signal_received); -in_addr_t getaddr_multi (unsigned int flags, - const char *hostname, - int resolve_retry_seconds, - bool *succeeded, - volatile int *signal_received, - struct resolve_list *reslist); +int openvpn_getaddrinfo (unsigned int flags, + const char *hostname, + int resolve_retry_seconds, + volatile int *signal_received, + int ai_family, + struct addrinfo **res); /* * Transport protocol naming and other details. diff --git a/openvpn/src/openvpn/ssl_common.h b/openvpn/src/openvpn/ssl_common.h index f3f43be2..cb259a96 100644 --- a/openvpn/src/openvpn/ssl_common.h +++ b/openvpn/src/openvpn/ssl_common.h @@ -288,7 +288,6 @@ struct tls_options # define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0) # define SSLF_USERNAME_AS_COMMON_NAME (1<<1) # define SSLF_AUTH_USER_PASS_OPTIONAL (1<<2) -# define SSLF_NO_NAME_REMAPPING (1<<3) # define SSLF_OPT_VERIFY (1<<4) # define SSLF_CRL_VERIFY_DIR (1<<5) unsigned int ssl_flags; diff --git a/openvpn/src/openvpn/ssl_verify_openssl.h b/openvpn/src/openvpn/ssl_verify_openssl.h index afd6110b..5a7e0a19 100644 --- a/openvpn/src/openvpn/ssl_verify_openssl.h +++ b/openvpn/src/openvpn/ssl_verify_openssl.h @@ -73,6 +73,4 @@ int verify_callback (int preverify_ok, X509_STORE_CTX * ctx); /** @} name Function for authenticating a new connection from a remote OpenVPN peer */ -char *_openssl_get_subject (X509 *cert, char *buf, int size); - #endif /* SSL_VERIFY_OPENSSL_H_ */ diff --git a/openvpn/src/openvpn/tun.c b/openvpn/src/openvpn/tun.c index 81979476..cd61baf4 100644 --- a/openvpn/src/openvpn/tun.c +++ b/openvpn/src/openvpn/tun.c @@ -925,7 +925,7 @@ do_ifconfig (struct tuntap *tt, #elif defined(TARGET_OPENBSD) /* - * On OpenBSD, tun interfaces are persistant if created with + * On OpenBSD, tun interfaces are persistent if created with * "ifconfig tunX create", and auto-destroyed if created by * opening "/dev/tunX" (so we just use the /dev/tunX) */ @@ -1270,7 +1270,7 @@ do_ifconfig (struct tuntap *tt, gc_free (&gc); } -void +static void clear_tuntap (struct tuntap *tuntap) { CLEAR (*tuntap); @@ -1379,6 +1379,13 @@ open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, if (!dynamic_opened) { + /* has named device existed before? if so, don't destroy at end */ + if ( if_nametoindex( dev ) > 0 ) + { + msg (M_INFO, "TUN/TAP device %s exists previously, keep at program end", dev ); + tt->persistent_if = true; + } + if ((tt->fd = open (tunname, O_RDWR)) < 0) msg (M_ERR, "Cannot open TUN/TAP dev %s", tunname); } @@ -2116,7 +2123,7 @@ close_tun (struct tuntap* tt) { /* only *TAP* devices need destroying, tun devices auto-self-destruct */ - if (tt && tt->type == DEV_TYPE_TUN ) + if (tt && (tt->type == DEV_TYPE_TUN || tt->persistent_if ) ) { close_tun_generic (tt); free(tt); @@ -2251,7 +2258,7 @@ close_tun (struct tuntap *tt) { /* only tun devices need destroying, tap devices auto-self-destruct */ - if (tt && tt->type != DEV_TYPE_TUN ) + if (tt && ( tt->type != DEV_TYPE_TUN || tt->persistent_if ) ) { close_tun_generic (tt); free(tt); @@ -2389,7 +2396,12 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu void close_tun (struct tuntap *tt) { - if (tt) + if (tt && tt->persistent_if ) /* keep pre-existing if around */ + { + close_tun_generic (tt); + free (tt); + } + else if (tt) /* close and destroy */ { struct gc_arena gc = gc_new (); struct argv argv; diff --git a/openvpn/src/openvpn/tun.h b/openvpn/src/openvpn/tun.h index 0f4f0123..c31ac001 100644 --- a/openvpn/src/openvpn/tun.h +++ b/openvpn/src/openvpn/tun.h @@ -137,6 +137,8 @@ struct tuntap bool ipv6; + bool persistent_if; /* if existed before, keep on program end */ + struct tuntap_options options; /* options set on command line */ char *actual_name; /* actual name of TUN/TAP dev, usually including unit number */ @@ -201,7 +203,7 @@ tuntap_defined (const struct tuntap *tt) * Function prototypes */ -void clear_tuntap (struct tuntap *tuntap); +static void clear_tuntap (struct tuntap *tuntap); void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt); diff --git a/openvpn/tests/t_client.sh.in b/openvpn/tests/t_client.sh.in index 8c66033f..189eecce 100755 --- a/openvpn/tests/t_client.sh.in +++ b/openvpn/tests/t_client.sh.in @@ -234,7 +234,8 @@ do fi echo " run openvpn $openvpn_conf" - $RUN_SUDO "${top_builddir}/src/openvpn/openvpn" $openvpn_conf >$LOGDIR/$SUF:openvpn.log & + echo "# src/openvpn/openvpn $openvpn_conf" >$LOGDIR/$SUF:openvpn.log + $RUN_SUDO "${top_builddir}/src/openvpn/openvpn" $openvpn_conf >>$LOGDIR/$SUF:openvpn.log & opid=$! # make sure openvpn client is terminated in case shell exits -- cgit v1.2.3