Freeswitch在NAT环境下ext-rtp-ip和ext-sip-ip失效/不生效的问题

Freeswitch在NAT环境下ext-rtp-ip不生效的问题最终版

  • 环境描述
  • 问题描述
    • 问题现象
    • 问题定位
    • 问题解决
      • 第一次尝试
      • 第二次尝试
      • 第三次尝试
        • switch_check_network_list_ip方法解析
        • 第三个参数
  • 总结
    • 适用场景
    • 解决方案

环境描述

在生产环境下我需要使用Freeswitch作为SIP的网关来与第三方对接,具体的网络环境如下

第三方SIP
Internet
NAT
我的FreeSwitch

此处环境中NAT为防火墙设备。假设设备及服务器的IP信息如下
第三方SIP的公网IP:1.1.1.1
NAT防火墙的公网IP: 2.2.2.2
我的Freeswitch的局域网IP:192.168.1.2,SIP端口为5060,UDP端口为30000~30020
NAT防火墙开启了端口转发,5060端口和30000~30020端口到192.168.1.2的映射转发。

freeswitch 的启动命令为 ./freeswitch -nonat -nc

问题描述

问题现象

与点三方的SIP对接,SIP协商INVITE,180,183,200,ACK均没有问题,但是SIP接通后对方能听到我说话,我听不到对方说话(所谓的单通)

问题定位

一般这种问题不用看肯定是SDP协商的问题,由于又是NAT环境肯定是穿透问题。于是直接开始查看INVITED与200中的SDP信息。内容如下图(IP经过处理)
对方发送的INVITED的SDP内容

   v=0
   o=SoftSWITCH 1631177472 1631177472 IN IP4 1.1.1.1
   s=SoftSWITCH
   c=IN IP4 1.1.1.1
   t=0 0
   m=audio 16968 RTP/AVP 8 0 18 101 105 104
   a=rtpmap:8 PCMA/8000
   a=rtpmap:0 PCMU/8000
   a=rtpmap:18 G729/8000
   a=rtpmap:105 AMR/8000/1
   a=rtpmap:104 AMR/8000/1
   a=rtpmap:101 telephone-event/16000
   a=fmtp:18 annexb=no
   a=fmtp:105 mode-change-capability=2;max-red=0
   a=fmtp:104 octet-align=1;mode-change-capability=2;max-red=0
   a=fmtp:101 0-15
   a=ptime:20
   a=maxptime:240
   a=sendrecv

可以看到对方发来的SDP信息使用的就是第三方SIP所在的公网ip地址暨1.1.1.1
而我的Freeswitch的200,OK回复内容呢如下:

   v=0
   o=Freeswitch 1631144526 1631144527 IN IP4 192.168.1.2
   s=Freeswitch
   c=IN IP4 192.168.1.2
   t=0 0
   m=audio 33004 RTP/AVP 8 96
   a=rtpmap:8 PCMA/8000
   a=rtpmap:96 telephone-event/8000
   a=fmtp:96 0-16
   a=ptime:20

可以看到我的Freeswitch回复的200消息中的SDP回传的竟然是 局域网IP暨192.168.1.2。那么显而易见三方的SIP接收到协商的IP和端口号后会往这个端口发送数据,他们肯定是没办法使用这个IP发送到我的Freeswitch上的,所以问题出现在这个IP上。

问题解决

第一次尝试

由于之前遇到过此类的问题所知道有一个参数叫做 ext-rtp-ip配置在sip_profile中,所以打开sip_profile/external.xml开始进行查验,得到的结果如下

<param name="ext-rtp-ip" value="2.2.2.2"/>
<param name="ext-sip-ip" value="2.2.2.2"/>

这。。。。。我已经修改了啊为什么~~~~~~~~~~·然后开始了我的折腾之旅

第二次尝试

这是开始没了头绪只能在百度和Google之间疯狂搜索,然后也把Freeswitch的Confluence翻了一遍,在过程中找到的大部分方法如下:

  • 修改profile的 disable-rtp-auto-adjust 参数
  • 修改profile的 local-network-acl 为 RFC918.auto或者其他值
  • 修改profile的 aggressive-nat-detection 参数
  • 修改profile的 ext-rtp-ip为 auto:ip

  • 甚至官方给的建议都是如下原文链接,只需要修改profile的ext-rtp-ip参数
    Freeswitch在NAT环境下ext-rtp-ip和ext-sip-ip失效/不生效的问题_第1张图片

经过验证以上方法都没解决我的问题

第三次尝试

在此首先感谢一位老哥提供的思路原文链接,但是根据老哥的配置去修改也没有成功。于是深入研究了下Freeswitch的相关源码,关键方法如下
Freeswitch在NAT环境下ext-rtp-ip和ext-sip-ip失效/不生效的问题_第2张图片
就是这个方法,如果这个方法返回的是true那么就会使用ext-rtp-ip的配置如果是false就会使用局域网的IP。然后我们逐个剖析其中的方法

  • 第一个参数 smh->mparams->extsipip经过跟踪,这个参数就是判断对应的profile是否配置了ext-rtp-ip这个参数,从我的配置文件和查看到的状态来看我的这个配置肯定是读取成功的
  • 第二个与第三个 使用了同一个方法 switch_check_network_list_ip,经过单步调试我发现我的环境在第一个 switch_check_network_list_ip(network_ip,“loopback.auto”)中返回了true从而导致整个方法返回了False,配置的ext-rtp-ip没有生效。
    那么我们就开始看一下这个方法到底干了什么吧

switch_check_network_list_ip方法解析

这个方法有两个参数,分别代表如下含义

  • 第一个参数: network_ip 是对端传递的sdp中的remote_ip 我的这个对接环境下也就是1.1.1.1
  • 第二个参数是一个字符串,经过跟踪代码他代表的是acl的名称,查看freeswitch/conf/auto_config/acl.conf.xml文件可以看到里面有类似的配置,它其实就是这个list的name(上游代码中也直接把这个变量定义为list_name)。
    <list name="lan" default="allow">
      <node type="deny" cidr="172.19.13.0/32"/>
      <node type="allow" cidr="111.39.247.230/32"/>
    list>

那这个方法到底是做什么的呢,根据单步调试确定这个方法的用处就是
判断这个IP是否是在这个acl的list中处于allow的状态
那么我的远端IP明明是1.1.1.1而switch_check_network_list_ip(network_ip,“loopback.auto”)这个方法明显是判断IP是否在回路的IP列表中,为什么一个公网IP会认为是回路IP呢,然后我就看到了我的acl.conf.xml中有如下的配置片段

    <list name="loopback.auto" default="allow">
        <node type="allow" cidr="192.168.1.1/28"/> 
    list>

这个acl规则就叫做loopback.auto 而且他是默认allow(暨黑名单模式)只要不配置deny那么所有的IP在这个规则下都是allow。
为什么????????????
我开始有点不理解为什么freeswitch为什么会有这么坑爹的东西,然后我又去看与源码对应,发现源码中根本没有这个配置,那这个就是我自己加上去的。
回想了一下我为什么加这个,原来是我在开启ESL功能的时候使用了另一台服务器上的组件进行调用,于是出现了ACL的拦截,而esl中的拦截的acl-list-name就是loopback.auto,为了能够正常调用esl于是我就加上了这个配置。导致了这一个蛋疼的问题~~
删除配置,重启fs,再次测试问题解决!!!

第三个参数

回到刚才的switch_check_network_list_ip方法,他在最后还有一个调用是switch_check_network_list_ip(network_ip,smh->mparams->local_network),这个方法调用的方法也是刚刚讲的方法,问题是他的第二个参数不是固定的而是一个变量,那么这个变量哪来的呢,他就是profile配置文件中的下面的参数配置

<param name="local-network-acl" value="rfc1918.auto"/>

所以在解决了上面那个固定值的问题后,你也要去看一下这个是不是对的。

总结

适用场景

Freeswitch放在防火墙后面,且做了防火墙的指定端口转发,然后与别的处于Internet环境下的SIP终端进行对接。然后出现我们的Freeswitch回复的sdp中的IP不是我们的防火墙IP。

解决方案

1、检查sip_profile文件夹下对应的配置文件中有没有配置 ext-rtp-ip的内容,如果没有请把它配置成你的防火墙地址(如果有其他网络环境请根据情况配置,如nat或者auto或者host等)

2、检查对端的SIP中SDP所携带的IP是不是内网IP

3、检查acl.conf.xml中是否二外配置了loopback.auto ,且处于黑名单模式或者对端SDP中的IP在这个配置下处于allow状态。如果是请根据需求删除或者加入黑名单等其他操作。

4、检查sip_profile文件下对应的配置文件中local-network-acl配置的值是什么,并依照第3步查看IP是否处于这个acl规则下的allow状态。

5、启动的时候注意使用-nonat指令关闭自动nat嗅探。

至此问题解决完毕~~~

你可能感兴趣的:(udp,sip,网络,tcp/ip,freeswitch)