- 网络
- 网络安全
【免费下载链接】scapy
Scapy: the Python-based interactive packet manipulation program & library.
SCTP(Stream Control Transmission Protocol,流控制传输协议)是一种融合 TCP 可靠性与 UDP 消息边界特性的传输层协议,主要活跃在电信运营商核心网(如 VoIP 信令承载)等场景。本篇指南以 doc/scapy/layers/sctp.rst 为骨架,结合 Scapy 仓库中 scapy/layers/sctp.py 的完整实现与 test/scapy/layers/sctp.uts 回归测试,系统讲解 SCTP 协议在 Scapy 中的报文结构、Chunk/参数体系、构造与解析方法,以及在与 SCTP 服务器联调时必须掌握的 Linux 内核扩展能力(RFC 4895 分块认证、RFC 5061 动态地址重配置)启用步骤。读完本文,你将具备用 Scapy 独立构造、发送、解析 SCTP 报文,并正确配置内核使 SCTP 服务器接受这些报文的能力。
SCTP 协议概览:兼具 TCP 与 UDP 特性的传输层协议
SCTP 是相对较年轻的传输层协议,由 RFC 3286 引入、RFC 4960 完整定义。原文档明确指出,它结合了 TCP 与 UDP 两者的特征:既像 TCP 一样提供面向连接的可靠传输、拥塞控制与有序交付,又像 UDP 一样以"消息(Message)"而非"字节流"为传输边界,且天然支持多宿主(Multi-homing)与多流(Multi-streaming)。
从实际部署看,SCTP 并非广泛使用的通用协议,其主要存在于电信运营商运营的核心网络中,典型用途是承载 VoIP 相关信令(如 M3UA、S1AP、Diameter 等协议栈的底层传输)。Scapy 的SCTP_SERVICES端口服务字典(scapy/data.py)即从系统/etc/services加载(无该文件时回退到 Scapy 自带的数据),其中收录的SCTP_PAYLOAD_PROTOCOL_INDENTIFIERS(协议负载标识符,定义于 scapy/layers/sctp.py)也印证了这一生态:包括 M2UA/M3UA/SUA 等 SIGTRAN 信令适配层、S1AP/X2AP/NBAP 等 3G/4G 移动网应用协议、Diameter、H.248、SSH/SCTP 以及 WebRTC 的 DCEP/字符串/二进制数据传输类型。
对安全研究与协议测试而言,这意味着 SCTP 报文通常出现在核心网边界、信令网关与移动回传链路上,而 Scapy 提供了完整的分层构造与解析能力来操作这些流量。
Scapy 中 SCTP 层的实现:报文头与校验和
Scapy 对 SCTP 的实现集中在 scapy/layers/sctp.py,首先在 sctp.py 第 42 行 定义了协议号常量:
IPPROTO_SCTP = 132随后在文件末尾通过bind_layers完成与 IPv4/IPv6 及 ICMP 错误报文层的绑定:
bind_layers(IP, SCTP, proto=IPPROTO_SCTP) bind_layers(IPerror, SCTPerror, proto=IPPROTO_SCTP) bind_layers(IPv6, SCTP, nh=IPPROTO_SCTP) bind_layers(IPerror6, SCTPerror, proto=IPPROTO_SCTP)SCTP 公共报文头
SCTP 类 定义在SCTP数据包头层,字段如下:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
sport | ShortEnumField | 0 | 源端口,取值枚举自SCTP_SERVICES |
dport | ShortEnumField | 0 | 目的端口,取值枚举自SCTP_SERVICES |
tag | XIntField | 0 | 验证标签(Verification Tag),十六进制显示 |
chksum | XIntField | None | 校验和,十六进制显示 |
其中tag用于 SCTP 关联(Association)的验证——每个 SCTP 关联由两端各自生成的 Initiate Tag 标识,收方必须校验数据包中的 Verification Tag 与自身记录一致,这是 SCTP 防止盲注入攻击的核心机制。
CRC32c 校验和的自动计算
SCTP 使用 CRC-32c(Castagnoli 多项式0x1EDC6F41)计算校验和,与 TCP/UDP 使用的传统 Internet 校验和算法不同。Scapy 在 sctp.py 第 45-110 行 内置了完整的 256 项查找表crc32c_table,并实现 crc32c 函数 完成逐字节的查表 CRC 计算与字节序反转:
def crc32c(buf): crc = 0xffffffff for c in buf: crc = (crc >> 8) ^ crc32c_table[(crc ^ (c)) & 0xFF] crc = (~crc) & 0xffffffff # reverse endianness return struct.unpack(">I", struct.pack("<I", crc))[0]注意 sctp.py 第 122-139 行 中保留了一段被注释掉的 RFC 2960 时代 Adler-32 旧校验算法,说明该模块经历了从旧规范到 RFC 4960 新校验的演进,当前活跃代码全部采用 CRC32c。
SCTP.post_build(sctp.py 第 283-288 行)在报文构建时自动执行:若chksum字段为None,则对完整报文计算 CRC32c 并回填到偏移 8 处。因此用 Scapy 构造 SCTP 报文时无需手动填写校验和,这一点在测试用例中得到了验证——例如 test/scapy/layers/sctp.uts 第 16 行 断言解析出的p[SCTP].chksum == 0x402c0b5f与构建时写入的值一致。
SCTP Chunk 体系:Scapy 支持的完整分块类型
SCTP 的数据包由一个公共头(上述 12 字节)后跟一个或多个 Chunk(分块)构成,每个 Chunk 至少包含 4 字节的公共头(类型、标志、长度),并按 4 字节对齐。Scapy 的_SCTPChunkGuessPayload(sctp.py 第 259-265 行)依据首个字节的类型值自动分派到对应 Chunk 类,实现从原始字节流到结构化对象的无缝解析。
sctpchunktypes 字典 完整映射了 Scapy 支持的类型号,涵盖基础规范与扩展规范:
| 类型值 | Chunk 名称 | Scapy 类 | 用途 |
|---|---|---|---|
| 0 | data | SCTPChunkData | 数据传输(RFC 4960) |
| 1 | init | SCTPChunkInit | 关联初始化 |
| 2 | init-ack | SCTPChunkInitAck | 关联初始化应答 |
| 3 | sack | SCTPChunkSACK | 选择性确认 |
| 4 / 5 | heartbeat-req / ack | SCTPChunkHeartbeatReq/Ack | 路径探测与保活 |
| 6 | abort | SCTPChunkAbort | 异常终止关联 |
| 7 / 8 | shutdown / ack | SCTPChunkShutdown/ShutdownAck | 优雅关闭 |
| 9 | error | SCTPChunkError | 错误报告 |
| 10 / 11 | cookie-echo / ack | SCTPChunkCookieEcho/CookieAck | 四次握手中的 Cookie 交换 |
| 14 | shutdown-complete | SCTPChunkShutdownComplete | 关闭完成 |
| 15 | authentication | SCTPChunkAuthentication | 分块认证(RFC 4895) |
| 64 | i-data | SCTPChunkIData | 交错数据(RFC 8260) |
| 130 | re-config | SCTPChunkReConfig | 流重置/重配置(RFC 6525) |
| 132 | pad | SCTPChunkPad | 填充(RFC 4820) |
| 0x80 / 0xc1 | address-configuration(-ack) | SCTPChunkAddressConfAck/AddressConf | 动态地址重配置(RFC 5061) |
| 192 / 194 | forward-tsn / i-forward-tsn | SCTPChunkForwardTSN/IForwardTSN | 部分可靠传输与跳过空洞 |
从源码结构看,这些 Chunk 类普遍继承_SCTPChunkGuessPayload,因此 Chunk 之后可以继续嵌套其他 Chunk,形成 SCTP 报文的多分块结构。
常用 Chunk 的字段要点
- SCTPChunkData(sctp.py 第 647-663 行):数据分块,包含 1 位
delay_sack(延迟确认位)、unordered(乱序标志)、beginning/ending(消息开始/结束位,用于分片重组),以及tsn(传输序号)、stream_id、stream_seq和按SCTP_PAYLOAD_PROTOCOL_INDENTIFIERS枚举的proto_id。len自动为数据长度 + 16。 - SCTPChunkInit / InitAck(sctp.py 第 723-737 行):包含
init_tag、a_rwnd(接收窗口)、n_out_streams/n_in_streams(出/入流数量)、init_tsn,以及可变的params参数列表。 - SCTPChunkSACK(sctp.py 第 760-775 行):确认分块,含
cumul_tsn_ack、a_rwnd、gap_ack_list(空洞确认区间,以"start:end"字符串表示)与dup_tsn_list(重复 TSN 列表)。 - SCTPChunkAuthentication(sctp.py 第 848-857 行):RFC 4895 认证分块,含
shared_key_id、HMAC_function与 HMAC 载荷。
Chunk 可变参数:Init/ReConfig 中的参数化扩展
许多 Chunk(尤其是 Init、InitAck、ReConfig、AddressConf)携带一个或多个可变参数(Parameters)。Scapy 通过ChunkParamField(sctp.py 第 323-332 行)依据参数类型号(type << 8 | 值)自动分派到 sctpchunkparamtypescls 中对应的参数类。原文档重点提及的两类扩展能力在参数层面均有完整实现:
RFC 4895(分块认证)相关参数:
SCTPChunkParamRandom(0x8002):随机数参数,默认RandBin(32),每次构建自动生成 32 字节随机数(test/scapy/layers/sctp.uts 第 324-327 行 专门验证两次实例化的随机数互不相同);SCTPChunkParamChunkList(0x8003):需要认证的 Chunk 类型列表;SCTPChunkParamRequestedHMACFunctions(0x8004):请求的 HMAC 算法列表,hmactypes字典(sctp.py 第 141-146 行)定义 1 为 SHA-1、3 为 SHA-256。
RFC 5061(动态地址重配置)相关参数:
SCTPChunkParamAddIPAddr(0xc001)/SCTPChunkParamDelIPAddr(0xc002):增加/删除 IP 地址,通过MultipleTypeField根据addr_type自动选择 IPv4(类型 5)或 IPv6(类型 6)解析;SCTPChunkParamSetPrimaryAddr(0xc004):设置主用地址;SCTPChunkParamSuccessIndication(0xc005)/ErrorIndication(0xc003):操作结果指示;- 流重配置(RFC 6525)参数族:
OutSSNResetReq(13)、InSSNResetReq(14)、SSNTSNResetReq(15)、ReConfigRes(16)以及增减流请求(17/18)。
其余通用参数还包括HeartbeatInfo(心跳信息)、IPv4Addr/IPv6Addr、StateCookie(状态 Cookie,四次握手中由服务器签发)、CookiePreservative、Hostname、SupportedAddrTypes、ECNCapable、SupportedExtensions等,类型定义完整覆盖 RFC 4960 基础规范及其主要扩展。
实战:用 Scapy 构造与解析 SCTP 报文
以下示例直接取自 test/scapy/layers/sctp.uts 的回归测试,可验证实现正确性并作为编写实际脚本的模板。
构造 Init 分块并携带 IPv4 地址参数
from scapy.all import * from scapy.layers.sctp import SCTP, SCTPChunkInit, SCTPChunkParamIPv4Addr s = raw(IP() / SCTP() / SCTPChunkInit(params=[SCTPChunkParamIPv4Addr()]))这会在 IP 层(协议号 132)之上构建 SCTP 公共头(端口 0、tag 0、chksum 自动计算),再嵌套 Init 分块,其中params列表包含一个 IPv4 地址参数(默认127.0.0.1,见 sctp.py 第 351-354 行)。测试断言生成的原始字节与期望十六进制完全一致,且重新解析后能还原出SCTPChunkParamIPv4Addr对象与正确的校验和。
构造 SACK 确认分块
s = raw(IP() / SCTP() / SCTPChunkSACK(gap_ack_list=["7:28"]))gap_ack_list接受"开始:结束"格式的字符串(或(start, end)元组,由GapAckField.any2i支持),解析后依旧以"7:28"形式返回,与测试第 24 行断言一致。
构造发送完整的 SCTP 数据包
from scapy.all import * # 构造一个携带数据分块的 SCTP 报文并发往本机 pkt = IP(src="192.168.1.10", dst="192.168.1.20") / \ SCTP(sport=2905, dport=3868, tag=0x11223344) / \ SCTPChunkInit(init_tag=0x55667788, a_rwnd=1024, n_out_streams=3, n_in_streams=3, init_tsn=100, params=[SCTPChunkParamIPv4Addr(addr="192.168.1.10"), SCTPChunkParamRandom()]) pkt.show() # 查看结构化字段 pkt.summary() # 查看简要摘要 send(pkt) # 通过内核套接字发送(需相应权限)解析抓取的 SCTP 报文
from scapy.all import * from scapy.layers.sctp import SCTP, SCTPChunkInit # 从 pcap 文件读取并定位 SCTP 报文 pkts = rdpcap("sctp_trace.pcap") for p in pkts: if p.haslayer(SCTP): print(p[SCTP].summary()) if p.haslayer(SCTPChunkInit): init = p[SCTPChunkInit] print("init_tag=%s a_rwnd=%s streams=%d/%d init_tsn=%s" % (init.init_tag, init.a_rwnd, init.n_out_streams, init.n_in_streams, init.init_tsn))Scapy 会自动将 TCP/UDP 之外端口与SCTP_SERVICES中的已知服务名关联显示,便于快速辨识 Diameter(3868)、SCTP 上的 SSH 等承载协议。
与 SCTP 服务器联调:启用 RFC 4895 与 RFC 5061 内核能力
原文档的核心实操部分指出:当使用 Scapy 与 SCTP 服务器通信时,可能需要用到 RFC 4895(SCTP 分块认证)与 RFC 5061(动态地址重配置)引入的能力,而这些能力在 Linux 上默认并不总是开启的。Scapy 自身无需任何修改即可构造/解析相关报文(前文已展示其 Chunk 与参数类完整支持),但 SCTP 服务器(依赖 Linux 内核 SCTP 协议栈)需要显式激活对应开关,否则服务器会拒绝或忽略这些扩展报文。
Linux 内核的 SCTP 扩展能力通过/proc/sys/net/sctp/下的 sysctl 节点控制,配置立即生效、无需重启,也不需要修改 Scapy。三组开关对应关系如下:
| sysctl 节点 | 对应 RFC | 能力 | 默认状态 |
|---|---|---|---|
/proc/sys/net/sctp/auth_enable | RFC 4895 | 允许对指定 Chunk 进行 HMAC 认证 | 通常关闭 |
/proc/sys/net/sctp/addip_enable | RFC 5061 | 允许动态增删/重配置关联的 IP 地址 | 通常关闭 |
/proc/sys/net/sctp/addip_noauth_enable | RFC 5061(无认证路径) | 在不启用分块认证的前提下使用动态地址重配置 | 通常关闭 |
启用步骤
1. 启用 RFC 4895 分块认证:
$ sudo echo 1 > /proc/sys/net/sctp/auth_enableauth_enable=1后,内核才允许处理携带SCTPChunkAuthentication(类型 15)分块及其关联参数(Random、ChunkList、RequestedHMACFunctions)的报文。
2. 启用 RFC 5061 动态地址重配置:
$ sudo echo 1 > /proc/sys/net/sctp/addip_enable开启后,内核支持处理SCTPChunkAddressConf(0xc1)分块及 AddIP/DelIP/SetPrimaryAddr 等参数,允许在关联存活期间动态变更成员地址。
3. 仅启用动态地址重配置(不启用分块认证):
$ sudo echo 1 > /proc/sys/net/sctp/addip_noauth_enable原文档特别提示了这种组合场景:你可能只需要动态地址重配置,而不必同时开启分块认证。此时单独置addip_noauth_enable=1即可,无需开启auth_enable。从内核 SCTP 实现看,addip_enable与addip_noauth_enable存在相互依赖关系,addip_noauth_enable提供了"非认证模式下的地址重配置"通道。
注意事项
- 权限:上述命令需要 root 权限(
sudo),且echo 1 > ...的写法会由 shell 以 root 身份执行重定向。原文档使用$ sudo echo 1 > /proc/sys/net/sctp/auth_enable的语法,含义是让echo以 root 输出 1 并写入该只读于普通用户的 sysctl 文件。 - 前提条件:目标 Linux 内核需要编译并加载 SCTP 协议栈支持(
net/sctp模块,ls /proc/sys/net/sctp目录存在即代表可用)。若目录不存在,可先加载 SCTP 模块。 - 持久化:这些 sysctl 设置在重启后恢复默认,如需持久化应写入
/etc/sysctl.conf(net.sctp.auth_enable=1等)。 - 验证:设置后可用
cat /proc/sys/net/sctp/auth_enable确认当前值;再用 Scapy 构造带认证/地址重配置分块的报文与服务器交互,观察服务器是否正常回应。
测试验证与回归保障
Scapy 仓库为 SCTP 层提供了完善的回归测试套件 test/scapy/layers/sctp.uts,覆盖范围包括:
- 构建-解析闭环:对 Init、InitAck、SACK、Heartbeat、Abort、Shutdown 系列、Error、Cookie 系列、Authentication、AddressConf/AddressConfAck、ReConfig、Pad、Data/IData、ForwardTSN/IForwardTSN 等全部 Chunk 类型进行原始字节的构建与反解析断言(含 CRC32c 校验和一致性);
- 边界与组合场景:Init 携带 7 个混合参数(ECNCapable、FwdTSN、SupportedExtensions、ChunkList、Random、RequestedHMACFunctions、SupportedAddrTypes)的复杂解析,InitAck 携带状态 Cookie 与 Hostname 的解析;
- 行为语义:
(IP()/SCTP()).answers(IP()/SCTP()) == True验证请求/应答匹配逻辑;"SCTP in ICMP" 用例验证 ICMP 错误报文(如端口不可达)内嵌 SCTP 头部时的SCTPerror解析与answers匹配(对应 sctp.py 第 291-307 行 的SCTPerror类实现); - 随机性:
SCTPChunkParamRandom连续两次构建生成不同随机数。
运行该测试套件可使用 Scapy 自带的 UTscapy 工具(scapy/tools/UTscapy.py):
$ python3 -m scapy.tools.UTscapy -t test/scapy/layers/sctp.uts结合本文示例与测试用例,你可以快速验证自己对 Scapy SCTP 层行为的理解,并在修改或扩展报文构造逻辑时获得即时反馈。至此,从协议原理、源码结构到内核配置与测试验证,你已掌握使用 Scapy 操作 SCTP 流量的完整链路。
- 网络
- 网络安全
【免费下载链接】scapy
Scapy: the Python-based interactive packet manipulation program & library.
相关推荐
Linux/LoongArch 启动指南:BootLoader 传参协议与 EFI 内核镜像头结构解析
Linux/LoongArch 启动指南:BootLoader 传参协议与 EFI 内核镜像头结构解析 本文基于 Linux 内核源码树中的 Documenta
操作系统内核驱动驱动开发虚拟化嵌入式网络存储新手必看:Qwen2-7B_rai_1.7.1_npu_16K模型文件结构与关键组件解析
新手必看:Qwen2 7B_rai_1.7.1_npu_16K模型文件结构与关键组件解析 想要深入了解Qwen2 7B_rai_1.7.1_npu_16K大语言
终极指南:如何通过KernelSU实现Android网络权限的精细化管控
终极指南:如何通过KernelSU实现Android网络权限的精细化管控 KernelSU作为基于内核的Android root解决方案,不仅提供了强大的roo
操作系统驱动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考