webrtc data channels

published: August 12, 2025
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:

  1. ice protocol for nat traversal using stun/turn servers
  2. dtls handshake for encrypted p2p connection
  3. sctp-over-dtls for reliable data delivery
  4. 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

implementationthroughputoverheadlatency
rtctunnel90-95% udp~5-10%+2-5ms
tor snowflake50-70% tcp~30-50%+50-100ms
native webrtc85-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
on this page