xref: /freebsd/sbin/ipfw/tests/test_add_rule.py (revision 7e1ec25c8b6d4090ab0c1fcac4f048015c216267)
19f44a47fSAlexander V. Chernikovimport errno
29f44a47fSAlexander V. Chernikovimport json
39f44a47fSAlexander V. Chernikovimport os
49f44a47fSAlexander V. Chernikovimport socket
59f44a47fSAlexander V. Chernikovimport struct
69f44a47fSAlexander V. Chernikovimport subprocess
79f44a47fSAlexander V. Chernikovimport sys
89f44a47fSAlexander V. Chernikovfrom ctypes import c_byte
99f44a47fSAlexander V. Chernikovfrom ctypes import c_char
109f44a47fSAlexander V. Chernikovfrom ctypes import c_int
119f44a47fSAlexander V. Chernikovfrom ctypes import c_long
129f44a47fSAlexander V. Chernikovfrom ctypes import c_uint32
139f44a47fSAlexander V. Chernikovfrom ctypes import c_uint8
149f44a47fSAlexander V. Chernikovfrom ctypes import c_ulong
159f44a47fSAlexander V. Chernikovfrom ctypes import c_ushort
169f44a47fSAlexander V. Chernikovfrom ctypes import sizeof
179f44a47fSAlexander V. Chernikovfrom ctypes import Structure
189f44a47fSAlexander V. Chernikovfrom enum import Enum
199f44a47fSAlexander V. Chernikovfrom typing import Any
209f44a47fSAlexander V. Chernikovfrom typing import Dict
219f44a47fSAlexander V. Chernikovfrom typing import List
229f44a47fSAlexander V. Chernikovfrom typing import NamedTuple
239f44a47fSAlexander V. Chernikovfrom typing import Optional
249f44a47fSAlexander V. Chernikovfrom typing import Union
259f44a47fSAlexander V. Chernikov
269f44a47fSAlexander V. Chernikovimport pytest
279f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import Icmp6RejectCode
289f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import IcmpRejectCode
299f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import Insn
309f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import InsnComment
319f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import InsnEmpty
329f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import InsnIp
339f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import InsnIp6
349f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import InsnPorts
359f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import InsnProb
369f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import InsnProto
379f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import InsnReject
389f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import InsnTable
399f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import IpFwOpcode
409f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import CTlv
419f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import CTlvRule
429f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import IpFwTlvType
439f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import IpFwXRule
449f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import NTlv
459f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import Op3CmdType
469f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import RawRule
479f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ipfw import DebugIoReader
489f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import enum_from_int
499f44a47fSAlexander V. Chernikovfrom atf_python.utils import BaseTest
509f44a47fSAlexander V. Chernikov
519f44a47fSAlexander V. Chernikov
529f44a47fSAlexander V. ChernikovIPFW_PATH = "/sbin/ipfw"
539f44a47fSAlexander V. Chernikov
549f44a47fSAlexander V. Chernikov
559f44a47fSAlexander V. Chernikovdef differ(w_obj, g_obj, w_stack=[], g_stack=[]):
569f44a47fSAlexander V. Chernikov    if bytes(w_obj) == bytes(g_obj):
579f44a47fSAlexander V. Chernikov        return True
589f44a47fSAlexander V. Chernikov    num_objects = 0
599f44a47fSAlexander V. Chernikov    for i, w_child in enumerate(w_obj.obj_list):
60*7e1ec25cSAlexander V. Chernikov        if i >= len(g_obj.obj_list):
619f44a47fSAlexander V. Chernikov            print("MISSING object from chain {}".format(" / ".join(w_stack)))
629f44a47fSAlexander V. Chernikov            w_child.print_obj()
639f44a47fSAlexander V. Chernikov            print("==========================")
649f44a47fSAlexander V. Chernikov            return False
659f44a47fSAlexander V. Chernikov        g_child = g_obj.obj_list[i]
669f44a47fSAlexander V. Chernikov        if bytes(w_child) == bytes(g_child):
679f44a47fSAlexander V. Chernikov            num_objects += 1
689f44a47fSAlexander V. Chernikov            continue
699f44a47fSAlexander V. Chernikov        w_stack.append(w_obj.obj_name)
709f44a47fSAlexander V. Chernikov        g_stack.append(g_obj.obj_name)
719f44a47fSAlexander V. Chernikov        if not differ(w_child, g_child, w_stack, g_stack):
729f44a47fSAlexander V. Chernikov            return False
739f44a47fSAlexander V. Chernikov        break
749f44a47fSAlexander V. Chernikov    if num_objects == len(w_obj.obj_list) and num_objects < len(g_obj.obj_list):
759f44a47fSAlexander V. Chernikov        g_child = g_obj.obj_list[num_objects]
769f44a47fSAlexander V. Chernikov        print("EXTRA object from chain {}".format(" / ".join(g_stack)))
779f44a47fSAlexander V. Chernikov        g_child.print_obj()
789f44a47fSAlexander V. Chernikov        print("==========================")
799f44a47fSAlexander V. Chernikov        return False
809f44a47fSAlexander V. Chernikov    print("OBJECTS DIFFER")
819f44a47fSAlexander V. Chernikov    print("WANTED CHAIN: {}".format(" / ".join(w_stack)))
829f44a47fSAlexander V. Chernikov    w_obj.print_obj()
839f44a47fSAlexander V. Chernikov    w_obj.print_obj_hex()
849f44a47fSAlexander V. Chernikov    print("==========================")
859f44a47fSAlexander V. Chernikov    print("GOT CHAIN: {}".format(" / ".join(g_stack)))
869f44a47fSAlexander V. Chernikov    g_obj.print_obj()
879f44a47fSAlexander V. Chernikov    g_obj.print_obj_hex()
889f44a47fSAlexander V. Chernikov    print("==========================")
899f44a47fSAlexander V. Chernikov    return False
909f44a47fSAlexander V. Chernikov
919f44a47fSAlexander V. Chernikov
929f44a47fSAlexander V. Chernikovclass TestAddRule(BaseTest):
939f44a47fSAlexander V. Chernikov    def compile_rule(self, out):
949f44a47fSAlexander V. Chernikov        tlvs = []
959f44a47fSAlexander V. Chernikov        if "objs" in out:
969f44a47fSAlexander V. Chernikov            tlvs.append(CTlv(IpFwTlvType.IPFW_TLV_TBLNAME_LIST, out["objs"]))
979f44a47fSAlexander V. Chernikov        rule = RawRule(rulenum=out.get("rulenum", 0), obj_list=out["insns"])
989f44a47fSAlexander V. Chernikov        tlvs.append(CTlvRule(obj_list=[rule]))
999f44a47fSAlexander V. Chernikov        return IpFwXRule(Op3CmdType.IP_FW_XADD, tlvs)
1009f44a47fSAlexander V. Chernikov
1019f44a47fSAlexander V. Chernikov    def verify_rule(self, in_data: str, out_data):
1029f44a47fSAlexander V. Chernikov        # Prepare the desired output
1039f44a47fSAlexander V. Chernikov        expected = self.compile_rule(out_data)
1049f44a47fSAlexander V. Chernikov
1059f44a47fSAlexander V. Chernikov        reader = DebugIoReader(IPFW_PATH)
1069f44a47fSAlexander V. Chernikov        ioctls = reader.get_records(in_data)
1079f44a47fSAlexander V. Chernikov        assert len(ioctls) == 1  # Only 1 ioctl request expected
1089f44a47fSAlexander V. Chernikov        got = ioctls[0]
1099f44a47fSAlexander V. Chernikov
1109f44a47fSAlexander V. Chernikov        if not differ(expected, got):
1119f44a47fSAlexander V. Chernikov            print("=> CMD: {}".format(in_data))
1129f44a47fSAlexander V. Chernikov            print("=> WANTED:")
1139f44a47fSAlexander V. Chernikov            expected.print_obj()
1149f44a47fSAlexander V. Chernikov            print("==========================")
1159f44a47fSAlexander V. Chernikov            print("=> GOT:")
1169f44a47fSAlexander V. Chernikov            got.print_obj()
1179f44a47fSAlexander V. Chernikov            print("==========================")
1189f44a47fSAlexander V. Chernikov        assert bytes(got) == bytes(expected)
1199f44a47fSAlexander V. Chernikov
1209f44a47fSAlexander V. Chernikov    @pytest.mark.parametrize(
1219f44a47fSAlexander V. Chernikov        "rule",
1229f44a47fSAlexander V. Chernikov        [
1239f44a47fSAlexander V. Chernikov            pytest.param(
1249f44a47fSAlexander V. Chernikov                {
1259f44a47fSAlexander V. Chernikov                    "in": "add 200 allow ip from any to any",
1269f44a47fSAlexander V. Chernikov                    "out": {
1279f44a47fSAlexander V. Chernikov                        "insns": [InsnEmpty(IpFwOpcode.O_ACCEPT)],
1289f44a47fSAlexander V. Chernikov                        "rulenum": 200,
1299f44a47fSAlexander V. Chernikov                    },
1309f44a47fSAlexander V. Chernikov                },
1319f44a47fSAlexander V. Chernikov                id="test_rulenum",
1329f44a47fSAlexander V. Chernikov            ),
1339f44a47fSAlexander V. Chernikov            pytest.param(
1349f44a47fSAlexander V. Chernikov                {
1359f44a47fSAlexander V. Chernikov                    "in": "add allow ip from { 1.2.3.4 or 2.3.4.5 } to any",
1369f44a47fSAlexander V. Chernikov                    "out": {
1379f44a47fSAlexander V. Chernikov                        "insns": [
1389f44a47fSAlexander V. Chernikov                            InsnIp(IpFwOpcode.O_IP_SRC, ip="1.2.3.4", is_or=True),
1399f44a47fSAlexander V. Chernikov                            InsnIp(IpFwOpcode.O_IP_SRC, ip="2.3.4.5"),
1409f44a47fSAlexander V. Chernikov                            InsnEmpty(IpFwOpcode.O_ACCEPT),
1419f44a47fSAlexander V. Chernikov                        ],
1429f44a47fSAlexander V. Chernikov                    },
1439f44a47fSAlexander V. Chernikov                },
1449f44a47fSAlexander V. Chernikov                id="test_or",
1459f44a47fSAlexander V. Chernikov            ),
1469f44a47fSAlexander V. Chernikov            pytest.param(
1479f44a47fSAlexander V. Chernikov                {
1489f44a47fSAlexander V. Chernikov                    "in": "add allow ip from table(AAA) to table(BBB)",
1499f44a47fSAlexander V. Chernikov                    "out": {
1509f44a47fSAlexander V. Chernikov                        "objs": [
1519f44a47fSAlexander V. Chernikov                            NTlv(IpFwTlvType.IPFW_TLV_TBL_NAME, idx=1, name="AAA"),
1529f44a47fSAlexander V. Chernikov                            NTlv(IpFwTlvType.IPFW_TLV_TBL_NAME, idx=2, name="BBB"),
1539f44a47fSAlexander V. Chernikov                        ],
1549f44a47fSAlexander V. Chernikov                        "insns": [
1559f44a47fSAlexander V. Chernikov                            InsnTable(IpFwOpcode.O_IP_SRC_LOOKUP, arg1=1),
1569f44a47fSAlexander V. Chernikov                            InsnTable(IpFwOpcode.O_IP_DST_LOOKUP, arg1=2),
1579f44a47fSAlexander V. Chernikov                            InsnEmpty(IpFwOpcode.O_ACCEPT),
1589f44a47fSAlexander V. Chernikov                        ],
1599f44a47fSAlexander V. Chernikov                    },
1609f44a47fSAlexander V. Chernikov                },
1619f44a47fSAlexander V. Chernikov                id="test_tables",
1629f44a47fSAlexander V. Chernikov            ),
1639f44a47fSAlexander V. Chernikov            pytest.param(
1649f44a47fSAlexander V. Chernikov                {
1659f44a47fSAlexander V. Chernikov                    "in": "add allow ip from any to 1.2.3.4 // test comment",
1669f44a47fSAlexander V. Chernikov                    "out": {
1679f44a47fSAlexander V. Chernikov                        "insns": [
1689f44a47fSAlexander V. Chernikov                            InsnIp(IpFwOpcode.O_IP_DST, ip="1.2.3.4"),
1699f44a47fSAlexander V. Chernikov                            InsnComment(comment="test comment"),
1709f44a47fSAlexander V. Chernikov                            InsnEmpty(IpFwOpcode.O_ACCEPT),
1719f44a47fSAlexander V. Chernikov                        ],
1729f44a47fSAlexander V. Chernikov                    },
1739f44a47fSAlexander V. Chernikov                },
1749f44a47fSAlexander V. Chernikov                id="test_comment",
1759f44a47fSAlexander V. Chernikov            ),
17684b41342SAlexander V. Chernikov            pytest.param(
17784b41342SAlexander V. Chernikov                {
17884b41342SAlexander V. Chernikov                    "in": "add tcp-setmss 123 ip from any to 1.2.3.4",
17984b41342SAlexander V. Chernikov                    "out": {
18084b41342SAlexander V. Chernikov                        "objs": [
18184b41342SAlexander V. Chernikov                            NTlv(IpFwTlvType.IPFW_TLV_EACTION, idx=1, name="tcp-setmss"),
18284b41342SAlexander V. Chernikov                        ],
18384b41342SAlexander V. Chernikov                        "insns": [
18484b41342SAlexander V. Chernikov                            InsnIp(IpFwOpcode.O_IP_DST, ip="1.2.3.4"),
18584b41342SAlexander V. Chernikov                            Insn(IpFwOpcode.O_EXTERNAL_ACTION, arg1=1),
18684b41342SAlexander V. Chernikov                            Insn(IpFwOpcode.O_EXTERNAL_DATA, arg1=123),
18784b41342SAlexander V. Chernikov                        ],
18884b41342SAlexander V. Chernikov                    },
18984b41342SAlexander V. Chernikov                },
19084b41342SAlexander V. Chernikov                id="test_eaction_tcp-setmss",
19184b41342SAlexander V. Chernikov            ),
19284b41342SAlexander V. Chernikov            pytest.param(
19384b41342SAlexander V. Chernikov                {
19484b41342SAlexander V. Chernikov                    "in": "add eaction ntpv6 AAA ip from any to 1.2.3.4",
19584b41342SAlexander V. Chernikov                    "out": {
19684b41342SAlexander V. Chernikov                        "objs": [
19784b41342SAlexander V. Chernikov                            NTlv(IpFwTlvType.IPFW_TLV_EACTION, idx=1, name="ntpv6"),
19884b41342SAlexander V. Chernikov                            NTlv(0, idx=2, name="AAA"),
19984b41342SAlexander V. Chernikov                        ],
20084b41342SAlexander V. Chernikov                        "insns": [
20184b41342SAlexander V. Chernikov                            InsnIp(IpFwOpcode.O_IP_DST, ip="1.2.3.4"),
20284b41342SAlexander V. Chernikov                            Insn(IpFwOpcode.O_EXTERNAL_ACTION, arg1=1),
20384b41342SAlexander V. Chernikov                            Insn(IpFwOpcode.O_EXTERNAL_INSTANCE, arg1=2),
20484b41342SAlexander V. Chernikov                        ],
20584b41342SAlexander V. Chernikov                    },
20684b41342SAlexander V. Chernikov                },
20784b41342SAlexander V. Chernikov                id="test_eaction_ntp",
20884b41342SAlexander V. Chernikov            ),
209*7e1ec25cSAlexander V. Chernikov            pytest.param(
210*7e1ec25cSAlexander V. Chernikov                {
211*7e1ec25cSAlexander V. Chernikov                    "in": "add // test comment",
212*7e1ec25cSAlexander V. Chernikov                    "out": {
213*7e1ec25cSAlexander V. Chernikov                        "insns": [
214*7e1ec25cSAlexander V. Chernikov                            InsnComment(comment="test comment"),
215*7e1ec25cSAlexander V. Chernikov                            Insn(IpFwOpcode.O_COUNT),
216*7e1ec25cSAlexander V. Chernikov                        ],
217*7e1ec25cSAlexander V. Chernikov                    },
218*7e1ec25cSAlexander V. Chernikov                },
219*7e1ec25cSAlexander V. Chernikov                id="test_action_comment",
220*7e1ec25cSAlexander V. Chernikov            ),
221*7e1ec25cSAlexander V. Chernikov            pytest.param(
222*7e1ec25cSAlexander V. Chernikov                {
223*7e1ec25cSAlexander V. Chernikov                    "in": "add check-state :OUT // test comment",
224*7e1ec25cSAlexander V. Chernikov                    "out": {
225*7e1ec25cSAlexander V. Chernikov                        "objs": [
226*7e1ec25cSAlexander V. Chernikov                            NTlv(IpFwTlvType.IPFW_TLV_STATE_NAME, idx=1, name="OUT"),
227*7e1ec25cSAlexander V. Chernikov                        ],
228*7e1ec25cSAlexander V. Chernikov                        "insns": [
229*7e1ec25cSAlexander V. Chernikov                            InsnComment(comment="test comment"),
230*7e1ec25cSAlexander V. Chernikov                            Insn(IpFwOpcode.O_CHECK_STATE, arg1=1),
231*7e1ec25cSAlexander V. Chernikov                        ],
232*7e1ec25cSAlexander V. Chernikov                    },
233*7e1ec25cSAlexander V. Chernikov                },
234*7e1ec25cSAlexander V. Chernikov                id="test_check_state",
235*7e1ec25cSAlexander V. Chernikov            ),
236*7e1ec25cSAlexander V. Chernikov            pytest.param(
237*7e1ec25cSAlexander V. Chernikov                {
238*7e1ec25cSAlexander V. Chernikov                    "in": "add allow tcp from any to any keep-state :OUT",
239*7e1ec25cSAlexander V. Chernikov                    "out": {
240*7e1ec25cSAlexander V. Chernikov                        "objs": [
241*7e1ec25cSAlexander V. Chernikov                            NTlv(IpFwTlvType.IPFW_TLV_STATE_NAME, idx=1, name="OUT"),
242*7e1ec25cSAlexander V. Chernikov                        ],
243*7e1ec25cSAlexander V. Chernikov                        "insns": [
244*7e1ec25cSAlexander V. Chernikov                            Insn(IpFwOpcode.O_PROBE_STATE, arg1=1),
245*7e1ec25cSAlexander V. Chernikov                            Insn(IpFwOpcode.O_PROTO, arg1=6),
246*7e1ec25cSAlexander V. Chernikov                            Insn(IpFwOpcode.O_KEEP_STATE, arg1=1),
247*7e1ec25cSAlexander V. Chernikov                            InsnEmpty(IpFwOpcode.O_ACCEPT),
248*7e1ec25cSAlexander V. Chernikov                        ],
249*7e1ec25cSAlexander V. Chernikov                    },
250*7e1ec25cSAlexander V. Chernikov                },
251*7e1ec25cSAlexander V. Chernikov                id="test_keep_state",
252*7e1ec25cSAlexander V. Chernikov            ),
253*7e1ec25cSAlexander V. Chernikov            pytest.param(
254*7e1ec25cSAlexander V. Chernikov                {
255*7e1ec25cSAlexander V. Chernikov                    "in": "add allow tcp from any to any record-state",
256*7e1ec25cSAlexander V. Chernikov                    "out": {
257*7e1ec25cSAlexander V. Chernikov                        "objs": [
258*7e1ec25cSAlexander V. Chernikov                            NTlv(IpFwTlvType.IPFW_TLV_STATE_NAME, idx=1, name="default"),
259*7e1ec25cSAlexander V. Chernikov                        ],
260*7e1ec25cSAlexander V. Chernikov                        "insns": [
261*7e1ec25cSAlexander V. Chernikov                            Insn(IpFwOpcode.O_PROTO, arg1=6),
262*7e1ec25cSAlexander V. Chernikov                            Insn(IpFwOpcode.O_KEEP_STATE, arg1=1),
263*7e1ec25cSAlexander V. Chernikov                            InsnEmpty(IpFwOpcode.O_ACCEPT),
264*7e1ec25cSAlexander V. Chernikov                        ],
265*7e1ec25cSAlexander V. Chernikov                    },
266*7e1ec25cSAlexander V. Chernikov                },
267*7e1ec25cSAlexander V. Chernikov                id="test_record_state",
268*7e1ec25cSAlexander V. Chernikov            ),
2699f44a47fSAlexander V. Chernikov        ],
2709f44a47fSAlexander V. Chernikov    )
2719f44a47fSAlexander V. Chernikov    def test_add_rule(self, rule):
2729f44a47fSAlexander V. Chernikov        """Tests if the compiled rule is sane and matches the spec"""
2739f44a47fSAlexander V. Chernikov        self.verify_rule(rule["in"], rule["out"])
2749f44a47fSAlexander V. Chernikov
2759f44a47fSAlexander V. Chernikov    @pytest.mark.parametrize(
2769f44a47fSAlexander V. Chernikov        "action",
2779f44a47fSAlexander V. Chernikov        [
2789f44a47fSAlexander V. Chernikov            pytest.param(("allow", InsnEmpty(IpFwOpcode.O_ACCEPT)), id="test_allow"),
2799f44a47fSAlexander V. Chernikov            pytest.param(
2809f44a47fSAlexander V. Chernikov                (
2819f44a47fSAlexander V. Chernikov                    "abort",
2829f44a47fSAlexander V. Chernikov                    Insn(IpFwOpcode.O_REJECT, arg1=IcmpRejectCode.ICMP_REJECT_ABORT),
2839f44a47fSAlexander V. Chernikov                ),
2849f44a47fSAlexander V. Chernikov                id="abort",
2859f44a47fSAlexander V. Chernikov            ),
2869f44a47fSAlexander V. Chernikov            pytest.param(
2879f44a47fSAlexander V. Chernikov                (
2889f44a47fSAlexander V. Chernikov                    "abort6",
2899f44a47fSAlexander V. Chernikov                    Insn(
2909f44a47fSAlexander V. Chernikov                        IpFwOpcode.O_UNREACH6, arg1=Icmp6RejectCode.ICMP6_UNREACH_ABORT
2919f44a47fSAlexander V. Chernikov                    ),
2929f44a47fSAlexander V. Chernikov                ),
2939f44a47fSAlexander V. Chernikov                id="abort6",
2949f44a47fSAlexander V. Chernikov            ),
2959f44a47fSAlexander V. Chernikov            pytest.param(("accept", InsnEmpty(IpFwOpcode.O_ACCEPT)), id="accept"),
2969f44a47fSAlexander V. Chernikov            pytest.param(("deny", InsnEmpty(IpFwOpcode.O_DENY)), id="deny"),
2979f44a47fSAlexander V. Chernikov            pytest.param(
2989f44a47fSAlexander V. Chernikov                (
2999f44a47fSAlexander V. Chernikov                    "reject",
3009f44a47fSAlexander V. Chernikov                    Insn(IpFwOpcode.O_REJECT, arg1=IcmpRejectCode.ICMP_UNREACH_HOST),
3019f44a47fSAlexander V. Chernikov                ),
3029f44a47fSAlexander V. Chernikov                id="reject",
3039f44a47fSAlexander V. Chernikov            ),
3049f44a47fSAlexander V. Chernikov            pytest.param(
3059f44a47fSAlexander V. Chernikov                (
3069f44a47fSAlexander V. Chernikov                    "reset",
3079f44a47fSAlexander V. Chernikov                    Insn(IpFwOpcode.O_REJECT, arg1=IcmpRejectCode.ICMP_REJECT_RST),
3089f44a47fSAlexander V. Chernikov                ),
3099f44a47fSAlexander V. Chernikov                id="reset",
3109f44a47fSAlexander V. Chernikov            ),
3119f44a47fSAlexander V. Chernikov            pytest.param(
3129f44a47fSAlexander V. Chernikov                (
3139f44a47fSAlexander V. Chernikov                    "reset6",
3149f44a47fSAlexander V. Chernikov                    Insn(IpFwOpcode.O_UNREACH6, arg1=Icmp6RejectCode.ICMP6_UNREACH_RST),
3159f44a47fSAlexander V. Chernikov                ),
3169f44a47fSAlexander V. Chernikov                id="reset6",
3179f44a47fSAlexander V. Chernikov            ),
3189f44a47fSAlexander V. Chernikov            pytest.param(
3199f44a47fSAlexander V. Chernikov                (
3209f44a47fSAlexander V. Chernikov                    "unreach port",
3219f44a47fSAlexander V. Chernikov                    InsnReject(
3229f44a47fSAlexander V. Chernikov                        IpFwOpcode.O_REJECT, arg1=IcmpRejectCode.ICMP_UNREACH_PORT
3239f44a47fSAlexander V. Chernikov                    ),
3249f44a47fSAlexander V. Chernikov                ),
3259f44a47fSAlexander V. Chernikov                id="unreach_port",
3269f44a47fSAlexander V. Chernikov            ),
3279f44a47fSAlexander V. Chernikov            pytest.param(
3289f44a47fSAlexander V. Chernikov                (
3299f44a47fSAlexander V. Chernikov                    "unreach port",
3309f44a47fSAlexander V. Chernikov                    InsnReject(
3319f44a47fSAlexander V. Chernikov                        IpFwOpcode.O_REJECT, arg1=IcmpRejectCode.ICMP_UNREACH_PORT
3329f44a47fSAlexander V. Chernikov                    ),
3339f44a47fSAlexander V. Chernikov                ),
3349f44a47fSAlexander V. Chernikov                id="unreach_port",
3359f44a47fSAlexander V. Chernikov            ),
3369f44a47fSAlexander V. Chernikov            pytest.param(
3379f44a47fSAlexander V. Chernikov                (
3389f44a47fSAlexander V. Chernikov                    "unreach needfrag",
3399f44a47fSAlexander V. Chernikov                    InsnReject(
3409f44a47fSAlexander V. Chernikov                        IpFwOpcode.O_REJECT, arg1=IcmpRejectCode.ICMP_UNREACH_NEEDFRAG
3419f44a47fSAlexander V. Chernikov                    ),
3429f44a47fSAlexander V. Chernikov                ),
3439f44a47fSAlexander V. Chernikov                id="unreach_needfrag",
3449f44a47fSAlexander V. Chernikov            ),
3459f44a47fSAlexander V. Chernikov            pytest.param(
3469f44a47fSAlexander V. Chernikov                (
3479f44a47fSAlexander V. Chernikov                    "unreach needfrag 1420",
3489f44a47fSAlexander V. Chernikov                    InsnReject(
3499f44a47fSAlexander V. Chernikov                        IpFwOpcode.O_REJECT,
3509f44a47fSAlexander V. Chernikov                        arg1=IcmpRejectCode.ICMP_UNREACH_NEEDFRAG,
3519f44a47fSAlexander V. Chernikov                        mtu=1420,
3529f44a47fSAlexander V. Chernikov                    ),
3539f44a47fSAlexander V. Chernikov                ),
3549f44a47fSAlexander V. Chernikov                id="unreach_needfrag_mtu",
3559f44a47fSAlexander V. Chernikov            ),
3569f44a47fSAlexander V. Chernikov            pytest.param(
3579f44a47fSAlexander V. Chernikov                (
3589f44a47fSAlexander V. Chernikov                    "unreach6 port",
3599f44a47fSAlexander V. Chernikov                    Insn(
3609f44a47fSAlexander V. Chernikov                        IpFwOpcode.O_UNREACH6,
3619f44a47fSAlexander V. Chernikov                        arg1=Icmp6RejectCode.ICMP6_DST_UNREACH_NOPORT,
3629f44a47fSAlexander V. Chernikov                    ),
3639f44a47fSAlexander V. Chernikov                ),
3649f44a47fSAlexander V. Chernikov                id="unreach6_port",
3659f44a47fSAlexander V. Chernikov            ),
3669f44a47fSAlexander V. Chernikov            pytest.param(("count", InsnEmpty(IpFwOpcode.O_COUNT)), id="count"),
3679f44a47fSAlexander V. Chernikov            # TOK_NAT
3689f44a47fSAlexander V. Chernikov            pytest.param(
3699f44a47fSAlexander V. Chernikov                ("queue 42", Insn(IpFwOpcode.O_QUEUE, arg1=42)), id="queue_42"
3709f44a47fSAlexander V. Chernikov            ),
3719f44a47fSAlexander V. Chernikov            pytest.param(("pipe 42", Insn(IpFwOpcode.O_PIPE, arg1=42)), id="pipe_42"),
3729f44a47fSAlexander V. Chernikov            pytest.param(
3739f44a47fSAlexander V. Chernikov                ("skipto 42", Insn(IpFwOpcode.O_SKIPTO, arg1=42)), id="skipto_42"
3749f44a47fSAlexander V. Chernikov            ),
3759f44a47fSAlexander V. Chernikov            pytest.param(
3769f44a47fSAlexander V. Chernikov                ("netgraph 42", Insn(IpFwOpcode.O_NETGRAPH, arg1=42)), id="netgraph_42"
3779f44a47fSAlexander V. Chernikov            ),
3789f44a47fSAlexander V. Chernikov            pytest.param(
3799f44a47fSAlexander V. Chernikov                ("ngtee 42", Insn(IpFwOpcode.O_NGTEE, arg1=42)), id="ngtee_42"
3809f44a47fSAlexander V. Chernikov            ),
3819f44a47fSAlexander V. Chernikov            pytest.param(
3829f44a47fSAlexander V. Chernikov                ("divert 42", Insn(IpFwOpcode.O_DIVERT, arg1=42)), id="divert_42"
3839f44a47fSAlexander V. Chernikov            ),
3849f44a47fSAlexander V. Chernikov            pytest.param(
3859f44a47fSAlexander V. Chernikov                ("divert natd", Insn(IpFwOpcode.O_DIVERT, arg1=8668)), id="divert_natd"
3869f44a47fSAlexander V. Chernikov            ),
3879f44a47fSAlexander V. Chernikov            pytest.param(("tee 42", Insn(IpFwOpcode.O_TEE, arg1=42)), id="tee_42"),
3889f44a47fSAlexander V. Chernikov            pytest.param(
3899f44a47fSAlexander V. Chernikov                ("call 420", Insn(IpFwOpcode.O_CALLRETURN, arg1=420)), id="call_420"
3909f44a47fSAlexander V. Chernikov            ),
3919f44a47fSAlexander V. Chernikov            # TOK_FORWARD
3929f44a47fSAlexander V. Chernikov            pytest.param(
3939f44a47fSAlexander V. Chernikov                ("setfib 1", Insn(IpFwOpcode.O_SETFIB, arg1=1 | 0x8000)),
3949f44a47fSAlexander V. Chernikov                id="setfib_1",
3959f44a47fSAlexander V. Chernikov                marks=pytest.mark.skip("needs net.fibs>1"),
3969f44a47fSAlexander V. Chernikov            ),
3979f44a47fSAlexander V. Chernikov            pytest.param(
3989f44a47fSAlexander V. Chernikov                ("setdscp 42", Insn(IpFwOpcode.O_SETDSCP, arg1=42 | 0x8000)),
3999f44a47fSAlexander V. Chernikov                id="setdscp_42",
4009f44a47fSAlexander V. Chernikov            ),
4019f44a47fSAlexander V. Chernikov            pytest.param(("reass", InsnEmpty(IpFwOpcode.O_REASS)), id="reass"),
4029f44a47fSAlexander V. Chernikov            pytest.param(
4039f44a47fSAlexander V. Chernikov                ("return", InsnEmpty(IpFwOpcode.O_CALLRETURN, is_not=True)), id="return"
4049f44a47fSAlexander V. Chernikov            ),
4059f44a47fSAlexander V. Chernikov        ],
4069f44a47fSAlexander V. Chernikov    )
4079f44a47fSAlexander V. Chernikov    def test_add_action(self, action):
4089f44a47fSAlexander V. Chernikov        """Tests if the rule action is compiled properly"""
4099f44a47fSAlexander V. Chernikov        rule_in = "add {} ip from any to any".format(action[0])
4109f44a47fSAlexander V. Chernikov        rule_out = {"insns": [action[1]]}
4119f44a47fSAlexander V. Chernikov        self.verify_rule(rule_in, rule_out)
4129f44a47fSAlexander V. Chernikov
4139f44a47fSAlexander V. Chernikov    @pytest.mark.parametrize(
4149f44a47fSAlexander V. Chernikov        "insn",
4159f44a47fSAlexander V. Chernikov        [
4169f44a47fSAlexander V. Chernikov            pytest.param(
4179f44a47fSAlexander V. Chernikov                {
4189f44a47fSAlexander V. Chernikov                    "in": "add prob 0.7 allow ip from any to any",
4199f44a47fSAlexander V. Chernikov                    "out": InsnProb(prob=0.7),
4209f44a47fSAlexander V. Chernikov                },
4219f44a47fSAlexander V. Chernikov                id="test_prob",
4229f44a47fSAlexander V. Chernikov            ),
4239f44a47fSAlexander V. Chernikov            pytest.param(
4249f44a47fSAlexander V. Chernikov                {
4259f44a47fSAlexander V. Chernikov                    "in": "add allow tcp from any to any",
4269f44a47fSAlexander V. Chernikov                    "out": InsnProto(arg1=6),
4279f44a47fSAlexander V. Chernikov                },
4289f44a47fSAlexander V. Chernikov                id="test_proto",
4299f44a47fSAlexander V. Chernikov            ),
4309f44a47fSAlexander V. Chernikov            pytest.param(
4319f44a47fSAlexander V. Chernikov                {
4329f44a47fSAlexander V. Chernikov                    "in": "add allow ip from any to any 57",
4339f44a47fSAlexander V. Chernikov                    "out": InsnPorts(IpFwOpcode.O_IP_DSTPORT, port_pairs=[57, 57]),
4349f44a47fSAlexander V. Chernikov                },
4359f44a47fSAlexander V. Chernikov                id="test_ports",
4369f44a47fSAlexander V. Chernikov            ),
4379f44a47fSAlexander V. Chernikov        ],
4389f44a47fSAlexander V. Chernikov    )
4399f44a47fSAlexander V. Chernikov    def test_add_single_instruction(self, insn):
4409f44a47fSAlexander V. Chernikov        """Tests if the compiled rule is sane and matches the spec"""
4419f44a47fSAlexander V. Chernikov
4429f44a47fSAlexander V. Chernikov        # Prepare the desired output
4439f44a47fSAlexander V. Chernikov        out = {
4449f44a47fSAlexander V. Chernikov            "insns": [insn["out"], InsnEmpty(IpFwOpcode.O_ACCEPT)],
4459f44a47fSAlexander V. Chernikov        }
4469f44a47fSAlexander V. Chernikov        self.verify_rule(insn["in"], out)
4479f44a47fSAlexander V. Chernikov
4489f44a47fSAlexander V. Chernikov    @pytest.mark.parametrize(
4499f44a47fSAlexander V. Chernikov        "opcode",
4509f44a47fSAlexander V. Chernikov        [
4519f44a47fSAlexander V. Chernikov            pytest.param(IpFwOpcode.O_IP_SRCPORT, id="src"),
4529f44a47fSAlexander V. Chernikov            pytest.param(IpFwOpcode.O_IP_DSTPORT, id="dst"),
4539f44a47fSAlexander V. Chernikov        ],
4549f44a47fSAlexander V. Chernikov    )
4559f44a47fSAlexander V. Chernikov    @pytest.mark.parametrize(
4569f44a47fSAlexander V. Chernikov        "params",
4579f44a47fSAlexander V. Chernikov        [
4589f44a47fSAlexander V. Chernikov            pytest.param(
4599f44a47fSAlexander V. Chernikov                {
4609f44a47fSAlexander V. Chernikov                    "in": "57",
4619f44a47fSAlexander V. Chernikov                    "out": [(57, 57)],
4629f44a47fSAlexander V. Chernikov                },
4639f44a47fSAlexander V. Chernikov                id="test_single",
4649f44a47fSAlexander V. Chernikov            ),
4659f44a47fSAlexander V. Chernikov            pytest.param(
4669f44a47fSAlexander V. Chernikov                {
4679f44a47fSAlexander V. Chernikov                    "in": "57-59",
4689f44a47fSAlexander V. Chernikov                    "out": [(57, 59)],
4699f44a47fSAlexander V. Chernikov                },
4709f44a47fSAlexander V. Chernikov                id="test_range",
4719f44a47fSAlexander V. Chernikov            ),
4729f44a47fSAlexander V. Chernikov            pytest.param(
4739f44a47fSAlexander V. Chernikov                {
4749f44a47fSAlexander V. Chernikov                    "in": "57-59,41",
4759f44a47fSAlexander V. Chernikov                    "out": [(57, 59), (41, 41)],
4769f44a47fSAlexander V. Chernikov                },
4779f44a47fSAlexander V. Chernikov                id="test_ranges",
4789f44a47fSAlexander V. Chernikov            ),
4799f44a47fSAlexander V. Chernikov        ],
4809f44a47fSAlexander V. Chernikov    )
4819f44a47fSAlexander V. Chernikov    def test_add_ports(self, params, opcode):
4829f44a47fSAlexander V. Chernikov        if opcode == IpFwOpcode.O_IP_DSTPORT:
4839f44a47fSAlexander V. Chernikov            txt = "add allow ip from any to any " + params["in"]
4849f44a47fSAlexander V. Chernikov        else:
4859f44a47fSAlexander V. Chernikov            txt = "add allow ip from any " + params["in"] + " to any"
4869f44a47fSAlexander V. Chernikov        out = {
4879f44a47fSAlexander V. Chernikov            "insns": [
4889f44a47fSAlexander V. Chernikov                InsnPorts(opcode, port_pairs=params["out"]),
4899f44a47fSAlexander V. Chernikov                InsnEmpty(IpFwOpcode.O_ACCEPT),
4909f44a47fSAlexander V. Chernikov            ]
4919f44a47fSAlexander V. Chernikov        }
4929f44a47fSAlexander V. Chernikov        self.verify_rule(txt, out)
493