如果 Kamailio 作为代理服务器(SIP Proxy)在转发 SIP 请求时不删除原始的 Via
信息,这确实可能会造成信息泄露。
Via
可能会泄露信息?暴露内部网络信息
Via
头包含了 前一个发送者的 IP 地址、端口和传输方式(UDP/TCP/TLS)。Via
头未被清理,可能会泄露 内部服务器 IP(如私有地址 192.168.x.x)或运营商信息。10.10.10.1
,但 SIP 服务器在 192.168.1.100
,那么 Via
头可能会泄露:Via: SIP/2.0/UDP 192.168.1.100:5060;branch=z9hG4bK12345
这个信息 不应该暴露给外网。攻击者可利用 Via
进行网络拓扑分析
Via
头中的 IP 地址 扫描 SIP 代理的拓扑结构,寻找潜在的攻击点(如未受保护的 SIP 服务器)。SIP 设备可能错误处理额外的 Via
Via
头,从而导致 SIP 处理异常(如 400 Bad Request
、483 Too Many Hops
)。Via
remove_hf("Via")
Kamailio 提供了 remove_hf("Via")
指令,可以在 SIP 代理模式下 移除所有 Via
头并重新生成,防止信息泄露。
在 kamailio.cfg
配置文件中:
request_route {
if (!is_method("ACK")) {
remove_hf("Via"); # 删除所有 Via 头
}
append_hf("Via: SIP/2.0/UDP $si:$sp;branch=z9hG4bK$var(branch)\r\n");
t_relay();
}
解释:
Via
头,防止泄露内部 IP。Via
,只显示 Kamailio 作为代理的 IP($si:$sp
)。topos
模块(推荐)topos
是 Kamailio 提供的 “拓扑隐藏”(Topology Hiding)模块,可以自动删除 Via
头,并在响应时恢复,防止信息泄露。
topos
模块sudo apt install kamailio-topos-modules
kamailio.cfg
启用 topos
loadmodule "topos.so"
request_route {
if (!is_method("ACK")) {
topos_request();
}
t_relay();
}
onreply_route {
topos_reply();
}
解释:
topos_request()
删除 Via
和 Record-Route
,隐藏内部拓扑。topos_reply()
在响应时恢复正确的路由,确保 SIP 消息能正确返回。✅ 不删除 Via
确实会导致信息泄露,特别是在 NAT 或运营商环境中!
✅ 推荐使用 remove_hf("Via")
或 topos
模块来移除 Via
,保护 SIP 代理的内部拓扑信息!
topos
模块后,目的地路由的 Via
头信息当 Kamailio 作为 SIP 代理(Proxy) 并启用了 topos
模块时,它会自动删除原始的 Via
头,并在转发 SIP 请求时仅留下 Kamailio 自己的 Via
。那么,在**目的地路由(最终 SIP 服务器)**收到的请求中,Via
头的情况如下:
topos
,最终目的地收到的 Via
头示例:
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP 192.168.1.100:5060;branch=z9hG4bK111111
Via: SIP/2.0/UDP 10.10.10.1:5060;branch=z9hG4bK222222
Via: SIP/2.0/UDP 222.211.75.75:5060;branch=z9hG4bK333333
这里 Via
头中包含了所有中间代理的 IP(内部网络信息)。
topos
)当 topos_request()
处理后,Kamailio 会:
Via
头(192.168.1.100
、10.10.10.1
、222.211.75.75
)。Via
头。Kamailio 转发后的 SIP 请求
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP 47.100.62.225:5060;branch=z9hG4bKabcdef
这里 Via
只保留了 Kamailio 自己的 IP(47.100.62.225
),不会暴露任何内部 IP!
Via
头最终,目的地路由(222.223.190.118) 只会看到 Kamailio 的 Via
:
INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/UDP 47.100.62.225:5060;branch=z9hG4bKabcdef
✅ 原始 Via
(192.168.1.100、10.10.10.1、222.211.75.75)已被隐藏,保护了 SIP 代理的内部网络结构!
Via
处理当 目的地(222.223.190.118) 发送 200 OK 响应时,它的 Via
头如下:
SIP/2.0 200 OK
Via: SIP/2.0/UDP 47.100.62.225:5060;branch=z9hG4bKabcdef
然后 Kamailio 会使用 topos_reply()
恢复正确的返回路径,但不会暴露目的地的 Via
,所以客户端最终收到的响应仍然不会看到 222.223.190.118 的 Via
。
✅ 目的地路由(最终 SIP 服务器)收到的 Via
头只包含 Kamailio 的 IP,不包含原始的 Via
头,确保了内部网络信息不被泄露!
✅ 响应时 Kamailio 也会正确恢复路径,确保 SIP 消息能够正确返回!
下面是一个完整的 Kamailio 作为 SIP 代理服务器(Proxy) 的 kamailio.cfg
配置,结合 Lua 脚本 进行 呼叫计费,并使用 topos
模块隐藏 Via
信息,确保 SIP 请求的安全性。
topos
模块,隐藏 Via
头/usr/local/kamailio/lua/billing.lua
)-- billing.lua - 计费逻辑(计算通话费用)
local billing = {}
function billing.calculate_fee(duration)
local rate_per_second = 0.05 -- 每秒 0.05 元
local cost = duration * rate_per_second
return cost
end
function billing.log_call(call_id, caller, callee, duration)
local cost = billing.calculate_fee(duration)
local log_str = string.format(
"CALL BILLING - Call-ID: %s, From: %s, To: %s, Duration: %d sec, Cost: %.2f 元",
call_id, caller, callee, duration, cost
)
-- 记录日志
KSR.info(log_str)
end
return billing
kamailio.cfg
配置####### 全局配置 ########
#!KAMAILIO
#!define WITH_LUA
#!define WITH_TOPO
loadmodule "sl.so" # SIP 事务管理
loadmodule "tm.so" # SIP 事务管理
loadmodule "rr.so" # 记录路由
loadmodule "maxfwd.so" # Max-Forwards 处理
loadmodule "siputils.so" # 处理 SIP 头
loadmodule "topos.so" # 隐藏 Via 头
loadmodule "topos_redis.so" # Redis 版本的 topos(推荐)
loadmodule "lua.so" # Lua 脚本支持
modparam("topos", "storage", "redis://127.0.0.1:6379/0") # 存储 SIP 会话信息到 Redis
modparam("lua", "load", "/usr/local/kamailio/lua/billing.lua")
####### SIP 请求路由 ########
request_route {
if (!mf_process_maxfwd(10)) {
sl_send_reply("483", "Too Many Hops");
exit;
}
if (is_method("OPTIONS")) {
sl_send_reply("200", "OK");
exit;
}
# 处理 INVITE
if (is_method("INVITE")) {
record_route();
topos_request(); # 删除原始 Via 信息
route(1);
exit;
}
# 处理 BYE(通话结束)
if (is_method("BYE")) {
handle_bye();
topos_request(); # 确保 Via 头处理
route(1);
exit;
}
route(1);
}
route[1] {
if (!t_relay()) {
sl_reply_error();
}
exit;
}
####### 响应处理 ########
onreply_route {
topos_reply(); # 确保 Via 头处理
}
####### 处理 BYE 进行计费 ########
event_route[tm:local-request] {
if (is_method("BYE")) {
handle_bye();
}
}
####### 计费逻辑(Lua 计费) ########
route[handle_bye] {
xlog("L_INFO", "Handling BYE request for call billing");
# 获取通话时长
if ($Ts - $T_req_time > 0) {
$var(duration) = $Ts - $T_req_time;
} else {
$var(duration) = 0;
}
# 获取通话 ID、主叫和被叫
$var(call_id) = $ci;
$var(caller) = $fU;
$var(callee) = $tU;
# 调用 Lua 计费
$var(lua_result) = lua_runstring(
string.format("require 'billing'.log_call('%s', '%s', '%s', %d)",
$var(call_id), $var(caller), $var(callee), $var(duration))
);
xlog("L_INFO", "Billing logged: " + $var(lua_result));
}
topos
模块
topos_request();
删除 Via
头,防止信息泄露topos_reply();
确保返回路径正确Via
丢失Lua 计费
calculate_fee(duration)
计算通话费用log_call(call_id, caller, callee, duration)
记录计费日志计费触发时机
onreply_route {}
处理 SIP 响应event_route[tm:local-request] {}
监听 BYE
事件并触发 Lua 计费SIP 代理功能
呼叫过程:
EP1 -> Kamailio
发送 INVITE
Kamailio
使用 topos_request()
删除原始 Via
头Kamailio -> 目的地
转发 INVITE
目的地 -> Kamailio
发送 200 OK
Kamailio
使用 topos_reply()
恢复路径 并转发给 EP1
EP1
发送 BYE
Kamailio
调用 Lua
计算通话时长和费用Kamailio
记录计费日志,并转发 BYE
到 目的地
CALL BILLING - Call-ID: c12345abcd, From: 01089672389, To: 13545769997, Duration: 120 sec, Cost: 6.00 元
✅ 隐藏 Via
头,保护代理服务器信息
✅ 使用 Lua 实现通话计费
✅ 支持 topos
,防止 Via
泄露
✅ 支持基本 SIP 代理功能(INVITE、BYE、ACK)
这是因为 Kamailio 的路由逻辑必须在 kamailio.cfg
中定义,Lua 主要是用于 业务逻辑扩展(如计费),而不是完全替代 kamailio.cfg
的 SIP 处理能力。下面详细解释 为什么 kamailio.cfg
仍然需要路由逻辑:
kamailio.cfg
仍然需要路由逻辑?Kamailio 主要用于 SIP 代理、注册和路由控制,其核心逻辑(如 INVITE
处理、路由转发、事务管理等)都是由 kamailio.cfg
配置完成的。Lua 只是一个辅助工具,不能完全代替 Kamailio 处理 SIP 消息。
kamailio.cfg
主要职责解析 SIP 请求
INVITE
、BYE
)Max-Forwards
以防止循环Record-Route
) 以保持通话链路管理 SIP 事务
tm
(事务管理)模块用于 SIP 事务控制sl
(状态回复)模块用于无事务性消息回复控制 SIP 代理逻辑
t_relay()
(SIP 请求转发)onreply_route{}
(SIP 响应处理)topos
隐藏 Via
头kamailio.cfg
Lua 不能直接控制 Kamailio 的 SIP 代理行为,它只是一个扩展工具。例如,Lua 不能执行 t_relay()
这样的 SIP 代理操作,必须在 kamailio.cfg
中完成。
t_relay()
),必须在 kamailio.cfg
内调用。kamailio.cfg
的核心 SIP 处理逻辑(如 record_route()
)。kamailio.cfg
处理 SIP 逻辑可以提升性能。kamailio.cfg
和 Luakamailio.cfg
负责 SIP 代理、转发、事务管理例如:
BYE
请求并调用 Lua 计费不能完全用 Lua 替代 kamailio.cfg
,因为 Lua 不能直接处理 SIP 代理逻辑。
最佳方式是:kamailio.cfg
处理 SIP 代理,Lua 负责计费、日志等业务逻辑。