Compare commits
77 Commits
v1.0-beta2
...
v1.1-beta4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1db7f45370 | ||
|
|
b271e19a23 | ||
|
|
79b6bdfda1 | ||
|
|
38088f28b0 | ||
|
|
dfb8b5f2fa | ||
|
|
9913e0e025 | ||
|
|
ce567ffdde | ||
|
|
5a9913eca5 | ||
|
|
eaf1ace681 | ||
|
|
a2d1f89922 | ||
|
|
7e09beb0c3 | ||
|
|
ebf5cbf1b9 | ||
|
|
d727710d60 | ||
|
|
0e31aeea00 | ||
|
|
2f437a0382 | ||
|
|
3ad4370fa5 | ||
|
|
a3bb9c2877 | ||
|
|
ee7e976084 | ||
|
|
099358d3e5 | ||
|
|
5297273937 | ||
|
|
80cfc9a25b | ||
|
|
2ae4da524e | ||
|
|
bbe7f28545 | ||
|
|
78ddd497ee | ||
|
|
8d044232af | ||
|
|
aa7e85caa7 | ||
|
|
46a8f24400 | ||
|
|
87bc292296 | ||
|
|
ac539ace70 | ||
|
|
a15b13978f | ||
|
|
0c975db0a6 | ||
|
|
cb4fea0240 | ||
|
|
8e7957d440 | ||
|
|
f7bed32c6f | ||
|
|
ef7f2d82c0 | ||
|
|
7aa97a332e | ||
|
|
7c30dde96b | ||
|
|
9cef2a0a8f | ||
|
|
f376683fc3 | ||
|
|
4b61d6e875 | ||
|
|
7d83e350fd | ||
|
|
500ba69548 | ||
|
|
9a422549b1 | ||
|
|
3b48fa455e | ||
|
|
ef013e0639 | ||
|
|
8f8437a88d | ||
|
|
1b091c9b07 | ||
|
|
4801b6f057 | ||
|
|
9078bc2de5 | ||
|
|
b69464dfe9 | ||
|
|
62fa48293a | ||
|
|
b206d0889b | ||
|
|
ee691d81bf | ||
|
|
56876a67cc | ||
|
|
4a0df713aa | ||
|
|
ef801cbfbe | ||
|
|
9378fc88d2 | ||
|
|
f46bfcc3d8 | ||
|
|
ccdb238843 | ||
|
|
f1f61b4e2b | ||
|
|
a44cb745d9 | ||
|
|
f5f5cb023c | ||
|
|
5813e0ce7a | ||
|
|
5a9c2b1e80 | ||
|
|
bda34fdb3b | ||
|
|
426b677eb8 | ||
|
|
67c7e9fd86 | ||
|
|
d8028a8632 | ||
|
|
374743d022 | ||
|
|
cd98ea5008 | ||
|
|
dbda0ed98a | ||
|
|
f5e0ead01c | ||
|
|
44818701bc | ||
|
|
e0f7387dff | ||
|
|
d440a01792 | ||
|
|
665c84ee42 | ||
|
|
e0de96eb4c |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -31,7 +31,7 @@ body:
|
|||||||
<details>
|
<details>
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ sing-box --version
|
$ sing-box version
|
||||||
# Paste output here
|
# Paste output here
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
7
.github/update_dependencies.sh
vendored
7
.github/update_dependencies.sh
vendored
@@ -1,10 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
PROJECTS=$(dirname "$0")/../..
|
PROJECTS=$(dirname "$0")/../..
|
||||||
|
go get -x github.com/sagernet/$1@$(git -C $PROJECTS/$1 rev-parse HEAD)
|
||||||
go get -x github.com/sagernet/sing@$(git -C $PROJECTS/sing rev-parse HEAD)
|
|
||||||
go get -x github.com/sagernet/sing-dns@$(git -C $PROJECTS/sing-dns rev-parse HEAD)
|
|
||||||
go get -x github.com/sagernet/sing-tun@$(git -C $PROJECTS/sing-tun rev-parse HEAD)
|
|
||||||
go get -x github.com/sagernet/sing-shadowsocks@$(git -C $PROJECTS/sing-shadowsocks rev-parse HEAD)
|
|
||||||
go get -x github.com/sagernet/sing-vmess@$(git -C $PROJECTS/sing-vmess rev-parse HEAD)
|
|
||||||
go mod tidy
|
go mod tidy
|
||||||
|
|||||||
4
.github/workflows/debug.yml
vendored
4
.github/workflows/debug.yml
vendored
@@ -3,14 +3,18 @@ name: Debug build
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
- main
|
||||||
- dev
|
- dev
|
||||||
|
- dev-next
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
- '.github/**'
|
- '.github/**'
|
||||||
- '!.github/workflows/debug.yml'
|
- '!.github/workflows/debug.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
|
- main
|
||||||
- dev
|
- dev
|
||||||
|
- dev-next
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|||||||
2
.github/workflows/mkdocs.yml
vendored
2
.github/workflows/mkdocs.yml
vendored
@@ -2,7 +2,7 @@ name: Generate Documents
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- dev
|
||||||
paths:
|
paths:
|
||||||
- docs/**
|
- docs/**
|
||||||
- .github/workflows/mkdocs.yml
|
- .github/workflows/mkdocs.yml
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ linters:
|
|||||||
- staticcheck
|
- staticcheck
|
||||||
- paralleltest
|
- paralleltest
|
||||||
|
|
||||||
|
run:
|
||||||
|
skip-dirs:
|
||||||
|
- transport/cloudflaretls
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
# gci:
|
# gci:
|
||||||
# sections:
|
# sections:
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ ENV GOPROXY ${GOPROXY}
|
|||||||
ENV CGO_ENABLED=0
|
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 HEAD) \
|
&& export COMMIT=$(git rev-parse --short HEAD) \
|
||||||
&& go build -v -trimpath -tags 'with_quic,with_acme,with_wireguard,with_clash_api' \
|
&& go build -v -trimpath -tags 'no_gvisor,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 "-X github.com/sagernet/sing-box/constant.Commit=${COMMIT} -w -s -buildid=" \
|
||||||
./cmd/sing-box
|
./cmd/sing-box
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -64,7 +64,7 @@ test:
|
|||||||
@go test -v . && \
|
@go test -v . && \
|
||||||
pushd test && \
|
pushd test && \
|
||||||
go mod tidy && \
|
go mod tidy && \
|
||||||
go test -v -tags with_quic,with_wireguard,with_grpc . && \
|
go test -v -tags with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_shadowsocksr . && \
|
||||||
popd
|
popd
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
@@ -9,18 +9,22 @@ import (
|
|||||||
|
|
||||||
type ClashServer interface {
|
type ClashServer interface {
|
||||||
Service
|
Service
|
||||||
TrafficController
|
Mode() string
|
||||||
|
StoreSelected() bool
|
||||||
|
CacheFile() ClashCacheFile
|
||||||
|
RoutedConnection(ctx context.Context, conn net.Conn, metadata InboundContext, matchedRule Rule) (net.Conn, Tracker)
|
||||||
|
RoutedPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext, matchedRule Rule) (N.PacketConn, Tracker)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClashCacheFile interface {
|
||||||
|
LoadSelected(group string) string
|
||||||
|
StoreSelected(group string, selected string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tracker interface {
|
type Tracker interface {
|
||||||
Leave()
|
Leave()
|
||||||
}
|
}
|
||||||
|
|
||||||
type TrafficController interface {
|
|
||||||
RoutedConnection(ctx context.Context, conn net.Conn, metadata InboundContext, matchedRule Rule) (net.Conn, Tracker)
|
|
||||||
RoutedPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext, matchedRule Rule) (N.PacketConn, Tracker)
|
|
||||||
}
|
|
||||||
|
|
||||||
type OutboundGroup interface {
|
type OutboundGroup interface {
|
||||||
Now() string
|
Now() string
|
||||||
All() []string
|
All() []string
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package adapter
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/process"
|
"github.com/sagernet/sing-box/common/process"
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Inbound interface {
|
type Inbound interface {
|
||||||
@@ -15,6 +17,13 @@ type Inbound interface {
|
|||||||
Tag() string
|
Tag() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InjectableInbound interface {
|
||||||
|
Inbound
|
||||||
|
Network() []string
|
||||||
|
NewConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error
|
||||||
|
NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
|
||||||
|
}
|
||||||
|
|
||||||
type InboundContext struct {
|
type InboundContext struct {
|
||||||
Inbound string
|
Inbound string
|
||||||
InboundType string
|
InboundType string
|
||||||
@@ -29,6 +38,8 @@ type InboundContext struct {
|
|||||||
|
|
||||||
// cache
|
// cache
|
||||||
|
|
||||||
|
InboundDetour string
|
||||||
|
LastInbound string
|
||||||
OriginDestination M.Socksaddr
|
OriginDestination M.Socksaddr
|
||||||
DomainStrategy dns.DomainStrategy
|
DomainStrategy dns.DomainStrategy
|
||||||
SniffEnabled bool
|
SniffEnabled bool
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ type Router interface {
|
|||||||
InterfaceMonitor() tun.DefaultInterfaceMonitor
|
InterfaceMonitor() tun.DefaultInterfaceMonitor
|
||||||
PackageManager() tun.PackageManager
|
PackageManager() tun.PackageManager
|
||||||
Rules() []Rule
|
Rules() []Rule
|
||||||
SetTrafficController(controller TrafficController)
|
|
||||||
|
ClashServer() ClashServer
|
||||||
|
SetClashServer(controller ClashServer)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
|
|||||||
4
box.go
4
box.go
@@ -138,7 +138,7 @@ func New(ctx context.Context, options option.Options) (*Box, error) {
|
|||||||
}
|
}
|
||||||
outbounds = append(outbounds, out)
|
outbounds = append(outbounds, out)
|
||||||
}
|
}
|
||||||
err = router.Initialize(outbounds, func() adapter.Outbound {
|
err = router.Initialize(inbounds, outbounds, func() adapter.Outbound {
|
||||||
out, oErr := outbound.New(ctx, router, logFactory.NewLogger("outbound/direct"), option.Outbound{Type: "direct", Tag: "default"})
|
out, oErr := outbound.New(ctx, router, logFactory.NewLogger("outbound/direct"), option.Outbound{Type: "direct", Tag: "default"})
|
||||||
common.Must(oErr)
|
common.Must(oErr)
|
||||||
outbounds = append(outbounds, out)
|
outbounds = append(outbounds, out)
|
||||||
@@ -154,7 +154,7 @@ func New(ctx context.Context, options option.Options) (*Box, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "create clash api server")
|
return nil, E.Cause(err, "create clash api server")
|
||||||
}
|
}
|
||||||
router.SetTrafficController(clashServer)
|
router.SetClashServer(clashServer)
|
||||||
}
|
}
|
||||||
return &Box{
|
return &Box{
|
||||||
router: router,
|
router: router,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func format() error {
|
|||||||
return E.Cause(err, "read config")
|
return E.Cause(err, "read config")
|
||||||
}
|
}
|
||||||
var options option.Options
|
var options option.Options
|
||||||
err = json.Unmarshal(configContent, &options)
|
err = options.UnmarshalJSON(configContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "decode config")
|
return E.Cause(err, "decode config")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box"
|
"github.com/sagernet/sing-box"
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"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"
|
||||||
@@ -46,7 +45,7 @@ func readConfig() (option.Options, error) {
|
|||||||
return option.Options{}, E.Cause(err, "read config")
|
return option.Options{}, E.Cause(err, "read config")
|
||||||
}
|
}
|
||||||
var options option.Options
|
var options option.Options
|
||||||
err = json.Unmarshal(configContent, &options)
|
err = options.UnmarshalJSON(configContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return option.Options{}, E.Cause(err, "decode config")
|
return option.Options{}, E.Cause(err, "decode config")
|
||||||
}
|
}
|
||||||
|
|||||||
62
common/baderror/baderror.go
Normal file
62
common/baderror/baderror.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package baderror
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Contains(err error, msgList ...string) bool {
|
||||||
|
for _, msg := range msgList {
|
||||||
|
if strings.Contains(err.Error(), msg) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapH2(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = E.Unwrap(err)
|
||||||
|
if err == io.ErrUnexpectedEOF {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
|
if Contains(err, "client disconnected", "body closed by handler") {
|
||||||
|
return net.ErrClosed
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapGRPC(err error) error {
|
||||||
|
// grpc uses stupid internal error types
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if Contains(err, "EOF") {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
|
if Contains(err, "Canceled") {
|
||||||
|
return context.Canceled
|
||||||
|
}
|
||||||
|
if Contains(err,
|
||||||
|
"the client connection is closing",
|
||||||
|
"server closed the stream without sending trailers") {
|
||||||
|
return net.ErrClosed
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func WrapQUIC(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if Contains(err, "canceled with error code 0") {
|
||||||
|
return net.ErrClosed
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing/common/control"
|
"github.com/sagernet/sing/common/control"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
@@ -111,6 +112,10 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
|
|||||||
if options.TCPFastOpen {
|
if options.TCPFastOpen {
|
||||||
warnTFOOnUnsupportedPlatform.Check()
|
warnTFOOnUnsupportedPlatform.Check()
|
||||||
}
|
}
|
||||||
|
if !options.UDPFragment {
|
||||||
|
dialer.Control = control.Append(dialer.Control, control.DisableUDPFragment())
|
||||||
|
listener.Control = control.Append(listener.Control, control.DisableUDPFragment())
|
||||||
|
}
|
||||||
var bindUDPAddr string
|
var bindUDPAddr string
|
||||||
udpDialer := dialer
|
udpDialer := dialer
|
||||||
var bindAddress netip.Addr
|
var bindAddress netip.Addr
|
||||||
@@ -130,6 +135,9 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDialer) DialContext(ctx context.Context, network string, address M.Socksaddr) (net.Conn, error) {
|
func (d *DefaultDialer) DialContext(ctx context.Context, network string, address M.Socksaddr) (net.Conn, error) {
|
||||||
|
if !address.IsValid() {
|
||||||
|
return nil, E.New("invalid address")
|
||||||
|
}
|
||||||
switch N.NetworkName(network) {
|
switch N.NetworkName(network) {
|
||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
return d.udpDialer.DialContext(ctx, network, address.String())
|
return d.udpDialer.DialContext(ctx, network, address.String())
|
||||||
|
|||||||
@@ -10,15 +10,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func New(router adapter.Router, options option.DialerOptions) N.Dialer {
|
func New(router adapter.Router, options option.DialerOptions) N.Dialer {
|
||||||
|
var dialer N.Dialer
|
||||||
if options.Detour == "" {
|
if options.Detour == "" {
|
||||||
return NewDefault(router, options)
|
dialer = NewDefault(router, options)
|
||||||
} else {
|
} else {
|
||||||
return NewDetour(router, options.Detour)
|
dialer = NewDetour(router, options.Detour)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func NewOutbound(router adapter.Router, options option.OutboundDialerOptions) N.Dialer {
|
|
||||||
dialer := New(router, options.DialerOptions)
|
|
||||||
domainStrategy := dns.DomainStrategy(options.DomainStrategy)
|
domainStrategy := dns.DomainStrategy(options.DomainStrategy)
|
||||||
if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" {
|
if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" {
|
||||||
dialer = NewResolveDialer(router, dialer, domainStrategy, time.Duration(options.FallbackDelay))
|
dialer = NewResolveDialer(router, dialer, domainStrategy, time.Duration(options.FallbackDelay))
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func (d *ResolveDialer) DialContext(ctx context.Context, network string, destina
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *ResolveDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (d *ResolveDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
if !destination.IsFqdn() || destination.Fqdn == "" {
|
if !destination.IsFqdn() {
|
||||||
return d.dialer.ListenPacket(ctx, destination)
|
return d.dialer.ListenPacket(ctx, destination)
|
||||||
}
|
}
|
||||||
ctx, metadata := adapter.AppendContext(ctx)
|
ctx, metadata := adapter.AppendContext(ctx)
|
||||||
|
|||||||
128
common/json/comment.go
Normal file
128
common/json/comment.go
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// kanged from v2ray
|
||||||
|
|
||||||
|
type commentFilterState = byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
commentFilterStateContent commentFilterState = iota
|
||||||
|
commentFilterStateEscape
|
||||||
|
commentFilterStateDoubleQuote
|
||||||
|
commentFilterStateDoubleQuoteEscape
|
||||||
|
commentFilterStateSingleQuote
|
||||||
|
commentFilterStateSingleQuoteEscape
|
||||||
|
commentFilterStateComment
|
||||||
|
commentFilterStateSlash
|
||||||
|
commentFilterStateMultilineComment
|
||||||
|
commentFilterStateMultilineCommentStar
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommentFilter struct {
|
||||||
|
br *bufio.Reader
|
||||||
|
state commentFilterState
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCommentFilter(reader io.Reader) io.Reader {
|
||||||
|
return &CommentFilter{br: bufio.NewReader(reader)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *CommentFilter) Read(b []byte) (int, error) {
|
||||||
|
p := b[:0]
|
||||||
|
for len(p) < len(b)-2 {
|
||||||
|
x, err := v.br.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
if len(p) == 0 {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
switch v.state {
|
||||||
|
case commentFilterStateContent:
|
||||||
|
switch x {
|
||||||
|
case '"':
|
||||||
|
v.state = commentFilterStateDoubleQuote
|
||||||
|
p = append(p, x)
|
||||||
|
case '\'':
|
||||||
|
v.state = commentFilterStateSingleQuote
|
||||||
|
p = append(p, x)
|
||||||
|
case '\\':
|
||||||
|
v.state = commentFilterStateEscape
|
||||||
|
case '#':
|
||||||
|
v.state = commentFilterStateComment
|
||||||
|
case '/':
|
||||||
|
v.state = commentFilterStateSlash
|
||||||
|
default:
|
||||||
|
p = append(p, x)
|
||||||
|
}
|
||||||
|
case commentFilterStateEscape:
|
||||||
|
p = append(p, '\\', x)
|
||||||
|
v.state = commentFilterStateContent
|
||||||
|
case commentFilterStateDoubleQuote:
|
||||||
|
switch x {
|
||||||
|
case '"':
|
||||||
|
v.state = commentFilterStateContent
|
||||||
|
p = append(p, x)
|
||||||
|
case '\\':
|
||||||
|
v.state = commentFilterStateDoubleQuoteEscape
|
||||||
|
default:
|
||||||
|
p = append(p, x)
|
||||||
|
}
|
||||||
|
case commentFilterStateDoubleQuoteEscape:
|
||||||
|
p = append(p, '\\', x)
|
||||||
|
v.state = commentFilterStateDoubleQuote
|
||||||
|
case commentFilterStateSingleQuote:
|
||||||
|
switch x {
|
||||||
|
case '\'':
|
||||||
|
v.state = commentFilterStateContent
|
||||||
|
p = append(p, x)
|
||||||
|
case '\\':
|
||||||
|
v.state = commentFilterStateSingleQuoteEscape
|
||||||
|
default:
|
||||||
|
p = append(p, x)
|
||||||
|
}
|
||||||
|
case commentFilterStateSingleQuoteEscape:
|
||||||
|
p = append(p, '\\', x)
|
||||||
|
v.state = commentFilterStateSingleQuote
|
||||||
|
case commentFilterStateComment:
|
||||||
|
if x == '\n' {
|
||||||
|
v.state = commentFilterStateContent
|
||||||
|
p = append(p, '\n')
|
||||||
|
}
|
||||||
|
case commentFilterStateSlash:
|
||||||
|
switch x {
|
||||||
|
case '/':
|
||||||
|
v.state = commentFilterStateComment
|
||||||
|
case '*':
|
||||||
|
v.state = commentFilterStateMultilineComment
|
||||||
|
default:
|
||||||
|
p = append(p, '/', x)
|
||||||
|
}
|
||||||
|
case commentFilterStateMultilineComment:
|
||||||
|
switch x {
|
||||||
|
case '*':
|
||||||
|
v.state = commentFilterStateMultilineCommentStar
|
||||||
|
case '\n':
|
||||||
|
p = append(p, '\n')
|
||||||
|
}
|
||||||
|
case commentFilterStateMultilineCommentStar:
|
||||||
|
switch x {
|
||||||
|
case '/':
|
||||||
|
v.state = commentFilterStateContent
|
||||||
|
case '*':
|
||||||
|
// Stay
|
||||||
|
case '\n':
|
||||||
|
p = append(p, '\n')
|
||||||
|
default:
|
||||||
|
v.state = commentFilterStateMultilineComment
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("Unknown state.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
@@ -22,13 +22,13 @@ func (s *androidSearcher) FindProcessInfo(ctx context.Context, network string, s
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if sharedPackage, loaded := s.packageManager.SharedPackageByID(uid); loaded {
|
if sharedPackage, loaded := s.packageManager.SharedPackageByID(uid % 100000); loaded {
|
||||||
return &Info{
|
return &Info{
|
||||||
UserId: int32(uid),
|
UserId: int32(uid),
|
||||||
PackageName: sharedPackage,
|
PackageName: sharedPackage,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
if packageName, loaded := s.packageManager.PackageByID(uid); loaded {
|
if packageName, loaded := s.packageManager.PackageByID(uid % 100000); loaded {
|
||||||
return &Info{
|
return &Info{
|
||||||
UserId: int32(uid),
|
UserId: int32(uid),
|
||||||
PackageName: packageName,
|
PackageName: packageName,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
type Listener struct {
|
type Listener struct {
|
||||||
net.Listener
|
net.Listener
|
||||||
|
AcceptNoHeader bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) Accept() (net.Conn, error) {
|
func (l *Listener) Accept() (net.Conn, error) {
|
||||||
@@ -22,7 +23,7 @@ func (l *Listener) Accept() (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
bufReader := std_bufio.NewReader(conn)
|
bufReader := std_bufio.NewReader(conn)
|
||||||
header, err := proxyproto.Read(bufReader)
|
header, err := proxyproto.Read(bufReader)
|
||||||
if err != nil {
|
if err != nil && !(l.AcceptNoHeader && err == proxyproto.ErrNoProxyProtocol) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if bufReader.Buffered() > 0 {
|
if bufReader.Buffered() > 0 {
|
||||||
@@ -33,8 +34,11 @@ func (l *Listener) Accept() (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
conn = bufio.NewCachedConn(conn, cache)
|
conn = bufio.NewCachedConn(conn, cache)
|
||||||
}
|
}
|
||||||
return &bufio.AddrConn{Conn: conn, Metadata: M.Metadata{
|
if header != nil {
|
||||||
Source: M.SocksaddrFromNet(header.SourceAddr),
|
return &bufio.AddrConn{Conn: conn, Metadata: M.Metadata{
|
||||||
Destination: M.SocksaddrFromNet(header.DestinationAddr),
|
Source: M.SocksaddrFromNet(header.SourceAddr),
|
||||||
}}, nil
|
Destination: M.SocksaddrFromNet(header.DestinationAddr),
|
||||||
|
}}, nil
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|||||||
64
common/redir/redir_darwin.go
Normal file
64
common/redir/redir_darwin.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package redir
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PF_OUT = 0x2
|
||||||
|
DIOCNATLOOK = 0xc0544417
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetOriginalDestination(conn net.Conn) (destination netip.AddrPort, err error) {
|
||||||
|
fd, err := syscall.Open("/dev/pf", 0, syscall.O_RDONLY)
|
||||||
|
if err != nil {
|
||||||
|
return netip.AddrPort{}, err
|
||||||
|
}
|
||||||
|
defer syscall.Close(fd)
|
||||||
|
nl := struct {
|
||||||
|
saddr, daddr, rsaddr, rdaddr [16]byte
|
||||||
|
sxport, dxport, rsxport, rdxport [4]byte
|
||||||
|
af, proto, protoVariant, direction uint8
|
||||||
|
}{
|
||||||
|
af: syscall.AF_INET,
|
||||||
|
proto: syscall.IPPROTO_TCP,
|
||||||
|
direction: PF_OUT,
|
||||||
|
}
|
||||||
|
la := conn.LocalAddr().(*net.TCPAddr)
|
||||||
|
ra := conn.RemoteAddr().(*net.TCPAddr)
|
||||||
|
raIP, laIP := ra.IP, la.IP
|
||||||
|
raPort, laPort := ra.Port, la.Port
|
||||||
|
switch {
|
||||||
|
case raIP.To4() != nil:
|
||||||
|
copy(nl.saddr[:net.IPv4len], raIP.To4())
|
||||||
|
copy(nl.daddr[:net.IPv4len], laIP.To4())
|
||||||
|
nl.af = syscall.AF_INET
|
||||||
|
default:
|
||||||
|
copy(nl.saddr[:], raIP.To16())
|
||||||
|
copy(nl.daddr[:], laIP.To16())
|
||||||
|
nl.af = syscall.AF_INET6
|
||||||
|
}
|
||||||
|
nl.sxport[0], nl.sxport[1] = byte(raPort>>8), byte(raPort)
|
||||||
|
nl.dxport[0], nl.dxport[1] = byte(laPort>>8), byte(laPort)
|
||||||
|
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), DIOCNATLOOK, uintptr(unsafe.Pointer(&nl))); errno != 0 {
|
||||||
|
return netip.AddrPort{}, errno
|
||||||
|
}
|
||||||
|
|
||||||
|
var ip net.IP
|
||||||
|
switch nl.af {
|
||||||
|
case syscall.AF_INET:
|
||||||
|
ip = make(net.IP, net.IPv4len)
|
||||||
|
copy(ip, nl.rdaddr[:net.IPv4len])
|
||||||
|
case syscall.AF_INET6:
|
||||||
|
ip = make(net.IP, net.IPv6len)
|
||||||
|
copy(ip, nl.rdaddr[:])
|
||||||
|
}
|
||||||
|
port := uint16(nl.rdxport[0])<<8 | uint16(nl.rdxport[1])
|
||||||
|
destination = netip.AddrPortFrom(M.AddrFromIP(ip), port)
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !linux
|
//go:build !linux && !darwin
|
||||||
|
|
||||||
package redir
|
package redir
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type systemProxy struct {
|
|||||||
isMixed bool
|
isMixed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *systemProxy) update() error {
|
func (p *systemProxy) update(event int) error {
|
||||||
newInterfaceName := p.monitor.DefaultInterfaceName(netip.IPv4Unspecified())
|
newInterfaceName := p.monitor.DefaultInterfaceName(netip.IPv4Unspecified())
|
||||||
if p.interfaceName == newInterfaceName {
|
if p.interfaceName == newInterfaceName {
|
||||||
return nil
|
return nil
|
||||||
@@ -88,7 +88,7 @@ func SetSystemProxy(router adapter.Router, port uint16, isMixed bool) (func() er
|
|||||||
port: port,
|
port: port,
|
||||||
isMixed: isMixed,
|
isMixed: isMixed,
|
||||||
}
|
}
|
||||||
err := proxy.update()
|
err := proxy.update(tun.EventInterfaceUpdate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//go:build with_acme
|
//go:build with_acme
|
||||||
|
|
||||||
package inbound
|
package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
//go:build !with_acme
|
//go:build !with_acme
|
||||||
|
|
||||||
package inbound
|
package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
63
common/tls/client.go
Normal file
63
common/tls/client.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewDialerFromOptions(router adapter.Router, dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) {
|
||||||
|
config, err := NewClient(router, serverAddress, options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewDialer(dialer, config), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
|
if options.ECH != nil && options.ECH.Enabled {
|
||||||
|
return newECHClient(router, serverAddress, options)
|
||||||
|
} else if options.UTLS != nil && options.UTLS.Enabled {
|
||||||
|
return newUTLSClient(router, serverAddress, options)
|
||||||
|
} else {
|
||||||
|
return newStdClient(serverAddress, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) {
|
||||||
|
tlsConn := config.Client(conn)
|
||||||
|
ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout)
|
||||||
|
defer cancel()
|
||||||
|
err := tlsConn.HandshakeContext(ctx)
|
||||||
|
return tlsConn, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dialer struct {
|
||||||
|
dialer N.Dialer
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDialer(dialer N.Dialer, config Config) N.Dialer {
|
||||||
|
return &Dialer{dialer, config}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
if network != N.NetworkTCP {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
conn, err := d.dialer.DialContext(ctx, network, destination)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ClientHandshake(ctx, conn, d.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
12
common/tls/common.go
Normal file
12
common/tls/common.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
const (
|
||||||
|
VersionTLS10 = 0x0301
|
||||||
|
VersionTLS11 = 0x0302
|
||||||
|
VersionTLS12 = 0x0303
|
||||||
|
VersionTLS13 = 0x0304
|
||||||
|
|
||||||
|
// Deprecated: SSLv3 is cryptographically broken, and is no longer
|
||||||
|
// supported by this package. See golang.org/issue/32716.
|
||||||
|
VersionSSL30 = 0x0300
|
||||||
|
)
|
||||||
49
common/tls/config.go
Normal file
49
common/tls/config.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
STDConfig = tls.Config
|
||||||
|
STDConn = tls.Conn
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config interface {
|
||||||
|
NextProtos() []string
|
||||||
|
SetNextProtos(nextProto []string)
|
||||||
|
Config() (*STDConfig, error)
|
||||||
|
Client(conn net.Conn) Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerConfig interface {
|
||||||
|
Config
|
||||||
|
adapter.Service
|
||||||
|
Server(conn net.Conn) Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
type Conn interface {
|
||||||
|
net.Conn
|
||||||
|
HandshakeContext(ctx context.Context) error
|
||||||
|
ConnectionState() tls.ConnectionState
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseTLSVersion(version string) (uint16, error) {
|
||||||
|
switch version {
|
||||||
|
case "1.0":
|
||||||
|
return tls.VersionTLS10, nil
|
||||||
|
case "1.1":
|
||||||
|
return tls.VersionTLS11, nil
|
||||||
|
case "1.2":
|
||||||
|
return tls.VersionTLS12, nil
|
||||||
|
case "1.3":
|
||||||
|
return tls.VersionTLS13, nil
|
||||||
|
default:
|
||||||
|
return 0, E.New("unknown tls version:", version)
|
||||||
|
}
|
||||||
|
}
|
||||||
219
common/tls/ech_client.go
Normal file
219
common/tls/ech_client.go
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
//go:build with_ech
|
||||||
|
|
||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
cftls "github.com/sagernet/sing-box/transport/cloudflaretls"
|
||||||
|
"github.com/sagernet/sing-dns"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
|
||||||
|
mDNS "github.com/miekg/dns"
|
||||||
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
|
)
|
||||||
|
|
||||||
|
type echClientConfig struct {
|
||||||
|
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) {
|
||||||
|
return nil, E.New("unsupported usage for ECH")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *echClientConfig) Client(conn net.Conn) Conn {
|
||||||
|
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) {
|
||||||
|
var serverName string
|
||||||
|
if options.ServerName != "" {
|
||||||
|
serverName = options.ServerName
|
||||||
|
} else if serverAddress != "" {
|
||||||
|
if _, err := netip.ParseAddr(serverName); err != nil {
|
||||||
|
serverName = serverAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if serverName == "" && !options.Insecure {
|
||||||
|
return nil, E.New("missing server_name or insecure=true")
|
||||||
|
}
|
||||||
|
|
||||||
|
var tlsConfig cftls.Config
|
||||||
|
if options.DisableSNI {
|
||||||
|
tlsConfig.ServerName = "127.0.0.1"
|
||||||
|
} else {
|
||||||
|
tlsConfig.ServerName = serverName
|
||||||
|
}
|
||||||
|
if options.Insecure {
|
||||||
|
tlsConfig.InsecureSkipVerify = options.Insecure
|
||||||
|
} else if options.DisableSNI {
|
||||||
|
tlsConfig.InsecureSkipVerify = true
|
||||||
|
tlsConfig.VerifyConnection = func(state cftls.ConnectionState) error {
|
||||||
|
verifyOptions := x509.VerifyOptions{
|
||||||
|
DNSName: serverName,
|
||||||
|
Intermediates: x509.NewCertPool(),
|
||||||
|
}
|
||||||
|
for _, cert := range state.PeerCertificates[1:] {
|
||||||
|
verifyOptions.Intermediates.AddCert(cert)
|
||||||
|
}
|
||||||
|
_, err := state.PeerCertificates[0].Verify(verifyOptions)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(options.ALPN) > 0 {
|
||||||
|
tlsConfig.NextProtos = options.ALPN
|
||||||
|
}
|
||||||
|
if options.MinVersion != "" {
|
||||||
|
minVersion, err := ParseTLSVersion(options.MinVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "parse min_version")
|
||||||
|
}
|
||||||
|
tlsConfig.MinVersion = minVersion
|
||||||
|
}
|
||||||
|
if options.MaxVersion != "" {
|
||||||
|
maxVersion, err := ParseTLSVersion(options.MaxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "parse max_version")
|
||||||
|
}
|
||||||
|
tlsConfig.MaxVersion = maxVersion
|
||||||
|
}
|
||||||
|
if options.CipherSuites != nil {
|
||||||
|
find:
|
||||||
|
for _, cipherSuite := range options.CipherSuites {
|
||||||
|
for _, tlsCipherSuite := range cftls.CipherSuites() {
|
||||||
|
if cipherSuite == tlsCipherSuite.Name {
|
||||||
|
tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, tlsCipherSuite.ID)
|
||||||
|
continue find
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, E.New("unknown cipher_suite: ", cipherSuite)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var certificate []byte
|
||||||
|
if options.Certificate != "" {
|
||||||
|
certificate = []byte(options.Certificate)
|
||||||
|
} else if options.CertificatePath != "" {
|
||||||
|
content, err := os.ReadFile(options.CertificatePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "read certificate")
|
||||||
|
}
|
||||||
|
certificate = content
|
||||||
|
}
|
||||||
|
if len(certificate) > 0 {
|
||||||
|
certPool := x509.NewCertPool()
|
||||||
|
if !certPool.AppendCertsFromPEM(certificate) {
|
||||||
|
return nil, E.New("failed to parse certificate:\n\n", certificate)
|
||||||
|
}
|
||||||
|
tlsConfig.RootCAs = certPool
|
||||||
|
}
|
||||||
|
|
||||||
|
// ECH Config
|
||||||
|
|
||||||
|
tlsConfig.ECHEnabled = true
|
||||||
|
tlsConfig.PQSignatureSchemesEnabled = options.ECH.PQSignatureSchemesEnabled
|
||||||
|
tlsConfig.DynamicRecordSizingDisabled = options.ECH.DynamicRecordSizingDisabled
|
||||||
|
if options.ECH.Config != "" {
|
||||||
|
clientConfigContent, err := base64.StdEncoding.DecodeString(options.ECH.Config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientConfig, err := cftls.UnmarshalECHConfigs(clientConfigContent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tlsConfig.ClientECHConfigs = clientConfig
|
||||||
|
} else {
|
||||||
|
tlsConfig.GetClientECHConfigs = fetchECHClientConfig(router)
|
||||||
|
}
|
||||||
|
return &echClientConfig{&tlsConfig}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const typeHTTPS = 65
|
||||||
|
|
||||||
|
func fetchECHClientConfig(router adapter.Router) func(ctx context.Context, serverName string) ([]cftls.ECHConfig, error) {
|
||||||
|
return func(ctx context.Context, serverName string) ([]cftls.ECHConfig, error) {
|
||||||
|
message := &dnsmessage.Message{
|
||||||
|
Header: dnsmessage.Header{
|
||||||
|
RecursionDesired: true,
|
||||||
|
},
|
||||||
|
Questions: []dnsmessage.Question{
|
||||||
|
{
|
||||||
|
Name: dnsmessage.MustNewName(serverName + "."),
|
||||||
|
Type: typeHTTPS,
|
||||||
|
Class: dnsmessage.ClassINET,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
response, err := router.Exchange(ctx, message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if response.RCode != dnsmessage.RCodeSuccess {
|
||||||
|
return nil, dns.RCodeError(response.RCode)
|
||||||
|
}
|
||||||
|
content, err := response.Pack()
|
||||||
|
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) {
|
||||||
|
case *mDNS.HTTPS:
|
||||||
|
for _, value := range resource.Value {
|
||||||
|
if value.Key().String() == "ech" {
|
||||||
|
echConfig, err := base64.StdEncoding.DecodeString(value.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "decode ECH config")
|
||||||
|
}
|
||||||
|
return cftls.UnmarshalECHConfigs(echConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, E.New("unknown resource record type: ", resource.Header().Rrtype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, E.New("no ECH config found")
|
||||||
|
}
|
||||||
|
}
|
||||||
13
common/tls/ech_stub.go
Normal file
13
common/tls/ech_stub.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//go:build !with_ech
|
||||||
|
|
||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newECHClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
|
return nil, E.New(`ECH is not included in this build, rebuild with -tags with_ech`)
|
||||||
|
}
|
||||||
12
common/tls/server.go
Normal file
12
common/tls/server.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/log"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) {
|
||||||
|
return newSTDServer(ctx, logger, options)
|
||||||
|
}
|
||||||
@@ -1,34 +1,26 @@
|
|||||||
package dialer
|
package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"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"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
|
||||||
N "github.com/sagernet/sing/common/network"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TLSDialer struct {
|
type stdClientConfig struct {
|
||||||
dialer N.Dialer
|
|
||||||
config *tls.Config
|
config *tls.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func TLSConfig(serverAddress string, options option.OutboundTLSOptions) (*tls.Config, error) {
|
func newStdClient(serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
if !options.Enabled {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
var serverName string
|
var serverName string
|
||||||
if options.ServerName != "" {
|
if options.ServerName != "" {
|
||||||
serverName = options.ServerName
|
serverName = options.ServerName
|
||||||
} else if serverAddress != "" {
|
} else if serverAddress != "" {
|
||||||
if _, err := netip.ParseAddr(serverName); err == nil {
|
if _, err := netip.ParseAddr(serverName); err != nil {
|
||||||
serverName = serverAddress
|
serverName = serverAddress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,14 +54,14 @@ func TLSConfig(serverAddress string, options option.OutboundTLSOptions) (*tls.Co
|
|||||||
tlsConfig.NextProtos = options.ALPN
|
tlsConfig.NextProtos = options.ALPN
|
||||||
}
|
}
|
||||||
if options.MinVersion != "" {
|
if options.MinVersion != "" {
|
||||||
minVersion, err := option.ParseTLSVersion(options.MinVersion)
|
minVersion, err := ParseTLSVersion(options.MinVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "parse min_version")
|
return nil, E.Cause(err, "parse min_version")
|
||||||
}
|
}
|
||||||
tlsConfig.MinVersion = minVersion
|
tlsConfig.MinVersion = minVersion
|
||||||
}
|
}
|
||||||
if options.MaxVersion != "" {
|
if options.MaxVersion != "" {
|
||||||
maxVersion, err := option.ParseTLSVersion(options.MaxVersion)
|
maxVersion, err := ParseTLSVersion(options.MaxVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "parse max_version")
|
return nil, E.Cause(err, "parse max_version")
|
||||||
}
|
}
|
||||||
@@ -104,42 +96,21 @@ func TLSConfig(serverAddress string, options option.OutboundTLSOptions) (*tls.Co
|
|||||||
}
|
}
|
||||||
tlsConfig.RootCAs = certPool
|
tlsConfig.RootCAs = certPool
|
||||||
}
|
}
|
||||||
return &tlsConfig, nil
|
return &stdClientConfig{&tlsConfig}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTLS(dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) {
|
func (s *stdClientConfig) NextProtos() []string {
|
||||||
if !options.Enabled {
|
return s.config.NextProtos
|
||||||
return dialer, nil
|
|
||||||
}
|
|
||||||
tlsConfig, err := TLSConfig(serverAddress, options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &TLSDialer{
|
|
||||||
dialer: dialer,
|
|
||||||
config: tlsConfig,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *TLSDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (s *stdClientConfig) SetNextProtos(nextProto []string) {
|
||||||
if network != N.NetworkTCP {
|
s.config.NextProtos = nextProto
|
||||||
return nil, os.ErrInvalid
|
|
||||||
}
|
|
||||||
conn, err := d.dialer.DialContext(ctx, network, destination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return TLSClient(ctx, conn, d.config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *TLSDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (s *stdClientConfig) Config() (*STDConfig, error) {
|
||||||
return nil, os.ErrInvalid
|
return s.config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TLSClient(ctx context.Context, conn net.Conn, tlsConfig *tls.Config) (*tls.Conn, error) {
|
func (s *stdClientConfig) Client(conn net.Conn) Conn {
|
||||||
tlsConn := tls.Client(conn, tlsConfig)
|
return tls.Client(conn, s.config)
|
||||||
ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout)
|
|
||||||
defer cancel()
|
|
||||||
err := tlsConn.HandshakeContext(ctx)
|
|
||||||
return tlsConn, err
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package inbound
|
package tls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -14,9 +15,7 @@ import (
|
|||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Service = (*TLSConfig)(nil)
|
type STDServerConfig struct {
|
||||||
|
|
||||||
type TLSConfig struct {
|
|
||||||
config *tls.Config
|
config *tls.Config
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
acmeService adapter.Service
|
acmeService adapter.Service
|
||||||
@@ -27,105 +26,15 @@ type TLSConfig struct {
|
|||||||
watcher *fsnotify.Watcher
|
watcher *fsnotify.Watcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TLSConfig) Config() *tls.Config {
|
func (c *STDServerConfig) NextProtos() []string {
|
||||||
return c.config
|
return c.config.NextProtos
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TLSConfig) Start() error {
|
func (c *STDServerConfig) SetNextProtos(nextProto []string) {
|
||||||
if c.acmeService != nil {
|
c.config.NextProtos = nextProto
|
||||||
return c.acmeService.Start()
|
|
||||||
} else {
|
|
||||||
if c.certificatePath == "" && c.keyPath == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err := c.startWatcher()
|
|
||||||
if err != nil {
|
|
||||||
c.logger.Warn("create fsnotify watcher: ", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TLSConfig) startWatcher() error {
|
func newSTDServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) {
|
||||||
watcher, err := fsnotify.NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if c.certificatePath != "" {
|
|
||||||
err = watcher.Add(c.certificatePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if c.keyPath != "" {
|
|
||||||
err = watcher.Add(c.keyPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.watcher = watcher
|
|
||||||
go c.loopUpdate()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TLSConfig) loopUpdate() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case event, ok := <-c.watcher.Events:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if event.Op&fsnotify.Write != fsnotify.Write {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err := c.reloadKeyPair()
|
|
||||||
if err != nil {
|
|
||||||
c.logger.Error(E.Cause(err, "reload TLS key pair"))
|
|
||||||
}
|
|
||||||
case err, ok := <-c.watcher.Errors:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.logger.Error(E.Cause(err, "fsnotify error"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TLSConfig) reloadKeyPair() error {
|
|
||||||
if c.certificatePath != "" {
|
|
||||||
certificate, err := os.ReadFile(c.certificatePath)
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "reload certificate from ", c.certificatePath)
|
|
||||||
}
|
|
||||||
c.certificate = certificate
|
|
||||||
}
|
|
||||||
if c.keyPath != "" {
|
|
||||||
key, err := os.ReadFile(c.keyPath)
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "reload key from ", c.keyPath)
|
|
||||||
}
|
|
||||||
c.key = key
|
|
||||||
}
|
|
||||||
keyPair, err := tls.X509KeyPair(c.certificate, c.key)
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "reload key pair")
|
|
||||||
}
|
|
||||||
c.config.Certificates = []tls.Certificate{keyPair}
|
|
||||||
c.logger.Info("reloaded TLS certificate")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TLSConfig) Close() error {
|
|
||||||
if c.acmeService != nil {
|
|
||||||
return c.acmeService.Close()
|
|
||||||
}
|
|
||||||
if c.watcher != nil {
|
|
||||||
return c.watcher.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTLSConfig(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (*TLSConfig, error) {
|
|
||||||
if !options.Enabled {
|
if !options.Enabled {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@@ -147,14 +56,14 @@ func NewTLSConfig(ctx context.Context, logger log.Logger, options option.Inbound
|
|||||||
tlsConfig.NextProtos = append(tlsConfig.NextProtos, options.ALPN...)
|
tlsConfig.NextProtos = append(tlsConfig.NextProtos, options.ALPN...)
|
||||||
}
|
}
|
||||||
if options.MinVersion != "" {
|
if options.MinVersion != "" {
|
||||||
minVersion, err := option.ParseTLSVersion(options.MinVersion)
|
minVersion, err := ParseTLSVersion(options.MinVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "parse min_version")
|
return nil, E.Cause(err, "parse min_version")
|
||||||
}
|
}
|
||||||
tlsConfig.MinVersion = minVersion
|
tlsConfig.MinVersion = minVersion
|
||||||
}
|
}
|
||||||
if options.MaxVersion != "" {
|
if options.MaxVersion != "" {
|
||||||
maxVersion, err := option.ParseTLSVersion(options.MaxVersion)
|
maxVersion, err := ParseTLSVersion(options.MaxVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "parse max_version")
|
return nil, E.Cause(err, "parse max_version")
|
||||||
}
|
}
|
||||||
@@ -205,7 +114,7 @@ func NewTLSConfig(ctx context.Context, logger log.Logger, options option.Inbound
|
|||||||
}
|
}
|
||||||
tlsConfig.Certificates = []tls.Certificate{keyPair}
|
tlsConfig.Certificates = []tls.Certificate{keyPair}
|
||||||
}
|
}
|
||||||
return &TLSConfig{
|
return &STDServerConfig{
|
||||||
config: tlsConfig,
|
config: tlsConfig,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
acmeService: acmeService,
|
acmeService: acmeService,
|
||||||
@@ -215,3 +124,109 @@ func NewTLSConfig(ctx context.Context, logger log.Logger, options option.Inbound
|
|||||||
keyPath: options.KeyPath,
|
keyPath: options.KeyPath,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) Config() (*STDConfig, error) {
|
||||||
|
return c.config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) Client(conn net.Conn) Conn {
|
||||||
|
return tls.Client(conn, c.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) Server(conn net.Conn) Conn {
|
||||||
|
return tls.Server(conn, c.config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) Start() error {
|
||||||
|
if c.acmeService != nil {
|
||||||
|
return c.acmeService.Start()
|
||||||
|
} else {
|
||||||
|
if c.certificatePath == "" && c.keyPath == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := c.startWatcher()
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Warn("create fsnotify watcher: ", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) startWatcher() error {
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c.certificatePath != "" {
|
||||||
|
err = watcher.Add(c.certificatePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.keyPath != "" {
|
||||||
|
err = watcher.Add(c.keyPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.watcher = watcher
|
||||||
|
go c.loopUpdate()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) loopUpdate() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event, ok := <-c.watcher.Events:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if event.Op&fsnotify.Write != fsnotify.Write {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := c.reloadKeyPair()
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error(E.Cause(err, "reload TLS key pair"))
|
||||||
|
}
|
||||||
|
case err, ok := <-c.watcher.Errors:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.logger.Error(E.Cause(err, "fsnotify error"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) reloadKeyPair() error {
|
||||||
|
if c.certificatePath != "" {
|
||||||
|
certificate, err := os.ReadFile(c.certificatePath)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "reload certificate from ", c.certificatePath)
|
||||||
|
}
|
||||||
|
c.certificate = certificate
|
||||||
|
}
|
||||||
|
if c.keyPath != "" {
|
||||||
|
key, err := os.ReadFile(c.keyPath)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "reload key from ", c.keyPath)
|
||||||
|
}
|
||||||
|
c.key = key
|
||||||
|
}
|
||||||
|
keyPair, err := tls.X509KeyPair(c.certificate, c.key)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "reload key pair")
|
||||||
|
}
|
||||||
|
c.config.Certificates = []tls.Certificate{keyPair}
|
||||||
|
c.logger.Info("reloaded TLS certificate")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *STDServerConfig) Close() error {
|
||||||
|
if c.acmeService != nil {
|
||||||
|
return c.acmeService.Close()
|
||||||
|
}
|
||||||
|
if c.watcher != nil {
|
||||||
|
return c.watcher.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
151
common/tls/utls_client.go
Normal file
151
common/tls/utls_client.go
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
//go:build with_utls
|
||||||
|
|
||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
|
||||||
|
utls "github.com/refraction-networking/utls"
|
||||||
|
)
|
||||||
|
|
||||||
|
type utlsClientConfig struct {
|
||||||
|
config *utls.Config
|
||||||
|
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) {
|
||||||
|
return nil, E.New("unsupported usage for uTLS")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *utlsClientConfig) Client(conn net.Conn) Conn {
|
||||||
|
return &utlsConnWrapper{utls.UClient(conn, e.config, e.id)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type utlsConnWrapper struct {
|
||||||
|
*utls.UConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *utlsConnWrapper) HandshakeContext(ctx context.Context) error {
|
||||||
|
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) {
|
||||||
|
var serverName string
|
||||||
|
if options.ServerName != "" {
|
||||||
|
serverName = options.ServerName
|
||||||
|
} else if serverAddress != "" {
|
||||||
|
if _, err := netip.ParseAddr(serverName); err != nil {
|
||||||
|
serverName = serverAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if serverName == "" && !options.Insecure {
|
||||||
|
return nil, E.New("missing server_name or insecure=true")
|
||||||
|
}
|
||||||
|
|
||||||
|
var tlsConfig utls.Config
|
||||||
|
if options.DisableSNI {
|
||||||
|
tlsConfig.ServerName = "127.0.0.1"
|
||||||
|
} else {
|
||||||
|
tlsConfig.ServerName = serverName
|
||||||
|
}
|
||||||
|
if options.Insecure {
|
||||||
|
tlsConfig.InsecureSkipVerify = options.Insecure
|
||||||
|
} else if options.DisableSNI {
|
||||||
|
return nil, E.New("disable_sni is unsupported in uTLS")
|
||||||
|
}
|
||||||
|
if len(options.ALPN) > 0 {
|
||||||
|
tlsConfig.NextProtos = options.ALPN
|
||||||
|
}
|
||||||
|
if options.MinVersion != "" {
|
||||||
|
minVersion, err := ParseTLSVersion(options.MinVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "parse min_version")
|
||||||
|
}
|
||||||
|
tlsConfig.MinVersion = minVersion
|
||||||
|
}
|
||||||
|
if options.MaxVersion != "" {
|
||||||
|
maxVersion, err := ParseTLSVersion(options.MaxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "parse max_version")
|
||||||
|
}
|
||||||
|
tlsConfig.MaxVersion = maxVersion
|
||||||
|
}
|
||||||
|
if options.CipherSuites != nil {
|
||||||
|
find:
|
||||||
|
for _, cipherSuite := range options.CipherSuites {
|
||||||
|
for _, tlsCipherSuite := range tls.CipherSuites() {
|
||||||
|
if cipherSuite == tlsCipherSuite.Name {
|
||||||
|
tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, tlsCipherSuite.ID)
|
||||||
|
continue find
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, E.New("unknown cipher_suite: ", cipherSuite)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var certificate []byte
|
||||||
|
if options.Certificate != "" {
|
||||||
|
certificate = []byte(options.Certificate)
|
||||||
|
} else if options.CertificatePath != "" {
|
||||||
|
content, err := os.ReadFile(options.CertificatePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "read certificate")
|
||||||
|
}
|
||||||
|
certificate = content
|
||||||
|
}
|
||||||
|
if len(certificate) > 0 {
|
||||||
|
certPool := x509.NewCertPool()
|
||||||
|
if !certPool.AppendCertsFromPEM(certificate) {
|
||||||
|
return nil, E.New("failed to parse certificate:\n\n", certificate)
|
||||||
|
}
|
||||||
|
tlsConfig.RootCAs = certPool
|
||||||
|
}
|
||||||
|
var id utls.ClientHelloID
|
||||||
|
switch options.UTLS.Fingerprint {
|
||||||
|
case "chrome", "":
|
||||||
|
id = utls.HelloChrome_Auto
|
||||||
|
case "firefox":
|
||||||
|
id = utls.HelloFirefox_Auto
|
||||||
|
case "ios":
|
||||||
|
id = utls.HelloIOS_Auto
|
||||||
|
case "android":
|
||||||
|
id = utls.HelloAndroid_11_OkHttp
|
||||||
|
case "random":
|
||||||
|
id = utls.HelloRandomized
|
||||||
|
}
|
||||||
|
return &utlsClientConfig{&tlsConfig, id}, nil
|
||||||
|
}
|
||||||
13
common/tls/utls_stub.go
Normal file
13
common/tls/utls_stub.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//go:build !with_utls
|
||||||
|
|
||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newUTLSClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
|
||||||
|
return nil, E.New(`uTLS is not included in this build, rebuild with -tags with_utls`)
|
||||||
|
}
|
||||||
@@ -1,23 +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"
|
||||||
|
TypeShadowsocksR = "shadowsocksr"
|
||||||
|
TypeVLESS = "vless"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Version = "1.0-beta2"
|
Version = "1.1-beta4"
|
||||||
Commit = ""
|
Commit = ""
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,130 @@
|
|||||||
|
#### 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
|
||||||
|
|
||||||
|
* Add Clash mode and persistence support **1**
|
||||||
|
* Add TLS ECH and uTLS support for outbound TLS options **2**
|
||||||
|
* Fix socks4 request
|
||||||
|
* Fix processing empty dns result
|
||||||
|
|
||||||
|
*1*:
|
||||||
|
|
||||||
|
Switching modes using the Clash API, and `store-selected` are now supported,
|
||||||
|
see [Experimental](/configuration/experimental).
|
||||||
|
|
||||||
|
*2*:
|
||||||
|
|
||||||
|
ECH (Encrypted Client Hello) is a TLS extension that allows a client to encrypt the first part of its ClientHello
|
||||||
|
message, see [TLS#ECH](/configuration/shared/tls#ech).
|
||||||
|
|
||||||
|
uTLS is a fork of "crypto/tls", which provides ClientHello fingerprinting resistance,
|
||||||
|
see [TLS#uTLS](/configuration/shared/tls#utls).
|
||||||
|
|
||||||
|
#### 1.0.2
|
||||||
|
|
||||||
|
* Fix socks4 request
|
||||||
|
* Fix processing empty dns result
|
||||||
|
|
||||||
|
#### 1.1-beta1
|
||||||
|
|
||||||
|
* Add support for use with android VPNService **1**
|
||||||
|
* Add tun support for WireGuard outbound **2**
|
||||||
|
* Add system tun stack **3**
|
||||||
|
* Add comment filter for config **4**
|
||||||
|
* Add option for allow optional proxy protocol header
|
||||||
|
* Add half close for smux
|
||||||
|
* Set UDP DF by default **5**
|
||||||
|
* Set default tun mtu to 9000
|
||||||
|
* Update gVisor to 20220905.0
|
||||||
|
|
||||||
|
*1*:
|
||||||
|
|
||||||
|
In previous versions, Android VPN would not work with tun enabled.
|
||||||
|
|
||||||
|
The usage of tun over VPN and VPN over tun is now supported, see [Tun Inbound](/configuration/inbound/tun#auto_route).
|
||||||
|
|
||||||
|
*2*:
|
||||||
|
|
||||||
|
In previous releases, WireGuard outbound support was backed by the lower performance gVisor virtual interface.
|
||||||
|
|
||||||
|
It achieves the same performance as wireguard-go by providing automatic system interface support.
|
||||||
|
|
||||||
|
*3*:
|
||||||
|
|
||||||
|
It does not depend on gVisor and has better performance in some cases.
|
||||||
|
|
||||||
|
It is less compatible and may not be available in some environments.
|
||||||
|
|
||||||
|
*4*:
|
||||||
|
|
||||||
|
Annotated json configuration files are now supported.
|
||||||
|
|
||||||
|
*5*:
|
||||||
|
|
||||||
|
UDP fragmentation is now blocked by default.
|
||||||
|
|
||||||
|
Including shadowsocks-libev, shadowsocks-rust and quic-go all disable segmentation by default.
|
||||||
|
|
||||||
|
See [Dial Fields](/configuration/shared/dial#udp_fragment)
|
||||||
|
and [Listen Fields](/configuration/shared/listen#udp_fragment).
|
||||||
|
|
||||||
|
#### 1.0.1
|
||||||
|
|
||||||
|
* Fix match 4in6 address in ip_cidr
|
||||||
|
* Fix clash api log level format error
|
||||||
|
* Fix clash api unknown proxy type
|
||||||
|
|
||||||
|
#### 1.0
|
||||||
|
|
||||||
|
* Fix wireguard reconnect
|
||||||
|
* Fix naive inbound
|
||||||
|
* Fix json format error message
|
||||||
|
* Fix processing vmess termination signal
|
||||||
|
* Fix hysteria stream error
|
||||||
|
* Fix listener close when proxyproto failed
|
||||||
|
|
||||||
|
#### 1.0-rc1
|
||||||
|
|
||||||
|
* Fix write log timestamp
|
||||||
|
* Fix write zero
|
||||||
|
* Fix dial parallel in direct outbound
|
||||||
|
* Fix write trojan udp
|
||||||
|
* Fix DNS routing
|
||||||
|
* Add attribute support for geosite
|
||||||
|
* Update documentation for [Dial Fields](/configuration/shared/dial)
|
||||||
|
|
||||||
|
#### 1.0-beta3
|
||||||
|
|
||||||
|
* Add [chained inbound](/configuration/shared/listen#detour) support
|
||||||
|
* Add process_path rule item
|
||||||
|
* Add macOS redirect support
|
||||||
|
* Add ShadowTLS [Inbound](/configuration/inbound/shadowtls), [Outbound](/configuration/outbound/shadowtls)
|
||||||
|
and [Examples](/examples/shadowtls)
|
||||||
|
* Fix search android package in non-owner users
|
||||||
|
* Fix socksaddr type condition
|
||||||
|
* Fix smux session status
|
||||||
|
* Refactor inbound and outbound documentation
|
||||||
|
* Minor fixes
|
||||||
|
|
||||||
#### 1.0-beta2
|
#### 1.0-beta2
|
||||||
|
|
||||||
* Add strict_route option for [Tun inbound](/configuration/inbound/tun#strict_route)
|
* Add strict_route option for [Tun inbound](/configuration/inbound/tun#strict_route)
|
||||||
@@ -111,4 +238,4 @@
|
|||||||
|
|
||||||
No changelog before.
|
No changelog before.
|
||||||
|
|
||||||
[#9]: https://github.com/SagerNet/sing-box/pull/9
|
[#9]: https://github.com/SagerNet/sing-box/pull/9
|
||||||
|
|||||||
@@ -61,6 +61,9 @@
|
|||||||
"process_name": [
|
"process_name": [
|
||||||
"curl"
|
"curl"
|
||||||
],
|
],
|
||||||
|
"process_path": [
|
||||||
|
"/usr/bin/curl"
|
||||||
|
],
|
||||||
"package_name": [
|
"package_name": [
|
||||||
"com.termux"
|
"com.termux"
|
||||||
],
|
],
|
||||||
@@ -70,6 +73,7 @@
|
|||||||
"user_id": [
|
"user_id": [
|
||||||
1000
|
1000
|
||||||
],
|
],
|
||||||
|
"clash_mode": "direct",
|
||||||
"invert": false,
|
"invert": false,
|
||||||
"outbound": [
|
"outbound": [
|
||||||
"direct"
|
"direct"
|
||||||
@@ -177,6 +181,14 @@ Match port range.
|
|||||||
|
|
||||||
Match process name.
|
Match process name.
|
||||||
|
|
||||||
|
#### process_path
|
||||||
|
|
||||||
|
!!! error ""
|
||||||
|
|
||||||
|
Only supported on Linux, Windows, and macOS.
|
||||||
|
|
||||||
|
Match process path.
|
||||||
|
|
||||||
#### package_name
|
#### package_name
|
||||||
|
|
||||||
Match android package name.
|
Match android package name.
|
||||||
@@ -197,6 +209,10 @@ Match user name.
|
|||||||
|
|
||||||
Match user id.
|
Match user id.
|
||||||
|
|
||||||
|
#### clash_mode
|
||||||
|
|
||||||
|
Match Clash mode.
|
||||||
|
|
||||||
#### invert
|
#### invert
|
||||||
|
|
||||||
Invert match result.
|
Invert match result.
|
||||||
|
|||||||
@@ -60,6 +60,9 @@
|
|||||||
"process_name": [
|
"process_name": [
|
||||||
"curl"
|
"curl"
|
||||||
],
|
],
|
||||||
|
"process_path": [
|
||||||
|
"/usr/bin/curl"
|
||||||
|
],
|
||||||
"package_name": [
|
"package_name": [
|
||||||
"com.termux"
|
"com.termux"
|
||||||
],
|
],
|
||||||
@@ -69,6 +72,7 @@
|
|||||||
"user_id": [
|
"user_id": [
|
||||||
1000
|
1000
|
||||||
],
|
],
|
||||||
|
"clash_mode": "direct",
|
||||||
"invert": false,
|
"invert": false,
|
||||||
"outbound": [
|
"outbound": [
|
||||||
"direct"
|
"direct"
|
||||||
@@ -176,6 +180,14 @@
|
|||||||
|
|
||||||
匹配进程名称。
|
匹配进程名称。
|
||||||
|
|
||||||
|
#### process_path
|
||||||
|
|
||||||
|
!!! error ""
|
||||||
|
|
||||||
|
仅支持 Linux、Windows 和 macOS.
|
||||||
|
|
||||||
|
匹配进程路径。
|
||||||
|
|
||||||
#### package_name
|
#### package_name
|
||||||
|
|
||||||
匹配 Android 应用包名。
|
匹配 Android 应用包名。
|
||||||
@@ -196,6 +208,10 @@
|
|||||||
|
|
||||||
匹配用户 ID。
|
匹配用户 ID。
|
||||||
|
|
||||||
|
#### clash_mode
|
||||||
|
|
||||||
|
匹配 Clash 模式。
|
||||||
|
|
||||||
#### invert
|
#### invert
|
||||||
|
|
||||||
反选匹配结果。
|
反选匹配结果。
|
||||||
|
|||||||
@@ -8,7 +8,10 @@
|
|||||||
"clash_api": {
|
"clash_api": {
|
||||||
"external_controller": "127.0.0.1:9090",
|
"external_controller": "127.0.0.1:9090",
|
||||||
"external_ui": "folder",
|
"external_ui": "folder",
|
||||||
"secret": ""
|
"secret": "",
|
||||||
|
"default_mode": "rule",
|
||||||
|
"store_selected": false,
|
||||||
|
"cache_file": "cache.db"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,7 +29,7 @@
|
|||||||
|
|
||||||
#### external_controller
|
#### external_controller
|
||||||
|
|
||||||
RESTful web API listening address. Disabled if empty.
|
RESTful web API listening address. Clash API will be disabled if empty.
|
||||||
|
|
||||||
#### external_ui
|
#### external_ui
|
||||||
|
|
||||||
@@ -38,4 +41,22 @@ serve it at `http://{{external-controller}}/ui`.
|
|||||||
|
|
||||||
Secret for the RESTful API (optional)
|
Secret for the RESTful API (optional)
|
||||||
Authenticate by spedifying HTTP header `Authorization: Bearer ${secret}`
|
Authenticate by spedifying HTTP header `Authorization: Bearer ${secret}`
|
||||||
ALWAYS set a secret if RESTful API is listening on 0.0.0.0
|
ALWAYS set a secret if RESTful API is listening on 0.0.0.0
|
||||||
|
|
||||||
|
#### default_mode
|
||||||
|
|
||||||
|
Default mode in clash, `rule` will be used if empty.
|
||||||
|
|
||||||
|
This setting has no direct effect, but can be used in routing and DNS rules via the `clash_mode` rule item.
|
||||||
|
|
||||||
|
#### store_selected
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
|
||||||
|
The tag must be set for target outbounds.
|
||||||
|
|
||||||
|
Store selected outbound for the `Selector` outbound in cache file.
|
||||||
|
|
||||||
|
#### cache_file
|
||||||
|
|
||||||
|
Cache file path, `cache.db` will be used if empty.
|
||||||
@@ -8,7 +8,10 @@
|
|||||||
"clash_api": {
|
"clash_api": {
|
||||||
"external_controller": "127.0.0.1:9090",
|
"external_controller": "127.0.0.1:9090",
|
||||||
"external_ui": "folder",
|
"external_ui": "folder",
|
||||||
"secret": ""
|
"secret": "",
|
||||||
|
"default_mode": "rule",
|
||||||
|
"store_selected": false,
|
||||||
|
"cache_file": "cache.db"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,7 +29,7 @@
|
|||||||
|
|
||||||
#### external_controller
|
#### external_controller
|
||||||
|
|
||||||
RESTful web API 监听地址。
|
RESTful web API 监听地址。如果为空,则禁用 Clash API。
|
||||||
|
|
||||||
#### external_ui
|
#### external_ui
|
||||||
|
|
||||||
@@ -36,4 +39,22 @@ RESTful web API 监听地址。
|
|||||||
|
|
||||||
RESTful API 的密钥(可选)
|
RESTful API 的密钥(可选)
|
||||||
通过指定 HTTP 标头 `Authorization: Bearer ${secret}` 进行身份验证
|
通过指定 HTTP 标头 `Authorization: Bearer ${secret}` 进行身份验证
|
||||||
如果 RESTful API 正在监听 0.0.0.0,请始终设置一个密钥。
|
如果 RESTful API 正在监听 0.0.0.0,请始终设置一个密钥。
|
||||||
|
|
||||||
|
#### default_mode
|
||||||
|
|
||||||
|
Clash 中的默认模式,默认使用 `rule`。
|
||||||
|
|
||||||
|
此设置没有直接影响,但可以通过 `clash_mode` 规则项在路由和 DNS 规则中使用。
|
||||||
|
|
||||||
|
#### store_selected
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
|
||||||
|
必须为目标出站设置标签。
|
||||||
|
|
||||||
|
将 `Selector` 中出站的选定的目标出站存储在缓存文件中。
|
||||||
|
|
||||||
|
#### cache_file
|
||||||
|
|
||||||
|
缓存文件路径,默认使用`cache.db`。
|
||||||
@@ -4,29 +4,22 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "direct",
|
||||||
{
|
"tag": "direct-in",
|
||||||
"type": "direct",
|
|
||||||
"tag": "direct-in",
|
... // Listen Fields
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 5353,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"udp_timeout": 300,
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"network": "udp",
|
"network": "udp",
|
||||||
"override_address": "1.0.0.1",
|
"override_address": "1.0.0.1",
|
||||||
"override_port": 53
|
"override_port": 53
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Direct Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### network
|
#### network
|
||||||
|
|
||||||
@@ -40,50 +33,4 @@ Override the connection destination address.
|
|||||||
|
|
||||||
#### override_port
|
#### override_port
|
||||||
|
|
||||||
Override the connection destination port.
|
Override the connection destination port.
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
Enable tcp fast open for listener.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|
||||||
#### udp_timeout
|
|
||||||
|
|
||||||
UDP NAT expiration time in seconds, default is 300 (5 minutes).
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
Parse [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) in the connection header.
|
|
||||||
@@ -4,29 +4,22 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "direct",
|
||||||
{
|
"tag": "direct-in",
|
||||||
"type": "direct",
|
|
||||||
"tag": "direct-in",
|
|
||||||
|
|
||||||
"listen": "::",
|
... // 监听字段
|
||||||
"listen_port": 5353,
|
|
||||||
"tcp_fast_open": false,
|
"network": "udp",
|
||||||
"sniff": false,
|
"override_address": "1.0.0.1",
|
||||||
"sniff_override_destination": false,
|
"override_port": 53
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"udp_timeout": 300,
|
|
||||||
|
|
||||||
"network": "udp",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
"override_address": "1.0.0.1",
|
|
||||||
"override_port": 53
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Direct 字段
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### network
|
#### network
|
||||||
|
|
||||||
@@ -42,48 +35,3 @@
|
|||||||
|
|
||||||
覆盖连接目标端口。
|
覆盖连接目标端口。
|
||||||
|
|
||||||
### 监听字段
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
为监听器启用 TCP 快速打开。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|
||||||
#### udp_timeout
|
|
||||||
|
|
||||||
UDP NAT 过期时间,以秒为单位,默认为 300(5 分钟)。
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
|
|
||||||
|
|||||||
@@ -2,33 +2,27 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "http",
|
||||||
|
"tag": "http-in",
|
||||||
|
|
||||||
|
... // Listen Fields
|
||||||
|
|
||||||
|
"users": [
|
||||||
{
|
{
|
||||||
"type": "http",
|
"username": "admin",
|
||||||
"tag": "http-in",
|
"password": "admin"
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"username": "admin",
|
|
||||||
"password": "admin"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tls": {},
|
|
||||||
"set_system_proxy": false
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"tls": {},
|
||||||
|
"set_system_proxy": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### HTTP Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### tls
|
#### tls
|
||||||
|
|
||||||
@@ -47,45 +41,3 @@ No authentication required if empty.
|
|||||||
Only supported on Linux, Android, Windows, and macOS.
|
Only supported on Linux, Android, Windows, and macOS.
|
||||||
|
|
||||||
Automatically set system proxy configuration when start and clean up when stop.
|
Automatically set system proxy configuration when start and clean up when stop.
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
Enable tcp fast open for listener.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
Parse [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) in the connection header.
|
|
||||||
@@ -2,33 +2,27 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "http",
|
||||||
|
"tag": "http-in",
|
||||||
|
|
||||||
|
... // 监听字段
|
||||||
|
|
||||||
|
"users": [
|
||||||
{
|
{
|
||||||
"type": "http",
|
"username": "admin",
|
||||||
"tag": "http-in",
|
"password": "admin"
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"username": "admin",
|
|
||||||
"password": "admin"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tls": {},
|
|
||||||
"set_system_proxy": false
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"tls": {},
|
||||||
|
"set_system_proxy": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### HTTP 字段
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### tls
|
#### tls
|
||||||
|
|
||||||
@@ -38,7 +32,7 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
|||||||
|
|
||||||
HTTP 用户
|
HTTP 用户
|
||||||
|
|
||||||
默认不需要验证。
|
如果为空则不需要验证。
|
||||||
|
|
||||||
#### set_system_proxy
|
#### set_system_proxy
|
||||||
|
|
||||||
@@ -46,46 +40,4 @@ HTTP 用户
|
|||||||
|
|
||||||
仅支持 Linux、Android、Windows 和 macOS。
|
仅支持 Linux、Android、Windows 和 macOS。
|
||||||
|
|
||||||
启动时自动设置系统代理,停止时自动清理。
|
启动时自动设置系统代理,停止时自动清理。
|
||||||
|
|
||||||
### 监听字段
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
为监听器启用 TCP 快速打开。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
|
|
||||||
@@ -2,31 +2,23 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "hysteria",
|
||||||
{
|
"tag": "hysteria-in",
|
||||||
"type": "hysteria",
|
|
||||||
"tag": "hysteria-in",
|
... // Listen Fields
|
||||||
|
|
||||||
"listen": "::",
|
"up": "100 Mbps",
|
||||||
"listen_port": 443,
|
"up_mbps": 100,
|
||||||
"sniff": false,
|
"down": "100 Mbps",
|
||||||
"sniff_override_destination": false,
|
"down_mbps": 100,
|
||||||
"domain_strategy": "prefer_ipv6",
|
"obfs": "fuck me till the daylight",
|
||||||
|
"auth": "",
|
||||||
"up": "100 Mbps",
|
"auth_str": "password",
|
||||||
"up_mbps": 100,
|
"recv_window_conn": 0,
|
||||||
"down": "100 Mbps",
|
"recv_window_client": 0,
|
||||||
"down_mbps": 100,
|
"max_conn_client": 0,
|
||||||
"obfs": "fuck me till the daylight",
|
"disable_mtu_discovery": false,
|
||||||
"auth": "",
|
"tls": {}
|
||||||
"auth_str": "password",
|
|
||||||
"recv_window_conn": 0,
|
|
||||||
"recv_window_client": 0,
|
|
||||||
"max_conn_client": 0,
|
|
||||||
"disable_mtu_discovery": false,
|
|
||||||
"tls": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -34,7 +26,11 @@
|
|||||||
|
|
||||||
QUIC, which is required by hysteria is not included by default, see [Installation](/#installation).
|
QUIC, which is required by hysteria is not included by default, see [Installation](/#installation).
|
||||||
|
|
||||||
### Hysteria Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### up, down
|
#### up, down
|
||||||
|
|
||||||
@@ -101,38 +97,4 @@ Force enabled on for systems other than Linux and Windows (according to upstream
|
|||||||
|
|
||||||
==Required==
|
==Required==
|
||||||
|
|
||||||
TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
@@ -2,31 +2,23 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "hysteria",
|
||||||
{
|
"tag": "hysteria-in",
|
||||||
"type": "hysteria",
|
|
||||||
"tag": "hysteria-in",
|
... // 监听字段
|
||||||
|
|
||||||
"listen": "::",
|
"up": "100 Mbps",
|
||||||
"listen_port": 443,
|
"up_mbps": 100,
|
||||||
"sniff": false,
|
"down": "100 Mbps",
|
||||||
"sniff_override_destination": false,
|
"down_mbps": 100,
|
||||||
"domain_strategy": "prefer_ipv6",
|
"obfs": "fuck me till the daylight",
|
||||||
|
"auth": "",
|
||||||
"up": "100 Mbps",
|
"auth_str": "password",
|
||||||
"up_mbps": 100,
|
"recv_window_conn": 0,
|
||||||
"down": "100 Mbps",
|
"recv_window_client": 0,
|
||||||
"down_mbps": 100,
|
"max_conn_client": 0,
|
||||||
"obfs": "fuck me till the daylight",
|
"disable_mtu_discovery": false,
|
||||||
"auth": "",
|
"tls": {}
|
||||||
"auth_str": "password",
|
|
||||||
"recv_window_conn": 0,
|
|
||||||
"recv_window_client": 0,
|
|
||||||
"max_conn_client": 0,
|
|
||||||
"disable_mtu_discovery": false,
|
|
||||||
"tls": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -34,7 +26,11 @@
|
|||||||
|
|
||||||
默认安装不包含被 Hysteria 依赖的 QUIC,参阅 [安装](/zh/#_2)。
|
默认安装不包含被 Hysteria 依赖的 QUIC,参阅 [安装](/zh/#_2)。
|
||||||
|
|
||||||
### Hysteria 字段
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### up, down
|
#### up, down
|
||||||
|
|
||||||
@@ -101,38 +97,4 @@ base64 编码的认证密码。
|
|||||||
|
|
||||||
==必填==
|
==必填==
|
||||||
|
|
||||||
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
||||||
|
|
||||||
### 监听字段
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
@@ -15,20 +15,20 @@
|
|||||||
|
|
||||||
### Fields
|
### Fields
|
||||||
|
|
||||||
| Type | Format |
|
| Type | Format | Injectable |
|
||||||
|---------------|------------------------------|
|
|---------------|------------------------------|------------|
|
||||||
| `direct` | [Direct](./direct) |
|
| `direct` | [Direct](./direct) | X |
|
||||||
| `mixed` | [Mixed](./mixed) |
|
| `mixed` | [Mixed](./mixed) | TCP |
|
||||||
| `socks` | [SOCKS](./socks) |
|
| `socks` | [SOCKS](./socks) | TCP |
|
||||||
| `http` | [HTTP](./http) |
|
| `http` | [HTTP](./http) | TCP |
|
||||||
| `shadowsocks` | [Shadowsocks](./shadowsocks) |
|
| `shadowsocks` | [Shadowsocks](./shadowsocks) | TCP |
|
||||||
| `vmess` | [VMess](./vmess) |
|
| `vmess` | [VMess](./vmess) | TCP |
|
||||||
| `trojan` | [Trojan](./trojan) |
|
| `trojan` | [Trojan](./trojan) | TCP |
|
||||||
| `naive` | [Naive](./naive) |
|
| `naive` | [Naive](./naive) | X |
|
||||||
| `hysteria` | [Hysteria](./hysteria) |
|
| `hysteria` | [Hysteria](./hysteria) | X |
|
||||||
| `tun` | [Tun](./tun) |
|
| `tun` | [Tun](./tun) | X |
|
||||||
| `redirect` | [Redirect](./redirect) |
|
| `redirect` | [Redirect](./redirect) | X |
|
||||||
| `tproxy` | [TProxy](./tproxy) |
|
| `tproxy` | [TProxy](./tproxy) | X |
|
||||||
|
|
||||||
#### tag
|
#### tag
|
||||||
|
|
||||||
|
|||||||
@@ -15,20 +15,20 @@
|
|||||||
|
|
||||||
### 字段
|
### 字段
|
||||||
|
|
||||||
| 类型 | 格式 |
|
| 类型 | 格式 | 注入支持 |
|
||||||
|---------------|------------------------------|
|
|---------------|------------------------------|------|
|
||||||
| `direct` | [Direct](./direct) |
|
| `direct` | [Direct](./direct) | X |
|
||||||
| `mixed` | [Mixed](./mixed) |
|
| `mixed` | [Mixed](./mixed) | TCP |
|
||||||
| `socks` | [SOCKS](./socks) |
|
| `socks` | [SOCKS](./socks) | TCP |
|
||||||
| `http` | [HTTP](./http) |
|
| `http` | [HTTP](./http) | TCP |
|
||||||
| `shadowsocks` | [Shadowsocks](./shadowsocks) |
|
| `shadowsocks` | [Shadowsocks](./shadowsocks) | TCP |
|
||||||
| `vmess` | [VMess](./vmess) |
|
| `vmess` | [VMess](./vmess) | TCP |
|
||||||
| `trojan` | [Trojan](./trojan) |
|
| `trojan` | [Trojan](./trojan) | TCP |
|
||||||
| `naive` | [Naive](./naive) |
|
| `naive` | [Naive](./naive) | X |
|
||||||
| `hysteria` | [Hysteria](./hysteria) |
|
| `hysteria` | [Hysteria](./hysteria) | X |
|
||||||
| `tun` | [Tun](./tun) |
|
| `tun` | [Tun](./tun) | X |
|
||||||
| `redirect` | [Redirect](./redirect) |
|
| `redirect` | [Redirect](./redirect) | X |
|
||||||
| `tproxy` | [TProxy](./tproxy) |
|
| `tproxy` | [TProxy](./tproxy) | X |
|
||||||
|
|
||||||
#### tag
|
#### tag
|
||||||
|
|
||||||
|
|||||||
@@ -4,32 +4,26 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "mixed",
|
||||||
|
"tag": "mixed-in",
|
||||||
|
|
||||||
|
... // Listen Fields
|
||||||
|
|
||||||
|
"users": [
|
||||||
{
|
{
|
||||||
"type": "mixed",
|
"username": "admin",
|
||||||
"tag": "mixed-in",
|
"password": "admin"
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"username": "admin",
|
|
||||||
"password": "admin"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"set_system_proxy": false
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"set_system_proxy": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Mixed Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### users
|
#### users
|
||||||
|
|
||||||
@@ -39,52 +33,6 @@ No authentication required if empty.
|
|||||||
|
|
||||||
#### set_system_proxy
|
#### set_system_proxy
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
Only supported on Linux, Android, Windows, and macOS.
|
|
||||||
|
|
||||||
Automatically set system proxy configuration when start and clean up when stop.
|
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
Enable tcp fast open for listener.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|
||||||
#### set_system_proxy
|
|
||||||
|
|
||||||
!!! error ""
|
!!! error ""
|
||||||
|
|
||||||
Only supported on Linux, Android, Windows, and macOS.
|
Only supported on Linux, Android, Windows, and macOS.
|
||||||
|
|||||||
@@ -4,38 +4,32 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "mixed",
|
||||||
|
"tag": "mixed-in",
|
||||||
|
|
||||||
|
... // 监听字段
|
||||||
|
|
||||||
|
"users": [
|
||||||
{
|
{
|
||||||
"type": "mixed",
|
"username": "admin",
|
||||||
"tag": "mixed-in",
|
"password": "admin"
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"username": "admin",
|
|
||||||
"password": "admin"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"set_system_proxy": false
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"set_system_proxy": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Mixed 字段
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### users
|
#### users
|
||||||
|
|
||||||
SOCKS 和 HTTP 用户
|
SOCKS 和 HTTP 用户
|
||||||
|
|
||||||
默认不需要验证。
|
如果为空则不需要验证。
|
||||||
|
|
||||||
#### set_system_proxy
|
#### set_system_proxy
|
||||||
|
|
||||||
@@ -43,46 +37,4 @@ SOCKS 和 HTTP 用户
|
|||||||
|
|
||||||
仅支持 Linux、Android、Windows 和 macOS。
|
仅支持 Linux、Android、Windows 和 macOS。
|
||||||
|
|
||||||
启动时自动设置系统代理,停止时自动清理。
|
启动时自动设置系统代理,停止时自动清理。
|
||||||
|
|
||||||
### 监听字段
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
为监听器启用 TCP 快速打开。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
|
|
||||||
@@ -2,29 +2,19 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "naive",
|
||||||
|
"tag": "naive-in",
|
||||||
|
"network": "udp",
|
||||||
|
|
||||||
|
... // Listen Fields
|
||||||
|
|
||||||
|
"users": [
|
||||||
{
|
{
|
||||||
"type": "naive",
|
"username": "sekai",
|
||||||
"tag": "naive-in",
|
"password": "password"
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 443,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"network": "udp",
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"username": "sekai",
|
|
||||||
"password": "password"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tls": {}
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"tls": {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -32,7 +22,11 @@
|
|||||||
|
|
||||||
HTTP3 transport is not included by default, see [Installation](/#installation).
|
HTTP3 transport is not included by default, see [Installation](/#installation).
|
||||||
|
|
||||||
### Naive Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### network
|
#### network
|
||||||
|
|
||||||
@@ -48,46 +42,4 @@ Naive users.
|
|||||||
|
|
||||||
#### tls
|
#### tls
|
||||||
|
|
||||||
TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
Enable tcp fast open for listener.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
Parse [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) in the connection header.
|
|
||||||
@@ -2,29 +2,19 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "naive",
|
||||||
{
|
"tag": "naive-in",
|
||||||
"type": "naive",
|
"network": "udp",
|
||||||
"tag": "naive-in",
|
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 443,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"network": "udp",
|
... // 监听字段
|
||||||
"users": [
|
|
||||||
{
|
"users": [
|
||||||
"username": "sekai",
|
{
|
||||||
"password": "password"
|
"username": "sekai",
|
||||||
}
|
"password": "password"
|
||||||
],
|
|
||||||
"tls": {}
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"tls": {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -32,7 +22,11 @@
|
|||||||
|
|
||||||
默认安装不包含 HTTP3 传输层, 参阅 [安装](/zh/#_2)。
|
默认安装不包含 HTTP3 传输层, 参阅 [安装](/zh/#_2)。
|
||||||
|
|
||||||
### Naive 字段
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### network
|
#### network
|
||||||
|
|
||||||
@@ -48,46 +42,4 @@ Naive 用户。
|
|||||||
|
|
||||||
#### tls
|
#### tls
|
||||||
|
|
||||||
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
||||||
|
|
||||||
### 监听字段
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
为监听器启用 TCP 快速打开。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
|
|
||||||
@@ -1,52 +1,18 @@
|
|||||||
|
!!! error ""
|
||||||
|
|
||||||
|
Only supported on Linux and macOS.
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "redirect",
|
||||||
{
|
"tag": "redirect-in",
|
||||||
"type": "redirect",
|
|
||||||
"tag": "redirect-in",
|
... // Listen Fields
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 5353,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Listen Fields
|
### Listen Fields
|
||||||
|
|
||||||
#### listen
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|||||||
@@ -1,52 +1,17 @@
|
|||||||
|
!!! error ""
|
||||||
|
|
||||||
|
仅支持 Linux 和 macOS。
|
||||||
|
|
||||||
### 结构
|
### 结构
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "redirect",
|
||||||
{
|
"tag": "redirect-in",
|
||||||
"type": "redirect",
|
|
||||||
"tag": "redirect-in",
|
... // 监听字段
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 5353,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 监听字段
|
### 监听字段
|
||||||
|
|
||||||
#### listen
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|||||||
@@ -2,25 +2,13 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "shadowsocks",
|
||||||
{
|
"tag": "ss-in",
|
||||||
"type": "shadowsocks",
|
|
||||||
"tag": "ss-in",
|
... // Listen Fields
|
||||||
|
|
||||||
"listen": "::",
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
"listen_port": 5353,
|
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"udp_timeout": 300,
|
|
||||||
"network": "udp",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -28,17 +16,12 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
|
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
||||||
|
"users": [
|
||||||
{
|
{
|
||||||
"type": "shadowsocks",
|
"name": "sekai",
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"name": "sekai",
|
|
||||||
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -48,25 +31,25 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "shadowsocks",
|
||||||
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
|
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
||||||
|
"destinations": [
|
||||||
{
|
{
|
||||||
"type": "shadowsocks",
|
"name": "test",
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
"server": "example.com",
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
"server_port": 8080,
|
||||||
"destinations": [
|
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
|
||||||
{
|
|
||||||
"name": "test",
|
|
||||||
"server": "example.com",
|
|
||||||
"server_port": 8080,
|
|
||||||
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Shadowsocks Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### network
|
#### network
|
||||||
|
|
||||||
|
|||||||
@@ -2,25 +2,13 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "shadowsocks",
|
||||||
{
|
"tag": "ss-in",
|
||||||
"type": "shadowsocks",
|
|
||||||
"tag": "ss-in",
|
... // 监听字段
|
||||||
|
|
||||||
"listen": "::",
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
"listen_port": 5353,
|
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"udp_timeout": 300,
|
|
||||||
"network": "udp",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -28,17 +16,12 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
|
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
||||||
|
"users": [
|
||||||
{
|
{
|
||||||
"type": "shadowsocks",
|
"name": "sekai",
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"name": "sekai",
|
|
||||||
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -48,25 +31,25 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "shadowsocks",
|
||||||
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
|
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
||||||
|
"destinations": [
|
||||||
{
|
{
|
||||||
"type": "shadowsocks",
|
"name": "test",
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
"server": "example.com",
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
"server_port": 8080,
|
||||||
"destinations": [
|
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
|
||||||
{
|
|
||||||
"name": "test",
|
|
||||||
"server": "example.com",
|
|
||||||
"server_port": 8080,
|
|
||||||
"password": "PCD2Z4o12bKUoFa3cC97Hw=="
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Shadowsocks 字段
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### network
|
#### network
|
||||||
|
|
||||||
@@ -98,50 +81,4 @@
|
|||||||
|---------------|-------------------------------|
|
|---------------|-------------------------------|
|
||||||
| none | / |
|
| none | / |
|
||||||
| 2022 methods | `openssl rand -base64 <密钥长度>` |
|
| 2022 methods | `openssl rand -base64 <密钥长度>` |
|
||||||
| other methods | 任意字符串 |
|
| other methods | 任意字符串 |
|
||||||
|
|
||||||
### 监听字段
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
为监听器启用 TCP 快速打开。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|
||||||
#### udp_timeout
|
|
||||||
|
|
||||||
UDP NAT 过期时间,以秒为单位,默认为 300(5 分钟)。
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
|
|
||||||
31
docs/configuration/inbound/shadowtls.md
Normal file
31
docs/configuration/inbound/shadowtls.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
### Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "shadowtls",
|
||||||
|
"tag": "st-in",
|
||||||
|
|
||||||
|
... // Listen Fields
|
||||||
|
|
||||||
|
"handshake": {
|
||||||
|
"server": "google.com",
|
||||||
|
"server_port": 443,
|
||||||
|
|
||||||
|
... // Dial Fields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
#### handshake
|
||||||
|
|
||||||
|
==Required==
|
||||||
|
|
||||||
|
Handshake server address and [dial options](/configuration/shared/dial).
|
||||||
|
|
||||||
29
docs/configuration/inbound/shadowtls.zh.md
Normal file
29
docs/configuration/inbound/shadowtls.zh.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
### 结构
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "shadowtls",
|
||||||
|
"tag": "st-in",
|
||||||
|
|
||||||
|
... // 监听字段
|
||||||
|
|
||||||
|
"handshake": {
|
||||||
|
"server": "google.com",
|
||||||
|
"server_port": 443,
|
||||||
|
|
||||||
|
... // 拨号字段
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
|
#### handshake
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
握手服务器地址和 [拨号参数](/zh/configuration/shared/dial/)。
|
||||||
@@ -4,76 +4,28 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "socks",
|
||||||
{
|
"tag": "socks-in",
|
||||||
"type": "socks",
|
|
||||||
"tag": "socks-in",
|
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"users": [
|
... // Listen Fields
|
||||||
{
|
|
||||||
"username": "admin",
|
"users": [
|
||||||
"password": "admin"
|
{
|
||||||
}
|
"username": "admin",
|
||||||
]
|
"password": "admin"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### SOCKS Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### users
|
#### users
|
||||||
|
|
||||||
SOCKS users.
|
SOCKS users.
|
||||||
|
|
||||||
No authentication required if empty.
|
No authentication required if empty.
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
Enable tcp fast open for listener.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
Parse [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) in the connection header.
|
|
||||||
|
|||||||
@@ -4,76 +4,28 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "socks",
|
||||||
{
|
"tag": "socks-in",
|
||||||
"type": "socks",
|
|
||||||
"tag": "socks-in",
|
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"users": [
|
... // 监听字段
|
||||||
{
|
|
||||||
"username": "admin",
|
"users": [
|
||||||
"password": "admin"
|
{
|
||||||
}
|
"username": "admin",
|
||||||
]
|
"password": "admin"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### SOCKS 字段
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### users
|
#### users
|
||||||
|
|
||||||
SOCKS 用户
|
SOCKS 用户
|
||||||
|
|
||||||
默认不需要验证。
|
如果为空则不需要验证。
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
为监听器启用 TCP 快速打开。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
|
|
||||||
|
|||||||
@@ -1,67 +1,28 @@
|
|||||||
|
!!! error ""
|
||||||
|
|
||||||
|
Only supported on Linux.
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "tproxy",
|
||||||
{
|
"tag": "tproxy-in",
|
||||||
"type": "tproxy",
|
|
||||||
"tag": "tproxy-in",
|
... // Listen Fields
|
||||||
|
|
||||||
"listen": "::",
|
"network": "udp"
|
||||||
"listen_port": 5353,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"udp_timeout": 300,
|
|
||||||
|
|
||||||
"network": "udp"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### TProxy Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### network
|
#### network
|
||||||
|
|
||||||
Listen network, one of `tcp` `udp`.
|
Listen network, one of `tcp` `udp`.
|
||||||
|
|
||||||
Both if empty.
|
Both if empty.
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|
||||||
#### udp_timeout
|
|
||||||
|
|
||||||
UDP NAT expiration time in seconds, default is 300 (5 minutes).
|
|
||||||
|
|||||||
@@ -1,67 +1,28 @@
|
|||||||
|
!!! error ""
|
||||||
|
|
||||||
|
仅支持 Linux。
|
||||||
|
|
||||||
### 结构
|
### 结构
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "tproxy",
|
||||||
{
|
"tag": "tproxy-in",
|
||||||
"type": "tproxy",
|
|
||||||
"tag": "tproxy-in",
|
... // 监听字段
|
||||||
|
|
||||||
"listen": "::",
|
"network": "udp"
|
||||||
"listen_port": 5353,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"udp_timeout": 300,
|
|
||||||
|
|
||||||
"network": "udp"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### TProxy 字段
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### network
|
#### network
|
||||||
|
|
||||||
监听的网络协议,`tcp` `udp` 之一。
|
监听的网络协议,`tcp` `udp` 之一。
|
||||||
|
|
||||||
默认所有。
|
默认所有。
|
||||||
|
|
||||||
### 监听字段
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|
||||||
#### udp_timeout
|
|
||||||
|
|
||||||
UDP NAT 过期时间,以秒为单位,默认为 300(5 分钟)。
|
|
||||||
@@ -2,43 +2,37 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "trojan",
|
||||||
{
|
"tag": "trojan-in",
|
||||||
"type": "trojan",
|
|
||||||
"tag": "trojan-in",
|
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"users": [
|
... // Listen Fields
|
||||||
{
|
|
||||||
"name": "sekai",
|
"users": [
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
{
|
||||||
}
|
"name": "sekai",
|
||||||
],
|
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
||||||
"tls": {},
|
|
||||||
"fallback": {
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 8080
|
|
||||||
},
|
|
||||||
"fallback_for_alpn": {
|
|
||||||
"http/1.1": {
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 8081
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"transport": {}
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"tls": {},
|
||||||
|
"fallback": {
|
||||||
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 8080
|
||||||
|
},
|
||||||
|
"fallback_for_alpn": {
|
||||||
|
"http/1.1": {
|
||||||
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 8081
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transport": {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Trojan Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### users
|
#### users
|
||||||
|
|
||||||
@@ -67,45 +61,3 @@ If not empty, TLS fallback requests with ALPN not in this table will be rejected
|
|||||||
#### transport
|
#### transport
|
||||||
|
|
||||||
V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport).
|
V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport).
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
Enable tcp fast open for listener.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
Parse [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) in the connection header.
|
|
||||||
@@ -2,41 +2,37 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "trojan",
|
||||||
|
"tag": "trojan-in",
|
||||||
|
|
||||||
|
... // 监听字段
|
||||||
|
|
||||||
|
"users": [
|
||||||
{
|
{
|
||||||
"type": "trojan",
|
"name": "sekai",
|
||||||
"tag": "trojan-in",
|
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
"users": [
|
|
||||||
{
|
|
||||||
"name": "sekai",
|
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg=="
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"tls": {},
|
|
||||||
"fallback": {
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 8080
|
|
||||||
},
|
|
||||||
"fallback_for_alpn": {
|
|
||||||
"http/1.1": {
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 8081
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"transport": {}
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"tls": {},
|
||||||
|
"fallback": {
|
||||||
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 8080
|
||||||
|
},
|
||||||
|
"fallback_for_alpn": {
|
||||||
|
"http/1.1": {
|
||||||
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 8081
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"transport": {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Trojan 字段
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### users
|
#### users
|
||||||
|
|
||||||
@@ -54,7 +50,7 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
|||||||
|
|
||||||
!!! error ""
|
!!! error ""
|
||||||
|
|
||||||
没有证据表明 GFW 基于 HTTP 响应检测并阻止木马服务器,并且在服务器上打开标准 http/s 端口是一个更大的特征。
|
没有证据表明 GFW 基于 HTTP 响应检测并阻止 Trojan 服务器,并且在服务器上打开标准 http/s 端口是一个更大的特征。
|
||||||
|
|
||||||
回退服务器配置。如果 `fallback` 和 `fallback_for_alpn` 为空,则禁用回退。
|
回退服务器配置。如果 `fallback` 和 `fallback_for_alpn` 为空,则禁用回退。
|
||||||
|
|
||||||
@@ -66,46 +62,4 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
|||||||
|
|
||||||
#### transport
|
#### transport
|
||||||
|
|
||||||
V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。
|
V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。
|
||||||
|
|
||||||
### 监听字段
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
为监听器启用 TCP 快速打开。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
|
|
||||||
@@ -6,48 +6,41 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "tun",
|
||||||
{
|
"tag": "tun-in",
|
||||||
"type": "tun",
|
|
||||||
"tag": "tun-in",
|
"interface_name": "tun0",
|
||||||
"interface_name": "tun0",
|
"inet4_address": "172.19.0.1/30",
|
||||||
"inet4_address": "172.19.0.1/30",
|
"inet6_address": "fdfe:dcba:9876::1/126",
|
||||||
"inet6_address": "fdfe:dcba:9876::1/128",
|
"mtu": 9000,
|
||||||
"mtu": 1500,
|
"auto_route": true,
|
||||||
"auto_route": true,
|
"strict_route": true,
|
||||||
"strict_route": true,
|
"endpoint_independent_nat": false,
|
||||||
"endpoint_independent_nat": false,
|
"stack": "gvisor",
|
||||||
"udp_timeout": 300,
|
"include_uid": [
|
||||||
"stack": "gvisor",
|
0
|
||||||
"include_uid": [
|
],
|
||||||
0
|
"include_uid_range": [
|
||||||
],
|
"1000-99999"
|
||||||
"include_uid_range": [
|
],
|
||||||
[
|
"exclude_uid": [
|
||||||
"1000-99999"
|
1000
|
||||||
]
|
],
|
||||||
],
|
"exclude_uid_range": [
|
||||||
"exclude_uid": [
|
"1000-99999"
|
||||||
1000
|
],
|
||||||
],
|
"include_android_user": [
|
||||||
"exclude_uid_range": [
|
0,
|
||||||
"1000-99999"
|
10
|
||||||
],
|
],
|
||||||
"include_android_user": [
|
"include_package": [
|
||||||
0,
|
"com.android.chrome"
|
||||||
10
|
],
|
||||||
],
|
"exclude_package": [
|
||||||
"include_package": [
|
"com.android.captiveportallogin"
|
||||||
"com.android.chrome"
|
],
|
||||||
],
|
|
||||||
"exclude_package": [
|
... // Listen Fields
|
||||||
"com.android.captiveportallogin"
|
|
||||||
],
|
|
||||||
"sniff": true,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv4"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -59,7 +52,7 @@
|
|||||||
|
|
||||||
If tun is running in non-privileged mode, addresses and MTU will not be configured automatically, please make sure the settings are accurate.
|
If tun is running in non-privileged mode, addresses and MTU will not be configured automatically, please make sure the settings are accurate.
|
||||||
|
|
||||||
### Tun Fields
|
### Fields
|
||||||
|
|
||||||
#### interface_name
|
#### interface_name
|
||||||
|
|
||||||
@@ -87,6 +80,10 @@ Set the default route to the Tun.
|
|||||||
|
|
||||||
To avoid traffic loopback, set `route.auto_detect_interface` or `route.default_interface` or `outbound.bind_interface`
|
To avoid traffic loopback, set `route.auto_detect_interface` or `route.default_interface` or `outbound.bind_interface`
|
||||||
|
|
||||||
|
!!! note "Use with Android VPN"
|
||||||
|
|
||||||
|
By default, VPN takes precedence over tun. To make tun go through VPN, enable `route.override_android_vpn`.
|
||||||
|
|
||||||
#### strict_route
|
#### strict_route
|
||||||
|
|
||||||
Enforce strict routing rules in Linux when `auto_route` is enabled:
|
Enforce strict routing rules in Linux when `auto_route` is enabled:
|
||||||
@@ -99,6 +96,10 @@ not be accessible by others.
|
|||||||
|
|
||||||
#### endpoint_independent_nat
|
#### endpoint_independent_nat
|
||||||
|
|
||||||
|
!!! info ""
|
||||||
|
|
||||||
|
This item is only available on the gvisor stack, other stacks are endpoint-independent NAT by default.
|
||||||
|
|
||||||
Enable endpoint-independent NAT.
|
Enable endpoint-independent NAT.
|
||||||
|
|
||||||
Performance may degrade slightly, so it is not recommended to enable on when it is not needed.
|
Performance may degrade slightly, so it is not recommended to enable on when it is not needed.
|
||||||
@@ -111,10 +112,11 @@ UDP NAT expiration time in seconds, default is 300 (5 minutes).
|
|||||||
|
|
||||||
TCP/IP stack.
|
TCP/IP stack.
|
||||||
|
|
||||||
| Stack | Upstream | Status |
|
| Stack | Description | Status |
|
||||||
|------------------|-----------------------------------------------------------------------|-------------------|
|
|------------------|--------------------------------------------------------------------------------|-------------------|
|
||||||
| gVisor (default) | [google/gvisor](https://github.com/google/gvisor) | recommended |
|
| gVisor (default) | Based on [google/gvisor](https://github.com/google/gvisor) | recommended |
|
||||||
| LWIP | [eycorsican/go-tun2socks](https://github.com/eycorsican/go-tun2socks) | upstream archived |
|
| system | Less compatibility and sometimes better performance. | recommended |
|
||||||
|
| LWIP | Based on [eycorsican/go-tun2socks](https://github.com/eycorsican/go-tun2socks) | upstream archived |
|
||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
@@ -163,22 +165,4 @@ Exclude android packages in route.
|
|||||||
|
|
||||||
### Listen Fields
|
### Listen Fields
|
||||||
|
|
||||||
#### sniff
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|||||||
@@ -6,48 +6,41 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "tun",
|
||||||
{
|
"tag": "tun-in",
|
||||||
"type": "tun",
|
|
||||||
"tag": "tun-in",
|
"interface_name": "tun0",
|
||||||
"interface_name": "tun0",
|
"inet4_address": "172.19.0.1/30",
|
||||||
"inet4_address": "172.19.0.1/30",
|
"inet6_address": "fdfe:dcba:9876::1/126",
|
||||||
"inet6_address": "fdfe:dcba:9876::1/128",
|
"mtu": 9000,
|
||||||
"mtu": 1500,
|
"auto_route": true,
|
||||||
"auto_route": true,
|
"strict_route": true,
|
||||||
"strict_route": true,
|
"endpoint_independent_nat": false,
|
||||||
"endpoint_independent_nat": false,
|
"stack": "gvisor",
|
||||||
"udp_timeout": 300,
|
"include_uid": [
|
||||||
"stack": "gvisor",
|
0
|
||||||
"include_uid": [
|
],
|
||||||
0
|
"include_uid_range": [
|
||||||
],
|
"1000-99999"
|
||||||
"include_uid_range": [
|
],
|
||||||
[
|
"exclude_uid": [
|
||||||
"1000-99999"
|
1000
|
||||||
]
|
],
|
||||||
],
|
"exclude_uid_range": [
|
||||||
"exclude_uid": [
|
"1000-99999"
|
||||||
1000
|
],
|
||||||
],
|
"include_android_user": [
|
||||||
"exclude_uid_range": [
|
0,
|
||||||
"1000-99999"
|
10
|
||||||
],
|
],
|
||||||
"include_android_user": [
|
"include_package": [
|
||||||
0,
|
"com.android.chrome"
|
||||||
10
|
],
|
||||||
],
|
"exclude_package": [
|
||||||
"include_package": [
|
"com.android.captiveportallogin"
|
||||||
"com.android.chrome"
|
],
|
||||||
],
|
|
||||||
"exclude_package": [
|
... // 监听字段
|
||||||
"com.android.captiveportallogin"
|
|
||||||
],
|
|
||||||
"sniff": true,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv4"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -87,6 +80,10 @@ tun 接口的 IPv6 前缀。
|
|||||||
|
|
||||||
为避免流量环回,请设置 `route.auto_detect_interface` 或 `route.default_interface` 或 `outbound.bind_interface`。
|
为避免流量环回,请设置 `route.auto_detect_interface` 或 `route.default_interface` 或 `outbound.bind_interface`。
|
||||||
|
|
||||||
|
!!! note "与 Android VPN 一起使用"
|
||||||
|
|
||||||
|
VPN 默认优先于 tun。要使 tun 经过 VPN,启用 `route.override_android_vpn`。
|
||||||
|
|
||||||
#### strict_route
|
#### strict_route
|
||||||
|
|
||||||
在 Linux 中启用 `auto_route` 时执行严格的路由规则。
|
在 Linux 中启用 `auto_route` 时执行严格的路由规则。
|
||||||
@@ -110,10 +107,11 @@ UDP NAT 过期时间,以秒为单位,默认为 300(5 分钟)。
|
|||||||
|
|
||||||
TCP/IP 栈。
|
TCP/IP 栈。
|
||||||
|
|
||||||
| 栈 | 上游 | 状态 |
|
| 栈 | 描述 | 状态 |
|
||||||
|------------------|-----------------------------------------------------------------------|-------|
|
|------------------|--------------------------------------------------------------------------|-------|
|
||||||
| gVisor (default) | [google/gvisor](https://github.com/google/gvisor) | 推荐 |
|
| gVisor (default) | 基于 [google/gvisor](https://github.com/google/gvisor) | 推荐 |
|
||||||
| LWIP | [eycorsican/go-tun2socks](https://github.com/eycorsican/go-tun2socks) | 上游已存档 |
|
| system | 兼容性较差,有时性能更好。 | 推荐 |
|
||||||
|
| LWIP | 基于 [eycorsican/go-tun2socks](https://github.com/eycorsican/go-tun2socks) | 上游已存档 |
|
||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
||||||
@@ -162,22 +160,4 @@ TCP/IP 栈。
|
|||||||
|
|
||||||
### 监听字段
|
### 监听字段
|
||||||
|
|
||||||
#### sniff
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
@@ -2,34 +2,28 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "vmess",
|
||||||
{
|
"tag": "vmess-in",
|
||||||
"type": "vmess",
|
|
||||||
"tag": "vmess-in",
|
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"users": [
|
... // Listen Fields
|
||||||
{
|
|
||||||
"name": "sekai",
|
"users": [
|
||||||
"uuid": "bf000d23-0752-40b4-affe-68f7707a9661",
|
{
|
||||||
"alterId": 0
|
"name": "sekai",
|
||||||
}
|
"uuid": "bf000d23-0752-40b4-affe-68f7707a9661",
|
||||||
],
|
"alterId": 0
|
||||||
"tls": {},
|
|
||||||
"transport": {}
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"tls": {},
|
||||||
|
"transport": {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### VMess Fields
|
### Listen Fields
|
||||||
|
|
||||||
|
See [Listen Fields](/configuration/shared/listen) for details.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
#### users
|
#### users
|
||||||
|
|
||||||
@@ -53,45 +47,3 @@ TLS configuration, see [TLS](/configuration/shared/tls/#inbound).
|
|||||||
#### transport
|
#### transport
|
||||||
|
|
||||||
V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport).
|
V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray-transport).
|
||||||
|
|
||||||
### Listen Fields
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen address.
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==Required==
|
|
||||||
|
|
||||||
Listen port.
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
Enable tcp fast open for listener.
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
Enable sniffing.
|
|
||||||
|
|
||||||
See [Protocol Sniff](/configuration/route/sniff/) for details.
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
Override the connection destination address with the sniffed domain.
|
|
||||||
|
|
||||||
If the domain name is invalid (like tor), this will not work.
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before routing.
|
|
||||||
|
|
||||||
If `sniff_override_destination` is in effect, its value will be taken as a fallback.
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
Parse [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) in the connection header.
|
|
||||||
@@ -2,34 +2,28 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"inbounds": [
|
"type": "vmess",
|
||||||
{
|
"tag": "vmess-in",
|
||||||
"type": "vmess",
|
|
||||||
"tag": "vmess-in",
|
|
||||||
|
|
||||||
"listen": "::",
|
|
||||||
"listen_port": 2080,
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"sniff": false,
|
|
||||||
"sniff_override_destination": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"proxy_protocol": false,
|
|
||||||
|
|
||||||
"users": [
|
... // 监听字段
|
||||||
{
|
|
||||||
"name": "sekai",
|
"users": [
|
||||||
"uuid": "bf000d23-0752-40b4-affe-68f7707a9661",
|
{
|
||||||
"alterId": 0
|
"name": "sekai",
|
||||||
}
|
"uuid": "bf000d23-0752-40b4-affe-68f7707a9661",
|
||||||
],
|
"alterId": 0
|
||||||
"tls": {},
|
|
||||||
"transport": {}
|
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"tls": {},
|
||||||
|
"transport": {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### VMess 字段
|
### 监听字段
|
||||||
|
|
||||||
|
参阅 [监听字段](/zh/configuration/shared/listen/)。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
#### users
|
#### users
|
||||||
|
|
||||||
@@ -53,45 +47,3 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#inbound)。
|
|||||||
#### transport
|
#### transport
|
||||||
|
|
||||||
V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。
|
V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-transport)。
|
||||||
|
|
||||||
### 监听字段
|
|
||||||
|
|
||||||
#### listen
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听地址。
|
|
||||||
|
|
||||||
#### listen_port
|
|
||||||
|
|
||||||
==必填==
|
|
||||||
|
|
||||||
监听端口。
|
|
||||||
|
|
||||||
#### tcp_fast_open
|
|
||||||
|
|
||||||
为监听器启用 TCP 快速打开。
|
|
||||||
|
|
||||||
#### sniff
|
|
||||||
|
|
||||||
启用协议探测。
|
|
||||||
|
|
||||||
参阅 [协议探测](/zh/configuration/route/sniff/)。
|
|
||||||
|
|
||||||
#### sniff_override_destination
|
|
||||||
|
|
||||||
用探测出的域名覆盖连接目标地址。
|
|
||||||
|
|
||||||
如果域名无效(如 Tor),将不生效。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值: `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,请求的域名将在路由之前解析为 IP。
|
|
||||||
|
|
||||||
如果 `sniff_override_destination` 生效,它的值将作为后备。
|
|
||||||
|
|
||||||
#### proxy_protocol
|
|
||||||
|
|
||||||
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ sing-box uses JSON for configuration files.
|
|||||||
{
|
{
|
||||||
"log": {},
|
"log": {},
|
||||||
"dns": {},
|
"dns": {},
|
||||||
"inbounds": {},
|
"inbounds": [],
|
||||||
"outbounds": {},
|
"outbounds": [],
|
||||||
"route": {},
|
"route": {},
|
||||||
"experimental": {}
|
"experimental": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ sing-box 使用 JSON 作为配置文件格式。
|
|||||||
{
|
{
|
||||||
"log": {},
|
"log": {},
|
||||||
"dns": {},
|
"dns": {},
|
||||||
"inbounds": {},
|
"inbounds": [],
|
||||||
"outbounds": {},
|
"outbounds": [],
|
||||||
"route": {},
|
"route": {},
|
||||||
"experimental": {}
|
"experimental": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# Log
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# 日志
|
||||||
|
|
||||||
### 结构
|
### 结构
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -4,12 +4,8 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "block",
|
||||||
{
|
"tag": "block"
|
||||||
"type": "block",
|
|
||||||
"tag": "block"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,8 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "block",
|
||||||
{
|
"tag": "block"
|
||||||
"type": "block",
|
|
||||||
"tag": "block"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -4,30 +4,18 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "direct",
|
||||||
{
|
"tag": "direct-out",
|
||||||
"type": "direct",
|
|
||||||
"tag": "direct-out",
|
"override_address": "1.0.0.1",
|
||||||
|
"override_port": 53,
|
||||||
"override_address": "1.0.0.1",
|
"proxy_protocol": 0,
|
||||||
"override_port": 53,
|
|
||||||
"proxy_protocol": 0,
|
... // Dial Fields
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Direct Fields
|
### Fields
|
||||||
|
|
||||||
#### override_address
|
#### override_address
|
||||||
|
|
||||||
@@ -45,54 +33,4 @@ Protocol value can be `1` or `2`.
|
|||||||
|
|
||||||
### Dial Fields
|
### Dial Fields
|
||||||
|
|
||||||
#### detour
|
See [Dial Fields](/configuration/shared/dial) for details.
|
||||||
|
|
||||||
The tag of the upstream outbound.
|
|
||||||
|
|
||||||
Other dial fields will be ignored when enabled.
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
The network interface to bind to.
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
The address to bind to.
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
Only supported on Linux.
|
|
||||||
|
|
||||||
Set netfilter routing mark.
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
Reuse listener address.
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
Connect timeout, in golang's Duration format.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of
|
|
||||||
decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the requested domain name will be resolved to IP before connect.
|
|
||||||
|
|
||||||
`dns.strategy` will be used if empty.
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
The length of time to wait before spawning a RFC 6555 Fast Fallback connection.
|
|
||||||
That is, is the amount of time to wait for IPv6 to succeed before assuming
|
|
||||||
that IPv6 is misconfigured and falling back to IPv4 if `prefer_ipv4` is set.
|
|
||||||
If zero, a default delay of 300ms is used.
|
|
||||||
|
|
||||||
Only take effect when `domain_strategy` is `prefer_ipv4` or `prefer_ipv6`.
|
|
||||||
|
|||||||
@@ -4,30 +4,18 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "direct",
|
||||||
{
|
"tag": "direct-out",
|
||||||
"type": "direct",
|
|
||||||
"tag": "direct-out",
|
"override_address": "1.0.0.1",
|
||||||
|
"override_port": 53,
|
||||||
"override_address": "1.0.0.1",
|
"proxy_protocol": 0,
|
||||||
"override_port": 53,
|
|
||||||
"proxy_protocol": 0,
|
... // 拨号字段
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Direct 字段
|
### 字段
|
||||||
|
|
||||||
#### override_address
|
#### override_address
|
||||||
|
|
||||||
@@ -45,51 +33,4 @@
|
|||||||
|
|
||||||
### 拨号字段
|
### 拨号字段
|
||||||
|
|
||||||
#### detour
|
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||||
|
|
||||||
上游出站的标签。
|
|
||||||
|
|
||||||
启用时,其他拨号字段将被忽略。
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
要绑定到的网络接口。
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
要绑定的地址。
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置 netfilter 路由标记。
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
重用监听地址。
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
连接超时,采用 golang 的 Duration 格式。
|
|
||||||
|
|
||||||
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
|
||||||
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,域名将在请求发出之前解析为 IP。
|
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
在生成 RFC 6555 快速回退连接之前等待的时间长度。
|
|
||||||
也就是说,是在假设之前等待 IPv6 成功的时间量如果设置了 "prefer_ipv4",则 IPv6 配置错误并回退到 IPv4。
|
|
||||||
如果为零,则使用 300 毫秒的默认延迟。
|
|
||||||
|
|
||||||
仅当 `domain_strategy` 为 `prefer_ipv4` 或 `prefer_ipv6` 时生效。
|
|
||||||
|
|||||||
@@ -4,12 +4,8 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "dns",
|
||||||
{
|
"tag": "dns-out"
|
||||||
"type": "dns",
|
|
||||||
"tag": "dns-out"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,8 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "dns",
|
||||||
{
|
"tag": "dns-out"
|
||||||
"type": "dns",
|
|
||||||
"tag": "dns-out"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -4,32 +4,20 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "http",
|
||||||
{
|
"tag": "http-out",
|
||||||
"type": "http",
|
|
||||||
"tag": "http-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
"server": "127.0.0.1",
|
"username": "sekai",
|
||||||
"server_port": 1080,
|
"password": "admin",
|
||||||
"username": "sekai",
|
"tls": {},
|
||||||
"password": "admin",
|
|
||||||
"tls": {},
|
... // Dial Fields
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### HTTP Fields
|
### Fields
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -57,54 +45,4 @@ TLS configuration, see [TLS](/configuration/shared/tls/#outbound).
|
|||||||
|
|
||||||
### Dial Fields
|
### Dial Fields
|
||||||
|
|
||||||
#### detour
|
See [Dial Fields](/configuration/shared/dial) for details.
|
||||||
|
|
||||||
The tag of the upstream outbound.
|
|
||||||
|
|
||||||
Other dial fields will be ignored when enabled.
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
The network interface to bind to.
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
The address to bind to.
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
Only supported on Linux.
|
|
||||||
|
|
||||||
Set netfilter routing mark.
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
Reuse listener address.
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
Connect timeout, in golang's Duration format.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of
|
|
||||||
decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the server domain name will be resolved to IP before connecting.
|
|
||||||
|
|
||||||
`dns.strategy` will be used if empty.
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
The length of time to wait before spawning a RFC 6555 Fast Fallback connection.
|
|
||||||
That is, is the amount of time to wait for IPv6 to succeed before assuming
|
|
||||||
that IPv6 is misconfigured and falling back to IPv4 if `prefer_ipv4` is set.
|
|
||||||
If zero, a default delay of 300ms is used.
|
|
||||||
|
|
||||||
Only take effect when `domain_strategy` is `prefer_ipv4` or `prefer_ipv6`.
|
|
||||||
|
|||||||
@@ -4,32 +4,20 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "http",
|
||||||
{
|
"tag": "http-out",
|
||||||
"type": "http",
|
|
||||||
"tag": "http-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
"server": "127.0.0.1",
|
"username": "sekai",
|
||||||
"server_port": 1080,
|
"password": "admin",
|
||||||
"username": "sekai",
|
"tls": {},
|
||||||
"password": "admin",
|
|
||||||
"tls": {},
|
... // 拨号字段
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### HTTP 字段
|
### 字段
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -57,51 +45,4 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。
|
|||||||
|
|
||||||
### 拨号字段
|
### 拨号字段
|
||||||
|
|
||||||
#### detour
|
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||||
|
|
||||||
上游出站的标签。
|
|
||||||
|
|
||||||
启用时,其他拨号字段将被忽略。
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
要绑定到的网络接口。
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
要绑定的地址。
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置 netfilter 路由标记。
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
重用监听地址。
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
连接超时,采用 golang 的 Duration 格式。
|
|
||||||
|
|
||||||
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
|
||||||
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,服务器域名将在连接前解析为 IP。
|
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
在生成 RFC 6555 快速回退连接之前等待的时间长度。
|
|
||||||
也就是说,是在假设之前等待 IPv6 成功的时间量如果设置了 "prefer_ipv4",则 IPv6 配置错误并回退到 IPv4。
|
|
||||||
如果为零,则使用 300 毫秒的默认延迟。
|
|
||||||
|
|
||||||
仅当 `domain_strategy` 为 `prefer_ipv4` 或 `prefer_ipv6` 时生效。
|
|
||||||
|
|||||||
@@ -2,37 +2,25 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "hysteria",
|
||||||
{
|
"tag": "hysteria-out",
|
||||||
"type": "hysteria",
|
|
||||||
"tag": "hysteria-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
"server": "127.0.0.1",
|
"up": "100 Mbps",
|
||||||
"server_port": 1080,
|
"up_mbps": 100,
|
||||||
|
"down": "100 Mbps",
|
||||||
"up": "100 Mbps",
|
"down_mbps": 100,
|
||||||
"up_mbps": 100,
|
"obfs": "fuck me till the daylight",
|
||||||
"down": "100 Mbps",
|
"auth": "",
|
||||||
"down_mbps": 100,
|
"auth_str": "password",
|
||||||
"obfs": "fuck me till the daylight",
|
"recv_window_conn": 0,
|
||||||
"auth": "",
|
"recv_window": 0,
|
||||||
"auth_str": "password",
|
"disable_mtu_discovery": false,
|
||||||
"recv_window_conn": 0,
|
"network": "tcp",
|
||||||
"recv_window": 0,
|
"tls": {},
|
||||||
"disable_mtu_discovery": false,
|
|
||||||
"network": "tcp",
|
... // Dial Fields
|
||||||
"tls": {},
|
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -40,7 +28,7 @@
|
|||||||
|
|
||||||
QUIC, which is required by hysteria is not included by default, see [Installation](/#installation).
|
QUIC, which is required by hysteria is not included by default, see [Installation](/#installation).
|
||||||
|
|
||||||
### Hysteria Fields
|
### Fields
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -125,54 +113,4 @@ Both is enabled by default.
|
|||||||
|
|
||||||
### Dial Fields
|
### Dial Fields
|
||||||
|
|
||||||
#### detour
|
See [Dial Fields](/configuration/shared/dial) for details.
|
||||||
|
|
||||||
The tag of the upstream outbound.
|
|
||||||
|
|
||||||
Other dial fields will be ignored when enabled.
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
The network interface to bind to.
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
The address to bind to.
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
Only supported on Linux.
|
|
||||||
|
|
||||||
Set netfilter routing mark.
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
Reuse listener address.
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
Connect timeout, in golang's Duration format.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of
|
|
||||||
decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the server domain name will be resolved to IP before connecting.
|
|
||||||
|
|
||||||
`dns.strategy` will be used if empty.
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
The length of time to wait before spawning a RFC 6555 Fast Fallback connection.
|
|
||||||
That is, is the amount of time to wait for IPv6 to succeed before assuming
|
|
||||||
that IPv6 is misconfigured and falling back to IPv4 if `prefer_ipv4` is set.
|
|
||||||
If zero, a default delay of 300ms is used.
|
|
||||||
|
|
||||||
Only take effect when `domain_strategy` is `prefer_ipv4` or `prefer_ipv6`.
|
|
||||||
|
|||||||
@@ -2,37 +2,25 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "hysteria",
|
||||||
{
|
"tag": "hysteria-out",
|
||||||
"type": "hysteria",
|
|
||||||
"tag": "hysteria-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
"server": "127.0.0.1",
|
"up": "100 Mbps",
|
||||||
"server_port": 1080,
|
"up_mbps": 100,
|
||||||
|
"down": "100 Mbps",
|
||||||
"up": "100 Mbps",
|
"down_mbps": 100,
|
||||||
"up_mbps": 100,
|
"obfs": "fuck me till the daylight",
|
||||||
"down": "100 Mbps",
|
"auth": "",
|
||||||
"down_mbps": 100,
|
"auth_str": "password",
|
||||||
"obfs": "fuck me till the daylight",
|
"recv_window_conn": 0,
|
||||||
"auth": "",
|
"recv_window": 0,
|
||||||
"auth_str": "password",
|
"disable_mtu_discovery": false,
|
||||||
"recv_window_conn": 0,
|
"network": "tcp",
|
||||||
"recv_window": 0,
|
"tls": {},
|
||||||
"disable_mtu_discovery": false,
|
|
||||||
"network": "tcp",
|
... // 拨号字段
|
||||||
"tls": {},
|
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -40,7 +28,7 @@
|
|||||||
|
|
||||||
默认安装不包含被 Hysteria 依赖的 QUIC,参阅 [安装](/zh/#_2)。
|
默认安装不包含被 Hysteria 依赖的 QUIC,参阅 [安装](/zh/#_2)。
|
||||||
|
|
||||||
### Hysteria 字段
|
### 字段
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -123,51 +111,4 @@ TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。
|
|||||||
|
|
||||||
### 拨号字段
|
### 拨号字段
|
||||||
|
|
||||||
#### detour
|
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||||
|
|
||||||
上游出站的标签。
|
|
||||||
|
|
||||||
启用时,其他拨号字段将被忽略。
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
要绑定到的网络接口。
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
要绑定的地址。
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置 netfilter 路由标记。
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
重用监听地址
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
连接超时,采用 golang 的 Duration 格式。
|
|
||||||
|
|
||||||
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
|
||||||
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,服务器域名将在连接前解析为 IP。
|
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
在生成 RFC 6555 快速回退连接之前等待的时间长度。
|
|
||||||
也就是说,是在假设之前等待 IPv6 成功的时间量如果设置了 "prefer_ipv4",则 IPv6 配置错误并回退到 IPv4。
|
|
||||||
如果为零,则使用 300 毫秒的默认延迟。
|
|
||||||
|
|
||||||
仅当 `domain_strategy` 为 `prefer_ipv4` 或 `prefer_ipv6` 时生效。
|
|
||||||
|
|||||||
@@ -2,19 +2,15 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"type": "selector",
|
||||||
|
"tag": "select",
|
||||||
|
|
||||||
"outbounds": [
|
"outbounds": [
|
||||||
{
|
"proxy-a",
|
||||||
"type": "selector",
|
"proxy-b",
|
||||||
"tag": "select",
|
"proxy-c"
|
||||||
|
],
|
||||||
"outbounds": [
|
"default": "proxy-c"
|
||||||
"proxy-a",
|
|
||||||
"proxy-b",
|
|
||||||
"proxy-c"
|
|
||||||
],
|
|
||||||
"default": "proxy-c"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -2,19 +2,15 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
"type": "selector",
|
||||||
|
"tag": "select",
|
||||||
|
|
||||||
"outbounds": [
|
"outbounds": [
|
||||||
{
|
"proxy-a",
|
||||||
"type": "selector",
|
"proxy-b",
|
||||||
"tag": "select",
|
"proxy-c"
|
||||||
|
],
|
||||||
"outbounds": [
|
"default": "proxy-c"
|
||||||
"proxy-a",
|
|
||||||
"proxy-b",
|
|
||||||
"proxy-c"
|
|
||||||
],
|
|
||||||
"default": "proxy-c"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -2,34 +2,24 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "shadowsocks",
|
||||||
{
|
"tag": "ss-out",
|
||||||
"type": "shadowsocks",
|
|
||||||
"tag": "ss-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
"server": "127.0.0.1",
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
"server_port": 1080,
|
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
"plugin": "",
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
"plugin_opts": "",
|
||||||
"network": "udp",
|
"network": "udp",
|
||||||
"udp_over_tcp": false,
|
"udp_over_tcp": false,
|
||||||
"multiplex": {},
|
"multiplex": {},
|
||||||
|
|
||||||
"detour": "upstream-out",
|
... // Dial Fields
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Shadowsocks Fields
|
### Fields
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -77,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
|
||||||
@@ -97,54 +97,4 @@ Multiplex configuration, see [Multiplex](/configuration/shared/multiplex).
|
|||||||
|
|
||||||
### Dial Fields
|
### Dial Fields
|
||||||
|
|
||||||
#### detour
|
See [Dial Fields](/configuration/shared/dial) for details.
|
||||||
|
|
||||||
The tag of the upstream outbound.
|
|
||||||
|
|
||||||
Other dial fields will be ignored when enabled.
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
The network interface to bind to.
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
The address to bind to.
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
Only supported on Linux.
|
|
||||||
|
|
||||||
Set netfilter routing mark.
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
Reuse listener address.
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
Connect timeout, in golang's Duration format.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of
|
|
||||||
decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the server domain name will be resolved to IP before connecting.
|
|
||||||
|
|
||||||
`dns.strategy` will be used if empty.
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
The length of time to wait before spawning a RFC 6555 Fast Fallback connection.
|
|
||||||
That is, is the amount of time to wait for IPv6 to succeed before assuming
|
|
||||||
that IPv6 is misconfigured and falling back to IPv4 if `prefer_ipv4` is set.
|
|
||||||
If zero, a default delay of 300ms is used.
|
|
||||||
|
|
||||||
Only take effect when `domain_strategy` is `prefer_ipv4` or `prefer_ipv6`.
|
|
||||||
|
|||||||
@@ -1,35 +1,25 @@
|
|||||||
### Structure
|
### 结构
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "shadowsocks",
|
||||||
{
|
"tag": "ss-out",
|
||||||
"type": "shadowsocks",
|
|
||||||
"tag": "ss-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
"server": "127.0.0.1",
|
"method": "2022-blake3-aes-128-gcm",
|
||||||
"server_port": 1080,
|
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
||||||
"method": "2022-blake3-aes-128-gcm",
|
"plugin": "",
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
"plugin_opts": "",
|
||||||
"network": "udp",
|
"network": "udp",
|
||||||
"udp_over_tcp": false,
|
"udp_over_tcp": false,
|
||||||
"multiplex": {},
|
"multiplex": {},
|
||||||
|
|
||||||
"detour": "upstream-out",
|
... // 拨号字段
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Shadowsocks 字段
|
### 字段
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -77,6 +67,16 @@
|
|||||||
|
|
||||||
Shadowsocks 密码。
|
Shadowsocks 密码。
|
||||||
|
|
||||||
|
#### plugin
|
||||||
|
|
||||||
|
Shadowsocks SIP003 插件,由内部实现。
|
||||||
|
|
||||||
|
仅支持 `obfs-local` 和 `v2ray-plugin`。
|
||||||
|
|
||||||
|
#### plugin_opts
|
||||||
|
|
||||||
|
Shadowsocks SIP003 插件参数。
|
||||||
|
|
||||||
#### network
|
#### network
|
||||||
|
|
||||||
启用的网络协议
|
启用的网络协议
|
||||||
@@ -97,51 +97,4 @@ Shadowsocks 密码。
|
|||||||
|
|
||||||
### 拨号字段
|
### 拨号字段
|
||||||
|
|
||||||
#### detour
|
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||||
|
|
||||||
上游出站的标签。
|
|
||||||
|
|
||||||
启用时,其他拨号字段将被忽略。
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
要绑定到的网络接口。
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
要绑定的地址。
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置 netfilter 路由标记。
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
重用监听地址。
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
连接超时,采用 golang 的 Duration 格式。
|
|
||||||
|
|
||||||
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
|
||||||
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,服务器域名将在连接前解析为 IP。
|
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
在生成 RFC 6555 快速回退连接之前等待的时间长度。
|
|
||||||
也就是说,是在假设之前等待 IPv6 成功的时间量如果设置了 "prefer_ipv4",则 IPv6 配置错误并回退到 IPv4。
|
|
||||||
如果为零,则使用 300 毫秒的默认延迟。
|
|
||||||
|
|
||||||
仅当 `domain_strategy` 为 `prefer_ipv4` 或 `prefer_ipv6` 时生效。
|
|
||||||
|
|||||||
106
docs/configuration/outbound/shadowsocksr.md
Normal file
106
docs/configuration/outbound/shadowsocksr.md
Normal 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.
|
||||||
106
docs/configuration/outbound/shadowsocksr.zh.md
Normal file
106
docs/configuration/outbound/shadowsocksr.zh.md
Normal 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/)。
|
||||||
38
docs/configuration/outbound/shadowtls.md
Normal file
38
docs/configuration/outbound/shadowtls.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
### Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "shadowtls",
|
||||||
|
"tag": "st-out",
|
||||||
|
|
||||||
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
|
"tls": {},
|
||||||
|
|
||||||
|
... // Dial Fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
#### server
|
||||||
|
|
||||||
|
==Required==
|
||||||
|
|
||||||
|
The server address.
|
||||||
|
|
||||||
|
#### server_port
|
||||||
|
|
||||||
|
==Required==
|
||||||
|
|
||||||
|
The server port.
|
||||||
|
|
||||||
|
#### tls
|
||||||
|
|
||||||
|
==Required==
|
||||||
|
|
||||||
|
TLS configuration, see [TLS](/configuration/shared/tls/#outbound).
|
||||||
|
|
||||||
|
### Dial Fields
|
||||||
|
|
||||||
|
See [Dial Fields](/configuration/shared/dial) for details.
|
||||||
38
docs/configuration/outbound/shadowtls.zh.md
Normal file
38
docs/configuration/outbound/shadowtls.zh.md
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
### 结构
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "shadowtls",
|
||||||
|
"tag": "st-out",
|
||||||
|
|
||||||
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
|
"tls": {},
|
||||||
|
|
||||||
|
... // 拨号字段
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
|
#### server
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
服务器地址。
|
||||||
|
|
||||||
|
#### server_port
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
服务器端口。
|
||||||
|
|
||||||
|
#### tls
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。
|
||||||
|
|
||||||
|
### 拨号字段
|
||||||
|
|
||||||
|
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||||
@@ -4,34 +4,22 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "socks",
|
||||||
{
|
"tag": "socks-out",
|
||||||
"type": "socks",
|
|
||||||
"tag": "socks-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
"server": "127.0.0.1",
|
"version": "5",
|
||||||
"server_port": 1080,
|
"username": "sekai",
|
||||||
"version": "5",
|
"password": "admin",
|
||||||
"username": "sekai",
|
"network": "udp",
|
||||||
"password": "admin",
|
"udp_over_tcp": false,
|
||||||
"network": "udp",
|
|
||||||
"udp_over_tcp": false,
|
|
||||||
|
|
||||||
"detour": "upstream-out",
|
... // Dial Fields
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### SOCKS Fields
|
### Fields
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -73,54 +61,4 @@ Enable the UDP over TCP protocol.
|
|||||||
|
|
||||||
### Dial Fields
|
### Dial Fields
|
||||||
|
|
||||||
#### detour
|
See [Dial Fields](/configuration/shared/dial) for details.
|
||||||
|
|
||||||
The tag of the upstream outbound.
|
|
||||||
|
|
||||||
Other dial fields will be ignored when enabled.
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
The network interface to bind to.
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
The address to bind to.
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
Only supported on Linux.
|
|
||||||
|
|
||||||
Set netfilter routing mark.
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
Reuse listener address.
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
Connect timeout, in golang's Duration format.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of
|
|
||||||
decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the server domain name will be resolved to IP before connecting.
|
|
||||||
|
|
||||||
`dns.strategy` will be used if empty.
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
The length of time to wait before spawning a RFC 6555 Fast Fallback connection.
|
|
||||||
That is, is the amount of time to wait for IPv6 to succeed before assuming
|
|
||||||
that IPv6 is misconfigured and falling back to IPv4 if `prefer_ipv4` is set.
|
|
||||||
If zero, a default delay of 300ms is used.
|
|
||||||
|
|
||||||
Only take effect when `domain_strategy` is `prefer_ipv4` or `prefer_ipv6`.
|
|
||||||
|
|||||||
@@ -1,37 +1,25 @@
|
|||||||
`socks` 出站是 socks4/socks4a/socks5 客户端
|
`socks` 出站是 socks4/socks4a/socks5 客户端
|
||||||
|
|
||||||
### Structure
|
### 结构
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "socks",
|
||||||
{
|
"tag": "socks-out",
|
||||||
"type": "socks",
|
|
||||||
"tag": "socks-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
"server": "127.0.0.1",
|
"version": "5",
|
||||||
"server_port": 1080,
|
"username": "sekai",
|
||||||
"version": "5",
|
"password": "admin",
|
||||||
"username": "sekai",
|
"network": "udp",
|
||||||
"password": "admin",
|
"udp_over_tcp": false,
|
||||||
"network": "udp",
|
|
||||||
"udp_over_tcp": false,
|
|
||||||
|
|
||||||
"detour": "upstream-out",
|
... // 拨号字段
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### SOCKS 字段
|
### 字段
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -73,51 +61,4 @@ SOCKS5 密码。
|
|||||||
|
|
||||||
### 拨号字段
|
### 拨号字段
|
||||||
|
|
||||||
#### detour
|
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||||
|
|
||||||
上游出站的标签。
|
|
||||||
|
|
||||||
启用时,其他拨号字段将被忽略。
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
要绑定到的网络接口。
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
要绑定的地址。
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置 netfilter 路由标记。
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
重用监听地址。
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
连接超时,采用 golang 的 Duration 格式。
|
|
||||||
|
|
||||||
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
|
||||||
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,服务器域名将在连接前解析为 IP。
|
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
在生成 RFC 6555 快速回退连接之前等待的时间长度。
|
|
||||||
也就是说,是在假设之前等待 IPv6 成功的时间量如果设置了 "prefer_ipv4",则 IPv6 配置错误并回退到 IPv4。
|
|
||||||
如果为零,则使用 300 毫秒的默认延迟。
|
|
||||||
|
|
||||||
仅当 `domain_strategy` 为 `prefer_ipv4` 或 `prefer_ipv6` 时生效。
|
|
||||||
|
|||||||
@@ -2,36 +2,24 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "ssh",
|
||||||
{
|
"tag": "ssh-out",
|
||||||
"type": "ssh",
|
|
||||||
"tag": "ssh-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 22,
|
||||||
"server": "127.0.0.1",
|
"user": "root",
|
||||||
"server_port": 22,
|
"password": "admin",
|
||||||
"user": "root",
|
"private_key": "",
|
||||||
"password": "admin",
|
"private_key_path": "$HOME/.ssh/id_rsa",
|
||||||
"private_key": "",
|
"private_key_passphrase": "",
|
||||||
"private_key_path": "$HOME/.ssh/id_rsa",
|
"host_key_algorithms": [],
|
||||||
"private_key_passphrase": "",
|
"client_version": "SSH-2.0-OpenSSH_7.4p1",
|
||||||
"host_key_algorithms": [],
|
|
||||||
"client_version": "SSH-2.0-OpenSSH_7.4p1",
|
... // Dial Fields
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### SSH Fields
|
### Fields
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -73,54 +61,4 @@ Client version. Random version will be used if empty.
|
|||||||
|
|
||||||
### Dial Fields
|
### Dial Fields
|
||||||
|
|
||||||
#### detour
|
See [Dial Fields](/configuration/shared/dial) for details.
|
||||||
|
|
||||||
The tag of the upstream outbound.
|
|
||||||
|
|
||||||
Other dial fields will be ignored when enabled.
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
The network interface to bind to.
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
The address to bind to.
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
Only supported on Linux.
|
|
||||||
|
|
||||||
Set netfilter routing mark.
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
Reuse listener address.
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
Connect timeout, in golang's Duration format.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of
|
|
||||||
decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the server domain name will be resolved to IP before connecting.
|
|
||||||
|
|
||||||
`dns.strategy` will be used if empty.
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
The length of time to wait before spawning a RFC 6555 Fast Fallback connection.
|
|
||||||
That is, is the amount of time to wait for IPv6 to succeed before assuming
|
|
||||||
that IPv6 is misconfigured and falling back to IPv4 if `prefer_ipv4` is set.
|
|
||||||
If zero, a default delay of 300ms is used.
|
|
||||||
|
|
||||||
Only take effect when `domain_strategy` is `prefer_ipv4` or `prefer_ipv6`.
|
|
||||||
|
|||||||
@@ -1,37 +1,25 @@
|
|||||||
### Structure
|
### 结构
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "ssh",
|
||||||
{
|
"tag": "ssh-out",
|
||||||
"type": "ssh",
|
|
||||||
"tag": "ssh-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 22,
|
||||||
"server": "127.0.0.1",
|
"user": "root",
|
||||||
"server_port": 22,
|
"password": "admin",
|
||||||
"user": "root",
|
"private_key": "",
|
||||||
"password": "admin",
|
"private_key_path": "$HOME/.ssh/id_rsa",
|
||||||
"private_key": "",
|
"private_key_passphrase": "",
|
||||||
"private_key_path": "$HOME/.ssh/id_rsa",
|
"host_key_algorithms": [],
|
||||||
"private_key_passphrase": "",
|
"client_version": "SSH-2.0-OpenSSH_7.4p1",
|
||||||
"host_key_algorithms": [],
|
|
||||||
"client_version": "SSH-2.0-OpenSSH_7.4p1",
|
... // 拨号字段
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### SSH 字段
|
### 字段
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -73,51 +61,4 @@ SSH 用户, 默认使用 root。
|
|||||||
|
|
||||||
### 拨号字段
|
### 拨号字段
|
||||||
|
|
||||||
#### detour
|
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||||
|
|
||||||
上游出站的标签。
|
|
||||||
|
|
||||||
启用时,其他拨号字段将被忽略。
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
要绑定到的网络接口。
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
要绑定的地址。
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置 netfilter 路由标记。
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
重用监听地址。
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
连接超时,采用 golang 的 Duration 格式。
|
|
||||||
|
|
||||||
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
|
||||||
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,服务器域名将在连接前解析为 IP。
|
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
在生成 RFC 6555 快速回退连接之前等待的时间长度。
|
|
||||||
也就是说,是在假设之前等待 IPv6 成功的时间量如果设置了 "prefer_ipv4",则 IPv6 配置错误并回退到 IPv4。
|
|
||||||
如果为零,则使用 300 毫秒的默认延迟。
|
|
||||||
|
|
||||||
仅当 `domain_strategy` 为 `prefer_ipv4` 或 `prefer_ipv6` 时生效。
|
|
||||||
|
|||||||
@@ -2,29 +2,17 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "tor",
|
||||||
{
|
"tag": "tor-out",
|
||||||
"type": "tor",
|
|
||||||
"tag": "tor-out",
|
"executable_path": "/usr/bin/tor",
|
||||||
|
"extra_args": [],
|
||||||
"executable_path": "/usr/bin/tor",
|
"data_directory": "$HOME/.cache/tor",
|
||||||
"extra_args": [],
|
"torrc": {
|
||||||
"data_directory": "$HOME/.cache/tor",
|
"ClientOnly": 1
|
||||||
"torrc": {
|
},
|
||||||
"ClientOnly": 1
|
|
||||||
},
|
... // Dial Fields
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -32,7 +20,7 @@
|
|||||||
|
|
||||||
Embedded tor is not included by default, see [Installation](/#installation).
|
Embedded tor is not included by default, see [Installation](/#installation).
|
||||||
|
|
||||||
### Tor Fields
|
### Fields
|
||||||
|
|
||||||
#### executable_path
|
#### executable_path
|
||||||
|
|
||||||
@@ -56,58 +44,8 @@ Each start will be very slow if not specified.
|
|||||||
|
|
||||||
Map of torrc options.
|
Map of torrc options.
|
||||||
|
|
||||||
See [tor(1)](https://linux.die.net/man/1/tor)
|
See [tor(1)](https://linux.die.net/man/1/tor) for details.
|
||||||
|
|
||||||
### Dial Fields
|
### Dial Fields
|
||||||
|
|
||||||
#### detour
|
See [Dial Fields](/configuration/shared/dial) for details.
|
||||||
|
|
||||||
The tag of the upstream outbound.
|
|
||||||
|
|
||||||
Other dial fields will be ignored when enabled.
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
The network interface to bind to.
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
The address to bind to.
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
Only supported on Linux.
|
|
||||||
|
|
||||||
Set netfilter routing mark.
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
Reuse listener address.
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
Connect timeout, in golang's Duration format.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of
|
|
||||||
decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the server domain name will be resolved to IP before connecting.
|
|
||||||
|
|
||||||
`dns.strategy` will be used if empty.
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
The length of time to wait before spawning a RFC 6555 Fast Fallback connection.
|
|
||||||
That is, is the amount of time to wait for IPv6 to succeed before assuming
|
|
||||||
that IPv6 is misconfigured and falling back to IPv4 if `prefer_ipv4` is set.
|
|
||||||
If zero, a default delay of 300ms is used.
|
|
||||||
|
|
||||||
Only take effect when `domain_strategy` is `prefer_ipv4` or `prefer_ipv6`.
|
|
||||||
|
|||||||
@@ -2,29 +2,17 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "tor",
|
||||||
{
|
"tag": "tor-out",
|
||||||
"type": "tor",
|
|
||||||
"tag": "tor-out",
|
"executable_path": "/usr/bin/tor",
|
||||||
|
"extra_args": [],
|
||||||
"executable_path": "/usr/bin/tor",
|
"data_directory": "$HOME/.cache/tor",
|
||||||
"extra_args": [],
|
"torrc": {
|
||||||
"data_directory": "$HOME/.cache/tor",
|
"ClientOnly": 1
|
||||||
"torrc": {
|
},
|
||||||
"ClientOnly": 1
|
|
||||||
},
|
... // 拨号字段
|
||||||
|
|
||||||
"detour": "upstream-out",
|
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -32,7 +20,7 @@
|
|||||||
|
|
||||||
默认安装不包含嵌入式 Tor, 参阅 [安装](/zh/#_2)。
|
默认安装不包含嵌入式 Tor, 参阅 [安装](/zh/#_2)。
|
||||||
|
|
||||||
### Tor 字段
|
### 字段
|
||||||
|
|
||||||
#### executable_path
|
#### executable_path
|
||||||
|
|
||||||
@@ -60,51 +48,4 @@ torrc 参数表。
|
|||||||
|
|
||||||
### 拨号字段
|
### 拨号字段
|
||||||
|
|
||||||
#### detour
|
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||||
|
|
||||||
上游出站的标签。
|
|
||||||
|
|
||||||
启用时,其他拨号字段将被忽略。
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
要绑定到的网络接口。
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
要绑定的地址。
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置 netfilter 路由标记。
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
重用监听地址。
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
连接超时,采用 golang 的 Duration 格式。
|
|
||||||
|
|
||||||
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
|
||||||
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,服务器域名将在连接前解析为 IP。
|
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
在生成 RFC 6555 快速回退连接之前等待的时间长度。
|
|
||||||
也就是说,是在假设之前等待 IPv6 成功的时间量如果设置了 "prefer_ipv4",则 IPv6 配置错误并回退到 IPv4。
|
|
||||||
如果为零,则使用 300 毫秒的默认延迟。
|
|
||||||
|
|
||||||
仅当 `domain_strategy` 为 `prefer_ipv4` 或 `prefer_ipv6` 时生效。
|
|
||||||
|
|||||||
@@ -2,34 +2,22 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "trojan",
|
||||||
{
|
"tag": "trojan-out",
|
||||||
"type": "trojan",
|
|
||||||
"tag": "trojan-out",
|
|
||||||
|
|
||||||
"server": "127.0.0.1",
|
|
||||||
"server_port": 1080,
|
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
|
||||||
"network": "tcp",
|
|
||||||
"tls": {},
|
|
||||||
"multiplex": {},
|
|
||||||
"transport": {},
|
|
||||||
|
|
||||||
"detour": "upstream-out",
|
"server": "127.0.0.1",
|
||||||
"bind_interface": "en0",
|
"server_port": 1080,
|
||||||
"bind_address": "0.0.0.0",
|
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
||||||
"routing_mark": 1234,
|
"network": "tcp",
|
||||||
"reuse_addr": false,
|
"tls": {},
|
||||||
"connect_timeout": "5s",
|
"multiplex": {},
|
||||||
"tcp_fast_open": false,
|
"transport": {},
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
... // Dial Fields
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Trojan Fields
|
### Fields
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -71,54 +59,4 @@ V2Ray Transport configuration, see [V2Ray Transport](/configuration/shared/v2ray
|
|||||||
|
|
||||||
### Dial Fields
|
### Dial Fields
|
||||||
|
|
||||||
#### detour
|
See [Dial Fields](/configuration/shared/dial) for details.
|
||||||
|
|
||||||
The tag of the upstream outbound.
|
|
||||||
|
|
||||||
Other dial fields will be ignored when enabled.
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
The network interface to bind to.
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
The address to bind to.
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
Only supported on Linux.
|
|
||||||
|
|
||||||
Set netfilter routing mark.
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
Reuse listener address.
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
Connect timeout, in golang's Duration format.
|
|
||||||
|
|
||||||
A duration string is a possibly signed sequence of
|
|
||||||
decimal numbers, each with optional fraction and a unit suffix,
|
|
||||||
such as "300ms", "-1.5h" or "2h45m".
|
|
||||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
One of `prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`.
|
|
||||||
|
|
||||||
If set, the server domain name will be resolved to IP before connecting.
|
|
||||||
|
|
||||||
`dns.strategy` will be used if empty.
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
The length of time to wait before spawning a RFC 6555 Fast Fallback connection.
|
|
||||||
That is, is the amount of time to wait for IPv6 to succeed before assuming
|
|
||||||
that IPv6 is misconfigured and falling back to IPv4 if `prefer_ipv4` is set.
|
|
||||||
If zero, a default delay of 300ms is used.
|
|
||||||
|
|
||||||
Only take effect when `domain_strategy` is `prefer_ipv4` or `prefer_ipv6`.
|
|
||||||
|
|||||||
@@ -2,34 +2,22 @@
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"outbounds": [
|
"type": "trojan",
|
||||||
{
|
"tag": "trojan-out",
|
||||||
"type": "trojan",
|
|
||||||
"tag": "trojan-out",
|
"server": "127.0.0.1",
|
||||||
|
"server_port": 1080,
|
||||||
"server": "127.0.0.1",
|
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
||||||
"server_port": 1080,
|
"network": "tcp",
|
||||||
"password": "8JCsPssfgS8tiRwiMlhARg==",
|
"tls": {},
|
||||||
"network": "tcp",
|
"multiplex": {},
|
||||||
"tls": {},
|
"transport": {},
|
||||||
"multiplex": {},
|
|
||||||
"transport": {},
|
|
||||||
|
|
||||||
"detour": "upstream-out",
|
... // 拨号字段
|
||||||
"bind_interface": "en0",
|
|
||||||
"bind_address": "0.0.0.0",
|
|
||||||
"routing_mark": 1234,
|
|
||||||
"reuse_addr": false,
|
|
||||||
"connect_timeout": "5s",
|
|
||||||
"tcp_fast_open": false,
|
|
||||||
"domain_strategy": "prefer_ipv6",
|
|
||||||
"fallback_delay": "300ms"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Trojan 字段
|
### 字段
|
||||||
|
|
||||||
#### server
|
#### server
|
||||||
|
|
||||||
@@ -71,51 +59,4 @@ V2Ray 传输配置,参阅 [V2Ray 传输层](/zh/configuration/shared/v2ray-tra
|
|||||||
|
|
||||||
### 拨号字段
|
### 拨号字段
|
||||||
|
|
||||||
#### detour
|
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||||
|
|
||||||
上游出站的标签。
|
|
||||||
|
|
||||||
启用时,其他拨号字段将被忽略。
|
|
||||||
|
|
||||||
#### bind_interface
|
|
||||||
|
|
||||||
要绑定到的网络接口。
|
|
||||||
|
|
||||||
#### bind_address
|
|
||||||
|
|
||||||
要绑定的地址。
|
|
||||||
|
|
||||||
#### routing_mark
|
|
||||||
|
|
||||||
!!! error ""
|
|
||||||
|
|
||||||
仅支持 Linux。
|
|
||||||
|
|
||||||
设置 netfilter 路由标记。
|
|
||||||
|
|
||||||
#### reuse_addr
|
|
||||||
|
|
||||||
重用监听地址。
|
|
||||||
|
|
||||||
#### connect_timeout
|
|
||||||
|
|
||||||
连接超时,采用 golang 的 Duration 格式。
|
|
||||||
|
|
||||||
持续时间字符串是一个可能有符号的序列十进制数,每个都有可选的分数和单位后缀, 例如 "300ms"、"-1.5h" 或 "2h45m"。
|
|
||||||
有效时间单位为 "ns"、"us"(或 "µs")、"ms"、"s"、"m"、"h"。
|
|
||||||
|
|
||||||
#### domain_strategy
|
|
||||||
|
|
||||||
可选值:`prefer_ipv4` `prefer_ipv6` `ipv4_only` `ipv6_only`。
|
|
||||||
|
|
||||||
如果设置,服务器域名将在连接前解析为 IP。
|
|
||||||
|
|
||||||
默认使用 `dns.strategy`。
|
|
||||||
|
|
||||||
#### fallback_delay
|
|
||||||
|
|
||||||
在生成 RFC 6555 快速回退连接之前等待的时间长度。
|
|
||||||
也就是说,是在假设之前等待 IPv6 成功的时间量如果设置了 "prefer_ipv4",则 IPv6 配置错误并回退到 IPv4。
|
|
||||||
如果为零,则使用 300 毫秒的默认延迟。
|
|
||||||
|
|
||||||
仅当 `domain_strategy` 为 `prefer_ipv4` 或 `prefer_ipv6` 时生效。
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user