mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-15 01:09:20 +02:00
Transport: Remove QUIC (#3754)
https://github.com/XTLS/Xray-core/pull/3554#issuecomment-2236171077
This commit is contained in:
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