19f44a47fSAlexander V. Chernikov#!/usr/bin/env python3 29f44a47fSAlexander V. Chernikovimport os 39f44a47fSAlexander V. Chernikovimport socket 49f44a47fSAlexander V. Chernikovimport struct 59f44a47fSAlexander V. Chernikovimport subprocess 69f44a47fSAlexander V. Chernikovimport sys 79f44a47fSAlexander V. Chernikovfrom ctypes import c_byte 89f44a47fSAlexander V. Chernikovfrom ctypes import c_char 99f44a47fSAlexander V. Chernikovfrom ctypes import c_int 109f44a47fSAlexander V. Chernikovfrom ctypes import c_long 119f44a47fSAlexander V. Chernikovfrom ctypes import c_uint32 129f44a47fSAlexander V. Chernikovfrom ctypes import c_uint8 139f44a47fSAlexander V. Chernikovfrom ctypes import c_ulong 149f44a47fSAlexander V. Chernikovfrom ctypes import c_ushort 159f44a47fSAlexander V. Chernikovfrom ctypes import sizeof 169f44a47fSAlexander V. Chernikovfrom ctypes import Structure 179f44a47fSAlexander V. Chernikovfrom enum import Enum 189f44a47fSAlexander V. Chernikovfrom typing import Any 199f44a47fSAlexander V. Chernikovfrom typing import Dict 209f44a47fSAlexander V. Chernikovfrom typing import List 219f44a47fSAlexander V. Chernikovfrom typing import NamedTuple 229f44a47fSAlexander V. Chernikovfrom typing import Optional 239f44a47fSAlexander V. Chernikovfrom typing import Union 249f44a47fSAlexander V. Chernikov 259f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insn_headers import IpFwOpcode 269f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insn_headers import IcmpRejectCode 279f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insn_headers import Icmp6RejectCode 289f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import AttrDescr 299f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import enum_or_int 309f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import enum_from_int 319f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import prepare_attrs_map 329f44a47fSAlexander V. Chernikov 339f44a47fSAlexander V. Chernikov 349f44a47fSAlexander V. Chernikovinsn_actions = ( 359f44a47fSAlexander V. Chernikov IpFwOpcode.O_CHECK_STATE.value, 369f44a47fSAlexander V. Chernikov IpFwOpcode.O_REJECT.value, 379f44a47fSAlexander V. Chernikov IpFwOpcode.O_UNREACH6.value, 389f44a47fSAlexander V. Chernikov IpFwOpcode.O_ACCEPT.value, 399f44a47fSAlexander V. Chernikov IpFwOpcode.O_DENY.value, 409f44a47fSAlexander V. Chernikov IpFwOpcode.O_COUNT.value, 419f44a47fSAlexander V. Chernikov IpFwOpcode.O_NAT.value, 429f44a47fSAlexander V. Chernikov IpFwOpcode.O_QUEUE.value, 439f44a47fSAlexander V. Chernikov IpFwOpcode.O_PIPE.value, 449f44a47fSAlexander V. Chernikov IpFwOpcode.O_SKIPTO.value, 459f44a47fSAlexander V. Chernikov IpFwOpcode.O_NETGRAPH.value, 469f44a47fSAlexander V. Chernikov IpFwOpcode.O_NGTEE.value, 479f44a47fSAlexander V. Chernikov IpFwOpcode.O_DIVERT.value, 489f44a47fSAlexander V. Chernikov IpFwOpcode.O_TEE.value, 499f44a47fSAlexander V. Chernikov IpFwOpcode.O_CALLRETURN.value, 509f44a47fSAlexander V. Chernikov IpFwOpcode.O_FORWARD_IP.value, 519f44a47fSAlexander V. Chernikov IpFwOpcode.O_FORWARD_IP6.value, 529f44a47fSAlexander V. Chernikov IpFwOpcode.O_SETFIB.value, 539f44a47fSAlexander V. Chernikov IpFwOpcode.O_SETDSCP.value, 549f44a47fSAlexander V. Chernikov IpFwOpcode.O_REASS.value, 559f44a47fSAlexander V. Chernikov IpFwOpcode.O_SETMARK.value, 569f44a47fSAlexander V. Chernikov IpFwOpcode.O_EXTERNAL_ACTION.value, 579f44a47fSAlexander V. Chernikov) 589f44a47fSAlexander V. Chernikov 599f44a47fSAlexander V. Chernikov 609f44a47fSAlexander V. Chernikovclass IpFwInsn(Structure): 619f44a47fSAlexander V. Chernikov _fields_ = [ 629f44a47fSAlexander V. Chernikov ("opcode", c_uint8), 639f44a47fSAlexander V. Chernikov ("length", c_uint8), 649f44a47fSAlexander V. Chernikov ("arg1", c_ushort), 659f44a47fSAlexander V. Chernikov ] 669f44a47fSAlexander V. Chernikov 679f44a47fSAlexander V. Chernikov 689f44a47fSAlexander V. Chernikovclass BaseInsn(object): 699f44a47fSAlexander V. Chernikov obj_enum_class = IpFwOpcode 709f44a47fSAlexander V. Chernikov 719f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or, is_not, arg1): 729f44a47fSAlexander V. Chernikov if isinstance(opcode, Enum): 739f44a47fSAlexander V. Chernikov self.obj_type = opcode.value 749f44a47fSAlexander V. Chernikov self._enum = opcode 759f44a47fSAlexander V. Chernikov else: 769f44a47fSAlexander V. Chernikov self.obj_type = opcode 779f44a47fSAlexander V. Chernikov self._enum = enum_from_int(self.obj_enum_class, self.obj_type) 789f44a47fSAlexander V. Chernikov self.is_or = is_or 799f44a47fSAlexander V. Chernikov self.is_not = is_not 809f44a47fSAlexander V. Chernikov self.arg1 = arg1 819f44a47fSAlexander V. Chernikov self.is_action = self.obj_type in insn_actions 829f44a47fSAlexander V. Chernikov self.ilen = 1 839f44a47fSAlexander V. Chernikov self.obj_list = [] 849f44a47fSAlexander V. Chernikov 859f44a47fSAlexander V. Chernikov @property 869f44a47fSAlexander V. Chernikov def obj_name(self): 879f44a47fSAlexander V. Chernikov if self._enum is not None: 889f44a47fSAlexander V. Chernikov return self._enum.name 899f44a47fSAlexander V. Chernikov else: 909f44a47fSAlexander V. Chernikov return "opcode#{}".format(self.obj_type) 919f44a47fSAlexander V. Chernikov 929f44a47fSAlexander V. Chernikov @staticmethod 939f44a47fSAlexander V. Chernikov def get_insn_len(data: bytes) -> int: 949f44a47fSAlexander V. Chernikov (opcode_len,) = struct.unpack("@B", data[1:2]) 959f44a47fSAlexander V. Chernikov return opcode_len & 0x3F 969f44a47fSAlexander V. Chernikov 979f44a47fSAlexander V. Chernikov @classmethod 989f44a47fSAlexander V. Chernikov def _validate_len(cls, data, valid_options=None): 999f44a47fSAlexander V. Chernikov if len(data) < 4: 1009f44a47fSAlexander V. Chernikov raise ValueError("opcode too short") 1019f44a47fSAlexander V. Chernikov opcode_type, opcode_len = struct.unpack("@BB", data[:2]) 1029f44a47fSAlexander V. Chernikov if len(data) != ((opcode_len & 0x3F) * 4): 1039f44a47fSAlexander V. Chernikov raise ValueError("wrong length") 1049f44a47fSAlexander V. Chernikov if valid_options and len(data) not in valid_options: 1059f44a47fSAlexander V. Chernikov raise ValueError( 1069f44a47fSAlexander V. Chernikov "len {} not in {} for {}".format( 1079f44a47fSAlexander V. Chernikov len(data), valid_options, 1089f44a47fSAlexander V. Chernikov enum_from_int(cls.obj_enum_class, data[0]) 1099f44a47fSAlexander V. Chernikov ) 1109f44a47fSAlexander V. Chernikov ) 1119f44a47fSAlexander V. Chernikov 1129f44a47fSAlexander V. Chernikov @classmethod 1139f44a47fSAlexander V. Chernikov def _validate(cls, data): 1149f44a47fSAlexander V. Chernikov cls._validate_len(data) 1159f44a47fSAlexander V. Chernikov 1169f44a47fSAlexander V. Chernikov @classmethod 1179f44a47fSAlexander V. Chernikov def _parse(cls, data): 1189f44a47fSAlexander V. Chernikov insn = IpFwInsn.from_buffer_copy(data[:4]) 1199f44a47fSAlexander V. Chernikov is_or = (insn.length & 0x40) != 0 1209f44a47fSAlexander V. Chernikov is_not = (insn.length & 0x80) != 0 1219f44a47fSAlexander V. Chernikov return cls(opcode=insn.opcode, is_or=is_or, is_not=is_not, arg1=insn.arg1) 1229f44a47fSAlexander V. Chernikov 1239f44a47fSAlexander V. Chernikov @classmethod 1249f44a47fSAlexander V. Chernikov def from_bytes(cls, data, attr_type_enum): 1259f44a47fSAlexander V. Chernikov cls._validate(data) 1269f44a47fSAlexander V. Chernikov opcode = cls._parse(data) 1279f44a47fSAlexander V. Chernikov opcode._enum = attr_type_enum 1289f44a47fSAlexander V. Chernikov return opcode 1299f44a47fSAlexander V. Chernikov 1309f44a47fSAlexander V. Chernikov def __bytes__(self): 1319f44a47fSAlexander V. Chernikov raise NotImplementedError() 1329f44a47fSAlexander V. Chernikov 1339f44a47fSAlexander V. Chernikov def print_obj(self, prepend=""): 1349f44a47fSAlexander V. Chernikov is_or = "" 1359f44a47fSAlexander V. Chernikov if self.is_or: 1369f44a47fSAlexander V. Chernikov is_or = " [OR]\\" 1379f44a47fSAlexander V. Chernikov is_not = "" 1389f44a47fSAlexander V. Chernikov if self.is_not: 1399f44a47fSAlexander V. Chernikov is_not = "[!] " 1409f44a47fSAlexander V. Chernikov print( 1419f44a47fSAlexander V. Chernikov "{}{}len={} type={}({}){}{}".format( 1429f44a47fSAlexander V. Chernikov prepend, 1439f44a47fSAlexander V. Chernikov is_not, 1449f44a47fSAlexander V. Chernikov len(bytes(self)), 1459f44a47fSAlexander V. Chernikov self.obj_name, 1469f44a47fSAlexander V. Chernikov self.obj_type, 1479f44a47fSAlexander V. Chernikov self._print_obj_value(), 1489f44a47fSAlexander V. Chernikov is_or, 1499f44a47fSAlexander V. Chernikov ) 1509f44a47fSAlexander V. Chernikov ) 1519f44a47fSAlexander V. Chernikov 1529f44a47fSAlexander V. Chernikov def _print_obj_value(self): 1539f44a47fSAlexander V. Chernikov raise NotImplementedError() 1549f44a47fSAlexander V. Chernikov 1559f44a47fSAlexander V. Chernikov def print_obj_hex(self, prepend=""): 1569f44a47fSAlexander V. Chernikov print(prepend) 1579f44a47fSAlexander V. Chernikov print() 1589f44a47fSAlexander V. Chernikov print(" ".join(["x{:02X}".format(b) for b in bytes(self)])) 1599f44a47fSAlexander V. Chernikov 1609f44a47fSAlexander V. Chernikov @staticmethod 1619f44a47fSAlexander V. Chernikov def parse_insns(data, attr_map): 1629f44a47fSAlexander V. Chernikov ret = [] 1639f44a47fSAlexander V. Chernikov off = 0 1649f44a47fSAlexander V. Chernikov while off + sizeof(IpFwInsn) <= len(data): 1659f44a47fSAlexander V. Chernikov hdr = IpFwInsn.from_buffer_copy(data[off : off + sizeof(IpFwInsn)]) 1669f44a47fSAlexander V. Chernikov insn_len = (hdr.length & 0x3F) * 4 1679f44a47fSAlexander V. Chernikov if off + insn_len > len(data): 1689f44a47fSAlexander V. Chernikov raise ValueError("wrng length") 1699f44a47fSAlexander V. Chernikov # print("GET insn type {} len {}".format(hdr.opcode, insn_len)) 1709f44a47fSAlexander V. Chernikov attr = attr_map.get(hdr.opcode, None) 1719f44a47fSAlexander V. Chernikov if attr is None: 1729f44a47fSAlexander V. Chernikov cls = InsnUnknown 1739f44a47fSAlexander V. Chernikov type_enum = enum_from_int(BaseInsn.obj_enum_class, hdr.opcode) 1749f44a47fSAlexander V. Chernikov else: 1759f44a47fSAlexander V. Chernikov cls = attr["ad"].cls 1769f44a47fSAlexander V. Chernikov type_enum = attr["ad"].val 1779f44a47fSAlexander V. Chernikov insn = cls.from_bytes(data[off : off + insn_len], type_enum) 1789f44a47fSAlexander V. Chernikov ret.append(insn) 1799f44a47fSAlexander V. Chernikov off += insn_len 1809f44a47fSAlexander V. Chernikov 1819f44a47fSAlexander V. Chernikov if off != len(data): 1829f44a47fSAlexander V. Chernikov raise ValueError("empty space") 1839f44a47fSAlexander V. Chernikov return ret 1849f44a47fSAlexander V. Chernikov 1859f44a47fSAlexander V. Chernikov 1869f44a47fSAlexander V. Chernikovclass Insn(BaseInsn): 1879f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0): 1889f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 1899f44a47fSAlexander V. Chernikov 1909f44a47fSAlexander V. Chernikov @classmethod 1919f44a47fSAlexander V. Chernikov def _validate(cls, data): 1929f44a47fSAlexander V. Chernikov cls._validate_len(data, [4]) 1939f44a47fSAlexander V. Chernikov 1949f44a47fSAlexander V. Chernikov def __bytes__(self): 1959f44a47fSAlexander V. Chernikov length = self.ilen 1969f44a47fSAlexander V. Chernikov if self.is_or: 1979f44a47fSAlexander V. Chernikov length |= 0x40 1989f44a47fSAlexander V. Chernikov if self.is_not: 1999f44a47fSAlexander V. Chernikov length | 0x80 2009f44a47fSAlexander V. Chernikov insn = IpFwInsn(opcode=self.obj_type, length=length, arg1=enum_or_int(self.arg1)) 2019f44a47fSAlexander V. Chernikov return bytes(insn) 2029f44a47fSAlexander V. Chernikov 2039f44a47fSAlexander V. Chernikov def _print_obj_value(self): 2049f44a47fSAlexander V. Chernikov return " arg1={}".format(self.arg1) 2059f44a47fSAlexander V. Chernikov 2069f44a47fSAlexander V. Chernikov 2079f44a47fSAlexander V. Chernikovclass InsnUnknown(Insn): 2089f44a47fSAlexander V. Chernikov @classmethod 2099f44a47fSAlexander V. Chernikov def _validate(cls, data): 2109f44a47fSAlexander V. Chernikov cls._validate_len(data) 2119f44a47fSAlexander V. Chernikov 2129f44a47fSAlexander V. Chernikov @classmethod 2139f44a47fSAlexander V. Chernikov def _parse(cls, data): 2149f44a47fSAlexander V. Chernikov self = super()._parse(data) 2159f44a47fSAlexander V. Chernikov self._data = data 2169f44a47fSAlexander V. Chernikov return self 2179f44a47fSAlexander V. Chernikov 2189f44a47fSAlexander V. Chernikov def __bytes__(self): 2199f44a47fSAlexander V. Chernikov return self._data 2209f44a47fSAlexander V. Chernikov 2219f44a47fSAlexander V. Chernikov def _print_obj_value(self): 2229f44a47fSAlexander V. Chernikov return " " + " ".join(["x{:02X}".format(b) for b in self._data]) 2239f44a47fSAlexander V. Chernikov 2249f44a47fSAlexander V. Chernikov 2259f44a47fSAlexander V. Chernikovclass InsnEmpty(Insn): 2269f44a47fSAlexander V. Chernikov @classmethod 2279f44a47fSAlexander V. Chernikov def _validate(cls, data): 2289f44a47fSAlexander V. Chernikov cls._validate_len(data, [4]) 2299f44a47fSAlexander V. Chernikov insn = IpFwInsn.from_buffer_copy(data[:4]) 2309f44a47fSAlexander V. Chernikov if insn.arg1 != 0: 2319f44a47fSAlexander V. Chernikov raise ValueError("arg1 should be empty") 2329f44a47fSAlexander V. Chernikov 2339f44a47fSAlexander V. Chernikov def _print_obj_value(self): 2349f44a47fSAlexander V. Chernikov return "" 2359f44a47fSAlexander V. Chernikov 2369f44a47fSAlexander V. Chernikov 2379f44a47fSAlexander V. Chernikovclass InsnComment(Insn): 2389f44a47fSAlexander V. Chernikov def __init__(self, opcode=IpFwOpcode.O_NOP, is_or=False, is_not=False, arg1=0, comment=""): 2399f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 2409f44a47fSAlexander V. Chernikov if comment: 2419f44a47fSAlexander V. Chernikov self.comment = comment 2429f44a47fSAlexander V. Chernikov else: 2439f44a47fSAlexander V. Chernikov self.comment = "" 2449f44a47fSAlexander V. Chernikov 2459f44a47fSAlexander V. Chernikov @classmethod 2469f44a47fSAlexander V. Chernikov def _validate(cls, data): 2479f44a47fSAlexander V. Chernikov cls._validate_len(data) 2489f44a47fSAlexander V. Chernikov if len(data) > 88: 2499f44a47fSAlexander V. Chernikov raise ValueError("comment too long") 2509f44a47fSAlexander V. Chernikov 2519f44a47fSAlexander V. Chernikov @classmethod 2529f44a47fSAlexander V. Chernikov def _parse(cls, data): 2539f44a47fSAlexander V. Chernikov self = super()._parse(data) 2549f44a47fSAlexander V. Chernikov # Comment encoding can be anything, 2559f44a47fSAlexander V. Chernikov # use utf-8 to ease debugging 2569f44a47fSAlexander V. Chernikov max_len = 0 2579f44a47fSAlexander V. Chernikov for b in range(4, len(data)): 2589f44a47fSAlexander V. Chernikov if data[b] == b"\0": 2599f44a47fSAlexander V. Chernikov break 2609f44a47fSAlexander V. Chernikov max_len += 1 2619f44a47fSAlexander V. Chernikov self.comment = data[4:max_len].decode("utf-8") 2629f44a47fSAlexander V. Chernikov return self 2639f44a47fSAlexander V. Chernikov 2649f44a47fSAlexander V. Chernikov def __bytes__(self): 2659f44a47fSAlexander V. Chernikov ret = super().__bytes__() 2669f44a47fSAlexander V. Chernikov comment_bytes = self.comment.encode("utf-8") + b"\0" 2679f44a47fSAlexander V. Chernikov if len(comment_bytes) % 4 > 0: 2689f44a47fSAlexander V. Chernikov comment_bytes += b"\0" * (4 - (len(comment_bytes) % 4)) 2699f44a47fSAlexander V. Chernikov ret += comment_bytes 2709f44a47fSAlexander V. Chernikov return ret 2719f44a47fSAlexander V. Chernikov 2729f44a47fSAlexander V. Chernikov def _print_obj_value(self): 2739f44a47fSAlexander V. Chernikov return " comment='{}'".format(self.comment) 2749f44a47fSAlexander V. Chernikov 2759f44a47fSAlexander V. Chernikov 2769f44a47fSAlexander V. Chernikovclass InsnProto(Insn): 2779f44a47fSAlexander V. Chernikov def __init__(self, opcode=IpFwOpcode.O_PROTO, is_or=False, is_not=False, arg1=0): 2789f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 2799f44a47fSAlexander V. Chernikov 2809f44a47fSAlexander V. Chernikov def _print_obj_value(self): 2819f44a47fSAlexander V. Chernikov known_map = {6: "TCP", 17: "UDP", 41: "IPV6"} 2829f44a47fSAlexander V. Chernikov proto = self.arg1 2839f44a47fSAlexander V. Chernikov if proto in known_map: 2849f44a47fSAlexander V. Chernikov return " proto={}".format(known_map[proto]) 2859f44a47fSAlexander V. Chernikov else: 2869f44a47fSAlexander V. Chernikov return " proto=#{}".format(proto) 2879f44a47fSAlexander V. Chernikov 2889f44a47fSAlexander V. Chernikov 2899f44a47fSAlexander V. Chernikovclass InsnU32(Insn): 2909f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, u32=0): 2919f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 2929f44a47fSAlexander V. Chernikov self.u32 = u32 2939f44a47fSAlexander V. Chernikov self.ilen = 2 2949f44a47fSAlexander V. Chernikov 2959f44a47fSAlexander V. Chernikov @classmethod 2969f44a47fSAlexander V. Chernikov def _validate(cls, data): 2979f44a47fSAlexander V. Chernikov cls._validate_len(data, [8]) 2989f44a47fSAlexander V. Chernikov 2999f44a47fSAlexander V. Chernikov @classmethod 3009f44a47fSAlexander V. Chernikov def _parse(cls, data): 3019f44a47fSAlexander V. Chernikov self = super()._parse(data[:4]) 3029f44a47fSAlexander V. Chernikov self.u32 = struct.unpack("@I", data[4:8])[0] 3039f44a47fSAlexander V. Chernikov return self 3049f44a47fSAlexander V. Chernikov 3059f44a47fSAlexander V. Chernikov def __bytes__(self): 3069f44a47fSAlexander V. Chernikov return super().__bytes__() + struct.pack("@I", self.u32) 3079f44a47fSAlexander V. Chernikov 3089f44a47fSAlexander V. Chernikov def _print_obj_value(self): 3099f44a47fSAlexander V. Chernikov return " arg1={} u32={}".format(self.arg1, self.u32) 3109f44a47fSAlexander V. Chernikov 3119f44a47fSAlexander V. Chernikov 3129f44a47fSAlexander V. Chernikovclass InsnProb(InsnU32): 3139f44a47fSAlexander V. Chernikov def __init__( 3149f44a47fSAlexander V. Chernikov self, 3159f44a47fSAlexander V. Chernikov opcode=IpFwOpcode.O_PROB, 3169f44a47fSAlexander V. Chernikov is_or=False, 3179f44a47fSAlexander V. Chernikov is_not=False, 3189f44a47fSAlexander V. Chernikov arg1=0, 3199f44a47fSAlexander V. Chernikov u32=0, 3209f44a47fSAlexander V. Chernikov prob=0.0, 3219f44a47fSAlexander V. Chernikov ): 3229f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not) 3239f44a47fSAlexander V. Chernikov self.prob = prob 3249f44a47fSAlexander V. Chernikov 3259f44a47fSAlexander V. Chernikov @property 3269f44a47fSAlexander V. Chernikov def prob(self): 3279f44a47fSAlexander V. Chernikov return 1.0 * self.u32 / 0x7FFFFFFF 3289f44a47fSAlexander V. Chernikov 3299f44a47fSAlexander V. Chernikov @prob.setter 3309f44a47fSAlexander V. Chernikov def prob(self, prob: float): 3319f44a47fSAlexander V. Chernikov self.u32 = int(prob * 0x7FFFFFFF) 3329f44a47fSAlexander V. Chernikov 3339f44a47fSAlexander V. Chernikov def _print_obj_value(self): 3349f44a47fSAlexander V. Chernikov return " prob={}".format(round(self.prob, 5)) 3359f44a47fSAlexander V. Chernikov 3369f44a47fSAlexander V. Chernikov 3379f44a47fSAlexander V. Chernikovclass InsnIp(InsnU32): 3389f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, u32=0, ip=None): 3399f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1, u32=u32) 3409f44a47fSAlexander V. Chernikov if ip: 3419f44a47fSAlexander V. Chernikov self.ip = ip 3429f44a47fSAlexander V. Chernikov 3439f44a47fSAlexander V. Chernikov @property 3449f44a47fSAlexander V. Chernikov def ip(self): 3459f44a47fSAlexander V. Chernikov return socket.inet_ntop(socket.AF_INET, struct.pack("@I", self.u32)) 3469f44a47fSAlexander V. Chernikov 3479f44a47fSAlexander V. Chernikov @ip.setter 3489f44a47fSAlexander V. Chernikov def ip(self, ip: str): 3499f44a47fSAlexander V. Chernikov ip_bin = socket.inet_pton(socket.AF_INET, ip) 3509f44a47fSAlexander V. Chernikov self.u32 = struct.unpack("@I", ip_bin)[0] 3519f44a47fSAlexander V. Chernikov 3529f44a47fSAlexander V. Chernikov def _print_opcode_value(self): 3539f44a47fSAlexander V. Chernikov return " ip={}".format(self.ip) 3549f44a47fSAlexander V. Chernikov 3559f44a47fSAlexander V. Chernikov 3569f44a47fSAlexander V. Chernikovclass InsnTable(Insn): 3579f44a47fSAlexander V. Chernikov @classmethod 3589f44a47fSAlexander V. Chernikov def _validate(cls, data): 3599f44a47fSAlexander V. Chernikov cls._validate_len(data, [4, 8]) 3609f44a47fSAlexander V. Chernikov 3619f44a47fSAlexander V. Chernikov @classmethod 3629f44a47fSAlexander V. Chernikov def _parse(cls, data): 3639f44a47fSAlexander V. Chernikov self = super()._parse(data) 3649f44a47fSAlexander V. Chernikov 3659f44a47fSAlexander V. Chernikov if len(data) == 8: 3669f44a47fSAlexander V. Chernikov (self.val,) = struct.unpack("@I", data[4:8]) 3679f44a47fSAlexander V. Chernikov self.ilen = 2 3689f44a47fSAlexander V. Chernikov else: 3699f44a47fSAlexander V. Chernikov self.val = None 3709f44a47fSAlexander V. Chernikov return self 3719f44a47fSAlexander V. Chernikov 3729f44a47fSAlexander V. Chernikov def __bytes__(self): 3739f44a47fSAlexander V. Chernikov ret = super().__bytes__() 3749f44a47fSAlexander V. Chernikov if getattr(self, "val", None) is not None: 3759f44a47fSAlexander V. Chernikov ret += struct.pack("@I", self.val) 3769f44a47fSAlexander V. Chernikov return ret 3779f44a47fSAlexander V. Chernikov 3789f44a47fSAlexander V. Chernikov def _print_obj_value(self): 3799f44a47fSAlexander V. Chernikov if getattr(self, "val", None) is not None: 3809f44a47fSAlexander V. Chernikov return " table={} value={}".format(self.arg1, self.val) 3819f44a47fSAlexander V. Chernikov else: 3829f44a47fSAlexander V. Chernikov return " table={}".format(self.arg1) 3839f44a47fSAlexander V. Chernikov 3849f44a47fSAlexander V. Chernikov 3859f44a47fSAlexander V. Chernikovclass InsnReject(Insn): 3869f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, mtu=None): 3879f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 3889f44a47fSAlexander V. Chernikov self.mtu = mtu 3899f44a47fSAlexander V. Chernikov if self.mtu is not None: 3909f44a47fSAlexander V. Chernikov self.ilen = 2 3919f44a47fSAlexander V. Chernikov 3929f44a47fSAlexander V. Chernikov @classmethod 3939f44a47fSAlexander V. Chernikov def _validate(cls, data): 3949f44a47fSAlexander V. Chernikov cls._validate_len(data, [4, 8]) 3959f44a47fSAlexander V. Chernikov 3969f44a47fSAlexander V. Chernikov @classmethod 3979f44a47fSAlexander V. Chernikov def _parse(cls, data): 3989f44a47fSAlexander V. Chernikov self = super()._parse(data) 3999f44a47fSAlexander V. Chernikov 4009f44a47fSAlexander V. Chernikov if len(data) == 8: 4019f44a47fSAlexander V. Chernikov (self.mtu,) = struct.unpack("@I", data[4:8]) 4029f44a47fSAlexander V. Chernikov self.ilen = 2 4039f44a47fSAlexander V. Chernikov else: 4049f44a47fSAlexander V. Chernikov self.mtu = None 4059f44a47fSAlexander V. Chernikov return self 4069f44a47fSAlexander V. Chernikov 4079f44a47fSAlexander V. Chernikov def __bytes__(self): 4089f44a47fSAlexander V. Chernikov ret = super().__bytes__() 4099f44a47fSAlexander V. Chernikov if getattr(self, "mtu", None) is not None: 4109f44a47fSAlexander V. Chernikov ret += struct.pack("@I", self.mtu) 4119f44a47fSAlexander V. Chernikov return ret 4129f44a47fSAlexander V. Chernikov 4139f44a47fSAlexander V. Chernikov def _print_obj_value(self): 4149f44a47fSAlexander V. Chernikov code = enum_from_int(IcmpRejectCode, self.arg1) 4159f44a47fSAlexander V. Chernikov if getattr(self, "mtu", None) is not None: 4169f44a47fSAlexander V. Chernikov return " code={} mtu={}".format(code, self.mtu) 4179f44a47fSAlexander V. Chernikov else: 4189f44a47fSAlexander V. Chernikov return " code={}".format(code) 4199f44a47fSAlexander V. Chernikov 4209f44a47fSAlexander V. Chernikov 4219f44a47fSAlexander V. Chernikovclass InsnPorts(Insn): 4229f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, port_pairs=[]): 4239f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not) 4249f44a47fSAlexander V. Chernikov self.port_pairs = [] 4259f44a47fSAlexander V. Chernikov if port_pairs: 4269f44a47fSAlexander V. Chernikov self.port_pairs = port_pairs 4279f44a47fSAlexander V. Chernikov 4289f44a47fSAlexander V. Chernikov @classmethod 4299f44a47fSAlexander V. Chernikov def _validate(cls, data): 4309f44a47fSAlexander V. Chernikov if len(data) < 8: 4319f44a47fSAlexander V. Chernikov raise ValueError("no ports specified") 4329f44a47fSAlexander V. Chernikov cls._validate_len(data) 4339f44a47fSAlexander V. Chernikov 4349f44a47fSAlexander V. Chernikov @classmethod 4359f44a47fSAlexander V. Chernikov def _parse(cls, data): 4369f44a47fSAlexander V. Chernikov self = super()._parse(data) 4379f44a47fSAlexander V. Chernikov 4389f44a47fSAlexander V. Chernikov off = 4 4399f44a47fSAlexander V. Chernikov port_pairs = [] 4409f44a47fSAlexander V. Chernikov while off + 4 <= len(data): 4419f44a47fSAlexander V. Chernikov low, high = struct.unpack("@HH", data[off : off + 4]) 4429f44a47fSAlexander V. Chernikov port_pairs.append((low, high)) 4439f44a47fSAlexander V. Chernikov off += 4 4449f44a47fSAlexander V. Chernikov self.port_pairs = port_pairs 4459f44a47fSAlexander V. Chernikov return self 4469f44a47fSAlexander V. Chernikov 4479f44a47fSAlexander V. Chernikov def __bytes__(self): 4489f44a47fSAlexander V. Chernikov ret = super().__bytes__() 4499f44a47fSAlexander V. Chernikov if getattr(self, "val", None) is not None: 4509f44a47fSAlexander V. Chernikov ret += struct.pack("@I", self.val) 4519f44a47fSAlexander V. Chernikov return ret 4529f44a47fSAlexander V. Chernikov 4539f44a47fSAlexander V. Chernikov def _print_obj_value(self): 4549f44a47fSAlexander V. Chernikov ret = [] 4559f44a47fSAlexander V. Chernikov for p in self.port_pairs: 4569f44a47fSAlexander V. Chernikov if p[0] == p[1]: 4579f44a47fSAlexander V. Chernikov ret.append(str(p[0])) 4589f44a47fSAlexander V. Chernikov else: 4599f44a47fSAlexander V. Chernikov ret.append("{}-{}".format(p[0], p[1])) 4609f44a47fSAlexander V. Chernikov return " ports={}".format(",".join(ret)) 4619f44a47fSAlexander V. Chernikov 4629f44a47fSAlexander V. Chernikov 4639f44a47fSAlexander V. Chernikovclass IpFwInsnIp6(Structure): 4649f44a47fSAlexander V. Chernikov _fields_ = [ 4659f44a47fSAlexander V. Chernikov ("o", IpFwInsn), 4669f44a47fSAlexander V. Chernikov ("addr6", c_byte * 16), 4679f44a47fSAlexander V. Chernikov ("mask6", c_byte * 16), 4689f44a47fSAlexander V. Chernikov ] 4699f44a47fSAlexander V. Chernikov 4709f44a47fSAlexander V. Chernikov 4719f44a47fSAlexander V. Chernikovclass InsnIp6(Insn): 4729f44a47fSAlexander V. Chernikov def __init__(self, opcode, is_or=False, is_not=False, arg1=0, ip6=None, mask6=None): 4739f44a47fSAlexander V. Chernikov super().__init__(opcode, is_or=is_or, is_not=is_not, arg1=arg1) 4749f44a47fSAlexander V. Chernikov self.ip6 = ip6 4759f44a47fSAlexander V. Chernikov self.mask6 = mask6 4769f44a47fSAlexander V. Chernikov if mask6 is not None: 4779f44a47fSAlexander V. Chernikov self.ilen = 9 4789f44a47fSAlexander V. Chernikov else: 4799f44a47fSAlexander V. Chernikov self.ilen = 5 4809f44a47fSAlexander V. Chernikov 4819f44a47fSAlexander V. Chernikov @classmethod 4829f44a47fSAlexander V. Chernikov def _validate(cls, data): 4839f44a47fSAlexander V. Chernikov cls._validate_len(data, [4 + 16, 4 + 16 * 2]) 4849f44a47fSAlexander V. Chernikov 4859f44a47fSAlexander V. Chernikov @classmethod 4869f44a47fSAlexander V. Chernikov def _parse(cls, data): 4879f44a47fSAlexander V. Chernikov self = super()._parse(data) 4889f44a47fSAlexander V. Chernikov self.ip6 = socket.inet_ntop(socket.AF_INET6, data[4:20]) 4899f44a47fSAlexander V. Chernikov 4909f44a47fSAlexander V. Chernikov if len(data) == 4 + 16 * 2: 4919f44a47fSAlexander V. Chernikov self.mask6 = socket.inet_ntop(socket.AF_INET6, data[20:36]) 4929f44a47fSAlexander V. Chernikov self.ilen = 9 4939f44a47fSAlexander V. Chernikov else: 4949f44a47fSAlexander V. Chernikov self.mask6 = None 4959f44a47fSAlexander V. Chernikov self.ilen = 5 4969f44a47fSAlexander V. Chernikov return self 4979f44a47fSAlexander V. Chernikov 4989f44a47fSAlexander V. Chernikov def __bytes__(self): 4999f44a47fSAlexander V. Chernikov ret = super().__bytes__() + socket.inet_pton(socket.AF_INET6, self.ip6) 5009f44a47fSAlexander V. Chernikov if self.mask6 is not None: 5019f44a47fSAlexander V. Chernikov ret += socket.inet_pton(socket.AF_INET6, self.mask6) 5029f44a47fSAlexander V. Chernikov return ret 5039f44a47fSAlexander V. Chernikov 5049f44a47fSAlexander V. Chernikov def _print_obj_value(self): 5059f44a47fSAlexander V. Chernikov if self.mask6: 5069f44a47fSAlexander V. Chernikov return " ip6={}/{}".format(self.ip6, self.mask6) 5079f44a47fSAlexander V. Chernikov else: 5089f44a47fSAlexander V. Chernikov return " ip6={}".format(self.ip6) 5099f44a47fSAlexander V. Chernikov 5109f44a47fSAlexander V. Chernikov 5119f44a47fSAlexander V. Chernikovinsn_attrs = prepare_attrs_map( 5129f44a47fSAlexander V. Chernikov [ 5139f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_CHECK_STATE, Insn), 5149f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_ACCEPT, InsnEmpty), 5159f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_COUNT, InsnEmpty), 5169f44a47fSAlexander V. Chernikov 5179f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_REJECT, InsnReject), 5189f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_UNREACH6, Insn), 5199f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_DENY, InsnEmpty), 5209f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_DIVERT, Insn), 5219f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_COUNT, InsnEmpty), 5229f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_QUEUE, Insn), 5239f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_PIPE, Insn), 5249f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_SKIPTO, Insn), 5259f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_NETGRAPH, Insn), 5269f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_NGTEE, Insn), 5279f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_DIVERT, Insn), 5289f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_TEE, Insn), 5299f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_CALLRETURN, Insn), 5309f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_SETFIB, Insn), 5319f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_SETDSCP, Insn), 5329f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_REASS, InsnEmpty), 5339f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_SETMARK, Insn), 5349f44a47fSAlexander V. Chernikov 5359f44a47fSAlexander V. Chernikov 5369f44a47fSAlexander V. Chernikov 5379f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_NOP, InsnComment), 5389f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_PROTO, InsnProto), 5399f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_PROB, InsnProb), 5409f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_DST_ME, InsnEmpty), 5419f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_SRC_ME, InsnEmpty), 5429f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP6_DST_ME, InsnEmpty), 5439f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP6_SRC_ME, InsnEmpty), 5449f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_SRC, InsnIp), 5459f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_DST, InsnIp), 5469f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP6_DST, InsnIp6), 5479f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP6_SRC, InsnIp6), 5489f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_SRC_LOOKUP, InsnTable), 5499f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_DST_LOOKUP, InsnTable), 5509f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_SRCPORT, InsnPorts), 5519f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_IP_DSTPORT, InsnPorts), 5529f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_PROBE_STATE, Insn), 5539f44a47fSAlexander V. Chernikov AttrDescr(IpFwOpcode.O_KEEP_STATE, Insn), 5549f44a47fSAlexander V. Chernikov ] 5559f44a47fSAlexander V. Chernikov) 556