这篇整理 FreeSWITCH 线上权限相关配置。

内容基于一台 Debian 11 服务器上的 /usr/local/freeswitch/etc/freeswitch 配置整理,重点看:

  1. autoload_configs/acl.conf.xml
  2. autoload_configs/event_socket.conf.xml
  3. sip_profiles/internal.xml
  4. sip_profiles/external.xml
  5. vars.xml

FreeSWITCH 权限配置最容易出问题的地方不是 XML 难写,而是边界不清楚:

  1. 哪些 IP 可以连 ESL?
  2. 哪些 IP 可以走 SIP profile?
  3. 哪些呼叫允许免鉴权?
  4. 内外网 profile 是否混用?
  5. 默认密码是否还在用?

ACL 配置

ACL 文件路径:

1
/usr/local/freeswitch/etc/freeswitch/autoload_configs/acl.conf.xml

线上配置里保留了 FreeSWITCH 默认说明,并增加了两个关键 list:domainsesl_only

1
2
3
4
5
6
7
8
9
10
11
12
<network-lists>
<list name="domains" default="deny">
<node type="allow" domain="$${domain}"/>
<node type="allow" cidr="127.0.0.1/32"/>
<node type="allow" cidr="192.168.2.184/32"/>
</list>

<list name="esl_only" default="deny">
<node type="allow" cidr="192.168.2.0/24"/>
<node type="allow" cidr="127.0.0.1/32"/>
</list>
</network-lists>

domains 用于 SIP profile 的入站访问控制。domain="$${domain}" 会根据 directory 里的
domain 信息构建 ACL,额外加入 127.0.0.1/32 和本机内网 IP,是为了允许本机和可信内网地址
访问。

esl_only 是专门给 ESL 用的 ACL。这里允许:

1
2
127.0.0.1/32
192.168.2.0/24

这个拆分很重要。SIP 能访问的范围和 ESL 能访问的范围不应该混在一起。ESL 是控制面接口,
可以 originate、hangup、uuid_transfer、监听事件,权限比普通 SIP 注册高很多。

ESL 权限

ESL inbound 配置路径:

1
/usr/local/freeswitch/etc/freeswitch/autoload_configs/event_socket.conf.xml

线上关键配置:

1
2
3
4
5
6
7
8
9
<configuration name="event_socket.conf" description="Socket Client">
<settings>
<param name="nat-map" value="false"/>
<param name="listen-ip" value="::"/>
<param name="listen-port" value="8021"/>
<param name="password" value="请改成强密码"/>
<param name="apply-inbound-acl" value="esl_only"/>
</settings>
</configuration>

listen-ip="::" 表示监听 IPv6 unspecified 地址,在很多系统上也可能同时覆盖 IPv4。
所以真正的安全边界不能只依赖监听地址,必须配合:

1
<param name="apply-inbound-acl" value="esl_only"/>

这样只有 esl_only 里允许的 IP 能连 8021。

线上建议:

  1. ESL 8021 不开放公网。
  2. ESL 只允许业务服务器、运维跳板机、本机访问。
  3. password 不使用默认值。
  4. 防火墙也要做同样的来源限制,ACL 不是唯一防线。
  5. 如果只允许本机访问,可以把 listen-ip 改成 127.0.0.1::1,并同步检查业务服务连接方式。

验证:

1
2
ss -lntup | grep 8021
fs_cli -H 127.0.0.1 -P 8021 -p 'ESL密码'

从未授权机器连接应该失败。

vars.xml 基础密码与地址

文件路径:

1
/usr/local/freeswitch/etc/freeswitch/vars.xml

关键项:

1
2
3
4
5
<X-PRE-PROCESS cmd="set" data="default_password=请改成强密码"/>
<X-PRE-PROCESS cmd="set" data="domain=$${local_ip_v4}"/>
<X-PRE-PROCESS cmd="set" data="bind_server_ip=$${domain}"/>
<X-PRE-PROCESS cmd="stun-set" data="external_rtp_ip=$${domain}"/>
<X-PRE-PROCESS cmd="stun-set" data="external_sip_ip=$${domain}"/>

default_password 会影响默认 directory 用户。测试环境常常为了方便统一密码,但线上不建议
所有分机共用一个密码。

domain=$${local_ip_v4} 表示默认 domain 使用本机 IPv4。内网测试可以这样配;如果线上需要
域名注册、多网卡、NAT 或公网线路,建议明确规划:

  1. SIP 终端注册用哪个 domain。
  2. SIP profile 监听哪个 IP。
  3. RTP 对外公布哪个 IP。
  4. 是否需要 STUN。

不要在多网卡服务器上只靠默认探测结果。

internal profile

文件路径:

1
/usr/local/freeswitch/etc/freeswitch/sip_profiles/internal.xml

线上关键配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<param name="context" value="public"/>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="apply-inbound-acl" value="domains"/>
<param name="local-network-acl" value="localnet.auto"/>
<param name="manage-presence" value="true"/>
<param name="accept-blind-auth" value="true"/>
<param name="nonce-ttl" value="60"/>
<param name="auth-calls" value="$${internal_auth_calls}"/>
<param name="inbound-reg-force-matching-username" value="true"/>
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="ext-sip-ip" value="$${external_sip_ip}"/>
<param name="force-register-domain" value="$${domain}"/>
<param name="force-subscription-domain" value="$${domain}"/>

这里最需要关注的是:

1
<param name="apply-inbound-acl" value="domains"/>

它表示 internal profile 的入站请求要经过 domains 这个 ACL。也就是说,不是任意来源都可以
直接打到 internal profile。

另一个高风险项是:

1
<param name="accept-blind-auth" value="true"/>

这个参数用于允许某些网关或上游设备以较宽松的方式通过认证。它不是所有环境都应该打开。
如果上游线路是固定 IP 的 SIP trunk,可以配合 ACL 限制来源;如果是公网软电话注册场景,
就要谨慎评估。

auth-calls 决定是否要求呼叫鉴权。internal profile 如果对公网可达,必须非常谨慎。
常见建议是:

  1. 终端注册走 internal,开启鉴权。
  2. SIP trunk 呼入走 external 或单独 profile,通过来源 IP 白名单控制。
  3. 不要把 accept-blind-auth=true 和大范围 ACL 放在一起。

数据库连接也在 profile 中配置:

1
2
<param name="odbc-dsn"
value="pgsql://hostaddr=数据库IP dbname=freeswitch user=用户名 password=密码 options='-c statement_timeout=3000' connect_timeout=5 keepalives=1 keepalives_idle=30 keepalives_interval=5 keepalives_count=3" />

这个配置会影响 SIP profile 相关数据,例如注册、恢复、状态存储等。线上建议加超时和 keepalive,
避免数据库短暂异常时把 SIP 处理拖死。

external profile

文件路径:

1
/usr/local/freeswitch/etc/freeswitch/sip_profiles/external.xml

线上关键配置:

1
2
3
4
5
6
7
8
9
<param name="context" value="public"/>
<param name="local-network-acl" value="localnet.auto"/>
<param name="manage-presence" value="false"/>
<param name="nonce-ttl" value="60"/>
<param name="auth-calls" value="false"/>
<param name="rtp-ip" value="$${local_ip_v4}"/>
<param name="sip-ip" value="$${local_ip_v4}"/>
<param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
<param name="ext-sip-ip" value="$${external_sip_ip}"/>

external profile 通常用于对接外部 SIP trunk。这里 auth-calls=false 比较常见,因为运营商
或者上游网关可能不走分机密码认证,而是通过固定 IP 和网关配置鉴权。

但这也意味着必须用其他方式限制来源:

  1. 防火墙只允许运营商或上游网关 IP 访问 SIP 端口。
  2. profile 层增加 ACL。
  3. dialplan 层限制可呼叫的号码范围。
  4. 出局路由不要让任意呼入直接转外呼。

external profile 不建议直接给普通软电话注册使用。如果确实要支持公网注册,建议单独做一个
profile,独立端口、独立 ACL、独立鉴权策略。

core db 配置

路径:

1
/usr/local/freeswitch/etc/freeswitch/autoload_configs/switch.conf.xml

线上使用 PostgreSQL core db:

1
2
<param name="core-db-dsn"
value="pgsql://hostaddr=数据库IP dbname=freeswitch user=用户名 password=密码 options='-c statement_timeout=3000' connect_timeout=5 keepalives=1 keepalives_idle=30 keepalives_interval=5 keepalives_count=3" />

这里同样建议:

  1. 独立数据库账号。
  2. 最小权限。
  3. 明确连接超时。
  4. 明确查询超时。
  5. 开启 keepalive。

数据库权限不是 SIP 权限,但数据库卡住会影响 FreeSWITCH 的稳定性,所以线上配置要把超时写清楚。

修改后的加载方式

修改 XML 后先检查格式。至少执行:

1
fs_cli -x reloadxml

如果改了 SIP profile 的监听 IP、ACL、NAT、数据库连接,建议重启对应 profile:

1
2
fs_cli -x "sofia profile internal restart"
fs_cli -x "sofia profile external restart"

如果只改了 ESL 的 ACL 或密码,最稳妥是重启 mod_event_socket 或安排 FreeSWITCH 进程重启。
线上已有通话时不要随便重启主进程。

检查:

1
2
3
fs_cli -x "sofia status"
fs_cli -x "sofia status profile internal"
fs_cli -x "sofia status profile external"

日志:

1
tail -f -n 500 /usr/local/freeswitch/var/log/freeswitch/freeswitch.log

线上推荐配置原则

1. ESL 是控制面,只走内网

ESL 8021 能控制通话,不要暴露公网。

推荐:

1
<param name="apply-inbound-acl" value="esl_only"/>

esl_only 里只放:

1
2
3
127.0.0.1/32
业务服务器IP/32
跳板机IP/32

不要为了方便写成 0.0.0.0/0

2. SIP 分 internal 和 external

internal 负责分机注册和内网业务,external 负责外部线路。不要把所有入口都塞进一个 profile。

internal 建议:

  1. 开启鉴权。
  2. 限制来源 ACL。
  3. 使用强密码。
  4. 只开放给可信终端或内网。

external 建议:

  1. 只允许 SIP trunk 来源 IP。
  2. 不允许任意号码转外呼。
  3. dialplan 做号码规则限制。
  4. 运营商 IP 变化时同步更新防火墙和 ACL。

3. 默认密码必须改

vars.xml 里的 default_password 不要保留默认值。更进一步,线上应该避免所有分机共用一个
默认密码。

4. ACL 和防火墙同时做

ACL 是 FreeSWITCH 应用层限制,防火墙是系统层限制。线上两层都要做。

常见组合:

1
2
3
4
5
ESL 8021     只允许业务服务器和跳板机
SIP 5060 只允许 SIP trunk、可信终端网段
SIP 5080 只允许外部线路来源
RTP 端口段 按运营商或业务实际情况开放
PostgreSQL 只允许 FreeSWITCH 服务器访问

5. 配置变更先备份

变更前先备份:

1
2
cp -r /usr/local/freeswitch/etc/freeswitch \
/usr/local/freeswitch/etc/freeswitch.bak_$(date +%F_%H%M%S)

配置出错时,FreeSWITCH 可能还能运行,但新加载的 profile、dialplan、ACL 不生效。
备份比事后回忆改了哪里可靠。

排查清单

ESL 连不上:

1
2
3
ss -lntup | grep 8021
grep -n "apply-inbound-acl" /usr/local/freeswitch/etc/freeswitch/autoload_configs/event_socket.conf.xml
grep -n "esl_only" /usr/local/freeswitch/etc/freeswitch/autoload_configs/acl.conf.xml

SIP 注册失败:

1
2
3
fs_cli -x "sofia status profile internal"
fs_cli -x "sofia status"
tail -f /usr/local/freeswitch/var/log/freeswitch/freeswitch.log

SIP trunk 呼入失败:

1
2
fs_cli -x "sofia status profile external"
fs_cli -x "sofia global siptrace on"

数据库异常:

1
2
3
grep -n "core-db-dsn" /usr/local/freeswitch/etc/freeswitch/autoload_configs/switch.conf.xml
grep -n "odbc-dsn" /usr/local/freeswitch/etc/freeswitch/sip_profiles/internal.xml
grep -n "odbc-dsn" /usr/local/freeswitch/etc/freeswitch/sip_profiles/external.xml

总结

FreeSWITCH 线上权限配置可以按一句话理解:

1
ESL 只给业务控制面,SIP 按入口拆 profile,ACL 和防火墙都要收紧,默认密码全部换掉。

安装成功只是第一步。真正上线前,至少要确认:

  1. ESL 8021 不在公网暴露。
  2. internal/external profile 边界明确。
  3. SIP trunk 来源 IP 有白名单。
  4. 分机密码不是默认值。
  5. 数据库连接有超时。
  6. 每次改配置都有备份和回滚路径。