flash p2p rtmfp协议解析
原文地址:http://blog.csdn.net/vinowan/article/details/459346271??????协议介绍Real-Time Media Flow Protocol(简称RTMFP)是Flash和Flash之间基于UDP的点对点传输协议,由Adobe公司在2008年在Flash 10.0中发布,随后在Flash10.1中加入了Groups功能。 2??????常见用法rtmfp在Flash 10中的典型使用场景如下图:
它有如下特点: l? 使用Cirrus或者开源的Cumulus来提供Rendezvous服务 l? Cirrus或者Cumulus并不提供Peer ID的交换服务,需要提供其它的方式来交换客户端之间的Peer ID l? Flash客户端之间使用NetStream来做点对点传输,Publisher需要给每一个Subscriber单独传输一份数据,这也限制集群的规模。 ? 为了解决这个问题,Adobe在Flash 10.1中提出了Groups的概念,典型的架构如下:
l? Cirrus或者开源的Cumulus提供Rendezvous服务并提供所有连接client列表 l? client从Cirrus或者开源的Cumulus获取邻居节点之后,就可以组成一个完整的P2P架构,所有的audio、video和data数据都在peer之间交互。 3??????协议解析3.1 基本概念l? session:session是两个UDP地址之间的双向管道。 l? flow:flow是从一个实体到另一个实体之间的逻辑路径。一个session可以包括多个flow。 l? packet:网络中实际传输的数据,一个packet可以包含多个message。数据传输时都经过了128 bit的AES加密 l? message:audio、video和data数据。 3.2 Scrambled Session IDrtmfp协议中每个包的格式如下: packet := scrambled-session-id | encrypted-part 其中scrambled-session-id是4字节,其后是经过AES加密的数据体。 scramble-session-id的生成规则如下: scrambled-session-id = a ^ b ^ c 这里^代表XOR操作,a是session-id,b和c是encrypted-part的头8个bytes。 当目标收到这个包后,unscramble的操作如下: session-id = x ^ b ^ c 其中x是scrambled-session-id,b和c同上。 使用scramble-session-id的目的为了减少数据包流经的NAT设备和layer-4 packet inspector对数据的干扰。 session-id用于标识通信双方建立的连接,并确定通信时使用的加密和解密的key,这些key是通过DH key exchange算法获得。但在session建立之前,双方使用一个公有加密key,即128 bit的字符串”Adobe System 02”。 3.3 raw partencrypted-part经过解密之后就得到了raw-part,它的格式如下: raw-part := checksum | network-layer-data | padding 其中checksum有16字节,network-layer-data是变长数据,padding都是0xFF,并把network-layer-data补齐为16字节的倍数,这是因为rtmfp使用的是16字节的加解密key。 checksum基于network-layer-data和padding计算。 3.4 network layer datanetwork-layer-data的格式如下: network-layer-data = flags | timestamp | timestamp-echo | chunks 其中flags为1个字节,其格式如下: 7?6? 5?????? 4?????3? 2? 1 0 TC TCR reserved reserved TS TSE mode l? mode:11代表握手包,01代表initiator发送包,10代表responder发送包,00不是合法值 l? TSE:包中是否包含timestamp-echo域 l? TS:包中是否包含timestamp域 l? TCR:time critical reverse notification表明发送方正在从其它地方收到timecritical包 l? TC:time critical forward notification表明发送方发送的是timecritical包 timestamp域有2字节,精度是4ms,他的计算方式如下: timestamp = int(time * 1000 / 4) & 0xFFFF timestamp-echo域是server收到包的时间戳,当发送放收到这个值之后,发送方就可以计算RTT值了。 chunk类型的格式如下: chunk = type | size | payload type字段为1个字节,其中0xFF不可用,这个是用来区分chunk数据和padding数据的标记。type的定义如下:
size是2字节payload长度。 payload根据type的不同有不同的数据体。 3.5 message flowsession中包括3类消息: l? handshake:握手包,包括initiator hello,responder hello,initiator initial keying,responder initial keying,responder hello cookie change和responderredirect l? control:控制包,包括ping,ping reply,rekeying initiate,rekeying response,close,closeacknowledge,forwarded initiator hello. l? flow:流消息,包括user data,next user data,buffer probe,user data ack,user dataack,flow exception report. ? session的建立是通过握手(handshake)来完成的,正常的messageflow如下:
如果是在NAT打洞是,cumulus server就作为一个forwarder,他会把initiatro hello包转发到其它的client: 另外,cumulus server还可以让client重定向到其它server: 这里所说的client是Flash Player,而server是cumulus server或者Flash media server。当然server也可以给client发送initiator hello请求,这个在cumulus中被称为man in the middle,不过这个特性还不稳定。 session的建立包括4次握手: 1??????????initiator -> target:initiator hello 2??????????target? -> initiator: responder hello 3??????????initiator -> target:initiator initial keying 4??????????target? -> initiator: responder initial keying 这个4次握手过程可以阻止Dos攻击和syn-flooding攻击。 每个session都有一个session-id来唯一标识这个session,并且session中的每个packet都会包含这个session-id,但是在session建立的4个握手包中,initiator-hello,responder hello和initiator initialkeying的session-id字段都是0,在发送最后一个包responder initial keying时,session建立成功并且session-id确定,所以responderinitial keying包含合法的session-id。 我们接下来详细介绍一下这4个握手包 3.5.1 initiator helloinitiator hello包的格式如上所述,这里只说明payload部分的格式: initiator-hello payload = first | epd type | epd value| tag 其中: l? first:1 byte magic number l? epd type:1 byte,只有两个合法值: n? 0x0a:client-server模式,epd value是想要连接的server的rtmfp url n? 0x0f:peer-to-peer模式,epd value是想要连接的client的peer id,一般是固定的32字节 l? epd value:varlen + body l? tag:16 bytes随机数 3.5.2 responder helloresponder hello包的payload格式如下: responder hello payload = tag-echo | cookie | responder-certificate l? tag-echo:和initiator hello中的tag一致,但和initiator hello中不同的是,这里在前面有一个varlen来表明tag的长度 l? cookie:responder产出的64 bytes随机数,用来防止syn-flooding攻击 l? responder certificate:diffie-hellman key exchange算法交换的信息,它的格式如下: certificate= x01 x0A x41 x0E | dh-public-num | x02 x15 x02 x02 x15 x05 x02 x15 x0E dh-public-num是一个64 byte(128 byte)随机数。 dh-public-num的生成规则为 y2 = g ^ x2 % p 其中g和p是公开的两个数,其中g等于2,p是一个1024 bits的数,x2是responder随机生成的数,y2就是在网络中传输的dh-public-num。 3.5.3 initiator initial keyinginitiator initial keying包的payload格式如下: payload = initiator-session-id | cookie-echo | initiator-certificate| initiator-component | ‘X’ 其中: l? initiator-session-id:initiator选择的session-id,responder用它来发送数据给initiator(生成scrambled session id) l? cookie-echo:和上一个包中的cookie一致 l??initiator-certificate:格式和上面的responder certificate一致 和上述的一样,这里的dh-public-num的生成规则如下: y1 = g ^ x1 % p 其中g和p的定义和上述一致,x1是initiator随机生成的数,y1就是传输的dh-public-num。这时initiator知道了y2和x1,就可以生成sharedsecret: shared secret = y2 ^ x1 % p 这时就可以生成这个session对应的加解密key了: decode key = HMAC-SHA256(shared-secret,HMAC-SHA256(responder nonce,initiator nonce)) encode key = HMAC-SHA256(shared-secret,HMAC-SHA256(initiator nonce,responder nonce)) 这些加解密key都只使用低位的128bit l??initiator-component:在DH算法中使用的initiator nonce。 3.5.4 responder initial keyingresponder initial keying的payload的格式如下: payload = responder session id | responder’s nonce | ‘X’ l? responder session id:responder生成的session id,initiator用它来生成scrambled session id,这个值和initiator session id不一样。 l??responder’s nonce: 这时responder知道了y1和x2,就可以生成sharedsecret: DH算法保证这个responder的sharedsecret和initiator的shared secret是一样的。 这些加解密key都只使用低位的128bit。 可以看到responder的encode key和initiator的decode key是一样的,同样,responder的decode key和initiator的encode key是一样的。 注意responder initial keying依然使用”Adobe System 02”作为对称key来加解密,而不是使用新生成的非对称的key来加解密,非对称的key仅在session建立之后使用。 3.5.5 user data至此session就建立好了,后续传输的就是数据消息,主要包括两类: l? normal user data:正常的flow中数据消息 l? next user data:和normal user data在一个packet中传输,不能单独使用。 normal user data包的payload格式如下: payload = flags | flow-id | seq | forward-seq-offset | options |data l? flags:1 byte,各bit的意义如下:
l? flow-id:flow标识,varlen类型 l? forward-seq-offset:用于滑窗的标识,varlen类型 l? options:一些选项 l? data:audio、video和data数据 next user data包的payload格式如下: payload = flags | data 字段定义同上 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |