呼叫中心平台中坐席是不可或缺的一环,而坐席打电话自然需要使用办公分机。通常情况下我们通过软交换平台FreeSWITCH、Asterisk即可搭建分机注册服务。
但单台FreeSWITCH或Asterisk难以承载高并发的注册服务,而且从服务模块化的角度,我们也希望将注册服务和媒体服务相分离,所以我们通常会是使用OpenSIPS 或 Kamailio 来搭建注册服务器。
今天就让我们一同来看一下,如何通过OpenSIPS搭建一个简单的分机注册服务器吧……

目录:

业务场景
运行环境
关键模块
涉及的数据库表
分机注册信令细节
注册的认证过程
auth_db模块变量说明
个性化功能禁止单个分机账户多地注册
注册脚步详情
术语解释
测试方法
  1. 业务场景:

    OpenSIPS为分机提供注册服务,分机可以经过OpenSIPS进行互打

  2. 运行环境:
    CentOS 7.4
    OpenSIPS 2.4.2

  3. 使用的关键模块:
    SIP signaling modules : registrar、signaling、sl
    Auth modules : auth、auth_db
    Data caching : usrloc

  4. 涉及的数据库表:
    subscriber : 存放分机号、密码等信息
    location : 已注册的分机信息

  5. 分机注册信令细节(RFC3261):

    分机注册、取消注册都是使用 SIP REGISTER 方法,只是取消注册的时候,消息头中的过期时长expires的值是 0
    分机注册需要进行认证
    注册服务器返回 401/407 来要求终端发起认证
    认证不通过,则注册服务器返回 403 (Forbidden)
    认证过程中,注册服务器找不到AOR (Address-of-Record),则返回404 (Not Found)
    分机注册的(建议)过期时长可以依次从下面两个地方获取 :
    Contact 头中的 expires 参数
    Expires 头
    以上两项都没有,则由注册服务器指定一个默认值 (如OpenSIPS的registrar模块配置"default_expires=120)
    注册成功后的实际过期时长是由注册服务器来决定,并在注册服务器返回的200 OK中的Contact里通过携带 'expires’参数来告知分机终端注册信息实际的有效时长:
    终端REGISTER请求中的expires可能不在注册服务器允许expires范围内,注册服务器会强制使用自己指定的expires值
    比如REGISTER中的Expires=20, 而OpenSIPS配置的min_expires=30,那么OpenSIPS返回的200 OK中的expires值是30 (如:Contact: sip:401999@10.32.26.19:56862;rinstance=870ce245f5361eaf;expires=30)
    分机终端需要周期性发送保活注册包
    保活过程中,每次重发注册请求,CSeq 值自增 1
    保活注册时,Call-ID始终不变
    保活注册包发送周期:在达到注册服务器返回的200 OK中的expires时长之前,重发保活注册请求 (如Yealink会在expires/2时长后重新注册,而Zoiper、EyeBeam会在注册过期前5秒重新注册)
    如果注册的响应报文包含Date 消息头,那么SIP终端需要通过该值来保持跟注册服务器的时间同步,以确保注册周期的准确性!http://www.wcsdyc.com

View Code

  1. 注册的认证过程:

    SIP 是采用HTTP摘要方式(Digest)进行认证。

    认证:
    调用auth_db模块的www_authorize("", “subscriber”)进行分机身份认证,根据认证情况继续
    返回 -3 (stale nonce)、-4 (no credentials),则调用 auth 模块的 www_challenge("",“0”)要求分机携带认证凭证再次注册。该方法会返回SIP 401,并且消息头中有一个 WWW-Authenticate 头,等SIP终端再次发送注册请求时就会在SIP INVITE 内携带 Authorization 头信息
    返回 -1 (invalid user),则调用signaling模块send_reply(“404”, “Not Found”)
    返回 -2 (invalid password)、-5 (generic error),则调用signaling模块send_reply(“403”, “Forbidden”)
    返回 1 (success),进行下一步
    存储注册信息:
    调用registrar模块的save(“location”, “f”) 将注册信息写入location表
    写入DB失败,则调用 sl 模块的 sl_reply_error() 返回错误信息

    www_authorize(realm, table_name) :
    realm : 所注册分机所属的域,通常是域名或IP

    该值并不一定是subscriber中的domain字段,具体根据auth_db里的参数配置决定。 (注册服务器返回401时,一定会有该参数,在所有的盘问中都必须有。它的目的是鉴别SIP消息中的机密。在SIP实际应用中,它通常设置为SIP代理服务器所负责的域名)

    通常该值是REG服务器的IP,如果realm填空串"",对于REGISTER注册请求而言,会从To头取domain/ip地址(相当于td),而其他请求则从From头中取(相当于td), 而其他请求则从From头中取(相当于td),而其他请求则从From头中取(相当于fd)。

    该值也可以使用伪变量指定。如 rd、rd 、rd、td 、$fd

     table_name : 认证信息存储的表名称,如subscriber
    

    www_challenge(realm, qop_enable) :
    realm : 同上所属
    qop_enable :

    是否双向认证。可选值 0、1, 当qop_enable=1时,后续步骤中的 WWW-Authenticate 和 Authorization 步骤得值都会携带qop参数,401会有nonce, 再次发送的 REGISTER会有cnonce

    如:qop_enable=1时,返回401消息:WWW-Authenticate: Digest realm=“10.2.32.112”, nonce=“5f05c370000000090661a6e56d5451e0ba81b4883dc37bca”, qop=“auth”, stale=true

    再次发送的REGISTER消息:Authorization: Digest username=“9001”,realm=“10.2.32.112”,nonce=“5f05c370000000090661a6e56d5451e0ba81b4883dc37bca”,uri=“sip:10.2.32.112;transport=tcp”,response=“d5792a2d89b0c158c1c9453f98385cb8”,cnonce=“06681fd4664cda35938959789ed84849”,nc=00000001,qop=auth,algorithm=MD5【response是加密后的密码, 其他参数的解释请参见https://www.cnblogs.com/shengs/p/4361314.html 或RFC2617 HTTP认证】

    除了身份认证,OpenSIPS还可以使用下面几个方法完成代理认证:

    proxy_authorize(realm, table_name)
    proxy_challenge(realm, qop_enable) [返回407,消息头 Proxy-Authenticate、Proxy-Authorization ]
    consume_credentials()

  2. auth_db模块变量说明:

    db_url : (string) 数据库访问路径,如果不设置,则采用db_default_url
    user_column : (string) 数据库subscriber表中用于存放UA的用户名信息的列名,默认是username
    domain_column : (string) 数据库subscriber表中存放UA所属的租户信息的列名,默认是domain
    password_column : (string) OpenSIPS运行时,使用subscriber表中作为UA密码的列名,默认是 ha1
    根据username、password、realm(非表中的domain)计算出的 MD5 hash值
    使用 MI命令 opensipsctl add username password 会自动生成 ha1的值
    注意,如果calculate_ha1=1,必须设置password_column=“password”,用于存储明文密码;calculate_ha1=0 时,该值可不设或者设置成ha1
    password_column_2 : (string) OpenSIPS运行时,使用subscriber表中作为UA密码的列名,默认是 ha1b
    同ha1, 但计算hash的方式不同,根据 username@domain、password、realm 计算出的MD5 hash值
    只有当calculate_ha1=0,并且UA发起的注册请求中username携带domain信息时有用,如username=9001@10.2.32.112 [$fu=sip:9001@010.2.32.112@10.2.32.112;transport=UDP]
    calculate_ha1 : (int) OpenSIPS处理REGISTER请求时,是否需要重新计算密码的HASH值,取值分别如下:
    1 :OpenSIPS会从加载明文密码,然后计算MD5 hash值,所以password_column的值必须=password
    0 :(默认值)不计算密码,如果注册请求中username不带domain时,则直接从ha1中取密码进行验证,否则取ha1b的值【此时不能设置成password_column=“password”】
    user_domain : (int) 是否支持多租户,取值范围 [0,1] ,默认值 0。
    MI命令 opensipsctl add username password 不支持添加多租户的UA信息
    所以需要自己想办法为不同租户初始化subscriber表中的 ha1和ha1b,当然你不设置ha1和ha1b,OpenSIPS根据明文计算的方式解决(模块参数password_column=“password”、calculate_ha1=1

    subscriber表样例:

     username : 用户名(分机号)domain     : 租户名称[IP、域名、或者是自己随意定义的名称],当你想支持多租户配置时有用(modparam("auth_db", "use_domain", 1)),注册请求From头样例: "9999"<sip:9999@tony.com>       从上面样例中可以看到 分机号为 9999  的 ha1 和 ha1b 的值为空,因为我采用根据明文密码计算MD5 hash值得方式模块参数password_column="password"、calculate_ha1=1
    
  3. 个性化功能:

    1、不允许单个分机账号被拥有不同IP的多个终端同时注册(但同一IP下,单个账户可以同时用多个SIP终端注册),并且单个终端注册成功后,可以重发注册请求,以便更新过期时间
    有以下两种方案,其中方案A性能更好。 方案B 更灵活。http://www.bhanxi.com

    实现方案A:【从OpenSIPS内存中获取分机登录状态】

    通过 registar 模块的 is_ip_registered、is_registered方法检测当前注册分机是否已经被注册过,如果已经被注册,则直接返回返回403 , 提示账户被占用 Occupied
    如果同时满足下面几个条件,则不允许再注册:(存在已经注册的分机,但IP不是自己)
    (1) is_ip_registered 根据 $tu 分机号(username) 和 si(分机终端IP)检测到分机未注册【未注册:返回−1】(2)isregistered检测到si (分机终端IP) 检测到分机未注册 【未注册:返回 -1】 (2) is_registered 检测到si(分机终端IP)检测到分机未注册【未注册:返回−1】(2)isr​egistered检测到tu 分机号(username) 已经注册 【已注册:返回 1】
    其中第一步如果返回1,表示已注册,则需放行因分机注册信息过期而再次发起的注册请求,以便更新过期时间【因为根据终端IP判断,所以不会影响端断电重启后再次注册】
    [备注:registar 模块还有 is_contact_registered方法,可以根据分机号+callid判断分机注册情况,如 is_contact_registered(“location”, “tu",,"tu", , "tu",,"ci”) ]

View Code

 实现方案B:【从DB获取分机登录状态】通过avpops模块的 avp_db_query 直接查询数据库的 location 表来实现功能

View Code

  1. 注册脚步详情:

    通过下面脚步,注册几个分机后,就能完成分机互打了
    添加分机的方式 : /usr/local/OpenSIPS/sbin/OpenSIPSctl add ${分机号} ${密码}
    /usr/local/OpenSIPS/sbin/OpenSIPSctl add 9001 9001
    添加的分机会写入 subscriber 表, 注册信息会写入 location表

View Code

  1. 术语解释:

    Contact : SIP终端账户的具体物理IP和端口,用于描述我在哪里。一个注册请求中可以有多个Contact消息头。SIP终端之间可以通过Contact中的信息实现点对点通信。
    AOR (Address of Record) : SIP终端账户的唯一标识,用于描述我是谁,From 和 To 头中就是 AOR地址,格式为 SIP:username@domain_host 或者 SIP:username@ip 。 AOR地址是可以解析得到Contact地址。

  2. 测试方法:
    启动OpenSIPS :
    /usr/local/OpenSIPS/sbin/OpenSIPS -f /usr/local/OpenSIPS/etc/OpenSIPS/OpenSIPS.cfg -P /var/run/opensips.pid -m 4096 -M 384 -u root -g root
    可以通过 /usr/local/OpenSIPS/sbin/OpenSIPSctl ul show [分机号(可选)] 查看内存中的分机的注册状态
    复制代码

[root@yuxiu home]# /usr/local/OpenSIPS/sbin/OpenSIPSctl ul show 9001
AOR:: 9001
Contact:: sip:9001@192.168.1.201:5060 Q=
ContactID:: 1767885864954038130
Expires:: 163
Callid:: 1_636487152@192.168.1.201
Cseq:: 96
User-agent:: SIP-T21P_E2 52.80.0.147
State:: CS_SYNC
Flags:: 0
Cflags::
Socket:: udp:192.168.1.218:5060
Methods:: 16383

复制代码

基于OpenSIPS 实现分机注册服务器相关推荐

  1. 注册到uddi服务器,基于UDDI的应用服务注册中心的设计与实现

    摘要:Web服务是当前基于Web的分布式计算与应用的关键技术基础.通用描述发现集成协议(UDDI)是Web服务的核心技术标准,提供了Web服务的信息注册查找规范,解决了Web服务的描述.发布以及查找问 ...

  2. go使用grpc实现异步_(python、go)基于ETCD的gRPC分布式服务器实现详解

    作者:Zarten知乎专栏:框架工具篇详解知乎ID: Zarten简介: 互联网一线工作者,尊重原创并欢迎评论留言指出不足之处,也希望多些关注和点赞是给作者最好的鼓励 ! 1-概述 gRPC框架是一个 ...

  3. 一款基于Netty开发的WebSocket服务器

    代码地址如下: http://www.demodashi.com/demo/13577.html 一款基于Netty开发的WebSocket服务器 这是一款基于Netty框架开发的服务端,通信协议为W ...

  4. Windows下基于IIS服务的SSL服务器的配置

    Windows下基于IIS服务的SSL服务器的配置 实验环境 Windows Server 2008 R1(CA) Windows Server 2008 R2(web服务器) Windows 7 x ...

  5. 基于Javaweb和阿里云服务器的用户管理平台

    基于Javaweb和阿里云服务器的用户管理平台 技术支持: 视图层:js+html+css 业务层:servlet 持久层:mysql5.6 项目介绍:myEclipse负责开发javaweb项目,t ...

  6. 《嵌入式系统 – 玩转ART-Pi开发板(基于RT-Thread系统)》第9章 基于Select/Poll实现并发服务器(二)

    基于Select/Poll实现并发服务器(一) 9.3 Select/Poll概述 在LWIP中,如果要实现并发服务器,可以基于Sequentaial API来实现,这种方式需要使用多线程,也就是为每 ...

  7. 基于Kerberos认证的NFS服务器

    基于Kerberos认证的NFS服务器 相关命令 kadmin.local: listprincs <==查看用户列表 服务器配置 NFS 服务器(同时作为 Kerberos 认证器) NFS客 ...

  8. linux ftp 团队认证,linux下ftp和ftps以及ftp基于mysql虚拟用户认证服务器的搭建

    linux下ftp和ftps以及ftp基于mysql虚拟用户认证服务器的搭建 1.FTP协议:有命令和数据连接两种 命令连接,控制连接:21/tcp 数据连接: 主动模式,运行在20/tcp端口 和 ...

  9. 基于select模型的TCP服务器

    之前的一篇博文是基于TCP的服务器和客户机程序,今天在这我要实现一个基于select模型的TCP服务器(仅实现了服务器). socket套接字编程提供了很多模型来使服务器高效的接受客户端的请求,sel ...

最新文章

  1. SQL查询前10条记录(SqlServer/mysql/oracle)[语法分析]
  2. 第4章 Python 数字图像处理(DIP) - 频率域滤波7 - 二维DFT和IDFT的一些性质 - 傅里叶频谱和相角
  3. encodingaeskey java,消息体签名与加解密-开发者QA
  4. [No0000B0]ReSharper操作指南1/16-入门与简介
  5. MBA已经全面***“中国式教育”!
  6. 【编译器】G++常用命令
  7. Q141:PBRT-V3,交点处各种微分的求解(球面,3.2章节)
  8. Suse Enterprise Server 11的安装
  9. linux 用户登陆全部记录,Linux—— 记录所有登陆用户的历史操作记录
  10. 使用命令行连接MySQL数据库
  11. Python 爬取QQ音乐个人单曲排行榜
  12. Python 计算父亲节和母亲节
  13. caxa图文档服务器未启动,CAXA协同管理图文档
  14. 【bzoj 4833】[Lydsy1704月赛]最小公倍佩尔数
  15. 钙钛矿在太阳能电池领域的研究进展
  16. html5 好看的折叠效果,9款HTML5实现的超酷特效
  17. 非常OK网独创BSC模式可行性分析
  18. 微信官方提供的生成二维码接口得到的是当前公众号的二维码
  19. java毕业设计智慧公寓系统演示录屏2021Mybatis+系统+数据库+调试部署
  20. phpyun6.1人才招聘系统nginx伪静态规则配置

热门文章

  1. 8.五言律诗和绝句的句型及平仄格式
  2. 坐式养生八段锦口诀及练法图解
  3. ATC 19 EROFS: A Compression-friendly Readonly File System for Resource-scarce Devices
  4. 产品取名——中国IT产品命名奇观
  5. CG-23H 超声波风速风向传感器--易风(加热型)
  6. 管理系统中计算机应用自考本科,重庆自考管理系统中计算机应用本科模拟试题 _ 重庆自考网...
  7. Qt moc: Too many input files specified
  8. 基于组合权重优化的风格中性多因子选股策略_数量化专题之五十七
  9. js filter 多条件过滤适合对象属性
  10. linux snap 原理,snap,snap和Snappy指的是什么?