Compare commits

..

31 Commits

Author SHA1 Message Date
世界
e458398bb2 documentation: Bump version 2023-12-21 10:51:57 +08:00
世界
a5d324177b documentation: Update package managers 2023-12-21 10:50:32 +08:00
世界
34d5441d56 documentation: Fix link format 2023-12-21 10:50:32 +08:00
世界
9713dfb29c Fix missing UDP timeout for QUIC protocols 2023-12-21 10:50:27 +08:00
世界
c0483a2b37 Migrate udp_timeout from seconds to duration format 2023-12-21 10:50:27 +08:00
世界
6fe582fcd7 Avoid nested direct outbound usage 2023-12-21 10:50:27 +08:00
世界
081c45b9d7 Add loopback detect for direct outbound 2023-12-21 10:50:27 +08:00
世界
4e02b9ea94 Fix missing handshake timeout for multiplex 2023-12-21 10:50:21 +08:00
世界
0b2023660b Fix DNS dial context 2023-12-21 10:50:18 +08:00
世界
dee6fffa23 Make generated files have SUDO_USER's permissions if possible. 2023-12-21 10:49:02 +08:00
世界
26d29761df Refactor inbound/outbound options struct 2023-12-21 10:49:02 +08:00
世界
4e4d220bbe Improve configuration merge 2023-12-21 10:49:02 +08:00
世界
d38336bec4 Update uTLS to 1.5.4 2023-12-21 10:49:02 +08:00
世界
de4f167402 Update tfo-go 2023-12-21 10:49:02 +08:00
世界
b9439b8fbd Update gomobile and add tag 2023-12-21 10:49:02 +08:00
世界
817be7af6e Update cloudflare-tls to go1.21.5 2023-12-21 10:49:02 +08:00
世界
f57e98dbb0 Remove unnecessary context wrappers 2023-12-21 10:49:02 +08:00
世界
47213f0616 Improve read wait interface &
Refactor Authenticator interface to struct &
Update smux &
Update gVisor to 20231204.0 &
Update wireguard-go &
Add GSO support for TUN/WireGuard &
Fix router pre-start &
Fix bind forwarder to interface for systems stack
2023-12-21 10:48:41 +08:00
世界
2f4f4e18ee Make type check strict 2023-12-18 22:26:02 +08:00
世界
bc2d73b2d6 Remove comparable limit for Listable 2023-12-18 22:26:01 +08:00
世界
abd4d8b367 Avoid opening log output before start &
Replace tracing logs with task monitor
2023-12-18 22:26:01 +08:00
世界
f998ccecde Update documentation 2023-12-18 22:26:01 +08:00
世界
fc9804b20f Add idle_timeout for URLTest outbound 2023-12-18 22:26:01 +08:00
世界
d1ad342cb0 Skip internal fake-ip queries 2023-12-18 22:26:01 +08:00
世界
80cc0cd5db Migrate contentjson and badjson to library &
Add omitempty in format
2023-12-18 22:25:54 +08:00
世界
3041f34dfa Update documentation 2023-12-18 22:25:54 +08:00
世界
3a9b787a6e Independent source_ip_is_private and ip_is_private rules 2023-12-18 22:25:53 +08:00
世界
bb70e8267e Add rule-set 2023-12-18 22:25:53 +08:00
世界
411f02ee4f Update buffer usage 2023-12-18 22:25:53 +08:00
世界
340e74eed4 Allow nested logical rules 2023-12-18 22:25:53 +08:00
世界
ad93b45021 Migrate to independent cache file 2023-12-18 22:25:53 +08:00
27 changed files with 321 additions and 183 deletions

View File

@@ -1,6 +1,7 @@
package main
import (
"encoding/json"
"io"
"os"
@@ -8,7 +9,6 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/json"
"github.com/spf13/cobra"
)

View File

@@ -6,21 +6,27 @@ import (
"sync"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
type DetourDialer struct {
router adapter.Router
detour string
dialer N.Dialer
initOnce sync.Once
initErr error
router adapter.Router
detour string
allowNestedDirect bool
dialer N.Dialer
initOnce sync.Once
initErr error
}
func NewDetour(router adapter.Router, detour string) N.Dialer {
return &DetourDialer{router: router, detour: detour}
func NewDetour(router adapter.Router, detour string, allowNestedDirect bool) N.Dialer {
return &DetourDialer{
router: router,
detour: detour,
allowNestedDirect: allowNestedDirect,
}
}
func (d *DetourDialer) Start() error {
@@ -30,10 +36,17 @@ func (d *DetourDialer) Start() error {
func (d *DetourDialer) Dialer() (N.Dialer, error) {
d.initOnce.Do(func() {
var loaded bool
d.dialer, loaded = d.router.Outbound(d.detour)
var (
dialer adapter.Outbound
loaded bool
)
dialer, loaded = d.router.Outbound(d.detour)
if !loaded {
d.initErr = E.New("outbound detour not found: ", d.detour)
} else if !d.allowNestedDirect && dialer.Type() == C.TypeDirect {
d.initErr = E.New("using a direct outbound as a detour is illegal")
} else {
d.dialer = dialer
}
})
return d.dialer, d.initErr

View File

@@ -23,7 +23,7 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error)
return nil, err
}
} else {
dialer = NewDetour(router, options.Detour)
dialer = NewDetour(router, options.Detour, false)
}
domainStrategy := dns.DomainStrategy(options.DomainStrategy)
if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" {

View File

@@ -2,20 +2,6 @@
icon: material/alert-decagram
---
#### 1.8.0-rc.3
* Fixes and improvements
* Fix V2Ray transport `path` validation behavior **1**
**1**:
See [V2Ray transport](/configuration/shared/v2ray-transport/).
#### 1.7.6
* Fixes and improvements
#### 1.8.0-rc.1
* Fixes and improvements

View File

@@ -2,11 +2,11 @@
Maintained by Project S to provide a unified experience and platform-specific functionality.
| Platform | Client |
|---------------------------------------|------------------------------------------|
| Platform | Client |
|---------------------------------------|-----------------------------------------|
| :material-android: Android | [sing-box for Android](./android/) |
| :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) |
| :material-laptop: Desktop | Working in progress |
| :material-laptop: Desktop | Working in progress |
Some third-party projects that claim to use sing-box or use sing-box as a selling point are not listed here. The core
motivation of the maintainers of such projects is to acquire more users, and even though they provide friendly VPN

View File

@@ -21,8 +21,8 @@
### 字段
| 键 | 格式 |
|----------|-------------------------|
| 键 | 格式 |
|----------|------------------------|
| `server` | 一组 [DNS 服务器](./server/) |
| `rules` | 一组 [DNS 规则](./rule/) |

View File

@@ -30,17 +30,17 @@ The tag of the dns server.
The address of the dns server.
| Protocol | Format |
|--------------------------------------|-------------------------------|
| `System` | `local` |
| `TCP` | `tcp://1.0.0.1` |
| `UDP` | `8.8.8.8` `udp://8.8.4.4` |
| `TLS` | `tls://dns.google` |
| `HTTPS` | `https://1.1.1.1/dns-query` |
| `QUIC` | `quic://dns.adguard.com` |
| `HTTP3` | `h3://8.8.8.8/dns-query` |
| `RCode` | `rcode://refused` |
| `DHCP` | `dhcp://auto` or `dhcp://en0` |
| Protocol | Format |
|-------------------------------------|-------------------------------|
| `System` | `local` |
| `TCP` | `tcp://1.0.0.1` |
| `UDP` | `8.8.8.8` `udp://8.8.4.4` |
| `TLS` | `tls://dns.google` |
| `HTTPS` | `https://1.1.1.1/dns-query` |
| `QUIC` | `quic://dns.adguard.com` |
| `HTTP3` | `h3://8.8.8.8/dns-query` |
| `RCode` | `rcode://refused` |
| `DHCP` | `dhcp://auto` or `dhcp://en0` |
| [FakeIP](/configuration/dns/fakeip/) | `fakeip` |
!!! warning ""

View File

@@ -30,17 +30,17 @@ DNS 服务器的标签。
DNS 服务器的地址。
| 协议 | 格式 |
|--------------------------------------|------------------------------|
| `System` | `local` |
| `TCP` | `tcp://1.0.0.1` |
| `UDP` | `8.8.8.8` `udp://8.8.4.4` |
| `TLS` | `tls://dns.google` |
| `HTTPS` | `https://1.1.1.1/dns-query` |
| `QUIC` | `quic://dns.adguard.com` |
| `HTTP3` | `h3://8.8.8.8/dns-query` |
| `RCode` | `rcode://refused` |
| `DHCP` | `dhcp://auto``dhcp://en0` |
| 协议 | 格式 |
|-------------------------------------|------------------------------|
| `System` | `local` |
| `TCP` | `tcp://1.0.0.1` |
| `UDP` | `8.8.8.8` `udp://8.8.4.4` |
| `TLS` | `tls://dns.google` |
| `HTTPS` | `https://1.1.1.1/dns-query` |
| `QUIC` | `quic://dns.adguard.com` |
| `HTTP3` | `h3://8.8.8.8/dns-query` |
| `RCode` | `rcode://refused` |
| `DHCP` | `dhcp://auto``dhcp://en0` |
| [FakeIP](/configuration/dns/fakeip/) | `fakeip` |
!!! warning ""

View File

@@ -15,8 +15,8 @@
### Fields
| Type | Format | Injectable |
|---------------|-------------------------------|------------|
| Type | Format | Injectable |
|---------------|------------------------------|------------|
| `direct` | [Direct](./direct/) | X |
| `mixed` | [Mixed](./mixed/) | TCP |
| `socks` | [SOCKS](./socks/) | TCP |

View File

@@ -18,8 +18,8 @@ sing-box uses JSON for configuration files.
### Fields
| Key | Format |
|----------------|---------------------------------|
| Key | Format |
|----------------|--------------------------------|
| `log` | [Log](./log/) |
| `dns` | [DNS](./dns/) |
| `ntp` | [NTP](./ntp/) |

View File

@@ -17,8 +17,8 @@ sing-box 使用 JSON 作为配置文件格式。
### 字段
| Key | Format |
|----------------|------------------------|
| Key | Format |
|----------------|-----------------------|
| `log` | [日志](./log/) |
| `dns` | [DNS](./dns/) |
| `inbounds` | [入站](./inbound/) |

View File

@@ -30,14 +30,15 @@ icon: material/alert-decagram
### 字段
| 键 | 格式 |
|-----------|-----------------------|
| `geoip` | [GeoIP](./geoip/) |
| `geosite` | [Geosite](./geosite/) |
| 键 | 格式 |
|------------|-----------------------------------|
| `geoip` | [GeoIP](./geoip/) |
| `geosite` | [Geosite](./geosite/) |
#### rule
一组 [路由规则](./rule/)
一组 [路由规则](./rule/)。
#### rule_set

View File

@@ -31,4 +31,4 @@ Version of Rule Set, must be `1`.
==Required==
List of [Headless Rule](./headless-rule.md/).
List of [Headless Rule](./headless-rule/).

View File

@@ -53,15 +53,9 @@ The client will choose randomly and the server will verify if not empty.
#### path
!!! warning
V2Ray's documentation says that the path between the server and the client must be consistent,
but the actual code allows the client to add any suffix to the path.
sing-box uses the same behavior as V2Ray, but note that the behavior does not exist in `WebSocket` and `HTTPUpgrade` transport.
Path of HTTP request.
The server will verify.
The server will verify if not empty.
#### method
@@ -83,10 +77,7 @@ Specifies the time until idle clients should be closed with a GOAWAY frame. PING
In HTTP2 client:
Specifies the period of time after which a health check will be performed using a ping frame if no frames have been
received on the connection.Please note that a ping response is considered a received frame, so if there is no other
traffic on the connection, the health check will be executed every interval. If the value is zero, no health check will
be performed.
Specifies the period of time after which a health check will be performed using a ping frame if no frames have been received on the connection. Please note that a ping response is considered a received frame, so if there is no other traffic on the connection, the health check will be executed every interval. If the value is zero, no health check will be performed.
Zero is used by default.
@@ -94,9 +85,7 @@ Zero is used by default.
In HTTP2 client:
Specifies the timeout duration after sending a PING frame, within which a response must be received.
If a response to the PING frame is not received within the specified timeout duration, the connection will be closed.
The default timeout duration is 15 seconds.
Specifies the timeout duration after sending a PING frame, within which a response must be received. If a response to the PING frame is not received within the specified timeout duration, the connection will be closed. The default timeout duration is 15 seconds.
### WebSocket
@@ -114,14 +103,12 @@ The default timeout duration is 15 seconds.
Path of HTTP request.
The server will verify.
The server will verify if not empty.
#### headers
Extra headers of HTTP request.
The server will write in response if not empty.
#### max_early_data
Allowed payload size is in the request. Enabled if not zero.
@@ -171,8 +158,7 @@ Service name of gRPC.
In standard gRPC server/client:
If the transport doesn't see any activity after a duration of this time,
it pings the client to check if the connection is still active.
If the transport doesn't see any activity after a duration of this time, it pings the client to check if the connection is still active.
In default gRPC server/client:
@@ -182,8 +168,7 @@ It has the same behavior as the corresponding setting in HTTP transport.
In standard gRPC server/client:
The timeout that after performing a keepalive check, the client will wait for activity.
If no activity is detected, the connection will be closed.
The timeout that after performing a keepalive check, the client will wait for activity. If no activity is detected, the connection will be closed.
In default gRPC server/client:
@@ -193,9 +178,7 @@ It has the same behavior as the corresponding setting in HTTP transport.
In standard gRPC client:
If enabled, the client transport sends keepalive pings even with no active connections.
If disabled, when there are no active connections, `idle_timeout` and `ping_timeout` will be ignored and no keepalive
pings will be sent.
If enabled, the client transport sends keepalive pings even with no active connections. If disabled, when there are no active connections, `idle_timeout` and `ping_timeout` will be ignored and no keepalive pings will be sent.
Disabled by default.
@@ -220,7 +203,7 @@ The server will verify if not empty.
Path of HTTP request.
The server will verify.
The server will verify if not empty.
#### headers

View File

@@ -48,30 +48,25 @@ V2Ray Transport 是 v2ray 发明的一组私有协议,并污染了其他协议
主机域名列表。
如果设置,客户端将随机选择,服务器将验证。
客户端将随机选择,默认服务器将验证。
#### path
!!! warning
V2Ray 文档称服务端和客户端的路径必须一致,但实际代码允许客户端向路径添加任何后缀。
sing-box 使用与 V2Ray 相同的行为,但请注意,该行为在 `WebSocket``HTTPUpgrade` 传输层中不存在。
HTTP 请求路径
服务器将验证。
默认服务器将验证。
#### method
HTTP 请求方法
如果设置,服务器将验证。
默认服务器将验证。
#### headers
HTTP 请求的额外标头
如果设置,服务器将写入响应。
默认服务器将写入响应。
#### idle_timeout
@@ -107,13 +102,11 @@ HTTP 请求的额外标头
HTTP 请求路径
服务器将验证。
默认服务器将验证。
#### headers
HTTP 请求的额外标头
如果设置,服务器将写入响应。
HTTP 请求的额外标头
#### max_early_data
@@ -203,16 +196,16 @@ gRPC 服务名称。
主机域名。
服务器将验证。
默认服务器将验证。
#### path
HTTP 请求路径
服务器将验证。
默认服务器将验证。
#### headers
HTTP 请求的额外标头。
如果设置,服务器将写入响应。
默认服务器将写入响应。

View File

@@ -53,19 +53,19 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
## :material-folder-settings: Build Tags
| Build Tag | Enabled by default | Description |
|------------------------------------|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Build Tag | Enabled by default | Description |
|------------------------------------|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `with_quic` | :material-check: | Build with QUIC support, see [QUIC and HTTP3 DNS transports](/configuration/dns/server/), [Naive inbound](/configuration/inbound/naive/), [Hysteria Inbound](/configuration/inbound/hysteria/), [Hysteria Outbound](/configuration/outbound/hysteria/) and [V2Ray Transport#QUIC](/configuration/shared/v2ray-transport#quic). |
| `with_grpc` | :material-close: | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). |
| `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). |
| `with_wireguard` | :material-check: | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard/). |
| `with_ech` | :material-check: | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). |
| `with_utls` | :material-check: | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). |
| `with_reality_server` | :material-check: | Build with reality TLS server support, see [TLS](/configuration/shared/tls/). |
| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). |
| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). |
| `with_v2ray_api` | :material-close: | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). |
| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). |
| `with_embedded_tor` (CGO required) | :material-close: | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). |
| `with_grpc` | :material-close: | Build with standard gRPC support, see [V2Ray Transport#gRPC](/configuration/shared/v2ray-transport#grpc). |
| `with_dhcp` | :material-check: | Build with DHCP support, see [DHCP DNS transport](/configuration/dns/server/). |
| `with_wireguard` | :material-check: | Build with WireGuard support, see [WireGuard outbound](/configuration/outbound/wireguard/). |
| `with_ech` | :material-check: | Build with TLS ECH extension support for TLS outbound, see [TLS](/configuration/shared/tls#ech). |
| `with_utls` | :material-check: | Build with [uTLS](https://github.com/refraction-networking/utls) support for TLS outbound, see [TLS](/configuration/shared/tls#utls). |
| `with_reality_server` | :material-check: | Build with reality TLS server support, see [TLS](/configuration/shared/tls/). |
| `with_acme` | :material-check: | Build with ACME TLS certificate issuer support, see [TLS](/configuration/shared/tls/). |
| `with_clash_api` | :material-check: | Build with Clash API support, see [Experimental](/configuration/experimental#clash-api-fields). |
| `with_v2ray_api` | :material-close: | Build with V2Ray API support, see [Experimental](/configuration/experimental#v2ray-api-fields). |
| `with_gvisor` | :material-check: | Build with gVisor support, see [Tun inbound](/configuration/inbound/tun#stack) and [WireGuard outbound](/configuration/outbound/wireguard#system_interface). |
| `with_embedded_tor` (CGO required) | :material-close: | Build with embedded Tor support, see [Tor outbound](/configuration/outbound/tor/). |
It is not recommended to change the default build tag list unless you really know what you are adding.

View File

@@ -1,6 +1,7 @@
package trafficontrol
import (
"encoding/json"
"net"
"net/netip"
"time"
@@ -9,7 +10,6 @@ import (
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/json"
N "github.com/sagernet/sing/common/network"
"github.com/gofrs/uuid/v5"

16
go.mod
View File

@@ -26,14 +26,14 @@ require (
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e
github.com/sagernet/quic-go v0.40.0
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.3.0-rc.3
github.com/sagernet/sing-dns v0.1.12
github.com/sagernet/sing-mux v0.1.7-rc.1
github.com/sagernet/sing-quic v0.1.7-rc.1
github.com/sagernet/sing v0.3.0-beta.7
github.com/sagernet/sing-dns v0.1.12-beta.1
github.com/sagernet/sing-mux v0.1.6-beta.3
github.com/sagernet/sing-quic v0.1.6-beta.2
github.com/sagernet/sing-shadowsocks v0.2.6
github.com/sagernet/sing-shadowsocks2 v0.1.6-rc.1
github.com/sagernet/sing-shadowsocks2 v0.1.6-beta.1
github.com/sagernet/sing-shadowtls v0.1.4
github.com/sagernet/sing-tun v0.2.0-rc.1
github.com/sagernet/sing-tun v0.2.0-beta.4
github.com/sagernet/sing-vmess v0.1.8
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6
@@ -44,7 +44,7 @@ require (
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.26.0
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.17.0
golang.org/x/crypto v0.16.0
golang.org/x/net v0.19.0
golang.org/x/sys v0.15.0
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
@@ -86,7 +86,7 @@ require (
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 // indirect
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect

34
go.sum
View File

@@ -109,24 +109,22 @@ github.com/sagernet/quic-go v0.40.0/go.mod h1:VqtdhlbkeeG5Okhb3eDMb/9o0EoglReHun
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.3.0-rc.3 h1:4GVTffZlbFkBTg3woQBY3O+y/jFUvlbY6u5TYu4G4Ck=
github.com/sagernet/sing v0.3.0-rc.3/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
github.com/sagernet/sing v0.3.0-rc.3.0.20231221131018-2b0a53a3a6c4 h1:0fzuZBSmCSWUQu2ZexJ8ys4Cg+mth2Nzu4ZwYolJ2GU=
github.com/sagernet/sing v0.3.0-rc.3.0.20231221131018-2b0a53a3a6c4/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
github.com/sagernet/sing-dns v0.1.12 h1:1HqZ+ln+Rezx/aJMStaS0d7oPeX2EobSV1NT537kyj4=
github.com/sagernet/sing-dns v0.1.12/go.mod h1:rx/DTOisneQpCgNQ4jbFU/JNEtnz0lYcHXenlVzpjEU=
github.com/sagernet/sing-mux v0.1.7-rc.1 h1:4XlQSeIqKA6uaW1KGQA9wCG5zt9ajhvc/zJnnZV/n1c=
github.com/sagernet/sing-mux v0.1.7-rc.1/go.mod h1:KK5zCbNujj5kn36G+wLFROOXyJhaaXLyaZWY2w7kBNQ=
github.com/sagernet/sing-quic v0.1.7-rc.1 h1:HoZC7YFmHCpfrUNXbousGauLw6yg25f6qcIkqrYIDbg=
github.com/sagernet/sing-quic v0.1.7-rc.1/go.mod h1:+XDZtFPD8YJ4V1MMObOdf2k5+Ma1jy75OlRnlBUHihI=
github.com/sagernet/sing v0.3.0-beta.7 h1:AAGnMovsI1r8su731Yl6nDMwWw5XIXkmdlaVBIeL7uI=
github.com/sagernet/sing v0.3.0-beta.7/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
github.com/sagernet/sing-dns v0.1.12-beta.1 h1:5J3VxSmz3ezVXYS0m8jce8jakbTiP8xiH2g2HGYjNR4=
github.com/sagernet/sing-dns v0.1.12-beta.1/go.mod h1:zJ/YjnYB61SYE+ubMcMqVdpaSvsyQ2iShQGO3vuLvvE=
github.com/sagernet/sing-mux v0.1.6-beta.3 h1:Bcd89O0zgDNs/q6MJBS0EpgRvry9dB0VJ2FAL9Q2Mp8=
github.com/sagernet/sing-mux v0.1.6-beta.3/go.mod h1:WWtRmrwCDgb+g+7Da6o62I9WiMNB0a3w6BJhEpNQlNA=
github.com/sagernet/sing-quic v0.1.6-beta.2 h1:u/tab4OB2IlEUxORJ0ncIWLemiJa2oQ/IonB1ysxHQo=
github.com/sagernet/sing-quic v0.1.6-beta.2/go.mod h1:+OLsIVPmgHzCqcF3lGBVngc7ItYM6v3T0rn6Qtd4T1g=
github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s=
github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM=
github.com/sagernet/sing-shadowsocks2 v0.1.6-rc.1 h1:E+8OyyVg0YfFNUmxMx9jYBEhjLYMQSAMzJrUmE934bo=
github.com/sagernet/sing-shadowsocks2 v0.1.6-rc.1/go.mod h1:wFkU7sKxyZADS/idtJqBhtc+QBf5iwX9nZO7ymcn6MM=
github.com/sagernet/sing-shadowsocks2 v0.1.6-beta.1 h1:0vbf4XA6QybVXhUqlmbceYWYpH96s4RRt6J+K+Xtr0A=
github.com/sagernet/sing-shadowsocks2 v0.1.6-beta.1/go.mod h1:H7p/X9U15oLBpdAHPk+n3GMEuJiimImj1B3GfwY2igE=
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
github.com/sagernet/sing-tun v0.2.0-rc.1 h1:CnlxRgrJKAMKYNuJOcKie6TjRz8wremEq1wndLup7cA=
github.com/sagernet/sing-tun v0.2.0-rc.1/go.mod h1:hpbL9jNAbYT9G2EHCpCXVIgSrM/2Wgnrm/Hped+8zdY=
github.com/sagernet/sing-tun v0.2.0-beta.4 h1:KcblUxYmG9/Qyn38AP1uFf/a/fh1kmFrybmF0eYlfrQ=
github.com/sagernet/sing-tun v0.2.0-beta.4/go.mod h1:bV5YMmTun6g8AavxZDLu9S69MLVlu3Y9isBr3z0ujW4=
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc=
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
@@ -170,10 +168,10 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848 h1:+iq7lrkxmFNBM7xx+Rae2W6uyPfhPeDWD+n+JgppptE=
golang.org/x/exp v0.0.0-20231219180239-dc181d75b848/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4=
golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=

View File

@@ -1,8 +1,9 @@
package option
import (
"encoding/json"
"github.com/sagernet/sing-box/common/humanize"
"github.com/sagernet/sing/common/json"
)
type DebugOptions struct {

View File

@@ -30,10 +30,14 @@ type Direct struct {
fallbackDelay time.Duration
overrideOption int
overrideDestination M.Socksaddr
loopBack *loopBackDetector
}
func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (*Direct, error) {
options.UDPFragmentDefault = true
if options.Detour != "" {
return nil, E.New("detour option for direct outbound is illegal")
}
outboundDialer, err := dialer.New(router, options.DialerOptions)
if err != nil {
return nil, err
@@ -50,6 +54,7 @@ func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, opti
domainStrategy: dns.DomainStrategy(options.DomainStrategy),
fallbackDelay: time.Duration(options.FallbackDelay),
dialer: outboundDialer,
loopBack: newLoopBackDetector(),
}
if options.ProxyProtocol != 0 {
return nil, E.New("Proxy Protocol is deprecated and removed in sing-box 1.6.0")
@@ -88,7 +93,11 @@ func (h *Direct) DialContext(ctx context.Context, network string, destination M.
case N.NetworkUDP:
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
}
return h.dialer.DialContext(ctx, network, destination)
conn, err := h.dialer.DialContext(ctx, network, destination)
if err != nil {
return nil, err
}
return h.loopBack.NewConn(conn), nil
}
func (h *Direct) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
@@ -142,6 +151,7 @@ func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
if err != nil {
return nil, err
}
conn = h.loopBack.NewPacketConn(conn)
if originDestination != destination {
conn = bufio.NewNATPacketConn(bufio.NewPacketConn(conn), destination, originDestination)
}
@@ -149,9 +159,15 @@ func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
}
func (h *Direct) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
if h.loopBack.CheckConn(metadata.Source.AddrPort()) {
return E.New("reject loopback connection to ", metadata.Destination)
}
return NewConnection(ctx, h, conn, metadata)
}
func (h *Direct) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
if h.loopBack.CheckPacketConn(metadata.Source.AddrPort()) {
return E.New("reject loopback packet connection to ", metadata.Destination)
}
return NewPacketConnection(ctx, h, conn, metadata)
}

View File

@@ -0,0 +1,153 @@
package outbound
import (
"net"
"net/netip"
"sync"
M "github.com/sagernet/sing/common/metadata"
)
type loopBackDetector struct {
connAccess sync.RWMutex
packetConnAccess sync.RWMutex
connMap map[netip.AddrPort]bool
packetConnMap map[netip.AddrPort]bool
}
func newLoopBackDetector() *loopBackDetector {
return &loopBackDetector{
connMap: make(map[netip.AddrPort]bool),
packetConnMap: make(map[netip.AddrPort]bool),
}
}
func (l *loopBackDetector) NewConn(conn net.Conn) net.Conn {
connAddr := M.AddrPortFromNet(conn.LocalAddr())
if !connAddr.IsValid() {
return conn
}
if udpConn, isUDPConn := conn.(abstractUDPConn); isUDPConn {
l.packetConnAccess.Lock()
l.packetConnMap[connAddr] = true
l.packetConnAccess.Unlock()
return &loopBackDetectUDPWrapper{abstractUDPConn: udpConn, detector: l, connAddr: connAddr}
} else {
l.connAccess.Lock()
l.connMap[connAddr] = true
l.connAccess.Unlock()
return &loopBackDetectWrapper{Conn: conn, detector: l, connAddr: connAddr}
}
}
func (l *loopBackDetector) NewPacketConn(conn net.PacketConn) net.PacketConn {
connAddr := M.AddrPortFromNet(conn.LocalAddr())
if !connAddr.IsValid() {
return conn
}
l.packetConnAccess.Lock()
l.packetConnMap[connAddr] = true
l.packetConnAccess.Unlock()
return &loopBackDetectPacketWrapper{PacketConn: conn, detector: l, connAddr: connAddr}
}
func (l *loopBackDetector) CheckConn(connAddr netip.AddrPort) bool {
l.connAccess.RLock()
defer l.connAccess.RUnlock()
return l.connMap[connAddr]
}
func (l *loopBackDetector) CheckPacketConn(connAddr netip.AddrPort) bool {
l.packetConnAccess.RLock()
defer l.packetConnAccess.RUnlock()
return l.packetConnMap[connAddr]
}
type loopBackDetectWrapper struct {
net.Conn
detector *loopBackDetector
connAddr netip.AddrPort
closeOnce sync.Once
}
func (w *loopBackDetectWrapper) Close() error {
w.closeOnce.Do(func() {
w.detector.connAccess.Lock()
delete(w.detector.connMap, w.connAddr)
w.detector.connAccess.Unlock()
})
return w.Conn.Close()
}
func (w *loopBackDetectWrapper) ReaderReplaceable() bool {
return true
}
func (w *loopBackDetectWrapper) WriterReplaceable() bool {
return true
}
func (w *loopBackDetectWrapper) Upstream() any {
return w.Conn
}
type loopBackDetectPacketWrapper struct {
net.PacketConn
detector *loopBackDetector
connAddr netip.AddrPort
closeOnce sync.Once
}
func (w *loopBackDetectPacketWrapper) Close() error {
w.closeOnce.Do(func() {
w.detector.packetConnAccess.Lock()
delete(w.detector.packetConnMap, w.connAddr)
w.detector.packetConnAccess.Unlock()
})
return w.PacketConn.Close()
}
func (w *loopBackDetectPacketWrapper) ReaderReplaceable() bool {
return true
}
func (w *loopBackDetectPacketWrapper) WriterReplaceable() bool {
return true
}
func (w *loopBackDetectPacketWrapper) Upstream() any {
return w.PacketConn
}
type abstractUDPConn interface {
net.Conn
net.PacketConn
}
type loopBackDetectUDPWrapper struct {
abstractUDPConn
detector *loopBackDetector
connAddr netip.AddrPort
closeOnce sync.Once
}
func (w *loopBackDetectUDPWrapper) Close() error {
w.closeOnce.Do(func() {
w.detector.packetConnAccess.Lock()
delete(w.detector.packetConnMap, w.connAddr)
w.detector.packetConnAccess.Unlock()
})
return w.abstractUDPConn.Close()
}
func (w *loopBackDetectUDPWrapper) ReaderReplaceable() bool {
return true
}
func (w *loopBackDetectUDPWrapper) WriterReplaceable() bool {
return true
}
func (w *loopBackDetectUDPWrapper) Upstream() any {
return w.abstractUDPConn
}

View File

@@ -195,7 +195,7 @@ func NewRouter(
if server.Detour == "" {
detour = dialer.NewRouter(router)
} else {
detour = dialer.NewDetour(router, server.Detour)
detour = dialer.NewDetour(router, server.Detour, true)
}
switch server.Address {
case "local":

View File

@@ -7,7 +7,6 @@ import (
"net"
"net/http"
"net/url"
"strings"
"time"
"github.com/sagernet/sing-box/adapter"
@@ -59,25 +58,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
},
}
}
if options.Method == "" {
options.Method = http.MethodPut
}
var requestURL url.URL
if tlsConfig == nil {
requestURL.Scheme = "http"
} else {
requestURL.Scheme = "https"
}
requestURL.Host = serverAddr.String()
requestURL.Path = options.Path
err := sHTTP.URLSetPath(&requestURL, options.Path)
if err != nil {
return nil, E.Cause(err, "parse path")
}
if !strings.HasPrefix(requestURL.Path, "/") {
requestURL.Path = "/" + requestURL.Path
}
return &Client{
client := &Client{
ctx: ctx,
dialer: dialer,
serverAddr: serverAddr,
@@ -86,7 +67,24 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
headers: options.Headers.Build(),
transport: transport,
http2: tlsConfig != nil,
}, nil
}
if client.method == "" {
client.method = "PUT"
}
var uri url.URL
if tlsConfig == nil {
uri.Scheme = "http"
} else {
uri.Scheme = "https"
}
uri.Host = serverAddr.String()
uri.Path = options.Path
err := sHTTP.URLSetPath(&uri, options.Path)
if err != nil {
return nil, E.Cause(err, "parse path")
}
client.url = &uri
return client, nil
}
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {

View File

@@ -65,7 +65,7 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
s.invalidRequest(writer, request, http.StatusBadRequest, E.New("bad host: ", host))
return
}
if request.URL.Path != s.path {
if !strings.HasPrefix(request.URL.Path, s.path) {
s.invalidRequest(writer, request, http.StatusNotFound, E.New("bad path: ", request.URL.Path))
return
}

View File

@@ -55,10 +55,15 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
if !strings.HasPrefix(requestURL.Path, "/") {
requestURL.Path = "/" + requestURL.Path
}
headers := options.Headers.Build()
if host := headers.Get("Host"); host != "" {
headers.Del("Host")
requestURL.Host = host
headers := make(http.Header)
for key, value := range options.Headers {
headers[key] = value
if key == "Host" {
if len(value) > 1 {
return nil, E.New("multiple Host headers")
}
requestURL.Host = value[0]
}
}
if headers.Get("User-Agent") == "" {
headers.Set("User-Agent", "Go-http-client/1.1")

View File

@@ -33,7 +33,6 @@ type Server struct {
path string
maxEarlyData uint32
earlyDataHeaderName string
upgrader ws.HTTPUpgrader
}
func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsConfig tls.ServerConfig, handler adapter.V2RayServerTransportHandler) (*Server, error) {
@@ -44,10 +43,6 @@ func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsCon
path: options.Path,
maxEarlyData: options.MaxEarlyData,
earlyDataHeaderName: options.EarlyDataHeaderName,
upgrader: ws.HTTPUpgrader{
Timeout: C.TCPTimeout,
Header: options.Headers.Build(),
},
}
if !strings.HasPrefix(server.path, "/") {
server.path = "/" + server.path
@@ -84,10 +79,6 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
return
}
} else {
if request.URL.Path != s.path {
s.invalidRequest(writer, request, http.StatusNotFound, E.New("bad path: ", request.URL.Path))
return
}
earlyDataStr := request.Header.Get(s.earlyDataHeaderName)
if earlyDataStr != "" {
earlyData, err = base64.RawURLEncoding.DecodeString(earlyDataStr)