Page MenuHomeFreeBSD

D48805.diff
No OneTemporary

D48805.diff

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1625,6 +1625,7 @@
struct pf_rule_actions act;
u_int32_t off; /* protocol header offset */
+ bool df; /* IPv4 Don't fragment flag. */
u_int32_t hdrlen; /* protocol header length */
u_int32_t p_len; /* total length of protocol payload */
u_int32_t extoff; /* extentsion header offset */
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -9990,6 +9990,7 @@
pd->ttl = h->ip_ttl;
pd->tot_len = ntohs(h->ip_len);
pd->act.rtableid = -1;
+ pd->df = h->ip_off & htons(IP_DF);
if (h->ip_hl > 5) /* has options */
pd->badopts++;
@@ -10317,21 +10318,6 @@
return (PF_PASS);
}
-#ifdef INET6
- /*
- * If we end up changing IP addresses (e.g. binat) the stack may get
- * confused and fail to send the icmp6 packet too big error. Just send
- * it here, before we do any NAT.
- */
- if (af == AF_INET6 && dir == PF_OUT && pflags & PFIL_FWD &&
- IN6_LINKMTU(ifp) < pf_max_frag_size(*m0)) {
- PF_RULES_RUNLOCK();
- icmp6_error(*m0, ICMP6_PACKET_TOO_BIG, 0, IN6_LINKMTU(ifp));
- *m0 = NULL;
- return (PF_DROP);
- }
-#endif
-
if (__predict_false(! M_WRITABLE(*m0))) {
*m0 = m_unshare(*m0, M_NOWAIT);
if (*m0 == NULL) {
@@ -10380,6 +10366,31 @@
goto done;
}
+#ifdef INET
+ if (af == AF_INET && dir == PF_OUT && pflags & PFIL_FWD &&
+ pd.df && (*m0)->m_pkthdr.len > ifp->if_mtu) {
+ PF_RULES_RUNLOCK();
+ icmp_error(*m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG,
+ 0, ifp->if_mtu);
+ *m0 = NULL;
+ return (PF_DROP);
+ }
+#endif
+#ifdef INET6
+ /*
+ * If we end up changing IP addresses (e.g. binat) the stack may get
+ * confused and fail to send the icmp6 packet too big error. Just send
+ * it here, before we do any NAT.
+ */
+ if (af == AF_INET6 && dir == PF_OUT && pflags & PFIL_FWD &&
+ IN6_LINKMTU(ifp) < pf_max_frag_size(*m0)) {
+ PF_RULES_RUNLOCK();
+ icmp6_error(*m0, ICMP6_PACKET_TOO_BIG, 0, IN6_LINKMTU(ifp));
+ *m0 = NULL;
+ return (PF_DROP);
+ }
+#endif
+
if (__predict_false(ip_divert_ptr != NULL) &&
((mtag = m_tag_locate(pd.m, MTAG_PF_DIVERT, 0, NULL)) != NULL)) {
struct pf_divert_mtag *dt = (struct pf_divert_mtag *)(mtag+1);
diff --git a/tests/sys/netpfil/pf/icmp.py b/tests/sys/netpfil/pf/icmp.py
--- a/tests/sys/netpfil/pf/icmp.py
+++ b/tests/sys/netpfil/pf/icmp.py
@@ -48,6 +48,7 @@
def vnet2_handler(self, vnet):
ifname = vnet.iface_alias_map["if1"].name
+ if2name = vnet.iface_alias_map["if2"].name
ToolsHelper.print_output("/sbin/pfctl -e")
ToolsHelper.pf_rules([
@@ -59,6 +60,8 @@
ToolsHelper.print_output("/sbin/sysctl net.inet.ip.forwarding=1")
ToolsHelper.print_output("/sbin/pfctl -x loud")
+ ToolsHelper.print_output("/sbin/ifconfig %s mtu 1492" % if2name)
+
def vnet3_handler(self, vnet):
# Import in the correct vnet, so at to not confuse Scapy
import scapy.all as sp
@@ -66,6 +69,7 @@
ifname = vnet.iface_alias_map["if2"].name
ToolsHelper.print_output("/sbin/route add default 198.51.100.1")
ToolsHelper.print_output("/sbin/ifconfig %s inet alias 198.51.100.3/24" % ifname)
+ ToolsHelper.print_output("/sbin/ifconfig %s mtu 1492" % ifname)
def checkfn(packet):
icmp = packet.getlayer(sp.ICMP)
@@ -124,3 +128,47 @@
# We expect the timeout here. It means we didn't get the destination
# unreachable packet in vnet3
pass
+
+ def check_icmp_echo(self, sp, payload_size):
+ packet = sp.IP(dst="198.51.100.2", flags="DF") \
+ / sp.ICMP(type='echo-request') \
+ / sp.raw(bytes.fromhex('f0') * payload_size)
+
+ p = sp.sr1(packet, iface=self.vnet.iface_alias_map["if1"].name,
+ timeout=3)
+ p.show()
+
+ ip = p.getlayer(sp.IP)
+ icmp = p.getlayer(sp.ICMP)
+ assert ip
+ assert icmp
+
+ if payload_size > 1464:
+ # Expect ICMP destination unreachable, fragmentation needed
+ assert ip.src == "192.0.2.1"
+ assert ip.dst == "192.0.2.2"
+ assert icmp.type == 3 # dest-unreach
+ assert icmp.code == 4
+ assert icmp.nexthopmtu == 1492
+ else:
+ # Expect echo reply
+ assert ip.src == "198.51.100.2"
+ assert ip.dst == "192.0.2.2"
+ assert icmp.type == 0 # "echo-reply"
+ assert icmp.code == 0
+
+ return
+
+ @pytest.mark.require_user("root")
+ def test_fragmentation_needed(self):
+ ToolsHelper.print_output("/sbin/route add default 192.0.2.1")
+
+ ToolsHelper.print_output("/sbin/ping -c 1 198.51.100.2")
+ ToolsHelper.print_output("/sbin/ping -c 1 -D -s 1472 198.51.100.2")
+
+ # Import in the correct vnet, so at to not confuse Scapy
+ import scapy.all as sp
+
+ self.check_icmp_echo(sp, 128)
+ self.check_icmp_echo(sp, 1464)
+ self.check_icmp_echo(sp, 1468)

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 10, 2:15 PM (6 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16578556
Default Alt Text
D48805.diff (4 KB)

Event Timeline