flashP2P协议rtmfp解析

1      协议介绍

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 ID

rtmfp协议中每个包的格式如下:

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 part

encrypted-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 data

network-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的定义如下:


type


meaning


0x30


initiator hello


0x70


responder hello


0x38


initiator initial keying


0x78


responder initial keying


0x0f


forwarded initiator hello


0x71


forwarded hello response


0x10


normal user data


0x11


next user data


0x0c


session failed on client side


0x4c


session died


0x01


reset keepalive request


0x41


reset keepalive response


0x5e


negative ack


0x51


some ack

size是2字节payload长度。

payload根据type的不同有不同的数据体。

3.5 message flow

session中包括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 hello

initiator 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 hello

responder 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= \0x01\0x0A\0x41\0x0E | dh-public-num | \0x02\0x15\0x02\0x02\0x15\0x05\0x02\0x15\0x0E

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 keying

initiator 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 keying

responder 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:

shared secret = y2 ^ x1 % p

DH算法保证这个responder的sharedsecret和initiator的shared secret是一样的。

这时就可以生成这个session对应的加解密key了:

encode key = HMAC-SHA256(shared-secret, HMAC-SHA256(responder nonce,initiator nonce))

decode key = HMAC-SHA256(shared-secret, HMAC-SHA256(initiator nonce,responder nonce))

这些加解密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的意义如下:


bit


meaning


0x80


options域是否存在


0x40


0x20


这个包前面还有包


0x10


这个包后面还有包


0x08


0x04


0x02


丢弃包


0x01


结束包

l  flow-id:flow标识,varlen类型

l  forward-seq-offset:用于滑窗的标识,varlen类型

l  options:一些选项

l  data:audio、video和data数据

next user data包的payload格式如下:

payload = flags | data

字段定义同上

时间: 2024-10-01 22:28:45

flashP2P协议rtmfp解析的相关文章

UDT协议深入解析

将近两年以前因为想选择一个兼顾TCP协议的可靠性和UDP协议的高效性来进行我们某种数据的传输曾经选择过UDT协议,也进行了一段时间的学习.实践.但最终由于不适合我们的业务场景放弃了它,但它的实现原理.代码实现.拓展使用的优秀给我留下了很深刻的印象,今天翻出自己曾经的一篇总结笔记来和大家一起回顾下UDT协议. UDT协议是什么?是一种基于UDP的数据传输协议(UDP-based Data Transfer Protocol,简称UDT). UDT协议的主要作用是什么?UDT的主要目的是支持高速广域

TCP协议 状态解析和状态统计

一.三次握手和四次挥手 1.建立连接(三次握手) (1)服务器会处于listen状态,客户端发送一个带SYN标志的TCP报文到服务器. (2)服务器端回应客户端的请求,这是三次握手中的第2个报文,这个报文同时带SYN标志和ACK标志. 因此它表示对刚才客户端SYN报文的回应:同时又标志SYN给客户端,询问客户端是否准备好进行数据通讯. (3)客户必须再次回应服务段一个ACK报文,这个时候两端就处于已经建立连接 2.连接终止(四次握手) 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭.这

https协议了解,以及相关协议的解析

https协议了解,以及相关协议的解析 HTTPS简介 HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版.即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL. 它是一个URI scheme(抽象标识符体系),句法类同http:体系.用于安全的HTTP数据传输.https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP

SSDP协议内容解析

SSDP(Simple Service Discovery Protocol),简单服务发现协议,用于发现局域网里面的设备和服务. SSDP消息分为设备查询消息.设备通知消息两种,通常情况下,使用更多地是设备查询消息. 1.设备查询消息: 格式例子如下: M-SEARCH * HTTP/1.1 HOST: 239.255.255.250:1900 MAN: "ssdp:discover" MX: 5 ST: ssdp:all 其中第一行是消息头,固定:HOST对应的是广播地址和端口,2

C# 串口操作系列(3) -- 协议篇,二进制协议数据解析

C# 串口操作系列(3) -- 协议篇,二进制协议数据解析 标签: c#bufferobject通讯byte硬件驱动 2010-05-27 09:54 51565人阅读 评论(215) 收藏 举报  分类: 通讯类库设计(4)  版权声明:本文为博主原创文章,未经博主允许不得转载. 我们的串口程序,除了通用的,进行串口监听收发的简单工具,大多都和下位机有关,这就需要关心我们的通讯协议如何缓存,分析,以及通知界面. 我们先说一下通讯协议.通讯协议就是通讯双方共同遵循的一套规则,定义协议的原则是尽可

C# 串口操作系列(4) -- 协议篇,文本协议数据解析

C# 串口操作系列(4) -- 协议篇,文本协议数据解析 标签: c#uiobjectstringbyte 2010-06-09 01:50 19739人阅读 评论(26) 收藏 举报  分类: 通讯类库设计(4)  版权声明:本文为博主原创文章,未经博主允许不得转载. 上一篇已经介绍了协议的组成,一个协议,一般具有 :协议头+长度+数据+校验 , 文本格式可以直观的定义回车换行是协议的结尾,所以我们可以省略数据长度,增加协议尾.即: 协议头 + 数据 + 校验 + 数据尾 . 文本方式的数据比

TCP/IP协议全解析 三次握手与四次挥手[转]

所谓三次握手(Three-Way Handshake)即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立.所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开. AD:51CTO网+ 首届中国APP创新评选大赛火热招募中…… 一.TCP报文格式 TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图: 图1 TCP报文格式 上图中

从头写rtsp服务器-RTSP协议的解析

rtps demo(linux是64位的,windows32位的):rtsp_demo.rar 1.首先服务器收到客户端连接请求,生产 一个RtspClientConnection对象,RtspClientConnection定义详见  从头写rtsp服务器-模块的划分 int rtsp::v_accept(netconnection * n) { netoperation::v_accept(n); printf("client accept\n\n\n"); RtspClientC

RTP协议全解析(H264码流和PS流)

目录(?)[+] RTP Header解析 RTP荷载H264码流 1单个NAL单元包 2分片单元FU-A RTP荷载PS流 1PS包头 2系统标题 3节目映射流 4PES分组头部 写在前面:RTP的解析,网上找了很多资料,但是都不全,所以我力图整理出一个比较全面的解析, 其中借鉴了很多文章,我都列在了文章最后,在此表示感谢. 互联网的发展离不开大家的无私奉献,我决定从我做起,希望大家支持. 原创不易,转载请附上链接,谢谢http://blog.csdn.net/chen495810242/ar