本文仅讨论FreeSWITCH部署在NAT之后(里面)这种场景,假设私网地址与公网地址有一个确定的映射关系。
这里只涉及mod_sofia(SIP信令及媒体)相关配置,其他模块不在本文讨论之列。

配置

mod_sofia默认提供两个profile,可以理解成是两套配置,最主要的区别是监听端口不一样,其他的区别包括是否启用TLS加密,使用哪个拨号计划等等。这里以internal profile为例。

1、配置预处理变量

FreeSWITCH的惯例是把预处理变量定义在vars.xml文件中,然后再由其他配置文件去引用。这里我们主要关注公网地址以及SIP监听端口。

etc/freeswitch/vars.xml

<include>
  <!-- 注意,X-PRE-PROCESS开头的配置都是预处理配置,有点像是定义全局变量,但是变量的值可以在程序启动时动态获取到 -->
 
  <!-- 这两个变量必须要设置成公网IP,有3种方法配置公网IP: -->
  <!-- 1、配一个固定的公网IP -->
  <X-PRE-PROCESS cmd="set" data="external_rtp_ip=172.21.221.137"/>
  <X-PRE-PROCESS cmd="set" data="external_sip_ip=172.21.221.137"/>
  <!-- 2、通过公网上的stun服务动态获取 -->
  <X-PRE-PROCESS cmd="stun-set" data="external_rtp_ip=stun:stun.freeswitch.org"/>
  <X-PRE-PROCESS cmd="stun-set" data="external_sip_ip=stun:stun.freeswitch.org"/>
  <!-- 3、通过域名解析动态获取 -->
  <X-PRE-PROCESS cmd="set" data="external_rtp_ip=host:host.server.com"/>
  <X-PRE-PROCESS cmd="set" data="external_sip_ip=host:host.server.com"/>
 
  <!-- 配置两个profile所监听的SIP端口: -->
  <!-- Internal SIP Profile -->
  <X-PRE-PROCESS cmd="set" data="internal_auth_calls=true"/>
  <X-PRE-PROCESS cmd="set" data="internal_sip_port=5060"/>
  <X-PRE-PROCESS cmd="set" data="internal_tls_port=5061"/>
  <X-PRE-PROCESS cmd="set" data="internal_ssl_enable=false"/>
  <!-- External SIP Profile -->
  <X-PRE-PROCESS cmd="set" data="external_auth_calls=false"/>
  <X-PRE-PROCESS cmd="set" data="external_sip_port=5080"/>
  <X-PRE-PROCESS cmd="set" data="external_tls_port=5081"/>
  <X-PRE-PROCESS cmd="set" data="external_ssl_enable=false"/>
</include>
2、配置sip profiles

这里才是mod_sofia真正会读取的配置。这里以internal profile为例,external同理。

etc/freeswitch/sip_profiles/internal.xml

  1. 首先配置SIP监听端口,这里引用了vars.xml中定义的全局变量。
    注意,要以$${var}的形式引用全局变量!

    <!-- port to bind to for sip traffic -->
    <param name="sip-port" value="$${internal_sip_port}"/>
  2. 配置用于接收SIP信令与RTP媒体流的IP地址,此处就使用默认配置$${local_ip_v4}
    local_ip_v4是fs_core自动设置的,不要手动改。若机器有多个IP,则为系统第一个返回的IP,详见官方文档

    <!-- ip address to use for rtp, DO NOT USE HOSTNAMES ONLY IP ADDRESSES -->
    <param name="rtp-ip" value="$${local_ip_v4}"/>
    <!-- ip address to bind to, DO NOT USE HOSTNAMES ONLY IP ADDRESSES -->
    <param name="sip-ip" value="$${local_ip_v4}"/>
  3. 配置SIP与SDP的通告地址,当mod_sofia检测到NAT时,会将这些地址填在SIP header和SDP消息中。

    <!-- 检测到NAT时,SDP的媒体地址会填这个 -->
    <param name="ext-rtp-ip" value="$${external_rtp_ip}"/>
    <!-- 这个地址会出现在Contact等header中 -->
    <param name="ext-sip-ip" value="$${external_sip_ip}"/>
  4. NAT检测。如果配置了ext-sip-ip,mod_sofia会检查remote_sip_ip是否命中loopback.auto和local-network-acl这两个ACL,若命中则SDP的媒体地址填rtp-ip,否则SDP的媒体地址填ext-rtp-ip。
    此处代码详见switch_core_media_choose_port()

    <!--
      为了简单起见,直接把这里改成none。
      这样只要SIP报文的远端IP不命中loopback.auto(127.0.0.x),
      它就会认为检测到NAT,从而在SDP中填ext-rtp-ip。
    -->
    <param name="local-network-acl" value="none"/>
3、配置媒体端口范围

有些NAT或防火墙只能允许一个范围内的端口,这就需要调整FreeSWITCH接收RTP媒体流所用的端口范围。
注意:FreeSWITCH使用偶数端口接收RTP流,使用奇数端口收发RTCP消息。假如需要承载50路通话,则至少要映射100个端口!

etc/freeswitch/autoload_configs/switch.conf.xml

<configuration name="switch.conf" description="Core Configuration">
  <settings>
    <!-- RTP port range -->
    <param name="rtp-start-port" value="40000"/>
    <param name="rtp-end-port" value="40009"/>
  </settings>
</configuration>

验证

人为改一下ext-rtp-ipext-sip-ip,观察它们的作用:

此时有一个到达internal profile的呼叫,从FreeSWITCH回复的200 OK中可以看到,Contact header中填的是ext-sip-ip,而SDP部分填的是ext-rtp-ip

问题

  1. 私网端口号与公网端口号不一样怎么办?比如:私网:5060 <==> 公网:8060
    恐怕只能修改代码了。

展望
1 声望0 粉丝