Created
October 30, 2025 16:17
-
-
Save exeral/90762c0aea005876b84db6c6e7e7969e to your computer and use it in GitHub Desktop.
LLDP parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import struct | |
| import sys | |
| import json # Importing json module for JSON formatting | |
| def byte_to_int(b): | |
| """Handles byte to integer conversion for Python 2 and 3 compatibility.""" | |
| return ord(b) if isinstance(b, str) else b | |
| def mac_address_format(byte_sequence): | |
| """Format MAC address bytes for both Python 2 and 3.""" | |
| return ":".join("{:02x}".format(byte_to_int(b)) for b in byte_sequence) | |
| def parse_lldp(data): | |
| """Parse LLDP packet and extract key TLVs, including VLAN information.""" | |
| lldp_info = {} | |
| lldp_vlans = [] # List of VLANs | |
| offset = 0 | |
| while offset < len(data): | |
| if offset + 2 > len(data): | |
| break | |
| tlv_header = struct.unpack(">H", data[offset:offset + 2])[0] | |
| tlv_type = (tlv_header >> 9) & 0x7F | |
| tlv_length = tlv_header & 0x1FF | |
| offset += 2 | |
| if offset + tlv_length > len(data): | |
| break | |
| tlv_value = data[offset:offset + tlv_length] | |
| offset += tlv_length | |
| if tlv_type == 1: # Chassis ID | |
| subtype = byte_to_int(tlv_value[0]) | |
| if subtype == 4: | |
| lldp_info['Chassis ID'] = mac_address_format(tlv_value[1:]) | |
| else: | |
| lldp_info['Chassis ID'] = tlv_value[1:].decode('utf-8', errors='ignore') | |
| elif tlv_type == 2: # Port ID | |
| subtype = byte_to_int(tlv_value[0]) | |
| if subtype == 3: | |
| lldp_info['Port ID'] = tlv_value[1:].decode('utf-8', errors='ignore') | |
| else: | |
| lldp_info['Port ID Raw'] = tlv_value[1:].decode('utf-8', errors='ignore') | |
| elif tlv_type == 4: # Port desc | |
| lldp_info['Port description'] = tlv_value.decode('utf-8', errors='ignore') | |
| elif tlv_type == 5: # System Name | |
| lldp_info['System Name'] = tlv_value.decode('utf-8', errors='ignore') | |
| elif tlv_type == 6: # System Description | |
| lldp_info['System Description'] = tlv_value.decode('utf-8', errors='ignore') | |
| elif tlv_type == 127: # Organizationally Specific TLV | |
| if tlv_length >= 3 and tlv_value[:3] == b'\x00\x80\xc2': | |
| subtype = byte_to_int(tlv_value[3]) | |
| if subtype == 3: # VLAN Name TLV | |
| vlan_id = struct.unpack(">H", tlv_value[4:6])[0] | |
| vlan_name = tlv_value[6:].decode('utf-8', errors='ignore') | |
| lldp_vlans.append({'VLAN ID': vlan_id, 'VLAN Name': vlan_name}) | |
| if lldp_vlans: | |
| lldp_info['VLANs'] = lldp_vlans | |
| return lldp_info | |
| def parse_pcap(file_path): | |
| """Parse a pcap file to extract LLDP packets.""" | |
| with open(file_path, 'rb') as f: | |
| f.read(24) # Skip pcap header | |
| packets = [] | |
| while True: | |
| packet_header = f.read(16) | |
| if len(packet_header) < 16: | |
| break | |
| _, _, incl_len, _ = struct.unpack("IIII", packet_header) | |
| packet_data = f.read(incl_len) | |
| if len(packet_data) < incl_len: | |
| break | |
| packets.append(packet_data) | |
| return packets | |
| def extract_lldp_packets(packets): | |
| """Filter and parse LLDP packets (EtherType 0x88cc).""" | |
| lldp_packets = [] | |
| for packet in packets: | |
| ethertype = struct.unpack(">H", packet[12:14])[0] | |
| if ethertype == 0x88cc: | |
| lldp_payload = packet[14:] | |
| lldp_packets.append(parse_lldp(lldp_payload)) | |
| return lldp_packets | |
| def main(): | |
| if len(sys.argv) != 2: | |
| print("Usage: python lldp_parser.py <path_to_pcap_file>") | |
| sys.exit(1) | |
| file_path = sys.argv[1] | |
| packets = parse_pcap(file_path) | |
| lldp_packets = extract_lldp_packets(packets) | |
| # Output LLDP information as JSON | |
| print(json.dumps(lldp_packets, indent=4)) | |
| if __name__ == "__main__": | |
| main() |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script will parse a packet capture file (pcap) from tool like tcpdump
it will search for lldp packets and will nicely print the content of the LLDP packet
can be used like this on ESXi:
pktcap-uw --uplink vmnic0 -c 1 --ethtype 0x88cc -s 0 -o /tmp/lldp.pcap > /dev/null && wget -qO- http://example.org/lldp-parser.py | python - /tmp/lldp.pcap && rm -f /tmp/lldp.pcapand will output something like