From be753f0208b7b517022bacbaf7a6cee2213ae95d Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sat, 29 Nov 2014 18:52:44 +0100 Subject: [PATCH] openconnect: made server IP resolving on reconnection conditional Signed-off-by: Nikos Mavrogiannopoulos --- net/openconnect/Makefile | 2 +- .../patches/001-always-resolve-ips.patch | 153 +++++++++++++++++- 2 files changed, 147 insertions(+), 8 deletions(-) diff --git a/net/openconnect/Makefile b/net/openconnect/Makefile index 79639af2e..2faa38cef 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:=1 +PKG_RELEASE:=2 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 d262ca0fa..820ee2dff 100644 --- a/net/openconnect/patches/001-always-resolve-ips.patch +++ b/net/openconnect/patches/001-always-resolve-ips.patch @@ -1,22 +1,161 @@ diff --git a/cstp.c b/cstp.c -index b1235ef..05c3444 100644 +index b1235ef..f955b82 100644 --- a/cstp.c +++ b/cstp.c -@@ -591,6 +591,8 @@ static int cstp_reconnect(struct openconnect_info *vpninfo) +@@ -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; -+ free(vpninfo->peer_addr); -+ vpninfo->peer_addr = NULL; ++ /* 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 +613,8 @@ static int cstp_reconnect(struct openconnect_info *vpninfo) +@@ -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; -+ free(vpninfo->peer_addr); -+ vpninfo->peer_addr = NULL; ++ ++ 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; + } +diff --git a/openconnect-internal.h b/openconnect-internal.h +index 1bc79e5..cafbb3c 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; ++ + int dtls_local_port; + + int deflate; +diff --git a/ssl.c b/ssl.c +index b50652d..e341871 100644 +--- a/ssl.c ++++ b/ssl.c +@@ -110,6 +110,7 @@ int connect_https_socket(struct openconnect_info *vpninfo) + { + int ssl_sock = -1; + int err; ++ unsigned retry_old_ip = 0; + + if (!vpninfo->port) + vpninfo->port = 443; +@@ -230,6 +231,8 @@ 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; + goto out; + } + if (hints.ai_flags & AI_NUMERICHOST) +@@ -291,7 +294,10 @@ int connect_https_socket(struct openconnect_info *vpninfo) + } + freeaddrinfo(result); + ++ + if (ssl_sock < 0) { ++ if (vpninfo->first_peer_addr != NULL) ++ retry_old_ip = 1; + vpn_progress(vpninfo, PRG_ERR, + _("Failed to connect to host %s\n"), + vpninfo->proxy?:vpninfo->hostname); +@@ -314,6 +320,21 @@ int connect_https_socket(struct openconnect_info *vpninfo) + } + } + 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);