#!/usr/bin/env python3 """ PTP Packet class for IEEE1588 PTP frame parsing """ import struct from typing import Dict, Optional try: from scapy.layers.inet import IP, UDP except ImportError: print("Error: scapy library not found. Install with: pip install scapy") exit(1) class PTPPacket: """Represents an IEEE1588 PTP packet""" def __init__(self, packet): """ Initialize PTP packet from raw scapy packet Args: packet: Raw scapy packet """ self.raw_packet = packet # Extract basic packet info self.timestamp = float(packet.time) # Extract IP/UDP info if available if packet.haslayer(IP) and packet.haslayer(UDP): ip_layer = packet[IP] udp_layer = packet[UDP] self.src_ip = ip_layer.src self.dst_ip = ip_layer.dst self.src_port = udp_layer.sport self.dst_port = udp_layer.dport self.payload = bytes(udp_layer.payload) else: self.src_ip = "" self.dst_ip = "" self.src_port = 0 self.dst_port = 0 self.payload = bytes() # Parse PTP header self.ptp_header = self._parse_ptp_header() def _parse_ptp_header(self) -> Optional[Dict]: """Parse PTP header from payload""" if len(self.payload) < 34: # Minimum PTP header size return None try: message_type = self.payload[0] & 0x0F version = (self.payload[1] >> 4) & 0x0F message_length = struct.unpack('>H', self.payload[2:4])[0] domain_number = self.payload[4] flags = struct.unpack('>H', self.payload[6:8])[0] correction_field = struct.unpack('>Q', self.payload[8:16])[0] source_port_id = self.payload[20:30].hex() sequence_id = struct.unpack('>H', self.payload[30:32])[0] control_field = self.payload[32] log_message_interval = struct.unpack('b', self.payload[33:34])[0] message_types = { 0x0: 'Sync', 0x1: 'Delay_Req', 0x2: 'Pdelay_Req', 0x3: 'Pdelay_Resp', 0x8: 'Follow_Up', 0x9: 'Delay_Resp', 0xA: 'Pdelay_Resp_Follow_Up', 0xB: 'Announce', 0xC: 'Signaling', 0xD: 'Management' } return { 'message_type': message_types.get(message_type, f'Unknown({message_type})'), 'version': version, 'message_length': message_length, 'domain_number': domain_number, 'flags': f'0x{flags:04X}', 'correction_field': correction_field, 'source_port_id': source_port_id, 'sequence_id': sequence_id, 'control_field': control_field, 'log_message_interval': log_message_interval } except (struct.error, IndexError): return None