mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-13 20:28:32 +10:00
Compare commits
54 Commits
v1.9.0-rc.
...
v1.9.0-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
996c1730c6 | ||
|
|
a70144f758 | ||
|
|
18975a0d22 | ||
|
|
5726e024eb | ||
|
|
1284e1fbd1 | ||
|
|
842cb5c747 | ||
|
|
2be5139f1d | ||
|
|
0cc77fd725 | ||
|
|
bc0964ee1d | ||
|
|
5899e95ff1 | ||
|
|
d7160c19cf | ||
|
|
da9e22b4e6 | ||
|
|
0e120f8a44 | ||
|
|
d918863ac5 | ||
|
|
2ae192305c | ||
|
|
71d1879bd6 | ||
|
|
917514e09f | ||
|
|
5327aeaea4 | ||
|
|
93ae3f7a1e | ||
|
|
f24a2aed7d | ||
|
|
0517ceef76 | ||
|
|
830ea46932 | ||
|
|
cd0fcd5ddc | ||
|
|
003176f069 | ||
|
|
71d92518c1 | ||
|
|
b5dcd6bf59 | ||
|
|
11c7b4a866 | ||
|
|
ee14135298 | ||
|
|
cbcf005f37 | ||
|
|
daee0b154e | ||
|
|
d530c724c0 | ||
|
|
7f698c1104 | ||
|
|
7a4a44c6d2 | ||
|
|
44277e5dd2 | ||
|
|
1f470c69c4 | ||
|
|
742adacce7 | ||
|
|
32e1d5a5e2 | ||
|
|
cb9f4ce597 | ||
|
|
4b1a6185ba | ||
|
|
8d85c92356 | ||
|
|
c6164c9eca | ||
|
|
3c85b8bc48 | ||
|
|
8b8fb4344c | ||
|
|
e85a38e059 | ||
|
|
f3ac91673a | ||
|
|
0f1e58b917 | ||
|
|
c4cfe24aef | ||
|
|
3d73b159ba | ||
|
|
0ae1afef44 | ||
|
|
a5e2a4073b | ||
|
|
b6cb3948a3 | ||
|
|
7b0f5061dc | ||
|
|
76f20482f7 | ||
|
|
e735a5bdc8 |
10
.github/workflows/debug.yml
vendored
10
.github/workflows/debug.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -208,7 +208,7 @@ jobs:
|
||||
TAGS: with_clash_api,with_quic
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
|
||||
31
.github/workflows/docker.yml
vendored
31
.github/workflows/docker.yml
vendored
@@ -4,13 +4,35 @@ on:
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "The tag version you want to build"
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get commit to build
|
||||
id: ref
|
||||
run: |-
|
||||
if [[ -z "${{ github.event.inputs.tag }}" ]]; then
|
||||
ref="${{ github.ref_name }}"
|
||||
else
|
||||
ref="${{ github.event.inputs.tag }}"
|
||||
fi
|
||||
echo "ref=$ref"
|
||||
echo "ref=$ref" >> $GITHUB_OUTPUT
|
||||
if [[ $ref == *"-"* ]]; then
|
||||
latest=latest-beta
|
||||
else
|
||||
latest=latest
|
||||
fi
|
||||
echo "latest=$latest"
|
||||
echo "latest=$latest" >> $GITHUB_OUTPUT
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
with:
|
||||
ref: ${{ steps.ref.outputs.ref }}
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Setup QEMU for Docker Buildx
|
||||
@@ -30,10 +52,11 @@ jobs:
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
platforms: linux/386,linux/amd64,linux/arm64,linux/s390x
|
||||
context: .
|
||||
target: dist
|
||||
build-args: |
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
||||
tags: |
|
||||
ghcr.io/sagernet/sing-box:latest
|
||||
ghcr.io/sagernet/sing-box:${{ github.ref_name }}
|
||||
ghcr.io/sagernet/sing-box:${{ steps.ref.outputs.latest }}
|
||||
ghcr.io/sagernet/sing-box:${{ steps.ref.outputs.ref }}
|
||||
push: true
|
||||
|
||||
4
.github/workflows/lint.yml
vendored
4
.github/workflows/lint.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
with:
|
||||
go-version: ^1.22
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v4
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout=30m
|
||||
|
||||
6
.github/workflows/linux.yml
vendored
6
.github/workflows/linux.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
@@ -22,7 +22,9 @@ jobs:
|
||||
mkdir -p $HOME/.gnupg
|
||||
cat > $HOME/.gnupg/sagernet.key <<EOF
|
||||
${{ secrets.GPG_KEY }}
|
||||
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
||||
EOF
|
||||
echo "HOME=$HOME" >> "$GITHUB_ENV"
|
||||
- name: Publish release
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
with:
|
||||
@@ -33,5 +35,5 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
|
||||
FURY_TOKEN: ${{ secrets.FURY_TOKEN }}
|
||||
NFPM_KEY_PATH: $HOME/.gnupg/sagernet.key
|
||||
NFPM_KEY_PATH: ${{ env.HOME }}/.gnupg/sagernet.key
|
||||
NFPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
|
||||
@@ -80,8 +80,8 @@ furies:
|
||||
- account: sagernet
|
||||
ids:
|
||||
- package
|
||||
skip: "{{ not (not .Prerelease) }}"
|
||||
disable: "{{ not (not .Prerelease) }}"
|
||||
- account: sagernet
|
||||
ids:
|
||||
- package_beta
|
||||
skip: "{{ not .Prerelease }}"
|
||||
disable: "{{ not .Prerelease }}"
|
||||
|
||||
@@ -99,3 +99,12 @@ func ExtendContext(ctx context.Context) (context.Context, *InboundContext) {
|
||||
}
|
||||
return WithContext(ctx, &newMetadata), &newMetadata
|
||||
}
|
||||
|
||||
func OverrideContext(ctx context.Context) context.Context {
|
||||
if metadata := ContextFrom(ctx); metadata != nil {
|
||||
var newMetadata InboundContext
|
||||
newMetadata = *metadata
|
||||
return WithContext(ctx, &newMetadata)
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ type DNSRule interface {
|
||||
Rule
|
||||
DisableCache() bool
|
||||
RewriteTTL() *uint32
|
||||
ClientSubnet() *netip.Addr
|
||||
ClientSubnet() *netip.Prefix
|
||||
WithAddressLimit() bool
|
||||
MatchAddressLimit(metadata *InboundContext) bool
|
||||
}
|
||||
|
||||
Submodule clients/android updated: 983a771212...9d463b269a
Submodule clients/apple updated: debd0ca1a2...17eec08615
@@ -32,14 +32,20 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||
var dialer net.Dialer
|
||||
var listener net.ListenConfig
|
||||
if options.BindInterface != "" {
|
||||
bindFunc := control.BindToInterface(router.InterfaceFinder(), options.BindInterface, -1)
|
||||
var interfaceFinder control.InterfaceFinder
|
||||
if router != nil {
|
||||
interfaceFinder = router.InterfaceFinder()
|
||||
} else {
|
||||
interfaceFinder = control.NewDefaultInterfaceFinder()
|
||||
}
|
||||
bindFunc := control.BindToInterface(interfaceFinder, options.BindInterface, -1)
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
} else if router.AutoDetectInterface() {
|
||||
} else if router != nil && router.AutoDetectInterface() {
|
||||
bindFunc := router.AutoDetectInterfaceFunc()
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
} else if router.DefaultInterface() != "" {
|
||||
} else if router != nil && router.DefaultInterface() != "" {
|
||||
bindFunc := control.BindToInterface(router.InterfaceFinder(), router.DefaultInterface(), -1)
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
@@ -47,7 +53,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDi
|
||||
if options.RoutingMark != 0 {
|
||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
|
||||
listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
|
||||
} else if router.DefaultMark() != 0 {
|
||||
} else if router != nil && router.DefaultMark() != 0 {
|
||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(router.DefaultMark()))
|
||||
listener.Control = control.Append(listener.Control, control.RoutingMark(router.DefaultMark()))
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error)
|
||||
if options.IsWireGuardListener {
|
||||
return NewDefault(router, options)
|
||||
}
|
||||
if router == nil {
|
||||
return NewDefault(nil, options)
|
||||
}
|
||||
var (
|
||||
dialer N.Dialer
|
||||
err error
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package mux
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-mux"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
@@ -30,7 +35,7 @@ func NewClientWithOptions(dialer N.Dialer, logger logger.Logger, options option.
|
||||
}
|
||||
}
|
||||
return mux.NewClient(mux.Options{
|
||||
Dialer: dialer,
|
||||
Dialer: &clientDialer{dialer},
|
||||
Logger: logger,
|
||||
Protocol: options.Protocol,
|
||||
MaxConnections: options.MaxConnections,
|
||||
@@ -40,3 +45,15 @@ func NewClientWithOptions(dialer N.Dialer, logger logger.Logger, options option.
|
||||
Brutal: brutalOptions,
|
||||
})
|
||||
}
|
||||
|
||||
type clientDialer struct {
|
||||
N.Dialer
|
||||
}
|
||||
|
||||
func (d *clientDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
return d.Dialer.DialContext(adapter.OverrideContext(ctx), network, destination)
|
||||
}
|
||||
|
||||
func (d *clientDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
return d.Dialer.ListenPacket(adapter.OverrideContext(ctx), destination)
|
||||
}
|
||||
|
||||
@@ -27,11 +27,10 @@ func (c *echClientConfig) DialEarly(ctx context.Context, conn net.PacketConn, ad
|
||||
return quic.DialEarly(ctx, conn, addr, c.config, config)
|
||||
}
|
||||
|
||||
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config, enableDatagrams bool) http.RoundTripper {
|
||||
func (c *echClientConfig) CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config) http.RoundTripper {
|
||||
return &http3.RoundTripper{
|
||||
TLSClientConfig: c.config,
|
||||
QuicConfig: quicConfig,
|
||||
EnableDatagrams: enableDatagrams,
|
||||
QUICConfig: quicConfig,
|
||||
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
||||
quicConn, err := quic.DialEarly(ctx, conn, serverAddr.UDPAddr(), tlsCfg, cfg)
|
||||
if err != nil {
|
||||
|
||||
@@ -2,7 +2,68 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.9.0-rc.9
|
||||
#### 1.9.0-rc.21
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.20
|
||||
|
||||
* Prioritize `*_route_address` in linux auto-route
|
||||
* Fix `*_route_address` in darwin auto-route
|
||||
|
||||
#### 1.8.14
|
||||
|
||||
* Fix hysteria2 panic
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.18
|
||||
|
||||
* Add custom prefix support in EDNS0 client subnet options
|
||||
* Fix hysteria2 crash
|
||||
* Fix `store_rdrc` corrupted
|
||||
* Update quic-go to v0.43.1
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.16
|
||||
|
||||
* Mitigating TunnelVision attacks **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
See [TunnelVision](/manual/misc/tunnelvision).
|
||||
|
||||
#### 1.9.0-rc.15
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.13
|
||||
|
||||
* Fix fake-ip mapping
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.14
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.9.0-rc.13
|
||||
|
||||
* Update Hysteria protocol
|
||||
* Update quic-go to v0.43.0
|
||||
* Update gVisor to 20240422.0
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.12
|
||||
|
||||
* Now we have official APT and DNF repositories **1**
|
||||
* Fix packet MTU for QUIC protocols
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
Including stable and beta versions, see https://sing-box.sagernet.org/installation/package-manager/
|
||||
|
||||
#### 1.9.0-rc.11
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
|
||||
@@ -15,11 +15,12 @@ platform-specific function implementation, such as TUN transparent proxy impleme
|
||||
## :material-download: Download
|
||||
|
||||
* [App Store](https://apps.apple.com/us/app/sing-box/id6451272673)
|
||||
* ~~[TestFlight (Beta)](https://testflight.apple.com/join/AcqO44FH)~~
|
||||
* ~~TestFlight (Beta)~~
|
||||
|
||||
_Our Testflight distribution has been temporarily blocked by Apple (possibly due to too many beta versions)
|
||||
and you cannot join the test, install or update the sing-box beta app right now.
|
||||
Please wait patiently for processing._
|
||||
TestFlight quota is only available to [sponsors](https://github.com/sponsors/nekohasekai)
|
||||
(one-time sponsorships are accepted).
|
||||
Once you donate, you can get an invitation by sending us your Apple ID [via email](mailto:contact@sagernet.org),
|
||||
or join our Telegram group for sponsors from [@yet_another_sponsor_bot](https://t.me/yet_another_sponsor_bot).
|
||||
|
||||
## :material-file-download: Download (macOS standalone version)
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ problematic in environments such as macOS, where DNS is proxied and cached by th
|
||||
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Append a `edns0-subnet` OPT extra record with the specified IP address to every query by default.
|
||||
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
|
||||
|
||||
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
|
||||
|
||||
Can be overrides by `servers.[].client_subnet` or `rules.[].client_subnet`.
|
||||
|
||||
@@ -71,8 +71,10 @@ icon: material/new-box
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
默认情况下,将带有指定 IP 地址的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||
|
||||
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||
|
||||
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
||||
|
||||
可以被 `servers.[].client_subnet` 或 `rules.[].client_subnet` 覆盖。
|
||||
|
||||
#### fakeip
|
||||
|
||||
@@ -125,7 +125,7 @@ icon: material/new-box
|
||||
"server": "local",
|
||||
"disable_cache": false,
|
||||
"rewrite_ttl": 100,
|
||||
"client_subnet": "127.0.0.1"
|
||||
"client_subnet": "127.0.0.1/24"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
@@ -134,7 +134,7 @@ icon: material/new-box
|
||||
"server": "local",
|
||||
"disable_cache": false,
|
||||
"rewrite_ttl": 100,
|
||||
"client_subnet": "127.0.0.1"
|
||||
"client_subnet": "127.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -339,7 +339,9 @@ Rewrite TTL in DNS responses.
|
||||
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Append a `edns0-subnet` OPT extra record with the specified IP address to every query by default.
|
||||
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
|
||||
|
||||
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
|
||||
|
||||
Will overrides `dns.client_subnet` and `servers.[].client_subnet`.
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ icon: material/new-box
|
||||
],
|
||||
"server": "local",
|
||||
"disable_cache": false,
|
||||
"client_subnet": "127.0.0.1"
|
||||
"client_subnet": "127.0.0.1/24"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
@@ -132,7 +132,7 @@ icon: material/new-box
|
||||
"rules": [],
|
||||
"server": "local",
|
||||
"disable_cache": false,
|
||||
"client_subnet": "127.0.0.1"
|
||||
"client_subnet": "127.0.0.1/24"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -337,7 +337,9 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
默认情况下,将带有指定 IP 地址的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||
|
||||
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
||||
|
||||
将覆盖 `dns.client_subnet` 与 `servers.[].client_subnet`。
|
||||
|
||||
|
||||
@@ -100,7 +100,9 @@ Default outbound will be used if empty.
|
||||
|
||||
!!! question "Since sing-box 1.9.0"
|
||||
|
||||
Append a `edns0-subnet` OPT extra record with the specified IP address to every query by default.
|
||||
Append a `edns0-subnet` OPT extra record with the specified IP prefix to every query by default.
|
||||
|
||||
If value is an IP address instead of prefix, `/32` or `/128` will be appended automatically.
|
||||
|
||||
Can be overrides by `rules.[].client_subnet`.
|
||||
|
||||
|
||||
@@ -100,7 +100,9 @@ DNS 服务器的地址。
|
||||
|
||||
!!! question "自 sing-box 1.9.0 起"
|
||||
|
||||
默认情况下,将带有指定 IP 地址的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
||||
|
||||
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
||||
|
||||
可以被 `rules.[].client_subnet` 覆盖。
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ Enforce strict routing rules when `auto_route` is enabled:
|
||||
* Let unsupported network unreachable
|
||||
* Route all connections to tun
|
||||
|
||||
It prevents address leaks and makes DNS hijacking work on Android, but your device will not be accessible by others.
|
||||
It prevents address leaks and makes DNS hijacking work on Android.
|
||||
|
||||
*In Windows*:
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ tun 接口的 IPv6 前缀。
|
||||
* 让不支持的网络无法到达
|
||||
* 将所有连接路由到 tun
|
||||
|
||||
它可以防止地址泄漏,并使 DNS 劫持在 Android 上工作,但你的设备将无法其他设备被访问。
|
||||
它可以防止地址泄漏,并使 DNS 劫持在 Android 上工作。
|
||||
|
||||
*在 Windows 中*:
|
||||
|
||||
|
||||
@@ -57,16 +57,16 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
|
||||
| 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_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_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_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.
|
||||
|
||||
@@ -54,19 +54,19 @@ go build -tags "tag_a tag_b" ./cmd/sing-box
|
||||
|
||||
## :material-folder-settings: 构建标记
|
||||
|
||||
| 构建标记 | 默认启动 | 说明 |
|
||||
|------------------------------------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| 构建标记 | 默认启动 | 说明 |
|
||||
|------------------------------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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/). |
|
||||
|
||||
除非您确实知道您正在启用什么,否则不建议更改默认构建标签列表。
|
||||
|
||||
@@ -57,38 +57,38 @@ icon: material/package
|
||||
|
||||
=== ":material-linux: Linux"
|
||||
|
||||
| Type | Platform | Link | Command | Actively maintained |
|
||||
|----------|---------------|-------------------------|------------------------------|---------------------|
|
||||
| APK | Alpine | [sing-box][alpine] | `apk add sing-box` | :material-check: |
|
||||
| AUR | Arch Linux | [sing-box][aur] ᴬᵁᴿ | `? -S sing-box` | :material-check: |
|
||||
| nixpkgs | NixOS | [sing-box][nixpkgs] | `nix-env -iA nixos.sing-box` | :material-check: |
|
||||
| Homebrew | macOS / Linux | [sing-box][brew] | `brew install sing-box` | :material-check: |
|
||||
| Type | Platform | Command | Link |
|
||||
|----------|---------------|------------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| AUR | Arch Linux | `? -S sing-box` | [][aur] |
|
||||
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [][nixpkgs] |
|
||||
| Homebrew | macOS / Linux | `brew install sing-box` | [][brew] |
|
||||
| APK | Alpine | `apk add sing-box` | [][alpine] |
|
||||
|
||||
=== ":material-apple: macOS"
|
||||
|
||||
| Type | Platform | Link | Command | Actively maintained |
|
||||
|----------|----------|------------------|-------------------------|---------------------|
|
||||
| Homebrew | macOS | [sing-box][brew] | `brew install sing-box` | :material-check: |
|
||||
| Type | Platform | Command | Link |
|
||||
|----------|----------|-------------------------|------------------------------------------------------------------------------------------------|
|
||||
| Homebrew | macOS | `brew install sing-box` | [][brew] |
|
||||
|
||||
=== ":material-microsoft-windows: Windows"
|
||||
|
||||
| Type | Platform | Link | Command | Actively maintained |
|
||||
|------------|--------------------|---------------------|------------------------------|---------------------|
|
||||
| Scoop | Windows | [sing-box][scoop] | `scoop install sing-box` | :material-check: |
|
||||
| Chocolatey | Windows | [sing-box][choco] | `choco install sing-box` | :material-check: |
|
||||
| winget | Windows | [sing-box][winget] | `winget install sing-box` | :material-alert: |
|
||||
| Type | Platform | Command | Link |
|
||||
|------------|----------|---------------------------|-----------------------------------------------------------------------------------------------------|
|
||||
| Scoop | Windows | `scoop install sing-box` | [][scoop] |
|
||||
| Chocolatey | Windows | `choco install sing-box` | [][choco] |
|
||||
| winget | Windows | `winget install sing-box` | [][winget] |
|
||||
|
||||
=== ":material-android: Android"
|
||||
|
||||
| Type | Platform | Link | Command | Actively maintained |
|
||||
|------------|--------------------|---------------------|------------------------------|---------------------|
|
||||
| Termux | Android | [sing-box][termux] | `pkg add sing-box` | :material-check: |
|
||||
| Type | Platform | Command | Link |
|
||||
|--------|----------|--------------------|----------------------------------------------------------------------------------------------|
|
||||
| Termux | Android | `pkg add sing-box` | [][termux] |
|
||||
|
||||
=== ":material-freebsd: FreeBSD"
|
||||
|
||||
| Type | Platform | Link | Command | Actively maintained |
|
||||
|------------|----------|-------------------|------------------------|---------------------|
|
||||
| FreshPorts | FreeBSD | [sing-box][ports] | `pkg install sing-box` | :material-alert: |
|
||||
| Type | Platform | Command | Link |
|
||||
|------------|----------|------------------------|--------------------------------------------------------------------------------------------|
|
||||
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
||||
|
||||
## :material-book-multiple: Service Management
|
||||
|
||||
|
||||
@@ -57,38 +57,38 @@ icon: material/package
|
||||
|
||||
=== ":material-linux: Linux"
|
||||
|
||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
||||
|----------|------------|---------------------|------------------------------|------------------|
|
||||
| Alpine | Alpine | [sing-box][alpine] | `apk add sing-box` | :material-check: |
|
||||
| AUR | Arch Linux | [sing-box][aur] ᴬᵁᴿ | `? -S sing-box` | :material-check: |
|
||||
| nixpkgs | NixOS | [sing-box][nixpkgs] | `nix-env -iA nixos.sing-box` | :material-check: |
|
||||
| Homebrew | Linux | [sing-box][brew] | `brew install sing-box` | :material-check: |
|
||||
| 类型 | 平台 | 链接 | 命令 |
|
||||
|----------|---------------|------------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| AUR | Arch Linux | `? -S sing-box` | [][aur] |
|
||||
| nixpkgs | NixOS | `nix-env -iA nixos.sing-box` | [][nixpkgs] |
|
||||
| Homebrew | macOS / Linux | `brew install sing-box` | [][brew] |
|
||||
| APK | Alpine | `apk add sing-box` | [][alpine] |
|
||||
|
||||
=== ":material-apple: macOS"
|
||||
|
||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
||||
|----------|-------|------------------|-------------------------|------------------|
|
||||
| Homebrew | macOS | [sing-box][brew] | `brew install sing-box` | :material-check: |
|
||||
| 类型 | 平台 | 链接 | 命令 |
|
||||
|----------|-------|-------------------------|------------------------------------------------------------------------------------------------|
|
||||
| Homebrew | macOS | `brew install sing-box` | [][brew] |
|
||||
|
||||
=== ":material-microsoft-windows: Windows"
|
||||
|
||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
||||
|------------|---------|--------------------|---------------------------|------------------|
|
||||
| Scoop | Windows | [sing-box][scoop] | `scoop install sing-box` | :material-check: |
|
||||
| Chocolatey | Windows | [sing-box][choco] | `choco install sing-box` | :material-check: |
|
||||
| winget | Windows | [sing-box][winget] | `winget install sing-box` | :material-alert: |
|
||||
| 类型 | 平台 | 链接 | 命令 |
|
||||
|------------|---------|---------------------------|-----------------------------------------------------------------------------------------------------|
|
||||
| Scoop | Windows | `scoop install sing-box` | [][scoop] |
|
||||
| Chocolatey | Windows | `choco install sing-box` | [][choco] |
|
||||
| winget | Windows | `winget install sing-box` | [][winget] |
|
||||
|
||||
=== ":material-android: Android"
|
||||
|
||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
||||
|--------|---------|--------------------|--------------------|------------------|
|
||||
| Termux | Android | [sing-box][termux] | `pkg add sing-box` | :material-check: |
|
||||
| 类型 | 平台 | 链接 | 命令 |
|
||||
|--------|---------|--------------------|----------------------------------------------------------------------------------------------|
|
||||
| Termux | Android | `pkg add sing-box` | [][termux] |
|
||||
|
||||
=== ":material-freebsd: FreeBSD"
|
||||
|
||||
| 类型 | 平台 | 链接 | 命令 | 活跃维护 |
|
||||
|------------|---------|-------------------|------------------------|------------------|
|
||||
| FreshPorts | FreeBSD | [sing-box][ports] | `pkg install sing-box` | :material-alert: |
|
||||
| 类型 | 平台 | 链接 | 命令 |
|
||||
|------------|---------|------------------------|--------------------------------------------------------------------------------------------|
|
||||
| FreshPorts | FreeBSD | `pkg install sing-box` | [][ports] |
|
||||
|
||||
## :material-book-multiple: 服务管理
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[sing-box]
|
||||
name=sing-box
|
||||
baseurl=https://rpm.sagernet.org/
|
||||
metalink=https://sing-box.app/sing-box.repo
|
||||
enabled=1
|
||||
repo_gpgcheck=1
|
||||
gpgcheck=1
|
||||
|
||||
38
docs/manual/misc/tunnelvision.md
Normal file
38
docs/manual/misc/tunnelvision.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
icon: material/book-lock-open
|
||||
---
|
||||
|
||||
# TunnelVision
|
||||
|
||||
TunnelVision is an attack that uses DHCP option 121 to set higher priority routes
|
||||
so that traffic does not go through the VPN.
|
||||
|
||||
Reference: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-3661
|
||||
|
||||
## Status
|
||||
|
||||
### Android
|
||||
|
||||
Android does not handle DHCP option 121 and is not affected.
|
||||
|
||||
### Apple platforms
|
||||
|
||||
Update [sing-box graphical client](/clients/apple/#download) to `1.9.0-rc.16` or newer,
|
||||
then enable `includeAllNetworks` in `Settings` — `Packet Tunnel` and you will be unaffected.
|
||||
|
||||
Note: when `includeAllNetworks` is enabled, the default TUN stack is changed to `gvisor`,
|
||||
and the `system` and `mixed` stacks are not available.
|
||||
|
||||
### Linux
|
||||
|
||||
Update sing-box to `1.9.0-rc.16` or newer, rules generated by `auto-route` are unaffected.
|
||||
|
||||
### Windows
|
||||
|
||||
No solution yet.
|
||||
|
||||
## Workarounds
|
||||
|
||||
* Don't connect to untrusted networks
|
||||
* Relay untrusted network through another device
|
||||
* Just ignore it
|
||||
@@ -1,208 +0,0 @@
|
||||
---
|
||||
icon: material/alpha-t-box
|
||||
---
|
||||
|
||||
# TUIC
|
||||
|
||||
A recently popular Chinese-made simple protocol based on QUIC, the selling point is the BBR congestion control algorithm.
|
||||
|
||||
!!! warning
|
||||
|
||||
Even though GFW rarely blocks UDP-based proxies, such protocols actually have far more characteristics than TCP based proxies.
|
||||
|
||||
| Specification | Binary Characteristics | Active Detect Hiddenness |
|
||||
|-----------------------------------------------------------|------------------------|--------------------------|
|
||||
| [GitHub](https://github.com/EAimTY/tuic/blob/dev/SPEC.md) | :material-alert: | :material-check: |
|
||||
|
||||
## Password Generator
|
||||
|
||||
| Generated UUID | Generated Password | Action |
|
||||
|------------------------|----------------------------|-----------------------------------------------------------------|
|
||||
| <code id="uuid"><code> | <code id="password"><code> | <button class="md-button" onclick="generate()">Refresh</button> |
|
||||
|
||||
<script>
|
||||
function generateUUID() {
|
||||
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
let r = Math.random() * 16 | 0,
|
||||
v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
document.getElementById("uuid").textContent = uuid;
|
||||
}
|
||||
function generatePassword() {
|
||||
const array = new Uint8Array(16);
|
||||
window.crypto.getRandomValues(array);
|
||||
document.getElementById("password").textContent = btoa(String.fromCharCode.apply(null, array));
|
||||
}
|
||||
function generate() {
|
||||
generateUUID();
|
||||
generatePassword();
|
||||
}
|
||||
generate();
|
||||
</script>
|
||||
|
||||
## :material-server: Server Example
|
||||
|
||||
=== ":material-harddisk: With local certificate"
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"listen": "::",
|
||||
"listen_port": 8080,
|
||||
"users": [
|
||||
{
|
||||
"name": "sekai",
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>"
|
||||
}
|
||||
],
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"key_path": "/path/to/key.pem",
|
||||
"certificate_path": "/path/to/certificate.pem"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-auto-fix: With ACME"
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"listen": "::",
|
||||
"listen_port": 8080,
|
||||
"users": [
|
||||
{
|
||||
"name": "sekai",
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>"
|
||||
}
|
||||
],
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"acme": {
|
||||
"domain": "example.org",
|
||||
"email": "admin@example.org"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-cloud: With ACME and Cloudflare API"
|
||||
|
||||
```json
|
||||
{
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"listen": "::",
|
||||
"listen_port": 8080,
|
||||
"users": [
|
||||
{
|
||||
"name": "sekai",
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>"
|
||||
}
|
||||
],
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"acme": {
|
||||
"domain": "example.org",
|
||||
"email": "admin@example.org",
|
||||
"dns01_challenge": {
|
||||
"provider": "cloudflare",
|
||||
"api_token": "my_token"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## :material-cellphone-link: Client Example
|
||||
|
||||
=== ":material-web-check: With valid certificate"
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 8080,
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>",
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-check: With self-sign certificate"
|
||||
|
||||
!!! info "Tip"
|
||||
|
||||
Use `sing-box merge` command to merge configuration and certificate into one file.
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 8080,
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>",
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"certificate_path": "/path/to/certificate.pem"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
=== ":material-alert: Ignore certificate verification"
|
||||
|
||||
```json
|
||||
{
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "tuic",
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 8080,
|
||||
"uuid": "<uuid>",
|
||||
"password": "<password>",
|
||||
"congestion_control": "bbr",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "example.org",
|
||||
"insecure": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -471,7 +471,7 @@ flowchart TB
|
||||
}
|
||||
],
|
||||
"server": "google",
|
||||
"client_subnet": "114.114.114.114" // Any China client IP address
|
||||
"client_subnet": "114.114.114.114/24" // Any China client IP address
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -57,6 +57,7 @@ type CacheFile struct {
|
||||
type saveRDRCCacheKey struct {
|
||||
TransportName string
|
||||
QuestionName string
|
||||
QType uint16
|
||||
}
|
||||
|
||||
func New(ctx context.Context, options option.CacheFileOptions) *CacheFile {
|
||||
|
||||
@@ -74,6 +74,7 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldDomain := bucket.Get(address.AsSlice())
|
||||
err = bucket.Put(address.AsSlice(), []byte(domain))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -86,12 +87,24 @@ func (c *CacheFile) FakeIPStore(address netip.Addr, domain string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if oldDomain != nil {
|
||||
if err := bucket.Delete(oldDomain); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return bucket.Put([]byte(domain), address.AsSlice())
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CacheFile) FakeIPStoreAsync(address netip.Addr, domain string, logger logger.Logger) {
|
||||
c.saveFakeIPAccess.Lock()
|
||||
if oldDomain, loaded := c.saveDomain[address]; loaded {
|
||||
if address.Is4() {
|
||||
delete(c.saveAddress4, oldDomain)
|
||||
} else {
|
||||
delete(c.saveAddress6, oldDomain)
|
||||
}
|
||||
}
|
||||
c.saveDomain[address] = domain
|
||||
if address.Is4() {
|
||||
c.saveAddress4[domain] = address
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
)
|
||||
|
||||
var bucketRDRC = []byte("rdrc")
|
||||
var bucketRDRC = []byte("rdrc2")
|
||||
|
||||
func (c *CacheFile) StoreRDRC() bool {
|
||||
return c.storeRDRC
|
||||
@@ -19,13 +19,17 @@ func (c *CacheFile) RDRCTimeout() time.Duration {
|
||||
return c.rdrcTimeout
|
||||
}
|
||||
|
||||
func (c *CacheFile) LoadRDRC(transportName string, qName string) (rejected bool) {
|
||||
func (c *CacheFile) LoadRDRC(transportName string, qName string, qType uint16) (rejected bool) {
|
||||
c.saveRDRCAccess.RLock()
|
||||
rejected, cached := c.saveRDRC[saveRDRCCacheKey{transportName, qName}]
|
||||
rejected, cached := c.saveRDRC[saveRDRCCacheKey{transportName, qName, qType}]
|
||||
c.saveRDRCAccess.RUnlock()
|
||||
if cached {
|
||||
return
|
||||
}
|
||||
key := buf.Get(2 + len(qName))
|
||||
binary.BigEndian.PutUint16(key, qType)
|
||||
copy(key[2:], qName)
|
||||
defer buf.Put(key)
|
||||
var deleteCache bool
|
||||
err := c.DB.View(func(tx *bbolt.Tx) error {
|
||||
bucket := c.bucket(tx, bucketRDRC)
|
||||
@@ -36,7 +40,7 @@ func (c *CacheFile) LoadRDRC(transportName string, qName string) (rejected bool)
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
content := bucket.Get([]byte(qName))
|
||||
content := bucket.Get(key)
|
||||
if content == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -61,13 +65,13 @@ func (c *CacheFile) LoadRDRC(transportName string, qName string) (rejected bool)
|
||||
if bucket == nil {
|
||||
return nil
|
||||
}
|
||||
return bucket.Delete([]byte(qName))
|
||||
return bucket.Delete(key)
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *CacheFile) SaveRDRC(transportName string, qName string) error {
|
||||
func (c *CacheFile) SaveRDRC(transportName string, qName string, qType uint16) error {
|
||||
return c.DB.Batch(func(tx *bbolt.Tx) error {
|
||||
bucket, err := c.createBucket(tx, bucketRDRC)
|
||||
if err != nil {
|
||||
@@ -77,20 +81,24 @@ func (c *CacheFile) SaveRDRC(transportName string, qName string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := buf.Get(2 + len(qName))
|
||||
binary.BigEndian.PutUint16(key, qType)
|
||||
copy(key[2:], qName)
|
||||
defer buf.Put(key)
|
||||
expiresAt := buf.Get(8)
|
||||
defer buf.Put(expiresAt)
|
||||
binary.BigEndian.PutUint64(expiresAt, uint64(time.Now().Add(c.rdrcTimeout).Unix()))
|
||||
return bucket.Put([]byte(qName), expiresAt)
|
||||
return bucket.Put(key, expiresAt)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CacheFile) SaveRDRCAsync(transportName string, qName string, logger logger.Logger) {
|
||||
saveKey := saveRDRCCacheKey{transportName, qName}
|
||||
func (c *CacheFile) SaveRDRCAsync(transportName string, qName string, qType uint16, logger logger.Logger) {
|
||||
saveKey := saveRDRCCacheKey{transportName, qName, qType}
|
||||
c.saveRDRCAccess.Lock()
|
||||
c.saveRDRC[saveKey] = true
|
||||
c.saveRDRCAccess.Unlock()
|
||||
go func() {
|
||||
err := c.SaveRDRC(transportName, qName)
|
||||
err := c.SaveRDRC(transportName, qName, qType)
|
||||
if err != nil {
|
||||
logger.Warn("save RDRC: ", err)
|
||||
}
|
||||
|
||||
@@ -82,6 +82,10 @@ func (s *platformInterfaceStub) UnderNetworkExtension() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) IncludeAllNetworks() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *platformInterfaceStub) ClearDNSCache() {
|
||||
}
|
||||
|
||||
@@ -136,7 +140,6 @@ func FormatConfig(configContent string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
var buffer bytes.Buffer
|
||||
json.NewEncoder(&buffer)
|
||||
encoder := json.NewEncoder(&buffer)
|
||||
encoder.SetIndent("", " ")
|
||||
err = encoder.Encode(options)
|
||||
|
||||
@@ -19,6 +19,7 @@ type PlatformInterface interface {
|
||||
UsePlatformInterfaceGetter() bool
|
||||
GetInterfaces() (NetworkInterfaceIterator, error)
|
||||
UnderNetworkExtension() bool
|
||||
IncludeAllNetworks() bool
|
||||
ReadWIFIState() *WIFIState
|
||||
ClearDNSCache()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ type Interface interface {
|
||||
UsePlatformInterfaceGetter() bool
|
||||
Interfaces() ([]control.Interface, error)
|
||||
UnderNetworkExtension() bool
|
||||
IncludeAllNetworks() bool
|
||||
ClearDNSCache()
|
||||
ReadWIFIState() adapter.WIFIState
|
||||
process.Searcher
|
||||
|
||||
@@ -213,6 +213,10 @@ func (w *platformInterfaceWrapper) UnderNetworkExtension() bool {
|
||||
return w.iif.UnderNetworkExtension()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) IncludeAllNetworks() bool {
|
||||
return w.iif.IncludeAllNetworks()
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) ClearDNSCache() {
|
||||
w.iif.ClearDNSCache()
|
||||
}
|
||||
|
||||
31
go.mod
31
go.mod
@@ -11,29 +11,29 @@ require (
|
||||
github.com/go-chi/chi/v5 v5.0.12
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-chi/render v1.0.3
|
||||
github.com/gofrs/uuid/v5 v5.1.0
|
||||
github.com/gofrs/uuid/v5 v5.2.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2
|
||||
github.com/libdns/alidns v1.0.3
|
||||
github.com/libdns/cloudflare v0.1.1
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/mholt/acmez v1.2.0
|
||||
github.com/miekg/dns v1.1.58
|
||||
github.com/miekg/dns v1.1.59
|
||||
github.com/ooni/go-libtor v1.1.8
|
||||
github.com/oschwald/maxminddb-golang v1.12.0
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1
|
||||
github.com/sagernet/gomobile v0.1.3
|
||||
github.com/sagernet/gvisor v0.0.0-20240315080113-799fb6b6d311
|
||||
github.com/sagernet/quic-go v0.42.0-beta.2
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f
|
||||
github.com/sagernet/quic-go v0.43.1-beta.1
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||
github.com/sagernet/sing v0.4.0-beta.15
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.16
|
||||
github.com/sagernet/sing v0.4.0-beta.20
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.18
|
||||
github.com/sagernet/sing-mux v0.2.0
|
||||
github.com/sagernet/sing-quic v0.1.12-beta.1
|
||||
github.com/sagernet/sing-quic v0.2.0-beta.5
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||
github.com/sagernet/sing-shadowtls v0.1.4
|
||||
github.com/sagernet/sing-tun v0.2.7-beta.1
|
||||
github.com/sagernet/sing-tun v0.3.0-beta.5
|
||||
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,9 +44,9 @@ require (
|
||||
github.com/stretchr/testify v1.9.0
|
||||
go.uber.org/zap v1.27.0
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.22.0
|
||||
golang.org/x/net v0.24.0
|
||||
golang.org/x/sys v0.19.0
|
||||
golang.org/x/crypto v0.23.0
|
||||
golang.org/x/net v0.25.0
|
||||
golang.org/x/sys v0.20.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
google.golang.org/grpc v1.63.2
|
||||
google.golang.org/protobuf v1.33.0
|
||||
@@ -84,11 +84,12 @@ 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-20240325151524-a685a6edb6d8 // indirect
|
||||
golang.org/x/mod v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.19.0 // indirect
|
||||
golang.org/x/tools v0.21.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
65
go.sum
65
go.sum
@@ -34,8 +34,8 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gofrs/uuid/v5 v5.1.0 h1:S5rqVKIigghZTCBKPCw0Y+bXkn26K3TB5mvQq2Ix8dk=
|
||||
github.com/gofrs/uuid/v5 v5.1.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM=
|
||||
github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
|
||||
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
@@ -71,8 +71,8 @@ github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczG
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
|
||||
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
|
||||
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
|
||||
@@ -97,31 +97,31 @@ github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1 h1:YbmpqPQ
|
||||
github.com/sagernet/cloudflare-tls v0.0.0-20231208171750-a4483c1b7cd1/go.mod h1:J2yAxTFPDjrDPhuAi9aWFz2L3ox9it4qAluBBbN0H5k=
|
||||
github.com/sagernet/gomobile v0.1.3 h1:ohjIb1Ou2+1558PnZour3od69suSuvkdSVOlO1tC4B8=
|
||||
github.com/sagernet/gomobile v0.1.3/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
||||
github.com/sagernet/gvisor v0.0.0-20240315080113-799fb6b6d311 h1:eUQ6kJZXK77xYZeeNrBb/7JMv0S0Wkk7EpmKUb3fsfc=
|
||||
github.com/sagernet/gvisor v0.0.0-20240315080113-799fb6b6d311/go.mod h1:mDrXZSv401qiaFiiIUC59Zp4VG5f4nqXFqDmp5o3hYI=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y/6ZHJWrnNLoiNnSJaow6DPb8VW2I=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE=
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/quic-go v0.42.0-beta.2 h1:E6vTGhveFE9Tnhu5rrt3M5fnENuqBJOv8gPcFPz0cSM=
|
||||
github.com/sagernet/quic-go v0.42.0-beta.2/go.mod h1:lf8OYop+fMxIlrfM/ZHpENt/7ZD4JaVNqMhOlq2QMwg=
|
||||
github.com/sagernet/quic-go v0.43.1-beta.1 h1:alizUjpvWYcz08dBCQsULOd+1xu0o7UtlyYf6SLbRNg=
|
||||
github.com/sagernet/quic-go v0.43.1-beta.1/go.mod h1:BkrQYeop7Jx3hN3TW8/76CXcdhYiNPyYEBL/BVJ1ifc=
|
||||
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.4.0-beta.15 h1:KS6lC36Pzf562ukWXPka1uMSqgzmXP3vpTq50DXxdVM=
|
||||
github.com/sagernet/sing v0.4.0-beta.15/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI=
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.16 h1:bzd4B8eHD7/WO3HrYknvgE8A56/R3n5oXBjNF97iPzQ=
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.16/go.mod h1:XU6Vqr6aHcMz/34Fcv8jmXpRCEuShzW+B7Qg1Xe1nxY=
|
||||
github.com/sagernet/sing v0.4.0-beta.20 h1:8rEepj4LMcR0Wd389fJIziv/jr3MBtX5qXBHsfxJ+dY=
|
||||
github.com/sagernet/sing v0.4.0-beta.20/go.mod h1:PFQKbElc2Pke7faBLv8oEba5ehtKO21Ho+TkYemTI3Y=
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.18 h1:6vzXZThRdA7YUzBOpSbUT48XRumtl/KIpIHFSOP0za8=
|
||||
github.com/sagernet/sing-dns v0.2.0-beta.18/go.mod h1:k/dmFcQpg6+m08gC1yQBy+13+QkuLqpKr4bIreq4U24=
|
||||
github.com/sagernet/sing-mux v0.2.0 h1:4C+vd8HztJCWNYfufvgL49xaOoOHXty2+EAjnzN3IYo=
|
||||
github.com/sagernet/sing-mux v0.2.0/go.mod h1:khzr9AOPocLa+g53dBplwNDz4gdsyx/YM3swtAhlkHQ=
|
||||
github.com/sagernet/sing-quic v0.1.12-beta.1 h1:6vh9AIuJfCYYsUSLZEgoAtb7kD97TQmPYgInA881lF8=
|
||||
github.com/sagernet/sing-quic v0.1.12-beta.1/go.mod h1:TTnOMr3o3rI+zNxTo+SGBJwouzjIEC3FchJJY1F1ca4=
|
||||
github.com/sagernet/sing-quic v0.2.0-beta.5 h1:ceKFLd1iS5AtM+pScKmcDp5k7R6WgYIe8vl6nB0aVsE=
|
||||
github.com/sagernet/sing-quic v0.2.0-beta.5/go.mod h1:lfad61lScAZhAxZ0DHZWvEIcAaT38O6zPTR4vLsHeP0=
|
||||
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.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
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.7-beta.1 h1:rudjVa4Gjg9f3uYaUwH8qK5uMxl7MOIiYlmGhTqWgXI=
|
||||
github.com/sagernet/sing-tun v0.2.7-beta.1/go.mod h1:9pauo20NImopbZ3ixnJs6m5CbzhJitfvii6w4Rk3QMg=
|
||||
github.com/sagernet/sing-tun v0.3.0-beta.5 h1:z+4l1mGjPeepxT3mzHzE2pms995iUac/AyKQvRnWbWA=
|
||||
github.com/sagernet/sing-tun v0.3.0-beta.5/go.mod h1:xPaOkQhngPMILx+/9DMLCFl4vSxUU2tMnCPSlf05HLo=
|
||||
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=
|
||||
@@ -163,17 +163,18 @@ 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.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
|
||||
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
|
||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -183,19 +184,19 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
|
||||
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
|
||||
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
|
||||
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
|
||||
|
||||
@@ -166,6 +166,14 @@ func (t *Tun) Start() error {
|
||||
}
|
||||
t.logger.Trace("creating stack")
|
||||
t.tunIf = tunInterface
|
||||
var (
|
||||
forwarderBindInterface bool
|
||||
includeAllNetworks bool
|
||||
)
|
||||
if t.platformInterface != nil {
|
||||
forwarderBindInterface = true
|
||||
includeAllNetworks = t.platformInterface.IncludeAllNetworks()
|
||||
}
|
||||
t.tunStack, err = tun.NewStack(t.stack, tun.StackOptions{
|
||||
Context: t.ctx,
|
||||
Tun: tunInterface,
|
||||
@@ -174,8 +182,9 @@ func (t *Tun) Start() error {
|
||||
UDPTimeout: t.udpTimeout,
|
||||
Handler: t,
|
||||
Logger: t.logger,
|
||||
ForwarderBindInterface: t.platformInterface != nil,
|
||||
ForwarderBindInterface: forwarderBindInterface,
|
||||
InterfaceFinder: t.router.InterfaceFinder(),
|
||||
IncludeAllNetworks: includeAllNetworks,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -53,7 +53,9 @@ func NewDefaultFactory(
|
||||
if platformWriter != nil {
|
||||
factory.platformFormatter.DisableColors = platformWriter.DisableColors()
|
||||
}
|
||||
factory.observer = observable.NewObserver[Entry](factory.subscriber, 64)
|
||||
if needObservable {
|
||||
factory.observer = observable.NewObserver[Entry](factory.subscriber, 64)
|
||||
}
|
||||
return factory
|
||||
}
|
||||
|
||||
@@ -72,7 +74,7 @@ func (f *defaultFactory) Start() error {
|
||||
func (f *defaultFactory) Close() error {
|
||||
return common.Close(
|
||||
common.PtrOrNil(f.file),
|
||||
f.observer,
|
||||
f.subscriber,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +66,9 @@ nav:
|
||||
- Proxy Protocol:
|
||||
- Shadowsocks: manual/proxy-protocol/shadowsocks.md
|
||||
- Trojan: manual/proxy-protocol/trojan.md
|
||||
- TUIC: manual/proxy-protocol/tuic.md
|
||||
- Hysteria 2: manual/proxy-protocol/hysteria2.md
|
||||
- Misc:
|
||||
- TunnelVision: manual/misc/tunnelvision.md
|
||||
- Configuration:
|
||||
- configuration/index.md
|
||||
- Log:
|
||||
|
||||
@@ -19,7 +19,7 @@ type DNSServerOptions struct {
|
||||
AddressFallbackDelay Duration `json:"address_fallback_delay,omitempty"`
|
||||
Strategy DomainStrategy `json:"strategy,omitempty"`
|
||||
Detour string `json:"detour,omitempty"`
|
||||
ClientSubnet *ListenAddress `json:"client_subnet,omitempty"`
|
||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
||||
}
|
||||
|
||||
type DNSClientOptions struct {
|
||||
@@ -27,7 +27,7 @@ type DNSClientOptions struct {
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
DisableExpire bool `json:"disable_expire,omitempty"`
|
||||
IndependentCache bool `json:"independent_cache,omitempty"`
|
||||
ClientSubnet *ListenAddress `json:"client_subnet,omitempty"`
|
||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
||||
}
|
||||
|
||||
type DNSFakeIPOptions struct {
|
||||
|
||||
@@ -101,7 +101,7 @@ type DefaultDNSRule struct {
|
||||
Server string `json:"server,omitempty"`
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||
ClientSubnet *ListenAddress `json:"client_subnet,omitempty"`
|
||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
||||
}
|
||||
|
||||
func (r DefaultDNSRule) IsValid() bool {
|
||||
@@ -115,13 +115,13 @@ func (r DefaultDNSRule) IsValid() bool {
|
||||
}
|
||||
|
||||
type LogicalDNSRule struct {
|
||||
Mode string `json:"mode"`
|
||||
Rules []DNSRule `json:"rules,omitempty"`
|
||||
Invert bool `json:"invert,omitempty"`
|
||||
Server string `json:"server,omitempty"`
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||
ClientSubnet *ListenAddress `json:"client_subnet,omitempty"`
|
||||
Mode string `json:"mode"`
|
||||
Rules []DNSRule `json:"rules,omitempty"`
|
||||
Invert bool `json:"invert,omitempty"`
|
||||
Server string `json:"server,omitempty"`
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
||||
}
|
||||
|
||||
func (r LogicalDNSRule) IsValid() bool {
|
||||
|
||||
@@ -51,6 +51,40 @@ func (a *ListenAddress) Build() netip.Addr {
|
||||
return (netip.Addr)(*a)
|
||||
}
|
||||
|
||||
type AddrPrefix netip.Prefix
|
||||
|
||||
func (a AddrPrefix) MarshalJSON() ([]byte, error) {
|
||||
prefix := netip.Prefix(a)
|
||||
if prefix.Bits() == prefix.Addr().BitLen() {
|
||||
return json.Marshal(prefix.Addr().String())
|
||||
} else {
|
||||
return json.Marshal(prefix.String())
|
||||
}
|
||||
}
|
||||
|
||||
func (a *AddrPrefix) UnmarshalJSON(content []byte) error {
|
||||
var value string
|
||||
err := json.Unmarshal(content, &value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
prefix, prefixErr := netip.ParsePrefix(value)
|
||||
if prefixErr == nil {
|
||||
*a = AddrPrefix(prefix)
|
||||
return nil
|
||||
}
|
||||
addr, addrErr := netip.ParseAddr(value)
|
||||
if addrErr == nil {
|
||||
*a = AddrPrefix(netip.PrefixFrom(addr, addr.BitLen()))
|
||||
return nil
|
||||
}
|
||||
return prefixErr
|
||||
}
|
||||
|
||||
func (a AddrPrefix) Build() netip.Prefix {
|
||||
return netip.Prefix(a)
|
||||
}
|
||||
|
||||
type NetworkList string
|
||||
|
||||
func (v *NetworkList) UnmarshalJSON(content []byte) error {
|
||||
|
||||
@@ -148,7 +148,7 @@ func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn = h.loopBack.NewPacketConn(bufio.NewPacketConn(conn))
|
||||
conn = h.loopBack.NewPacketConn(bufio.NewPacketConn(conn), destination)
|
||||
if originDestination != destination {
|
||||
conn = bufio.NewNATPacketConn(bufio.NewPacketConn(conn), destination, originDestination)
|
||||
}
|
||||
@@ -156,14 +156,14 @@ 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()) {
|
||||
if h.loopBack.CheckConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
||||
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()) {
|
||||
if h.loopBack.CheckPacketConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
|
||||
return E.New("reject loopback packet connection to ", metadata.Destination)
|
||||
}
|
||||
return NewPacketConnection(ctx, h, conn, metadata)
|
||||
|
||||
@@ -14,78 +14,86 @@ type loopBackDetector struct {
|
||||
router adapter.Router
|
||||
connAccess sync.RWMutex
|
||||
packetConnAccess sync.RWMutex
|
||||
connMap map[netip.AddrPort]bool
|
||||
packetConnMap map[uint16]bool
|
||||
connMap map[netip.AddrPort]netip.AddrPort
|
||||
packetConnMap map[uint16]uint16
|
||||
}
|
||||
|
||||
func newLoopBackDetector(router adapter.Router) *loopBackDetector {
|
||||
return &loopBackDetector{
|
||||
router: router,
|
||||
connMap: make(map[netip.AddrPort]bool),
|
||||
packetConnMap: make(map[uint16]bool),
|
||||
connMap: make(map[netip.AddrPort]netip.AddrPort),
|
||||
packetConnMap: make(map[uint16]uint16),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *loopBackDetector) NewConn(conn net.Conn) net.Conn {
|
||||
connAddr := M.AddrPortFromNet(conn.LocalAddr())
|
||||
if !connAddr.IsValid() {
|
||||
source := M.AddrPortFromNet(conn.LocalAddr())
|
||||
if !source.IsValid() {
|
||||
return conn
|
||||
}
|
||||
if udpConn, isUDPConn := conn.(abstractUDPConn); isUDPConn {
|
||||
if !connAddr.Addr().IsLoopback() {
|
||||
_, err := l.router.InterfaceFinder().InterfaceByAddr(connAddr.Addr())
|
||||
if !source.Addr().IsLoopback() {
|
||||
_, err := l.router.InterfaceFinder().InterfaceByAddr(source.Addr())
|
||||
if err != nil {
|
||||
return conn
|
||||
}
|
||||
}
|
||||
if !N.IsPublicAddr(source.Addr()) {
|
||||
return conn
|
||||
}
|
||||
l.packetConnAccess.Lock()
|
||||
l.packetConnMap[connAddr.Port()] = true
|
||||
l.packetConnMap[source.Port()] = M.AddrPortFromNet(conn.RemoteAddr()).Port()
|
||||
l.packetConnAccess.Unlock()
|
||||
return &loopBackDetectUDPWrapper{abstractUDPConn: udpConn, detector: l, connPort: connAddr.Port()}
|
||||
return &loopBackDetectUDPWrapper{abstractUDPConn: udpConn, detector: l, connPort: source.Port()}
|
||||
} else {
|
||||
l.connAccess.Lock()
|
||||
l.connMap[connAddr] = true
|
||||
l.connMap[source] = M.AddrPortFromNet(conn.RemoteAddr())
|
||||
l.connAccess.Unlock()
|
||||
return &loopBackDetectWrapper{Conn: conn, detector: l, connAddr: connAddr}
|
||||
return &loopBackDetectWrapper{Conn: conn, detector: l, connAddr: source}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *loopBackDetector) NewPacketConn(conn N.NetPacketConn) N.NetPacketConn {
|
||||
connAddr := M.AddrPortFromNet(conn.LocalAddr())
|
||||
if !connAddr.IsValid() {
|
||||
func (l *loopBackDetector) NewPacketConn(conn N.NetPacketConn, destination M.Socksaddr) N.NetPacketConn {
|
||||
source := M.AddrPortFromNet(conn.LocalAddr())
|
||||
if !source.IsValid() {
|
||||
return conn
|
||||
}
|
||||
if !connAddr.Addr().IsLoopback() {
|
||||
_, err := l.router.InterfaceFinder().InterfaceByAddr(connAddr.Addr())
|
||||
if !source.Addr().IsLoopback() {
|
||||
_, err := l.router.InterfaceFinder().InterfaceByAddr(source.Addr())
|
||||
if err != nil {
|
||||
return conn
|
||||
}
|
||||
}
|
||||
l.packetConnAccess.Lock()
|
||||
l.packetConnMap[connAddr.Port()] = true
|
||||
l.packetConnMap[source.Port()] = destination.AddrPort().Port()
|
||||
l.packetConnAccess.Unlock()
|
||||
return &loopBackDetectPacketWrapper{NetPacketConn: conn, detector: l, connPort: connAddr.Port()}
|
||||
return &loopBackDetectPacketWrapper{NetPacketConn: conn, detector: l, connPort: source.Port()}
|
||||
}
|
||||
|
||||
func (l *loopBackDetector) CheckConn(connAddr netip.AddrPort) bool {
|
||||
func (l *loopBackDetector) CheckConn(source netip.AddrPort, local netip.AddrPort) bool {
|
||||
l.connAccess.RLock()
|
||||
defer l.connAccess.RUnlock()
|
||||
return l.connMap[connAddr]
|
||||
destination, loaded := l.connMap[source]
|
||||
return loaded && destination != local
|
||||
}
|
||||
|
||||
func (l *loopBackDetector) CheckPacketConn(connAddr netip.AddrPort) bool {
|
||||
if !connAddr.IsValid() || !connAddr.Addr().IsLoopback() {
|
||||
func (l *loopBackDetector) CheckPacketConn(source netip.AddrPort, local netip.AddrPort) bool {
|
||||
if !source.IsValid() {
|
||||
return false
|
||||
}
|
||||
if !connAddr.Addr().IsLoopback() {
|
||||
_, err := l.router.InterfaceFinder().InterfaceByAddr(connAddr.Addr())
|
||||
if !source.Addr().IsLoopback() {
|
||||
_, err := l.router.InterfaceFinder().InterfaceByAddr(source.Addr())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if N.IsPublicAddr(source.Addr()) {
|
||||
return false
|
||||
}
|
||||
l.packetConnAccess.RLock()
|
||||
defer l.packetConnAccess.RUnlock()
|
||||
return l.packetConnMap[connAddr.Port()]
|
||||
destinationPort, loaded := l.packetConnMap[source.Port()]
|
||||
return loaded && destinationPort != local.Port()
|
||||
}
|
||||
|
||||
type loopBackDetectWrapper struct {
|
||||
|
||||
@@ -287,8 +287,23 @@ func (g *URLTestGroup) Close() error {
|
||||
|
||||
func (g *URLTestGroup) Select(network string) (adapter.Outbound, bool) {
|
||||
var minDelay uint16
|
||||
var minTime time.Time
|
||||
var minOutbound adapter.Outbound
|
||||
switch network {
|
||||
case N.NetworkTCP:
|
||||
if g.selectedOutboundTCP != nil {
|
||||
if history := g.history.LoadURLTestHistory(RealTag(g.selectedOutboundTCP)); history != nil {
|
||||
minOutbound = g.selectedOutboundTCP
|
||||
minDelay = history.Delay
|
||||
}
|
||||
}
|
||||
case N.NetworkUDP:
|
||||
if g.selectedOutboundUDP != nil {
|
||||
if history := g.history.LoadURLTestHistory(RealTag(g.selectedOutboundUDP)); history != nil {
|
||||
minOutbound = g.selectedOutboundUDP
|
||||
minDelay = history.Delay
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, detour := range g.outbounds {
|
||||
if !common.Contains(detour.Network(), network) {
|
||||
continue
|
||||
@@ -297,9 +312,8 @@ func (g *URLTestGroup) Select(network string) (adapter.Outbound, bool) {
|
||||
if history == nil {
|
||||
continue
|
||||
}
|
||||
if minDelay == 0 || minDelay > history.Delay+g.tolerance || minDelay > history.Delay-g.tolerance && minTime.Before(history.Time) {
|
||||
if minDelay == 0 || minDelay > history.Delay+g.tolerance {
|
||||
minDelay = history.Delay
|
||||
minTime = history.Time
|
||||
minOutbound = detour
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
"github.com/sagernet/sing-box/outbound"
|
||||
"github.com/sagernet/sing-box/transport/fakeip"
|
||||
"github.com/sagernet/sing-dns"
|
||||
mux "github.com/sagernet/sing-mux"
|
||||
"github.com/sagernet/sing-mux"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing-vmess"
|
||||
"github.com/sagernet/sing/common"
|
||||
@@ -69,7 +69,6 @@ type Router struct {
|
||||
geositeCache map[string]adapter.Rule
|
||||
needFindProcess bool
|
||||
dnsClient *dns.Client
|
||||
dnsIndependentCache bool
|
||||
defaultDomainStrategy dns.DomainStrategy
|
||||
dnsRules []adapter.DNSRule
|
||||
ruleSets []adapter.RuleSet
|
||||
@@ -123,7 +122,6 @@ func NewRouter(
|
||||
geositeOptions: common.PtrValueOrDefault(options.Geosite),
|
||||
geositeCache: make(map[string]adapter.Rule),
|
||||
needFindProcess: hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess,
|
||||
dnsIndependentCache: dnsOptions.IndependentCache,
|
||||
defaultDetour: options.Final,
|
||||
defaultDomainStrategy: dns.DomainStrategy(dnsOptions.Strategy),
|
||||
interfaceFinder: control.NewDefaultInterfaceFinder(),
|
||||
@@ -237,7 +235,7 @@ func NewRouter(
|
||||
return nil, E.New("parse dns server[", tag, "]: missing address_resolver")
|
||||
}
|
||||
}
|
||||
var clientSubnet netip.Addr
|
||||
var clientSubnet netip.Prefix
|
||||
if server.ClientSubnet != nil {
|
||||
clientSubnet = server.ClientSubnet.Build()
|
||||
} else if dnsOptions.ClientSubnet != nil {
|
||||
|
||||
@@ -65,7 +65,7 @@ func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, index int) (con
|
||||
ruleIndex += index + 1
|
||||
}
|
||||
r.dnsLogger.DebugContext(ctx, "match[", ruleIndex, "] ", rule.String(), " => ", detour)
|
||||
if (isFakeIP && !r.dnsIndependentCache) || rule.DisableCache() {
|
||||
if isFakeIP || rule.DisableCache() {
|
||||
ctx = dns.ContextWithDisableCache(ctx, true)
|
||||
}
|
||||
if rewriteTTL := rule.RewriteTTL(); rewriteTTL != nil {
|
||||
|
||||
@@ -40,7 +40,7 @@ type DefaultDNSRule struct {
|
||||
abstractDefaultRule
|
||||
disableCache bool
|
||||
rewriteTTL *uint32
|
||||
clientSubnet *netip.Addr
|
||||
clientSubnet *netip.Prefix
|
||||
}
|
||||
|
||||
func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options option.DefaultDNSRule) (*DefaultDNSRule, error) {
|
||||
@@ -51,7 +51,7 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
|
||||
},
|
||||
disableCache: options.DisableCache,
|
||||
rewriteTTL: options.RewriteTTL,
|
||||
clientSubnet: (*netip.Addr)(options.ClientSubnet),
|
||||
clientSubnet: (*netip.Prefix)(options.ClientSubnet),
|
||||
}
|
||||
if len(options.Inbound) > 0 {
|
||||
item := NewInboundRule(options.Inbound)
|
||||
@@ -234,7 +234,7 @@ func (r *DefaultDNSRule) RewriteTTL() *uint32 {
|
||||
return r.rewriteTTL
|
||||
}
|
||||
|
||||
func (r *DefaultDNSRule) ClientSubnet() *netip.Addr {
|
||||
func (r *DefaultDNSRule) ClientSubnet() *netip.Prefix {
|
||||
return r.clientSubnet
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ type LogicalDNSRule struct {
|
||||
abstractLogicalRule
|
||||
disableCache bool
|
||||
rewriteTTL *uint32
|
||||
clientSubnet *netip.Addr
|
||||
clientSubnet *netip.Prefix
|
||||
}
|
||||
|
||||
func NewLogicalDNSRule(router adapter.Router, logger log.ContextLogger, options option.LogicalDNSRule) (*LogicalDNSRule, error) {
|
||||
@@ -284,6 +284,7 @@ func NewLogicalDNSRule(router adapter.Router, logger log.ContextLogger, options
|
||||
},
|
||||
disableCache: options.DisableCache,
|
||||
rewriteTTL: options.RewriteTTL,
|
||||
clientSubnet: (*netip.Prefix)(options.ClientSubnet),
|
||||
}
|
||||
switch options.Mode {
|
||||
case C.LogicalTypeAnd:
|
||||
@@ -311,7 +312,7 @@ func (r *LogicalDNSRule) RewriteTTL() *uint32 {
|
||||
return r.rewriteTTL
|
||||
}
|
||||
|
||||
func (r *LogicalDNSRule) ClientSubnet() *netip.Addr {
|
||||
func (r *LogicalDNSRule) ClientSubnet() *netip.Prefix {
|
||||
return r.clientSubnet
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,13 @@ func (s *MemoryStorage) FakeIPSaveMetadataAsync(metadata *adapter.FakeIPMetadata
|
||||
func (s *MemoryStorage) FakeIPStore(address netip.Addr, domain string) error {
|
||||
s.addressAccess.Lock()
|
||||
s.domainAccess.Lock()
|
||||
if oldDomain, loaded := s.addressCache[address]; loaded {
|
||||
if address.Is4() {
|
||||
delete(s.domainCache4, oldDomain)
|
||||
} else {
|
||||
delete(s.domainCache6, oldDomain)
|
||||
}
|
||||
}
|
||||
s.addressCache[address] = domain
|
||||
if address.Is4() {
|
||||
s.domainCache4[domain] = address
|
||||
|
||||
Reference in New Issue
Block a user