- 网络
- 网络安全
【免费下载链接】scapy
Scapy: the Python-based interactive packet manipulation program & library.
本文是 Scapy 官方文档 Build your own tools(构建你自己的工具) 的深度实战解读。你将在本文中掌握三类核心能力:把 Scapy 作为库嵌入你自己的 Python 脚本(实现 ping 探测、ARP 扫描、流量监控等自动化工具);精确控制 Scapy 日志系统与输出详细度;以及不修改 Scapy 源码、以独立 add-on 文件扩展协议与函数,并通过interact()启动带自定义 banner 的交互式控制台。
写在前面:Scapy 扩展的两条路径
Scapy 的价值不仅在于交互式命令行,更在于它提供了两条清晰的扩展路径,本文覆盖官方文档的全部内容:
- 在你的工具中使用 Scapy:将
scapy.all作为 Python 库导入,编写独立的自动化脚本; - 以 add-on 方式扩展 Scapy:把自定义协议类、辅助函数写在一个单独的文件中,不修改 Scapy 源码,并通过
interact()将其注入到交互式会话中。
官方文档(doc/scapy/extending.rst)明确表示:"You can also extend Scapy without having to edit its source file",这正是两种路径的共同基石。下面逐一展开。
在你的工具中使用 Scapy
把 Scapy 嵌入你自己的工具非常简单:导入所需模块,直接调用即可。其底层能力由 scapy/sendrecv.py(发送与接收)、scapy/layers/inet.py(IP/ICMP 等网络层协议)和 scapy/packet.py(包构建与解析)等模块支撑。
示例一:ICMP 回显探测
第一个例子接收一个 IP 地址或主机名作为参数,发送 ICMP 回显请求包,并显示完整解析后的返回包:
#! /usr/bin/env python import sys from scapy.all import sr1, IP, ICMP p = sr1(IP(dst=sys.argv[1]) / ICMP()) if p: p.show()要点说明:
sr1()发送一层(Layer 3)数据包并等待第一个响应,返回解析后的应答包;p.show()以分层缩进方式打印包的完整字段;- 使用
/操作符组合IP(dst=...)与ICMP(),这是 Scapy 构建协议栈的标准语法; - 若
sr1()超时未收到应答(默认超时行为由conf相关参数控制),p为None,脚本因此做了判空保护。
示例二:ARP ping 并输出 LaTeX 表格(arping2tex)
这是一个更完整的实战工具:对指定网段执行 ARP ping,并将结果格式化为 LaTeX 表格输出:
#! /usr/bin/env python # arping2tex : arpings a network and outputs a LaTeX table as a result import sys if len(sys.argv) != 2: print("Usage: arping2tex <net>\n eg: arping2tex 192.168.1.0/24") sys.exit(1) from scapy.all import srp, Ether, ARP, conf conf.verb = 0 ans, unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=sys.argv[1]), timeout=2) print(r"\begin{tabular}{|l|l|}") print(r"\hline") print(r"MAC & IP\\") print(r"\hline") for snd, rcv in ans: print(rcv.sprintf(r"%Ether.src% & %ARP.psrc%\\")) print(r"\hline") print(r"\end{tabular}")该脚本用到三个关键机制:
conf.verb = 0静默模式:conf是 Scapy 的全局配置对象(定义于 scapy/config.py),其中verb字段控制输出详细度。源码注释(scapy/config.py#L984)写明其取值范围为 0(几乎静默)到 3(详细),默认值为 2。设置为 0 可以让脚本输出保持干净;srp()二层收发:srp()发送 Layer 2 帧(区别于一层的sr1()),返回二元组(answered, unanswered),即ans与unans。通过广播目的 MACff:ff:ff:ff:ff:ff加上ARP(pdst=网段)实现网段扫描,timeout=2秒控制等待时间;sprintf()格式化:rcv.sprintf("%Ether.src% & %ARP.psrc%")按模板提取应答包中的源 MAC 与源 IP,逐行拼接成 LaTeX 表格行。
示例三:ARP 流量实时监控回调
下面的工具会持续监听本机所有接口,并打印捕获到的所有 ARP 请求(包括来自 Wi-Fi 网卡 monitor 模式下 802.11 帧中的 ARP)。注意sniff()的store=0参数,避免在内存中无谓地保存全部报文:
#! /usr/bin/env python from scapy.all import * def arp_monitor_callback(pkt): if ARP in pkt and pkt[ARP].op in (1, 2): # who-has or is-at return pkt.sprintf("%ARP.hwsrc% %ARP.psrc%") sniff(prn=arp_monitor_callback, filter="arp", store=0)要点说明:
sniff()是 Scapy 抓包入口(实现在 scapy/sendrecv.py)。prn指定对每个捕获包调用的回调函数,回调的返回值会被打印;filter使用 BPF(Berkeley Packet Filter)语法只捕获 ARP 流量;store=0让数据包不被保存在内存列表中,适合长时间运行的监控型工具;ARP in pkt检查数据包中是否包含 ARP 层;pkt[ARP].op取 ARP 操作码,1 表示 who-has(请求)、2 表示 is-at(应答);if ARP in pkt之所以必要,是因为在 monitor 模式下,Wi-Fi 帧(802.11)可能承载着不同链路层协议,需要先确认内部确有 ARP 层再访问字段。
配置 Scapy 的日志系统
Scapy 会自动基于 Python 标准库的logging模块配置一个 logger。这个 logger 是定制化的,支持颜色输出和频率过滤等特性。默认情况下(非交互模式)日志级别为WARNING,你可以通过以下方式修改,例如设为CRITICAL以几乎禁用所有日志:
import logging logging.getLogger("scapy").setLevel(logging.CRITICAL)需要理解的两点:
- 默认级别因模式而异:官方文档特别提示,交互模式下默认日志级别为
INFO。这与 scapy/config.py#L967 中的logLevel配置项直接相关——该配置项是一个带拦截器(Interceptor)的属性,级别变化会触发_loglevel_changer回调(scapy/config.py#L915)来同步调整底层log_scapy的实际级别; - CRITICAL 的边界:官方文档明确指出"Scapy simply won't work properly if a CRITICAL failure occurs",即 CRITICAL 用于严重故障,设为该级别后正常运行时几乎无日志输出,但如果真发生 CRITICAL 级错误,Scapy 可能无法正常工作——因此该设置适合对输出有洁癖的稳定脚本,调试期建议保留
WARNING甚至INFO。
用 add-on 扩展 Scapy:自定义协议与 interact()
当你需要新增协议、函数等任何内容时,直接写进 Scapy 源码当然可以,但官方文档明确不推荐这种方式:"But this is not very convenient. Even if those modifications are to be integrated into Scapy, it can be more convenient to write them in a separate file." 更优雅的做法是写成独立文件:
- 编写包含自定义内容(协议类、辅助函数等)的 Python 文件;
- 让该文件可执行,并在
if __name__ == "__main__":分支中调用 Scapy 的interact()函数,把自定义命名空间与自定义 banner 注入交互式会话。
官方文档给出的完整 add-on 示例:
#! /usr/bin/env python # Set log level to benefit from Scapy warnings import logging logger = logging.getLogger("scapy") logger.setLevel(logging.INFO) from scapy.all import * class Test(Packet): name = "Test packet" fields_desc = [ShortField("test1", 1), ShortField("test2", 2)] def make_test(x, y): return Ether() / IP() / Test(test1=x, test2=y) if __name__ == "__main__": interact(mydict=globals(), mybanner="Test add-on v3.14")自定义协议类的结构
Test继承自Packet基类(scapy/packet.py#L82),核心组成:
name:协议的人类可读名称,显示在show()等输出中;fields_desc:字段描述列表,定义了该包的二进制布局。这里使用两个ShortField(16 位短整数),字段名分别为test1(默认值 1)与test2(默认值 2)。ShortField等基础字段类定义在 scapy/fields.py(例如 scapy/fields.py#L1319),同族还包括ByteField(scapy/fields.py#L1062)、IntField(scapy/fields.py#L1349)等,可按需组合出不同的包结构。
interact() 如何把自定义内容注入会话
interact()定义于 scapy/main.py#L648,签名如下:
def interact(mydict=None, argv=None, mybanner=None, mybanneronly=False, loglevel=logging.INFO):其工作流程(对应 scapy/main.py 的实现)可以概括为:
- 进入交互模式:设置
conf.interactive = True、加载默认主题(scapy/main.py#L661-L663),并将conf.logLevel设为传入的loglevel(默认logging.INFO,这与交互模式下默认 INFO 级别的行为一致); - 解析命令行选项:支持
-h(帮助)、-H(无花哨 banner)、-c/-C(自定义/禁用启动文件)、-p/-P(自定义/禁用预启动文件)、-d(降低日志级别)等参数(scapy/main.py#L674-L691); - 注入自定义命名空间:调用
init_session(mydict=mydict, ret=True)(scapy/main.py#L713)。在 scapy/main.py#L530-L532 可以看到,mydict中的键值会被更新进scapy_session,因此你在 add-on 中通过globals()传入的自定义类(Test)和函数(make_test)都会成为交互控制台中的可用名字; - 拼接自定义 banner:当
mybanner非空时,会追加到默认 banner 之后;若同时设置mybanneronly=True,则默认 banner 被清空、只显示你的自定义 banner(scapy/main.py#L857-L861); - 选择交互式 shell:根据
conf.interactive_shell(可选ipython、bpython、ptpython、ptipython、python、auto)启动对应的解释器,默认auto模式下依次探测 IPython → bpython → ptpython,都不存在时回退到标准 Python shell(scapy/main.py#L741-L778)。
运行效果
把上面的代码保存为test_interact.py并赋予可执行权限后运行,会得到官方文档所示的输出:
# ./test_interact.py Welcome to Scapy (0.9.17.109beta) Test add-on v3.14 >>> make_test(42,666) <Ether type=0x800 |<IP |<Test test1=42 test2=666 |>>>可以看到:默认 banner 之后紧跟着自定义 banner "Test add-on v3.14";make_test(42, 666)直接可用,返回的是Ether/IP/Test三层叠放的包对象,test1=42、test2=666正是传入的自定义字段值。这样,你就拥有一个带个人定制协议的交互式 Scapy 环境,无需改动 Scapy 任何源码。
小结与进一步探索
本文覆盖了官方文档 doc/scapy/extending.rst 的全部核心内容:作为库嵌入脚本(ICMP 探测、ARP ping + LaTeX 输出、ARP 监控回调)、日志级别控制(logging.getLogger("scapy").setLevel(...)与conf.verb)、以及以 add-on 方式扩展(自定义Packet子类 +interact(mydict=globals(), mybanner=...))。这些能力相互独立又可自由组合——例如你可以在自动化脚本中conf.verb = 0保持输出干净,也可以把调试期日志设为INFO借助频率过滤器观察告警。
如果你想深入底层,建议继续阅读:
- scapy/packet.py:
Packet基类与/组合操作符的构造与解析机制; - scapy/sendrecv.py:
sr1、srp、sniff等收发与抓包函数的完整实现; - scapy/fields.py:
ByteField、ShortField、IntField等字段类家族,是自定义协议布局的基础; - scapy/main.py:
interact()、init_session()与启动文件(startup file)机制的完整实现; - scapy/config.py:
conf全局配置,包括verb、logLevel、interactive等开关的默认值。
- 网络
- 网络安全
【免费下载链接】scapy
Scapy: the Python-based interactive packet manipulation program & library.
相关推荐
Airsonic功能详解:10个必知的核心特性与使用技巧
Airsonic功能详解:10个必知的核心特性与使用技巧 Airsonic是一款免费开源的媒体服务器,作为Subsonic和Libresonic的分支项目,它允
PaintingLight与其他光照工具对比:优势、局限性与适用场景
PaintingLight与其他光照工具对比:优势、局限性与适用场景 PaintingLight是一款基于RGB空间几何的数字绘画光照效果生成工具,由Style
OpenSpec与Git集成:规范版本控制的最佳实践
OpenSpec与Git集成:规范版本控制的最佳实践 OpenSpec是一款面向AI编码助手的规范驱动开发(SDD)工具,它通过结构化的规范定义和变更管理,帮助
开发工具CLIAI 应用工作流自动化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考