Bug 229006 - ipfw+nat and ng_nat Silently Drop Packets over 4k
Summary: ipfw+nat and ng_nat Silently Drop Packets over 4k
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 11.1-RELEASE
Hardware: Any Any
: --- Affects Some People
Assignee: Andrey V. Elsukov
Depends on:
Reported: 2018-06-14 00:02 UTC by Jeff Kletsky
Modified: 2018-06-14 23:44 UTC (History)
2 users (show)

See Also:

Possible patch from suggestion of Andrey V. Elsukov (566 bytes, patch)
2018-06-14 00:07 UTC, Jeff Kletsky
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jeff Kletsky 2018-06-14 00:02:28 UTC
As discovered on 11.1-RELEASE-p9 and present on -p10, reassembled packets over 4k are silently dropped by in-kernel NAT.

Patch based on suggestion of Andrey V. Elsukov supplied.

Cause identified by Andrey V. Elsukov on the freebsd-net and freebsd-ipfw lists on 2018-06-13 as being due to buffer allocation limits in the in-kernel implementation of libalias.

"The kernel version of libalias uses m_megapullup() function to make
single contiguous buffer. m_megapullup() uses m_get2() function to
allocate mbuf of appropriate size. If size of packet greater than 4k it
will fail. So, if you use MTU greater than 4k or if after fragments
reassembly you get a packet with length greater than 4k, ipfw_nat()
function will drop this packet."

Additional communication on those lists by Andrey suggested a patch might resolve this issue. The following is his code, I take no credit for it. Tested and "works for me" on kernel sources from 11.1-RELEASE-p10 and GENERIC kernconf.

/usr/src/sys/netinet/libalias]$ diff -u alias.c.orig alias.c
--- alias.c.orig	2017-07-20 16:42:02.000000000 -0700
+++ alias.c	2018-06-13 15:41:46.862121000 -0700
@@ -1758,7 +1758,14 @@
 	if (m->m_next == NULL && M_WRITABLE(m))
 		return (m);
-	mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
+	if (len <= MJUMPAGESIZE)
+		mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
+	else if (len <= MJUM9BYTES)
+		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
+	else if (len <= MJUM16BYTES)
+		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
+	else
+		goto bad;
 	if (mcl == NULL)
 		goto bad;
 	m_align(mcl, len);

Additional details on the situation that highlighted this can be found at 
Comment 1 Jeff Kletsky 2018-06-14 00:03:48 UTC
Relates to documentation issue #229003
Comment 2 Jeff Kletsky 2018-06-14 00:07:03 UTC
Created attachment 194242 [details]
Possible patch from suggestion of Andrey V. Elsukov
Comment 3 commit-hook freebsd_committer 2018-06-14 11:16:13 UTC
A commit references this bug:

Author: ae
Date: Thu Jun 14 11:15:40 UTC 2018
New revision: 335133
URL: https://svnweb.freebsd.org/changeset/base/335133

  In m_megapullup() use m_getjcl() to allocate 9k or 16k mbuf when requested.

  It is better to try allocate a big mbuf, than just silently drop a big
  packet. A better solution could be reworking of libalias modules to be
  able use m_copydata()/m_copyback() instead of requiring the single
  contiguous buffer.

  PR:		229006
  MFC after:	1 week

Comment 4 Gleb Smirnoff freebsd_committer 2018-06-14 23:44:13 UTC
Some historical context:


Due to discussion thread after this commit: