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