Client generates SDP with "IN IP4 0.0.0.0", causing proxy to send "client_ip=0.0.0.0" and bridge to send "USERADDR 0.0.0.0:1"
There is a pipeline of relaying the client IP address:
- The proxy infers the client's IP address by grepping it out of the SDP during ICE negotiation (proxy, proxy-go) and attaches it to the WebSocket connection as a URL query parameter
?client_ip=A.B.C.D
. - The bridge parses the
client_ip
query parameter and passes it on to tor with aUSERADDR A.B.C.D:1
command on the ExtORPort. - tor does geoip lookups and aggregates statistics and ultimately sends them to Tor Metrics for country-specific graphs.
It looks like the pion SDP code puts 0.0.0.0
in the place where proxy and proxy-go look for the remote IP address. This causes the proxy to send ?client_ip=0.0.0.0
to the bridge, and the bridge to send USERADDR 0.0.0.0:1
to tor. I'm not sure that this happens every time; see below for bridge-extra-infos output.
I found it while testing proxy-go with a localhost client and a patch like:
--- a/proxy-go/snowflake.go
+++ b/proxy-go/snowflake.go
@@ -22,3 +22,3 @@ import (
"git.torproject.org/pluggable-transports/snowflake.git/common/messages"
- "git.torproject.org/pluggable-transports/snowflake.git/common/safelog"
+ _ "git.torproject.org/pluggable-transports/snowflake.git/common/safelog"
"git.torproject.org/pluggable-transports/snowflake.git/common/websocketconn"
@@ -93,3 +93,3 @@ func (c *webRTCConn) Write(b []byte) (int, error) {
// log.Printf("webrtc Write %d %+q", len(b), string(b))
- log.Printf("Write %d bytes --> WebRTC", len(b))
+ // log.Printf("Write %d bytes --> WebRTC", len(b))
if c.dc != nil {
@@ -114,2 +114,3 @@ func (c *webRTCConn) RemoteAddr() net.Addr {
clientIP := remoteIPFromSDP(c.pc.RemoteDescription().SDP)
+ log.Printf("RemoteAddr %+q", c.pc.RemoteDescription().SDP)
if clientIP == nil {
@@ -322,3 +323,3 @@ func makePeerConnectionFromOffer(sdp *webrtc.SessionDescription, config webrtc.C
dc.OnMessage(func(msg webrtc.DataChannelMessage) {
- log.Printf("OnMessage <--- %d bytes", len(msg.Data))
+ // log.Printf("OnMessage <--- %d bytes", len(msg.Data))
var n int
@@ -432,3 +433,4 @@ func main() {
//We want to send the log output through our scrubber first
- log.SetOutput(&safelog.LogScrubber{Output: logOutput})
+ // log.SetOutput(&safelog.LogScrubber{Output: logOutput})
+ log.SetOutput(logOutput)
For example, the beginning of an SDP string for me is
v=0
o=- 34318359 1580881353 IN IP4 0.0.0.0
s=-
t=0 0
a=fingerprint:sha-256 80:EE:E6:8D:55:07:CB:52:58:7A:CC:61:70:F9:F3:65:DB:4B:D3:69:CB:F9:68:C8:5F:E3:06:3D:D3:90:C1:E6
a=group:BUNDLE 0
m=application 9 DTLS/SCTP 5000
c=IN IP4 0.0.0.0
The client IP address inference, implemented in legacy/trac#18628 (moved), was always a bit of a hack, but it was effective enough, as evidenced by country counts in comment:4:ticket:29734. I just now looked at bridge-extra-infos-2020-02.tar.xz and it seems that we are still sometimes getting identified countries, but the largest count belongs to ??
.
$ tar -O -xf bridge-extra-infos-2020-02.tar.xz | grep -A 24 '^extra-info flakey 5481936581E23D2D178105D44DB6915AB06BFB7F$' | grep -E '^dirreq-v3-reqs '
dirreq-v3-reqs ??=16,tr=16,cn=8,de=8,eg=8,in=8,ir=8,ph=8,us=8
dirreq-v3-reqs ??=16,tr=16,cn=8,de=8,eg=8,in=8,ir=8,ph=8,us=8
dirreq-v3-reqs ??=24,cn=8,es=8,fr=8,ir=8,tr=8
dirreq-v3-reqs ??=48,tr=16,ar=8,ca=8,eg=8,gb=8,ir=8,us=8
dirreq-v3-reqs ??=16,tr=16,cn=8,de=8,eg=8,in=8,ir=8,ph=8,us=8
dirreq-v3-reqs ??=24,cn=8,es=8,fr=8,ir=8,tr=8
dirreq-v3-reqs ??=48,tr=16,ar=8,ca=8,eg=8,gb=8,ir=8,us=8
dirreq-v3-reqs ??=24,cn=8,es=8,fr=8,ir=8,tr=8
dirreq-v3-reqs ??=24,cn=8,es=8,fr=8,ir=8,tr=8
dirreq-v3-reqs ??=24,cn=8,es=8,fr=8,ir=8,tr=8
dirreq-v3-reqs ??=48,tr=16,ar=8,ca=8,eg=8,gb=8,ir=8,us=8
dirreq-v3-reqs ??=16,tr=16,cn=8,de=8,eg=8,in=8,ir=8,ph=8,us=8
dirreq-v3-reqs ??=24,cn=8,es=8,fr=8,ir=8,tr=8
dirreq-v3-reqs ??=48,tr=16,ar=8,ca=8,eg=8,gb=8,ir=8,us=8
dirreq-v3-reqs ??=16,tr=16,cn=8,de=8,eg=8,in=8,ir=8,ph=8,us=8
dirreq-v3-reqs ??=16,tr=16,cn=8,de=8,eg=8,in=8,ir=8,ph=8,us=8
dirreq-v3-reqs ??=24,cn=8,es=8,fr=8,ir=8,tr=8
dirreq-v3-reqs ??=16,tr=16,cn=8,de=8,eg=8,in=8,ir=8,ph=8,us=8
dirreq-v3-reqs ??=24,cn=8,es=8,fr=8,ir=8,tr=8
dirreq-v3-reqs ??=24,tr=16,fr=8,om=8,ru=8,us=8
dirreq-v3-reqs ??=16,tr=16,cn=8,de=8,eg=8,in=8,ir=8,ph=8,us=8
dirreq-v3-reqs ??=48,tr=16,ar=8,ca=8,eg=8,gb=8,ir=8,us=8
Maybe it happens only intermittently. pion/sdp sets UnicastAddress: "0.0.0.0"
unconditionally and I don't see where it is ever modified. Maybe the others are older non-pion clients?
A little searching indicates that IN IP4 0.0.0.0
has something to do with trickle ICE:
It seems that ultimately, we need a more reliable way for the proxy to infer the client's external IP address.