xref: /freebsd/tests/sys/netpfil/pf/nat44.py (revision c23eda976a8aad6bbd6c2042fa2ba1f0bc640e19)
1*c23eda97SKristof Provost#
2*c23eda97SKristof Provost# SPDX-License-Identifier: BSD-2-Clause
3*c23eda97SKristof Provost#
4*c23eda97SKristof Provost# Copyright (c) 2025 Rubicon Communications, LLC (Netgate)
5*c23eda97SKristof Provost#
6*c23eda97SKristof Provost# Redistribution and use in source and binary forms, with or without
7*c23eda97SKristof Provost# modification, are permitted provided that the following conditions
8*c23eda97SKristof Provost# are met:
9*c23eda97SKristof Provost# 1. Redistributions of source code must retain the above copyright
10*c23eda97SKristof Provost#    notice, this list of conditions and the following disclaimer.
11*c23eda97SKristof Provost# 2. Redistributions in binary form must reproduce the above copyright
12*c23eda97SKristof Provost#    notice, this list of conditions and the following disclaimer in the
13*c23eda97SKristof Provost#    documentation and/or other materials provided with the distribution.
14*c23eda97SKristof Provost#
15*c23eda97SKristof Provost# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*c23eda97SKristof Provost# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*c23eda97SKristof Provost# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*c23eda97SKristof Provost# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*c23eda97SKristof Provost# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*c23eda97SKristof Provost# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*c23eda97SKristof Provost# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*c23eda97SKristof Provost# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*c23eda97SKristof Provost# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*c23eda97SKristof Provost# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*c23eda97SKristof Provost# SUCH DAMAGE.
26*c23eda97SKristof Provost
27*c23eda97SKristof Provostimport pytest
28*c23eda97SKristof Provostfrom atf_python.sys.net.tools import ToolsHelper
29*c23eda97SKristof Provostfrom atf_python.sys.net.vnet import VnetTestTemplate
30*c23eda97SKristof Provost
31*c23eda97SKristof Provostclass TestNAT44(VnetTestTemplate):
32*c23eda97SKristof Provost    REQUIRED_MODULES = [ "pf" ]
33*c23eda97SKristof Provost    TOPOLOGY = {
34*c23eda97SKristof Provost        "vnet1": {"ifaces": ["if1"]},
35*c23eda97SKristof Provost        "vnet2": {"ifaces": ["if1", "if2"]},
36*c23eda97SKristof Provost        "vnet3": {"ifaces": ["if2"]},
37*c23eda97SKristof Provost        "if1": {"prefixes4": [("192.0.2.2/24", "192.0.2.1/24")]},
38*c23eda97SKristof Provost        "if2": {"prefixes4": [("198.51.100.1/24", "198.51.100.2")]},
39*c23eda97SKristof Provost    }
40*c23eda97SKristof Provost
41*c23eda97SKristof Provost    def vnet2_handler(self, vnet):
42*c23eda97SKristof Provost        outifname = vnet.iface_alias_map["if2"].name
43*c23eda97SKristof Provost        ToolsHelper.print_output("/sbin/sysctl net.inet.ip.forwarding=1")
44*c23eda97SKristof Provost
45*c23eda97SKristof Provost        ToolsHelper.print_output("/sbin/pfctl -e")
46*c23eda97SKristof Provost        ToolsHelper.print_output("/sbin/pfctl -x loud")
47*c23eda97SKristof Provost        ToolsHelper.pf_rules([
48*c23eda97SKristof Provost            "set reassemble yes",
49*c23eda97SKristof Provost            "nat on {} inet from 192.0.2.0/24 -> ({})".format(outifname, outifname),
50*c23eda97SKristof Provost            "pass"])
51*c23eda97SKristof Provost
52*c23eda97SKristof Provost    def vnet3_handler(self, vnet):
53*c23eda97SKristof Provost        pass
54*c23eda97SKristof Provost
55*c23eda97SKristof Provost    @pytest.mark.require_user("root")
56*c23eda97SKristof Provost    @pytest.mark.require_progs(["scapy"])
57*c23eda97SKristof Provost    def test_nat_igmp(self):
58*c23eda97SKristof Provost        "Verify that NAT translation of !(TCP|UDP|SCTP|ICMP) doesn't panic"
59*c23eda97SKristof Provost        ToolsHelper.print_output("/sbin/route add default 192.0.2.1")
60*c23eda97SKristof Provost        ToolsHelper.print_output("ping -c 3 198.51.100.2")
61*c23eda97SKristof Provost
62*c23eda97SKristof Provost        # Import in the correct vnet, so at to not confuse Scapy
63*c23eda97SKristof Provost        import scapy.all as sp
64*c23eda97SKristof Provost        import scapy.contrib as sc
65*c23eda97SKristof Provost        import scapy.contrib.igmp
66*c23eda97SKristof Provost
67*c23eda97SKristof Provost        pkt = sp.IP(dst="198.51.100.2", ttl=64) \
68*c23eda97SKristof Provost            / sc.igmp.IGMP(type=0x11, mrcode=1)
69*c23eda97SKristof Provost        sp.send(pkt)
70*c23eda97SKristof Provost
71*c23eda97SKristof Provost        # This time we'll hit an existing state
72*c23eda97SKristof Provost        pkt = sp.IP(dst="198.51.100.2", ttl=64) \
73*c23eda97SKristof Provost            / sc.igmp.IGMP(type=0x11, mrcode=1)
74*c23eda97SKristof Provost        reply = sp.sr1(pkt, timeout=3)
75*c23eda97SKristof Provost        if reply:
76*c23eda97SKristof Provost            reply.show()
77