]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
attempt to coax server to accept a larger MRU by nak-offering our MTU if it's greater...
authorDaniel Lenski <dlenski@gmail.com>
Sun, 17 May 2020 20:02:31 +0000 (13:02 -0700)
committerDaniel Lenski <dlenski@gmail.com>
Sun, 17 May 2020 20:21:16 +0000 (13:21 -0700)
We only attempt this once before giving up.

Tested on F5, and this works: we nak-offer a larger MRU, and the server
responds with a new CONFACK requesting the same value.

The F5 server often offers erroneously low MRU values, too small for IPv6
(minimum MTU of 1280), and is consistently strict about not accepting
incoming IP packets which are even 1 byte larger than its MRU, so this is
useful. 🍺

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
ppp.c
ppp.h

diff --git a/ppp.c b/ppp.c
index 53029ec1c7f95e5da67cc1f289aae7bf39a492ef..78de5890c394c1e335da14acda75c91fe719dcd5 100644 (file)
--- a/ppp.c
+++ b/ppp.c
@@ -258,7 +258,7 @@ int openconnect_ppp_new(struct openconnect_info *vpninfo,
        ppp->exp_ppp_hdr_size = 4; /* Address(1), Control(1), Proto(2) */
 
        ppp->out_asyncmap = 0;
-       ppp->out_lcp_opts = BIT_MRU | BIT_ASYNCMAP | BIT_MAGIC | BIT_PFCOMP | BIT_ACCOMP;
+       ppp->out_lcp_opts = BIT_MRU | BIT_ASYNCMAP | BIT_MAGIC | BIT_PFCOMP | BIT_ACCOMP | BIT_MRU_COAX;
 
        return 0;
 }
@@ -330,7 +330,7 @@ static int handle_config_request(struct openconnect_info *vpninfo,
                                 int proto, int id, unsigned char *payload, int len)
 {
        struct oc_ppp *ppp = vpninfo->ppp;
-       struct oc_text_buf *rejbuf = NULL;
+       struct oc_text_buf *rejbuf = NULL, *nakbuf = NULL;
        int ret;
        struct oc_ncp *ncp;
        unsigned char *p;
@@ -345,12 +345,25 @@ static int handle_config_request(struct openconnect_info *vpninfo,
        for (p = payload ; p+1 < payload+len && p+p[1] <= payload+len; p += p[1]) {
                unsigned char t = p[0], l = p[1];
                switch (PROTO_TAG_LEN(proto, t, l-2)) {
-               case PROTO_TAG_LEN(PPP_LCP, LCP_MRU, 2):
-                       vpninfo->ip_info.mtu = load_be16(p+2);
-                       vpn_progress(vpninfo, PRG_DEBUG,
-                                    _("Received MTU %d from server\n"),
-                                    vpninfo->ip_info.mtu);
+               case PROTO_TAG_LEN(PPP_LCP, LCP_MRU, 2): {
+                       int mru = load_be16(p + 2);
+                       if ((ppp->out_lcp_opts & BIT_MRU_COAX) && mru < vpninfo->ip_info.mtu) {
+                               /* XX: nak-offer our (larger) MTU to the server, but only try this once */
+                               store_be16(p + 2, vpninfo->ip_info.mtu);
+                               ppp->out_lcp_opts &= ~BIT_MRU_COAX;
+
+                               vpn_progress(vpninfo, PRG_DEBUG,
+                                            _("Received MRU %d from server. Nak-offering larger MRU of %d (our MTU)\n"),
+                                            mru, vpninfo->ip_info.mtu);
+                               goto nak;
+                       } else {
+                               vpninfo->ip_info.mtu = mru;
+                               vpn_progress(vpninfo, PRG_DEBUG,
+                                            _("Received MRU %d from server. Setting our MTU to match.\n"),
+                                            mru);
+                       }
                        break;
+               }
                case PROTO_TAG_LEN(PPP_LCP, LCP_ASYNCMAP, 4):
                        ppp->in_asyncmap = load_be32(p+2);
                        vpn_progress(vpninfo, PRG_DEBUG,
@@ -413,6 +426,13 @@ static int handle_config_request(struct openconnect_info *vpninfo,
                                return -ENOMEM;
                        buf_append_bytes(rejbuf, p, l);
                        break;
+               nak:
+                       if (!nakbuf)
+                               nakbuf = buf_alloc();
+                       if (!nakbuf)
+                               return -ENOMEM;
+                       buf_append_bytes(nakbuf, p, l);
+
                }
        }
        ncp->state |= NCP_CONF_REQ_RECEIVED;
@@ -433,7 +453,19 @@ static int handle_config_request(struct openconnect_info *vpninfo,
                if ((ret = queue_config_packet(vpninfo, proto, id, CONFREJ, rejbuf->pos, rejbuf->data)) >= 0) {
                        ret = 0;
                }
-       } else {
+       }
+       if (nakbuf) {
+               if (buf_error(nakbuf)) {
+                       vpn_progress(vpninfo, PRG_ERR,
+                                    _("Error composing ConfNak packet\n"));
+                       return buf_free(nakbuf);
+               }
+               vpn_progress(vpninfo, PRG_DEBUG, _("Nak proto 0x%04x/id %d config from server\n"), proto, id);
+               if ((ret = queue_config_packet(vpninfo, proto, id, CONFNAK, nakbuf->pos, nakbuf->data)) >= 0) {
+                       ret = 0;
+               }
+       }
+       if (!rejbuf && !nakbuf) {
                vpn_progress(vpninfo, PRG_DEBUG, _("Ack proto 0x%04x/id %d config from server\n"), proto, id);
                if ((ret = queue_config_packet(vpninfo, proto, id, CONFACK, len, payload)) >= 0) {
                        ncp->state |= NCP_CONF_ACK_SENT;
diff --git a/ppp.h b/ppp.h
index 048c12b94c02444e272568dea76fcca6c83c1a61..07f2a8f590f5a18692cbffcd5c26179c7353065e 100644 (file)
--- a/ppp.h
+++ b/ppp.h
@@ -73,6 +73,7 @@
 #define BIT_MAGIC      (1 << LCP_MAGIC)
 #define BIT_PFCOMP     (1 << LCP_PFCOMP)
 #define BIT_ACCOMP     (1 << LCP_ACCOMP)
+#define BIT_MRU_COAX    (1 << 9)
 
 /* RFC1332 */
 #define IPCP_IPADDRS           1