mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-11 17:47:20 +10:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d735281f4 | ||
|
|
8760a0d94d | ||
|
|
2239b59933 | ||
|
|
425a63f59d | ||
|
|
b85725c009 | ||
|
|
17aebc56c1 | ||
|
|
f76b21b02c | ||
|
|
704545a2ec | ||
|
|
dc7b7afc06 | ||
|
|
e478d3c2dc | ||
|
|
c8318058bb | ||
|
|
abca2118e7 | ||
|
|
a8ee41715a | ||
|
|
94f76d6671 | ||
|
|
bf6cc8903c | ||
|
|
1b15e1692a | ||
|
|
017372db25 | ||
|
|
216a0380fe | ||
|
|
71b9e4ff17 | ||
|
|
9b7deb5246 | ||
|
|
a850a73e1a | ||
|
|
c4d9be9e0d | ||
|
|
f31c604b3d | ||
|
|
4c8a50a52b | ||
|
|
b326e60998 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
github: nekohasekai
|
||||
36
.github/workflows/debug.yml
vendored
36
.github/workflows/debug.yml
vendored
@@ -25,22 +25,10 @@ jobs:
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Get latest go version
|
||||
id: version
|
||||
run: |
|
||||
echo go_version=$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') >> $GITHUB_OUTPUT
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ steps.version.outputs.go_version }}
|
||||
- name: Add cache to Go proxy
|
||||
run: |
|
||||
version=`git rev-parse HEAD`
|
||||
mkdir build
|
||||
pushd build
|
||||
go mod init build
|
||||
go get -v github.com/sagernet/sing-box@$version
|
||||
popd
|
||||
go-version: ^1.21
|
||||
continue-on-error: true
|
||||
- name: Run Test
|
||||
run: |
|
||||
@@ -56,7 +44,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.18.10
|
||||
go-version: ~1.18
|
||||
- name: Cache go module
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -76,13 +64,13 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.20.7
|
||||
go-version: ^1.20
|
||||
- name: Cache go module
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
key: go118-${{ hashFiles('**/go.sum') }}
|
||||
key: go120-${{ hashFiles('**/go.sum') }}
|
||||
- name: Run Test
|
||||
run: make ci_build
|
||||
cross:
|
||||
@@ -188,8 +176,7 @@ jobs:
|
||||
- name: freebsd-arm64
|
||||
goos: freebsd
|
||||
goarch: arm64
|
||||
|
||||
fail-fast: false
|
||||
fail-fast: true
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
@@ -204,19 +191,10 @@ jobs:
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Get latest go version
|
||||
id: version
|
||||
run: |
|
||||
echo go_version=$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') >> $GITHUB_OUTPUT
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ steps.version.outputs.go_version }}
|
||||
go-version: ^1.21
|
||||
- name: Build
|
||||
id: build
|
||||
run: make
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sing-box-${{ matrix.name }}
|
||||
path: sing-box*
|
||||
run: make
|
||||
22
.github/workflows/docker.yml
vendored
22
.github/workflows/docker.yml
vendored
@@ -1,9 +1,10 @@
|
||||
name: Build Docker Images
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "The tag version you want to build"
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -25,15 +26,6 @@ jobs:
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/sagernet/sing-box
|
||||
- name: Get tag to build
|
||||
id: tag
|
||||
run: |
|
||||
echo "latest=ghcr.io/sagernet/sing-box:latest" >> $GITHUB_OUTPUT
|
||||
if [[ -z "${{ github.event.inputs.tag }}" ]]; then
|
||||
echo "versioned=ghcr.io/sagernet/sing-box:${{ github.ref_name }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "versioned=ghcr.io/sagernet/sing-box:${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
- name: Build and release Docker images
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
@@ -42,6 +34,6 @@ jobs:
|
||||
build-args: |
|
||||
BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
|
||||
tags: |
|
||||
${{ steps.tag.outputs.latest }}
|
||||
${{ steps.tag.outputs.versioned }}
|
||||
ghcr.io/sagernet/sing-box:latest
|
||||
ghcr.io/sagernet/sing-box:${{ github.ref_name }}
|
||||
push: true
|
||||
|
||||
8
.github/workflows/lint.yml
vendored
8
.github/workflows/lint.yml
vendored
@@ -25,10 +25,10 @@ jobs:
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Get latest go version
|
||||
id: version
|
||||
run: |
|
||||
echo go_version=$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') >> $GITHUB_OUTPUT
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ^1.21
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
|
||||
@@ -85,8 +85,15 @@ var GoBinPath string
|
||||
|
||||
func FindMobile() {
|
||||
goBin := filepath.Join(build.Default.GOPATH, "bin")
|
||||
if !rw.FileExists(goBin + "/" + "gobind") {
|
||||
log.Fatal("missing gomobile installation")
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
if !rw.FileExists(goBin + "/" + "gobind.exe") {
|
||||
log.Fatal("missing gomobile.exe installation")
|
||||
}
|
||||
} else {
|
||||
if !rw.FileExists(goBin + "/" + "gobind") {
|
||||
log.Fatal("missing gomobile installation")
|
||||
}
|
||||
}
|
||||
GoBinPath = goBin
|
||||
}
|
||||
|
||||
@@ -108,6 +108,10 @@ func (c *ReadWaitConn) WaitReadBuffer() (buffer *buf.Buffer, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ReadWaitConn) Upstream() any {
|
||||
return c.STDConn
|
||||
}
|
||||
|
||||
//go:linkname tlsReadRecord crypto/tls.(*Conn).readRecord
|
||||
func tlsReadRecord(c *tls.STDConn) error
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ func (c *slowOpenConn) Write(b []byte) (n int, err error) {
|
||||
c.conn = nil
|
||||
c.err = E.Cause(err, "dial tcp fast open")
|
||||
}
|
||||
n = len(b)
|
||||
close(c.create)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ func writeDefaultRule(writer io.Writer, rule option.DefaultHeadlessRule) error {
|
||||
if len(rule.SourceIPCIDR) > 0 {
|
||||
err = writeRuleItemCIDR(writer, ruleItemSourceIPCIDR, rule.SourceIPCIDR)
|
||||
if err != nil {
|
||||
return E.Cause(err, "source_ipcidr")
|
||||
return E.Cause(err, "source_ip_cidr")
|
||||
}
|
||||
}
|
||||
if len(rule.IPCIDR) > 0 {
|
||||
|
||||
@@ -2,6 +2,22 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.8.5
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.4
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.2
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.1
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.8.0
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
@@ -322,17 +322,7 @@ flowchart TB
|
||||
"server": "google"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"geosite": "geolocation-!cn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"geosite": "cn",
|
||||
}
|
||||
],
|
||||
"geosite": "geolocation-cn",
|
||||
"server": "local"
|
||||
}
|
||||
]
|
||||
@@ -374,17 +364,7 @@ flowchart TB
|
||||
"server": "google"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-geolocation-!cn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"rule_set": "geosite-cn",
|
||||
}
|
||||
],
|
||||
"rule_set": "geosite-geolocation-cn",
|
||||
"server": "local"
|
||||
}
|
||||
]
|
||||
@@ -393,15 +373,9 @@ flowchart TB
|
||||
"rule_set": [
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-cn",
|
||||
"tag": "geosite-geolocation-cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-cn.srs"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-geolocation-!cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -467,18 +441,7 @@ flowchart TB
|
||||
"outbound": "block"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"geosite": "geolocation-!cn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"geosite": "cn",
|
||||
"geoip": "cn"
|
||||
}
|
||||
],
|
||||
"geosite": "geolocation-cn",
|
||||
"outbound": "direct"
|
||||
}
|
||||
]
|
||||
@@ -545,19 +508,9 @@ flowchart TB
|
||||
"outbound": "block"
|
||||
},
|
||||
{
|
||||
"type": "logical",
|
||||
"mode": "and",
|
||||
"rules": [
|
||||
{
|
||||
"rule_set": "geosite-geolocation-!cn",
|
||||
"invert": true
|
||||
},
|
||||
{
|
||||
"rule_set": [
|
||||
"geoip-cn",
|
||||
"geosite-cn"
|
||||
]
|
||||
}
|
||||
"rule_set": [
|
||||
"geoip-cn",
|
||||
"geosite-geolocation-cn"
|
||||
],
|
||||
"outbound": "direct"
|
||||
}
|
||||
@@ -571,15 +524,9 @@ flowchart TB
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-cn",
|
||||
"tag": "geosite-geolocation-cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-cn.srs"
|
||||
},
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "geosite-geolocation-!cn",
|
||||
"format": "binary",
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
|
||||
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -93,13 +93,11 @@ func (s *CommandServer) listenUNIX() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "listen ", sockPath)
|
||||
}
|
||||
if sUserID > 0 {
|
||||
err = os.Chown(sockPath, sUserID, sGroupID)
|
||||
if err != nil {
|
||||
listener.Close()
|
||||
os.Remove(sockPath)
|
||||
return E.Cause(err, "chown")
|
||||
}
|
||||
err = os.Chown(sockPath, sUserID, sGroupID)
|
||||
if err != nil {
|
||||
listener.Close()
|
||||
os.Remove(sockPath)
|
||||
return E.Cause(err, "chown")
|
||||
}
|
||||
s.listener = listener
|
||||
go s.loopConnection(listener)
|
||||
|
||||
@@ -20,13 +20,11 @@ func RedirectStderr(path string) error {
|
||||
return err
|
||||
}
|
||||
if runtime.GOOS != "android" {
|
||||
if sUserID > 0 {
|
||||
err = outputFile.Chown(sUserID, sGroupID)
|
||||
if err != nil {
|
||||
outputFile.Close()
|
||||
os.Remove(outputFile.Name())
|
||||
return err
|
||||
}
|
||||
err = outputFile.Chown(sUserID, sGroupID)
|
||||
if err != nil {
|
||||
outputFile.Close()
|
||||
os.Remove(outputFile.Name())
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = unix.Dup2(int(outputFile.Fd()), int(os.Stderr.Fd()))
|
||||
|
||||
@@ -97,6 +97,17 @@ func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Eleme
|
||||
}
|
||||
|
||||
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32) {
|
||||
if interfaceName == "" || interfaceIndex32 == -1 {
|
||||
m.defaultInterfaceName = ""
|
||||
m.defaultInterfaceIndex = -1
|
||||
m.access.Lock()
|
||||
callbacks := m.callbacks.Array()
|
||||
m.access.Unlock()
|
||||
for _, callback := range callbacks {
|
||||
callback(tun.EventNoRoute)
|
||||
}
|
||||
return
|
||||
}
|
||||
var err error
|
||||
if m.iif.UsePlatformInterfaceGetter() {
|
||||
err = m.updateInterfacesPlatform()
|
||||
@@ -110,28 +121,6 @@ func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName s
|
||||
m.logger.Error(E.Cause(err, "update interfaces"))
|
||||
}
|
||||
interfaceIndex := int(interfaceIndex32)
|
||||
if interfaceName == "" {
|
||||
for _, netIf := range m.networkAddresses {
|
||||
if netIf.interfaceIndex == interfaceIndex {
|
||||
interfaceName = netIf.interfaceName
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if interfaceIndex == -1 {
|
||||
for _, netIf := range m.networkAddresses {
|
||||
if netIf.interfaceName == interfaceName {
|
||||
interfaceIndex = netIf.interfaceIndex
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if interfaceName == "" {
|
||||
m.logger.Error(E.New("invalid interface name for ", interfaceIndex))
|
||||
return
|
||||
} else if interfaceIndex == -1 {
|
||||
m.logger.Error(E.New("invalid interface index for ", interfaceName))
|
||||
return
|
||||
}
|
||||
if m.defaultInterfaceName == interfaceName && m.defaultInterfaceIndex == interfaceIndex {
|
||||
return
|
||||
}
|
||||
|
||||
32
experimental/libbox/service_error.go
Normal file
32
experimental/libbox/service_error.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func serviceErrorPath() string {
|
||||
return filepath.Join(sWorkingPath, "network_extension_error")
|
||||
}
|
||||
|
||||
func ClearServiceError() {
|
||||
os.Remove(serviceErrorPath())
|
||||
}
|
||||
|
||||
func ReadServiceError() (string, error) {
|
||||
data, err := os.ReadFile(serviceErrorPath())
|
||||
if err == nil {
|
||||
os.Remove(serviceErrorPath())
|
||||
}
|
||||
return string(data), err
|
||||
}
|
||||
|
||||
func WriteServiceError(message string) error {
|
||||
errorFile, err := os.Create(serviceErrorPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errorFile.WriteString(message)
|
||||
errorFile.Chown(sUserID, sGroupID)
|
||||
return errorFile.Close()
|
||||
}
|
||||
@@ -25,6 +25,8 @@ func Setup(basePath string, workingPath string, tempPath string, isTVOS bool) {
|
||||
sUserID = os.Getuid()
|
||||
sGroupID = os.Getgid()
|
||||
sTVOS = isTVOS
|
||||
os.MkdirAll(sWorkingPath, 0o777)
|
||||
os.MkdirAll(sTempPath, 0o777)
|
||||
}
|
||||
|
||||
func SetupWithUsername(basePath string, workingPath string, tempPath string, username string) error {
|
||||
@@ -37,6 +39,10 @@ func SetupWithUsername(basePath string, workingPath string, tempPath string, use
|
||||
}
|
||||
sUserID, _ = strconv.Atoi(sUser.Uid)
|
||||
sGroupID, _ = strconv.Atoi(sUser.Gid)
|
||||
os.MkdirAll(sWorkingPath, 0o777)
|
||||
os.MkdirAll(sTempPath, 0o777)
|
||||
os.Chown(sWorkingPath, sUserID, sGroupID)
|
||||
os.Chown(sTempPath, sUserID, sGroupID)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
26
go.mod
26
go.mod
@@ -5,7 +5,7 @@ go 1.20
|
||||
require (
|
||||
berty.tech/go-libtor v1.0.385
|
||||
github.com/caddyserver/certmagic v0.20.0
|
||||
github.com/cloudflare/circl v1.3.6
|
||||
github.com/cloudflare/circl v1.3.7
|
||||
github.com/cretz/bine v0.2.0
|
||||
github.com/fsnotify/fsnotify v1.7.0
|
||||
github.com/go-chi/chi/v5 v5.0.11
|
||||
@@ -17,23 +17,23 @@ require (
|
||||
github.com/libdns/cloudflare v0.1.0
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/mholt/acmez v1.2.0
|
||||
github.com/miekg/dns v1.1.57
|
||||
github.com/miekg/dns v1.1.58
|
||||
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.1
|
||||
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e
|
||||
github.com/sagernet/quic-go v0.40.1-beta.2
|
||||
github.com/sagernet/quic-go v0.40.1
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||
github.com/sagernet/sing v0.3.0-rc.7
|
||||
github.com/sagernet/sing v0.3.0
|
||||
github.com/sagernet/sing-dns v0.1.12
|
||||
github.com/sagernet/sing-mux v0.1.8-rc.1
|
||||
github.com/sagernet/sing-quic v0.1.7-rc.2
|
||||
github.com/sagernet/sing-mux v0.2.0
|
||||
github.com/sagernet/sing-quic v0.1.8
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.6-rc.1
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||
github.com/sagernet/sing-shadowtls v0.1.4
|
||||
github.com/sagernet/sing-tun v0.2.0-rc.1
|
||||
github.com/sagernet/sing-tun v0.2.1
|
||||
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.8.4
|
||||
go.uber.org/zap v1.26.0
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||
golang.org/x/crypto v0.17.0
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/sys v0.15.0
|
||||
golang.org/x/crypto v0.18.0
|
||||
golang.org/x/net v0.20.0
|
||||
golang.org/x/sys v0.16.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
google.golang.org/grpc v1.60.1
|
||||
google.golang.org/protobuf v1.32.0
|
||||
@@ -86,11 +86,11 @@ 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-20231226003508-02704c960a9b // indirect
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
golang.org/x/tools v0.17.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
56
go.sum
56
go.sum
@@ -6,8 +6,8 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sx
|
||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/caddyserver/certmagic v0.20.0 h1:bTw7LcEZAh9ucYCRXyCpIrSAGplplI0vGYJ4BpCQ/Fc=
|
||||
github.com/caddyserver/certmagic v0.20.0/go.mod h1:N4sXgpICQUskEWpj7zVzvWD41p3NYacrNoZYiRM2jTg=
|
||||
github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg=
|
||||
github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
@@ -74,8 +74,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.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||
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/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=
|
||||
@@ -104,27 +104,27 @@ github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e h1:DOkjByVeAR56dks
|
||||
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e/go.mod h1:fLxq/gtp0qzkaEwywlRRiGmjOK5ES/xUzyIKIFP2Asw=
|
||||
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.40.1-beta.2 h1:USRwm36XuAFdcrmv4vDRD+YUOO08DfvLNruXThrVHZU=
|
||||
github.com/sagernet/quic-go v0.40.1-beta.2/go.mod h1:CcKTpzTAISxrM4PA5M20/wYuz9Tj6Tx4DwGbNl9UQrU=
|
||||
github.com/sagernet/quic-go v0.40.1 h1:qLeTIJR0d0JWRmDWo346nLsVN6EWihd1kalJYPEd0TM=
|
||||
github.com/sagernet/quic-go v0.40.1/go.mod h1:CcKTpzTAISxrM4PA5M20/wYuz9Tj6Tx4DwGbNl9UQrU=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing v0.3.0-rc.7 h1:FmnzFRYC6usVgWf112cUxiexwvL+iAurKmCL4Axa9+A=
|
||||
github.com/sagernet/sing v0.3.0-rc.7/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
|
||||
github.com/sagernet/sing v0.3.0 h1:PIDVFZHnQAAYRL1UYqNM+0k5s8f/tb1lUW6UDcQiOc8=
|
||||
github.com/sagernet/sing v0.3.0/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
|
||||
github.com/sagernet/sing-dns v0.1.12 h1:1HqZ+ln+Rezx/aJMStaS0d7oPeX2EobSV1NT537kyj4=
|
||||
github.com/sagernet/sing-dns v0.1.12/go.mod h1:rx/DTOisneQpCgNQ4jbFU/JNEtnz0lYcHXenlVzpjEU=
|
||||
github.com/sagernet/sing-mux v0.1.8-rc.1 h1:5dsZgWmNr9W6JzQj4fb3xX2pMP0OyJH6kVtlqc2kFKA=
|
||||
github.com/sagernet/sing-mux v0.1.8-rc.1/go.mod h1:KK5zCbNujj5kn36G+wLFROOXyJhaaXLyaZWY2w7kBNQ=
|
||||
github.com/sagernet/sing-quic v0.1.7-rc.2 h1:rCWhtvzQwgkWbX4sVHYdNwzyPweoUPEgBCBatywHjMs=
|
||||
github.com/sagernet/sing-quic v0.1.7-rc.2/go.mod h1:IbKCPWXP13zd3cdu0rirtYjkMlquc5zWtc3avfSUGAw=
|
||||
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.8 h1:G4iBXAKIII+uTzd55oZ/9cAQswGjlvHh/0yKMQioDS0=
|
||||
github.com/sagernet/sing-quic v0.1.8/go.mod h1:2w7DZXtf4MPjIGpovA3+vpI6bvOf1n1f9cQ1E2qQJSg=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.6-rc.1 h1:E+8OyyVg0YfFNUmxMx9jYBEhjLYMQSAMzJrUmE934bo=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.1.6-rc.1/go.mod h1:wFkU7sKxyZADS/idtJqBhtc+QBf5iwX9nZO7ymcn6MM=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.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.0-rc.1 h1:CnlxRgrJKAMKYNuJOcKie6TjRz8wremEq1wndLup7cA=
|
||||
github.com/sagernet/sing-tun v0.2.0-rc.1/go.mod h1:hpbL9jNAbYT9G2EHCpCXVIgSrM/2Wgnrm/Hped+8zdY=
|
||||
github.com/sagernet/sing-tun v0.2.1 h1:xZ/MkQbAX4yuOXq/s1pfhWa0lK1Ld7t4gOpSUbRl1Rs=
|
||||
github.com/sagernet/sing-tun v0.2.1/go.mod h1:w1HTPPEL575m+Ob3GOIWaTs3ZrTdgLIwoldce/p3WPU=
|
||||
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=
|
||||
@@ -168,17 +168,17 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4=
|
||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
|
||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
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=
|
||||
@@ -188,10 +188,10 @@ 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.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.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.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||
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=
|
||||
@@ -199,8 +199,8 @@ golang.org/x/text v0.14.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.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
|
||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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=
|
||||
|
||||
@@ -11,12 +11,14 @@ theme:
|
||||
logo: assets/icon.svg
|
||||
favicon: assets/icon.svg
|
||||
palette:
|
||||
- scheme: default
|
||||
- media: "(prefers-color-scheme: light)"
|
||||
scheme: default
|
||||
primary: white
|
||||
toggle:
|
||||
icon: material/brightness-7
|
||||
name: Switch to dark mode
|
||||
- scheme: slate
|
||||
- media: "(prefers-color-scheme: dark)"
|
||||
scheme: slate
|
||||
primary: black
|
||||
toggle:
|
||||
icon: material/brightness-4
|
||||
|
||||
@@ -30,6 +30,7 @@ type Direct struct {
|
||||
fallbackDelay time.Duration
|
||||
overrideOption int
|
||||
overrideDestination M.Socksaddr
|
||||
loopBack *loopBackDetector
|
||||
}
|
||||
|
||||
func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (*Direct, error) {
|
||||
@@ -50,6 +51,7 @@ func NewDirect(router adapter.Router, logger log.ContextLogger, tag string, opti
|
||||
domainStrategy: dns.DomainStrategy(options.DomainStrategy),
|
||||
fallbackDelay: time.Duration(options.FallbackDelay),
|
||||
dialer: outboundDialer,
|
||||
loopBack: newLoopBackDetector(),
|
||||
}
|
||||
if options.ProxyProtocol != 0 {
|
||||
return nil, E.New("Proxy Protocol is deprecated and removed in sing-box 1.6.0")
|
||||
@@ -88,7 +90,11 @@ func (h *Direct) DialContext(ctx context.Context, network string, destination M.
|
||||
case N.NetworkUDP:
|
||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
}
|
||||
return h.dialer.DialContext(ctx, network, destination)
|
||||
conn, err := h.dialer.DialContext(ctx, network, destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.loopBack.NewConn(conn), nil
|
||||
}
|
||||
|
||||
func (h *Direct) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
|
||||
@@ -142,6 +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))
|
||||
if originDestination != destination {
|
||||
conn = bufio.NewNATPacketConn(bufio.NewPacketConn(conn), destination, originDestination)
|
||||
}
|
||||
@@ -149,9 +156,15 @@ func (h *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net
|
||||
}
|
||||
|
||||
func (h *Direct) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
if h.loopBack.CheckConn(metadata.Source.AddrPort()) {
|
||||
return E.New("reject loopback connection to ", metadata.Destination)
|
||||
}
|
||||
return NewConnection(ctx, h, conn, metadata)
|
||||
}
|
||||
|
||||
func (h *Direct) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
if h.loopBack.CheckPacketConn(metadata.Source.AddrPort()) {
|
||||
return E.New("reject loopback packet connection to ", metadata.Destination)
|
||||
}
|
||||
return NewPacketConnection(ctx, h, conn, metadata)
|
||||
}
|
||||
|
||||
154
outbound/direct_loopback_detect.go
Normal file
154
outbound/direct_loopback_detect.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package outbound
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
type loopBackDetector struct {
|
||||
connAccess sync.RWMutex
|
||||
packetConnAccess sync.RWMutex
|
||||
connMap map[netip.AddrPort]bool
|
||||
packetConnMap map[netip.AddrPort]bool
|
||||
}
|
||||
|
||||
func newLoopBackDetector() *loopBackDetector {
|
||||
return &loopBackDetector{
|
||||
connMap: make(map[netip.AddrPort]bool),
|
||||
packetConnMap: make(map[netip.AddrPort]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *loopBackDetector) NewConn(conn net.Conn) net.Conn {
|
||||
connAddr := M.AddrPortFromNet(conn.LocalAddr())
|
||||
if !connAddr.IsValid() {
|
||||
return conn
|
||||
}
|
||||
if udpConn, isUDPConn := conn.(abstractUDPConn); isUDPConn {
|
||||
l.packetConnAccess.Lock()
|
||||
l.packetConnMap[connAddr] = true
|
||||
l.packetConnAccess.Unlock()
|
||||
return &loopBackDetectUDPWrapper{abstractUDPConn: udpConn, detector: l, connAddr: connAddr}
|
||||
} else {
|
||||
l.connAccess.Lock()
|
||||
l.connMap[connAddr] = true
|
||||
l.connAccess.Unlock()
|
||||
return &loopBackDetectWrapper{Conn: conn, detector: l, connAddr: connAddr}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *loopBackDetector) NewPacketConn(conn N.NetPacketConn) N.NetPacketConn {
|
||||
connAddr := M.AddrPortFromNet(conn.LocalAddr())
|
||||
if !connAddr.IsValid() {
|
||||
return conn
|
||||
}
|
||||
l.packetConnAccess.Lock()
|
||||
l.packetConnMap[connAddr] = true
|
||||
l.packetConnAccess.Unlock()
|
||||
return &loopBackDetectPacketWrapper{NetPacketConn: conn, detector: l, connAddr: connAddr}
|
||||
}
|
||||
|
||||
func (l *loopBackDetector) CheckConn(connAddr netip.AddrPort) bool {
|
||||
l.connAccess.RLock()
|
||||
defer l.connAccess.RUnlock()
|
||||
return l.connMap[connAddr]
|
||||
}
|
||||
|
||||
func (l *loopBackDetector) CheckPacketConn(connAddr netip.AddrPort) bool {
|
||||
l.packetConnAccess.RLock()
|
||||
defer l.packetConnAccess.RUnlock()
|
||||
return l.packetConnMap[connAddr]
|
||||
}
|
||||
|
||||
type loopBackDetectWrapper struct {
|
||||
net.Conn
|
||||
detector *loopBackDetector
|
||||
connAddr netip.AddrPort
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func (w *loopBackDetectWrapper) Close() error {
|
||||
w.closeOnce.Do(func() {
|
||||
w.detector.connAccess.Lock()
|
||||
delete(w.detector.connMap, w.connAddr)
|
||||
w.detector.connAccess.Unlock()
|
||||
})
|
||||
return w.Conn.Close()
|
||||
}
|
||||
|
||||
func (w *loopBackDetectWrapper) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *loopBackDetectWrapper) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *loopBackDetectWrapper) Upstream() any {
|
||||
return w.Conn
|
||||
}
|
||||
|
||||
type loopBackDetectPacketWrapper struct {
|
||||
N.NetPacketConn
|
||||
detector *loopBackDetector
|
||||
connAddr netip.AddrPort
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func (w *loopBackDetectPacketWrapper) Close() error {
|
||||
w.closeOnce.Do(func() {
|
||||
w.detector.packetConnAccess.Lock()
|
||||
delete(w.detector.packetConnMap, w.connAddr)
|
||||
w.detector.packetConnAccess.Unlock()
|
||||
})
|
||||
return w.NetPacketConn.Close()
|
||||
}
|
||||
|
||||
func (w *loopBackDetectPacketWrapper) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *loopBackDetectPacketWrapper) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *loopBackDetectPacketWrapper) Upstream() any {
|
||||
return w.NetPacketConn
|
||||
}
|
||||
|
||||
type abstractUDPConn interface {
|
||||
net.Conn
|
||||
net.PacketConn
|
||||
}
|
||||
|
||||
type loopBackDetectUDPWrapper struct {
|
||||
abstractUDPConn
|
||||
detector *loopBackDetector
|
||||
connAddr netip.AddrPort
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
func (w *loopBackDetectUDPWrapper) Close() error {
|
||||
w.closeOnce.Do(func() {
|
||||
w.detector.packetConnAccess.Lock()
|
||||
delete(w.detector.packetConnMap, w.connAddr)
|
||||
w.detector.packetConnAccess.Unlock()
|
||||
})
|
||||
return w.abstractUDPConn.Close()
|
||||
}
|
||||
|
||||
func (w *loopBackDetectUDPWrapper) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *loopBackDetectUDPWrapper) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *loopBackDetectUDPWrapper) Upstream() any {
|
||||
return w.abstractUDPConn
|
||||
}
|
||||
@@ -241,7 +241,8 @@ func (d *DNS) newPacketConnection(ctx context.Context, conn N.PacketConn, readWa
|
||||
return err
|
||||
}
|
||||
timeout.Update()
|
||||
responseBuffer := buf.NewPacket()
|
||||
response = truncateDNSMessage(response, 512) // TODO: add an option to custom UDP buffer size
|
||||
responseBuffer := buf.NewSize(dns.FixedPacketSize)
|
||||
responseBuffer.Resize(1024, 0)
|
||||
n, err := response.PackBuffer(responseBuffer.FreeBytes())
|
||||
if err != nil {
|
||||
@@ -263,3 +264,21 @@ func (d *DNS) newPacketConnection(ctx context.Context, conn N.PacketConn, readWa
|
||||
})
|
||||
return group.Run(fastClose)
|
||||
}
|
||||
|
||||
func truncateDNSMessage(response *mDNS.Msg, maxLen int) *mDNS.Msg {
|
||||
responseLen := response.Len()
|
||||
if responseLen <= maxLen {
|
||||
return response
|
||||
}
|
||||
response = response.Copy()
|
||||
for len(response.Answer) > 0 && responseLen > maxLen {
|
||||
response.Answer = response.Answer[:len(response.Answer)-1]
|
||||
response.Truncated = true
|
||||
responseLen = response.Len()
|
||||
}
|
||||
if responseLen > maxLen {
|
||||
response.Ns = nil
|
||||
response.Extra = nil
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
@@ -125,7 +125,18 @@ func (s *URLTest) CheckOutbounds() {
|
||||
|
||||
func (s *URLTest) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
s.group.Touch()
|
||||
outbound := s.group.Select(network)
|
||||
var outbound adapter.Outbound
|
||||
switch N.NetworkName(network) {
|
||||
case N.NetworkTCP:
|
||||
outbound = s.group.selectedOutboundTCP
|
||||
case N.NetworkUDP:
|
||||
outbound = s.group.selectedOutboundUDP
|
||||
default:
|
||||
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
||||
}
|
||||
if outbound == nil {
|
||||
outbound, _ = s.group.Select(network)
|
||||
}
|
||||
if outbound == nil {
|
||||
return nil, E.New("missing supported outbound")
|
||||
}
|
||||
@@ -140,7 +151,10 @@ func (s *URLTest) DialContext(ctx context.Context, network string, destination M
|
||||
|
||||
func (s *URLTest) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
s.group.Touch()
|
||||
outbound := s.group.Select(N.NetworkUDP)
|
||||
outbound := s.group.selectedOutboundUDP
|
||||
if outbound == nil {
|
||||
outbound, _ = s.group.Select(N.NetworkUDP)
|
||||
}
|
||||
if outbound == nil {
|
||||
return nil, E.New("missing supported outbound")
|
||||
}
|
||||
@@ -271,7 +285,7 @@ func (g *URLTestGroup) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) Select(network string) adapter.Outbound {
|
||||
func (g *URLTestGroup) Select(network string) (adapter.Outbound, bool) {
|
||||
var minDelay uint16
|
||||
var minTime time.Time
|
||||
var minOutbound adapter.Outbound
|
||||
@@ -294,11 +308,11 @@ func (g *URLTestGroup) Select(network string) adapter.Outbound {
|
||||
if !common.Contains(detour.Network(), network) {
|
||||
continue
|
||||
}
|
||||
minOutbound = detour
|
||||
break
|
||||
return detour, false
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
return minOutbound
|
||||
return minOutbound, true
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) loopCheck() {
|
||||
@@ -382,14 +396,12 @@ func (g *URLTestGroup) urlTest(ctx context.Context, force bool) (map[string]uint
|
||||
}
|
||||
|
||||
func (g *URLTestGroup) performUpdateCheck() {
|
||||
outbound := g.Select(N.NetworkTCP)
|
||||
var updated bool
|
||||
if outbound != nil && outbound != g.selectedOutboundTCP {
|
||||
if outbound, exists := g.Select(N.NetworkTCP); outbound != nil && (g.selectedOutboundTCP == nil || (exists && outbound != g.selectedOutboundTCP)) {
|
||||
g.selectedOutboundTCP = outbound
|
||||
updated = true
|
||||
}
|
||||
outbound = g.Select(N.NetworkUDP)
|
||||
if outbound != nil && outbound != g.selectedOutboundUDP {
|
||||
if outbound, exists := g.Select(N.NetworkUDP); outbound != nil && (g.selectedOutboundUDP == nil || (exists && outbound != g.selectedOutboundUDP)) {
|
||||
g.selectedOutboundUDP = outbound
|
||||
updated = true
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[Unit]
|
||||
Description=sing-box service
|
||||
Documentation=https://sing-box.sagernet.org
|
||||
After=network.target nss-lookup.target
|
||||
After=network.target nss-lookup.target network-online.target
|
||||
|
||||
[Service]
|
||||
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[Unit]
|
||||
Description=sing-box service
|
||||
Documentation=https://sing-box.sagernet.org
|
||||
After=network.target nss-lookup.target
|
||||
After=network.target nss-lookup.target network-online.target
|
||||
|
||||
[Service]
|
||||
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[Unit]
|
||||
Description=sing-box service
|
||||
Documentation=https://sing-box.sagernet.org
|
||||
After=network.target nss-lookup.target
|
||||
After=network.target nss-lookup.target network-online.target
|
||||
|
||||
[Service]
|
||||
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_SYS_PTRACE CAP_DAC_READ_SEARCH
|
||||
|
||||
@@ -72,7 +72,7 @@ func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool {
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.sourcePortItems) > 0 && !metadata.SourceAddressMatch {
|
||||
if len(r.sourcePortItems) > 0 && !metadata.SourcePortMatch {
|
||||
for _, item := range r.sourcePortItems {
|
||||
if item.Match(metadata) {
|
||||
metadata.SourcePortMatch = true
|
||||
@@ -81,7 +81,7 @@ func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool {
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.destinationAddressItems) > 0 && !metadata.SourceAddressMatch {
|
||||
if len(r.destinationAddressItems) > 0 && !metadata.DestinationAddressMatch {
|
||||
for _, item := range r.destinationAddressItems {
|
||||
if item.Match(metadata) {
|
||||
metadata.DestinationAddressMatch = true
|
||||
@@ -90,7 +90,7 @@ func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool {
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.destinationPortItems) > 0 && !metadata.SourceAddressMatch {
|
||||
if len(r.destinationPortItems) > 0 && !metadata.DestinationPortMatch {
|
||||
for _, item := range r.destinationPortItems {
|
||||
if item.Match(metadata) {
|
||||
metadata.DestinationPortMatch = true
|
||||
|
||||
@@ -115,7 +115,7 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt
|
||||
if len(options.SourceIPCIDR) > 0 {
|
||||
item, err := NewIPCIDRItem(true, options.SourceIPCIDR)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "source_ipcidr")
|
||||
return nil, E.Cause(err, "source_ip_cidr")
|
||||
}
|
||||
rule.sourceAddressItems = append(rule.sourceAddressItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
|
||||
@@ -114,7 +114,7 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
|
||||
if len(options.SourceIPCIDR) > 0 {
|
||||
item, err := NewIPCIDRItem(true, options.SourceIPCIDR)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "source_ipcidr")
|
||||
return nil, E.Cause(err, "source_ip_cidr")
|
||||
}
|
||||
rule.sourceAddressItems = append(rule.sourceAddressItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
|
||||
@@ -66,7 +66,7 @@ func NewDefaultHeadlessRule(router adapter.Router, options option.DefaultHeadles
|
||||
if len(options.SourceIPCIDR) > 0 {
|
||||
item, err := NewIPCIDRItem(true, options.SourceIPCIDR)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "source_ipcidr")
|
||||
return nil, E.Cause(err, "source_ip_cidr")
|
||||
}
|
||||
rule.sourceAddressItems = append(rule.sourceAddressItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
|
||||
@@ -35,9 +35,9 @@ func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
|
||||
}
|
||||
var description string
|
||||
if isSource {
|
||||
description = "source_ipcidr="
|
||||
description = "source_ip_cidr="
|
||||
} else {
|
||||
description = "ipcidr="
|
||||
description = "ip_cidr="
|
||||
}
|
||||
if dLen := len(prefixStrings); dLen == 1 {
|
||||
description += prefixStrings[0]
|
||||
@@ -60,9 +60,9 @@ func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
|
||||
func NewRawIPCIDRItem(isSource bool, ipSet *netipx.IPSet) *IPCIDRItem {
|
||||
var description string
|
||||
if isSource {
|
||||
description = "source_ipcidr="
|
||||
description = "source_ip_cidr="
|
||||
} else {
|
||||
description = "ipcidr="
|
||||
description = "ip_cidr="
|
||||
}
|
||||
description += "<binary>"
|
||||
return &IPCIDRItem{
|
||||
|
||||
@@ -30,11 +30,11 @@ func NewDomainItem(domains []string, domainSuffixes []string) *DomainItem {
|
||||
description += " "
|
||||
}
|
||||
if dsLen == 1 {
|
||||
description += "domainSuffix=" + domainSuffixes[0]
|
||||
description += "domain_suffix=" + domainSuffixes[0]
|
||||
} else if dsLen > 3 {
|
||||
description += "domainSuffix=[" + strings.Join(domainSuffixes[:3], " ") + "...]"
|
||||
description += "domain_suffix=[" + strings.Join(domainSuffixes[:3], " ") + "...]"
|
||||
} else {
|
||||
description += "domainSuffix=[" + strings.Join(domainSuffixes, " ") + "]"
|
||||
description += "domain_suffix=[" + strings.Join(domainSuffixes, " ") + "]"
|
||||
}
|
||||
}
|
||||
return &DomainItem{
|
||||
|
||||
@@ -24,7 +24,7 @@ var tlsRegistry []func(conn net.Conn) (loaded bool, netConn net.Conn, reflectTyp
|
||||
|
||||
func init() {
|
||||
tlsRegistry = append(tlsRegistry, func(conn net.Conn) (loaded bool, netConn net.Conn, reflectType reflect.Type, reflectPointer uintptr) {
|
||||
tlsConn, loaded := conn.(*tls.Conn)
|
||||
tlsConn, loaded := common.Cast[*tls.Conn](conn)
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user