]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Introduce an option to resolve dns names in advance for --remote, --local and --http...
authorArne Schwabe <arne@rfc2549.org>
Sun, 23 Mar 2014 12:13:06 +0000 (13:13 +0100)
committerGert Doering <gert@greenie.muc.de>
Sun, 23 Mar 2014 18:51:52 +0000 (19:51 +0100)
Also introduce x_gc_addspeical function that allows to add objects with a
custom free function to the gc.

Some additional addrinfo cleanup

Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1395576786-17507-1-git-send-email-arne@rfc2549.org>
URL: http://article.gmane.org/gmane.network.openvpn.devel/8386

Signed-off-by: Gert Doering <gert@greenie.muc.de>
src/openvpn/buffer.c
src/openvpn/buffer.h
src/openvpn/init.c
src/openvpn/manage.c
src/openvpn/openvpn.h
src/openvpn/options.c
src/openvpn/options.h
src/openvpn/route.c
src/openvpn/socket.c
src/openvpn/socket.h

index fb3b52d1747fff1a485693d67524fcd5ebf055c4..36611415a95b2f9e9ccde07bfaf63ec38264efd4 100644 (file)
@@ -371,6 +371,44 @@ x_gc_free (struct gc_arena *a)
     }
 }
 
+/*
+ * Functions to handle special objects in gc_entries
+ */
+
+void
+x_gc_freespecial (struct gc_arena *a)
+{
+  struct gc_entry_special *e;
+  e = a->list_special;
+  a->list_special = NULL;
+
+  while (e != NULL)
+    {
+      struct gc_entry_special *next = e->next;
+      e->free_fnc (e->addr);
+      free(e);
+      e = next;
+    }
+}
+
+void gc_addspecial (void *addr, void (free_function)(void*), struct gc_arena *a)
+{
+  ASSERT(a);
+  struct gc_entry_special *e;
+#ifdef DMALLOC
+  e = (struct gc_entry_special *) openvpn_dmalloc (file, line, sizeof (struct gc_entry_special));
+#else
+  e = (struct gc_entry_special *) malloc (sizeof (struct gc_entry_special));
+#endif
+  check_malloc_return (e);
+  e->free_fnc = free_function;
+  e->addr = addr;
+
+  e->next = a->list_special;
+  a->list_special = e;
+}
+
+
 /*
  * Transfer src arena to dest, resetting src to an empty arena.
  */
index 93efb0962b3b99891f35a595f8de5d9459f4f160..19fa1fa253ee24c935863f3fd24586028d387e67 100644 (file)
@@ -91,6 +91,18 @@ struct gc_entry
                                  *   linked list. */
 };
 
+/**
+ * Gargabe collection entry for a specially allocated structure that needs
+ * a custom free function to be freed like struct addrinfo
+ *
+ */
+struct gc_entry_special
+{
+  struct gc_entry_special *next;
+  void (*free_fnc)(void*);
+  void *addr;
+};
+
 
 /**
  * Garbage collection arena used to keep track of dynamically allocated
@@ -106,6 +118,7 @@ struct gc_arena
 {
   struct gc_entry *list;        /**< First element of the linked list of
                                  *   \c gc_entry structures. */
+  struct gc_entry_special *list_special;
 };
 
 
@@ -163,6 +176,9 @@ struct buffer string_alloc_buf (const char *str, struct gc_arena *gc);
 
 #endif
 
+void gc_addspecial (void *addr, void (*free_function)(void*), struct gc_arena *a);
+
+
 #ifdef BUF_INIT_TRACKING
 #define buf_init(buf, offset) buf_init_debug (buf, offset, __FILE__, __LINE__)
 bool buf_init_debug (struct buffer *buf, int offset, const char *file, int line);
@@ -172,6 +188,11 @@ bool buf_init_debug (struct buffer *buf, int offset, const char *file, int line)
 
 
 /* inline functions */
+inline static void
+gc_freeaddrinfo_callback (void *addr)
+{
+  freeaddrinfo((struct addrinfo*) addr);
+}
 
 static inline bool
 buf_defined (const struct buffer *buf)
@@ -778,6 +799,7 @@ void character_class_debug (void);
 void gc_transfer (struct gc_arena *dest, struct gc_arena *src);
 
 void x_gc_free (struct gc_arena *a);
+void x_gc_freespecial (struct gc_arena *a);
 
 static inline bool
 gc_defined (struct gc_arena *a)
@@ -789,6 +811,7 @@ static inline void
 gc_init (struct gc_arena *a)
 {
   a->list = NULL;
+  a->list_special = NULL;
 }
 
 static inline void
@@ -801,7 +824,7 @@ static inline struct gc_arena
 gc_new (void)
 {
   struct gc_arena ret;
-  ret.list = NULL;
+  gc_init (&ret);
   return ret;
 }
 
@@ -810,6 +833,8 @@ gc_free (struct gc_arena *a)
 {
   if (a->list)
     x_gc_free (a);
+  if (a->list_special)
+    x_gc_freespecial(a);
 }
 
 static inline void
index 21e305274816d85f669e67617da294f401d31fbc..c2907cd3fe9eca4d8d307fb1f9f538cbb8e2a82c 100644 (file)
@@ -131,7 +131,8 @@ management_callback_proxy_cmd (void *arg, const char **p)
           msg (M_WARN, "HTTP proxy support is not available");
 #else
           struct http_proxy_options *ho;
-          if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_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;
             }
@@ -306,11 +307,10 @@ init_connection_list (struct context *c)
 /*
  * Clear the remote address list
  */
-static void clear_remote_addrlist (struct link_socket_addr *lsa)
+static void clear_remote_addrlist (struct link_socket_addr *lsa, bool free)
 {
-    if (lsa->remote_list) {
-        freeaddrinfo(lsa->remote_list);
-    }
+    if (lsa->remote_list && free)
+      freeaddrinfo(lsa->remote_list);
     lsa->remote_list = NULL;
     lsa->current_remote = NULL;
 }
@@ -348,9 +348,12 @@ next_connection_entry (struct context *c)
              * 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);
+             {
+               /* close_instance should have cleared the addrinfo objects */
+               ASSERT (c->c1.link_socket_addr.current_remote == NULL);
+               ASSERT (c->c1.link_socket_addr.remote_list == NULL);
+             }
             else
                 c->c1.link_socket_addr.current_remote =
                 c->c1.link_socket_addr.remote_list;
@@ -2688,6 +2691,7 @@ do_init_socket_1 (struct context *c, const int mode)
                           c->options.ce.local_port,
                           c->options.ce.remote,
                           c->options.ce.remote_port,
+                          c->c1.dns_cache,
                           c->options.ce.proto,
                           c->options.ce.af,
                           c->options.ce.bind_ipv6_only,
@@ -2908,7 +2912,7 @@ do_close_link_socket (struct context *c)
            || c->options.no_advance))
          )))
     {
-      clear_remote_addrlist(&c->c1.link_socket_addr);
+      clear_remote_addrlist(&c->c1.link_socket_addr, !c->options.resolve_in_advance);
     }
 
     /* Clear the remote actual address when persist_remote_ip is not in use */
@@ -2916,8 +2920,9 @@ do_close_link_socket (struct context *c)
       CLEAR (c->c1.link_socket_addr.actual);
 
   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);
+    if (c->c1.link_socket_addr.bind_local && !c->options.resolve_in_advance)
+       freeaddrinfo(c->c1.link_socket_addr.bind_local);
+
     c->c1.link_socket_addr.bind_local=NULL;
   }
 }
@@ -3359,6 +3364,13 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
        goto sig;
     }
 
+  if (c->options.resolve_in_advance)
+    {
+      do_preresolve (c);
+      if (IS_SIG (c))
+       goto sig;
+    }
+
   /* map in current connection entry */
   next_connection_entry (c);
 
index 8097905ce345c17a65424bc720d9718b4e4c9f7a..7215caf5871b0111eee6e8f6f01d47bb7c3ae1cc 100644 (file)
@@ -1568,9 +1568,9 @@ man_listen (struct management *man)
       else
 #endif
        {
-         man->connection.sd_top = create_socket_tcp (AF_INET);
+         man->connection.sd_top = create_socket_tcp (man->settings.local->ai_family);
          socket_bind (man->connection.sd_top, man->settings.local,
-                       AF_INET, "MANAGEMENT", true);
+                       man->settings.local->ai_family, "MANAGEMENT", false);
        }
 
       /*
@@ -2151,8 +2151,14 @@ man_settings_init (struct man_settings *ms,
            }
          else
            {
-              int status = openvpn_getaddrinfo(GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL,
-                                               addr, port, 0, NULL, AF_INET, &ms->local);
+             int status;
+             int resolve_flags = GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL;
+
+             if (! (flags & MF_CONNECT_AS_CLIENT))
+                 resolve_flags |= GETADDR_PASSIVE;
+
+              status = openvpn_getaddrinfo (resolve_flags, addr, port, 0,
+                                           NULL, AF_UNSPEC, &ms->local);
               ASSERT(status==0);
            }
        }
@@ -2179,6 +2185,8 @@ man_settings_init (struct man_settings *ms,
 static void
 man_settings_close (struct man_settings *ms)
 {
+  if (ms->local)
+    freeaddrinfo(ms->local);
   free (ms->write_peer_info_file);
   CLEAR (*ms);
 }
@@ -2616,7 +2624,7 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i
       int ret;
 
       ia.s_addr = htonl(tun_local_ip);
-      ret = openvpn_getaddrinfo(0, inet_ntoa(ia), NULL, 0, NULL,
+      ret = openvpn_getaddrinfo(GETADDR_PASSIVE, inet_ntoa(ia), NULL, 0, NULL,
                                 AF_INET, &man->settings.local);
       ASSERT (ret==0);
       man_connection_init (man);
index 606a4f595f29d8cf9a8fe8854b6ff30f31715f59..7ad6c55cf8ad583d0bdcbb4c3d3a39ded82f097a 100644 (file)
@@ -166,6 +166,9 @@ struct context_1
   /* tunnel session keys */
   struct key_schedule ks;
 
+  /* preresolved and cached host names */
+  struct cached_dns_entry *dns_cache;
+
   /* persist crypto sequence number to/from file */
   struct packet_id_persist pid_persist;
 
index e7259f7548e7c7707d6beaf1156b3be4f8741c16..cb2cf9524d61f5e3db3af27612487e08ad42ec08 100644 (file)
@@ -796,6 +796,7 @@ init_options (struct options *o, const bool init_gc)
   o->ce.mssfix = MSSFIX_DEFAULT;
   o->route_delay_window = 30;
   o->resolve_retry_seconds = RESOLV_RETRY_INFINITE;
+  o->resolve_in_advance = false;
   o->proto_force = -1;
 #ifdef ENABLE_OCC
   o->occ = true;
@@ -1369,6 +1370,7 @@ show_connection_entry (const struct connection_entry *o)
   SHOW_BOOL (remote_float);
   SHOW_BOOL (bind_defined);
   SHOW_BOOL (bind_local);
+  SHOW_BOOL (bind_ipv6_only);
   SHOW_INT (connect_retry_seconds);
   SHOW_INT (connect_timeout);
 
@@ -1494,6 +1496,7 @@ show_settings (const struct options *o)
 #endif
 
   SHOW_INT (resolve_retry_seconds);
+  SHOW_BOOL (resolve_in_advance);
 
   SHOW_STR (username);
   SHOW_STR (groupname);
@@ -4540,6 +4543,15 @@ add_option (struct options *options,
       else
        options->resolve_retry_seconds = positive_atoi (p[1]);
     }
+  else if (streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint"))
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->resolve_in_advance = true;
+      /* Note the ip-remote-hint and the argument p[1] are for
+        backward compatibility */
+      if (p[1])
+       options->ip_remote_hint=p[1];
+    }
   else if (streq (p[0], "connect-retry") && p[1])
     {
       VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
index 175918edbfa1b36066d4407ac0c9896132d3a21e..ec1d0911104862d3ac780455f077bc01e4e98d2f 100644 (file)
@@ -90,7 +90,7 @@ struct connection_entry
   sa_family_t af;
   const char* local_port;
   bool local_port_defined;
-  const charremote_port;
+  const char *remote_port;
   const char *local;
   const char *remote;
   bool remote_float;
@@ -278,6 +278,8 @@ struct options
 #endif
 
   int resolve_retry_seconds;    /* If hostname resolve fails, retry for n seconds */
+  bool resolve_in_advance;
+  const char *ip_remote_hint;
 
   struct tuntap_options tuntap_options;
 
index 392e2486881e5dc28d72d8f359b297ee27a1efa9..1dd14fb86d6a3743cb133da27c1023a639343879 100644 (file)
@@ -638,6 +638,7 @@ init_route_list (struct route_list *rl,
        else
          {
             struct addrinfo* curele;
+            gc_addspecial(netlist, &gc_freeaddrinfo_callback, &gc);
             for (curele        = netlist; curele; curele = curele->ai_next)
              {
                 struct route_ipv4 *new;
@@ -647,7 +648,6 @@ init_route_list (struct route_list *rl,
                 new->next = rl->routes;
                 rl->routes = new;
              }
-            freeaddrinfo(netlist);
          }
       }
   }
index 91c6af0c53105206e507a3f039de13cb91dfd802..0903afb4b83c67dae06c43abb41c9e7d23d42d49 100644 (file)
@@ -39,6 +39,7 @@
 #include "manage.h"
 #include "misc.h"
 #include "manage.h"
+#include "openvpn.h"
 
 #include "memdbg.h"
 
@@ -117,6 +118,178 @@ getaddr (unsigned int flags,
   }
 }
 
+static inline bool
+streqnull (const char* a, const char* b)
+{
+  if (a == NULL && b == NULL)
+    return true;
+  else if (a == NULL || b == NULL)
+    return false;
+  else
+    return streq (a, b);
+}
+
+/*
+  get_cached_dns_entry return 0 on success and -1
+  otherwise. (like getaddrinfo)
+ */
+static int
+get_cached_dns_entry (struct cached_dns_entry* dns_cache,
+                     const char* hostname,
+                     const char* servname,
+                     int ai_family,
+                     int resolve_flags,
+                     struct addrinfo **ai)
+{
+  struct cached_dns_entry *ph;
+  int flags;
+
+  /* Only use flags that are relevant for the structure */
+  flags = resolve_flags & GETADDR_CACHE_MASK;
+
+  for (ph = dns_cache; ph ; ph = ph->next)
+    {
+      if (streqnull (ph->hostname, hostname) &&
+         streqnull (ph->servname, servname) &&
+         ph->ai_family == ai_family &&
+         ph->flags == flags)
+       {
+         *ai = ph->ai;
+         return 0;
+       }
+    }
+  return -1;
+}
+
+
+static int
+do_preresolve_host (struct context *c,
+                   const char *hostname,
+                   const char *servname,
+                   const int af,
+                   const int flags)
+{
+  struct addrinfo *ai;
+  int status;
+
+  if (get_cached_dns_entry(c->c1.dns_cache,
+                          hostname,
+                          servname,
+                          af,
+                          flags,
+                          &ai) == 0 )
+    {
+      /* entry already cached, return success */
+      return 0;
+    }
+
+  status = openvpn_getaddrinfo (flags, hostname, servname,
+                               c->options.resolve_retry_seconds, NULL,
+                               af, &ai);
+  if (status == 0)
+    {
+      struct cached_dns_entry *ph;
+
+      ALLOC_OBJ_CLEAR_GC (ph, struct cached_dns_entry, &c->gc);
+      ph->ai = ai;
+      ph->hostname = hostname;
+      ph->servname = servname;
+      ph->flags = flags & GETADDR_CACHE_MASK;
+
+      if (!c->c1.dns_cache)
+       c->c1.dns_cache = ph;
+      else
+       {
+         struct cached_dns_entry *prev = c->c1.dns_cache;
+         while (prev->next)
+           prev = prev->next;
+         prev->next = ph;
+       }
+
+      gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc);
+
+    }
+  return status;
+}
+
+void
+do_preresolve (struct context *c)
+{
+  int i;
+  struct connection_list *l = c->options.connection_list;
+  const unsigned int preresolve_flags = GETADDR_RESOLVE|
+    GETADDR_UPDATE_MANAGEMENT_STATE|
+    GETADDR_MENTION_RESOLVE_RETRY|
+    GETADDR_FATAL;
+
+
+  for (i = 0; i < l->len; ++i)
+    {
+      int status;
+      const char *remote;
+      int flags = preresolve_flags;
+
+      struct connection_entry* ce = c->options.connection_list->array[i];
+
+      if (proto_is_dgram(ce->proto))
+         flags |= GETADDR_DATAGRAM;
+
+      if (c->options.sockflags & SF_HOST_RANDOMIZE)
+         flags |= GETADDR_RANDOMIZE;
+
+      if (c->options.ip_remote_hint)
+         remote = c->options.ip_remote_hint;
+      else
+         remote = ce->remote;
+
+      /* HTTP remote hostname does not need to be resolved */
+      if (! ce->http_proxy_options)
+       {
+         status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags);
+         if (status != 0)
+             goto err;
+       }
+
+      /* Preresolve proxy */
+      if (ce->http_proxy_options)
+       {
+         status = do_preresolve_host (c,
+                                      ce->http_proxy_options->server,
+                                      ce->http_proxy_options->port,
+                                      ce->af,
+                                      preresolve_flags);
+
+         if (status != 0)
+             goto err;
+       }
+
+      if (ce->socks_proxy_server)
+       {
+         status = do_preresolve_host (c,
+                                      ce->socks_proxy_server,
+                                      ce->socks_proxy_port,
+                                      ce->af,
+                                      flags);
+         if (status != 0)
+             goto err;
+       }
+
+      if (ce->bind_local)
+       {
+         flags |= GETADDR_PASSIVE;
+         flags &= ~GETADDR_RANDOMIZE;
+         status = do_preresolve_host (c, ce->local, ce->local_port, ce->af, flags);
+         if (status != 0)
+             goto err;
+
+       }
+
+    }
+    return;
+
+ err:
+  throw_signal_soft (SIGHUP, "Preresolving failed");
+}
 
 /*
  * Translate IPv4/IPv6 addr or hostname into struct addrinfo
@@ -1155,7 +1328,15 @@ resolve_bind_local (struct link_socket *sock, const sa_family_t af)
        flags |= GETADDR_DATAGRAM;
 
       /* will return AF_{INET|INET6}from local_host */
-      status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
+      status = get_cached_dns_entry (sock->dns_cache,
+                                    sock->local_host,
+                                    sock->local_port,
+                                    af,
+                                    flags,
+                                    &sock->info.lsa->bind_local);
+
+      if (status)
+       status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
                                   NULL, af, &sock->info.lsa->bind_local);
 
       if(status !=0) {
@@ -1193,103 +1374,104 @@ resolve_remote (struct link_socket *sock,
 {
   struct gc_arena gc = gc_new ();
 
-  if (!sock->did_resolve_remote)
+  /* resolve remote address if undefined */
+  if (!sock->info.lsa->remote_list)
     {
-      /* resolve remote address if undefined */
-      if (!sock->info.lsa->remote_list)
+      if (sock->remote_host)
        {
-         if (sock->remote_host)
+         unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
+         int retry = 0;
+         int status = -1;
+         struct addrinfo* ai;
+         if (proto_is_dgram(sock->info.proto))
+           flags |= GETADDR_DATAGRAM;
+
+         if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
+           {
+             if (phase == 2)
+               flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
+             retry = 0;
+           }
+         else if (phase == 1)
            {
-             unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
-             int retry = 0;
-             int status = -1;
-              struct addrinfo* ai;
-              if (proto_is_dgram(sock->info.proto))
-                  flags |= GETADDR_DATAGRAM;
-
-             if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
+             if (sock->resolve_retry_seconds)
                {
-                 if (phase == 2)
-                   flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
                  retry = 0;
                }
-             else if (phase == 1)
+             else
                {
-                 if (sock->resolve_retry_seconds)
-                   {
-                     retry = 0;
-                   }
-                 else
-                   {
-                     flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
-                     retry = 0;
-                   }
+                 flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
+                 retry = 0;
                }
-             else if (phase == 2)
+           }
+         else if (phase == 2)
+           {
+             if (sock->resolve_retry_seconds)
                {
-                 if (sock->resolve_retry_seconds)
-                   {
-                     flags |= GETADDR_FATAL;
-                     retry = sock->resolve_retry_seconds;
-                   }
-                 else
-                   {
-                     ASSERT (0);
-                   }
+                 flags |= GETADDR_FATAL;
+                 retry = sock->resolve_retry_seconds;
                }
              else
                {
                  ASSERT (0);
                }
+           }
+         else
+           {
+             ASSERT (0);
+           }
 
-             status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
-                                           retry, signal_received, sock->info.af, &ai);
-
-             if(status == 0) {
-               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,
-                     phase,
-                     retry,
-                     signal_received ? *signal_received : -1,
-                     status);
-             }
-             if (signal_received)
-               {
-                 if (*signal_received)
-                   goto done;
-               }
+
+         status = get_cached_dns_entry (sock->dns_cache,
+                                        sock->remote_host,
+                                        sock->remote_port,
+                                        sock->info.af,
+                                        flags, &ai);
+         if (status)
+           status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
+                                         retry, signal_received, sock->info.af, &ai);
+
+         if(status == 0) {
+           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,
+                 phase,
+                 retry,
+                 signal_received ? *signal_received : -1,
+                 status);
+         }
+         if (signal_received)
+           {
+             if (*signal_received)
+               goto done;
+           }
              if (status!=0)
                {
                  if (signal_received)
                    *signal_received = SIGUSR1;
                  goto done;
                }
-           }
        }
+    }
   
-      /* should we re-use previous active remote address? */
-      if (link_socket_actual_defined (&sock->info.lsa->actual))
-       {
-         msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
-              print_link_socket_actual (&sock->info.lsa->actual, &gc));
-         if (remote_dynamic)
-           *remote_dynamic = NULL;
-       }
-      else
+  /* should we re-use previous active remote address? */
+  if (link_socket_actual_defined (&sock->info.lsa->actual))
+    {
+      msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
+          print_link_socket_actual (&sock->info.lsa->actual, &gc));
+      if (remote_dynamic)
+       *remote_dynamic = NULL;
+    }
+  else
+    {
+      CLEAR (sock->info.lsa->actual);
+      if(sock->info.lsa->current_remote)
        {
-         CLEAR (sock->info.lsa->actual);
-         if(sock->info.lsa->current_remote)
-           {
-             set_actual_address (&sock->info.lsa->actual,
-                                 sock->info.lsa->current_remote);
-           }
+         set_actual_address (&sock->info.lsa->actual,
+                             sock->info.lsa->current_remote);
        }
-
-      /* remember that we finished */
-      sock->did_resolve_remote = true;
     }
 
  done:
@@ -1341,6 +1523,7 @@ create_new_socket (struct link_socket* sock)
       if (sock->bind_local)
           bind_local(sock);
     }
+
 }
 
 
@@ -1351,6 +1534,7 @@ link_socket_init_phase1 (struct link_socket *sock,
                         const char *local_port,
                         const char *remote_host,
                         const char *remote_port,
+                        struct cached_dns_entry *dns_cache,
                         int proto,
                         sa_family_t af,
                         bool bind_ipv6_only,
@@ -1385,6 +1569,7 @@ link_socket_init_phase1 (struct link_socket *sock,
   sock->local_port = local_port;
   sock->remote_host = remote_host;
   sock->remote_port = remote_port;
+  sock->dns_cache = dns_cache;
 
 #ifdef ENABLE_HTTP_PROXY
   sock->http_proxy = http_proxy;
@@ -1564,33 +1749,33 @@ linksock_print_addr (struct link_socket *sock)
   const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
 
   /* print local address */
 if (sock->inetd)
+ if (sock->inetd)
     msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true));
-    else if (sock->bind_local)
-      {
-       /* Socket is always bound on the first matching address */
-       struct addrinfo *cur;
-       for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
-         {
-           if(cur->ai_family == sock->info.lsa->actual.ai_family)
-               break;
-         }
-       ASSERT (cur);
-       msg (msglevel, "%s link local (bound): %s",
+  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: (not bound)",
-            proto2ascii (sock->info.proto, sock->info.af, true));
+    }
+  else
+    msg (msglevel, "%s link local: (not bound)",
+        proto2ascii (sock->info.proto, sock->info.af, true));
 
   /* print active remote address */
   msg (msglevel, "%s link remote: %s",
-        proto2ascii (sock->info.proto, sock->info.af, true),
-        print_link_socket_actual_ex (&sock->info.lsa->actual,
-                                     ":",
-                                     PS_SHOW_PORT_IF_DEFINED,
-                                     &gc));
+       proto2ascii (sock->info.proto, sock->info.af, true),
+       print_link_socket_actual_ex (&sock->info.lsa->actual,
+                                   ":",
+                                   PS_SHOW_PORT_IF_DEFINED,
+                                   &gc));
   gc_free(&gc);
 }
 
@@ -1707,7 +1892,6 @@ phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info)
 
     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)
@@ -2579,30 +2763,6 @@ proto2ascii_all (struct gc_arena *gc)
   return BSTR (&out);
 }
 
-int
-addr_guess_family(sa_family_t af, const char *name)
-{
-  unsigned short ret;
-  if (af)
-    {
-      return af;       /* already stamped */
-    } 
-  else
-    {
-      struct addrinfo hints , *ai;
-      int err;
-      CLEAR(hints);
-      hints.ai_flags = AI_NUMERICHOST;
-      err = getaddrinfo(name, NULL, &hints, &ai);
-      if ( 0 == err )
-       {
-         ret=ai->ai_family;
-         freeaddrinfo(ai);
-         return ret;
-       }
-    }
-  return AF_INET;      /* default */
-}
 const char *
 addr_family_name (int af) 
 {
index 191668fbb648a3f357ec645aecc9e79b2f9481f4..40f524b2e16bcdd8c0c40fd778d225cf6f158a43 100644 (file)
@@ -77,6 +77,16 @@ struct openvpn_sockaddr
   } addr;
 };
 
+/* struct to hold preresolved host names */
+struct cached_dns_entry {
+    const char *hostname;
+    const char *servname;
+    int ai_family;
+    int flags;
+    struct addrinfo *ai;
+    struct cached_dns_entry *next;
+};
+
 /* actual address of remote, based on source address of received packets */
 struct link_socket_actual
 {
@@ -188,6 +198,7 @@ struct link_socket
   const char *remote_port;
   const char *local_host;
   const char *local_port;
+  struct cached_dns_entry *dns_cache;
   bool bind_local;
 
 # define INETD_NONE   0
@@ -208,8 +219,6 @@ struct link_socket
 
   int mtu;                      /* OS discovered MTU, or 0 if unknown */
 
-  bool did_resolve_remote;
-
 # define SF_USE_IP_PKTINFO (1<<0)
 # define SF_TCP_NODELAY (1<<1)
 # define SF_PORT_SHARE (1<<2)
@@ -298,6 +307,8 @@ int openvpn_connect (socket_descriptor_t sd,
                     int connect_timeout,
                     volatile int *signal_received);
 
+
+
 /*
  * Initialize link_socket object.
  */
@@ -308,6 +319,7 @@ link_socket_init_phase1 (struct link_socket *sock,
                         const char *local_port,
                         const char *remote_host,
                         const char *remote_port,
+                        struct cached_dns_entry *dns_cache,
                         int proto,
                         sa_family_t af,
                         bool bind_ipv6_only,
@@ -340,6 +352,8 @@ void link_socket_init_phase2 (struct link_socket *sock,
                              const struct frame *frame,
                              struct signal_info *sig_info);
 
+void do_preresolve(struct context *c);
+
 void socket_adjust_frame_parameters (struct frame *frame, int proto);
 
 void frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto);
@@ -514,6 +528,8 @@ bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *
 #define GETADDR_PASSIVE               (1<<10)
 #define GETADDR_DATAGRAM              (1<<11)
 
+#define GETADDR_CACHE_MASK             GETADDR_DATAGRAM|GETADDR_PASSIVE
+
 in_addr_t getaddr (unsigned int flags,
                   const char *hostname,
                   int resolve_retry_seconds,