commit d7aa9b835645bc52c29ba13cdab461fe0d0e4e66 Author: Cecylia Bocovich cohosh@torproject.org Date: Wed Sep 30 10:10:29 2020 -0400
Extract remote address from ICE candidates
Parse the received ICE candidates as well as the Connection Data field for a non-local IP address to pass to the bridge. This fixes bug #33157. --- proxy/proxy-go_test.go | 126 +++++++++++++++++++++++++++++++++++++++++++++---- proxy/snowflake.go | 41 ++++++++++++++-- 2 files changed, 154 insertions(+), 13 deletions(-)
diff --git a/proxy/proxy-go_test.go b/proxy/proxy-go_test.go index 168ca25..1218289 100644 --- a/proxy/proxy-go_test.go +++ b/proxy/proxy-go_test.go @@ -64,6 +64,51 @@ m=audio 49170 RTP/AVP 0 m=video 51372 RTP/AVP 99 a=rtpmap:99 h263-1998/90000 `, net.ParseIP("224.2.17.12")}, + // local addresses only + {`v=0 +o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5 +s=SDP Seminar +i=A Seminar on the session description protocol +u=http://www.example.com/seminars/sdp.pdf +e=j.doe@example.com (Jane Doe) +c=IN IP4 10.47.16.5/127 +t=2873397496 2873404696 +a=recvonly +m=audio 49170 RTP/AVP 0 +m=video 51372 RTP/AVP 99 +a=rtpmap:99 h263-1998/90000 +`, nil}, + // Remote IP in candidate attribute only + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP4 0.0.0.0 +a=candidate:3769337065 1 udp 2122260223 1.2.3.4 56688 typ host generation 0 network-id 1 network-cost 50 +a=ice-ufrag:aMAZ +a=ice-pwd:jcHb08Jjgrazp2dzjdrvPPvV +a=ice-options:trickle +a=fingerprint:sha-256 C8:88:EE:B9:E7:02:2E:21:37:ED:7A:D1:EB:2B:A3:15:A2:3B:5B:1C:3D:D4:D5:1F:06:CF:52:40:03:F8:DD:66 +a=setup:actpass +a=mid:data +a=sctpmap:5000 webrtc-datachannel 1024 +`, net.ParseIP("1.2.3.4")}, + // Unspecified address + {`v=0 +o=jdoe 2890844526 2890842807 IN IP4 0.0.0.0 +s=SDP Seminar +i=A Seminar on the session description protocol +u=http://www.example.com/seminars/sdp.pdf +e=j.doe@example.com (Jane Doe) +t=2873397496 2873404696 +a=recvonly +m=audio 49170 RTP/AVP 0 +m=video 51372 RTP/AVP 99 +a=rtpmap:99 h263-1998/90000 +`, nil}, // Missing c= line {`v=0 o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5 @@ -78,22 +123,64 @@ m=video 51372 RTP/AVP 99 a=rtpmap:99 h263-1998/90000 `, nil}, // Single line, IP address only - {`c=IN IP4 224.2.1.1 + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP4 224.2.1.1 `, net.ParseIP("224.2.1.1")}, // Same, with TTL - {`c=IN IP4 224.2.1.1/127 + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP4 224.2.1.1/127 `, net.ParseIP("224.2.1.1")}, // Same, with TTL and multicast addresses - {`c=IN IP4 224.2.1.1/127/3 + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP4 224.2.1.1/127/3 `, net.ParseIP("224.2.1.1")}, // IPv6, address only - {`c=IN IP6 FF15::101 + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP6 FF15::101 `, net.ParseIP("ff15::101")}, // Same, with multicast addresses - {`c=IN IP6 FF15::101/3 + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP6 FF15::101/3 `, net.ParseIP("ff15::101")}, // Multiple c= lines - {`c=IN IP4 1.2.3.4 + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP4 1.2.3.4 c=IN IP4 5.6.7.8 `, net.ParseIP("1.2.3.4")}, // Modified from SDP sent by snowflake-client. @@ -116,13 +203,34 @@ a=mid:data a=sctpmap:5000 webrtc-datachannel 1024 `, net.ParseIP("1.2.3.4")}, // Improper character within IPv4 - {`c=IN IP4 224.2z.1.1 + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP4 224.2z.1.1 `, nil}, // Improper character within IPv6 - {`c=IN IP6 ff15:g::101 + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP6 ff15:g::101 `, nil}, // Bogus "IP7" addrtype - {`c=IN IP7 1.2.3.4 + {`v=0 +o=- 4358805017720277108 2 IN IP4 0.0.0.0 +s=- +t=0 0 +a=group:BUNDLE data +a=msid-semantic: WMS +m=application 56688 DTLS/SCTP 5000 +c=IN IP7 1.2.3.4 `, nil}, }
diff --git a/proxy/snowflake.go b/proxy/snowflake.go index b880b36..ac85527 100644 --- a/proxy/snowflake.go +++ b/proxy/snowflake.go @@ -24,6 +24,7 @@ import ( "git.torproject.org/pluggable-transports/snowflake.git/common/util" "git.torproject.org/pluggable-transports/snowflake.git/common/websocketconn" "github.com/gorilla/websocket" + "github.com/pion/sdp/v2" "github.com/pion/webrtc/v2" )
@@ -65,15 +66,47 @@ var remoteIPPatterns = []*regexp.Regexp{ regexp.MustCompile(`(?m)^c=IN IP6 ([0-9A-Fa-f:.]+)(?:/\d+)?(:? |\r?\n)`), }
-// https://tools.ietf.org/html/rfc4566#section-5.7 -func remoteIPFromSDP(sdp string) net.IP { +// Checks whether an IP address is a remote address for the client +func isRemoteAddress(ip net.IP) bool { + return !(util.IsLocal(ip) || ip.IsUnspecified() || ip.IsLoopback()) +} + +func remoteIPFromSDP(str string) net.IP { + // Look for remote IP in "a=candidate" attribute fields + // https://tools.ietf.org/html/rfc5245#section-15.1 + var desc sdp.SessionDescription + err := desc.Unmarshal([]byte(str)) + if err != nil { + log.Println("Error parsing SDP: ", err.Error()) + return nil + } + for _, m := range desc.MediaDescriptions { + for _, a := range m.Attributes { + if a.IsICECandidate() { + ice, err := a.ToICECandidate() + if err == nil { + ip := net.ParseIP(ice.Address) + if ip != nil && isRemoteAddress(ip) { + return ip + } + } + } + } + } + // Finally look for remote IP in "c=" Connection Data field + // https://tools.ietf.org/html/rfc4566#section-5.7 for _, pattern := range remoteIPPatterns { - m := pattern.FindStringSubmatch(sdp) + m := pattern.FindStringSubmatch(str) if m != nil { // Ignore parsing errors, ParseIP returns nil. - return net.ParseIP(m[1]) + ip := net.ParseIP(m[1]) + if ip != nil && isRemoteAddress(ip) { + return ip + } + } } + return nil }
tor-commits@lists.torproject.org