WebRTC网络基础

WebRTC网络基础

1.NAT协议

是将IP数据报头中的IP地址转换为另一个IP地址的过程。

作用:

  1. 在实际应用中,NAT主要用于实现私有网络访问公共网络的功能。这种通过使用少量的公网IP地址代表较多的私网IP地址的方式,将有助于减缓可用IP地址空间的枯竭。
  2. 出于安全考虑 外网想要攻击内网就需要经过网关 部分就会被过滤

种类:

  • 完全锥型 无限制

    内网主机建立一个UDP socket(LocalIP:LocalPort) 第一次使用这个socket给外部主机发送数据时NAT会给其分配一个公网(PublicIP:PublicPort),以后用这个socket向外面任何主机发送数据都将使用这对(PublicIP:PublicPort)。此外,任何外部主机只要知道这个(PublicIP:PublicPort)就可以发送数据给(PublicIP:PublicPort),内网的主机就能收到这个数据包。

    其在NAT上建立的内外网的映射表如下:

    {

    内网:IP,

    内网端口,

    映射的外网IP,

    映射的外网端口

    }

    • C1,C2向STUN发消息
    • 交换公网IP及端口
  • 地址限制型

    内网主机建立一个UDP socket(LocalIP:LocalPort) 第一次使用这个socket给外部主机发送数据时NAT会给其分配一个公网(PublicIP:PublicPort),以后用这个socket向外面任何主机发送数据都将使用这对(PublicIP:PublicPort)。此外,如果任何外部主机想要发送数据给这个内网主机,只要知道这个(PublicIP:PublicPort)并且内网主机之前用这个socket曾向这个外部主机IP发送过数据。只要满足这两个条件,这个外部主机就可以用自己的**(IP,任何端口)**发送数据给(PublicIP:PublicPort),内网的主机就能收到这个数据包。

    其在NAT上建立的内外网的映射表如下:

    {

    内网:IP,

    内网端口,

    映射的外网IP,

    映射的外网端口,

    被访问主机的IP

    }

    • C1向C2发请求 C2通过C1发的请求返回数据
    • 交换公网IP及端口 端口限制型类似
  • 端口限制型

    内网主机建立一个UDP socket(LocalIP:LocalPort) 第一次使用这个socket给外部主机发送数据时NAT会给其分配一个公网(PublicIP:PublicPort),以后用这个socket向外面任何主机发送数据都将使用这对(PublicIP:PublicPort)。此外,如果任何外部主机想要发送数据给这个内网主机,只要知道这个(PublicIP:PublicPort)并且内网主机之前用这个socket曾向这个外部主机(IP,Port)发送过数据。只要满足这两个条件,这个外部主机就可以用自己的**(IP,Port)**发送数据给(PublicIP:PublicPort),内网的主机就能收到这个数据包

    其在NAT上建立的内外网的映射表如下:

    {

    内网:IP,

    内网端口,

    映射的外网IP,

    映射的外网端口,

    被访问主机的IP,

    被访问主机的端口

    }

  • 对称型

    内网主机建立一个UDP socket(LocalIP,LocalPort),当用这个socket第一次发数据给外部主机1时,NAT为其映射一个(PublicIP-1,Port-1),以后内网主机发送给外部主机1的所有数据都是用这个(PublicIP-1,Port-1),如果内网主机同时用这个socket给外部主机2发送数据,第一次发送时,NAT会为其分配一个(PublicIP-2,Port-2), 以后内网主机发送给外部主机2的所有数据都是用这个(PublicIP-2,Port-2).如果NAT有多于一个公网IP,则PublicIP-1和PublicIP-2可能不同,如果NAT只有一个公网IP,则Port-1和Port-2肯定不同,也就是说一定不能是PublicIP-1等于 PublicIP-2且Port-1等于Port-2。此外,如果任何外部主机想要发送数据给这个内网主机,那么它首先应该收到内网主机发给他的数据,然后才能往回发送,否则即使他知道内网主机的一个(PublicIP,Port)也不能发送数据给内网主机,这种NAT无法实现UDP-P2P通信。

    • 端口猜测
  • 穿越组合

    • 端口受限 --> 对称
    • 对称 --> 对称 二者无法打通

2.STUN服务

(Simple Traversal of User Datagram Protocol (UDP) Through Network Address Translators (NATs))
STUN(穿越NAT的简单UDP传输)服务器允许所有的NAT客户终端(如防火墙后边的计算机)与位于局区域网以外的VOIP服务商实现电话通话。
其允许应用程序发现自己和公网之间的中间件类型,同时也能允许应用程序发现自己被NAT分配的公网IP。

协议内容

  • STUN header

    img

    • 2个字节类型

    • 2个字节消息长度,不包括消息头

    • 16个字节事务ID(128bit),请求与相应事务ID相同

      STUN Message Type:

      1. 最高的2位必须置零,这可以在当STUN和其他协议复用的时候,用来区分STUN包和其他协议数据包。

      2. STUN Message Type 字段定义了消息的类型( 请求/成功响应/失败响应/指示)和消息的主方法。
        虽然我们有4个消息类别,但在STUN中只有两种类型的事务,即请求/响应类型和指示类型。响应类型分为成功和出错两种,用来帮助快速处理STUN信息。Message Type字段又可以进一步分解为如下结构:

        img

        MessageClass定义:0b00表示request,0b01表示indication,0b10表示success response,0b11表示error response

      3. Message Length 字段存储了信息的长度,以字节为单位,不包括20字节的STUN头部。由于所有的STUN属性都是都是4字节对齐(填充)的,因此这个字段最后两位应该恒等于零,这也是辨别STUN包的一个方法之一。

      4. Magic Cookie 字段包含固定值0x2112A442,**这是为了前向兼容RFC3489,因为在RFC3489/STUN中,这一区域是事务ID的一部分。另外选择固定数值也是为了服务器判断客户端是否能识别特定的属性。**还有一个作用就是在协议多路复用时候也可以将其作为判断标志之一。(32位)

      5. Transaction ID

        字段是个96位的标识符,用来区分不同的STUN传输事务。

        对于request/response传输,事务ID由客户端选择,服务器收到后以同样的事务ID返回response;对于indication则由发送方自行选择。事务ID的主要功能是把request和response联系起来,同时也在防止攻击方面有一定作用。服务端也把事务ID当作一个Key来识别不同的STUN客户端,因此必须格式化且随机在0~2^(96-1)之间。重发同样的request请求时可以重用相同的事务ID,但是客户端进行新的传输时,必须选择一个新的事务ID。

  • STUN Message Body

    • 通常跟着0个或者多个属性,每个属性必须是TLV编码的(Type-Length-Value)

    img

3.TURN服务

1
TURN的全称为Traversal Using Relays around NAT,是STUN/RFC5389的一个拓展,主要添加了Relay功能。如果终端在NAT之后, 那么在特定的情景下,有可能使得终端无法和其对等端(peer)进行直接的通信,这时就需要公网的服务器作为一个中继, 对来往的数据进行转发。这个转发的协议就被定义为TURN。TURN和其他中继协议的不同之处在于,它允许客户端使用同一个中继地址(relay address) 与多个不同的peer进行通信。

整体流程
img
TURN Allocate
img

4.NAT类型检测

前提条件

1
有一个公网的Server并且绑定了两个公网IP(IP-1,IP-2)。这个Server做UDP监听(IP-1,Port-1),(IP-2,Port-2)并根据客户端的要求进行应答。

为什么使用UDP协议

因为UDP是无连接协议,只要你发送数据给他,他就可以收到,而TCP需要建立连接

步骤

客户端发送ECHO请求给服务端  客户端等待服务端返回数据

NAT打洞步骤

5.ICE框架

1
2
3
4
webrtc就是通过 ICE 这套框架来处理复杂的网络环境的。
如果想启用这个功能,你必须让你的应用程序传 ICE 服务器的URL:
ICE试着找最好的路径来让客户端建立连接,他会尝试所有可能的选项,然后选择最合适的方案。
ICE首先尝试P2P连接(STUN),如果失败就会通过TURN服务器进行转接。

介绍

1. ICE 的角色

分为 controlling和controlled。

offer 一方为controlling角色,answer一方为controlled角色。

2. ICE的模式

分为FULL ICE和Lite ICE:

FULL ICE:是双方都要进行连通性检查,完成的走一遍流程。

Lite ICE: 在FULL ICE和Lite ICE互通时,只需要FULL ICE一方进行连通性检查, Lite一方只需回应response消息。这种模式对于部署在公网的设备比较常用。

3. ICE Candidate

媒体传输的候选地址(包括协议,ip,端口,类型),组成candidate pair做连通性检查,确定传输路径。(ICE主要收集Candidate 对Candidate pair做排序 以及连通性)

  • 主机候选者(本机的)
  • 映射候选者(NAT映射的)
  • 中继候选者(TURN服务器开通的)

4. Componet ID

传输媒体的类型,1代表RTP;2代表 RTCP。

WebRTC采用Rtcp-mux方式,也就是RTP和RTCP在同一通道内传输,减少ICE的协商和通道的保活。

5. Type

(Host/Srvflx/Relay/Prflx)

6. Checklist

由candidate pair生成按优先级排序的链表,用于ICE连通性检查。

7. Validlist

由连通性检查成功的candidate pair按优先级排序的链表,用于ICE提名和选择最终路径。

8. Base

是指候选者的基础地址(Srvflx address 的base 是本地host address。

host address和 relayed address 的base 是自身。)

9. SDP协议

是一种通用的会话描述协议,主要用来描述多媒体会话,用途包括会话声明、会话邀请、会话初始化等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
SDP的每行都是<type>=<value>的形式

v=0 协议版本号

o=alice 2890844526 2890844526 IN IP4 host.anywhere.com 会话发起者
其中o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
username:发起者的用户名,不允许存在空格,如果应用不支持用户名,则为-。
sess-id:会话id,由应用自行定义,规范的建议是NTP(Network Time Protocol)时间戳。
sess-version:会话版本,用途由应用自行定义,只要会话数据发生变化时(比如编码),sess-version随着递增就行。同样的,规范的建议是NTP时间戳。
nettype:网络类型,比如IN表示Internet。
addrtype:地址类型,比如IP4、IV6
unicast-address:域名,或者IP地址。

s= 会话名(不能为空 可以赋一个空格)

c=IN IP4 host.anywhere.com
连接数据 c=<nettype> <addrtype> <connection-address>
nettype:网络类型,比如IN,表示 Internet。
addrtype:地址类型,比如IP4、IP6。
connection-address:如果是广播,则为广播地址组;如果是单播,则为单播地址;

t=0 0
时间 作用:声明会话的开始、结束时间。 t=<start-time> <stop-time>

m=audio 49170 RTP/AVP 0
媒体描述 m=<media> <port> <proto> <fmt> ...
media:媒体类型。包括 video、audio、text、application、message等。
port:传输媒体流的端口,具体含义取决于使用的网络类型(在c=中声明)和使用的协议(proto,在m=中声明)。
proto:传输协议,具体含义取决于c=中定义的地址类型,比如c=是IP4,那么这里的传输协议运行在IP4之上。比如:
UDP:传输层协议是UDP。
RTP/AVP:针对视频、音频的RTP协议,跑在UDP之上。
RTP/SAVP:针对视频、音频的SRTP协议,跑在UDP之上。
fmt:媒体格式的描述,可能有多个。根据 proto 的不同,fmt 的含义也不同。比如 proto 为 RTP/SAVP 时,fmt 表示 RTP payload 的类型。如果有多个,表示在这次会话中,多种payload类型可能会用到,且第一个为默认的payload类型。
例如:m=video 9 UDP/TLS/RTP/SAVPF 122 102 100 101 124 120 123 119

a=rtpmap:0 PCMU/8000
附加属性 作用:用于扩展SDP。
作用:用于扩展SDP。

有两种作用范围:会话级别(session-level)、媒体级别(media-level)。
媒体级别:媒体描述(m=)后面可以跟任意数量的 a= 字段,对媒体描述进行扩展。
会话级别:在第一个媒体字段(media field)前,添加的 a= 字段是会话级别的。
有如下两种格式:
a=<attribute> a=recvonly
a=<attribute>:<value> a=rtpmap:0 PCMU/8000

m=video 51372 RTP/AVP 31

a=rtpmap:31 H261/90000

m=video 53000 RTP/AVP 32

a=rtpmap:32 MPV/90000

ICE过程

1. Gather candidates

根据Componet ID获取所有候选者 同时生成foundation foundation是用于判断candiadate是否相同

2. 删除重复的候选者

如果两个候选者地址,Base地址一样 则删除

3. 交换candidates

ICE使用offer/answer的方式,双方通过SDP协商交换candidates信息。

Candidate信息包括type,foundation,base,component id,transport。

SDP a行格式如下:

1
a=candidate:1 1 UDP 9654321 212.223.223.223 12345 typ srflx raddr 10.216.33.9 rport 54321

表示 foundation为1,媒体是RTP,采用UDP协议,公网映射地址为212.223.223.223:12345,优先级为9654321,type为srflx,base地址为10.216.33.9:54321。

4. 生成candidate pairs

在本端收到远端candidates后,将Component ID和transport protocol相同的candidates组成pair。
修整candidate pair,如果是srvflx地址,则需要用其base地址替换。
对端也是同样的流程。

5. 生成checklist

将candidate pairs按照优先级排序,生成checklist,供连通性检查使用

6. 连通性检查

Ordinary checks 两端都按照各自checklist分别进行检查。

Triggered checks 收到对端的检查时,也在对应的candidate pair上发起连通性检查,以提高效率

如果checklist里有relay candidate,则必须首先为relay candidate创建permission。

7. 发送连通性检查请求

8. 生成validlist

9. 提名candidate pair

10. 选择最终传输地址

网络协议分析 (tcpdump 与 wireshark)

tcpdump

tcpdump tcp -i eth1 -t -s 0 -c 100 and dst port ! 22 and src net 192.168.1.0/24 -w ./target.cap
其中:
tcp: ip icmp arp rarp 和 tcp、udp、icmp这些选项等都要放到第一个参数的位置,用来过滤数据报的类型
-i eth1 : 只抓经过接口eth1的包
-t : 不显示时间戳
-s 0 : 抓取数据包时默认抓取长度为68字节。加上-S 0 后可以抓到完整的数据包
-c 100 : 只抓取100个数据包
dst port ! 22 : 不抓取目标端口是22的数据包
src net 192.168.1.0/24 : 数据包的源网络地址为192.168.1.0/24
-w ./target.cap : 保存成cap文件,方便用ethereal(即wireshark)分析

搭建TRUN服务器

1. 下载并安装libevent-2.0

1
2
3
4
wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
tar zxvf libevent-2.0.21-stable.tar.gz
cd libevent-2.0.21-stable && ./configure
make && make install

2. 下载编译安装coturn

1
2
3
4
5
6
7
git clone https://github.com/coturn/coturn
cd coturn
./configure
make
make install
查看是否安装成功
which turnserver

3. 配置文件

在/usr/local/etc/目录下有turnserver.conf.default,复制为turnserver.conf

1
2
cd /usr/local/etc/
cp turnserver.conf.default turnserver.conf

使用ifcongig查询网卡名称和内网地址

4. 生成签名证书

1
2
3
yum install openssl 
openssl req -x509 -newkey rsa:2048 -keyout /etc/turn_server_pkey.pem -out /etc/turn_server_cert.pem -days 99999 -nodes
生成的两个文件一般在/etc/目录下

5. 修改配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
relay-device=eth0   #与前ifconfig查到的网卡名称一致
listening-ip=xxx #内网IP
listening-port=3478
tls-listening-port=5349
relay-ip=xxx #内网IP
external-ip=xxx #公网IP
relay-threads=50
lt-cred-mech
cert=/etc/turn_server_cert.pem
pkey=/etc/turn_server_pkey.pem
pidfile=”/var/run/turnserver.pid”
min-port=49152
max-port=65535
user=hxh:123456 #用户名密码,创建IceServer时用

6. 开启turnserver,执行命令

1
turnserver -o -a -f -user=zjf:123456 -r Guangdong

7. 在阿里云后台的安全组规则中添加用到的端口,包括3478端口的tcp/udp

1
2
3
4
5
6
7
8
或者使用命令行
添加
firewall-cmd --zone=public --add-port=3478/udp --permanent
firewall-cmd --zone=public --add-port=3478/tcp --permanent
重新载入
firewall-cmd --reload
重启防火墙
systemctl restart firewalld

8. 在浏览器中打开https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/进行验证

如果返回relay类型的数据且最终为Done则说明测试成功
需要注意的是:在Chrome中测试虽然同样会返回relay数据但会报一些错误

1
2
3
4
5
Note: errors from onicecandidateerror above are not neccessarily fatal. For example an IPv6 DNS lookup may fail but relay candidates can still be gathered via IPv4.
The server stun:47.115.206.47:3478 returned an error with code=701:
STUN server address is incompatible.
The server stun:stun.l.google.com:19302 returned an error with code=701:
STUN host lookup received error.

但是在firfox中则不会存在这个问题,但无论如何均不影响使用。


WebRTC网络基础
https://jing-jiu.github.io/jing-jiu/2021/12/25/其他/WebRTC网络基础/
作者
Jing-Jiu
发布于
2021年12月25日
许可协议