简介:面向网络协议分析与VoIP运维人员的轻量级抓包工具源码包,基于libpcap实现SIP信令嗅探,可监听指定网卡并将SIP/RTP会话按会话粒度分别落盘为独立命名的.pcap文件,便于后续用tcpdump、Wireshark等工具逐条回放分析,适合排查呼叫建立失败、媒体流异常等场景,也适合作为学习libpcap编程与SIP协议解析的参考实现。压缩包共16个文件,约15KB,以cpp与h源码为核心,辅以Makefile构建脚本、Red Hat与Debian的init及sysconfig启动配置、Solaris说明、spec打包描述、ChangeLog与LICENSE等,覆盖编译、安装与多平台部署所需材料。已有300人学习下载。读者可从中获得完整的会话分文件存储思路、抓包过滤与文件命名策略,以及跨发行版的服务化配置范例,便于二次开发或直接用于现网SIP流量取证。
1. 抓包文件里翻不出 SIP 信令?先把这个 0.2 版的小工具跑起来
排查一通电话打不通,最难受的不是没日志,而是日志全在——几百兆的 pcap 里混着 RTP、DNS、ARP,你用通用抓包工具打开,过滤框里敲sip,结果只筛出零星几条 REGISTER,INVITE 和它后面的响应散落在不同时间点,靠肉眼一条条对 Call-ID。pcapsipdump 就是冲着这个场景来的:它读一个 pcap,按 SIP 会话把属于同一通呼叫的报文抽出来,一通电话一个文件,信令和媒体各归各位。这个 0.2 版的 tar.gz 包不大,编译依赖也少,适合放在跳板机或测试机上随手用。它面向的是要复现呼叫故障、做信令比对、给第三方交抓包证据的从业者,不是给只想看个大概的人。下面按「它怎么切会话 → 怎么编怎么跑 → 参数怎么调 → 哪里会翻车」的顺序拆。
2. 会话切分的原理与编译落地:它凭什么把一通电话认成一条流
2.1 按 Call-ID 归并,而不是按五元组
通用抓包工具的会话重组大多基于五元组(源 IP、目的 IP、源端口、目的端口、协议),对 SIP 来说这套逻辑会失灵:一通呼叫里 INVITE 走 UDP 5060,后续可能切到 TCP,媒体又跑到高位端口,中间还夹着代理转发导致 IP 变化。pcapsipdump 换了个锚点——SIP 头里的Call-ID。同一通呼叫的所有请求和响应共享同一个 Call-ID,工具解析每个 SIP 报文头部,取出 Call-ID 作为分组键,把命中同一键的报文写进同一个输出文件。
这个设计带来两个直接后果,用之前必须心里有数。第一,它只认能解析出 Call-ID 的报文,畸形包、分片包、加密的 SIP over TLS 它处理不了,遇到就跳过或归到未分类。第二,它默认只处理 SIP 端口上的流量,端口不是 5060 的部署(很多内网把信令挪到 15060 之类)需要显式指定端口,否则一条都抓不到,这是新手最常见的「跑起来没输出」原因。
2.2 编译:三个依赖,缺一个就卡在 configure
包是标准 autotools 结构,解压后先看configure在不在。常见做法是先补齐 libpcap 开发包,再补 libssl(部分版本用它做摘要校验),最后是编译工具链。以常见的 Linux 发行版为例:
# 解压并进入源码目录 tar -xzf pcapsipdump-0.2.tar.gz cd pcapsipdump-0.2 # 依赖:libpcap 开发头文件是硬依赖,缺了 configure 直接报错 # Debian/Ubuntu 系 sudo apt-get install -y libpcap-dev build-essential # 生成构建脚本并编译 ./configure --prefix=/usr/local make sudo make install--prefix决定安装路径,装到/usr/local后二进制在/usr/local/bin/pcapsipdump,普通用户 PATH 里通常已包含。make阶段如果报pcap.h: No such file or directory,就是 libpcap 开发包没装,装运行时库不够,必须是-dev或-devel包。编译通过后先跑pcapsipdump -h确认能起来,别急着上真实抓包。
2.3 第一次运行:从离线 pcap 到按呼叫拆分的目录
最稳的验证方式是拿一个已知内容的离线 pcap 跑,而不是直接抓活流量。假设手里有个capture.pcap,里面混着三通呼叫:
# -r 读离线文件,-d 指定输出目录,目录不存在会报错,先建好 mkdir -p ./sip_out pcapsipdump -r capture.pcap -d ./sip_out # 跑完看结果:每通呼叫一个子目录或文件,命名里带 Call-ID 片段 ls -l ./sip_out输出结构在不同版本间略有差异,0.2 版常见做法是每通呼叫生成一个以 Call-ID 或序号命名的文件,里面按时间顺序排列该呼叫的全部 SIP 报文。跑完先别急着信结果,用ls数一下文件数,和你预估的呼叫数对一对;对不上就说明有报文没被归并,多半是端口或解析问题,回到 2.1 的两个后果里找原因。这一步是整个流程的验收点,跳过它后面全是盲调。
3. 参数调优与输出解读:端口、过滤器和文件命名怎么定
3.1 端口与 BPF 过滤:先缩小范围再谈归并
pcapsipdump 底层用 libpcap,支持传入 BPF 过滤表达式。默认它盯着 5060,但真实环境里信令端口五花八门。常见做法是显式把端口写进过滤条件,既覆盖非标端口,又顺手把无关流量挡在外面:
# -f 传 BPF 过滤表达式,这里同时覆盖 5060 和 15060 两个信令端口 pcapsipdump -r capture.pcap -d ./sip_out -f "udp port 5060 or udp port 15060 or tcp port 5060" # 只想看某两个 IP 之间的呼叫,把地址也塞进过滤器,减少误归并 pcapsipdump -r capture.pcap -d ./sip_out -f "host 10.0.0.5 and host 10.0.0.9 and port 5060"-f的表达式语法就是标准 BPF,和通用抓包工具一致,会写tcp port 5060 and host x.x.x.x就能用。这里有个参数边界要讲清:过滤器只决定「哪些包进入解析流程」,不决定「怎么归并」,归并仍然靠 Call-ID。所以过滤器写太宽不会导致归并错乱,只会让解析变慢、输出目录里多出无关文件;写太窄则会漏掉呼叫的后续报文,导致一个呼叫被拆成两半。我一般先宽后窄,先全端口跑一遍看总量,再收窄定位。
3.2 输出文件命名与后续处理
输出文件命名直接决定你后面能不能批量处理。0.2 版的命名通常包含 Call-ID 或时间戳片段,具体格式以-h输出为准,不同构建可能不同。拿到文件后,常见的下游动作是转成文本做比对,或者喂给信令分析工具。转文本这一步用通用抓包工具的-r读单文件、-V展开详情即可:
# 把某通呼叫的输出文件转成可读文本,重点看 INVITE 到 200 OK 的时序 tcpdump -r ./sip_out/<某个呼叫文件> -nn -v # 批量统计每个呼叫文件里的报文数,快速找出异常短或异常长的呼叫 for f in ./sip_out/*; do echo "$(wc -l < "$f") $f"; done | sort -n第二段脚本是排查利器:正常一通呼叫的报文数在一个区间内,明显偏短的往往是呼叫建立到一半就断了(比如只有 INVITE 没有 200 OK),明显偏长的可能是重传风暴。用报文数排序,异常呼叫会浮到两端,比逐个打开文件快得多。参数上-nn关掉域名和端口名解析,避免 DNS 反查拖慢速度,离线分析时这个习惯能省不少时间。
3.3 活流量抓取与资源占用
除了-r读文件,它也支持从网卡直接抓。活抓时要注意磁盘和内存:一通呼叫一个文件,高并发场景下文件数会爆炸,目录里几万个文件时ls都会卡。常见做法是限定抓取时长或报文数,或者先落一个大 pcap 再离线拆分:
# 从指定网卡活抓,配合 timeout 限定运行时长,避免无限增长 timeout 300 pcapsipdump -i eth0 -d ./sip_live -f "port 5060" # 更稳的做法:先用通用工具落盘,再离线拆分,可控性更好 tcpdump -i eth0 -w big.pcap -s 0 "port 5060" -G 600 -W 6 pcapsipdump -r big.pcap -d ./sip_out-s 0抓完整报文长度,别截断,SIP 头被截了 Call-ID 就解析不出来。-G 600 -W 6是通用抓包工具的轮转参数,每 600 秒切一个文件、最多保留 6 个,防止磁盘写满。活抓直接上 pcapsipdump 的优点是省一步,缺点是出问题时不好回溯原始流量,所以我更倾向先落盘再拆,原始 pcap 留着当后悔药。
4. 避坑与排查:五条血泪经验
4.1 跑完输出目录是空的
现象:命令正常退出,./sip_out里什么都没有。原因:九成是端口不对,信令不在 5060,默认过滤器把包全挡了;剩下一成是 pcap 本身不含 SIP,或者报文被截断导致头部解析失败。解决:先用通用抓包工具tcpdump -r capture.pcap -nn port 5060确认里面到底有没有 SIP,有的话换端口重跑,把-f写成port 5060 or port 你的端口。
4.2 一通呼叫被拆成好几个文件
现象:明明是一通电话,输出里出现多个文件,Call-ID 相同却分散。原因:过滤器太窄,中途切换了传输方式(UDP 转 TCP)或端口,后半段报文没进解析流程;也可能是中间有代理改写了 Call-ID。解决:放宽-f覆盖所有可能端口和协议,udp or tcp port 5060起步;确认代理是否改写 Call-ID,改写了就得按代理侧的口径重新归并,工具本身无能为力。
4.3 编译报错找不到 pcap 头文件
现象:./configure或make阶段报pcap.h缺失。原因:只装了 libpcap 运行时库,没装开发头文件。解决:装libpcap-dev(Debian 系)或libpcap-devel(RHEL 系),装完重新./configure && make。别去手动改 Makefile 里的 include 路径,那是治标。
4.4 大文件跑到一半内存飙升
现象:处理几百兆以上的 pcap 时进程内存持续上涨。原因:工具需要在内存里维护 Call-ID 到输出文件的映射,呼叫数极多时映射表膨胀。解决:先用 BPF 过滤器把范围缩到目标 IP 或时间段,分片处理;或者用通用抓包工具的-c限制单次处理报文数,切成多个小 pcap 分批跑。
4.5 输出文件打不开或内容乱码
现象:tcpdump -r读输出文件报格式错误。原因:输出文件不是标准 pcap 格式,或者写入过程中进程被中断导致文件不完整。解决:确认工具版本对输出格式的约定,用file命令看文件类型;中断导致的半截文件直接丢弃重跑,别试图修复,重跑成本比修低。
5. 进阶:把拆分结果接进自动化比对流程
单次拆分只是起点,真正省时间的是把「拆分 → 提取关键信令 → 比对」串成一条流水线。我的习惯是拆完之后,对每个呼叫文件提取 INVITE 的 From/To 头和最终响应码,生成一张呼叫摘要表,异常呼叫一眼可见。下面这段脚本用通用抓包工具的输出做二次解析,不依赖额外库:
#!/bin/bash # 遍历拆分结果,为每个呼叫文件提取首条 INVITE 的方法行和最终响应码 for f in ./sip_out/*; do # 取第一条 SIP 请求行,通常是 INVITE 或 REGISTER first=$(tcpdump -r "$f" -nn -A 2>/dev/null | grep -m1 -E '^(INVITE|REGISTER|OPTIONS) ') # 取最后一条 SIP 响应行里的状态码 last=$(tcpdump -r "$f" -nn -A 2>/dev/null | grep -E '^SIP/2.0 [0-9]{3}' | tail -1) echo "$(basename "$f") | ${first:-NO_REQ} | ${last:-NO_RESP}" done > call_summary.txt逻辑说明:-A让通用抓包工具以 ASCII 输出报文内容,grep -m1只取第一条请求行避免重复,tail -1取最后一条响应,因为一通呼叫的最终状态由最后一个响应决定。参数上2>/dev/null屏蔽解析告警,避免污染输出。跑完看call_summary.txt,NO_RESP的行就是没有收到任何响应的呼叫,NO_REQ的行说明文件里只有响应没有请求,多半是抓包起点在呼叫中途——这两类直接进排查队列,不用再逐个打开文件。
再进一步,可以把摘要表和历史基线做 diff。同一套测试环境反复跑,正常呼叫的响应码分布是稳定的,某次跑出来 486、503 突然变多,就是环境或对端出了问题。这一步不需要复杂工具,sort | uniq -c统计响应码分布就够用。要注意的是,这套流程的前提是拆分结果干净,如果第 4 章那些坑没排掉,摘要表本身就是错的,比对毫无意义。所以每次上自动化之前,我都会先抽三五个文件人工核对一遍拆分是否正确,确认无误再批量跑。从那以后我每次处理信令抓包,都强制先做「数文件数对呼叫数」这一步验收,再谈后面的分析。希望帮到你。
本文还有配套的精品资源,点击获取