From 077f361f7a910ad0e95724a95e0d8b25af185bcc Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 9 Dec 2013 21:17:15 +0100 Subject: Update pre resolve yet again --HG-- extra : source : d87e130c3a907b46caedc89e651c65827a3508ed --- openvpn/src/openvpn/init.c | 16 +++- openvpn/src/openvpn/openvpn.h | 3 + openvpn/src/openvpn/options.h | 2 - openvpn/src/openvpn/proxy.c | 2 + openvpn/src/openvpn/proxy.h | 2 + openvpn/src/openvpn/socket.c | 172 ++++++++++++++++++++++++++++++++++-------- openvpn/src/openvpn/socket.h | 18 ++++- 7 files changed, 175 insertions(+), 40 deletions(-) (limited to 'openvpn') diff --git a/openvpn/src/openvpn/init.c b/openvpn/src/openvpn/init.c index 0f76b2cc..c42c0f78 100644 --- a/openvpn/src/openvpn/init.c +++ b/openvpn/src/openvpn/init.c @@ -130,16 +130,25 @@ management_callback_proxy_cmd (void *arg, const char **p) #ifndef ENABLE_HTTP_PROXY 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 ) { + struct http_proxy_options *ho, *oldho; + if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT ) { msg (M_WARN, "HTTP proxy support only works for TCP based connections"); return false; } + oldho = ce->http_proxy_options; ho = init_http_proxy_options_once (&ce->http_proxy_options, gc); ho->server = string_alloc (p[2], gc); ho->port = string_alloc (p[3], gc); ho->retry = true; ho->auth_retry = (p[4] && streq (p[4], "nct") ? PAR_NCT : PAR_ALL); + + /* Save the old preresolved addrinfo we are using the same proxy again */ + if (oldho && + oldho->preresolved_proxy && + streq(oldho->server, ho->server) && + streq(oldho->port, ho->port)) + ho->preresolved_proxy = oldho->preresolved_proxy; + ret = true; #endif } @@ -2690,10 +2699,9 @@ do_init_socket_1 (struct context *c, const int mode) link_socket_init_phase1 (c->c2.link_socket, c->options.ce.local, c->options.ce.local_port, - c->options.ce.preresolved_local, c->options.ce.remote, c->options.ce.remote_port, - c->options.ce.preresolved_remote, + c->c1.preresolved, c->options.ce.proto, c->options.ce.af, c->options.ce.bind_ipv6_only, diff --git a/openvpn/src/openvpn/openvpn.h b/openvpn/src/openvpn/openvpn.h index 606a4f59..3ed7810a 100644 --- a/openvpn/src/openvpn/openvpn.h +++ b/openvpn/src/openvpn/openvpn.h @@ -166,6 +166,9 @@ struct context_1 /* tunnel session keys */ struct key_schedule ks; + /* preresolved host names */ + struct preresovled_host *preresolved; + /* persist crypto sequence number to/from file */ struct packet_id_persist pid_persist; diff --git a/openvpn/src/openvpn/options.h b/openvpn/src/openvpn/options.h index ddeb8b38..dafb8ff6 100644 --- a/openvpn/src/openvpn/options.h +++ b/openvpn/src/openvpn/options.h @@ -93,8 +93,6 @@ struct connection_entry const char *remote_port; const char *local; const char *remote; - struct addrinfo *preresolved_remote; - struct addrinfo *preresolved_local; bool remote_float; bool bind_defined; bool bind_ipv6_only; diff --git a/openvpn/src/openvpn/proxy.c b/openvpn/src/openvpn/proxy.c index f7f06487..53cd1cda 100644 --- a/openvpn/src/openvpn/proxy.c +++ b/openvpn/src/openvpn/proxy.c @@ -478,6 +478,8 @@ http_proxy_new (const struct http_proxy_options *o) msg (M_FATAL, "Sorry, this version of " PACKAGE_NAME " was built without NTLM Proxy support."); #endif + p->preresoveld_proxy = o->preresolved_proxy; + p->defined = true; return p; } diff --git a/openvpn/src/openvpn/proxy.h b/openvpn/src/openvpn/proxy.h index 0e7a6dfb..cea910cf 100644 --- a/openvpn/src/openvpn/proxy.h +++ b/openvpn/src/openvpn/proxy.h @@ -59,6 +59,7 @@ struct http_proxy_options { const char *auth_file; const char *http_version; const char *user_agent; + struct addrinfo *preresolved_proxy; struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER]; }; @@ -73,6 +74,7 @@ struct http_proxy_info { int auth_method; struct http_proxy_options options; struct user_pass up; + struct addrinfo* preresoveld_proxy; char *proxy_authenticate; bool queried_creds; }; diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c index 26ef14c3..f99669aa 100644 --- a/openvpn/src/openvpn/socket.c +++ b/openvpn/src/openvpn/socket.c @@ -118,20 +118,114 @@ 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); +} + +static int +get_preresolved_host (struct preresovled_host* preresolved, + const char* hostname, + const char* servname, + int ai_family, + int resolve_flags, + struct addrinfo **ai) +{ + struct preresovled_host *ph; + int flags; + + /* Only use flags that are relevant for the structure */ + flags = resolve_flags & GETADDR_PRERESOLVE_MASK; + + for (ph = preresolved; 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; + if (get_preresolved_host(c->c1.preresolved, + hostname, + servname, + af, + flags, + &ai)) + { + int status; + status = openvpn_getaddrinfo (flags, hostname, servname, + c->options.resolve_retry_seconds, NULL, + af, &ai); + if (status == 0) + { + struct preresovled_host *ph; + + ALLOC_OBJ_CLEAR_GC (ph, struct preresovled_host, &c->gc); + ph->ai = ai; + ph->hostname = hostname; + ph->servname = servname; + ph->flags = flags & GETADDR_PRERESOLVE_MASK; + + if (!c->c1.preresolved) + c->c1.preresolved = ph; + else + { + struct preresovled_host *prev = c->c1.preresolved; + while (prev->next) + prev = prev->next; + prev->next = ph; + } + + gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc); + + } + return status; + } + else + { + /* already in preresolved list, return success */ + return 0; + } +} 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]; - unsigned int flags = GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE| - GETADDR_MENTION_RESOLVE_RETRY|GETADDR_FATAL; if (proto_is_dgram(ce->proto)) flags |= GETADDR_DATAGRAM; @@ -144,28 +238,45 @@ do_preresolve(struct context *c) else remote = ce->remote; - if (! ce->preresolved_remote) + /* HTTP remote hostname does not need to be resolved */ + if (! ce->http_proxy_options) { - status = openvpn_getaddrinfo (flags, remote, ce->remote_port, - c->options.resolve_retry_seconds, NULL, - ce->af, &ce->preresolved_remote); - - if (status != 0) + status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags); + if (!status) goto err; - gc_addspecial (ce->preresolved_remote, &gc_freeaddrinfo_callback, &c->gc); } flags |= GETADDR_PASSIVE; - if (ce->bind_local && !ce->preresolved_local) + + if (ce->bind_local) { - status = openvpn_getaddrinfo (flags, ce->local, ce->local_port, - c->options.resolve_retry_seconds, NULL, - ce->af, &ce->preresolved_local); + status = do_preresolve_host (c, ce->local, ce->local_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; - gc_addspecial (ce->preresolved_local, &gc_freeaddrinfo_callback, &c->gc); + } + 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; } } @@ -1211,12 +1322,14 @@ resolve_bind_local (struct link_socket *sock, const sa_family_t af) flags |= GETADDR_DATAGRAM; /* will return AF_{INET|INET6}from local_host */ - if (sock->preresolved_local) - { - status=0; - sock->info.lsa->bind_local=sock->preresolved_local; - } - else + status = get_preresolved_host (sock->preresolved, + 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); @@ -1302,12 +1415,13 @@ resolve_remote (struct link_socket *sock, ASSERT (0); } - if (sock->preresolved_remote) - { - status = 0; - ai = sock->preresolved_remote; - } - else + + status = get_preresolved_host (sock->preresolved, + 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); @@ -1412,10 +1526,9 @@ void link_socket_init_phase1 (struct link_socket *sock, const char *local_host, const char *local_port, - struct addrinfo *local_preresolved, const char *remote_host, const char *remote_port, - struct addrinfo *remote_preresolved, + struct preresovled_host *preresolved, int proto, sa_family_t af, bool bind_ipv6_only, @@ -1448,10 +1561,9 @@ link_socket_init_phase1 (struct link_socket *sock, sock->local_host = local_host; sock->local_port = local_port; - sock->preresolved_local = local_preresolved; sock->remote_host = remote_host; sock->remote_port = remote_port; - sock->preresolved_remote = remote_preresolved; + sock->preresolved = preresolved; #ifdef ENABLE_HTTP_PROXY sock->http_proxy = http_proxy; diff --git a/openvpn/src/openvpn/socket.h b/openvpn/src/openvpn/socket.h index 8a118cd1..7c0b040c 100644 --- a/openvpn/src/openvpn/socket.h +++ b/openvpn/src/openvpn/socket.h @@ -77,6 +77,16 @@ struct openvpn_sockaddr } addr; }; +/* struct to hold preresolved host names */ +struct preresovled_host { + const char *hostname; + const char *servname; + int ai_family; + int flags; + struct addrinfo *ai; + struct preresovled_host *next; +}; + /* actual address of remote, based on source address of received packets */ struct link_socket_actual { @@ -186,10 +196,9 @@ struct link_socket const char *remote_host; const char *remote_port; - struct addrinfo *preresolved_remote; const char *local_host; const char *local_port; - struct addrinfo *preresolved_local; + struct preresovled_host *preresolved; bool bind_local; # define INETD_NONE 0 @@ -308,10 +317,9 @@ void link_socket_init_phase1 (struct link_socket *sock, const char *local_host, const char *local_port, - struct addrinfo *local_preresolved, const char *remote_host, const char *remote_port, - struct addrinfo *remote_preresolved, + struct preresovled_host *preresolved, int proto, sa_family_t af, bool bind_ipv6_only, @@ -520,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_PRERESOLVE_MASK GETADDR_DATAGRAM|GETADDR_PASSIVE + in_addr_t getaddr (unsigned int flags, const char *hostname, int resolve_retry_seconds, -- cgit v1.2.3