From owner-svn-src-all@freebsd.org Mon Oct 16 15:03:46 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 67A4FE3CB08; Mon, 16 Oct 2017 15:03:46 +0000 (UTC) (envelope-from kp@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4404983D92; Mon, 16 Oct 2017 15:03:46 +0000 (UTC) (envelope-from kp@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v9GF3jVI065748; Mon, 16 Oct 2017 15:03:45 GMT (envelope-from kp@FreeBSD.org) Received: (from kp@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v9GF3jE5065745; Mon, 16 Oct 2017 15:03:45 GMT (envelope-from kp@FreeBSD.org) Message-Id: <201710161503.v9GF3jE5065745@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kp set sender to kp@FreeBSD.org using -f From: Kristof Provost Date: Mon, 16 Oct 2017 15:03:45 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r324663 - head/tests/sys/netpfil/pf X-SVN-Group: head X-SVN-Commit-Author: kp X-SVN-Commit-Paths: head/tests/sys/netpfil/pf X-SVN-Commit-Revision: 324663 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 16 Oct 2017 15:03:46 -0000 Author: kp Date: Mon Oct 16 15:03:45 2017 New Revision: 324663 URL: https://svnweb.freebsd.org/changeset/base/324663 Log: pf tests: Basic IPv6 forwarding tests Pass/block packets in the forwarding path with pf. Introduce the pft_set_rules() helper function, because we need to remember to flush states between individual tests. If not we can get packets passing despite rules blocking them because they match states created in a previous test. Extend pft_ping.py to be able to send IPv6 echo requests. Modified: head/tests/sys/netpfil/pf/forward.sh head/tests/sys/netpfil/pf/pft_ping.py head/tests/sys/netpfil/pf/utils.subr Modified: head/tests/sys/netpfil/pf/forward.sh ============================================================================== --- head/tests/sys/netpfil/pf/forward.sh Mon Oct 16 15:01:49 2017 (r324662) +++ head/tests/sys/netpfil/pf/forward.sh Mon Oct 16 15:03:45 2017 (r324663) @@ -61,7 +61,87 @@ v4_cleanup() pft_cleanup } +atf_test_case "v6" "cleanup" +v6_head() +{ + atf_set descr 'Basic IPv6 forwarding test' + atf_set require.user root + atf_set require.progs scapy +} + +v6_body() +{ + pft_init + + epair_send=$(pft_mkepair) + epair_recv=$(pft_mkepair) + + ifconfig ${epair_send}a inet6 2001:db8:42::1/64 up no_dad -ifdisabled + ifconfig ${epair_recv}a up + + pft_mkjail alcatraz ${epair_send}b ${epair_recv}b + + jexec alcatraz ifconfig ${epair_send}b inet6 2001:db8:42::2/64 up no_dad + jexec alcatraz ifconfig ${epair_recv}b inet6 2001:db8:43::2/64 up no_dad + jexec alcatraz sysctl net.inet6.ip6.forwarding=1 + jexec alcatraz ndp -s 2001:db8:43::3 00:01:02:03:04:05 + route add -6 2001:db8:43::/64 2001:db8:42::2 + + # Sanity check, can we forward ICMP echo requests without pf? + atf_check -s exit:0 $(atf_get_srcdir)/pft_ping.py \ + --ip6 \ + --sendif ${epair_send}a \ + --to 2001:db8:43::3 \ + --recvif ${epair_recv}a + + jexec alcatraz pfctl -e + + # Block incoming echo request packets + pft_set_rules alcatraz \ + "block in inet6 proto icmp6 icmp6-type echoreq" + atf_check -s exit:1 $(atf_get_srcdir)/pft_ping.py \ + --ip6 \ + --sendif ${epair_send}a \ + --to 2001:db8:43::3 \ + --recvif ${epair_recv}a + + # Block outgoing echo request packets + pft_set_rules alcatraz \ + "block out inet6 proto icmp6 icmp6-type echoreq" + atf_check -s exit:1 -e ignore $(atf_get_srcdir)/pft_ping.py \ + --ip6 \ + --sendif ${epair_send}a \ + --to 2001:db8:43::3 \ + --recvif ${epair_recv}a + + # Allow ICMPv6 but nothing else + pft_set_rules alcatraz \ + "block out" \ + "pass out inet6 proto icmp6" + atf_check -s exit:0 $(atf_get_srcdir)/pft_ping.py \ + --ip6 \ + --sendif ${epair_send}a \ + --to 2001:db8:43::3 \ + --recvif ${epair_recv}a + + # Allowing ICMPv4 does not allow ICMPv6 + pft_set_rules alcatraz \ + "block out inet6 proto icmp6 icmp6-type echoreq" \ + "pass in proto icmp" + atf_check -s exit:1 $(atf_get_srcdir)/pft_ping.py \ + --ip6 \ + --sendif ${epair_send}a \ + --to 2001:db8:43::3 \ + --recvif ${epair_recv}a +} + +v6_cleanup() +{ + pft_cleanup +} + atf_init_test_cases() { atf_add_test_case "v4" + atf_add_test_case "v6" } Modified: head/tests/sys/netpfil/pf/pft_ping.py ============================================================================== --- head/tests/sys/netpfil/pf/pft_ping.py Mon Oct 16 15:01:49 2017 (r324662) +++ head/tests/sys/netpfil/pf/pft_ping.py Mon Oct 16 15:03:45 2017 (r324663) @@ -19,6 +19,12 @@ class Sniffer(threading.Thread): self.packets = sp.sniff(iface=self._recvif, timeout=3) def check_ping_request(packet, dst_ip, args): + if args.ip6: + return check_ping6_request(packet, dst_ip, args) + else: + return check_ping4_request(packet, dst_ip, args) + +def check_ping4_request(packet, dst_ip, args): """ Verify that the packet matches what we'd have sent """ @@ -51,6 +57,24 @@ def check_ping_request(packet, dst_ip, args): return True +def check_ping6_request(packet, dst_ip, args): + """ + Verify that the packet matches what we'd have sent + """ + ip = packet.getlayer(sp.IPv6) + if not ip: + return False + if ip.dst != dst_ip: + return False + + icmp = packet.getlayer(sp.ICMPv6EchoRequest) + if not icmp: + return False + if icmp.data != str(PAYLOAD_MAGIC): + return False + + return True + def ping(send_if, dst_ip, args): ether = sp.Ether() ip = sp.IP(dst=dst_ip) @@ -63,6 +87,14 @@ def ping(send_if, dst_ip, args): req = ether / ip / icmp / raw sp.sendp(req, iface=send_if, verbose=False) +def ping6(send_if, dst_ip, args): + ether = sp.Ether() + ip6 = sp.IPv6(dst=dst_ip) + icmp = sp.ICMPv6EchoRequest(data=PAYLOAD_MAGIC) + + req = ether / ip6 / icmp + sp.sendp(req, iface=send_if, verbose=False) + def main(): parser = argparse.ArgumentParser("pft_ping.py", description="Ping test tool") @@ -71,6 +103,8 @@ def main(): help='The interface through which the packet(s) will be sent') parser.add_argument('--recvif', nargs=1, help='The interface on which to expect the ICMP echo response') + parser.add_argument('--ip6', action='store_true', + help='Use IPv6') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address for the ICMP echo request') @@ -85,11 +119,17 @@ def main(): args = parser.parse_args() + # We may not have a default route. Tell scapy where to start looking for routes + sp.conf.iface6 = args.sendif[0] + sniffer = None if not args.recvif is None: sniffer = Sniffer(args.recvif[0]) - ping(args.sendif[0], args.to[0], args) + if args.ip6: + ping6(args.sendif[0], args.to[0], args) + else: + ping(args.sendif[0], args.to[0], args) if sniffer: sniffer.join() Modified: head/tests/sys/netpfil/pf/utils.subr ============================================================================== --- head/tests/sys/netpfil/pf/utils.subr Mon Oct 16 15:01:49 2017 (r324662) +++ head/tests/sys/netpfil/pf/utils.subr Mon Oct 16 15:03:45 2017 (r324663) @@ -35,6 +35,20 @@ pft_mkjail() echo $jailname >> created_jails.lst } +pft_set_rules() +{ + jname=$1 + shift + + # Flush all states, rules, fragments, ... + jexec ${jname} pfctl -F all + + while [ $# -gt 0 ]; do + printf "$1\n" + shift + done | jexec ${jname} pfctl -f - +} + pft_cleanup() { if [ -f created_interfaces.lst ]; then