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