mirror of https://github.com/XTLS/Xray-core
				
				
				
			Transport: Remove QUIC (#3754)
https://github.com/XTLS/Xray-core/pull/3554#issuecomment-2236171077pull/3757/head^2
							parent
							
								
									ab3c00e96b
								
							
						
					
					
						commit
						9a953c070f
					
				| 
						 | 
				
			
			@ -13,7 +13,6 @@ type TransportConfig struct {
 | 
			
		|||
	WSConfig          *WebSocketConfig    `json:"wsSettings"`
 | 
			
		||||
	HTTPConfig        *HTTPConfig         `json:"httpSettings"`
 | 
			
		||||
	DSConfig          *DomainSocketConfig `json:"dsSettings"`
 | 
			
		||||
	QUICConfig        *QUICConfig         `json:"quicSettings"`
 | 
			
		||||
	GRPCConfig        *GRPCConfig         `json:"grpcSettings"`
 | 
			
		||||
	GUNConfig         *GRPCConfig         `json:"gunSettings"`
 | 
			
		||||
	HTTPUPGRADEConfig *HttpUpgradeConfig  `json:"httpupgradeSettings"`
 | 
			
		||||
| 
						 | 
				
			
			@ -79,17 +78,6 @@ func (c *TransportConfig) Build() (*global.Config, error) {
 | 
			
		|||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.QUICConfig != nil {
 | 
			
		||||
		qs, err := c.QUICConfig.Build()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.New("Failed to build QUIC config.").Base(err)
 | 
			
		||||
		}
 | 
			
		||||
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
			
		||||
			ProtocolName: "quic",
 | 
			
		||||
			Settings:     serial.ToTypedMessage(qs),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.GRPCConfig == nil {
 | 
			
		||||
		c.GRPCConfig = c.GUNConfig
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,6 @@ import (
 | 
			
		|||
	"github.com/xtls/xray-core/common/errors"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net"
 | 
			
		||||
	"github.com/xtls/xray-core/common/platform/filesystem"
 | 
			
		||||
	"github.com/xtls/xray-core/common/protocol"
 | 
			
		||||
	"github.com/xtls/xray-core/common/serial"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/domainsocket"
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +21,6 @@ import (
 | 
			
		|||
	"github.com/xtls/xray-core/transport/internet/http"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/httpupgrade"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/kcp"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/quic"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/reality"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/splithttp"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/tcp"
 | 
			
		||||
| 
						 | 
				
			
			@ -315,47 +313,6 @@ func (c *HTTPConfig) Build() (proto.Message, error) {
 | 
			
		|||
	return config, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type QUICConfig struct {
 | 
			
		||||
	Header   json.RawMessage `json:"header"`
 | 
			
		||||
	Security string          `json:"security"`
 | 
			
		||||
	Key      string          `json:"key"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Build implements Buildable.
 | 
			
		||||
func (c *QUICConfig) Build() (proto.Message, error) {
 | 
			
		||||
	config := &quic.Config{
 | 
			
		||||
		Key: c.Key,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(c.Header) > 0 {
 | 
			
		||||
		headerConfig, _, err := kcpHeaderLoader.Load(c.Header)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.New("invalid QUIC header config.").Base(err).AtError()
 | 
			
		||||
		}
 | 
			
		||||
		ts, err := headerConfig.(Buildable).Build()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.New("invalid QUIC header config").Base(err).AtError()
 | 
			
		||||
		}
 | 
			
		||||
		config.Header = serial.ToTypedMessage(ts)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var st protocol.SecurityType
 | 
			
		||||
	switch strings.ToLower(c.Security) {
 | 
			
		||||
	case "aes-128-gcm":
 | 
			
		||||
		st = protocol.SecurityType_AES128_GCM
 | 
			
		||||
	case "chacha20-poly1305":
 | 
			
		||||
		st = protocol.SecurityType_CHACHA20_POLY1305
 | 
			
		||||
	default:
 | 
			
		||||
		st = protocol.SecurityType_NONE
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config.Security = &protocol.SecurityConfig{
 | 
			
		||||
		Type: st,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return config, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type DomainSocketConfig struct {
 | 
			
		||||
	Path     string `json:"path"`
 | 
			
		||||
	Abstract bool   `json:"abstract"`
 | 
			
		||||
| 
						 | 
				
			
			@ -691,8 +648,6 @@ func (p TransportProtocol) Build() (string, error) {
 | 
			
		|||
		return "http", nil
 | 
			
		||||
	case "ds", "domainsocket":
 | 
			
		||||
		return "domainsocket", nil
 | 
			
		||||
	case "quic":
 | 
			
		||||
		return "quic", nil
 | 
			
		||||
	case "grpc", "gun":
 | 
			
		||||
		return "grpc", nil
 | 
			
		||||
	case "httpupgrade":
 | 
			
		||||
| 
						 | 
				
			
			@ -829,7 +784,6 @@ type StreamConfig struct {
 | 
			
		|||
	WSSettings          *WebSocketConfig    `json:"wsSettings"`
 | 
			
		||||
	HTTPSettings        *HTTPConfig         `json:"httpSettings"`
 | 
			
		||||
	DSSettings          *DomainSocketConfig `json:"dsSettings"`
 | 
			
		||||
	QUICSettings        *QUICConfig         `json:"quicSettings"`
 | 
			
		||||
	SocketSettings      *SocketConfig       `json:"sockopt"`
 | 
			
		||||
	GRPCConfig          *GRPCConfig         `json:"grpcSettings"`
 | 
			
		||||
	GUNConfig           *GRPCConfig         `json:"gunSettings"`
 | 
			
		||||
| 
						 | 
				
			
			@ -932,16 +886,6 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
 | 
			
		|||
			Settings:     serial.ToTypedMessage(ds),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if c.QUICSettings != nil {
 | 
			
		||||
		qs, err := c.QUICSettings.Build()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, errors.New("Failed to build QUIC config").Base(err)
 | 
			
		||||
		}
 | 
			
		||||
		config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
 | 
			
		||||
			ProtocolName: "quic",
 | 
			
		||||
			Settings:     serial.ToTypedMessage(qs),
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	if c.GRPCConfig == nil {
 | 
			
		||||
		c.GRPCConfig = c.GUNConfig
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ import (
 | 
			
		|||
	"encoding/json"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/common/protocol"
 | 
			
		||||
	"github.com/xtls/xray-core/common/serial"
 | 
			
		||||
	. "github.com/xtls/xray-core/infra/conf"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/global"
 | 
			
		||||
| 
						 | 
				
			
			@ -12,9 +11,7 @@ import (
 | 
			
		|||
	"github.com/xtls/xray-core/transport/internet/grpc"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/headers/http"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/headers/noop"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/headers/tls"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/kcp"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/quic"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/tcp"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/websocket"
 | 
			
		||||
	"google.golang.org/protobuf/proto"
 | 
			
		||||
| 
						 | 
				
			
			@ -203,12 +200,6 @@ func TestTransportConfig(t *testing.T) {
 | 
			
		|||
				"wsSettings": {
 | 
			
		||||
					"path": "/t"
 | 
			
		||||
				},
 | 
			
		||||
				"quicSettings": {
 | 
			
		||||
					"key": "abcd",
 | 
			
		||||
					"header": {
 | 
			
		||||
						"type": "dtls"
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"grpcSettings": {
 | 
			
		||||
					"serviceName": "name",
 | 
			
		||||
					"multiMode": true
 | 
			
		||||
| 
						 | 
				
			
			@ -272,16 +263,6 @@ func TestTransportConfig(t *testing.T) {
 | 
			
		|||
							Path: "/t",
 | 
			
		||||
						}),
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						ProtocolName: "quic",
 | 
			
		||||
						Settings: serial.ToTypedMessage(&quic.Config{
 | 
			
		||||
							Key: "abcd",
 | 
			
		||||
							Security: &protocol.SecurityConfig{
 | 
			
		||||
								Type: protocol.SecurityType_NONE,
 | 
			
		||||
							},
 | 
			
		||||
							Header: serial.ToTypedMessage(&tls.PacketConfig{}),
 | 
			
		||||
						}),
 | 
			
		||||
					},
 | 
			
		||||
					{
 | 
			
		||||
						ProtocolName: "grpc",
 | 
			
		||||
						Settings: serial.ToTypedMessage(&grpc.Config{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,7 +55,6 @@ import (
 | 
			
		|||
	_ "github.com/xtls/xray-core/transport/internet/http"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/httpupgrade"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/kcp"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/quic"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/reality"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/splithttp"
 | 
			
		||||
	_ "github.com/xtls/xray-core/transport/internet/tcp"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,10 +6,8 @@ import (
 | 
			
		|||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/app/log"
 | 
			
		||||
	"github.com/xtls/xray-core/app/proxyman"
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	clog "github.com/xtls/xray-core/common/log"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net"
 | 
			
		||||
	"github.com/xtls/xray-core/common/protocol"
 | 
			
		||||
	"github.com/xtls/xray-core/common/serial"
 | 
			
		||||
| 
						 | 
				
			
			@ -21,14 +19,10 @@ import (
 | 
			
		|||
	"github.com/xtls/xray-core/proxy/vmess/inbound"
 | 
			
		||||
	"github.com/xtls/xray-core/proxy/vmess/outbound"
 | 
			
		||||
	"github.com/xtls/xray-core/testing/servers/tcp"
 | 
			
		||||
	"github.com/xtls/xray-core/testing/servers/udp"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/domainsocket"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/headers/http"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/headers/wechat"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/quic"
 | 
			
		||||
	tcptransport "github.com/xtls/xray-core/transport/internet/tcp"
 | 
			
		||||
	"golang.org/x/sync/errgroup"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestHTTPConnectionHeader(t *testing.T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -248,136 +242,3 @@ func TestDomainSocket(t *testing.T) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestVMessQuic(t *testing.T) {
 | 
			
		||||
	tcpServer := tcp.Server{
 | 
			
		||||
		MsgProcessor: xor,
 | 
			
		||||
	}
 | 
			
		||||
	dest, err := tcpServer.Start()
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
	defer tcpServer.Close()
 | 
			
		||||
 | 
			
		||||
	userID := protocol.NewID(uuid.New())
 | 
			
		||||
	serverPort := udp.PickPort()
 | 
			
		||||
	serverConfig := &core.Config{
 | 
			
		||||
		App: []*serial.TypedMessage{
 | 
			
		||||
			serial.ToTypedMessage(&log.Config{
 | 
			
		||||
				ErrorLogLevel: clog.Severity_Debug,
 | 
			
		||||
				ErrorLogType:  log.LogType_Console,
 | 
			
		||||
			}),
 | 
			
		||||
		},
 | 
			
		||||
		Inbound: []*core.InboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
 | 
			
		||||
					PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
 | 
			
		||||
					Listen:   net.NewIPOrDomain(net.LocalHostIP),
 | 
			
		||||
					StreamSettings: &internet.StreamConfig{
 | 
			
		||||
						ProtocolName: "quic",
 | 
			
		||||
						TransportSettings: []*internet.TransportConfig{
 | 
			
		||||
							{
 | 
			
		||||
								ProtocolName: "quic",
 | 
			
		||||
								Settings: serial.ToTypedMessage(&quic.Config{
 | 
			
		||||
									Header: serial.ToTypedMessage(&wechat.VideoConfig{}),
 | 
			
		||||
									Security: &protocol.SecurityConfig{
 | 
			
		||||
										Type: protocol.SecurityType_NONE,
 | 
			
		||||
									},
 | 
			
		||||
								}),
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&inbound.Config{
 | 
			
		||||
					User: []*protocol.User{
 | 
			
		||||
						{
 | 
			
		||||
							Account: serial.ToTypedMessage(&vmess.Account{
 | 
			
		||||
								Id: userID.String(),
 | 
			
		||||
							}),
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	clientPort := tcp.PickPort()
 | 
			
		||||
	clientConfig := &core.Config{
 | 
			
		||||
		App: []*serial.TypedMessage{
 | 
			
		||||
			serial.ToTypedMessage(&log.Config{
 | 
			
		||||
				ErrorLogLevel: clog.Severity_Debug,
 | 
			
		||||
				ErrorLogType:  log.LogType_Console,
 | 
			
		||||
			}),
 | 
			
		||||
		},
 | 
			
		||||
		Inbound: []*core.InboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
 | 
			
		||||
					PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
 | 
			
		||||
					Listen:   net.NewIPOrDomain(net.LocalHostIP),
 | 
			
		||||
				}),
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
 | 
			
		||||
					Address: net.NewIPOrDomain(dest.Address),
 | 
			
		||||
					Port:    uint32(dest.Port),
 | 
			
		||||
					NetworkList: &net.NetworkList{
 | 
			
		||||
						Network: []net.Network{net.Network_TCP},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		Outbound: []*core.OutboundHandlerConfig{
 | 
			
		||||
			{
 | 
			
		||||
				SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
 | 
			
		||||
					StreamSettings: &internet.StreamConfig{
 | 
			
		||||
						ProtocolName: "quic",
 | 
			
		||||
						TransportSettings: []*internet.TransportConfig{
 | 
			
		||||
							{
 | 
			
		||||
								ProtocolName: "quic",
 | 
			
		||||
								Settings: serial.ToTypedMessage(&quic.Config{
 | 
			
		||||
									Header: serial.ToTypedMessage(&wechat.VideoConfig{}),
 | 
			
		||||
									Security: &protocol.SecurityConfig{
 | 
			
		||||
										Type: protocol.SecurityType_NONE,
 | 
			
		||||
									},
 | 
			
		||||
								}),
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
				ProxySettings: serial.ToTypedMessage(&outbound.Config{
 | 
			
		||||
					Receiver: []*protocol.ServerEndpoint{
 | 
			
		||||
						{
 | 
			
		||||
							Address: net.NewIPOrDomain(net.LocalHostIP),
 | 
			
		||||
							Port:    uint32(serverPort),
 | 
			
		||||
							User: []*protocol.User{
 | 
			
		||||
								{
 | 
			
		||||
									Account: serial.ToTypedMessage(&vmess.Account{
 | 
			
		||||
										Id: userID.String(),
 | 
			
		||||
										SecuritySettings: &protocol.SecurityConfig{
 | 
			
		||||
											Type: protocol.SecurityType_AES128_GCM,
 | 
			
		||||
										},
 | 
			
		||||
									}),
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				}),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	servers, err := InitializeServerConfigs(serverConfig, clientConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal("Failed to initialize all servers: ", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
	defer CloseAllServers(servers)
 | 
			
		||||
 | 
			
		||||
	var errg errgroup.Group
 | 
			
		||||
	for i := 0; i < 10; i++ {
 | 
			
		||||
		errg.Go(testTCPConn(clientPort, 10240*1024, time.Second*40))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := errg.Wait(); err != nil {
 | 
			
		||||
		t.Error(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,48 +0,0 @@
 | 
			
		|||
package quic
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/aes"
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"crypto/sha256"
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	"github.com/xtls/xray-core/common/protocol"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"golang.org/x/crypto/chacha20poly1305"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func getAuth(config *Config) (cipher.AEAD, error) {
 | 
			
		||||
	security := config.Security.GetSecurityType()
 | 
			
		||||
	if security == protocol.SecurityType_NONE {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	salted := []byte(config.Key + "xray-quic-salt")
 | 
			
		||||
	key := sha256.Sum256(salted)
 | 
			
		||||
 | 
			
		||||
	if security == protocol.SecurityType_AES128_GCM {
 | 
			
		||||
		block, err := aes.NewCipher(key[:16])
 | 
			
		||||
		common.Must(err)
 | 
			
		||||
		return cipher.NewGCM(block)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if security == protocol.SecurityType_CHACHA20_POLY1305 {
 | 
			
		||||
		return chacha20poly1305.New(key[:])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errors.New("unsupported security type")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getHeader(config *Config) (internet.PacketHeader, error) {
 | 
			
		||||
	if config.Header == nil {
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msg, err := config.Header.GetInstance()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return internet.CreatePacketHeader(msg)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,184 +0,0 @@
 | 
			
		|||
// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
			
		||||
// versions:
 | 
			
		||||
// 	protoc-gen-go v1.34.2
 | 
			
		||||
// 	protoc        v5.27.0
 | 
			
		||||
// source: transport/internet/quic/config.proto
 | 
			
		||||
 | 
			
		||||
package quic
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	protocol "github.com/xtls/xray-core/common/protocol"
 | 
			
		||||
	serial "github.com/xtls/xray-core/common/serial"
 | 
			
		||||
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 | 
			
		||||
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 | 
			
		||||
	reflect "reflect"
 | 
			
		||||
	sync "sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Verify that this generated code is sufficiently up-to-date.
 | 
			
		||||
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
 | 
			
		||||
	// Verify that runtime/protoimpl is sufficiently up-to-date.
 | 
			
		||||
	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	state         protoimpl.MessageState
 | 
			
		||||
	sizeCache     protoimpl.SizeCache
 | 
			
		||||
	unknownFields protoimpl.UnknownFields
 | 
			
		||||
 | 
			
		||||
	Key      string                   `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
 | 
			
		||||
	Security *protocol.SecurityConfig `protobuf:"bytes,2,opt,name=security,proto3" json:"security,omitempty"`
 | 
			
		||||
	Header   *serial.TypedMessage     `protobuf:"bytes,3,opt,name=header,proto3" json:"header,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) Reset() {
 | 
			
		||||
	*x = Config{}
 | 
			
		||||
	if protoimpl.UnsafeEnabled {
 | 
			
		||||
		mi := &file_transport_internet_quic_config_proto_msgTypes[0]
 | 
			
		||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
			
		||||
		ms.StoreMessageInfo(mi)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) String() string {
 | 
			
		||||
	return protoimpl.X.MessageStringOf(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*Config) ProtoMessage() {}
 | 
			
		||||
 | 
			
		||||
func (x *Config) ProtoReflect() protoreflect.Message {
 | 
			
		||||
	mi := &file_transport_internet_quic_config_proto_msgTypes[0]
 | 
			
		||||
	if protoimpl.UnsafeEnabled && x != nil {
 | 
			
		||||
		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 | 
			
		||||
		if ms.LoadMessageInfo() == nil {
 | 
			
		||||
			ms.StoreMessageInfo(mi)
 | 
			
		||||
		}
 | 
			
		||||
		return ms
 | 
			
		||||
	}
 | 
			
		||||
	return mi.MessageOf(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
 | 
			
		||||
func (*Config) Descriptor() ([]byte, []int) {
 | 
			
		||||
	return file_transport_internet_quic_config_proto_rawDescGZIP(), []int{0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) GetKey() string {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.Key
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) GetSecurity() *protocol.SecurityConfig {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.Security
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *Config) GetHeader() *serial.TypedMessage {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.Header
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var File_transport_internet_quic_config_proto protoreflect.FileDescriptor
 | 
			
		||||
 | 
			
		||||
var file_transport_internet_quic_config_proto_rawDesc = []byte{
 | 
			
		||||
	0x0a, 0x24, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65,
 | 
			
		||||
	0x72, 0x6e, 0x65, 0x74, 0x2f, 0x71, 0x75, 0x69, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
 | 
			
		||||
	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61,
 | 
			
		||||
	0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e,
 | 
			
		||||
	0x71, 0x75, 0x69, 0x63, 0x1a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72,
 | 
			
		||||
	0x69, 0x61, 0x6c, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
 | 
			
		||||
	0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f,
 | 
			
		||||
	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73,
 | 
			
		||||
	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x96, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69,
 | 
			
		||||
	0x67, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
 | 
			
		||||
	0x6b, 0x65, 0x79, 0x12, 0x40, 0x0a, 0x08, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x18,
 | 
			
		||||
	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
 | 
			
		||||
	0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x53, 0x65, 0x63,
 | 
			
		||||
	0x75, 0x72, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x63,
 | 
			
		||||
	0x75, 0x72, 0x69, 0x74, 0x79, 0x12, 0x38, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18,
 | 
			
		||||
	0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
 | 
			
		||||
	0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x64,
 | 
			
		||||
	0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42,
 | 
			
		||||
	0x76, 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
 | 
			
		||||
	0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x71,
 | 
			
		||||
	0x75, 0x69, 0x63, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
 | 
			
		||||
	0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65,
 | 
			
		||||
	0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72,
 | 
			
		||||
	0x6e, 0x65, 0x74, 0x2f, 0x71, 0x75, 0x69, 0x63, 0xaa, 0x02, 0x1c, 0x58, 0x72, 0x61, 0x79, 0x2e,
 | 
			
		||||
	0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
 | 
			
		||||
	0x65, 0x74, 0x2e, 0x51, 0x75, 0x69, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	file_transport_internet_quic_config_proto_rawDescOnce sync.Once
 | 
			
		||||
	file_transport_internet_quic_config_proto_rawDescData = file_transport_internet_quic_config_proto_rawDesc
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func file_transport_internet_quic_config_proto_rawDescGZIP() []byte {
 | 
			
		||||
	file_transport_internet_quic_config_proto_rawDescOnce.Do(func() {
 | 
			
		||||
		file_transport_internet_quic_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_transport_internet_quic_config_proto_rawDescData)
 | 
			
		||||
	})
 | 
			
		||||
	return file_transport_internet_quic_config_proto_rawDescData
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var file_transport_internet_quic_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
 | 
			
		||||
var file_transport_internet_quic_config_proto_goTypes = []any{
 | 
			
		||||
	(*Config)(nil),                  // 0: xray.transport.internet.quic.Config
 | 
			
		||||
	(*protocol.SecurityConfig)(nil), // 1: xray.common.protocol.SecurityConfig
 | 
			
		||||
	(*serial.TypedMessage)(nil),     // 2: xray.common.serial.TypedMessage
 | 
			
		||||
}
 | 
			
		||||
var file_transport_internet_quic_config_proto_depIdxs = []int32{
 | 
			
		||||
	1, // 0: xray.transport.internet.quic.Config.security:type_name -> xray.common.protocol.SecurityConfig
 | 
			
		||||
	2, // 1: xray.transport.internet.quic.Config.header:type_name -> xray.common.serial.TypedMessage
 | 
			
		||||
	2, // [2:2] is the sub-list for method output_type
 | 
			
		||||
	2, // [2:2] is the sub-list for method input_type
 | 
			
		||||
	2, // [2:2] is the sub-list for extension type_name
 | 
			
		||||
	2, // [2:2] is the sub-list for extension extendee
 | 
			
		||||
	0, // [0:2] is the sub-list for field type_name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() { file_transport_internet_quic_config_proto_init() }
 | 
			
		||||
func file_transport_internet_quic_config_proto_init() {
 | 
			
		||||
	if File_transport_internet_quic_config_proto != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if !protoimpl.UnsafeEnabled {
 | 
			
		||||
		file_transport_internet_quic_config_proto_msgTypes[0].Exporter = func(v any, i int) any {
 | 
			
		||||
			switch v := v.(*Config); i {
 | 
			
		||||
			case 0:
 | 
			
		||||
				return &v.state
 | 
			
		||||
			case 1:
 | 
			
		||||
				return &v.sizeCache
 | 
			
		||||
			case 2:
 | 
			
		||||
				return &v.unknownFields
 | 
			
		||||
			default:
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	type x struct{}
 | 
			
		||||
	out := protoimpl.TypeBuilder{
 | 
			
		||||
		File: protoimpl.DescBuilder{
 | 
			
		||||
			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 | 
			
		||||
			RawDescriptor: file_transport_internet_quic_config_proto_rawDesc,
 | 
			
		||||
			NumEnums:      0,
 | 
			
		||||
			NumMessages:   1,
 | 
			
		||||
			NumExtensions: 0,
 | 
			
		||||
			NumServices:   0,
 | 
			
		||||
		},
 | 
			
		||||
		GoTypes:           file_transport_internet_quic_config_proto_goTypes,
 | 
			
		||||
		DependencyIndexes: file_transport_internet_quic_config_proto_depIdxs,
 | 
			
		||||
		MessageInfos:      file_transport_internet_quic_config_proto_msgTypes,
 | 
			
		||||
	}.Build()
 | 
			
		||||
	File_transport_internet_quic_config_proto = out.File
 | 
			
		||||
	file_transport_internet_quic_config_proto_rawDesc = nil
 | 
			
		||||
	file_transport_internet_quic_config_proto_goTypes = nil
 | 
			
		||||
	file_transport_internet_quic_config_proto_depIdxs = nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,16 +0,0 @@
 | 
			
		|||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
package xray.transport.internet.quic;
 | 
			
		||||
option csharp_namespace = "Xray.Transport.Internet.Quic";
 | 
			
		||||
option go_package = "github.com/xtls/xray-core/transport/internet/quic";
 | 
			
		||||
option java_package = "com.xray.transport.internet.quic";
 | 
			
		||||
option java_multiple_files = true;
 | 
			
		||||
 | 
			
		||||
import "common/serial/typed_message.proto";
 | 
			
		||||
import "common/protocol/headers.proto";
 | 
			
		||||
 | 
			
		||||
message Config {
 | 
			
		||||
  string key = 1;
 | 
			
		||||
  xray.common.protocol.SecurityConfig security = 2;
 | 
			
		||||
  xray.common.serial.TypedMessage header = 3;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,198 +0,0 @@
 | 
			
		|||
package quic
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/cipher"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/quic-go/quic-go"
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	"github.com/xtls/xray-core/common/buf"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type sysConn struct {
 | 
			
		||||
	conn   *net.UDPConn
 | 
			
		||||
	header internet.PacketHeader
 | 
			
		||||
	auth   cipher.AEAD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func wrapSysConn(rawConn *net.UDPConn, config *Config) (*sysConn, error) {
 | 
			
		||||
	header, err := getHeader(config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	auth, err := getAuth(config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &sysConn{
 | 
			
		||||
		conn:   rawConn,
 | 
			
		||||
		header: header,
 | 
			
		||||
		auth:   auth,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errInvalidPacket = errors.New("invalid packet")
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) readFromInternal(p []byte) (int, net.Addr, error) {
 | 
			
		||||
	buffer := getBuffer()
 | 
			
		||||
	defer putBuffer(buffer)
 | 
			
		||||
 | 
			
		||||
	nBytes, addr, err := c.conn.ReadFrom(buffer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	payload := buffer[:nBytes]
 | 
			
		||||
	if c.header != nil {
 | 
			
		||||
		if len(payload) <= int(c.header.Size()) {
 | 
			
		||||
			return 0, nil, errInvalidPacket
 | 
			
		||||
		}
 | 
			
		||||
		payload = payload[c.header.Size():]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.auth == nil {
 | 
			
		||||
		n := copy(p, payload)
 | 
			
		||||
		return n, addr, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(payload) <= c.auth.NonceSize() {
 | 
			
		||||
		return 0, nil, errInvalidPacket
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nonce := payload[:c.auth.NonceSize()]
 | 
			
		||||
	payload = payload[c.auth.NonceSize():]
 | 
			
		||||
 | 
			
		||||
	p, err = c.auth.Open(p[:0], nonce, payload, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, nil, errInvalidPacket
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return len(p), addr, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) ReadFrom(p []byte) (int, net.Addr, error) {
 | 
			
		||||
	if c.header == nil && c.auth == nil {
 | 
			
		||||
		return c.conn.ReadFrom(p)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		n, addr, err := c.readFromInternal(p)
 | 
			
		||||
		if err != nil && err != errInvalidPacket {
 | 
			
		||||
			return 0, nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return n, addr, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) WriteTo(p []byte, addr net.Addr) (int, error) {
 | 
			
		||||
	if c.header == nil && c.auth == nil {
 | 
			
		||||
		return c.conn.WriteTo(p, addr)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buffer := getBuffer()
 | 
			
		||||
	defer putBuffer(buffer)
 | 
			
		||||
 | 
			
		||||
	payload := buffer
 | 
			
		||||
	n := 0
 | 
			
		||||
	if c.header != nil {
 | 
			
		||||
		c.header.Serialize(payload)
 | 
			
		||||
		n = int(c.header.Size())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if c.auth == nil {
 | 
			
		||||
		nBytes := copy(payload[n:], p)
 | 
			
		||||
		n += nBytes
 | 
			
		||||
	} else {
 | 
			
		||||
		nounce := payload[n : n+c.auth.NonceSize()]
 | 
			
		||||
		common.Must2(rand.Read(nounce))
 | 
			
		||||
		n += c.auth.NonceSize()
 | 
			
		||||
		pp := c.auth.Seal(payload[:n], nounce, p, nil)
 | 
			
		||||
		n = len(pp)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return c.conn.WriteTo(payload[:n], addr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) Close() error {
 | 
			
		||||
	return c.conn.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) LocalAddr() net.Addr {
 | 
			
		||||
	return c.conn.LocalAddr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) SetReadBuffer(bytes int) error {
 | 
			
		||||
	return c.conn.SetReadBuffer(bytes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) SetWriteBuffer(bytes int) error {
 | 
			
		||||
	return c.conn.SetWriteBuffer(bytes)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) SetDeadline(t time.Time) error {
 | 
			
		||||
	return c.conn.SetDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) SetReadDeadline(t time.Time) error {
 | 
			
		||||
	return c.conn.SetReadDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) SetWriteDeadline(t time.Time) error {
 | 
			
		||||
	return c.conn.SetWriteDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *sysConn) SyscallConn() (syscall.RawConn, error) {
 | 
			
		||||
	return c.conn.SyscallConn()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type interConn struct {
 | 
			
		||||
	stream quic.Stream
 | 
			
		||||
	local  net.Addr
 | 
			
		||||
	remote net.Addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *interConn) Read(b []byte) (int, error) {
 | 
			
		||||
	return c.stream.Read(b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *interConn) WriteMultiBuffer(mb buf.MultiBuffer) error {
 | 
			
		||||
	mb = buf.Compact(mb)
 | 
			
		||||
	mb, err := buf.WriteMultiBuffer(c, mb)
 | 
			
		||||
	buf.ReleaseMulti(mb)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *interConn) Write(b []byte) (int, error) {
 | 
			
		||||
	return c.stream.Write(b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *interConn) Close() error {
 | 
			
		||||
	return c.stream.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *interConn) LocalAddr() net.Addr {
 | 
			
		||||
	return c.local
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *interConn) RemoteAddr() net.Addr {
 | 
			
		||||
	return c.remote
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *interConn) SetDeadline(t time.Time) error {
 | 
			
		||||
	return c.stream.SetDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *interConn) SetReadDeadline(t time.Time) error {
 | 
			
		||||
	return c.stream.SetReadDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *interConn) SetWriteDeadline(t time.Time) error {
 | 
			
		||||
	return c.stream.SetWriteDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,236 +0,0 @@
 | 
			
		|||
package quic
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/quic-go/quic-go"
 | 
			
		||||
	"github.com/quic-go/quic-go/logging"
 | 
			
		||||
	"github.com/quic-go/quic-go/qlog"
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	"github.com/xtls/xray-core/common/errors"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net"
 | 
			
		||||
	"github.com/xtls/xray-core/common/task"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/stat"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/tls"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type connectionContext struct {
 | 
			
		||||
	rawConn *sysConn
 | 
			
		||||
	conn    quic.Connection
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var errConnectionClosed = errors.New("connection closed")
 | 
			
		||||
 | 
			
		||||
func (c *connectionContext) openStream(destAddr net.Addr) (*interConn, error) {
 | 
			
		||||
	if !isActive(c.conn) {
 | 
			
		||||
		return nil, errConnectionClosed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stream, err := c.conn.OpenStream()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn := &interConn{
 | 
			
		||||
		stream: stream,
 | 
			
		||||
		local:  c.conn.LocalAddr(),
 | 
			
		||||
		remote: destAddr,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return conn, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type clientConnections struct {
 | 
			
		||||
	access  sync.Mutex
 | 
			
		||||
	conns   map[net.Destination][]*connectionContext
 | 
			
		||||
	cleanup *task.Periodic
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isActive(s quic.Connection) bool {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-s.Context().Done():
 | 
			
		||||
		return false
 | 
			
		||||
	default:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeInactiveConnections(conns []*connectionContext) []*connectionContext {
 | 
			
		||||
	activeConnections := make([]*connectionContext, 0, len(conns))
 | 
			
		||||
	for i, s := range conns {
 | 
			
		||||
		if isActive(s.conn) {
 | 
			
		||||
			activeConnections = append(activeConnections, s)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		errors.LogInfo(context.Background(), "closing quic connection at index: ", i)
 | 
			
		||||
		if err := s.conn.CloseWithError(0, ""); err != nil {
 | 
			
		||||
			errors.LogInfoInner(context.Background(), err, "failed to close connection")
 | 
			
		||||
		}
 | 
			
		||||
		if err := s.rawConn.Close(); err != nil {
 | 
			
		||||
			errors.LogInfoInner(context.Background(), err, "failed to close raw connection")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(activeConnections) < len(conns) {
 | 
			
		||||
		errors.LogInfo(context.Background(), "active quic connection reduced from ", len(conns), " to ", len(activeConnections))
 | 
			
		||||
		return activeConnections
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return conns
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *clientConnections) cleanConnections() error {
 | 
			
		||||
	s.access.Lock()
 | 
			
		||||
	defer s.access.Unlock()
 | 
			
		||||
 | 
			
		||||
	if len(s.conns) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newConnMap := make(map[net.Destination][]*connectionContext)
 | 
			
		||||
 | 
			
		||||
	for dest, conns := range s.conns {
 | 
			
		||||
		conns = removeInactiveConnections(conns)
 | 
			
		||||
		if len(conns) > 0 {
 | 
			
		||||
			newConnMap[dest] = conns
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	s.conns = newConnMap
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *clientConnections) openConnection(ctx context.Context, destAddr net.Addr, config *Config, tlsConfig *tls.Config, sockopt *internet.SocketConfig) (stat.Connection, error) {
 | 
			
		||||
	s.access.Lock()
 | 
			
		||||
	defer s.access.Unlock()
 | 
			
		||||
 | 
			
		||||
	if s.conns == nil {
 | 
			
		||||
		s.conns = make(map[net.Destination][]*connectionContext)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	dest := net.DestinationFromAddr(destAddr)
 | 
			
		||||
 | 
			
		||||
	var conns []*connectionContext
 | 
			
		||||
	if s, found := s.conns[dest]; found {
 | 
			
		||||
		conns = s
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(conns) > 0 {
 | 
			
		||||
		s := conns[len(conns)-1]
 | 
			
		||||
		if isActive(s.conn) {
 | 
			
		||||
			conn, err := s.openStream(destAddr)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				return conn, nil
 | 
			
		||||
			}
 | 
			
		||||
			errors.LogInfoInner(ctx, err, "failed to openStream: ")
 | 
			
		||||
		} else {
 | 
			
		||||
			errors.LogInfo(ctx, "current quic connection is not active!")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conns = removeInactiveConnections(conns)
 | 
			
		||||
	errors.LogInfo(ctx, "dialing quic to ", dest)
 | 
			
		||||
	rawConn, err := internet.DialSystem(ctx, dest, sockopt)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errors.New("failed to dial to dest: ", err).AtWarning().Base(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quicConfig := &quic.Config{
 | 
			
		||||
		KeepAlivePeriod:      0,
 | 
			
		||||
		HandshakeIdleTimeout: time.Second * 8,
 | 
			
		||||
		MaxIdleTimeout:       time.Second * 300,
 | 
			
		||||
		Tracer: func(ctx context.Context, p logging.Perspective, ci quic.ConnectionID) *logging.ConnectionTracer {
 | 
			
		||||
			return qlog.NewConnectionTracer(&QlogWriter{connID: ci}, p, ci)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var udpConn *net.UDPConn
 | 
			
		||||
	switch conn := rawConn.(type) {
 | 
			
		||||
	case *net.UDPConn:
 | 
			
		||||
		udpConn = conn
 | 
			
		||||
	case *internet.PacketConnWrapper:
 | 
			
		||||
		udpConn = conn.Conn.(*net.UDPConn)
 | 
			
		||||
	default:
 | 
			
		||||
		// TODO: Support sockopt for QUIC
 | 
			
		||||
		rawConn.Close()
 | 
			
		||||
		return nil, errors.New("QUIC with sockopt is unsupported").AtWarning()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sysConn, err := wrapSysConn(udpConn, config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		rawConn.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	tr := quic.Transport{
 | 
			
		||||
		ConnectionIDLength: 12,
 | 
			
		||||
		Conn:               sysConn,
 | 
			
		||||
	}
 | 
			
		||||
	conn, err := tr.Dial(context.Background(), destAddr, tlsConfig.GetTLSConfig(tls.WithDestination(dest)), quicConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		sysConn.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	context := &connectionContext{
 | 
			
		||||
		conn:    conn,
 | 
			
		||||
		rawConn: sysConn,
 | 
			
		||||
	}
 | 
			
		||||
	s.conns[dest] = append(conns, context)
 | 
			
		||||
	return context.openStream(destAddr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var client clientConnections
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	client.conns = make(map[net.Destination][]*connectionContext)
 | 
			
		||||
	client.cleanup = &task.Periodic{
 | 
			
		||||
		Interval: time.Minute,
 | 
			
		||||
		Execute:  client.cleanConnections,
 | 
			
		||||
	}
 | 
			
		||||
	common.Must(client.cleanup.Start())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {
 | 
			
		||||
	tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
 | 
			
		||||
	if tlsConfig == nil {
 | 
			
		||||
		tlsConfig = &tls.Config{
 | 
			
		||||
			ServerName:    internalDomain,
 | 
			
		||||
			AllowInsecure: true,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var destAddr *net.UDPAddr
 | 
			
		||||
	if dest.Address.Family().IsIP() {
 | 
			
		||||
		destAddr = &net.UDPAddr{
 | 
			
		||||
			IP:   dest.Address.IP(),
 | 
			
		||||
			Port: int(dest.Port),
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		dialerIp := internet.DestIpAddress()
 | 
			
		||||
		if dialerIp != nil {
 | 
			
		||||
			destAddr = &net.UDPAddr{
 | 
			
		||||
				IP:   dialerIp,
 | 
			
		||||
				Port: int(dest.Port),
 | 
			
		||||
			}
 | 
			
		||||
			errors.LogInfo(ctx, "quic Dial use dialer dest addr: ", destAddr)
 | 
			
		||||
		} else {
 | 
			
		||||
			addr, err := net.ResolveUDPAddr("udp", dest.NetAddr())
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			destAddr = addr
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config := streamSettings.ProtocolSettings.(*Config)
 | 
			
		||||
 | 
			
		||||
	return client.openConnection(ctx, destAddr, config, tlsConfig, streamSettings.SocketSettings)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	common.Must(internet.RegisterTransportDialer(protocolName, Dial))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,146 +0,0 @@
 | 
			
		|||
package quic
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/quic-go/quic-go"
 | 
			
		||||
	"github.com/quic-go/quic-go/logging"
 | 
			
		||||
	"github.com/quic-go/quic-go/qlog"
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	"github.com/xtls/xray-core/common/errors"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net"
 | 
			
		||||
	"github.com/xtls/xray-core/common/protocol/tls/cert"
 | 
			
		||||
	"github.com/xtls/xray-core/common/signal/done"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/tls"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Listener is an internet.Listener that listens for TCP connections.
 | 
			
		||||
type Listener struct {
 | 
			
		||||
	rawConn  *sysConn
 | 
			
		||||
	listener *quic.Listener
 | 
			
		||||
	done     *done.Instance
 | 
			
		||||
	addConn  internet.ConnHandler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *Listener) acceptStreams(conn quic.Connection) {
 | 
			
		||||
	for {
 | 
			
		||||
		stream, err := conn.AcceptStream(context.Background())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			errors.LogInfoInner(context.Background(), err, "failed to accept stream")
 | 
			
		||||
			select {
 | 
			
		||||
			case <-conn.Context().Done():
 | 
			
		||||
				return
 | 
			
		||||
			case <-l.done.Wait():
 | 
			
		||||
				if err := conn.CloseWithError(0, ""); err != nil {
 | 
			
		||||
					errors.LogInfoInner(context.Background(), err, "failed to close connection")
 | 
			
		||||
				}
 | 
			
		||||
				return
 | 
			
		||||
			default:
 | 
			
		||||
				time.Sleep(time.Second)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		conn := &interConn{
 | 
			
		||||
			stream: stream,
 | 
			
		||||
			local:  conn.LocalAddr(),
 | 
			
		||||
			remote: conn.RemoteAddr(),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		l.addConn(conn)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *Listener) keepAccepting() {
 | 
			
		||||
	for {
 | 
			
		||||
		conn, err := l.listener.Accept(context.Background())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			errors.LogInfoInner(context.Background(), err, "failed to accept QUIC connection")
 | 
			
		||||
			if l.done.Done() {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			time.Sleep(time.Second)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		go l.acceptStreams(conn)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Addr implements internet.Listener.Addr.
 | 
			
		||||
func (l *Listener) Addr() net.Addr {
 | 
			
		||||
	return l.listener.Addr()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close implements internet.Listener.Close.
 | 
			
		||||
func (l *Listener) Close() error {
 | 
			
		||||
	l.done.Close()
 | 
			
		||||
	l.listener.Close()
 | 
			
		||||
	l.rawConn.Close()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Listen creates a new Listener based on configurations.
 | 
			
		||||
func Listen(ctx context.Context, address net.Address, port net.Port, streamSettings *internet.MemoryStreamConfig, handler internet.ConnHandler) (internet.Listener, error) {
 | 
			
		||||
	if address.Family().IsDomain() {
 | 
			
		||||
		return nil, errors.New("domain address is not allows for listening quic")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
 | 
			
		||||
	if tlsConfig == nil {
 | 
			
		||||
		tlsConfig = &tls.Config{
 | 
			
		||||
			Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil, cert.DNSNames(internalDomain), cert.CommonName(internalDomain)))},
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config := streamSettings.ProtocolSettings.(*Config)
 | 
			
		||||
	rawConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{
 | 
			
		||||
		IP:   address.IP(),
 | 
			
		||||
		Port: int(port),
 | 
			
		||||
	}, streamSettings.SocketSettings)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quicConfig := &quic.Config{
 | 
			
		||||
		KeepAlivePeriod:       0,
 | 
			
		||||
		HandshakeIdleTimeout:  time.Second * 8,
 | 
			
		||||
		MaxIdleTimeout:        time.Second * 300,
 | 
			
		||||
		MaxIncomingStreams:    32,
 | 
			
		||||
		MaxIncomingUniStreams: -1,
 | 
			
		||||
		Tracer: func(ctx context.Context, p logging.Perspective, ci quic.ConnectionID) *logging.ConnectionTracer {
 | 
			
		||||
			return qlog.NewConnectionTracer(&QlogWriter{connID: ci}, p, ci)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn, err := wrapSysConn(rawConn.(*net.UDPConn), config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		conn.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	tr := quic.Transport{
 | 
			
		||||
		ConnectionIDLength: 12,
 | 
			
		||||
		Conn:               conn,
 | 
			
		||||
	}
 | 
			
		||||
	qListener, err := tr.Listen(tlsConfig.GetTLSConfig(), quicConfig)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		conn.Close()
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	listener := &Listener{
 | 
			
		||||
		done:     done.New(),
 | 
			
		||||
		rawConn:  conn,
 | 
			
		||||
		listener: qListener,
 | 
			
		||||
		addConn:  handler,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go listener.keepAccepting()
 | 
			
		||||
 | 
			
		||||
	return listener, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	common.Must(internet.RegisterTransportListener(protocolName, Listen))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,21 +0,0 @@
 | 
			
		|||
package quic
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/xtls/xray-core/common/bytespool"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var pool *sync.Pool
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	pool = bytespool.GetPool(2048)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getBuffer() []byte {
 | 
			
		||||
	return pool.Get().([]byte)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func putBuffer(p []byte) {
 | 
			
		||||
	pool.Put(p)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,24 +0,0 @@
 | 
			
		|||
package quic
 | 
			
		||||
 | 
			
		||||
import "github.com/quic-go/quic-go"
 | 
			
		||||
 | 
			
		||||
type QlogWriter struct {
 | 
			
		||||
	connID quic.ConnectionID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *QlogWriter) Write(b []byte) (int, error) {
 | 
			
		||||
	// to much log, only turn on when debug Quic
 | 
			
		||||
 | 
			
		||||
	// if len(b) > 1 { // skip line separator "0a" in qlog
 | 
			
		||||
	// 	log.Record(&log.GeneralMessage{
 | 
			
		||||
	// 		Severity: log.Severity_Debug,
 | 
			
		||||
	// 		Content:  fmt.Sprintf("[%x] %s", w.connID, b),
 | 
			
		||||
	// 	})
 | 
			
		||||
	// }
 | 
			
		||||
	return len(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *QlogWriter) Close() error {
 | 
			
		||||
	// Noop
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,25 +0,0 @@
 | 
			
		|||
package quic
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//go:generate go run github.com/xtls/xray-core/common/errors/errorgen
 | 
			
		||||
 | 
			
		||||
// Here is some modification needs to be done before update quic vendor.
 | 
			
		||||
// * use bytespool in buffer_pool.go
 | 
			
		||||
// * set MaxReceivePacketSize to 1452 - 32 (16 bytes auth, 16 bytes head)
 | 
			
		||||
//
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	protocolName   = "quic"
 | 
			
		||||
	internalDomain = "quic.internal.example.com"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	common.Must(internet.RegisterProtocolConfigCreator(protocolName, func() interface{} {
 | 
			
		||||
		return new(Config)
 | 
			
		||||
	}))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,223 +0,0 @@
 | 
			
		|||
package quic_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/google/go-cmp/cmp"
 | 
			
		||||
	"github.com/xtls/xray-core/common"
 | 
			
		||||
	"github.com/xtls/xray-core/common/buf"
 | 
			
		||||
	"github.com/xtls/xray-core/common/net"
 | 
			
		||||
	"github.com/xtls/xray-core/common/protocol"
 | 
			
		||||
	"github.com/xtls/xray-core/common/protocol/tls/cert"
 | 
			
		||||
	"github.com/xtls/xray-core/common/serial"
 | 
			
		||||
	"github.com/xtls/xray-core/testing/servers/udp"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/headers/wireguard"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/quic"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/stat"
 | 
			
		||||
	"github.com/xtls/xray-core/transport/internet/tls"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestQuicConnection(t *testing.T) {
 | 
			
		||||
	port := udp.PickPort()
 | 
			
		||||
 | 
			
		||||
	listener, err := quic.Listen(context.Background(), net.LocalHostIP, port, &internet.MemoryStreamConfig{
 | 
			
		||||
		ProtocolName:     "quic",
 | 
			
		||||
		ProtocolSettings: &quic.Config{},
 | 
			
		||||
		SecurityType:     "tls",
 | 
			
		||||
		SecuritySettings: &tls.Config{
 | 
			
		||||
			Certificate: []*tls.Certificate{
 | 
			
		||||
				tls.ParseCertificate(
 | 
			
		||||
					cert.MustGenerate(nil,
 | 
			
		||||
						cert.DNSNames("www.example.com"),
 | 
			
		||||
					),
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}, func(conn stat.Connection) {
 | 
			
		||||
		go func() {
 | 
			
		||||
			defer conn.Close()
 | 
			
		||||
 | 
			
		||||
			b := buf.New()
 | 
			
		||||
			defer b.Release()
 | 
			
		||||
 | 
			
		||||
			for {
 | 
			
		||||
				b.Clear()
 | 
			
		||||
				if _, err := b.ReadFrom(conn); err != nil {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				common.Must2(conn.Write(b.Bytes()))
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	})
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
 | 
			
		||||
	defer listener.Close()
 | 
			
		||||
 | 
			
		||||
	time.Sleep(time.Second)
 | 
			
		||||
 | 
			
		||||
	dctx := context.Background()
 | 
			
		||||
	conn, err := quic.Dial(dctx, net.TCPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{
 | 
			
		||||
		ProtocolName:     "quic",
 | 
			
		||||
		ProtocolSettings: &quic.Config{},
 | 
			
		||||
		SecurityType:     "tls",
 | 
			
		||||
		SecuritySettings: &tls.Config{
 | 
			
		||||
			ServerName:    "www.example.com",
 | 
			
		||||
			AllowInsecure: true,
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
	defer conn.Close()
 | 
			
		||||
 | 
			
		||||
	const N = 1024
 | 
			
		||||
	b1 := make([]byte, N)
 | 
			
		||||
	common.Must2(rand.Read(b1))
 | 
			
		||||
	b2 := buf.New()
 | 
			
		||||
 | 
			
		||||
	common.Must2(conn.Write(b1))
 | 
			
		||||
 | 
			
		||||
	b2.Clear()
 | 
			
		||||
	common.Must2(b2.ReadFullFrom(conn, N))
 | 
			
		||||
	if r := cmp.Diff(b2.Bytes(), b1); r != "" {
 | 
			
		||||
		t.Error(r)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	common.Must2(conn.Write(b1))
 | 
			
		||||
 | 
			
		||||
	b2.Clear()
 | 
			
		||||
	common.Must2(b2.ReadFullFrom(conn, N))
 | 
			
		||||
	if r := cmp.Diff(b2.Bytes(), b1); r != "" {
 | 
			
		||||
		t.Error(r)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestQuicConnectionWithoutTLS(t *testing.T) {
 | 
			
		||||
	port := udp.PickPort()
 | 
			
		||||
 | 
			
		||||
	listener, err := quic.Listen(context.Background(), net.LocalHostIP, port, &internet.MemoryStreamConfig{
 | 
			
		||||
		ProtocolName:     "quic",
 | 
			
		||||
		ProtocolSettings: &quic.Config{},
 | 
			
		||||
	}, func(conn stat.Connection) {
 | 
			
		||||
		go func() {
 | 
			
		||||
			defer conn.Close()
 | 
			
		||||
 | 
			
		||||
			b := buf.New()
 | 
			
		||||
			defer b.Release()
 | 
			
		||||
 | 
			
		||||
			for {
 | 
			
		||||
				b.Clear()
 | 
			
		||||
				if _, err := b.ReadFrom(conn); err != nil {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				common.Must2(conn.Write(b.Bytes()))
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	})
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
 | 
			
		||||
	defer listener.Close()
 | 
			
		||||
 | 
			
		||||
	time.Sleep(time.Second)
 | 
			
		||||
 | 
			
		||||
	dctx := context.Background()
 | 
			
		||||
	conn, err := quic.Dial(dctx, net.TCPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{
 | 
			
		||||
		ProtocolName:     "quic",
 | 
			
		||||
		ProtocolSettings: &quic.Config{},
 | 
			
		||||
	})
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
	defer conn.Close()
 | 
			
		||||
 | 
			
		||||
	const N = 1024
 | 
			
		||||
	b1 := make([]byte, N)
 | 
			
		||||
	common.Must2(rand.Read(b1))
 | 
			
		||||
	b2 := buf.New()
 | 
			
		||||
 | 
			
		||||
	common.Must2(conn.Write(b1))
 | 
			
		||||
 | 
			
		||||
	b2.Clear()
 | 
			
		||||
	common.Must2(b2.ReadFullFrom(conn, N))
 | 
			
		||||
	if r := cmp.Diff(b2.Bytes(), b1); r != "" {
 | 
			
		||||
		t.Error(r)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	common.Must2(conn.Write(b1))
 | 
			
		||||
 | 
			
		||||
	b2.Clear()
 | 
			
		||||
	common.Must2(b2.ReadFullFrom(conn, N))
 | 
			
		||||
	if r := cmp.Diff(b2.Bytes(), b1); r != "" {
 | 
			
		||||
		t.Error(r)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestQuicConnectionAuthHeader(t *testing.T) {
 | 
			
		||||
	port := udp.PickPort()
 | 
			
		||||
 | 
			
		||||
	listener, err := quic.Listen(context.Background(), net.LocalHostIP, port, &internet.MemoryStreamConfig{
 | 
			
		||||
		ProtocolName: "quic",
 | 
			
		||||
		ProtocolSettings: &quic.Config{
 | 
			
		||||
			Header: serial.ToTypedMessage(&wireguard.WireguardConfig{}),
 | 
			
		||||
			Key:    "abcd",
 | 
			
		||||
			Security: &protocol.SecurityConfig{
 | 
			
		||||
				Type: protocol.SecurityType_AES128_GCM,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}, func(conn stat.Connection) {
 | 
			
		||||
		go func() {
 | 
			
		||||
			defer conn.Close()
 | 
			
		||||
 | 
			
		||||
			b := buf.New()
 | 
			
		||||
			defer b.Release()
 | 
			
		||||
 | 
			
		||||
			for {
 | 
			
		||||
				b.Clear()
 | 
			
		||||
				if _, err := b.ReadFrom(conn); err != nil {
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				common.Must2(conn.Write(b.Bytes()))
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	})
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
 | 
			
		||||
	defer listener.Close()
 | 
			
		||||
 | 
			
		||||
	time.Sleep(time.Second)
 | 
			
		||||
 | 
			
		||||
	dctx := context.Background()
 | 
			
		||||
	conn, err := quic.Dial(dctx, net.TCPDestination(net.LocalHostIP, port), &internet.MemoryStreamConfig{
 | 
			
		||||
		ProtocolName: "quic",
 | 
			
		||||
		ProtocolSettings: &quic.Config{
 | 
			
		||||
			Header: serial.ToTypedMessage(&wireguard.WireguardConfig{}),
 | 
			
		||||
			Key:    "abcd",
 | 
			
		||||
			Security: &protocol.SecurityConfig{
 | 
			
		||||
				Type: protocol.SecurityType_AES128_GCM,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	common.Must(err)
 | 
			
		||||
	defer conn.Close()
 | 
			
		||||
 | 
			
		||||
	const N = 1024
 | 
			
		||||
	b1 := make([]byte, N)
 | 
			
		||||
	common.Must2(rand.Read(b1))
 | 
			
		||||
	b2 := buf.New()
 | 
			
		||||
 | 
			
		||||
	common.Must2(conn.Write(b1))
 | 
			
		||||
 | 
			
		||||
	b2.Clear()
 | 
			
		||||
	common.Must2(b2.ReadFullFrom(conn, N))
 | 
			
		||||
	if r := cmp.Diff(b2.Bytes(), b1); r != "" {
 | 
			
		||||
		t.Error(r)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	common.Must2(conn.Write(b1))
 | 
			
		||||
 | 
			
		||||
	b2.Clear()
 | 
			
		||||
	common.Must2(b2.ReadFullFrom(conn, N))
 | 
			
		||||
	if r := cmp.Diff(b2.Bytes(), b1); r != "" {
 | 
			
		||||
		t.Error(r)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue