resetting manifest requested domain to floor
[platform/upstream/openconnect.git] / dtls.c
diff --git a/dtls.c b/dtls.c
index 9739b87..9c21a3f 100644 (file)
--- a/dtls.c
+++ b/dtls.c
@@ -378,8 +378,6 @@ static int start_dtls_handshake(struct openconnect_info *vpninfo, int dtls_fd)
                vpninfo->dtls_attempt_period = 0;
                return -EINVAL;
        }
-       /* +1 for packet header, +13 for DTLS overhead */
-       gnutls_dtls_set_mtu(dtls_ssl, vpninfo->mtu + 14);
        gnutls_transport_set_ptr(dtls_ssl,
                                 (gnutls_transport_ptr_t)(long) dtls_fd);
        gnutls_record_disable_padding(dtls_ssl);
@@ -409,6 +407,29 @@ int dtls_try_handshake(struct openconnect_info *vpninfo)
        int err = gnutls_handshake(vpninfo->new_dtls_ssl);
 
        if (!err) {
+#ifdef HAVE_GNUTLS_DTLS_SET_DATA_MTU
+               /* Make sure GnuTLS's idea of the MTU is sufficient to take
+                  a full VPN MTU (with 1-byte header) in a data record. */
+               err = gnutls_dtls_set_data_mtu(vpninfo->new_dtls_ssl, vpninfo->actual_mtu + 1);
+               if (err) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("Failed to set DTLS MTU: %s\n"),
+                                    gnutls_strerror(err));
+                       goto error;
+               }
+#else
+               /* If we don't have gnutls_dtls_set_data_mtu() then make sure
+                  we leave enough headroom by adding the worst-case overhead.
+                  We only support AES128-CBC and DES-CBC3-SHA anyway, so
+                  working out the worst case isn't hard. */
+               gnutls_dtls_set_mtu(vpninfo->new_dtls_ssl,
+                                   vpninfo->actual_mtu + 1 /* packet + header */
+                                   + 13 /* DTLS header */
+                                   + 20 /* biggest supported MAC (SHA1) */
+                                   + 16 /* biggest supported IV (AES-128) */
+                                   + 16 /* max padding */);
+#endif
+
                vpn_progress(vpninfo, PRG_INFO, _("Established DTLS connection (using GnuTLS)\n"));
 
                if (vpninfo->dtls_ssl) {
@@ -440,6 +461,8 @@ int dtls_try_handshake(struct openconnect_info *vpninfo)
        vpn_progress(vpninfo, PRG_ERR, _("DTLS handshake failed: %s\n"),
                     gnutls_strerror(err));
 
+       goto error;
+ error:
        /* Kill the new (failed) connection... */
        gnutls_deinit(vpninfo->new_dtls_ssl);
        FD_CLR(vpninfo->new_dtls_fd, &vpninfo->select_rfds);
@@ -497,18 +520,21 @@ int connect_dtls_socket(struct openconnect_info *vpninfo)
        }
 
        if (vpninfo->dtls_local_port) {
-               struct sockaddr_storage dtls_bind_addr;
+               union {
+                       struct sockaddr_in in;
+                       struct sockaddr_in6 in6;
+               } dtls_bind_addr;
                int dtls_bind_addrlen;
                memset(&dtls_bind_addr, 0, sizeof(dtls_bind_addr));
 
                if (vpninfo->peer_addr->sa_family == AF_INET) {
-                       struct sockaddr_in *addr = (struct sockaddr_in *)&dtls_bind_addr;
+                       struct sockaddr_in *addr = &dtls_bind_addr.in;
                        dtls_bind_addrlen = sizeof(*addr);
                        addr->sin_family = AF_INET;
                        addr->sin_addr.s_addr = INADDR_ANY;
                        addr->sin_port = htons(vpninfo->dtls_local_port);
                } else if (vpninfo->peer_addr->sa_family == AF_INET6) {
-                       struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&dtls_bind_addr;
+                       struct sockaddr_in6 *addr = &dtls_bind_addr.in6;
                        dtls_bind_addrlen = sizeof(*addr);
                        addr->sin6_family = AF_INET6;
                        addr->sin6_addr = in6addr_any;
@@ -518,11 +544,13 @@ int connect_dtls_socket(struct openconnect_info *vpninfo)
                                     _("Unknown protocol family %d. Cannot do DTLS\n"),
                                     vpninfo->peer_addr->sa_family);
                        vpninfo->dtls_attempt_period = 0;
+                       close(dtls_fd);
                        return -EINVAL;
                }
 
                if (bind(dtls_fd, (struct sockaddr *)&dtls_bind_addr, dtls_bind_addrlen)) {
                        perror(_("Bind UDP socket for DTLS"));
+                       close(dtls_fd);
                        return -EINVAL;
                }
        }
@@ -653,7 +681,7 @@ int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout)
        char magic_pkt;
 
        while (1) {
-               int len = vpninfo->mtu;
+               int len = vpninfo->actual_mtu;
                unsigned char *buf;
 
                if (!dtls_pkt) {