Compare commits

...

16 Commits

Author SHA1 Message Date
世界
f5f5cb023c Update documentation 2022-08-31 14:34:32 +08:00
世界
5813e0ce7a Add shadowtls (#49)
* Add shadowtls outbound

* Add shadowtls inbound

* Add shadowtls example

* Add shadowtls documentation
2022-08-31 14:21:53 +08:00
dyhkwong
5a9c2b1e80 darwin pf support (#52) 2022-08-31 14:21:37 +08:00
世界
bda34fdb3b Refactor outbound documentation 2022-08-31 13:42:30 +08:00
世界
426b677eb8 Fix process_name rule item 2022-08-31 12:51:38 +08:00
世界
67c7e9fd86 Refactor inbound documetation 2022-08-31 12:50:26 +08:00
世界
d8028a8632 Fix smux session status 2022-08-31 10:00:15 +08:00
dyhkwong
374743d022 Add process_path rule item (#51)
* process matching supports full path
* Remove strings.ToLower
2022-08-30 10:44:40 +08:00
世界
cd98ea5008 Fix socksaddr type condition 2022-08-29 19:58:58 +08:00
世界
dbda0ed98a Add chained inbound support 2022-08-29 19:50:28 +08:00
世界
f5e0ead01c Fix inject conn 2022-08-29 19:02:41 +08:00
0x7d274284
44818701bc Fix issue template (#48)
The correct command to get the version is `sing-box version`
2022-08-29 16:52:15 +08:00
世界
e0f7387dff Fix search android package in non-owner users 2022-08-29 12:02:29 +08:00
世界
d440a01792 Add grpc compatibility test 2022-08-29 10:15:25 +08:00
世界
665c84ee42 Fix log item on document menu 2022-08-28 12:47:23 +08:00
Hellojack
e0de96eb4c Minor fixes (#45)
* Cleanup code
* Fix documentation typo
2022-08-28 12:40:44 +08:00
128 changed files with 2899 additions and 3567 deletions

View File

@@ -31,7 +31,7 @@ body:
<details> <details>
```console ```console
$ sing-box --version $ sing-box version
# Paste output here # Paste output here
``` ```

View File

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

2
box.go
View File

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

View File

@@ -0,0 +1,12 @@
package baderror
import "strings"
func Contains(err error, msgList ...string) bool {
for _, msg := range msgList {
if strings.Contains(err.Error(), msg) {
return true
}
}
return false
}

26
common/baderror/grpc.go Normal file
View File

@@ -0,0 +1,26 @@
package baderror
import (
"context"
"io"
"net"
)
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
}

22
common/baderror/h2.go Normal file
View File

@@ -0,0 +1,22 @@
package baderror
import (
"io"
"net"
E "github.com/sagernet/sing/common/exceptions"
)
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
}

View File

@@ -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"
@@ -130,6 +131,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())

View File

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

View File

@@ -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,

View 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
}

View File

@@ -1,4 +1,4 @@
//go:build !linux //go:build !linux && !darwin
package redir package redir

View File

@@ -18,6 +18,7 @@ const (
TypeHysteria = "hysteria" TypeHysteria = "hysteria"
TypeTor = "tor" TypeTor = "tor"
TypeSSH = "ssh" TypeSSH = "ssh"
TypeShadowTLS = "shadowtls"
) )
const ( const (

View File

@@ -1,6 +1,6 @@
package constant package constant
var ( var (
Version = "1.0-beta2" Version = "1.0-beta3"
Commit = "" Commit = ""
) )

View File

@@ -1,3 +1,15 @@
#### 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 +123,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

View File

@@ -61,6 +61,9 @@
"process_name": [ "process_name": [
"curl" "curl"
], ],
"process_path": [
"/usr/bin/curl"
],
"package_name": [ "package_name": [
"com.termux" "com.termux"
], ],
@@ -177,6 +180,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.

View File

@@ -60,6 +60,9 @@
"process_name": [ "process_name": [
"curl" "curl"
], ],
"process_path": [
"/usr/bin/curl"
],
"package_name": [ "package_name": [
"com.termux" "com.termux"
], ],
@@ -176,6 +179,14 @@
匹配进程名称。 匹配进程名称。
#### process_path
!!! error ""
仅支持 Linux、Windows 和 macOS.
匹配进程路径。
#### package_name #### package_name
匹配 Android 应用包名。 匹配 Android 应用包名。

View File

@@ -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.

View File

@@ -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 过期时间,以秒为单位,默认为 3005 分钟)。
#### proxy_protocol
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。

View File

@@ -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.

View File

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

View File

@@ -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.

View File

@@ -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` 生效,它的值将作为后备。

View File

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

View File

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

View File

@@ -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.

View File

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

View File

@@ -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.

View File

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

View File

@@ -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.

View File

@@ -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` 生效,它的值将作为后备。

View File

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

View File

@@ -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 过期时间,以秒为单位,默认为 3005 分钟)。
#### proxy_protocol
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。

View 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).

View 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/)。

View File

@@ -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.

View File

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

View File

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

View File

@@ -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 过期时间,以秒为单位,默认为 3005 分钟)。

View File

@@ -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.

View File

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

View File

@@ -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/128",
"inet6_address": "fdfe:dcba:9876::1/128", "mtu": 1500,
"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
@@ -163,22 +156,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.

View File

@@ -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/128",
"inet6_address": "fdfe:dcba:9876::1/128", "mtu": 1500,
"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"
}
]
} }
``` ```
@@ -162,22 +155,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` 生效,它的值将作为后备。

View File

@@ -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.

View File

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

View File

@@ -8,8 +8,8 @@ sing-box uses JSON for configuration files.
{ {
"log": {}, "log": {},
"dns": {}, "dns": {},
"inbounds": {}, "inbounds": [],
"outbounds": {}, "outbounds": [],
"route": {}, "route": {},
"experimental": {} "experimental": {}
} }

View File

@@ -8,8 +8,8 @@ sing-box 使用 JSON 作为配置文件格式。
{ {
"log": {}, "log": {},
"dns": {}, "dns": {},
"inbounds": {}, "inbounds": [],
"outbounds": {}, "outbounds": [],
"route": {}, "route": {},
"experimental": {} "experimental": {}
} }

View File

@@ -1,3 +1,5 @@
# Log
### Structure ### Structure
```json ```json

View File

@@ -1,3 +1,5 @@
# 日志
### 结构 ### 结构
```json ```json

View File

@@ -4,12 +4,8 @@
```json ```json
{ {
"outbounds": [ "type": "block",
{ "tag": "block"
"type": "block",
"tag": "block"
}
]
} }
``` ```

View File

@@ -4,12 +4,8 @@
```json ```json
{ {
"outbounds": [ "type": "block",
{ "tag": "block"
"type": "block",
"tag": "block"
}
]
} }
``` ```

View File

@@ -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`.

View File

@@ -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` 时生效。

View File

@@ -4,12 +4,8 @@
```json ```json
{ {
"outbounds": [ "type": "dns",
{ "tag": "dns-out"
"type": "dns",
"tag": "dns-out"
}
]
} }
``` ```

View File

@@ -4,12 +4,8 @@
```json ```json
{ {
"outbounds": [ "type": "dns",
{ "tag": "dns-out"
"type": "dns",
"tag": "dns-out"
}
]
} }
``` ```

View File

@@ -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`.

View File

@@ -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` 时生效。

View File

@@ -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`.

View File

@@ -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` 时生效。

View File

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

View File

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

View File

@@ -2,34 +2,22 @@
```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", "network": "udp",
"password": "8JCsPssfgS8tiRwiMlhARg==", "udp_over_tcp": false,
"network": "udp", "multiplex": {},
"udp_over_tcp": false,
"multiplex": {}, ... // 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"
}
]
} }
``` ```
### Shadowsocks Fields ### Fields
#### server #### server
@@ -97,54 +85,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`.

View File

@@ -1,35 +1,23 @@
### 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", "network": "udp",
"password": "8JCsPssfgS8tiRwiMlhARg==", "udp_over_tcp": false,
"network": "udp", "multiplex": {},
"udp_over_tcp": false,
"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
@@ -97,51 +85,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` 时生效。

View 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.

View 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/)。

View File

@@ -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`.

View File

@@ -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` 时生效。

View File

@@ -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`.

View File

@@ -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` 时生效。

View File

@@ -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`.

View File

@@ -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` 时生效。

View File

@@ -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`.

View File

@@ -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` 时生效。

View File

@@ -2,39 +2,27 @@
```json ```json
{ {
"outbounds": [ "type": "vmess",
{ "tag": "vmess-out",
"type": "vmess",
"tag": "vmess-out", "server": "127.0.0.1",
"server_port": 1080,
"server": "127.0.0.1", "uuid": "bf000d23-0752-40b4-affe-68f7707a9661",
"server_port": 1080, "security": "auto",
"uuid": "bf000d23-0752-40b4-affe-68f7707a9661", "alter_id": 0,
"security": "auto", "global_padding": false,
"alter_id": 0, "authenticated_length": true,
"global_padding": false, "network": "tcp",
"authenticated_length": true, "tls": {},
"network": "tcp", "packet_addr": false,
"tls": {}, "multiplex": {},
"packet_addr": false, "transport": {},
"multiplex": {},
"transport": {},
"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"
}
]
} }
``` ```
### VMess Fields ### Fields
#### server #### server
@@ -110,54 +98,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`.

View File

@@ -2,39 +2,27 @@
```json ```json
{ {
"outbounds": [ "type": "vmess",
{ "tag": "vmess-out",
"type": "vmess",
"tag": "vmess-out", "server": "127.0.0.1",
"server_port": 1080,
"server": "127.0.0.1", "uuid": "bf000d23-0752-40b4-affe-68f7707a9661",
"server_port": 1080, "security": "auto",
"uuid": "bf000d23-0752-40b4-affe-68f7707a9661", "alter_id": 0,
"security": "auto", "global_padding": false,
"alter_id": 0, "authenticated_length": true,
"global_padding": false, "network": "tcp",
"authenticated_length": true, "tls": {},
"network": "tcp", "packet_addr": false,
"tls": {}, "multiplex": {},
"packet_addr": false, "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"
}
]
} }
``` ```
### VMess 字段 ### 字段
#### server #### server
@@ -110,51 +98,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` 时生效。

View File

@@ -2,34 +2,22 @@
```json ```json
{ {
"outbounds": [ "type": "wireguard",
{ "tag": "wireguard-out",
"type": "wireguard",
"tag": "wireguard-out", "server": "127.0.0.1",
"server_port": 1080,
"server": "127.0.0.1", "local_address": [
"server_port": 1080, "10.0.0.1",
"local_address": [ "10.0.0.2/32"
"10.0.0.1", ],
"10.0.0.2/32" "private_key": "YNXtAzepDqRv9H52osJVDQnznT5AM11eCK3ESpwSt04=",
], "peer_public_key": "Z1XXLsKYkYxuiYjJIkRvtIKFepCYHTgON+GwPq7SOV4=",
"private_key": "YNXtAzepDqRv9H52osJVDQnznT5AM11eCK3ESpwSt04=", "pre_shared_key": "31aIhAPwktDGpH4JDhA8GNvjFXEf/a6+UaQRyOAiyfM=",
"peer_public_key": "Z1XXLsKYkYxuiYjJIkRvtIKFepCYHTgON+GwPq7SOV4=", "mtu": 1408,
"pre_shared_key": "31aIhAPwktDGpH4JDhA8GNvjFXEf/a6+UaQRyOAiyfM=", "network": "tcp",
"mtu": 1408,
"network": "tcp", ... // 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"
}
]
} }
``` ```
@@ -37,7 +25,7 @@
WireGuard is not included by default, see [Installation](/#installation). WireGuard is not included by default, see [Installation](/#installation).
### WireGuard Fields ### Fields
#### server #### server
@@ -92,54 +80,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`.

View File

@@ -2,34 +2,22 @@
```json ```json
{ {
"outbounds": [ "type": "wireguard",
{ "tag": "wireguard-out",
"type": "wireguard",
"tag": "wireguard-out", "server": "127.0.0.1",
"server_port": 1080,
"server": "127.0.0.1", "local_address": [
"server_port": 1080, "10.0.0.1",
"local_address": [ "10.0.0.2/32"
"10.0.0.1", ],
"10.0.0.2/32" "private_key": "YNXtAzepDqRv9H52osJVDQnznT5AM11eCK3ESpwSt04=",
], "peer_public_key": "Z1XXLsKYkYxuiYjJIkRvtIKFepCYHTgON+GwPq7SOV4=",
"private_key": "YNXtAzepDqRv9H52osJVDQnznT5AM11eCK3ESpwSt04=", "pre_shared_key": "31aIhAPwktDGpH4JDhA8GNvjFXEf/a6+UaQRyOAiyfM=",
"peer_public_key": "Z1XXLsKYkYxuiYjJIkRvtIKFepCYHTgON+GwPq7SOV4=", "mtu": 1408,
"pre_shared_key": "31aIhAPwktDGpH4JDhA8GNvjFXEf/a6+UaQRyOAiyfM=", "network": "tcp",
"mtu": 1408,
"network": "tcp", ... // 拨号字段
"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"
}
]
} }
``` ```
@@ -37,7 +25,7 @@
默认安装不包含 WireGuard, 参阅 [安装](/zh/#_2)。 默认安装不包含 WireGuard, 参阅 [安装](/zh/#_2)。
### WireGuard 字段 ### 字段
#### server #### server
@@ -94,51 +82,4 @@ WireGuard MTU。 默认1408。
### 拨号字段 ### 拨号字段
#### 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` 时生效。

View File

@@ -68,6 +68,9 @@
"process_name": [ "process_name": [
"curl" "curl"
], ],
"process_path": [
"/usr/bin/curl"
],
"package_name": [ "package_name": [
"com.termux" "com.termux"
], ],
@@ -188,6 +191,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.

View File

@@ -66,6 +66,9 @@
"process_name": [ "process_name": [
"curl" "curl"
], ],
"process_path": [
"/usr/bin/curl"
],
"package_name": [ "package_name": [
"com.termux" "com.termux"
], ],
@@ -186,6 +189,14 @@
匹配进程名称。 匹配进程名称。
#### process_path
!!! error ""
仅支持 Linux、Windows 和 macOS.
匹配进程路径。
#### package_name #### package_name
匹配 Android 应用包名。 匹配 Android 应用包名。

View File

@@ -0,0 +1,69 @@
### Structure
```json
{
"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"
}
```
### Fields
#### detour
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`.

View File

@@ -0,0 +1,66 @@
### 结构
```json
{
"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"
}
```
### 字段
#### detour
上游出站的标签。
启用时,其他拨号字段将被忽略。
#### 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` 时生效。

View File

@@ -0,0 +1,73 @@
### Structure
```json
{
"listen": "::",
"listen_port": 5353,
"tcp_fast_open": false,
"sniff": false,
"sniff_override_destination": false,
"domain_strategy": "prefer_ipv6",
"udp_timeout": 300,
"proxy_protocol": false,
"detour": "another-in"
}
```
### Fields
| Field | Available Context |
|------------------|-------------------------------------------------------------------|
| `listen` | Needs to listen on TCP or UDP. |
| `listen_port` | Needs to listen on TCP or UDP. |
| `tcp_fast_open` | Needs to listen on TCP. |
| `udp_timeout` | Needs to assemble UDP connections, currently Tun and Shadowsocks. |
| `proxy_protocol` | Needs to listen on TCP. |
#### listen
==Required==
Listen address.
#### listen_port
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.
#### detour
If set, connections will be forwarded to the specified inbound.
Requires target inbound support, see [Injectable](/configuration/inbound/#fields).

View File

@@ -0,0 +1,72 @@
### 结构
```json
{
"listen": "::",
"listen_port": 5353,
"tcp_fast_open": false,
"sniff": false,
"sniff_override_destination": false,
"domain_strategy": "prefer_ipv6",
"udp_timeout": 300,
"detour": "another-in"
}
```
| 字段 | 可用上下文 |
|------------------|-------------------------------------|
| `listen` | 需要监听 TCP 或 UDP。 |
| `listen_port` | 需要监听 TCP 或 UDP。 |
| `tcp_fast_open` | 需要监听 TCP。 |
| `udp_timeout` | 需要组装 UDP 连接, 当前为 Tun 和 Shadowsocks。 |
| `proxy_protocol` | 需要监听 TCP。 |
### 字段
#### 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 过期时间,以秒为单位,默认为 3005 分钟)。
#### proxy_protocol
解析连接头中的 [代理协议](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)。
#### detour
如果设置,连接将被转发到指定的入站。
需要目标入站支持,参阅 [注入支持](/zh/configuration/inbound/#_3)。

View File

@@ -0,0 +1,55 @@
#### Server
```json
{
"inbounds": [
{
"type": "shadowtls",
"listen": "::",
"listen_port": 4443,
"handshake": {
"server": "google.com",
"server_port": 443
},
"detour": "shadowsocks-in"
},
{
"type": "shadowsocks",
"tag": "shadowsocks-in",
"listen": "127.0.0.1",
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg=="
}
]
}
```
#### Client
```json
{
"outbounds": [
{
"type": "shadowsocks",
"method": "2022-blake3-aes-128-gcm",
"password": "8JCsPssfgS8tiRwiMlhARg==",
"detour": "shadowtls-out",
"multiplex": {
"enabled": 1,
"max_connections": 4,
"min_streams": 4
}
},
{
"type": "shadowtls",
"tag": "shadowtls-out",
"server": "127.0.0.1",
"server_port": 4443,
"tls": {
"enabled": true,
"server_name": "google.com"
}
}
]
}
```

12
go.mod
View File

@@ -20,20 +20,20 @@ require (
github.com/pires/go-proxyproto v0.6.2 github.com/pires/go-proxyproto v0.6.2
github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a github.com/sagernet/certmagic v0.0.0-20220819042630-4a57f8b6853a
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb
github.com/sagernet/sing v0.0.0-20220826124916-d4ba8fdfac88 github.com/sagernet/sing v0.0.0-20220829115648-e09c9f3fc812
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83
github.com/sagernet/sing-vmess v0.0.0-20220827032426-01665c9c4e31 github.com/sagernet/sing-vmess v0.0.0-20220829020559-33915075430c
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939 github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195
github.com/spf13/cobra v1.5.0 github.com/spf13/cobra v1.5.0
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
go.uber.org/atomic v1.10.0 go.uber.org/atomic v1.10.0
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 golang.org/x/sys v0.0.0-20220829200755-d48e67d00261
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b
google.golang.org/grpc v1.49.0 google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.28.1 google.golang.org/protobuf v1.28.1
gvisor.dev/gvisor v0.0.0-20220819163037-ba6e795b139a gvisor.dev/gvisor v0.0.0-20220819163037-ba6e795b139a

24
go.sum
View File

@@ -135,18 +135,18 @@ github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTY
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4= github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.0.0-20220826124916-d4ba8fdfac88 h1:wxUQfVBqiUtAemytzP9mNjAkSiI0nVsRZBQvCLP8r5g= github.com/sagernet/sing v0.0.0-20220829115648-e09c9f3fc812 h1:z5AqoJcMy+MaD9pstLt08c95t2Txlzvp5pk4lqXBQPc=
github.com/sagernet/sing v0.0.0-20220826124916-d4ba8fdfac88/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ= github.com/sagernet/sing v0.0.0-20220829115648-e09c9f3fc812/go.mod h1:kZvzh1VDa/Dg/Bt5WaYKU0jl5ept8KKDpl3Ay4gRtRQ=
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFxUX+xJCWMPPFZCn2GC/uLrBjTSr1vHY= github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666 h1:XUTocA/Ek0dFxUX+xJCWMPPFZCn2GC/uLrBjTSr1vHY=
github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM= github.com/sagernet/sing-dns v0.0.0-20220822023312-3e086b06d666/go.mod h1:eDyH7AJmqBGjZQdQmpZIzlbTREudZuWDExMuGKgjRVM=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM= github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 h1:SoWiHYuOCVedqA7T/CJSZUUrcPGKQb2wFKEq8DphiAI= github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83 h1:SoWiHYuOCVedqA7T/CJSZUUrcPGKQb2wFKEq8DphiAI=
github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83/go.mod h1:76r07HS1WRcEI4mE9pFsohfTBUt1j/G9Avz6DaOP3VU= github.com/sagernet/sing-tun v0.0.0-20220828031750-185b6c880a83/go.mod h1:76r07HS1WRcEI4mE9pFsohfTBUt1j/G9Avz6DaOP3VU=
github.com/sagernet/sing-vmess v0.0.0-20220827032426-01665c9c4e31 h1:FAsJsVwpPcoITcj6/9JxRKxy8n3bIKLqKmDGVzmfeOo= github.com/sagernet/sing-vmess v0.0.0-20220829020559-33915075430c h1:92Gn78/z/t6CkzZ4XWG/uPiCxhUmjPULFEHFMDY6K8k=
github.com/sagernet/sing-vmess v0.0.0-20220827032426-01665c9c4e31/go.mod h1:82O6gzbxLha/W/jxSVQbsqf2lVdRTjMIgyLug0lpJps= github.com/sagernet/sing-vmess v0.0.0-20220829020559-33915075430c/go.mod h1:82O6gzbxLha/W/jxSVQbsqf2lVdRTjMIgyLug0lpJps=
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939 h1:pB1Dh1NbwVrLhQhotr4O4Hs3yhiBzmg3AvnUyYjL4x4= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
github.com/sagernet/smux v0.0.0-20220812084127-e2d085ee3939/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8= github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -181,8 +181,8 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
@@ -244,8 +244,8 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -276,8 +276,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 h1:vDy//hdR+GnROE3OdYbQKt9rdtNdHkDtONvpRwmls/0= golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b h1:qgrKnOfe1zyURRNdmDlGbN32i38Zjmw0B1+TMdHcOvg=
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U= golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b/go.mod h1:6y4CqPAy54NwiN4nC8K+R1eMpQDB1P2d25qmunh2RSA=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=

View File

@@ -39,6 +39,8 @@ func New(ctx context.Context, router adapter.Router, logger log.ContextLogger, o
return NewNaive(ctx, router, logger, options.Tag, options.NaiveOptions) return NewNaive(ctx, router, logger, options.Tag, options.NaiveOptions)
case C.TypeHysteria: case C.TypeHysteria:
return NewHysteria(ctx, router, logger, options.Tag, options.HysteriaOptions) return NewHysteria(ctx, router, logger, options.Tag, options.HysteriaOptions)
case C.TypeShadowTLS:
return NewShadowTLS(ctx, router, logger, options.Tag, options.ShadowTLSOptions)
default: default:
return nil, E.New("unknown inbound type: ", options.Type) return nil, E.New("unknown inbound type: ", options.Type)
} }

View File

@@ -3,25 +3,18 @@ package inbound
import ( import (
"context" "context"
"net" "net"
"net/netip"
"os"
"sync" "sync"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/proxyproto"
"github.com/sagernet/sing-box/common/settings" "github.com/sagernet/sing-box/common/settings"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-dns" "github.com/sagernet/sing-dns"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions" 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"
"github.com/database64128/tfo-go"
) )
var _ adapter.Inbound = (*myInboundAdapter)(nil) var _ adapter.Inbound = (*myInboundAdapter)(nil)
@@ -62,6 +55,10 @@ func (a *myInboundAdapter) Tag() string {
return a.tag return a.tag
} }
func (a *myInboundAdapter) Network() []string {
return a.network
}
func (a *myInboundAdapter) Start() error { func (a *myInboundAdapter) Start() error {
var err error var err error
if common.Contains(a.network, N.NetworkTCP) { if common.Contains(a.network, N.NetworkTCP) {
@@ -102,38 +99,6 @@ func (a *myInboundAdapter) Start() error {
return nil return nil
} }
func (a *myInboundAdapter) ListenTCP() (net.Listener, error) {
var err error
bindAddr := M.SocksaddrFrom(netip.Addr(a.listenOptions.Listen), a.listenOptions.ListenPort)
var tcpListener net.Listener
if !a.listenOptions.TCPFastOpen {
tcpListener, err = net.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr())
} else {
tcpListener, err = tfo.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr())
}
if err == nil {
a.logger.Info("tcp server started at ", tcpListener.Addr())
}
if a.listenOptions.ProxyProtocol {
a.logger.Debug("proxy protocol enabled")
tcpListener = &proxyproto.Listener{Listener: tcpListener}
}
a.tcpListener = tcpListener
return tcpListener, err
}
func (a *myInboundAdapter) ListenUDP() (net.PacketConn, error) {
bindAddr := M.SocksaddrFrom(netip.Addr(a.listenOptions.Listen), a.listenOptions.ListenPort)
udpConn, err := net.ListenUDP(M.NetworkFromNetAddr(N.NetworkUDP, bindAddr.Addr), bindAddr.UDPAddr())
if err != nil {
return nil, err
}
a.udpConn = udpConn
a.udpAddr = bindAddr
a.logger.Info("udp server started at ", udpConn.LocalAddr())
return udpConn, err
}
func (a *myInboundAdapter) Close() error { func (a *myInboundAdapter) Close() error {
var err error var err error
if a.clearSystemProxy != nil { if a.clearSystemProxy != nil {
@@ -170,20 +135,10 @@ func (a *myInboundAdapter) newPacketConnection(ctx context.Context, conn N.Packe
return a.router.RoutePacketConnection(ctx, conn, metadata) return a.router.RoutePacketConnection(ctx, conn, metadata)
} }
func (a *myInboundAdapter) loopTCPIn() {
tcpListener := a.tcpListener
for {
conn, err := tcpListener.Accept()
if err != nil {
return
}
go a.injectTCP(conn)
}
}
func (a *myInboundAdapter) createMetadata(conn net.Conn, metadata adapter.InboundContext) adapter.InboundContext { func (a *myInboundAdapter) createMetadata(conn net.Conn, metadata adapter.InboundContext) adapter.InboundContext {
metadata.Inbound = a.tag metadata.Inbound = a.tag
metadata.InboundType = a.protocol metadata.InboundType = a.protocol
metadata.InboundDetour = a.listenOptions.Detour
metadata.SniffEnabled = a.listenOptions.SniffEnabled metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy) metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
@@ -199,166 +154,6 @@ func (a *myInboundAdapter) createMetadata(conn net.Conn, metadata adapter.Inboun
return metadata return metadata
} }
func (a *myInboundAdapter) injectTCP(conn net.Conn) {
ctx := log.ContextWithNewID(a.ctx)
metadata := a.createMetadata(conn, adapter.InboundContext{})
a.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
hErr := a.connHandler.NewConnection(ctx, conn, metadata)
if hErr != nil {
conn.Close()
a.NewError(ctx, E.Cause(hErr, "process connection from ", metadata.Source))
}
}
func (a *myInboundAdapter) routeTCP(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) {
a.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
hErr := a.newConnection(ctx, conn, metadata)
if hErr != nil {
conn.Close()
a.NewError(ctx, E.Cause(hErr, "process connection from ", metadata.Source))
}
}
func (a *myInboundAdapter) loopUDPIn() {
defer close(a.packetOutboundClosed)
_buffer := buf.StackNewPacket()
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
buffer.IncRef()
defer buffer.DecRef()
packetService := (*myInboundPacketAdapter)(a)
for {
buffer.Reset()
n, addr, err := a.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil {
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.InboundType = a.protocol
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Source = M.SocksaddrFromNetIP(addr)
metadata.OriginDestination = a.udpAddr
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
if err != nil {
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPOOBIn() {
defer close(a.packetOutboundClosed)
_buffer := buf.StackNewPacket()
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
buffer.IncRef()
defer buffer.DecRef()
packetService := (*myInboundPacketAdapter)(a)
oob := make([]byte, 1024)
for {
buffer.Reset()
n, oobN, _, addr, err := a.udpConn.ReadMsgUDPAddrPort(buffer.FreeBytes(), oob)
if err != nil {
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.InboundType = a.protocol
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Source = M.SocksaddrFromNetIP(addr)
metadata.OriginDestination = a.udpAddr
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
if err != nil {
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPInThreadSafe() {
defer close(a.packetOutboundClosed)
packetService := (*myInboundPacketAdapter)(a)
for {
buffer := buf.NewPacket()
n, addr, err := a.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil {
buffer.Release()
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.InboundType = a.protocol
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Source = M.SocksaddrFromNetIP(addr)
metadata.OriginDestination = a.udpAddr
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
if err != nil {
buffer.Release()
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPOOBInThreadSafe() {
defer close(a.packetOutboundClosed)
packetService := (*myInboundPacketAdapter)(a)
oob := make([]byte, 1024)
for {
buffer := buf.NewPacket()
n, oobN, _, addr, err := a.udpConn.ReadMsgUDPAddrPort(buffer.FreeBytes(), oob)
if err != nil {
buffer.Release()
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.InboundType = a.protocol
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Source = M.SocksaddrFromNetIP(addr)
metadata.OriginDestination = a.udpAddr
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
if err != nil {
buffer.Release()
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPOut() {
for {
select {
case packet := <-a.packetOutbound:
err := a.writePacket(packet.buffer, packet.destination)
if err != nil && !E.IsClosed(err) {
a.newError(E.New("write back udp: ", err))
}
continue
case <-a.packetOutboundClosed:
}
for {
select {
case packet := <-a.packetOutbound:
packet.buffer.Release()
default:
return
}
}
}
}
func (a *myInboundAdapter) newError(err error) { func (a *myInboundAdapter) newError(err error) {
a.logger.Error(err) a.logger.Error(err)
} }
@@ -375,72 +170,3 @@ func NewError(logger log.ContextLogger, ctx context.Context, err error) {
} }
logger.ErrorContext(ctx, err) logger.ErrorContext(ctx, err)
} }
func (a *myInboundAdapter) writePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
defer buffer.Release()
if destination.IsFqdn() {
udpAddr, err := net.ResolveUDPAddr(N.NetworkUDP, destination.String())
if err != nil {
return err
}
return common.Error(a.udpConn.WriteTo(buffer.Bytes(), udpAddr))
}
return common.Error(a.udpConn.WriteToUDPAddrPort(buffer.Bytes(), destination.AddrPort()))
}
type myInboundPacketAdapter myInboundAdapter
func (s *myInboundPacketAdapter) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
n, addr, err := s.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil {
return M.Socksaddr{}, err
}
buffer.Truncate(n)
return M.SocksaddrFromNetIP(addr), nil
}
func (s *myInboundPacketAdapter) WriteIsThreadUnsafe() {
}
type myInboundPacket struct {
buffer *buf.Buffer
destination M.Socksaddr
}
func (s *myInboundPacketAdapter) Upstream() any {
return s.udpConn
}
func (s *myInboundPacketAdapter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
s.packetAccess.RLock()
defer s.packetAccess.RUnlock()
select {
case <-s.packetOutboundClosed:
return os.ErrClosed
default:
}
s.packetOutbound <- &myInboundPacket{buffer, destination}
return nil
}
func (s *myInboundPacketAdapter) Close() error {
return s.udpConn.Close()
}
func (s *myInboundPacketAdapter) LocalAddr() net.Addr {
return s.udpConn.LocalAddr()
}
func (s *myInboundPacketAdapter) SetDeadline(t time.Time) error {
return s.udpConn.SetDeadline(t)
}
func (s *myInboundPacketAdapter) SetReadDeadline(t time.Time) error {
return s.udpConn.SetReadDeadline(t)
}
func (s *myInboundPacketAdapter) SetWriteDeadline(t time.Time) error {
return s.udpConn.SetWriteDeadline(t)
}

67
inbound/default_tcp.go Normal file
View File

@@ -0,0 +1,67 @@
package inbound
import (
"context"
"net"
"net/netip"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/proxyproto"
"github.com/sagernet/sing-box/log"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/database64128/tfo-go"
)
func (a *myInboundAdapter) ListenTCP() (net.Listener, error) {
var err error
bindAddr := M.SocksaddrFrom(netip.Addr(a.listenOptions.Listen), a.listenOptions.ListenPort)
var tcpListener net.Listener
if !a.listenOptions.TCPFastOpen {
tcpListener, err = net.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr())
} else {
tcpListener, err = tfo.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr())
}
if err == nil {
a.logger.Info("tcp server started at ", tcpListener.Addr())
}
if a.listenOptions.ProxyProtocol {
a.logger.Debug("proxy protocol enabled")
tcpListener = &proxyproto.Listener{Listener: tcpListener}
}
a.tcpListener = tcpListener
return tcpListener, err
}
func (a *myInboundAdapter) loopTCPIn() {
tcpListener := a.tcpListener
for {
conn, err := tcpListener.Accept()
if err != nil {
return
}
go a.injectTCP(conn, adapter.InboundContext{})
}
}
func (a *myInboundAdapter) injectTCP(conn net.Conn, metadata adapter.InboundContext) {
ctx := log.ContextWithNewID(a.ctx)
metadata = a.createMetadata(conn, metadata)
a.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
hErr := a.connHandler.NewConnection(ctx, conn, metadata)
if hErr != nil {
conn.Close()
a.NewError(ctx, E.Cause(hErr, "process connection from ", metadata.Source))
}
}
func (a *myInboundAdapter) routeTCP(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) {
a.logger.InfoContext(ctx, "inbound connection from ", metadata.Source)
hErr := a.newConnection(ctx, conn, metadata)
if hErr != nil {
conn.Close()
a.NewError(ctx, E.Cause(hErr, "process connection from ", metadata.Source))
}
}

237
inbound/default_udp.go Normal file
View File

@@ -0,0 +1,237 @@
package inbound
import (
"net"
"net/netip"
"os"
"time"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-dns"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
func (a *myInboundAdapter) ListenUDP() (net.PacketConn, error) {
bindAddr := M.SocksaddrFrom(netip.Addr(a.listenOptions.Listen), a.listenOptions.ListenPort)
udpConn, err := net.ListenUDP(M.NetworkFromNetAddr(N.NetworkUDP, bindAddr.Addr), bindAddr.UDPAddr())
if err != nil {
return nil, err
}
a.udpConn = udpConn
a.udpAddr = bindAddr
a.logger.Info("udp server started at ", udpConn.LocalAddr())
return udpConn, err
}
func (a *myInboundAdapter) loopUDPIn() {
defer close(a.packetOutboundClosed)
_buffer := buf.StackNewPacket()
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
buffer.IncRef()
defer buffer.DecRef()
packetService := (*myInboundPacketAdapter)(a)
for {
buffer.Reset()
n, addr, err := a.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil {
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.InboundType = a.protocol
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Source = M.SocksaddrFromNetIP(addr)
metadata.OriginDestination = a.udpAddr
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
if err != nil {
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPOOBIn() {
defer close(a.packetOutboundClosed)
_buffer := buf.StackNewPacket()
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
buffer.IncRef()
defer buffer.DecRef()
packetService := (*myInboundPacketAdapter)(a)
oob := make([]byte, 1024)
for {
buffer.Reset()
n, oobN, _, addr, err := a.udpConn.ReadMsgUDPAddrPort(buffer.FreeBytes(), oob)
if err != nil {
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.InboundType = a.protocol
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Source = M.SocksaddrFromNetIP(addr)
metadata.OriginDestination = a.udpAddr
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
if err != nil {
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPInThreadSafe() {
defer close(a.packetOutboundClosed)
packetService := (*myInboundPacketAdapter)(a)
for {
buffer := buf.NewPacket()
n, addr, err := a.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil {
buffer.Release()
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.InboundType = a.protocol
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Source = M.SocksaddrFromNetIP(addr)
metadata.OriginDestination = a.udpAddr
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
if err != nil {
buffer.Release()
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPOOBInThreadSafe() {
defer close(a.packetOutboundClosed)
packetService := (*myInboundPacketAdapter)(a)
oob := make([]byte, 1024)
for {
buffer := buf.NewPacket()
n, oobN, _, addr, err := a.udpConn.ReadMsgUDPAddrPort(buffer.FreeBytes(), oob)
if err != nil {
buffer.Release()
return
}
buffer.Truncate(n)
var metadata adapter.InboundContext
metadata.Inbound = a.tag
metadata.InboundType = a.protocol
metadata.SniffEnabled = a.listenOptions.SniffEnabled
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
metadata.Source = M.SocksaddrFromNetIP(addr)
metadata.OriginDestination = a.udpAddr
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
if err != nil {
buffer.Release()
a.newError(E.Cause(err, "process packet from ", metadata.Source))
}
}
}
func (a *myInboundAdapter) loopUDPOut() {
for {
select {
case packet := <-a.packetOutbound:
err := a.writePacket(packet.buffer, packet.destination)
if err != nil && !E.IsClosed(err) {
a.newError(E.New("write back udp: ", err))
}
continue
case <-a.packetOutboundClosed:
}
for {
select {
case packet := <-a.packetOutbound:
packet.buffer.Release()
default:
return
}
}
}
}
func (a *myInboundAdapter) writePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
defer buffer.Release()
if destination.IsFqdn() {
udpAddr, err := net.ResolveUDPAddr(N.NetworkUDP, destination.String())
if err != nil {
return err
}
return common.Error(a.udpConn.WriteTo(buffer.Bytes(), udpAddr))
}
return common.Error(a.udpConn.WriteToUDPAddrPort(buffer.Bytes(), destination.AddrPort()))
}
type myInboundPacketAdapter myInboundAdapter
func (s *myInboundPacketAdapter) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
n, addr, err := s.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil {
return M.Socksaddr{}, err
}
buffer.Truncate(n)
return M.SocksaddrFromNetIP(addr), nil
}
func (s *myInboundPacketAdapter) WriteIsThreadUnsafe() {
}
type myInboundPacket struct {
buffer *buf.Buffer
destination M.Socksaddr
}
func (s *myInboundPacketAdapter) Upstream() any {
return s.udpConn
}
func (s *myInboundPacketAdapter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
s.packetAccess.RLock()
defer s.packetAccess.RUnlock()
select {
case <-s.packetOutboundClosed:
return os.ErrClosed
default:
}
s.packetOutbound <- &myInboundPacket{buffer, destination}
return nil
}
func (s *myInboundPacketAdapter) Close() error {
return s.udpConn.Close()
}
func (s *myInboundPacketAdapter) LocalAddr() net.Addr {
return s.udpConn.LocalAddr()
}
func (s *myInboundPacketAdapter) SetDeadline(t time.Time) error {
return s.udpConn.SetDeadline(t)
}
func (s *myInboundPacketAdapter) SetReadDeadline(t time.Time) error {
return s.udpConn.SetReadDeadline(t)
}
func (s *myInboundPacketAdapter) SetWriteDeadline(t time.Time) error {
return s.udpConn.SetWriteDeadline(t)
}

View File

@@ -5,6 +5,7 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"net" "net"
"os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@@ -17,7 +18,10 @@ import (
"github.com/sagernet/sing/protocol/http" "github.com/sagernet/sing/protocol/http"
) )
var _ adapter.Inbound = (*HTTP)(nil) var (
_ adapter.Inbound = (*HTTP)(nil)
_ adapter.InjectableInbound = (*HTTP)(nil)
)
type HTTP struct { type HTTP struct {
myInboundAdapter myInboundAdapter
@@ -74,6 +78,10 @@ func (h *HTTP) NewConnection(ctx context.Context, conn net.Conn, metadata adapte
return http.HandleConnection(ctx, conn, std_bufio.NewReader(conn), h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata)) return http.HandleConnection(ctx, conn, std_bufio.NewReader(conn), h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata))
} }
func (h *HTTP) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return os.ErrInvalid
}
func (a *myInboundAdapter) upstreamUserHandler(metadata adapter.InboundContext) adapter.UpstreamHandlerAdapter { func (a *myInboundAdapter) upstreamUserHandler(metadata adapter.InboundContext) adapter.UpstreamHandlerAdapter {
return adapter.NewUpstreamHandler(metadata, a.newUserConnection, a.streamUserPacketConnection, a) return adapter.NewUpstreamHandler(metadata, a.newUserConnection, a.streamUserPacketConnection, a)
} }

View File

@@ -4,6 +4,7 @@ import (
std_bufio "bufio" std_bufio "bufio"
"context" "context"
"net" "net"
"os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@@ -20,7 +21,10 @@ import (
"github.com/sagernet/sing/protocol/socks/socks5" "github.com/sagernet/sing/protocol/socks/socks5"
) )
var _ adapter.Inbound = (*Mixed)(nil) var (
_ adapter.Inbound = (*Mixed)(nil)
_ adapter.InjectableInbound = (*Mixed)(nil)
)
type Mixed struct { type Mixed struct {
myInboundAdapter myInboundAdapter
@@ -57,3 +61,7 @@ func (h *Mixed) NewConnection(ctx context.Context, conn net.Conn, metadata adapt
reader := std_bufio.NewReader(bufio.NewCachedReader(conn, buf.As([]byte{headerType}))) reader := std_bufio.NewReader(bufio.NewCachedReader(conn, buf.As([]byte{headerType})))
return http.HandleConnection(ctx, conn, reader, h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata)) return http.HandleConnection(ctx, conn, reader, h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata))
} }
func (h *Mixed) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return os.ErrInvalid
}

View File

@@ -3,6 +3,7 @@ package inbound
import ( import (
"context" "context"
"net" "net"
"os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@@ -30,7 +31,10 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
} }
} }
var _ adapter.Inbound = (*Shadowsocks)(nil) var (
_ adapter.Inbound = (*Shadowsocks)(nil)
_ adapter.InjectableInbound = (*Shadowsocks)(nil)
)
type Shadowsocks struct { type Shadowsocks struct {
myInboundAdapter myInboundAdapter
@@ -80,14 +84,6 @@ func (h *Shadowsocks) NewPacket(ctx context.Context, conn N.PacketConn, buffer *
return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata)) return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
} }
func (h *Shadowsocks) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *Shadowsocks) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
h.logger.InfoContext(ctx, "inbound connection to ", metadata.Destination) return os.ErrInvalid
return h.router.RouteConnection(ctx, conn, metadata)
}
func (h *Shadowsocks) newPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
ctx = log.ContextWithNewID(ctx)
h.logger.InfoContext(ctx, "inbound packet connection from ", metadata.Source)
h.logger.InfoContext(ctx, "inbound packet connection to ", metadata.Destination)
return h.router.RoutePacketConnection(ctx, conn, metadata)
} }

View File

@@ -21,7 +21,10 @@ import (
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
) )
var _ adapter.Inbound = (*ShadowsocksMulti)(nil) var (
_ adapter.Inbound = (*ShadowsocksMulti)(nil)
_ adapter.InjectableInbound = (*ShadowsocksMulti)(nil)
)
type ShadowsocksMulti struct { type ShadowsocksMulti struct {
myInboundAdapter myInboundAdapter
@@ -114,6 +117,10 @@ func (h *ShadowsocksMulti) NewPacket(ctx context.Context, conn N.PacketConn, buf
return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata)) return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
} }
func (h *ShadowsocksMulti) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return os.ErrInvalid
}
func (h *ShadowsocksMulti) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *ShadowsocksMulti) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
userIndex, loaded := auth.UserFromContext[int](ctx) userIndex, loaded := auth.UserFromContext[int](ctx)
if !loaded { if !loaded {

View File

@@ -17,7 +17,10 @@ import (
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
) )
var _ adapter.Inbound = (*ShadowsocksMulti)(nil) var (
_ adapter.Inbound = (*ShadowsocksRelay)(nil)
_ adapter.InjectableInbound = (*ShadowsocksRelay)(nil)
)
type ShadowsocksRelay struct { type ShadowsocksRelay struct {
myInboundAdapter myInboundAdapter
@@ -76,6 +79,10 @@ func (h *ShadowsocksRelay) NewPacket(ctx context.Context, conn N.PacketConn, buf
return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata)) return h.service.NewPacket(adapter.WithContext(ctx, &metadata), conn, buffer, adapter.UpstreamMetadata(metadata))
} }
func (h *ShadowsocksRelay) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return os.ErrInvalid
}
func (h *ShadowsocksRelay) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *ShadowsocksRelay) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
destinationIndex, loaded := auth.UserFromContext[int](ctx) destinationIndex, loaded := auth.UserFromContext[int](ctx)
if !loaded { if !loaded {

93
inbound/shadowtls.go Normal file
View File

@@ -0,0 +1,93 @@
package inbound
import (
"bytes"
"context"
"encoding/binary"
"io"
"net"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/dialer"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/task"
)
type ShadowTLS struct {
myInboundAdapter
handshakeDialer N.Dialer
handshakeAddr M.Socksaddr
}
func NewShadowTLS(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowTLSInboundOptions) (*ShadowTLS, error) {
inbound := &ShadowTLS{
myInboundAdapter: myInboundAdapter{
protocol: C.TypeShadowTLS,
network: []string{N.NetworkTCP},
ctx: ctx,
router: router,
logger: logger,
tag: tag,
listenOptions: options.ListenOptions,
},
handshakeDialer: dialer.New(router, options.Handshake.DialerOptions),
handshakeAddr: options.Handshake.ServerOptions.Build(),
}
inbound.connHandler = inbound
return inbound, nil
}
func (s *ShadowTLS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
handshakeConn, err := s.handshakeDialer.DialContext(ctx, N.NetworkTCP, s.handshakeAddr)
if err != nil {
return err
}
var handshake task.Group
handshake.Append("client handshake", func(ctx context.Context) error {
return s.copyUntilHandshakeFinished(handshakeConn, conn)
})
handshake.Append("server handshake", func(ctx context.Context) error {
return s.copyUntilHandshakeFinished(conn, handshakeConn)
})
handshake.FastFail()
err = handshake.Run(ctx)
if err != nil {
return err
}
return s.newConnection(ctx, conn, metadata)
}
func (s *ShadowTLS) copyUntilHandshakeFinished(dst io.Writer, src io.Reader) error {
const handshake = 0x16
const changeCipherSpec = 0x14
var hasSeenChangeCipherSpec bool
var tlsHdr [5]byte
for {
_, err := io.ReadFull(src, tlsHdr[:])
if err != nil {
return err
}
length := binary.BigEndian.Uint16(tlsHdr[3:])
_, err = io.Copy(dst, io.MultiReader(bytes.NewReader(tlsHdr[:]), io.LimitReader(src, int64(length))))
if err != nil {
return err
}
if tlsHdr[0] != handshake {
if tlsHdr[0] != changeCipherSpec {
return E.New("unexpected tls frame type: ", tlsHdr[0])
}
if !hasSeenChangeCipherSpec {
hasSeenChangeCipherSpec = true
continue
}
}
if hasSeenChangeCipherSpec {
return nil
}
}
}

View File

@@ -3,6 +3,7 @@ package inbound
import ( import (
"context" "context"
"net" "net"
"os"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
@@ -13,7 +14,10 @@ import (
"github.com/sagernet/sing/protocol/socks" "github.com/sagernet/sing/protocol/socks"
) )
var _ adapter.Inbound = (*Socks)(nil) var (
_ adapter.Inbound = (*Socks)(nil)
_ adapter.InjectableInbound = (*Socks)(nil)
)
type Socks struct { type Socks struct {
myInboundAdapter myInboundAdapter
@@ -40,3 +44,7 @@ func NewSocks(ctx context.Context, router adapter.Router, logger log.ContextLogg
func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
return socks.HandleConnection(ctx, conn, h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata)) return socks.HandleConnection(ctx, conn, h.authenticator, h.upstreamUserHandler(metadata), adapter.UpstreamMetadata(metadata))
} }
func (h *Socks) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return os.ErrInvalid
}

View File

@@ -20,7 +20,10 @@ import (
"github.com/sagernet/sing/protocol/trojan" "github.com/sagernet/sing/protocol/trojan"
) )
var _ adapter.Inbound = (*Trojan)(nil) var (
_ adapter.Inbound = (*Trojan)(nil)
_ adapter.InjectableInbound = (*Trojan)(nil)
)
type Trojan struct { type Trojan struct {
myInboundAdapter myInboundAdapter
@@ -145,16 +148,20 @@ func (h *Trojan) Close() error {
) )
} }
func (h *Trojan) newTransportConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
h.injectTCP(conn, metadata)
return nil
}
func (h *Trojan) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *Trojan) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
if h.tlsConfig != nil { if h.tlsConfig != nil && h.transport == nil {
conn = tls.Server(conn, h.tlsConfig.Config()) conn = tls.Server(conn, h.tlsConfig.Config())
} }
return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata)) return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
} }
func (h *Trojan) newTransportConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
metadata = h.createMetadata(conn, metadata) return os.ErrInvalid
return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
} }
func (h *Trojan) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *Trojan) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {

View File

@@ -21,7 +21,10 @@ import (
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
) )
var _ adapter.Inbound = (*VMess)(nil) var (
_ adapter.Inbound = (*VMess)(nil)
_ adapter.InjectableInbound = (*VMess)(nil)
)
type VMess struct { type VMess struct {
myInboundAdapter myInboundAdapter
@@ -125,16 +128,20 @@ func (h *VMess) Close() error {
) )
} }
func (h *VMess) newTransportConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
h.injectTCP(conn, metadata)
return nil
}
func (h *VMess) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *VMess) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
if h.tlsConfig != nil { if h.tlsConfig != nil && h.transport == nil {
conn = tls.Server(conn, h.tlsConfig.Config()) conn = tls.Server(conn, h.tlsConfig.Config())
} }
return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata)) return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
} }
func (h *VMess) newTransportConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *VMess) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
metadata = h.createMetadata(conn, metadata) return os.ErrInvalid
return h.service.NewConnection(adapter.WithContext(log.ContextWithNewID(ctx), &metadata), conn, adapter.UpstreamMetadata(metadata))
} }
func (h *VMess) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { func (h *VMess) newConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {

View File

@@ -37,7 +37,8 @@ nav:
- Change Log: changelog.md - Change Log: changelog.md
- Configuration: - Configuration:
- configuration/index.md - configuration/index.md
- Log: configuration/log.md - Log:
- configuration/log/index.md
- DNS: - DNS:
- configuration/dns/index.md - configuration/dns/index.md
- DNS Server: configuration/dns/server.md - DNS Server: configuration/dns/server.md
@@ -51,6 +52,8 @@ nav:
- Experimental: - Experimental:
- configuration/experimental/index.md - configuration/experimental/index.md
- Shared: - Shared:
- Listen Fields: configuration/shared/listen.md
- Dial Fields: configuration/shared/dial.md
- TLS: configuration/shared/tls.md - TLS: configuration/shared/tls.md
- Multiplex: configuration/shared/multiplex.md - Multiplex: configuration/shared/multiplex.md
- V2Ray Transport: configuration/shared/v2ray-transport.md - V2Ray Transport: configuration/shared/v2ray-transport.md
@@ -65,6 +68,7 @@ nav:
- Trojan: configuration/inbound/trojan.md - Trojan: configuration/inbound/trojan.md
- Naive: configuration/inbound/naive.md - Naive: configuration/inbound/naive.md
- Hysteria: configuration/inbound/hysteria.md - Hysteria: configuration/inbound/hysteria.md
- ShadowTLS: configuration/inbound/shadowtls.md
- Tun: configuration/inbound/tun.md - Tun: configuration/inbound/tun.md
- Redirect: configuration/inbound/redirect.md - Redirect: configuration/inbound/redirect.md
- TProxy: configuration/inbound/tproxy.md - TProxy: configuration/inbound/tproxy.md
@@ -79,6 +83,7 @@ nav:
- Trojan: configuration/outbound/trojan.md - Trojan: configuration/outbound/trojan.md
- WireGuard: configuration/outbound/wireguard.md - WireGuard: configuration/outbound/wireguard.md
- Hysteria: configuration/outbound/hysteria.md - Hysteria: configuration/outbound/hysteria.md
- ShadowTLS: configuration/outbound/shadowtls.md
- Tor: configuration/outbound/tor.md - Tor: configuration/outbound/tor.md
- SSH: configuration/outbound/ssh.md - SSH: configuration/outbound/ssh.md
- DNS: configuration/outbound/dns.md - DNS: configuration/outbound/dns.md
@@ -92,6 +97,7 @@ nav:
- Shadowsocks Server: examples/ss-server.md - Shadowsocks Server: examples/ss-server.md
- Shadowsocks Client: examples/ss-client.md - Shadowsocks Client: examples/ss-client.md
- Shadowsocks Tun: examples/ss-tun.md - Shadowsocks Tun: examples/ss-tun.md
- ShadowTLS: examples/shadowtls.md
- DNS Hijack: examples/dns-hijack.md - DNS Hijack: examples/dns-hijack.md
- Contributing: - Contributing:
- contributing/index.md - contributing/index.md
@@ -149,6 +155,8 @@ plugins:
Protocol Sniff: 协议探测 Protocol Sniff: 协议探测
Experimental: 实验性 Experimental: 实验性
Shared: 通用 Shared: 通用
Listen Fields: 监听字段
Dial Fields: 拨号字段
Multiplex: 多路复用 Multiplex: 多路复用
V2Ray Transport: V2Ray 传输层 V2Ray Transport: V2Ray 传输层
Inbound: 入站 Inbound: 入站

View File

@@ -94,6 +94,7 @@ type DefaultDNSRule struct {
Port Listable[uint16] `json:"port,omitempty"` Port Listable[uint16] `json:"port,omitempty"`
PortRange Listable[string] `json:"port_range,omitempty"` PortRange Listable[string] `json:"port_range,omitempty"`
ProcessName Listable[string] `json:"process_name,omitempty"` ProcessName Listable[string] `json:"process_name,omitempty"`
ProcessPath Listable[string] `json:"process_path,omitempty"`
PackageName Listable[string] `json:"package_name,omitempty"` PackageName Listable[string] `json:"package_name,omitempty"`
User Listable[string] `json:"user,omitempty"` User Listable[string] `json:"user,omitempty"`
UserID Listable[int32] `json:"user_id,omitempty"` UserID Listable[int32] `json:"user_id,omitempty"`

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