proxy-go_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. package snowflake_proxy
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "net"
  7. "net/http"
  8. "strconv"
  9. "strings"
  10. "testing"
  11. "github.com/pion/webrtc/v4"
  12. . "github.com/smartystreets/goconvey/convey"
  13. "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/messages"
  14. "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/util"
  15. )
  16. // Set up a mock broker to communicate with
  17. type MockTransport struct {
  18. statusOverride int
  19. body []byte
  20. }
  21. // Just returns a response with fake SDP answer.
  22. func (m *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  23. s := io.NopCloser(bytes.NewReader(m.body))
  24. r := &http.Response{
  25. StatusCode: m.statusOverride,
  26. Body: s,
  27. }
  28. return r, nil
  29. }
  30. // Set up a mock faulty transport
  31. type FaultyTransport struct {
  32. statusOverride int
  33. body []byte
  34. }
  35. // Just returns a response with fake SDP answer.
  36. func (f *FaultyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  37. return nil, fmt.Errorf("TransportFailed")
  38. }
  39. func TestRemoteIPFromSDP(t *testing.T) {
  40. tests := []struct {
  41. sdp string
  42. expected net.IP
  43. }{
  44. // https://tools.ietf.org/html/rfc4566#section-5
  45. {`v=0
  46. o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
  47. s=SDP Seminar
  48. i=A Seminar on the session description protocol
  49. u=http://www.example.com/seminars/sdp.pdf
  50. e=j.doe@example.com (Jane Doe)
  51. c=IN IP4 224.2.17.12/127
  52. t=2873397496 2873404696
  53. a=recvonly
  54. m=audio 49170 RTP/AVP 0
  55. m=video 51372 RTP/AVP 99
  56. a=rtpmap:99 h263-1998/90000
  57. `, net.ParseIP("224.2.17.12")},
  58. // local addresses only
  59. {`v=0
  60. o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
  61. s=SDP Seminar
  62. i=A Seminar on the session description protocol
  63. u=http://www.example.com/seminars/sdp.pdf
  64. e=j.doe@example.com (Jane Doe)
  65. c=IN IP4 10.47.16.5/127
  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. // Remote IP in candidate attribute only
  73. {`v=0
  74. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  75. s=-
  76. t=0 0
  77. a=group:BUNDLE data
  78. a=msid-semantic: WMS
  79. m=application 56688 DTLS/SCTP 5000
  80. c=IN IP4 0.0.0.0
  81. a=candidate:3769337065 1 udp 2122260223 1.2.3.4 56688 typ host generation 0 network-id 1 network-cost 50
  82. a=ice-ufrag:aMAZ
  83. a=ice-pwd:jcHb08Jjgrazp2dzjdrvPPvV
  84. a=ice-options:trickle
  85. 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
  86. a=setup:actpass
  87. a=mid:data
  88. a=sctpmap:5000 webrtc-datachannel 1024
  89. `, net.ParseIP("1.2.3.4")},
  90. // Unspecified address
  91. {`v=0
  92. o=jdoe 2890844526 2890842807 IN IP4 0.0.0.0
  93. s=SDP Seminar
  94. i=A Seminar on the session description protocol
  95. u=http://www.example.com/seminars/sdp.pdf
  96. e=j.doe@example.com (Jane Doe)
  97. t=2873397496 2873404696
  98. a=recvonly
  99. m=audio 49170 RTP/AVP 0
  100. m=video 51372 RTP/AVP 99
  101. a=rtpmap:99 h263-1998/90000
  102. `, nil},
  103. // Missing c= line
  104. {`v=0
  105. o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
  106. s=SDP Seminar
  107. i=A Seminar on the session description protocol
  108. u=http://www.example.com/seminars/sdp.pdf
  109. e=j.doe@example.com (Jane Doe)
  110. t=2873397496 2873404696
  111. a=recvonly
  112. m=audio 49170 RTP/AVP 0
  113. m=video 51372 RTP/AVP 99
  114. a=rtpmap:99 h263-1998/90000
  115. `, nil},
  116. // Single line, IP address only
  117. {`v=0
  118. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  119. s=-
  120. t=0 0
  121. a=group:BUNDLE data
  122. a=msid-semantic: WMS
  123. m=application 56688 DTLS/SCTP 5000
  124. c=IN IP4 224.2.1.1
  125. `, net.ParseIP("224.2.1.1")},
  126. // Same, with TTL
  127. {`v=0
  128. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  129. s=-
  130. t=0 0
  131. a=group:BUNDLE data
  132. a=msid-semantic: WMS
  133. m=application 56688 DTLS/SCTP 5000
  134. c=IN IP4 224.2.1.1/127
  135. `, net.ParseIP("224.2.1.1")},
  136. // Same, with TTL and multicast addresses
  137. {`v=0
  138. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  139. s=-
  140. t=0 0
  141. a=group:BUNDLE data
  142. a=msid-semantic: WMS
  143. m=application 56688 DTLS/SCTP 5000
  144. c=IN IP4 224.2.1.1/127/3
  145. `, net.ParseIP("224.2.1.1")},
  146. // IPv6, address only
  147. {`v=0
  148. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  149. s=-
  150. t=0 0
  151. a=group:BUNDLE data
  152. a=msid-semantic: WMS
  153. m=application 56688 DTLS/SCTP 5000
  154. c=IN IP6 FF15::101
  155. `, net.ParseIP("ff15::101")},
  156. // Same, with multicast addresses
  157. {`v=0
  158. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  159. s=-
  160. t=0 0
  161. a=group:BUNDLE data
  162. a=msid-semantic: WMS
  163. m=application 56688 DTLS/SCTP 5000
  164. c=IN IP6 FF15::101/3
  165. `, net.ParseIP("ff15::101")},
  166. // Multiple c= lines
  167. {`v=0
  168. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  169. s=-
  170. t=0 0
  171. a=group:BUNDLE data
  172. a=msid-semantic: WMS
  173. m=application 56688 DTLS/SCTP 5000
  174. c=IN IP4 1.2.3.4
  175. c=IN IP4 5.6.7.8
  176. `, net.ParseIP("1.2.3.4")},
  177. // Modified from SDP sent by snowflake-client.
  178. {`v=0
  179. o=- 7860378660295630295 2 IN IP4 127.0.0.1
  180. s=-
  181. t=0 0
  182. a=group:BUNDLE data
  183. a=msid-semantic: WMS
  184. m=application 54653 DTLS/SCTP 5000
  185. c=IN IP4 1.2.3.4
  186. a=candidate:3581707038 1 udp 2122260223 192.168.0.1 54653 typ host generation 0 network-id 1 network-cost 50
  187. a=candidate:2617212910 1 tcp 1518280447 192.168.0.1 59673 typ host tcptype passive generation 0 network-id 1 network-cost 50
  188. 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
  189. a=ice-ufrag:IBdf
  190. a=ice-pwd:G3lTrrC9gmhQx481AowtkhYz
  191. 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
  192. a=setup:actpass
  193. a=mid:data
  194. a=sctpmap:5000 webrtc-datachannel 1024
  195. `, net.ParseIP("1.2.3.4")},
  196. // Improper character within IPv4
  197. {`v=0
  198. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  199. s=-
  200. t=0 0
  201. a=group:BUNDLE data
  202. a=msid-semantic: WMS
  203. m=application 56688 DTLS/SCTP 5000
  204. c=IN IP4 224.2z.1.1
  205. `, nil},
  206. // Improper character within IPv6
  207. {`v=0
  208. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  209. s=-
  210. t=0 0
  211. a=group:BUNDLE data
  212. a=msid-semantic: WMS
  213. m=application 56688 DTLS/SCTP 5000
  214. c=IN IP6 ff15:g::101
  215. `, nil},
  216. // Bogus "IP7" addrtype
  217. {`v=0
  218. o=- 4358805017720277108 2 IN IP4 0.0.0.0
  219. s=-
  220. t=0 0
  221. a=group:BUNDLE data
  222. a=msid-semantic: WMS
  223. m=application 56688 DTLS/SCTP 5000
  224. c=IN IP7 1.2.3.4
  225. `, nil},
  226. }
  227. for _, test := range tests {
  228. // https://tools.ietf.org/html/rfc4566#section-5: "The sequence
  229. // CRLF (0x0d0a) is used to end a record, although parsers
  230. // SHOULD be tolerant and also accept records terminated with a
  231. // single newline character." We represent the test cases with
  232. // LF line endings for convenience, and test them both that way
  233. // and with CRLF line endings.
  234. lfSDP := test.sdp
  235. crlfSDP := strings.Replace(lfSDP, "\n", "\r\n", -1)
  236. ip := remoteIPFromSDP(lfSDP)
  237. if !ip.Equal(test.expected) {
  238. t.Errorf("expected %q, got %q from %q", test.expected, ip, lfSDP)
  239. }
  240. ip = remoteIPFromSDP(crlfSDP)
  241. if !ip.Equal(test.expected) {
  242. t.Errorf("expected %q, got %q from %q", test.expected, ip, crlfSDP)
  243. }
  244. }
  245. }
  246. func TestSessionDescriptions(t *testing.T) {
  247. Convey("Session description deserialization", t, func() {
  248. for _, test := range []struct {
  249. msg string
  250. ret *webrtc.SessionDescription
  251. }{
  252. {
  253. "test",
  254. nil,
  255. },
  256. {
  257. `{"type":"answer"}`,
  258. nil,
  259. },
  260. {
  261. `{"sdp":"test"}`,
  262. nil,
  263. },
  264. {
  265. `{"type":"test", "sdp":"test"}`,
  266. nil,
  267. },
  268. {
  269. `{"type":"answer", "sdp":"test"}`,
  270. &webrtc.SessionDescription{
  271. Type: webrtc.SDPTypeAnswer,
  272. SDP: "test",
  273. },
  274. },
  275. {
  276. `{"type":"pranswer", "sdp":"test"}`,
  277. &webrtc.SessionDescription{
  278. Type: webrtc.SDPTypePranswer,
  279. SDP: "test",
  280. },
  281. },
  282. {
  283. `{"type":"rollback", "sdp":"test"}`,
  284. &webrtc.SessionDescription{
  285. Type: webrtc.SDPTypeRollback,
  286. SDP: "test",
  287. },
  288. },
  289. {
  290. `{"type":"offer", "sdp":"test"}`,
  291. &webrtc.SessionDescription{
  292. Type: webrtc.SDPTypeOffer,
  293. SDP: "test",
  294. },
  295. },
  296. } {
  297. desc, _ := util.DeserializeSessionDescription(test.msg)
  298. So(desc, ShouldResemble, test.ret)
  299. }
  300. })
  301. Convey("Session description serialization", t, func() {
  302. for _, test := range []struct {
  303. desc *webrtc.SessionDescription
  304. ret string
  305. }{
  306. {
  307. &webrtc.SessionDescription{
  308. Type: webrtc.SDPTypeOffer,
  309. SDP: "test",
  310. },
  311. `{"type":"offer","sdp":"test"}`,
  312. },
  313. } {
  314. msg, err := util.SerializeSessionDescription(test.desc)
  315. So(msg, ShouldResemble, test.ret)
  316. So(err, ShouldBeNil)
  317. }
  318. })
  319. }
  320. func TestBrokerInteractions(t *testing.T) {
  321. 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"`
  322. const sampleOffer = `{"type":"offer","sdp":` + sampleSDP + `}`
  323. const sampleAnswer = `{"type":"answer","sdp":` + sampleSDP + `}`
  324. Convey("Proxy connections to broker", t, func() {
  325. var err error
  326. broker, err = newSignalingServer("localhost", false)
  327. So(err, ShouldBeNil)
  328. tokens = newTokens(0)
  329. //Mock peerConnection
  330. config = webrtc.Configuration{
  331. ICEServers: []webrtc.ICEServer{
  332. {
  333. URLs: []string{"stun:stun.l.google.com:19302"},
  334. },
  335. },
  336. }
  337. pc, _ := webrtc.NewPeerConnection(config)
  338. offer, _ := util.DeserializeSessionDescription(sampleOffer)
  339. pc.SetRemoteDescription(*offer)
  340. answer, _ := pc.CreateAnswer(nil)
  341. pc.SetLocalDescription(answer)
  342. Convey("polls broker correctly", func() {
  343. var err error
  344. b, err := messages.EncodePollResponse(sampleOffer, true, "unknown")
  345. So(err, ShouldBeNil)
  346. broker.transport = &MockTransport{
  347. http.StatusOK,
  348. b,
  349. }
  350. sdp, _ := broker.pollOffer(sampleOffer, DefaultProxyType, "")
  351. expectedSDP, _ := strconv.Unquote(sampleSDP)
  352. So(sdp.SDP, ShouldResemble, expectedSDP)
  353. })
  354. Convey("handles poll error", func() {
  355. var err error
  356. b := []byte("test")
  357. So(err, ShouldBeNil)
  358. broker.transport = &MockTransport{
  359. http.StatusOK,
  360. b,
  361. }
  362. sdp, _ := broker.pollOffer(sampleOffer, DefaultProxyType, "")
  363. So(sdp, ShouldBeNil)
  364. })
  365. Convey("sends answer to broker", func() {
  366. var err error
  367. b, err := messages.EncodeAnswerResponse(true)
  368. So(err, ShouldBeNil)
  369. broker.transport = &MockTransport{
  370. http.StatusOK,
  371. b,
  372. }
  373. err = broker.sendAnswer(sampleAnswer, pc)
  374. So(err, ShouldBeNil)
  375. b, err = messages.EncodeAnswerResponse(false)
  376. So(err, ShouldBeNil)
  377. broker.transport = &MockTransport{
  378. http.StatusOK,
  379. b,
  380. }
  381. err = broker.sendAnswer(sampleAnswer, pc)
  382. So(err, ShouldNotBeNil)
  383. })
  384. Convey("handles answer error", func() {
  385. //Error if faulty transport
  386. broker.transport = &FaultyTransport{}
  387. err := broker.sendAnswer(sampleAnswer, pc)
  388. So(err, ShouldNotBeNil)
  389. //Error if status code is not ok
  390. broker.transport = &MockTransport{
  391. http.StatusGone,
  392. []byte(""),
  393. }
  394. err = broker.sendAnswer("test", pc)
  395. So(err, ShouldNotEqual, nil)
  396. So(err.Error(), ShouldResemble,
  397. "error sending answer to broker: remote returned status code 410")
  398. //Error if we can't parse broker message
  399. broker.transport = &MockTransport{
  400. http.StatusOK,
  401. []byte("test"),
  402. }
  403. err = broker.sendAnswer("test", pc)
  404. So(err, ShouldNotBeNil)
  405. //Error if broker message surpasses read limit
  406. broker.transport = &MockTransport{
  407. http.StatusOK,
  408. make([]byte, 100001),
  409. }
  410. err = broker.sendAnswer("test", pc)
  411. So(err, ShouldNotBeNil)
  412. })
  413. })
  414. }
  415. func TestUtilityFuncs(t *testing.T) {
  416. Convey("LimitedRead", t, func() {
  417. c, s := net.Pipe()
  418. Convey("Successful read", func() {
  419. go func() {
  420. bytes := make([]byte, 50)
  421. c.Write(bytes)
  422. c.Close()
  423. }()
  424. bytes, err := limitedRead(s, 60)
  425. So(len(bytes), ShouldEqual, 50)
  426. So(err, ShouldBeNil)
  427. })
  428. Convey("Large read", func() {
  429. go func() {
  430. bytes := make([]byte, 50)
  431. c.Write(bytes)
  432. c.Close()
  433. }()
  434. bytes, err := limitedRead(s, 49)
  435. So(len(bytes), ShouldEqual, 49)
  436. So(err, ShouldEqual, io.ErrUnexpectedEOF)
  437. })
  438. Convey("Failed read", func() {
  439. s.Close()
  440. bytes, err := limitedRead(s, 49)
  441. So(len(bytes), ShouldEqual, 0)
  442. So(err, ShouldEqual, io.ErrClosedPipe)
  443. })
  444. })
  445. Convey("SessionID Generation", t, func() {
  446. sid1 := genSessionID()
  447. sid2 := genSessionID()
  448. So(sid1, ShouldNotEqual, sid2)
  449. })
  450. Convey("CopyLoop", t, func() {
  451. c1, s1 := net.Pipe()
  452. c2, s2 := net.Pipe()
  453. go copyLoop(s1, s2, nil)
  454. go func() {
  455. bytes := []byte("Hello!")
  456. c1.Write(bytes)
  457. }()
  458. bytes := make([]byte, 6)
  459. n, err := c2.Read(bytes)
  460. So(n, ShouldEqual, 6)
  461. So(err, ShouldBeNil)
  462. So(bytes, ShouldResemble, []byte("Hello!"))
  463. s1.Close()
  464. //Check that copy loop has closed other connection
  465. _, err = s2.Write(bytes)
  466. So(err, ShouldNotBeNil)
  467. })
  468. Convey("isRelayURLAcceptable", t, func() {
  469. testingVector := []struct {
  470. pattern string
  471. allowPrivateAddresses bool
  472. allowNonTLS bool
  473. targetURL string
  474. expects error
  475. }{
  476. // These are copied from `TestMatchMember`.
  477. {pattern: "^snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://snowflake.torproject.net", expects: nil},
  478. {pattern: "^snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://faketorproject.net", expects: fmt.Errorf("")},
  479. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://faketorproject.net", expects: fmt.Errorf("")},
  480. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://snowflake.torproject.net", expects: nil},
  481. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://imaginary-01-snowflake.torproject.net", expects: nil},
  482. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://imaginary-aaa-snowflake.torproject.net", expects: nil},
  483. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://imaginary-aaa-snowflake.faketorproject.net", expects: fmt.Errorf("")},
  484. {pattern: "^torproject.net$", allowNonTLS: false, targetURL: "wss://faketorproject.net", expects: fmt.Errorf("")},
  485. // Yes, this is how it works if there is no "^".
  486. {pattern: "torproject.net$", allowNonTLS: false, targetURL: "wss://faketorproject.net", expects: nil},
  487. // NonTLS
  488. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "ws://snowflake.torproject.net", expects: fmt.Errorf("")},
  489. {pattern: "snowflake.torproject.net$", allowNonTLS: true, targetURL: "ws://snowflake.torproject.net", expects: nil},
  490. // Sneaky attempt to use path
  491. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://evil.com/snowflake.torproject.net", expects: fmt.Errorf("")},
  492. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://evil.com/?test=snowflake.torproject.net", expects: fmt.Errorf("")},
  493. // IP address
  494. {pattern: "^1.1.1.1$", allowNonTLS: true, targetURL: "ws://1.1.1.1/test?test=test#test", expects: nil},
  495. {pattern: "^1.1.1.1$", allowNonTLS: true, targetURL: "ws://231.1.1.1/test?test=test#test", expects: fmt.Errorf("")},
  496. {pattern: "1.1.1.1$", allowNonTLS: true, targetURL: "ws://231.1.1.1/test?test=test#test", expects: nil},
  497. // Private IP address
  498. {pattern: "$", allowNonTLS: true, targetURL: "ws://192.168.1.1", expects: fmt.Errorf("")},
  499. {pattern: "$", allowNonTLS: true, targetURL: "ws://127.0.0.1", expects: fmt.Errorf("")},
  500. {pattern: "$", allowNonTLS: true, targetURL: "ws://[fc00::]/", expects: fmt.Errorf("")},
  501. {pattern: "$", allowNonTLS: true, targetURL: "ws://[::1]/", expects: fmt.Errorf("")},
  502. {pattern: "$", allowNonTLS: true, targetURL: "ws://0.0.0.0/", expects: fmt.Errorf("")},
  503. {pattern: "$", allowNonTLS: true, targetURL: "ws://169.254.1.1/", expects: fmt.Errorf("")},
  504. {pattern: "$", allowNonTLS: true, targetURL: "ws://100.111.1.1/", expects: fmt.Errorf("")},
  505. {pattern: "192.168.1.100$", allowPrivateAddresses: true, allowNonTLS: true, targetURL: "ws://192.168.1.100/test?test=test", expects: nil},
  506. {pattern: "localhost$", allowPrivateAddresses: true, allowNonTLS: true, targetURL: "ws://localhost/test?test=test", expects: nil},
  507. {pattern: "::1$", allowPrivateAddresses: true, allowNonTLS: true, targetURL: "ws://[::1]/test?test=test", expects: nil},
  508. // Multicast IP address. `checkIsRelayURLAcceptable` allows it,
  509. // but it's not valid in the context of WebSocket
  510. {pattern: "255.255.255.255$", allowPrivateAddresses: true, allowNonTLS: true, targetURL: "ws://255.255.255.255/test?test=test", expects: nil},
  511. // Port
  512. {pattern: "^snowflake.torproject.net$", allowNonTLS: false, targetURL: "wss://snowflake.torproject.net:8080/test?test=test#test", expects: nil},
  513. // This currently doesn't work as we only check hostname.
  514. // {pattern: "^snowflake.torproject.net:443$", allowNonTLS: false, targetURL: "wss://snowflake.torproject.net:443", expects: nil},
  515. // {pattern: "^snowflake.torproject.net:443$", allowNonTLS: false, targetURL: "wss://snowflake.torproject.net:9999", expects: fmt.Errorf("")},
  516. // Any URL
  517. {pattern: "$", allowNonTLS: false, targetURL: "wss://any.com/test?test=test#test", expects: nil},
  518. {pattern: "$", allowNonTLS: false, targetURL: "wss://1.1.1.1/test?test=test#test", expects: nil},
  519. // Weird / invalid / ambiguous URL
  520. {pattern: "$", allowNonTLS: true, targetURL: "snowflake.torproject.net", expects: fmt.Errorf("")},
  521. {pattern: "$", allowNonTLS: true, targetURL: "//snowflake.torproject.net", expects: fmt.Errorf("")},
  522. {pattern: "$", allowNonTLS: true, targetURL: "/path", expects: fmt.Errorf("")},
  523. {pattern: "$", allowNonTLS: true, targetURL: "wss://snowflake.torproject .net", expects: fmt.Errorf("")},
  524. {pattern: "$", allowNonTLS: true, targetURL: "wss://😀", expects: nil},
  525. {pattern: "$", allowNonTLS: true, targetURL: "wss://пример.рф", expects: nil},
  526. // Non-websocket protocols
  527. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "https://snowflake.torproject.net", expects: fmt.Errorf("")},
  528. {pattern: "snowflake.torproject.net$", allowNonTLS: false, targetURL: "ftp://snowflake.torproject.net", expects: fmt.Errorf("")},
  529. {pattern: "snowflake.torproject.net$", allowNonTLS: true, targetURL: "https://snowflake.torproject.net", expects: fmt.Errorf("")},
  530. {pattern: "snowflake.torproject.net$", allowNonTLS: true, targetURL: "ftp://snowflake.torproject.net", expects: fmt.Errorf("")},
  531. }
  532. for _, v := range testingVector {
  533. err := checkIsRelayURLAcceptable(v.pattern, v.allowPrivateAddresses, v.allowNonTLS, v.targetURL)
  534. if v.expects != nil {
  535. So(err, ShouldNotBeNil)
  536. } else {
  537. So(err, ShouldBeNil)
  538. }
  539. }
  540. })
  541. }