Skip to content

Commit 4d9442c

Browse files
committed
feat: release v0.4.0 with packet context, hex view, and advanced search
1 parent f314fdd commit 4d9442c

14 files changed

Lines changed: 915 additions & 131 deletions

File tree

CLAUDE.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Wireshark MCP Developer Guide
2+
3+
## Commands
4+
- **Install**: `pip install -e .`
5+
- **Test**: `python -m unittest discover tests`
6+
- **Run (Local)**: `python src/wireshark_mcp/server.py`
7+
- **Syntax Check**: `python -m compileall src`
8+
- **Build**: `python -m build` (or `hatch build`)
9+
10+
## Code Style
11+
- **Type Hints**: All functions should have type hints.
12+
- **Async/Await**: This project uses `asyncio`. Ensure all I/O bound tools are `async`.
13+
- **Error Handling**: Return JSON error objects `{"success": False, "error": {...}}` instead of raising exceptions for tools.
14+
- **TShark Wrapper**: Use `wireshark_mcp.tshark.client.TSharkClient` for all system calls. Do not use `subprocess` directly in tools.
15+
16+
## Architecture
17+
- `src/wireshark_mcp/server.py`: MCP server entry point and tool registration.
18+
- `src/wireshark_mcp/tshark/client.py`: Core logic wrapping TShark CLI commands.
19+
- `src/wireshark_mcp/tools/`: Individual tool definitions (extract, decode, visualize, etc.).

README.md

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,57 @@ Your task is to analyze a pcap file using Wireshark MCP tools.
6464
- Create a report.md with your findings.
6565
```
6666

67-
## Core Functions
68-
69-
### Packet Analysis
70-
- `wireshark_get_packet_list(pcap_file, limit, offset, display_filter)`: Get a summary list of packets (like Wireshark's top pane).
71-
- `wireshark_get_packet_details(pcap_file, frame_number)`: Get full details for a SINGLE packet (like Wireshark's bottom pane).
72-
- `wireshark_follow_stream(pcap_file, stream_index, protocol, ...)`: Reassemble and view complete stream content with pagination and search.
73-
74-
### Data Extraction
75-
- `wireshark_extract_fields(pcap_file, fields, ...)`: Extract specific fields as tabular data.
76-
- `wireshark_extract_http_requests(pcap_file)`: Convenience tool for HTTP method, URI, host.
77-
- `wireshark_extract_dns_queries(pcap_file)`: Convenience tool for DNS queries.
78-
- `wireshark_list_ips(pcap_file)`: List all unique IP addresses in capture.
79-
80-
### Stats & Capture
81-
- `wireshark_stats_protocol_hierarchy(pcap_file)`: Protocol distribution.
82-
- `wireshark_stats_conversations(pcap_file, type)`: Traffic between endpoints.
83-
- `wireshark_filter_save(input_file, output_file, display_filter)`: Save a subset of packets to a new file.
84-
85-
### Security
86-
- `wireshark_check_threats(pcap_file)`: Check IPs against threat intelligence feeds.
87-
- `wireshark_extract_credentials(pcap_file)`: Scan for plaintext credentials.
67+
## Available Tools
68+
69+
### Packet Analysis (extract.py)
70+
- `wireshark_get_packet_list(pcap_file, limit=20, offset=0, display_filter="", custom_columns="")`:
71+
Get summary list of packets. Supports custom columns (e.g., "ip.src,http.host") to replace default view.
72+
- `wireshark_get_packet_details(pcap_file, frame_number, layers="")`:
73+
Get full JSON details for a single packet. Supports layer filtering (e.g., "ip,tcp,http") to significantly reduce token usage.
74+
- `wireshark_get_packet_bytes(pcap_file, frame_number)`:
75+
**[New]** Get raw Hex/ASCII dump (Packet Bytes view).
76+
- `wireshark_get_packet_context(pcap_file, frame_number, count=5)`:
77+
**[New]** View packets surrounding a specific frame (before and after) to understand context.
78+
- `wireshark_follow_stream(...)`: Reassemble and view complete stream content with pagination and search.
79+
- `wireshark_search_packets(pcap_file, match_pattern, search_type="string", limit=50, scope="bytes")`:
80+
**[Enhanced]** Find packets.
81+
* `scope="bytes"`: Search in raw payload (Hex/String).
82+
* `scope="details"`: Search in decoded text/fields (Regex supported).
83+
- `wireshark_read_packets(...)`: [DEPRECATED] Use `get_packet_details` instead.
84+
85+
### Data Extraction (extract.py)
86+
- `wireshark_extract_fields(pcap_file, fields, display_filter="", limit=100, offset=0)`: Extract specific fields as tabular data.
87+
- `wireshark_extract_http_requests(pcap_file, limit=100)`: Convenience tool for HTTP method, URI, host.
88+
- `wireshark_extract_dns_queries(pcap_file, limit=100)`: Convenience tool for DNS queries.
89+
- `wireshark_list_ips(pcap_file, type="both")`: List all unique IP addresses (src, dst, or both).
90+
- `wireshark_export_objects(pcap_file, protocol, dest_dir)`: Extract embedded files (http, smb, etc.) from traffic.
91+
- `wireshark_verify_ssl_decryption(pcap_file, keylog_file)`: Verify TLS decryption using a keylog file.
92+
93+
### Statistics (stats.py)
94+
- `wireshark_stats_protocol_hierarchy(pcap_file)`: Get Protocol Hierarchy Statistics (PHS).
95+
- `wireshark_stats_endpoints(pcap_file, type="ip")`: List all endpoints and their traffic stats.
96+
- `wireshark_stats_conversations(pcap_file, type="ip")`: Show communication pairs and their stats.
97+
- `wireshark_stats_io_graph(pcap_file, interval=1)`: Get traffic volume over time (I/O Graph).
98+
- `wireshark_stats_expert_info(pcap_file)`: Get Expert Information (anomalies, warnings).
99+
- `wireshark_stats_service_response_time(pcap_file, protocol="http")`: Service Response Time (SRT) statistics.
100+
101+
### File Operations (files.py & capture.py)
102+
- `wireshark_get_file_info(pcap_file)`: Get detailed metadata about a capture file (capinfos).
103+
- `wireshark_merge_pcaps(output_file, input_files)`: Merge multiple capture files into one.
104+
- `wireshark_list_interfaces()`: List available network interfaces for capture.
105+
- `wireshark_capture(interface, output_file, duration_seconds=10, packet_count=0, capture_filter="", ring_buffer="")`: Capture live network traffic.
106+
- `wireshark_filter_save(input_file, output_file, display_filter)`: Filter packets from a pcap and save to a new file.
107+
108+
### Security (security.py)
109+
- `wireshark_check_threats(pcap_file)`: Check captured IPs against URLhaus threat intelligence.
110+
- `wireshark_extract_credentials(pcap_file)`: Scan for plaintext credentials (HTTP Auth, FTP, Telnet).
111+
112+
### Decoding (decode.py)
113+
- `wireshark_decode_payload(data, encoding="auto")`: Decode common encodings (Base64, Hex, URL, Gzip, Deflate, Rot13, etc.) with smart auto-detection.
114+
115+
### Visualization (visualize.py)
116+
- `wireshark_plot_traffic(pcap_file, interval=1)`: Generate ASCII bar chart of traffic volume over time.
117+
- `wireshark_plot_protocols(pcap_file)`: Generate ASCII tree view of protocol hierarchy.
88118

89119
## Development
90120

README_zh.md

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,57 @@ Your task is to analyze a pcap file using Wireshark MCP tools.
6464
- Create a report.md with your findings.
6565
```
6666

67-
## 核心功能
67+
## 可用工具 (Available Tools)
6868

6969
### 数据包分析 (Packet Analysis)
70-
- `wireshark_get_packet_list(pcap_file, limit, offset, display_filter)`: 获取数据包摘要列表 (类似 Wireshark 上方窗格)。
71-
- `wireshark_get_packet_details(pcap_file, frame_number)`: 获取**单个**数据包的完整详情 (类似 Wireshark 下方窗格)。
72-
- `wireshark_follow_stream(pcap_file, stream_index, protocol, ...)`: 重组并查看完整的流内容 (支持**分页****搜索**)。
70+
- `wireshark_get_packet_list(pcap_file, limit=20, offset=0, display_filter="", custom_columns="")`:
71+
获取数据包摘要列表。**新增支持自定义列** (如 "ip.src,http.host"),可替代默认视图。
72+
- `wireshark_get_packet_details(pcap_file, frame_number, layers="")`:
73+
获取单个数据包的完整详情。**新增支持层级过滤** (如 "ip,tcp,http"),大幅减少 Token 消耗。
74+
- `wireshark_get_packet_bytes(pcap_file, frame_number)`:
75+
**[新增]** 获取原始 Hex/ASCII 转储 (类似 Wireshark '分组字节流' 窗格)。
76+
- `wireshark_get_packet_context(pcap_file, frame_number, count=5)`:
77+
**[新增]** 查看上下文数据包 (前后 N 个包),便于理解故障现场。
78+
- `wireshark_follow_stream(pcap_file, stream_index, protocol="tcp", output_mode="ascii", limit_lines=500, offset_lines=0, search_content="")`: 重组并查看完整的流内容 (支持**分页****搜索**)。
79+
- `wireshark_search_packets(pcap_file, match_pattern, search_type="string", limit=50, scope="bytes")`:
80+
**[增强]** 搜索数据包。
81+
* `scope="bytes"`: 搜索原始载荷 (Hex/字符串)。
82+
* `scope="details"`: 搜索解码后的文本层 (支持 Regex)。
83+
- `wireshark_read_packets(...)`: [**已弃用**] 请使用 `get_packet_details`
7384

7485
### 数据提取 (Data Extraction)
75-
- `wireshark_extract_fields(pcap_file, fields, ...)`:这也是一个表格形式的字段提取工具。
76-
- `wireshark_extract_http_requests(pcap_file)`: 便捷工具,提取 HTTP 方法、URI、主机名。
77-
- `wireshark_extract_dns_queries(pcap_file)`: 便捷工具,提取 DNS 查询。
78-
- `wireshark_list_ips(pcap_file)`: 列出捕获文件中的所有唯一 IP 地址。
79-
80-
### 统计与捕获 (Stats & Capture)
81-
- `wireshark_stats_protocol_hierarchy(pcap_file)`: 协议分布统计。
82-
- `wireshark_stats_conversations(pcap_file, type)`: 端点之间的流量统计。
83-
- `wireshark_filter_save(input_file, output_file, display_filter)`: 将过滤后的数据包保存为新文件。
86+
- `wireshark_extract_fields(pcap_file, fields, display_filter="", limit=100, offset=0)`: 提取特定字段为表格数据。
87+
- `wireshark_extract_http_requests(pcap_file, limit=100)`: 提取 HTTP 请求详情 (方法, URI, 主机名) 的便捷工具。
88+
- `wireshark_extract_dns_queries(pcap_file, limit=100)`: 提取 DNS 查询的便捷工具。
89+
- `wireshark_list_ips(pcap_file, type="both")`: 列出所有唯一的 IP 地址 (源,目的,或两者)。
90+
- `wireshark_export_objects(pcap_file, protocol, dest_dir)`: 从流量中提取嵌入的文件 (http, smb 等)。
91+
- `wireshark_verify_ssl_decryption(pcap_file, keylog_file)`: 使用密钥日志文件验证 TLS 解密。
92+
93+
### 统计 (Statistics)
94+
- `wireshark_stats_protocol_hierarchy(pcap_file)`: 获取协议分级统计 (PHS)。
95+
- `wireshark_stats_endpoints(pcap_file, type="ip")`: 列出所有端点及其流量统计。
96+
- `wireshark_stats_conversations(pcap_file, type="ip")`: 显示通信对及其统计信息。
97+
- `wireshark_stats_io_graph(pcap_file, interval=1)`: 获取随时间变化的流量 (I/O 图表)。
98+
- `wireshark_stats_expert_info(pcap_file)`: 获取专家信息 (异常, 警告)。
99+
- `wireshark_stats_service_response_time(pcap_file, protocol="http")`: 服务响应时间 (SRT) 统计。
100+
101+
### 文件操作 (File Operations)
102+
- `wireshark_get_file_info(pcap_file)`: 获取关于捕获文件的详细元数据 (capinfos)。
103+
- `wireshark_merge_pcaps(output_file, input_files)`: 将多个捕获文件合并为一个。
104+
- `wireshark_list_interfaces()`: 列出可用于捕获的网络接口。
105+
- `wireshark_capture(interface, output_file, duration_seconds=10, packet_count=0, capture_filter="", ring_buffer="")`: 捕获实时网络流量。
106+
- `wireshark_filter_save(input_file, output_file, display_filter)`: 从 pcap 中过滤数据包并保存到新文件。
84107

85108
### 安全 (Security)
86-
- `wireshark_check_threats(pcap_file)`: 对照威胁情报源检查 IP。
87-
- `wireshark_extract_credentials(pcap_file)`: 扫描明文凭证。
109+
- `wireshark_check_threats(pcap_file)`: 对照 URLhaus 威胁情报检查捕获的 IP。
110+
- `wireshark_extract_credentials(pcap_file)`: 扫描明文凭证 (HTTP Auth, FTP, Telnet)。
111+
112+
### 解码工具 (Decoding)
113+
- `wireshark_decode_payload(data, encoding="auto")`: 智能解码常见编码 (Base64, Hex, URL, Gzip, Deflate, Rot13 等)。
114+
115+
### 可视化工具 (Visualization)
116+
- `wireshark_plot_traffic(pcap_file, interval=1)`: 生成 ASCII 字符画形式的流量波峰图 (可识别 DDoS/扫描)。
117+
- `wireshark_plot_protocols(pcap_file)`: 生成 ASCII 字符画形式的协议分级树 (直观查看协议占比)。
88118

89119
## 开发
90120

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "wireshark-mcp"
7-
version = "0.2.1"
7+
version = "0.4.0"
88
description = "A production-grade Model Context Protocol (MCP) server for Wireshark"
99
readme = "README.md"
1010
requires-python = ">=3.10"

src/wireshark_mcp/server.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
from .tools.extract import register_extract_tools
66
from .tools.files import register_files_tools
77
from .tools.security import register_security_tools
8+
from .tools.decode import register_decode_tools
9+
from .tools.visualize import register_visualize_tools
810
import asyncio
911

1012
# Initialize Server
@@ -18,6 +20,8 @@
1820
register_extract_tools(mcp, client)
1921
register_files_tools(mcp, client)
2022
register_security_tools(mcp, client)
23+
register_decode_tools(mcp)
24+
register_visualize_tools(mcp, client)
2125

2226
def main():
2327
"""Entry point for the application script"""

src/wireshark_mcp/tools/decode.py

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
from mcp.server.fastmcp import FastMCP
2+
import base64
3+
import binascii
4+
import gzip
5+
import zlib
6+
import urllib.parse
7+
import html
8+
import quopri
9+
import codecs
10+
import json
11+
import string
12+
13+
def _calculate_score(data: bytes) -> float:
14+
"""Calculate a 'readability' score for bytes (0.0 to 1.0)."""
15+
if not data:
16+
return 0.0
17+
try:
18+
text = data.decode('utf-8')
19+
printable = set(string.printable)
20+
count = sum(1 for c in text if c in printable)
21+
return count / len(text)
22+
except UnicodeDecodeError:
23+
# If not utf-8, check if it's mostly ASCII printable bytes
24+
printable_bytes = set(string.printable.encode('ascii'))
25+
count = sum(1 for b in data if b in printable_bytes)
26+
return (count / len(data)) * 0.5 # Penalty for non-utf8
27+
28+
def _try_decode(data: str, encoding: str):
29+
"""Try to decode data with specific encoding, returning (success, result_bytes, error)."""
30+
try:
31+
if encoding == "base64":
32+
# Handle standard and url-safe base64, and padding
33+
missing_padding = len(data) % 4
34+
if missing_padding:
35+
data += '=' * (4 - missing_padding)
36+
return True, base64.b64decode(data, validate=True), None
37+
38+
elif encoding == "hex":
39+
# Remove spaces/colons/0x
40+
clean_data = data.replace(" ", "").replace(":", "").replace("0x", "")
41+
return True, binascii.unhexlify(clean_data), None
42+
43+
elif encoding == "url":
44+
return True, urllib.parse.unquote_to_bytes(data), None
45+
46+
elif encoding == "rot13":
47+
return True, codecs.decode(data, 'rot_13').encode('utf-8'), None
48+
49+
elif encoding == "gzip":
50+
# Latin-1 allows 1:1 mapping of bytes to chars
51+
b = data.encode('latin-1')
52+
return True, gzip.decompress(b), None
53+
54+
elif encoding == "deflate":
55+
b = data.encode('latin-1')
56+
# -15 for raw deflate (no header), standard zlib has header
57+
try:
58+
return True, zlib.decompress(b), None
59+
except:
60+
return True, zlib.decompress(b, -15), None
61+
62+
elif encoding == "quopri":
63+
return True, quopri.decodestring(data.encode('utf-8')), None
64+
65+
elif encoding == "html":
66+
return True, html.unescape(data).encode('utf-8'), None
67+
68+
elif encoding == "unicode":
69+
# "Hello\u0020World" -> bytes
70+
return True, data.encode('utf-8').decode('unicode_escape').encode('utf-8'), None
71+
72+
elif encoding == "ascii85":
73+
# Adobe Ascii85 usually delimited by <~ ~>
74+
d = data.strip()
75+
if d.startswith("<~"): d = d[2:]
76+
if d.endswith("~>"): d = d[:-2]
77+
return True, base64.a85decode(d), None
78+
79+
except Exception as e:
80+
return False, None, str(e)
81+
82+
return False, None, "Unknown encoding"
83+
84+
def register_decode_tools(mcp: FastMCP):
85+
86+
@mcp.tool()
87+
def wireshark_decode_payload(data: str, encoding: str = "auto") -> str:
88+
"""
89+
[Utils] Decode common encodings (Base64, Hex, URL, Gzip, etc.).
90+
91+
Args:
92+
data: The string to decode.
93+
encoding: Target encoding. Supported:
94+
'base64', 'hex', 'url', 'rot13', 'gzip', 'deflate',
95+
'html', 'unicode', 'quopri', 'ascii85'.
96+
Use 'auto' to try all and sort by readability.
97+
98+
Returns:
99+
Decoded string (or JSON in 'auto' mode).
100+
"""
101+
encodings = ["base64", "hex", "url", "rot13", "html", "unicode", "quopri", "ascii85"]
102+
# Exclude gzip/deflate from simple auto list, handled in chaining
103+
104+
if encoding == "auto":
105+
results = []
106+
107+
# 1. Try single-step decodes
108+
for enc in encodings:
109+
success, res_bytes, _ = _try_decode(data, enc)
110+
if success:
111+
try:
112+
text = res_bytes.decode('utf-8')
113+
score = _calculate_score(res_bytes)
114+
# Filter out trivial results
115+
if text == data and enc in ["url", "html", "unicode", "rot13"]:
116+
continue
117+
if enc == "hex" and score < 0.1:
118+
continue
119+
120+
results.append({
121+
"encoding": enc,
122+
"result": text[:200] + "..." if len(text) > 200 else text,
123+
"score": round(score, 2),
124+
"is_text": True
125+
})
126+
except:
127+
# Binary result
128+
results.append({
129+
"encoding": enc,
130+
"result": "<binary_data>",
131+
"hex_preview": binascii.hexlify(res_bytes[:20]).decode('ascii'),
132+
"score": 0.0,
133+
"is_text": False
134+
})
135+
136+
# 2. Try Chained (e.g., Base64 -> Gzip)
137+
success, b64_bytes, _ = _try_decode(data, "base64")
138+
if success:
139+
try:
140+
gzip_bytes = gzip.decompress(b64_bytes)
141+
results.append({
142+
"encoding": "base64+gzip",
143+
"result": gzip_bytes.decode('utf-8', errors='replace')[:200],
144+
"score": _calculate_score(gzip_bytes),
145+
"is_text": True
146+
})
147+
except: pass
148+
149+
try:
150+
zlib_bytes = zlib.decompress(b64_bytes)
151+
results.append({
152+
"encoding": "base64+zlib",
153+
"result": zlib_bytes.decode('utf-8', errors='replace')[:200],
154+
"score": _calculate_score(zlib_bytes),
155+
"is_text": True
156+
})
157+
except: pass
158+
159+
# Sort by score desc
160+
results.sort(key=lambda x: x["score"], reverse=True)
161+
162+
return json.dumps({
163+
"success": True,
164+
"candidates": results[:5] # Return top 5
165+
}, indent=2)
166+
167+
else:
168+
success, res_bytes, err = _try_decode(data, encoding)
169+
if not success:
170+
return json.dumps({"success": False, "error": err})
171+
172+
try:
173+
return res_bytes.decode('utf-8')
174+
except UnicodeDecodeError:
175+
return f"[Binary Data] Hex: {binascii.hexlify(res_bytes).decode('ascii')}"

0 commit comments

Comments
 (0)