Compare commits

..

30 Commits

Author SHA1 Message Date
世界
d32c30c4b7 documentation: Bump version 2024-02-24 13:20:43 +08:00
世界
4823023806 Remove invalid archlinux packages from release 2024-02-24 13:20:43 +08:00
Aleksandr Razumov
bb355d17b2 Add riscv64 to platform list in release 2024-02-24 13:20:43 +08:00
hiddify
aaf30bf92b platform: Fix group update interval not taking effect 2024-02-24 13:20:43 +08:00
hiddify
f8c400cffc platform: Remove duplicated close 2024-02-24 13:20:43 +08:00
hatune-miku
3c24411e14 documentation: Fix navigation menu 2024-02-24 13:20:42 +08:00
世界
4a44aa3c21 Fix HTTP inbound 2024-02-24 13:20:42 +08:00
世界
8db2ae0c83 Fix documentation 2024-02-24 13:20:42 +08:00
世界
80d1aebcb7 platform: Unify client versions 2024-02-24 13:20:27 +08:00
世界
5583e01c99 platform: Export NeedWIFIState for Android 2024-02-18 14:24:21 +08:00
世界
bca0b86549 Copy DNS message struct instead of deep copy 2024-02-10 23:49:09 +08:00
世界
8332878cdc Fix destination IP CIDR match in DNS 2024-02-10 22:37:42 +08:00
世界
d0ba69ad22 Fix TUN unaligned panic on windows 2024-02-10 21:22:02 +08:00
世界
31b8834427 documentation: Fix description for with_ech 2024-02-10 12:01:09 +08:00
renovate[bot]
d0f7a59e9b [dependencies] Update golang Docker tag to v1.22 2024-02-10 11:54:40 +08:00
renovate[bot]
71e7d517a8 [dependencies] Update github-actions 2024-02-10 11:54:31 +08:00
世界
e6885e9967 platform: Ignore momentary pause on iOS 2024-02-09 13:57:47 +08:00
世界
e2090923db Bump Go version 2024-02-08 20:31:40 +08:00
世界
46be319976 Fix external controller crash before started 2024-02-08 20:31:40 +08:00
renovate[bot]
b27bc45cf2 [dependencies] Update actions/cache action to v4 2024-02-03 15:08:41 +08:00
世界
3d735281f4 documentation: Bump version 2024-02-02 17:51:40 +08:00
世界
8760a0d94d Fix android interface monitor 2024-02-02 17:51:40 +08:00
世界
2239b59933 Remove duplicated rules 2024-02-02 14:30:27 +08:00
世界
425a63f59d Fix rawConn not closed for hy/hy2 2024-02-02 14:30:27 +08:00
世界
b85725c009 urltest: Remember the last choice when there is no valid result 2024-02-02 11:27:36 +08:00
世界
17aebc56c1 Fix UDP DNS response not truncated 2024-02-01 14:43:59 +08:00
Devman
f76b21b02c Fix mobile build on windows
gobind executable name is not exactly `gobind` on windows it's `gobind.exe`

Signed-off-by: Devman <85770917+amir-devman@users.noreply.github.com>
2024-02-01 12:07:39 +08:00
kkocdko
704545a2ec Fix rule description header of domain_suffix
I read other rule_item_xxx.go files, they are all snake case. This description is showed on dashboard like yacd.

Signed-off-by: kkocdko <31189892+kkocdko@users.noreply.github.com>
2024-02-01 10:42:12 +08:00
dyhkwong
dc7b7afc06 Fix loop back detector 2024-02-01 10:41:38 +08:00
世界
e478d3c2dc Update workflow 2024-01-24 12:21:18 +08:00
35 changed files with 288 additions and 157 deletions

14
.github/update_clients.sh vendored Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
PROJECTS=$(dirname "$0")/../..
function updateClient() {
pushd clients/$1
git fetch
git reset FETCH_HEAD --hard
popd
git add clients/$1
}
updateClient "apple"
updateClient "android"

View File

@@ -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.22
continue-on-error: true
- name: Run Test
run: |
@@ -56,9 +44,9 @@ 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
uses: actions/cache@v4
with:
path: |
~/go/pkg/mod
@@ -76,13 +64,33 @@ 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
uses: actions/cache@v4
with:
path: |
~/go/pkg/mod
key: go118-${{ hashFiles('**/go.sum') }}
key: go120-${{ hashFiles('**/go.sum') }}
- name: Run Test
run: make ci_build_go120
build_go121:
name: Debug build (Go 1.21)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.21
- name: Cache go module
uses: actions/cache@v4
with:
path: |
~/go/pkg/mod
key: go121-${{ hashFiles('**/go.sum') }}
- name: Run Test
run: make ci_build
cross:
@@ -188,8 +196,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 +211,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

View File

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

View File

@@ -25,16 +25,16 @@ 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: ^1.22
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ steps.version.outputs.go_version }}
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v4
with:
version: latest
args: --timeout=30m

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "clients/apple"]
path = clients/apple
url = https://github.com/SagerNet/sing-box-for-apple.git
[submodule "clients/android"]
path = clients/android
url = https://github.com/SagerNet/sing-box-for-android.git

View File

@@ -30,6 +30,7 @@ builds:
- linux_arm64
- linux_arm_7
- linux_s390x
- linux_riscv64
- windows_amd64_v1
- windows_amd64_v3
- windows_386
@@ -54,7 +55,6 @@ builds:
- with_quic
- with_dhcp
- with_wireguard
- with_ech
- with_utls
- with_reality_server
- with_acme

View File

@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder
FROM --platform=$BUILDPLATFORM golang:1.22-alpine AS builder
LABEL maintainer="nekohasekai <contact-git@sekai.icu>"
COPY . /go/src/github.com/sagernet/sing-box
WORKDIR /go/src/github.com/sagernet/sing-box

View File

@@ -1,8 +1,9 @@
NAME = sing-box
COMMIT = $(shell git rev-parse --short HEAD)
TAGS_GO118 = with_gvisor,with_dhcp,with_wireguard,with_reality_server,with_clash_api
TAGS_GO120 = with_quic,with_ech,with_utls
TAGS ?= $(TAGS_GO118),$(TAGS_GO120)
TAGS_GO120 = with_quic,with_utls
TAGS_GO121 = with_ech
TAGS ?= $(TAGS_GO118),$(TAGS_GO120),$(TAGS_GO121)
TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_reality_server
GOHOSTOS = $(shell go env GOHOSTOS)
@@ -23,6 +24,10 @@ ci_build_go118:
go build $(PARAMS) $(MAIN)
go build $(PARAMS) -tags "$(TAGS_GO118)" $(MAIN)
ci_build_go120:
go build $(PARAMS) $(MAIN)
go build $(PARAMS) -tags "$(TAGS_GO118),$(TAGS_GO120)" $(MAIN)
ci_build:
go build $(PARAMS) $(MAIN)
go build $(MAIN_PARAMS) $(MAIN)
@@ -61,7 +66,14 @@ proto_install:
release:
go run ./cmd/internal/build goreleaser release --clean --skip-publish || exit 1
mkdir dist/release
mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/*.pkg.tar.zst dist/release
mv dist/*.tar.gz \
dist/*.zip \
dist/*.deb \
dist/*.rpm \
dist/*_amd64.pkg.tar.zst \
dist/*_amd64v3.pkg.tar.zst \
dist/*_arm64.pkg.tar.zst \
dist/release
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release
rm -r dist/release
@@ -73,11 +85,12 @@ update_android_version:
go run ./cmd/internal/update_android_version
build_android:
cd ../sing-box-for-android && ./gradlew :app:assemblePlayRelease && ./gradlew --stop
cd ../sing-box-for-android && ./gradlew :app:assemblePlayRelease && ./gradlew :app:assembleOtherRelease && ./gradlew --stop
upload_android:
mkdir -p dist/release_android
cp ../sing-box-for-android/app/build/outputs/apk/play/release/*.apk dist/release_android
cp ../sing-box-for-android/app/build/outputs/apk/other/release/*-universal.apk dist/release_android
ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release_android
rm -rf dist/release_android

View File

@@ -33,6 +33,8 @@ type Router interface {
RuleSet(tag string) (RuleSet, bool)
NeedWIFIState() bool
Exchange(ctx context.Context, message *mdns.Msg) (*mdns.Msg, error)
Lookup(ctx context.Context, domain string, strategy dns.DomainStrategy) ([]netip.Addr, error)
LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)

1
clients/android Submodule

Submodule clients/android added at 3b9d24a0bb

1
clients/apple Submodule

Submodule clients/apple added at 60f96985a3

View File

@@ -11,7 +11,9 @@ import (
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/rw"
"github.com/sagernet/sing/common/shell"
)
var (
@@ -40,6 +42,14 @@ func FindSDK() {
log.Fatal("android NDK not found")
}
javaVersion, err := shell.Exec("java", "--version").ReadOutput()
if err != nil {
log.Fatal(E.Cause(err, "check java version"))
}
if !strings.Contains(javaVersion, "openjdk 17") {
log.Fatal("java version should be openjdk 17")
}
os.Setenv("ANDROID_HOME", androidSDKPath)
os.Setenv("ANDROID_SDK_HOME", androidSDKPath)
os.Setenv("ANDROID_NDK_HOME", androidNDKPath)
@@ -85,8 +95,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
}

View File

@@ -3,6 +3,7 @@ package main
import (
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
@@ -18,34 +19,46 @@ func main() {
log.Fatal(err)
}
common.Must(os.Chdir(androidPath))
localProps := common.Must1(os.ReadFile("local.properties"))
localProps := common.Must1(os.ReadFile("version.properties"))
var propsList [][]string
for _, propLine := range strings.Split(string(localProps), "\n") {
propsList = append(propsList, strings.Split(propLine, "="))
}
var (
versionUpdated bool
goVersionUpdated bool
)
for _, propPair := range propsList {
if propPair[0] == "VERSION_NAME" {
if propPair[1] == newVersion.String() {
log.Info("version not changed")
return
switch propPair[0] {
case "VERSION_NAME":
if propPair[1] != newVersion.String() {
versionUpdated = true
propPair[1] = newVersion.String()
log.Info("updated version to ", newVersion.String())
}
case "GO_VERSION":
if propPair[1] != runtime.Version() {
goVersionUpdated = true
propPair[1] = runtime.Version()
log.Info("updated Go version to ", runtime.Version())
}
propPair[1] = newVersion.String()
log.Info("updated version to ", newVersion.String())
}
}
if !(versionUpdated || goVersionUpdated) {
log.Info("version not changed")
return
}
for _, propPair := range propsList {
switch propPair[0] {
case "VERSION_CODE":
versionCode := common.Must1(strconv.ParseInt(propPair[1], 10, 64))
propPair[1] = strconv.Itoa(int(versionCode + 1))
log.Info("updated version code to ", propPair[1])
case "RELEASE_NOTES":
propPair[1] = "sing-box " + newVersion.String()
}
}
var newProps []string
for _, propPair := range propsList {
newProps = append(newProps, strings.Join(propPair, "="))
}
common.Must(os.WriteFile("local.properties", []byte(strings.Join(newProps, "\n")), 0o644))
common.Must(os.WriteFile("version.properties", []byte(strings.Join(newProps, "\n")), 0o644))
}

View File

@@ -2,6 +2,14 @@
icon: material/alert-decagram
---
#### 1.8.6
* Fixes and improvements
#### 1.8.5
* Fixes and improvements
#### 1.8.4
* Fixes and improvements

View File

@@ -32,8 +32,6 @@ suffers from a number of problems, including lack of maintenance, inaccurate rul
sing-box 1.8.0 introduces [Rule Set](/configuration/rule-set/), which can completely replace Geosite,
check [Migration](/migration/#migrate-geosite-to-rule-sets).
Geosite即由 V2Ray 维护的 domain-list-community 项目,作为早期流量绕过解决方案,存在着大量问题,包括缺少维护、规则不准确、管理困难。
## 1.6.0
The following features will be marked deprecated in 1.5.0 and removed entirely in 1.6.0.

View File

@@ -23,7 +23,8 @@ Since sing-box 1.5.0:
Since sing-box 1.8.0:
* Go 1.18.5 - ~
* Go 1.20.0 - ~ with tag `with_quic`, `with_ech`, or `with_utls` enabled
* Go 1.20.0 - ~ with tag `with_quic`, or `with_utls` enabled
* Go 1.21.0 - ~ with tag `with_ech` enabled
You can download and install Go from: https://go.dev/doc/install, latest version is recommended.

View File

@@ -23,7 +23,8 @@ sing-box 1.4.0 前:
从 sing-box 1.8.0:
* Go 1.18.5 - ~
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic``with_ech``with_utls`
* Go 1.20.0 - ~ 如果启用构建标记 `with_quic``with_utls`
* Go 1.20.1 - ~ 如果启用构建标记 `with_ech`
您可以从 https://go.dev/doc/install 下载并安装 Go推荐使用最新版本。

View File

@@ -30,7 +30,6 @@ func (c *CommandClient) SetClashMode(newMode string) error {
}
func (s *CommandServer) handleSetClashMode(conn net.Conn) error {
defer conn.Close()
newMode, err := rw.ReadVString(conn)
if err != nil {
return err
@@ -61,7 +60,6 @@ func (c *CommandClient) handleModeConn(conn net.Conn) {
}
func (s *CommandServer) handleModeConn(conn net.Conn) error {
defer conn.Close()
ctx := connKeepAlive(conn)
for s.service == nil {
select {
@@ -73,7 +71,6 @@ func (s *CommandServer) handleModeConn(conn net.Conn) error {
}
clashServer := s.service.instance.Router().ClashServer()
if clashServer == nil {
defer conn.Close()
return binary.Write(conn, binary.BigEndian, uint16(0))
}
err := writeClashModeList(conn, clashServer)

View File

@@ -58,7 +58,13 @@ func (c *CommandClient) handleGroupConn(conn net.Conn) {
}
func (s *CommandServer) handleGroupConn(conn net.Conn) error {
defer conn.Close()
var interval int64
err := binary.Read(conn, binary.BigEndian, &interval)
if err != nil {
return E.Cause(err, "read interval")
}
ticker := time.NewTicker(time.Duration(interval))
defer ticker.Stop()
ctx := connKeepAlive(conn)
for {
service := s.service
@@ -76,7 +82,7 @@ func (s *CommandServer) handleGroupConn(conn net.Conn) error {
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(2 * time.Second):
case <-ticker.C:
}
select {
case <-ctx.Done():
@@ -274,7 +280,6 @@ func (c *CommandClient) SetGroupExpand(groupTag string, isExpand bool) error {
}
func (s *CommandServer) handleSetGroupExpand(conn net.Conn) error {
defer conn.Close()
groupTag, err := rw.ReadVString(conn)
if err != nil {
return err

View File

@@ -31,7 +31,6 @@ func (c *CommandClient) SelectOutbound(groupTag string, outboundTag string) erro
}
func (s *CommandServer) handleSelectOutbound(conn net.Conn) error {
defer conn.Close()
groupTag, err := rw.ReadVString(conn)
if err != nil {
return err

View File

@@ -35,7 +35,6 @@ func (c *CommandClient) GetSystemProxyStatus() (*SystemProxyStatus, error) {
}
func (s *CommandServer) handleGetSystemProxyStatus(conn net.Conn) error {
defer conn.Close()
status := s.handler.GetSystemProxyStatus()
err := binary.Write(conn, binary.BigEndian, status.Available)
if err != nil {
@@ -68,7 +67,6 @@ func (c *CommandClient) SetSystemProxyEnabled(isEnabled bool) error {
}
func (s *CommandServer) handleSetSystemProxyEnabled(conn net.Conn) error {
defer conn.Close()
var isEnabled bool
err := binary.Read(conn, binary.BigEndian, &isEnabled)
if err != nil {

View File

@@ -33,7 +33,6 @@ func (c *CommandClient) URLTest(groupTag string) error {
}
func (s *CommandServer) handleURLTest(conn net.Conn) error {
defer conn.Close()
groupTag, err := rw.ReadVString(conn)
if err != nil {
return err

View File

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

View File

@@ -32,6 +32,8 @@ type BoxService struct {
instance *box.Box
pauseManager pause.Manager
urlTestHistoryStorage *urltest.HistoryStorage
servicePauseFields
}
func NewService(configContent string, platformInterface PlatformInterface) (*BoxService, error) {
@@ -75,14 +77,8 @@ func (s *BoxService) Close() error {
return s.instance.Close()
}
func (s *BoxService) Sleep() {
s.pauseManager.DevicePause()
_ = s.instance.Router().ResetNetwork()
}
func (s *BoxService) Wake() {
s.pauseManager.DeviceWake()
_ = s.instance.Router().ResetNetwork()
func (s *BoxService) NeedWIFIState() bool {
return s.instance.Router().NeedWIFIState()
}
var (

View File

@@ -0,0 +1,45 @@
package libbox
import (
"sync"
"time"
)
type servicePauseFields struct {
pauseAccess sync.Mutex
pauseTimer *time.Timer
}
func (s *BoxService) Pause() {
s.pauseAccess.Lock()
defer s.pauseAccess.Unlock()
if s.pauseTimer != nil {
s.pauseTimer.Stop()
}
s.pauseTimer = time.AfterFunc(time.Minute, s.pause)
}
func (s *BoxService) pause() {
s.pauseAccess.Lock()
defer s.pauseAccess.Unlock()
s.pauseManager.DevicePause()
_ = s.instance.Router().ResetNetwork()
s.pauseTimer = nil
}
func (s *BoxService) Wake() {
s.pauseAccess.Lock()
defer s.pauseAccess.Unlock()
if s.pauseTimer != nil {
s.pauseTimer.Stop()
s.pauseTimer = nil
return
}
s.pauseManager.DeviceWake()
_ = s.instance.Router().ResetNetwork()
}

10
go.mod
View File

@@ -26,14 +26,14 @@ require (
github.com/sagernet/gvisor v0.0.0-20231209105102-8d27a30e436e
github.com/sagernet/quic-go v0.40.1
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.3.0
github.com/sagernet/sing v0.3.2
github.com/sagernet/sing-dns v0.1.12
github.com/sagernet/sing-mux v0.2.0
github.com/sagernet/sing-quic v0.1.7
github.com/sagernet/sing-quic v0.1.8
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.0
github.com/sagernet/sing-tun v0.2.2-beta.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
@@ -46,7 +46,7 @@ require (
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
golang.org/x/crypto v0.18.0
golang.org/x/net v0.20.0
golang.org/x/sys v0.16.0
golang.org/x/sys v0.17.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,7 +86,7 @@ require (
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // 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

20
go.sum
View File

@@ -109,22 +109,22 @@ github.com/sagernet/quic-go v0.40.1/go.mod h1:CcKTpzTAISxrM4PA5M20/wYuz9Tj6Tx4Dw
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 h1:PIDVFZHnQAAYRL1UYqNM+0k5s8f/tb1lUW6UDcQiOc8=
github.com/sagernet/sing v0.3.0/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g=
github.com/sagernet/sing v0.3.2 h1:CwWcxUBPkMvwgfe2/zUgY5oHG9qOL8Aob/evIFYK9jo=
github.com/sagernet/sing v0.3.2/go.mod h1:qHySJ7u8po9DABtMYEkNBcOumx7ZZJf/fbv2sfTkNHE=
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.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.7 h1:SC45rAnvQ9BuyO0V186OdDScMBitmZo0XcM9LBYRUW8=
github.com/sagernet/sing-quic v0.1.7/go.mod h1:wUg1Z6AGKeJguruZo0lhrie3dqPiRCKaidLAbK2ttEs=
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.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 h1:/WloeRTWvwKIuiIvY+HVJaaZsTGb3XqJXZUbn6wVhz4=
github.com/sagernet/sing-tun v0.2.0/go.mod h1:vJHzPAbwFUHxdFHUFQlH+Fb4rT3K4/SHODdMLU1rrQI=
github.com/sagernet/sing-tun v0.2.2-beta.1 h1:B/P2TbV4ORNyZbLad4V74ZVCkgcsZG7vYqugEmof/Gc=
github.com/sagernet/sing-tun v0.2.2-beta.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=
@@ -170,8 +170,8 @@ golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaE
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
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-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
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=
@@ -188,8 +188,8 @@ 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.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.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.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@@ -133,7 +133,6 @@ nav:
- WireGuard: configuration/outbound/wireguard.md
- Hysteria: configuration/outbound/hysteria.md
- ShadowTLS: configuration/outbound/shadowtls.md
- ShadowsocksR: configuration/outbound/shadowsocksr.md
- VLESS: configuration/outbound/vless.md
- TUIC: configuration/outbound/tuic.md
- Hysteria2: configuration/outbound/hysteria2.md
@@ -236,4 +235,4 @@ plugins:
Manual: 手册
reconfigure_material: true
reconfigure_search: true
reconfigure_search: true

View File

@@ -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(conn)
conn = h.loopBack.NewPacketConn(bufio.NewPacketConn(conn))
if originDestination != destination {
conn = bufio.NewNATPacketConn(bufio.NewPacketConn(conn), destination, originDestination)
}

View File

@@ -6,6 +6,7 @@ import (
"sync"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
type loopBackDetector struct {
@@ -40,7 +41,7 @@ func (l *loopBackDetector) NewConn(conn net.Conn) net.Conn {
}
}
func (l *loopBackDetector) NewPacketConn(conn net.PacketConn) net.PacketConn {
func (l *loopBackDetector) NewPacketConn(conn N.NetPacketConn) N.NetPacketConn {
connAddr := M.AddrPortFromNet(conn.LocalAddr())
if !connAddr.IsValid() {
return conn
@@ -48,7 +49,7 @@ func (l *loopBackDetector) NewPacketConn(conn net.PacketConn) net.PacketConn {
l.packetConnAccess.Lock()
l.packetConnMap[connAddr] = true
l.packetConnAccess.Unlock()
return &loopBackDetectPacketWrapper{PacketConn: conn, detector: l, connAddr: connAddr}
return &loopBackDetectPacketWrapper{NetPacketConn: conn, detector: l, connAddr: connAddr}
}
func (l *loopBackDetector) CheckConn(connAddr netip.AddrPort) bool {
@@ -92,7 +93,7 @@ func (w *loopBackDetectWrapper) Upstream() any {
}
type loopBackDetectPacketWrapper struct {
net.PacketConn
N.NetPacketConn
detector *loopBackDetector
connAddr netip.AddrPort
closeOnce sync.Once
@@ -104,7 +105,7 @@ func (w *loopBackDetectPacketWrapper) Close() error {
delete(w.detector.packetConnMap, w.connAddr)
w.detector.packetConnAccess.Unlock()
})
return w.PacketConn.Close()
return w.NetPacketConn.Close()
}
func (w *loopBackDetectPacketWrapper) ReaderReplaceable() bool {
@@ -116,7 +117,7 @@ func (w *loopBackDetectPacketWrapper) WriterReplaceable() bool {
}
func (w *loopBackDetectPacketWrapper) Upstream() any {
return w.PacketConn
return w.NetPacketConn
}
type abstractUDPConn interface {

View File

@@ -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,22 @@ 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
}
newResponse := *response
response = &newResponse
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
}

View File

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

View File

@@ -415,6 +415,9 @@ func (r *Router) Initialize(inbounds []adapter.Inbound, outbounds []adapter.Outb
}
func (r *Router) Outbounds() []adapter.Outbound {
if !r.started {
return nil
}
return r.outbounds
}
@@ -557,13 +560,12 @@ func (r *Router) Start() error {
}
}
}
if needWIFIStateFromRuleSet || r.needWIFIState {
if (needWIFIStateFromRuleSet || r.needWIFIState) && r.platformInterface != nil {
monitor.Start("initialize WIFI state")
if r.platformInterface != nil && r.interfaceMonitor != nil {
r.interfaceMonitor.RegisterCallback(func(_ int) {
r.updateWIFIState()
})
}
r.needWIFIState = true
r.interfaceMonitor.RegisterCallback(func(_ int) {
r.updateWIFIState()
})
r.updateWIFIState()
monitor.Finish()
}
@@ -713,6 +715,10 @@ func (r *Router) RuleSet(tag string) (adapter.RuleSet, bool) {
return ruleSet, loaded
}
func (r *Router) NeedWIFIState() bool {
return r.needWIFIState
}
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
if r.pauseManager.IsDevicePaused() {
return E.New("reject connection to ", metadata.Destination, " while device paused")

View File

@@ -73,7 +73,7 @@ func NewRawIPCIDRItem(isSource bool, ipSet *netipx.IPSet) *IPCIDRItem {
}
func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
if r.isSource || metadata.QueryType != 0 || metadata.IPCIDRMatchSource {
if r.isSource || metadata.IPCIDRMatchSource {
return r.ipSet.Contains(metadata.Source.Addr)
} else {
if metadata.Destination.IsIP() {

View File

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