openconnect: added upstream patch for dynamic IPs
That requires an update to ocserv as well to advertise them.
This commit is contained in:
parent
5b9977c6a7
commit
9ea507c3ab
2 changed files with 115 additions and 133 deletions
|
@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
||||||
|
|
||||||
PKG_NAME:=openconnect
|
PKG_NAME:=openconnect
|
||||||
PKG_VERSION:=7.00
|
PKG_VERSION:=7.00
|
||||||
PKG_RELEASE:=2
|
PKG_RELEASE:=3
|
||||||
|
|
||||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||||
PKG_SOURCE_URL:=ftp://ftp.infradead.org/pub/openconnect/
|
PKG_SOURCE_URL:=ftp://ftp.infradead.org/pub/openconnect/
|
||||||
|
|
|
@ -1,161 +1,143 @@
|
||||||
|
From 2f55fec323730a94ed49d401d93b913d85e43b65 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Nikos Mavrogiannopoulos <nmav@gnutls.org>
|
||||||
|
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 <nmav@gnutls.org>
|
||||||
|
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
|
||||||
|
---
|
||||||
|
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
|
diff --git a/cstp.c b/cstp.c
|
||||||
index b1235ef..f955b82 100644
|
index 3b93538..55225f4 100644
|
||||||
--- a/cstp.c
|
--- a/cstp.c
|
||||||
+++ b/cstp.c
|
+++ b/cstp.c
|
||||||
@@ -570,7 +570,10 @@ int openconnect_make_cstp_connection(struct openconnect_info *vpninfo)
|
@@ -378,6 +378,9 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
|
||||||
return ret;
|
int cstpmtu = atol(colon);
|
||||||
}
|
if (cstpmtu > mtu)
|
||||||
|
mtu = cstpmtu;
|
||||||
-static int cstp_reconnect(struct openconnect_info *vpninfo)
|
+ } else if (!strcmp(buf + 7, "DynDNS")) {
|
||||||
+/* When dead peer is set, this function will re-attempt resolving
|
+ if (!strcmp(colon, "true"))
|
||||||
+ * the peer in case its IP changed.
|
+ vpninfo->is_dyndns = 1;
|
||||||
+ */
|
} else if (!strcmp(buf + 7, "Address-IP6")) {
|
||||||
+static int cstp_reconnect(struct openconnect_info *vpninfo, unsigned dead_peer)
|
vpninfo->ip_info.netmask6 = new_option->value;
|
||||||
{
|
} else if (!strcmp(buf + 7, "Address")) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
diff --git a/openconnect-internal.h b/openconnect-internal.h
|
diff --git a/openconnect-internal.h b/openconnect-internal.h
|
||||||
index 1bc79e5..cafbb3c 100644
|
index 1bc79e5..db6c2ba 100644
|
||||||
--- a/openconnect-internal.h
|
--- a/openconnect-internal.h
|
||||||
+++ b/openconnect-internal.h
|
+++ b/openconnect-internal.h
|
||||||
@@ -424,6 +424,9 @@ struct openconnect_info {
|
@@ -427,6 +427,7 @@ 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 dtls_local_port;
|
||||||
|
|
||||||
int deflate;
|
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
|
diff --git a/ssl.c b/ssl.c
|
||||||
index b50652d..e341871 100644
|
index b50652d..d47a819 100644
|
||||||
--- a/ssl.c
|
--- a/ssl.c
|
||||||
+++ b/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 ssl_sock = -1;
|
||||||
int err;
|
@@ -114,7 +131,11 @@ int connect_https_socket(struct openconnect_info *vpninfo)
|
||||||
+ unsigned retry_old_ip = 0;
|
|
||||||
|
|
||||||
if (!vpninfo->port)
|
if (!vpninfo->port)
|
||||||
vpninfo->port = 443;
|
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)
|
if (hints.ai_flags & AI_NUMERICHOST)
|
||||||
free(hostname);
|
free(hostname);
|
||||||
ssl_sock = -EINVAL;
|
ssl_sock = -EINVAL;
|
||||||
+ if (vpninfo->first_peer_addr != NULL)
|
+ /* If we were just retrying for dynamic DNS, reconnct using
|
||||||
+ retry_old_ip = 1;
|
+ 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;
|
goto out;
|
||||||
}
|
}
|
||||||
if (hints.ai_flags & AI_NUMERICHOST)
|
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);
|
freeaddrinfo(result);
|
||||||
|
|
||||||
+
|
@@ -296,6 +337,11 @@ int connect_https_socket(struct openconnect_info *vpninfo)
|
||||||
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"),
|
_("Failed to connect to host %s\n"),
|
||||||
vpninfo->proxy?:vpninfo->hostname);
|
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) {
|
2.1.3
|
||||||
+ 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);
|
|
||||||
|
|
Loading…
Reference in a new issue