diff options
Diffstat (limited to 'openvpn/src')
| -rw-r--r-- | openvpn/src/openvpn/options.c | 36 | ||||
| -rw-r--r-- | openvpn/src/openvpn/plugin.c | 5 | ||||
| -rw-r--r-- | openvpn/src/openvpn/ssl.c | 26 | ||||
| -rw-r--r-- | openvpn/src/openvpn/ssl_backend.h | 30 | ||||
| -rw-r--r-- | openvpn/src/openvpn/ssl_common.h | 4 | ||||
| -rw-r--r-- | openvpn/src/openvpn/ssl_openssl.c | 39 | ||||
| -rw-r--r-- | openvpn/src/openvpn/ssl_polarssl.c | 40 | ||||
| -rw-r--r-- | openvpn/src/openvpn/ssl_verify.c | 2 | ||||
| -rw-r--r-- | openvpn/src/openvpn/tun.c | 338 | ||||
| -rw-r--r-- | openvpn/src/openvpn/tun.h | 3 | 
10 files changed, 437 insertions, 86 deletions
| diff --git a/openvpn/src/openvpn/options.c b/openvpn/src/openvpn/options.c index e31f918f..48065f99 100644 --- a/openvpn/src/openvpn/options.c +++ b/openvpn/src/openvpn/options.c @@ -6,9 +6,7 @@   *             packet compression.   *   *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> - * - *  Additions for eurephia plugin done by: - *         David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2009 + *  Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net>   *   *  This program is free software; you can redistribute it and/or modify   *  it under the terms of the GNU General Public License version 2 @@ -107,9 +105,6 @@ const char title_string[] =  #ifdef ENABLE_PKCS11    " [PKCS11]"  #endif -#ifdef ENABLE_EUREPHIA -  " [eurephia]" -#endif  #if ENABLE_IP_PKTINFO    " [MH]"  #endif @@ -582,6 +577,9 @@ static const char usage_message[] =    "                  by a Certificate Authority in --ca file.\n"    "--extra-certs file : one or more PEM certs that complete the cert chain.\n"    "--key file      : Local private key in .pem format.\n" +  "--tls-version-min <version> ['or-highest'] : sets the minimum TLS version we\n" +  "    will accept from the peer.  If version is unrecognized and 'or-highest'\n" +  "    is specified, require max TLS version supported by SSL implementation.\n"  #ifndef ENABLE_CRYPTO_POLARSSL    "--pkcs12 file   : PKCS#12 file containing local private key, local certificate\n"    "                  and optionally the root CA certificate.\n" @@ -4013,7 +4011,18 @@ add_option (struct options *options,    const bool pull_mode = BOOL_CAST (permission_mask & OPT_P_PULL_MODE);    int msglevel_fc = msglevel_forward_compatible (options, msglevel); -  ASSERT (MAX_PARMS >= 5); +  ASSERT (MAX_PARMS >= 7); + +  /* +   * If directive begins with "setenv opt" prefix, don't raise an error if +   * directive is unrecognized. +   */ +  if (streq (p[0], "setenv") && p[1] && streq (p[1], "opt") && !(permission_mask & OPT_P_PULL_MODE)) +    { +      p += 2; +      msglevel_fc = M_WARN; +    } +    if (!file)      {        file = "[CMD-LINE]"; @@ -6408,6 +6417,19 @@ add_option (struct options *options,  	  options->priv_key_file_inline = p[2];  	}      } +  else if (streq (p[0], "tls-version-min") && p[1]) +    { +      int ver; +      VERIFY_PERMISSION (OPT_P_GENERAL); +      ver = tls_version_min_parse(p[1], p[2]); +      if (ver == TLS_VER_BAD) +	{ +	  msg (msglevel, "unknown tls-version-min parameter: %s", p[1]); +          goto err; +	} +      options->ssl_flags &= ~(SSLF_TLS_VERSION_MASK << SSLF_TLS_VERSION_SHIFT); +      options->ssl_flags |= (ver << SSLF_TLS_VERSION_SHIFT); +    }  #ifndef ENABLE_CRYPTO_POLARSSL    else if (streq (p[0], "pkcs12") && p[1])      { diff --git a/openvpn/src/openvpn/plugin.c b/openvpn/src/openvpn/plugin.c index c96c121f..0948f238 100644 --- a/openvpn/src/openvpn/plugin.c +++ b/openvpn/src/openvpn/plugin.c @@ -40,8 +40,8 @@  #include "error.h"  #include "misc.h"  #include "plugin.h" +#include "ssl_backend.h"  #include "win32.h" -  #include "memdbg.h"  #define PLUGIN_SYMBOL_REQUIRED (1<<0) @@ -374,7 +374,8 @@ plugin_open_item (struct plugin *p,          struct openvpn_plugin_args_open_in args = { p->plugin_type_mask,                                                      (const char ** const) o->argv,                                                      (const char ** const) envp, -                                                    &callbacks }; +                                                    &callbacks, +                                                    SSLAPI };          struct openvpn_plugin_args_open_return retargs;          CLEAR(retargs); diff --git a/openvpn/src/openvpn/ssl.c b/openvpn/src/openvpn/ssl.c index 7cf3b2e4..f78cca88 100644 --- a/openvpn/src/openvpn/ssl.c +++ b/openvpn/src/openvpn/ssl.c @@ -7,10 +7,7 @@   *   *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>   *  Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> - * - *  Additions for eurephia plugin done by: - *         David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2008-2009 - * + *  Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net>   *   *  This program is free software; you can redistribute it and/or modify   *  it under the terms of the GNU General Public License version 2 @@ -448,6 +445,27 @@ ssl_put_auth_challenge (const char *cr_str)  #endif  /* + * Parse a TLS version string, returning a TLS_VER_x constant. + * If version string is not recognized and extra == "or-highest", + * return tls_version_max(). + */ +int +tls_version_min_parse(const char *vstr, const char *extra) +{ +  const int max_version = tls_version_max(); +  if (!strcmp(vstr, "1.0") && TLS_VER_1_0 <= max_version) +    return TLS_VER_1_0; +  else if (!strcmp(vstr, "1.1") && TLS_VER_1_1 <= max_version) +    return TLS_VER_1_1; +  else if (!strcmp(vstr, "1.2") && TLS_VER_1_2 <= max_version) +    return TLS_VER_1_2; +  else if (extra && !strcmp(extra, "or-highest")) +    return max_version; +  else +    return TLS_VER_BAD; +} + +/*   * Initialize SSL context.   * All files are in PEM format.   */ diff --git a/openvpn/src/openvpn/ssl_backend.h b/openvpn/src/openvpn/ssl_backend.h index 72235ae5..4d2958c7 100644 --- a/openvpn/src/openvpn/ssl_backend.h +++ b/openvpn/src/openvpn/ssl_backend.h @@ -36,10 +36,17 @@  #ifdef ENABLE_CRYPTO_OPENSSL  #include "ssl_openssl.h"  #include "ssl_verify_openssl.h" +#define SSLAPI SSLAPI_OPENSSL  #endif  #ifdef ENABLE_CRYPTO_POLARSSL  #include "ssl_polarssl.h"  #include "ssl_verify_polarssl.h" +#define SSLAPI SSLAPI_POLARSSL +#endif + +/* Ensure that SSLAPI got a sane value if SSL is disabled or unknown */ +#ifndef SSLAPI +#define SSLAPI SSLAPI_NONE  #endif  /** @@ -94,6 +101,29 @@ void tls_free_lib();  void tls_clear_error();  /** + * Parse a TLS version specifier + * + * @param vstr		The TLS version string + * @param extra	        An optional extra parameter, may be NULL + * + * @return 		One of the TLS_VER_x constants or TLS_VER_BAD + *                      if a parse error should be flagged. + */ +#define TLS_VER_BAD   -1 +#define TLS_VER_1_0    0 /* default */ +#define TLS_VER_1_1    1 +#define TLS_VER_1_2    2 +int tls_version_min_parse(const char *vstr, const char *extra); + +/** + * Return the maximum TLS version (as a TLS_VER_x constant) + * supported by current SSL implementation + * + * @return 		One of the TLS_VER_x constants (but not TLS_VER_BAD). + */ +int tls_version_max(void); + +/**   * Initialise a library-specific TLS context for a server.   *   * @param ctx		TLS context to initialise diff --git a/openvpn/src/openvpn/ssl_common.h b/openvpn/src/openvpn/ssl_common.h index 7e52f9a2..04ba7892 100644 --- a/openvpn/src/openvpn/ssl_common.h +++ b/openvpn/src/openvpn/ssl_common.h @@ -290,12 +290,14 @@ struct tls_options    struct compress_options comp_options;  #endif -  /* configuration file boolean options */ +  /* configuration file SSL-related boolean and low-permutation 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_OPT_VERIFY               (1<<4)  # define SSLF_CRL_VERIFY_DIR           (1<<5) +# define SSLF_TLS_VERSION_SHIFT        6 +# define SSLF_TLS_VERSION_MASK         0xF /* (uses bit positions 6 to 9) */    unsigned int ssl_flags;  #ifdef MANAGEMENT_DEF_AUTH diff --git a/openvpn/src/openvpn/ssl_openssl.c b/openvpn/src/openvpn/ssl_openssl.c index 5db717df..12c725d9 100644 --- a/openvpn/src/openvpn/ssl_openssl.c +++ b/openvpn/src/openvpn/ssl_openssl.c @@ -114,7 +114,7 @@ tls_ctx_server_new(struct tls_root_ctx *ctx)  {    ASSERT(NULL != ctx); -  ctx->ctx = SSL_CTX_new (TLSv1_server_method ()); +  ctx->ctx = SSL_CTX_new (SSLv23_server_method ());    if (ctx->ctx == NULL)      msg (M_SSLERR, "SSL_CTX_new TLSv1_server_method"); @@ -127,7 +127,7 @@ tls_ctx_client_new(struct tls_root_ctx *ctx)  {    ASSERT(NULL != ctx); -  ctx->ctx = SSL_CTX_new (TLSv1_client_method ()); +  ctx->ctx = SSL_CTX_new (SSLv23_client_method ());    if (ctx->ctx == NULL)      msg (M_SSLERR, "SSL_CTX_new TLSv1_client_method"); @@ -174,13 +174,46 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret)      }  } +/* + * Return maximum TLS version supported by local OpenSSL library. + * Assume that presence of SSL_OP_NO_TLSvX macro indicates that + * TLSvX is supported. + */ +int +tls_version_max(void) +{ +#if defined(SSL_OP_NO_TLSv1_2) +  return TLS_VER_1_2; +#elif defined(SSL_OP_NO_TLSv1_1) +  return TLS_VER_1_1; +#else +  return TLS_VER_1_0; +#endif +} +  void  tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)  {    ASSERT(NULL != ctx); +  /* process SSL options including minimum TLS version we will accept from peer */ +  { +    long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; +    const int tls_version_min = (ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK; +    if (tls_version_min > TLS_VER_1_0) +      sslopt |= SSL_OP_NO_TLSv1; +#ifdef SSL_OP_NO_TLSv1_1 +    if (tls_version_min > TLS_VER_1_1) +      sslopt |= SSL_OP_NO_TLSv1_1; +#endif +#ifdef SSL_OP_NO_TLSv1_2 +    if (tls_version_min > TLS_VER_1_2) +      sslopt |= SSL_OP_NO_TLSv1_2; +#endif +    SSL_CTX_set_options (ctx->ctx, sslopt); +  } +    SSL_CTX_set_session_cache_mode (ctx->ctx, SSL_SESS_CACHE_OFF); -  SSL_CTX_set_options (ctx->ctx, SSL_OP_SINGLE_DH_USE);    SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback);    /* Require peer certificate verification */ diff --git a/openvpn/src/openvpn/ssl_polarssl.c b/openvpn/src/openvpn/ssl_polarssl.c index 8a917b34..fb732254 100644 --- a/openvpn/src/openvpn/ssl_polarssl.c +++ b/openvpn/src/openvpn/ssl_polarssl.c @@ -501,6 +501,18 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx)      }  } +int +tls_version_max(void) +{ +#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3) +  return TLS_VER_1_2; +#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2) +  return TLS_VER_1_1; +#else +  return TLS_VER_1_0; +#endif +} +  void key_state_ssl_init(struct key_state_ssl *ks_ssl,      const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session)  { @@ -550,6 +562,34 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,        /* TODO: PolarSSL does not currently support sending the CA chain to the client */        ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL ); +      /* Initialize minimum TLS version */ +      { +	const int tls_version_min = (session->opt->ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK; +	int polar_major; +	int polar_minor; +	switch (tls_version_min) +	  { +	  case TLS_VER_1_0: +	  default: +	    polar_major = SSL_MAJOR_VERSION_3; +	    polar_minor = SSL_MINOR_VERSION_1; +	    break; +#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2) +	  case TLS_VER_1_1: +	    polar_major = SSL_MAJOR_VERSION_3; +	    polar_minor = SSL_MINOR_VERSION_2; +	    break; +#endif +#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3) +	  case TLS_VER_1_2: +	    polar_major = SSL_MAJOR_VERSION_3; +	    polar_minor = SSL_MINOR_VERSION_3; +	    break; +#endif +	  } +	ssl_set_min_version(ks_ssl->ctx, polar_major, polar_minor); +      } +        /* Initialise BIOs */        ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer);        ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer); diff --git a/openvpn/src/openvpn/ssl_verify.c b/openvpn/src/openvpn/ssl_verify.c index b1bbc96f..4dd3aa2d 100644 --- a/openvpn/src/openvpn/ssl_verify.c +++ b/openvpn/src/openvpn/ssl_verify.c @@ -425,7 +425,6 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert    setenv_str (es, envname, common_name);  #endif -#ifdef ENABLE_EUREPHIA    /* export X509 cert SHA1 fingerprint */    {      unsigned char *sha1_hash = x509_get_sha1_hash(peer_cert, &gc); @@ -434,7 +433,6 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert      setenv_str (es, envname, format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1,  					  ":", &gc));    } -#endif    /* export serial number as environmental variable */    serial = x509_get_serial(peer_cert, &gc); diff --git a/openvpn/src/openvpn/tun.c b/openvpn/src/openvpn/tun.c index 98cb16f3..bd62b392 100644 --- a/openvpn/src/openvpn/tun.c +++ b/openvpn/src/openvpn/tun.c @@ -74,6 +74,12 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co  #include <stropts.h>  #endif +#if defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H +#include <sys/kern_control.h> +#include <net/if_utun.h> +#include <sys/sys_domain.h> +#endif +  static void clear_tuntap (struct tuntap *tuntap);  bool @@ -1284,6 +1290,87 @@ open_null (struct tuntap *tt)    tt->actual_name = string_alloc ("null", NULL);  } + +#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H) + +/* + * OpenBSD and Mac OS X when using utun + * have a slightly incompatible TUN device from + * the rest of the world, in that it prepends a + * uint32 to the beginning of the IP header + * to designate the protocol (why not just + * look at the version field in the IP header to + * determine v4 or v6?). + * + * We strip off this field on reads and + * put it back on writes. + * + * I have not tested TAP devices on OpenBSD, + * but I have conditionalized the special + * TUN handling code described above to + * go away for TAP devices. + */ + +#include <netinet/ip.h> +#include <sys/uio.h> + +static inline int +header_modify_read_write_return (int len) +{ +    if (len > 0) +        return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; +    else +        return len; +} + +int +write_tun_header (struct tuntap* tt, uint8_t *buf, int len) +{ +    if (tt->type == DEV_TYPE_TUN) +      { +        u_int32_t type; +        struct iovec iv[2]; +        struct ip *iph; + +        iph = (struct ip *) buf; + +        if (tt->ipv6 && iph->ip_v == 6) +            type = htonl (AF_INET6); +        else +            type = htonl (AF_INET); + +        iv[0].iov_base = &type; +        iv[0].iov_len = sizeof (type); +        iv[1].iov_base = buf; +        iv[1].iov_len = len; + +        return header_modify_read_write_return (writev (tt->fd, iv, 2)); +      } +    else +        return write (tt->fd, buf, len); +} + +int +read_tun_header (struct tuntap* tt, uint8_t *buf, int len) +{ +    if (tt->type == DEV_TYPE_TUN) +      { +        u_int32_t type; +        struct iovec iv[2]; + +        iv[0].iov_base = &type; +        iv[0].iov_len = sizeof (type); +        iv[1].iov_base = buf; +        iv[1].iov_len = len; + +        return header_modify_read_write_return (readv (tt->fd, iv, 2)); +      } +    else +        return read (tt->fd, buf, len); +} +#endif + +  #ifndef WIN32  static void  open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, @@ -2062,23 +2149,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)  #elif defined(TARGET_OPENBSD) -/* - * OpenBSD has a slightly incompatible TUN device from - * the rest of the world, in that it prepends a - * uint32 to the beginning of the IP header - * to designate the protocol (why not just - * look at the version field in the IP header to - * determine v4 or v6?). - * - * We strip off this field on reads and - * put it back on writes. - * - * I have not tested TAP devices on OpenBSD, - * but I have conditionalized the special - * TUN handling code described above to - * go away for TAP devices. - */ -  void  open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)  { @@ -2145,59 +2215,16 @@ close_tun (struct tuntap* tt)      }  } -static inline int -openbsd_modify_read_write_return (int len) -{ - if (len > 0) -    return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; -  else -    return len; -} -  int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len)  { -  if (tt->type == DEV_TYPE_TUN) -    { -      u_int32_t type; -      struct iovec iv[2]; -      struct ip *iph; - -      iph = (struct ip *) buf; - -      if (tt->ipv6 && iph->ip_v == 6) -	type = htonl (AF_INET6); -      else  -	type = htonl (AF_INET); - -      iv[0].iov_base = &type; -      iv[0].iov_len = sizeof (type); -      iv[1].iov_base = buf; -      iv[1].iov_len = len; - -      return openbsd_modify_read_write_return (writev (tt->fd, iv, 2)); -    } -  else -    return write (tt->fd, buf, len); +  return write_tun_header (tt, buf, len);  }  int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun (struct tuntap *tt, uint8_t *buf, int len)  { -  if (tt->type == DEV_TYPE_TUN) -    { -      u_int32_t type; -      struct iovec iv[2]; - -      iv[0].iov_base = &type; -      iv[0].iov_len = sizeof (type); -      iv[1].iov_base = buf; -      iv[1].iov_len = len; - -      return openbsd_modify_read_write_return (readv (tt->fd, iv, 2)); -    } -  else -    return read (tt->fd, buf, len); +    return read_tun_header (tt, buf, len);  }  #elif defined(TARGET_NETBSD) @@ -2557,10 +2584,177 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)   * pointing to lo0.  Need to unconfigure...  (observed on 10.5)   */ +/* + * utun is the native Darwin tun driver present since at least 10.7 + * Thanks goes to Jonathan Levin for providing an example how to utun + * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c) + */ + +#ifdef HAVE_NET_IF_UTUN_H + +/* Helper functions that tries to open utun device +   return -2 on early initialization failures (utun not supported +   at all (old OS X) and -1 on initlization failure of utun +   device (utun works but utunX is already used */ +static +int utun_open_helper (struct ctl_info ctlInfo, int utunnum) +{ +  struct sockaddr_ctl sc; +  int fd; + +  fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + +  if (fd < 0) +    { +      msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)", +           strerror (errno)); +      return -2; +    } + +  if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) +    { +      close (fd); +      msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)", +           strerror (errno)); +      return -2; +    } + + +  sc.sc_id = ctlInfo.ctl_id; +  sc.sc_len = sizeof(sc); +  sc.sc_family = AF_SYSTEM; +  sc.ss_sysaddr = AF_SYS_CONTROL; + +  sc.sc_unit = utunnum+1; + + +  /* If the connect is successful, a utun%d device will be created, where "%d" +   * is (sc.sc_unit - 1) */ + +  if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0) +    { +      msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)", +           strerror (errno)); +      close(fd); +      return -1; +    } + +  set_nonblock (fd); +  set_cloexec (fd); /* don't pass fd to scripts */ + +  return fd; +} + +void +open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +{ +  struct ctl_info ctlInfo; +  int fd; +  char utunname[20]; +  int utunnum =-1; +  socklen_t utunname_len = sizeof(utunname); + +  /* dev_node is simply utun, do the normal dynamic utun +   * otherwise try to parse the utun number */ +  if (dev_node && !strcmp ("utun", dev_node)==0) +    { +      if (!sscanf (dev_node, "utun%d", &utunnum)==1) +        msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'" +             "to use a utun device number X", dev_node); +    } + + + +  CLEAR (ctlInfo); +  if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >= +      sizeof(ctlInfo.ctl_name)) +    { +      msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long"); +    } + +  /* try to open first available utun device if no specific utun is requested */ +  if (utunnum == -1) +    { +      for (utunnum=0; utunnum<255; utunnum++) +        { +          fd = utun_open_helper (ctlInfo, utunnum); +          /* Break if the fd is valid, +           * or if early initalization failed (-2) */ +          if (fd !=-1) +            break; +        } +    } +  else +    { +      fd = utun_open_helper (ctlInfo, utunnum); +    } + +  /* opening an utun device failed */ +  tt->fd = fd; + +  if (fd < 0) +      return; + +  /* Retrieve the assigned interface name. */ +  if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len)) +   msg (M_ERR | M_ERRNO, "Error retrieving utun interface name"); + +  tt->actual_name = string_alloc (utunname, NULL); + +  msg (M_INFO, "Opened utun device %s", utunname); +  tt->is_utun = true; +} + +#endif +  void  open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)  { -  open_tun_generic (dev, dev_type, dev_node, true, true, tt); +#ifdef HAVE_NET_IF_UTUN_H +  /* If dev_node does not start start with utun assume regular tun/tap */ +  if ((!dev_node && tt->type==DEV_TYPE_TUN) || +      (dev_node && !strncmp (dev_node, "utun", 4))) +    { + +      /* Check if user has specific dev_type tap and forced utun with +         dev-node utun */ +      if (tt->type!=DEV_TYPE_TUN) +        msg (M_FATAL, "Cannot use utun devices with --dev-type %s", +             dev_type_string (dev, dev_type)); + +      /* Try utun first and fall back to normal tun if utun fails +         and dev_node is not specified */ +      open_darwin_utun(dev, dev_type, dev_node, tt); + +      if (!tt->is_utun) +        { +          if (!dev_node) +            { +              /* No explicit utun and utun failed, try the generic way) */ +              msg (M_INFO, "Failed to open utun device. Falling back to /dev/tun device"); +              open_tun_generic (dev, dev_type, NULL, true, true, tt); +            } +          else +            { +              /* Specific utun device or generic utun request with no tun +                 fall back failed, consider this a fatal failure */ +              msg (M_FATAL, "Cannot open utun device"); +            } +        } +    } +  else +#endif +    { + +      /* Use plain dev-node tun to select /dev/tun style +       * Unset dev_node variable prior to passing to open_tun_generic to +       * let open_tun_generic pick the first available tun device */ + +      if (dev_node && strcmp (dev_node, "tun")==0) +        dev_node=NULL; + +      open_tun_generic (dev, dev_type, dev_node, true, true, tt); +    }  }  void @@ -2593,13 +2787,23 @@ close_tun (struct tuntap* tt)  int  write_tun (struct tuntap* tt, uint8_t *buf, int len)  { -  return write (tt->fd, buf, len); +#ifdef HAVE_NET_IF_UTUN_H +  if (tt->is_utun) +    return write_tun_header (tt, buf, len); +  else +#endif +    return write (tt->fd, buf, len);  }  int  read_tun (struct tuntap* tt, uint8_t *buf, int len)  { -  return read (tt->fd, buf, len); +#ifdef HAVE_NET_IF_UTUN_H +  if (tt->is_utun) +    return read_tun_header (tt, buf, len); +  else +#endif +    return read (tt->fd, buf, len);  }  #elif defined(WIN32) diff --git a/openvpn/src/openvpn/tun.h b/openvpn/src/openvpn/tun.h index 2bbb8133..631b53c6 100644 --- a/openvpn/src/openvpn/tun.h +++ b/openvpn/src/openvpn/tun.h @@ -181,6 +181,9 @@ struct tuntap    int ip_fd;  #endif +#ifdef HAVE_NET_IF_UTUN_H +  bool is_utun; +#endif    /* used for printing status info only */    unsigned int rwflags_debug; | 
