Some systems produce IP fragments that are so small that the minimum ethernet frame size requires padding. For example, a VOIP server may produce UDP SIP messages with 1516 bytes of UDP payload, using an MTU of 1500, creating a first fragment of 1472 bytes payload (+8 bytes UDP header, +20 bytes IP header, +14 bytes ethernet header), and a second fragment of 16 bytes (+20 bytes IP header, +14 bytes ethernet header, +10 bytes trailing ethernet padding). When pf is reassembling the second fragment, it is seeing an mbuf with m_len == 46 (including the 10 bytes of ethernet padding). The reassembly code will produce a reassembled IP packet that wrongly includes the padding bytes (as invalid ethernet checksum), which causes the IP packet to be dropped (usually after re-fragmentation) on the destination (or intermediate hops). Fix: /* Create a new reassembly queue for this packet */ if (*frag == NULL) {--T30TsdF5SEvHAJTyn0iuCO8EKqf3hnSKaLzC4YjmGKSmyHML Content-Type: text/plain; name="file.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="file.diff" Index: sys/contrib/pf/net/pf_norm.c =================================================================== RCS file: /home/ncvs/src/sys/contrib/pf/net/pf_norm.c,v retrieving revision 1.19.10.1 diff -u -r1.19.10.1 pf_norm.c --- sys/contrib/pf/net/pf_norm.c 3 Aug 2009 08:13:06 -0000 1.19.10.1 +++ sys/contrib/pf/net/pf_norm.c 3 Jul 2012 10:57:25 -0000 @@ -413,6 +413,10 @@ /* Strip off ip header */ m->m_data += hlen; m->m_len -= hlen; + if (m->m_len > ip_len) { + DPFPRINTF(("truncating m_len %d -> %d\n", m->m_len, ip_len)); + m->m_len = ip_len; + } How-To-Repeat: Use two hosts, each with two interfaces (em0 and em1). Configure the second host as a bridge filtering with pf doing fragment reassembly. Connect them so the second host bridges between the first host's two interfaces. On the first host, send two fragments through the bridge. Expect the fragments to arrive at the bridge, get reassembled by pf, get re-fragmented, then arrive back at the first host. Instead, the first fragment will either not make it back, or is corrupted. #!/bin/sh dd if=/dev/random bs=1 count=1472 | \ dnet udp sport 5060 dport 5060 | \ dnet ip tos 104 id 49430 off 0+ ttl 63 proto udp src 172.19.243.20 dst 172.19.241.49 | \ dnet eth type ip src 00:50:56:9b:00:02 dst 00:50:56:9b:00:0b | \ dnet send em0 dnet hex "nt-Length: 0\r\n\r\n" | \ dnet ip tos 104 id 49430 off 1480 ttl 63 proto udp src 172.19.243.20 dst 172.19.241.49 | \ dnet eth type ip src 00:50:56:9b:00:02 dst 00:50:56:9b:00:0b | \ dnet send em0
Responsible Changed From-To: freebsd-bugs->freebsd-pf Over to maintainer(s).
For bugs matching the following criteria: Status: In Progress Changed: (is less than) 2014-06-01 Reset to default assignee and clear in-progress tags. Mail being skipped
I believe this got fixed a long time ago. The normalisation code now contains this: /* Strip off any trailing bytes. */ m_adj(m2, frent->fe_len - m2->m_pkthdr.len); Please re-open this bug if the problem can be reproduced on 12.0 or 11.2.