WebRTC 獲取內外網 IP


簡介

WebRTC 技術主要適用於瀏覽器用戶之間的視屏和語音通話技術,全稱是 Web Real Time Connection,最先由谷歌提出,目前絕大多數瀏覽器都支持 WebRTC 技術。javascript

目前咱們獲取瀏覽器 IP 相關的技術也是 WebRTC 標準的一部分:java

  • MediaStream(aka getUserMedia)web

  • RTCPeerConnection正則表達式

  • RTCDataChannelshell


其中獲取用戶 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 信息,主要有三步:

  1. 初始化 RTCPeerConnection

  2. 創建數據管道 DataChannel

  3. 註冊回調,解析 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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索