SIP协议

1、简介

SIP(Session Initiation Protocol,会话初始协议)是由IETF(Internet Engineering Task Force,因特网工程任务组)制定的多媒体通信协议。广泛应用于CS(Circuit Switched,电路交换)、NGN(Next Generation Network,下一代网络)以及IMS(IP Multimedia Subsystem,IP多媒体子系统)的网络中,可以支持并应用于语音、视频、数据等多媒体业务,同时也可以应用于Presence(呈现)、Instant Message(即时消息)等特色业务。所有说,有IP网络的地方就有SIP协议的存在。

SIP协议与HTTP类似,SIP可以减少应用特别是高级应用的开发时间。

2、SIP消息的两种会话模式

在SIP IM通信应用中,一般存在两种会话模式:

  • Session Model
  • Pager Model

2.1 Session Model

会话中,对于消息体内容大于1300字节时,一般采用Session Model。其会话建立过程(整个流程称为一个Dialogue)如下图所示:

主叫方A呼叫被叫方B:

  • 步骤1:主叫方A发送INVITE请求到代理服务器;
  • 步骤2:代理服务器发送100 Trying 响应主叫方A;
  • 步骤3~6:代理服务器搜索被叫方B的地址,获取地址后转发INVITE请求;
  • 步骤7~9:被叫方B生成的180 振铃响应,返回给主叫方A;
  • 步骤10~12:被叫方B生成的200 OK响应,返回给主叫方A;
  • 步骤13~17:主叫方A收到被叫方B200 OK响应后,向被叫方B发送一个ACK,会话建立;
  • 步骤18~20:会话结束后,任何参与者(A或B)都可以发送一个BYE请求来终止会话;
  • 步骤21~23:主叫方A发送200 OK响应来确认BYE,会话终止。

2.2 Pager Model

在Sip消息中,对于消息体不大于1300字节时,一般采用Pager Model。Sip消息通信中采用MESSAGE方法,MESSAGE方法本身并不建立Dialog,在多数应用中,每条IM消息都是独立的,颇似分页消息。

MESSAGE方法的由来

RFC3428对Sip协议进行了扩展,在Sip协议中增加了MESSAGE请求方法。采用Pager Model进行通信,传递不超过1300字节的数据。MESSAGE方法详细可参考 “SIP-RFC3428” https://tools.ietf.org/html/rfc3428 。

MESSAGE方法消息体

 当User1想给User2发送IM消息时,只需构造一个MESSAGE,发出去即可。

对于其消息体body可以是任何MIME格式。但必须支持plain/text格式,可以选择支持message/cpim、message/sdp格式,可能用message/cpim会好一点,因为已有的IM系统标准是message/cpim格式。

Pager Model请求流程

以User1向User2发送MESSAGE消息为例:

  • 步骤1:User1发送MESSAGE请求到代理服务器;
  • 步骤2:代理服务器转发User1的MESSAGE请求给USER2;
  • 步骤3:User2收到User1的消息后,回复200 OK给代理服务器;
  • 步骤7~9:代理服务器转发200 OK回复给User1

3、SIP消息格式

SIP消息体结构与Http协议结构相似,均由三部分组成:

  • 请求行(request-line) or 状态行(status-line)
  • 消息头(header)
  • 正文(body)

3.1 请求行

请求行格式:

Method Request-URI SIP-Version CRLF

请求行举例:

INVITE sip:bob@zte.com SIP/2.0 /r/n

Method

以下列出了几种消息Method方法:

Request-URI

指示请求的用户或者服务的地址信息。

SIP-Version

请求和响应消息都需要包含SIP版本信息。

3.2 状态行

状态行格式:

SIP-Version Status-Code Reason-Phrase CRLF

状态行举例:

SIP/2.0 200 OK /r/n

Status-Code状态码:

状态代码由3位数字组成,表示请求是否被理解或被满足。状态代码的第一个数字定义了响应的类别,后面两位没有具体的分类。第一个数字有五种可能的取值:

常用的状态码举例:

3.3 消息头

发送MESSAGE消息给user2

MESSAGE sip:user2@domain.com SIP/2.0
Via: SIP/2.0/TCP user1pc.domain.com;branch=z9hG4bK776sgdkse
Max-Forwards: 70
From: sip:user1@domain.com;tag=49583
To: sip:user2@domain.com
Call-ID: asd88asd77a@1.2.3.4
CSeq: 1 MESSAGE
Content-Type: text/plain
Content-Length: 18

user2, come here.

Header 字段含义说明:

4、SIP消息举例

4.1 MESSAGE消息(Pager Model)

以User1发送MESSAGE消息给user2为例:

步骤1:User1发送MESSAGE请求到代理服务器

MESSAGE sip:user2@domain.com SIP/2.0

Via: SIP/2.0/TCP user1pc.domain.com;branch=z9hG4bK776sgdkse
Max-Forwards: 70
From: sip:user1@domain.com;tag=49583
To: sip:user2@domain.com
Call-ID: asd88asd77a@1.2.3.4
CSeq: 1 MESSAGE
Content-Type: text/plain
Content-Length: 18

user2, come here.

步骤2:代理服务器转发User1的MESSAGE请求给USER2,代理服务器收到步骤1请求,到数据库中查找User2(注册过程中生成数据库),随后生成步骤2的数据。

MESSAGE sip:user2@domain.com SIP/2.0
Via: SIP/2.0/TCP proxy.domain.com;branch=z9hG4bK123dsghds
Via: SIP/2.0/TCP user1pc.domain.com;branch=z9hG4bK776sgdkse;received=1.2.3.4
Max-Forwards: 69
From: sip:user1@domain.com;tag=49394
To: sip:user2@domain.com
Call-ID: asd88asd77a@1.2.3.4
CSeq: 1 MESSAGE
Content-Type: text/plain
Content-Length: 18

user2, come here.

步骤3:User2收到User1的消息后,回复200 OK给代理服务器。直接回应(200-OK) 没有Body,也不携带Contact头域。

SIP/2.0 200 OK
Via: SIP/2.0/TCP proxy.domain.com;branch=z9hG4bK123dsghds;received=192.0.2.1
Via: SIP/2.0/TCP user1pc.domain.com;;branch=z9hG4bK776sgdkse;received=1.2.3.4
From: sip:user1@domain.com;tag=49394
To: sip:user2@domain.com;tag=ab8asdasd9
Call-ID: asd88asd77a@1.2.3.4
CSeq: 1 MESSAGE
Content-Length: 0

步骤4:代理服务器转发200 OK回复给User1。代理服务器收到回复后,去掉最顶端的Via,转发如下消息给User1。

SIP/2.0 200 OK

Via: SIP/2.0/TCP user1pc.domain.com;branch=z9hG4bK776sgdkse;received=1.2.3.4
From: sip:user1@domain.com;;tag=49394
To: sip:user2@domain.com;tag=ab8asdasd9
Call-ID: asd88asd77a@1.2.3.4
CSeq: 1 MESSAGE
Content-Length: 0

4.2 REGISTER消息

4.2.1 非鉴权注册消息

192.168.2.161机器发送注册消息给192.168.2.89服务器:

REGISTER sip:192.168.2.89 SIP/2.0

Via: SIP/2.0/UDP 192.168.2.161:10586
Max-Forwards: 70
From: <sip:01062237496@192.168.2.89>;tag=ca04c1391af3429491f2c4dfbe5e1b2e;epid=4f2e395931
To: <sip:01062237496@192.168.2.89>
Call-ID: da56b0fab5c54398b16c0d9f9c0ffcf2@192.168.2.161
CSeq: 1 REGISTER
Contact: <sip:192.168.2.161:10586>;methods="INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER"
User-Agent: RTC/1.2.4949 (BOL SIP Phone 1005)
Event: registration
Allow-Events: presence
Content-Length: 0

当注册成功(回送200 OK)时,服务器发送的res消息参考如下:

SIP/2.0 200 OK

Via: SIP/2.0/UDP 192.168.2.161:10586
From: <sip:01062237496@192.168.2.89>;tag=ca04c1391af3429491f2c4dfbe5e1b2e;epid=4f2e395931
To: <sip:01062237496@192.168.2.89>;tag=-00834-14d0805b62bc026d
Call-ID: da56b0fab5c54398b16c0d9f9c0ffcf2@192.168.2.161
CSeq: 1 REGISTER
Allow: INVITE,ACK,OPTIONS,BYE,CANCEL,REGISTER,INFO,UPDATE,PRACK,REFER,SUBSCRIBE,NOTIFY,MESSAGE
Contact: sip:192.168.2.161:10586
Content-Length: 0
Expires: 3600

4.2.2 鉴权注册消息

 当需要鉴权注册时

  • 请求端192.168.2.161发送注册消息给192.168.2.89服务器
  • 服务器对192.168.2.161发送“401 Unauthorized”信息给请求端,提示请求端需要带上鉴权信息重新注册
  • 请求端带上鉴权信息后(带有“Authorization”头字段)重新向服务器注册
  • 服务器验证鉴权头的正确性,如果鉴权成功,给请求端发送200 OK消息。若失败,继续发送401消息。

步骤一:

请求端192.168.2.161发送注册消息给192.168.2.89服务器

REGISTER sip:192.168.2.89 SIP/2.0

Via: SIP/2.0/UDP 192.168.2.161:8021
Max-Forwards: 70
From: <sip:01062237493@192.168.2.89>;tag=efca469543ce4788a6a6a2c7b66cd01f;epid=de4504430d
To: <sip:01062237493@192.168.2.89>
Call-ID: c88a247a74b54a8c9e676bdde3bba6c9@192.168.2.161
CSeq: 1 REGISTER
Contact: <sip:192.168.2.161:8021>;methods="INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER"
User-Agent: RTC/1.2.4949 (BOL SIP Phone 1005)
Event: registration
Allow-Events: presence
Content-Length: 0

步骤二:

服务器对192.168.2.161发送401 Unauthorized信息给请求端,提示请求端需要带上鉴权信息重新注册:

SIP/2.0 401 Unauthorized

Via: SIP/2.0/UDP 192.168.2.161:8021
From: <sip:01062237493@192.168.2.89>;tag=efca469543ce4788a6a6a2c7b66cd01f;epid=de4504430d
To: <sip:01062237493@192.168.2.89>;tag=-001893-38ba013ba3dde36e
Call-ID: c88a247a74b54a8c9e676bdde3bba6c9@192.168.2.161
CSeq: 1 REGISTER
Allow: INVITE,ACK,OPTIONS,BYE,CANCEL,REGISTER,INFO,UPDATE,PRACK,REFER,SUBSCRIBE,NOTIFY,MESSAGE
Contact: <sip:192.168.2.89:14010>
Content-Length: 0
WWW-Authenticate: Digest realm="192.168.2.89", qop="auth", nonce="e17d377c3d2d9c343e26576a7fd04738481dfc10", opaque="", stale=FALSE, algorithm=MD5

注:

这里192.168.2.89服务器带了一个WWW-Authenticate头。里面告知了如下几个重要的信息:

  • algorithm :加密方式采用MD5
  • nonce:服务器生成的随机值
  • realm:域名

步骤三:

请求端192.168.2.161通过Authorization头字段带上鉴权头信息,发送一个新的REGISTER消息:

REGISTER sip:192.168.2.89 SIP/2.0

Via: SIP/2.0/UDP 192.168.2.161:8021
Max-Forwards: 70
From: <sip:01062237493@192.168.2.89>;tag=efca469543ce4788a6a6a2c7b66cd01f;epid=de4504430d
To: <sip:01062237493@192.168.2.89>
Call-ID: c88a247a74b54a8c9e676bdde3bba6c9@192.168.2.161
CSeq: 2 REGISTER
Contact: <sip:192.168.2.161:8021>;methods="INVITE, MESSAGE, INFO, SUBSCRIBE, OPTIONS, BYE, CANCEL, NOTIFY, ACK, REFER"
User-Agent: RTC/1.2.4949 (BOL SIP Phone 1005)
Authorization: Digest username="01062237493", realm="192.168.2.89", qop=auth, algorithm=MD5, uri="sip:192.168.2.89", nonce="e17d377c3d2d9c343e26576a7fd04738481dfc10", nc=00000001, cnonce="12660455546344082314666316435946", response="f57e47ce03162293b9ced07362ce2b79"
Event: registration
Allow-Events: presence
Content-Length: 0

注:

这里比第一次REGIETER消息多了Authorization头。其中:

  • algorithm:加密方式采用MD5(同401)。
  • nonce:服务器生成的随机值(同401)。
  • realm:域名(同401)。
  • username:用户名,这里等同于注册号码。
  • cnonce:注册端生成的随机值。
  • url:SIP注册时的url。
  • nc:nonce-count,请求的计数。
  • response:加密后的密码。

FreeSWITCH加密密钥生成流程:

其中服务器响应信令如下:

SIP/2.0 401 Unauthorized

Via: SIP/2.0/UDP 172.20.10.6:50024;branch=z9hG4bK-524287-1---e4fb8a53caa2f313;rport=50024

From: "1015"<sip:1015@www.freeswitch.com>;tag=61a25f79

To: "1015" <sip:1015@www.freeswitch.com>;tag=pjeF9m9c63Nym

Call-ID: 89320ZWY3ZWVmNGVhODBiMzUzYWQwM2U3NWE4YTVmMWJlY2Y

CSeq: 1 REGISTER

User-Agent: FreeSWITCH-mod_sofia/1.9.0+git~20180119T195505Z~3f8585f636~64bit

Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, PRACK, NOTIFY, PUBLISH, SUBSCRIBE

Supported: precondition, 100rel, timer, path, replaces

WWW-Authenticate: Digest realm="www.freeswitch.com", nonce="3135ef65-3466-4f70-8035-ec70ff10ae75", algorithm=MD5, qop="auth"

Content-Length: 0
  • HA1:首先我们需要计算HA1,HA1是计算`username:relam:password`字符串的MD5值。除了密码,其它字段从上述信令中我们能找到,就是计算`1015:www.freeswitch.com:1234`的MD5值(默认密码为1234)。
HA1 = md5("1015:www.freeswitch.com:1234") = fe7632dead0ef79b9f1b0bde9d71ac7a
  • HA2:HA2是计算method:uri字符串的MD5值。也就是计算REGISTER:sip:www.freeswitch.com的MD5值。
HA2 = md5("REGISTER:sip:www.freeswitch.com") = 357860fa5d775b1ec660c952831a065
  • 加密密码:最终根据HA1和HA2生成最终的MD5值。即计算`HA1:nonce:nc:cnonce:qop:HA2`字符串的MD5值。从上述信令中找到相关字段。
MD5=md5("fe7632dead0ef79b9f1b0bde9d71ac7a:3135ef65-3466-4f70-8035-ec70ff10ae75:00000001:be28d6ed344661886ad93c8504358936:auth:357860fa5d775b1ec66
  • 最后我们会发现计算出来的值其实就是response字段。FreeSWITCH会按照相同的方式计算加密密码,并比对来完成鉴权。

步骤四:

服务器验证鉴权头的正确性,如果鉴权成功,给请求端发送200 OK消息。若失败,继续发送401消息:

SIP/2.0 200 OK

Via: SIP/2.0/UDP 192.168.2.161:8021
From: <sip:01062237493@192.168.2.89>;tag=efca469543ce4788a6a6a2c7b66cd01f;epid=de4504430d
To: <sip:01062237493@192.168.2.89>;tag=-001894-a5eb977c8969aa51
Call-ID: c88a247a74b54a8c9e676bdde3bba6c9@192.168.2.161
CSeq: 2 REGISTER
Allow: INVITE,ACK,OPTIONS,BYE,CANCEL,REGISTER,INFO,UPDATE,PRACK,REFER,SUBSCRIBE,NOTIFY,MESSAGE
Contact: sip:192.168.2.161:8021
Content-Length: 0
Expires: 3600

 

posted @ 2021-05-27 11:45  钟齐峰  阅读(1040)  评论(0编辑  收藏  举报