From nobody Fri Aug 4 13:59:15 2023 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4RHS4h6K3wz4kVKp; Fri, 4 Aug 2023 13:59:16 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4RHS4g6n85z3Fmd; Fri, 4 Aug 2023 13:59:15 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1691157556; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=DLb9WVg+VM/D8s4ClXfXcduDzkrQC6S+dXJNpVREwyk=; b=XMhS7RaByhgjVARkDL/eGdDEZPZo0+jhMr3qChynaB2dUlOUivnRyPtEpQvJ2Kq08w3L+b UyNtpbg0VscQjtjRPcSOTubpiZQJeyR/ZeX/N8FZOxJhhYIOyav8+xZDwc8gAgYVAkJ+MW YjpmLd28X/AQckXB9qdnQUUaA5ApTnVn66enZKSsqo/hLYGdTPshpAWbYtLTMNG62arcfH Oj4iYOqhjxF/SIh1YGZaY+8tJ6nV6go74O8rQYFTTVgZjDx98Wu9k5AXlghcsPWAZQbICk QooQYiP5WhgmmFnBdH3B7LwgX1zx74ttM3OArAgBMIXMRRpl2rqtN1T7T1HiUw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1691157555; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=DLb9WVg+VM/D8s4ClXfXcduDzkrQC6S+dXJNpVREwyk=; b=sZSbJjg8OJOF/VMp0tcgssMFuyzIFpXyw/fzdXA/yDPU889dd9REEqxK2hOVqcTJ8Q87fe 2RK4mW+i2hlssHb0tIuUUnfOnltNNGZeukW978j446EnaCJ6eEL80Y5vLAhe3PBBv6suN3 I9K4xiQfCHwLqxePUbXvhhnAD/1duTV+1lVQ8PLhr8238lwgQPjybX5M/rjMVFEN3q1VxJ UmcNGZdXn/Gv5VoiDsw+Vwyr/QqoZJD+sExST+O2bbd9NN/e71y95aCQvDoAPOuCx6R1fO 6RvmY4KcKY9uxGygHZBiMNHB661/4AMOe6EirSI47KfvAA1Pp718nv+tIY6pqA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1691157555; a=rsa-sha256; cv=none; b=sD7fS3xMvk/s33KeMLP7bK5d6Ia4Rsi8F6WuwpwxlvwDjvjlZNHCJryeFQAX7grFzGtT08 bHYjD/nk2n8gkghqxnKX57c36z93t9GIMavf2umZDiBM4RzNKZcZFxwtZusBIpSlRu2mc/ HAsb7NuMEU6ZjcP8kAdo1OsvoY2aZmwjsBeERLEbzPot0FCjqfDCJ4Q6UnakGHngXBaJBO X50e4oVeZ0LUp+CLJUXJg1lnfzDB90+H6V4BF9/TfXhIQCtKzj2YWXuQiqTta2vINXIZHx di3kQQcm0RlqwNijBg6ZTWxpKcVYZjMRpxoNYX1ATij5p7Ltvi3fxMB/O6iezg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4RHS4g5sSPz14pD; Fri, 4 Aug 2023 13:59:15 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 374DxFD2070047; Fri, 4 Aug 2023 13:59:15 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 374DxFGx070046; Fri, 4 Aug 2023 13:59:15 GMT (envelope-from git) Date: Fri, 4 Aug 2023 13:59:15 GMT Message-Id: <202308041359.374DxFGx070046@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kristof Provost Subject: git: b23dbabb7f3e - main - pf: test rules evaluation in the face of multiple IPv6 fragment headers List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: b23dbabb7f3edb3f323a64f03e37be2c9a8b2a45 Auto-Submitted: auto-generated The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=b23dbabb7f3edb3f323a64f03e37be2c9a8b2a45 commit b23dbabb7f3edb3f323a64f03e37be2c9a8b2a45 Author: Kristof Provost AuthorDate: 2023-07-13 06:34:54 +0000 Commit: Kristof Provost CommitDate: 2023-08-04 13:24:16 +0000 pf: test rules evaluation in the face of multiple IPv6 fragment headers Send an ICMPv6 echo request packet with multiple IPv6 fragment headers. Set rules to pass all packets, except for ICMPv6 echo requests. pf ought to drop the echo request, but doesn't because it reassembles the packet, and then doesn't handle the second fragment header. In other words: it fails to detect the ICMPv6 echo header. Reported by: Enrico Bassetti bassetti@di.uniroma1.it (NetSecurityLab @ Sapienza University of Rome) MFC after: instant Sponsored by: Rubicon Communications, LLC ("Netgate") --- tests/atf_python/sys/net/tools.py | 21 ++++++++++++++ tests/sys/netpfil/pf/Makefile | 2 ++ tests/sys/netpfil/pf/frag6.py | 60 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+) diff --git a/tests/atf_python/sys/net/tools.py b/tests/atf_python/sys/net/tools.py index 567d9d4b21ac..44bd74d8578f 100644 --- a/tests/atf_python/sys/net/tools.py +++ b/tests/atf_python/sys/net/tools.py @@ -1,6 +1,7 @@ #!/usr/local/bin/python3 import json import os +import subprocess class ToolsHelper(object): @@ -13,6 +14,26 @@ class ToolsHelper(object): print("run: '{}'".format(cmd)) return os.popen(cmd).read() + @classmethod + def pf_rules(cls, rules, verbose=True): + pf_conf = "" + for r in rules: + pf_conf = pf_conf + r + "\n" + + if verbose: + print("Set rules:") + print(pf_conf) + + ps = subprocess.Popen("/sbin/pfctl -g -f -", shell=True, + stdin=subprocess.PIPE) + ps.communicate(bytes(pf_conf, 'utf-8')) + ret = ps.wait() + if ret != 0: + raise Exception("Failed to set pf rules %d" % ret) + + if verbose: + cls.print_output("/sbin/pfctl -sr") + @classmethod def print_output(cls, cmd: str, verbose=True): if verbose: diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile index 19c87486d8bb..5c59584d2ec9 100644 --- a/tests/sys/netpfil/pf/Makefile +++ b/tests/sys/netpfil/pf/Makefile @@ -40,6 +40,8 @@ ATF_TESTS_SH+= altq \ table \ tos +ATF_TESTS_PYTEST+= frag6.py + # Tests reuse jail names and so cannot run in parallel. TEST_METADATA+= is_exclusive=true diff --git a/tests/sys/netpfil/pf/frag6.py b/tests/sys/netpfil/pf/frag6.py new file mode 100644 index 000000000000..28b1829d418c --- /dev/null +++ b/tests/sys/netpfil/pf/frag6.py @@ -0,0 +1,60 @@ +import pytest +import logging +import threading +import time +logging.getLogger("scapy").setLevel(logging.CRITICAL) +from atf_python.sys.net.tools import ToolsHelper +from atf_python.sys.net.vnet import VnetTestTemplate + +class DelayedSend(threading.Thread): + def __init__(self, packet): + threading.Thread.__init__(self) + self._packet = packet + + self.start() + + def run(self): + import scapy.all as sp + time.sleep(1) + sp.send(self._packet) + +class TestFrag6(VnetTestTemplate): + REQUIRED_MODULES = ["pf"] + TOPOLOGY = { + "vnet1": {"ifaces": ["if1"]}, + "vnet2": {"ifaces": ["if1"]}, + "if1": {"prefixes6": [("2001:db8::1/64", "2001:db8::2/64")]}, + } + + def vnet2_handler(self, vnet): + ToolsHelper.print_output("/sbin/pfctl -e") + ToolsHelper.pf_rules([ + "scrub fragment reassemble", + "pass", + "block in inet6 proto icmp6 icmp6-type echoreq", + ]) + + def check_ping_reply(self, packet): + print(packet) + return False + + @pytest.mark.require_user("root") + def test_dup_frag_hdr(self): + "Test packets with duplicate fragment headers" + srv_vnet = self.vnet_map["vnet2"] + + # Import in the correct vnet, so at to not confuse Scapy + import scapy.all as sp + + packet = sp.IPv6(src="2001:db8::1", dst="2001:db8::2") \ + / sp.IPv6ExtHdrFragment(offset = 0, m = 0) \ + / sp.IPv6ExtHdrFragment(offset = 0, m = 0) \ + / sp.ICMPv6EchoRequest(data=sp.raw(bytes.fromhex('f00f') * 128)) + + # Delay the send so the sniffer is running when we transmit. + s = DelayedSend(packet) + + packets = sp.sniff(iface=self.vnet.iface_alias_map["if1"].name, + timeout=3) + for p in packets: + assert not p.getlayer(sp.ICMPv6EchoReply)