xref: /freebsd/tests/atf_python/sys/netpfil/ipfw/ipfw.py (revision 9f44a47fd07924afc035991af15d84e6585dea4f)
1*9f44a47fSAlexander V. Chernikov#!/usr/bin/env python3
2*9f44a47fSAlexander V. Chernikovimport os
3*9f44a47fSAlexander V. Chernikovimport socket
4*9f44a47fSAlexander V. Chernikovimport struct
5*9f44a47fSAlexander V. Chernikovimport subprocess
6*9f44a47fSAlexander V. Chernikovimport sys
7*9f44a47fSAlexander V. Chernikovfrom ctypes import c_byte
8*9f44a47fSAlexander V. Chernikovfrom ctypes import c_char
9*9f44a47fSAlexander V. Chernikovfrom ctypes import c_int
10*9f44a47fSAlexander V. Chernikovfrom ctypes import c_long
11*9f44a47fSAlexander V. Chernikovfrom ctypes import c_uint32
12*9f44a47fSAlexander V. Chernikovfrom ctypes import c_uint8
13*9f44a47fSAlexander V. Chernikovfrom ctypes import c_ulong
14*9f44a47fSAlexander V. Chernikovfrom ctypes import c_ushort
15*9f44a47fSAlexander V. Chernikovfrom ctypes import sizeof
16*9f44a47fSAlexander V. Chernikovfrom ctypes import Structure
17*9f44a47fSAlexander V. Chernikovfrom enum import Enum
18*9f44a47fSAlexander V. Chernikovfrom typing import Any
19*9f44a47fSAlexander V. Chernikovfrom typing import Dict
20*9f44a47fSAlexander V. Chernikovfrom typing import List
21*9f44a47fSAlexander V. Chernikovfrom typing import NamedTuple
22*9f44a47fSAlexander V. Chernikovfrom typing import Optional
23*9f44a47fSAlexander V. Chernikovfrom typing import Union
24*9f44a47fSAlexander V. Chernikov
25*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import get3_classes
26*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import legacy_classes
27*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl import set3_classes
28*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import AttrDescr
29*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import enum_from_int
30*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import enum_or_int
31*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import prepare_attrs_map
32*9f44a47fSAlexander V. Chernikov
33*9f44a47fSAlexander V. Chernikov
34*9f44a47fSAlexander V. Chernikovclass DebugHeader(Structure):
35*9f44a47fSAlexander V. Chernikov    _fields_ = [
36*9f44a47fSAlexander V. Chernikov        ("cmd_type", c_ushort),
37*9f44a47fSAlexander V. Chernikov        ("spare1", c_ushort),
38*9f44a47fSAlexander V. Chernikov        ("opt_name", c_uint32),
39*9f44a47fSAlexander V. Chernikov        ("total_len", c_uint32),
40*9f44a47fSAlexander V. Chernikov        ("spare2", c_uint32),
41*9f44a47fSAlexander V. Chernikov    ]
42*9f44a47fSAlexander V. Chernikov
43*9f44a47fSAlexander V. Chernikov
44*9f44a47fSAlexander V. Chernikovclass DebugType(Enum):
45*9f44a47fSAlexander V. Chernikov    DO_CMD = 1
46*9f44a47fSAlexander V. Chernikov    DO_SET3 = 2
47*9f44a47fSAlexander V. Chernikov    DO_GET3 = 3
48*9f44a47fSAlexander V. Chernikov
49*9f44a47fSAlexander V. Chernikov
50*9f44a47fSAlexander V. Chernikovclass DebugIoReader(object):
51*9f44a47fSAlexander V. Chernikov    HANDLER_CLASSES = {
52*9f44a47fSAlexander V. Chernikov        DebugType.DO_CMD: legacy_classes,
53*9f44a47fSAlexander V. Chernikov        DebugType.DO_SET3: set3_classes,
54*9f44a47fSAlexander V. Chernikov        DebugType.DO_GET3: get3_classes,
55*9f44a47fSAlexander V. Chernikov    }
56*9f44a47fSAlexander V. Chernikov
57*9f44a47fSAlexander V. Chernikov    def __init__(self, ipfw_path):
58*9f44a47fSAlexander V. Chernikov        self._msgmap = self.build_msgmap()
59*9f44a47fSAlexander V. Chernikov        self.ipfw_path = ipfw_path
60*9f44a47fSAlexander V. Chernikov
61*9f44a47fSAlexander V. Chernikov    def build_msgmap(self):
62*9f44a47fSAlexander V. Chernikov        xmap = {}
63*9f44a47fSAlexander V. Chernikov        for debug_type, handler_classes in self.HANDLER_CLASSES.items():
64*9f44a47fSAlexander V. Chernikov            debug_type = enum_or_int(debug_type)
65*9f44a47fSAlexander V. Chernikov            if debug_type not in xmap:
66*9f44a47fSAlexander V. Chernikov                xmap[debug_type] = {}
67*9f44a47fSAlexander V. Chernikov            for handler_class in handler_classes:
68*9f44a47fSAlexander V. Chernikov                for msg in handler_class.messages:
69*9f44a47fSAlexander V. Chernikov                    xmap[debug_type][enum_or_int(msg)] = handler_class
70*9f44a47fSAlexander V. Chernikov        return xmap
71*9f44a47fSAlexander V. Chernikov
72*9f44a47fSAlexander V. Chernikov    def print_obj_header(self, hdr):
73*9f44a47fSAlexander V. Chernikov        debug_type = "#{}".format(hdr.cmd_type)
74*9f44a47fSAlexander V. Chernikov        for _type in self.HANDLER_CLASSES.keys():
75*9f44a47fSAlexander V. Chernikov            if _type.value == hdr.cmd_type:
76*9f44a47fSAlexander V. Chernikov                debug_type = _type.name.lower()
77*9f44a47fSAlexander V. Chernikov                break
78*9f44a47fSAlexander V. Chernikov        print(
79*9f44a47fSAlexander V. Chernikov            "@@ record for {} len={} optname={}".format(
80*9f44a47fSAlexander V. Chernikov                debug_type, hdr.total_len, hdr.opt_name
81*9f44a47fSAlexander V. Chernikov            )
82*9f44a47fSAlexander V. Chernikov        )
83*9f44a47fSAlexander V. Chernikov
84*9f44a47fSAlexander V. Chernikov    def parse_record(self, data):
85*9f44a47fSAlexander V. Chernikov        hdr = DebugHeader.from_buffer_copy(data[: sizeof(DebugHeader)])
86*9f44a47fSAlexander V. Chernikov        data = data[sizeof(DebugHeader) :]
87*9f44a47fSAlexander V. Chernikov        cls = self._msgmap[hdr.cmd_type].get(hdr.opt_name)
88*9f44a47fSAlexander V. Chernikov        if cls is not None:
89*9f44a47fSAlexander V. Chernikov            return cls.from_bytes(data)
90*9f44a47fSAlexander V. Chernikov        raise ValueError(
91*9f44a47fSAlexander V. Chernikov            "unsupported cmd_type={} opt_name={}".format(hdr.cmd_type, hdr.opt_name)
92*9f44a47fSAlexander V. Chernikov        )
93*9f44a47fSAlexander V. Chernikov
94*9f44a47fSAlexander V. Chernikov    def get_record_from_stdin(self):
95*9f44a47fSAlexander V. Chernikov        data = sys.stdin.buffer.peek(sizeof(DebugHeader))
96*9f44a47fSAlexander V. Chernikov        if len(data) == 0:
97*9f44a47fSAlexander V. Chernikov            return None
98*9f44a47fSAlexander V. Chernikov
99*9f44a47fSAlexander V. Chernikov        hdr = DebugHeader.from_buffer_copy(data)
100*9f44a47fSAlexander V. Chernikov        data = sys.stdin.buffer.read(hdr.total_len)
101*9f44a47fSAlexander V. Chernikov        return self.parse_record(data)
102*9f44a47fSAlexander V. Chernikov
103*9f44a47fSAlexander V. Chernikov    def get_records_from_buffer(self, data):
104*9f44a47fSAlexander V. Chernikov        off = 0
105*9f44a47fSAlexander V. Chernikov        ret = []
106*9f44a47fSAlexander V. Chernikov        while off + sizeof(DebugHeader) <= len(data):
107*9f44a47fSAlexander V. Chernikov            hdr = DebugHeader.from_buffer_copy(data[off : off + sizeof(DebugHeader)])
108*9f44a47fSAlexander V. Chernikov            ret.append(self.parse_record(data[off : off + hdr.total_len]))
109*9f44a47fSAlexander V. Chernikov            off += hdr.total_len
110*9f44a47fSAlexander V. Chernikov        return ret
111*9f44a47fSAlexander V. Chernikov
112*9f44a47fSAlexander V. Chernikov    def run_ipfw(self, cmd: str) -> bytes:
113*9f44a47fSAlexander V. Chernikov        args = [self.ipfw_path, "-xqn"] + cmd.split()
114*9f44a47fSAlexander V. Chernikov        r = subprocess.run(args, capture_output=True)
115*9f44a47fSAlexander V. Chernikov        return r.stdout
116*9f44a47fSAlexander V. Chernikov
117*9f44a47fSAlexander V. Chernikov    def get_records(self, cmd: str):
118*9f44a47fSAlexander V. Chernikov        return self.get_records_from_buffer(self.run_ipfw(cmd))
119