mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-14 05:11:19 -04:00
begin meek-webrtc signalling channel for client (issue #1)
This commit is contained in:
parent
bc1e147ca2
commit
b4934f3979
2 changed files with 124 additions and 7 deletions
84
client/meek-webrtc.go
Normal file
84
client/meek-webrtc.go
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// Exchange WebRTC SessionDescriptions over meek.
|
||||||
|
// Much of this source is extracted from meek-client.go.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/keroserene/go-webrtc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RequestInfo encapsulates all the configuration used for a request–response
|
||||||
|
// roundtrip, including variables that may come from SOCKS args or from the
|
||||||
|
// command line.
|
||||||
|
type RequestInfo struct {
|
||||||
|
// What to put in the X-Session-ID header.
|
||||||
|
// SessionID string
|
||||||
|
// The URL to request.
|
||||||
|
URL *url.URL
|
||||||
|
// The Host header to put in the HTTP request (optional and may be
|
||||||
|
// different from the host name in URL).
|
||||||
|
Host string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRequestInfo(meekUrl string, front string) *RequestInfo {
|
||||||
|
info := new(RequestInfo)
|
||||||
|
requestUrl, err := url.Parse(meekUrl)
|
||||||
|
if nil != err {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
info.URL = requestUrl
|
||||||
|
info.Host = info.URL.Host
|
||||||
|
info.URL.Host = front
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meek Signalling Channel
|
||||||
|
type MeekChannel struct {
|
||||||
|
info *RequestInfo
|
||||||
|
// Used to make all requests.
|
||||||
|
transport http.Transport
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMeekChannel(info *RequestInfo) *MeekChannel {
|
||||||
|
m := new(MeekChannel)
|
||||||
|
// We make a copy of DefaultTransport because we want the default Dial
|
||||||
|
// and TLSHandshakeTimeout settings. But we want to disable the default
|
||||||
|
// ProxyFromEnvironment setting. Proxy is overridden below if
|
||||||
|
// options.ProxyURL is set.
|
||||||
|
m.transport = *http.DefaultTransport.(*http.Transport)
|
||||||
|
m.transport.Proxy = nil
|
||||||
|
m.info = info
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do an HTTP roundtrip using the payload data in buf.
|
||||||
|
func (m *MeekChannel) roundTripHTTP(buf []byte) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("POST", m.info.URL.String(), bytes.NewReader(buf))
|
||||||
|
if nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if "" != m.info.Host {
|
||||||
|
req.Host = m.info.Host
|
||||||
|
}
|
||||||
|
// req.Header.Set("X-Session-Id", m.info.SessionID)
|
||||||
|
return m.transport.RoundTrip(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send an SDP offer to the meek facilitator, and wait for an SDP answer from
|
||||||
|
// the assigned proxy in the response.
|
||||||
|
func (m *MeekChannel) Negotiate(offer *webrtc.SessionDescription) (
|
||||||
|
*webrtc.SessionDescription, error) {
|
||||||
|
buf := []byte(offer.Serialize())
|
||||||
|
resp, err := m.roundTripHTTP(buf)
|
||||||
|
if nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
answer := webrtc.DeserializeSessionDescription(string(body))
|
||||||
|
return answer, nil
|
||||||
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Client transport plugin for the snowflake pluggable transport.
|
||||||
|
//
|
||||||
|
// TODO: Use meek for signalling.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -18,6 +21,13 @@ import (
|
||||||
"git.torproject.org/pluggable-transports/goptlib.git"
|
"git.torproject.org/pluggable-transports/goptlib.git"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Hard-coded meek signalling channel for now.
|
||||||
|
// TODO: expose as param
|
||||||
|
const (
|
||||||
|
MEEK_URL = "not implemented yet"
|
||||||
|
FRONT_DOMAIN = "www.google.com"
|
||||||
|
)
|
||||||
|
|
||||||
var ptInfo pt.ClientInfo
|
var ptInfo pt.ClientInfo
|
||||||
var logFile *os.File
|
var logFile *os.File
|
||||||
|
|
||||||
|
@ -89,8 +99,10 @@ func (c *webRTCConn) SetWriteDeadline(t time.Time) error {
|
||||||
return fmt.Errorf("SetWriteDeadline not implemented")
|
return fmt.Errorf("SetWriteDeadline not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func dialWebRTC(config *webrtc.Configuration) (*webRTCConn, error) {
|
func dialWebRTC(config *webrtc.Configuration, meek *MeekChannel) (
|
||||||
blobChan := make(chan string)
|
*webRTCConn, error) {
|
||||||
|
|
||||||
|
offerChan := make(chan *webrtc.SessionDescription)
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
openChan := make(chan bool)
|
openChan := make(chan bool)
|
||||||
|
|
||||||
|
@ -123,7 +135,7 @@ func dialWebRTC(config *webrtc.Configuration) (*webRTCConn, error) {
|
||||||
// TODO: This may soon be deprecated, consider OnIceGatheringStateChange.
|
// TODO: This may soon be deprecated, consider OnIceGatheringStateChange.
|
||||||
pc.OnIceComplete = func() {
|
pc.OnIceComplete = func() {
|
||||||
log.Printf("OnIceComplete")
|
log.Printf("OnIceComplete")
|
||||||
blobChan <- pc.LocalDescription().Serialize()
|
offerChan <- pc.LocalDescription()
|
||||||
}
|
}
|
||||||
pc.OnDataChannel = func(channel *data.Channel) {
|
pc.OnDataChannel = func(channel *data.Channel) {
|
||||||
log.Println("OnDataChannel")
|
log.Println("OnDataChannel")
|
||||||
|
@ -162,10 +174,22 @@ func dialWebRTC(config *webrtc.Configuration) (*webRTCConn, error) {
|
||||||
case err := <-errChan:
|
case err := <-errChan:
|
||||||
pc.Close()
|
pc.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
case offer := <-blobChan:
|
case offer := <-offerChan:
|
||||||
log.Printf("----------------")
|
log.Printf("----------------")
|
||||||
fmt.Fprintln(logFile, "\n"+offer+"\n")
|
fmt.Fprintln(logFile, "\n"+offer.Serialize()+"\n")
|
||||||
log.Printf("----------------")
|
log.Printf("----------------")
|
||||||
|
go func() {
|
||||||
|
log.Printf("Sending offer via meek...")
|
||||||
|
answer, err := meek.Negotiate(pc.LocalDescription())
|
||||||
|
if nil != err {
|
||||||
|
log.Printf("Signalling error: %s", err)
|
||||||
|
}
|
||||||
|
if nil == answer {
|
||||||
|
log.Printf("No answer received from meek channel.")
|
||||||
|
} else {
|
||||||
|
signalChan <- answer
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("waiting for answer")
|
log.Printf("waiting for answer")
|
||||||
|
@ -184,6 +208,7 @@ func dialWebRTC(config *webrtc.Configuration) (*webRTCConn, error) {
|
||||||
|
|
||||||
// Wait until data channel is open; otherwise for example sends may get
|
// Wait until data channel is open; otherwise for example sends may get
|
||||||
// lost.
|
// lost.
|
||||||
|
// TODO: Buffering *should* work though.
|
||||||
_, ok = <-openChan
|
_, ok = <-openChan
|
||||||
if !ok {
|
if !ok {
|
||||||
pc.Close()
|
pc.Close()
|
||||||
|
@ -215,8 +240,16 @@ func handler(conn *pt.SocksConn) error {
|
||||||
}()
|
}()
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
config := webrtc.NewConfiguration(webrtc.OptionIceServer("stun:stun.l.google.com:19302"))
|
// go func() {
|
||||||
remote, err := dialWebRTC(config)
|
// }()
|
||||||
|
// Prepare meek signalling channel.
|
||||||
|
info := NewRequestInfo(MEEK_URL, FRONT_DOMAIN)
|
||||||
|
meek := NewMeekChannel(info)
|
||||||
|
|
||||||
|
config := webrtc.NewConfiguration(
|
||||||
|
webrtc.OptionIceServer("stun:stun.l.google.com:19302"))
|
||||||
|
// remote, err := dialWebRTC(config, nil)
|
||||||
|
remote, err := dialWebRTC(config, meek)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Reject()
|
conn.Reject()
|
||||||
return err
|
return err
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue