proxy-go_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "net"
  8. "net/http"
  9. "net/url"
  10. "strconv"
  11. "strings"
  12. "testing"
  13. "git.torproject.org/pluggable-transports/snowflake.git/common/messages"
  14. "github.com/pion/webrtc"
  15. . "github.com/smartystreets/goconvey/convey"
  16. )
  17. // Set up a mock broker to communicate with
  18. type MockTransport struct {
  19. statusOverride int
  20. body []byte
  21. }
  22. // Just returns a response with fake SDP answer.
  23. func (m *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  24. s := ioutil.NopCloser(bytes.NewReader(m.body))
  25. r := &http.Response{
  26. StatusCode: m.statusOverride,
  27. Body: s,
  28. }
  29. return r, nil
  30. }
  31. // Set up a mock faulty transport
  32. type FaultyTransport struct {
  33. statusOverride int
  34. body []byte
  35. }
  36. // Just returns a response with fake SDP answer.
  37. func (f *FaultyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  38. return nil, fmt.Errorf("TransportFailed")
  39. }
  40. func TestRemoteIPFromSDP(t *testing.T) {
  41. tests := []struct {
  42. sdp string
  43. expected net.IP
  44. }{
  45. // https://tools.ietf.org/html/rfc4566#section-5
  46. {`v=0
  47. o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
  48. s=SDP Seminar
  49. i=A Seminar on the session description protocol
  50. u=http://www.example.com/seminars/sdp.pdf
  51. e=j.doe@example.com (Jane Doe)
  52. c=IN IP4 224.2.17.12/127
  53. t=2873397496 2873404696
  54. a=recvonly
  55. m=audio 49170 RTP/AVP 0
  56. m=video 51372 RTP/AVP 99
  57. a=rtpmap:99 h263-1998/90000
  58. `, net.ParseIP("224.2.17.12")},
  59. // Missing c= line
  60. {`v=0
  61. o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
  62. s=SDP Seminar
  63. i=A Seminar on the session description protocol
  64. u=http://www.example.com/seminars/sdp.pdf
  65. e=j.doe@example.com (Jane Doe)
  66. t=2873397496 2873404696
  67. a=recvonly
  68. m=audio 49170 RTP/AVP 0
  69. m=video 51372 RTP/AVP 99
  70. a=rtpmap:99 h263-1998/90000
  71. `, nil},
  72. // Single line, IP address only
  73. {`c=IN IP4 224.2.1.1
  74. `, net.ParseIP("224.2.1.1")},
  75. // Same, with TTL
  76. {`c=IN IP4 224.2.1.1/127
  77. `, net.ParseIP("224.2.1.1")},
  78. // Same, with TTL and multicast addresses
  79. {`c=IN IP4 224.2.1.1/127/3
  80. `, net.ParseIP("224.2.1.1")},
  81. // IPv6, address only
  82. {`c=IN IP6 FF15::101
  83. `, net.ParseIP("ff15::101")},
  84. // Same, with multicast addresses
  85. {`c=IN IP6 FF15::101/3
  86. `, net.ParseIP("ff15::101")},
  87. // Multiple c= lines
  88. {`c=IN IP4 1.2.3.4
  89. c=IN IP4 5.6.7.8
  90. `, net.ParseIP("1.2.3.4")},
  91. // Modified from SDP sent by snowflake-client.
  92. {`v=0
  93. o=- 7860378660295630295 2 IN IP4 127.0.0.1
  94. s=-
  95. t=0 0
  96. a=group:BUNDLE data
  97. a=msid-semantic: WMS
  98. m=application 54653 DTLS/SCTP 5000
  99. c=IN IP4 1.2.3.4
  100. a=candidate:3581707038 1 udp 2122260223 192.168.0.1 54653 typ host generation 0 network-id 1 network-cost 50
  101. a=candidate:2617212910 1 tcp 1518280447 192.168.0.1 59673 typ host tcptype passive generation 0 network-id 1 network-cost 50
  102. a=candidate:2082671819 1 udp 1686052607 1.2.3.4 54653 typ srflx raddr 192.168.0.1 rport 54653 generation 0 network-id 1 network-cost 50
  103. a=ice-ufrag:IBdf
  104. a=ice-pwd:G3lTrrC9gmhQx481AowtkhYz
  105. a=fingerprint:sha-256 53:F8:84:D9:3C:1F:A0:44:AA:D6:3C:65:80:D3:CB:6F:23:90:17:41:06:F9:9C:10:D8:48:4A:A8:B6:FA:14:A1
  106. a=setup:actpass
  107. a=mid:data
  108. a=sctpmap:5000 webrtc-datachannel 1024
  109. `, net.ParseIP("1.2.3.4")},
  110. // Improper character within IPv4
  111. {`c=IN IP4 224.2z.1.1
  112. `, nil},
  113. // Improper character within IPv6
  114. {`c=IN IP6 ff15:g::101
  115. `, nil},
  116. // Bogus "IP7" addrtype
  117. {`c=IN IP7 1.2.3.4
  118. `, nil},
  119. }
  120. for _, test := range tests {
  121. // https://tools.ietf.org/html/rfc4566#section-5: "The sequence
  122. // CRLF (0x0d0a) is used to end a record, although parsers
  123. // SHOULD be tolerant and also accept records terminated with a
  124. // single newline character." We represent the test cases with
  125. // LF line endings for convenience, and test them both that way
  126. // and with CRLF line endings.
  127. lfSDP := test.sdp
  128. crlfSDP := strings.Replace(lfSDP, "\n", "\r\n", -1)
  129. ip := remoteIPFromSDP(lfSDP)
  130. if !ip.Equal(test.expected) {
  131. t.Errorf("expected %q, got %q from %q", test.expected, ip, lfSDP)
  132. }
  133. ip = remoteIPFromSDP(crlfSDP)
  134. if !ip.Equal(test.expected) {
  135. t.Errorf("expected %q, got %q from %q", test.expected, ip, crlfSDP)
  136. }
  137. }
  138. }
  139. func TestSessionDescriptions(t *testing.T) {
  140. Convey("Session description deserialization", t, func() {
  141. for _, test := range []struct {
  142. msg string
  143. ret *webrtc.SessionDescription
  144. }{
  145. {
  146. "test",
  147. nil,
  148. },
  149. {
  150. `{"type":"answer"}`,
  151. nil,
  152. },
  153. {
  154. `{"sdp":"test"}`,
  155. nil,
  156. },
  157. {
  158. `{"type":"test", "sdp":"test"}`,
  159. nil,
  160. },
  161. {
  162. `{"type":"answer", "sdp":"test"}`,
  163. &webrtc.SessionDescription{
  164. Type: webrtc.SDPTypeAnswer,
  165. SDP: "test",
  166. },
  167. },
  168. {
  169. `{"type":"pranswer", "sdp":"test"}`,
  170. &webrtc.SessionDescription{
  171. Type: webrtc.SDPTypePranswer,
  172. SDP: "test",
  173. },
  174. },
  175. {
  176. `{"type":"rollback", "sdp":"test"}`,
  177. &webrtc.SessionDescription{
  178. Type: webrtc.SDPTypeRollback,
  179. SDP: "test",
  180. },
  181. },
  182. {
  183. `{"type":"offer", "sdp":"test"}`,
  184. &webrtc.SessionDescription{
  185. Type: webrtc.SDPTypeOffer,
  186. SDP: "test",
  187. },
  188. },
  189. } {
  190. desc := deserializeSessionDescription(test.msg)
  191. So(desc, ShouldResemble, test.ret)
  192. }
  193. })
  194. Convey("Session description serialization", t, func() {
  195. for _, test := range []struct {
  196. desc *webrtc.SessionDescription
  197. ret string
  198. }{
  199. {
  200. &webrtc.SessionDescription{
  201. Type: webrtc.SDPTypeOffer,
  202. SDP: "test",
  203. },
  204. `{"type":"offer","sdp":"test"}`,
  205. },
  206. } {
  207. msg := serializeSessionDescription(test.desc)
  208. So(msg, ShouldResemble, test.ret)
  209. }
  210. })
  211. }
  212. func TestBrokerInteractions(t *testing.T) {
  213. const sampleSDP = `"v=0\r\no=- 4358805017720277108 2 IN IP4 8.8.8.8\r\ns=-\r\nt=0 0\r\na=group:BUNDLE data\r\na=msid-semantic: WMS\r\nm=application 56688 DTLS/SCTP 5000\r\nc=IN IP4 8.8.8.8\r\na=candidate:3769337065 1 udp 2122260223 8.8.8.8 56688 typ host generation 0 network-id 1 network-cost 50\r\na=candidate:2921887769 1 tcp 1518280447 8.8.8.8 35441 typ host tcptype passive generation 0 network-id 1 network-cost 50\r\na=ice-ufrag:aMAZ\r\na=ice-pwd:jcHb08Jjgrazp2dzjdrvPPvV\r\na=ice-options:trickle\r\na=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\r\na=setup:actpass\r\na=mid:data\r\na=sctpmap:5000 webrtc-datachannel 1024\r\n"`
  214. const sampleOffer = `{"type":"offer","sdp":` + sampleSDP + `}`
  215. const sampleAnswer = `{"type":"answer","sdp":` + sampleSDP + `}`
  216. Convey("Proxy connections to broker", t, func() {
  217. broker := new(Broker)
  218. broker.url, _ = url.Parse("localhost")
  219. //Mock peerConnection
  220. config = webrtc.Configuration{
  221. ICEServers: []webrtc.ICEServer{
  222. {
  223. URLs: []string{"stun:stun.l.google.com:19302"},
  224. },
  225. },
  226. }
  227. pc, _ := webrtc.NewPeerConnection(config)
  228. offer := deserializeSessionDescription(sampleOffer)
  229. pc.SetRemoteDescription(*offer)
  230. answer, _ := pc.CreateAnswer(nil)
  231. pc.SetLocalDescription(answer)
  232. Convey("polls broker correctly", func() {
  233. var err error
  234. b, err := messages.EncodePollResponse(sampleOffer, true)
  235. So(err, ShouldEqual, nil)
  236. broker.transport = &MockTransport{
  237. http.StatusOK,
  238. b,
  239. }
  240. sdp := broker.pollOffer(sampleOffer)
  241. expectedSDP, _ := strconv.Unquote(sampleSDP)
  242. So(sdp.SDP, ShouldResemble, expectedSDP)
  243. })
  244. Convey("handles poll error", func() {
  245. var err error
  246. b := []byte("test")
  247. So(err, ShouldEqual, nil)
  248. broker.transport = &MockTransport{
  249. http.StatusOK,
  250. b,
  251. }
  252. sdp := broker.pollOffer(sampleOffer)
  253. So(sdp, ShouldBeNil)
  254. })
  255. Convey("sends answer to broker", func() {
  256. var err error
  257. b, err := messages.EncodeAnswerResponse(true)
  258. So(err, ShouldEqual, nil)
  259. broker.transport = &MockTransport{
  260. http.StatusOK,
  261. b,
  262. }
  263. err = broker.sendAnswer(sampleAnswer, pc)
  264. So(err, ShouldEqual, nil)
  265. b, err = messages.EncodeAnswerResponse(false)
  266. So(err, ShouldEqual, nil)
  267. broker.transport = &MockTransport{
  268. http.StatusOK,
  269. b,
  270. }
  271. err = broker.sendAnswer(sampleAnswer, pc)
  272. So(err, ShouldNotBeNil)
  273. })
  274. Convey("handles answer error", func() {
  275. //Error if faulty transport
  276. broker.transport = &FaultyTransport{}
  277. err := broker.sendAnswer(sampleAnswer, pc)
  278. So(err, ShouldNotBeNil)
  279. //Error if status code is not ok
  280. broker.transport = &MockTransport{
  281. http.StatusGone,
  282. []byte(""),
  283. }
  284. err = broker.sendAnswer("test", pc)
  285. So(err, ShouldNotEqual, nil)
  286. So(err.Error(), ShouldResemble, "broker returned 410")
  287. //Error if we can't parse broker message
  288. broker.transport = &MockTransport{
  289. http.StatusOK,
  290. []byte("test"),
  291. }
  292. err = broker.sendAnswer("test", pc)
  293. So(err, ShouldNotBeNil)
  294. //Error if broker message surpasses read limit
  295. broker.transport = &MockTransport{
  296. http.StatusOK,
  297. make([]byte, 100001),
  298. }
  299. err = broker.sendAnswer("test", pc)
  300. So(err, ShouldNotBeNil)
  301. })
  302. })
  303. }
  304. func TestUtilityFuncs(t *testing.T) {
  305. Convey("LimitedRead", t, func() {
  306. c, s := net.Pipe()
  307. Convey("Successful read", func() {
  308. go func() {
  309. bytes := make([]byte, 50)
  310. c.Write(bytes)
  311. c.Close()
  312. }()
  313. bytes, err := limitedRead(s, 60)
  314. So(len(bytes), ShouldEqual, 50)
  315. So(err, ShouldBeNil)
  316. })
  317. Convey("Large read", func() {
  318. go func() {
  319. bytes := make([]byte, 50)
  320. c.Write(bytes)
  321. c.Close()
  322. }()
  323. bytes, err := limitedRead(s, 49)
  324. So(len(bytes), ShouldEqual, 49)
  325. So(err, ShouldEqual, io.ErrUnexpectedEOF)
  326. })
  327. Convey("Failed read", func() {
  328. s.Close()
  329. bytes, err := limitedRead(s, 49)
  330. So(len(bytes), ShouldEqual, 0)
  331. So(err, ShouldEqual, io.ErrClosedPipe)
  332. })
  333. })
  334. Convey("Tokens", t, func() {
  335. tokens = make(chan bool, 2)
  336. for i := uint(0); i < 2; i++ {
  337. tokens <- true
  338. }
  339. So(len(tokens), ShouldEqual, 2)
  340. getToken()
  341. So(len(tokens), ShouldEqual, 1)
  342. retToken()
  343. So(len(tokens), ShouldEqual, 2)
  344. })
  345. Convey("SessionID Generation", t, func() {
  346. sid1 := genSessionID()
  347. sid2 := genSessionID()
  348. So(sid1, ShouldNotEqual, sid2)
  349. })
  350. Convey("CopyLoop", t, func() {
  351. c1, s1 := net.Pipe()
  352. c2, s2 := net.Pipe()
  353. go CopyLoop(s1, s2)
  354. go func() {
  355. bytes := []byte("Hello!")
  356. c1.Write(bytes)
  357. }()
  358. bytes := make([]byte, 6)
  359. n, err := c2.Read(bytes)
  360. So(n, ShouldEqual, 6)
  361. So(err, ShouldEqual, nil)
  362. So(bytes, ShouldResemble, []byte("Hello!"))
  363. s1.Close()
  364. //Check that copy loop has closed other connection
  365. _, err = s2.Write(bytes)
  366. So(err, ShouldNotBeNil)
  367. })
  368. }