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): 2404a03660SAlexander 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 84*f0ffe1ceSAlexander V. Chernikov def get_nla(self, nla_type): 85*f0ffe1ceSAlexander V. Chernikov nla_type_raw = enum_or_int(nla_type) 86*f0ffe1ceSAlexander V. Chernikov for nla in self.nla_list: 87*f0ffe1ceSAlexander V. Chernikov if nla.nla_type == nla_type_raw: 88*f0ffe1ceSAlexander V. Chernikov return nla 89*f0ffe1ceSAlexander V. Chernikov return None 90*f0ffe1ceSAlexander V. Chernikov 91fee65b7eSAlexander V. Chernikov @property 92fee65b7eSAlexander V. Chernikov def nla_len(self): 93fee65b7eSAlexander V. Chernikov return align4(len(b"".join([bytes(nla) for nla in self.nla_list]))) + 4 94fee65b7eSAlexander V. Chernikov 95fee65b7eSAlexander V. Chernikov def print_attr(self, prepend=""): 96fee65b7eSAlexander V. Chernikov if self._enum is not None: 97fee65b7eSAlexander V. Chernikov type_str = self._enum.name 98fee65b7eSAlexander V. Chernikov else: 99fee65b7eSAlexander V. Chernikov type_str = "nla#{}".format(self.nla_type) 100fee65b7eSAlexander V. Chernikov print( 101fee65b7eSAlexander V. Chernikov "{}len={} type={}({}) {{".format( 102fee65b7eSAlexander V. Chernikov prepend, self.nla_len, type_str, self.nla_type 103fee65b7eSAlexander V. Chernikov ) 104fee65b7eSAlexander V. Chernikov ) 105fee65b7eSAlexander V. Chernikov for nla in self.nla_list: 106fee65b7eSAlexander V. Chernikov nla.print_attr(prepend + " ") 107fee65b7eSAlexander V. Chernikov print("{}}}".format(prepend)) 108fee65b7eSAlexander V. Chernikov 109fee65b7eSAlexander V. Chernikov def __bytes__(self): 110fee65b7eSAlexander V. Chernikov return self._to_bytes(b"".join([bytes(nla) for nla in self.nla_list])) 111fee65b7eSAlexander V. Chernikov 112fee65b7eSAlexander V. Chernikov 113fee65b7eSAlexander V. Chernikovclass NlAttrU32(NlAttr): 114fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, val): 115fee65b7eSAlexander V. Chernikov self.u32 = enum_or_int(val) 116fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 117fee65b7eSAlexander V. Chernikov 118fee65b7eSAlexander V. Chernikov @property 119fee65b7eSAlexander V. Chernikov def nla_len(self): 120fee65b7eSAlexander V. Chernikov return 8 121fee65b7eSAlexander V. Chernikov 122fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 123fee65b7eSAlexander V. Chernikov return " val={}".format(self.u32) 124fee65b7eSAlexander V. Chernikov 125fee65b7eSAlexander V. Chernikov @staticmethod 126fee65b7eSAlexander V. Chernikov def _validate(data): 127fee65b7eSAlexander V. Chernikov assert len(data) == 8 128fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 129fee65b7eSAlexander V. Chernikov assert nla_len == 8 130fee65b7eSAlexander V. Chernikov 131fee65b7eSAlexander V. Chernikov @classmethod 132fee65b7eSAlexander V. Chernikov def _parse(cls, data): 133fee65b7eSAlexander V. Chernikov nla_len, nla_type, val = struct.unpack("@HHI", data) 134fee65b7eSAlexander V. Chernikov return cls(nla_type, val) 135fee65b7eSAlexander V. Chernikov 136fee65b7eSAlexander V. Chernikov def __bytes__(self): 137fee65b7eSAlexander V. Chernikov return self._to_bytes(struct.pack("@I", self.u32)) 138fee65b7eSAlexander V. Chernikov 139fee65b7eSAlexander V. Chernikov 140*f0ffe1ceSAlexander V. Chernikovclass NlAttrS32(NlAttr): 141*f0ffe1ceSAlexander V. Chernikov def __init__(self, nla_type, val): 142*f0ffe1ceSAlexander V. Chernikov self.s32 = enum_or_int(val) 143*f0ffe1ceSAlexander V. Chernikov super().__init__(nla_type, b"") 144*f0ffe1ceSAlexander V. Chernikov 145*f0ffe1ceSAlexander V. Chernikov @property 146*f0ffe1ceSAlexander V. Chernikov def nla_len(self): 147*f0ffe1ceSAlexander V. Chernikov return 8 148*f0ffe1ceSAlexander V. Chernikov 149*f0ffe1ceSAlexander V. Chernikov def _print_attr_value(self): 150*f0ffe1ceSAlexander V. Chernikov return " val={}".format(self.s32) 151*f0ffe1ceSAlexander V. Chernikov 152*f0ffe1ceSAlexander V. Chernikov @staticmethod 153*f0ffe1ceSAlexander V. Chernikov def _validate(data): 154*f0ffe1ceSAlexander V. Chernikov assert len(data) == 8 155*f0ffe1ceSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 156*f0ffe1ceSAlexander V. Chernikov assert nla_len == 8 157*f0ffe1ceSAlexander V. Chernikov 158*f0ffe1ceSAlexander V. Chernikov @classmethod 159*f0ffe1ceSAlexander V. Chernikov def _parse(cls, data): 160*f0ffe1ceSAlexander V. Chernikov nla_len, nla_type, val = struct.unpack("@HHi", data) 161*f0ffe1ceSAlexander V. Chernikov return cls(nla_type, val) 162*f0ffe1ceSAlexander V. Chernikov 163*f0ffe1ceSAlexander V. Chernikov def __bytes__(self): 164*f0ffe1ceSAlexander V. Chernikov return self._to_bytes(struct.pack("@i", self.s32)) 165*f0ffe1ceSAlexander V. Chernikov 166*f0ffe1ceSAlexander V. Chernikov 167fee65b7eSAlexander V. Chernikovclass NlAttrU16(NlAttr): 168fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, val): 169fee65b7eSAlexander V. Chernikov self.u16 = enum_or_int(val) 170fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 171fee65b7eSAlexander V. Chernikov 172fee65b7eSAlexander V. Chernikov @property 173fee65b7eSAlexander V. Chernikov def nla_len(self): 174fee65b7eSAlexander V. Chernikov return 6 175fee65b7eSAlexander V. Chernikov 176fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 177fee65b7eSAlexander V. Chernikov return " val={}".format(self.u16) 178fee65b7eSAlexander V. Chernikov 179fee65b7eSAlexander V. Chernikov @staticmethod 180fee65b7eSAlexander V. Chernikov def _validate(data): 181fee65b7eSAlexander V. Chernikov assert len(data) == 6 182fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 183fee65b7eSAlexander V. Chernikov assert nla_len == 6 184fee65b7eSAlexander V. Chernikov 185fee65b7eSAlexander V. Chernikov @classmethod 186fee65b7eSAlexander V. Chernikov def _parse(cls, data): 187fee65b7eSAlexander V. Chernikov nla_len, nla_type, val = struct.unpack("@HHH", data) 188fee65b7eSAlexander V. Chernikov return cls(nla_type, val) 189fee65b7eSAlexander V. Chernikov 190fee65b7eSAlexander V. Chernikov def __bytes__(self): 191fee65b7eSAlexander V. Chernikov return self._to_bytes(struct.pack("@H", self.u16)) 192fee65b7eSAlexander V. Chernikov 193fee65b7eSAlexander V. Chernikov 194fee65b7eSAlexander V. Chernikovclass NlAttrU8(NlAttr): 195fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, val): 196fee65b7eSAlexander V. Chernikov self.u8 = enum_or_int(val) 197fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 198fee65b7eSAlexander V. Chernikov 199fee65b7eSAlexander V. Chernikov @property 200fee65b7eSAlexander V. Chernikov def nla_len(self): 201fee65b7eSAlexander V. Chernikov return 5 202fee65b7eSAlexander V. Chernikov 203fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 204fee65b7eSAlexander V. Chernikov return " val={}".format(self.u8) 205fee65b7eSAlexander V. Chernikov 206fee65b7eSAlexander V. Chernikov @staticmethod 207fee65b7eSAlexander V. Chernikov def _validate(data): 208fee65b7eSAlexander V. Chernikov assert len(data) == 5 209fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 210fee65b7eSAlexander V. Chernikov assert nla_len == 5 211fee65b7eSAlexander V. Chernikov 212fee65b7eSAlexander V. Chernikov @classmethod 213fee65b7eSAlexander V. Chernikov def _parse(cls, data): 214fee65b7eSAlexander V. Chernikov nla_len, nla_type, val = struct.unpack("@HHB", data) 215fee65b7eSAlexander V. Chernikov return cls(nla_type, val) 216fee65b7eSAlexander V. Chernikov 217fee65b7eSAlexander V. Chernikov def __bytes__(self): 218fee65b7eSAlexander V. Chernikov return self._to_bytes(struct.pack("@B", self.u8)) 219fee65b7eSAlexander V. Chernikov 220fee65b7eSAlexander V. Chernikov 221fee65b7eSAlexander V. Chernikovclass NlAttrIp(NlAttr): 222fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, addr: str): 223fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 224fee65b7eSAlexander V. Chernikov self.addr = addr 225fee65b7eSAlexander V. Chernikov if ":" in self.addr: 226fee65b7eSAlexander V. Chernikov self.family = socket.AF_INET6 227fee65b7eSAlexander V. Chernikov else: 228fee65b7eSAlexander V. Chernikov self.family = socket.AF_INET 229fee65b7eSAlexander V. Chernikov 230fee65b7eSAlexander V. Chernikov @staticmethod 231fee65b7eSAlexander V. Chernikov def _validate(data): 232fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 233fee65b7eSAlexander V. Chernikov data_len = nla_len - 4 234fee65b7eSAlexander V. Chernikov if data_len != 4 and data_len != 16: 235fee65b7eSAlexander V. Chernikov raise ValueError( 236fee65b7eSAlexander V. Chernikov "Error validating attr {}: nla_len is not valid".format( # noqa: E501 237fee65b7eSAlexander V. Chernikov nla_type 238fee65b7eSAlexander V. Chernikov ) 239fee65b7eSAlexander V. Chernikov ) 240fee65b7eSAlexander V. Chernikov 241fee65b7eSAlexander V. Chernikov @property 242fee65b7eSAlexander V. Chernikov def nla_len(self): 243fee65b7eSAlexander V. Chernikov if self.family == socket.AF_INET6: 244fee65b7eSAlexander V. Chernikov return 20 245fee65b7eSAlexander V. Chernikov else: 246fee65b7eSAlexander V. Chernikov return 8 247fee65b7eSAlexander V. Chernikov return align4(len(self._data)) + 4 248fee65b7eSAlexander V. Chernikov 249fee65b7eSAlexander V. Chernikov @classmethod 250fee65b7eSAlexander V. Chernikov def _parse(cls, data): 251fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 252fee65b7eSAlexander V. Chernikov data_len = len(data) - 4 253fee65b7eSAlexander V. Chernikov if data_len == 4: 254fee65b7eSAlexander V. Chernikov addr = socket.inet_ntop(socket.AF_INET, data[4:8]) 255fee65b7eSAlexander V. Chernikov else: 256fee65b7eSAlexander V. Chernikov addr = socket.inet_ntop(socket.AF_INET6, data[4:20]) 257fee65b7eSAlexander V. Chernikov return cls(nla_type, addr) 258fee65b7eSAlexander V. Chernikov 259fee65b7eSAlexander V. Chernikov def __bytes__(self): 260fee65b7eSAlexander V. Chernikov return self._to_bytes(socket.inet_pton(self.family, self.addr)) 261fee65b7eSAlexander V. Chernikov 262fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 263fee65b7eSAlexander V. Chernikov return " addr={}".format(self.addr) 264fee65b7eSAlexander V. Chernikov 265fee65b7eSAlexander V. Chernikov 266*f0ffe1ceSAlexander V. Chernikovclass NlAttrIp4(NlAttrIp): 267*f0ffe1ceSAlexander V. Chernikov def __init__(self, nla_type, addr: str): 268*f0ffe1ceSAlexander V. Chernikov super().__init__(nla_type, addr) 269*f0ffe1ceSAlexander V. Chernikov assert self.family == socket.AF_INET 270*f0ffe1ceSAlexander V. Chernikov 271*f0ffe1ceSAlexander V. Chernikov 272*f0ffe1ceSAlexander V. Chernikovclass NlAttrIp6(NlAttrIp): 273*f0ffe1ceSAlexander V. Chernikov def __init__(self, nla_type, addr: str): 274*f0ffe1ceSAlexander V. Chernikov super().__init__(nla_type, addr) 275*f0ffe1ceSAlexander V. Chernikov assert self.family == socket.AF_INET6 276*f0ffe1ceSAlexander V. Chernikov 277*f0ffe1ceSAlexander V. Chernikov 278fee65b7eSAlexander V. Chernikovclass NlAttrStr(NlAttr): 279fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, text): 280fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 281fee65b7eSAlexander V. Chernikov self.text = text 282fee65b7eSAlexander V. Chernikov 283fee65b7eSAlexander V. Chernikov @staticmethod 284fee65b7eSAlexander V. Chernikov def _validate(data): 285fee65b7eSAlexander V. Chernikov NlAttr._validate(data) 286fee65b7eSAlexander V. Chernikov try: 287fee65b7eSAlexander V. Chernikov data[4:].decode("utf-8") 288fee65b7eSAlexander V. Chernikov except Exception as e: 289fee65b7eSAlexander V. Chernikov raise ValueError("wrong utf-8 string: {}".format(e)) 290fee65b7eSAlexander V. Chernikov 291fee65b7eSAlexander V. Chernikov @property 292fee65b7eSAlexander V. Chernikov def nla_len(self): 293fee65b7eSAlexander V. Chernikov return len(self.text) + 5 294fee65b7eSAlexander V. Chernikov 295fee65b7eSAlexander V. Chernikov @classmethod 296fee65b7eSAlexander V. Chernikov def _parse(cls, data): 297fee65b7eSAlexander V. Chernikov text = data[4:-1].decode("utf-8") 298fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 299fee65b7eSAlexander V. Chernikov return cls(nla_type, text) 300fee65b7eSAlexander V. Chernikov 301fee65b7eSAlexander V. Chernikov def __bytes__(self): 302fee65b7eSAlexander V. Chernikov return self._to_bytes(bytes(self.text, encoding="utf-8") + bytes(1)) 303fee65b7eSAlexander V. Chernikov 304fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 305fee65b7eSAlexander V. Chernikov return ' val="{}"'.format(self.text) 306fee65b7eSAlexander V. Chernikov 307fee65b7eSAlexander V. Chernikov 308fee65b7eSAlexander V. Chernikovclass NlAttrStrn(NlAttr): 309fee65b7eSAlexander V. Chernikov def __init__(self, nla_type, text): 310fee65b7eSAlexander V. Chernikov super().__init__(nla_type, b"") 311fee65b7eSAlexander V. Chernikov self.text = text 312fee65b7eSAlexander V. Chernikov 313fee65b7eSAlexander V. Chernikov @staticmethod 314fee65b7eSAlexander V. Chernikov def _validate(data): 315fee65b7eSAlexander V. Chernikov NlAttr._validate(data) 316fee65b7eSAlexander V. Chernikov try: 317fee65b7eSAlexander V. Chernikov data[4:].decode("utf-8") 318fee65b7eSAlexander V. Chernikov except Exception as e: 319fee65b7eSAlexander V. Chernikov raise ValueError("wrong utf-8 string: {}".format(e)) 320fee65b7eSAlexander V. Chernikov 321fee65b7eSAlexander V. Chernikov @property 322fee65b7eSAlexander V. Chernikov def nla_len(self): 323fee65b7eSAlexander V. Chernikov return len(self.text) + 4 324fee65b7eSAlexander V. Chernikov 325fee65b7eSAlexander V. Chernikov @classmethod 326fee65b7eSAlexander V. Chernikov def _parse(cls, data): 327fee65b7eSAlexander V. Chernikov text = data[4:].decode("utf-8") 328fee65b7eSAlexander V. Chernikov nla_len, nla_type = struct.unpack("@HH", data[:4]) 329fee65b7eSAlexander V. Chernikov return cls(nla_type, text) 330fee65b7eSAlexander V. Chernikov 331fee65b7eSAlexander V. Chernikov def __bytes__(self): 332fee65b7eSAlexander V. Chernikov return self._to_bytes(bytes(self.text, encoding="utf-8")) 333fee65b7eSAlexander V. Chernikov 334fee65b7eSAlexander V. Chernikov def _print_attr_value(self): 335fee65b7eSAlexander V. Chernikov return ' val="{}"'.format(self.text) 336