webrtc data channels
on this page
webrtc data channels provide peer-to-peer network tunneling using the webrtc datachannel api with dtls encryption and nat traversal capabilities.
technical description
webrtc (web real-time communication) uses dtls over udp for encryption with configurable ordered/unordered delivery. data channels provide a browser-based api for arbitrary data exchange between peers without server intermediaries.
the technique works by:
- ice protocol for nat traversal using stun/turn servers
- dtls handshake for encrypted p2p connection
- sctp-over-dtls for reliable data delivery
- custom application-level tunneling protocol
implementation: rtctunnel
overview
rtctunnel (https://github.com/rtctunnel/rtctunnel) implements p2p network tunnels using webrtc datachannels with:
- peer identification via public keys
- automatic nat traversal
- encrypted data transmission
- cross-platform support (go implementation)
- performance: 90-95% of udp throughput
installation
# from binary releases
wget https://github.com/rtctunnel/rtctunnel/releases/latest/download/rtctunnel-linux
chmod +x rtctunnel-linux
# from source
git clone https://github.com/rtctunnel/rtctunnel.git
cd rtctunnel
go build -o rtctunnel ./cmd/rtctunnel
server setup
# generate server keypair
rtctunnel genkey -o server.key
# extract public key
rtctunnel pubkey -k server.key > server.pub
# start server
rtctunnel server -k server.key -p 8080
client connection
# connect to server using public key
rtctunnel client -s wss://server.example.com:8080 \
  -k server.pub \
  -l 127.0.0.1:8022 \
  -r 127.0.0.1:22
# ssh through tunnel
ssh -p 8022 user@127.0.0.1
configuration
# rtctunnel.yaml
server:
  key_file: 'server.key'
  bind_addr: ':8080'
  ice_servers:
    - urls: ['stun:stun.l.google.com:19302']
client:
  server_url: 'wss://server.example.com:8080'
  server_pubkey_file: 'server.pub'
  local_addr: '127.0.0.1:8022'
  remote_addr: '127.0.0.1:22'
implementation: tor snowflake
overview
tor snowflake (https://github.com/keroserene/snowflake) routes traffic through webrtc to circumvent censorship:
- makes traffic appear as voice/video calls
- volunteer proxy network
- browser-based proxy support
- automatic failover mechanisms
proxy setup
// browser-based proxy
const snowflake = new Snowflake({
  brokerUrl: 'https://snowflake-broker.torproject.net/',
  relayAddr: {
    host: '127.0.0.1',
    port: 9902,
  },
});
snowflake.setRelayAddr('127.0.0.1', 9902);
snowflake.beginWebRTC();
tor configuration
# torrc configuration
clienttransportplugin snowflake exec ./client \
-url https://snowflake-broker.torproject.net/ \
-front cdn.sstatic.net \
-ice stun:stun.l.google.com:19302
standalone proxy
# compile snowflake proxy
git clone https://git.torproject.org/pluggable-transports/snowflake.git
cd snowflake/proxy
go build
# run proxy
./proxy -broker https://snowflake-broker.torproject.net/ \
  -relay wss://snowflake.torproject.net/ \
  -stun stun:stun.l.google.com:19302
implementation: torkameleon
overview
torkameleon (https://github.com/afonsovilalonga/torkameleon) provides:
- webrtc mimicry for tor traffic
- multiple transport protocols
- traffic shaping capabilities
- protocol obfuscation
configuration
{
  "transport": "webrtc",
  "ice_servers": [{ "urls": "stun:stun.l.google.com:19302" }],
  "signaling_server": "wss://signal.example.com",
  "obfuscation": true,
  "traffic_shaping": {
    "enabled": true,
    "pattern": "video_call"
  }
}
traffic characteristics
webrtc signaling
client -> signaling server: offer (sdp)
signaling server -> peer: offer
peer -> signaling server: answer (sdp)
signaling server -> client: answer
ice candidate exchange:
candidate:foundation priority type address port
data channel traffic
# packet analysis with scapy
from scapy.all import *
def analyze_webrtc_traffic(pcap_file):
    packets = rdpcap(pcap_file)
    # identify dtls handshakes
    dtls_packets = []
    for p in packets:
        if p.haslayer(UDP):
            payload = bytes(p[UDP].payload)
            # dtls content types: 20=change_cipher, 21=alert, 22=handshake, 23=application
            if len(payload) > 0 and payload[0] in [20, 21, 22, 23]:
                dtls_packets.append(p)
    print(f"found {len(dtls_packets)} potential dtls packets")
    # analyze packet timing and sizes
    sizes = [len(p) for p in dtls_packets]
    print(f"avg packet size: {sum(sizes)/len(sizes):.1f} bytes")
analyze_webrtc_traffic('webrtc_tunnel.pcap')
ice candidate leakage
// detect webrtc ip leakage
function getWebRTCIPs() {
  const ips = [];
  const rtc = new RTCPeerConnection({
    iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
  });
  rtc.createDataChannel('');
  rtc.onicecandidate = (e) => {
    if (e.candidate) {
      const ip = e.candidate.candidate.match(/(\d+\.\d+\.\d+\.\d+)/);
      if (ip) ips.push(ip[1]);
    }
  };
  rtc.createOffer().then(rtc.setLocalDescription.bind(rtc));
  return ips;
}
detection methods
traffic indicators
- unusual webrtc connection patterns outside media contexts
- high data volumes over data channels vs media streams
- ice candidate patterns suggesting automation
- dtls certificate anomalies
- persistent connections with low media traffic
detection rules
# suricata rule for webrtc tunneling
alert tls any any -> any any (
    msg:"suspicious webrtc data channel usage";
    tls.sni; content:"webrtc"; nocase;
    flow:established,to_server;
    threshold: type limit, track by_src, seconds 3600, count 100;
    sid:1000010;
)
behavioral analysis
# webrtc connection analysis
import json
from collections import defaultdict
def analyze_webrtc_connections(flows):
    webrtc_flows = []
    for flow in flows:
        # identify webrtc by port ranges and dtls
        if (flow['dst_port'] in range(10000, 65535) and
            flow['protocol'] == 'UDP' and
            'dtls' in flow.get('app_proto', '')):
            webrtc_flows.append(flow)
    # group by source ip
    src_connections = defaultdict(list)
    for flow in webrtc_flows:
        src_connections[flow['src_ip']].append(flow)
    # flag suspicious patterns
    for src_ip, flows in src_connections.items():
        if len(flows) > 10:  # many connections
            data_ratio = sum(f.get('bytes', 0) for f in flows) / len(flows)
            if data_ratio > 10000:  # high data per connection
                print(f"suspicious webrtc usage from {src_ip}")
# example usage with network flow data
flows = [
    {'src_ip': '192.168.1.10', 'dst_port': 45678, 'protocol': 'UDP',
     'app_proto': 'dtls', 'bytes': 150000},
    # ... more flows
]
analyze_webrtc_connections(flows)
countermeasures
network level
# block webrtc ports (dynamic range)
iptables -A FORWARD -p udp --dport 10000:65535 -m recent --update --seconds 10 --hitcount 50 -j DROP
# restrict stun/turn servers
iptables -A FORWARD -p udp --dport 3478 -j DROP  # standard stun
iptables -A FORWARD -p tcp --dport 3478 -j DROP  # stun over tcp
iptables -A FORWARD -p udp --dport 5349 -j DROP  # stuns (secure)
application level
// disable webrtc in browser policies
{
  "WebRtcUdpPortRange": "",
  "WebRtcLocalIpsAllowedUrls": [],
  "DefaultWebRtcUdpPortRange": ""
}
monitoring
# monitor webrtc connections
ss -tuln | grep -E ":(10000|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])"
# analyze dtls certificates
tshark -r webrtc_traffic.pcap -Y "dtls.handshake.type == 11" \
  -T fields -e dtls.handshake.certificate
advantages and limitations
advantages
- true peer-to-peer communication
- strong encryption (dtls)
- nat traversal capabilities
- browser-based deployment
- appears as legitimate media traffic
- difficult to block without breaking voip/video
limitations
- requires signaling server infrastructure
- ice negotiation can reveal ip addresses
- limited by webrtc browser policies
- stun/turn servers may be blocked
- higher overhead than raw protocols
performance metrics
bandwidth comparison
| implementation | throughput | overhead | latency | 
|---|---|---|---|
| rtctunnel | 90-95% udp | ~5-10% | +2-5ms | 
| tor snowflake | 50-70% tcp | ~30-50% | +50-100ms | 
| native webrtc | 85-95% udp | ~5-15% | +1-3ms | 
connection establishment
# measure webrtc connection time
start_time=$(date +%s%3N)
# ... webrtc connection code ...
end_time=$(date +%s%3N)
echo "connection time: $((end_time - start_time))ms"
# typical times:
# ice gathering: 1-3 seconds
# dtls handshake: 200-500ms
# data channel open: 100-200ms
browser integration
chrome extension
// manifest.json
{
  "permissions": ["webRequest", "webRequestBlocking", "*://*/*"],
  "background": {
    "scripts": ["background.js"]
  }
}
// background.js - webrtc tunnel proxy
chrome.webRequest.onBeforeRequest.addListener(
  function(details) {
    if (details.url.includes('target-domain.com')) {
      // redirect through webrtc tunnel
      return {redirectUrl: 'http://localhost:8080' + details.url.pathname};
    }
  },
  {urls: ["<all_urls>"]},
  ["blocking"]
);
firefox addon
// background script
function setupWebRTCTunnel() {
  const pc = new RTCPeerConnection({
    iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
  });
  const dc = pc.createDataChannel('tunnel', {
    ordered: true,
  });
  dc.onopen = () => {
    console.log('webrtc tunnel established');
    // proxy browser requests through data channel
  };
  return pc;
}
real-world usage
censorship circumvention
- tor snowflake: 10,000+ daily users
- webrtc proxies: widespread in restrictive countries
- voice-over-ip mimicry: blends with legitimate traffic
enterprise environments
- rtctunnel: remote access through firewalls
- peer-to-peer file sharing: direct transfers
- collaborative tools: whiteboard/document sharing
testing setup
local development
# setup test environment
git clone https://github.com/rtctunnel/rtctunnel.git
cd rtctunnel
# generate test keys
./rtctunnel genkey -o test.key
./rtctunnel pubkey -k test.key > test.pub
# start local server
./rtctunnel server -k test.key -p 8080 &
# test client connection
./rtctunnel client -s ws://localhost:8080 -k test.pub \
  -l 127.0.0.1:2222 -r 127.0.0.1:22
# verify tunnel
ssh -p 2222 localhost
performance testing
# bandwidth test through webrtc tunnel
iperf3 -s &
iperf3 -c 127.0.0.1 -p 2222 -t 60
# latency measurement
ping -c 100 -i 0.1 127.0.0.1 | grep avg
references
- rfc 8831: webrtc data channels
- rfc 8445: interactive connectivity establishment (ice)
- rfc 6347: datagram transport layer security (dtls)
- “webrtc security analysis” - ietf security considerations
- tor project snowflake documentation