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  }