Skip to main content
WebRTC opens UDP sockets outside the page’s HTTP connections. A page can read the addresses in its ICE candidates, and a peer or STUN server sees the address the packets come from. Apostate decides where that UDP goes from the proxy setup.

Where UDP goes

Behind SOCKS5, the relay needs a proxy that supports UDP ASSOCIATE. A SOCKS5 proxy that refuses it gets no UDP, as an HTTP proxy does. The browser logs each refusal with its reason. With UDP relayed through SOCKS5, host candidates carry the relay’s address, and a peer receives packets from the proxy’s exit. With no UDP socket, the page gets no UDP candidates and ICE gathering still completes. QUIC traffic takes the same route through a SOCKS5 proxy.

The switches

--fingerprint-webrtc-udp with any other value is logged and treated as block. --fingerprint-webrtc-ip changes only the candidate text. The browser does not check the value, and packets still leave from the socket’s real address, so a peer that receives them sees where they came from. Use it behind a SOCKS5 proxy, set to the exit’s address, so the candidate text and the packets agree.

The packages

The two packages differ behind a proxy: Behind a SOCKS5 proxy, a Python launch shows an mDNS name (<uuid>.local) in its host candidate, as stock Chrome does, and a Node launch shows the exit IP. Both relay UDP through the proxy. The Node package runs the GeoIP lookup behind a proxy even when you pass locale and timezone, to learn the exit IP. With geoip: false, or when the lookup fails, it sets no --fingerprint-webrtc-ip. To set the address yourself, for example from Python, pass the switch in args with the exit’s IP:
A --fingerprint-webrtc-ip in args replaces the one the Node package would set.

List the ICE candidates

This script gathers candidates against a public STUN server and prints them. It runs with --fingerprint-webrtc-ip=203.0.113.7, a documentation address, so the output shows no real address.
With --fingerprint-webrtc-udp=block in place of the address, the same script prints nothing. To check a proxied setup, remove the args line, add your proxy, and read each candidate:
  • typ host shows an mDNS name ending in .local, or the address --fingerprint-webrtc-ip set. It must not show the host’s real address.
  • typ srflx is the address the STUN server saw. It must be the proxy’s exit, the IP the proxy check prints.
  • No candidates at all means the proxy carries no UDP. Pages that use WebRTC for calls then fail, and a page can see that WebRTC gathered nothing. Known gaps tracks this.
Verify covers checking a launch with public test pages.