简介
WebRTC 技术主要适用于浏览器用户之间的视屏和语音通话技术,全称是 Web Real Time Connection,最先由谷歌提出,目前绝大多数浏览器都支持 WebRTC 技术。javascript
目前咱们获取浏览器 IP 相关的技术也是 WebRTC 标准的一部分:java
MediaStream
(aka getUserMedia)webRTCPeerConnection
正则表达式RTCDataChannel
shell
其中获取用户 IP 主要依靠 RTCPeerConnection 和 RTCDataChannel 两个 API,这两个 API 的支持状况以下:浏览器
大多数的浏览器都支持这两个 API。服务器
通讯原理
WebRTC 底层使用了 ICE 框架进行 P2P 通讯,ICE 框架的主要通讯组件有 STUN 和 TURN 服务器。微信
STUN server 主要用在创建 P2P 通讯阶段,协助双方完成 Signal 通讯,而 TURN server 主要协助企业复杂防火墙的状况下,数据中继的问题。框架
STUN 服务器
STUN 服务器是一台公网服务器,用来接收用户的链接,并回传 IP 和端口信息,STUN 服务器传递下去的是用户 NAT 网关的 IP 和端口信息,并将此信息传递至对端,以帮助其创建通讯链接,STUN 服务器和客户端使用 UDP 协议进行通讯。ide
STUN 服务器功能:
探测和发现通信对方是否躲在防火墙或者 NAT 路由器后面
肯定内网客户端所暴露在广域网的 IP 和端口以及 NAT 类型等信息; STUN 服务器利用这些信息协助不一样内网的计算机之间创建点对点的 UDP 通信
NAT 类型
NAT 对待 UDP 的实现方式有 4 种,分别以下:
Full Cone NAT
彻底锥形 NAT,全部从同一个内网 IP 和端口号发送过来的请求都会被映射成同一个外网 IP 和端口号,而且任何一个外网主机均可以经过这个映射的外网 IP 和端口号向这台内网主机发送包。
Restricted Cone NAT
限制锥形 NAT,它也是全部从同一个内网 IP 和端口号发送过来的请求都会被映射成同一个外网 IP 和端口号。与彻底锥形不一样的是,外网主机只可以向先前已经向它发送过数据包的内网主机发送包。
Port Restricted Cone NAT
端口限制锥形 NAT,与限制锥形 NAT 很类似,只不过它包括端口号。也就是说,一台 IP 地址 X 和端口 P 的外网主机想给内网主机发送包,必须是这台内网主机先前已经给这个 IP 地址 X 和端口 P 发送过数据包。
Symmetric NAT
对称 NAT,全部从同一个内网 IP 和端口号发送到一个特定的目的 IP 和端口号的请求,都会被映射到同一个 IP s 和端口号。若是同一台主机使用相同的源地址和端口号发送包,可是发往不一样的目的地,NAT 将会使用不一样的映射。此外,只有收到数据的外网主机才能够反过来向内网主机发送包。
UDP 打洞
对于锥形的 NAT,要采用 UDP 打洞,须要一个公网机器 C 来充当 “介绍人”,内网的 A、B 先分别和 C 通讯,打开各自的 NAT 端口,C 这个时候知道 A、B 的公网 IP:Port,如今 A 和 B 想直接链接,好比 A 给 B 发,除非 B 是 Full Cone,不然不能通讯,反之亦然。
A 要链接 B,A 给 B 发一个 UDP 包,同时,A 让那个介绍人 C 给 B 发一个命令,让 B 同时给 A 发一个 UDP 包,这样双方的 NAT 都会记录对方的 IP,而后就会容许互相通讯。
TURN 服务器
TURN 服务器主要解决 STUN 没法完成的 NAT 穿越工做,好比有些企业级的防火墙,可能不是锥形的,致使没法进行 P2P 通讯,这个时候须要一个中继服务器来中继数据进行通讯,辅助打洞, TURN 服务器也是一台公网的服务器。
WebRTC IP 获取
浏览器利用 WebRTC 通讯主要利用了 UDP 打洞阶段的通讯包。
通讯双方发送的信息包会放置到 description 字段中:
candidate:10426681 1 udp 2113937151 192.168.20.18 64810 typ \
host generation 0 ufrag tsFU network-cost 999
candidate:842163049 1 udp 1677729535 221.234.130.184 64810 typ \
srflx raddr 192.168.20.18 rport 64810 generation 0 ufrag tsFU \
network-cost 999
只须要从中间获取到其 IP 便可,一般使用正则表达式解析,可是协议中并无说明如何识别内网 IP 如何识别外网 IP。
IPV4 内网 IP CIDR
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
127.0.0.0/8
0.0.0.0/8
169.254.0.0/16
192.0.2.0/24
224.0.0.0/4
100.64.0.0/10
192.0.0.0/24
IPV6 内网 IP CIDR
fc00::/8
fd00::/8
::1/128
::/128
::ffff:0:0/96
fe80::/10
能够经过 CDIR 来判断什么是内网 IP 什么是外网 IP。
Javascript 使用 WebRTC
利用 javascript 代码获取 IP 信息,主要有三步:
初始化 RTCPeerConnection
创建数据管道 DataChannel
注册回调,解析 IP 数据
const getIPS = (e) => {
const o = /([0-9]{1,3}(\.[0-9]{1,3}){3}|\
(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|\
(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|\
((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|\
2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]\
{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|\
:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|\
2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]\
{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-\
Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\
(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|\
(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|\
((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|\
[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|\
:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|\
((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|\
[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|\
(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|\
((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|\
[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|\
:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|\
((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|\
[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))/;
const parseFlags = {};
if (e.candidate) {
try {
const t = o.exec(e.candidate.candidate)[1];
if (parseFlags[t] === undefined) {
console.log(e.candidate.candidate);
}
parseFlags[t] = !0;
} catch (s) {
console.log(s);
}
}
};
const webrct = () => {
// 初始化 WebRTC
const RTCConnection = (window.RTCPeerConnection || \
window.mozRTCPeerConnection || \
window.webkitRTCPeerConnection);
// 填写使用的 STUN server
const rctConnectionInstance = new RTCConnection({
iceServers: [
{urls: 'stun:stun.l.google.com:19302'},
{urls: 'stun:stun.services.mozilla.com:3478'},
{urls: 'stun:stun.qq.com:3478'}],
}, {optional: [{ RtpDataChannels: !0}] });
// 注册回调
rctConnectionInstance.onicecandidate = getIPS;
try {
rctConnectionInstance.createDataChannel('bl');
} catch (s) {
console.log(s);
}
try {
rctConnectionInstance.createOffer()
.then((e) => {
rctConnectionInstance.setLocalDescription(e, () => {
}, () => {
});
});
} catch (d) {
rctConnectionInstance.createOffer((e) => {
rctConnectionInstance.setLocalDescription(e, () => {
}, () => {
});
}, () => {
});
}
};
STUN 服务器列表
尽可能填写多个,防止出现一个不通的状况下,致使没法获取外网 IP 地址。
stun:stun01.sipphone.com
stun:stun.ekiga.net
stun:stun.fwdnet.net
stun:stun.ideasip.com
stun:stun.iptel.org
stun:stun.rixtelecom.se
stun:stun.schlund.de
stun:stun.l.google.com:19302
stun:stun1.l.google.com:19302
stun:stun2.l.google.com:19302
stun:stun3.l.google.com:19302
stun:stun4.l.google.com:19302
本文分享自微信公众号 - 茶歇小栈(smilehackerboy)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。