### Install hiktools Source: https://github.com/matrixeditor/hiktools/blob/master/docs/index.md Clone the repository and install the package using pip. ```shell git clone https://github.com/MatrixEditor/hiktools.git cd hiktools/ && pip install . ``` -------------------------------- ### Build Documentation Source: https://github.com/matrixeditor/hiktools/blob/master/docs/index.md Install Sphinx and build the HTML documentation from the source files. ```shell cd docs/ pip install -U sphinx sphinx-build -b html source build ``` -------------------------------- ### Install hiktools using pip Source: https://context7.com/matrixeditor/hiktools/llms.txt Install the hiktools library from PyPI using pip. ```bash pip install hiktools ``` -------------------------------- ### Full SADP Library Usage Example Source: https://github.com/matrixeditor/hiktools/blob/master/cpp/README.md A complete workflow demonstrating socket creation, binding, sending an inquiry, and parsing received packet headers. ```cpp #include "sadplib" using namespace eth; int main(void) { // Create a new socket; IISocket sock; // Creates the socket descriptor; Note that the interface // can be queried by calling eth::adapter::GetNetInterfaces(). if (sock.Create(&networkInterface, 0x3380) < 0) { // log error exit(1); } // To bind the socket in order to receive packets, use Bind() if (sock.Bind() < 0) { exit(1); } // To send a simple Inquiry-packet, there is a utility method, // that automatically builds and sends the packet. sadp::packet::SendInquiry(sock); // Receiving is rather simple, just call Receive() and the bytes // that have been read are returned. const int bytes = sock.Receive(); if (bytes < 0) { exit(1); } // The packet creation can be done by simply casting the received // bytes to the packet structure. Note that the receiving buffer // will be cleared automatically when trying to receive the next // packet. const sadp::sadp_hdr *header = (const sadp::sadp_hdr *)sock.GetBuffer(); // Check against the SADP identifier if (ntohns(header->h_proto) == 0x8033) { // Same as above: simply casting the payload pointer to the // pre-defined sadp_frame structure. const sadp::sadp_frame *frame = (const sadp::sadp_frame *)header->payload; //handle packet... } } ``` -------------------------------- ### Install Wireshark Dissector Source: https://github.com/matrixeditor/hiktools/blob/master/docs/index.md Copy the Lua dissector file to the Wireshark global plugins directory. ```shell $LOCATION="..." # on unix cp hiktools/lua/sadp.lua $LOCATION/sadp.lua # on windows copy "hiktools\lua\sadp.lua" "$LOCATION/sadp.lua" ``` -------------------------------- ### Install hiktools via pip Source: https://github.com/matrixeditor/hiktools/blob/master/README.md Use this command to install the hiktools module in your Python environment. ```bash $ python3 -m pip install hiktools ``` -------------------------------- ### Initialize and use SADPClient Source: https://github.com/matrixeditor/hiktools/blob/master/docs/sadp.md Demonstrates how to use the SADPClient context manager to send messages and iterate over incoming responses. ```python from hiktools import sadp with sadp.SADPClient(timeout=3) as client: # send data with client.write client.write(some_message) # receive bytes with client.recv_next() or just iterate # over next SADPMessages: for message in client: if message is None: break # de-serialize message response = sadp.unmarshal(message) ``` -------------------------------- ### Initialize and Configure SADP Sockets Source: https://github.com/matrixeditor/hiktools/blob/master/cpp/README.md Demonstrates the declaration, creation, and binding of a layer 2 socket for network communication. ```cpp #include "sadplib.h" eth::IISocket sock; ``` ```cpp eth::adapter::NetworkInterface &ni = ...; if (sock.Create(&ni, 0x3380) < 0) { //report error } ``` ```cpp if (sock.Bind() < 0) { // report error } ``` -------------------------------- ### Extract firmware via CLI Source: https://github.com/matrixeditor/hiktools/blob/master/README.md Use the module's main script to extract firmware files directly from the command line. ```console python3 -m hiktools.fmod input.dav outputDir ``` -------------------------------- ### Perform Device Inquiry with CSADP Source: https://github.com/matrixeditor/hiktools/blob/master/docs/csadp.md Requires root privileges to initialize the L2 socket. Ensure the network interface name and device addresses are correctly specified. ```python from hiktools import csadp # Because the following module requires root priviledges it # has to be imported directly. from hiktools.csadp import CService sock = CService.l2socket('wlan0') counter = 0x115e # To build an Inquiry packet, we need the following information: # - our mac, ipv4 and ipv6 address (and the counter of course) packet = csadp.Inquiry('', '', '', counter) # before we can send the message, a checksum has to be calculated packet.insert_checksum() sock.send(bytes(packet)) response = csadp.SADPPacket(sock.recv(1024)) # to view the contents just print the str() version print(str(response)) ``` -------------------------------- ### Create Raw Ethernet Sockets Source: https://context7.com/matrixeditor/hiktools/llms.txt Initialize a raw Layer 2 socket for Ethernet communication. Requires root privileges on Linux. ```python # Note: Requires root privileges on Linux from hiktools import csadp from hiktools.csadp import CService # Create layer 2 socket bound to network interface sock = CService.l2socket('eth0') # or 'wlan0' for wireless # Socket is ready for raw packet transmission print(f"Socket timeout: {sock.gettimeout()} seconds") # Don't forget to close when done sock.close() ``` -------------------------------- ### Open and Export Firmware Files with fmod.DigiCap Source: https://github.com/matrixeditor/hiktools/blob/master/docs/fmod.md Use fmod.DigiCap to open firmware files, iterate over their contents, and export them to a specified directory. Ensure the file path is correct. ```python from hiktools import fmod # Open the resource at the specified path (loading is done automatically) # or manually decrypt the firmware file. with fmod.DigiCap('filename.dav') as dcap: # Iterate over all files stored in the DigiCap object for file_info in dcap: print('> File name="%s", size=%d, pos=%d, checksum=%d' % file_info) # get file amount and current language print("Files: %d, Language: %d" % (dcap.head.files, dcap.head.language)) # save all files stored in fmod.export(dcap, "outdir/") ``` -------------------------------- ### Extract Firmware Files via CLI Source: https://context7.com/matrixeditor/hiktools/llms.txt Extract firmware files directly from the command line using the `hiktools.fmod` module without writing Python code. ```bash # Extract firmware files via CLI python3 -m hiktools.fmod firmware.dav output_directory/ ``` -------------------------------- ### Inspect and Extract Firmware Source: https://github.com/matrixeditor/hiktools/blob/master/docs/index.md Use the DigiCap class to iterate over files in a firmware image and export them to a directory. ```python from hiktools import fmod # Open the resource at the specified path (loading is done automatically) # or manually decrypt the firmware file. with fmod.DigiCap('filename.dav') as dcap: # Iterate over all files stored in the DigiCap object for file_info in dcap: print('> File name="%s", size=%d, pos=%d, checksum=%d' % file_info) # get file amount and current language print("Files: %d, Language: %d" % (dcap.head.files, dcap.head.language)) # save all files stored in fmod.export(dcap, "outdir/") ``` -------------------------------- ### Inspect and extract firmware Source: https://github.com/matrixeditor/hiktools/blob/master/README.md Use the fmod module to open, iterate, and export files from a Hikvision firmware file. ```python from hiktools import fmod # Open the resource at the specified path (loading is done automatically) # or manually decrypt the firmware file (see documentation for actual code). with fmod.DigiCap('filename.dav') as dcap: # Iterate over all files stored in the DigiCap object for file_info in dcap: print('> File name="%s", size=%d, pos=%d, checksum=%d' % file_info) # get file amount and current language print("Files: %d, Language: %d" % (dcap.head.files, dcap.head.language)) # save all files stored in fmod.export(dcap, "outdir/") ``` -------------------------------- ### Construct Raw SADP Packets Source: https://context7.com/matrixeditor/hiktools/llms.txt Manually build and configure raw SADP packets, including Ethernet and SADP headers. ```python from hiktools import csadp # Create a new packet from scratch packet = csadp.SADPPacket() # Configure ethernet header packet.eth_header.src = 'AA:BB:CC:DD:EE:FF' # Source MAC packet.eth_header.dest = 'FF:FF:FF:FF:FF:FF' # Broadcast MAC packet.eth_header.eth_type = 0x8033 # SADP ethernet type # Configure SADP header packet.header.prefix = csadp.CLIENT_PREFIX # 0x42 for client packet.header.packet_type = csadp.PACKET_TYPE['Inquiry'] # 0x03 packet.header.counter = 0x1000 # Set IP addresses packet.src_ip = '192.168.1.50' packet.dest_ip = '0.0.0.0' packet.subnet = '0.0.0.0' # Add payload for inquiry packet.payload = csadp.InquiryPayload(ipv6='fe80::1') # Calculate checksum packet.insert_checksum() ``` -------------------------------- ### CMake Build Configuration for sadplib Source: https://github.com/matrixeditor/hiktools/blob/master/cpp/CMakeLists.txt This CMakeLists.txt file configures the build for the sadplib project. It specifies the minimum required CMake version, the project name and version, and defines an executable target named 'sadptool' with its associated source files. ```cmake cmake_minimum_required(VERSION 3.0.0) project(sadplib VERSION 0.1.1) set(DIR ${PROJECT_SOURCE_DIR}) add_executable(sadptool ${DIR}/sadptool.cpp ${DIR}/adapter.cpp ${DIR}/checksum.cpp ${DIR}/ethernet.cpp ${DIR}/sadplib.cpp ) ``` -------------------------------- ### Build and Send Inquiry Packets Source: https://context7.com/matrixeditor/hiktools/llms.txt Construct and transmit raw SADP inquiry packets at the Ethernet frame level. ```python from hiktools import csadp from hiktools.csadp import CService # Create layer 2 socket (requires root on Linux) sock = CService.l2socket('eth0') # Packet counter (increment for each packet) counter = 0x115e # Build inquiry packet with network addresses packet = csadp.inquiry( mac='AA:BB:CC:DD:EE:FF', # Your MAC address ipv4='192.168.1.50', # Your IPv4 address ipv6='fe80::1', # Your IPv6 address counter=counter ) # Calculate and insert checksum before sending packet.insert_checksum() # Send raw packet sock.send(bytes(packet)) # Receive response response_data = sock.recv(1024) response = csadp.SADPPacket(response_data) # Access response fields print(f"Source IP: {response.src_ip}") print(f"Dest IP: {response.dest_ip}") print(f"Subnet: {response.subnet}") print(f"Packet type: {response.header.packet_type}") sock.close() ``` -------------------------------- ### Parse and Extract Firmware Files with DigiCap Source: https://context7.com/matrixeditor/hiktools/llms.txt Use the DigiCap class as a context manager to open, parse, and extract files from Hikvision firmware images. Access header information and iterate over embedded files. ```python from hiktools import fmod # Open and parse a firmware file using context manager with fmod.DigiCap('firmware.dav') as dcap: # Access header information print(f"Files: {dcap.head.files}") print(f"Language: {dcap.head.language}") print(f"Header length: {dcap.head.header_length}") # Iterate over all embedded files for file_name, file_size, file_pos, checksum in dcap: print(f'File: "{file_name}", size={file_size}, pos={file_pos}, checksum={checksum}') # Access files by index first_file = dcap[0] print(f"First file: {first_file[0]}") # Read raw file content fname, flen, fpos, _ = dcap[0] raw_content = dcap.fread(flen, fpos) ``` -------------------------------- ### Query Network Interfaces in C++ Source: https://github.com/matrixeditor/hiktools/blob/master/cpp/README.md Retrieves a list of available network interfaces to identify MAC addresses, IP addresses, and interface indices. ```cpp using namespace eth::adapter; NetInterfaceList *list = GetNetInterfaces(); if (list) { for (int i = 0; i < list.size(); i++) { // The returned NetInterface stores information about the // following attributes: // - MAC address // - Interface index // - IPv6 address // - Current IPv4 address // - Interface name const NetInterface &ni = list.at(i); } } ``` -------------------------------- ### fmod.DigiCap - Firmware File Handler Source: https://context7.com/matrixeditor/hiktools/llms.txt The DigiCap class allows for parsing and reading files from Hikvision's digicap.dav firmware format. ```APIDOC ## Python Class: fmod.DigiCap ### Description Provides a context manager to open, parse, and extract files from Hikvision firmware images. ### Methods - **__init__(filename)**: Opens the firmware file. - **fread(size, pos)**: Reads raw content from the firmware at a specific position. ### Attributes - **head**: Contains firmware metadata (files, language, header_length). ### Example ```python with fmod.DigiCap('firmware.dav') as dcap: print(dcap.head.files) raw_content = dcap.fread(size, pos) ``` ``` -------------------------------- ### Send Raw Packets (Linux Only) Source: https://github.com/matrixeditor/hiktools/blob/master/docs/index.md Utilize the CService module to send raw packets via a layer 2 socket. Requires root privileges. ```python from hiktools import csadp # Because the following module requires root priviledges it has to be # imported directly from hiktools.csadp import CService sock = CService.l2socket('wlan0') counter = 2855 # Building an inquiry packet packet = csadp.packet( 'src_mac', 'src_ip', 0x03, counter, checksum=csadp.from_counter(counter), payload='\x00'*28 ) # If you want to have the packet as an object use parse() packet_obj = csadp.parse(packet) sock.send(packet) # or sock.send(bytes(packet_obj)) response = csadp.parse(sock.recv(1024)) ``` -------------------------------- ### IPv4 Address Conversion Utilities Source: https://context7.com/matrixeditor/hiktools/llms.txt Convert IPv4 addresses between string and byte formats using `inet_stoip` and `inet_iptos`. Ensure buffer is correctly sliced if parsing partial data. ```python # IPv4 conversions ipv4_str = '192.168.1.100' ipv4_bytes = inet_stoip(ipv4_str) print(f"IPv4 bytes: {ipv4_bytes.hex()}") # c0a80164 ``` ```python buffer = b'\xc0\xa8\x01\x64' ipv4_string = inet_iptos(buffer, 0) print(f"IPv4 string: {ipv4_string}") # 192.168.1.100 ``` -------------------------------- ### Discover Hikvision Devices via UDP Broadcast Source: https://context7.com/matrixeditor/hiktools/llms.txt Use the `SADPClient` to send UDP broadcast discovery requests and receive responses from Hikvision devices on port 37020. Parses XML responses to extract device information like IP address and MAC. ```python from hiktools import sadp from uuid import uuid4 # Create an inquiry packet to discover devices inquiry = sadp.fromdict({ 'Uuid': str(uuid4()).upper(), 'MAC': 'ff-ff-ff-ff-ff-ff', 'Types': 'inquiry' }) # Open UDP client and send discovery request with sadp.SADPClient(port=37020, timeout=2) as client: # Send inquiry broadcast bytes_sent = client.write(inquiry) print(f"Sent {bytes_sent} bytes") # Iterate over all device responses for response in client: if response is None: break # Parse the XML response message = sadp.unmarshal(response.toxml()) # Access device properties if 'IPv4Address' in message: print(f"Device found at: {message['IPv4Address']}") if 'MAC' in message: print(f"MAC Address: {message['MAC']}") if 'DeviceType' in message: print(f"Device Type: {message['DeviceType']}") ``` -------------------------------- ### MAC Address Conversion Utilities Source: https://context7.com/matrixeditor/hiktools/llms.txt Convert MAC addresses between string and byte formats using `inet_stomac` and `inet_mactos`. Ensure correct separator is used for string conversion. ```python from hiktools.csadp import ( inet_stomac, inet_mactos, inet_stoip, inet_iptos, inet6_stoip, inet6_iptos ) # MAC address conversions mac_str = 'AA:BB:CC:DD:EE:FF' mac_bytes = inet_stomac(mac_str) print(f"MAC bytes: {mac_bytes.hex()}") # aabbccddeeff ``` ```python # Convert bytes back to string buffer = b'\xaa\xbb\xcc\xdd\xee\xff' mac_string = inet_mactos(buffer, 0, sep=':') print(f"MAC string: {mac_string}") # aa:bb:cc:dd:ee:ff ``` -------------------------------- ### IPv6 Address Conversion Utilities Source: https://context7.com/matrixeditor/hiktools/llms.txt Convert IPv6 addresses between string and byte formats using `inet6_stoip` and `inet6_iptos`. Note that IPv6 addresses are always 16 bytes. ```python # IPv6 conversions ipv6_str = 'fe80::1' ipv6_bytes = inet6_stoip(ipv6_str) print(f"IPv6 bytes length: {len(ipv6_bytes)}") # 16 ``` ```python buffer = b'\xfe\x80' + b'\x00' * 13 + b'\x01' ipv6_string = inet6_iptos(buffer, 0) print(f"IPv6 string: {ipv6_string}") # fe80::1 ``` -------------------------------- ### sadp.SADPClient - Device Discovery Source: https://context7.com/matrixeditor/hiktools/llms.txt High-level interface for discovering Hikvision devices via UDP broadcast on port 37020. ```APIDOC ## Python Class: sadp.SADPClient ### Description Handles UDP broadcast communication for device discovery using the Search Active Devices Protocol. ### Methods - **write(packet)**: Sends a discovery inquiry packet. - **__iter__()**: Iterates over device responses received within the timeout period. ### Parameters - **port** (int) - Optional - Default 37020. - **timeout** (int) - Optional - Timeout in seconds for responses. ``` -------------------------------- ### Export All Firmware Files Source: https://context7.com/matrixeditor/hiktools/llms.txt Use the `export` function to extract all embedded files from a DigiCap firmware image to a specified directory. It returns True on success and False on failure. ```python from hiktools import fmod # Extract all files from firmware to output directory with fmod.DigiCap('firmware.dav') as dcap: # Export returns True on success, False on failure success = fmod.export(dcap, 'extracted_files/') if success: print(f"Successfully extracted {len(dcap)} files") else: print("Extraction failed") ``` -------------------------------- ### Send SADP Inquiry Packets Source: https://github.com/matrixeditor/hiktools/blob/master/cpp/README.md Uses the pre-defined utility method to build and send an inquiry packet over the network. ```cpp // This method will call BuildInquiry(), GetSize() and the // sock.Send(...) method. eth::sadp::packet::SendInquiry(sock); ``` -------------------------------- ### Generate Legacy Reset Codes Source: https://context7.com/matrixeditor/hiktools/llms.txt Generate reset codes for older Hikvision devices using the serial number and a date tuple. ```python from hiktools.sadp import hik_code # Generate reset code for a device serial_number = "DS-2CD2132F-I20161018AACH123456789" timestamp = (15, 3, 2024) # (day, month, year) reset_code = hik_code(serial_number, timestamp) print(f"Reset code: {reset_code}") ``` -------------------------------- ### Decode XOR-Encrypted Firmware Header Source: https://context7.com/matrixeditor/hiktools/llms.txt Manually read and decode the initial XOR-encrypted header of a firmware file using the `decode_xor16` function and the predefined XOR key. ```python from hiktools.fmod.digicap import decode_xor16, read_raw_header, DigiCap # Read and decode firmware header manually with open('firmware.dav', 'rb') as f: raw_header = f.read(0x6C) # First 108 bytes # Decode using the XOR key key = DigiCap.KEY_XOR # b'\xBA\xCD\xBC\xFE\xD6\xCA\xDD\xD3\xBA\xB9\xA3\xAB\xBF\xCB\xB5\xBE' decoded_header = decode_xor16(raw_header, key, 0x6C) print(f"Magic bytes: {decoded_header[:4].hex()}") ``` -------------------------------- ### Interact via UDP Broadcast Source: https://github.com/matrixeditor/hiktools/blob/master/docs/index.md Use SADPClient to send inquiry packets and process responses from devices on the network. ```python from hiktools import sadp from uuid import uuid4 # create a packet from a simple dict object inquiry = sadp.fromdict({ 'Uuid': str(uuid4()).upper(), 'MAC': 'ff-ff-ff-ff-ff-ff', 'Types': 'inquiry' }) # Open up a client to communicate over broadcast with sadp.SADPClient() as client: # send the inquiry packet client.write(inquiry) # iterate over all received packets (None is returned on error) for response in client: if response is None: break # initiate the response message = sadp.unmarshal(response.toxml()) # message objects contain a dict-like implementation for property_name in message: print(message[property_name]) # e.g. print('Device at', message['IPv4Address']) ``` -------------------------------- ### Send raw SADP packets Source: https://github.com/matrixeditor/hiktools/blob/master/README.md Send raw ethernet packets using the csadp module. This requires root privileges and is only supported on Linux. ```python from hiktools import csadp # Because the following module requires root priviledges it # has to be imported directly. from hiktools.csadp import CService sock = CService.l2socket('wlan0') counter = 0x115e # To build an Inquiry packet, we need the following information: # - our mac, ipv4 and ipv6 address (and the counter of course) packet = csadp.inquiry('', '', '', counter) # before we can send the message, a checksum has to be calculated packet.insert_checksum() sock.send(bytes(packet)) response = csadp.SADPPacket(sock.recv(1024)) # to view the contents just print the str() version print(str(response)) ``` -------------------------------- ### Create SADP Messages from Dictionaries Source: https://context7.com/matrixeditor/hiktools/llms.txt Build SADP message packets from Python dictionaries, which are automatically converted to XML format. ```python from hiktools import sadp from uuid import uuid4 # Create an inquiry message inquiry_msg = sadp.fromdict({ 'Uuid': str(uuid4()).upper(), 'MAC': 'ff-ff-ff-ff-ff-ff', 'Types': 'inquiry' }) print(inquiry_msg.message) # Output: ...ff-ff-ff-ff-ff-ffinquiry # Create a getcode request for password reset getcode_msg = sadp.fromdict({ 'Uuid': str(uuid4()).upper(), 'MAC': 'aa-bb-cc-dd-ee-ff', 'Types': 'getcode' }) # Convert message to bytes for transmission raw_bytes = bytes(getcode_msg) ``` -------------------------------- ### fmod.export - Extract Firmware Source: https://context7.com/matrixeditor/hiktools/llms.txt Utility function to extract all embedded files from a DigiCap object to a target directory. ```APIDOC ## Function: fmod.export ### Description Extracts all files embedded in a DigiCap firmware image to a specified directory. ### Parameters - **dcap** (DigiCap object) - Required - The opened firmware object. - **path** (string) - Required - The destination directory path. ### Response - **bool** - Returns True on success, False on failure. ``` -------------------------------- ### Interact via UDP broadcast Source: https://github.com/matrixeditor/hiktools/blob/master/README.md Communicate with devices using the sadp module to send inquiries and process XML responses. ```python from hiktools import sadp from uuid import uuid4 # create a packet from a simple dict object inquiry = sadp.fromdict({ 'Uuid': str(uuid4()).upper(), 'MAC': 'ff-ff-ff-ff-ff-ff', 'Types': 'inquiry' }) # Open up a client to communicate over broadcast with sadp.SADPClient() as client: # send the inquiry packet client.write(inquiry) # iterate over all received packets (None is returned on error) for response in client: if response is None: break # initiate the response message = sadp.unmarshal(response.toxml()) # message objects contain a dict-like implementation for property_name in message: print(message[property_name]) # e.g. print('Device at', message['IPv4Address']) ``` -------------------------------- ### Parse SADP XML Responses Source: https://context7.com/matrixeditor/hiktools/llms.txt Convert XML responses from devices into typed Python objects for property access. ```python from hiktools import sadp # Example XML response from device (typically received via SADPClient) xml_response = b''' inquiry IPCamera aa:bb:cc:dd:ee:ff 192.168.1.100 255.255.255.0 192.168.1.1 80 true ''' import xml.etree.ElementTree as ET root = ET.fromstring(xml_response) # Parse into typed object (DiscoveryPacket for inquiry responses) device = sadp.unmarshal(root) # Access device properties via dict-like interface print(f"IP: {device['IPv4Address']}") print(f"MAC: {device['MAC']}") print(f"HTTP Port: {device['HttpPort']}") print(f"Activated: {device['Activated']}") # Iterate over all properties for prop_name in device: print(f"{prop_name}: {device[prop_name]}") # Expected output: # IP: 192.168.1.100 # MAC: aa:bb:cc:dd:ee:ff # HTTP Port: 80 # Activated: true ``` -------------------------------- ### Packet Conversion and Parsing Source: https://context7.com/matrixeditor/hiktools/llms.txt Convert packets to bytes for transmission and parse received raw data. Useful for low-level SADP protocol interaction. ```python raw_packet = bytes(packet) print(f"Packet size: {len(raw_packet)} bytes") print(f"Checksum: {packet.header.checksum:#06x}") ``` ```python received_data = b'...' # Raw bytes from socket parsed_packet = csadp.SADPPacket(received_data) print(f"Received from: {parsed_packet.eth_header.src}") ``` -------------------------------- ### Register Custom Payload Handler Source: https://context7.com/matrixeditor/hiktools/llms.txt Register a custom payload class for specific SADP packet types using the `@payload` decorator. The custom class must inherit from `SADPPayload` and handle parsing and serialization. ```python from hiktools.csadp import SADPPayload, payload, PACKET_TYPE # Register a custom payload handler for UpdateIP packets @payload(PACKET_TYPE['UpdateIP']) # 0x06 class UpdateIPPayload(SADPPayload): def __init__(self, buf: bytes = None) -> None: super().__init__(buf) self.new_ip = None self.new_subnet = None self.new_gateway = None if buf is not None: # Parse buffer to extract IP configuration from hiktools.csadp import inet_iptos self.new_ip = inet_iptos(buf, 0) self.new_subnet = inet_iptos(buf, 4) self.new_gateway = inet_iptos(buf, 8) def __bytes__(self) -> bytes: from hiktools.csadp import inet_stoip buf = bytearray() buf += inet_stoip(self.new_ip or '0.0.0.0') buf += inet_stoip(self.new_subnet or '255.255.255.0') buf += inet_stoip(self.new_gateway or '0.0.0.0') return bytes(buf) # Now SADPPacket will automatically use this class for UpdateIP packets ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.