I did not test your patch, though I assume it would work, because I
did not want to reinforce the idea that the VPN gateway is doing
something wrong. Instead, I continued my own investigation.

It turns out that in gnutls 3.5.8, gnutls_dtls_get_data_mtu() does not
return the same value that was passed to  gnutls_dtls_set_data_mtu():

Trying to set DTLS MTU to 1301
DTLS MTU (data) is 1291
Trying to set DTLS MTU to 1302
DTLS MTU (data) is 1307

I assume this is because when gnutls_dtls_get_data_mtu tries to
recover the data mtu from the internal mtu, it calculates the overhead
based on the currently set internal mtu, not the originally requested
data mtu. If the padding for those sizes is different, the wrong
result will be returned.
I guess the next step is to try to report this to gnutls, if anyone
agrees with my interpretation of the issue.

I think that openconnect should try to detect over-large incoming DTLS
packets and log or discard them.
It might also be nice to detect truncated IP packets, but that would
involve introspection into the tunneled IP packets that it doesn't
have to do now.
--- a/gnutls-dtls.c
+++ b/gnutls-dtls.c
@@ -313,6 +313,7 @@
 int dtls_try_handshake(struct openconnect_info *vpninfo)
 {
 	int err = gnutls_handshake(vpninfo->dtls_ssl);
+	int mtu, newmtu=0;
 	char *str;
 
 	if (!err) {
@@ -355,14 +356,43 @@
 			}
 
 #ifdef HAVE_GNUTLS_DTLS_SET_DATA_MTU
+			mtu = gnutls_dtls_get_data_mtu(vpninfo->dtls_ssl);
+			if (mtu == 0) {
+			  vpn_progress(vpninfo, PRG_INFO,
+				       _("Failed to get active DTLS MTU\n"));
+			} else {
+			  vpn_progress(vpninfo, PRG_INFO,
+				       _("Initial DTLS MTU (data) is %d\n"),
+				       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->dtls_ssl, vpninfo->ip_info.mtu + 1);
-			if (err) {
-				vpn_progress(vpninfo, PRG_ERR,
-					     _("Failed to set DTLS MTU: %s\n"),
-					     gnutls_strerror(err));
-				goto error;
+			while (mtu < vpninfo->ip_info.mtu + 1) {
+			  if (newmtu == 0) {
+			    newmtu = vpninfo->ip_info.mtu + 1;
+			  } else {
+			    newmtu++;
+			  }
+			  vpn_progress(vpninfo, PRG_INFO,
+				       _("Trying to set DTLS MTU to %d\n"),
+					 newmtu);
+			  err = gnutls_dtls_set_data_mtu(vpninfo->dtls_ssl, newmtu);
+			  if (err) {
+			    vpn_progress(vpninfo, PRG_ERR,
+					 _("Failed to set DTLS MTU: %s\n"),
+					 gnutls_strerror(err));
+			    goto error;
+			  }
+			  mtu = gnutls_dtls_get_data_mtu(vpninfo->dtls_ssl);
+			  if (mtu == 0) {
+			    vpn_progress(vpninfo, PRG_INFO,
+					 _("Failed to get active DTLS MTU\n"));
+			    break;
+			  } else {
+			    vpn_progress(vpninfo, PRG_INFO,
+					 _("DTLS MTU (data) is %d\n"),
+					 mtu);
+			  }
 			}
 #else
 			/* If we don't have gnutls_dtls_set_data_mtu() then make sure
_______________________________________________
openconnect-devel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/openconnect-devel

Reply via email to