Add shadowsocks uot and test
This commit is contained in:
parent
5af17f70b4
commit
a562b249a2
3 changed files with 76 additions and 0 deletions
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/sagernet/sing/common/buf"
|
"github.com/sagernet/sing/common/buf"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
"github.com/sagernet/sing/common/uot"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -29,6 +30,7 @@ type ShadowSocks struct {
|
||||||
*Base
|
*Base
|
||||||
method shadowsocks.Method
|
method shadowsocks.Method
|
||||||
|
|
||||||
|
option *ShadowSocksOption
|
||||||
// obfs
|
// obfs
|
||||||
obfsMode string
|
obfsMode string
|
||||||
obfsOption *simpleObfsOption
|
obfsOption *simpleObfsOption
|
||||||
|
@ -45,6 +47,7 @@ type ShadowSocksOption struct {
|
||||||
UDP bool `proxy:"udp,omitempty"`
|
UDP bool `proxy:"udp,omitempty"`
|
||||||
Plugin string `proxy:"plugin,omitempty"`
|
Plugin string `proxy:"plugin,omitempty"`
|
||||||
PluginOpts map[string]any `proxy:"plugin-opts,omitempty"`
|
PluginOpts map[string]any `proxy:"plugin-opts,omitempty"`
|
||||||
|
UDPOverTCP bool `proxy:"udp-over-tcp,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type simpleObfsOption struct {
|
type simpleObfsOption struct {
|
||||||
|
@ -96,6 +99,15 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata, op
|
||||||
|
|
||||||
// ListenPacketContext implements C.ProxyAdapter
|
// ListenPacketContext implements C.ProxyAdapter
|
||||||
func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
|
func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
|
||||||
|
if ss.option.UDPOverTCP {
|
||||||
|
metadata.Host = uot.UOTMagicAddress
|
||||||
|
metadata.DstPort = "443"
|
||||||
|
tcpConn, err := ss.DialContext(ctx, metadata, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newPacketConn(uot.NewClientConn(tcpConn), ss), nil
|
||||||
|
}
|
||||||
pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...)
|
pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -167,6 +179,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||||
},
|
},
|
||||||
method: method,
|
method: method,
|
||||||
|
|
||||||
|
option: &option,
|
||||||
obfsMode: obfsMode,
|
obfsMode: obfsMode,
|
||||||
v2rayOption: v2rayOption,
|
v2rayOption: v2rayOption,
|
||||||
obfsOption: obfsOption,
|
obfsOption: obfsOption,
|
||||||
|
|
27
test/config/xray-shadowsocks.json
Normal file
27
test/config/xray-shadowsocks.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"inbounds": [
|
||||||
|
{
|
||||||
|
"port": 10002,
|
||||||
|
"listen": "0.0.0.0",
|
||||||
|
"protocol": "shadowsocks",
|
||||||
|
"settings": {
|
||||||
|
"network": "tcp,udp",
|
||||||
|
"clients": [
|
||||||
|
{
|
||||||
|
"method": "aes-128-gcm",
|
||||||
|
"level": 0,
|
||||||
|
"password": "FzcLbKs2dY9mhL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outbounds": [
|
||||||
|
{
|
||||||
|
"protocol": "freedom"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"log": {
|
||||||
|
"loglevel": "debug"
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,11 +3,13 @@ package main
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/outbound"
|
"github.com/Dreamacro/clash/adapter/outbound"
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -277,3 +279,37 @@ func Benchmark_Shadowsocks(b *testing.B) {
|
||||||
require.True(b, TCPing(net.JoinHostPort(localIP.String(), "10002")))
|
require.True(b, TCPing(net.JoinHostPort(localIP.String(), "10002")))
|
||||||
benchmarkProxy(b, proxy)
|
benchmarkProxy(b, proxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClash_ShadowsocksUoT(t *testing.T) {
|
||||||
|
configPath := C.Path.Resolve("xray-shadowsocks.json")
|
||||||
|
|
||||||
|
cfg := &container.Config{
|
||||||
|
Image: ImageVless,
|
||||||
|
ExposedPorts: defaultExposedPorts,
|
||||||
|
}
|
||||||
|
hostCfg := &container.HostConfig{
|
||||||
|
PortBindings: defaultPortBindings,
|
||||||
|
Binds: []string{fmt.Sprintf("%s:/etc/xray/config.json", configPath)},
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := startContainer(cfg, hostCfg, "xray-ss")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
cleanContainer(id)
|
||||||
|
})
|
||||||
|
|
||||||
|
proxy, err := outbound.NewShadowSocks(outbound.ShadowSocksOption{
|
||||||
|
Name: "ss",
|
||||||
|
Server: localIP.String(),
|
||||||
|
Port: 10002,
|
||||||
|
Password: "FzcLbKs2dY9mhL",
|
||||||
|
Cipher: "aes-128-gcm",
|
||||||
|
UDP: true,
|
||||||
|
UDPOverTCP: true,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(waitTime)
|
||||||
|
testSuit(t, proxy)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue