From e2c36e363595f90ecb8b97aea82c41489411094b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 8 Jun 2012 14:25:15 +0100 Subject: [PATCH] Set X-CSTP-Base-MTU: for new servers Signed-off-by: David Woodhouse --- cstp.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++- main.c | 12 ++++++++- openconnect-internal.h | 2 +- openconnect.8.in | 10 +++++++- 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/cstp.c b/cstp.c index dbc24b9..0e9e6c1 100644 --- a/cstp.c +++ b/cstp.c @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include #include #include @@ -86,6 +89,64 @@ static int __attribute__ ((format (printf, 3, 4))) return ret; } +/* Calculate MTU to request. Old servers simply use the X-CSTP-MTU: header, + * which represents the tunnel MTU, while new servers do calculations on the + * X-CSTP-Base-MTU: header which represents the cleartext MTU between client + * and server. + * + * If possible, the legacy MTU value should be the TCP MSS less 5 bytes of + * TLS and 8 bytes of CSTP overhead. We can get the MSS from either the + * TCP_INFO or TCP_MAXSEG sockopts. + * + * The base MTU comes from the TCP_INFO sockopt under Linux, but I don't know + * how to work it out on other systems. So leave it blank and do things the + * legacy way there. Contributions welcome... + * + * If we don't even have TCP_MAXSEG, then default to sending a legacy MTU of + * 1406 which is what we always used to do. + */ +static void calculate_mtu(struct openconnect_info *vpninfo, int *base_mtu, int *mtu) +{ + *mtu = vpninfo->mtu; + *base_mtu = vpninfo->basemtu; + +#ifdef TCP_INFO + if (!*mtu || !*base_mtu) { + struct tcp_info ti; + socklen_t ti_size = sizeof(ti); + + if (!getsockopt(vpninfo->ssl_fd, SOL_TCP, TCP_INFO, + &ti, &ti_size)) { + vpn_progress(vpninfo, PRG_TRACE, + _("TCP_INFO rcv mss %d, snd mss %d, adv mss %d, pmtu %d\n"), + ti.tcpi_rcv_mss, ti.tcpi_snd_mss, ti.tcpi_advmss, ti.tcpi_pmtu); + if (!*base_mtu) *base_mtu = ti.tcpi_pmtu; + if (!*mtu) { + if (ti.tcpi_rcv_mss < ti.tcpi_snd_mss) + *mtu = ti.tcpi_rcv_mss - 13; + else + *mtu = ti.tcpi_snd_mss - 13; + } + } + } +#endif +#ifdef TCP_MAXSEG + if (!*mtu) { + int mss; + socklen_t mss_size = sizeof(mss); + if (!getsockopt(vpninfo->ssl_fd, SOL_TCP, TCP_MAXSEG, + &mss, &mss_size)) { + vpn_progress(vpninfo, PRG_TRACE, _("TCP_MAXSEG %d\n"), mss); + *mtu = mss - 13; + } + } +#endif + if (!*mtu) { + /* Default */ + *mtu = 1406; + } +} + static int start_cstp_connection(struct openconnect_info *vpninfo) { char buf[65536]; @@ -100,6 +161,7 @@ static int start_cstp_connection(struct openconnect_info *vpninfo) const char *old_addr6 = vpninfo->vpn_addr6; const char *old_netmask6 = vpninfo->vpn_netmask6; struct split_include *inc; + int base_mtu, mtu; /* Clear old options which will be overwritten */ vpninfo->vpn_addr = vpninfo->vpn_netmask = NULL; @@ -132,6 +194,8 @@ static int start_cstp_connection(struct openconnect_info *vpninfo) } retry: + calculate_mtu(vpninfo, &base_mtu, &mtu); + buf[0] = 0; buf_append(buf, sizeof(buf), "CONNECT /CSCOSSLC/tunnel HTTP/1.1\r\n"); buf_append(buf, sizeof(buf), "Host: %s\r\n", vpninfo->hostname); @@ -141,7 +205,9 @@ static int start_cstp_connection(struct openconnect_info *vpninfo) buf_append(buf, sizeof(buf), "X-CSTP-Hostname: %s\r\n", vpninfo->localname); if (vpninfo->deflate && i < sizeof(buf)) buf_append(buf, sizeof(buf), "X-CSTP-Accept-Encoding: deflate;q=1.0\r\n"); - buf_append(buf, sizeof(buf), "X-CSTP-MTU: %d\r\n", vpninfo->mtu); + if (base_mtu) + buf_append(buf, sizeof(buf), "X-CSTP-Base-MTU: %d\r\n", base_mtu); + buf_append(buf, sizeof(buf), "X-CSTP-MTU: %d\r\n", mtu); buf_append(buf, sizeof(buf), "X-CSTP-Address-Type: %s\r\n", vpninfo->disable_ipv6?"IPv4":"IPv6,IPv4"); buf_append(buf, sizeof(buf), "X-DTLS-Master-Secret: "); diff --git a/main.c b/main.c index 6f7f86c..fa03558 100644 --- a/main.c +++ b/main.c @@ -82,6 +82,7 @@ int non_inter; enum { OPT_AUTHGROUP = 0x100, + OPT_BASEMTU, OPT_CAFILE, OPT_CONFIGFILE, OPT_COOKIEONLY, @@ -130,6 +131,7 @@ static struct option long_options[] = { OPTION("help", 0, 'h'), OPTION("interface", 1, 'i'), OPTION("mtu", 1, 'm'), + OPTION("base-mtu", 1, OPT_BASEMTU), OPTION("setuid", 1, 'U'), OPTION("script", 1, 's'), OPTION("script-tun", 0, 'S'), @@ -199,6 +201,7 @@ static void usage(void) printf(" --csd-user=USER %s\n", _("Drop privileges during CSD execution")); printf(" --csd-wrapper=SCRIPT %s\n", _("Run SCRIPT instead of CSD binary")); printf(" -m, --mtu=MTU %s\n", _("Request MTU from server")); + printf(" --base-mtu=MTU %s\n", _("Indicate path MTU to/from server")); printf(" -p, --key-password=PASS %s\n", _("Set key passphrase or TPM SRK PIN")); printf(" --key-password-from-fsid %s\n", _("Key passphrase is fsid of file system")); printf(" -P, --proxy=URL %s\n", _("Set proxy server")); @@ -412,7 +415,7 @@ int main(int argc, char **argv) /* Set up some defaults */ vpninfo->tun_fd = vpninfo->ssl_fd = vpninfo->dtls_fd = vpninfo->new_dtls_fd = -1; vpninfo->useragent = openconnect_create_useragent("Open AnyConnect VPN Agent"); - vpninfo->mtu = 1406; + vpninfo->mtu = 0; vpninfo->deflate = 1; vpninfo->dtls_attempt_period = 60; vpninfo->max_qlen = 10; @@ -548,6 +551,13 @@ int main(int argc, char **argv) vpninfo->mtu = 576; } break; + case OPT_BASEMTU: + vpninfo->basemtu = atol(config_arg); + if (vpninfo->basemtu < 576) { + fprintf(stderr, _("MTU %d too small\n"), vpninfo->basemtu); + vpninfo->basemtu = 576; + } + break; case 'p': vpninfo->cert_password = strdup(config_arg); break; diff --git a/openconnect-internal.h b/openconnect-internal.h index 0235c33..340fc6c 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -199,7 +199,7 @@ struct openconnect_info { int script_tun; char *ifname; - int mtu; + int mtu, basemtu; const char *banner; const char *vpn_addr; const char *vpn_netmask; diff --git a/openconnect.8.in b/openconnect.8.in index 97b183e..0902556 100644 --- a/openconnect.8.in +++ b/openconnect.8.in @@ -22,6 +22,7 @@ openconnect \- Connect to Cisco AnyConnect VPN .OP \-U,\-\-setuid user .OP \-\-csd\-user user .OP \-m,\-\-mtu mtu +.OP \-\-basemtu mtu .OP \-p,\-\-key\-password pass .OP \-P,\-\-proxy proxyurl .OP \-\-no\-proxy @@ -159,7 +160,14 @@ instead of the CSD (Cisco Secure Desktop) script. .B \-m,\-\-mtu=MTU Request .I MTU -from server +from server as the MTU of the tunnel. +.TP +.B \-\-basemtu=MTU +Indicate +.I MTU +as the path MTU between client and server on the unencrypted network. Newer +servers will automatically calculate the MTU to be used on the tunnel from +this value. .TP .B \-p,\-\-key\-password=PASS Provide passphrase for certificate file, or SRK (System Root Key) PIN for TPM -- 2.7.4