mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 11:11:30 -04:00
Refactor webRTCConn to its own file
This commit is contained in:
parent
7a1857c42f
commit
ced539f234
2 changed files with 121 additions and 109 deletions
|
@ -13,7 +13,6 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -23,8 +22,6 @@ 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/ice/v2"
|
||||
"github.com/pion/sdp/v3"
|
||||
"github.com/pion/webrtc/v3"
|
||||
)
|
||||
|
||||
|
@ -60,117 +57,11 @@ var (
|
|||
client http.Client
|
||||
)
|
||||
|
||||
var remoteIPPatterns = []*regexp.Regexp{
|
||||
/* IPv4 */
|
||||
regexp.MustCompile(`(?m)^c=IN IP4 ([\d.]+)(?:(?:\/\d+)?\/\d+)?(:? |\r?\n)`),
|
||||
/* IPv6 */
|
||||
regexp.MustCompile(`(?m)^c=IN IP6 ([0-9A-Fa-f:.]+)(?:\/\d+)?(:? |\r?\n)`),
|
||||
}
|
||||
|
||||
// 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() {
|
||||
c, err := ice.UnmarshalCandidate(a.Value)
|
||||
if err == nil {
|
||||
ip := net.ParseIP(c.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
|
||||
}
|
||||
|
||||
type webRTCConn struct {
|
||||
dc *webrtc.DataChannel
|
||||
pc *webrtc.PeerConnection
|
||||
pr *io.PipeReader
|
||||
|
||||
lock sync.Mutex // Synchronization for DataChannel destruction
|
||||
once sync.Once // Synchronization for PeerConnection destruction
|
||||
|
||||
bytesLogger BytesLogger
|
||||
}
|
||||
|
||||
func (c *webRTCConn) Read(b []byte) (int, error) {
|
||||
return c.pr.Read(b)
|
||||
}
|
||||
|
||||
func (c *webRTCConn) Write(b []byte) (int, error) {
|
||||
c.bytesLogger.AddInbound(len(b))
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if c.dc != nil {
|
||||
c.dc.Send(b)
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (c *webRTCConn) Close() (err error) {
|
||||
c.once.Do(func() {
|
||||
err = c.pc.Close()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (c *webRTCConn) LocalAddr() net.Addr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *webRTCConn) RemoteAddr() net.Addr {
|
||||
//Parse Remote SDP offer and extract client IP
|
||||
clientIP := remoteIPFromSDP(c.pc.RemoteDescription().SDP)
|
||||
if clientIP == nil {
|
||||
return nil
|
||||
}
|
||||
return &net.IPAddr{IP: clientIP, Zone: ""}
|
||||
}
|
||||
|
||||
func (c *webRTCConn) SetDeadline(t time.Time) error {
|
||||
// nolint: golint
|
||||
return fmt.Errorf("SetDeadline not implemented")
|
||||
}
|
||||
|
||||
func (c *webRTCConn) SetReadDeadline(t time.Time) error {
|
||||
// nolint: golint
|
||||
return fmt.Errorf("SetReadDeadline not implemented")
|
||||
}
|
||||
|
||||
func (c *webRTCConn) SetWriteDeadline(t time.Time) error {
|
||||
// nolint: golint
|
||||
return fmt.Errorf("SetWriteDeadline not implemented")
|
||||
}
|
||||
|
||||
func genSessionID() string {
|
||||
buf := make([]byte, sessionIDLength)
|
||||
_, err := rand.Read(buf)
|
||||
|
|
121
proxy/webrtcconn.go
Normal file
121
proxy/webrtcconn.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"regexp"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pion/ice/v2"
|
||||
"github.com/pion/sdp/v3"
|
||||
"github.com/pion/webrtc/v3"
|
||||
)
|
||||
|
||||
var remoteIPPatterns = []*regexp.Regexp{
|
||||
/* IPv4 */
|
||||
regexp.MustCompile(`(?m)^c=IN IP4 ([\d.]+)(?:(?:\/\d+)?\/\d+)?(:? |\r?\n)`),
|
||||
/* IPv6 */
|
||||
regexp.MustCompile(`(?m)^c=IN IP6 ([0-9A-Fa-f:.]+)(?:\/\d+)?(:? |\r?\n)`),
|
||||
}
|
||||
|
||||
type webRTCConn struct {
|
||||
dc *webrtc.DataChannel
|
||||
pc *webrtc.PeerConnection
|
||||
pr *io.PipeReader
|
||||
|
||||
lock sync.Mutex // Synchronization for DataChannel destruction
|
||||
once sync.Once // Synchronization for PeerConnection destruction
|
||||
|
||||
bytesLogger BytesLogger
|
||||
}
|
||||
|
||||
func (c *webRTCConn) Read(b []byte) (int, error) {
|
||||
return c.pr.Read(b)
|
||||
}
|
||||
|
||||
func (c *webRTCConn) Write(b []byte) (int, error) {
|
||||
c.bytesLogger.AddInbound(len(b))
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if c.dc != nil {
|
||||
c.dc.Send(b)
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (c *webRTCConn) Close() (err error) {
|
||||
c.once.Do(func() {
|
||||
err = c.pc.Close()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (c *webRTCConn) LocalAddr() net.Addr {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *webRTCConn) RemoteAddr() net.Addr {
|
||||
//Parse Remote SDP offer and extract client IP
|
||||
clientIP := remoteIPFromSDP(c.pc.RemoteDescription().SDP)
|
||||
if clientIP == nil {
|
||||
return nil
|
||||
}
|
||||
return &net.IPAddr{IP: clientIP, Zone: ""}
|
||||
}
|
||||
|
||||
func (c *webRTCConn) SetDeadline(t time.Time) error {
|
||||
// nolint: golint
|
||||
return fmt.Errorf("SetDeadline not implemented")
|
||||
}
|
||||
|
||||
func (c *webRTCConn) SetReadDeadline(t time.Time) error {
|
||||
// nolint: golint
|
||||
return fmt.Errorf("SetReadDeadline not implemented")
|
||||
}
|
||||
|
||||
func (c *webRTCConn) SetWriteDeadline(t time.Time) error {
|
||||
// nolint: golint
|
||||
return fmt.Errorf("SetWriteDeadline not implemented")
|
||||
}
|
||||
|
||||
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() {
|
||||
c, err := ice.UnmarshalCandidate(a.Value)
|
||||
if err == nil {
|
||||
ip := net.ParseIP(c.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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue