1、双机对接 假设你有两台Freeswitch主机,分别为A和B,IP地址分别为192.168.200.A和192.168.200.B。每台机器均使用默认配置,也就是每台机器上100~1019这20个号码之间可以互打电话。位于同一机器上的用户称为本地用户,如果需要与其他机器上的用户通信,则其他机器上的用户就称为外地用户。
如果我们需要两台机器之间的用户可以互拨,最需要解决的问题不是技术上如何配置,而是一个逻辑问题。例如:如果A上的1000想拨打B上的1000,则B上的1000相对于A上的1000来说就是外地用户。 为了完成对接,我们规定:不管是A上的用户还是B上的用户,拨打外网用户均需要在实际的电话号码前加拨0。 在A机上,把以下Dialplan片断加到conf/dialplan/default.xml中(注意在测试时,把配置加得靠前一点,以防与其他现有的配置项相冲突): <extension name="B"> <condition field="destinantion_number" expression="^0(.*)$"/> <action application="bridge" data="sofia/external/sip:$1@192.168.200.B:5080"/> </condition> </extension> 其中,正则表达式^0(.*)$表示匹配所有以0开头的被叫号码,匹配完成后,括号中的匹配结果会被绑定到变量$1中。因此,如果A上的用户呼叫01000,则$1的值就是1000,bridge是一个App,它的参数就变成sofia/external/sip:1000@192.168.200.B:5080,它是一个呼叫字符串。在一个呼叫中,当Freeswitch执行到这里的bridge时,就会从本机的external Profile(本机的5080端口)向B的5080端口发送INVITE呼叫请求。 注意,上述过程中,被叫号码中的第一个0在到达B时丢失了。这是系统对接中常用的一个策略,俗称把“0”吃掉了。 B在5080端口上收到INVITE请求后,由于5080端口默认走public Dialplan,所以查找public.xml,可以找到以下的Dialplan配置项: <extension name="public_extensions"> <condition field="destination_number" expression="^(10[01][0-9])$"> <action application="transfer" data="$1 XML default"/> </condition> </extension> 上述Dialplan中的正则表达式^(10[01][0-9])$会匹配被叫号码1000,然后执行transfer,并把来话转到default Dialplan。呼叫转到default Dialplan后,路由规则就跟本地用户的来话一样了,因而最终B上的1000就会振铃。如果B接听电话就接通了。 注意,如果你对接不同的服务器,服务器中的用户号码不是默认的1000-1019,那么就在public.xml中的正则表达式^(10[01][0-9])$中添加你的用户号码。如服务器中的用户号码为800-809,则添加^(10[01][0-9]|80[0-9])$。 如果B上的用户要拨打A上的用户,那么只需要在B上做类似A上的配置就可以了。 2、汇接 理论上,所有的对接模式都可以采用上面的双机对接模式,上述的对接模式是一切对接的基础。下面我们考虑更复杂的情况,A、B、C、D开会讨论。D说:“我为你们提供转接服务。”所以D就成了一个汇接局,为A、B、C之间的通话做转接服务。A、B、C就称为端局,因为他们只有终端用户。拓扑结构如1-1。 ![]() 1-1 汇接局模式 同时,大家商量新的拨号规则:本地用户之间的通话拨号规则不变,但是如果拨叫其他外地用户的话,则需要拨打相应的局号(如果A上帝额用户呼叫B上1000,则拨打B1000),并统一送到D进行汇接。我们以A为例,它上面的Dialplan如下: <extension name=”D”> <condition field=”destination_number” expression=”^([B-Z].*)$”> <action application=”bridge” data=”sofia/external/sip:$1 @192.168.200.D:5080”/> </condition> </extension> 其中,正则表达式^([B-Z].*)$表示任何以B-Z开头的号码都送到D的5080端口上去。注意:这里没有“吃掉”第一位号码,因为如果吃掉的话,D就不知道如何进行下一步路由了。所以,如果A上的用户拨打B1000,在D上将收到B1000。 在D上,收到5080端口的呼叫请求后,查找public Dialplan对来话进行路由。它的Dialplan设置如下: <extension name=”D”> <condition field=”destination_number” expression=”^D(.*)$”> <action application=”transfer” data=”$1 XML default”/> </condition> </extension> 上述配置说明,如果被叫号码的首位是D,则说明是一个本地用户,所以“吃掉”首位的D,然后把路由转到default Dialplan进行处理。 对于被叫号码不在本地的用户,使用下面的Dialplan: <extension name=”D”> <condition field=”destination_number” expression=”^([A-CE-Z])(.*)$”> <action application=”bridge” data=”sofia/external/sip:$2 @192.168.200.$1:5080”/> </condition> </extension> 其中,^([A-CE-Z])(.*)$表示匹配所有除D以外的被叫号码。我们以有人拨打B1000为例,匹配成功后,$1的值为B,$2的值为1000,所以,bridge的参数中呼叫字符就变成sofia/external/sip:1000@192.168.200.B:5080,因而相当于在D上吃掉了被叫号码中最首位的B,并把电话送到B的5080端口上。电话到达B后,B上默认的Dialplan就可以将电话路由到本地用户上,电话接通。这种方式就称为汇接模式。 所有局间的通话都是通过D的,因而它的压力比较大。实际上,如果A、B、C之间的网络直接可达,则可以让D仅转发SIP信令,而让RTP流直接在端局之间传递。在上述配置的bridge Action之前增加如下参数可以让D工作在Bypass Media(媒体绕过)模式,仅转发SIP信令,而让RTP媒体流在端局间传递: <action application=”set” data=”bypass_media=true”/> 上述参数是在Dialplan中设置的,因而仅针对当前通话有效。如果想让D对所有通话都是用Bypass Media,则可以直接在Profile(external)中,添加如下设置: <param name=”inbound-bypass-media” value=”true”> 3、双归属 即使采用了Bypass Media,D的压力还是很大。一旦D出现了故障,则A、B、C之间的用户就都打不通电话了。 为了解决这个问题,它们又找来了E,来做一个备份的汇接局。并且把D和E的本地用户都分了一下,放到A、B、C上,让D和E专门做汇接。拓扑结构如图2。
![]() 图2 双汇接局双归属网络拓扑 <extension name=”DE”> <condition field=”destination_number” expression=”^([B-Z].*)$”> <action application=”bridge” data=”sofia/external/sip:$1@IP.D:5080 |sofia/external/sip:$1@IP.E:5080”/> </condition> </extension> 这里我们修改了呼叫字符串,使用了“|”连接两个呼叫字符串。它的意思是,如果第一个呼叫不成功,则使用下一个呼叫字符串。这种方式就称主备用模式。 我们以负荷分担的方式处理话务,就是在端局将50%的通话送到D上,50%通话送到E上。这里我们使用如下Dialplan实现(以A上的额出具路由为例): <extension name=”DE”> <condition field=”destination_number” expression=”^([B-Z].*[13579])$”> <action application=”bridge” data=”sofia/external/sip:$1@IP.D:5080 |sofia/external/sip:$1@IP.E:5080”/> </condition> </extension>
<extension name=”ED”> <condition field=”destination_number” expression=”^([B-Z].*[24680])$”> <action application=”bridge” data=”sofia/external/sip:$1@IP.E:5080 |sofia/external/sip:$1@IP.D:5080”/> </condition> </extension> 通过上述配置,根据正则表达式^([B-Z].*[13579])$,所有被叫号码以奇数结尾的都优先送到汇接局D上(如果失败仍会送到E上)。同理,所有号码以奇数结尾的都优先送到汇接局E上(如果失败仍会送到D上)。 4、ACL 在实际环境中,只考虑把电话接通是不够的,还要考虑安全性。上面的方法只使用5080端口从public Dialplan做互通,而发送到5080端口的INVITE是不需要鉴权的,这意味着任何人均可以向它发送INVITE从而按你设定的路由规则打电话。 为了防止这个问题,我们在汇接局上关闭5080端口,而让所有来话都送到5060端口上(internal Profile)。5060端口上的来话是需要先鉴权才能路由的。在这种汇接局模式中,一般会使用IP地址鉴权方式。而IP地址鉴权就会用到ACL。 ACL(Access Control List)即 访问控制列表,它通过一个列表矩阵来控制哪些用户可以访问哪些资源。在Freeswitch中,实现了基于ACL的鉴权。 其中,internal Profile默认使用“domains”这个ACL进行鉴权。配置如下: <param name="apply-inbound-acl" value="domains"/> 上述配置说明,当收到呼叫(INVITE)请求时,要查看“domains”这个ACL,看是否允许来源IP地址进行呼叫。 ACL是在conf/autoload_configs/acl.conf.xml中配置的,其中domains的默认配置如下: <list name="domains" default="deny"> <!--domains是一种特殊情况,它会根据用户目录中的配置生成ACL--> <node type="allow" domain="$${domain}"/> <!--如果你想允许某些IP段能通过ACL检查的话,使用cidr=的配置方式 --> <!-- <node type=”allow” cidr=”192.168.200.158/32”>--> </list> 如果我们想在D上允许来自A、B、C的呼叫,就可以把A、B、C的地址加到上述配置里面,如可以添加以下配置,以允许来自这些IP的呼叫。 <node type=”allow” cidr=”192.168.200.A/32”> <node type=”allow” cidr=”192.168.200.B/32”> <node type=”allow” cidr=”192.168.200.C/32”> 通过设置上述ACL,我们就保证了只有授权的用户才能从D上进行路由。 |
|
来自: 草莓加冰 > 《Freeswitch》