mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-12 01:57:18 +10:00
Compare commits
115 Commits
v1.12.0-be
...
dev-dns-ti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d8c15932f | ||
|
|
70371c3cbe | ||
|
|
32bc8b48f1 | ||
|
|
b5df508bc9 | ||
|
|
4789846113 | ||
|
|
ad94f94cfb | ||
|
|
1f9de9f321 | ||
|
|
344bbf9494 | ||
|
|
b7e16e70ab | ||
|
|
391153ecb8 | ||
|
|
3d821db0b2 | ||
|
|
344ecd3798 | ||
|
|
a8a3f863cd | ||
|
|
ea190ca428 | ||
|
|
e65b78d1e4 | ||
|
|
84f7d80da7 | ||
|
|
2b57eb0b30 | ||
|
|
9884f81298 | ||
|
|
8493b4f1da | ||
|
|
8f1a8add85 | ||
|
|
85ee6bb266 | ||
|
|
c4387f7c37 | ||
|
|
dcb7a5caed | ||
|
|
ae77cdeedd | ||
|
|
ec05d4e5e3 | ||
|
|
1f766d2b89 | ||
|
|
a5a6c1f7d4 | ||
|
|
cd43786279 | ||
|
|
43a211db28 | ||
|
|
d4f6bdf792 | ||
|
|
99cf27bedd | ||
|
|
0a14c5ab1f | ||
|
|
533b31e1f6 | ||
|
|
8ed6523872 | ||
|
|
e5c162222d | ||
|
|
88babbf3a7 | ||
|
|
49a03e0b23 | ||
|
|
9a8e9a34c0 | ||
|
|
17551db7be | ||
|
|
83201bb088 | ||
|
|
f0f1942f1f | ||
|
|
c7e318be61 | ||
|
|
2a5e0d0c92 | ||
|
|
956e485342 | ||
|
|
23ede74e74 | ||
|
|
03317e61dd | ||
|
|
fc81bd9a5b | ||
|
|
4d406cad84 | ||
|
|
1f0282de9c | ||
|
|
b097912418 | ||
|
|
056c29e73a | ||
|
|
7aa0a57e60 | ||
|
|
2673e64bcb | ||
|
|
3d3c1709d7 | ||
|
|
9de29a590f | ||
|
|
a5282b08ec | ||
|
|
b26c2083bf | ||
|
|
c1f4c691dc | ||
|
|
c0ef6eb728 | ||
|
|
074d61021f | ||
|
|
246c9d4e40 | ||
|
|
3e3466c8d7 | ||
|
|
f73415a732 | ||
|
|
ecabe9ffe1 | ||
|
|
2dae1ee284 | ||
|
|
2afb24d698 | ||
|
|
ade83ee758 | ||
|
|
ac9c300ca7 | ||
|
|
e6eb3cec2b | ||
|
|
601b79371b | ||
|
|
56b957d30d | ||
|
|
eb87b1a708 | ||
|
|
c0a5561bd4 | ||
|
|
4a3fe1d41c | ||
|
|
4cbbcfb04d | ||
|
|
b3ad4e0e39 | ||
|
|
49f9c0011d | ||
|
|
c8c165af87 | ||
|
|
3f790ff8c9 | ||
|
|
f2272ae1e7 | ||
|
|
b40c264c0a | ||
|
|
29fc8d6a86 | ||
|
|
46ca27c926 | ||
|
|
243a5dd477 | ||
|
|
844e9f09a6 | ||
|
|
9aa673f79e | ||
|
|
5abd74ffe3 | ||
|
|
68a32960bd | ||
|
|
1e62e3e5d4 | ||
|
|
40c03a9913 | ||
|
|
2ea4029868 | ||
|
|
66f5cdd014 | ||
|
|
89da2b6355 | ||
|
|
ee2b8498e6 | ||
|
|
b1eaf537bd | ||
|
|
63739c1621 | ||
|
|
3c8ddee029 | ||
|
|
23aad70045 | ||
|
|
0d67b51267 | ||
|
|
c02f939265 | ||
|
|
36b84e25c2 | ||
|
|
9fd4b0e9ae | ||
|
|
e68cdcc98a | ||
|
|
2691617c5e | ||
|
|
04056a1357 | ||
|
|
faac858e5d | ||
|
|
a818c8abeb | ||
|
|
15cbe9fc87 | ||
|
|
e186f2d31e | ||
|
|
e9323481a4 | ||
|
|
a0a41ff2bb | ||
|
|
549daf9d41 | ||
|
|
fa370f7d04 | ||
|
|
795cb17bfa | ||
|
|
00d8add761 |
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.24.5
|
||||
go-version: ^1.24
|
||||
- name: Check input version
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: |-
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
if: ${{ ! matrix.legacy_go }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.24.5
|
||||
go-version: ^1.24
|
||||
- name: Cache Legacy Go
|
||||
if: matrix.require_legacy_go
|
||||
id: cache-legacy-go
|
||||
@@ -294,7 +294,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.24.5
|
||||
go-version: ^1.24
|
||||
- name: Setup Android NDK
|
||||
id: setup-ndk
|
||||
uses: nttld/setup-ndk@v1
|
||||
@@ -374,7 +374,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.24.5
|
||||
go-version: ^1.24
|
||||
- name: Setup Android NDK
|
||||
id: setup-ndk
|
||||
uses: nttld/setup-ndk@v1
|
||||
@@ -472,7 +472,7 @@ jobs:
|
||||
if: matrix.if
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.24.5
|
||||
go-version: ^1.24
|
||||
- name: Setup Xcode stable
|
||||
if: matrix.if && github.ref == 'refs/heads/main-next'
|
||||
run: |-
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.24.5
|
||||
go-version: ^1.24
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
|
||||
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.24.5
|
||||
go-version: ^1.24
|
||||
- name: Check input version
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: |-
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.24.5
|
||||
go-version: ^1.24
|
||||
- name: Setup Android NDK
|
||||
if: matrix.os == 'android'
|
||||
uses: nttld/setup-ndk@v1
|
||||
|
||||
4
Makefile
4
Makefile
@@ -245,8 +245,8 @@ lib:
|
||||
go run ./cmd/internal/build_libbox -target ios
|
||||
|
||||
lib_install:
|
||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.7
|
||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.7
|
||||
go install -v github.com/sagernet/gomobile/cmd/gomobile@v0.1.6
|
||||
go install -v github.com/sagernet/gomobile/cmd/gobind@v0.1.6
|
||||
|
||||
docs:
|
||||
venv/bin/mkdocs serve
|
||||
|
||||
@@ -3,6 +3,7 @@ package adapter
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
@@ -36,6 +37,7 @@ type DNSQueryOptions struct {
|
||||
Transport DNSTransport
|
||||
Strategy C.DomainStrategy
|
||||
LookupStrategy C.DomainStrategy
|
||||
Timeout time.Duration
|
||||
DisableCache bool
|
||||
RewriteTTL *uint32
|
||||
ClientSubnet netip.Prefix
|
||||
@@ -53,6 +55,7 @@ func DNSQueryOptionsFrom(ctx context.Context, options *option.DomainResolveOptio
|
||||
return &DNSQueryOptions{
|
||||
Transport: transport,
|
||||
Strategy: C.DomainStrategy(options.Strategy),
|
||||
Timeout: time.Duration(options.Timeout),
|
||||
DisableCache: options.DisableCache,
|
||||
RewriteTTL: options.RewriteTTL,
|
||||
ClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
|
||||
@@ -70,6 +73,7 @@ type DNSTransport interface {
|
||||
Type() string
|
||||
Tag() string
|
||||
Dependencies() []string
|
||||
HasDetour() bool
|
||||
Exchange(ctx context.Context, message *dns.Msg) (*dns.Msg, error)
|
||||
}
|
||||
|
||||
|
||||
Submodule clients/android updated: 7f1fa971e3...eb2e13a6f9
Submodule clients/apple updated: f7883b0f3e...ae5818ee5a
@@ -177,7 +177,7 @@ func publishTestflight(ctx context.Context) error {
|
||||
}
|
||||
log.Info(string(platform), " ", tag, " publish")
|
||||
response, err := client.TestFlight.AddBuildsToBetaGroup(ctx, groupID, []string{build.ID})
|
||||
if response != nil && (response.StatusCode == http.StatusUnprocessableEntity || response.StatusCode == http.StatusNotFound) {
|
||||
if response != nil && response.StatusCode == http.StatusUnprocessableEntity {
|
||||
log.Info("waiting for process")
|
||||
time.Sleep(15 * time.Second)
|
||||
continue
|
||||
|
||||
@@ -46,9 +46,8 @@ var (
|
||||
sharedFlags []string
|
||||
debugFlags []string
|
||||
sharedTags []string
|
||||
darwinTags []string
|
||||
iosTags []string
|
||||
memcTags []string
|
||||
notMemcTags []string
|
||||
debugTags []string
|
||||
)
|
||||
|
||||
@@ -63,9 +62,8 @@ func init() {
|
||||
debugFlags = append(debugFlags, "-ldflags", "-X github.com/sagernet/sing-box/constant.Version="+currentTag)
|
||||
|
||||
sharedTags = append(sharedTags, "with_gvisor", "with_quic", "with_wireguard", "with_utls", "with_clash_api", "with_conntrack")
|
||||
darwinTags = append(darwinTags, "with_dhcp")
|
||||
iosTags = append(iosTags, "with_dhcp", "with_low_memory")
|
||||
memcTags = append(memcTags, "with_tailscale")
|
||||
notMemcTags = append(notMemcTags, "with_low_memory")
|
||||
debugTags = append(debugTags, "debug")
|
||||
}
|
||||
|
||||
@@ -155,7 +153,6 @@ func buildApple() {
|
||||
"-v",
|
||||
"-target", bindTarget,
|
||||
"-libname=box",
|
||||
"-tags-not-macos=with_low_memory",
|
||||
}
|
||||
if !withTailscale {
|
||||
args = append(args, "-tags-macos="+strings.Join(memcTags, ","))
|
||||
@@ -167,7 +164,7 @@ func buildApple() {
|
||||
args = append(args, debugFlags...)
|
||||
}
|
||||
|
||||
tags := append(sharedTags, darwinTags...)
|
||||
tags := append(sharedTags, iosTags...)
|
||||
if withTailscale {
|
||||
tags = append(tags, memcTags...)
|
||||
}
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/include"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/shell"
|
||||
)
|
||||
|
||||
var iperf3Path string
|
||||
|
||||
func main() {
|
||||
err := main0()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main0() error {
|
||||
err := shell.Exec("sudo", "ls").Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
results, err := runTests()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encoder := json.NewEncoder(os.Stdout)
|
||||
encoder.SetIndent("", " ")
|
||||
return encoder.Encode(results)
|
||||
}
|
||||
|
||||
func runTests() ([]TestResult, error) {
|
||||
boxPaths := []string{
|
||||
//"/Users/sekai/Downloads/sing-box-1.11.15-darwin-arm64/sing-box",
|
||||
//"/Users/sekai/Downloads/sing-box-1.11.15-linux-arm64/sing-box",
|
||||
"./sing-box",
|
||||
}
|
||||
stacks := []string{
|
||||
"gvisor",
|
||||
"system",
|
||||
}
|
||||
mtus := []int{
|
||||
// 1500,
|
||||
// 4064,
|
||||
// 16384,
|
||||
32768,
|
||||
49152,
|
||||
65535,
|
||||
}
|
||||
flagList := [][]string{
|
||||
{},
|
||||
}
|
||||
var results []TestResult
|
||||
for _, boxPath := range boxPaths {
|
||||
for _, stack := range stacks {
|
||||
for _, mtu := range mtus {
|
||||
if strings.HasPrefix(boxPath, ".") {
|
||||
for _, flags := range flagList {
|
||||
result, err := testOnce(boxPath, stack, mtu, false, flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, *result)
|
||||
}
|
||||
} else {
|
||||
result, err := testOnce(boxPath, stack, mtu, false, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results = append(results, *result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
type TestResult struct {
|
||||
BoxPath string `json:"box_path"`
|
||||
Stack string `json:"stack"`
|
||||
MTU int `json:"mtu"`
|
||||
Flags []string `json:"flags"`
|
||||
MultiThread bool `json:"multi_thread"`
|
||||
UploadSpeed string `json:"upload_speed"`
|
||||
DownloadSpeed string `json:"download_speed"`
|
||||
}
|
||||
|
||||
func testOnce(boxPath string, stackName string, mtu int, multiThread bool, flags []string) (result *TestResult, err error) {
|
||||
testAddress := netip.MustParseAddr("1.1.1.1")
|
||||
testConfig := option.Options{
|
||||
Inbounds: []option.Inbound{
|
||||
{
|
||||
Type: C.TypeTun,
|
||||
Options: &option.TunInboundOptions{
|
||||
Address: []netip.Prefix{netip.MustParsePrefix("172.18.0.1/30")},
|
||||
AutoRoute: true,
|
||||
MTU: uint32(mtu),
|
||||
Stack: stackName,
|
||||
RouteAddress: []netip.Prefix{netip.PrefixFrom(testAddress, testAddress.BitLen())},
|
||||
},
|
||||
},
|
||||
},
|
||||
Route: &option.RouteOptions{
|
||||
Rules: []option.Rule{
|
||||
{
|
||||
Type: C.RuleTypeDefault,
|
||||
DefaultOptions: option.DefaultRule{
|
||||
RawDefaultRule: option.RawDefaultRule{
|
||||
IPCIDR: []string{testAddress.String()},
|
||||
},
|
||||
RuleAction: option.RuleAction{
|
||||
Action: C.RuleActionTypeRouteOptions,
|
||||
RouteOptionsOptions: option.RouteOptionsActionOptions{
|
||||
OverrideAddress: "127.0.0.1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
AutoDetectInterface: true,
|
||||
},
|
||||
}
|
||||
ctx := include.Context(context.Background())
|
||||
tempConfig, err := os.CreateTemp("", "tun-bench-*.json")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer os.Remove(tempConfig.Name())
|
||||
encoder := json.NewEncoderContext(ctx, tempConfig)
|
||||
encoder.SetIndent("", " ")
|
||||
err = encoder.Encode(testConfig)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "encode test config")
|
||||
}
|
||||
tempConfig.Close()
|
||||
var sudoArgs []string
|
||||
if len(flags) > 0 {
|
||||
sudoArgs = append(sudoArgs, "env")
|
||||
for _, flag := range flags {
|
||||
sudoArgs = append(sudoArgs, flag)
|
||||
}
|
||||
}
|
||||
sudoArgs = append(sudoArgs, boxPath, "run", "-c", tempConfig.Name())
|
||||
boxProcess := shell.Exec("sudo", sudoArgs...)
|
||||
boxProcess.Stdout = &stderrWriter{}
|
||||
boxProcess.Stderr = io.Discard
|
||||
err = boxProcess.Start()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if C.IsDarwin {
|
||||
iperf3Path, err = exec.LookPath("iperf3-darwin")
|
||||
} else {
|
||||
iperf3Path, err = exec.LookPath("iperf3")
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serverProcess := shell.Exec(iperf3Path, "-s")
|
||||
serverProcess.Stdout = io.Discard
|
||||
serverProcess.Stderr = io.Discard
|
||||
err = serverProcess.Start()
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "start iperf3 server")
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
args := []string{"-c", testAddress.String(), "-t", "5"}
|
||||
if multiThread {
|
||||
args = append(args, "-P", "10")
|
||||
}
|
||||
|
||||
uploadProcess := shell.Exec(iperf3Path, args...)
|
||||
output, err := uploadProcess.Read()
|
||||
if err != nil {
|
||||
boxProcess.Process.Signal(syscall.SIGKILL)
|
||||
serverProcess.Process.Signal(syscall.SIGKILL)
|
||||
println(output)
|
||||
return
|
||||
}
|
||||
|
||||
uploadResult := common.SubstringBeforeLast(output, "iperf Done.")
|
||||
uploadResult = common.SubstringBeforeLast(uploadResult, "sender")
|
||||
uploadResult = common.SubstringBeforeLast(uploadResult, "bits/sec")
|
||||
uploadResult = common.SubstringAfterLast(uploadResult, "Bytes")
|
||||
uploadResult = strings.ReplaceAll(uploadResult, " ", "")
|
||||
|
||||
result = &TestResult{
|
||||
BoxPath: boxPath,
|
||||
Stack: stackName,
|
||||
MTU: mtu,
|
||||
Flags: flags,
|
||||
MultiThread: multiThread,
|
||||
UploadSpeed: uploadResult,
|
||||
}
|
||||
|
||||
downloadProcess := shell.Exec(iperf3Path, append(args, "-R")...)
|
||||
output, err = downloadProcess.Read()
|
||||
if err != nil {
|
||||
boxProcess.Process.Signal(syscall.SIGKILL)
|
||||
serverProcess.Process.Signal(syscall.SIGKILL)
|
||||
println(output)
|
||||
return
|
||||
}
|
||||
|
||||
downloadResult := common.SubstringBeforeLast(output, "iperf Done.")
|
||||
downloadResult = common.SubstringBeforeLast(downloadResult, "receiver")
|
||||
downloadResult = common.SubstringBeforeLast(downloadResult, "bits/sec")
|
||||
downloadResult = common.SubstringAfterLast(downloadResult, "Bytes")
|
||||
downloadResult = strings.ReplaceAll(downloadResult, " ", "")
|
||||
|
||||
result.DownloadSpeed = downloadResult
|
||||
|
||||
printArgs := []any{boxPath, stackName, mtu, "upload", uploadResult, "download", downloadResult}
|
||||
if len(flags) > 0 {
|
||||
printArgs = append(printArgs, "flags", strings.Join(flags, " "))
|
||||
}
|
||||
if multiThread {
|
||||
printArgs = append(printArgs, "(-P 10)")
|
||||
}
|
||||
fmt.Println(printArgs...)
|
||||
err = boxProcess.Process.Signal(syscall.SIGTERM)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = serverProcess.Process.Signal(syscall.SIGTERM)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
boxDone := make(chan struct{})
|
||||
go func() {
|
||||
boxProcess.Cmd.Wait()
|
||||
close(boxDone)
|
||||
}()
|
||||
|
||||
serverDone := make(chan struct{})
|
||||
go func() {
|
||||
serverProcess.Process.Wait()
|
||||
close(serverDone)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-boxDone:
|
||||
case <-time.After(2 * time.Second):
|
||||
boxProcess.Process.Kill()
|
||||
case <-time.After(4 * time.Second):
|
||||
println("box process did not close!")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-serverDone:
|
||||
case <-time.After(2 * time.Second):
|
||||
serverProcess.Process.Kill()
|
||||
case <-time.After(4 * time.Second):
|
||||
println("server process did not close!")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type stderrWriter struct{}
|
||||
|
||||
func (w *stderrWriter) Write(p []byte) (n int, err error) {
|
||||
return os.Stderr.Write(p)
|
||||
}
|
||||
@@ -89,6 +89,7 @@ func NewWithOptions(options Options) (N.Dialer, error) {
|
||||
dnsQueryOptions = adapter.DNSQueryOptions{
|
||||
Transport: transport,
|
||||
Strategy: strategy,
|
||||
Timeout: time.Duration(dialOptions.DomainResolver.Timeout),
|
||||
DisableCache: dialOptions.DomainResolver.DisableCache,
|
||||
RewriteTTL: dialOptions.DomainResolver.RewriteTTL,
|
||||
ClientSubnet: dialOptions.DomainResolver.ClientSubnet.Build(netip.Prefix{}),
|
||||
|
||||
@@ -9,6 +9,7 @@ const (
|
||||
TCPTimeout = 15 * time.Second
|
||||
ReadPayloadTimeout = 300 * time.Millisecond
|
||||
DNSTimeout = 10 * time.Second
|
||||
DirectDNSTimeout = 5 * time.Second
|
||||
UDPTimeout = 5 * time.Minute
|
||||
DefaultURLTestInterval = 3 * time.Minute
|
||||
DefaultURLTestIdleTimeout = 30 * time.Minute
|
||||
|
||||
@@ -30,7 +30,6 @@ var (
|
||||
var _ adapter.DNSClient = (*Client)(nil)
|
||||
|
||||
type Client struct {
|
||||
timeout time.Duration
|
||||
disableCache bool
|
||||
disableExpire bool
|
||||
independentCache bool
|
||||
@@ -43,7 +42,6 @@ type Client struct {
|
||||
}
|
||||
|
||||
type ClientOptions struct {
|
||||
Timeout time.Duration
|
||||
DisableCache bool
|
||||
DisableExpire bool
|
||||
IndependentCache bool
|
||||
@@ -55,7 +53,6 @@ type ClientOptions struct {
|
||||
|
||||
func NewClient(options ClientOptions) *Client {
|
||||
client := &Client{
|
||||
timeout: options.Timeout,
|
||||
disableCache: options.DisableCache,
|
||||
disableExpire: options.DisableExpire,
|
||||
independentCache: options.IndependentCache,
|
||||
@@ -63,9 +60,6 @@ func NewClient(options ClientOptions) *Client {
|
||||
initRDRCFunc: options.RDRC,
|
||||
logger: options.Logger,
|
||||
}
|
||||
if client.timeout == 0 {
|
||||
client.timeout = C.DNSTimeout
|
||||
}
|
||||
cacheCapacity := options.CacheCapacity
|
||||
if cacheCapacity < 1024 {
|
||||
cacheCapacity = 1024
|
||||
@@ -153,7 +147,15 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
|
||||
return nil, ErrResponseRejectedCached
|
||||
}
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, c.timeout)
|
||||
timeout := options.Timeout
|
||||
if timeout == 0 {
|
||||
if transport.HasDetour() {
|
||||
timeout = C.DNSTimeout
|
||||
} else {
|
||||
timeout = C.DirectDNSTimeout
|
||||
}
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
response, err := transport.Exchange(ctx, message)
|
||||
cancel()
|
||||
if err != nil {
|
||||
@@ -195,13 +197,8 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
|
||||
}
|
||||
}*/
|
||||
if responseChecker != nil {
|
||||
var rejected bool
|
||||
if !(response.Rcode == dns.RcodeSuccess || response.Rcode == dns.RcodeNameError) {
|
||||
rejected = true
|
||||
} else {
|
||||
rejected = !responseChecker(MessageToAddresses(response))
|
||||
}
|
||||
if rejected {
|
||||
addr, addrErr := MessageToAddresses(response)
|
||||
if addrErr != nil || !responseChecker(addr) {
|
||||
if c.rdrc != nil {
|
||||
c.rdrc.SaveRDRCAsync(transport.Tag(), question.Name, question.Qtype, c.logger)
|
||||
}
|
||||
@@ -425,10 +422,7 @@ func (c *Client) lookupToExchange(ctx context.Context, transport adapter.DNSTran
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if response.Rcode != dns.RcodeSuccess {
|
||||
return nil, RcodeError(response.Rcode)
|
||||
}
|
||||
return MessageToAddresses(response), nil
|
||||
return MessageToAddresses(response)
|
||||
}
|
||||
|
||||
func (c *Client) questionCache(question dns.Question, transport adapter.DNSTransport) ([]netip.Addr, error) {
|
||||
@@ -436,10 +430,7 @@ func (c *Client) questionCache(question dns.Question, transport adapter.DNSTrans
|
||||
if response == nil {
|
||||
return nil, ErrNotCached
|
||||
}
|
||||
if response.Rcode != dns.RcodeSuccess {
|
||||
return nil, RcodeError(response.Rcode)
|
||||
}
|
||||
return MessageToAddresses(response), nil
|
||||
return MessageToAddresses(response)
|
||||
}
|
||||
|
||||
func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransport) (*dns.Msg, int) {
|
||||
@@ -516,7 +507,10 @@ func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransp
|
||||
}
|
||||
}
|
||||
|
||||
func MessageToAddresses(response *dns.Msg) []netip.Addr {
|
||||
func MessageToAddresses(response *dns.Msg) ([]netip.Addr, error) {
|
||||
if response.Rcode != dns.RcodeSuccess {
|
||||
return nil, RcodeError(response.Rcode)
|
||||
}
|
||||
addresses := make([]netip.Addr, 0, len(response.Answer))
|
||||
for _, rawAnswer := range response.Answer {
|
||||
switch answer := rawAnswer.(type) {
|
||||
@@ -532,7 +526,7 @@ func MessageToAddresses(response *dns.Msg) []netip.Addr {
|
||||
}
|
||||
}
|
||||
}
|
||||
return addresses
|
||||
return addresses, nil
|
||||
}
|
||||
|
||||
func wrapError(err error) error {
|
||||
|
||||
@@ -158,6 +158,9 @@ func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, ruleIndex int,
|
||||
if action.Strategy != C.DomainStrategyAsIS {
|
||||
options.Strategy = action.Strategy
|
||||
}
|
||||
if action.Timeout > 0 {
|
||||
options.Timeout = action.Timeout
|
||||
}
|
||||
if isFakeIP || action.DisableCache {
|
||||
options.DisableCache = true
|
||||
}
|
||||
@@ -180,6 +183,9 @@ func (r *Router) matchDNS(ctx context.Context, allowFakeIP bool, ruleIndex int,
|
||||
if action.Strategy != C.DomainStrategyAsIS {
|
||||
options.Strategy = action.Strategy
|
||||
}
|
||||
if action.Timeout > 0 {
|
||||
options.Timeout = action.Timeout
|
||||
}
|
||||
if action.DisableCache {
|
||||
options.DisableCache = true
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ type Transport struct {
|
||||
dns.TransportAdapter
|
||||
ctx context.Context
|
||||
dialer N.Dialer
|
||||
hasDetour bool
|
||||
logger logger.ContextLogger
|
||||
networkManager adapter.NetworkManager
|
||||
interfaceName string
|
||||
@@ -59,6 +60,7 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
|
||||
TransportAdapter: dns.NewTransportAdapterWithLocalOptions(C.DNSTypeDHCP, tag, options.LocalDNSServerOptions),
|
||||
ctx: ctx,
|
||||
dialer: transportDialer,
|
||||
hasDetour: options.Detour != "",
|
||||
logger: logger,
|
||||
networkManager: service.FromContext[adapter.NetworkManager](ctx),
|
||||
interfaceName: options.Interface,
|
||||
@@ -89,6 +91,10 @@ func (t *Transport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) HasDetour() bool {
|
||||
return t.hasDetour
|
||||
}
|
||||
|
||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
err := t.fetchServers()
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package local
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
@@ -90,9 +91,9 @@ func (t *Transport) exchangeParallel(ctx context.Context, systemConfig *dnsConfi
|
||||
startRacer := func(ctx context.Context, fqdn string) {
|
||||
response, err := t.tryOneName(ctx, systemConfig, fqdn, message)
|
||||
if err == nil {
|
||||
if response.Rcode != mDNS.RcodeSuccess {
|
||||
err = dns.RcodeError(response.Rcode)
|
||||
} else if len(dns.MessageToAddresses(response)) == 0 {
|
||||
var addresses []netip.Addr
|
||||
addresses, err = dns.MessageToAddresses(response)
|
||||
if err == nil && len(addresses) == 0 {
|
||||
err = E.New(fqdn, ": empty result")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func NewUDPRaw(logger logger.ContextLogger, adapter dns.TransportAdapter, dialer
|
||||
logger: logger,
|
||||
dialer: dialer,
|
||||
serverAddr: serverAddr,
|
||||
udpSize: 2048,
|
||||
udpSize: 512,
|
||||
tcpTransport: &TCPTransport{
|
||||
dialer: dialer,
|
||||
serverAddr: serverAddr,
|
||||
@@ -97,19 +97,15 @@ func (t *UDPTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.M
|
||||
}
|
||||
|
||||
func (t *UDPTransport) exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
t.access.Lock()
|
||||
if edns0Opt := message.IsEdns0(); edns0Opt != nil {
|
||||
if udpSize := int(edns0Opt.UDPSize()); udpSize > t.udpSize {
|
||||
t.udpSize = udpSize
|
||||
close(t.done)
|
||||
t.done = make(chan struct{})
|
||||
}
|
||||
}
|
||||
t.access.Unlock()
|
||||
conn, err := t.open(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if edns0Opt := message.IsEdns0(); edns0Opt != nil {
|
||||
if udpSize := int(edns0Opt.UDPSize()); udpSize > t.udpSize {
|
||||
t.udpSize = udpSize
|
||||
}
|
||||
}
|
||||
buffer := buf.NewSize(1 + message.Len())
|
||||
defer buffer.Release()
|
||||
exMessage := *message
|
||||
|
||||
@@ -14,6 +14,7 @@ type TransportAdapter struct {
|
||||
transportType string
|
||||
transportTag string
|
||||
dependencies []string
|
||||
hasDetour bool
|
||||
strategy C.DomainStrategy
|
||||
clientSubnet netip.Prefix
|
||||
}
|
||||
@@ -35,6 +36,7 @@ func NewTransportAdapterWithLocalOptions(transportType string, transportTag stri
|
||||
transportType: transportType,
|
||||
transportTag: transportTag,
|
||||
dependencies: dependencies,
|
||||
hasDetour: localOptions.Detour != "",
|
||||
strategy: C.DomainStrategy(localOptions.LegacyStrategy),
|
||||
clientSubnet: localOptions.LegacyClientSubnet,
|
||||
}
|
||||
@@ -69,6 +71,10 @@ func (a *TransportAdapter) Dependencies() []string {
|
||||
return a.dependencies
|
||||
}
|
||||
|
||||
func (a *TransportAdapter) HasDetour() bool {
|
||||
return a.hasDetour
|
||||
}
|
||||
|
||||
func (a *TransportAdapter) LegacyStrategy() C.DomainStrategy {
|
||||
return a.strategy
|
||||
}
|
||||
|
||||
@@ -2,26 +2,10 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.12.0-beta.34
|
||||
#### 1.12.0-beta.30
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
### 1.11.15
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
_We are temporarily unable to update sing-box apps on the App Store because the reviewer mistakenly found that we
|
||||
violated the rules (TestFlight users are not affected)._
|
||||
|
||||
#### 1.12.0-beta.32
|
||||
|
||||
* Improve tun performance on Apple platforms **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
We have significantly improved the performance of tun inbound on Apple platforms, especially in the gVisor stack.
|
||||
|
||||
### 1.11.14
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
8
go.mod
8
go.mod
@@ -25,16 +25,16 @@ require (
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||
github.com/sagernet/cors v1.2.1
|
||||
github.com/sagernet/fswatch v0.1.1
|
||||
github.com/sagernet/gomobile v0.1.7
|
||||
github.com/sagernet/gomobile v0.1.6
|
||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1
|
||||
github.com/sagernet/sing v0.6.12-0.20250718132236-21daaa465e88
|
||||
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b
|
||||
github.com/sagernet/sing-mux v0.3.2
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.3
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.2
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
||||
github.com/sagernet/sing-tun v0.6.10-0.20250718030019-3af7305b853e
|
||||
github.com/sagernet/sing-tun v0.6.10-0.20250630100036-8763c24e4935
|
||||
github.com/sagernet/sing-vmess v0.2.4-0.20250605032146-38cc72672c88
|
||||
github.com/sagernet/smux v1.5.34-mod.2
|
||||
github.com/sagernet/tailscale v1.80.3-mod.5
|
||||
|
||||
16
go.sum
16
go.sum
@@ -157,8 +157,8 @@ github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
|
||||
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||
github.com/sagernet/gomobile v0.1.7 h1:I9jCJZTH0weP5MsuydvYHX5QfN/r6Fe8ptAIj1+SJVg=
|
||||
github.com/sagernet/gomobile v0.1.7/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
||||
github.com/sagernet/gomobile v0.1.6 h1:JkR1ToKOrdoiwULte4pYS5HYdPBzl2N+JNuuwVuLs0k=
|
||||
github.com/sagernet/gomobile v0.1.6/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb h1:pprQtDqNgqXkRsXn+0E8ikKOemzmum8bODjSfDene38=
|
||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb/go.mod h1:QkkPEJLw59/tfxgapHta14UL5qMUah5NXhO0Kw2Kan4=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||
@@ -168,20 +168,20 @@ github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/l
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
|
||||
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.6.12-0.20250718132236-21daaa465e88 h1:Wu6hu+JsZ2gsFRJMqGzaZJ4ctGnmNrLGm9ckmotBFOs=
|
||||
github.com/sagernet/sing v0.6.12-0.20250718132236-21daaa465e88/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b h1:ZjTCYPb5f7aHdf1UpUvE22dVmf7BL8eQ/zLZhjgh7Wo=
|
||||
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-mux v0.3.2 h1:meZVFiiStvHThb/trcpAkCrmtJOuItG5Dzl1RRP5/NE=
|
||||
github.com/sagernet/sing-mux v0.3.2/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.3 h1:X/acRNsqQNfDlmwE7SorHfaZiny5e67hqIzM/592ric=
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.3/go.mod h1:SAv/qdeDN+75msGG5U5ZIwG+3Ua50jVIKNrRSY8pkx0=
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.2 h1:j7KAbBuGmsKwSxVAQL5soJ+wDqxim4/llK2kxB0hSKk=
|
||||
github.com/sagernet/sing-quic v0.5.0-beta.2/go.mod h1:SAv/qdeDN+75msGG5U5ZIwG+3Ua50jVIKNrRSY8pkx0=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-tun v0.6.10-0.20250718030019-3af7305b853e h1:IH6N3oTKs4bqXLoKP7uFfIAAuZHCNq6OCV4MlrGGLqs=
|
||||
github.com/sagernet/sing-tun v0.6.10-0.20250718030019-3af7305b853e/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||
github.com/sagernet/sing-tun v0.6.10-0.20250630100036-8763c24e4935 h1:wha4BG4mrEKaIoouVyiU5BcPfKD1n0LkiL4vqdjaVps=
|
||||
github.com/sagernet/sing-tun v0.6.10-0.20250630100036-8763c24e4935/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||
github.com/sagernet/sing-vmess v0.2.4-0.20250605032146-38cc72672c88 h1:0pVm8sPOel+BoiCddW3pV3cKDKEaSioVTYDdTSKjyFI=
|
||||
github.com/sagernet/sing-vmess v0.2.4-0.20250605032146-38cc72672c88/go.mod h1:IL8Rr+EGwuqijszZkNrEFTQDKhilEpkqFqOlvdpS6/w=
|
||||
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=
|
||||
|
||||
@@ -180,7 +180,7 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
||||
options := o.Options.(*LegacyDNSServerOptions)
|
||||
serverURL, _ := url.Parse(options.Address)
|
||||
var serverType string
|
||||
if serverURL != nil && serverURL.Scheme != "" {
|
||||
if serverURL.Scheme != "" {
|
||||
serverType = serverURL.Scheme
|
||||
} else {
|
||||
switch options.Address {
|
||||
@@ -217,7 +217,7 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
||||
o.Type = C.DNSTypeUDP
|
||||
o.Options = &remoteOptions
|
||||
var serverAddr M.Socksaddr
|
||||
if serverURL == nil || serverURL.Scheme == "" {
|
||||
if serverURL.Scheme == "" {
|
||||
serverAddr = M.ParseSocksaddr(options.Address)
|
||||
} else {
|
||||
serverAddr = M.ParseSocksaddr(serverURL.Host)
|
||||
@@ -232,9 +232,6 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
||||
case C.DNSTypeTCP:
|
||||
o.Type = C.DNSTypeTCP
|
||||
o.Options = &remoteOptions
|
||||
if serverURL == nil {
|
||||
return E.New("invalid server address")
|
||||
}
|
||||
serverAddr := M.ParseSocksaddr(serverURL.Host)
|
||||
if !serverAddr.IsValid() {
|
||||
return E.New("invalid server address")
|
||||
@@ -245,9 +242,6 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
||||
}
|
||||
case C.DNSTypeTLS, C.DNSTypeQUIC:
|
||||
o.Type = serverType
|
||||
if serverURL == nil {
|
||||
return E.New("invalid server address")
|
||||
}
|
||||
serverAddr := M.ParseSocksaddr(serverURL.Host)
|
||||
if !serverAddr.IsValid() {
|
||||
return E.New("invalid server address")
|
||||
@@ -267,9 +261,6 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
||||
},
|
||||
}
|
||||
o.Options = &httpsOptions
|
||||
if serverURL == nil {
|
||||
return E.New("invalid server address")
|
||||
}
|
||||
serverAddr := M.ParseSocksaddr(serverURL.Host)
|
||||
if !serverAddr.IsValid() {
|
||||
return E.New("invalid server address")
|
||||
@@ -283,9 +274,6 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
||||
}
|
||||
case "rcode":
|
||||
var rcode int
|
||||
if serverURL == nil {
|
||||
return E.New("invalid server address")
|
||||
}
|
||||
switch serverURL.Host {
|
||||
case "success":
|
||||
rcode = dns.RcodeSuccess
|
||||
@@ -307,9 +295,6 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
||||
case C.DNSTypeDHCP:
|
||||
o.Type = C.DNSTypeDHCP
|
||||
dhcpOptions := DHCPDNSServerOptions{}
|
||||
if serverURL == nil {
|
||||
return E.New("invalid server address")
|
||||
}
|
||||
if serverURL.Host != "" && serverURL.Host != "auto" {
|
||||
dhcpOptions.Interface = serverURL.Host
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ type DialerOptions struct {
|
||||
type _DomainResolveOptions struct {
|
||||
Server string `json:"server"`
|
||||
Strategy DomainStrategy `json:"strategy,omitempty"`
|
||||
Timeout badoption.Duration `json:"timeout,omitempty"`
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
||||
@@ -102,6 +103,7 @@ func (o DomainResolveOptions) MarshalJSON() ([]byte, error) {
|
||||
if o.Server == "" {
|
||||
return []byte("{}"), nil
|
||||
} else if o.Strategy == DomainStrategy(C.DomainStrategyAsIS) &&
|
||||
o.Timeout == 0 &&
|
||||
!o.DisableCache &&
|
||||
o.RewriteTTL == nil &&
|
||||
o.ClientSubnet == nil {
|
||||
|
||||
@@ -180,6 +180,7 @@ func (r *RouteOptionsActionOptions) UnmarshalJSON(data []byte) error {
|
||||
type DNSRouteActionOptions struct {
|
||||
Server string `json:"server,omitempty"`
|
||||
Strategy DomainStrategy `json:"strategy,omitempty"`
|
||||
Timeout badoption.Duration `json:"timeout,omitempty"`
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
||||
@@ -187,6 +188,7 @@ type DNSRouteActionOptions struct {
|
||||
|
||||
type _DNSRouteOptionsActionOptions struct {
|
||||
Strategy DomainStrategy `json:"strategy,omitempty"`
|
||||
Timeout badoption.Duration `json:"timeout,omitempty"`
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
||||
|
||||
@@ -130,16 +130,9 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
deprecated.Report(ctx, deprecated.OptionTUNGSO)
|
||||
}
|
||||
|
||||
platformInterface := service.FromContext[platform.Interface](ctx)
|
||||
tunMTU := options.MTU
|
||||
enableGSO := C.IsLinux && options.Stack == "gvisor" && platformInterface == nil && tunMTU > 0 && tunMTU < 49152
|
||||
if tunMTU == 0 {
|
||||
if platformInterface != nil && platformInterface.UnderNetworkExtension() {
|
||||
// In Network Extension, when MTU exceeds 4064 (4096-UTUN_IF_HEADROOM_SIZE), the performance of tun will drop significantly, which may be a system bug.
|
||||
tunMTU = 4064
|
||||
} else {
|
||||
tunMTU = 65535
|
||||
}
|
||||
tunMTU = 9000
|
||||
}
|
||||
var udpTimeout time.Duration
|
||||
if options.UDPTimeout != 0 {
|
||||
@@ -180,7 +173,6 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
outputMark = tun.DefaultAutoRedirectOutputMark
|
||||
}
|
||||
networkManager := service.FromContext[adapter.NetworkManager](ctx)
|
||||
multiPendingPackets := C.IsDarwin && ((options.Stack == "gvisor" && tunMTU < 32768) || (options.Stack != "gvisor" && options.MTU <= 9000))
|
||||
inbound := &Inbound{
|
||||
tag: tag,
|
||||
ctx: ctx,
|
||||
@@ -191,7 +183,6 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
tunOptions: tun.Options{
|
||||
Name: options.InterfaceName,
|
||||
MTU: tunMTU,
|
||||
GSO: enableGSO,
|
||||
Inet4Address: inet4Address,
|
||||
Inet6Address: inet6Address,
|
||||
AutoRoute: options.AutoRoute,
|
||||
@@ -214,11 +205,10 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
IncludePackage: options.IncludePackage,
|
||||
ExcludePackage: options.ExcludePackage,
|
||||
InterfaceMonitor: networkManager.InterfaceMonitor(),
|
||||
EXP_MultiPendingPackets: multiPendingPackets,
|
||||
},
|
||||
udpTimeout: udpTimeout,
|
||||
stack: options.Stack,
|
||||
platformInterface: platformInterface,
|
||||
platformInterface: service.FromContext[platform.Interface](ctx),
|
||||
platformOptions: common.PtrValueOrDefault(options.Platform),
|
||||
}
|
||||
for _, routeAddressSet := range options.RouteAddressSet {
|
||||
|
||||
@@ -277,7 +277,7 @@ func (m *ConnectionManager) connectionCopy(ctx context.Context, source net.Conn,
|
||||
return
|
||||
}
|
||||
}
|
||||
_, err := bufio.CopyWithCounters(destinationWriter, sourceReader, source, readCounters, writeCounters, bufio.DefaultIncreaseBufferAfter, bufio.DefaultBatchSize)
|
||||
_, err := bufio.CopyWithCounters(destinationWriter, sourceReader, source, readCounters, writeCounters)
|
||||
if err != nil {
|
||||
common.Close(source, destination)
|
||||
} else if duplexDst, isDuplex := destination.(N.WriteCloser); isDuplex {
|
||||
|
||||
@@ -76,6 +76,7 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOp
|
||||
DomainResolver: defaultDomainResolver.Server,
|
||||
DomainResolveOptions: adapter.DNSQueryOptions{
|
||||
Strategy: C.DomainStrategy(defaultDomainResolver.Strategy),
|
||||
Timeout: time.Duration(defaultDomainResolver.Timeout),
|
||||
DisableCache: defaultDomainResolver.DisableCache,
|
||||
RewriteTTL: defaultDomainResolver.RewriteTTL,
|
||||
ClientSubnet: defaultDomainResolver.ClientSubnet.Build(netip.Prefix{}),
|
||||
|
||||
@@ -666,6 +666,7 @@ func (r *Router) actionResolve(ctx context.Context, metadata *adapter.InboundCon
|
||||
addresses, err := r.dns.Lookup(adapter.WithContext(ctx, metadata), metadata.Destination.Fqdn, adapter.DNSQueryOptions{
|
||||
Transport: transport,
|
||||
Strategy: action.Strategy,
|
||||
Timeout: action.Timeout,
|
||||
DisableCache: action.DisableCache,
|
||||
RewriteTTL: action.RewriteTTL,
|
||||
ClientSubnet: action.ClientSubnet,
|
||||
|
||||
@@ -113,6 +113,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
|
||||
Server: action.RouteOptions.Server,
|
||||
RuleActionDNSRouteOptions: RuleActionDNSRouteOptions{
|
||||
Strategy: C.DomainStrategy(action.RouteOptions.Strategy),
|
||||
Timeout: time.Duration(action.RouteOptions.Timeout),
|
||||
DisableCache: action.RouteOptions.DisableCache,
|
||||
RewriteTTL: action.RouteOptions.RewriteTTL,
|
||||
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptions.ClientSubnet)),
|
||||
@@ -121,6 +122,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
|
||||
case C.RuleActionTypeRouteOptions:
|
||||
return &RuleActionDNSRouteOptions{
|
||||
Strategy: C.DomainStrategy(action.RouteOptionsOptions.Strategy),
|
||||
Timeout: time.Duration(action.RouteOptionsOptions.Timeout),
|
||||
DisableCache: action.RouteOptionsOptions.DisableCache,
|
||||
RewriteTTL: action.RouteOptionsOptions.RewriteTTL,
|
||||
ClientSubnet: netip.Prefix(common.PtrValueOrDefault(action.RouteOptionsOptions.ClientSubnet)),
|
||||
@@ -235,20 +237,13 @@ func (r *RuleActionDNSRoute) Type() string {
|
||||
func (r *RuleActionDNSRoute) String() string {
|
||||
var descriptions []string
|
||||
descriptions = append(descriptions, r.Server)
|
||||
if r.DisableCache {
|
||||
descriptions = append(descriptions, "disable-cache")
|
||||
}
|
||||
if r.RewriteTTL != nil {
|
||||
descriptions = append(descriptions, F.ToString("rewrite-ttl=", *r.RewriteTTL))
|
||||
}
|
||||
if r.ClientSubnet.IsValid() {
|
||||
descriptions = append(descriptions, F.ToString("client-subnet=", r.ClientSubnet))
|
||||
}
|
||||
descriptions = append(descriptions, r.Descriptions()...)
|
||||
return F.ToString("route(", strings.Join(descriptions, ","), ")")
|
||||
}
|
||||
|
||||
type RuleActionDNSRouteOptions struct {
|
||||
Strategy C.DomainStrategy
|
||||
Timeout time.Duration
|
||||
DisableCache bool
|
||||
RewriteTTL *uint32
|
||||
ClientSubnet netip.Prefix
|
||||
@@ -259,7 +254,17 @@ func (r *RuleActionDNSRouteOptions) Type() string {
|
||||
}
|
||||
|
||||
func (r *RuleActionDNSRouteOptions) String() string {
|
||||
return F.ToString("route-options(", strings.Join(r.Descriptions(), ","), ")")
|
||||
}
|
||||
|
||||
func (r *RuleActionDNSRouteOptions) Descriptions() []string {
|
||||
var descriptions []string
|
||||
if r.Strategy != C.DomainStrategyAsIS {
|
||||
descriptions = append(descriptions, F.ToString("strategy=", option.DomainStrategy(r.Strategy)))
|
||||
}
|
||||
if r.Timeout > 0 {
|
||||
descriptions = append(descriptions, F.ToString("timeout=", r.Timeout.String()))
|
||||
}
|
||||
if r.DisableCache {
|
||||
descriptions = append(descriptions, "disable-cache")
|
||||
}
|
||||
@@ -269,7 +274,7 @@ func (r *RuleActionDNSRouteOptions) String() string {
|
||||
if r.ClientSubnet.IsValid() {
|
||||
descriptions = append(descriptions, F.ToString("client-subnet=", r.ClientSubnet))
|
||||
}
|
||||
return F.ToString("route-options(", strings.Join(descriptions, ","), ")")
|
||||
return descriptions
|
||||
}
|
||||
|
||||
type RuleActionDirect struct {
|
||||
@@ -421,6 +426,7 @@ func (r *RuleActionSniff) String() string {
|
||||
type RuleActionResolve struct {
|
||||
Server string
|
||||
Strategy C.DomainStrategy
|
||||
Timeout time.Duration
|
||||
DisableCache bool
|
||||
RewriteTTL *uint32
|
||||
ClientSubnet netip.Prefix
|
||||
@@ -438,6 +444,9 @@ func (r *RuleActionResolve) String() string {
|
||||
if r.Strategy != C.DomainStrategyAsIS {
|
||||
options = append(options, F.ToString(option.DomainStrategy(r.Strategy)))
|
||||
}
|
||||
if r.Timeout > 0 {
|
||||
options = append(options, F.ToString("timeout=", r.Timeout.String()))
|
||||
}
|
||||
if r.DisableCache {
|
||||
options = append(options, "disable_cache")
|
||||
}
|
||||
|
||||
@@ -31,9 +31,6 @@ type HTTPConn struct {
|
||||
}
|
||||
|
||||
func NewHTTP1Conn(conn net.Conn, request *http.Request) *HTTPConn {
|
||||
if request.Header.Get("Host") == "" {
|
||||
request.Header.Set("Host", request.Host)
|
||||
}
|
||||
return &HTTPConn{
|
||||
Conn: conn,
|
||||
request: request,
|
||||
@@ -92,6 +89,9 @@ func (c *HTTPConn) writeRequest(payload []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.request.Header.Get("Host") == "" {
|
||||
c.request.Header.Set("Host", c.request.Host)
|
||||
}
|
||||
for key, value := range c.request.Header {
|
||||
_, err = writer.Write([]byte(F.ToString(key, ": ", strings.Join(value, ", "), CRLF)))
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user