Harden sip-call ownership and capture failure handling
This commit is contained in:
+14
-2
@@ -21,23 +21,35 @@ chmod 600 sip-xx.env
|
||||
## 运行条件
|
||||
|
||||
- 在已有原生 Asterisk 的主机运行;已有 `asterisk.conf`、0600 的 `pjsip.conf`、原生 PJSIP/ARI 模块及私有 `ari-secret`。
|
||||
- 以 Asterisk 配置的所属用户运行(登记测试机为 `rogee`),**不要 `sudo sip-call`**。root 或文件归属不匹配会在创建结果、抓包及改配置前明确拒绝;不自动改归属或放宽权限。
|
||||
- 使用现有本地 ARI 用户 `go-sip-agent` 和已配置的 loopback HTTP 地址;密码只从 `ASTERISK_CONFIG_DIR/ari-secret` 在内存读取,不复制到 ENV 或结果。
|
||||
- 已有静态 `go-sip-udp` UDP transport,绑定 `0.0.0.0:5060`;工具不更改静态 transport,不启动/重启 Asterisk。
|
||||
- 不存在活动通话,且业务调用方、Agent/其他 ARI 应用已停止。工具拒绝接管业务应用;采用独立 `sip-call` ARI 应用及 `siptest-<SIP_ID>` endpoint。
|
||||
- 只支持 IPv4、UDP、IP 鉴权、无需 REGISTER、PCMA(alaw)。其他方式明确拒绝,不猜测配置。
|
||||
- ENV 为 0600 普通文件;结果目录为 0700。所有配置项见 [`sip.env.example`](sip.env.example);不读取 shell 环境覆盖线路,也不执行 `source`。
|
||||
|
||||
## 调试抓包权限
|
||||
|
||||
主程序不提权。Linux 主机安装人员可仅为 tcpdump 设置抓包能力,生产与测试按同样方式准备:
|
||||
|
||||
```sh
|
||||
sudo setcap cap_net_raw,cap_net_admin=eip /usr/bin/tcpdump
|
||||
/usr/sbin/getcap /usr/bin/tcpdump
|
||||
```
|
||||
|
||||
先确认该路径是主机实际安装的 tcpdump;不对 `sip-call`、tshark 或整个目录设置能力。普通用户仍使用前述不带 sudo 的 `-D` 命令。权限不足时不拨号、不回退到无抓包模式,输出“已请求,但未启动”;具体启动错误保留在本次私有 `tcpdump.log`。
|
||||
|
||||
## 自动配置与退出
|
||||
|
||||
取得该 Asterisk 配置目录的独占测试锁,确认空闲后保存原 `pjsip.conf` 到本次私有目录的 `pjsip.conf.before`。临时增加独立 include/endpoint/AOR,使用原生 `module reload res_pjsip.so` 并核对明确的成功响应,不依赖可选的 `pjsip reload` 别名,不把 CLI 退出码 0 当作加载成功;随后核对实际服务地址、主叫、codec、transport 和 context。通过才执行一次原生 ARI Dial。
|
||||
|
||||
收到真正的 `Up` 和 `StasisStart` 才记录接通;按 `HOLD_SECONDS` 保持后挂断。观察到通道结束或挂断后的 ARI 404 才记录结束确认。正常结束后恢复原 `pjsip.conf` 原字节、删除本次专用配置、reload 并确认 endpoint 已移除,不改 `go-sip-managed.conf` 或业务 SIP 加载代次。
|
||||
收到真正的 `Up` 和 `StasisStart` 才记录接通;按 `HOLD_SECONDS` 保持后挂断。观察到通道结束或挂断后的 ARI 404 才记录结束确认。正常结束后恢复原 `pjsip.conf` 原字节及原所属用户/组、保持 `0600`,删除本次专用配置、reload 并确认 endpoint 已移除,不改 `go-sip-managed.conf` 或业务 SIP 加载代次。临时 include 同样使用原配置的所属用户/组;恢复前后及 reload 后均核对配置归属和权限,期间发生变化则明确报错并保留恢复资料,不覆盖变化后的文件。
|
||||
|
||||
旧 `sip-call-managed.conf`/include、并发配置修改或未知通道状态均报错。无法确认结束时保留测试配置和原配置副本供人工排查,**不要直接重跑或自行清理**。恢复、抓包停止或证据解析失败都保留错误并以非零退出,不报告“全部正常”。
|
||||
|
||||
## 输出与证据
|
||||
|
||||
每次创建独立私有目录,成功或失败均有 `result.json`:线路、服务地址、主叫、原始/线路被叫、SIP Call-ID、拨号前绑定时间、接通时间、结束确认时间、最终状态及失败原因。
|
||||
归属与输入检查通过后创建独立私有目录,此后的成功或失败均有 `result.json`(检查未通过时不创建结果):线路、服务地址、主叫、原始/线路被叫、SIP Call-ID、拨号前绑定时间、接通时间、结束确认时间、最终状态及失败原因。
|
||||
|
||||
开启调试后另有:
|
||||
|
||||
|
||||
@@ -66,7 +66,11 @@ func printReport(out io.Writer, r *sipcall.Report) error {
|
||||
_, e := fmt.Fprintf(out, "抓包:%s\nSHA-256:%s\nSIP 时间线:%s\n原始 INVITE 最终响应:%s\n媒体观察:%s\n", r.Evidence.PCAP, r.Evidence.PCAPSHA256, r.Evidence.SIPTimeline, code, r.Evidence.RTPStatus)
|
||||
err = errors.Join(err, e)
|
||||
} else {
|
||||
_, e := fmt.Fprintln(out, "抓包:未启用(使用 --debug/-D 开启);没有抓包链路证据或媒体验证。")
|
||||
message := "抓包:未启用(使用 --debug/-D 开启);没有抓包链路证据或媒体验证。"
|
||||
if r.Debug {
|
||||
message = "抓包:已请求,但未启动;没有抓包链路证据或媒体验证。"
|
||||
}
|
||||
_, e := fmt.Fprintln(out, message)
|
||||
err = errors.Join(err, e)
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -77,6 +77,17 @@ func TestCallCLIRejectsMissingOrMalformedInputsBeforeHostAccess(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebugStartupFailureDoesNotClaimCaptureDisabled(t *testing.T) {
|
||||
out := &bytes.Buffer{}
|
||||
err := printReport(out, &sipcall.Report{Status: "not_dialed", Directory: "/tmp/test", Debug: true, Failure: "tcpdump startup failed"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(out.String(), "抓包:未启用") || !strings.Contains(out.String(), "抓包:已请求,但未启动") {
|
||||
t.Fatalf("debug failure was reported as disabled: %s", out.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallCLIDoesNotHideRunFailures(t *testing.T) {
|
||||
errExpected := errors.New("unconfirmed call")
|
||||
out := &bytes.Buffer{}
|
||||
|
||||
Reference in New Issue
Block a user