Skip to content

Commit

Permalink
Merge pull request #25 from GFW-knocker/bring-quic-back
Browse files Browse the repository at this point in the history
Bring quic back
  • Loading branch information
GFW-knocker authored Dec 27, 2024
2 parents 7d0de3e + 3c1623d commit 88de780
Show file tree
Hide file tree
Showing 15 changed files with 1,460 additions and 1 deletion.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/miekg/dns v1.1.62
github.com/pelletier/go-toml v1.9.5
github.com/pires/go-proxyproto v0.8.0
github.com/quic-go/quic-go v0.46.0
github.com/refraction-networking/utls v1.6.7
github.com/sagernet/sing v0.5.1
github.com/sagernet/sing-shadowsocks v0.2.7
Expand All @@ -38,6 +39,7 @@ require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
Expand Down
157 changes: 157 additions & 0 deletions go.sum

Large diffs are not rendered by default.

57 changes: 56 additions & 1 deletion infra/conf/transport_internet.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import (
"github.com/GFW-knocker/Xray-core/common/errors"
"github.com/GFW-knocker/Xray-core/common/net"
"github.com/GFW-knocker/Xray-core/common/platform/filesystem"
"github.com/GFW-knocker/Xray-core/common/protocol"
"github.com/GFW-knocker/Xray-core/common/serial"
"github.com/GFW-knocker/Xray-core/transport/internet"
"github.com/GFW-knocker/Xray-core/transport/internet/httpupgrade"
"github.com/GFW-knocker/Xray-core/transport/internet/kcp"
"github.com/GFW-knocker/Xray-core/transport/internet/quic"
"github.com/GFW-knocker/Xray-core/transport/internet/reality"
"github.com/GFW-knocker/Xray-core/transport/internet/splithttp"
"github.com/GFW-knocker/Xray-core/transport/internet/tcp"
Expand Down Expand Up @@ -330,6 +332,47 @@ func (c *SplitHTTPConfig) 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
}

func readFileOrString(f string, s []string) ([]byte, error) {
if len(f) > 0 {
return filesystem.ReadFile(f)
Expand Down Expand Up @@ -664,7 +707,8 @@ func (p TransportProtocol) Build() (string, error) {
case "h2", "h3", "http":
return "", errors.PrintRemovedFeatureError("HTTP transport (without header padding, etc.)", "XHTTP stream-one H2 & H3")
case "quic":
return "", errors.PrintRemovedFeatureError("QUIC transport (without web service, etc.)", "XHTTP stream-one H3")
errors.PrintRemovedFeatureError("QUIC transport (without web service, etc.)", "XHTTP stream-one H3")
return "quic", nil
default:
return "", errors.New("Config: unknown transport protocol: ", p)
}
Expand Down Expand Up @@ -797,6 +841,7 @@ type StreamConfig struct {
XHTTPSettings *SplitHTTPConfig `json:"xhttpSettings"`
SplitHTTPSettings *SplitHTTPConfig `json:"splithttpSettings"`
KCPSettings *KCPConfig `json:"kcpSettings"`
QUICSettings *QUICConfig `json:"quicSettings"`
GRPCSettings *GRPCConfig `json:"grpcSettings"`
WSSettings *WebSocketConfig `json:"wsSettings"`
HTTPUPGRADESettings *HttpUpgradeConfig `json:"httpupgradeSettings"`
Expand Down Expand Up @@ -908,6 +953,16 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
Settings: serial.ToTypedMessage(ts),
})
}
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.HTTPUPGRADESettings != nil {
hs, err := c.HTTPUPGRADESettings.Build()
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions main/distro/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import (
_ "github.com/GFW-knocker/Xray-core/transport/internet/grpc"
_ "github.com/GFW-knocker/Xray-core/transport/internet/httpupgrade"
_ "github.com/GFW-knocker/Xray-core/transport/internet/kcp"
_ "github.com/GFW-knocker/Xray-core/transport/internet/quic"
_ "github.com/GFW-knocker/Xray-core/transport/internet/reality"
_ "github.com/GFW-knocker/Xray-core/transport/internet/splithttp"
_ "github.com/GFW-knocker/Xray-core/transport/internet/tcp"
Expand Down
138 changes: 138 additions & 0 deletions testing/scenarios/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"testing"
"time"

"github.com/GFW-knocker/Xray-core/app/log"
"github.com/GFW-knocker/Xray-core/app/proxyman"
"github.com/GFW-knocker/Xray-core/common"
clog "github.com/GFW-knocker/Xray-core/common/log"
"github.com/GFW-knocker/Xray-core/common/net"
"github.com/GFW-knocker/Xray-core/common/protocol"
"github.com/GFW-knocker/Xray-core/common/serial"
Expand All @@ -17,9 +19,13 @@ import (
"github.com/GFW-knocker/Xray-core/proxy/vmess/inbound"
"github.com/GFW-knocker/Xray-core/proxy/vmess/outbound"
"github.com/GFW-knocker/Xray-core/testing/servers/tcp"
"github.com/GFW-knocker/Xray-core/testing/servers/udp"
"github.com/GFW-knocker/Xray-core/transport/internet"
"github.com/GFW-knocker/Xray-core/transport/internet/headers/http"
"github.com/GFW-knocker/Xray-core/transport/internet/headers/wechat"
"github.com/GFW-knocker/Xray-core/transport/internet/quic"
tcptransport "github.com/GFW-knocker/Xray-core/transport/internet/tcp"
"golang.org/x/sync/errgroup"
)

func TestHTTPConnectionHeader(t *testing.T) {
Expand Down Expand Up @@ -123,3 +129,135 @@ func TestHTTPConnectionHeader(t *testing.T) {
t.Error(err)
}
}

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),
Networks: []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)
}
}
48 changes: 48 additions & 0 deletions transport/internet/quic/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package quic

import (
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"errors"

"github.com/GFW-knocker/Xray-core/common"
"github.com/GFW-knocker/Xray-core/common/protocol"
"github.com/GFW-knocker/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)
}
Loading

0 comments on commit 88de780

Please sign in to comment.