client_test.go 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. package quic
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/tls"
  6. "errors"
  7. "fmt"
  8. "net"
  9. "os"
  10. "time"
  11. "github.com/bifurcation/mint"
  12. "github.com/golang/mock/gomock"
  13. "github.com/lucas-clemente/quic-go/internal/handshake"
  14. "github.com/lucas-clemente/quic-go/internal/protocol"
  15. "github.com/lucas-clemente/quic-go/internal/utils"
  16. "github.com/lucas-clemente/quic-go/internal/wire"
  17. "github.com/lucas-clemente/quic-go/qerr"
  18. . "github.com/onsi/ginkgo"
  19. . "github.com/onsi/gomega"
  20. )
  21. var _ = Describe("Client", func() {
  22. var (
  23. cl *client
  24. packetConn *mockPacketConn
  25. addr net.Addr
  26. connID protocol.ConnectionID
  27. mockMultiplexer *MockMultiplexer
  28. origMultiplexer multiplexer
  29. supportedVersionsWithoutGQUIC44 []protocol.VersionNumber
  30. originalClientSessConstructor func(connection, sessionRunner, string, protocol.VersionNumber, protocol.ConnectionID, protocol.ConnectionID, *tls.Config, *Config, protocol.VersionNumber, []protocol.VersionNumber, utils.Logger) (quicSession, error)
  31. )
  32. // generate a packet sent by the server that accepts the QUIC version suggested by the client
  33. acceptClientVersionPacket := func(connID protocol.ConnectionID) []byte {
  34. b := &bytes.Buffer{}
  35. err := (&wire.Header{
  36. DestConnectionID: connID,
  37. PacketNumber: 1,
  38. PacketNumberLen: 1,
  39. }).Write(b, protocol.PerspectiveServer, protocol.VersionWhatever)
  40. Expect(err).ToNot(HaveOccurred())
  41. return b.Bytes()
  42. }
  43. composeVersionNegotiationPacket := func(connID protocol.ConnectionID, versions []protocol.VersionNumber) *receivedPacket {
  44. return &receivedPacket{
  45. rcvTime: time.Now(),
  46. header: &wire.Header{
  47. IsVersionNegotiation: true,
  48. DestConnectionID: connID,
  49. SupportedVersions: versions,
  50. },
  51. }
  52. }
  53. BeforeEach(func() {
  54. connID = protocol.ConnectionID{0, 0, 0, 0, 0, 0, 0x13, 0x37}
  55. originalClientSessConstructor = newClientSession
  56. Eventually(areSessionsRunning).Should(BeFalse())
  57. // sess = NewMockQuicSession(mockCtrl)
  58. addr = &net.UDPAddr{IP: net.IPv4(192, 168, 100, 200), Port: 1337}
  59. packetConn = newMockPacketConn()
  60. packetConn.addr = &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 1234}
  61. packetConn.dataReadFrom = addr
  62. cl = &client{
  63. srcConnID: connID,
  64. destConnID: connID,
  65. version: protocol.SupportedVersions[0],
  66. conn: &conn{pconn: packetConn, currentAddr: addr},
  67. logger: utils.DefaultLogger,
  68. }
  69. getMultiplexer() // make the sync.Once execute
  70. // replace the clientMuxer. getClientMultiplexer will now return the MockMultiplexer
  71. mockMultiplexer = NewMockMultiplexer(mockCtrl)
  72. origMultiplexer = connMuxer
  73. connMuxer = mockMultiplexer
  74. for _, v := range protocol.SupportedVersions {
  75. if v != protocol.Version44 {
  76. supportedVersionsWithoutGQUIC44 = append(supportedVersionsWithoutGQUIC44, v)
  77. }
  78. }
  79. Expect(supportedVersionsWithoutGQUIC44).ToNot(BeEmpty())
  80. })
  81. AfterEach(func() {
  82. connMuxer = origMultiplexer
  83. newClientSession = originalClientSessConstructor
  84. })
  85. AfterEach(func() {
  86. if s, ok := cl.session.(*session); ok {
  87. s.Close()
  88. }
  89. Eventually(areSessionsRunning).Should(BeFalse())
  90. })
  91. Context("Dialing", func() {
  92. var origGenerateConnectionID func(int) (protocol.ConnectionID, error)
  93. var origGenerateConnectionIDForInitial func() (protocol.ConnectionID, error)
  94. BeforeEach(func() {
  95. origGenerateConnectionID = generateConnectionID
  96. origGenerateConnectionIDForInitial = generateConnectionIDForInitial
  97. generateConnectionID = func(int) (protocol.ConnectionID, error) {
  98. return connID, nil
  99. }
  100. generateConnectionIDForInitial = func() (protocol.ConnectionID, error) {
  101. return connID, nil
  102. }
  103. })
  104. AfterEach(func() {
  105. generateConnectionID = origGenerateConnectionID
  106. generateConnectionIDForInitial = origGenerateConnectionIDForInitial
  107. })
  108. It("resolves the address", func() {
  109. manager := NewMockPacketHandlerManager(mockCtrl)
  110. manager.EXPECT().Add(gomock.Any(), gomock.Any())
  111. mockMultiplexer.EXPECT().AddConn(gomock.Any(), gomock.Any()).Return(manager, nil)
  112. if os.Getenv("APPVEYOR") == "True" {
  113. Skip("This test is flaky on AppVeyor.")
  114. }
  115. remoteAddrChan := make(chan string, 1)
  116. newClientSession = func(
  117. conn connection,
  118. _ sessionRunner,
  119. _ string,
  120. _ protocol.VersionNumber,
  121. _ protocol.ConnectionID,
  122. _ protocol.ConnectionID,
  123. _ *tls.Config,
  124. _ *Config,
  125. _ protocol.VersionNumber,
  126. _ []protocol.VersionNumber,
  127. _ utils.Logger,
  128. ) (quicSession, error) {
  129. remoteAddrChan <- conn.RemoteAddr().String()
  130. sess := NewMockQuicSession(mockCtrl)
  131. sess.EXPECT().run()
  132. return sess, nil
  133. }
  134. _, err := DialAddr("localhost:17890", nil, &Config{HandshakeTimeout: time.Millisecond})
  135. Expect(err).ToNot(HaveOccurred())
  136. Eventually(remoteAddrChan).Should(Receive(Equal("127.0.0.1:17890")))
  137. })
  138. It("uses the tls.Config.ServerName as the hostname, if present", func() {
  139. manager := NewMockPacketHandlerManager(mockCtrl)
  140. manager.EXPECT().Add(gomock.Any(), gomock.Any())
  141. mockMultiplexer.EXPECT().AddConn(gomock.Any(), gomock.Any()).Return(manager, nil)
  142. hostnameChan := make(chan string, 1)
  143. newClientSession = func(
  144. _ connection,
  145. _ sessionRunner,
  146. h string,
  147. _ protocol.VersionNumber,
  148. _ protocol.ConnectionID,
  149. _ protocol.ConnectionID,
  150. _ *tls.Config,
  151. _ *Config,
  152. _ protocol.VersionNumber,
  153. _ []protocol.VersionNumber,
  154. _ utils.Logger,
  155. ) (quicSession, error) {
  156. hostnameChan <- h
  157. sess := NewMockQuicSession(mockCtrl)
  158. sess.EXPECT().run()
  159. return sess, nil
  160. }
  161. _, err := DialAddr("localhost:17890", &tls.Config{ServerName: "foobar"}, nil)
  162. Expect(err).ToNot(HaveOccurred())
  163. Eventually(hostnameChan).Should(Receive(Equal("foobar")))
  164. })
  165. It("returns after the handshake is complete", func() {
  166. manager := NewMockPacketHandlerManager(mockCtrl)
  167. manager.EXPECT().Add(gomock.Any(), gomock.Any())
  168. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  169. run := make(chan struct{})
  170. newClientSession = func(
  171. _ connection,
  172. runner sessionRunner,
  173. _ string,
  174. _ protocol.VersionNumber,
  175. _ protocol.ConnectionID,
  176. _ protocol.ConnectionID,
  177. _ *tls.Config,
  178. _ *Config,
  179. _ protocol.VersionNumber,
  180. _ []protocol.VersionNumber,
  181. _ utils.Logger,
  182. ) (quicSession, error) {
  183. sess := NewMockQuicSession(mockCtrl)
  184. sess.EXPECT().run().Do(func() { close(run) })
  185. runner.onHandshakeComplete(sess)
  186. return sess, nil
  187. }
  188. s, err := Dial(
  189. packetConn,
  190. addr,
  191. "quic.clemente.io:1337",
  192. nil,
  193. &Config{Versions: supportedVersionsWithoutGQUIC44},
  194. )
  195. Expect(err).ToNot(HaveOccurred())
  196. Expect(s).ToNot(BeNil())
  197. Eventually(run).Should(BeClosed())
  198. })
  199. It("refuses to multiplex gQUIC 44", func() {
  200. _, err := Dial(
  201. packetConn,
  202. addr,
  203. "quic.clemente.io:1337",
  204. nil,
  205. &Config{Versions: []protocol.VersionNumber{protocol.Version44}},
  206. )
  207. Expect(err).To(HaveOccurred())
  208. Expect(err.Error()).To(ContainSubstring("Cannot multiplex connections using gQUIC 44"))
  209. })
  210. It("returns an error that occurs while waiting for the connection to become secure", func() {
  211. manager := NewMockPacketHandlerManager(mockCtrl)
  212. manager.EXPECT().Add(gomock.Any(), gomock.Any())
  213. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  214. testErr := errors.New("early handshake error")
  215. newClientSession = func(
  216. conn connection,
  217. _ sessionRunner,
  218. _ string,
  219. _ protocol.VersionNumber,
  220. _ protocol.ConnectionID,
  221. _ protocol.ConnectionID,
  222. _ *tls.Config,
  223. _ *Config,
  224. _ protocol.VersionNumber,
  225. _ []protocol.VersionNumber,
  226. _ utils.Logger,
  227. ) (quicSession, error) {
  228. sess := NewMockQuicSession(mockCtrl)
  229. sess.EXPECT().run().Return(testErr)
  230. return sess, nil
  231. }
  232. packetConn.dataToRead <- acceptClientVersionPacket(cl.srcConnID)
  233. _, err := Dial(
  234. packetConn,
  235. addr,
  236. "quic.clemente.io:1337",
  237. nil,
  238. &Config{Versions: supportedVersionsWithoutGQUIC44},
  239. )
  240. Expect(err).To(MatchError(testErr))
  241. })
  242. It("closes the session when the context is canceled", func() {
  243. manager := NewMockPacketHandlerManager(mockCtrl)
  244. manager.EXPECT().Add(gomock.Any(), gomock.Any())
  245. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  246. sessionRunning := make(chan struct{})
  247. defer close(sessionRunning)
  248. sess := NewMockQuicSession(mockCtrl)
  249. sess.EXPECT().run().Do(func() {
  250. <-sessionRunning
  251. })
  252. newClientSession = func(
  253. conn connection,
  254. _ sessionRunner,
  255. _ string,
  256. _ protocol.VersionNumber,
  257. _ protocol.ConnectionID,
  258. _ protocol.ConnectionID,
  259. _ *tls.Config,
  260. _ *Config,
  261. _ protocol.VersionNumber,
  262. _ []protocol.VersionNumber,
  263. _ utils.Logger,
  264. ) (quicSession, error) {
  265. return sess, nil
  266. }
  267. ctx, cancel := context.WithCancel(context.Background())
  268. dialed := make(chan struct{})
  269. go func() {
  270. defer GinkgoRecover()
  271. _, err := DialContext(
  272. ctx,
  273. packetConn,
  274. addr,
  275. "quic.clemnte.io:1337",
  276. nil,
  277. &Config{Versions: supportedVersionsWithoutGQUIC44},
  278. )
  279. Expect(err).To(MatchError(context.Canceled))
  280. close(dialed)
  281. }()
  282. Consistently(dialed).ShouldNot(BeClosed())
  283. sess.EXPECT().Close()
  284. cancel()
  285. Eventually(dialed).Should(BeClosed())
  286. })
  287. It("removes closed sessions from the multiplexer", func() {
  288. manager := NewMockPacketHandlerManager(mockCtrl)
  289. manager.EXPECT().Add(connID, gomock.Any())
  290. manager.EXPECT().Remove(connID)
  291. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  292. var runner sessionRunner
  293. sess := NewMockQuicSession(mockCtrl)
  294. newClientSession = func(
  295. conn connection,
  296. runnerP sessionRunner,
  297. _ string,
  298. _ protocol.VersionNumber,
  299. _ protocol.ConnectionID,
  300. _ protocol.ConnectionID,
  301. _ *tls.Config,
  302. _ *Config,
  303. _ protocol.VersionNumber,
  304. _ []protocol.VersionNumber,
  305. _ utils.Logger,
  306. ) (quicSession, error) {
  307. runner = runnerP
  308. return sess, nil
  309. }
  310. sess.EXPECT().run().Do(func() {
  311. runner.removeConnectionID(connID)
  312. })
  313. _, err := DialContext(
  314. context.Background(),
  315. packetConn,
  316. addr,
  317. "quic.clemnte.io:1337",
  318. nil,
  319. &Config{Versions: supportedVersionsWithoutGQUIC44},
  320. )
  321. Expect(err).ToNot(HaveOccurred())
  322. })
  323. It("closes the connection when it was created by DialAddr", func() {
  324. manager := NewMockPacketHandlerManager(mockCtrl)
  325. mockMultiplexer.EXPECT().AddConn(gomock.Any(), gomock.Any()).Return(manager, nil)
  326. manager.EXPECT().Add(gomock.Any(), gomock.Any())
  327. var conn connection
  328. run := make(chan struct{})
  329. sessionCreated := make(chan struct{})
  330. sess := NewMockQuicSession(mockCtrl)
  331. newClientSession = func(
  332. connP connection,
  333. _ sessionRunner,
  334. _ string,
  335. _ protocol.VersionNumber,
  336. _ protocol.ConnectionID,
  337. _ protocol.ConnectionID,
  338. _ *tls.Config,
  339. _ *Config,
  340. _ protocol.VersionNumber,
  341. _ []protocol.VersionNumber,
  342. _ utils.Logger,
  343. ) (quicSession, error) {
  344. conn = connP
  345. close(sessionCreated)
  346. return sess, nil
  347. }
  348. sess.EXPECT().run().Do(func() {
  349. <-run
  350. })
  351. done := make(chan struct{})
  352. go func() {
  353. defer GinkgoRecover()
  354. _, err := DialAddr("quic.clemente.io:1337", nil, nil)
  355. Expect(err).ToNot(HaveOccurred())
  356. close(done)
  357. }()
  358. Eventually(sessionCreated).Should(BeClosed())
  359. // check that the connection is not closed
  360. Expect(conn.Write([]byte("foobar"))).To(Succeed())
  361. close(run)
  362. time.Sleep(50 * time.Millisecond)
  363. // check that the connection is closed
  364. err := conn.Write([]byte("foobar"))
  365. Expect(err).To(HaveOccurred())
  366. Expect(err.Error()).To(ContainSubstring("use of closed network connection"))
  367. Eventually(done).Should(BeClosed())
  368. })
  369. Context("quic.Config", func() {
  370. It("setups with the right values", func() {
  371. config := &Config{
  372. HandshakeTimeout: 1337 * time.Minute,
  373. IdleTimeout: 42 * time.Hour,
  374. RequestConnectionIDOmission: true,
  375. MaxIncomingStreams: 1234,
  376. MaxIncomingUniStreams: 4321,
  377. ConnectionIDLength: 13,
  378. Versions: supportedVersionsWithoutGQUIC44,
  379. }
  380. c := populateClientConfig(config, false)
  381. Expect(c.HandshakeTimeout).To(Equal(1337 * time.Minute))
  382. Expect(c.IdleTimeout).To(Equal(42 * time.Hour))
  383. Expect(c.RequestConnectionIDOmission).To(BeTrue())
  384. Expect(c.MaxIncomingStreams).To(Equal(1234))
  385. Expect(c.MaxIncomingUniStreams).To(Equal(4321))
  386. Expect(c.ConnectionIDLength).To(Equal(13))
  387. })
  388. It("uses a 0 byte connection IDs if gQUIC 44 is supported", func() {
  389. config := &Config{
  390. Versions: []protocol.VersionNumber{protocol.Version43, protocol.Version44},
  391. ConnectionIDLength: 13,
  392. }
  393. c := populateClientConfig(config, false)
  394. Expect(c.Versions).To(Equal([]protocol.VersionNumber{protocol.Version43, protocol.Version44}))
  395. Expect(c.ConnectionIDLength).To(BeZero())
  396. })
  397. It("doesn't use 0-byte connection IDs when dialing an address", func() {
  398. config := &Config{Versions: supportedVersionsWithoutGQUIC44}
  399. c := populateClientConfig(config, false)
  400. Expect(c.ConnectionIDLength).To(Equal(protocol.DefaultConnectionIDLength))
  401. })
  402. It("errors when the Config contains an invalid version", func() {
  403. manager := NewMockPacketHandlerManager(mockCtrl)
  404. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  405. version := protocol.VersionNumber(0x1234)
  406. _, err := Dial(packetConn, nil, "localhost:1234", &tls.Config{}, &Config{Versions: []protocol.VersionNumber{version}})
  407. Expect(err).To(MatchError("0x1234 is not a valid QUIC version"))
  408. })
  409. It("disables bidirectional streams", func() {
  410. config := &Config{
  411. MaxIncomingStreams: -1,
  412. MaxIncomingUniStreams: 4321,
  413. }
  414. c := populateClientConfig(config, false)
  415. Expect(c.MaxIncomingStreams).To(BeZero())
  416. Expect(c.MaxIncomingUniStreams).To(Equal(4321))
  417. })
  418. It("disables unidirectional streams", func() {
  419. config := &Config{
  420. MaxIncomingStreams: 1234,
  421. MaxIncomingUniStreams: -1,
  422. }
  423. c := populateClientConfig(config, false)
  424. Expect(c.MaxIncomingStreams).To(Equal(1234))
  425. Expect(c.MaxIncomingUniStreams).To(BeZero())
  426. })
  427. It("uses 0-byte connection IDs when dialing an address", func() {
  428. config := &Config{}
  429. c := populateClientConfig(config, true)
  430. Expect(c.ConnectionIDLength).To(BeZero())
  431. })
  432. It("fills in default values if options are not set in the Config", func() {
  433. c := populateClientConfig(&Config{}, false)
  434. Expect(c.Versions).To(Equal(protocol.SupportedVersions))
  435. Expect(c.HandshakeTimeout).To(Equal(protocol.DefaultHandshakeTimeout))
  436. Expect(c.IdleTimeout).To(Equal(protocol.DefaultIdleTimeout))
  437. Expect(c.RequestConnectionIDOmission).To(BeFalse())
  438. })
  439. })
  440. Context("gQUIC", func() {
  441. It("errors if it can't create a session", func() {
  442. manager := NewMockPacketHandlerManager(mockCtrl)
  443. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  444. testErr := errors.New("error creating session")
  445. newClientSession = func(
  446. _ connection,
  447. _ sessionRunner,
  448. _ string,
  449. _ protocol.VersionNumber,
  450. _ protocol.ConnectionID,
  451. _ protocol.ConnectionID,
  452. _ *tls.Config,
  453. _ *Config,
  454. _ protocol.VersionNumber,
  455. _ []protocol.VersionNumber,
  456. _ utils.Logger,
  457. ) (quicSession, error) {
  458. return nil, testErr
  459. }
  460. _, err := Dial(
  461. packetConn,
  462. addr,
  463. "quic.clemente.io:1337",
  464. nil,
  465. &Config{Versions: supportedVersionsWithoutGQUIC44},
  466. )
  467. Expect(err).To(MatchError(testErr))
  468. })
  469. })
  470. Context("IETF QUIC", func() {
  471. It("creates new TLS sessions with the right parameters", func() {
  472. manager := NewMockPacketHandlerManager(mockCtrl)
  473. manager.EXPECT().Add(connID, gomock.Any())
  474. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  475. config := &Config{Versions: []protocol.VersionNumber{protocol.VersionTLS}}
  476. c := make(chan struct{})
  477. var cconn connection
  478. var version protocol.VersionNumber
  479. var conf *Config
  480. newTLSClientSession = func(
  481. connP connection,
  482. _ sessionRunner,
  483. tokenP []byte,
  484. _ protocol.ConnectionID,
  485. _ protocol.ConnectionID,
  486. configP *Config,
  487. _ *mint.Config,
  488. paramsChan <-chan handshake.TransportParameters,
  489. _ protocol.PacketNumber,
  490. _ utils.Logger,
  491. versionP protocol.VersionNumber,
  492. ) (quicSession, error) {
  493. cconn = connP
  494. version = versionP
  495. conf = configP
  496. close(c)
  497. // TODO: check connection IDs?
  498. sess := NewMockQuicSession(mockCtrl)
  499. sess.EXPECT().run()
  500. return sess, nil
  501. }
  502. _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, config)
  503. Expect(err).ToNot(HaveOccurred())
  504. Eventually(c).Should(BeClosed())
  505. Expect(cconn.(*conn).pconn).To(Equal(packetConn))
  506. Expect(version).To(Equal(config.Versions[0]))
  507. Expect(conf.Versions).To(Equal(config.Versions))
  508. })
  509. It("creates a new session when the server performs a retry", func() {
  510. manager := NewMockPacketHandlerManager(mockCtrl)
  511. manager.EXPECT().Add(gomock.Any(), gomock.Any()).Do(func(id protocol.ConnectionID, handler packetHandler) {
  512. go handler.handlePacket(&receivedPacket{
  513. header: &wire.Header{
  514. IsLongHeader: true,
  515. Type: protocol.PacketTypeRetry,
  516. Token: []byte("foobar"),
  517. DestConnectionID: id,
  518. OrigDestConnectionID: connID,
  519. },
  520. })
  521. })
  522. manager.EXPECT().Add(gomock.Any(), gomock.Any())
  523. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  524. config := &Config{Versions: []protocol.VersionNumber{protocol.VersionTLS}}
  525. cl.config = config
  526. run1 := make(chan error)
  527. sess1 := NewMockQuicSession(mockCtrl)
  528. sess1.EXPECT().run().DoAndReturn(func() error {
  529. return <-run1
  530. })
  531. sess1.EXPECT().destroy(errCloseSessionForRetry).Do(func(e error) {
  532. run1 <- e
  533. })
  534. sess2 := NewMockQuicSession(mockCtrl)
  535. sess2.EXPECT().run()
  536. sessions := make(chan quicSession, 2)
  537. sessions <- sess1
  538. sessions <- sess2
  539. newTLSClientSession = func(
  540. _ connection,
  541. _ sessionRunner,
  542. _ []byte,
  543. _ protocol.ConnectionID,
  544. _ protocol.ConnectionID,
  545. _ *Config,
  546. _ *mint.Config,
  547. _ <-chan handshake.TransportParameters,
  548. _ protocol.PacketNumber,
  549. _ utils.Logger,
  550. _ protocol.VersionNumber,
  551. ) (quicSession, error) {
  552. return <-sessions, nil
  553. }
  554. _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, config)
  555. Expect(err).ToNot(HaveOccurred())
  556. Expect(sessions).To(BeEmpty())
  557. })
  558. It("only accepts 3 retries", func() {
  559. manager := NewMockPacketHandlerManager(mockCtrl)
  560. manager.EXPECT().Add(gomock.Any(), gomock.Any()).Do(func(id protocol.ConnectionID, handler packetHandler) {
  561. go handler.handlePacket(&receivedPacket{
  562. header: &wire.Header{
  563. IsLongHeader: true,
  564. Type: protocol.PacketTypeRetry,
  565. Token: []byte("foobar"),
  566. SrcConnectionID: connID,
  567. DestConnectionID: id,
  568. OrigDestConnectionID: connID,
  569. Version: protocol.VersionTLS,
  570. },
  571. })
  572. }).AnyTimes()
  573. manager.EXPECT().Add(gomock.Any(), gomock.Any()).AnyTimes()
  574. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  575. config := &Config{Versions: []protocol.VersionNumber{protocol.VersionTLS}}
  576. cl.config = config
  577. sessions := make(chan quicSession, protocol.MaxRetries+1)
  578. for i := 0; i < protocol.MaxRetries+1; i++ {
  579. run := make(chan error)
  580. sess := NewMockQuicSession(mockCtrl)
  581. sess.EXPECT().run().DoAndReturn(func() error {
  582. return <-run
  583. })
  584. sess.EXPECT().destroy(gomock.Any()).Do(func(e error) {
  585. run <- e
  586. })
  587. sessions <- sess
  588. }
  589. newTLSClientSession = func(
  590. _ connection,
  591. _ sessionRunner,
  592. _ []byte,
  593. _ protocol.ConnectionID,
  594. _ protocol.ConnectionID,
  595. _ *Config,
  596. _ *mint.Config,
  597. _ <-chan handshake.TransportParameters,
  598. _ protocol.PacketNumber,
  599. _ utils.Logger,
  600. _ protocol.VersionNumber,
  601. ) (quicSession, error) {
  602. return <-sessions, nil
  603. }
  604. _, err := Dial(packetConn, addr, "quic.clemente.io:1337", nil, config)
  605. Expect(err).To(HaveOccurred())
  606. Expect(err.(qerr.ErrorCode)).To(Equal(qerr.CryptoTooManyRejects))
  607. Expect(sessions).To(BeEmpty())
  608. })
  609. })
  610. Context("version negotiation", func() {
  611. var origSupportedVersions []protocol.VersionNumber
  612. BeforeEach(func() {
  613. origSupportedVersions = protocol.SupportedVersions
  614. protocol.SupportedVersions = append(protocol.SupportedVersions, []protocol.VersionNumber{77, 78}...)
  615. })
  616. AfterEach(func() {
  617. protocol.SupportedVersions = origSupportedVersions
  618. })
  619. It("returns an error that occurs during version negotiation", func() {
  620. manager := NewMockPacketHandlerManager(mockCtrl)
  621. manager.EXPECT().Add(connID, gomock.Any())
  622. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  623. testErr := errors.New("early handshake error")
  624. newClientSession = func(
  625. conn connection,
  626. _ sessionRunner,
  627. _ string,
  628. _ protocol.VersionNumber,
  629. _ protocol.ConnectionID,
  630. _ protocol.ConnectionID,
  631. _ *tls.Config,
  632. _ *Config,
  633. _ protocol.VersionNumber,
  634. _ []protocol.VersionNumber,
  635. _ utils.Logger,
  636. ) (quicSession, error) {
  637. Expect(conn.Write([]byte("0 fake CHLO"))).To(Succeed())
  638. sess := NewMockQuicSession(mockCtrl)
  639. sess.EXPECT().run().Return(testErr)
  640. return sess, nil
  641. }
  642. _, err := Dial(
  643. packetConn,
  644. addr,
  645. "quic.clemente.io:1337",
  646. nil,
  647. &Config{Versions: supportedVersionsWithoutGQUIC44},
  648. )
  649. Expect(err).To(MatchError(testErr))
  650. })
  651. It("recognizes that a packet without VersionFlag means that the server accepted the suggested version", func() {
  652. sess := NewMockQuicSession(mockCtrl)
  653. sess.EXPECT().handlePacket(gomock.Any())
  654. cl.session = sess
  655. cl.config = &Config{}
  656. ph := &wire.Header{
  657. PacketNumber: 1,
  658. PacketNumberLen: protocol.PacketNumberLen2,
  659. DestConnectionID: connID,
  660. SrcConnectionID: connID,
  661. }
  662. err := cl.handlePacketImpl(&receivedPacket{header: ph})
  663. Expect(err).ToNot(HaveOccurred())
  664. Expect(cl.versionNegotiated).To(BeTrue())
  665. })
  666. It("changes the version after receiving a Version Negotiation Packet", func() {
  667. phm := NewMockPacketHandlerManager(mockCtrl)
  668. phm.EXPECT().Add(connID, gomock.Any()).Times(2)
  669. cl.packetHandlers = phm
  670. version1 := protocol.Version39
  671. version2 := protocol.Version39 + 1
  672. Expect(version2.UsesTLS()).To(BeFalse())
  673. sess1 := NewMockQuicSession(mockCtrl)
  674. run1 := make(chan struct{})
  675. sess1.EXPECT().run().Do(func() { <-run1 }).Return(errCloseSessionForNewVersion)
  676. sess1.EXPECT().destroy(errCloseSessionForNewVersion).Do(func(error) { close(run1) })
  677. sess2 := NewMockQuicSession(mockCtrl)
  678. sess2.EXPECT().run()
  679. sessionChan := make(chan *MockQuicSession, 2)
  680. sessionChan <- sess1
  681. sessionChan <- sess2
  682. newClientSession = func(
  683. _ connection,
  684. _ sessionRunner,
  685. _ string,
  686. _ protocol.VersionNumber,
  687. _ protocol.ConnectionID,
  688. _ protocol.ConnectionID,
  689. _ *tls.Config,
  690. _ *Config,
  691. _ protocol.VersionNumber,
  692. _ []protocol.VersionNumber,
  693. _ utils.Logger,
  694. ) (quicSession, error) {
  695. return <-sessionChan, nil
  696. }
  697. cl.config = &Config{Versions: []protocol.VersionNumber{version1, version2}}
  698. dialed := make(chan struct{})
  699. go func() {
  700. defer GinkgoRecover()
  701. err := cl.dial(context.Background())
  702. Expect(err).ToNot(HaveOccurred())
  703. close(dialed)
  704. }()
  705. Eventually(sessionChan).Should(HaveLen(1))
  706. cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{version2}))
  707. Eventually(sessionChan).Should(BeEmpty())
  708. })
  709. It("only accepts one version negotiation packet", func() {
  710. phm := NewMockPacketHandlerManager(mockCtrl)
  711. phm.EXPECT().Add(connID, gomock.Any()).Times(2)
  712. cl.packetHandlers = phm
  713. version1 := protocol.Version39
  714. version2 := protocol.Version39 + 1
  715. version3 := protocol.Version39 + 2
  716. Expect(version2.UsesTLS()).To(BeFalse())
  717. Expect(version3.UsesTLS()).To(BeFalse())
  718. sess1 := NewMockQuicSession(mockCtrl)
  719. run1 := make(chan struct{})
  720. sess1.EXPECT().run().Do(func() { <-run1 }).Return(errCloseSessionForNewVersion)
  721. sess1.EXPECT().destroy(errCloseSessionForNewVersion).Do(func(error) { close(run1) })
  722. sess2 := NewMockQuicSession(mockCtrl)
  723. sess2.EXPECT().run()
  724. sessionChan := make(chan *MockQuicSession, 2)
  725. sessionChan <- sess1
  726. sessionChan <- sess2
  727. newClientSession = func(
  728. _ connection,
  729. _ sessionRunner,
  730. _ string,
  731. _ protocol.VersionNumber,
  732. _ protocol.ConnectionID,
  733. _ protocol.ConnectionID,
  734. _ *tls.Config,
  735. _ *Config,
  736. _ protocol.VersionNumber,
  737. _ []protocol.VersionNumber,
  738. _ utils.Logger,
  739. ) (quicSession, error) {
  740. return <-sessionChan, nil
  741. }
  742. cl.config = &Config{Versions: []protocol.VersionNumber{version1, version2, version3}}
  743. dialed := make(chan struct{})
  744. go func() {
  745. defer GinkgoRecover()
  746. err := cl.dial(context.Background())
  747. Expect(err).ToNot(HaveOccurred())
  748. close(dialed)
  749. }()
  750. Eventually(sessionChan).Should(HaveLen(1))
  751. cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{version2}))
  752. Eventually(sessionChan).Should(BeEmpty())
  753. Expect(cl.version).To(Equal(version2))
  754. cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{version3}))
  755. Eventually(dialed).Should(BeClosed())
  756. Expect(cl.version).To(Equal(version2))
  757. })
  758. It("errors if no matching version is found", func() {
  759. sess := NewMockQuicSession(mockCtrl)
  760. sess.EXPECT().destroy(qerr.InvalidVersion)
  761. cl.session = sess
  762. cl.config = &Config{Versions: protocol.SupportedVersions}
  763. cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{1}))
  764. })
  765. It("errors if the version is supported by quic-go, but disabled by the quic.Config", func() {
  766. sess := NewMockQuicSession(mockCtrl)
  767. sess.EXPECT().destroy(qerr.InvalidVersion)
  768. cl.session = sess
  769. v := protocol.VersionNumber(1234)
  770. Expect(v).ToNot(Equal(cl.version))
  771. cl.config = &Config{Versions: protocol.SupportedVersions}
  772. cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{v}))
  773. })
  774. It("changes to the version preferred by the quic.Config", func() {
  775. phm := NewMockPacketHandlerManager(mockCtrl)
  776. cl.packetHandlers = phm
  777. sess := NewMockQuicSession(mockCtrl)
  778. sess.EXPECT().destroy(errCloseSessionForNewVersion)
  779. cl.session = sess
  780. versions := []protocol.VersionNumber{1234, 4321}
  781. cl.config = &Config{Versions: versions}
  782. cl.handlePacket(composeVersionNegotiationPacket(connID, versions))
  783. Expect(cl.version).To(Equal(protocol.VersionNumber(1234)))
  784. })
  785. It("drops version negotiation packets that contain the offered version", func() {
  786. cl.config = &Config{}
  787. ver := cl.version
  788. cl.handlePacket(composeVersionNegotiationPacket(connID, []protocol.VersionNumber{ver}))
  789. Expect(cl.version).To(Equal(ver))
  790. })
  791. })
  792. })
  793. It("tells its version", func() {
  794. Expect(cl.version).ToNot(BeZero())
  795. Expect(cl.GetVersion()).To(Equal(cl.version))
  796. })
  797. It("ignores packets with the wrong Long Header Type", func() {
  798. cl.config = &Config{}
  799. hdr := &wire.Header{
  800. IsLongHeader: true,
  801. Type: protocol.PacketTypeInitial,
  802. PayloadLen: 123,
  803. SrcConnectionID: connID,
  804. DestConnectionID: connID,
  805. PacketNumberLen: protocol.PacketNumberLen1,
  806. Version: versionIETFFrames,
  807. }
  808. err := cl.handlePacketImpl(&receivedPacket{
  809. remoteAddr: addr,
  810. header: hdr,
  811. data: make([]byte, 456),
  812. })
  813. Expect(err).To(MatchError("Received unsupported packet type: Initial"))
  814. })
  815. It("ignores packets without connection id, if it didn't request connection id trunctation", func() {
  816. cl.version = versionGQUICFrames
  817. cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any handlePacket calls
  818. cl.config = &Config{RequestConnectionIDOmission: false}
  819. hdr := &wire.Header{
  820. IsPublicHeader: true,
  821. PacketNumber: 1,
  822. PacketNumberLen: 1,
  823. }
  824. err := cl.handlePacketImpl(&receivedPacket{
  825. remoteAddr: addr,
  826. header: hdr,
  827. })
  828. Expect(err).To(MatchError("received packet with truncated connection ID, but didn't request truncation"))
  829. })
  830. It("ignores packets with the wrong destination connection ID", func() {
  831. cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any handlePacket calls
  832. cl.version = versionIETFFrames
  833. cl.config = &Config{RequestConnectionIDOmission: false}
  834. connID2 := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}
  835. Expect(connID).ToNot(Equal(connID2))
  836. hdr := &wire.Header{
  837. DestConnectionID: connID2,
  838. SrcConnectionID: connID,
  839. PacketNumber: 1,
  840. PacketNumberLen: protocol.PacketNumberLen1,
  841. Version: versionIETFFrames,
  842. }
  843. err := cl.handlePacketImpl(&receivedPacket{
  844. remoteAddr: addr,
  845. header: hdr,
  846. })
  847. Expect(err).To(MatchError(fmt.Sprintf("received a packet with an unexpected connection ID (0x0807060504030201, expected %s)", connID)))
  848. })
  849. It("creates new gQUIC sessions with the right parameters", func() {
  850. manager := NewMockPacketHandlerManager(mockCtrl)
  851. manager.EXPECT().Add(gomock.Any(), gomock.Any())
  852. mockMultiplexer.EXPECT().AddConn(packetConn, gomock.Any()).Return(manager, nil)
  853. c := make(chan struct{})
  854. var cconn connection
  855. var hostname string
  856. var version protocol.VersionNumber
  857. var conf *Config
  858. newClientSession = func(
  859. connP connection,
  860. _ sessionRunner,
  861. hostnameP string,
  862. versionP protocol.VersionNumber,
  863. connIDP protocol.ConnectionID,
  864. _ protocol.ConnectionID,
  865. _ *tls.Config,
  866. configP *Config,
  867. _ protocol.VersionNumber,
  868. _ []protocol.VersionNumber,
  869. _ utils.Logger,
  870. ) (quicSession, error) {
  871. cconn = connP
  872. hostname = hostnameP
  873. version = versionP
  874. conf = configP
  875. connID = connIDP
  876. close(c)
  877. sess := NewMockQuicSession(mockCtrl)
  878. sess.EXPECT().run()
  879. return sess, nil
  880. }
  881. config := &Config{Versions: supportedVersionsWithoutGQUIC44}
  882. _, err := Dial(
  883. packetConn,
  884. addr,
  885. "quic.clemente.io:1337",
  886. nil,
  887. config,
  888. )
  889. Expect(err).ToNot(HaveOccurred())
  890. Eventually(c).Should(BeClosed())
  891. Expect(cconn.(*conn).pconn).To(Equal(packetConn))
  892. Expect(hostname).To(Equal("quic.clemente.io"))
  893. Expect(version).To(Equal(config.Versions[0]))
  894. Expect(conf.Versions).To(Equal(config.Versions))
  895. })
  896. Context("Public Reset handling", func() {
  897. var (
  898. pr []byte
  899. hdr *wire.Header
  900. hdrLen int
  901. )
  902. BeforeEach(func() {
  903. cl.config = &Config{}
  904. pr = wire.WritePublicReset(cl.destConnID, 1, 0)
  905. r := bytes.NewReader(pr)
  906. iHdr, err := wire.ParseInvariantHeader(r, 0)
  907. Expect(err).ToNot(HaveOccurred())
  908. hdr, err = iHdr.Parse(r, protocol.PerspectiveServer, versionGQUICFrames)
  909. Expect(err).ToNot(HaveOccurred())
  910. hdrLen = r.Len()
  911. })
  912. It("closes the session when receiving a Public Reset", func() {
  913. cl.version = versionGQUICFrames
  914. sess := NewMockQuicSession(mockCtrl)
  915. sess.EXPECT().closeRemote(gomock.Any()).Do(func(err error) {
  916. Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.PublicReset))
  917. })
  918. cl.session = sess
  919. cl.handlePacketImpl(&receivedPacket{
  920. remoteAddr: addr,
  921. header: hdr,
  922. data: pr[len(pr)-hdrLen:],
  923. })
  924. })
  925. It("ignores Public Resets from the wrong remote address", func() {
  926. cl.version = versionGQUICFrames
  927. cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any calls
  928. spoofedAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 5678}
  929. err := cl.handlePacketImpl(&receivedPacket{
  930. remoteAddr: spoofedAddr,
  931. header: hdr,
  932. data: pr[len(pr)-hdrLen:],
  933. })
  934. Expect(err).To(MatchError("Received a spoofed Public Reset"))
  935. })
  936. It("ignores unparseable Public Resets", func() {
  937. cl.version = versionGQUICFrames
  938. cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any calls
  939. err := cl.handlePacketImpl(&receivedPacket{
  940. remoteAddr: addr,
  941. header: hdr,
  942. data: pr[len(pr)-hdrLen : len(pr)-5], // cut off the last 5 bytes
  943. })
  944. Expect(err.Error()).To(ContainSubstring("Received a Public Reset. An error occurred parsing the packet"))
  945. })
  946. })
  947. })