openconnect: added upstream patch for dynamic IPs
authorNikos Mavrogiannopoulos <redacted>
Fri, 5 Dec 2014 19:00:13 +0000 (20:00 +0100)
committerNikos Mavrogiannopoulos <redacted>
Fri, 5 Dec 2014 19:01:32 +0000 (20:01 +0100)
That requires an update to ocserv as well to advertise them.

net/openconnect/Makefile
net/openconnect/patches/001-always-resolve-ips.patch

index 2faa38cef5ace5f9d524d9295c0f760241a277ec..7fe2b91e334ea2e22f2b680f4b426b6c4ec226da 100644 (file)
@@ -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/
index 820ee2dff3e40197dfa3700ee186b7ef11d4289a..809dd23db8886ca06c6cdf5278bb733f0f65bd0b 100644 (file)
+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
-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
+
git clone https://git.99rst.org/PROJECT