github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/quic/gquic.go (about) 1 //go:build !PSIPHON_DISABLE_QUIC && !PSIPHON_DISABLE_GQUIC 2 // +build !PSIPHON_DISABLE_QUIC,!PSIPHON_DISABLE_GQUIC 3 4 /* 5 * Copyright (c) 2021, Psiphon Inc. 6 * All rights reserved. 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * 21 */ 22 23 package quic 24 25 import ( 26 "context" 27 "crypto/tls" 28 "net" 29 "time" 30 31 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors" 32 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic/gquic-go" 33 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic/gquic-go/h2quic" 34 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic/gquic-go/qerr" 35 ) 36 37 func GQUICEnabled() bool { 38 return true 39 } 40 41 type gQUICListener struct { 42 gquic.Listener 43 } 44 45 func (l *gQUICListener) Accept() (quicSession, error) { 46 session, err := l.Listener.Accept() 47 if err != nil { 48 return nil, errors.Trace(err) 49 } 50 return &gQUICSession{Session: session}, nil 51 } 52 53 func gQUICListen( 54 conn net.PacketConn, 55 tlsCertificate tls.Certificate, 56 serverIdleTimeout time.Duration) (quicListener, error) { 57 58 tlsConfig := &tls.Config{ 59 Certificates: []tls.Certificate{tlsCertificate}, 60 } 61 62 gQUICConfig := &gquic.Config{ 63 HandshakeTimeout: SERVER_HANDSHAKE_TIMEOUT, 64 IdleTimeout: serverIdleTimeout, 65 MaxIncomingStreams: 1, 66 MaxIncomingUniStreams: -1, 67 KeepAlive: true, 68 } 69 70 gl, err := gquic.Listen(conn, tlsConfig, gQUICConfig) 71 if err != nil { 72 return nil, errors.Trace(err) 73 } 74 75 return &gQUICListener{Listener: gl}, nil 76 } 77 78 type gQUICSession struct { 79 gquic.Session 80 } 81 82 func (s *gQUICSession) AcceptStream() (quicStream, error) { 83 stream, err := s.Session.AcceptStream() 84 if err != nil { 85 return nil, errors.Trace(err) 86 } 87 return stream, nil 88 } 89 90 func (s *gQUICSession) OpenStream() (quicStream, error) { 91 return s.Session.OpenStream() 92 } 93 94 func (s *gQUICSession) isErrorIndicatingClosed(err error) bool { 95 if err == nil { 96 return false 97 } 98 if quicErr, ok := err.(*qerr.QuicError); ok { 99 switch quicErr.ErrorCode { 100 case qerr.PeerGoingAway, qerr.NetworkIdleTimeout: 101 return true 102 } 103 } 104 return false 105 } 106 107 func gQUICDialContext( 108 ctx context.Context, 109 packetConn net.PacketConn, 110 remoteAddr *net.UDPAddr, 111 quicSNIAddress string, 112 versionNumber uint32) (quicSession, error) { 113 114 quicConfig := &gquic.Config{ 115 HandshakeTimeout: time.Duration(1<<63 - 1), 116 IdleTimeout: CLIENT_IDLE_TIMEOUT, 117 KeepAlive: true, 118 Versions: []gquic.VersionNumber{ 119 gquic.VersionNumber(versionNumber)}, 120 } 121 122 deadline, ok := ctx.Deadline() 123 if ok { 124 quicConfig.HandshakeTimeout = time.Until(deadline) 125 } 126 127 dialSession, err := gquic.DialContext( 128 ctx, 129 packetConn, 130 remoteAddr, 131 quicSNIAddress, 132 &tls.Config{ 133 InsecureSkipVerify: true, 134 }, 135 quicConfig) 136 if err != nil { 137 return nil, errors.Trace(err) 138 } 139 140 return &gQUICSession{Session: dialSession}, nil 141 } 142 143 func gQUICRoundTripper(t *QUICTransporter) (quicRoundTripper, error) { 144 return &h2quic.RoundTripper{Dial: t.dialgQUIC}, nil 145 } 146 147 func (t *QUICTransporter) dialgQUIC( 148 _, _ string, _ *tls.Config, _ *gquic.Config) (gquic.Session, error) { 149 session, err := t.dialQUIC() 150 if err != nil { 151 return nil, errors.Trace(err) 152 } 153 return session.(*gQUICSession).Session, nil 154 }