diff --git a/Makefile b/Makefile index c0760e84..9bd74cba 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,7 @@ test: @go test -v . && \ pushd test && \ go mod tidy && \ - go test -v -tags with_quic,with_wireguard,with_grpc,with_ech,with_utls . && \ + go test -v -tags with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_shadowsocksr . && \ popd clean: diff --git a/constant/proxy.go b/constant/proxy.go index 8ea820e9..2b09d8f3 100644 --- a/constant/proxy.go +++ b/constant/proxy.go @@ -1,24 +1,25 @@ package constant const ( - TypeTun = "tun" - TypeRedirect = "redirect" - TypeTProxy = "tproxy" - TypeDirect = "direct" - TypeBlock = "block" - TypeDNS = "dns" - TypeSocks = "socks" - TypeHTTP = "http" - TypeMixed = "mixed" - TypeShadowsocks = "shadowsocks" - TypeVMess = "vmess" - TypeTrojan = "trojan" - TypeNaive = "naive" - TypeWireGuard = "wireguard" - TypeHysteria = "hysteria" - TypeTor = "tor" - TypeSSH = "ssh" - TypeShadowTLS = "shadowtls" + TypeTun = "tun" + TypeRedirect = "redirect" + TypeTProxy = "tproxy" + TypeDirect = "direct" + TypeBlock = "block" + TypeDNS = "dns" + TypeSocks = "socks" + TypeHTTP = "http" + TypeMixed = "mixed" + TypeShadowsocks = "shadowsocks" + TypeVMess = "vmess" + TypeTrojan = "trojan" + TypeNaive = "naive" + TypeWireGuard = "wireguard" + TypeHysteria = "hysteria" + TypeTor = "tor" + TypeSSH = "ssh" + TypeShadowTLS = "shadowtls" + TypeShadowsocksR = "shadowsocksr" ) const ( diff --git a/go.mod b/go.mod index 75a18e83..ef617196 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/refraction-networking/utls v1.1.2 github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb + github.com/sagernet/shadowsocksr v0.0.0-20220912092645-c9ab93f81bb0 github.com/sagernet/sing v0.0.0-20220910144724-62c4ebdbcb3f github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 diff --git a/go.sum b/go.sum index 89fecc37..2e0a7ec8 100644 --- a/go.sum +++ b/go.sum @@ -143,6 +143,8 @@ github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6E github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTYRwpwvEm3nc4eRdxk6vtRbouLVZAzk= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= +github.com/sagernet/shadowsocksr v0.0.0-20220912092645-c9ab93f81bb0 h1:lQ4RFWY/wBYmXl/zJJCwQbhiEIbgEqC7j+nhZYkgwmU= +github.com/sagernet/shadowsocksr v0.0.0-20220912092645-c9ab93f81bb0/go.mod h1:xSHLCsdgy5QIozXFEv6uDgMWzyrRdFFjr3TgL+juu6g= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220910144724-62c4ebdbcb3f h1:w1TJq7Lw3It35tDyMsZLtYz4T2msf1UK9JxC85L5+sk= @@ -192,6 +194,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= @@ -245,6 +248,7 @@ golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -264,6 +268,7 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 h1:wM1k/lXfpc5HdkJJyW9GELpd8ERGdnh8sMGL6Gzq3Ho= golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/option/outbound.go b/option/outbound.go index 0b00d44f..e7a4727d 100644 --- a/option/outbound.go +++ b/option/outbound.go @@ -8,20 +8,21 @@ import ( ) type _Outbound struct { - Type string `json:"type"` - Tag string `json:"tag,omitempty"` - DirectOptions DirectOutboundOptions `json:"-"` - SocksOptions SocksOutboundOptions `json:"-"` - HTTPOptions HTTPOutboundOptions `json:"-"` - ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"` - VMessOptions VMessOutboundOptions `json:"-"` - TrojanOptions TrojanOutboundOptions `json:"-"` - WireGuardOptions WireGuardOutboundOptions `json:"-"` - HysteriaOptions HysteriaOutboundOptions `json:"-"` - TorOptions TorOutboundOptions `json:"-"` - SSHOptions SSHOutboundOptions `json:"-"` - ShadowTLSOptions ShadowTLSOutboundOptions `json:"-"` - SelectorOptions SelectorOutboundOptions `json:"-"` + Type string `json:"type"` + Tag string `json:"tag,omitempty"` + DirectOptions DirectOutboundOptions `json:"-"` + SocksOptions SocksOutboundOptions `json:"-"` + HTTPOptions HTTPOutboundOptions `json:"-"` + ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"` + VMessOptions VMessOutboundOptions `json:"-"` + TrojanOptions TrojanOutboundOptions `json:"-"` + WireGuardOptions WireGuardOutboundOptions `json:"-"` + HysteriaOptions HysteriaOutboundOptions `json:"-"` + TorOptions TorOutboundOptions `json:"-"` + SSHOptions SSHOutboundOptions `json:"-"` + ShadowTLSOptions ShadowTLSOutboundOptions `json:"-"` + ShadowsocksROptions ShadowsocksROutboundOptions `json:"-"` + SelectorOptions SelectorOutboundOptions `json:"-"` } type Outbound _Outbound @@ -53,6 +54,8 @@ func (h Outbound) MarshalJSON() ([]byte, error) { v = h.SSHOptions case C.TypeShadowTLS: v = h.ShadowTLSOptions + case C.TypeShadowsocksR: + v = h.ShadowsocksROptions case C.TypeSelector: v = h.SelectorOptions default: @@ -92,6 +95,8 @@ func (h *Outbound) UnmarshalJSON(bytes []byte) error { v = &h.SSHOptions case C.TypeShadowTLS: v = &h.ShadowTLSOptions + case C.TypeShadowsocksR: + v = &h.ShadowsocksROptions case C.TypeSelector: v = &h.SelectorOptions default: diff --git a/option/shadowsocksr.go b/option/shadowsocksr.go new file mode 100644 index 00000000..b87255bb --- /dev/null +++ b/option/shadowsocksr.go @@ -0,0 +1,13 @@ +package option + +type ShadowsocksROutboundOptions struct { + DialerOptions + ServerOptions + Method string `json:"method"` + Password string `json:"password"` + Obfs string `json:"obfs,omitempty"` + ObfsParam string `json:"obfs_param,omitempty"` + Protocol string `json:"protocol,omitempty"` + ProtocolParam string `json:"protocol_param,omitempty"` + Network NetworkList `json:"network,omitempty"` +} diff --git a/outbound/builder.go b/outbound/builder.go index fc00044f..7206546a 100644 --- a/outbound/builder.go +++ b/outbound/builder.go @@ -41,6 +41,8 @@ func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, o return NewSSH(ctx, router, logger, options.Tag, options.SSHOptions) case C.TypeShadowTLS: return NewShadowTLS(ctx, router, logger, options.Tag, options.ShadowTLSOptions) + case C.TypeShadowsocksR: + return NewShadowsocksR(ctx, router, logger, options.Tag, options.ShadowsocksROptions) case C.TypeSelector: return NewSelector(router, logger, options.Tag, options.SelectorOptions) default: diff --git a/outbound/shadowsocksr.go b/outbound/shadowsocksr.go new file mode 100644 index 00000000..19ff67fe --- /dev/null +++ b/outbound/shadowsocksr.go @@ -0,0 +1,140 @@ +//go:build with_shadowsocksr + +package outbound + +import ( + "context" + "net" + "strings" + + "github.com/sagernet/shadowsocksr" + "github.com/sagernet/shadowsocksr/obfs" + "github.com/sagernet/shadowsocksr/protocol" + "github.com/sagernet/shadowsocksr/ssr" + "github.com/sagernet/shadowsocksr/streamCipher" + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/dialer" + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing-shadowsocks" + "github.com/sagernet/sing-shadowsocks/shadowimpl" + "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/bufio" + E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +var _ adapter.Outbound = (*ShadowsocksR)(nil) + +type ShadowsocksR struct { + myOutboundAdapter + dialer N.Dialer + serverAddr M.Socksaddr + method shadowsocks.Method + cipher string + password string + obfs string + obfsParams *ssr.ServerInfo + protocol string + protocolParams *ssr.ServerInfo +} + +func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (*ShadowsocksR, error) { + outbound := &ShadowsocksR{ + myOutboundAdapter: myOutboundAdapter{ + protocol: C.TypeShadowsocksR, + network: options.Network.Build(), + router: router, + logger: logger, + tag: tag, + }, + dialer: dialer.New(router, options.DialerOptions), + serverAddr: options.ServerOptions.Build(), + cipher: options.Method, + password: options.Password, + obfs: options.Obfs, + protocol: options.Protocol, + } + var err error + outbound.method, err = shadowimpl.FetchMethod(options.Method, options.Password) + if err != nil { + return nil, err + } + if _, err = streamCipher.NewStreamCipher(options.Method, options.Password); err != nil { + return nil, E.New(strings.ToLower(err.Error())) + } + if obfs.NewObfs(options.Obfs) == nil { + return nil, E.New("unknown obfs: " + options.Obfs) + } + outbound.obfsParams = &ssr.ServerInfo{ + Host: outbound.serverAddr.AddrString(), + Port: outbound.serverAddr.Port, + TcpMss: 1460, + Param: options.ObfsParam, + } + if protocol.NewProtocol(options.Protocol) == nil { + return nil, E.New("unknown protocol: " + options.Protocol) + } + outbound.protocolParams = &ssr.ServerInfo{ + Host: outbound.serverAddr.AddrString(), + Port: outbound.serverAddr.Port, + TcpMss: 1460, + Param: options.Protocol, + } + if outbound.method == nil { + outbound.network = common.Filter(outbound.network, func(it string) bool { return it == N.NetworkTCP }) + } + return outbound, nil +} + +func (h *ShadowsocksR) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + switch network { + case N.NetworkTCP: + h.logger.InfoContext(ctx, "outbound connection to ", destination) + conn, err := h.dialer.DialContext(ctx, network, h.serverAddr) + if err != nil { + return nil, err + } + cipher, err := streamCipher.NewStreamCipher(h.cipher, h.password) + if err != nil { + return nil, E.New(strings.ToLower(err.Error())) + } + ssConn := shadowsocksr.NewSSTCPConn(conn, cipher) + ssConn.IObfs = obfs.NewObfs(h.obfs) + ssConn.IObfs.SetServerInfo(h.obfsParams) + ssConn.IProtocol = protocol.NewProtocol(h.protocol) + ssConn.IProtocol.SetServerInfo(h.protocolParams) + err = M.SocksaddrSerializer.WriteAddrPort(ssConn, destination) + if err != nil { + return nil, E.Cause(err, "write request") + } + return ssConn, nil + case N.NetworkUDP: + conn, err := h.ListenPacket(ctx, destination) + if err != nil { + return nil, err + } + return &bufio.BindPacketConn{PacketConn: conn, Addr: destination}, nil + default: + return nil, E.Extend(N.ErrUnknownNetwork, network) + } +} + +func (h *ShadowsocksR) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + h.logger.InfoContext(ctx, "outbound packet connection to ", destination) + outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr) + if err != nil { + return nil, err + } + return h.method.DialPacketConn(outConn), nil +} + +func (h *ShadowsocksR) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { + return NewConnection(ctx, h, conn, metadata) +} + +func (h *ShadowsocksR) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { + return NewPacketConnection(ctx, h, conn, metadata) +} diff --git a/outbound/shadowsocksr_stub.go b/outbound/shadowsocksr_stub.go new file mode 100644 index 00000000..d3625876 --- /dev/null +++ b/outbound/shadowsocksr_stub.go @@ -0,0 +1,16 @@ +//go:build !with_shadowsocksr + +package outbound + +import ( + "context" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" +) + +func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (adapter.Outbound, error) { + return nil, E.New(`ShadowsocksR is not included in this build, rebuild with -tags with_shadowsocksr`) +} diff --git a/test/box_test.go b/test/box_test.go index ef2d8767..2d8205e2 100644 --- a/test/box_test.go +++ b/test/box_test.go @@ -53,8 +53,8 @@ func testSuit(t *testing.T, clientPort uint16, testPort uint16) { dialUDP := func() (net.PacketConn, error) { return dialer.ListenPacket(context.Background(), M.ParseSocksaddrHostPort("127.0.0.1", testPort)) } - // require.NoError(t, testPingPongWithConn(t, testPort, dialTCP)) - // require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP)) + require.NoError(t, testPingPongWithConn(t, testPort, dialTCP)) + require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP)) require.NoError(t, testLargeDataWithConn(t, testPort, dialTCP)) require.NoError(t, testLargeDataWithPacketConn(t, testPort, dialUDP)) @@ -80,6 +80,8 @@ func testSuitSimple(t *testing.T, clientPort uint16, testPort uint16) { } require.NoError(t, testPingPongWithConn(t, testPort, dialTCP)) require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP)) + require.NoError(t, testPingPongWithConn(t, testPort, dialTCP)) + require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP)) } func testSuitWg(t *testing.T, clientPort uint16, testPort uint16) { diff --git a/test/clash_test.go b/test/clash_test.go index c2495d09..fa258681 100644 --- a/test/clash_test.go +++ b/test/clash_test.go @@ -37,6 +37,7 @@ const ( ImageHysteria = "tobyxdd/hysteria:latest" ImageNginx = "nginx:stable" ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest" + ImageShadowsocksR = "teddysun/shadowsocks-r:latest" ) var allImages = []string{ @@ -49,6 +50,7 @@ var allImages = []string{ ImageHysteria, ImageNginx, ImageShadowTLS, + ImageShadowsocksR, } var localIP = netip.MustParseAddr("127.0.0.1") diff --git a/test/config/shadowsocksr.json b/test/config/shadowsocksr.json new file mode 100644 index 00000000..efae403c --- /dev/null +++ b/test/config/shadowsocksr.json @@ -0,0 +1,19 @@ +{ + "server": "0.0.0.0", + "server_ipv6": "::", + "server_port": 10000, + "local_address": "127.0.0.1", + "local_port": 1080, + "password": "password0", + "timeout": 120, + "method": "aes-256-cfb", + "protocol": "origin", + "protocol_param": "", + "obfs": "plain", + "obfs_param": "", + "redirect": "", + "dns_ipv6": false, + "fast_open": true, + "workers": 1, + "forbidden_ip": "" +} \ No newline at end of file diff --git a/test/go.mod b/test/go.mod index f77a2434..d9f7ca49 100644 --- a/test/go.mod +++ b/test/go.mod @@ -66,8 +66,9 @@ require ( github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect + github.com/sagernet/shadowsocksr v0.0.0-20220912092645-c9ab93f81bb0 // indirect github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 // indirect - github.com/sagernet/sing-tun v0.0.0-20220909114108-a6b5a9289ecb // indirect + github.com/sagernet/sing-tun v0.0.0-20220911034209-c7dd5d457e24 // indirect github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f // indirect github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect github.com/sirupsen/logrus v1.8.1 // indirect diff --git a/test/go.sum b/test/go.sum index 71369609..d6d3470a 100644 --- a/test/go.sum +++ b/test/go.sum @@ -163,6 +163,8 @@ github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6E github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTYRwpwvEm3nc4eRdxk6vtRbouLVZAzk= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= +github.com/sagernet/shadowsocksr v0.0.0-20220912092645-c9ab93f81bb0 h1:lQ4RFWY/wBYmXl/zJJCwQbhiEIbgEqC7j+nhZYkgwmU= +github.com/sagernet/shadowsocksr v0.0.0-20220912092645-c9ab93f81bb0/go.mod h1:xSHLCsdgy5QIozXFEv6uDgMWzyrRdFFjr3TgL+juu6g= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220910144724-62c4ebdbcb3f h1:w1TJq7Lw3It35tDyMsZLtYz4T2msf1UK9JxC85L5+sk= @@ -171,8 +173,8 @@ github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFx github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM= -github.com/sagernet/sing-tun v0.0.0-20220909114108-a6b5a9289ecb h1:/swVU2mgwDwZ9l67v1Sim1ias/ZmriGTxQLnMakPhtQ= -github.com/sagernet/sing-tun v0.0.0-20220909114108-a6b5a9289ecb/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM= +github.com/sagernet/sing-tun v0.0.0-20220911034209-c7dd5d457e24 h1:LsmPeFvj4GhiV5Y7Rm8I845XysdxVN4MQmfZ36P5bmw= +github.com/sagernet/sing-tun v0.0.0-20220911034209-c7dd5d457e24/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM= github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f h1:6l9aXZqAl1JqXJWi89KHpWnM/moQUPGG+XiwMc+yD0A= github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38= @@ -216,6 +218,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= @@ -295,6 +298,7 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 h1:wM1k/lXfpc5HdkJJyW9GELpd8ERGdnh8sMGL6Gzq3Ho= golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/test/hysteria_test.go b/test/hysteria_test.go index cb21bc3f..a283543b 100644 --- a/test/hysteria_test.go +++ b/test/hysteria_test.go @@ -9,9 +9,6 @@ import ( ) func TestHysteriaSelf(t *testing.T) { - if !C.QUIC_AVAILABLE { - t.Skip("QUIC not included") - } _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") startInstance(t, option.Options{ Inbounds: []option.Inbound{ @@ -84,9 +81,6 @@ func TestHysteriaSelf(t *testing.T) { } func TestHysteriaInbound(t *testing.T) { - if !C.QUIC_AVAILABLE { - t.Skip("QUIC not included") - } caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") startInstance(t, option.Options{ Inbounds: []option.Inbound{ @@ -120,13 +114,10 @@ func TestHysteriaInbound(t *testing.T) { caPem: "/etc/hysteria/ca.pem", }, }) - testSuit(t, clientPort, testPort) + testSuitSimple(t, clientPort, testPort) } func TestHysteriaOutbound(t *testing.T) { - if !C.QUIC_AVAILABLE { - t.Skip("QUIC not included") - } _, certPem, keyPem := createSelfSignedCertificate(t, "example.org") startDockerContainer(t, DockerOptions{ Image: ImageHysteria, diff --git a/test/naive_test.go b/test/naive_test.go index 25bb4c38..b6292b7d 100644 --- a/test/naive_test.go +++ b/test/naive_test.go @@ -99,9 +99,6 @@ func TestNaiveInbound(t *testing.T) { } func TestNaiveHTTP3Inbound(t *testing.T) { - if !C.QUIC_AVAILABLE { - t.Skip("QUIC not included") - } caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") startInstance(t, option.Options{ Inbounds: []option.Inbound{ diff --git a/test/shadowsocksr_test.go b/test/shadowsocksr_test.go new file mode 100644 index 00000000..a81c61b1 --- /dev/null +++ b/test/shadowsocksr_test.go @@ -0,0 +1,48 @@ +package main + +import ( + "net/netip" + "testing" + + C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/option" +) + +func TestShadowsocksR(t *testing.T) { + startDockerContainer(t, DockerOptions{ + Image: ImageShadowsocksR, + Ports: []uint16{serverPort, testPort}, + Bind: map[string]string{ + "shadowsocksr.json": "/etc/shadowsocks-r/config.json", + }, + }) + startInstance(t, option.Options{ + Inbounds: []option.Inbound{ + { + Type: C.TypeMixed, + MixedOptions: option.HTTPMixedInboundOptions{ + ListenOptions: option.ListenOptions{ + Listen: option.ListenAddress(netip.IPv4Unspecified()), + ListenPort: clientPort, + }, + }, + }, + }, + Outbounds: []option.Outbound{ + { + Type: C.TypeShadowsocksR, + ShadowsocksROptions: option.ShadowsocksROutboundOptions{ + ServerOptions: option.ServerOptions{ + Server: "127.0.0.1", + ServerPort: serverPort, + }, + Method: "aes-256-cfb", + Password: "password0", + Obfs: "plain", + Protocol: "origin", + }, + }, + }, + }) + testSuit(t, clientPort, testPort) +} diff --git a/transport/sip003/plugin.go b/transport/sip003/plugin.go index 53a63de1..e6a0ba77 100644 --- a/transport/sip003/plugin.go +++ b/transport/sip003/plugin.go @@ -19,6 +19,9 @@ type Plugin interface { var plugins map[string]PluginConstructor func RegisterPlugin(name string, constructor PluginConstructor) { + if plugins == nil { + plugins = make(map[string]PluginConstructor) + } plugins[name] = constructor }