Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Expert skill for packet capture and analysis using libpcap/Wireshark. Execute tcpdump/tshark commands, write BPF filter expressions, analyze pcap files, decode protocol layers, calculate statistics, and generate Wireshark dissectors.
.claude/skills/a5c-ai-packet-capture/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 106% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 177% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 77% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 133% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 136% | 0% |
You are packet-capture - a specialized skill for network packet capture and analysis, providing expert capabilities with libpcap, tcpdump, tshark, and Wireshark for deep network traffic inspection.
This skill enables AI-powered packet capture and analysis including:
tcpdump or tshark installedCapture network traffic with tcpdump and tshark:
bash# Basic capture on interface tcpdump -i eth0 -nn # Capture with timestamp precision tcpdump -i eth0 -nn -tttt # Capture to file tcpdump -i eth0 -w capture.pcap # Capture with rotation (100MB files, keep 10) tcpdump -i eth0 -w capture_%Y%m%d_%H%M%S.pcap -C 100 -W 10 # Capture specific traffic tcpdump -i eth0 -nn 'port 80 or port 443' # tshark capture with display filter tshark -i eth0 -Y 'http.request.method == "GET"' # tshark capture specific fields tshark -i eth0 -T fields \ -e frame.time \ -e ip.src \ -e ip.dst \ -e tcp.port \ -e http.host
Write efficient Berkeley Packet Filter expressions:
bash# Host filters tcpdump host 192.168.1.100 tcpdump src host 192.168.1.100 tcpdump dst host 192.168.1.100 # Network filters tcpdump net 192.168.1.0/24 tcpdump src net 10.0.0.0/8 # Port filters tcpdump port 80 tcpdump src port 443 tcpdump portrange 8000-8100 # Protocol filters tcpdump tcp tcpdump udp tcpdump icmp tcpdump 'ip proto 47' # GRE # Combining filters tcpdump 'host 192.168.1.100 and port 80' tcpdump 'src host 192.168.1.100 or dst host 192.168.1.100' tcpdump 'tcp and (port 80 or port 443)' tcpdump 'not port 22' # Exclude SSH # TCP flag filters tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0' tcpdump 'tcp[tcpflags] & tcp-syn != 0' # SYN packets tcpdump 'tcp[tcpflags] & tcp-rst != 0' # RST packets # Payload filters tcpdump 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420' # HTTP GET tcpdump 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354' # HTTP POST # VLAN filters tcpdump 'vlan 100' tcpdump 'vlan and host 192.168.1.100'
Analyze captured packet files:
bash# Read pcap file tcpdump -r capture.pcap -nn # Count packets tcpdump -r capture.pcap | wc -l # Extract specific fields with tshark tshark -r capture.pcap -T fields \ -e frame.number \ -e frame.time_relative \ -e ip.src \ -e ip.dst \ -e tcp.stream \ -e http.request.uri # Protocol hierarchy statistics tshark -r capture.pcap -q -z io,phs # Conversation statistics tshark -r capture.pcap -q -z conv,tcp tshark -r capture.pcap -q -z conv,ip # Endpoint statistics tshark -r capture.pcap -q -z endpoints,tcp # HTTP statistics tshark -r capture.pcap -q -z http,tree tshark -r capture.pcap -q -z http_req,tree # Follow TCP stream tshark -r capture.pcap -q -z follow,tcp,ascii,0 # Export objects (HTTP, SMB, etc.) tshark -r capture.pcap --export-objects http,./http_exports/ # Time-based statistics tshark -r capture.pcap -q -z io,stat,1
Decode and analyze protocol layers:
pythonfrom scapy.all import * def analyze_packet(packet): """Analyze packet layers.""" analysis = {} # Ethernet layer if Ether in packet: eth = packet[Ether] analysis['ethernet'] = { 'src': eth.src, 'dst': eth.dst, 'type': hex(eth.type) } # IP layer if IP in packet: ip = packet[IP] analysis['ip'] = { 'version': ip.version, 'ihl': ip.ihl, 'tos': ip.tos, 'len': ip.len, 'id': ip.id, 'flags': str(ip.flags), 'frag': ip.frag, 'ttl': ip.ttl, 'proto': ip.proto, 'src': ip.src, 'dst': ip.dst } # TCP layer if TCP in packet: tcp = packet[TCP] analysis['tcp'] = { 'sport': tcp.sport, 'dport': tcp.dport, 'seq': tcp.seq, 'ack': tcp.ack, 'flags': str(tcp.flags), 'window': tcp.window, 'options': [(name, val) for name, val in tcp.options] } # UDP layer if UDP in packet: udp = packet[UDP] analysis['udp'] = { 'sport': udp.sport, 'dport': udp.dport, 'len': udp.len } # HTTP layer (raw) if Raw in packet: payload = packet[Raw].load if payload.startswith(b'GET ') or payload.startswith(b'POST ') or \ payload.startswith(b'HTTP/'): analysis['http'] = { 'payload': payload[:500].decode('utf-8', errors='replace') } return analysis def analyze_pcap(filename): """Analyze all packets in a pcap file.""" packets = rdpcap(filename) results = [] for i, pkt in enumerate(packets): result = { 'number': i + 1, 'time': float(pkt.time), 'length': len(pkt), 'layers': analyze_packet(pkt) } results.append(result) return results
Analyze network flows and connections:
pythonfrom collections import defaultdict from scapy.all import * def extract_flows(pcap_file): """Extract TCP/UDP flows from pcap file.""" packets = rdpcap(pcap_file) flows = defaultdict(lambda: { 'packets': [], 'bytes': 0, 'start_time': None, 'end_time': None }) for pkt in packets: if IP not in pkt: continue src_ip = pkt[IP].src dst_ip = pkt[IP].dst if TCP in pkt: src_port = pkt[TCP].sport dst_port = pkt[TCP].dport proto = 'tcp' elif UDP in pkt: src_port = pkt[UDP].sport dst_port = pkt[UDP].dport proto = 'udp' else: continue # Create bidirectional flow key if (src_ip, src_port) < (dst_ip, dst_port): flow_key = (src_ip, src_port, dst_ip, dst_port, proto) else: flow_key = (dst_ip, dst_port, src_ip, src_port, proto) flow = flows[flow_key] flow['packets'].append(pkt) flow['bytes'] += len(pkt) pkt_time = float(pkt.time) if flow['start_time'] is None or pkt_time < flow['start_time']: flow['start_time'] = pkt_time if flow['end_time'] is None or pkt_time > flow['end_time']: flow['end_time'] = pkt_time return flows def flow_statistics(flows): """Calculate statistics for flows.""" stats = [] for key, flow in flows.items(): src_ip, src_port, dst_ip, dst_port, proto = key duration = flow['end_time'] - flow['start_time'] if flow['end_time'] != flow['start_time'] else 0.001 stats.append({ 'src': f"{src_ip}:{src_port}", 'dst': f"{dst_ip}:{dst_port}", 'protocol': proto, 'packets': len(flow['packets']), 'bytes': flow['bytes'], 'duration': duration, 'bps': flow['bytes'] * 8 / duration, 'pps': len(flow['packets']) / duration }) return sorted(stats, key=lambda x: x['bytes'], reverse=True)
Generate custom Wireshark dissectors:
lua-- Custom Protocol Dissector for Lua -- Save as myprotocol.lua in Wireshark plugins directory local myproto = Proto("myproto", "My Custom Protocol") -- Define fields local f_magic = ProtoField.uint8("myproto.magic", "Magic", base.HEX) local f_version = ProtoField.uint8("myproto.version", "Version", base.DEC) local f_type = ProtoField.uint8("myproto.type", "Message Type", base.DEC) local f_flags = ProtoField.uint8("myproto.flags", "Flags", base.HEX) local f_length = ProtoField.uint32("myproto.length", "Payload Length", base.DEC) local f_payload = ProtoField.bytes("myproto.payload", "Payload") myproto.fields = { f_magic, f_version, f_type, f_flags, f_length, f_payload } -- Message type names local type_names = { [0x01] = "HANDSHAKE", [0x02] = "DATA", [0x03] = "ACK", [0x04] = "ERROR", [0x05] = "CLOSE" } -- Dissector function function myproto.dissector(buffer, pinfo, tree) local length = buffer:len() if length < 8 then return end -- Minimum header size pinfo.cols.protocol = myproto.name local subtree = tree:add(myproto, buffer(), "My Protocol Data") -- Parse header local magic = buffer(0, 1):uint() if magic ~= 0xAB then return 0 end -- Not our protocol subtree:add(f_magic, buffer(0, 1)) subtree:add(f_version, buffer(1, 1)) local msg_type = buffer(2, 1):uint() local type_item = subtree:add(f_type, buffer(2, 1)) type_item:append_text(" (" .. (type_names[msg_type] or "UNKNOWN") .. ")") subtree:add(f_flags, buffer(3, 1)) local payload_len = buffer(4, 4):uint() subtree:add(f_length, buffer(4, 4)) -- Parse payload if present if payload_len > 0 and length >= 8 + payload_len then subtree:add(f_payload, buffer(8, payload_len)) end -- Update info column pinfo.cols.info = type_names[msg_type] or "Unknown" return 8 + payload_len end -- Register on TCP port local tcp_port = DissectorTable.get("tcp.port") tcp_port:add(12345, myproto)
This skill can leverage the following MCP servers for enhanced capabilities:
| Server | Description | Integration | |--------|-------------|-------------| | Wireshark MCP (sarthaksiddha) | Live capture and analysis | AI-powered packet inspection | | WireMCP | Real-time traffic analysis | Threat detection | | mcp-wireshark | Wireshark/tshark integration | IDE integration | | Network Monitor MCP | Security analysis | Real-time monitoring |
bash# Install from npm npm install -g @sarthaksiddha/wireshark-mcp # Add to Claude claude mcp add wireshark -- npx @sarthaksiddha/wireshark-mcp
Capabilities:
-s-WThis skill integrates with the following processes:
packet-capture-analysis.js - Packet capture and analysisprotocol-dissector.js - Protocol dissectionnetwork-traffic-analyzer.js - Traffic pattern analysisWhen executing operations, provide structured output:
json{ "operation": "analyze", "file": "capture.pcap", "status": "success", "summary": { "packets": 10000, "bytes": 5242880, "duration": 60.5, "avgPacketSize": 524 }, "protocols": { "tcp": 8500, "udp": 1200, "icmp": 300 }, "topTalkers": [ {"ip": "192.168.1.100", "packets": 3000, "bytes": 1500000} ], "flows": 150, "artifacts": ["analysis.json", "flows.csv"] }
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 16,816 | 24,535 | +46% | 1 | 1 | 0% | 3,037 | 6,267 | +106% | 0 | 0 | — |
case-02 | fail→pass | 10,954 | 11,887 | +9% | 1 | 1 | 0% | 2,358 | 6,543 | +177% | 0 | 0 | — |
case-03 | fail→pass | 23,728 | 9,475 | -60% | 1 | 1 | 0% | 3,352 | 5,926 | +77% | 0 | 0 | — |
case-04 | pass→pass | 6,377 | 6,881 | +8% | 1 | 1 | 0% | 1,189 | 5,053 | +325% | 0 | 0 | — |
case-05 | pass→pass | 5,269 | 3,749 | -29% | 1 | 1 | 0% | 923 | 4,449 | +382% | 0 | 0 | — |
case-06 | pass→pass | 13,694 | 9,200 | -33% | 1 | 1 | 0% | 2,744 | 5,611 | +104% | 0 | 0 | — |
case-07 | pass→pass | 6,076 | 4,526 | -26% | 1 | 1 | 0% | 1,083 | 4,560 | +321% | 0 | 0 | — |
case-08 | pass→pass | 4,242 | 4,737 | +12% | 1 | 1 | 0% | 761 | 4,650 | +511% | 0 | 0 | — |
case-09 | pass→pass | 4,194 | 4,666 | +11% | 1 | 1 | 0% | 788 | 4,469 | +467% | 0 | 0 | — |
case-10 | pass→pass | 10,134 | 6,942 | -31% | 1 | 1 | 0% | 1,592 | 5,174 | +225% | 0 | 0 | — |
case-11 | pass→pass | 9,911 | 5,620 | -43% | 1 | 1 | 0% | 1,497 | 4,871 | +225% | 0 | 0 | — |
case-12 | pass→pass | 9,153 | 8,238 | -10% | 1 | 1 | 0% | 1,425 | 5,527 | +288% | 0 | 0 | — |
case-13 | fail→pass | 13,169 | 9,921 | -25% | 1 | 1 | 0% | 2,442 | 5,680 | +133% | 0 | 0 | — |
case-14 | pass→pass | 15,981 | 19,915 | +25% | 1 | 1 | 0% | 3,423 | 7,033 | +105% | 0 | 0 | — |
case-15 | pass→pass | 3,789 | 5,129 | +35% | 1 | 1 | 0% | 575 | 4,669 | +712% | 0 | 0 | — |
case-16 | fail→pass | 9,148 | 2,221 | -76% | 1 | 1 | 0% | 1,769 | 4,167 | +136% | 0 | 0 | — |
case-17 | pass→pass | 6,587 | 5,243 | -20% | 1 | 1 | 0% | 1,222 | 4,869 | +298% | 0 | 0 | — |
case-18 | pass→pass | 6,843 | 4,579 | -33% | 1 | 1 | 0% | 1,271 | 4,575 | +260% | 0 | 0 | — |
case-19 | pass→pass | 4,708 | 4,734 | +1% | 1 | 1 | 0% | 925 | 4,617 | +399% | 0 | 0 | — |
case-20 | pass→pass | 14,991 | 15,126 | +1% | 1 | 1 | 0% | 2,775 | 6,653 | +140% | 0 | 0 | — |
case-21 | pass→pass | 11,252 | 17,905 | +59% | 1 | 1 | 0% | 2,039 | 5,778 | +183% | 0 | 0 | — |
case-22 | pass→pass | 13,920 | 12,473 | -10% | 1 | 1 | 0% | 2,640 | 6,027 | +128% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +23 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.