You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.9 KiB

  1. From 2f55fec323730a94ed49d401d93b913d85e43b65 Mon Sep 17 00:00:00 2001
  2. From: Nikos Mavrogiannopoulos <nmav@gnutls.org>
  3. Date: Mon, 1 Dec 2014 20:10:06 +0100
  4. Subject: [PATCH 1/2] Re-resolve when reconnecting CSTP and the X-CSTP-DynDNS
  5. is set by the server
  6. That is, when reconnecting CSTP due to peer tearing the connection
  7. down attempt to re-resolve its IP. That handles the case where
  8. the server is using dynamic DNS and is advertising it.
  9. [dwmw2: refactored to simplify it somewhat]
  10. Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
  11. Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
  12. ---
  13. cstp.c | 3 +++
  14. openconnect-internal.h | 1 +
  15. ssl.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
  16. 4 files changed, 52 insertions(+), 2 deletions(-)
  17. diff --git a/cstp.c b/cstp.c
  18. index 3b93538..55225f4 100644
  19. --- a/cstp.c
  20. +++ b/cstp.c
  21. @@ -378,6 +378,9 @@ static int start_cstp_connection(struct openconnect_info *vpninfo)
  22. int cstpmtu = atol(colon);
  23. if (cstpmtu > mtu)
  24. mtu = cstpmtu;
  25. + } else if (!strcmp(buf + 7, "DynDNS")) {
  26. + if (!strcmp(colon, "true"))
  27. + vpninfo->is_dyndns = 1;
  28. } else if (!strcmp(buf + 7, "Address-IP6")) {
  29. vpninfo->ip_info.netmask6 = new_option->value;
  30. } else if (!strcmp(buf + 7, "Address")) {
  31. diff --git a/openconnect-internal.h b/openconnect-internal.h
  32. index 1bc79e5..db6c2ba 100644
  33. --- a/openconnect-internal.h
  34. +++ b/openconnect-internal.h
  35. @@ -427,6 +427,7 @@ struct openconnect_info {
  36. int dtls_local_port;
  37. int deflate;
  38. + int is_dyndns; /* Attempt to redo DNS lookup on each CSTP reconnect */
  39. char *useragent;
  40. const char *quit_reason;
  41. diff --git a/ssl.c b/ssl.c
  42. index b50652d..d47a819 100644
  43. --- a/ssl.c
  44. +++ b/ssl.c
  45. @@ -106,6 +106,23 @@ unsigned string_is_hostname(const char *str)
  46. return 1;
  47. }
  48. +static int match_sockaddr(struct sockaddr *a, struct sockaddr *b)
  49. +{
  50. + if (a->sa_family == AF_INET) {
  51. + struct sockaddr_in *a4 = (void *)a;
  52. + struct sockaddr_in *b4 = (void *)b;
  53. +
  54. + return (a4->sin_addr.s_addr == b4->sin_addr.s_addr) &&
  55. + (a4->sin_port == b4->sin_port);
  56. + } else if (a->sa_family == AF_INET6) {
  57. + struct sockaddr_in6 *a6 = (void *)a;
  58. + struct sockaddr_in6 *b6 = (void *)b;
  59. + return !memcmp(&a6->sin6_addr, &b6->sin6_addr, sizeof(a6->sin6_addr) &&
  60. + a6->sin6_port == b6->sin6_port);
  61. + } else
  62. + return 0;
  63. +}
  64. +
  65. int connect_https_socket(struct openconnect_info *vpninfo)
  66. {
  67. int ssl_sock = -1;
  68. @@ -114,7 +131,11 @@ int connect_https_socket(struct openconnect_info *vpninfo)
  69. if (!vpninfo->port)
  70. vpninfo->port = 443;
  71. - if (vpninfo->peer_addr) {
  72. + /* If we're talking to a server which told us it has dynamic DNS, don't
  73. + just re-use its previous IP address. If we're talking to a proxy, we
  74. + can use *its* previous IP address. We expect it'll re-do the DNS
  75. + lookup for the server anyway. */
  76. + if (vpninfo->peer_addr && (!vpninfo->is_dyndns || vpninfo->proxy)) {
  77. reconnect:
  78. #ifdef SOCK_CLOEXEC
  79. ssl_sock = socket(vpninfo->peer_addr->sa_family, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_IP);
  80. @@ -230,6 +251,13 @@ int connect_https_socket(struct openconnect_info *vpninfo)
  81. if (hints.ai_flags & AI_NUMERICHOST)
  82. free(hostname);
  83. ssl_sock = -EINVAL;
  84. + /* If we were just retrying for dynamic DNS, reconnct using
  85. + the previously-known IP address */
  86. + if (vpninfo->peer_addr) {
  87. + vpn_progress(vpninfo, PRG_ERR,
  88. + _("Reconnecting to DynDNS server using previously cached IP address\n"));
  89. + goto reconnect;
  90. + }
  91. goto out;
  92. }
  93. if (hints.ai_flags & AI_NUMERICHOST)
  94. @@ -257,6 +285,8 @@ int connect_https_socket(struct openconnect_info *vpninfo)
  95. if (cancellable_connect(vpninfo, ssl_sock, rp->ai_addr, rp->ai_addrlen) >= 0) {
  96. /* Store the peer address we actually used, so that DTLS can
  97. use it again later */
  98. + free(vpninfo->peer_addr);
  99. + vpninfo->peer_addrlen = 0;
  100. vpninfo->peer_addr = malloc(rp->ai_addrlen);
  101. if (!vpninfo->peer_addr) {
  102. vpn_progress(vpninfo, PRG_ERR,
  103. @@ -288,6 +318,17 @@ int connect_https_socket(struct openconnect_info *vpninfo)
  104. }
  105. closesocket(ssl_sock);
  106. ssl_sock = -1;
  107. +
  108. + /* If we're in DynDNS mode but this *was* the cached IP address,
  109. + * don't bother falling back to it if it didn't work. */
  110. + if (vpninfo->peer_addr && vpninfo->peer_addrlen == rp->ai_addrlen &&
  111. + match_sockaddr(vpninfo->peer_addr, rp->ai_addr)) {
  112. + vpn_progress(vpninfo, PRG_TRACE,
  113. + _("Forgetting non-functional previous peer address\n"));
  114. + free(vpninfo->peer_addr);
  115. + vpninfo->peer_addr = 0;
  116. + vpninfo->peer_addrlen = 0;
  117. + }
  118. }
  119. freeaddrinfo(result);
  120. @@ -296,6 +337,11 @@ int connect_https_socket(struct openconnect_info *vpninfo)
  121. _("Failed to connect to host %s\n"),
  122. vpninfo->proxy?:vpninfo->hostname);
  123. ssl_sock = -EINVAL;
  124. + if (vpninfo->peer_addr) {
  125. + vpn_progress(vpninfo, PRG_ERR,
  126. + _("Reconnecting to DynDNS server using previously cached IP address\n"));
  127. + goto reconnect;
  128. + }
  129. goto out;
  130. }
  131. }
  132. --
  133. 2.1.3