diff --git a/net/openconnect/Makefile b/net/openconnect/Makefile index 2faa38cef..7fe2b91e3 100644 --- a/net/openconnect/Makefile +++ b/net/openconnect/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=openconnect PKG_VERSION:=7.00 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=ftp://ftp.infradead.org/pub/openconnect/ diff --git a/net/openconnect/patches/001-always-resolve-ips.patch b/net/openconnect/patches/001-always-resolve-ips.patch index 820ee2dff..809dd23db 100644 --- a/net/openconnect/patches/001-always-resolve-ips.patch +++ b/net/openconnect/patches/001-always-resolve-ips.patch @@ -1,161 +1,143 @@ +From 2f55fec323730a94ed49d401d93b913d85e43b65 Mon Sep 17 00:00:00 2001 +From: Nikos Mavrogiannopoulos +Date: Mon, 1 Dec 2014 20:10:06 +0100 +Subject: [PATCH 1/2] Re-resolve when reconnecting CSTP and the X-CSTP-DynDNS + is set by the server + +That is, when reconnecting CSTP due to peer tearing the connection +down attempt to re-resolve its IP. That handles the case where +the server is using dynamic DNS and is advertising it. + +[dwmw2: refactored to simplify it somewhat] + +Signed-off-by: Nikos Mavrogiannopoulos +Signed-off-by: David Woodhouse +--- + cstp.c | 3 +++ + openconnect-internal.h | 1 + + ssl.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- + 4 files changed, 52 insertions(+), 2 deletions(-) + diff --git a/cstp.c b/cstp.c -index b1235ef..f955b82 100644 +index 3b93538..55225f4 100644 --- a/cstp.c +++ b/cstp.c -@@ -570,7 +570,10 @@ int openconnect_make_cstp_connection(struct openconnect_info *vpninfo) - return ret; - } - --static int cstp_reconnect(struct openconnect_info *vpninfo) -+/* When dead peer is set, this function will re-attempt resolving -+ * the peer in case its IP changed. -+ */ -+static int cstp_reconnect(struct openconnect_info *vpninfo, unsigned dead_peer) - { - int ret; - int timeout; -@@ -591,6 +594,16 @@ static int cstp_reconnect(struct openconnect_info *vpninfo) - timeout = vpninfo->reconnect_timeout; - interval = vpninfo->reconnect_interval; - -+ /* handle cases with dynamic DNS by forcing a new resolve. -+ * The original IP is saved to retry as fallback if resolving -+ * fails. -+ */ -+ if (dead_peer && vpninfo->first_peer_addr == NULL) { -+ vpninfo->first_peer_addr = vpninfo->peer_addr; -+ vpninfo->first_peer_addrlen = vpninfo->peer_addrlen; -+ vpninfo->peer_addr = NULL; -+ } -+ - while ((ret = openconnect_make_cstp_connection(vpninfo))) { - if (timeout <= 0) - return ret; -@@ -611,6 +624,11 @@ static int cstp_reconnect(struct openconnect_info *vpninfo) - interval += vpninfo->reconnect_interval; - if (interval > RECONNECT_INTERVAL_MAX) - interval = RECONNECT_INTERVAL_MAX; -+ -+ if (dead_peer && vpninfo->first_peer_addr != NULL) { -+ free(vpninfo->peer_addr); -+ vpninfo->peer_addr = NULL; -+ } - } - script_config_tun(vpninfo, "reconnect"); - return 0; -@@ -903,8 +921,15 @@ int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout) - /* Not that this will ever happen; we don't even process - the setting when we're asked for it. */ - vpn_progress(vpninfo, PRG_INFO, _("CSTP rekey due\n")); -- if (vpninfo->ssl_times.rekey_method == REKEY_TUNNEL) -- goto do_reconnect; -+ if (vpninfo->ssl_times.rekey_method == REKEY_TUNNEL) { -+ ret = cstp_reconnect(vpninfo, 0); -+ if (ret) { -+ vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n")); -+ vpninfo->quit_reason = "CSTP reconnect failed"; -+ return ret; -+ } -+ goto do_dtls_reconnect; -+ } - else if (vpninfo->ssl_times.rekey_method == REKEY_SSL) { - ret = cstp_handshake(vpninfo, 0); - if (ret) { -@@ -922,7 +947,7 @@ int cstp_mainloop(struct openconnect_info *vpninfo, int *timeout) - vpn_progress(vpninfo, PRG_ERR, - _("CSTP Dead Peer Detection detected dead peer!\n")); - do_reconnect: -- ret = cstp_reconnect(vpninfo); -+ ret = cstp_reconnect(vpninfo, 1); - if (ret) { - vpn_progress(vpninfo, PRG_ERR, _("Reconnect failed\n")); - vpninfo->quit_reason = "CSTP reconnect failed"; -diff --git a/library.c b/library.c -index f5d3dc9..7c8d5ec 100644 ---- a/library.c -+++ b/library.c -@@ -178,6 +178,7 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo) - CloseHandle(vpninfo->dtls_event); - #endif - free(vpninfo->peer_addr); -+ free(vpninfo->first_peer_addr); - free_optlist(vpninfo->csd_env); - free_optlist(vpninfo->script_env); - free_optlist(vpninfo->cookies); -@@ -291,6 +292,8 @@ int openconnect_set_hostname(struct openconnect_info *vpninfo, - vpninfo->unique_hostname = NULL; - free(vpninfo->peer_addr); - vpninfo->peer_addr = NULL; -+ free(vpninfo->first_peer_addr); -+ vpninfo->first_peer_addr = NULL; - - return 0; - } +@@ -378,6 +378,9 @@ static int start_cstp_connection(struct openconnect_info *vpninfo) + int cstpmtu = atol(colon); + if (cstpmtu > mtu) + mtu = cstpmtu; ++ } else if (!strcmp(buf + 7, "DynDNS")) { ++ if (!strcmp(colon, "true")) ++ vpninfo->is_dyndns = 1; + } else if (!strcmp(buf + 7, "Address-IP6")) { + vpninfo->ip_info.netmask6 = new_option->value; + } else if (!strcmp(buf + 7, "Address")) { diff --git a/openconnect-internal.h b/openconnect-internal.h -index 1bc79e5..cafbb3c 100644 +index 1bc79e5..db6c2ba 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h -@@ -424,6 +424,9 @@ struct openconnect_info { - struct sockaddr *peer_addr; - struct sockaddr *dtls_addr; - -+ struct sockaddr *first_peer_addr; -+ socklen_t first_peer_addrlen; -+ +@@ -427,6 +427,7 @@ struct openconnect_info { int dtls_local_port; int deflate; ++ int is_dyndns; /* Attempt to redo DNS lookup on each CSTP reconnect */ + char *useragent; + + const char *quit_reason; diff --git a/ssl.c b/ssl.c -index b50652d..e341871 100644 +index b50652d..d47a819 100644 --- a/ssl.c +++ b/ssl.c -@@ -110,6 +110,7 @@ int connect_https_socket(struct openconnect_info *vpninfo) +@@ -106,6 +106,23 @@ unsigned string_is_hostname(const char *str) + return 1; + } + ++static int match_sockaddr(struct sockaddr *a, struct sockaddr *b) ++{ ++ if (a->sa_family == AF_INET) { ++ struct sockaddr_in *a4 = (void *)a; ++ struct sockaddr_in *b4 = (void *)b; ++ ++ return (a4->sin_addr.s_addr == b4->sin_addr.s_addr) && ++ (a4->sin_port == b4->sin_port); ++ } else if (a->sa_family == AF_INET6) { ++ struct sockaddr_in6 *a6 = (void *)a; ++ struct sockaddr_in6 *b6 = (void *)b; ++ return !memcmp(&a6->sin6_addr, &b6->sin6_addr, sizeof(a6->sin6_addr) && ++ a6->sin6_port == b6->sin6_port); ++ } else ++ return 0; ++} ++ + int connect_https_socket(struct openconnect_info *vpninfo) { int ssl_sock = -1; - int err; -+ unsigned retry_old_ip = 0; - +@@ -114,7 +131,11 @@ int connect_https_socket(struct openconnect_info *vpninfo) if (!vpninfo->port) vpninfo->port = 443; -@@ -230,6 +231,8 @@ int connect_https_socket(struct openconnect_info *vpninfo) + +- if (vpninfo->peer_addr) { ++ /* If we're talking to a server which told us it has dynamic DNS, don't ++ just re-use its previous IP address. If we're talking to a proxy, we ++ can use *its* previous IP address. We expect it'll re-do the DNS ++ lookup for the server anyway. */ ++ if (vpninfo->peer_addr && (!vpninfo->is_dyndns || vpninfo->proxy)) { + reconnect: + #ifdef SOCK_CLOEXEC + ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_IP); +@@ -230,6 +251,13 @@ int connect_https_socket(struct openconnect_info *vpninfo) if (hints.ai_flags & AI_NUMERICHOST) free(hostname); ssl_sock = -EINVAL; -+ if (vpninfo->first_peer_addr != NULL) -+ retry_old_ip = 1; ++ /* If we were just retrying for dynamic DNS, reconnct using ++ the previously-known IP address */ ++ if (vpninfo->peer_addr) { ++ vpn_progress(vpninfo, PRG_ERR, ++ _("Reconnecting to DynDNS server using previously cached IP address\n")); ++ goto reconnect; ++ } goto out; } if (hints.ai_flags & AI_NUMERICHOST) -@@ -291,7 +294,10 @@ int connect_https_socket(struct openconnect_info *vpninfo) +@@ -257,6 +285,8 @@ int connect_https_socket(struct openconnect_info *vpninfo) + if (cancellable_connect(vpninfo, ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) { + /* Store the peer address we actually used, so that DTLS can + use it again later */ ++ free(vpninfo->peer_addr); ++ vpninfo->peer_addrlen = 0; + vpninfo->peer_addr = malloc(rp->ai_addrlen); + if (!vpninfo->peer_addr) { + vpn_progress(vpninfo, PRG_ERR, +@@ -288,6 +318,17 @@ int connect_https_socket(struct openconnect_info *vpninfo) + } + closesocket(ssl_sock); + ssl_sock = -1; ++ ++ /* If we're in DynDNS mode but this *was* the cached IP address, ++ * don't bother falling back to it if it didn't work. */ ++ if (vpninfo->peer_addr && vpninfo->peer_addrlen == rp->ai_addrlen && ++ match_sockaddr(vpninfo->peer_addr, rp->ai_addr)) { ++ vpn_progress(vpninfo, PRG_TRACE, ++ _("Forgetting non-functional previous peer address\n")); ++ free(vpninfo->peer_addr); ++ vpninfo->peer_addr = 0; ++ vpninfo->peer_addrlen = 0; ++ } } freeaddrinfo(result); -+ - if (ssl_sock < 0) { -+ if (vpninfo->first_peer_addr != NULL) -+ retry_old_ip = 1; - vpn_progress(vpninfo, PRG_ERR, +@@ -296,6 +337,11 @@ int connect_https_socket(struct openconnect_info *vpninfo) _("Failed to connect to host %s\n"), vpninfo->proxy?:vpninfo->hostname); -@@ -314,6 +320,21 @@ int connect_https_socket(struct openconnect_info *vpninfo) + ssl_sock = -EINVAL; ++ if (vpninfo->peer_addr) { ++ vpn_progress(vpninfo, PRG_ERR, ++ _("Reconnecting to DynDNS server using previously cached IP address\n")); ++ goto reconnect; ++ } + goto out; } } - out: -+ if (retry_old_ip != 0 && vpninfo->first_peer_addr != NULL) { -+ vpn_progress(vpninfo, PRG_ERR, -+ _("Retrying connection to host %s with original IP\n"), -+ vpninfo->proxy?:vpninfo->hostname); -+ -+ retry_old_ip = 0; -+ if (vpninfo->first_peer_addrlen > vpninfo->peer_addrlen || vpninfo->peer_addr == NULL) -+ realloc_inplace(vpninfo->peer_addr, vpninfo->first_peer_addrlen); -+ -+ if (vpninfo->peer_addr != NULL) { -+ memcpy(vpninfo->peer_addr, vpninfo->first_peer_addr, vpninfo->first_peer_addrlen); -+ goto reconnect; -+ } -+ } -+ - /* If proxy processing returned -EAGAIN to reconnect before attempting - further auth, and we failed to reconnect, we have to clean up here. */ - cleanup_proxy_auth(vpninfo); +-- +2.1.3 +