Compare commits

...

26 Commits

Author SHA1 Message Date
世界
4d24cf5ec4 Update documentation 2022-09-15 13:25:51 +08:00
世界
668d354771 Make gVisor optional 2022-09-15 12:24:08 +08:00
世界
ad14719b14 Fix clash api proxy type 2022-09-14 23:02:11 +08:00
世界
d9aa0a67d6 Fix port rule match logic 2022-09-14 22:03:26 +08:00
世界
92bf784f4f Move shadowsocksr implementation to clash 2022-09-14 21:57:40 +08:00
世界
395b13103a Fix test 2022-09-14 18:02:51 +08:00
世界
628cf56d3c Fix close grpc conn 2022-09-14 18:02:37 +08:00
世界
ac5582537f Add back test workflow 2022-09-14 18:02:37 +08:00
世界
9aa7a20d96 Print tags in version command 2022-09-14 18:02:37 +08:00
世界
189f02c802 Refactor bind control 2022-09-14 18:02:37 +08:00
世界
2373281c41 Fix clash store-selected 2022-09-13 17:34:37 +08:00
世界
e8f4c2d36f Redirect clash hello to external ui 2022-09-13 17:29:57 +08:00
世界
07b6db23c1 Update install go script 2022-09-13 16:24:44 +08:00
世界
9a3360e5d0 Fix build on go1.18 2022-09-13 16:23:20 +08:00
世界
007a278ac8 Refactor to miekg/dns 2022-09-13 16:18:39 +08:00
世界
1db7f45370 Update documentation 2022-09-13 11:24:33 +08:00
世界
b271e19a23 Fix concurrent write 2022-09-13 10:41:10 +08:00
世界
79b6bdfda1 Skip wait for hysteria tcp handshake response
Co-authored-by: arm64v8a <48624112+arm64v8a@users.noreply.github.com>
2022-09-13 10:40:26 +08:00
世界
38088f28b0 Add vless outbound and xudp 2022-09-12 21:59:27 +08:00
世界
dfb8b5f2fa Fix hysteria inbound 2022-09-12 18:35:36 +08:00
世界
9913e0e025 Add shadowsocksr outbound 2022-09-12 18:35:36 +08:00
世界
ce567ffdde Add obfs-local and v2ray-plugin support for shadowsocks outbound 2022-09-12 14:55:00 +08:00
世界
5a9913eca5 Fix socks4 client 2022-09-12 11:33:38 +08:00
世界
eaf1ace681 Update documentation 2022-09-11 22:48:42 +08:00
世界
a2d1f89922 Add custom tls client support for v2ray h2/grpclite transports 2022-09-11 22:44:35 +08:00
世界
7e09beb0c3 Minor fixes 2022-09-11 22:44:35 +08:00
136 changed files with 5017 additions and 600 deletions

34
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: Test build
on:
pull_request:
branches:
- main
- dev
- dev-next
jobs:
build:
name: Debug build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Get latest go version
id: version
run: |
echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g')
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ steps.version.outputs.go_version }}
- name: Cache go module
uses: actions/cache@v2
with:
path: |
~/go/pkg/mod
key: go-${{ hashFiles('**/go.sum') }}
- name: Run Test
run: make test

View File

@@ -9,8 +9,9 @@ builds:
gcflags: gcflags:
- all=-trimpath={{.Env.GOPATH}} - all=-trimpath={{.Env.GOPATH}}
ldflags: ldflags:
- -X github.com/sagernet/sing-box/constant.Commit={{ .ShortCommit }} -s -w -buildid= - -s -w -buildid=
tags: tags:
- with_gvisor
- with_quic - with_quic
- with_wireguard - with_wireguard
- with_clash_api - with_clash_api

View File

@@ -8,9 +8,9 @@ ENV CGO_ENABLED=0
RUN set -ex \ RUN set -ex \
&& apk add git build-base \ && apk add git build-base \
&& export COMMIT=$(git rev-parse --short HEAD) \ && export COMMIT=$(git rev-parse --short HEAD) \
&& go build -v -trimpath -tags 'no_gvisor,with_quic,with_wireguard,with_acme' \ && go build -v -trimpath -tags with_quic,with_wireguard,with_acme \
-o /go/bin/sing-box \ -o /go/bin/sing-box \
-ldflags "-X github.com/sagernet/sing-box/constant.Commit=${COMMIT} -w -s -buildid=" \ -ldflags "-s -w -buildid=" \
./cmd/sing-box ./cmd/sing-box
FROM alpine AS dist FROM alpine AS dist
LABEL maintainer="nekohasekai <contact-git@sekai.icu>" LABEL maintainer="nekohasekai <contact-git@sekai.icu>"

View File

@@ -1,9 +1,7 @@
NAME = sing-box NAME = sing-box
COMMIT = $(shell git rev-parse --short HEAD) COMMIT = $(shell git rev-parse --short HEAD)
TAGS ?= with_quic,with_wireguard,with_clash_api TAGS ?= with_gvisor,with_quic,with_wireguard,with_clash_api
PARAMS = -v -trimpath -tags '$(TAGS)' -ldflags \ PARAMS = -v -trimpath -tags '$(TAGS)' -ldflags '-s -w -buildid='
'-X "github.com/sagernet/sing-box/constant.Commit=$(COMMIT)" \
-w -s -buildid='
MAIN = ./cmd/sing-box MAIN = ./cmd/sing-box
.PHONY: test release .PHONY: test release
@@ -62,10 +60,9 @@ release_install:
test: test:
@go test -v . && \ @go test -v . && \
pushd test && \ cd test && \
go mod tidy && \ go mod tidy && \
go test -v -tags with_quic,with_wireguard,with_grpc,with_ech,with_utls . && \ go test -v -tags with_gvisor,with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_shadowsocksr .
popd
clean: clean:
rm -rf bin dist rm -rf bin dist

View File

@@ -11,7 +11,7 @@ import (
"github.com/sagernet/sing/common/control" "github.com/sagernet/sing/common/control"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"golang.org/x/net/dns/dnsmessage" mdns "github.com/miekg/dns"
) )
type Router interface { type Router interface {
@@ -27,11 +27,11 @@ type Router interface {
GeoIPReader() *geoip.Reader GeoIPReader() *geoip.Reader
LoadGeosite(code string) (Rule, error) LoadGeosite(code string) (Rule, error)
Exchange(ctx context.Context, message *dnsmessage.Message) (*dnsmessage.Message, error) Exchange(ctx context.Context, message *mdns.Msg) (*mdns.Msg, error)
Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error) Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error)
LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error) LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
InterfaceBindManager() control.BindManager InterfaceFinder() control.InterfaceFinder
DefaultInterface() string DefaultInterface() string
AutoDetectInterface() bool AutoDetectInterface() bool
DefaultMark() int DefaultMark() int

View File

@@ -3,9 +3,9 @@ package main
import ( import (
"os" "os"
"runtime" "runtime"
"runtime/debug"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
F "github.com/sagernet/sing/common/format"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -25,30 +25,40 @@ func init() {
} }
func printVersion(cmd *cobra.Command, args []string) { func printVersion(cmd *cobra.Command, args []string) {
var version string if nameOnly {
if !nameOnly { os.Stdout.WriteString(C.Version + "\n")
version = "sing-box " return
} }
version += F.ToString(C.Version) version := "sing-box version " + C.Version + "\n\n"
if C.Commit != "" { version += "Environment: " + runtime.Version() + " " + runtime.GOOS + "/" + runtime.GOARCH + "\n"
version += "." + C.Commit
} var tags string
if !nameOnly { var revision string
version += " ("
version += runtime.Version() debugInfo, loaded := debug.ReadBuildInfo()
version += ", " if loaded {
version += runtime.GOOS for _, setting := range debugInfo.Settings {
version += "/" switch setting.Key {
version += runtime.GOARCH case "-tags":
version += ", " tags = setting.Value
version += "CGO " case "vcs.revision":
if C.CGO_ENABLED { revision = setting.Value
version += "enabled" }
} else {
version += "disabled"
} }
version += ")"
} }
version += "\n"
if tags != "" {
version += "Tags: " + tags + "\n"
}
if revision != "" {
version += "Revision: " + revision + "\n"
}
if C.CGO_ENABLED {
version += "CGO: enabled\n"
} else {
version += "CGO: disabled\n"
}
os.Stdout.WriteString(version) os.Stdout.WriteString(version)
} }

View File

@@ -3,6 +3,7 @@ package main
import ( import (
"os" "os"
_ "github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"

View File

@@ -65,25 +65,23 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
var listener net.ListenConfig var listener net.ListenConfig
if options.BindInterface != "" { if options.BindInterface != "" {
warnBindInterfaceOnUnsupportedPlatform.Check() warnBindInterfaceOnUnsupportedPlatform.Check()
bindFunc := control.BindToInterface(router.InterfaceBindManager(), options.BindInterface) bindFunc := control.BindToInterface(router.InterfaceFinder(), options.BindInterface, -1)
dialer.Control = control.Append(dialer.Control, bindFunc) dialer.Control = control.Append(dialer.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc) listener.Control = control.Append(listener.Control, bindFunc)
} else if router.AutoDetectInterface() { } else if router.AutoDetectInterface() {
if C.IsWindows { const useInterfaceName = C.IsLinux
bindFunc := control.BindToInterfaceIndexFunc(func(network, address string) int { bindFunc := control.BindToInterfaceFunc(router.InterfaceFinder(), func(network string, address string) (interfaceName string, interfaceIndex int) {
return router.InterfaceMonitor().DefaultInterfaceIndex(M.ParseSocksaddr(address).Addr) remoteAddr := M.ParseSocksaddr(address).Addr
}) if C.IsLinux {
dialer.Control = control.Append(dialer.Control, bindFunc) return router.InterfaceMonitor().DefaultInterfaceName(remoteAddr), -1
listener.Control = control.Append(listener.Control, bindFunc) } else {
} else { return "", router.InterfaceMonitor().DefaultInterfaceIndex(remoteAddr)
bindFunc := control.BindToInterfaceFunc(router.InterfaceBindManager(), func(network, address string) string { }
return router.InterfaceMonitor().DefaultInterfaceName(M.ParseSocksaddr(address).Addr) })
}) dialer.Control = control.Append(dialer.Control, bindFunc)
dialer.Control = control.Append(dialer.Control, bindFunc) listener.Control = control.Append(listener.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc)
}
} else if router.DefaultInterface() != "" { } else if router.DefaultInterface() != "" {
bindFunc := control.BindToInterface(router.InterfaceBindManager(), router.DefaultInterface()) bindFunc := control.BindToInterface(router.InterfaceFinder(), router.DefaultInterface(), -1)
dialer.Control = control.Append(dialer.Control, bindFunc) dialer.Control = control.Append(dialer.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc) listener.Control = control.Append(listener.Control, bindFunc)
} }

View File

@@ -13,7 +13,7 @@ import (
"github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/task" "github.com/sagernet/sing/common/task"
"golang.org/x/net/dns/dnsmessage" mDNS "github.com/miekg/dns"
) )
func StreamDomainNameQuery(readCtx context.Context, reader io.Reader) (*adapter.InboundContext, error) { func StreamDomainNameQuery(readCtx context.Context, reader io.Reader) (*adapter.InboundContext, error) {
@@ -44,18 +44,10 @@ func StreamDomainNameQuery(readCtx context.Context, reader io.Reader) (*adapter.
} }
func DomainNameQuery(ctx context.Context, packet []byte) (*adapter.InboundContext, error) { func DomainNameQuery(ctx context.Context, packet []byte) (*adapter.InboundContext, error) {
var parser dnsmessage.Parser var msg mDNS.Msg
_, err := parser.Start(packet) err := msg.Unpack(packet)
if err != nil { if err != nil {
return nil, err return nil, err
} }
question, err := parser.Question() return &adapter.InboundContext{Protocol: C.ProtocolDNS}, nil
if err != nil {
return nil, os.ErrInvalid
}
domain := question.Name.String()
if question.Class == dnsmessage.ClassINET && IsDomainName(domain) {
return &adapter.InboundContext{Protocol: C.ProtocolDNS /*, Domain: domain*/}, nil
}
return nil, os.ErrInvalid
} }

View File

@@ -7,11 +7,11 @@ import (
"crypto/tls" "crypto/tls"
"strings" "strings"
"github.com/sagernet/certmagic"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
"github.com/caddyserver/certmagic"
"github.com/mholt/acmez/acme" "github.com/mholt/acmez/acme"
) )

View File

@@ -30,7 +30,7 @@ func NewClient(router adapter.Router, serverAddress string, options option.Outbo
} }
} }
func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (net.Conn, error) { func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) {
tlsConn := config.Client(conn) tlsConn := config.Client(conn)
ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout) ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout)
defer cancel() defer cancel()

View File

@@ -15,6 +15,8 @@ type (
) )
type Config interface { type Config interface {
NextProtos() []string
SetNextProtos(nextProto []string)
Config() (*STDConfig, error) Config() (*STDConfig, error)
Client(conn net.Conn) Conn Client(conn net.Conn) Conn
} }
@@ -28,6 +30,7 @@ type ServerConfig interface {
type Conn interface { type Conn interface {
net.Conn net.Conn
HandshakeContext(ctx context.Context) error HandshakeContext(ctx context.Context) error
ConnectionState() tls.ConnectionState
} }
func ParseTLSVersion(version string) (uint16, error) { func ParseTLSVersion(version string) (uint16, error) {

View File

@@ -4,6 +4,7 @@ package tls
import ( import (
"context" "context"
"crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/base64" "encoding/base64"
"net" "net"
@@ -12,16 +13,23 @@ import (
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/cloudflaretls" cftls "github.com/sagernet/sing-box/transport/cloudflaretls"
"github.com/sagernet/sing-dns" "github.com/sagernet/sing-dns"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
mDNS "github.com/miekg/dns" mDNS "github.com/miekg/dns"
"golang.org/x/net/dns/dnsmessage"
) )
type echClientConfig struct { type echClientConfig struct {
config *tls.Config config *cftls.Config
}
func (e *echClientConfig) NextProtos() []string {
return e.config.NextProtos
}
func (e *echClientConfig) SetNextProtos(nextProto []string) {
e.config.NextProtos = nextProto
} }
func (e *echClientConfig) Config() (*STDConfig, error) { func (e *echClientConfig) Config() (*STDConfig, error) {
@@ -29,7 +37,29 @@ func (e *echClientConfig) Config() (*STDConfig, error) {
} }
func (e *echClientConfig) Client(conn net.Conn) Conn { func (e *echClientConfig) Client(conn net.Conn) Conn {
return tls.Client(conn, e.config) return &echConnWrapper{cftls.Client(conn, e.config)}
}
type echConnWrapper struct {
*cftls.Conn
}
func (c *echConnWrapper) ConnectionState() tls.ConnectionState {
state := c.Conn.ConnectionState()
return tls.ConnectionState{
Version: state.Version,
HandshakeComplete: state.HandshakeComplete,
DidResume: state.DidResume,
CipherSuite: state.CipherSuite,
NegotiatedProtocol: state.NegotiatedProtocol,
NegotiatedProtocolIsMutual: state.NegotiatedProtocolIsMutual,
ServerName: state.ServerName,
PeerCertificates: state.PeerCertificates,
VerifiedChains: state.VerifiedChains,
SignedCertificateTimestamps: state.SignedCertificateTimestamps,
OCSPResponse: state.OCSPResponse,
TLSUnique: state.TLSUnique,
}
} }
func newECHClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) { func newECHClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
@@ -45,7 +75,7 @@ func newECHClient(router adapter.Router, serverAddress string, options option.Ou
return nil, E.New("missing server_name or insecure=true") return nil, E.New("missing server_name or insecure=true")
} }
var tlsConfig tls.Config var tlsConfig cftls.Config
if options.DisableSNI { if options.DisableSNI {
tlsConfig.ServerName = "127.0.0.1" tlsConfig.ServerName = "127.0.0.1"
} else { } else {
@@ -55,7 +85,7 @@ func newECHClient(router adapter.Router, serverAddress string, options option.Ou
tlsConfig.InsecureSkipVerify = options.Insecure tlsConfig.InsecureSkipVerify = options.Insecure
} else if options.DisableSNI { } else if options.DisableSNI {
tlsConfig.InsecureSkipVerify = true tlsConfig.InsecureSkipVerify = true
tlsConfig.VerifyConnection = func(state tls.ConnectionState) error { tlsConfig.VerifyConnection = func(state cftls.ConnectionState) error {
verifyOptions := x509.VerifyOptions{ verifyOptions := x509.VerifyOptions{
DNSName: serverName, DNSName: serverName,
Intermediates: x509.NewCertPool(), Intermediates: x509.NewCertPool(),
@@ -87,7 +117,7 @@ func newECHClient(router adapter.Router, serverAddress string, options option.Ou
if options.CipherSuites != nil { if options.CipherSuites != nil {
find: find:
for _, cipherSuite := range options.CipherSuites { for _, cipherSuite := range options.CipherSuites {
for _, tlsCipherSuite := range tls.CipherSuites() { for _, tlsCipherSuite := range cftls.CipherSuites() {
if cipherSuite == tlsCipherSuite.Name { if cipherSuite == tlsCipherSuite.Name {
tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, tlsCipherSuite.ID) tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, tlsCipherSuite.ID)
continue find continue find
@@ -124,7 +154,7 @@ func newECHClient(router adapter.Router, serverAddress string, options option.Ou
if err != nil { if err != nil {
return nil, err return nil, err
} }
clientConfig, err := tls.UnmarshalECHConfigs(clientConfigContent) clientConfig, err := cftls.UnmarshalECHConfigs(clientConfigContent)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -137,17 +167,17 @@ func newECHClient(router adapter.Router, serverAddress string, options option.Ou
const typeHTTPS = 65 const typeHTTPS = 65
func fetchECHClientConfig(router adapter.Router) func(ctx context.Context, serverName string) ([]tls.ECHConfig, error) { func fetchECHClientConfig(router adapter.Router) func(ctx context.Context, serverName string) ([]cftls.ECHConfig, error) {
return func(ctx context.Context, serverName string) ([]tls.ECHConfig, error) { return func(ctx context.Context, serverName string) ([]cftls.ECHConfig, error) {
message := &dnsmessage.Message{ message := &mDNS.Msg{
Header: dnsmessage.Header{ MsgHdr: mDNS.MsgHdr{
RecursionDesired: true, RecursionDesired: true,
}, },
Questions: []dnsmessage.Question{ Question: []mDNS.Question{
{ {
Name: dnsmessage.MustNewName(serverName + "."), Name: serverName + ".",
Type: typeHTTPS, Qtype: mDNS.TypeHTTPS,
Class: dnsmessage.ClassINET, Qclass: mDNS.ClassINET,
}, },
}, },
} }
@@ -155,19 +185,10 @@ func fetchECHClientConfig(router adapter.Router) func(ctx context.Context, serve
if err != nil { if err != nil {
return nil, err return nil, err
} }
if response.RCode != dnsmessage.RCodeSuccess { if response.Rcode != mDNS.RcodeSuccess {
return nil, dns.RCodeError(response.RCode) return nil, dns.RCodeError(response.Rcode)
} }
content, err := response.Pack() for _, rr := range response.Answer {
if err != nil {
return nil, err
}
var mMsg mDNS.Msg
err = mMsg.Unpack(content)
if err != nil {
return nil, err
}
for _, rr := range mMsg.Answer {
switch resource := rr.(type) { switch resource := rr.(type) {
case *mDNS.HTTPS: case *mDNS.HTTPS:
for _, value := range resource.Value { for _, value := range resource.Value {
@@ -176,7 +197,7 @@ func fetchECHClientConfig(router adapter.Router) func(ctx context.Context, serve
if err != nil { if err != nil {
return nil, E.Cause(err, "decode ECH config") return nil, E.Cause(err, "decode ECH config")
} }
return tls.UnmarshalECHConfigs(echConfig) return cftls.UnmarshalECHConfigs(echConfig)
} }
} }
default: default:

View File

@@ -99,6 +99,14 @@ func newStdClient(serverAddress string, options option.OutboundTLSOptions) (Conf
return &stdClientConfig{&tlsConfig}, nil return &stdClientConfig{&tlsConfig}, nil
} }
func (s *stdClientConfig) NextProtos() []string {
return s.config.NextProtos
}
func (s *stdClientConfig) SetNextProtos(nextProto []string) {
s.config.NextProtos = nextProto
}
func (s *stdClientConfig) Config() (*STDConfig, error) { func (s *stdClientConfig) Config() (*STDConfig, error) {
return s.config, nil return s.config, nil
} }

View File

@@ -26,6 +26,14 @@ type STDServerConfig struct {
watcher *fsnotify.Watcher watcher *fsnotify.Watcher
} }
func (c *STDServerConfig) NextProtos() []string {
return c.config.NextProtos
}
func (c *STDServerConfig) SetNextProtos(nextProto []string) {
c.config.NextProtos = nextProto
}
func newSTDServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { func newSTDServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) {
if !options.Enabled { if !options.Enabled {
return nil, nil return nil, nil

View File

@@ -22,6 +22,14 @@ type utlsClientConfig struct {
id utls.ClientHelloID id utls.ClientHelloID
} }
func (e *utlsClientConfig) NextProtos() []string {
return e.config.NextProtos
}
func (e *utlsClientConfig) SetNextProtos(nextProto []string) {
e.config.NextProtos = nextProto
}
func (e *utlsClientConfig) Config() (*STDConfig, error) { func (e *utlsClientConfig) Config() (*STDConfig, error) {
return nil, E.New("unsupported usage for uTLS") return nil, E.New("unsupported usage for uTLS")
} }
@@ -38,6 +46,24 @@ func (c *utlsConnWrapper) HandshakeContext(ctx context.Context) error {
return c.Conn.Handshake() return c.Conn.Handshake()
} }
func (c *utlsConnWrapper) ConnectionState() tls.ConnectionState {
state := c.Conn.ConnectionState()
return tls.ConnectionState{
Version: state.Version,
HandshakeComplete: state.HandshakeComplete,
DidResume: state.DidResume,
CipherSuite: state.CipherSuite,
NegotiatedProtocol: state.NegotiatedProtocol,
NegotiatedProtocolIsMutual: state.NegotiatedProtocolIsMutual,
ServerName: state.ServerName,
PeerCertificates: state.PeerCertificates,
VerifiedChains: state.VerifiedChains,
SignedCertificateTimestamps: state.SignedCertificateTimestamps,
OCSPResponse: state.OCSPResponse,
TLSUnique: state.TLSUnique,
}
}
func newUTLSClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) { func newUTLSClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
var serverName string var serverName string
if options.ServerName != "" { if options.ServerName != "" {

View File

@@ -1,24 +1,26 @@
package constant package constant
const ( const (
TypeTun = "tun" TypeTun = "tun"
TypeRedirect = "redirect" TypeRedirect = "redirect"
TypeTProxy = "tproxy" TypeTProxy = "tproxy"
TypeDirect = "direct" TypeDirect = "direct"
TypeBlock = "block" TypeBlock = "block"
TypeDNS = "dns" TypeDNS = "dns"
TypeSocks = "socks" TypeSocks = "socks"
TypeHTTP = "http" TypeHTTP = "http"
TypeMixed = "mixed" TypeMixed = "mixed"
TypeShadowsocks = "shadowsocks" TypeShadowsocks = "shadowsocks"
TypeVMess = "vmess" TypeVMess = "vmess"
TypeTrojan = "trojan" TypeTrojan = "trojan"
TypeNaive = "naive" TypeNaive = "naive"
TypeWireGuard = "wireguard" TypeWireGuard = "wireguard"
TypeHysteria = "hysteria" TypeHysteria = "hysteria"
TypeTor = "tor" TypeTor = "tor"
TypeSSH = "ssh" TypeSSH = "ssh"
TypeShadowTLS = "shadowtls" TypeShadowTLS = "shadowtls"
TypeShadowsocksR = "shadowsocksr"
TypeVLESS = "vless"
) )
const ( const (

View File

@@ -1,5 +0,0 @@
//go:build with_quic
package constant
const QUIC_AVAILABLE = true

View File

@@ -1,9 +0,0 @@
//go:build !with_quic
package constant
import E "github.com/sagernet/sing/common/exceptions"
const QUIC_AVAILABLE = false
var ErrQUICNotIncluded = E.New(`QUIC is not included in this build, rebuild with -tags with_quic`)

View File

@@ -1,6 +1,3 @@
package constant package constant
var ( var Version = "1.1-beta5"
Version = "1.1-beta2"
Commit = ""
)

View File

@@ -1,3 +1,50 @@
#### 1.1-beta5
* Print tags in version command
* Redirect clash hello to external ui
* Move shadowsocksr implementation to clash
* Make gVisor optional **1**
* Refactor to miekg/dns
* Refactor bind control
* Fix build on go1.18
* Fix clash store-selected
* Fix close grpc conn
* Fix port rule match logic
* Fix clash api proxy type
*1*:
The build tag `no_gvisor` is replaced by `with_gvisor`.
The default tun stack is changed to system.
#### 1.0.4
* Fix close grpc conn
* Fix port rule match logic
* Fix clash api proxy type
#### 1.1-beta4
* Add internal simple-obfs and v2ray-plugin [Shadowsocks plugins](/configuration/outbound/shadowsocks#plugin)
* Add [ShadowsocksR outbound](/configuration/outbound/shadowsocksr)
* Add [VLESS outbound and XUDP](/configuration/outbound/vless)
* Skip wait for hysteria tcp handshake response
* Fix socks4 client
* Fix hysteria inbound
* Fix concurrent write
#### 1.0.3
* Fix socks4 client
* Fix hysteria inbound
* Fix concurrent write
#### 1.1-beta3
* Fix using custom TLS client in http2 client
* Fix bugs in 1.1-beta2
#### 1.1-beta2 #### 1.1-beta2
* Add Clash mode and persistence support **1** * Add Clash mode and persistence support **1**

View File

@@ -104,8 +104,10 @@
The default rule uses the following matching logic: The default rule uses the following matching logic:
(`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite`) && (`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite`) &&
(`port` || `port_range`) &&
(`source_geoip` || `source_ip_cidr`) && (`source_geoip` || `source_ip_cidr`) &&
`other fields` (`source_port` || `source_port_range`) &&
`other fields`
#### inbound #### inbound

View File

@@ -103,8 +103,10 @@
默认规则使用以下匹配逻辑: 默认规则使用以下匹配逻辑:
(`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite`) && (`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite`) &&
(`port` || `port_range`) &&
(`source_geoip` || `source_ip_cidr`) && (`source_geoip` || `source_ip_cidr`) &&
`other fields` (`source_port` || `source_port_range`) &&
`other fields`
#### inbound #### inbound

View File

@@ -16,7 +16,7 @@
"auto_route": true, "auto_route": true,
"strict_route": true, "strict_route": true,
"endpoint_independent_nat": false, "endpoint_independent_nat": false,
"stack": "gvisor", "stack": "system",
"include_uid": [ "include_uid": [
0 0
], ],
@@ -112,15 +112,15 @@ UDP NAT expiration time in seconds, default is 300 (5 minutes).
TCP/IP stack. TCP/IP stack.
| Stack | Description | Status | | Stack | Description | Status |
|------------------|--------------------------------------------------------------------------------|-------------------| |------------------|----------------------------------------------------------------------------------|-------------------|
| gVisor (default) | Based on [google/gvisor](https://github.com/google/gvisor) | recommended | | system (default) | Sometimes better performance | recommended |
| system | Less compatibility and sometimes better performance. | recommended | | gVisor | Better compatibility, based on [google/gvisor](https://github.com/google/gvisor) | recommended |
| LWIP | Based on [eycorsican/go-tun2socks](https://github.com/eycorsican/go-tun2socks) | upstream archived | | LWIP | Based on [eycorsican/go-tun2socks](https://github.com/eycorsican/go-tun2socks) | upstream archived |
!!! warning "" !!! warning ""
The LWIP stack is not included by default, see [Installation](/#installation). gVisor and LWIP stacks is not included by default, see [Installation](/#installation).
#### include_uid #### include_uid

View File

@@ -16,7 +16,7 @@
"auto_route": true, "auto_route": true,
"strict_route": true, "strict_route": true,
"endpoint_independent_nat": false, "endpoint_independent_nat": false,
"stack": "gvisor", "stack": "system",
"include_uid": [ "include_uid": [
0 0
], ],
@@ -107,15 +107,15 @@ UDP NAT 过期时间,以秒为单位,默认为 3005 分钟)。
TCP/IP 栈。 TCP/IP 栈。
| 栈 | 描述 | 状态 | | 栈 | 描述 | 状态 |
|------------------|--------------------------------------------------------------------------|-------| |-------------|--------------------------------------------------------------------------|-------|
| gVisor (default) | 基于 [google/gvisor](https://github.com/google/gvisor) | 推荐 | | system (默认) | 有时性能更好 | 推荐 |
| system | 兼容性较差,有时性能更好。 | 推荐 | | gVisor | 兼容性较好,基于 [google/gvisor](https://github.com/google/gvisor) | 推荐 |
| LWIP | 基于 [eycorsican/go-tun2socks](https://github.com/eycorsican/go-tun2socks) | 上游已存档 | | LWIP | 基于 [eycorsican/go-tun2socks](https://github.com/eycorsican/go-tun2socks) | 上游已存档 |
!!! warning "" !!! warning ""
默认安装不包含 LWIP 栈,请参阅 [安装](/zh/#_2)。 默认安装不包含 gVisor 和 LWIP 栈,请参阅 [安装](/zh/#_2)。
#### include_uid #### include_uid
@@ -145,10 +145,10 @@ TCP/IP 栈。
限制被路由的 Android 用户。 限制被路由的 Android 用户。
| 常用用户 | ID | | 常用用户 | ID |
|--|-----| |--|-----|
| 您 | 0 | | 您 | 0 |
| 工作资料 | 10 | | 工作资料 | 10 |
#### include_package #### include_package

View File

@@ -9,6 +9,8 @@
"server_port": 1080, "server_port": 1080,
"method": "2022-blake3-aes-128-gcm", "method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg==", "password": "8JCsPssfgS8tiRwiMlhARg==",
"plugin": "",
"plugin_opts": "",
"network": "udp", "network": "udp",
"udp_over_tcp": false, "udp_over_tcp": false,
"multiplex": {}, "multiplex": {},
@@ -65,6 +67,16 @@ Legacy encryption methods:
The shadowsocks password. The shadowsocks password.
#### plugin
Shadowsocks SIP003 plugin, implemented in internal.
Only `obfs-local` and `v2ray-plugin` are supported.
#### plugin_opts
Shadowsocks SIP003 plugin options.
#### network #### network
Enabled network Enabled network

View File

@@ -9,6 +9,8 @@
"server_port": 1080, "server_port": 1080,
"method": "2022-blake3-aes-128-gcm", "method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg==", "password": "8JCsPssfgS8tiRwiMlhARg==",
"plugin": "",
"plugin_opts": "",
"network": "udp", "network": "udp",
"udp_over_tcp": false, "udp_over_tcp": false,
"multiplex": {}, "multiplex": {},
@@ -65,6 +67,16 @@
Shadowsocks 密码。 Shadowsocks 密码。
#### plugin
Shadowsocks SIP003 插件,由内部实现。
仅支持 `obfs-local``v2ray-plugin`
#### plugin_opts
Shadowsocks SIP003 插件参数。
#### network #### network
启用的网络协议 启用的网络协议

View File

@@ -0,0 +1,106 @@
### Structure
```json
{
"type": "shadowsocksr",
"tag": "ssr-out",
"server": "127.0.0.1",
"server_port": 1080,
"method": "aes-128-cfb",
"password": "8JCsPssfgS8tiRwiMlhARg==",
"obfs": "plain",
"obfs_param": "",
"protocol": "origin",
"protocol_param": "",
"network": "udp",
... // Dial Fields
}
```
!!! warning ""
The ShadowsocksR protocol is obsolete and unmaintained. This outbound is provided for compatibility only.
!!! warning ""
ShadowsocksR is not included by default, see [Installation](/#installation).
### Fields
#### server
==Required==
The server address.
#### server_port
==Required==
The server port.
#### method
==Required==
Encryption methods:
* `aes-128-ctr`
* `aes-192-ctr`
* `aes-256-ctr`
* `aes-128-cfb`
* `aes-192-cfb`
* `aes-256-cfb`
* `rc4-md5`
* `chacha20-ietf`
* `xchacha20`
#### password
==Required==
The shadowsocks password.
#### obfs
The ShadowsocksR obfuscate.
* plain
* http_simple
* http_post
* random_head
* tls1.2_ticket_auth
#### obfs_param
The ShadowsocksR obfuscate parameter.
#### protocol
The ShadowsocksR protocol.
* origin
* verify_sha1
* auth_sha1_v4
* auth_aes128_md5
* auth_aes128_sha1
* auth_chain_a
* auth_chain_b
#### protocol_param
The ShadowsocksR protocol parameter.
#### network
Enabled network
One of `tcp` `udp`.
Both is enabled by default.
### Dial Fields
See [Dial Fields](/configuration/shared/dial) for details.

View File

@@ -0,0 +1,106 @@
### 结构
```json
{
"type": "shadowsocksr",
"tag": "ssr-out",
"server": "127.0.0.1",
"server_port": 1080,
"method": "aes-128-cfb",
"password": "8JCsPssfgS8tiRwiMlhARg==",
"obfs": "plain",
"obfs_param": "",
"protocol": "origin",
"protocol_param": "",
"network": "udp",
... // 拨号字段
}
```
!!! warning ""
ShadowsocksR 协议已过时且无人维护。 提供此出站仅出于兼容性目的。
!!! warning ""
默认安装不包含被 ShadowsocksR参阅 [安装](/zh/#_2)。
### 字段
#### server
==必填==
服务器地址。
#### server_port
==必填==
服务器端口。
#### method
==必填==
加密方法:
* `aes-128-ctr`
* `aes-192-ctr`
* `aes-256-ctr`
* `aes-128-cfb`
* `aes-192-cfb`
* `aes-256-cfb`
* `rc4-md5`
* `chacha20-ietf`
* `xchacha20`
#### password
==必填==
Shadowsocks 密码。
#### obfs
ShadowsocksR 混淆。
* plain
* http_simple
* http_post
* random_head
* tls1.2_ticket_auth
#### obfs_param
ShadowsocksR 混淆参数。
#### protocol
ShadowsocksR 协议。
* origin
* verify_sha1
* auth_sha1_v4
* auth_aes128_md5
* auth_aes128_sha1
* auth_chain_a
* auth_chain_b
#### protocol_param
ShadowsocksR 协议参数。
#### network
启用的网络协议
`tcp``udp`
默认所有。
### 拨号字段
参阅 [拨号字段](/zh/configuration/shared/dial/)。

View File

@@ -0,0 +1,70 @@
### Structure
```json
{
"type": "vless",
"tag": "vless-out",
"server": "127.0.0.1",
"server_port": 1080,
"uuid": "bf000d23-0752-40b4-affe-68f7707a9661",
"network": "tcp",
"tls": {},
"packet_encoding": "",
"transport": {},
... // Dial Fields
}
```
!!! warning ""
The VLESS protocol is architecturally coupled to v2ray and is unmaintained. This outbound is provided for compatibility purposes only.
### Fields
#### server
==Required==
The server address.
#### server_port
==Required==
The server port.
#### uuid
==Required==
The VLESS user id.
#### network
Enabled network
One of `tcp` `udp`.
Both is enabled by default.
#### tls
TLS configuration, see [TLS](/configuration/shared/tls/#outbound).
#### packet_encoding
| Encoding | Description |
|------------|-----------------------|
| (none) | Disabled |
| packetaddr | Supported by v2ray 5+ |
| xudp | Supported by xray |
#### transport
V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport).
### Dial Fields
See [Dial Fields](/configuration/shared/dial) for details.

View File

@@ -0,0 +1,70 @@
### 结构
```json
{
"type": "vless",
"tag": "vless-out",
"server": "127.0.0.1",
"server_port": 1080,
"uuid": "bf000d23-0752-40b4-affe-68f7707a9661",
"network": "tcp",
"tls": {},
"packet_encoding": "",
"transport": {},
... // 拨号字段
}
```
!!! warning ""
VLESS 协议与 v2ray 架构耦合且无人维护。 提供此出站仅出于兼容性目的。
### 字段
#### server
==必填==
服务器地址。
#### server_port
==必填==
服务器端口。
#### uuid
==必填==
VLESS 用户 ID。
#### network
启用的网络协议。
`tcp``udp`
默认所有。
#### tls
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。
#### packet_encoding
| 编码 | 描述 |
|------------|---------------|
| (空) | 禁用 |
| packetaddr | 由 v2ray 5+ 支持 |
| xudp | 由 xray 支持 |
#### transport
V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。
### 拨号字段
参阅 [拨号字段](/zh/configuration/shared/dial/)。

View File

@@ -26,6 +26,10 @@
WireGuard is not included by default, see [Installation](/#installation). WireGuard is not included by default, see [Installation](/#installation).
!!! warning ""
gVisor, which is required by the unprivileged WireGuard is not included by default, see [Installation](/#installation).
### Fields ### Fields
#### server #### server
@@ -44,7 +48,9 @@ The server port.
Use system tun support. Use system tun support.
Requires privileges and cannot conflict with system interfaces. Requires privilege and cannot conflict with system interfaces.
Forced if gVisor not included in the build.
#### interface_name #### interface_name

View File

@@ -26,6 +26,10 @@
默认安装不包含 WireGuard, 参阅 [安装](/zh/#_2)。 默认安装不包含 WireGuard, 参阅 [安装](/zh/#_2)。
!!! warning ""
默认安装不包含被非特权 WireGuard 需要的 gVisor, 参阅 [安装](/zh/#_2)。
### 字段 ### 字段
#### server #### server
@@ -46,6 +50,8 @@
需要特权且不能与系统接口冲突。 需要特权且不能与系统接口冲突。
如果 gVisor 未包含在构建中,则强制执行。
#### interface_name #### interface_name
启用 `system_interface` 时的自定义设备名称。 启用 `system_interface` 时的自定义设备名称。

View File

@@ -107,8 +107,10 @@
The default rule uses the following matching logic: The default rule uses the following matching logic:
(`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite` || `geoip` || `ip_cidr`) && (`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite` || `geoip` || `ip_cidr`) &&
(`port` || `port_range`) &&
(`source_geoip` || `source_ip_cidr`) && (`source_geoip` || `source_ip_cidr`) &&
`other fields` (`source_port` || `source_port_range`) &&
`other fields`
#### inbound #### inbound

View File

@@ -105,8 +105,10 @@
默认规则使用以下匹配逻辑: 默认规则使用以下匹配逻辑:
(`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite` || `geoip` || `ip_cidr`) && (`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `geosite` || `geoip` || `ip_cidr`) &&
(`port` || `port_range`) &&
(`source_geoip` || `source_ip_cidr`) && (`source_geoip` || `source_ip_cidr`) &&
`other fields` (`source_port` || `source_port_range`) &&
`other fields`
#### inbound #### inbound

View File

@@ -53,17 +53,6 @@ we need to do this.
The library needs to be updated with the upstream. The library needs to be updated with the upstream.
#### certmagic
Link: [GitHub repository](https://github.com/SagerNet/certmagic)
Fork of `caddyserver/certmagic`
Since upstream uses `miekg/dns` and we use `x/net/dnsmessage`, we need to replace its DNS part with our own
implementation.
The library needs to be updated with the upstream.
#### smux #### smux
Link: [GitHub repository](https://github.com/SagerNet/smux) Link: [GitHub repository](https://github.com/SagerNet/smux)

View File

@@ -27,11 +27,12 @@ go install -v -tags with_clash_api github.com/sagernet/sing-box/cmd/sing-box@lat
| `with_quic` | Build with QUIC support, see [QUIC and HTTP3 dns transports](./configuration/dns/server), [Naive inbound](./configuration/inbound/naive), [Hysteria Inbound](./configuration/inbound/hysteria), [Hysteria Outbound](./configuration/outbound/hysteria) and [V2Ray Transport#QUIC](./configuration/shared/v2ray-transport#quic). | | `with_quic` | Build with QUIC support, see [QUIC and HTTP3 dns transports](./configuration/dns/server), [Naive inbound](./configuration/inbound/naive), [Hysteria Inbound](./configuration/inbound/hysteria), [Hysteria Outbound](./configuration/outbound/hysteria) and [V2Ray Transport#QUIC](./configuration/shared/v2ray-transport#quic). |
| `with_grpc` | Build with standard gRPC support, see [V2Ray Transport#gRPC](./configuration/shared/v2ray-transport#grpc). | | `with_grpc` | Build with standard gRPC support, see [V2Ray Transport#gRPC](./configuration/shared/v2ray-transport#grpc). |
| `with_wireguard` | Build with WireGuard support, see [WireGuard outbound](./configuration/outbound/wireguard). | | `with_wireguard` | Build with WireGuard support, see [WireGuard outbound](./configuration/outbound/wireguard). |
| `with_shadowsocksr` | Build with ShadowsocksR support, see [ShadowsocksR outbound](./configuration/outbound/shadowsocksr). |
| `with_ech` | Build with TLS ECH extension support for TLS outbound, see [TLS](./configuration/shared/tls#ech). | | `with_ech` | Build with TLS ECH extension support for TLS outbound, see [TLS](./configuration/shared/tls#ech). |
| `with_utls` | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](./configuration/shared/tls#utls). | | `with_utls` | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](./configuration/shared/tls#utls). |
| `with_acme` | Build with ACME TLS certificate issuer support, see [TLS](./configuration/shared/tls). | | `with_acme` | Build with ACME TLS certificate issuer support, see [TLS](./configuration/shared/tls). |
| `with_clash_api` | Build with Clash API support, see [Experimental](./configuration/experimental#clash-api-fields). | | `with_clash_api` | Build with Clash API support, see [Experimental](./configuration/experimental#clash-api-fields). |
| `no_gvisor` | Build without gVisor Tun stack support, see [Tun inbound](./configuration/inbound/tun#stack). | | `with_gvisor` | Build with gVisor support, see [Tun inbound](./configuration/inbound/tun#stack) and [WireGuard outbound](./configuration/outbound/wireguard#system_interface). |
| `with_embedded_tor` (CGO required) | Build with embedded Tor support, see [Tor outbound](./configuration/outbound/tor). | | `with_embedded_tor` (CGO required) | Build with embedded Tor support, see [Tor outbound](./configuration/outbound/tor). |
| `with_lwip` (CGO required) | Build with LWIP Tun stack support, see [Tun inbound](./configuration/inbound/tun#stack). | | `with_lwip` (CGO required) | Build with LWIP Tun stack support, see [Tun inbound](./configuration/inbound/tun#stack). |

View File

@@ -25,13 +25,14 @@ go install -v -tags with_clash_api github.com/sagernet/sing-box/cmd/sing-box@lat
| 构建标志 | 描述 | | 构建标志 | 描述 |
|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `with_quic` | 启用 QUIC 支持,参阅 [QUIC 和 HTTP3 DNS 传输层](./configuration/dns/server)[Naive 入站](./configuration/inbound/naive)[Hysteria 入站](./configuration/inbound/hysteria)[Hysteria 出站](./configuration/outbound/hysteria) 和 [V2Ray 传输层#QUIC](./configuration/shared/v2ray-transport#quic)。 | | `with_quic` | 启用 QUIC 支持,参阅 [QUIC 和 HTTP3 DNS 传输层](./configuration/dns/server)[Naive 入站](./configuration/inbound/naive)[Hysteria 入站](./configuration/inbound/hysteria)[Hysteria 出站](./configuration/outbound/hysteria) 和 [V2Ray 传输层#QUIC](./configuration/shared/v2ray-transport#quic)。 |
| `with_grpc` | 启用标准 gRPC 支持,参阅 [V2Ray 传输层#gRPC](./configuration/shared/v2ray-transport#grpc)。 | | `with_grpc` | 启用标准 gRPCuTLS](https://github.com/refraction-networking/utls) 支持, 参阅 [TLS](./configuration/shared/tls#utls)。 |
| `with_wireguard` | 启用 WireGuard 支持,参阅 [WireGuard 出站](./configuration/outbound/wireguard)。 |
| `with_ech` | 启用 TLS ECH 扩展支持,参阅 [TLS](./configuration/shared/tls#ech)。 |
| `with_utls` | 启用 [uTLS](https://github.com/refraction-networking/utls) 支持, 参阅 [TLS](./configuration/shared/tls#utls)。 |
| `with_acme` | 启用 ACME TLS 证书签发支持,参阅 [TLS](./configuration/shared/tls)。 | | `with_acme` | 启用 ACME TLS 证书签发支持,参阅 [TLS](./configuration/shared/tls)。 |
| `with_clash_api` | 启用 Clash api 支持,参阅 [实验性](./configuration/experimental#clash-api-fields)。 | | `with_clash_api` | 启用 Clash api 支持,参阅 [V2Ray 传输层#gRPC](./configuration/shared/v2ray-transport#grpc)。 |
| `no_gvisor` | gVisor Tun 栈支持,参阅 [Tun 入](./configuration/inbound/tun#stack)。 | | `with_wireguard` | WireGuard 支持,参阅 [WireGuard 出](./configuration/outbound/wireguard)。 |
| `with_shadowsocksr` | 启用 ShadowsocksR 支持,参阅 [ShadowsocksR 出站](./configuration/outbound/shadowsocksr)。 |
| `with_ech` | 启用 TLS ECH 扩展支持,参阅 [TLS](./configuration/shared/tls#ech)。 |
| `with_utls` | 启用 [持,参阅 [实验性](./configuration/experimental#clash-api-fields)。 |
| `with_gvisor` | 启用 gVisor 支持,参阅 [Tun 入站](./configuration/inbound/tun#stack) 和 [WireGuard 出站](./configuration/outbound/wireguard#system_interface)。 |
| `with_embedded_tor` (需要 CGO) | 启用 嵌入式 Tor 支持,参阅 [Tor 出站](./configuration/outbound/tor)。 | | `with_embedded_tor` (需要 CGO) | 启用 嵌入式 Tor 支持,参阅 [Tor 出站](./configuration/outbound/tor)。 |
| `with_lwip` (需要 CGO) | 启用 LWIP Tun 栈支持,参阅 [Tun 入站](./configuration/inbound/tun#stack)。 | | `with_lwip` (需要 CGO) | 启用 LWIP Tun 栈支持,参阅 [Tun 入站](./configuration/inbound/tun#stack)。 |

View File

@@ -8,10 +8,10 @@ import (
"github.com/sagernet/sing-box/common/json" "github.com/sagernet/sing-box/common/json"
"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol" "github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
"github.com/sagernet/websocket"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/render" "github.com/go-chi/render"
"github.com/gorilla/websocket"
) )
func connectionRouter(trafficManager *trafficontrol.Manager) http.Handler { func connectionRouter(trafficManager *trafficontrol.Manager) http.Handler {

View File

@@ -70,18 +70,30 @@ func proxyInfo(server *Server, detour adapter.Outbound) *badjson.JSONObject {
case C.TypeSocks: case C.TypeSocks:
clashType = "Socks" clashType = "Socks"
case C.TypeHTTP: case C.TypeHTTP:
clashType = "Http" clashType = "HTTP"
case C.TypeShadowsocks: case C.TypeShadowsocks:
clashType = "Shadowsocks" clashType = "Shadowsocks"
case C.TypeVMess: case C.TypeVMess:
clashType = "Vmess" clashType = "VMess"
case C.TypeTrojan: case C.TypeTrojan:
clashType = "Trojan" clashType = "Trojan"
case C.TypeHysteria:
clashType = "Hysteria"
case C.TypeWireGuard:
clashType = "WireGuard"
case C.TypeShadowsocksR:
clashType = "ShadowsocksR"
case C.TypeVLESS:
clashType = "VLESS"
case C.TypeTor:
clashType = "Tor"
case C.TypeSSH:
clashType = "SSH"
case C.TypeSelector: case C.TypeSelector:
clashType = "Selector" clashType = "Selector"
isGroup = true isGroup = true
default: default:
clashType = "Socks" clashType = "Direct"
} }
info.Put("type", clashType) info.Put("type", clashType)
info.Put("name", detour.Tag()) info.Put("name", detour.Tag())

View File

@@ -22,11 +22,11 @@ import (
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/websocket"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/cors" "github.com/go-chi/cors"
"github.com/go-chi/render" "github.com/go-chi/render"
"github.com/gorilla/websocket"
) )
var _ adapter.ClashServer = (*Server)(nil) var _ adapter.ClashServer = (*Server)(nil)
@@ -61,6 +61,7 @@ func NewServer(router adapter.Router, logFactory log.ObservableFactory, options
server.mode = "rule" server.mode = "rule"
} }
if options.StoreSelected { if options.StoreSelected {
server.storeSelected = true
cachePath := os.ExpandEnv(options.CacheFile) cachePath := os.ExpandEnv(options.CacheFile)
if cachePath == "" { if cachePath == "" {
cachePath = "cache.db" cachePath = "cache.db"
@@ -80,7 +81,7 @@ func NewServer(router adapter.Router, logFactory log.ObservableFactory, options
chiRouter.Use(cors.Handler) chiRouter.Use(cors.Handler)
chiRouter.Group(func(r chi.Router) { chiRouter.Group(func(r chi.Router) {
r.Use(authentication(options.Secret)) r.Use(authentication(options.Secret))
r.Get("/", hello) r.Get("/", hello(options.ExternalUI != ""))
r.Get("/logs", getLogs(logFactory)) r.Get("/logs", getLogs(logFactory))
r.Get("/traffic", traffic(trafficManager)) r.Get("/traffic", traffic(trafficManager))
r.Get("/version", version) r.Get("/version", version)
@@ -232,8 +233,14 @@ func authentication(serverSecret string) func(next http.Handler) http.Handler {
} }
} }
func hello(w http.ResponseWriter, r *http.Request) { func hello(redirect bool) func(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, render.M{"hello": "clash"}) return func(w http.ResponseWriter, r *http.Request) {
if redirect {
http.Redirect(w, r, "/ui/", http.StatusTemporaryRedirect)
} else {
render.JSON(w, r, render.M{"hello": "clash"})
}
}
} }
var upgrader = websocket.Upgrader{ var upgrader = websocket.Upgrader{

19
go.mod
View File

@@ -4,6 +4,8 @@ go 1.18
require ( require (
berty.tech/go-libtor v1.0.385 berty.tech/go-libtor v1.0.385
github.com/Dreamacro/clash v1.11.8
github.com/caddyserver/certmagic v0.17.1
github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc
github.com/cretz/bine v0.2.0 github.com/cretz/bine v0.2.0
github.com/database64128/tfo-go v1.1.2 github.com/database64128/tfo-go v1.1.2
@@ -13,7 +15,6 @@ require (
github.com/go-chi/cors v1.2.1 github.com/go-chi/cors v1.2.1
github.com/go-chi/render v1.0.2 github.com/go-chi/render v1.0.2
github.com/gofrs/uuid v4.3.0+incompatible github.com/gofrs/uuid v4.3.0+incompatible
github.com/gorilla/websocket v1.5.0
github.com/hashicorp/yamux v0.1.1 github.com/hashicorp/yamux v0.1.1
github.com/logrusorgru/aurora v2.0.3+incompatible github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mholt/acmez v1.0.4 github.com/mholt/acmez v1.0.4
@@ -21,14 +22,14 @@ require (
github.com/oschwald/maxminddb-golang v1.10.0 github.com/oschwald/maxminddb-golang v1.10.0
github.com/pires/go-proxyproto v0.6.2 github.com/pires/go-proxyproto v0.6.2
github.com/refraction-networking/utls v1.1.2 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/quic-go v0.0.0-20220818150011-de611ab3e2bb
github.com/sagernet/sing v0.0.0-20220910144724-62c4ebdbcb3f github.com/sagernet/sing v0.0.0-20220915031330-38f39bc0c690
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 github.com/sagernet/sing-dns v0.0.0-20220913115644-aebff1dfbba8
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
github.com/sagernet/sing-tun v0.0.0-20220909114108-a6b5a9289ecb github.com/sagernet/sing-tun v0.0.0-20220915032336-60b1da576469
github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f github.com/sagernet/sing-vmess v0.0.0-20220913015714-c4ab86d40e12
github.com/sagernet/smux v0.0.0-20220907034654-1acb8471c15a github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
github.com/spf13/cobra v1.5.0 github.com/spf13/cobra v1.5.0
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
go.etcd.io/bbolt v1.3.6 go.etcd.io/bbolt v1.3.6
@@ -36,8 +37,8 @@ require (
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 golang.org/x/net v0.0.0-20220909164309-bea034e7d591
golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 golang.org/x/sys v0.0.0-20220913120320-3275c407cedc
golang.zx2c4.com/wireguard v0.0.0-20220904105730-b51010ba13f0 golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b
google.golang.org/grpc v1.49.0 google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.28.1 google.golang.org/protobuf v1.28.1
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c

42
go.sum
View File

@@ -3,6 +3,8 @@ berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+f
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Dreamacro/clash v1.11.8 h1:t/sy3/tiihRlvV3SsliYFjj8rKpbLw5IJ2PymiHcwS8=
github.com/Dreamacro/clash v1.11.8/go.mod h1:LsWCcJFoKuL1C5F2c0m/1690wihTHYSU3J+im09yTwQ=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
@@ -10,6 +12,8 @@ github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/caddyserver/certmagic v0.17.1 h1:VrWANhQAj3brK7jAUKyN6XBHg56WsyorI/84Ilq1tCQ=
github.com/caddyserver/certmagic v0.17.1/go.mod h1:pSS2aZcdKlrTZrb2DKuRafckx20o5Fz1EdDKEB8KOQM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc h1:307gdRLiZ08dwOIKwc5lAQ19DRFaQQvdhHalyB4Asx8= github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc h1:307gdRLiZ08dwOIKwc5lAQ19DRFaQQvdhHalyB4Asx8=
@@ -77,8 +81,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
@@ -93,8 +95,8 @@ github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8t
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
@@ -135,8 +137,6 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34=
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g=
github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a h1:SE3Xn4GOQ+kxbgGa2Xp0H2CCsx1o2pVTt0f+hmfuHH4=
github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a/go.mod h1:Q+ZXyesnkjV5B70B1ixk65ecKrlJ2jz0atv3fPKsVVo=
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
@@ -145,18 +145,20 @@ github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTY
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= 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-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.0.0-20220910144724-62c4ebdbcb3f h1:w1TJq7Lw3It35tDyMsZLtYz4T2msf1UK9JxC85L5+sk= github.com/sagernet/sing v0.0.0-20220915031330-38f39bc0c690 h1:pvaLdkDmsGN2K46vf8rorAhYGFvKPuQNzcofuy3aXXg=
github.com/sagernet/sing v0.0.0-20220910144724-62c4ebdbcb3f/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ= github.com/sagernet/sing v0.0.0-20220915031330-38f39bc0c690/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY=
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFxUX+xJCWMPPFZCn2GC/uLrBjTSr1vHY= github.com/sagernet/sing-dns v0.0.0-20220913115644-aebff1dfbba8 h1:Iyfl+Rm5jcDvXuy/jpOBI3eu35ujci50tkqYHHwwg+8=
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM= github.com/sagernet/sing-dns v0.0.0-20220913115644-aebff1dfbba8/go.mod h1:bPVnJ5gJ0WmUfN1bJP9Cis0ab8SSByx6JVzyLJjDMwA=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4= 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-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-20220915032336-60b1da576469 h1:tvGUJsOqxZ3ofAY9undQfQ+JCWvmIwLpIOC+XaBFO88=
github.com/sagernet/sing-tun v0.0.0-20220909114108-a6b5a9289ecb/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM= github.com/sagernet/sing-tun v0.0.0-20220915032336-60b1da576469/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-20220913015714-c4ab86d40e12 h1:4HYGbTDDemgBVTmaspXbkgjJlXc3hYVjNxSddJndq8Y=
github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0= github.com/sagernet/sing-vmess v0.0.0-20220913015714-c4ab86d40e12/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0=
github.com/sagernet/smux v0.0.0-20220907034654-1acb8471c15a h1:GCNwsN8MEckpjGJjK3qjQBQ9qHsoXB9B/KHUWBvE1V4= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
github.com/sagernet/smux v0.0.0-20220907034654-1acb8471c15a/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -236,8 +238,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -262,8 +264,8 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-20220913120320-3275c407cedc h1:dpclq5m2YrqPGStKmtw7IcNbKLfbIqKXvNxDJKdIKYc=
golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220913120320-3275c407cedc/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -295,8 +297,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20220904105730-b51010ba13f0 h1:5ZkdpbduT/g+9OtbSDvbF3KvfQG45CtH/ppO8FUmvCQ= golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b h1:qgrKnOfe1zyURRNdmDlGbN32i38Zjmw0B1+TMdHcOvg=
golang.zx2c4.com/wireguard v0.0.0-20220904105730-b51010ba13f0/go.mod h1:enML0deDxY1ux+B6ANGiwtg0yAJi1rctkTpcHNAVPyg= golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b/go.mod h1:6y4CqPAy54NwiN4nC8K+R1eMpQDB1P2d25qmunh2RSA=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=

View File

@@ -3,7 +3,6 @@ package inbound
import ( import (
"context" "context"
"net" "net"
"sync"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/settings" "github.com/sagernet/sing-box/common/settings"
@@ -42,7 +41,6 @@ type myInboundAdapter struct {
tcpListener net.Listener tcpListener net.Listener
udpConn *net.UDPConn udpConn *net.UDPConn
udpAddr M.Socksaddr udpAddr M.Socksaddr
packetAccess sync.RWMutex
packetOutboundClosed chan struct{} packetOutboundClosed chan struct{}
packetOutbound chan *myInboundPacket packetOutbound chan *myInboundPacket
} }

View File

@@ -208,17 +208,12 @@ func (s *myInboundPacketAdapter) Upstream() any {
} }
func (s *myInboundPacketAdapter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { func (s *myInboundPacketAdapter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
s.packetAccess.RLock()
defer s.packetAccess.RUnlock()
select { select {
case s.packetOutbound <- &myInboundPacket{buffer, destination}:
return nil
case <-s.packetOutboundClosed: case <-s.packetOutboundClosed:
return os.ErrClosed return os.ErrClosed
default:
} }
s.packetOutbound <- &myInboundPacket{buffer, destination}
return nil
} }
func (s *myInboundPacketAdapter) Close() error { func (s *myInboundPacketAdapter) Close() error {

View File

@@ -255,12 +255,6 @@ func (h *Hysteria) acceptStream(ctx context.Context, conn quic.Connection, strea
if err != nil { if err != nil {
return err return err
} }
err = hysteria.WriteServerResponse(stream, hysteria.ServerResponse{
OK: true,
})
if err != nil {
return err
}
var metadata adapter.InboundContext var metadata adapter.InboundContext
metadata.Inbound = h.tag metadata.Inbound = h.tag
metadata.InboundType = C.TypeHysteria metadata.InboundType = C.TypeHysteria
@@ -270,9 +264,16 @@ func (h *Hysteria) acceptStream(ctx context.Context, conn quic.Connection, strea
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr()) metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr())
metadata.OriginDestination = M.SocksaddrFromNet(conn.LocalAddr()) metadata.OriginDestination = M.SocksaddrFromNet(conn.LocalAddr())
metadata.Destination = M.ParseSocksaddrHostPort(request.Host, request.Port) metadata.Destination = M.ParseSocksaddrHostPort(request.Host, request.Port)
if !request.UDP { if !request.UDP {
err = hysteria.WriteServerResponse(stream, hysteria.ServerResponse{
OK: true,
})
if err != nil {
return err
}
h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination) h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination)
return h.router.RouteConnection(ctx, hysteria.NewConn(stream, metadata.Destination), metadata) return h.router.RouteConnection(ctx, hysteria.NewConn(stream, metadata.Destination, false), metadata)
} else { } else {
h.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination) h.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
var id uint32 var id uint32
@@ -282,6 +283,13 @@ func (h *Hysteria) acceptStream(ctx context.Context, conn quic.Connection, strea
h.udpSessions[id] = nCh h.udpSessions[id] = nCh
h.udpSessionId += 1 h.udpSessionId += 1
h.udpAccess.Unlock() h.udpAccess.Unlock()
err = hysteria.WriteServerResponse(stream, hysteria.ServerResponse{
OK: true,
UDPSessionID: id,
})
if err != nil {
return err
}
packetConn := hysteria.NewPacketConn(conn, stream, id, metadata.Destination, nCh, common.Closer(func() error { packetConn := hysteria.NewPacketConn(conn, stream, id, metadata.Destination, nCh, common.Closer(func() error {
h.udpAccess.Lock() h.udpAccess.Lock()
if ch, ok := h.udpSessions[id]; ok { if ch, ok := h.udpSessions[id]; ok {

View File

@@ -6,11 +6,11 @@ import (
"context" "context"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant" I "github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
) )
func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaInboundOptions) (adapter.Inbound, error) { func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaInboundOptions) (adapter.Inbound, error) {
return nil, C.ErrQUICNotIncluded return nil, I.ErrQUICNotIncluded
} }

View File

@@ -15,6 +15,7 @@ import (
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
@@ -105,7 +106,7 @@ func (n *Naive) Start() error {
if common.Contains(n.network, N.NetworkUDP) { if common.Contains(n.network, N.NetworkUDP) {
err := n.configureHTTP3Listener() err := n.configureHTTP3Listener()
if !C.QUIC_AVAILABLE && len(n.network) > 1 { if !include.WithQUIC && len(n.network) > 1 {
log.Warn(E.Cause(err, "naive http3 disabled")) log.Warn(E.Cause(err, "naive http3 disabled"))
} else if err != nil { } else if err != nil {
return err return err

View File

@@ -3,9 +3,9 @@
package inbound package inbound
import ( import (
C "github.com/sagernet/sing-box/constant" I "github.com/sagernet/sing-box/include"
) )
func (n *Naive) configureHTTP3Listener() error { func (n *Naive) configureHTTP3Listener() error {
return C.ErrQUICNotIncluded return I.ErrQUICNotIncluded
} }

7
include/quic.go Normal file
View File

@@ -0,0 +1,7 @@
//go:build with_quic
package include
import _ "github.com/sagernet/sing-dns/quic"
const WithQUIC = true

21
include/quic_stub.go Normal file
View File

@@ -0,0 +1,21 @@
//go:build !with_quic
package include
import (
"context"
"github.com/sagernet/sing-dns"
E "github.com/sagernet/sing/common/exceptions"
N "github.com/sagernet/sing/common/network"
)
const WithQUIC = false
var ErrQUICNotIncluded = E.New(`QUIC is not included in this build, rebuild with -tags with_quic`)
func init() {
dns.RegisterTransport([]string{"quic", "h3"}, func(ctx context.Context, dialer N.Dialer, link string) (dns.Transport, error) {
return nil, ErrQUICNotIncluded
})
}

View File

@@ -84,6 +84,8 @@ nav:
- WireGuard: configuration/outbound/wireguard.md - WireGuard: configuration/outbound/wireguard.md
- Hysteria: configuration/outbound/hysteria.md - Hysteria: configuration/outbound/hysteria.md
- ShadowTLS: configuration/outbound/shadowtls.md - ShadowTLS: configuration/outbound/shadowtls.md
- ShadowsocksR: configuration/outbound/shadowsocksr.md
- VLESS: configuration/outbound/vless.md
- Tor: configuration/outbound/tor.md - Tor: configuration/outbound/tor.md
- SSH: configuration/outbound/ssh.md - SSH: configuration/outbound/ssh.md
- DNS: configuration/outbound/dns.md - DNS: configuration/outbound/dns.md

View File

@@ -8,20 +8,22 @@ import (
) )
type _Outbound struct { type _Outbound struct {
Type string `json:"type"` Type string `json:"type"`
Tag string `json:"tag,omitempty"` Tag string `json:"tag,omitempty"`
DirectOptions DirectOutboundOptions `json:"-"` DirectOptions DirectOutboundOptions `json:"-"`
SocksOptions SocksOutboundOptions `json:"-"` SocksOptions SocksOutboundOptions `json:"-"`
HTTPOptions HTTPOutboundOptions `json:"-"` HTTPOptions HTTPOutboundOptions `json:"-"`
ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"` ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"`
VMessOptions VMessOutboundOptions `json:"-"` VMessOptions VMessOutboundOptions `json:"-"`
TrojanOptions TrojanOutboundOptions `json:"-"` TrojanOptions TrojanOutboundOptions `json:"-"`
WireGuardOptions WireGuardOutboundOptions `json:"-"` WireGuardOptions WireGuardOutboundOptions `json:"-"`
HysteriaOptions HysteriaOutboundOptions `json:"-"` HysteriaOptions HysteriaOutboundOptions `json:"-"`
TorOptions TorOutboundOptions `json:"-"` TorOptions TorOutboundOptions `json:"-"`
SSHOptions SSHOutboundOptions `json:"-"` SSHOptions SSHOutboundOptions `json:"-"`
ShadowTLSOptions ShadowTLSOutboundOptions `json:"-"` ShadowTLSOptions ShadowTLSOutboundOptions `json:"-"`
SelectorOptions SelectorOutboundOptions `json:"-"` ShadowsocksROptions ShadowsocksROutboundOptions `json:"-"`
VLESSOptions VLESSOutboundOptions `json:"-"`
SelectorOptions SelectorOutboundOptions `json:"-"`
} }
type Outbound _Outbound type Outbound _Outbound
@@ -53,6 +55,10 @@ func (h Outbound) MarshalJSON() ([]byte, error) {
v = h.SSHOptions v = h.SSHOptions
case C.TypeShadowTLS: case C.TypeShadowTLS:
v = h.ShadowTLSOptions v = h.ShadowTLSOptions
case C.TypeShadowsocksR:
v = h.ShadowsocksROptions
case C.TypeVLESS:
v = h.VLESSOptions
case C.TypeSelector: case C.TypeSelector:
v = h.SelectorOptions v = h.SelectorOptions
default: default:
@@ -92,6 +98,10 @@ func (h *Outbound) UnmarshalJSON(bytes []byte) error {
v = &h.SSHOptions v = &h.SSHOptions
case C.TypeShadowTLS: case C.TypeShadowTLS:
v = &h.ShadowTLSOptions v = &h.ShadowTLSOptions
case C.TypeShadowsocksR:
v = &h.ShadowsocksROptions
case C.TypeVLESS:
v = &h.VLESSOptions
case C.TypeSelector: case C.TypeSelector:
v = &h.SelectorOptions v = &h.SelectorOptions
default: default:

View File

@@ -26,6 +26,8 @@ type ShadowsocksOutboundOptions struct {
ServerOptions ServerOptions
Method string `json:"method"` Method string `json:"method"`
Password string `json:"password"` Password string `json:"password"`
Plugin string `json:"plugin,omitempty"`
PluginOptions string `json:"plugin_opts,omitempty"`
Network NetworkList `json:"network,omitempty"` Network NetworkList `json:"network,omitempty"`
UoT bool `json:"udp_over_tcp,omitempty"` UoT bool `json:"udp_over_tcp,omitempty"`
MultiplexOptions *MultiplexOptions `json:"multiplex,omitempty"` MultiplexOptions *MultiplexOptions `json:"multiplex,omitempty"`

13
option/shadowsocksr.go Normal file
View File

@@ -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"`
}

11
option/vless.go Normal file
View File

@@ -0,0 +1,11 @@
package option
type VLESSOutboundOptions struct {
DialerOptions
ServerOptions
UUID string `json:"uuid"`
Network NetworkList `json:"network,omitempty"`
TLS *OutboundTLSOptions `json:"tls,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"`
PacketEncoding string `json:"packet_encoding,omitempty"`
}

View File

@@ -41,6 +41,10 @@ func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, o
return NewSSH(ctx, router, logger, options.Tag, options.SSHOptions) return NewSSH(ctx, router, logger, options.Tag, options.SSHOptions)
case C.TypeShadowTLS: case C.TypeShadowTLS:
return NewShadowTLS(ctx, router, logger, options.Tag, options.ShadowTLSOptions) return NewShadowTLS(ctx, router, logger, options.Tag, options.ShadowTLSOptions)
case C.TypeShadowsocksR:
return NewShadowsocksR(ctx, router, logger, options.Tag, options.ShadowsocksROptions)
case C.TypeVLESS:
return NewVLESS(ctx, router, logger, options.Tag, options.VLESSOptions)
case C.TypeSelector: case C.TypeSelector:
return NewSelector(router, logger, options.Tag, options.SelectorOptions) return NewSelector(router, logger, options.Tag, options.SelectorOptions)
default: default:

View File

@@ -16,7 +16,7 @@ import (
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/task" "github.com/sagernet/sing/common/task"
"golang.org/x/net/dns/dnsmessage" mDNS "github.com/miekg/dns"
) )
var _ adapter.Outbound = (*DNS)(nil) var _ adapter.Outbound = (*DNS)(nil)
@@ -72,7 +72,7 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
if err != nil { if err != nil {
return err return err
} }
var message dnsmessage.Message var message mDNS.Msg
err = message.Unpack(buffer.Bytes()) err = message.Unpack(buffer.Bytes())
if err != nil { if err != nil {
return err return err
@@ -88,7 +88,7 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
responseBuffer := common.Dup(_responseBuffer) responseBuffer := common.Dup(_responseBuffer)
defer responseBuffer.Release() defer responseBuffer.Release()
responseBuffer.Resize(2, 0) responseBuffer.Resize(2, 0)
n, err := response.AppendPack(responseBuffer.Index(0)) n, err := response.PackBuffer(responseBuffer.FreeBytes())
if err != nil { if err != nil {
return err return err
} }
@@ -117,7 +117,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
if err != nil { if err != nil {
return err return err
} }
var message dnsmessage.Message var message mDNS.Msg
err = message.Unpack(buffer.Bytes()) err = message.Unpack(buffer.Bytes())
if err != nil { if err != nil {
return err return err
@@ -131,7 +131,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
} }
timeout.Update() timeout.Update()
responseBuffer := buf.NewPacket() responseBuffer := buf.NewPacket()
n, err := response.AppendPack(responseBuffer.Index(0)) n, err := response.PackBuffer(responseBuffer.FreeBytes())
if err != nil { if err != nil {
responseBuffer.Release() responseBuffer.Release()
return err return err

View File

@@ -276,16 +276,7 @@ func (h *Hysteria) DialContext(ctx context.Context, network string, destination
stream.Close() stream.Close()
return nil, err return nil, err
} }
response, err := hysteria.ReadServerResponse(stream) return hysteria.NewConn(stream, destination, true), nil
if err != nil {
stream.Close()
return nil, err
}
if !response.OK {
stream.Close()
return nil, E.New("remote error: ", response.Message)
}
return hysteria.NewConn(stream, destination), nil
case N.NetworkUDP: case N.NetworkUDP:
conn, err := h.ListenPacket(ctx, destination) conn, err := h.ListenPacket(ctx, destination)
if err != nil { if err != nil {

View File

@@ -6,11 +6,11 @@ import (
"context" "context"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant" I "github.com/sagernet/sing-box/include"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
) )
func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaOutboundOptions) (adapter.Outbound, error) { func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HysteriaOutboundOptions) (adapter.Outbound, error) {
return nil, C.ErrQUICNotIncluded return nil, I.ErrQUICNotIncluded
} }

View File

@@ -10,6 +10,7 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/sip003"
"github.com/sagernet/sing-shadowsocks" "github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowimpl" "github.com/sagernet/sing-shadowsocks/shadowimpl"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
@@ -27,6 +28,7 @@ type Shadowsocks struct {
dialer N.Dialer dialer N.Dialer
method shadowsocks.Method method shadowsocks.Method
serverAddr M.Socksaddr serverAddr M.Socksaddr
plugin sip003.Plugin
uot bool uot bool
multiplexDialer N.Dialer multiplexDialer N.Dialer
} }
@@ -49,6 +51,12 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
serverAddr: options.ServerOptions.Build(), serverAddr: options.ServerOptions.Build(),
uot: options.UoT, uot: options.UoT,
} }
if options.Plugin != "" {
outbound.plugin, err = sip003.CreatePlugin(options.Plugin, options.PluginOptions, router, outbound.dialer, outbound.serverAddr)
if err != nil {
return nil, err
}
}
if !options.UoT { if !options.UoT {
outbound.multiplexDialer, err = mux.NewClientWithOptions(ctx, (*shadowsocksDialer)(outbound), common.PtrValueOrDefault(options.MultiplexOptions)) outbound.multiplexDialer, err = mux.NewClientWithOptions(ctx, (*shadowsocksDialer)(outbound), common.PtrValueOrDefault(options.MultiplexOptions))
if err != nil { if err != nil {
@@ -135,7 +143,13 @@ type shadowsocksDialer Shadowsocks
func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
switch N.NetworkName(network) { switch N.NetworkName(network) {
case N.NetworkTCP: case N.NetworkTCP:
outConn, err := h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr) var outConn net.Conn
var err error
if h.plugin != nil {
outConn, err = h.plugin.DialContext(ctx)
} else {
outConn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }

182
outbound/shadowsocksr.go Normal file
View File

@@ -0,0 +1,182 @@
//go:build with_shadowsocksr
package outbound
import (
"context"
"errors"
"fmt"
"net"
"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-box/transport/clashssr/obfs"
"github.com/sagernet/sing-box/transport/clashssr/protocol"
"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"
"github.com/Dreamacro/clash/transport/shadowsocks/core"
"github.com/Dreamacro/clash/transport/shadowsocks/shadowstream"
"github.com/Dreamacro/clash/transport/socks5"
)
var _ adapter.Outbound = (*ShadowsocksR)(nil)
type ShadowsocksR struct {
myOutboundAdapter
dialer N.Dialer
serverAddr M.Socksaddr
cipher core.Cipher
obfs obfs.Obfs
protocol protocol.Protocol
}
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(),
}
var cipher string
var err error
switch options.Method {
case "none":
cipher = "dummy"
default:
cipher = options.Method
}
outbound.cipher, err = core.PickCipher(cipher, nil, options.Password)
if err != nil {
return nil, err
}
var (
ivSize int
key []byte
)
if cipher == "dummy" {
ivSize = 0
key = core.Kdf(options.Password, 16)
} else {
streamCipher, ok := outbound.cipher.(*core.StreamCipher)
if !ok {
return nil, fmt.Errorf("%s is not none or a supported stream cipher in ssr", cipher)
}
ivSize = streamCipher.IVSize()
key = streamCipher.Key
}
obfs, obfsOverhead, err := obfs.PickObfs(options.Obfs, &obfs.Base{
Host: options.Server,
Port: int(options.ServerPort),
Key: key,
IVSize: ivSize,
Param: options.ObfsParam,
})
if err != nil {
return nil, E.Cause(err, "initialize obfs")
}
protocol, err := protocol.PickProtocol(options.Protocol, &protocol.Base{
Key: key,
Overhead: obfsOverhead,
Param: options.ProtocolParam,
})
if err != nil {
return nil, E.Cause(err, "initialize protocol")
}
outbound.obfs = obfs
outbound.protocol = protocol
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
}
conn = h.cipher.StreamConn(h.obfs.StreamConn(conn))
writeIv, err := conn.(*shadowstream.Conn).ObtainWriteIV()
if err != nil {
return nil, err
}
conn = h.protocol.StreamConn(conn, writeIv)
err = M.SocksaddrSerializer.WriteAddrPort(conn, destination)
if err != nil {
return nil, E.Cause(err, "write request")
}
return conn, 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
}
packetConn := h.cipher.PacketConn(bufio.NewUnbindPacketConn(outConn))
packetConn = h.protocol.PacketConn(packetConn)
packetConn = &ssPacketConn{packetConn, outConn.RemoteAddr()}
return packetConn, 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)
}
type ssPacketConn struct {
net.PacketConn
rAddr net.Addr
}
func (spc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
if err != nil {
return
}
return spc.PacketConn.WriteTo(packet[3:], spc.rAddr)
}
func (spc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
n, _, e := spc.PacketConn.ReadFrom(b)
if e != nil {
return 0, nil, e
}
addr := socks5.SplitAddr(b[:n])
if addr == nil {
return 0, nil, errors.New("parse addr error")
}
udpAddr := addr.UDPAddr()
if udpAddr == nil {
return 0, nil, errors.New("parse addr error")
}
copy(b, b[len(addr):])
return n - len(addr), udpAddr, e
}

View File

@@ -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`)
}

View File

@@ -60,7 +60,11 @@ func (s *ShadowTLS) DialContext(ctx context.Context, network string, destination
if err != nil { if err != nil {
return nil, err return nil, err
} }
return tls.ClientHandshake(ctx, conn, s.tlsConfig) _, err = tls.ClientHandshake(ctx, conn, s.tlsConfig)
if err != nil {
return nil, err
}
return conn, nil
} }
func (s *ShadowTLS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { func (s *ShadowTLS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {

View File

@@ -20,8 +20,9 @@ var _ adapter.Outbound = (*Socks)(nil)
type Socks struct { type Socks struct {
myOutboundAdapter myOutboundAdapter
client *socks.Client client *socks.Client
uot bool resolve bool
uot bool
} }
func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) { func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) {
@@ -45,6 +46,7 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio
tag: tag, tag: tag,
}, },
socks.NewClient(detour, options.ServerOptions.Build(), version, options.Username, options.Password), socks.NewClient(detour, options.ServerOptions.Build(), version, options.Username, options.Password),
version == socks.Version4,
options.UoT, options.UoT,
}, nil }, nil
} }
@@ -72,6 +74,13 @@ func (h *Socks) DialContext(ctx context.Context, network string, destination M.S
default: default:
return nil, E.Extend(N.ErrUnknownNetwork, network) return nil, E.Extend(N.ErrUnknownNetwork, network)
} }
if destination.IsFqdn() {
addrs, err := h.router.LookupDefault(ctx, destination.Fqdn)
if err != nil {
return nil, err
}
return N.DialSerial(ctx, h.client, network, destination, addrs)
}
return h.client.DialContext(ctx, network, destination) return h.client.DialContext(ctx, network, destination)
} }

146
outbound/vless.go Normal file
View File

@@ -0,0 +1,146 @@
package outbound
import (
"context"
"net"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-box/common/tls"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/v2ray"
"github.com/sagernet/sing-box/transport/vless"
"github.com/sagernet/sing-vmess/packetaddr"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
var _ adapter.Outbound = (*VLESS)(nil)
type VLESS struct {
myOutboundAdapter
dialer N.Dialer
client *vless.Client
serverAddr M.Socksaddr
tlsConfig tls.Config
transport adapter.V2RayClientTransport
packetAddr bool
xudp bool
}
func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VLESSOutboundOptions) (*VLESS, error) {
outbound := &VLESS{
myOutboundAdapter: myOutboundAdapter{
protocol: C.TypeVLESS,
network: options.Network.Build(),
router: router,
logger: logger,
tag: tag,
},
dialer: dialer.New(router, options.DialerOptions),
serverAddr: options.ServerOptions.Build(),
}
var err error
if options.TLS != nil {
outbound.tlsConfig, err = tls.NewClient(router, options.Server, common.PtrValueOrDefault(options.TLS))
if err != nil {
return nil, err
}
}
if options.Transport != nil {
outbound.transport, err = v2ray.NewClientTransport(ctx, outbound.dialer, outbound.serverAddr, common.PtrValueOrDefault(options.Transport), outbound.tlsConfig)
if err != nil {
return nil, E.Cause(err, "create client transport: ", options.Transport.Type)
}
}
switch options.PacketEncoding {
case "":
case "packetaddr":
outbound.packetAddr = true
case "xudp":
outbound.xudp = true
default:
return nil, E.New("unknown packet encoding: ", options.PacketEncoding)
}
outbound.client, err = vless.NewClient(options.UUID)
if err != nil {
return nil, err
}
return outbound, nil
}
func (h *VLESS) Close() error {
return common.Close(h.transport)
}
func (h *VLESS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
ctx, metadata := adapter.AppendContext(ctx)
metadata.Outbound = h.tag
metadata.Destination = destination
var conn net.Conn
var err error
if h.transport != nil {
conn, err = h.transport.DialContext(ctx)
} else {
conn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr)
if err == nil && h.tlsConfig != nil {
conn, err = tls.ClientHandshake(ctx, conn, h.tlsConfig)
}
}
if err != nil {
return nil, err
}
switch N.NetworkName(network) {
case N.NetworkTCP:
case N.NetworkUDP:
}
switch N.NetworkName(network) {
case N.NetworkTCP:
h.logger.InfoContext(ctx, "outbound connection to ", destination)
return h.client.DialEarlyConn(conn, destination), nil
case N.NetworkUDP:
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
return h.client.DialPacketConn(conn, destination), nil
default:
return nil, E.Extend(N.ErrUnknownNetwork, network)
}
}
func (h *VLESS) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
ctx, metadata := adapter.AppendContext(ctx)
metadata.Outbound = h.tag
metadata.Destination = destination
var conn net.Conn
var err error
if h.transport != nil {
conn, err = h.transport.DialContext(ctx)
} else {
conn, err = h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr)
if err == nil && h.tlsConfig != nil {
conn, err = tls.ClientHandshake(ctx, conn, h.tlsConfig)
}
}
if err != nil {
return nil, err
}
if h.xudp {
return h.client.DialXUDPPacketConn(conn, destination), nil
} else if h.packetAddr {
return packetaddr.NewConn(h.client.DialPacketConn(conn, M.Socksaddr{Fqdn: packetaddr.SeqPacketMagicAddress}), destination), nil
} else {
return h.client.DialPacketConn(conn, destination), nil
}
}
func (h *VLESS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
return NewEarlyConnection(ctx, h, conn, metadata)
}
func (h *VLESS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return NewPacketConnection(ctx, h, conn, metadata)
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/wireguard" "github.com/sagernet/sing-box/transport/wireguard"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/debug" "github.com/sagernet/sing/common/debug"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
@@ -98,7 +99,7 @@ func NewWireGuard(ctx context.Context, router adapter.Router, logger log.Context
} }
var wireTunDevice wireguard.Device var wireTunDevice wireguard.Device
var err error var err error
if !options.SystemInterface { if !options.SystemInterface && tun.WithGVisor {
wireTunDevice, err = wireguard.NewStackDevice(localPrefixes, mtu) wireTunDevice, err = wireguard.NewStackDevice(localPrefixes, mtu)
} else { } else {
wireTunDevice, err = wireguard.NewSystemDevice(router, options.InterfaceName, localPrefixes, mtu) wireTunDevice, err = wireguard.NewSystemDevice(router, options.InterfaceName, localPrefixes, mtu)

View File

@@ -13,7 +13,7 @@ pushd $PROJECT
git fetch git fetch
git reset FETCH_HEAD --hard git reset FETCH_HEAD --hard
git clean -fdx git clean -fdx
go install -v -trimpath -ldflags "-s -w -buildid=" -tags no_gvisor,with_quic,with_acme,debug ./cmd/sing-box go install -v -trimpath -ldflags "-s -w -buildid=" -tags with_quic,with_acme,debug ./cmd/sing-box
popd popd
sudo systemctl stop sing-box sudo systemctl stop sing-box

View File

@@ -10,7 +10,7 @@ DIR=$(dirname "$0")
PROJECT=$DIR/../.. PROJECT=$DIR/../..
pushd $PROJECT pushd $PROJECT
go install -v -trimpath -ldflags "-s -w -buildid=" -tags no_gvisor,with_quic,with_wireguard,with_acme ./cmd/sing-box go install -v -trimpath -ldflags "-s -w -buildid=" -tags with_quic,with_wireguard,with_acme ./cmd/sing-box
popd popd
sudo cp $(go env GOPATH)/bin/sing-box /usr/local/bin/ sudo cp $(go env GOPATH)/bin/sing-box /usr/local/bin/

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e -o pipefail set -e -o pipefail
curl -Lo go.tar.gz https://go.dev/dl/go1.19.linux-amd64.tar.gz curl -Lo go.tar.gz https://go.dev/dl/go1.19.1.linux-amd64.tar.gz
sudo rm -rf /usr/local/go sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go.tar.gz sudo tar -C /usr/local -xzf go.tar.gz
rm go.tar.gz rm go.tar.gz

View File

@@ -10,7 +10,7 @@ DIR=$(dirname "$0")
PROJECT=$DIR/../.. PROJECT=$DIR/../..
pushd $PROJECT pushd $PROJECT
go install -v -trimpath -ldflags "-s -w -buildid=" -tags no_gvisor,with_quic,with_wireguard,with_acme ./cmd/sing-box go install -v -trimpath -ldflags "-s -w -buildid=" -tags with_quic,with_wireguard,with_acme ./cmd/sing-box
popd popd
sudo systemctl stop sing-box sudo systemctl stop sing-box

50
route/interface_finder.go Normal file
View File

@@ -0,0 +1,50 @@
package route
import (
"net"
"github.com/sagernet/sing/common/control"
)
var _ control.InterfaceFinder = (*myInterfaceFinder)(nil)
type myInterfaceFinder struct {
ifs []net.Interface
}
func (f *myInterfaceFinder) update() error {
ifs, err := net.Interfaces()
if err != nil {
return err
}
f.ifs = ifs
return nil
}
func (f *myInterfaceFinder) InterfaceIndexByName(name string) (interfaceIndex int, err error) {
for _, netInterface := range f.ifs {
if netInterface.Name == name {
return netInterface.Index, nil
}
}
netInterface, err := net.InterfaceByName(name)
if err != nil {
return
}
f.update()
return netInterface.Index, nil
}
func (f *myInterfaceFinder) InterfaceNameByIndex(index int) (interfaceName string, err error) {
for _, netInterface := range f.ifs {
if netInterface.Index == index {
return netInterface.Name, nil
}
}
netInterface, err := net.InterfaceByIndex(index)
if err != nil {
return
}
f.update()
return netInterface.Name, nil
}

View File

@@ -86,7 +86,7 @@ type Router struct {
transports []dns.Transport transports []dns.Transport
transportMap map[string]dns.Transport transportMap map[string]dns.Transport
transportDomainStrategy map[dns.Transport]dns.DomainStrategy transportDomainStrategy map[dns.Transport]dns.DomainStrategy
interfaceBindManager control.BindManager interfaceFinder myInterfaceFinder
autoDetectInterface bool autoDetectInterface bool
defaultInterface string defaultInterface string
defaultMark int defaultMark int
@@ -123,7 +123,6 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
defaultDetour: options.Final, defaultDetour: options.Final,
dnsClient: dns.NewClient(dnsOptions.DNSClientOptions.DisableCache, dnsOptions.DNSClientOptions.DisableExpire), dnsClient: dns.NewClient(dnsOptions.DNSClientOptions.DisableCache, dnsOptions.DNSClientOptions.DisableExpire),
defaultDomainStrategy: dns.DomainStrategy(dnsOptions.Strategy), defaultDomainStrategy: dns.DomainStrategy(dnsOptions.Strategy),
interfaceBindManager: control.NewBindManager(),
autoDetectInterface: options.AutoDetectInterface, autoDetectInterface: options.AutoDetectInterface,
defaultInterface: options.DefaultInterface, defaultInterface: options.DefaultInterface,
defaultMark: options.DefaultMark, defaultMark: options.DefaultMark,
@@ -196,7 +195,7 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
return nil, E.New("parse dns server[", tag, "]: missing address_resolver") return nil, E.New("parse dns server[", tag, "]: missing address_resolver")
} }
} }
transport, err := dns.NewTransport(ctx, detour, server.Address) transport, err := dns.CreateTransport(ctx, detour, server.Address)
if err != nil { if err != nil {
return nil, E.Cause(err, "parse dns server[", tag, "]") return nil, E.Cause(err, "parse dns server[", tag, "]")
} }
@@ -233,7 +232,7 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
} }
if defaultTransport == nil { if defaultTransport == nil {
if len(transports) == 0 { if len(transports) == 0 {
transports = append(transports, dns.NewLocalTransport()) transports = append(transports, &dns.LocalTransport{})
} }
defaultTransport = transports[0] defaultTransport = transports[0]
} }
@@ -247,13 +246,11 @@ func NewRouter(ctx context.Context, logger log.ContextLogger, dnsLogger log.Cont
return inbound.HTTPOptions.SetSystemProxy || inbound.MixedOptions.SetSystemProxy || C.IsAndroid && inbound.TunOptions.AutoRoute return inbound.HTTPOptions.SetSystemProxy || inbound.MixedOptions.SetSystemProxy || C.IsAndroid && inbound.TunOptions.AutoRoute
}) })
if router.interfaceBindManager != nil || needInterfaceMonitor { if needInterfaceMonitor {
networkMonitor, err := tun.NewNetworkUpdateMonitor(router) networkMonitor, err := tun.NewNetworkUpdateMonitor(router)
if err == nil { if err == nil {
router.networkMonitor = networkMonitor router.networkMonitor = networkMonitor
if router.interfaceBindManager != nil { networkMonitor.RegisterCallback(router.interfaceFinder.update)
networkMonitor.RegisterCallback(router.interfaceBindManager.Update)
}
} }
} }
@@ -714,8 +711,8 @@ func (r *Router) match(ctx context.Context, metadata *adapter.InboundContext, de
return nil, defaultOutbound return nil, defaultOutbound
} }
func (r *Router) InterfaceBindManager() control.BindManager { func (r *Router) InterfaceFinder() control.InterfaceFinder {
return r.interfaceBindManager return &r.interfaceFinder
} }
func (r *Router) AutoDetectInterface() bool { func (r *Router) AutoDetectInterface() bool {

View File

@@ -12,7 +12,7 @@ import (
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"golang.org/x/net/dns/dnsmessage" mDNS "github.com/miekg/dns"
) )
func (r *Router) matchDNS(ctx context.Context) (context.Context, dns.Transport, dns.DomainStrategy) { func (r *Router) matchDNS(ctx context.Context) (context.Context, dns.Transport, dns.DomainStrategy) {
@@ -40,29 +40,29 @@ func (r *Router) matchDNS(ctx context.Context) (context.Context, dns.Transport,
return ctx, r.defaultTransport, r.defaultDomainStrategy return ctx, r.defaultTransport, r.defaultDomainStrategy
} }
func (r *Router) Exchange(ctx context.Context, message *dnsmessage.Message) (*dnsmessage.Message, error) { func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
if len(message.Questions) > 0 { if len(message.Question) > 0 {
r.dnsLogger.DebugContext(ctx, "exchange ", formatDNSQuestion(message.Questions[0])) r.dnsLogger.DebugContext(ctx, "exchange ", formatQuestion(message.Question[0].String()))
} }
ctx, metadata := adapter.AppendContext(ctx) ctx, metadata := adapter.AppendContext(ctx)
if len(message.Questions) > 0 { if len(message.Question) > 0 {
switch message.Questions[0].Type { switch message.Question[0].Qtype {
case dnsmessage.TypeA: case mDNS.TypeA:
metadata.IPVersion = 4 metadata.IPVersion = 4
case dnsmessage.TypeAAAA: case mDNS.TypeAAAA:
metadata.IPVersion = 6 metadata.IPVersion = 6
} }
metadata.Domain = string(message.Questions[0].Name.Data[:message.Questions[0].Name.Length-1]) metadata.Domain = fqdnToDomain(message.Question[0].Name)
} }
ctx, transport, strategy := r.matchDNS(ctx) ctx, transport, strategy := r.matchDNS(ctx)
ctx, cancel := context.WithTimeout(ctx, C.DNSTimeout) ctx, cancel := context.WithTimeout(ctx, C.DNSTimeout)
defer cancel() defer cancel()
response, err := r.dnsClient.Exchange(ctx, transport, message, strategy) response, err := r.dnsClient.Exchange(ctx, transport, message, strategy)
if err != nil && len(message.Questions) > 0 { if err != nil && len(message.Question) > 0 {
r.dnsLogger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", message.Questions[0].Name.String())) r.dnsLogger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", formatQuestion(message.Question[0].String())))
} }
if len(message.Questions) > 0 && response != nil { if len(message.Question) > 0 && response != nil {
LogDNSAnswers(r.dnsLogger, ctx, message.Questions[0].Name.String(), response.Answers) LogDNSAnswers(r.dnsLogger, ctx, message.Question[0].Name, response.Answer)
} }
return response, err return response, err
} }
@@ -93,61 +93,26 @@ func (r *Router) LookupDefault(ctx context.Context, domain string) ([]netip.Addr
return r.Lookup(ctx, domain, dns.DomainStrategyAsIS) return r.Lookup(ctx, domain, dns.DomainStrategyAsIS)
} }
func LogDNSAnswers(logger log.ContextLogger, ctx context.Context, domain string, answers []dnsmessage.Resource) { func LogDNSAnswers(logger log.ContextLogger, ctx context.Context, domain string, answers []mDNS.RR) {
for _, rawAnswer := range answers { for _, answer := range answers {
var content string logger.InfoContext(ctx, "exchanged ", domain, " ", mDNS.Type(answer.Header().Rrtype).String(), " ", formatQuestion(answer.String()))
switch answer := rawAnswer.Body.(type) {
case *dnsmessage.AResource:
content = netip.AddrFrom4(answer.A).String()
case *dnsmessage.NSResource:
content = answer.NS.String()
case *dnsmessage.CNAMEResource:
content = answer.CNAME.String()
case *dnsmessage.SOAResource:
content = answer.MBox.String()
case *dnsmessage.PTRResource:
content = answer.PTR.String()
case *dnsmessage.MXResource:
content = answer.MX.String()
case *dnsmessage.TXTResource:
content = strings.Join(answer.TXT, " ")
case *dnsmessage.AAAAResource:
content = netip.AddrFrom16(answer.AAAA).String()
case *dnsmessage.SRVResource:
content = answer.Target.String()
case *dnsmessage.UnknownResource:
content = answer.Type.String()
default:
continue
}
rType := formatDNSType(rawAnswer.Header.Type)
if rType == "" {
logger.InfoContext(ctx, "exchanged ", domain, " ", rType)
} else {
logger.InfoContext(ctx, "exchanged ", domain, " ", rType, " ", content)
}
} }
} }
func formatDNSQuestion(question dnsmessage.Question) string { func fqdnToDomain(fqdn string) string {
var qType string if mDNS.IsFqdn(fqdn) {
qType = question.Type.String() return fqdn[:len(fqdn)-1]
if len(qType) > 4 {
qType = qType[4:]
} }
var qClass string return fqdn
qClass = question.Class.String()
if len(qClass) > 5 {
qClass = qClass[5:]
}
return string(question.Name.Data[:question.Name.Length-1]) + " " + qType + " " + qClass
} }
func formatDNSType(qType dnsmessage.Type) string { func formatQuestion(string string) string {
qTypeName := qType.String() if strings.HasPrefix(string, ";") {
if len(qTypeName) > 4 { string = string[1:]
return qTypeName[4:]
} else {
return F.ToString("unknown (type ", qTypeName, ")")
} }
string = strings.ReplaceAll(string, "\t", " ")
for strings.Contains(string, " ") {
string = strings.ReplaceAll(string, " ", " ")
}
return string
} }

View File

@@ -41,7 +41,9 @@ var _ adapter.Rule = (*DefaultRule)(nil)
type DefaultRule struct { type DefaultRule struct {
items []RuleItem items []RuleItem
sourceAddressItems []RuleItem sourceAddressItems []RuleItem
sourcePortItems []RuleItem
destinationAddressItems []RuleItem destinationAddressItems []RuleItem
destinationPortItems []RuleItem
allItems []RuleItem allItems []RuleItem
invert bool invert bool
outbound string outbound string
@@ -143,7 +145,7 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt
} }
if len(options.SourcePort) > 0 { if len(options.SourcePort) > 0 {
item := NewPortItem(true, options.SourcePort) item := NewPortItem(true, options.SourcePort)
rule.items = append(rule.items, item) rule.sourcePortItems = append(rule.sourcePortItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.SourcePortRange) > 0 { if len(options.SourcePortRange) > 0 {
@@ -151,12 +153,12 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt
if err != nil { if err != nil {
return nil, E.Cause(err, "source_port_range") return nil, E.Cause(err, "source_port_range")
} }
rule.items = append(rule.items, item) rule.sourcePortItems = append(rule.sourcePortItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.Port) > 0 { if len(options.Port) > 0 {
item := NewPortItem(false, options.Port) item := NewPortItem(false, options.Port)
rule.items = append(rule.items, item) rule.destinationPortItems = append(rule.destinationPortItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.PortRange) > 0 { if len(options.PortRange) > 0 {
@@ -164,7 +166,7 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt
if err != nil { if err != nil {
return nil, E.Cause(err, "port_range") return nil, E.Cause(err, "port_range")
} }
rule.items = append(rule.items, item) rule.destinationPortItems = append(rule.destinationPortItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.ProcessName) > 0 { if len(options.ProcessName) > 0 {
@@ -256,6 +258,19 @@ func (r *DefaultRule) Match(metadata *adapter.InboundContext) bool {
} }
} }
if len(r.sourcePortItems) > 0 {
var sourcePortMatch bool
for _, item := range r.sourcePortItems {
if item.Match(metadata) {
sourcePortMatch = true
break
}
}
if !sourcePortMatch {
return r.invert
}
}
if len(r.destinationAddressItems) > 0 { if len(r.destinationAddressItems) > 0 {
var destinationAddressMatch bool var destinationAddressMatch bool
for _, item := range r.destinationAddressItems { for _, item := range r.destinationAddressItems {
@@ -269,6 +284,19 @@ func (r *DefaultRule) Match(metadata *adapter.InboundContext) bool {
} }
} }
if len(r.destinationPortItems) > 0 {
var destinationPortMatch bool
for _, item := range r.destinationPortItems {
if item.Match(metadata) {
destinationPortMatch = true
break
}
}
if !destinationPortMatch {
return r.invert
}
}
return !r.invert return !r.invert
} }

View File

@@ -39,12 +39,15 @@ func NewDNSRule(router adapter.Router, logger log.ContextLogger, options option.
var _ adapter.DNSRule = (*DefaultDNSRule)(nil) var _ adapter.DNSRule = (*DefaultDNSRule)(nil)
type DefaultDNSRule struct { type DefaultDNSRule struct {
items []RuleItem items []RuleItem
addressItems []RuleItem sourceAddressItems []RuleItem
allItems []RuleItem sourcePortItems []RuleItem
invert bool destinationAddressItems []RuleItem
outbound string destinationPortItems []RuleItem
disableCache bool allItems []RuleItem
invert bool
outbound string
disableCache bool
} }
func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options option.DefaultDNSRule) (*DefaultDNSRule, error) { func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options option.DefaultDNSRule) (*DefaultDNSRule, error) {
@@ -90,12 +93,12 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
} }
if len(options.Domain) > 0 || len(options.DomainSuffix) > 0 { if len(options.Domain) > 0 || len(options.DomainSuffix) > 0 {
item := NewDomainItem(options.Domain, options.DomainSuffix) item := NewDomainItem(options.Domain, options.DomainSuffix)
rule.addressItems = append(rule.addressItems, item) rule.destinationAddressItems = append(rule.destinationAddressItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.DomainKeyword) > 0 { if len(options.DomainKeyword) > 0 {
item := NewDomainKeywordItem(options.DomainKeyword) item := NewDomainKeywordItem(options.DomainKeyword)
rule.addressItems = append(rule.addressItems, item) rule.destinationAddressItems = append(rule.destinationAddressItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.DomainRegex) > 0 { if len(options.DomainRegex) > 0 {
@@ -103,17 +106,17 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
if err != nil { if err != nil {
return nil, E.Cause(err, "domain_regex") return nil, E.Cause(err, "domain_regex")
} }
rule.addressItems = append(rule.addressItems, item) rule.destinationAddressItems = append(rule.destinationAddressItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.Geosite) > 0 { if len(options.Geosite) > 0 {
item := NewGeositeItem(router, logger, options.Geosite) item := NewGeositeItem(router, logger, options.Geosite)
rule.addressItems = append(rule.addressItems, item) rule.destinationAddressItems = append(rule.destinationAddressItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.SourceGeoIP) > 0 { if len(options.SourceGeoIP) > 0 {
item := NewGeoIPItem(router, logger, true, options.SourceGeoIP) item := NewGeoIPItem(router, logger, true, options.SourceGeoIP)
rule.items = append(rule.items, item) rule.sourceAddressItems = append(rule.sourceAddressItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.SourceIPCIDR) > 0 { if len(options.SourceIPCIDR) > 0 {
@@ -121,12 +124,12 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
if err != nil { if err != nil {
return nil, E.Cause(err, "source_ipcidr") return nil, E.Cause(err, "source_ipcidr")
} }
rule.items = append(rule.items, item) rule.sourceAddressItems = append(rule.sourceAddressItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.SourcePort) > 0 { if len(options.SourcePort) > 0 {
item := NewPortItem(true, options.SourcePort) item := NewPortItem(true, options.SourcePort)
rule.items = append(rule.items, item) rule.sourcePortItems = append(rule.sourcePortItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.SourcePortRange) > 0 { if len(options.SourcePortRange) > 0 {
@@ -134,12 +137,12 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
if err != nil { if err != nil {
return nil, E.Cause(err, "source_port_range") return nil, E.Cause(err, "source_port_range")
} }
rule.items = append(rule.items, item) rule.sourcePortItems = append(rule.sourcePortItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.Port) > 0 { if len(options.Port) > 0 {
item := NewPortItem(false, options.Port) item := NewPortItem(false, options.Port)
rule.items = append(rule.items, item) rule.destinationPortItems = append(rule.destinationPortItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.PortRange) > 0 { if len(options.PortRange) > 0 {
@@ -147,7 +150,7 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
if err != nil { if err != nil {
return nil, E.Cause(err, "port_range") return nil, E.Cause(err, "port_range")
} }
rule.items = append(rule.items, item) rule.destinationPortItems = append(rule.destinationPortItems, item)
rule.allItems = append(rule.allItems, item) rule.allItems = append(rule.allItems, item)
} }
if len(options.ProcessName) > 0 { if len(options.ProcessName) > 0 {
@@ -230,18 +233,59 @@ func (r *DefaultDNSRule) Match(metadata *adapter.InboundContext) bool {
return r.invert return r.invert
} }
} }
if len(r.addressItems) > 0 {
var addressMatch bool if len(r.sourceAddressItems) > 0 {
for _, item := range r.addressItems { var sourceAddressMatch bool
for _, item := range r.sourceAddressItems {
if item.Match(metadata) { if item.Match(metadata) {
addressMatch = true sourceAddressMatch = true
break break
} }
} }
if !addressMatch { if !sourceAddressMatch {
return r.invert return r.invert
} }
} }
if len(r.sourcePortItems) > 0 {
var sourcePortMatch bool
for _, item := range r.sourcePortItems {
if item.Match(metadata) {
sourcePortMatch = true
break
}
}
if !sourcePortMatch {
return r.invert
}
}
if len(r.destinationAddressItems) > 0 {
var destinationAddressMatch bool
for _, item := range r.destinationAddressItems {
if item.Match(metadata) {
destinationAddressMatch = true
break
}
}
if !destinationAddressMatch {
return r.invert
}
}
if len(r.destinationPortItems) > 0 {
var destinationPortMatch bool
for _, item := range r.destinationPortItems {
if item.Match(metadata) {
destinationPortMatch = true
break
}
}
if !destinationPortMatch {
return r.invert
}
}
return !r.invert return !r.invert
} }

View File

@@ -53,8 +53,8 @@ func testSuit(t *testing.T, clientPort uint16, testPort uint16) {
dialUDP := func() (net.PacketConn, error) { dialUDP := func() (net.PacketConn, error) {
return dialer.ListenPacket(context.Background(), M.ParseSocksaddrHostPort("127.0.0.1", testPort)) return dialer.ListenPacket(context.Background(), M.ParseSocksaddrHostPort("127.0.0.1", testPort))
} }
// require.NoError(t, testPingPongWithConn(t, testPort, dialTCP)) require.NoError(t, testPingPongWithConn(t, testPort, dialTCP))
// require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP)) require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP))
require.NoError(t, testLargeDataWithConn(t, testPort, dialTCP)) require.NoError(t, testLargeDataWithConn(t, testPort, dialTCP))
require.NoError(t, testLargeDataWithPacketConn(t, testPort, dialUDP)) require.NoError(t, testLargeDataWithPacketConn(t, testPort, dialUDP))
@@ -80,6 +80,22 @@ func testSuitSimple(t *testing.T, clientPort uint16, testPort uint16) {
} }
require.NoError(t, testPingPongWithConn(t, testPort, dialTCP)) require.NoError(t, testPingPongWithConn(t, testPort, dialTCP))
require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP)) require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP))
require.NoError(t, testPingPongWithConn(t, testPort, dialTCP))
require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP))
}
func testSuitSimple1(t *testing.T, clientPort uint16, testPort uint16) {
dialer := socks.NewClient(N.SystemDialer, M.ParseSocksaddrHostPort("127.0.0.1", clientPort), socks.Version5, "", "")
dialTCP := func() (net.Conn, error) {
return dialer.DialContext(context.Background(), "tcp", M.ParseSocksaddrHostPort("127.0.0.1", testPort))
}
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, testLargeDataWithPacketConn(t, testPort, dialUDP))
} }
func testSuitWg(t *testing.T, clientPort uint16, testPort uint16) { func testSuitWg(t *testing.T, clientPort uint16, testPort uint16) {
@@ -94,8 +110,8 @@ func testSuitWg(t *testing.T, clientPort uint16, testPort uint16) {
} }
return bufio.NewUnbindPacketConn(conn), nil return bufio.NewUnbindPacketConn(conn), nil
} }
require.NoError(t, testPingPongWithConn(t, testPort, dialTCP))
require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP))
require.NoError(t, testLargeDataWithConn(t, testPort, dialTCP)) require.NoError(t, testLargeDataWithConn(t, testPort, dialTCP))
require.NoError(t, testLargeDataWithPacketConn(t, testPort, dialUDP)) require.NoError(t, testLargeDataWithPacketConn(t, testPort, dialUDP))
// require.NoError(t, testPingPongWithConn(t, testPort, dialTCP))
// require.NoError(t, testPingPongWithPacketConn(t, testPort, dialUDP))
} }

View File

@@ -37,6 +37,8 @@ const (
ImageHysteria = "tobyxdd/hysteria:latest" ImageHysteria = "tobyxdd/hysteria:latest"
ImageNginx = "nginx:stable" ImageNginx = "nginx:stable"
ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest" ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest"
ImageShadowsocksR = "teddysun/shadowsocks-r:latest"
ImageXRayCore = "teddysun/xray:latest"
) )
var allImages = []string{ var allImages = []string{
@@ -49,6 +51,8 @@ var allImages = []string{
ImageHysteria, ImageHysteria,
ImageNginx, ImageNginx,
ImageShadowTLS, ImageShadowTLS,
ImageShadowsocksR,
ImageXRayCore,
} }
var localIP = netip.MustParseAddr("127.0.0.1") var localIP = netip.MustParseAddr("127.0.0.1")
@@ -385,21 +389,24 @@ func testLargeDataWithPacketConn(t *testing.T, port uint16, pcc func() (net.Pack
hashMap := map[int][]byte{} hashMap := map[int][]byte{}
mux := sync.Mutex{} mux := sync.Mutex{}
for i := 0; i < times; i++ { for i := 0; i < times; i++ {
buf := make([]byte, chunkSize) go func(idx int) {
if _, err = rand.Read(buf[1:]); err != nil { buf := make([]byte, chunkSize)
t.Log(err.Error()) if _, err := rand.Read(buf[1:]); err != nil {
continue t.Log(err.Error())
} return
buf[0] = byte(i) }
buf[0] = byte(idx)
hash := md5.Sum(buf) hash := md5.Sum(buf)
mux.Lock() mux.Lock()
hashMap[i] = hash[:] hashMap[idx] = hash[:]
mux.Unlock() mux.Unlock()
if _, err = pc.WriteTo(buf, addr); err != nil {
t.Log(err) if _, err := pc.WriteTo(buf, addr); err != nil {
continue t.Log(err.Error())
} return
}
}(i)
} }
return hashMap, nil return hashMap, nil

View File

@@ -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": ""
}

View File

@@ -0,0 +1,25 @@
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"listen": "0.0.0.0",
"port": 1234,
"protocol": "vless",
"settings": {
"decryption": "none",
"clients": [
{
"id": "b831381d-6324-4d53-ad4f-8cda48b30811"
}
]
}
}
],
"outbounds": [
{
"protocol": "freedom"
}
]
}

View File

@@ -7,14 +7,14 @@ require github.com/sagernet/sing-box v0.0.0
replace github.com/sagernet/sing-box => ../ replace github.com/sagernet/sing-box => ../
require ( require (
github.com/docker/docker v20.10.17+incompatible github.com/docker/docker v20.10.18+incompatible
github.com/docker/go-connections v0.4.0 github.com/docker/go-connections v0.4.0
github.com/gofrs/uuid v4.2.0+incompatible github.com/gofrs/uuid v4.3.0+incompatible
github.com/sagernet/sing v0.0.0-20220905164441-f3d346256d4a github.com/sagernet/sing v0.0.0-20220914045234-93cc53b60cee
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
github.com/spyzhov/ajson v0.7.1 github.com/spyzhov/ajson v0.7.1
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
golang.org/x/net v0.0.0-20220907135653-1e95f45603a7 golang.org/x/net v0.0.0-20220909164309-bea034e7d591
) )
//replace github.com/sagernet/sing => ../../sing //replace github.com/sagernet/sing => ../../sing
@@ -24,6 +24,7 @@ require (
github.com/Microsoft/go-winio v0.5.1 // indirect github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/ajg/form v1.5.1 // indirect github.com/ajg/form v1.5.1 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect github.com/andybalholm/brotli v1.0.4 // indirect
github.com/caddyserver/certmagic v0.17.1 // indirect
github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc // indirect github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc // indirect
github.com/cretz/bine v0.2.0 // indirect github.com/cretz/bine v0.2.0 // indirect
github.com/database64128/tfo-go v1.1.2 // indirect github.com/database64128/tfo-go v1.1.2 // indirect
@@ -39,7 +40,6 @@ require (
github.com/golang/mock v1.6.0 // indirect github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect github.com/google/btree v1.0.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect
github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/compress v1.13.6 // indirect
github.com/klauspost/cpuid/v2 v2.1.0 // indirect github.com/klauspost/cpuid/v2 v2.1.0 // indirect
@@ -62,16 +62,18 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/refraction-networking/utls v1.1.2 // indirect github.com/refraction-networking/utls v1.1.2 // indirect
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect
github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a // indirect
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect 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/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect
github.com/sagernet/sing-dns v0.0.0-20220903082137-b1102b8fc961 // indirect github.com/sagernet/shadowsocksr v0.0.0-20220912092645-c9ab93f81bb0 // indirect
github.com/sagernet/sing-tun v0.0.0-20220909114108-a6b5a9289ecb // indirect github.com/sagernet/sing-dns v0.0.0-20220913115644-aebff1dfbba8 // indirect
github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f // indirect github.com/sagernet/sing-tun v0.0.0-20220914100102-057dd738a7f7 // indirect
github.com/sagernet/smux v0.0.0-20220907034654-1acb8471c15a // indirect github.com/sagernet/sing-vmess v0.0.0-20220913015714-c4ab86d40e12 // indirect
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
github.com/sirupsen/logrus v1.8.1 // indirect github.com/sirupsen/logrus v1.8.1 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.10.0 // indirect go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.22.0 // indirect go.uber.org/zap v1.22.0 // indirect
@@ -79,7 +81,7 @@ require (
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect golang.org/x/sys v0.0.0-20220913120320-3275c407cedc // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect
@@ -89,7 +91,6 @@ require (
google.golang.org/grpc v1.49.0 // indirect google.golang.org/grpc v1.49.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.3.0 // indirect gotest.tools/v3 v3.3.0 // indirect
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect

View File

@@ -14,6 +14,8 @@ github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/caddyserver/certmagic v0.17.1 h1:VrWANhQAj3brK7jAUKyN6XBHg56WsyorI/84Ilq1tCQ=
github.com/caddyserver/certmagic v0.17.1/go.mod h1:pSS2aZcdKlrTZrb2DKuRafckx20o5Fz1EdDKEB8KOQM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc h1:307gdRLiZ08dwOIKwc5lAQ19DRFaQQvdhHalyB4Asx8= github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc h1:307gdRLiZ08dwOIKwc5lAQ19DRFaQQvdhHalyB4Asx8=
@@ -32,8 +34,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE= github.com/docker/docker v20.10.18+incompatible h1:SN84VYXTBNGn92T/QwIRPlum9zfemfitN7pbsp26WSc=
github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v20.10.18+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
@@ -57,8 +59,8 @@ github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -89,8 +91,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
@@ -155,28 +155,30 @@ github.com/refraction-networking/utls v1.1.2/go.mod h1:+D89TUtA8+NKVFj1IXWr0p3tS
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34=
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g=
github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a h1:SE3Xn4GOQ+kxbgGa2Xp0H2CCsx1o2pVTt0f+hmfuHH4=
github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a/go.mod h1:Q+ZXyesnkjV5B70B1ixk65ecKrlJ2jz0atv3fPKsVVo=
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA=
github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms=
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= 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 h1:wc0yQ+SBn4TaTYRwpwvEm3nc4eRdxk6vtRbouLVZAzk=
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= 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-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-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.0.0-20220905164441-f3d346256d4a h1:Bqt+eYP7vJocAgAVAXC0B0ZN0uMr6g6exAoF3Ado2pg= github.com/sagernet/sing v0.0.0-20220914045234-93cc53b60cee h1:+3w7+QWnhWi3Qz7+Xcais8zViHRUPIkmxq3eYZm/zvk=
github.com/sagernet/sing v0.0.0-20220905164441-f3d346256d4a/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ= github.com/sagernet/sing v0.0.0-20220914045234-93cc53b60cee/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY=
github.com/sagernet/sing-dns v0.0.0-20220903082137-b1102b8fc961 h1:5JeqhvCGV6AQQiAO0V67Loh2eyO3JNjIQnvRF8NnTE0= github.com/sagernet/sing-dns v0.0.0-20220913115644-aebff1dfbba8 h1:Iyfl+Rm5jcDvXuy/jpOBI3eu35ujci50tkqYHHwwg+8=
github.com/sagernet/sing-dns v0.0.0-20220903082137-b1102b8fc961/go.mod h1:vKBBy4mNJRaFuJ8H6kYIOPofsZ1JT5mgdwIlebtvnZ4= github.com/sagernet/sing-dns v0.0.0-20220913115644-aebff1dfbba8/go.mod h1:bPVnJ5gJ0WmUfN1bJP9Cis0ab8SSByx6JVzyLJjDMwA=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4= 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-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-20220914100102-057dd738a7f7 h1:zdvFDYMz8s0e9UmOxMk0wNGOKh64KfeWpx8UAbJJI60=
github.com/sagernet/sing-tun v0.0.0-20220909114108-a6b5a9289ecb/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM= github.com/sagernet/sing-tun v0.0.0-20220914100102-057dd738a7f7/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-20220913015714-c4ab86d40e12 h1:4HYGbTDDemgBVTmaspXbkgjJlXc3hYVjNxSddJndq8Y=
github.com/sagernet/sing-vmess v0.0.0-20220907073918-72d7fdf6825f/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0= github.com/sagernet/sing-vmess v0.0.0-20220913015714-c4ab86d40e12/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0=
github.com/sagernet/smux v0.0.0-20220907034654-1acb8471c15a h1:GCNwsN8MEckpjGJjK3qjQBQ9qHsoXB9B/KHUWBvE1V4= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
github.com/sagernet/smux v0.0.0-20220907034654-1acb8471c15a/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
@@ -197,6 +199,8 @@ github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
@@ -214,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-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-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-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-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-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
@@ -251,8 +256,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220907135653-1e95f45603a7 h1:1WGATo9HAhkWMbfyuVU0tEFP88OIkUvwaHFveQPvzCQ= golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
golang.org/x/net v0.0.0-20220907135653-1e95f45603a7/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -275,6 +280,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200217220822-9197077df867/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= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -290,8 +296,9 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY= golang.org/x/sys v0.0.0-20220913120320-3275c407cedc h1:dpclq5m2YrqPGStKmtw7IcNbKLfbIqKXvNxDJKdIKYc=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220913120320-3275c407cedc/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-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 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -370,9 +377,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -9,9 +9,6 @@ import (
) )
func TestHysteriaSelf(t *testing.T) { func TestHysteriaSelf(t *testing.T) {
if !C.QUIC_AVAILABLE {
t.Skip("QUIC not included")
}
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
@@ -80,13 +77,10 @@ func TestHysteriaSelf(t *testing.T) {
}, },
}, },
}) })
testSuitSimple(t, clientPort, testPort) testSuitSimple1(t, clientPort, testPort)
} }
func TestHysteriaInbound(t *testing.T) { func TestHysteriaInbound(t *testing.T) {
if !C.QUIC_AVAILABLE {
t.Skip("QUIC not included")
}
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
@@ -120,13 +114,10 @@ func TestHysteriaInbound(t *testing.T) {
caPem: "/etc/hysteria/ca.pem", caPem: "/etc/hysteria/ca.pem",
}, },
}) })
testSuit(t, clientPort, testPort) testSuitSimple1(t, clientPort, testPort)
} }
func TestHysteriaOutbound(t *testing.T) { func TestHysteriaOutbound(t *testing.T) {
if !C.QUIC_AVAILABLE {
t.Skip("QUIC not included")
}
_, certPem, keyPem := createSelfSignedCertificate(t, "example.org") _, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startDockerContainer(t, DockerOptions{ startDockerContainer(t, DockerOptions{
Image: ImageHysteria, Image: ImageHysteria,
@@ -171,5 +162,5 @@ func TestHysteriaOutbound(t *testing.T) {
}, },
}, },
}) })
testSuitSimple(t, clientPort, testPort) testSuitSimple1(t, clientPort, testPort)
} }

View File

@@ -99,9 +99,6 @@ func TestNaiveInbound(t *testing.T) {
} }
func TestNaiveHTTP3Inbound(t *testing.T) { func TestNaiveHTTP3Inbound(t *testing.T) {
if !C.QUIC_AVAILABLE {
t.Skip("QUIC not included")
}
caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org") caPem, certPem, keyPem := createSelfSignedCertificate(t, "example.org")
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{

48
test/shadowsocksr_test.go Normal file
View File

@@ -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)
}

View File

@@ -122,3 +122,62 @@ func TestTrojanSelf(t *testing.T) {
}) })
testSuit(t, clientPort, testPort) testSuit(t, clientPort, testPort)
} }
func TestTrojanPlainSelf(t *testing.T) {
startInstance(t, option.Options{
Inbounds: []option.Inbound{
{
Type: C.TypeMixed,
Tag: "mixed-in",
MixedOptions: option.HTTPMixedInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.ListenAddress(netip.IPv4Unspecified()),
ListenPort: clientPort,
},
},
},
{
Type: C.TypeTrojan,
TrojanOptions: option.TrojanInboundOptions{
ListenOptions: option.ListenOptions{
Listen: option.ListenAddress(netip.IPv4Unspecified()),
ListenPort: serverPort,
},
Users: []option.TrojanUser{
{
Name: "sekai",
Password: "password",
},
},
},
},
},
Outbounds: []option.Outbound{
{
Type: C.TypeDirect,
},
{
Type: C.TypeTrojan,
Tag: "trojan-out",
TrojanOptions: option.TrojanOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: serverPort,
},
Password: "password",
},
},
},
Route: &option.RouteOptions{
Rules: []option.Rule{
{
DefaultOptions: option.DefaultRule{
Inbound: []string{"mixed-in"},
Outbound: "trojan-out",
},
},
},
},
})
testSuit(t, clientPort, testPort)
}

View File

@@ -161,7 +161,7 @@ func testV2RayGRPCOutbound(t *testing.T, forceLite bool) {
}, },
}, },
}) })
testSuitSimple(t, clientPort, testPort) testSuit(t, clientPort, testPort)
} }
func TestV2RayGRPCLite(t *testing.T) { func TestV2RayGRPCLite(t *testing.T) {

View File

@@ -266,7 +266,7 @@ func TestVMessQUICSelf(t *testing.T) {
}, },
}, },
}) })
testSuitSimple(t, clientPort, testPort) testSuitSimple1(t, clientPort, testPort)
} }
func testV2RayTransportNOTLSSelf(t *testing.T, transport *option.V2RayTransportOptions) { func testV2RayTransportNOTLSSelf(t *testing.T, transport *option.V2RayTransportOptions) {
@@ -330,5 +330,5 @@ func testV2RayTransportNOTLSSelf(t *testing.T, transport *option.V2RayTransportO
}, },
}, },
}) })
testSuitSimple(t, clientPort, testPort) testSuit(t, clientPort, testPort)
} }

View File

@@ -193,5 +193,5 @@ func testV2RayWebsocketOutbound(t *testing.T, maxEarlyData uint32, earlyDataHead
}, },
}, },
}) })
testSuitSimple(t, clientPort, testPort) testSuit(t, clientPort, testPort)
} }

120
test/vless_test.go Normal file
View File

@@ -0,0 +1,120 @@
package main
import (
"net/netip"
"os"
"testing"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/spyzhov/ajson"
"github.com/stretchr/testify/require"
)
func TestVLESS(t *testing.T) {
content, err := os.ReadFile("config/vless-server.json")
require.NoError(t, err)
config, err := ajson.Unmarshal(content)
require.NoError(t, err)
user := newUUID()
inbound := config.MustKey("inbounds").MustIndex(0)
inbound.MustKey("port").SetNumeric(float64(serverPort))
inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("id").SetString(user.String())
content, err = ajson.Marshal(config)
require.NoError(t, err)
startDockerContainer(t, DockerOptions{
Image: ImageV2RayCore,
Ports: []uint16{serverPort, testPort},
EntryPoint: "v2ray",
Stdin: content,
})
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.TypeVLESS,
VLESSOptions: option.VLESSOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: serverPort,
},
UUID: user.String(),
},
},
},
})
testSuit(t, clientPort, testPort)
}
func TestVLESSXRay(t *testing.T) {
testVLESSXray(t, "")
}
func TestVLESSXUDP(t *testing.T) {
testVLESSXray(t, "xudp")
}
func testVLESSXray(t *testing.T, packetEncoding string) {
content, err := os.ReadFile("config/vless-server.json")
require.NoError(t, err)
config, err := ajson.Unmarshal(content)
require.NoError(t, err)
user := newUUID()
inbound := config.MustKey("inbounds").MustIndex(0)
inbound.MustKey("port").SetNumeric(float64(serverPort))
inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("id").SetString(user.String())
content, err = ajson.Marshal(config)
require.NoError(t, err)
startDockerContainer(t, DockerOptions{
Image: ImageXRayCore,
Ports: []uint16{serverPort, testPort},
EntryPoint: "xray",
Stdin: content,
})
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.TypeVLESS,
VLESSOptions: option.VLESSOutboundOptions{
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: serverPort,
},
UUID: user.String(),
PacketEncoding: packetEncoding,
},
},
},
})
testSuit(t, clientPort, testPort)
}

View File

@@ -13,21 +13,24 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func newUUID() uuid.UUID {
user, _ := uuid.DefaultGenerator.NewV4()
return user
}
func _TestVMessAuto(t *testing.T) { func _TestVMessAuto(t *testing.T) {
security := "auto" security := "auto"
user, err := uuid.DefaultGenerator.NewV4()
require.NoError(t, err)
t.Run("self", func(t *testing.T) { t.Run("self", func(t *testing.T) {
testVMessSelf(t, security, user, 0, false, false, false) testVMessSelf(t, security, 0, false, false, false)
}) })
t.Run("packetaddr", func(t *testing.T) { t.Run("packetaddr", func(t *testing.T) {
testVMessSelf(t, security, user, 0, false, false, true) testVMessSelf(t, security, 0, false, false, true)
}) })
t.Run("inbound", func(t *testing.T) { t.Run("inbound", func(t *testing.T) {
testVMessInboundWithV2Ray(t, security, user, 0, false) testVMessInboundWithV2Ray(t, security, 0, false)
}) })
t.Run("outbound", func(t *testing.T) { t.Run("outbound", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, false, false, 0) testVMessOutboundWithV2Ray(t, security, false, false, 0)
}) })
} }
@@ -56,102 +59,97 @@ func TestVMess(t *testing.T) {
} }
func testVMess0(t *testing.T, security string) { func testVMess0(t *testing.T, security string) {
user, err := uuid.DefaultGenerator.NewV4()
require.NoError(t, err)
t.Run("self", func(t *testing.T) { t.Run("self", func(t *testing.T) {
testVMessSelf(t, security, user, 0, false, false, false) testVMessSelf(t, security, 0, false, false, false)
}) })
t.Run("self-legacy", func(t *testing.T) { t.Run("self-legacy", func(t *testing.T) {
testVMessSelf(t, security, user, 1, false, false, false) testVMessSelf(t, security, 1, false, false, false)
}) })
t.Run("packetaddr", func(t *testing.T) { t.Run("packetaddr", func(t *testing.T) {
testVMessSelf(t, security, user, 0, false, false, true) testVMessSelf(t, security, 0, false, false, true)
}) })
t.Run("outbound", func(t *testing.T) { t.Run("outbound", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, false, false, 0) testVMessOutboundWithV2Ray(t, security, false, false, 0)
}) })
t.Run("outbound-legacy", func(t *testing.T) { t.Run("outbound-legacy", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, false, false, 1) testVMessOutboundWithV2Ray(t, security, false, false, 1)
}) })
} }
func testVMess1(t *testing.T, security string) { func testVMess1(t *testing.T, security string) {
user, err := uuid.DefaultGenerator.NewV4()
require.NoError(t, err)
t.Run("self", func(t *testing.T) { t.Run("self", func(t *testing.T) {
testVMessSelf(t, security, user, 0, false, false, false) testVMessSelf(t, security, 0, false, false, false)
}) })
t.Run("self-legacy", func(t *testing.T) { t.Run("self-legacy", func(t *testing.T) {
testVMessSelf(t, security, user, 1, false, false, false) testVMessSelf(t, security, 1, false, false, false)
}) })
t.Run("packetaddr", func(t *testing.T) { t.Run("packetaddr", func(t *testing.T) {
testVMessSelf(t, security, user, 0, false, false, true) testVMessSelf(t, security, 0, false, false, true)
}) })
t.Run("inbound", func(t *testing.T) { t.Run("inbound", func(t *testing.T) {
testVMessInboundWithV2Ray(t, security, user, 0, false) testVMessInboundWithV2Ray(t, security, 0, false)
}) })
t.Run("outbound", func(t *testing.T) { t.Run("outbound", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, false, false, 0) testVMessOutboundWithV2Ray(t, security, false, false, 0)
}) })
t.Run("outbound-legacy", func(t *testing.T) { t.Run("outbound-legacy", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, false, false, 1) testVMessOutboundWithV2Ray(t, security, false, false, 1)
}) })
} }
func testVMess2(t *testing.T, security string) { func testVMess2(t *testing.T, security string) {
user, err := uuid.DefaultGenerator.NewV4()
require.NoError(t, err)
t.Run("self", func(t *testing.T) { t.Run("self", func(t *testing.T) {
testVMessSelf(t, security, user, 0, false, false, false) testVMessSelf(t, security, 0, false, false, false)
}) })
t.Run("self-padding", func(t *testing.T) { t.Run("self-padding", func(t *testing.T) {
testVMessSelf(t, security, user, 0, true, false, false) testVMessSelf(t, security, 0, true, false, false)
}) })
t.Run("self-authid", func(t *testing.T) { t.Run("self-authid", func(t *testing.T) {
testVMessSelf(t, security, user, 0, false, true, false) testVMessSelf(t, security, 0, false, true, false)
}) })
t.Run("self-padding-authid", func(t *testing.T) { t.Run("self-padding-authid", func(t *testing.T) {
testVMessSelf(t, security, user, 0, true, true, false) testVMessSelf(t, security, 0, true, true, false)
}) })
t.Run("self-legacy", func(t *testing.T) { t.Run("self-legacy", func(t *testing.T) {
testVMessSelf(t, security, user, 1, false, false, false) testVMessSelf(t, security, 1, false, false, false)
}) })
t.Run("self-legacy-padding", func(t *testing.T) { t.Run("self-legacy-padding", func(t *testing.T) {
testVMessSelf(t, security, user, 1, true, false, false) testVMessSelf(t, security, 1, true, false, false)
}) })
t.Run("packetaddr", func(t *testing.T) { t.Run("packetaddr", func(t *testing.T) {
testVMessSelf(t, security, user, 0, false, false, true) testVMessSelf(t, security, 0, false, false, true)
}) })
t.Run("inbound", func(t *testing.T) { t.Run("inbound", func(t *testing.T) {
testVMessInboundWithV2Ray(t, security, user, 0, false) testVMessInboundWithV2Ray(t, security, 0, false)
}) })
t.Run("inbound-authid", func(t *testing.T) { t.Run("inbound-authid", func(t *testing.T) {
testVMessInboundWithV2Ray(t, security, user, 0, true) testVMessInboundWithV2Ray(t, security, 0, true)
}) })
t.Run("inbound-legacy", func(t *testing.T) { t.Run("inbound-legacy", func(t *testing.T) {
testVMessInboundWithV2Ray(t, security, user, 64, false) testVMessInboundWithV2Ray(t, security, 64, false)
}) })
t.Run("outbound", func(t *testing.T) { t.Run("outbound", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, false, false, 0) testVMessOutboundWithV2Ray(t, security, false, false, 0)
}) })
t.Run("outbound-padding", func(t *testing.T) { t.Run("outbound-padding", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, true, false, 0) testVMessOutboundWithV2Ray(t, security, true, false, 0)
}) })
t.Run("outbound-authid", func(t *testing.T) { t.Run("outbound-authid", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, false, true, 0) testVMessOutboundWithV2Ray(t, security, false, true, 0)
}) })
t.Run("outbound-padding-authid", func(t *testing.T) { t.Run("outbound-padding-authid", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, true, true, 0) testVMessOutboundWithV2Ray(t, security, true, true, 0)
}) })
t.Run("outbound-legacy", func(t *testing.T) { t.Run("outbound-legacy", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, false, false, 1) testVMessOutboundWithV2Ray(t, security, false, false, 1)
}) })
t.Run("outbound-legacy-padding", func(t *testing.T) { t.Run("outbound-legacy-padding", func(t *testing.T) {
testVMessOutboundWithV2Ray(t, security, user, true, false, 1) testVMessOutboundWithV2Ray(t, security, true, false, 1)
}) })
} }
func testVMessInboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, alterId int, authenticatedLength bool) { func testVMessInboundWithV2Ray(t *testing.T, security string, alterId int, authenticatedLength bool) {
userId := newUUID()
content, err := os.ReadFile("config/vmess-client.json") content, err := os.ReadFile("config/vmess-client.json")
require.NoError(t, err) require.NoError(t, err)
config, err := ajson.Unmarshal(content) config, err := ajson.Unmarshal(content)
@@ -161,7 +159,7 @@ func testVMessInboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, al
outbound := config.MustKey("outbounds").MustIndex(0).MustKey("settings").MustKey("vnext").MustIndex(0) outbound := config.MustKey("outbounds").MustIndex(0).MustKey("settings").MustKey("vnext").MustIndex(0)
outbound.MustKey("port").SetNumeric(float64(serverPort)) outbound.MustKey("port").SetNumeric(float64(serverPort))
user := outbound.MustKey("users").MustIndex(0) user := outbound.MustKey("users").MustIndex(0)
user.MustKey("id").SetString(uuid.String()) user.MustKey("id").SetString(userId.String())
user.MustKey("alterId").SetNumeric(float64(alterId)) user.MustKey("alterId").SetNumeric(float64(alterId))
user.MustKey("security").SetString(security) user.MustKey("security").SetString(security)
var experiments string var experiments string
@@ -193,7 +191,7 @@ func testVMessInboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, al
Users: []option.VMessUser{ Users: []option.VMessUser{
{ {
Name: "sekai", Name: "sekai",
UUID: uuid.String(), UUID: userId.String(),
AlterId: alterId, AlterId: alterId,
}, },
}, },
@@ -205,7 +203,8 @@ func testVMessInboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, al
testSuitSimple(t, clientPort, testPort) testSuitSimple(t, clientPort, testPort)
} }
func testVMessOutboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, globalPadding bool, authenticatedLength bool, alterId int) { func testVMessOutboundWithV2Ray(t *testing.T, security string, globalPadding bool, authenticatedLength bool, alterId int) {
user := newUUID()
content, err := os.ReadFile("config/vmess-server.json") content, err := os.ReadFile("config/vmess-server.json")
require.NoError(t, err) require.NoError(t, err)
config, err := ajson.Unmarshal(content) config, err := ajson.Unmarshal(content)
@@ -213,7 +212,7 @@ func testVMessOutboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, g
inbound := config.MustKey("inbounds").MustIndex(0) inbound := config.MustKey("inbounds").MustIndex(0)
inbound.MustKey("port").SetNumeric(float64(serverPort)) inbound.MustKey("port").SetNumeric(float64(serverPort))
inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("id").SetString(uuid.String()) inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("id").SetString(user.String())
inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("alterId").SetNumeric(float64(alterId)) inbound.MustKey("settings").MustKey("clients").MustIndex(0).MustKey("alterId").SetNumeric(float64(alterId))
content, err = ajson.Marshal(config) content, err = ajson.Marshal(config)
@@ -248,7 +247,7 @@ func testVMessOutboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, g
ServerPort: serverPort, ServerPort: serverPort,
}, },
Security: security, Security: security,
UUID: uuid.String(), UUID: user.String(),
GlobalPadding: globalPadding, GlobalPadding: globalPadding,
AuthenticatedLength: authenticatedLength, AuthenticatedLength: authenticatedLength,
AlterId: alterId, AlterId: alterId,
@@ -256,10 +255,11 @@ func testVMessOutboundWithV2Ray(t *testing.T, security string, uuid uuid.UUID, g
}, },
}, },
}) })
testSuitSimple(t, clientPort, testPort) testSuit(t, clientPort, testPort)
} }
func testVMessSelf(t *testing.T, security string, uuid uuid.UUID, alterId int, globalPadding bool, authenticatedLength bool, packetAddr bool) { func testVMessSelf(t *testing.T, security string, alterId int, globalPadding bool, authenticatedLength bool, packetAddr bool) {
user := newUUID()
startInstance(t, option.Options{ startInstance(t, option.Options{
Inbounds: []option.Inbound{ Inbounds: []option.Inbound{
{ {
@@ -282,7 +282,7 @@ func testVMessSelf(t *testing.T, security string, uuid uuid.UUID, alterId int, g
Users: []option.VMessUser{ Users: []option.VMessUser{
{ {
Name: "sekai", Name: "sekai",
UUID: uuid.String(), UUID: user.String(),
AlterId: alterId, AlterId: alterId,
}, },
}, },
@@ -302,7 +302,7 @@ func testVMessSelf(t *testing.T, security string, uuid uuid.UUID, alterId int, g
ServerPort: serverPort, ServerPort: serverPort,
}, },
Security: security, Security: security,
UUID: uuid.String(), UUID: user.String(),
AlterId: alterId, AlterId: alterId,
GlobalPadding: globalPadding, GlobalPadding: globalPadding,
AuthenticatedLength: authenticatedLength, AuthenticatedLength: authenticatedLength,

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"net/netip" "net/netip"
"os"
"testing" "testing"
"time" "time"
@@ -50,49 +49,3 @@ func TestWireGuard(t *testing.T) {
}) })
testSuitWg(t, clientPort, testPort) testSuitWg(t, clientPort, testPort)
} }
func TestWireGuardSystem(t *testing.T) {
if os.Getuid() != 0 {
t.Skip("requires root")
}
startDockerContainer(t, DockerOptions{
Image: ImageBoringTun,
Cap: []string{"MKNOD", "NET_ADMIN", "NET_RAW"},
Ports: []uint16{serverPort, testPort},
Bind: map[string]string{
"wireguard.conf": "/etc/wireguard/wg0.conf",
},
Cmd: []string{"wg0"},
})
time.Sleep(5 * time.Second)
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.TypeWireGuard,
WireGuardOptions: option.WireGuardOutboundOptions{
InterfaceName: "wg",
ServerOptions: option.ServerOptions{
Server: "127.0.0.1",
ServerPort: serverPort,
},
LocalAddress: []option.ListenPrefix{option.ListenPrefix(netip.MustParsePrefix("10.0.0.2/32"))},
PrivateKey: "qGnwlkZljMxeECW8fbwAWdvgntnbK7B8UmMFl3zM0mk=",
PeerPublicKey: "QsdcBm+oJw2oNv0cIFXLIq1E850lgTBonup4qnKEQBg=",
},
},
},
})
time.Sleep(10 * time.Second)
testSuitWg(t, clientPort, testPort)
}

View File

@@ -0,0 +1,9 @@
package obfs
type Base struct {
Host string
Port int
Key []byte
IVSize int
Param string
}

View File

@@ -0,0 +1,9 @@
package obfs
func init() {
register("http_post", newHTTPPost, 0)
}
func newHTTPPost(b *Base) Obfs {
return &httpObfs{Base: b, post: true}
}

View File

@@ -0,0 +1,405 @@
package obfs
import (
"bytes"
"encoding/hex"
"io"
"math/rand"
"net"
"strconv"
"strings"
"github.com/Dreamacro/clash/common/pool"
)
func init() {
register("http_simple", newHTTPSimple, 0)
}
type httpObfs struct {
*Base
post bool
}
func newHTTPSimple(b *Base) Obfs {
return &httpObfs{Base: b}
}
type httpConn struct {
net.Conn
*httpObfs
hasSentHeader bool
hasRecvHeader bool
buf []byte
}
func (h *httpObfs) StreamConn(c net.Conn) net.Conn {
return &httpConn{Conn: c, httpObfs: h}
}
func (c *httpConn) Read(b []byte) (int, error) {
if c.buf != nil {
n := copy(b, c.buf)
if n == len(c.buf) {
c.buf = nil
} else {
c.buf = c.buf[n:]
}
return n, nil
}
if c.hasRecvHeader {
return c.Conn.Read(b)
}
buf := pool.Get(pool.RelayBufferSize)
defer pool.Put(buf)
n, err := c.Conn.Read(buf)
if err != nil {
return 0, err
}
pos := bytes.Index(buf[:n], []byte("\r\n\r\n"))
if pos == -1 {
return 0, io.EOF
}
c.hasRecvHeader = true
dataLength := n - pos - 4
n = copy(b, buf[4+pos:n])
if dataLength > n {
c.buf = append(c.buf, buf[4+pos+n:4+pos+dataLength]...)
}
return n, nil
}
func (c *httpConn) Write(b []byte) (int, error) {
if c.hasSentHeader {
return c.Conn.Write(b)
}
// 30: head length
headLength := c.IVSize + 30
bLength := len(b)
headDataLength := bLength
if bLength-headLength > 64 {
headDataLength = headLength + rand.Intn(65)
}
headData := b[:headDataLength]
b = b[headDataLength:]
var body string
host := c.Host
if len(c.Param) > 0 {
pos := strings.Index(c.Param, "#")
if pos != -1 {
body = strings.ReplaceAll(c.Param[pos+1:], "\n", "\r\n")
body = strings.ReplaceAll(body, "\\n", "\r\n")
host = c.Param[:pos]
} else {
host = c.Param
}
}
hosts := strings.Split(host, ",")
host = hosts[rand.Intn(len(hosts))]
buf := pool.GetBuffer()
defer pool.PutBuffer(buf)
if c.post {
buf.WriteString("POST /")
} else {
buf.WriteString("GET /")
}
packURLEncodedHeadData(buf, headData)
buf.WriteString(" HTTP/1.1\r\nHost: " + host)
if c.Port != 80 {
buf.WriteString(":" + strconv.Itoa(c.Port))
}
buf.WriteString("\r\n")
if len(body) > 0 {
buf.WriteString(body + "\r\n\r\n")
} else {
buf.WriteString("User-Agent: ")
buf.WriteString(userAgent[rand.Intn(len(userAgent))])
buf.WriteString("\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Encoding: gzip, deflate\r\n")
if c.post {
packBoundary(buf)
}
buf.WriteString("DNT: 1\r\nConnection: keep-alive\r\n\r\n")
}
buf.Write(b)
_, err := c.Conn.Write(buf.Bytes())
if err != nil {
return 0, nil
}
c.hasSentHeader = true
return bLength, nil
}
func packURLEncodedHeadData(buf *bytes.Buffer, data []byte) {
dataLength := len(data)
for i := 0; i < dataLength; i++ {
buf.WriteRune('%')
buf.WriteString(hex.EncodeToString(data[i : i+1]))
}
}
func packBoundary(buf *bytes.Buffer) {
buf.WriteString("Content-Type: multipart/form-data; boundary=")
set := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for i := 0; i < 32; i++ {
buf.WriteByte(set[rand.Intn(62)])
}
buf.WriteString("\r\n")
}
var userAgent = []string{
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; Moto C Build/NRD90M.059) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1.1; SM-J120M Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; Moto G (5) Build/NPPS25.137-93-14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G570M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; CAM-L03 Build/HUAWEICAM-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3",
"Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36",
"Mozilla/5.0 (X11; Datanyze; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1.1; SM-J111M Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-J700M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36",
"Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Slackware/Chrome/12.0.742.100 Safari/534.30",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
"Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX3 Build/HUAWEIWAS-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.1805 Safari/537.36 MVisionPlayer/1.0.0.0",
"Mozilla/5.0 (Linux; Android 7.0; TRT-LX3 Build/HUAWEITRT-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; vivo 1610 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36",
"Mozilla/5.0 (Linux; Android 4.4.2; de-de; SAMSUNG GT-I9195 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
"Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX3 Build/HUAWEIANE-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (X11; U; Linux i586; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G610M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-J500M Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; vivo 1606 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G610M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.1; vivo 1716 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G570M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; MYA-L22 Build/HUAWEIMYA-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; TRT-LX2 Build/HUAWEITRT-LX2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17",
"Mozilla/5.0 (Linux; Android 6.0; CAM-L21 Build/HUAWEICAM-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24",
"Mozilla/5.0 (Linux; Android 7.1.2; Redmi 4X Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
"Mozilla/5.0 (Linux; Android 4.4.2; SM-G7102 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L22 Build/HUAWEICUN-L22; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1.1; A37fw Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-J730GM Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.1.2; Redmi Note 5A Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36",
"Mozilla/5.0 (Unknown; Linux) AppleWebKit/538.1 (KHTML, like Gecko) Chrome/v1.0.0 Safari/538.1",
"Mozilla/5.0 (Linux; Android 7.0; BLL-L22 Build/HUAWEIBLL-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-J710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.1.1; CPH1723 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
"Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX3 Build/HUAWEIFIG-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.1; Mi A1 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36 MVisionPlayer/1.0.0.0",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.93 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; CPH1607 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; vivo 1603 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; Redmi 4A Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.116 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; vivo 1713 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
}

View File

@@ -0,0 +1,42 @@
package obfs
import (
"errors"
"fmt"
"net"
)
var (
errTLS12TicketAuthIncorrectMagicNumber = errors.New("tls1.2_ticket_auth incorrect magic number")
errTLS12TicketAuthTooShortData = errors.New("tls1.2_ticket_auth too short data")
errTLS12TicketAuthHMACError = errors.New("tls1.2_ticket_auth hmac verifying failed")
)
type authData struct {
clientID [32]byte
}
type Obfs interface {
StreamConn(net.Conn) net.Conn
}
type obfsCreator func(b *Base) Obfs
var obfsList = make(map[string]struct {
overhead int
new obfsCreator
})
func register(name string, c obfsCreator, o int) {
obfsList[name] = struct {
overhead int
new obfsCreator
}{overhead: o, new: c}
}
func PickObfs(name string, b *Base) (Obfs, int, error) {
if choice, ok := obfsList[name]; ok {
return choice.new(b), choice.overhead, nil
}
return nil, 0, fmt.Errorf("Obfs %s not supported", name)
}

View File

@@ -0,0 +1,15 @@
package obfs
import "net"
type plain struct{}
func init() {
register("plain", newPlain, 0)
}
func newPlain(b *Base) Obfs {
return &plain{}
}
func (p *plain) StreamConn(c net.Conn) net.Conn { return c }

View File

@@ -0,0 +1,71 @@
package obfs
import (
"encoding/binary"
"hash/crc32"
"math/rand"
"net"
"github.com/Dreamacro/clash/common/pool"
)
func init() {
register("random_head", newRandomHead, 0)
}
type randomHead struct {
*Base
}
func newRandomHead(b *Base) Obfs {
return &randomHead{Base: b}
}
type randomHeadConn struct {
net.Conn
*randomHead
hasSentHeader bool
rawTransSent bool
rawTransRecv bool
buf []byte
}
func (r *randomHead) StreamConn(c net.Conn) net.Conn {
return &randomHeadConn{Conn: c, randomHead: r}
}
func (c *randomHeadConn) Read(b []byte) (int, error) {
if c.rawTransRecv {
return c.Conn.Read(b)
}
buf := pool.Get(pool.RelayBufferSize)
defer pool.Put(buf)
c.Conn.Read(buf)
c.rawTransRecv = true
c.Write(nil)
return 0, nil
}
func (c *randomHeadConn) Write(b []byte) (int, error) {
if c.rawTransSent {
return c.Conn.Write(b)
}
c.buf = append(c.buf, b...)
if !c.hasSentHeader {
c.hasSentHeader = true
dataLength := rand.Intn(96) + 4
buf := pool.Get(dataLength + 4)
defer pool.Put(buf)
rand.Read(buf[:dataLength])
binary.LittleEndian.PutUint32(buf[dataLength:], 0xffffffff-crc32.ChecksumIEEE(buf[:dataLength]))
_, err := c.Conn.Write(buf)
return len(b), err
}
if c.rawTransRecv {
_, err := c.Conn.Write(c.buf)
c.buf = nil
c.rawTransSent = true
return len(b), err
}
return len(b), nil
}

View File

@@ -0,0 +1,226 @@
package obfs
import (
"bytes"
"crypto/hmac"
"encoding/binary"
"math/rand"
"net"
"strings"
"time"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/transport/ssr/tools"
)
func init() {
register("tls1.2_ticket_auth", newTLS12Ticket, 5)
register("tls1.2_ticket_fastauth", newTLS12Ticket, 5)
}
type tls12Ticket struct {
*Base
*authData
}
func newTLS12Ticket(b *Base) Obfs {
r := &tls12Ticket{Base: b, authData: &authData{}}
rand.Read(r.clientID[:])
return r
}
type tls12TicketConn struct {
net.Conn
*tls12Ticket
handshakeStatus int
decoded bytes.Buffer
underDecoded bytes.Buffer
sendBuf bytes.Buffer
}
func (t *tls12Ticket) StreamConn(c net.Conn) net.Conn {
return &tls12TicketConn{Conn: c, tls12Ticket: t}
}
func (c *tls12TicketConn) Read(b []byte) (int, error) {
if c.decoded.Len() > 0 {
return c.decoded.Read(b)
}
buf := pool.Get(pool.RelayBufferSize)
defer pool.Put(buf)
n, err := c.Conn.Read(buf)
if err != nil {
return 0, err
}
if c.handshakeStatus == 8 {
c.underDecoded.Write(buf[:n])
for c.underDecoded.Len() > 5 {
if !bytes.Equal(c.underDecoded.Bytes()[:3], []byte{0x17, 3, 3}) {
c.underDecoded.Reset()
return 0, errTLS12TicketAuthIncorrectMagicNumber
}
size := int(binary.BigEndian.Uint16(c.underDecoded.Bytes()[3:5]))
if c.underDecoded.Len() < 5+size {
break
}
c.underDecoded.Next(5)
c.decoded.Write(c.underDecoded.Next(size))
}
n, _ = c.decoded.Read(b)
return n, nil
}
if n < 11+32+1+32 {
return 0, errTLS12TicketAuthTooShortData
}
if !hmac.Equal(buf[33:43], c.hmacSHA1(buf[11:33])[:10]) || !hmac.Equal(buf[n-10:n], c.hmacSHA1(buf[:n-10])[:10]) {
return 0, errTLS12TicketAuthHMACError
}
c.Write(nil)
return 0, nil
}
func (c *tls12TicketConn) Write(b []byte) (int, error) {
length := len(b)
if c.handshakeStatus == 8 {
buf := pool.GetBuffer()
defer pool.PutBuffer(buf)
for len(b) > 2048 {
size := rand.Intn(4096) + 100
if len(b) < size {
size = len(b)
}
packData(buf, b[:size])
b = b[size:]
}
if len(b) > 0 {
packData(buf, b)
}
_, err := c.Conn.Write(buf.Bytes())
if err != nil {
return 0, err
}
return length, nil
}
if len(b) > 0 {
packData(&c.sendBuf, b)
}
if c.handshakeStatus == 0 {
c.handshakeStatus = 1
data := pool.GetBuffer()
defer pool.PutBuffer(data)
data.Write([]byte{3, 3})
c.packAuthData(data)
data.WriteByte(0x20)
data.Write(c.clientID[:])
data.Write([]byte{0x00, 0x1c, 0xc0, 0x2b, 0xc0, 0x2f, 0xcc, 0xa9, 0xcc, 0xa8, 0xcc, 0x14, 0xcc, 0x13, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0x0a})
data.Write([]byte{0x1, 0x0})
ext := pool.GetBuffer()
defer pool.PutBuffer(ext)
host := c.getHost()
ext.Write([]byte{0xff, 0x01, 0x00, 0x01, 0x00})
packSNIData(ext, host)
ext.Write([]byte{0, 0x17, 0, 0})
c.packTicketBuf(ext, host)
ext.Write([]byte{0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x06, 0x01, 0x06, 0x03, 0x05, 0x01, 0x05, 0x03, 0x04, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x03, 0x02, 0x01, 0x02, 0x03})
ext.Write([]byte{0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00})
ext.Write([]byte{0x00, 0x12, 0x00, 0x00})
ext.Write([]byte{0x75, 0x50, 0x00, 0x00})
ext.Write([]byte{0x00, 0x0b, 0x00, 0x02, 0x01, 0x00})
ext.Write([]byte{0x00, 0x0a, 0x00, 0x06, 0x00, 0x04, 0x00, 0x17, 0x00, 0x18})
binary.Write(data, binary.BigEndian, uint16(ext.Len()))
data.ReadFrom(ext)
ret := pool.GetBuffer()
defer pool.PutBuffer(ret)
ret.Write([]byte{0x16, 3, 1})
binary.Write(ret, binary.BigEndian, uint16(data.Len()+4))
ret.Write([]byte{1, 0})
binary.Write(ret, binary.BigEndian, uint16(data.Len()))
ret.ReadFrom(data)
_, err := c.Conn.Write(ret.Bytes())
if err != nil {
return 0, err
}
return length, nil
} else if c.handshakeStatus == 1 && len(b) == 0 {
buf := pool.GetBuffer()
defer pool.PutBuffer(buf)
buf.Write([]byte{0x14, 3, 3, 0, 1, 1, 0x16, 3, 3, 0, 0x20})
tools.AppendRandBytes(buf, 22)
buf.Write(c.hmacSHA1(buf.Bytes())[:10])
buf.ReadFrom(&c.sendBuf)
c.handshakeStatus = 8
_, err := c.Conn.Write(buf.Bytes())
return 0, err
}
return length, nil
}
func packData(buf *bytes.Buffer, data []byte) {
buf.Write([]byte{0x17, 3, 3})
binary.Write(buf, binary.BigEndian, uint16(len(data)))
buf.Write(data)
}
func (t *tls12Ticket) packAuthData(buf *bytes.Buffer) {
binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix()))
tools.AppendRandBytes(buf, 18)
buf.Write(t.hmacSHA1(buf.Bytes()[buf.Len()-22:])[:10])
}
func packSNIData(buf *bytes.Buffer, u string) {
len := uint16(len(u))
buf.Write([]byte{0, 0})
binary.Write(buf, binary.BigEndian, len+5)
binary.Write(buf, binary.BigEndian, len+3)
buf.WriteByte(0)
binary.Write(buf, binary.BigEndian, len)
buf.WriteString(u)
}
func (c *tls12TicketConn) packTicketBuf(buf *bytes.Buffer, u string) {
length := 16 * (rand.Intn(17) + 8)
buf.Write([]byte{0, 0x23})
binary.Write(buf, binary.BigEndian, uint16(length))
tools.AppendRandBytes(buf, length)
}
func (t *tls12Ticket) hmacSHA1(data []byte) []byte {
key := pool.Get(len(t.Key) + 32)
defer pool.Put(key)
copy(key, t.Key)
copy(key[len(t.Key):], t.clientID[:])
sha1Data := tools.HmacSHA1(key, data)
return sha1Data[:10]
}
func (t *tls12Ticket) getHost() string {
host := t.Param
if len(host) == 0 {
host = t.Host
}
if len(host) > 0 && host[len(host)-1] >= '0' && host[len(host)-1] <= '9' {
host = ""
}
hosts := strings.Split(host, ",")
host = hosts[rand.Intn(len(hosts))]
return host
}

View File

@@ -0,0 +1,18 @@
package protocol
import "github.com/Dreamacro/clash/transport/ssr/tools"
func init() {
register("auth_aes128_md5", newAuthAES128MD5, 9)
}
func newAuthAES128MD5(b *Base) Protocol {
a := &authAES128{
Base: b,
authData: &authData{},
authAES128Function: &authAES128Function{salt: "auth_aes128_md5", hmac: tools.HmacMD5, hashDigest: tools.MD5Sum},
userData: &userData{},
}
a.initUserData()
return a
}

Some files were not shown because too many files have changed in this diff Show More