Compare commits

..

No commits in common. "348cc39975bc0d384c6b9d38c4ec0590d8ccf8bb" and "49498f643926c6f109f918f148c533298b4c8352" have entirely different histories.

27 changed files with 151 additions and 327 deletions

View File

@ -181,14 +181,13 @@ jobs:
fi
echo "DIR_NAME=${DIR_NAME}" >> "${GITHUB_ENV}"
PKG_VERSION="${{ needs.calculate_version.outputs.version }}"
PKG_VERSION="${PKG_VERSION//-/\~}"
PKG_VERSION="${PKG_VERSION//-/\~}-1"
echo "PKG_VERSION=${PKG_VERSION}" >> "${GITHUB_ENV}"
- name: Package DEB
if: matrix.debian != ''
run: |
set -xeuo pipefail
sudo gem install fpm
sudo apt-get update
sudo apt-get install -y debsigs
cp .fpm_systemd .fpm
fpm -t deb \
@ -227,7 +226,6 @@ jobs:
run: |-
set -xeuo pipefail
sudo gem install fpm
sudo apt-get update
sudo apt-get install -y libarchive-tools
cp .fpm_systemd .fpm
fpm -t pacman \

View File

@ -120,7 +120,6 @@ jobs:
set -xeuo pipefail
sudo gem install fpm
sudo apt-get install -y debsigs
cp .fpm_systemd .fpm
fpm -t deb \
--name "${NAME}" \
-v "$PKG_VERSION" \
@ -139,7 +138,6 @@ jobs:
run: |-
set -xeuo pipefail
sudo gem install fpm
cp .fpm_systemd .fpm
fpm -t rpm \
--name "${NAME}" \
-v "$PKG_VERSION" \

@ -1 +1 @@
Subproject commit 6a15780ce1659a234816f7248cbc09e8ea54a1be
Subproject commit 55f31c29bb68895ce544e0dfbf852b4b3e32b530

View File

@ -333,17 +333,7 @@ func (d *DefaultDialer) ListenSerialInterfacePacket(ctx context.Context, destina
}
func (d *DefaultDialer) ListenPacketCompat(network, address string) (net.PacketConn, error) {
udpListener := d.udpListener
udpListener.Control = control.Append(udpListener.Control, func(network, address string, conn syscall.RawConn) error {
for _, wgControlFn := range WgControlFns {
err := wgControlFn(network, address, conn)
if err != nil {
return err
}
}
return nil
})
return udpListener.ListenPacket(context.Background(), network, address)
return d.udpListener.ListenPacket(context.Background(), network, address)
}
func trackConn(conn net.Conn, err error) (net.Conn, error) {

View File

@ -31,18 +31,13 @@ func BitTorrent(_ context.Context, metadata *adapter.InboundContext, reader io.R
return os.ErrInvalid
}
const header = "BitTorrent protocol"
var protocol [19]byte
var n int
n, err = reader.Read(protocol[:])
if string(protocol[:n]) != header[:n] {
return os.ErrInvalid
}
_, err = reader.Read(protocol[:])
if err != nil {
return E.Cause1(ErrNeedMoreData, err)
}
if n < 19 {
return ErrNeedMoreData
if string(protocol[:]) != "BitTorrent protocol" {
return os.ErrInvalid
}
metadata.Protocol = C.ProtocolBitTorrent

View File

@ -32,27 +32,6 @@ func TestSniffBittorrent(t *testing.T) {
}
}
func TestSniffIncompleteBittorrent(t *testing.T) {
t.Parallel()
pkt, err := hex.DecodeString("13426974546f7272656e74")
require.NoError(t, err)
var metadata adapter.InboundContext
err = sniff.BitTorrent(context.TODO(), &metadata, bytes.NewReader(pkt))
require.ErrorIs(t, err, sniff.ErrNeedMoreData)
}
func TestSniffNotBittorrent(t *testing.T) {
t.Parallel()
pkt, err := hex.DecodeString("13426974546f7272656e75")
require.NoError(t, err)
var metadata adapter.InboundContext
err = sniff.BitTorrent(context.TODO(), &metadata, bytes.NewReader(pkt))
require.NotEmpty(t, err)
require.NotErrorIs(t, err, sniff.ErrNeedMoreData)
}
func TestSniffUTP(t *testing.T) {
t.Parallel()

View File

@ -20,36 +20,22 @@ func StreamDomainNameQuery(readCtx context.Context, metadata *adapter.InboundCon
if err != nil {
return E.Cause1(ErrNeedMoreData, err)
}
if length < 12 {
if length == 0 {
return os.ErrInvalid
}
buffer := buf.NewSize(int(length))
defer buffer.Release()
var n int
n, err = buffer.ReadFullFrom(reader, buffer.FreeLen())
packet := buffer.Bytes()
if n > 2 && packet[2]&0x80 != 0 { // QR
return os.ErrInvalid
}
if n > 5 && packet[4] == 0 && packet[5] == 0 { // QDCOUNT
return os.ErrInvalid
}
for i := 6; i < 10; i++ {
// ANCOUNT, NSCOUNT
if n > i && packet[i] != 0 {
return os.ErrInvalid
}
}
_, err = buffer.ReadFullFrom(reader, buffer.FreeLen())
if err != nil {
return E.Cause1(ErrNeedMoreData, err)
}
return DomainNameQuery(readCtx, metadata, packet)
return DomainNameQuery(readCtx, metadata, buffer.Bytes())
}
func DomainNameQuery(ctx context.Context, metadata *adapter.InboundContext, packet []byte) error {
var msg mDNS.Msg
err := msg.Unpack(packet)
if err != nil || msg.Response || len(msg.Question) == 0 || len(msg.Answer) > 0 || len(msg.Ns) > 0 {
if err != nil {
return err
}
metadata.Protocol = C.ProtocolDNS

View File

@ -1,7 +1,6 @@
package sniff_test
import (
"bytes"
"context"
"encoding/hex"
"testing"
@ -22,32 +21,3 @@ func TestSniffDNS(t *testing.T) {
require.NoError(t, err)
require.Equal(t, C.ProtocolDNS, metadata.Protocol)
}
func TestSniffStreamDNS(t *testing.T) {
t.Parallel()
query, err := hex.DecodeString("001e740701000001000000000000012a06676f6f676c6503636f6d0000010001")
require.NoError(t, err)
var metadata adapter.InboundContext
err = sniff.StreamDomainNameQuery(context.TODO(), &metadata, bytes.NewReader(query))
require.NoError(t, err)
require.Equal(t, C.ProtocolDNS, metadata.Protocol)
}
func TestSniffIncompleteStreamDNS(t *testing.T) {
t.Parallel()
query, err := hex.DecodeString("001e740701000001000000000000")
require.NoError(t, err)
var metadata adapter.InboundContext
err = sniff.StreamDomainNameQuery(context.TODO(), &metadata, bytes.NewReader(query))
require.ErrorIs(t, err, sniff.ErrNeedMoreData)
}
func TestSniffNotStreamDNS(t *testing.T) {
t.Parallel()
query, err := hex.DecodeString("001e740701000000000000000000")
require.NoError(t, err)
var metadata adapter.InboundContext
err = sniff.StreamDomainNameQuery(context.TODO(), &metadata, bytes.NewReader(query))
require.NotEmpty(t, err)
require.NotErrorIs(t, err, sniff.ErrNeedMoreData)
}

View File

@ -68,7 +68,7 @@ func PeekStream(ctx context.Context, metadata *adapter.InboundContext, conn net.
}
sniffError = E.Errors(sniffError, err)
}
if !errors.Is(sniffError, ErrNeedMoreData) {
if !errors.Is(err, ErrNeedMoreData) {
break
}
}

View File

@ -15,11 +15,10 @@ func SSH(_ context.Context, metadata *adapter.InboundContext, reader io.Reader)
const sshPrefix = "SSH-2.0-"
bReader := bufio.NewReader(reader)
prefix, err := bReader.Peek(len(sshPrefix))
if string(prefix[:]) != sshPrefix[:len(prefix)] {
return os.ErrInvalid
}
if err != nil {
return E.Cause1(ErrNeedMoreData, err)
} else if string(prefix) != sshPrefix {
return os.ErrInvalid
}
fistLine, _, err := bReader.ReadLine()
if err != nil {

View File

@ -24,24 +24,3 @@ func TestSniffSSH(t *testing.T) {
require.Equal(t, C.ProtocolSSH, metadata.Protocol)
require.Equal(t, "dropbear", metadata.Client)
}
func TestSniffIncompleteSSH(t *testing.T) {
t.Parallel()
pkt, err := hex.DecodeString("5353482d322e30")
require.NoError(t, err)
var metadata adapter.InboundContext
err = sniff.SSH(context.TODO(), &metadata, bytes.NewReader(pkt))
require.ErrorIs(t, err, sniff.ErrNeedMoreData)
}
func TestSniffNotSSH(t *testing.T) {
t.Parallel()
pkt, err := hex.DecodeString("5353482d322e31")
require.NoError(t, err)
var metadata adapter.InboundContext
err = sniff.SSH(context.TODO(), &metadata, bytes.NewReader(pkt))
require.NotEmpty(t, err)
require.NotErrorIs(t, err, sniff.ErrNeedMoreData)
}

View File

@ -2,12 +2,6 @@
icon: material/alert-decagram
---
### 1.11.9
* 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.11.8
* Improve `auto_redirect` **1**

View File

@ -8,57 +8,56 @@ icon: material/package
=== ":material-debian: Debian / APT"
```bash
sudo mkdir -p /etc/apt/keyrings &&
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc &&
sudo chmod a+r /etc/apt/keyrings/sagernet.asc &&
echo '
Types: deb
URIs: https://deb.sagernet.org/
Suites: *
Components: *
Enabled: yes
Signed-By: /etc/apt/keyrings/sagernet.asc
' | sudo tee /etc/apt/sources.list.d/sagernet.sources &&
sudo apt-get update &&
sudo apt-get install sing-box # or sing-box-beta
```
```bash
sudo mkdir -p /etc/apt/keyrings &&
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc &&
sudo chmod a+r /etc/apt/keyrings/sagernet.asc &&
echo '
Types: deb
URIs: https://deb.sagernet.org/
Suites: *
Components: *
Enabled: yes
Signed-By: /etc/apt/keyrings/sagernet.asc
' | sudo tee /etc/apt/sources.list.d/sagernet.sources &&
sudo apt-get update &&
sudo apt-get install sing-box # or sing-box-beta
```
=== ":material-redhat: Redhat / DNF 5"
```bash
sudo dnf config-manager addrepo --from-repofile=https://sing-box.app/sing-box.repo &&
sudo dnf install sing-box # or sing-box-beta
```
```bash
sudo dnf config-manager addrepo --from-repofile=https://sing-box.app/sing-box.repo &&
sudo dnf install sing-box # or sing-box-beta
```
=== ":material-redhat: Redhat / DNF 4"
```bash
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo &&
sudo dnf -y install dnf-plugins-core &&
sudo dnf install sing-box # or sing-box-beta
```
```bash
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo &&
sudo dnf -y install dnf-plugins-core &&
sudo dnf install sing-box # or sing-box-beta
```
## :material-download-box: Manual Installation
The script download and install the latest package from GitHub releases
for deb or rpm based Linux distributions, ArchLinux and OpenWrt.
```shell
curl -fsSL https://sing-box.app/install.sh | sh
```
or latest beta:
```shell
curl -fsSL https://sing-box.app/install.sh | sh -s -- --beta
```
or specific version:
```shell
curl -fsSL https://sing-box.app/install.sh | sh -s -- --version <version>
```
The script download and install the latest package from GitHub releases for deb or rpm based Linux distributions, ArchLinux and OpenWrt.
```shell
curl -fsSL https://sing-box.app/install.sh | sh
```
or latest beta:
```shell
curl -fsSL https://sing-box.app/install.sh | sh -s -- --beta
```
or specific version:
```shell
curl -fsSL https://sing-box.app/install.sh | sh -s -- --version <version>
```
## :material-book-lock-open: Managed Installation

View File

@ -26,38 +26,39 @@ icon: material/package
=== ":material-redhat: Redhat / DNF 5"
```bash
sudo dnf config-manager addrepo --from-repofile=https://sing-box.app/sing-box.repo &&
sudo dnf install sing-box # or sing-box-beta
```
```bash
sudo dnf config-manager addrepo --from-repofile=https://sing-box.app/sing-box.repo &&
sudo dnf install sing-box # or sing-box-beta
```
=== ":material-redhat: Redhat / DNF 4"
```bash
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo &&
sudo dnf -y install dnf-plugins-core &&
sudo dnf install sing-box # or sing-box-beta
```
```bash
sudo dnf config-manager --add-repo https://sing-box.app/sing-box.repo &&
sudo dnf -y install dnf-plugins-core &&
sudo dnf install sing-box # or sing-box-beta
```
## :material-download-box: 手动安装
该脚本从 GitHub 发布中下载并安装最新的软件包,适用于基于 deb 或 rpm 的 Linux 发行版、ArchLinux 和 OpenWrt。
=== ":material-debian: Debian / DEB"
```shell
curl -fsSL https://sing-box.app/install.sh | sh
```
```bash
bash <(curl -fsSL https://sing-box.app/deb-install.sh)
```
或最新测试版:
=== ":material-redhat: Redhat / RPM"
```shell
curl -fsSL https://sing-box.app/install.sh | sh -s -- --beta
```
```bash
bash <(curl -fsSL https://sing-box.app/rpm-install.sh)
```
(这适用于任何使用 `rpm``systemd` 的发行版。由于 `rpm` 定义依赖关系的方式,如果安装成功,就多半能用。)
或指定版本:
=== ":simple-archlinux: Archlinux / PKG"
```shell
curl -fsSL https://sing-box.app/install.sh | sh -s -- --version <version>
```
```bash
bash <(curl -fsSL https://sing-box.app/arch-install.sh)
```
## :material-book-lock-open: 托管安装

View File

@ -3,92 +3,76 @@
download_beta=false
download_version=""
while [ $# -gt 0 ]; do
case "$1" in
--beta)
download_beta=true
shift
;;
--version)
shift
if [ $# -eq 0 ]; then
echo "Missing argument for --version"
echo "Usage: $0 [--beta] [--version <version>]"
exit 1
fi
download_version="$1"
shift
;;
*)
echo "Unknown argument: $1"
echo "Usage: $0 [--beta] [--version <version>]"
exit 1
;;
esac
for arg in "$@"; do
if [[ "$arg" == "--beta" ]]; then
download_beta=true
elif [[ "$arg" == "--version" ]]; then
download_version=true
elif [[ "$download_version" == 'true' ]]; then
download_version="$arg"
else
echo "Unknown argument: $arg"
echo "Usage: $0 [--beta] [--version <version>]"
exit 1
fi
done
if command -v pacman >/dev/null 2>&1; then
os="linux"
arch=$(uname -m)
package_suffix=".pkg.tar.zst"
package_install="pacman -U --noconfirm"
elif command -v dpkg >/dev/null 2>&1; then
if [[ $(command -v dpkg) ]]; then
os="linux"
arch=$(dpkg --print-architecture)
package_suffix=".deb"
package_install="dpkg -i"
elif command -v dnf >/dev/null 2>&1; then
elif [[ $(command -v dnf) ]]; then
os="linux"
arch=$(uname -m)
package_suffix=".rpm"
package_install="dnf install -y"
elif command -v rpm >/dev/null 2>&1; then
elif [[ $(command -v rpm) ]]; then
os="linux"
arch=$(uname -m)
package_suffix=".rpm"
package_install="rpm -i"
elif command -v opkg >/dev/null 2>&1; then
elif [[ $(command -v pacman) ]]; then
os="linux"
arch=$(uname -m)
package_suffix=".pkg.tar.zst"
package_install="pacman -U --noconfirm"
elif [[ $(command -v opkg) ]]; then
os="openwrt"
. /etc/os-release
source /etc/os-release
arch="$OPENWRT_ARCH"
package_suffix=".ipk"
package_install="opkg update && opkg install"
package_install="opkg update && opkg install -y"
else
echo "Missing supported package manager."
exit 1
fi
if [ -z "$download_version" ]; then
if [ "$download_beta" != "true" ]; then
if [ -n "$GITHUB_TOKEN" ]; then
latest_release=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/SagerNet/sing-box/releases/latest)
if [[ -z "$download_version" ]]; then
if [[ "$download_beta" != 'true' ]]; then
if [[ -n "$GITHUB_TOKEN" ]]; then
latest_release=$(curl -s --fail-with-body -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/SagerNet/sing-box/releases/latest)
else
latest_release=$(curl -s https://api.github.com/repos/SagerNet/sing-box/releases/latest)
latest_release=$(curl -s --fail-with-body https://api.github.com/repos/SagerNet/sing-box/releases/latest)
fi
curl_exit_status=$?
if [ $curl_exit_status -ne 0 ]; then
exit $curl_exit_status
fi
if [ "$(echo "$latest_release" | grep tag_name | wc -l)" -eq 0 ]; then
if [[ $curl_exit_status -ne 0 ]]; then
echo "$latest_release"
exit 1
exit $?
fi
download_version=$(echo "$latest_release" | grep tag_name | head -n 1 | awk -F: '{print $2}' | sed 's/[", v]//g')
download_version=$(echo "$latest_release" | grep tag_name | cut -d ":" -f2 | sed 's/\"//g;s/\,//g;s/\ //g;s/v//')
else
if [ -n "$GITHUB_TOKEN" ]; then
latest_release=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/SagerNet/sing-box/releases)
if [[ -n "$GITHUB_TOKEN" ]]; then
latest_release=$(curl -s --fail-with-body -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/SagerNet/sing-box/releases)
else
latest_release=$(curl -s https://api.github.com/repos/SagerNet/sing-box/releases)
latest_release=$(curl -s --fail-with-body https://api.github.com/repos/SagerNet/sing-box/releases)
fi
curl_exit_status=$?
if [ $curl_exit_status -ne 0 ]; then
exit $curl_exit_status
fi
if [ "$(echo "$latest_release" | grep tag_name | wc -l)" -eq 0 ]; then
if [[ $? -ne 0 ]]; then
echo "$latest_release"
exit 1
exit $?
fi
download_version=$(echo "$latest_release" | grep tag_name | head -n 1 | awk -F: '{print $2}' | sed 's/[", v]//g')
download_version=$(echo "$latest_release" | grep tag_name | head -n 1 | cut -d ":" -f2 | sed 's/\"//g;s/\,//g;s/\ //g;s/v//')
fi
fi
@ -96,21 +80,18 @@ package_name="sing-box_${download_version}_${os}_${arch}${package_suffix}"
package_url="https://github.com/SagerNet/sing-box/releases/download/v${download_version}/${package_name}"
echo "Downloading $package_url"
if [ -n "$GITHUB_TOKEN" ]; then
curl --fail -Lo "$package_name" -H "Authorization: token ${GITHUB_TOKEN}" "$package_url"
if [[ -n "$GITHUB_TOKEN" ]]; then
curl --fail-with-body -Lo "$package_name" -H "Authorization: token ${GITHUB_TOKEN}" "$package_url"
else
curl --fail -Lo "$package_name" "$package_url"
curl --fail-with-body -Lo "$package_name" "$package_url"
fi
curl_exit_status=$?
if [ $curl_exit_status -ne 0 ]; then
exit $curl_exit_status
if [[ $? -ne 0 ]]; then
exit $?
fi
if command -v sudo >/dev/null 2>&1; then
if [[ $(command -v sudo) ]]; then
package_install="sudo $package_install"
fi
echo "$package_install $package_name"
sh -c "$package_install \"$package_name\""
rm -f "$package_name"
echo "$package_install $package_name" && $package_install "$package_name" && rm "$package_name"

10
go.mod
View File

@ -26,18 +26,18 @@ require (
github.com/sagernet/gvisor v0.0.0-20241123041152-536d05261cff
github.com/sagernet/quic-go v0.49.0-beta.1
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.6.7
github.com/sagernet/sing-dns v0.4.2
github.com/sagernet/sing v0.6.6
github.com/sagernet/sing-dns v0.4.1
github.com/sagernet/sing-mux v0.3.1
github.com/sagernet/sing-quic v0.4.1-0.20250423030647-0eb05f373a76
github.com/sagernet/sing-quic v0.4.1
github.com/sagernet/sing-shadowsocks v0.2.7
github.com/sagernet/sing-shadowsocks2 v0.2.0
github.com/sagernet/sing-shadowtls v0.2.0
github.com/sagernet/sing-tun v0.6.4
github.com/sagernet/sing-vmess v0.2.1
github.com/sagernet/sing-vmess v0.2.0
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
github.com/sagernet/utls v1.6.7
github.com/sagernet/wireguard-go v0.0.1-beta.7
github.com/sagernet/wireguard-go v0.0.1-beta.5
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.10.0

22
go.sum
View File

@ -119,14 +119,16 @@ github.com/sagernet/quic-go v0.49.0-beta.1/go.mod h1:uesWD1Ihrldq1M3XtjuEvIUqi8W
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.6.7 h1:NIWBLZ9AUWDXAQBKGleKwsitbQrI9M0nqoheXhUKnrI=
github.com/sagernet/sing v0.6.7/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-dns v0.4.2 h1:cWe2XPUBFLep2j9kJV4Epg3bctGhMvrrl/sWi9Wszfg=
github.com/sagernet/sing-dns v0.4.2/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8=
github.com/sagernet/sing v0.6.6-0.20250406121928-926a5a1e8bb7 h1:ZJauxLmH12Gzv3nucfjsSBQw9UA8t7Sxu8pYHBSP2TU=
github.com/sagernet/sing v0.6.6-0.20250406121928-926a5a1e8bb7/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing v0.6.6 h1:3JkvJ0vqDj/jJcx0a+ve/6lMOrSzZm30I3wrIuZtmRE=
github.com/sagernet/sing v0.6.6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-dns v0.4.1 h1:nozS7iqpxZ7aV73oHbkD/8haOvf3XXDCgT//8NdYirk=
github.com/sagernet/sing-dns v0.4.1/go.mod h1:dweQs54ng2YGzoJfz+F9dGuDNdP5pJ3PLeggnK5VWc8=
github.com/sagernet/sing-mux v0.3.1 h1:kvCc8HyGAskDHDQ0yQvoTi/7J4cZPB/VJMsAM3MmdQI=
github.com/sagernet/sing-mux v0.3.1/go.mod h1:Mkdz8LnDstthz0HWuA/5foncnDIdcNN5KZ6AdJX+x78=
github.com/sagernet/sing-quic v0.4.1-0.20250423030647-0eb05f373a76 h1:iwpCX6H3nZEOGUGwx0q5azcgYOA9f6v9YssihXoRKHk=
github.com/sagernet/sing-quic v0.4.1-0.20250423030647-0eb05f373a76/go.mod h1:tqPa0/Wqa19MkkSlKVZZX5sHxtiDR9BROcn4ufcbVdY=
github.com/sagernet/sing-quic v0.4.1 h1:pxlMa4efZu/M07RgGagNNDDyl6ZUwpmNUjRTpgHOWK4=
github.com/sagernet/sing-quic v0.4.1/go.mod h1:tqPa0/Wqa19MkkSlKVZZX5sHxtiDR9BROcn4ufcbVdY=
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
@ -135,14 +137,14 @@ github.com/sagernet/sing-shadowtls v0.2.0 h1:cLKe4OAOFwuhmAIuPLj//CIL7Q9js+pIDar
github.com/sagernet/sing-shadowtls v0.2.0/go.mod h1:agU+Fw5X+xnWVyRHyFthoZCX3MfWKCFPm4JUf+1oaxo=
github.com/sagernet/sing-tun v0.6.4 h1:3Iew6UtAf1+mucVeHKNhAEQI5xmq3CUCbGptUbjebts=
github.com/sagernet/sing-tun v0.6.4/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
github.com/sagernet/sing-vmess v0.2.1 h1:6izHC2+B68aQCxTagki6eZZc+g5eh4dYwxOV5a2Lhug=
github.com/sagernet/sing-vmess v0.2.1/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA=
github.com/sagernet/sing-vmess v0.2.0 h1:pCMGUXN2k7RpikQV65/rtXtDHzb190foTfF9IGTMZrI=
github.com/sagernet/sing-vmess v0.2.0/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo=
github.com/sagernet/utls v1.6.7 h1:Ep3+aJ8FUGGta+II2IEVNUc3EDhaRCZINWkj/LloIA8=
github.com/sagernet/utls v1.6.7/go.mod h1:Uua1TKO/FFuAhLr9rkaVnnrTmmiItzDjv1BUb2+ERwM=
github.com/sagernet/wireguard-go v0.0.1-beta.7 h1:ltgBwYHfr+9Wz1eG59NiWnHrYEkDKHG7otNZvu85DXI=
github.com/sagernet/wireguard-go v0.0.1-beta.7/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
github.com/sagernet/wireguard-go v0.0.1-beta.5 h1:aBEsxJUMEONwOZqKPIkuAcv4zJV5p6XlzEN04CF0FXc=
github.com/sagernet/wireguard-go v0.0.1-beta.5/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=

View File

@ -252,14 +252,6 @@ type _RejectActionOptions struct {
type RejectActionOptions _RejectActionOptions
func (r RejectActionOptions) MarshalJSON() ([]byte, error) {
switch r.Method {
case C.RuleActionRejectMethodDefault:
r.Method = ""
}
return json.Marshal((_RejectActionOptions)(r))
}
func (r *RejectActionOptions) UnmarshalJSON(bytes []byte) error {
err := json.Unmarshal(bytes, (*_RejectActionOptions)(r))
if err != nil {

View File

@ -10,7 +10,6 @@ import (
"strconv"
"strings"
"sync"
"time"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/adapter/outbound"
@ -192,29 +191,9 @@ func (s *Outbound) DialContext(ctx context.Context, network string, destination
if err != nil {
return nil, err
}
conn, err := client.Dial(network, destination.String())
if err != nil {
return nil, err
}
return &chanConnWrapper{Conn: conn}, nil
return client.Dial(network, destination.String())
}
func (s *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return nil, os.ErrInvalid
}
type chanConnWrapper struct {
net.Conn
}
func (c *chanConnWrapper) SetDeadline(t time.Time) error {
return os.ErrInvalid
}
func (c *chanConnWrapper) SetReadDeadline(t time.Time) error {
return os.ErrInvalid
}
func (c *chanConnWrapper) SetWriteDeadline(t time.Time) error {
return os.ErrInvalid
}

View File

@ -418,7 +418,6 @@ match:
Port: metadata.Destination.Port,
Fqdn: routeOptions.OverrideAddress.Fqdn,
}
metadata.DestinationAddresses = nil
}
if routeOptions.OverridePort > 0 {
metadata.Destination = M.Socksaddr{

View File

@ -223,9 +223,6 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS
err error
)
printResult := func() {
if err == nil && len(responseAddrs) == 0 {
err = E.New("empty result")
}
if err != nil {
if errors.Is(err, dns.ErrResponseRejectedCached) {
r.dnsLogger.DebugContext(ctx, "response rejected for ", domain, " (cached)")
@ -234,6 +231,9 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS
} else {
r.dnsLogger.ErrorContext(ctx, E.Cause(err, "lookup failed for ", domain))
}
} else if len(responseAddrs) == 0 {
r.dnsLogger.ErrorContext(ctx, "lookup failed for ", domain, ": empty result")
err = dns.RCodeNameError
}
}
responseAddrs, cached = r.dnsClient.LookupCache(ctx, domain, strategy)

View File

@ -102,10 +102,7 @@ func NewDefaultRule(ctx context.Context, logger log.ContextLogger, options optio
rule.allItems = append(rule.allItems, item)
}
if len(options.Domain) > 0 || len(options.DomainSuffix) > 0 {
item, err := NewDomainItem(options.Domain, options.DomainSuffix)
if err != nil {
return nil, err
}
item := NewDomainItem(options.Domain, options.DomainSuffix)
rule.destinationAddressItems = append(rule.destinationAddressItems, item)
rule.allItems = append(rule.allItems, item)
}

View File

@ -93,10 +93,7 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
rule.allItems = append(rule.allItems, item)
}
if len(options.Domain) > 0 || len(options.DomainSuffix) > 0 {
item, err := NewDomainItem(options.Domain, options.DomainSuffix)
if err != nil {
return nil, err
}
item := NewDomainItem(options.Domain, options.DomainSuffix)
rule.destinationAddressItems = append(rule.destinationAddressItems, item)
rule.allItems = append(rule.allItems, item)
}

View File

@ -47,10 +47,7 @@ func NewDefaultHeadlessRule(ctx context.Context, options option.DefaultHeadlessR
rule.allItems = append(rule.allItems, item)
}
if len(options.Domain) > 0 || len(options.DomainSuffix) > 0 {
item, err := NewDomainItem(options.Domain, options.DomainSuffix)
if err != nil {
return nil, err
}
item := NewDomainItem(options.Domain, options.DomainSuffix)
rule.destinationAddressItems = append(rule.destinationAddressItems, item)
rule.allItems = append(rule.allItems, item)
} else if options.DomainMatcher != nil {

View File

@ -5,7 +5,6 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing/common/domain"
E "github.com/sagernet/sing/common/exceptions"
)
var _ RuleItem = (*DomainItem)(nil)
@ -15,17 +14,7 @@ type DomainItem struct {
description string
}
func NewDomainItem(domains []string, domainSuffixes []string) (*DomainItem, error) {
for _, domainItem := range domains {
if domainItem == "" {
return nil, E.New("domain: empty item is not allowed")
}
}
for _, domainSuffixItem := range domainSuffixes {
if domainSuffixItem == "" {
return nil, E.New("domain_suffix: empty item is not allowed")
}
}
func NewDomainItem(domains []string, domainSuffixes []string) *DomainItem {
var description string
if dLen := len(domains); dLen > 0 {
if dLen == 1 {
@ -51,7 +40,7 @@ func NewDomainItem(domains []string, domainSuffixes []string) (*DomainItem, erro
return &DomainItem{
domain.NewMatcher(domains, domainSuffixes, false),
description,
}, nil
}
}
func NewRawDomainItem(matcher *domain.Matcher) *DomainItem {

View File

@ -91,7 +91,10 @@ func (c *Client) dialContext(ctx context.Context, requestURL *url.URL, headers h
} else {
deadlineConn = conn
}
deadlineConn.SetDeadline(time.Now().Add(C.TCPTimeout))
err = deadlineConn.SetDeadline(time.Now().Add(C.TCPTimeout))
if err != nil {
return nil, E.Cause(err, "set read deadline")
}
var protocols []string
if protocolHeader := headers.Get("Sec-WebSocket-Protocol"); protocolHeader != "" {
protocols = []string{protocolHeader}

View File

@ -141,7 +141,7 @@ func (e *Endpoint) Start(resolve bool) error {
return nil
}
var bind conn.Bind
wgListener, isWgListener := common.Cast[conn.Listener](e.options.Dialer)
wgListener, isWgListener := e.options.Dialer.(conn.Listener)
if isWgListener {
bind = conn.NewStdNetBind(wgListener)
} else {