Browse code

Introduce an option to resolve dns names in advance for --remote, --local and --http-proxy

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>

Arne Schwabe authored on 2014/03/23 21:13:06
Showing 10 changed files
... ...
@@ -372,6 +372,44 @@ x_gc_free (struct gc_arena *a)
372 372
 }
373 373
 
374 374
 /*
375
+ * Functions to handle special objects in gc_entries
376
+ */
377
+
378
+void
379
+x_gc_freespecial (struct gc_arena *a)
380
+{
381
+  struct gc_entry_special *e;
382
+  e = a->list_special;
383
+  a->list_special = NULL;
384
+
385
+  while (e != NULL)
386
+    {
387
+      struct gc_entry_special *next = e->next;
388
+      e->free_fnc (e->addr);
389
+      free(e);
390
+      e = next;
391
+    }
392
+}
393
+
394
+void gc_addspecial (void *addr, void (free_function)(void*), struct gc_arena *a)
395
+{
396
+  ASSERT(a);
397
+  struct gc_entry_special *e;
398
+#ifdef DMALLOC
399
+  e = (struct gc_entry_special *) openvpn_dmalloc (file, line, sizeof (struct gc_entry_special));
400
+#else
401
+  e = (struct gc_entry_special *) malloc (sizeof (struct gc_entry_special));
402
+#endif
403
+  check_malloc_return (e);
404
+  e->free_fnc = free_function;
405
+  e->addr = addr;
406
+
407
+  e->next = a->list_special;
408
+  a->list_special = e;
409
+}
410
+
411
+
412
+/*
375 413
  * Transfer src arena to dest, resetting src to an empty arena.
376 414
  */
377 415
 void
... ...
@@ -91,6 +91,18 @@ struct gc_entry
91 91
                                  *   linked list. */
92 92
 };
93 93
 
94
+/**
95
+ * Gargabe collection entry for a specially allocated structure that needs
96
+ * a custom free function to be freed like struct addrinfo
97
+ *
98
+ */
99
+struct gc_entry_special
100
+{
101
+  struct gc_entry_special *next;
102
+  void (*free_fnc)(void*);
103
+  void *addr;
104
+};
105
+
94 106
 
95 107
 /**
96 108
  * Garbage collection arena used to keep track of dynamically allocated
... ...
@@ -106,6 +118,7 @@ struct gc_arena
106 106
 {
107 107
   struct gc_entry *list;        /**< First element of the linked list of
108 108
                                  *   \c gc_entry structures. */
109
+  struct gc_entry_special *list_special;
109 110
 };
110 111
 
111 112
 
... ...
@@ -163,6 +176,9 @@ struct buffer string_alloc_buf (const char *str, struct gc_arena *gc);
163 163
 
164 164
 #endif
165 165
 
166
+void gc_addspecial (void *addr, void (*free_function)(void*), struct gc_arena *a);
167
+
168
+
166 169
 #ifdef BUF_INIT_TRACKING
167 170
 #define buf_init(buf, offset) buf_init_debug (buf, offset, __FILE__, __LINE__)
168 171
 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)
172 172
 
173 173
 
174 174
 /* inline functions */
175
+inline static void
176
+gc_freeaddrinfo_callback (void *addr)
177
+{
178
+  freeaddrinfo((struct addrinfo*) addr);
179
+}
175 180
 
176 181
 static inline bool
177 182
 buf_defined (const struct buffer *buf)
... ...
@@ -778,6 +799,7 @@ void character_class_debug (void);
778 778
 void gc_transfer (struct gc_arena *dest, struct gc_arena *src);
779 779
 
780 780
 void x_gc_free (struct gc_arena *a);
781
+void x_gc_freespecial (struct gc_arena *a);
781 782
 
782 783
 static inline bool
783 784
 gc_defined (struct gc_arena *a)
... ...
@@ -789,6 +811,7 @@ static inline void
789 789
 gc_init (struct gc_arena *a)
790 790
 {
791 791
   a->list = NULL;
792
+  a->list_special = NULL;
792 793
 }
793 794
 
794 795
 static inline void
... ...
@@ -801,7 +824,7 @@ static inline struct gc_arena
801 801
 gc_new (void)
802 802
 {
803 803
   struct gc_arena ret;
804
-  ret.list = NULL;
804
+  gc_init (&ret);
805 805
   return ret;
806 806
 }
807 807
 
... ...
@@ -810,6 +833,8 @@ gc_free (struct gc_arena *a)
810 810
 {
811 811
   if (a->list)
812 812
     x_gc_free (a);
813
+  if (a->list_special)
814
+    x_gc_freespecial(a);
813 815
 }
814 816
 
815 817
 static inline void
... ...
@@ -131,7 +131,8 @@ management_callback_proxy_cmd (void *arg, const char **p)
131 131
           msg (M_WARN, "HTTP proxy support is not available");
132 132
 #else
133 133
           struct http_proxy_options *ho;
134
-          if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT )            {
134
+          if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT )
135
+            {
135 136
               msg (M_WARN, "HTTP proxy support only works for TCP based connections");
136 137
               return false;
137 138
             }
... ...
@@ -306,11 +307,10 @@ init_connection_list (struct context *c)
306 306
 /*
307 307
  * Clear the remote address list
308 308
  */
309
-static void clear_remote_addrlist (struct link_socket_addr *lsa)
309
+static void clear_remote_addrlist (struct link_socket_addr *lsa, bool free)
310 310
 {
311
-    if (lsa->remote_list) {
312
-        freeaddrinfo(lsa->remote_list);
313
-    }
311
+    if (lsa->remote_list && free)
312
+      freeaddrinfo(lsa->remote_list);
314 313
     lsa->remote_list = NULL;
315 314
     lsa->current_remote = NULL;
316 315
 }
... ...
@@ -348,9 +348,12 @@ next_connection_entry (struct context *c)
348 348
              * this is broken probably ever since connection lists and multiple
349 349
              * remote existed
350 350
              */
351
-
352 351
             if (!c->options.persist_remote_ip)
353
-                clear_remote_addrlist (&c->c1.link_socket_addr);
352
+	      {
353
+		/* close_instance should have cleared the addrinfo objects */
354
+		ASSERT (c->c1.link_socket_addr.current_remote == NULL);
355
+		ASSERT (c->c1.link_socket_addr.remote_list == NULL);
356
+	      }
354 357
             else
355 358
                 c->c1.link_socket_addr.current_remote =
356 359
                 c->c1.link_socket_addr.remote_list;
... ...
@@ -2688,6 +2691,7 @@ do_init_socket_1 (struct context *c, const int mode)
2688 2688
 			   c->options.ce.local_port,
2689 2689
 			   c->options.ce.remote,
2690 2690
 			   c->options.ce.remote_port,
2691
+			   c->c1.dns_cache,
2691 2692
 			   c->options.ce.proto,
2692 2693
 			   c->options.ce.af,
2693 2694
 			   c->options.ce.bind_ipv6_only,
... ...
@@ -2908,7 +2912,7 @@ do_close_link_socket (struct context *c)
2908 2908
            || c->options.no_advance))
2909 2909
          )))
2910 2910
     {
2911
-      clear_remote_addrlist(&c->c1.link_socket_addr);
2911
+      clear_remote_addrlist(&c->c1.link_socket_addr, !c->options.resolve_in_advance);
2912 2912
     }
2913 2913
 
2914 2914
     /* Clear the remote actual address when persist_remote_ip is not in use */
... ...
@@ -2916,8 +2920,9 @@ do_close_link_socket (struct context *c)
2916 2916
       CLEAR (c->c1.link_socket_addr.actual);
2917 2917
 
2918 2918
   if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) {
2919
-    if (c->c1.link_socket_addr.bind_local)
2920
-        freeaddrinfo(c->c1.link_socket_addr.bind_local);
2919
+    if (c->c1.link_socket_addr.bind_local && !c->options.resolve_in_advance)
2920
+	freeaddrinfo(c->c1.link_socket_addr.bind_local);
2921
+
2921 2922
     c->c1.link_socket_addr.bind_local=NULL;
2922 2923
   }
2923 2924
 }
... ...
@@ -3359,6 +3364,13 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
3359 3359
 	goto sig;
3360 3360
     }
3361 3361
 
3362
+  if (c->options.resolve_in_advance)
3363
+    {
3364
+      do_preresolve (c);
3365
+      if (IS_SIG (c))
3366
+	goto sig;
3367
+    }
3368
+
3362 3369
   /* map in current connection entry */
3363 3370
   next_connection_entry (c);
3364 3371
 
... ...
@@ -1568,9 +1568,9 @@ man_listen (struct management *man)
1568 1568
       else
1569 1569
 #endif
1570 1570
 	{
1571
-	  man->connection.sd_top = create_socket_tcp (AF_INET);
1571
+	  man->connection.sd_top = create_socket_tcp (man->settings.local->ai_family);
1572 1572
 	  socket_bind (man->connection.sd_top, man->settings.local,
1573
-                       AF_INET, "MANAGEMENT", true);
1573
+                       man->settings.local->ai_family, "MANAGEMENT", false);
1574 1574
 	}
1575 1575
 
1576 1576
       /*
... ...
@@ -2151,8 +2151,14 @@ man_settings_init (struct man_settings *ms,
2151 2151
 	    }
2152 2152
 	  else
2153 2153
 	    {
2154
-              int status = openvpn_getaddrinfo(GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL,
2155
-                                               addr, port, 0, NULL, AF_INET, &ms->local);
2154
+	      int status;
2155
+	      int resolve_flags = GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL;
2156
+
2157
+	      if (! (flags & MF_CONNECT_AS_CLIENT))
2158
+		  resolve_flags |= GETADDR_PASSIVE;
2159
+
2160
+              status = openvpn_getaddrinfo (resolve_flags, addr, port, 0,
2161
+					    NULL, AF_UNSPEC, &ms->local);
2156 2162
               ASSERT(status==0);
2157 2163
 	    }
2158 2164
 	}
... ...
@@ -2179,6 +2185,8 @@ man_settings_init (struct man_settings *ms,
2179 2179
 static void
2180 2180
 man_settings_close (struct man_settings *ms)
2181 2181
 {
2182
+  if (ms->local)
2183
+    freeaddrinfo(ms->local);
2182 2184
   free (ms->write_peer_info_file);
2183 2185
   CLEAR (*ms);
2184 2186
 }
... ...
@@ -2616,7 +2624,7 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i
2616 2616
       int ret;
2617 2617
 
2618 2618
       ia.s_addr = htonl(tun_local_ip);
2619
-      ret = openvpn_getaddrinfo(0, inet_ntoa(ia), NULL, 0, NULL,
2619
+      ret = openvpn_getaddrinfo(GETADDR_PASSIVE, inet_ntoa(ia), NULL, 0, NULL,
2620 2620
                                 AF_INET, &man->settings.local);
2621 2621
       ASSERT (ret==0);
2622 2622
       man_connection_init (man);
... ...
@@ -166,6 +166,9 @@ struct context_1
166 166
   /* tunnel session keys */
167 167
   struct key_schedule ks;
168 168
 
169
+  /* preresolved and cached host names */
170
+  struct cached_dns_entry *dns_cache;
171
+
169 172
   /* persist crypto sequence number to/from file */
170 173
   struct packet_id_persist pid_persist;
171 174
 
... ...
@@ -796,6 +796,7 @@ init_options (struct options *o, const bool init_gc)
796 796
   o->ce.mssfix = MSSFIX_DEFAULT;
797 797
   o->route_delay_window = 30;
798 798
   o->resolve_retry_seconds = RESOLV_RETRY_INFINITE;
799
+  o->resolve_in_advance = false;
799 800
   o->proto_force = -1;
800 801
 #ifdef ENABLE_OCC
801 802
   o->occ = true;
... ...
@@ -1369,6 +1370,7 @@ show_connection_entry (const struct connection_entry *o)
1369 1369
   SHOW_BOOL (remote_float);
1370 1370
   SHOW_BOOL (bind_defined);
1371 1371
   SHOW_BOOL (bind_local);
1372
+  SHOW_BOOL (bind_ipv6_only);
1372 1373
   SHOW_INT (connect_retry_seconds);
1373 1374
   SHOW_INT (connect_timeout);
1374 1375
 
... ...
@@ -1494,6 +1496,7 @@ show_settings (const struct options *o)
1494 1494
 #endif
1495 1495
 
1496 1496
   SHOW_INT (resolve_retry_seconds);
1497
+  SHOW_BOOL (resolve_in_advance);
1497 1498
 
1498 1499
   SHOW_STR (username);
1499 1500
   SHOW_STR (groupname);
... ...
@@ -4540,6 +4543,15 @@ add_option (struct options *options,
4540 4540
       else
4541 4541
 	options->resolve_retry_seconds = positive_atoi (p[1]);
4542 4542
     }
4543
+  else if (streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint"))
4544
+    {
4545
+      VERIFY_PERMISSION (OPT_P_GENERAL);
4546
+      options->resolve_in_advance = true;
4547
+      /* Note the ip-remote-hint and the argument p[1] are for
4548
+	 backward compatibility */
4549
+      if (p[1])
4550
+	options->ip_remote_hint=p[1];
4551
+    }
4543 4552
   else if (streq (p[0], "connect-retry") && p[1])
4544 4553
     {
4545 4554
       VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
... ...
@@ -90,7 +90,7 @@ struct connection_entry
90 90
   sa_family_t af;
91 91
   const char* local_port;
92 92
   bool local_port_defined;
93
-  const char* remote_port;
93
+  const char *remote_port;
94 94
   const char *local;
95 95
   const char *remote;
96 96
   bool remote_float;
... ...
@@ -278,6 +278,8 @@ struct options
278 278
 #endif
279 279
 
280 280
   int resolve_retry_seconds;    /* If hostname resolve fails, retry for n seconds */
281
+  bool resolve_in_advance;
282
+  const char *ip_remote_hint;
281 283
 
282 284
   struct tuntap_options tuntap_options;
283 285
 
... ...
@@ -638,6 +638,7 @@ init_route_list (struct route_list *rl,
638 638
 	else
639 639
 	  {
640 640
             struct addrinfo* curele;
641
+            gc_addspecial(netlist, &gc_freeaddrinfo_callback, &gc);
641 642
             for (curele	= netlist; curele; curele = curele->ai_next)
642 643
 	      {
643 644
                 struct route_ipv4 *new;
... ...
@@ -647,7 +648,6 @@ init_route_list (struct route_list *rl,
647 647
                 new->next = rl->routes;
648 648
                 rl->routes = new;
649 649
 	      }
650
-            freeaddrinfo(netlist);
651 650
 	  }
652 651
       }
653 652
   }
... ...
@@ -39,6 +39,7 @@
39 39
 #include "manage.h"
40 40
 #include "misc.h"
41 41
 #include "manage.h"
42
+#include "openvpn.h"
42 43
 
43 44
 #include "memdbg.h"
44 45
 
... ...
@@ -117,6 +118,178 @@ getaddr (unsigned int flags,
117 117
   }
118 118
 }
119 119
 
120
+static inline bool
121
+streqnull (const char* a, const char* b)
122
+{
123
+  if (a == NULL && b == NULL)
124
+    return true;
125
+  else if (a == NULL || b == NULL)
126
+    return false;
127
+  else
128
+    return streq (a, b);
129
+}
130
+
131
+/*
132
+  get_cached_dns_entry return 0 on success and -1
133
+  otherwise. (like getaddrinfo)
134
+ */
135
+static int
136
+get_cached_dns_entry (struct cached_dns_entry* dns_cache,
137
+		      const char* hostname,
138
+		      const char* servname,
139
+		      int ai_family,
140
+		      int resolve_flags,
141
+		      struct addrinfo **ai)
142
+{
143
+  struct cached_dns_entry *ph;
144
+  int flags;
145
+
146
+  /* Only use flags that are relevant for the structure */
147
+  flags = resolve_flags & GETADDR_CACHE_MASK;
148
+
149
+  for (ph = dns_cache; ph ; ph = ph->next)
150
+    {
151
+      if (streqnull (ph->hostname, hostname) &&
152
+	  streqnull (ph->servname, servname) &&
153
+	  ph->ai_family == ai_family &&
154
+	  ph->flags == flags)
155
+	{
156
+	  *ai = ph->ai;
157
+	  return 0;
158
+	}
159
+    }
160
+  return -1;
161
+}
162
+
163
+
164
+static int
165
+do_preresolve_host (struct context *c,
166
+		    const char *hostname,
167
+		    const char *servname,
168
+		    const int af,
169
+		    const int flags)
170
+{
171
+  struct addrinfo *ai;
172
+  int status;
173
+
174
+  if (get_cached_dns_entry(c->c1.dns_cache,
175
+			   hostname,
176
+			   servname,
177
+			   af,
178
+			   flags,
179
+			   &ai) == 0 )
180
+    {
181
+      /* entry already cached, return success */
182
+      return 0;
183
+    }
184
+
185
+  status = openvpn_getaddrinfo (flags, hostname, servname,
186
+				c->options.resolve_retry_seconds, NULL,
187
+				af, &ai);
188
+  if (status == 0)
189
+    {
190
+      struct cached_dns_entry *ph;
191
+
192
+      ALLOC_OBJ_CLEAR_GC (ph, struct cached_dns_entry, &c->gc);
193
+      ph->ai = ai;
194
+      ph->hostname = hostname;
195
+      ph->servname = servname;
196
+      ph->flags = flags & GETADDR_CACHE_MASK;
197
+
198
+      if (!c->c1.dns_cache)
199
+	c->c1.dns_cache = ph;
200
+      else
201
+	{
202
+	  struct cached_dns_entry *prev = c->c1.dns_cache;
203
+	  while (prev->next)
204
+	    prev = prev->next;
205
+	  prev->next = ph;
206
+	}
207
+
208
+      gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc);
209
+
210
+    }
211
+  return status;
212
+}
213
+
214
+void
215
+do_preresolve (struct context *c)
216
+{
217
+  int i;
218
+  struct connection_list *l = c->options.connection_list;
219
+  const unsigned int preresolve_flags = GETADDR_RESOLVE|
220
+    GETADDR_UPDATE_MANAGEMENT_STATE|
221
+    GETADDR_MENTION_RESOLVE_RETRY|
222
+    GETADDR_FATAL;
223
+
224
+
225
+  for (i = 0; i < l->len; ++i)
226
+    {
227
+      int status;
228
+      const char *remote;
229
+      int flags = preresolve_flags;
230
+
231
+      struct connection_entry* ce = c->options.connection_list->array[i];
232
+
233
+      if (proto_is_dgram(ce->proto))
234
+	  flags |= GETADDR_DATAGRAM;
235
+
236
+      if (c->options.sockflags & SF_HOST_RANDOMIZE)
237
+	  flags |= GETADDR_RANDOMIZE;
238
+
239
+      if (c->options.ip_remote_hint)
240
+	  remote = c->options.ip_remote_hint;
241
+      else
242
+	  remote = ce->remote;
243
+
244
+      /* HTTP remote hostname does not need to be resolved */
245
+      if (! ce->http_proxy_options)
246
+	{
247
+	  status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags);
248
+	  if (status != 0)
249
+	      goto err;
250
+	}
251
+
252
+      /* Preresolve proxy */
253
+      if (ce->http_proxy_options)
254
+	{
255
+	  status = do_preresolve_host (c,
256
+				       ce->http_proxy_options->server,
257
+				       ce->http_proxy_options->port,
258
+				       ce->af,
259
+				       preresolve_flags);
260
+
261
+	  if (status != 0)
262
+	      goto err;
263
+	}
264
+
265
+      if (ce->socks_proxy_server)
266
+	{
267
+	  status = do_preresolve_host (c,
268
+				       ce->socks_proxy_server,
269
+				       ce->socks_proxy_port,
270
+				       ce->af,
271
+				       flags);
272
+	  if (status != 0)
273
+	      goto err;
274
+	}
275
+
276
+      if (ce->bind_local)
277
+	{
278
+	  flags |= GETADDR_PASSIVE;
279
+	  flags &= ~GETADDR_RANDOMIZE;
280
+	  status = do_preresolve_host (c, ce->local, ce->local_port, ce->af, flags);
281
+	  if (status != 0)
282
+	      goto err;
283
+
284
+	}
285
+
286
+    }
287
+    return;
288
+
289
+ err:
290
+  throw_signal_soft (SIGHUP, "Preresolving failed");
291
+}
120 292
 
121 293
 /*
122 294
  * 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)
1155 1155
 	flags |= GETADDR_DATAGRAM;
1156 1156
 
1157 1157
       /* will return AF_{INET|INET6}from local_host */
1158
-      status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
1158
+      status = get_cached_dns_entry (sock->dns_cache,
1159
+				     sock->local_host,
1160
+				     sock->local_port,
1161
+				     af,
1162
+				     flags,
1163
+				     &sock->info.lsa->bind_local);
1164
+
1165
+      if (status)
1166
+	status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
1159 1167
 				   NULL, af, &sock->info.lsa->bind_local);
1160 1168
 
1161 1169
       if(status !=0) {
... ...
@@ -1193,103 +1374,104 @@ resolve_remote (struct link_socket *sock,
1193 1193
 {
1194 1194
   struct gc_arena gc = gc_new ();
1195 1195
 
1196
-  if (!sock->did_resolve_remote)
1196
+  /* resolve remote address if undefined */
1197
+  if (!sock->info.lsa->remote_list)
1197 1198
     {
1198
-      /* resolve remote address if undefined */
1199
-      if (!sock->info.lsa->remote_list)
1199
+      if (sock->remote_host)
1200 1200
 	{
1201
-	  if (sock->remote_host)
1201
+	  unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
1202
+	  int retry = 0;
1203
+	  int status = -1;
1204
+	  struct addrinfo* ai;
1205
+	  if (proto_is_dgram(sock->info.proto))
1206
+	    flags |= GETADDR_DATAGRAM;
1207
+
1208
+	  if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
1209
+	    {
1210
+	      if (phase == 2)
1211
+		flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
1212
+	      retry = 0;
1213
+	    }
1214
+	  else if (phase == 1)
1202 1215
 	    {
1203
-	      unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
1204
-	      int retry = 0;
1205
-	      int status = -1;
1206
-              struct addrinfo* ai;
1207
-              if (proto_is_dgram(sock->info.proto))
1208
-                  flags |= GETADDR_DATAGRAM;
1209
-
1210
-	      if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
1216
+	      if (sock->resolve_retry_seconds)
1211 1217
 		{
1212
-		  if (phase == 2)
1213
-		    flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
1214 1218
 		  retry = 0;
1215 1219
 		}
1216
-	      else if (phase == 1)
1220
+	      else
1217 1221
 		{
1218
-		  if (sock->resolve_retry_seconds)
1219
-		    {
1220
-		      retry = 0;
1221
-		    }
1222
-		  else
1223
-		    {
1224
-		      flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
1225
-		      retry = 0;
1226
-		    }
1222
+		  flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
1223
+		  retry = 0;
1227 1224
 		}
1228
-	      else if (phase == 2)
1225
+	    }
1226
+	  else if (phase == 2)
1227
+	    {
1228
+	      if (sock->resolve_retry_seconds)
1229 1229
 		{
1230
-		  if (sock->resolve_retry_seconds)
1231
-		    {
1232
-		      flags |= GETADDR_FATAL;
1233
-		      retry = sock->resolve_retry_seconds;
1234
-		    }
1235
-		  else
1236
-		    {
1237
-		      ASSERT (0);
1238
-		    }
1230
+		  flags |= GETADDR_FATAL;
1231
+		  retry = sock->resolve_retry_seconds;
1239 1232
 		}
1240 1233
 	      else
1241 1234
 		{
1242 1235
 		  ASSERT (0);
1243 1236
 		}
1237
+	    }
1238
+	  else
1239
+	    {
1240
+	      ASSERT (0);
1241
+	    }
1244 1242
 
1245
-	      status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
1246
-					    retry, signal_received, sock->info.af, &ai);
1247
-
1248
-	      if(status == 0) {
1249
-		sock->info.lsa->remote_list = ai;
1250
-		sock->info.lsa->current_remote = ai;
1251
-
1252
-		dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
1253
-		      flags,
1254
-		      phase,
1255
-		      retry,
1256
-		      signal_received ? *signal_received : -1,
1257
-		      status);
1258
-	      }
1259
-	      if (signal_received)
1260
-		{
1261
-		  if (*signal_received)
1262
-		    goto done;
1263
-		}
1243
+
1244
+	  status = get_cached_dns_entry (sock->dns_cache,
1245
+					 sock->remote_host,
1246
+					 sock->remote_port,
1247
+					 sock->info.af,
1248
+					 flags, &ai);
1249
+	  if (status)
1250
+	    status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
1251
+					  retry, signal_received, sock->info.af, &ai);
1252
+
1253
+	  if(status == 0) {
1254
+	    sock->info.lsa->remote_list = ai;
1255
+	    sock->info.lsa->current_remote = ai;
1256
+
1257
+	    dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
1258
+		  flags,
1259
+		  phase,
1260
+		  retry,
1261
+		  signal_received ? *signal_received : -1,
1262
+		  status);
1263
+	  }
1264
+	  if (signal_received)
1265
+	    {
1266
+	      if (*signal_received)
1267
+		goto done;
1268
+	    }
1264 1269
 	      if (status!=0)
1265 1270
 		{
1266 1271
 		  if (signal_received)
1267 1272
 		    *signal_received = SIGUSR1;
1268 1273
 		  goto done;
1269 1274
 		}
1270
-	    }
1271 1275
 	}
1276
+    }
1272 1277
   
1273
-      /* should we re-use previous active remote address? */
1274
-      if (link_socket_actual_defined (&sock->info.lsa->actual))
1275
-	{
1276
-	  msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
1277
-	       print_link_socket_actual (&sock->info.lsa->actual, &gc));
1278
-	  if (remote_dynamic)
1279
-	    *remote_dynamic = NULL;
1280
-	}
1281
-      else
1278
+  /* should we re-use previous active remote address? */
1279
+  if (link_socket_actual_defined (&sock->info.lsa->actual))
1280
+    {
1281
+      msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
1282
+	   print_link_socket_actual (&sock->info.lsa->actual, &gc));
1283
+      if (remote_dynamic)
1284
+	*remote_dynamic = NULL;
1285
+    }
1286
+  else
1287
+    {
1288
+      CLEAR (sock->info.lsa->actual);
1289
+      if(sock->info.lsa->current_remote)
1282 1290
 	{
1283
-	  CLEAR (sock->info.lsa->actual);
1284
-	  if(sock->info.lsa->current_remote)
1285
-	    {
1286
-	      set_actual_address (&sock->info.lsa->actual,
1287
-				  sock->info.lsa->current_remote);
1288
-	    }
1291
+	  set_actual_address (&sock->info.lsa->actual,
1292
+			      sock->info.lsa->current_remote);
1289 1293
 	}
1290
-
1291
-      /* remember that we finished */
1292
-      sock->did_resolve_remote = true;
1293 1294
     }
1294 1295
 
1295 1296
  done:
... ...
@@ -1341,6 +1523,7 @@ create_new_socket (struct link_socket* sock)
1341 1341
       if (sock->bind_local)
1342 1342
           bind_local(sock);
1343 1343
     }
1344
+
1344 1345
 }
1345 1346
 
1346 1347
 
... ...
@@ -1351,6 +1534,7 @@ link_socket_init_phase1 (struct link_socket *sock,
1351 1351
 			 const char *local_port,
1352 1352
 			 const char *remote_host,
1353 1353
 			 const char *remote_port,
1354
+			 struct cached_dns_entry *dns_cache,
1354 1355
 			 int proto,
1355 1356
 			 sa_family_t af,
1356 1357
 			 bool bind_ipv6_only,
... ...
@@ -1385,6 +1569,7 @@ link_socket_init_phase1 (struct link_socket *sock,
1385 1385
   sock->local_port = local_port;
1386 1386
   sock->remote_host = remote_host;
1387 1387
   sock->remote_port = remote_port;
1388
+  sock->dns_cache = dns_cache;
1388 1389
 
1389 1390
 #ifdef ENABLE_HTTP_PROXY
1390 1391
   sock->http_proxy = http_proxy;
... ...
@@ -1564,33 +1749,33 @@ linksock_print_addr (struct link_socket *sock)
1564 1564
   const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
1565 1565
 
1566 1566
   /* print local address */
1567
-  if (sock->inetd)
1567
+ if (sock->inetd)
1568 1568
     msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true));
1569
-    else if (sock->bind_local)
1570
-      {
1571
-	/* Socket is always bound on the first matching address */
1572
-	struct addrinfo *cur;
1573
-	for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
1574
-	  {
1575
-	    if(cur->ai_family == sock->info.lsa->actual.ai_family)
1576
-		break;
1577
-	  }
1578
-	ASSERT (cur);
1579
-	msg (msglevel, "%s link local (bound): %s",
1569
+  else if (sock->bind_local)
1570
+    {
1571
+      /* Socket is always bound on the first matching address */
1572
+      struct addrinfo *cur;
1573
+      for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
1574
+	{
1575
+	  if(cur->ai_family == sock->info.lsa->actual.ai_family)
1576
+	    break;
1577
+	}
1578
+      ASSERT (cur);
1579
+      msg (msglevel, "%s link local (bound): %s",
1580 1580
 	   proto2ascii (sock->info.proto, sock->info.af, true),
1581 1581
 	   print_sockaddr(cur->ai_addr,&gc));
1582
-      }
1583
-    else
1584
-	msg (msglevel, "%s link local: (not bound)",
1585
-	     proto2ascii (sock->info.proto, sock->info.af, true));
1582
+    }
1583
+  else
1584
+    msg (msglevel, "%s link local: (not bound)",
1585
+	 proto2ascii (sock->info.proto, sock->info.af, true));
1586 1586
 
1587 1587
   /* print active remote address */
1588 1588
   msg (msglevel, "%s link remote: %s",
1589
-	 proto2ascii (sock->info.proto, sock->info.af, true),
1590
-	 print_link_socket_actual_ex (&sock->info.lsa->actual,
1591
-				      ":",
1592
-				      PS_SHOW_PORT_IF_DEFINED,
1593
-				      &gc));
1589
+       proto2ascii (sock->info.proto, sock->info.af, true),
1590
+       print_link_socket_actual_ex (&sock->info.lsa->actual,
1591
+				    ":",
1592
+				    PS_SHOW_PORT_IF_DEFINED,
1593
+				    &gc));
1594 1594
   gc_free(&gc);
1595 1595
 }
1596 1596
 
... ...
@@ -1707,7 +1892,6 @@ phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info)
1707 1707
 
1708 1708
     sock->remote_host = sock->proxy_dest_host;
1709 1709
     sock->remote_port = sock->proxy_dest_port;
1710
-    sock->did_resolve_remote = false;
1711 1710
 
1712 1711
     addr_zero_host(&sock->info.lsa->actual.dest);
1713 1712
     if (sock->info.lsa->remote_list)
... ...
@@ -2579,30 +2763,6 @@ proto2ascii_all (struct gc_arena *gc)
2579 2579
   return BSTR (&out);
2580 2580
 }
2581 2581
 
2582
-int
2583
-addr_guess_family(sa_family_t af, const char *name)
2584
-{
2585
-  unsigned short ret;
2586
-  if (af)
2587
-    {
2588
-      return af;	/* already stamped */
2589
-    } 
2590
-  else
2591
-    {
2592
-      struct addrinfo hints , *ai;
2593
-      int err;
2594
-      CLEAR(hints);
2595
-      hints.ai_flags = AI_NUMERICHOST;
2596
-      err = getaddrinfo(name, NULL, &hints, &ai);
2597
-      if ( 0 == err )
2598
-	{
2599
-	  ret=ai->ai_family;
2600
-	  freeaddrinfo(ai);
2601
-	  return ret;
2602
-	}
2603
-    }
2604
-  return AF_INET;	/* default */
2605
-}
2606 2582
 const char *
2607 2583
 addr_family_name (int af) 
2608 2584
 {
... ...
@@ -77,6 +77,16 @@ struct openvpn_sockaddr
77 77
   } addr;
78 78
 };
79 79
 
80
+/* struct to hold preresolved host names */
81
+struct cached_dns_entry {
82
+    const char *hostname;
83
+    const char *servname;
84
+    int ai_family;
85
+    int flags;
86
+    struct addrinfo *ai;
87
+    struct cached_dns_entry *next;
88
+};
89
+
80 90
 /* actual address of remote, based on source address of received packets */
81 91
 struct link_socket_actual
82 92
 {
... ...
@@ -188,6 +198,7 @@ struct link_socket
188 188
   const char *remote_port;
189 189
   const char *local_host;
190 190
   const char *local_port;
191
+  struct cached_dns_entry *dns_cache;
191 192
   bool bind_local;
192 193
 
193 194
 # define INETD_NONE   0
... ...
@@ -208,8 +219,6 @@ struct link_socket
208 208
 
209 209
   int mtu;                      /* OS discovered MTU, or 0 if unknown */
210 210
 
211
-  bool did_resolve_remote;
212
-
213 211
 # define SF_USE_IP_PKTINFO (1<<0)
214 212
 # define SF_TCP_NODELAY (1<<1)
215 213
 # define SF_PORT_SHARE (1<<2)
... ...
@@ -298,6 +307,8 @@ int openvpn_connect (socket_descriptor_t sd,
298 298
 		     int connect_timeout,
299 299
 		     volatile int *signal_received);
300 300
 
301
+
302
+
301 303
 /*
302 304
  * Initialize link_socket object.
303 305
  */
... ...
@@ -308,6 +319,7 @@ link_socket_init_phase1 (struct link_socket *sock,
308 308
 			 const char *local_port,
309 309
 			 const char *remote_host,
310 310
 			 const char *remote_port,
311
+			 struct cached_dns_entry *dns_cache,
311 312
 			 int proto,
312 313
 			 sa_family_t af,
313 314
 			 bool bind_ipv6_only,
... ...
@@ -340,6 +352,8 @@ void link_socket_init_phase2 (struct link_socket *sock,
340 340
 			      const struct frame *frame,
341 341
 			      struct signal_info *sig_info);
342 342
 
343
+void do_preresolve(struct context *c);
344
+
343 345
 void socket_adjust_frame_parameters (struct frame *frame, int proto);
344 346
 
345 347
 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 *
514 514
 #define GETADDR_PASSIVE               (1<<10)
515 515
 #define GETADDR_DATAGRAM              (1<<11)
516 516
 
517
+#define GETADDR_CACHE_MASK		GETADDR_DATAGRAM|GETADDR_PASSIVE
518
+
517 519
 in_addr_t getaddr (unsigned int flags,
518 520
 		   const char *hostname,
519 521
 		   int resolve_retry_seconds,