Это Proof of Concept: использование звонков (WebRTC) в одном из самых безопасных мессенджеров в России как транспорта для проксирования трафика.
Идея:
- есть устойчивый зашифрованный канал связи между двумя клиентами (звонок + datachannel),
- на уровне браузера мы подцепляемся к datachannel (через инжект),
- поверх этого канала строим обычный HTTP proxy: локально на машине A, с выходом в интернет на машине B.
Цель PoC: показать, что звонок можно использовать как универсальный двусторонний транспорт для байтов, поверх которого поднимаются привычные сетевые примитивы (TCP, HTTP CONNECT, прокси).
Идея: поднять локальный HTTP proxy на машине A (go1), а выход в интернет делать с машины B (go2) через WebRTC datachannel. Между браузером и Go процессами используется WebSocket.
Схема:
- Tab A: WebRTC datachannel <-> WS
127.0.0.1:9000/ws<->go1(HTTP proxy127.0.0.1:8080) - Tab B: WebRTC datachannel <-> WS
127.0.0.1:9001/ws<->go2(egress TCP dial)
На сервере (машина B):
cd ~/max
go run ./go2Локально (машина A):
cd /path/to/max
go run ./go1 -proxy-listen 127.0.0.1:8080Нужно 2 вкладки (A и B), в каждой открыть DevTools Console и вставить соответствующий инжект.
Важно: инжект нужно вставлять до установления WebRTC соединения (то есть до начала/подключения к звонку). Если вставить после, RTCPeerConnection и datachannel уже могут быть созданы, и хук не сработает.
(() => {
const LABEL = "customBytes";
const ID = 2;
let dc = null, readyResolve;
window.__dcReady = new Promise(res => readyResolve = res);
const ws = new WebSocket("ws://127.0.0.1:9000/ws");
ws.binaryType = "arraybuffer";
function attach(ch){
dc = ch; window.__dc = ch;
dc.binaryType = "arraybuffer";
dc.addEventListener("open", () => {
console.log("[DC] open A");
readyResolve(ch);
});
dc.addEventListener("message", (e) => {
if (ws.readyState === 1) ws.send(e.data);
window.__onDcMessage?.(e.data);
});
}
const Orig = window.RTCPeerConnection;
window.RTCPeerConnection = function (...args) {
const pc = new Orig(...args);
pc.addEventListener("datachannel", (ev) => {
if (ev.channel?.label === LABEL) attach(ev.channel);
});
try { attach(pc.createDataChannel(LABEL, { negotiated: true, id: ID })); } catch (_) {}
return pc;
};
window.RTCPeerConnection.prototype = Orig.prototype;
ws.onmessage = (e) => dc?.readyState === "open" && dc.send(e.data);
ws.onopen = () => console.log("[WS] open A");
window.__dcSend = (buf) => dc?.readyState === "open" && dc.send(buf);
})();(() => {
const LABEL = "customBytes";
const ID = 2;
let dc = null, readyResolve;
window.__dcReady = new Promise(res => readyResolve = res);
const ws = new WebSocket("ws://127.0.0.1:9001/ws");
ws.binaryType = "arraybuffer";
function attach(ch){
dc = ch; window.__dc = ch;
dc.binaryType = "arraybuffer";
dc.addEventListener("open", () => {
console.log("[DC] open B");
readyResolve(ch);
});
dc.addEventListener("message", (e) => {
if (ws.readyState === 1) ws.send(e.data);
window.__onDcMessage?.(e.data);
});
}
const Orig = window.RTCPeerConnection;
window.RTCPeerConnection = function (...args) {
const pc = new Orig(...args);
pc.addEventListener("datachannel", (ev) => {
if (ev.channel?.label === LABEL) attach(ev.channel);
});
try { attach(pc.createDataChannel(LABEL, { negotiated: true, id: ID })); } catch (_) {}
return pc;
};
window.RTCPeerConnection.prototype = Orig.prototype;
ws.onmessage = (e) => dc?.readyState === "open" && dc.send(e.data);
ws.onopen = () => console.log("[WS] open B");
window.__dcSend = (buf) => dc?.readyState === "open" && dc.send(buf);
})();Когда оба инжекта вставлены, инициируй звонок/подключение к звонку и дождись логов в консоли вкладок: [WS] open ... и [DC] open ....
После того как обе вкладки показали [WS] open ... и [DC] open ..., можно делать запросы через proxy на машине A:
curl -x http://127.0.0.1:8080 https://api.ipify.orgОжидаемо: вернется публичный IP машины B (сервер).
В реальных условиях стабильные ~25 Mbit/s выглядят нормально для этого PoC, но иногда бывает разрыв соединения (connection loss).
go1 и go2 по умолчанию печатают счетчики байт по транспорту:
Флаги:
-stats=true|false-stats-interval=5s







