kern/182212: [patch] [ng_mppc] ng_mppc(4) blocks on network errors unconditionaly

Eugene Grosbein egrosbein at rdtc.ru
Wed Sep 18 19:30:01 UTC 2013


>Number:         182212
>Category:       kern
>Synopsis:       [patch] [ng_mppc] ng_mppc(4) blocks on network errors unconditionaly
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Sep 18 19:30:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Eugene Grosbein
>Release:        FreeBSD 8.4-STABLE amd64
>Organization:
RDTC JSC
>Environment:
System: FreeBSD eg.sd.rdtc.ru 8.4-STABLE FreeBSD 8.4-STABLE #2 r251830M: Mon Jun 17 18:05:24 NOVT 2013 root at eg.sd.rdtc.ru:/usr/local/obj/usr/local/src/sys/EG amd64

>Description:
	Netgraph node ng_mppc(4) is used by mpd daemon to implement
	MPPC/MPPE for Compression Control Protocol (CCP) used with various
	PPP tunnels (pptp/l2tp/etc.)

	This node blocks itself when "too many" packets got dropped in between
	PPP peers and MPPE should do "re-keying". The threshold is hardcoded
	in its code. The code considers "re-keying" as too CPU intensive task.
	Thus, it tries to protect the box from DoS.
	This code dates back to year 2000.

	When such event occcurs, PPP tunnel hangs: CCP does not get reset,
	IP packets cannot pass tunnel anymore but system interface "looks fine".

	These days mpd runs on multi-MHZ and GHZ boxes and may be used
	not for BRAS'es with lots of tunnels but to form VPN between a pair
	of routers. In the latter case, manual reset of mpd link is required
	to revive VPN tunnel.


>How-To-Repeat:
	
	Run PPtP or L2TP tunnel between two mpd servers over WAN link
	with non-zero amount of packet drops and/or packet rearrangements
	having MPPC/MPPE enabled. Soon, you will get a message in the dmesg
	buffer similar to:

ng_mppc_decompress: too many (4094) packets dropped, disabling node 0xc7020900!

	Then tunnel just hangs until manually restarted as LCP echos
	cannot detect this problem.

>Fix:

	Let's system administrator decides if such behavour is needed.
	The following patch introduces new sysctl subtree "net.graph.mppe"
	with three read/write sysctls (each one is loader tunnable too):

net.graph.mppe.block_on_max_rekey - non-zero value means current behavour,
zero disables node block;

net.graph.mppe.mppe_log_max_rekey - non-zero value permits to write messages
to the log to notify of described event;

net.graph.mppe.max_rekey - allows to change the threshold.

	By default, node block is prohibited and mpd just resets CCP
	and tunnel continues to work. Mpd writes a line like this to its log:

CCP: SendResetReq #3 link 0 (Opened)
	
	At the another side, next line is written to mpd log:

CCP: rec'd Reset Request #3 (Opened)

--- sys/netgraph/ng_mppc.c.orig	2013-04-07 01:07:27.000000000 +0700
+++ sys/netgraph/ng_mppc.c	2013-09-19 01:54:54.000000000 +0700
@@ -55,6 +55,7 @@
 #include <sys/malloc.h>
 #include <sys/endian.h>
 #include <sys/errno.h>
+#include <sys/sysctl.h>
 #include <sys/syslog.h>
 
 #include <netgraph/ng_message.h>
@@ -107,6 +108,23 @@
  */
 #define MPPE_MAX_REKEY		1000
 
+SYSCTL_NODE(_net_graph, OID_AUTO, mppe, CTLFLAG_RW, 0, "MPPE");
+
+static int mppe_block_on_max_rekey = 0;
+TUNABLE_INT("net.graph.mppe.block_on_max_rekey", &mppe_block_on_max_rekey);
+SYSCTL_INT(_net_graph_mppe, OID_AUTO, block_on_max_rekey, CTLFLAG_RW,
+    &mppe_block_on_max_rekey, 0, "Block node on max MPPE key re-calculations");
+
+static int mppe_log_max_rekey = 1;
+TUNABLE_INT("net.graph.mppe.log_max_rekey", &mppe_log_max_rekey);
+SYSCTL_INT(_net_graph_mppe, OID_AUTO, log_max_rekey, CTLFLAG_RW,
+    &mppe_log_max_rekey, 0, "Log max MPPE key re-calculations event");
+
+static int mppe_max_rekey = MPPE_MAX_REKEY;
+TUNABLE_INT("net.graph.mppe.max_rekey", &mppe_max_rekey);
+SYSCTL_INT(_net_graph_mppe, OID_AUTO, max_rekey, CTLFLAG_RW,
+    &mppe_max_rekey, 0, "Maximum number of MPPE key re-calculations");
+
 /* MPPC packet header bits */
 #define MPPC_FLAG_FLUSHED	0x8000		/* xmitter reset state */
 #define MPPC_FLAG_RESTART	0x4000		/* compress history restart */
@@ -651,12 +669,23 @@
 			/* How many times are we going to have to re-key? */
 			rekey = ((d->cfg.bits & MPPE_STATELESS) != 0) ?
 			    numLost : (numLost / (MPPE_UPDATE_MASK + 1));
-			if (rekey > MPPE_MAX_REKEY) {
-				log(LOG_ERR, "%s: too many (%d) packets"
-				    " dropped, disabling node %p!",
-				    __func__, numLost, node);
+			if (rekey > mppe_max_rekey) {
+			    if (mppe_block_on_max_rekey) {
+				if (mppe_log_max_rekey) {
+				    log(LOG_ERR, "%s: too many (%d) packets"
+					" dropped, disabling node %p!\n",
+					__func__, numLost, node);
+				}
 				priv->recv.cfg.enable = 0;
 				goto failed;
+			    } else {
+				if (mppe_log_max_rekey) {
+				    log(LOG_ERR, "%s: %d packets"
+					" dropped, node %p\n",
+					__func__, numLost, node);
+				}
+				goto failed;
+			    }
 			}
 
 			/* Re-key as necessary to catch up to peer */

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list