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.insn_headers import IpFwOpcode 26*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insn_headers import IcmpRejectCode 27*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insn_headers import Icmp6RejectCode 28*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import AttrDescr 29*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import enum_or_int 30*9f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import enum_from_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. Chernikovinsn_actions = ( 35*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_CHECK_STATE.value, 36*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_REJECT.value, 37*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_UNREACH6.value, 38*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_ACCEPT.value, 39*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_DENY.value, 40*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_COUNT.value, 41*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_NAT.value, 42*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_QUEUE.value, 43*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_PIPE.value, 44*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_SKIPTO.value, 45*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_NETGRAPH.value, 46*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_NGTEE.value, 47*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_DIVERT.value, 48*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_TEE.value, 49*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_CALLRETURN.value, 50*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_FORWARD_IP.value, 51*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_FORWARD_IP6.value, 52*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_SETFIB.value, 53*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_SETDSCP.value, 54*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_REASS.value, 55*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_SETMARK.value, 56*9f44a47fSAlexander V. Chernikov IpFwOpcode.O_EXTERNAL_ACTION.value, 57*9f44a47fSAlexander V. Chernikov) 58*9f44a47fSAlexander V. Chernikov 59*9f44a47fSAlexander V. Chernikov 60*9f44a47fSAlexander V. Chernikovclass IpFwInsn(Structure): 61*9f44a47fSAlexander V. Chernikov _fields_ = [ 62*9f44a47fSAlexander V. Chernikov ("opcode", c_uint8), 63*9f44a47fSAlexander V. Chernikov ("length", c_uint8), 64*9f44a47fSAlexander V. Chernikov ("arg1", c_ushort), 65*9f44a47fSAlexander V. Chernikov ] 66*9f44a47fSAlexander V. Chernikov 67*9f44a47fSAlexander V. Chernikov 68*9f44a47fSAlexander V. Chernikovclass BaseInsn(object): 69*9f44a47fSAlexander V. Chernikov obj_enum_class = IpFwOpcode 70*9f44a47fSAlexander V. Chernikov 71*9f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or, is_not, arg1): 72*9f44a47fSAlexander V. Chernikov if isinstance(opcode, Enum): 73*9f44a47fSAlexander V. Chernikov self.obj_type = opcode.value 74*9f44a47fSAlexander V. Chernikov self._enum = opcode 75*9f44a47fSAlexander V. Chernikov else: 76*9f44a47fSAlexander V. Chernikov self.obj_type = opcode 77*9f44a47fSAlexander V. Chernikov self._enum = enum_from_int(self.obj_enum_class, self.obj_type) 78*9f44a47fSAlexander V. Chernikov self.is_or = is_or 79*9f44a47fSAlexander V. Chernikov self.is_not = is_not 80*9f44a47fSAlexander V. Chernikov self.arg1 = arg1 81*9f44a47fSAlexander V. Chernikov self.is_action = self.obj_type in insn_actions 82*9f44a47fSAlexander V. Chernikov self.ilen = 1 83*9f44a47fSAlexander V. Chernikov self.obj_list = [] 84*9f44a47fSAlexander V. Chernikov 85*9f44a47fSAlexander V. Chernikov @property 86*9f44a47fSAlexander V. Chernikov def obj_name(self): 87*9f44a47fSAlexander V. Chernikov if self._enum is not None: 88*9f44a47fSAlexander V. Chernikov return self._enum.name 89*9f44a47fSAlexander V. Chernikov else: 90*9f44a47fSAlexander V. Chernikov return "opcode#{}".format(self.obj_type) 91*9f44a47fSAlexander V. Chernikov 92*9f44a47fSAlexander V. Chernikov @staticmethod 93*9f44a47fSAlexander V. Chernikov def get_insn_len(data: bytes) -> int: 94*9f44a47fSAlexander V. Chernikov (opcode_len,) = struct.unpack("@B", data[1:2]) 95*9f44a47fSAlexander V. Chernikov return opcode_len & 0x3F 96*9f44a47fSAlexander V. Chernikov 97*9f44a47fSAlexander V. Chernikov @classmethod 98*9f44a47fSAlexander V. Chernikov def _validate_len(cls, data, valid_options=None): 99*9f44a47fSAlexander V. Chernikov if len(data) < 4: 100*9f44a47fSAlexander V. Chernikov raise ValueError("opcode too short") 101*9f44a47fSAlexander V. Chernikov opcode_type, opcode_len = struct.unpack("@BB", data[:2]) 102*9f44a47fSAlexander V. Chernikov if len(data) != ((opcode_len & 0x3F) * 4): 103*9f44a47fSAlexander V. Chernikov raise ValueError("wrong length") 104*9f44a47fSAlexander V. Chernikov if valid_options and len(data) not in valid_options: 105*9f44a47fSAlexander V. Chernikov raise ValueError( 106*9f44a47fSAlexander V. Chernikov "len {} not in {} for {}".format( 107*9f44a47fSAlexander V. Chernikov len(data), valid_options, 108*9f44a47fSAlexander V. Chernikov enum_from_int(cls.obj_enum_class, data[0]) 109*9f44a47fSAlexander V. Chernikov ) 110*9f44a47fSAlexander V. Chernikov ) 111*9f44a47fSAlexander V. Chernikov 112*9f44a47fSAlexander V. Chernikov @classmethod 113*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 114*9f44a47fSAlexander V. Chernikov cls._validate_len(data) 115*9f44a47fSAlexander V. Chernikov 116*9f44a47fSAlexander V. Chernikov @classmethod 117*9f44a47fSAlexander V. Chernikov def _parse(cls, data): 118*9f44a47fSAlexander V. Chernikov insn = IpFwInsn.from_buffer_copy(data[:4]) 119*9f44a47fSAlexander V. Chernikov is_or = (insn.length & 0x40) != 0 120*9f44a47fSAlexander V. Chernikov is_not = (insn.length & 0x80) != 0 121*9f44a47fSAlexander V. Chernikov return cls(opcode=insn.opcode, is_or=is_or, is_not=is_not, arg1=insn.arg1) 122*9f44a47fSAlexander V. Chernikov 123*9f44a47fSAlexander V. Chernikov @classmethod 124*9f44a47fSAlexander V. Chernikov def from_bytes(cls, data, attr_type_enum): 125*9f44a47fSAlexander V. Chernikov cls._validate(data) 126*9f44a47fSAlexander V. Chernikov opcode = cls._parse(data) 127*9f44a47fSAlexander V. Chernikov opcode._enum = attr_type_enum 128*9f44a47fSAlexander V. Chernikov return opcode 129*9f44a47fSAlexander V. Chernikov 130*9f44a47fSAlexander V. Chernikov def __bytes__(self): 131*9f44a47fSAlexander V. Chernikov raise NotImplementedError() 132*9f44a47fSAlexander V. Chernikov 133*9f44a47fSAlexander V. Chernikov def print_obj(self, prepend=""): 134*9f44a47fSAlexander V. Chernikov is_or = "" 135*9f44a47fSAlexander V. Chernikov if self.is_or: 136*9f44a47fSAlexander V. Chernikov is_or = " [OR]\\" 137*9f44a47fSAlexander V. Chernikov is_not = "" 138*9f44a47fSAlexander V. Chernikov if self.is_not: 139*9f44a47fSAlexander V. Chernikov is_not = "[!] " 140*9f44a47fSAlexander V. Chernikov print( 141*9f44a47fSAlexander V. Chernikov "{}{}len={} type={}({}){}{}".format( 142*9f44a47fSAlexander V. Chernikov prepend, 143*9f44a47fSAlexander V. Chernikov is_not, 144*9f44a47fSAlexander V. Chernikov len(bytes(self)), 145*9f44a47fSAlexander V. Chernikov self.obj_name, 146*9f44a47fSAlexander V. Chernikov self.obj_type, 147*9f44a47fSAlexander V. Chernikov self._print_obj_value(), 148*9f44a47fSAlexander V. Chernikov is_or, 149*9f44a47fSAlexander V. Chernikov ) 150*9f44a47fSAlexander V. Chernikov ) 151*9f44a47fSAlexander V. Chernikov 152*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 153*9f44a47fSAlexander V. Chernikov raise NotImplementedError() 154*9f44a47fSAlexander V. Chernikov 155*9f44a47fSAlexander V. Chernikov def print_obj_hex(self, prepend=""): 156*9f44a47fSAlexander V. Chernikov print(prepend) 157*9f44a47fSAlexander V. Chernikov print() 158*9f44a47fSAlexander V. Chernikov print(" ".join(["x{:02X}".format(b) for b in bytes(self)])) 159*9f44a47fSAlexander V. Chernikov 160*9f44a47fSAlexander V. Chernikov @staticmethod 161*9f44a47fSAlexander V. Chernikov def parse_insns(data, attr_map): 162*9f44a47fSAlexander V. Chernikov ret = [] 163*9f44a47fSAlexander V. Chernikov off = 0 164*9f44a47fSAlexander V. Chernikov while off + sizeof(IpFwInsn) <= len(data): 165*9f44a47fSAlexander V. Chernikov hdr = IpFwInsn.from_buffer_copy(data[off : off + sizeof(IpFwInsn)]) 166*9f44a47fSAlexander V. Chernikov insn_len = (hdr.length & 0x3F) * 4 167*9f44a47fSAlexander V. Chernikov if off + insn_len > len(data): 168*9f44a47fSAlexander V. Chernikov raise ValueError("wrng length") 169*9f44a47fSAlexander V. Chernikov # print("GET insn type {} len {}".format(hdr.opcode, insn_len)) 170*9f44a47fSAlexander V. Chernikov attr = attr_map.get(hdr.opcode, None) 171*9f44a47fSAlexander V. Chernikov if attr is None: 172*9f44a47fSAlexander V. Chernikov cls = InsnUnknown 173*9f44a47fSAlexander V. Chernikov type_enum = enum_from_int(BaseInsn.obj_enum_class, hdr.opcode) 174*9f44a47fSAlexander V. Chernikov else: 175*9f44a47fSAlexander V. Chernikov cls = attr["ad"].cls 176*9f44a47fSAlexander V. Chernikov type_enum = attr["ad"].val 177*9f44a47fSAlexander V. Chernikov insn = cls.from_bytes(data[off : off + insn_len], type_enum) 178*9f44a47fSAlexander V. Chernikov ret.append(insn) 179*9f44a47fSAlexander V. Chernikov off += insn_len 180*9f44a47fSAlexander V. Chernikov 181*9f44a47fSAlexander V. Chernikov if off != len(data): 182*9f44a47fSAlexander V. Chernikov raise ValueError("empty space") 183*9f44a47fSAlexander V. Chernikov return ret 184*9f44a47fSAlexander V. Chernikov 185*9f44a47fSAlexander V. Chernikov 186*9f44a47fSAlexander V. Chernikovclass Insn(BaseInsn): 187*9f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0): 188*9f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 189*9f44a47fSAlexander V. Chernikov 190*9f44a47fSAlexander V. Chernikov @classmethod 191*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 192*9f44a47fSAlexander V. Chernikov cls._validate_len(data, [4]) 193*9f44a47fSAlexander V. Chernikov 194*9f44a47fSAlexander V. Chernikov def __bytes__(self): 195*9f44a47fSAlexander V. Chernikov length = self.ilen 196*9f44a47fSAlexander V. Chernikov if self.is_or: 197*9f44a47fSAlexander V. Chernikov length |= 0x40 198*9f44a47fSAlexander V. Chernikov if self.is_not: 199*9f44a47fSAlexander V. Chernikov length | 0x80 200*9f44a47fSAlexander V. Chernikov insn = IpFwInsn(opcode=self.obj_type, length=length, arg1=enum_or_int(self.arg1)) 201*9f44a47fSAlexander V. Chernikov return bytes(insn) 202*9f44a47fSAlexander V. Chernikov 203*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 204*9f44a47fSAlexander V. Chernikov return " arg1={}".format(self.arg1) 205*9f44a47fSAlexander V. Chernikov 206*9f44a47fSAlexander V. Chernikov 207*9f44a47fSAlexander V. Chernikovclass InsnUnknown(Insn): 208*9f44a47fSAlexander V. Chernikov @classmethod 209*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 210*9f44a47fSAlexander V. Chernikov cls._validate_len(data) 211*9f44a47fSAlexander V. Chernikov 212*9f44a47fSAlexander V. Chernikov @classmethod 213*9f44a47fSAlexander V. Chernikov def _parse(cls, data): 214*9f44a47fSAlexander V. Chernikov self = super()._parse(data) 215*9f44a47fSAlexander V. Chernikov self._data = data 216*9f44a47fSAlexander V. Chernikov return self 217*9f44a47fSAlexander V. Chernikov 218*9f44a47fSAlexander V. Chernikov def __bytes__(self): 219*9f44a47fSAlexander V. Chernikov return self._data 220*9f44a47fSAlexander V. Chernikov 221*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 222*9f44a47fSAlexander V. Chernikov return " " + " ".join(["x{:02X}".format(b) for b in self._data]) 223*9f44a47fSAlexander V. Chernikov 224*9f44a47fSAlexander V. Chernikov 225*9f44a47fSAlexander V. Chernikovclass InsnEmpty(Insn): 226*9f44a47fSAlexander V. Chernikov @classmethod 227*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 228*9f44a47fSAlexander V. Chernikov cls._validate_len(data, [4]) 229*9f44a47fSAlexander V. Chernikov insn = IpFwInsn.from_buffer_copy(data[:4]) 230*9f44a47fSAlexander V. Chernikov if insn.arg1 != 0: 231*9f44a47fSAlexander V. Chernikov raise ValueError("arg1 should be empty") 232*9f44a47fSAlexander V. Chernikov 233*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 234*9f44a47fSAlexander V. Chernikov return "" 235*9f44a47fSAlexander V. Chernikov 236*9f44a47fSAlexander V. Chernikov 237*9f44a47fSAlexander V. Chernikovclass InsnComment(Insn): 238*9f44a47fSAlexander V. Chernikov def __init__(self, opcode=IpFwOpcode.O_NOP, is_or=False, is_not=False, arg1=0, comment=""): 239*9f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 240*9f44a47fSAlexander V. Chernikov if comment: 241*9f44a47fSAlexander V. Chernikov self.comment = comment 242*9f44a47fSAlexander V. Chernikov else: 243*9f44a47fSAlexander V. Chernikov self.comment = "" 244*9f44a47fSAlexander V. Chernikov 245*9f44a47fSAlexander V. Chernikov @classmethod 246*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 247*9f44a47fSAlexander V. Chernikov cls._validate_len(data) 248*9f44a47fSAlexander V. Chernikov if len(data) > 88: 249*9f44a47fSAlexander V. Chernikov raise ValueError("comment too long") 250*9f44a47fSAlexander V. Chernikov 251*9f44a47fSAlexander V. Chernikov @classmethod 252*9f44a47fSAlexander V. Chernikov def _parse(cls, data): 253*9f44a47fSAlexander V. Chernikov self = super()._parse(data) 254*9f44a47fSAlexander V. Chernikov # Comment encoding can be anything, 255*9f44a47fSAlexander V. Chernikov # use utf-8 to ease debugging 256*9f44a47fSAlexander V. Chernikov max_len = 0 257*9f44a47fSAlexander V. Chernikov for b in range(4, len(data)): 258*9f44a47fSAlexander V. Chernikov if data[b] == b"\0": 259*9f44a47fSAlexander V. Chernikov break 260*9f44a47fSAlexander V. Chernikov max_len += 1 261*9f44a47fSAlexander V. Chernikov self.comment = data[4:max_len].decode("utf-8") 262*9f44a47fSAlexander V. Chernikov return self 263*9f44a47fSAlexander V. Chernikov 264*9f44a47fSAlexander V. Chernikov def __bytes__(self): 265*9f44a47fSAlexander V. Chernikov ret = super().__bytes__() 266*9f44a47fSAlexander V. Chernikov comment_bytes = self.comment.encode("utf-8") + b"\0" 267*9f44a47fSAlexander V. Chernikov if len(comment_bytes) % 4 > 0: 268*9f44a47fSAlexander V. Chernikov comment_bytes += b"\0" * (4 - (len(comment_bytes) % 4)) 269*9f44a47fSAlexander V. Chernikov ret += comment_bytes 270*9f44a47fSAlexander V. Chernikov return ret 271*9f44a47fSAlexander V. Chernikov 272*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 273*9f44a47fSAlexander V. Chernikov return " comment='{}'".format(self.comment) 274*9f44a47fSAlexander V. Chernikov 275*9f44a47fSAlexander V. Chernikov 276*9f44a47fSAlexander V. Chernikovclass InsnProto(Insn): 277*9f44a47fSAlexander V. Chernikov def __init__(self, opcode=IpFwOpcode.O_PROTO, is_or=False, is_not=False, arg1=0): 278*9f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 279*9f44a47fSAlexander V. Chernikov 280*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 281*9f44a47fSAlexander V. Chernikov known_map = {6: "TCP", 17: "UDP", 41: "IPV6"} 282*9f44a47fSAlexander V. Chernikov proto = self.arg1 283*9f44a47fSAlexander V. Chernikov if proto in known_map: 284*9f44a47fSAlexander V. Chernikov return " proto={}".format(known_map[proto]) 285*9f44a47fSAlexander V. Chernikov else: 286*9f44a47fSAlexander V. Chernikov return " proto=#{}".format(proto) 287*9f44a47fSAlexander V. Chernikov 288*9f44a47fSAlexander V. Chernikov 289*9f44a47fSAlexander V. Chernikovclass InsnU32(Insn): 290*9f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, u32=0): 291*9f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 292*9f44a47fSAlexander V. Chernikov self.u32 = u32 293*9f44a47fSAlexander V. Chernikov self.ilen = 2 294*9f44a47fSAlexander V. Chernikov 295*9f44a47fSAlexander V. Chernikov @classmethod 296*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 297*9f44a47fSAlexander V. Chernikov cls._validate_len(data, [8]) 298*9f44a47fSAlexander V. Chernikov 299*9f44a47fSAlexander V. Chernikov @classmethod 300*9f44a47fSAlexander V. Chernikov def _parse(cls, data): 301*9f44a47fSAlexander V. Chernikov self = super()._parse(data[:4]) 302*9f44a47fSAlexander V. Chernikov self.u32 = struct.unpack("@I", data[4:8])[0] 303*9f44a47fSAlexander V. Chernikov return self 304*9f44a47fSAlexander V. Chernikov 305*9f44a47fSAlexander V. Chernikov def __bytes__(self): 306*9f44a47fSAlexander V. Chernikov return super().__bytes__() + struct.pack("@I", self.u32) 307*9f44a47fSAlexander V. Chernikov 308*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 309*9f44a47fSAlexander V. Chernikov return " arg1={} u32={}".format(self.arg1, self.u32) 310*9f44a47fSAlexander V. Chernikov 311*9f44a47fSAlexander V. Chernikov 312*9f44a47fSAlexander V. Chernikovclass InsnProb(InsnU32): 313*9f44a47fSAlexander V. Chernikov def __init__( 314*9f44a47fSAlexander V. Chernikov self, 315*9f44a47fSAlexander V. Chernikov opcode=IpFwOpcode.O_PROB, 316*9f44a47fSAlexander V. Chernikov is_or=False, 317*9f44a47fSAlexander V. Chernikov is_not=False, 318*9f44a47fSAlexander V. Chernikov arg1=0, 319*9f44a47fSAlexander V. Chernikov u32=0, 320*9f44a47fSAlexander V. Chernikov prob=0.0, 321*9f44a47fSAlexander V. Chernikov ): 322*9f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not) 323*9f44a47fSAlexander V. Chernikov self.prob = prob 324*9f44a47fSAlexander V. Chernikov 325*9f44a47fSAlexander V. Chernikov @property 326*9f44a47fSAlexander V. Chernikov def prob(self): 327*9f44a47fSAlexander V. Chernikov return 1.0 * self.u32 / 0x7FFFFFFF 328*9f44a47fSAlexander V. Chernikov 329*9f44a47fSAlexander V. Chernikov @prob.setter 330*9f44a47fSAlexander V. Chernikov def prob(self, prob: float): 331*9f44a47fSAlexander V. Chernikov self.u32 = int(prob * 0x7FFFFFFF) 332*9f44a47fSAlexander V. Chernikov 333*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 334*9f44a47fSAlexander V. Chernikov return " prob={}".format(round(self.prob, 5)) 335*9f44a47fSAlexander V. Chernikov 336*9f44a47fSAlexander V. Chernikov 337*9f44a47fSAlexander V. Chernikovclass InsnIp(InsnU32): 338*9f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, u32=0, ip=None): 339*9f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1, u32=u32) 340*9f44a47fSAlexander V. Chernikov if ip: 341*9f44a47fSAlexander V. Chernikov self.ip = ip 342*9f44a47fSAlexander V. Chernikov 343*9f44a47fSAlexander V. Chernikov @property 344*9f44a47fSAlexander V. Chernikov def ip(self): 345*9f44a47fSAlexander V. Chernikov return socket.inet_ntop(socket.AF_INET, struct.pack("@I", self.u32)) 346*9f44a47fSAlexander V. Chernikov 347*9f44a47fSAlexander V. Chernikov @ip.setter 348*9f44a47fSAlexander V. Chernikov def ip(self, ip: str): 349*9f44a47fSAlexander V. Chernikov ip_bin = socket.inet_pton(socket.AF_INET, ip) 350*9f44a47fSAlexander V. Chernikov self.u32 = struct.unpack("@I", ip_bin)[0] 351*9f44a47fSAlexander V. Chernikov 352*9f44a47fSAlexander V. Chernikov def _print_opcode_value(self): 353*9f44a47fSAlexander V. Chernikov return " ip={}".format(self.ip) 354*9f44a47fSAlexander V. Chernikov 355*9f44a47fSAlexander V. Chernikov 356*9f44a47fSAlexander V. Chernikovclass InsnTable(Insn): 357*9f44a47fSAlexander V. Chernikov @classmethod 358*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 359*9f44a47fSAlexander V. Chernikov cls._validate_len(data, [4, 8]) 360*9f44a47fSAlexander V. Chernikov 361*9f44a47fSAlexander V. Chernikov @classmethod 362*9f44a47fSAlexander V. Chernikov def _parse(cls, data): 363*9f44a47fSAlexander V. Chernikov self = super()._parse(data) 364*9f44a47fSAlexander V. Chernikov 365*9f44a47fSAlexander V. Chernikov if len(data) == 8: 366*9f44a47fSAlexander V. Chernikov (self.val,) = struct.unpack("@I", data[4:8]) 367*9f44a47fSAlexander V. Chernikov self.ilen = 2 368*9f44a47fSAlexander V. Chernikov else: 369*9f44a47fSAlexander V. Chernikov self.val = None 370*9f44a47fSAlexander V. Chernikov return self 371*9f44a47fSAlexander V. Chernikov 372*9f44a47fSAlexander V. Chernikov def __bytes__(self): 373*9f44a47fSAlexander V. Chernikov ret = super().__bytes__() 374*9f44a47fSAlexander V. Chernikov if getattr(self, "val", None) is not None: 375*9f44a47fSAlexander V. Chernikov ret += struct.pack("@I", self.val) 376*9f44a47fSAlexander V. Chernikov return ret 377*9f44a47fSAlexander V. Chernikov 378*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 379*9f44a47fSAlexander V. Chernikov if getattr(self, "val", None) is not None: 380*9f44a47fSAlexander V. Chernikov return " table={} value={}".format(self.arg1, self.val) 381*9f44a47fSAlexander V. Chernikov else: 382*9f44a47fSAlexander V. Chernikov return " table={}".format(self.arg1) 383*9f44a47fSAlexander V. Chernikov 384*9f44a47fSAlexander V. Chernikov 385*9f44a47fSAlexander V. Chernikovclass InsnReject(Insn): 386*9f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, mtu=None): 387*9f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 388*9f44a47fSAlexander V. Chernikov self.mtu = mtu 389*9f44a47fSAlexander V. Chernikov if self.mtu is not None: 390*9f44a47fSAlexander V. Chernikov self.ilen = 2 391*9f44a47fSAlexander V. Chernikov 392*9f44a47fSAlexander V. Chernikov @classmethod 393*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 394*9f44a47fSAlexander V. Chernikov cls._validate_len(data, [4, 8]) 395*9f44a47fSAlexander V. Chernikov 396*9f44a47fSAlexander V. Chernikov @classmethod 397*9f44a47fSAlexander V. Chernikov def _parse(cls, data): 398*9f44a47fSAlexander V. Chernikov self = super()._parse(data) 399*9f44a47fSAlexander V. Chernikov 400*9f44a47fSAlexander V. Chernikov if len(data) == 8: 401*9f44a47fSAlexander V. Chernikov (self.mtu,) = struct.unpack("@I", data[4:8]) 402*9f44a47fSAlexander V. Chernikov self.ilen = 2 403*9f44a47fSAlexander V. Chernikov else: 404*9f44a47fSAlexander V. Chernikov self.mtu = None 405*9f44a47fSAlexander V. Chernikov return self 406*9f44a47fSAlexander V. Chernikov 407*9f44a47fSAlexander V. Chernikov def __bytes__(self): 408*9f44a47fSAlexander V. Chernikov ret = super().__bytes__() 409*9f44a47fSAlexander V. Chernikov if getattr(self, "mtu", None) is not None: 410*9f44a47fSAlexander V. Chernikov ret += struct.pack("@I", self.mtu) 411*9f44a47fSAlexander V. Chernikov return ret 412*9f44a47fSAlexander V. Chernikov 413*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 414*9f44a47fSAlexander V. Chernikov code = enum_from_int(IcmpRejectCode, self.arg1) 415*9f44a47fSAlexander V. Chernikov if getattr(self, "mtu", None) is not None: 416*9f44a47fSAlexander V. Chernikov return " code={} mtu={}".format(code, self.mtu) 417*9f44a47fSAlexander V. Chernikov else: 418*9f44a47fSAlexander V. Chernikov return " code={}".format(code) 419*9f44a47fSAlexander V. Chernikov 420*9f44a47fSAlexander V. Chernikov 421*9f44a47fSAlexander V. Chernikovclass InsnPorts(Insn): 422*9f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, port_pairs=[]): 423*9f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not) 424*9f44a47fSAlexander V. Chernikov self.port_pairs = [] 425*9f44a47fSAlexander V. Chernikov if port_pairs: 426*9f44a47fSAlexander V. Chernikov self.port_pairs = port_pairs 427*9f44a47fSAlexander V. Chernikov 428*9f44a47fSAlexander V. Chernikov @classmethod 429*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 430*9f44a47fSAlexander V. Chernikov if len(data) < 8: 431*9f44a47fSAlexander V. Chernikov raise ValueError("no ports specified") 432*9f44a47fSAlexander V. Chernikov cls._validate_len(data) 433*9f44a47fSAlexander V. Chernikov 434*9f44a47fSAlexander V. Chernikov @classmethod 435*9f44a47fSAlexander V. Chernikov def _parse(cls, data): 436*9f44a47fSAlexander V. Chernikov self = super()._parse(data) 437*9f44a47fSAlexander V. Chernikov 438*9f44a47fSAlexander V. Chernikov off = 4 439*9f44a47fSAlexander V. Chernikov port_pairs = [] 440*9f44a47fSAlexander V. Chernikov while off + 4 <= len(data): 441*9f44a47fSAlexander V. Chernikov low, high = struct.unpack("@HH", data[off : off + 4]) 442*9f44a47fSAlexander V. Chernikov port_pairs.append((low, high)) 443*9f44a47fSAlexander V. Chernikov off += 4 444*9f44a47fSAlexander V. Chernikov self.port_pairs = port_pairs 445*9f44a47fSAlexander V. Chernikov return self 446*9f44a47fSAlexander V. Chernikov 447*9f44a47fSAlexander V. Chernikov def __bytes__(self): 448*9f44a47fSAlexander V. Chernikov ret = super().__bytes__() 449*9f44a47fSAlexander V. Chernikov if getattr(self, "val", None) is not None: 450*9f44a47fSAlexander V. Chernikov ret += struct.pack("@I", self.val) 451*9f44a47fSAlexander V. Chernikov return ret 452*9f44a47fSAlexander V. Chernikov 453*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 454*9f44a47fSAlexander V. Chernikov ret = [] 455*9f44a47fSAlexander V. Chernikov for p in self.port_pairs: 456*9f44a47fSAlexander V. Chernikov if p[0] == p[1]: 457*9f44a47fSAlexander V. Chernikov ret.append(str(p[0])) 458*9f44a47fSAlexander V. Chernikov else: 459*9f44a47fSAlexander V. Chernikov ret.append("{}-{}".format(p[0], p[1])) 460*9f44a47fSAlexander V. Chernikov return " ports={}".format(",".join(ret)) 461*9f44a47fSAlexander V. Chernikov 462*9f44a47fSAlexander V. Chernikov 463*9f44a47fSAlexander V. Chernikovclass IpFwInsnIp6(Structure): 464*9f44a47fSAlexander V. Chernikov _fields_ = [ 465*9f44a47fSAlexander V. Chernikov ("o", IpFwInsn), 466*9f44a47fSAlexander V. Chernikov ("addr6", c_byte * 16), 467*9f44a47fSAlexander V. Chernikov ("mask6", c_byte * 16), 468*9f44a47fSAlexander V. Chernikov ] 469*9f44a47fSAlexander V. Chernikov 470*9f44a47fSAlexander V. Chernikov 471*9f44a47fSAlexander V. Chernikovclass InsnIp6(Insn): 472*9f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, ip6=None, mask6=None): 473*9f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 474*9f44a47fSAlexander V. Chernikov self.ip6 = ip6 475*9f44a47fSAlexander V. Chernikov self.mask6 = mask6 476*9f44a47fSAlexander V. Chernikov if mask6 is not None: 477*9f44a47fSAlexander V. Chernikov self.ilen = 9 478*9f44a47fSAlexander V. Chernikov else: 479*9f44a47fSAlexander V. Chernikov self.ilen = 5 480*9f44a47fSAlexander V. Chernikov 481*9f44a47fSAlexander V. Chernikov @classmethod 482*9f44a47fSAlexander V. Chernikov def _validate(cls, data): 483*9f44a47fSAlexander V. Chernikov cls._validate_len(data, [4 + 16, 4 + 16 * 2]) 484*9f44a47fSAlexander V. Chernikov 485*9f44a47fSAlexander V. Chernikov @classmethod 486*9f44a47fSAlexander V. Chernikov def _parse(cls, data): 487*9f44a47fSAlexander V. Chernikov self = super()._parse(data) 488*9f44a47fSAlexander V. Chernikov self.ip6 = socket.inet_ntop(socket.AF_INET6, data[4:20]) 489*9f44a47fSAlexander V. Chernikov 490*9f44a47fSAlexander V. Chernikov if len(data) == 4 + 16 * 2: 491*9f44a47fSAlexander V. Chernikov self.mask6 = socket.inet_ntop(socket.AF_INET6, data[20:36]) 492*9f44a47fSAlexander V. Chernikov self.ilen = 9 493*9f44a47fSAlexander V. Chernikov else: 494*9f44a47fSAlexander V. Chernikov self.mask6 = None 495*9f44a47fSAlexander V. Chernikov self.ilen = 5 496*9f44a47fSAlexander V. Chernikov return self 497*9f44a47fSAlexander V. Chernikov 498*9f44a47fSAlexander V. Chernikov def __bytes__(self): 499*9f44a47fSAlexander V. Chernikov ret = super().__bytes__() + socket.inet_pton(socket.AF_INET6, self.ip6) 500*9f44a47fSAlexander V. Chernikov if self.mask6 is not None: 501*9f44a47fSAlexander V. Chernikov ret += socket.inet_pton(socket.AF_INET6, self.mask6) 502*9f44a47fSAlexander V. Chernikov return ret 503*9f44a47fSAlexander V. Chernikov 504*9f44a47fSAlexander V. Chernikov def _print_obj_value(self): 505*9f44a47fSAlexander V. Chernikov if self.mask6: 506*9f44a47fSAlexander V. Chernikov return " ip6={}/{}".format(self.ip6, self.mask6) 507*9f44a47fSAlexander V. Chernikov else: 508*9f44a47fSAlexander V. Chernikov return " ip6={}".format(self.ip6) 509*9f44a47fSAlexander V. Chernikov 510*9f44a47fSAlexander V. Chernikov 511*9f44a47fSAlexander V. Chernikovinsn_attrs = prepare_attrs_map( 512*9f44a47fSAlexander V. Chernikov [ 513*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_CHECK_STATE, Insn), 514*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_ACCEPT, InsnEmpty), 515*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_COUNT, InsnEmpty), 516*9f44a47fSAlexander V. Chernikov 517*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_REJECT, InsnReject), 518*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_UNREACH6, Insn), 519*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_DENY, InsnEmpty), 520*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_DIVERT, Insn), 521*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_COUNT, InsnEmpty), 522*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_QUEUE, Insn), 523*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_PIPE, Insn), 524*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_SKIPTO, Insn), 525*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_NETGRAPH, Insn), 526*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_NGTEE, Insn), 527*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_DIVERT, Insn), 528*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_TEE, Insn), 529*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_CALLRETURN, Insn), 530*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_SETFIB, Insn), 531*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_SETDSCP, Insn), 532*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_REASS, InsnEmpty), 533*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_SETMARK, Insn), 534*9f44a47fSAlexander V. Chernikov 535*9f44a47fSAlexander V. Chernikov 536*9f44a47fSAlexander V. Chernikov 537*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_NOP, InsnComment), 538*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_PROTO, InsnProto), 539*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_PROB, InsnProb), 540*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_DST_ME, InsnEmpty), 541*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_SRC_ME, InsnEmpty), 542*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP6_DST_ME, InsnEmpty), 543*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP6_SRC_ME, InsnEmpty), 544*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_SRC, InsnIp), 545*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_DST, InsnIp), 546*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP6_DST, InsnIp6), 547*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP6_SRC, InsnIp6), 548*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_SRC_LOOKUP, InsnTable), 549*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_DST_LOOKUP, InsnTable), 550*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_SRCPORT, InsnPorts), 551*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_DSTPORT, InsnPorts), 552*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_PROBE_STATE, Insn), 553*9f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_KEEP_STATE, Insn), 554*9f44a47fSAlexander V. Chernikov ] 555*9f44a47fSAlexander V. Chernikov) 556