STUN
简介
- STUN(
Session Traversal Utilities for NAT)
,其主要作用就是进行NAT穿越
- B/S模式
RFC5389/STUN
协议结构
20B
的header- 消息体中可以有若干个属性
SUTN header
字段 | 大小 |
---|---|
Message Type 类型 | 2B |
Message Length 消息长度,不算header | 2B |
Magic Cookie 魔数 | 4B |
Transaction ID 事务ID | 12B |
Message Type
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--++--+--+--+-+-+-+-+-+-+-+-+-+-+-+-+
0 0 |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
|11|10|9|8|7|1|6|5|4|0|3|2|1|0|
+--+--+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 最低两位一定是
00
,主要是为了不同协议复用同一个端口时,用于标志这是STUN协议
C0
和C1
用于区别分类- 00 : 请求
- 10 : 成功的响应
- 11 : 失败的响应
M
占的12bit,用于不同请求的定义
4bit
为一组进行划分:
0 0 0 0 | 0 0 0 0 | 0 0 0 0 | 0 0 0 1 => 绑定的请求消息
0 0 0 0 | 0 0 0 1 | 0 0 0 0 | 0 0 0 1 => 成功响应消息
0 0 0 0 | 0 0 0 1 | 0 0 0 1 | 0 0 0 1 => 错误的绑定
Magic Cookie
固定为0x2112a442
,可以判断客户端是否支持特定的属性
Transaction ID
用于标志同一个事务的请求和响应
。
当客户端发送多个请求的时候,可以将请求和响应联系起来
SUTN Body
里面有若干个属性
,并且每个属性使用的是TLV
编码(Type-Length-Value)
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Value (variable) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
属性列表:略
TURN
简介
- 解决
对称NAT
穿越失败的问题 - 客户端如果无法正常穿越建立p2p的时候,将数据先传输给该
TURN服务器
,然后TURN服务器
当做中转的节点,传输给另外一个客户端 - 使用的消息格式和
STUN
一致
使用的传输协议
client -> turn server
- UDP
- TCP
- TLS over TCP
使用流程
- 绑定STUN
- 发起方进行对TURN 进行
Allocation request
- 发起方通过信令服务器发送
SDP offer
- 对端进行对TURN 进行
Allocation request
- 对端接收到发起方的
offer
后,通过信令服务器响应一个SDP answer
- 互相交换
candidate IP 端口
- 通过
ICE
框架检测是否能进行P2P
连接 - 如果无法使用P2P,则需要通过中继服务来进行数据的交换
turn server -> peer
UDP
工作原理
建立连接
- 此时,其它客户端想和
A
通信时,只需将数据传输到TURN的x端口
就可以了,该x
端口会进行消息的转发,传输给A
。 - 通过
Refresh request
进行保活操作,类似心跳包,如果超时没有接收到刷新请求,那么这个服务就算失效了
数据传输机制
Send + Data
- 和
TURN server
建立连接 A
向TURN server发送数据- TURN server收到数据以后,将TURN协议头去掉,拿到里面的原始
UDP数据
,直接通过分配的端口 ,发送给A的对端B - 如果B要给A发送数据,则B直接给TURN server分配的端口发送
UDP数据
- 当TURN server收到B发送的数据时,先将该数据添加上TURN协议消息头,再通过 Data 消息转发给A
Channel
建立管道,每次就可以不用传输头部信息
此时Send + Data
可以和Channel一起使用
抓包
在https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/中进行candidate获取和查看
使用wireshark进行stun/turn抓包
由图可知:
Binding Request
尝试进行stun绑定
Session Traversal Utilities for NAT
[Response In: 25]
Message Type: 0x0001 (Binding Request)
Message Length: 0
Message Cookie: 2112a442
Message Transaction ID: 7650576551702f45515a6f43
和上述协议结构一致,有消息类型、属性长度、魔数,以及事务ID
Allocate Request
Session Traversal Utilities for NAT
[Response In: 26]
Message Type: 0x0003 (Allocate Request)
Message Length: 8
Message Cookie: 2112a442
Message Transaction ID: 77593259697564687a5a4758
Attributes
REQUESTED-TRANSPORT: UDP
分配地址端口请求,请求一个能进行UDP通信的转发端口
Binding Success Response
Session Traversal Utilities for NAT
[Request In: 23]
[Time: 0.052215000 seconds]
Message Type: 0x0101 (Binding Success Response)
Message Length: 68
Message Cookie: 2112a442
Message Transaction ID: 7650576551702f45515a6f43
Attributes
XOR-MAPPED-ADDRESS: 42.49.169.5:3612
MAPPED-ADDRESS: 42.49.169.5:3612
RESPONSE-ORIGIN: 139.199.19.250:3478
SOFTWARE
绑定成功响应,返回了出NAT映射后的公网ip和端口,可发现该Transaction ID
和之前进行绑定请求的数据包中字段一致,所以这两个是相关联的。
Allocate Error
Session Traversal Utilities for NAT
[Request In: 24]
[Time: 0.040645000 seconds]
Message Type: 0x0113 (Allocate Error Response)
Message Length: 92
Message Cookie: 2112a442
Message Transaction ID: 77593259697564687a5a4758
Attributes
ERROR-CODE 401 (Unauthorized): Unauthorized
NONCE: ebdeedc2c1e79f7d
REALM: 139.199.19.250
SOFTWARE
第一次尝试请求分配中转端口的时候,没有带上验证信息,导致验证失败,当前的Transaction ID
和上面Allocate Request
的是相同的。
Allocate Request With username & password
当由于认证问题而请求分配失败时,带上验证信息去请求分配端口
Session Traversal Utilities for NAT
[Response In: 28]
Message Type: 0x0003 (Allocate Request)
Message Length: 80
Message Cookie: 2112a442
Message Transaction ID: 4d6d49786134713842376d2f
Attributes
REQUESTED-TRANSPORT: UDP
USERNAME: mao
REALM: 139.199.19.250
NONCE: ebdeedc2c1e79f7d
MESSAGE-INTEGRITY
这时是个新的事务,Transaction ID
也是和之前发送的数据包无关
Allocate Success Response
当带上验证信息以后,turn
服务器成功的为客户端分配了一个转发端口49974
Session Traversal Utilities for NAT
[Request In: 27]
[Time: 0.038153000 seconds]
Message Type: 0x0103 (Allocate Success Response)
Message Length: 88
Message Cookie: 2112a442
Message Transaction ID: 4d6d49786134713842376d2f
Attributes
XOR-RELAYED-ADDRESS: 139.199.19.250:49974
XOR-MAPPED-ADDRESS: 42.49.169.5:3612
LIFETIME 600
SOFTWARE
MESSAGE-INTEGRITY
保活
之后就是发refresh request
包来证明客户端并没有掉线了,服务端也会回复一个refresh response
包
Refresh Request
Session Traversal Utilities for NAT
[Response In: 30]
Message Type: 0x0004 (Refresh Request)
Message Length: 80
Message Cookie: 2112a442
Message Transaction ID: 41527766432f386d67685a6b
Attributes
LIFETIME 0
USERNAME: mao
REALM: 139.199.19.250
NONCE: ebdeedc2c1e79f7d
MESSAGE-INTEGRITY
Refresh Response
Session Traversal Utilities for NAT
[Request In: 29]
[Time: 0.032752000 seconds]
Message Type: 0x0104 (Refresh Success Response)
Message Length: 64
Message Cookie: 2112a442
Message Transaction ID: 41527766432f386d67685a6b
Attributes
LIFETIME 0
SOFTWARE
MESSAGE-INTEGRITY
debian下安装coturn
安装步骤
1.下载源码
# github上下载
git clone https://github.com/coturn/coturn
# 进入源码文件夹中
cd coturn
2.安装必要依赖
apt install g++
apt install libevent-dev
apt install libssl-dev
apt install make
2.配置安装目录,检查依赖
./configure --prefix=/usr/local/coturn
3.开始编译安装
# 编译
make -j 2
# 安装
make install
配置/运行
此时/usr/local/coturn/
就是coturn的安装路径:
bin etc include lib man share var
进入配置文件夹中
# 进入文件夹中
cd /usr/local/coturn/etc
# 拷贝一份样本然后编辑
cp turnserver.conf.default turnserver.conf
vim turnserver.conf
配置主要的参数:
参数名 | 例子 | 说明 |
---|---|---|
listening-port | 3478 | 监听端口 |
listening-ip | 10.104.250.191 | 内网ip |
external-ip | 139.199.19.250 | 外网ip |
user | mao:111111 | 账号密码验证 |
realm | 139.199.19.250 | 外网域名 |
cli-password | 111111 | 必须设置这个参数,否则会报错 |
添加环境变量
export PATH=$PATH:/usr/local/coturn/bin
运行coturn
# -c 后面是使用的配置文件路径
hohup coturn -c /usr/local/coturn/etc/turnserver.conf &
检测是否正常的部署了服务
进入网站
https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/
开始测试
填写好服务信息以后,点击Add Server
,然后点击Gather candidate
,就可以
在下面的表格中会出现每个candidate的详细信息