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. Chernikovimport pytest 269f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import BaseInsn 279f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.insns import insn_attrs 289f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl_headers import IpFwTableLookupType 299f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl_headers import IpFwTlvType 309f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.ioctl_headers import Op3CmdType 319f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import align8 329f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import AttrDescr 339f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import enum_from_int 349f44a47fSAlexander V. Chernikovfrom atf_python.sys.netpfil.ipfw.utils import prepare_attrs_map 359f44a47fSAlexander V. Chernikov 369f44a47fSAlexander V. Chernikov 379f44a47fSAlexander V. Chernikovclass IpFw3OpHeader(Structure): 389f44a47fSAlexander V. Chernikov _fields_ = [ 399f44a47fSAlexander V. Chernikov ("opcode", c_ushort), 409f44a47fSAlexander V. Chernikov ("version", c_ushort), 419f44a47fSAlexander V. Chernikov ("reserved1", c_ushort), 429f44a47fSAlexander V. Chernikov ("reserved2", c_ushort), 439f44a47fSAlexander V. Chernikov ] 449f44a47fSAlexander V. Chernikov 459f44a47fSAlexander V. Chernikov 469f44a47fSAlexander V. Chernikovclass IpFwObjTlv(Structure): 479f44a47fSAlexander V. Chernikov _fields_ = [ 489f44a47fSAlexander V. Chernikov ("n_type", c_ushort), 499f44a47fSAlexander V. Chernikov ("flags", c_ushort), 509f44a47fSAlexander V. Chernikov ("length", c_uint32), 519f44a47fSAlexander V. Chernikov ] 529f44a47fSAlexander V. Chernikov 539f44a47fSAlexander V. Chernikov 549f44a47fSAlexander V. Chernikovclass BaseTlv(object): 559f44a47fSAlexander V. Chernikov obj_enum_class = IpFwTlvType 569f44a47fSAlexander V. Chernikov 579f44a47fSAlexander V. Chernikov def __init__(self, obj_type): 589f44a47fSAlexander V. Chernikov if isinstance(obj_type, Enum): 599f44a47fSAlexander V. Chernikov self.obj_type = obj_type.value 609f44a47fSAlexander V. Chernikov self._enum = obj_type 619f44a47fSAlexander V. Chernikov else: 629f44a47fSAlexander V. Chernikov self.obj_type = obj_type 639f44a47fSAlexander V. Chernikov self._enum = enum_from_int(self.obj_enum_class, obj_type) 649f44a47fSAlexander V. Chernikov self.obj_list = [] 659f44a47fSAlexander V. Chernikov 669f44a47fSAlexander V. Chernikov def add_obj(self, obj): 679f44a47fSAlexander V. Chernikov self.obj_list.append(obj) 689f44a47fSAlexander V. Chernikov 699f44a47fSAlexander V. Chernikov @property 709f44a47fSAlexander V. Chernikov def len(self): 719f44a47fSAlexander V. Chernikov return len(bytes(self)) 729f44a47fSAlexander V. Chernikov 739f44a47fSAlexander V. Chernikov @property 749f44a47fSAlexander V. Chernikov def obj_name(self): 759f44a47fSAlexander V. Chernikov if self._enum is not None: 769f44a47fSAlexander V. Chernikov return self._enum.name 779f44a47fSAlexander V. Chernikov else: 789f44a47fSAlexander V. Chernikov return "tlv#{}".format(self.obj_type) 799f44a47fSAlexander V. Chernikov 809f44a47fSAlexander V. Chernikov def print_hdr(self, prepend=""): 819f44a47fSAlexander V. Chernikov print( 829f44a47fSAlexander V. Chernikov "{}len={} type={}({}){}".format( 839f44a47fSAlexander V. Chernikov prepend, self.len, self.obj_name, self.obj_type, self._print_obj_value() 849f44a47fSAlexander V. Chernikov ) 859f44a47fSAlexander V. Chernikov ) 869f44a47fSAlexander V. Chernikov 879f44a47fSAlexander V. Chernikov def print_obj(self, prepend=""): 889f44a47fSAlexander V. Chernikov self.print_hdr(prepend) 899f44a47fSAlexander V. Chernikov prepend = " " + prepend 909f44a47fSAlexander V. Chernikov for obj in self.obj_list: 919f44a47fSAlexander V. Chernikov obj.print_obj(prepend) 929f44a47fSAlexander V. Chernikov 93*84b41342SAlexander V. Chernikov def print_obj_hex(self, prepend=""): 94*84b41342SAlexander V. Chernikov print(prepend) 95*84b41342SAlexander V. Chernikov print() 96*84b41342SAlexander V. Chernikov print(" ".join(["x{:02X}".format(b) for b in bytes(self)])) 97*84b41342SAlexander V. Chernikov 989f44a47fSAlexander V. Chernikov @classmethod 999f44a47fSAlexander V. Chernikov def _validate(cls, data): 1009f44a47fSAlexander V. Chernikov if len(data) < sizeof(IpFwObjTlv): 1019f44a47fSAlexander V. Chernikov raise ValueError("TLV too short") 1029f44a47fSAlexander V. Chernikov hdr = IpFwObjTlv.from_buffer_copy(data[: sizeof(IpFwObjTlv)]) 1039f44a47fSAlexander V. Chernikov if len(data) != hdr.length: 1049f44a47fSAlexander V. Chernikov raise ValueError("wrong TLV size") 1059f44a47fSAlexander V. Chernikov 1069f44a47fSAlexander V. Chernikov @classmethod 1079f44a47fSAlexander V. Chernikov def _parse(cls, data, attr_map): 1089f44a47fSAlexander V. Chernikov hdr = IpFwObjTlv.from_buffer_copy(data[: sizeof(IpFwObjTlv)]) 1099f44a47fSAlexander V. Chernikov return cls(hdr.n_type) 1109f44a47fSAlexander V. Chernikov 1119f44a47fSAlexander V. Chernikov @classmethod 1129f44a47fSAlexander V. Chernikov def from_bytes(cls, data, attr_map=None): 1139f44a47fSAlexander V. Chernikov cls._validate(data) 1149f44a47fSAlexander V. Chernikov obj = cls._parse(data, attr_map) 1159f44a47fSAlexander V. Chernikov return obj 1169f44a47fSAlexander V. Chernikov 1179f44a47fSAlexander V. Chernikov def __bytes__(self): 1189f44a47fSAlexander V. Chernikov raise NotImplementedError() 1199f44a47fSAlexander V. Chernikov 1209f44a47fSAlexander V. Chernikov def _print_obj_value(self): 1219f44a47fSAlexander V. Chernikov return " " + " ".join( 1229f44a47fSAlexander V. Chernikov ["x{:02X}".format(b) for b in self._data[sizeof(IpFwObjTlv) :]] 1239f44a47fSAlexander V. Chernikov ) 1249f44a47fSAlexander V. Chernikov 1259f44a47fSAlexander V. Chernikov def as_hexdump(self): 1269f44a47fSAlexander V. Chernikov return " ".join(["x{:02X}".format(b) for b in bytes(self)]) 1279f44a47fSAlexander V. Chernikov 1289f44a47fSAlexander V. Chernikov 1299f44a47fSAlexander V. Chernikovclass UnknownTlv(BaseTlv): 1309f44a47fSAlexander V. Chernikov def __init__(self, obj_type, data): 1319f44a47fSAlexander V. Chernikov super().__init__(obj_type) 1329f44a47fSAlexander V. Chernikov self._data = data 1339f44a47fSAlexander V. Chernikov 1349f44a47fSAlexander V. Chernikov @classmethod 1359f44a47fSAlexander V. Chernikov def _validate(cls, data): 1369f44a47fSAlexander V. Chernikov if len(data) < sizeof(IpFwObjNTlv): 1379f44a47fSAlexander V. Chernikov raise ValueError("TLV size is too short") 1389f44a47fSAlexander V. Chernikov hdr = IpFwObjTlv.from_buffer_copy(data[: sizeof(IpFwObjTlv)]) 1399f44a47fSAlexander V. Chernikov if len(data) != hdr.length: 1409f44a47fSAlexander V. Chernikov raise ValueError("wrong TLV size") 1419f44a47fSAlexander V. Chernikov 1429f44a47fSAlexander V. Chernikov @classmethod 1439f44a47fSAlexander V. Chernikov def _parse(cls, data, attr_map): 1449f44a47fSAlexander V. Chernikov hdr = IpFwObjTlv.from_buffer_copy(data[: sizeof(IpFwObjTlv)]) 1459f44a47fSAlexander V. Chernikov self = cls(hdr.n_type, data) 1469f44a47fSAlexander V. Chernikov return self 1479f44a47fSAlexander V. Chernikov 1489f44a47fSAlexander V. Chernikov def __bytes__(self): 1499f44a47fSAlexander V. Chernikov return self._data 1509f44a47fSAlexander V. Chernikov 1519f44a47fSAlexander V. Chernikov 1529f44a47fSAlexander V. Chernikovclass Tlv(BaseTlv): 1539f44a47fSAlexander V. Chernikov @staticmethod 1549f44a47fSAlexander V. Chernikov def parse_tlvs(data, attr_map): 1559f44a47fSAlexander V. Chernikov # print("PARSING " + " ".join(["x{:02X}".format(b) for b in data])) 1569f44a47fSAlexander V. Chernikov off = 0 1579f44a47fSAlexander V. Chernikov ret = [] 1589f44a47fSAlexander V. Chernikov while off + sizeof(IpFwObjTlv) <= len(data): 1599f44a47fSAlexander V. Chernikov hdr = IpFwObjTlv.from_buffer_copy(data[off : off + sizeof(IpFwObjTlv)]) 1609f44a47fSAlexander V. Chernikov if off + hdr.length > len(data): 1619f44a47fSAlexander V. Chernikov raise ValueError("TLV size do not match") 1629f44a47fSAlexander V. Chernikov obj_data = data[off : off + hdr.length] 1639f44a47fSAlexander V. Chernikov obj_descr = attr_map.get(hdr.n_type, None) 1649f44a47fSAlexander V. Chernikov if obj_descr is None: 1659f44a47fSAlexander V. Chernikov # raise ValueError("unknown child TLV {}".format(hdr.n_type)) 1669f44a47fSAlexander V. Chernikov cls = UnknownTlv 1679f44a47fSAlexander V. Chernikov child_map = {} 1689f44a47fSAlexander V. Chernikov else: 1699f44a47fSAlexander V. Chernikov cls = obj_descr["ad"].cls 1709f44a47fSAlexander V. Chernikov child_map = obj_descr.get("child", {}) 1719f44a47fSAlexander V. Chernikov # print("FOUND OBJECT type {}".format(cls)) 1729f44a47fSAlexander V. Chernikov # print() 1739f44a47fSAlexander V. Chernikov obj = cls.from_bytes(obj_data, child_map) 1749f44a47fSAlexander V. Chernikov ret.append(obj) 1759f44a47fSAlexander V. Chernikov off += hdr.length 1769f44a47fSAlexander V. Chernikov return ret 1779f44a47fSAlexander V. Chernikov 1789f44a47fSAlexander V. Chernikov 1799f44a47fSAlexander V. Chernikovclass IpFwObjNTlv(Structure): 1809f44a47fSAlexander V. Chernikov _fields_ = [ 1819f44a47fSAlexander V. Chernikov ("head", IpFwObjTlv), 1829f44a47fSAlexander V. Chernikov ("idx", c_ushort), 1839f44a47fSAlexander V. Chernikov ("n_set", c_uint8), 1849f44a47fSAlexander V. Chernikov ("n_type", c_uint8), 1859f44a47fSAlexander V. Chernikov ("spare", c_uint32), 1869f44a47fSAlexander V. Chernikov ("name", c_char * 64), 1879f44a47fSAlexander V. Chernikov ] 1889f44a47fSAlexander V. Chernikov 1899f44a47fSAlexander V. Chernikov 1909f44a47fSAlexander V. Chernikovclass NTlv(Tlv): 1919f44a47fSAlexander V. Chernikov def __init__(self, obj_type, idx=0, n_set=0, n_type=0, name=None): 1929f44a47fSAlexander V. Chernikov super().__init__(obj_type) 1939f44a47fSAlexander V. Chernikov self.n_idx = idx 1949f44a47fSAlexander V. Chernikov self.n_set = n_set 1959f44a47fSAlexander V. Chernikov self.n_type = n_type 1969f44a47fSAlexander V. Chernikov self.n_name = name 1979f44a47fSAlexander V. Chernikov 1989f44a47fSAlexander V. Chernikov @classmethod 1999f44a47fSAlexander V. Chernikov def _validate(cls, data): 2009f44a47fSAlexander V. Chernikov if len(data) != sizeof(IpFwObjNTlv): 2019f44a47fSAlexander V. Chernikov raise ValueError("TLV size is not correct") 2029f44a47fSAlexander V. Chernikov hdr = IpFwObjTlv.from_buffer_copy(data[: sizeof(IpFwObjTlv)]) 2039f44a47fSAlexander V. Chernikov if len(data) != hdr.length: 2049f44a47fSAlexander V. Chernikov raise ValueError("wrong TLV size") 2059f44a47fSAlexander V. Chernikov 2069f44a47fSAlexander V. Chernikov @classmethod 2079f44a47fSAlexander V. Chernikov def _parse(cls, data, attr_map): 2089f44a47fSAlexander V. Chernikov hdr = IpFwObjNTlv.from_buffer_copy(data[: sizeof(IpFwObjNTlv)]) 2099f44a47fSAlexander V. Chernikov name = hdr.name.decode("utf-8") 2109f44a47fSAlexander V. Chernikov self = cls(hdr.head.n_type, hdr.idx, hdr.n_set, hdr.n_type, name) 2119f44a47fSAlexander V. Chernikov return self 2129f44a47fSAlexander V. Chernikov 2139f44a47fSAlexander V. Chernikov def __bytes__(self): 2149f44a47fSAlexander V. Chernikov name_bytes = self.n_name.encode("utf-8") 2159f44a47fSAlexander V. Chernikov if len(name_bytes) < 64: 2169f44a47fSAlexander V. Chernikov name_bytes += b"\0" * (64 - len(name_bytes)) 2179f44a47fSAlexander V. Chernikov hdr = IpFwObjNTlv( 2189f44a47fSAlexander V. Chernikov head=IpFwObjTlv(n_type=self.obj_type, length=sizeof(IpFwObjNTlv)), 2199f44a47fSAlexander V. Chernikov idx=self.n_idx, 2209f44a47fSAlexander V. Chernikov n_set=self.n_set, 2219f44a47fSAlexander V. Chernikov n_type=self.n_type, 2229f44a47fSAlexander V. Chernikov name=name_bytes[:64], 2239f44a47fSAlexander V. Chernikov ) 2249f44a47fSAlexander V. Chernikov return bytes(hdr) 2259f44a47fSAlexander V. Chernikov 2269f44a47fSAlexander V. Chernikov def _print_obj_value(self): 2279f44a47fSAlexander V. Chernikov return " " + "type={} set={} idx={} name={}".format( 2289f44a47fSAlexander V. Chernikov self.n_type, self.n_set, self.n_idx, self.n_name 2299f44a47fSAlexander V. Chernikov ) 2309f44a47fSAlexander V. Chernikov 2319f44a47fSAlexander V. Chernikov 2329f44a47fSAlexander V. Chernikovclass IpFwObjCTlv(Structure): 2339f44a47fSAlexander V. Chernikov _fields_ = [ 2349f44a47fSAlexander V. Chernikov ("head", IpFwObjTlv), 2359f44a47fSAlexander V. Chernikov ("count", c_uint32), 2369f44a47fSAlexander V. Chernikov ("objsize", c_ushort), 2379f44a47fSAlexander V. Chernikov ("version", c_uint8), 2389f44a47fSAlexander V. Chernikov ("flags", c_uint8), 2399f44a47fSAlexander V. Chernikov ] 2409f44a47fSAlexander V. Chernikov 2419f44a47fSAlexander V. Chernikov 2429f44a47fSAlexander V. Chernikovclass CTlv(Tlv): 2439f44a47fSAlexander V. Chernikov def __init__(self, obj_type, obj_list=[]): 2449f44a47fSAlexander V. Chernikov super().__init__(obj_type) 2459f44a47fSAlexander V. Chernikov if obj_list: 2469f44a47fSAlexander V. Chernikov self.obj_list.extend(obj_list) 2479f44a47fSAlexander V. Chernikov 2489f44a47fSAlexander V. Chernikov @classmethod 2499f44a47fSAlexander V. Chernikov def _validate(cls, data): 2509f44a47fSAlexander V. Chernikov if len(data) < sizeof(IpFwObjCTlv): 2519f44a47fSAlexander V. Chernikov raise ValueError("TLV too short") 2529f44a47fSAlexander V. Chernikov hdr = IpFwObjCTlv.from_buffer_copy(data[: sizeof(IpFwObjCTlv)]) 2539f44a47fSAlexander V. Chernikov if len(data) != hdr.head.length: 2549f44a47fSAlexander V. Chernikov raise ValueError("wrong TLV size") 2559f44a47fSAlexander V. Chernikov 2569f44a47fSAlexander V. Chernikov @classmethod 2579f44a47fSAlexander V. Chernikov def _parse(cls, data, attr_map): 2589f44a47fSAlexander V. Chernikov hdr = IpFwObjCTlv.from_buffer_copy(data[: sizeof(IpFwObjCTlv)]) 2599f44a47fSAlexander V. Chernikov tlv_list = cls.parse_tlvs(data[sizeof(IpFwObjCTlv) :], attr_map) 2609f44a47fSAlexander V. Chernikov if len(tlv_list) != hdr.count: 2619f44a47fSAlexander V. Chernikov raise ValueError("wrong number of objects") 2629f44a47fSAlexander V. Chernikov self = cls(hdr.head.n_type, obj_list=tlv_list) 2639f44a47fSAlexander V. Chernikov return self 2649f44a47fSAlexander V. Chernikov 2659f44a47fSAlexander V. Chernikov def __bytes__(self): 2669f44a47fSAlexander V. Chernikov ret = b"" 2679f44a47fSAlexander V. Chernikov for obj in self.obj_list: 2689f44a47fSAlexander V. Chernikov ret += bytes(obj) 2699f44a47fSAlexander V. Chernikov length = len(ret) + sizeof(IpFwObjCTlv) 2709f44a47fSAlexander V. Chernikov if self.obj_list: 2719f44a47fSAlexander V. Chernikov objsize = len(bytes(self.obj_list[0])) 2729f44a47fSAlexander V. Chernikov else: 2739f44a47fSAlexander V. Chernikov objsize = 0 2749f44a47fSAlexander V. Chernikov hdr = IpFwObjCTlv( 2759f44a47fSAlexander V. Chernikov head=IpFwObjTlv(n_type=self.obj_type, length=sizeof(IpFwObjNTlv)), 2769f44a47fSAlexander V. Chernikov count=len(self.obj_list), 2779f44a47fSAlexander V. Chernikov objsize=objsize, 2789f44a47fSAlexander V. Chernikov ) 2799f44a47fSAlexander V. Chernikov return bytes(hdr) + ret 2809f44a47fSAlexander V. Chernikov 2819f44a47fSAlexander V. Chernikov def _print_obj_value(self): 2829f44a47fSAlexander V. Chernikov return "" 2839f44a47fSAlexander V. Chernikov 2849f44a47fSAlexander V. Chernikov 2859f44a47fSAlexander V. Chernikovclass IpFwRule(Structure): 2869f44a47fSAlexander V. Chernikov _fields_ = [ 2879f44a47fSAlexander V. Chernikov ("act_ofs", c_ushort), 2889f44a47fSAlexander V. Chernikov ("cmd_len", c_ushort), 2899f44a47fSAlexander V. Chernikov ("spare", c_ushort), 2909f44a47fSAlexander V. Chernikov ("n_set", c_uint8), 2919f44a47fSAlexander V. Chernikov ("flags", c_uint8), 2929f44a47fSAlexander V. Chernikov ("rulenum", c_uint32), 2939f44a47fSAlexander V. Chernikov ("n_id", c_uint32), 2949f44a47fSAlexander V. Chernikov ] 2959f44a47fSAlexander V. Chernikov 2969f44a47fSAlexander V. Chernikov 2979f44a47fSAlexander V. Chernikovclass RawRule(Tlv): 2989f44a47fSAlexander V. Chernikov def __init__(self, obj_type=0, n_set=0, rulenum=0, obj_list=[]): 2999f44a47fSAlexander V. Chernikov super().__init__(obj_type) 3009f44a47fSAlexander V. Chernikov self.n_set = n_set 3019f44a47fSAlexander V. Chernikov self.rulenum = rulenum 3029f44a47fSAlexander V. Chernikov if obj_list: 3039f44a47fSAlexander V. Chernikov self.obj_list.extend(obj_list) 3049f44a47fSAlexander V. Chernikov 3059f44a47fSAlexander V. Chernikov @classmethod 3069f44a47fSAlexander V. Chernikov def _validate(cls, data): 3079f44a47fSAlexander V. Chernikov min_size = sizeof(IpFwRule) 3089f44a47fSAlexander V. Chernikov if len(data) < min_size: 3099f44a47fSAlexander V. Chernikov raise ValueError("rule TLV too short") 3109f44a47fSAlexander V. Chernikov rule = IpFwRule.from_buffer_copy(data[:min_size]) 3119f44a47fSAlexander V. Chernikov if len(data) != min_size + rule.cmd_len * 4: 3129f44a47fSAlexander V. Chernikov raise ValueError("rule TLV cmd_len incorrect") 3139f44a47fSAlexander V. Chernikov 3149f44a47fSAlexander V. Chernikov @classmethod 3159f44a47fSAlexander V. Chernikov def _parse(cls, data, attr_map): 3169f44a47fSAlexander V. Chernikov hdr = IpFwRule.from_buffer_copy(data[: sizeof(IpFwRule)]) 3179f44a47fSAlexander V. Chernikov self = cls( 3189f44a47fSAlexander V. Chernikov n_set=hdr.n_set, 3199f44a47fSAlexander V. Chernikov rulenum=hdr.rulenum, 3209f44a47fSAlexander V. Chernikov obj_list=BaseInsn.parse_insns(data[sizeof(IpFwRule) :], insn_attrs), 3219f44a47fSAlexander V. Chernikov ) 3229f44a47fSAlexander V. Chernikov return self 3239f44a47fSAlexander V. Chernikov 3249f44a47fSAlexander V. Chernikov def __bytes__(self): 3259f44a47fSAlexander V. Chernikov act_ofs = 0 3269f44a47fSAlexander V. Chernikov cmd_len = 0 3279f44a47fSAlexander V. Chernikov ret = b"" 3289f44a47fSAlexander V. Chernikov for obj in self.obj_list: 3299f44a47fSAlexander V. Chernikov if obj.is_action and act_ofs == 0: 3309f44a47fSAlexander V. Chernikov act_ofs = cmd_len 3319f44a47fSAlexander V. Chernikov obj_bytes = bytes(obj) 3329f44a47fSAlexander V. Chernikov cmd_len += len(obj_bytes) // 4 3339f44a47fSAlexander V. Chernikov ret += obj_bytes 3349f44a47fSAlexander V. Chernikov 3359f44a47fSAlexander V. Chernikov hdr = IpFwRule( 3369f44a47fSAlexander V. Chernikov act_ofs=act_ofs, 3379f44a47fSAlexander V. Chernikov cmd_len=cmd_len, 3389f44a47fSAlexander V. Chernikov n_set=self.n_set, 3399f44a47fSAlexander V. Chernikov rulenum=self.rulenum, 3409f44a47fSAlexander V. Chernikov ) 3419f44a47fSAlexander V. Chernikov return bytes(hdr) + ret 3429f44a47fSAlexander V. Chernikov 3439f44a47fSAlexander V. Chernikov @property 3449f44a47fSAlexander V. Chernikov def obj_name(self): 3459f44a47fSAlexander V. Chernikov return "rule#{}".format(self.rulenum) 3469f44a47fSAlexander V. Chernikov 3479f44a47fSAlexander V. Chernikov def _print_obj_value(self): 3489f44a47fSAlexander V. Chernikov cmd_len = sum([len(bytes(obj)) for obj in self.obj_list]) // 4 3499f44a47fSAlexander V. Chernikov return " set={} cmd_len={}".format(self.n_set, cmd_len) 3509f44a47fSAlexander V. Chernikov 3519f44a47fSAlexander V. Chernikov 3529f44a47fSAlexander V. Chernikovclass CTlvRule(CTlv): 3539f44a47fSAlexander V. Chernikov def __init__(self, obj_type=IpFwTlvType.IPFW_TLV_RULE_LIST, obj_list=[]): 3549f44a47fSAlexander V. Chernikov super().__init__(obj_type, obj_list) 3559f44a47fSAlexander V. Chernikov 3569f44a47fSAlexander V. Chernikov @classmethod 3579f44a47fSAlexander V. Chernikov def _parse(cls, data, attr_map): 3589f44a47fSAlexander V. Chernikov chdr = IpFwObjCTlv.from_buffer_copy(data[: sizeof(IpFwObjCTlv)]) 3599f44a47fSAlexander V. Chernikov rule_list = [] 3609f44a47fSAlexander V. Chernikov off = sizeof(IpFwObjCTlv) 3619f44a47fSAlexander V. Chernikov while off + sizeof(IpFwRule) <= len(data): 3629f44a47fSAlexander V. Chernikov hdr = IpFwRule.from_buffer_copy(data[off : off + sizeof(IpFwRule)]) 3639f44a47fSAlexander V. Chernikov rule_len = sizeof(IpFwRule) + hdr.cmd_len * 4 3649f44a47fSAlexander V. Chernikov # print("FOUND RULE len={} cmd_len={}".format(rule_len, hdr.cmd_len)) 3659f44a47fSAlexander V. Chernikov if off + rule_len > len(data): 3669f44a47fSAlexander V. Chernikov raise ValueError("wrong rule size") 3679f44a47fSAlexander V. Chernikov rule = RawRule.from_bytes(data[off : off + rule_len]) 3689f44a47fSAlexander V. Chernikov rule_list.append(rule) 3699f44a47fSAlexander V. Chernikov off += align8(rule_len) 3709f44a47fSAlexander V. Chernikov if off != len(data): 3719f44a47fSAlexander V. Chernikov raise ValueError("rule bytes left: off={} len={}".format(off, len(data))) 3729f44a47fSAlexander V. Chernikov return cls(chdr.head.n_type, obj_list=rule_list) 3739f44a47fSAlexander V. Chernikov 3749f44a47fSAlexander V. Chernikov # XXX: _validate 3759f44a47fSAlexander V. Chernikov 3769f44a47fSAlexander V. Chernikov def __bytes__(self): 3779f44a47fSAlexander V. Chernikov ret = b"" 3789f44a47fSAlexander V. Chernikov for rule in self.obj_list: 3799f44a47fSAlexander V. Chernikov rule_bytes = bytes(rule) 3809f44a47fSAlexander V. Chernikov remainder = len(rule_bytes) % 8 3819f44a47fSAlexander V. Chernikov if remainder > 0: 3829f44a47fSAlexander V. Chernikov rule_bytes += b"\0" * (8 - remainder) 3839f44a47fSAlexander V. Chernikov ret += rule_bytes 3849f44a47fSAlexander V. Chernikov hdr = IpFwObjCTlv( 3859f44a47fSAlexander V. Chernikov head=IpFwObjTlv( 3869f44a47fSAlexander V. Chernikov n_type=self.obj_type, length=len(ret) + sizeof(IpFwObjCTlv) 3879f44a47fSAlexander V. Chernikov ), 3889f44a47fSAlexander V. Chernikov count=len(self.obj_list), 3899f44a47fSAlexander V. Chernikov ) 3909f44a47fSAlexander V. Chernikov return bytes(hdr) + ret 3919f44a47fSAlexander V. Chernikov 3929f44a47fSAlexander V. Chernikov 3939f44a47fSAlexander V. Chernikovclass BaseIpFwMessage(object): 3949f44a47fSAlexander V. Chernikov messages = [] 3959f44a47fSAlexander V. Chernikov 3969f44a47fSAlexander V. Chernikov def __init__(self, msg_type, obj_list=[]): 3979f44a47fSAlexander V. Chernikov if isinstance(msg_type, Enum): 3989f44a47fSAlexander V. Chernikov self.obj_type = msg_type.value 3999f44a47fSAlexander V. Chernikov self._enum = msg_type 4009f44a47fSAlexander V. Chernikov else: 4019f44a47fSAlexander V. Chernikov self.obj_type = msg_type 4029f44a47fSAlexander V. Chernikov self._enum = enum_from_int(self.messages, self.obj_type) 4039f44a47fSAlexander V. Chernikov self.obj_list = [] 4049f44a47fSAlexander V. Chernikov if obj_list: 4059f44a47fSAlexander V. Chernikov self.obj_list.extend(obj_list) 4069f44a47fSAlexander V. Chernikov 4079f44a47fSAlexander V. Chernikov def add_obj(self, obj): 4089f44a47fSAlexander V. Chernikov self.obj_list.append(obj) 4099f44a47fSAlexander V. Chernikov 4109f44a47fSAlexander V. Chernikov def get_obj(self, obj_type): 4119f44a47fSAlexander V. Chernikov obj_type_raw = enum_or_int(obj_type) 4129f44a47fSAlexander V. Chernikov for obj in self.obj_list: 4139f44a47fSAlexander V. Chernikov if obj.obj_type == obj_type_raw: 4149f44a47fSAlexander V. Chernikov return obj 4159f44a47fSAlexander V. Chernikov return None 4169f44a47fSAlexander V. Chernikov 4179f44a47fSAlexander V. Chernikov @staticmethod 4189f44a47fSAlexander V. Chernikov def parse_header(data: bytes): 4199f44a47fSAlexander V. Chernikov if len(data) < sizeof(IpFw3OpHeader): 4209f44a47fSAlexander V. Chernikov raise ValueError("length less than op3 message header") 4219f44a47fSAlexander V. Chernikov return IpFw3OpHeader.from_buffer_copy(data), sizeof(IpFw3OpHeader) 4229f44a47fSAlexander V. Chernikov 4239f44a47fSAlexander V. Chernikov def parse_obj_list(self, data: bytes): 4249f44a47fSAlexander V. Chernikov off = 0 4259f44a47fSAlexander V. Chernikov while off < len(data): 4269f44a47fSAlexander V. Chernikov # print("PARSE off={} rem={}".format(off, len(data) - off)) 4279f44a47fSAlexander V. Chernikov hdr = IpFwObjTlv.from_buffer_copy(data[off : off + sizeof(IpFwObjTlv)]) 4289f44a47fSAlexander V. Chernikov # print(" tlv len {}".format(hdr.length)) 4299f44a47fSAlexander V. Chernikov if hdr.length + off > len(data): 4309f44a47fSAlexander V. Chernikov raise ValueError("TLV too big") 4319f44a47fSAlexander V. Chernikov tlv = Tlv(hdr.n_type, data[off : off + hdr.length]) 4329f44a47fSAlexander V. Chernikov self.add_obj(tlv) 4339f44a47fSAlexander V. Chernikov off += hdr.length 4349f44a47fSAlexander V. Chernikov 4359f44a47fSAlexander V. Chernikov def is_type(self, msg_type): 4369f44a47fSAlexander V. Chernikov return enum_or_int(msg_type) == self.msg_type 4379f44a47fSAlexander V. Chernikov 4389f44a47fSAlexander V. Chernikov @property 4399f44a47fSAlexander V. Chernikov def obj_name(self): 4409f44a47fSAlexander V. Chernikov if self._enum is not None: 4419f44a47fSAlexander V. Chernikov return self._enum.name 4429f44a47fSAlexander V. Chernikov else: 4439f44a47fSAlexander V. Chernikov return "msg#{}".format(self.obj_type) 4449f44a47fSAlexander V. Chernikov 4459f44a47fSAlexander V. Chernikov def print_hdr(self, prepend=""): 4469f44a47fSAlexander V. Chernikov print("{}len={}, type={}".format(prepend, len(bytes(self)), self.obj_name)) 4479f44a47fSAlexander V. Chernikov 4489f44a47fSAlexander V. Chernikov @classmethod 4499f44a47fSAlexander V. Chernikov def from_bytes(cls, data): 4509f44a47fSAlexander V. Chernikov try: 4519f44a47fSAlexander V. Chernikov hdr, hdrlen = cls.parse_header(data) 4529f44a47fSAlexander V. Chernikov self = cls(hdr.opcode) 4539f44a47fSAlexander V. Chernikov self._orig_data = data 4549f44a47fSAlexander V. Chernikov except ValueError as e: 4559f44a47fSAlexander V. Chernikov print("Failed to parse op3 header: {}".format(e)) 4569f44a47fSAlexander V. Chernikov cls.print_as_bytes(data) 4579f44a47fSAlexander V. Chernikov raise 4589f44a47fSAlexander V. Chernikov tlv_list = Tlv.parse_tlvs(data[hdrlen:], self.attr_map) 4599f44a47fSAlexander V. Chernikov self.obj_list.extend(tlv_list) 4609f44a47fSAlexander V. Chernikov return self 4619f44a47fSAlexander V. Chernikov 4629f44a47fSAlexander V. Chernikov def __bytes__(self): 4639f44a47fSAlexander V. Chernikov ret = bytes(IpFw3OpHeader(opcode=self.obj_type)) 4649f44a47fSAlexander V. Chernikov for obj in self.obj_list: 4659f44a47fSAlexander V. Chernikov ret += bytes(obj) 4669f44a47fSAlexander V. Chernikov return ret 4679f44a47fSAlexander V. Chernikov 4689f44a47fSAlexander V. Chernikov def print_obj(self): 4699f44a47fSAlexander V. Chernikov self.print_hdr() 4709f44a47fSAlexander V. Chernikov for obj in self.obj_list: 4719f44a47fSAlexander V. Chernikov obj.print_obj(" ") 4729f44a47fSAlexander V. Chernikov 4739f44a47fSAlexander V. Chernikov @staticmethod 4749f44a47fSAlexander V. Chernikov def print_as_bytes(data: bytes, descr: str): 4759f44a47fSAlexander V. Chernikov print("===vv {} (len:{:3d}) vv===".format(descr, len(data))) 4769f44a47fSAlexander V. Chernikov off = 0 4779f44a47fSAlexander V. Chernikov step = 16 4789f44a47fSAlexander V. Chernikov while off < len(data): 4799f44a47fSAlexander V. Chernikov for i in range(step): 4809f44a47fSAlexander V. Chernikov if off + i < len(data): 4819f44a47fSAlexander V. Chernikov print(" {:02X}".format(data[off + i]), end="") 4829f44a47fSAlexander V. Chernikov print("") 4839f44a47fSAlexander V. Chernikov off += step 4849f44a47fSAlexander V. Chernikov print("--------------------") 4859f44a47fSAlexander V. Chernikov 4869f44a47fSAlexander V. Chernikov 4879f44a47fSAlexander V. Chernikovrule_attrs = prepare_attrs_map( 4889f44a47fSAlexander V. Chernikov [ 4899f44a47fSAlexander V. Chernikov AttrDescr( 4909f44a47fSAlexander V. Chernikov IpFwTlvType.IPFW_TLV_TBLNAME_LIST, 4919f44a47fSAlexander V. Chernikov CTlv, 4929f44a47fSAlexander V. Chernikov [ 4939f44a47fSAlexander V. Chernikov AttrDescr(IpFwTlvType.IPFW_TLV_TBL_NAME, NTlv), 4949f44a47fSAlexander V. Chernikov AttrDescr(IpFwTlvType.IPFW_TLV_STATE_NAME, NTlv), 495*84b41342SAlexander V. Chernikov AttrDescr(IpFwTlvType.IPFW_TLV_EACTION, NTlv), 4969f44a47fSAlexander V. Chernikov ], 4979f44a47fSAlexander V. Chernikov True, 4989f44a47fSAlexander V. Chernikov ), 4999f44a47fSAlexander V. Chernikov AttrDescr(IpFwTlvType.IPFW_TLV_RULE_LIST, CTlvRule), 5009f44a47fSAlexander V. Chernikov ] 5019f44a47fSAlexander V. Chernikov) 5029f44a47fSAlexander V. Chernikov 5039f44a47fSAlexander V. Chernikov 5049f44a47fSAlexander V. Chernikovclass IpFwXRule(BaseIpFwMessage): 5059f44a47fSAlexander V. Chernikov messages = [Op3CmdType.IP_FW_XADD] 5069f44a47fSAlexander V. Chernikov attr_map = rule_attrs 5079f44a47fSAlexander V. Chernikov 5089f44a47fSAlexander V. Chernikov 5099f44a47fSAlexander V. Chernikovlegacy_classes = [] 5109f44a47fSAlexander V. Chernikovset3_classes = [] 5119f44a47fSAlexander V. Chernikovget3_classes = [IpFwXRule] 512