1fee65b7eSAlexander V. Chernikovimport socket 2fee65b7eSAlexander V. Chernikovimport struct 3fee65b7eSAlexander V. Chernikovfrom enum import Enum 4fee65b7eSAlexander V. Chernikov 5388420e6SAlexander V. Chernikovfrom atf_python.sys.netlink.utils import align4 6388420e6SAlexander V. Chernikovfrom atf_python.sys.netlink.utils import enum_or_int 7fee65b7eSAlexander V. Chernikov 8fee65b7eSAlexander V. Chernikov 9fee65b7eSAlexander V. Chernikovclass NlAttr(object): 103e5d0784SAlexander V. Chernikov HDR_LEN = 4 # sizeof(struct nlattr) 113e5d0784SAlexander V. Chernikov 12fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, data): 13fee65b7eSAlexander V. Chernikov if isinstance(nla_type, Enum): 14fee65b7eSAlexander V. Chernikov self._nla_type = nla_type.value 15fee65b7eSAlexander V. Chernikov self._enum = nla_type 16fee65b7eSAlexander V. Chernikov else: 17fee65b7eSAlexander V. Chernikov self._nla_type = nla_type 18fee65b7eSAlexander V. Chernikov self._enum = None 19fee65b7eSAlexander V. Chernikov self.nla_list = [] 20fee65b7eSAlexander V. Chernikov self._data = data 21fee65b7eSAlexander V. Chernikov 22fee65b7eSAlexander V. Chernikov @property 23fee65b7eSAlexander V. Chernikov def nla_type(self): 24*04a03660SAlexander V. Chernikov return self._nla_type & 0x3FFF 25fee65b7eSAlexander V. Chernikov 26fee65b7eSAlexander V. Chernikov @property 27fee65b7eSAlexander V. Chernikov def nla_len(self): 28fee65b7eSAlexander V. Chernikov return len(self._data) + 4 29fee65b7eSAlexander V. Chernikov 30fee65b7eSAlexander V. Chernikov def add_nla(self, nla): 31fee65b7eSAlexander V. Chernikov self.nla_list.append(nla) 32fee65b7eSAlexander V. Chernikov 33fee65b7eSAlexander V. Chernikov def print_attr(self, prepend=""): 34fee65b7eSAlexander V. Chernikov if self._enum is not None: 35fee65b7eSAlexander V. Chernikov type_str = self._enum.name 36fee65b7eSAlexander V. Chernikov else: 37fee65b7eSAlexander V. Chernikov type_str = "nla#{}".format(self.nla_type) 38fee65b7eSAlexander V. Chernikov print( 39fee65b7eSAlexander V. Chernikov "{}len={} type={}({}){}".format( 40fee65b7eSAlexander V. Chernikov prepend, self.nla_len, type_str, self.nla_type, self._print_attr_value() 41fee65b7eSAlexander V. Chernikov ) 42fee65b7eSAlexander V. Chernikov ) 43fee65b7eSAlexander V. Chernikov 44fee65b7eSAlexander V. Chernikov @staticmethod 45fee65b7eSAlexander V. Chernikov def _validate(data): 46fee65b7eSAlexander V. Chernikov if len(data) < 4: 47fee65b7eSAlexander V. Chernikov raise ValueError("attribute too short") 48fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 49fee65b7eSAlexander V. Chernikov if nla_len > len(data): 50fee65b7eSAlexander V. Chernikov raise ValueError("attribute length too big") 51fee65b7eSAlexander V. Chernikov if nla_len < 4: 52fee65b7eSAlexander V. Chernikov raise ValueError("attribute length too short") 53fee65b7eSAlexander V. Chernikov 54fee65b7eSAlexander V. Chernikov @classmethod 55fee65b7eSAlexander V. Chernikov def _parse(cls, data): 56fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 57fee65b7eSAlexander V. Chernikov return cls(nla_type, data[4:]) 58fee65b7eSAlexander V. Chernikov 59fee65b7eSAlexander V. Chernikov @classmethod 60fee65b7eSAlexander V. Chernikov def from_bytes(cls, data, attr_type_enum=None): 61fee65b7eSAlexander V. Chernikov cls._validate(data) 62fee65b7eSAlexander V. Chernikov attr = cls._parse(data) 63fee65b7eSAlexander V. Chernikov attr._enum = attr_type_enum 64fee65b7eSAlexander V. Chernikov return attr 65fee65b7eSAlexander V. Chernikov 66fee65b7eSAlexander V. Chernikov def _to_bytes(self, data: bytes): 67fee65b7eSAlexander V. Chernikov ret = data 68fee65b7eSAlexander V. Chernikov if align4(len(ret)) != len(ret): 69fee65b7eSAlexander V. Chernikov ret = data + bytes(align4(len(ret)) - len(ret)) 70fee65b7eSAlexander V. Chernikov return struct.pack("@HH", len(data) + 4, self._nla_type) + ret 71fee65b7eSAlexander V. Chernikov 72fee65b7eSAlexander V. Chernikov def __bytes__(self): 73fee65b7eSAlexander V. Chernikov return self._to_bytes(self._data) 74fee65b7eSAlexander V. Chernikov 75fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 76fee65b7eSAlexander V. Chernikov return " " + " ".join(["x{:02X}".format(b) for b in self._data]) 77fee65b7eSAlexander V. Chernikov 78fee65b7eSAlexander V. Chernikov 79fee65b7eSAlexander V. Chernikovclass NlAttrNested(NlAttr): 80fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, val): 81fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 82fee65b7eSAlexander V. Chernikov self.nla_list = val 83fee65b7eSAlexander V. Chernikov 84fee65b7eSAlexander V. Chernikov @property 85fee65b7eSAlexander V. Chernikov def nla_len(self): 86fee65b7eSAlexander V. Chernikov return align4(len(b"".join([bytes(nla) for nla in self.nla_list]))) + 4 87fee65b7eSAlexander V. Chernikov 88fee65b7eSAlexander V. Chernikov def print_attr(self, prepend=""): 89fee65b7eSAlexander V. Chernikov if self._enum is not None: 90fee65b7eSAlexander V. Chernikov type_str = self._enum.name 91fee65b7eSAlexander V. Chernikov else: 92fee65b7eSAlexander V. Chernikov type_str = "nla#{}".format(self.nla_type) 93fee65b7eSAlexander V. Chernikov print( 94fee65b7eSAlexander V. Chernikov "{}len={} type={}({}) {{".format( 95fee65b7eSAlexander V. Chernikov prepend, self.nla_len, type_str, self.nla_type 96fee65b7eSAlexander V. Chernikov ) 97fee65b7eSAlexander V. Chernikov ) 98fee65b7eSAlexander V. Chernikov for nla in self.nla_list: 99fee65b7eSAlexander V. Chernikov nla.print_attr(prepend + " ") 100fee65b7eSAlexander V. Chernikov print("{}}}".format(prepend)) 101fee65b7eSAlexander V. Chernikov 102fee65b7eSAlexander V. Chernikov def __bytes__(self): 103fee65b7eSAlexander V. Chernikov return self._to_bytes(b"".join([bytes(nla) for nla in self.nla_list])) 104fee65b7eSAlexander V. Chernikov 105fee65b7eSAlexander V. Chernikov 106fee65b7eSAlexander V. Chernikovclass NlAttrU32(NlAttr): 107fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, val): 108fee65b7eSAlexander V. Chernikov self.u32 = enum_or_int(val) 109fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 110fee65b7eSAlexander V. Chernikov 111fee65b7eSAlexander V. Chernikov @property 112fee65b7eSAlexander V. Chernikov def nla_len(self): 113fee65b7eSAlexander V. Chernikov return 8 114fee65b7eSAlexander V. Chernikov 115fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 116fee65b7eSAlexander V. Chernikov return " val={}".format(self.u32) 117fee65b7eSAlexander V. Chernikov 118fee65b7eSAlexander V. Chernikov @staticmethod 119fee65b7eSAlexander V. Chernikov def _validate(data): 120fee65b7eSAlexander V. Chernikov assert len(data) == 8 121fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 122fee65b7eSAlexander V. Chernikov assert nla_len == 8 123fee65b7eSAlexander V. Chernikov 124fee65b7eSAlexander V. Chernikov @classmethod 125fee65b7eSAlexander V. Chernikov def _parse(cls, data): 126fee65b7eSAlexander V. Chernikov nla_len, nla_type, val = struct.unpack("@HHI", data) 127fee65b7eSAlexander V. Chernikov return cls(nla_type, val) 128fee65b7eSAlexander V. Chernikov 129fee65b7eSAlexander V. Chernikov def __bytes__(self): 130fee65b7eSAlexander V. Chernikov return self._to_bytes(struct.pack("@I", self.u32)) 131fee65b7eSAlexander V. Chernikov 132fee65b7eSAlexander V. Chernikov 133fee65b7eSAlexander V. Chernikovclass NlAttrU16(NlAttr): 134fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, val): 135fee65b7eSAlexander V. Chernikov self.u16 = enum_or_int(val) 136fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 137fee65b7eSAlexander V. Chernikov 138fee65b7eSAlexander V. Chernikov @property 139fee65b7eSAlexander V. Chernikov def nla_len(self): 140fee65b7eSAlexander V. Chernikov return 6 141fee65b7eSAlexander V. Chernikov 142fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 143fee65b7eSAlexander V. Chernikov return " val={}".format(self.u16) 144fee65b7eSAlexander V. Chernikov 145fee65b7eSAlexander V. Chernikov @staticmethod 146fee65b7eSAlexander V. Chernikov def _validate(data): 147fee65b7eSAlexander V. Chernikov assert len(data) == 6 148fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 149fee65b7eSAlexander V. Chernikov assert nla_len == 6 150fee65b7eSAlexander V. Chernikov 151fee65b7eSAlexander V. Chernikov @classmethod 152fee65b7eSAlexander V. Chernikov def _parse(cls, data): 153fee65b7eSAlexander V. Chernikov nla_len, nla_type, val = struct.unpack("@HHH", data) 154fee65b7eSAlexander V. Chernikov return cls(nla_type, val) 155fee65b7eSAlexander V. Chernikov 156fee65b7eSAlexander V. Chernikov def __bytes__(self): 157fee65b7eSAlexander V. Chernikov return self._to_bytes(struct.pack("@H", self.u16)) 158fee65b7eSAlexander V. Chernikov 159fee65b7eSAlexander V. Chernikov 160fee65b7eSAlexander V. Chernikovclass NlAttrU8(NlAttr): 161fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, val): 162fee65b7eSAlexander V. Chernikov self.u8 = enum_or_int(val) 163fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 164fee65b7eSAlexander V. Chernikov 165fee65b7eSAlexander V. Chernikov @property 166fee65b7eSAlexander V. Chernikov def nla_len(self): 167fee65b7eSAlexander V. Chernikov return 5 168fee65b7eSAlexander V. Chernikov 169fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 170fee65b7eSAlexander V. Chernikov return " val={}".format(self.u8) 171fee65b7eSAlexander V. Chernikov 172fee65b7eSAlexander V. Chernikov @staticmethod 173fee65b7eSAlexander V. Chernikov def _validate(data): 174fee65b7eSAlexander V. Chernikov assert len(data) == 5 175fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 176fee65b7eSAlexander V. Chernikov assert nla_len == 5 177fee65b7eSAlexander V. Chernikov 178fee65b7eSAlexander V. Chernikov @classmethod 179fee65b7eSAlexander V. Chernikov def _parse(cls, data): 180fee65b7eSAlexander V. Chernikov nla_len, nla_type, val = struct.unpack("@HHB", data) 181fee65b7eSAlexander V. Chernikov return cls(nla_type, val) 182fee65b7eSAlexander V. Chernikov 183fee65b7eSAlexander V. Chernikov def __bytes__(self): 184fee65b7eSAlexander V. Chernikov return self._to_bytes(struct.pack("@B", self.u8)) 185fee65b7eSAlexander V. Chernikov 186fee65b7eSAlexander V. Chernikov 187fee65b7eSAlexander V. Chernikovclass NlAttrIp(NlAttr): 188fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, addr: str): 189fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 190fee65b7eSAlexander V. Chernikov self.addr = addr 191fee65b7eSAlexander V. Chernikov if ":" in self.addr: 192fee65b7eSAlexander V. Chernikov self.family = socket.AF_INET6 193fee65b7eSAlexander V. Chernikov else: 194fee65b7eSAlexander V. Chernikov self.family = socket.AF_INET 195fee65b7eSAlexander V. Chernikov 196fee65b7eSAlexander V. Chernikov @staticmethod 197fee65b7eSAlexander V. Chernikov def _validate(data): 198fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 199fee65b7eSAlexander V. Chernikov data_len = nla_len - 4 200fee65b7eSAlexander V. Chernikov if data_len != 4 and data_len != 16: 201fee65b7eSAlexander V. Chernikov raise ValueError( 202fee65b7eSAlexander V. Chernikov "Error validating attr {}: nla_len is not valid".format( # noqa: E501 203fee65b7eSAlexander V. Chernikov nla_type 204fee65b7eSAlexander V. Chernikov ) 205fee65b7eSAlexander V. Chernikov ) 206fee65b7eSAlexander V. Chernikov 207fee65b7eSAlexander V. Chernikov @property 208fee65b7eSAlexander V. Chernikov def nla_len(self): 209fee65b7eSAlexander V. Chernikov if self.family == socket.AF_INET6: 210fee65b7eSAlexander V. Chernikov return 20 211fee65b7eSAlexander V. Chernikov else: 212fee65b7eSAlexander V. Chernikov return 8 213fee65b7eSAlexander V. Chernikov return align4(len(self._data)) + 4 214fee65b7eSAlexander V. Chernikov 215fee65b7eSAlexander V. Chernikov @classmethod 216fee65b7eSAlexander V. Chernikov def _parse(cls, data): 217fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 218fee65b7eSAlexander V. Chernikov data_len = len(data) - 4 219fee65b7eSAlexander V. Chernikov if data_len == 4: 220fee65b7eSAlexander V. Chernikov addr = socket.inet_ntop(socket.AF_INET, data[4:8]) 221fee65b7eSAlexander V. Chernikov else: 222fee65b7eSAlexander V. Chernikov addr = socket.inet_ntop(socket.AF_INET6, data[4:20]) 223fee65b7eSAlexander V. Chernikov return cls(nla_type, addr) 224fee65b7eSAlexander V. Chernikov 225fee65b7eSAlexander V. Chernikov def __bytes__(self): 226fee65b7eSAlexander V. Chernikov return self._to_bytes(socket.inet_pton(self.family, self.addr)) 227fee65b7eSAlexander V. Chernikov 228fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 229fee65b7eSAlexander V. Chernikov return " addr={}".format(self.addr) 230fee65b7eSAlexander V. Chernikov 231fee65b7eSAlexander V. Chernikov 232fee65b7eSAlexander V. Chernikovclass NlAttrStr(NlAttr): 233fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, text): 234fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 235fee65b7eSAlexander V. Chernikov self.text = text 236fee65b7eSAlexander V. Chernikov 237fee65b7eSAlexander V. Chernikov @staticmethod 238fee65b7eSAlexander V. Chernikov def _validate(data): 239fee65b7eSAlexander V. Chernikov NlAttr._validate(data) 240fee65b7eSAlexander V. Chernikov try: 241fee65b7eSAlexander V. Chernikov data[4:].decode("utf-8") 242fee65b7eSAlexander V. Chernikov except Exception as e: 243fee65b7eSAlexander V. Chernikov raise ValueError("wrong utf-8 string: {}".format(e)) 244fee65b7eSAlexander V. Chernikov 245fee65b7eSAlexander V. Chernikov @property 246fee65b7eSAlexander V. Chernikov def nla_len(self): 247fee65b7eSAlexander V. Chernikov return len(self.text) + 5 248fee65b7eSAlexander V. Chernikov 249fee65b7eSAlexander V. Chernikov @classmethod 250fee65b7eSAlexander V. Chernikov def _parse(cls, data): 251fee65b7eSAlexander V. Chernikov text = data[4:-1].decode("utf-8") 252fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 253fee65b7eSAlexander V. Chernikov return cls(nla_type, text) 254fee65b7eSAlexander V. Chernikov 255fee65b7eSAlexander V. Chernikov def __bytes__(self): 256fee65b7eSAlexander V. Chernikov return self._to_bytes(bytes(self.text, encoding="utf-8") + bytes(1)) 257fee65b7eSAlexander V. Chernikov 258fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 259fee65b7eSAlexander V. Chernikov return ' val="{}"'.format(self.text) 260fee65b7eSAlexander V. Chernikov 261fee65b7eSAlexander V. Chernikov 262fee65b7eSAlexander V. Chernikovclass NlAttrStrn(NlAttr): 263fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, text): 264fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 265fee65b7eSAlexander V. Chernikov self.text = text 266fee65b7eSAlexander V. Chernikov 267fee65b7eSAlexander V. Chernikov @staticmethod 268fee65b7eSAlexander V. Chernikov def _validate(data): 269fee65b7eSAlexander V. Chernikov NlAttr._validate(data) 270fee65b7eSAlexander V. Chernikov try: 271fee65b7eSAlexander V. Chernikov data[4:].decode("utf-8") 272fee65b7eSAlexander V. Chernikov except Exception as e: 273fee65b7eSAlexander V. Chernikov raise ValueError("wrong utf-8 string: {}".format(e)) 274fee65b7eSAlexander V. Chernikov 275fee65b7eSAlexander V. Chernikov @property 276fee65b7eSAlexander V. Chernikov def nla_len(self): 277fee65b7eSAlexander V. Chernikov return len(self.text) + 4 278fee65b7eSAlexander V. Chernikov 279fee65b7eSAlexander V. Chernikov @classmethod 280fee65b7eSAlexander V. Chernikov def _parse(cls, data): 281fee65b7eSAlexander V. Chernikov text = data[4:].decode("utf-8") 282fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 283fee65b7eSAlexander V. Chernikov return cls(nla_type, text) 284fee65b7eSAlexander V. Chernikov 285fee65b7eSAlexander V. Chernikov def __bytes__(self): 286fee65b7eSAlexander V. Chernikov return self._to_bytes(bytes(self.text, encoding="utf-8")) 287fee65b7eSAlexander V. Chernikov 288fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 289fee65b7eSAlexander V. Chernikov return ' val="{}"'.format(self.text) 290