From: Daniel Lenski <dlenski@gmail.com>
Date: Sun, 17 May 2020 23:27:52 +0000 (-0700)
Subject: Need to handle case where rejected protocol was sent as only 1 byte
X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=d621b76fe0ba4ec07b51f5676e2f23f3b42ec602;p=users%2Fdwmw2%2Fopenconnect.git

Need to handle case where rejected protocol was sent as only 1 byte

… as well as the admittedly-unlikely case where the rejected protocol is
larger than peer's MRU (which we've already accepted as our MTU).

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

diff --git a/ppp.c b/ppp.c
index 1a2a6b4f..c1846aa2 100644
--- a/ppp.c
+++ b/ppp.c
@@ -1084,12 +1084,23 @@ int ppp_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
 
 		default:
 			vpn_progress(vpninfo, PRG_ERR,
-				     _("PPP packet with unknown protocol 0x%04x. Payload:\n"),
+				     _("Sending Protocol-Reject for unknown protocol 0x%04x. Payload:\n"),
 				     proto);
 			dump_buf_hex(vpninfo, PRG_ERR, '<', pp, payload_len);
-			if (queue_config_packet(vpninfo, PPP_LCP, ++ppp->lcp.id, PROTREJ, payload_len + (pp - ph), ph))
-				vpn_progress(vpninfo, PRG_ERR,
-					     _("Failed queuing Protocol-Reject for unknown protocol 0x%04x.\n"), proto);
+
+			/* The rejected protocol MUST occupy 2 bytes prior to the rejected packet contents.
+			 * (https://tools.ietf.org/html/rfc1661#section-5.7). We can clobber these bytes
+			 * because we are throwing out this packet anyway.
+			 *
+			 * The rejected packet body is fully included, unless it must be truncated to the
+			 * peer's MRU (taking into account the preceding 4 bytes for PPP header, 4 for LCP
+			 * config header, and 2 for rejected proto.
+			 */
+			store_be16(pp - 2, proto);
+			if ((ret = queue_config_packet(vpninfo, PPP_LCP, ++ppp->lcp.id, PROTREJ,
+						       MIN(payload_len + 2, vpninfo->ip_info.mtu - 10),
+						       pp - 2)) < 0)
+				return ret;
 		}
 
 		if (next_len) {