rendezvous.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // WebRTC rendezvous requires the exchange of SessionDescriptions between
  2. // peers in order to establish a PeerConnection.
  3. //
  4. // This file contains the one method currently available to Snowflake:
  5. //
  6. // - Domain-fronted HTTP signaling. The Broker automatically exchange offers
  7. // and answers between this client and some remote WebRTC proxy.
  8. package lib
  9. import (
  10. "bytes"
  11. "errors"
  12. "io"
  13. "io/ioutil"
  14. "log"
  15. "net/http"
  16. "net/url"
  17. "sync"
  18. "time"
  19. "git.torproject.org/pluggable-transports/snowflake.git/common/messages"
  20. "git.torproject.org/pluggable-transports/snowflake.git/common/nat"
  21. "git.torproject.org/pluggable-transports/snowflake.git/common/util"
  22. "github.com/pion/webrtc/v3"
  23. )
  24. const (
  25. BrokerErrorUnexpected string = "Unexpected error, no answer."
  26. readLimit = 100000 //Maximum number of bytes to be read from an HTTP response
  27. )
  28. // Signalling Channel to the Broker.
  29. type BrokerChannel struct {
  30. // The Host header to put in the HTTP request (optional and may be
  31. // different from the host name in URL).
  32. Host string
  33. url *url.URL
  34. transport http.RoundTripper // Used to make all requests.
  35. keepLocalAddresses bool
  36. NATType string
  37. lock sync.Mutex
  38. }
  39. // We make a copy of DefaultTransport because we want the default Dial
  40. // and TLSHandshakeTimeout settings. But we want to disable the default
  41. // ProxyFromEnvironment setting.
  42. func CreateBrokerTransport() http.RoundTripper {
  43. transport := http.DefaultTransport.(*http.Transport)
  44. transport.Proxy = nil
  45. transport.ResponseHeaderTimeout = 15 * time.Second
  46. return transport
  47. }
  48. // Construct a new BrokerChannel, where:
  49. // |broker| is the full URL of the facilitating program which assigns proxies
  50. // to clients, and |front| is the option fronting domain.
  51. func NewBrokerChannel(broker string, front string, transport http.RoundTripper, keepLocalAddresses bool) (*BrokerChannel, error) {
  52. targetURL, err := url.Parse(broker)
  53. if err != nil {
  54. return nil, err
  55. }
  56. log.Println("Rendezvous using Broker at:", broker)
  57. bc := new(BrokerChannel)
  58. bc.url = targetURL
  59. if front != "" { // Optional front domain.
  60. log.Println("Domain fronting using:", front)
  61. bc.Host = bc.url.Host
  62. bc.url.Host = front
  63. }
  64. bc.transport = transport
  65. bc.keepLocalAddresses = keepLocalAddresses
  66. bc.NATType = nat.NATUnknown
  67. return bc, nil
  68. }
  69. func limitedRead(r io.Reader, limit int64) ([]byte, error) {
  70. p, err := ioutil.ReadAll(&io.LimitedReader{R: r, N: limit + 1})
  71. if err != nil {
  72. return p, err
  73. } else if int64(len(p)) == limit+1 {
  74. return p[0:limit], io.ErrUnexpectedEOF
  75. }
  76. return p, err
  77. }
  78. // Roundtrip HTTP POST using WebRTC SessionDescriptions.
  79. //
  80. // Send an SDP offer to the broker, which assigns a proxy and responds
  81. // with an SDP answer from a designated remote WebRTC peer.
  82. func (bc *BrokerChannel) Negotiate(offer *webrtc.SessionDescription) (
  83. *webrtc.SessionDescription, error) {
  84. log.Println("Negotiating via BrokerChannel...\nTarget URL: ",
  85. bc.Host, "\nFront URL: ", bc.url.Host)
  86. // Ideally, we could specify an `RTCIceTransportPolicy` that would handle
  87. // this for us. However, "public" was removed from the draft spec.
  88. // See https://developer.mozilla.org/en-US/docs/Web/API/RTCConfiguration#RTCIceTransportPolicy_enum
  89. if !bc.keepLocalAddresses {
  90. offer = &webrtc.SessionDescription{
  91. Type: offer.Type,
  92. SDP: util.StripLocalAddresses(offer.SDP),
  93. }
  94. }
  95. offerSDP, err := util.SerializeSessionDescription(offer)
  96. if err != nil {
  97. return nil, err
  98. }
  99. // Encode client poll request
  100. bc.lock.Lock()
  101. req := &messages.ClientPollRequest{
  102. Offer: offerSDP,
  103. NAT: bc.NATType,
  104. }
  105. body, err := req.EncodePollRequest()
  106. bc.lock.Unlock()
  107. if err != nil {
  108. return nil, err
  109. }
  110. data := bytes.NewReader([]byte(body))
  111. // Suffix with broker's client registration handler.
  112. clientURL := bc.url.ResolveReference(&url.URL{Path: "client"})
  113. request, err := http.NewRequest("POST", clientURL.String(), data)
  114. if nil != err {
  115. return nil, err
  116. }
  117. if "" != bc.Host { // Set true host if necessary.
  118. request.Host = bc.Host
  119. }
  120. resp, err := bc.transport.RoundTrip(request)
  121. if nil != err {
  122. return nil, err
  123. }
  124. defer resp.Body.Close()
  125. log.Printf("BrokerChannel Response:\n%s\n\n", resp.Status)
  126. switch resp.StatusCode {
  127. case http.StatusOK:
  128. body, err := limitedRead(resp.Body, readLimit)
  129. if nil != err {
  130. return nil, err
  131. }
  132. log.Printf("Received answer: %s", string(body))
  133. resp, err := messages.DecodeClientPollResponse(body)
  134. if err != nil {
  135. return nil, err
  136. }
  137. if resp.Error != "" {
  138. return nil, errors.New(resp.Error)
  139. }
  140. return util.DeserializeSessionDescription(resp.Answer)
  141. default:
  142. return nil, errors.New(BrokerErrorUnexpected)
  143. }
  144. }
  145. func (bc *BrokerChannel) SetNATType(NATType string) {
  146. bc.lock.Lock()
  147. bc.NATType = NATType
  148. bc.lock.Unlock()
  149. log.Printf("NAT Type: %s", NATType)
  150. }
  151. // Implements the |Tongue| interface to catch snowflakes, using BrokerChannel.
  152. type WebRTCDialer struct {
  153. *BrokerChannel
  154. webrtcConfig *webrtc.Configuration
  155. max int
  156. }
  157. func NewWebRTCDialer(broker *BrokerChannel, iceServers []webrtc.ICEServer, max int) *WebRTCDialer {
  158. config := webrtc.Configuration{
  159. ICEServers: iceServers,
  160. }
  161. return &WebRTCDialer{
  162. BrokerChannel: broker,
  163. webrtcConfig: &config,
  164. max: max,
  165. }
  166. }
  167. // Initialize a WebRTC Connection by signaling through the broker.
  168. func (w WebRTCDialer) Catch() (*WebRTCPeer, error) {
  169. // TODO: [#25591] Fetch ICE server information from Broker.
  170. // TODO: [#25596] Consider TURN servers here too.
  171. return NewWebRTCPeer(w.webrtcConfig, w.BrokerChannel)
  172. }
  173. // Returns the maximum number of snowflakes to collect
  174. func (w WebRTCDialer) GetMax() int {
  175. return w.max
  176. }