mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 20:11:19 -04:00
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.
This commit is contained in:
parent
8467c01e9e
commit
d7aa9b8356
2 changed files with 157 additions and 16 deletions
|
@ -64,6 +64,51 @@ m=audio 49170 RTP/AVP 0
|
||||||
m=video 51372 RTP/AVP 99
|
m=video 51372 RTP/AVP 99
|
||||||
a=rtpmap:99 h263-1998/90000
|
a=rtpmap:99 h263-1998/90000
|
||||||
`, net.ParseIP("224.2.17.12")},
|
`, 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
|
// Missing c= line
|
||||||
{`v=0
|
{`v=0
|
||||||
o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
|
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
|
a=rtpmap:99 h263-1998/90000
|
||||||
`, nil},
|
`, nil},
|
||||||
// Single line, IP address only
|
// 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")},
|
`, net.ParseIP("224.2.1.1")},
|
||||||
// Same, with TTL
|
// 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")},
|
`, net.ParseIP("224.2.1.1")},
|
||||||
// Same, with TTL and multicast addresses
|
// 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")},
|
`, net.ParseIP("224.2.1.1")},
|
||||||
// IPv6, address only
|
// 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")},
|
`, net.ParseIP("ff15::101")},
|
||||||
// Same, with multicast addresses
|
// 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")},
|
`, net.ParseIP("ff15::101")},
|
||||||
// Multiple c= lines
|
// 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
|
c=IN IP4 5.6.7.8
|
||||||
`, net.ParseIP("1.2.3.4")},
|
`, net.ParseIP("1.2.3.4")},
|
||||||
// Modified from SDP sent by snowflake-client.
|
// Modified from SDP sent by snowflake-client.
|
||||||
|
@ -116,13 +203,34 @@ a=mid:data
|
||||||
a=sctpmap:5000 webrtc-datachannel 1024
|
a=sctpmap:5000 webrtc-datachannel 1024
|
||||||
`, net.ParseIP("1.2.3.4")},
|
`, net.ParseIP("1.2.3.4")},
|
||||||
// Improper character within IPv4
|
// 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},
|
`, nil},
|
||||||
// Improper character within IPv6
|
// 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},
|
`, nil},
|
||||||
// Bogus "IP7" addrtype
|
// 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},
|
`, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"git.torproject.org/pluggable-transports/snowflake.git/common/util"
|
"git.torproject.org/pluggable-transports/snowflake.git/common/util"
|
||||||
"git.torproject.org/pluggable-transports/snowflake.git/common/websocketconn"
|
"git.torproject.org/pluggable-transports/snowflake.git/common/websocketconn"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/pion/sdp/v2"
|
||||||
"github.com/pion/webrtc/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)`),
|
regexp.MustCompile(`(?m)^c=IN IP6 ([0-9A-Fa-f:.]+)(?:\/\d+)?(:? |\r?\n)`),
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://tools.ietf.org/html/rfc4566#section-5.7
|
// Checks whether an IP address is a remote address for the client
|
||||||
func remoteIPFromSDP(sdp string) net.IP {
|
func isRemoteAddress(ip net.IP) bool {
|
||||||
for _, pattern := range remoteIPPatterns {
|
return !(util.IsLocal(ip) || ip.IsUnspecified() || ip.IsLoopback())
|
||||||
m := pattern.FindStringSubmatch(sdp)
|
}
|
||||||
if m != nil {
|
|
||||||
// Ignore parsing errors, ParseIP returns nil.
|
func remoteIPFromSDP(str string) net.IP {
|
||||||
return net.ParseIP(m[1])
|
// 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(str)
|
||||||
|
if m != nil {
|
||||||
|
// Ignore parsing errors, ParseIP returns nil.
|
||||||
|
ip := net.ParseIP(m[1])
|
||||||
|
if ip != nil && isRemoteAddress(ip) {
|
||||||
|
return ip
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue