mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-13 20:28:32 +10:00
Compare commits
9 Commits
2e3cb87263
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d82be7d86b | ||
|
|
64a5cc88e1 | ||
|
|
71626beaf8 | ||
|
|
004a967e72 | ||
|
|
3ab8ba76d0 | ||
|
|
1edc8fd855 | ||
|
|
22a8661858 | ||
|
|
52aa5716be | ||
|
|
2c24e82257 |
@@ -4,7 +4,6 @@
|
||||
--license GPL-3.0-or-later
|
||||
--description "The universal proxy platform."
|
||||
--url "https://sing-box.sagernet.org/"
|
||||
--vendor SagerNet
|
||||
--maintainer "nekohasekai <contact-git@sekai.icu>"
|
||||
--deb-field "Bug: https://github.com/SagerNet/sing-box/issues"
|
||||
--no-deb-generate-changes
|
||||
|
||||
33
.github/detect_track.sh
vendored
33
.github/detect_track.sh
vendored
@@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
branches=$(git branch -r --contains HEAD)
|
||||
if echo "$branches" | grep -q 'origin/stable'; then
|
||||
track=stable
|
||||
elif echo "$branches" | grep -q 'origin/testing'; then
|
||||
track=testing
|
||||
elif echo "$branches" | grep -q 'origin/oldstable'; then
|
||||
track=oldstable
|
||||
else
|
||||
echo "ERROR: HEAD is not on any known release branch (stable/testing/oldstable)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$track" == "stable" ]]; then
|
||||
tag=$(git describe --tags --exact-match HEAD 2>/dev/null || true)
|
||||
if [[ -n "$tag" && "$tag" == *"-"* ]]; then
|
||||
track=beta
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$track" in
|
||||
stable) name=sing-box; docker_tag=latest ;;
|
||||
beta) name=sing-box-beta; docker_tag=latest-beta ;;
|
||||
testing) name=sing-box-testing; docker_tag=latest-testing ;;
|
||||
oldstable) name=sing-box-oldstable; docker_tag=latest-oldstable ;;
|
||||
esac
|
||||
|
||||
echo "track=${track} name=${name} docker_tag=${docker_tag}" >&2
|
||||
echo "TRACK=${track}" >> "$GITHUB_ENV"
|
||||
echo "NAME=${name}" >> "$GITHUB_ENV"
|
||||
echo "DOCKER_TAG=${docker_tag}" >> "$GITHUB_ENV"
|
||||
19
.github/workflows/docker.yml
vendored
19
.github/workflows/docker.yml
vendored
@@ -19,6 +19,7 @@ env:
|
||||
jobs:
|
||||
build_binary:
|
||||
name: Build binary
|
||||
if: github.event_name != 'release' || github.event.release.target_commitish != 'oldstable'
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: true
|
||||
@@ -259,13 +260,13 @@ jobs:
|
||||
fi
|
||||
echo "ref=$ref"
|
||||
echo "ref=$ref" >> $GITHUB_OUTPUT
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
with:
|
||||
ref: ${{ steps.ref.outputs.ref }}
|
||||
fetch-depth: 0
|
||||
- name: Detect track
|
||||
run: bash .github/detect_track.sh
|
||||
if [[ $ref == *"-"* ]]; then
|
||||
latest=latest-beta
|
||||
else
|
||||
latest=latest
|
||||
fi
|
||||
echo "latest=$latest"
|
||||
echo "latest=$latest" >> $GITHUB_OUTPUT
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
@@ -285,11 +286,11 @@ jobs:
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
docker buildx imagetools create \
|
||||
-t "${{ env.REGISTRY_IMAGE }}:${{ env.DOCKER_TAG }}" \
|
||||
-t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}" \
|
||||
-t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}" \
|
||||
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
|
||||
- name: Inspect image
|
||||
if: github.event_name != 'push'
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ env.DOCKER_TAG }}
|
||||
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.latest }}
|
||||
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}
|
||||
|
||||
16
.github/workflows/linux.yml
vendored
16
.github/workflows/linux.yml
vendored
@@ -11,6 +11,11 @@ on:
|
||||
description: "Version name"
|
||||
required: true
|
||||
type: string
|
||||
forceBeta:
|
||||
description: "Force beta"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
@@ -18,6 +23,7 @@ on:
|
||||
jobs:
|
||||
calculate_version:
|
||||
name: Calculate version
|
||||
if: github.event_name != 'release' || github.event.release.target_commitish != 'oldstable'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.outputs.outputs.version }}
|
||||
@@ -162,8 +168,14 @@ jobs:
|
||||
- name: Set mtime
|
||||
run: |-
|
||||
TZ=UTC touch -t '197001010000' dist/sing-box
|
||||
- name: Detect track
|
||||
run: bash .github/detect_track.sh
|
||||
- name: Set name
|
||||
if: (! contains(needs.calculate_version.outputs.version, '-')) && !inputs.forceBeta
|
||||
run: |-
|
||||
echo "NAME=sing-box" >> "$GITHUB_ENV"
|
||||
- name: Set beta name
|
||||
if: contains(needs.calculate_version.outputs.version, '-') || inputs.forceBeta
|
||||
run: |-
|
||||
echo "NAME=sing-box-beta" >> "$GITHUB_ENV"
|
||||
- name: Set version
|
||||
run: |-
|
||||
PKG_VERSION="${{ needs.calculate_version.outputs.version }}"
|
||||
|
||||
Submodule clients/android updated: cba1cc3ce0...82ffed6cd7
Submodule clients/apple updated: ffbf405b52...bcdd385b79
@@ -25,7 +25,6 @@ const (
|
||||
TypeTUIC = "tuic"
|
||||
TypeHysteria2 = "hysteria2"
|
||||
TypeTailscale = "tailscale"
|
||||
TypeCloudflared = "cloudflared"
|
||||
TypeDERP = "derp"
|
||||
TypeResolved = "resolved"
|
||||
TypeSSMAPI = "ssm-api"
|
||||
@@ -91,8 +90,6 @@ func ProxyDisplayName(proxyType string) string {
|
||||
return "AnyTLS"
|
||||
case TypeTailscale:
|
||||
return "Tailscale"
|
||||
case TypeCloudflared:
|
||||
return "Cloudflared"
|
||||
case TypeSelector:
|
||||
return "Selector"
|
||||
case TypeURLTest:
|
||||
|
||||
@@ -2,49 +2,13 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.14.0-alpha.8
|
||||
|
||||
* Add BBR profile and hop interval randomization for Hysteria2 **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
See [Hysteria2 Inbound](/configuration/inbound/hysteria2/#bbr_profile) and [Hysteria2 Outbound](/configuration/outbound/hysteria2/#bbr_profile).
|
||||
|
||||
#### 1.14.0-alpha.8
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.13.5
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.14.0-alpha.7
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.13.4
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.14.0-alpha.4
|
||||
|
||||
* Refactor ACME support to certificate provider system **1**
|
||||
* Add Cloudflare Origin CA certificate provider **2**
|
||||
* Add Tailscale certificate provider **3**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
#### 1.13.4-beta.1
|
||||
|
||||
See [Certificate Provider](/configuration/shared/certificate-provider/) and [Migration](/migration/#migrate-inline-acme-to-certificate-provider).
|
||||
|
||||
**2**:
|
||||
|
||||
See [Cloudflare Origin CA](/configuration/shared/certificate-provider/cloudflare-origin-ca).
|
||||
|
||||
**3**:
|
||||
|
||||
See [Tailscale](/configuration/shared/certificate-provider/tailscale).
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.13.3
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ icon: material/alert-decagram
|
||||
(`source_port` || `source_port_range`) &&
|
||||
`other fields`
|
||||
|
||||
Additionally, each branch inside an included rule-set can be considered merged into the outer rule, while different branches keep OR semantics.
|
||||
Additionally, included rule-sets can be considered merged rather than as a single rule sub-item.
|
||||
|
||||
#### inbound
|
||||
|
||||
@@ -577,4 +577,4 @@ Match any IP with query response.
|
||||
|
||||
#### rules
|
||||
|
||||
Included rules.
|
||||
Included rules.
|
||||
@@ -219,7 +219,7 @@ icon: material/alert-decagram
|
||||
(`source_port` || `source_port_range`) &&
|
||||
`other fields`
|
||||
|
||||
另外,引用规则集中的每个分支都可视为与外层规则合并,不同分支之间仍保持 OR 语义。
|
||||
另外,引用的规则集可视为被合并,而不是作为一个单独的规则子项。
|
||||
|
||||
#### inbound
|
||||
|
||||
@@ -581,4 +581,4 @@ Available values: `wifi`, `cellular`, `ethernet` and `other`.
|
||||
|
||||
==必填==
|
||||
|
||||
包括的规则。
|
||||
包括的规则。
|
||||
@@ -2,10 +2,6 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "Changes in sing-box 1.14.0"
|
||||
|
||||
:material-plus: [bbr_profile](#bbr_profile)
|
||||
|
||||
!!! quote "Changes in sing-box 1.11.0"
|
||||
|
||||
:material-alert: [masquerade](#masquerade)
|
||||
@@ -35,7 +31,6 @@ icon: material/alert-decagram
|
||||
"ignore_client_bandwidth": false,
|
||||
"tls": {},
|
||||
"masquerade": "", // or {}
|
||||
"bbr_profile": "",
|
||||
"brutal_debug": false
|
||||
}
|
||||
```
|
||||
@@ -146,14 +141,6 @@ Fixed response headers.
|
||||
|
||||
Fixed response content.
|
||||
|
||||
#### bbr_profile
|
||||
|
||||
!!! question "Since sing-box 1.14.0"
|
||||
|
||||
BBR congestion control algorithm profile, one of `conservative` `standard` `aggressive`.
|
||||
|
||||
`standard` is used by default.
|
||||
|
||||
#### brutal_debug
|
||||
|
||||
Enable debug information logging for Hysteria Brutal CC.
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
!!! quote "sing-box 1.14.0 中的更改"
|
||||
|
||||
:material-plus: [bbr_profile](#bbr_profile)
|
||||
|
||||
!!! quote "sing-box 1.11.0 中的更改"
|
||||
|
||||
:material-alert: [masquerade](#masquerade)
|
||||
@@ -35,7 +31,6 @@ icon: material/alert-decagram
|
||||
"ignore_client_bandwidth": false,
|
||||
"tls": {},
|
||||
"masquerade": "", // 或 {}
|
||||
"bbr_profile": "",
|
||||
"brutal_debug": false
|
||||
}
|
||||
```
|
||||
@@ -143,14 +138,6 @@ HTTP3 服务器认证失败时的行为 (对象配置)。
|
||||
|
||||
固定响应内容。
|
||||
|
||||
#### bbr_profile
|
||||
|
||||
!!! question "自 sing-box 1.14.0 起"
|
||||
|
||||
BBR 拥塞控制算法配置,可选 `conservative` `standard` `aggressive`。
|
||||
|
||||
默认使用 `standard`。
|
||||
|
||||
#### brutal_debug
|
||||
|
||||
启用 Hysteria Brutal CC 的调试信息日志记录。
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
!!! quote "Changes in sing-box 1.14.0"
|
||||
|
||||
:material-plus: [hop_interval_max](#hop_interval_max)
|
||||
:material-plus: [bbr_profile](#bbr_profile)
|
||||
|
||||
!!! quote "Changes in sing-box 1.11.0"
|
||||
|
||||
:material-plus: [server_ports](#server_ports)
|
||||
@@ -14,14 +9,13 @@
|
||||
{
|
||||
"type": "hysteria2",
|
||||
"tag": "hy2-out",
|
||||
|
||||
|
||||
"server": "127.0.0.1",
|
||||
"server_port": 1080,
|
||||
"server_ports": [
|
||||
"2080:3000"
|
||||
],
|
||||
"hop_interval": "",
|
||||
"hop_interval_max": "",
|
||||
"up_mbps": 100,
|
||||
"down_mbps": 100,
|
||||
"obfs": {
|
||||
@@ -31,9 +25,8 @@
|
||||
"password": "goofy_ahh_password",
|
||||
"network": "tcp",
|
||||
"tls": {},
|
||||
"bbr_profile": "",
|
||||
"brutal_debug": false,
|
||||
|
||||
|
||||
... // Dial Fields
|
||||
}
|
||||
```
|
||||
@@ -82,14 +75,6 @@ Port hopping interval.
|
||||
|
||||
`30s` is used by default.
|
||||
|
||||
#### hop_interval_max
|
||||
|
||||
!!! question "Since sing-box 1.14.0"
|
||||
|
||||
Maximum port hopping interval, used for randomization.
|
||||
|
||||
If set, the actual hop interval will be randomly chosen between `hop_interval` and `hop_interval_max`.
|
||||
|
||||
#### up_mbps, down_mbps
|
||||
|
||||
Max bandwidth, in Mbps.
|
||||
@@ -124,14 +109,6 @@ Both is enabled by default.
|
||||
|
||||
TLS configuration, see [TLS](/configuration/shared/tls/#outbound).
|
||||
|
||||
#### bbr_profile
|
||||
|
||||
!!! question "Since sing-box 1.14.0"
|
||||
|
||||
BBR congestion control algorithm profile, one of `conservative` `standard` `aggressive`.
|
||||
|
||||
`standard` is used by default.
|
||||
|
||||
#### brutal_debug
|
||||
|
||||
Enable debug information logging for Hysteria Brutal CC.
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
!!! quote "sing-box 1.14.0 中的更改"
|
||||
|
||||
:material-plus: [hop_interval_max](#hop_interval_max)
|
||||
:material-plus: [bbr_profile](#bbr_profile)
|
||||
|
||||
!!! quote "sing-box 1.11.0 中的更改"
|
||||
|
||||
:material-plus: [server_ports](#server_ports)
|
||||
@@ -21,7 +16,6 @@
|
||||
"2080:3000"
|
||||
],
|
||||
"hop_interval": "",
|
||||
"hop_interval_max": "",
|
||||
"up_mbps": 100,
|
||||
"down_mbps": 100,
|
||||
"obfs": {
|
||||
@@ -31,9 +25,8 @@
|
||||
"password": "goofy_ahh_password",
|
||||
"network": "tcp",
|
||||
"tls": {},
|
||||
"bbr_profile": "",
|
||||
"brutal_debug": false,
|
||||
|
||||
|
||||
... // 拨号字段
|
||||
}
|
||||
```
|
||||
@@ -80,14 +73,6 @@
|
||||
|
||||
默认使用 `30s`。
|
||||
|
||||
#### hop_interval_max
|
||||
|
||||
!!! question "自 sing-box 1.14.0 起"
|
||||
|
||||
最大端口跳跃间隔,用于随机化。
|
||||
|
||||
如果设置,实际跳跃间隔将在 `hop_interval` 和 `hop_interval_max` 之间随机选择。
|
||||
|
||||
#### up_mbps, down_mbps
|
||||
|
||||
最大带宽。
|
||||
@@ -122,14 +107,6 @@ QUIC 流量混淆器密码.
|
||||
|
||||
TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#出站)。
|
||||
|
||||
#### bbr_profile
|
||||
|
||||
!!! question "自 sing-box 1.14.0 起"
|
||||
|
||||
BBR 拥塞控制算法配置,可选 `conservative` `standard` `aggressive`。
|
||||
|
||||
默认使用 `standard`。
|
||||
|
||||
#### brutal_debug
|
||||
|
||||
启用 Hysteria Brutal CC 的调试信息日志记录。
|
||||
|
||||
@@ -210,7 +210,7 @@ icon: material/new-box
|
||||
(`source_port` || `source_port_range`) &&
|
||||
`other fields`
|
||||
|
||||
Additionally, each branch inside an included rule-set can be considered merged into the outer rule, while different branches keep OR semantics.
|
||||
Additionally, included rule-sets can be considered merged rather than as a single rule sub-item.
|
||||
|
||||
#### inbound
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ icon: material/new-box
|
||||
(`source_port` || `source_port_range`) &&
|
||||
`other fields`
|
||||
|
||||
另外,引用规则集中的每个分支都可视为与外层规则合并,不同分支之间仍保持 OR 语义。
|
||||
另外,引用的规则集可视为被合并,而不是作为一个单独的规则子项。
|
||||
|
||||
#### inbound
|
||||
|
||||
@@ -532,4 +532,4 @@ icon: material/new-box
|
||||
|
||||
==必填==
|
||||
|
||||
包括的规则。
|
||||
包括的规则。
|
||||
@@ -52,11 +52,6 @@ type HTTPRequest interface {
|
||||
type HTTPResponse interface {
|
||||
GetContent() (*StringBox, error)
|
||||
WriteTo(path string) error
|
||||
WriteToWithProgress(path string, handler HTTPResponseWriteToProgressHandler) error
|
||||
}
|
||||
|
||||
type HTTPResponseWriteToProgressHandler interface {
|
||||
Update(progress int64, total int64)
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -244,31 +239,3 @@ func (h *httpResponse) WriteTo(path string) error {
|
||||
defer file.Close()
|
||||
return common.Error(bufio.Copy(file, h.Body))
|
||||
}
|
||||
|
||||
func (h *httpResponse) WriteToWithProgress(path string, handler HTTPResponseWriteToProgressHandler) error {
|
||||
defer h.Body.Close()
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
return common.Error(bufio.Copy(&progressWriter{
|
||||
writer: file,
|
||||
handler: handler,
|
||||
total: h.ContentLength,
|
||||
}, h.Body))
|
||||
}
|
||||
|
||||
type progressWriter struct {
|
||||
writer io.Writer
|
||||
handler HTTPResponseWriteToProgressHandler
|
||||
total int64
|
||||
written int64
|
||||
}
|
||||
|
||||
func (w *progressWriter) Write(p []byte) (int, error) {
|
||||
n, err := w.writer.Write(p)
|
||||
w.written += int64(n)
|
||||
w.handler.Update(w.written, w.total)
|
||||
return n, err
|
||||
}
|
||||
|
||||
15
go.mod
15
go.mod
@@ -6,7 +6,6 @@ require (
|
||||
github.com/anthropics/anthropic-sdk-go v1.26.0
|
||||
github.com/anytls/sing-anytls v0.0.11
|
||||
github.com/caddyserver/certmagic v0.25.2
|
||||
github.com/caddyserver/zerossl v0.1.5
|
||||
github.com/coder/websocket v1.8.14
|
||||
github.com/cretz/bine v0.2.0
|
||||
github.com/database64128/tfo-go/v2 v2.3.2
|
||||
@@ -20,7 +19,6 @@ require (
|
||||
github.com/libdns/acmedns v0.5.0
|
||||
github.com/libdns/alidns v1.0.6
|
||||
github.com/libdns/cloudflare v0.2.2
|
||||
github.com/libdns/libdns v1.1.1
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/mdlayher/netlink v1.9.0
|
||||
github.com/metacubex/utls v1.8.4
|
||||
@@ -37,14 +35,13 @@ require (
|
||||
github.com/sagernet/gomobile v0.1.12
|
||||
github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4
|
||||
github.com/sagernet/sing v0.8.4
|
||||
github.com/sagernet/sing-cloudflared v0.0.0-20260407120610-7715dc2523fa
|
||||
github.com/sagernet/sing v0.8.3-0.20260315153529-ed51f65fbfde
|
||||
github.com/sagernet/sing-mux v0.3.4
|
||||
github.com/sagernet/sing-quic v0.6.2-0.20260330152607-bf674c163212
|
||||
github.com/sagernet/sing-quic v0.6.0
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
||||
github.com/sagernet/sing-tun v0.8.7-0.20260402180740-11f6e77ec6c6
|
||||
github.com/sagernet/sing-tun v0.8.7-0.20260323120017-8eb4e8acfc2d
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1
|
||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7
|
||||
@@ -72,9 +69,9 @@ require (
|
||||
github.com/akutz/memconn v0.1.0 // indirect
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.5 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.17.0 // indirect
|
||||
github.com/database64128/netx-go v0.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
|
||||
@@ -84,7 +81,6 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gaissmai/bart v0.18.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
@@ -100,9 +96,9 @@ require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/libdns/libdns v1.1.1 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
github.com/philhofer/fwd v1.2.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pires/go-proxyproto v0.8.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
@@ -169,5 +165,4 @@ require (
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.3.0 // indirect
|
||||
zombiezen.com/go/capnproto2 v2.18.2+incompatible // indirect
|
||||
)
|
||||
|
||||
24
go.sum
24
go.sum
@@ -28,8 +28,6 @@ github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9
|
||||
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0=
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=
|
||||
github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
@@ -112,8 +110,6 @@ github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zt
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh5YzC3JVwU=
|
||||
github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk=
|
||||
github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U=
|
||||
@@ -146,8 +142,6 @@ github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xx
|
||||
github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
|
||||
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
|
||||
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
|
||||
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
|
||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
|
||||
@@ -242,22 +236,20 @@ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNen
|
||||
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o=
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4=
|
||||
github.com/sagernet/sing v0.8.4 h1:Fj+jlY3F8vhcRfz/G/P3Dwcs5wqnmyNPT7u1RVVmjFI=
|
||||
github.com/sagernet/sing v0.8.4/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-cloudflared v0.0.0-20260407120610-7715dc2523fa h1:165HiOfgfofJIirEp1NGSmsoJAi+++WhR29IhtAu4A4=
|
||||
github.com/sagernet/sing-cloudflared v0.0.0-20260407120610-7715dc2523fa/go.mod h1:bH2NKX+NpDTY1Zkxfboxw6MXB/ZywaNLmrDJYgKMJ2Y=
|
||||
github.com/sagernet/sing v0.8.3-0.20260315153529-ed51f65fbfde h1:RNQzlpnsXIuu1HGts/fIzJ1PR7RhrzaNlU52MDyiX1c=
|
||||
github.com/sagernet/sing v0.8.3-0.20260315153529-ed51f65fbfde/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s=
|
||||
github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
|
||||
github.com/sagernet/sing-quic v0.6.2-0.20260330152607-bf674c163212 h1:7mFOUqy+DyOj7qKGd1X54UMXbnbJiiMileK/tn17xYc=
|
||||
github.com/sagernet/sing-quic v0.6.2-0.20260330152607-bf674c163212/go.mod h1:K5bWvITOm4vE10fwLfrWpw27bCoVJ+tfQ79tOWg+Ko8=
|
||||
github.com/sagernet/sing-quic v0.6.0 h1:dhrFnP45wgVKEOT1EvtsToxdzRnHIDIAgj6WHV9pLyM=
|
||||
github.com/sagernet/sing-quic v0.6.0/go.mod h1:K5bWvITOm4vE10fwLfrWpw27bCoVJ+tfQ79tOWg+Ko8=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-tun v0.8.7-0.20260402180740-11f6e77ec6c6 h1:HV2I7DicF5Ar8v6F55f03W5FviBB7jgvLhJSDwbFvbk=
|
||||
github.com/sagernet/sing-tun v0.8.7-0.20260402180740-11f6e77ec6c6/go.mod h1:pLCo4o+LacXEzz0bhwhJkKBjLlKOGPBNOAZ97ZVZWzs=
|
||||
github.com/sagernet/sing-tun v0.8.7-0.20260323120017-8eb4e8acfc2d h1:vi0j6301f6H8t2GYgAC2PA2AdnGdMwkP34B4+N03Qt4=
|
||||
github.com/sagernet/sing-tun v0.8.7-0.20260323120017-8eb4e8acfc2d/go.mod h1:pLCo4o+LacXEzz0bhwhJkKBjLlKOGPBNOAZ97ZVZWzs=
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o=
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
|
||||
@@ -302,8 +294,6 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/tinylib/msgp v1.6.3 h1:bCSxiTz386UTgyT1i0MSCvdbWjVW+8sG3PjkGsZQt4s=
|
||||
github.com/tinylib/msgp v1.6.3/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA=
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM=
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA=
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
@@ -411,5 +401,3 @@ lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
|
||||
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
|
||||
software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
|
||||
zombiezen.com/go/capnproto2 v2.18.2+incompatible h1:v3BD1zbruvffn7zjJUU5Pn8nZAB11bhZSQC4W+YnnKo=
|
||||
zombiezen.com/go/capnproto2 v2.18.2+incompatible/go.mod h1:XO5Pr2SbXgqZwn0m0Ru54QBqpOf4K5AYBO+8LAOBQEQ=
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
//go:build with_cloudflared
|
||||
|
||||
package include
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/adapter/inbound"
|
||||
"github.com/sagernet/sing-box/protocol/cloudflare"
|
||||
)
|
||||
|
||||
func registerCloudflaredInbound(registry *inbound.Registry) {
|
||||
cloudflare.RegisterInbound(registry)
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
//go:build !with_cloudflared
|
||||
|
||||
package include
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/inbound"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
func registerCloudflaredInbound(registry *inbound.Registry) {
|
||||
inbound.Register[option.CloudflaredInboundOptions](registry, C.TypeCloudflared, func(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.CloudflaredInboundOptions) (adapter.Inbound, error) {
|
||||
return nil, E.New(`Cloudflared is not included in this build, rebuild with -tags with_cloudflared`)
|
||||
})
|
||||
}
|
||||
@@ -66,7 +66,6 @@ func InboundRegistry() *inbound.Registry {
|
||||
anytls.RegisterInbound(registry)
|
||||
|
||||
registerQUICInbounds(registry)
|
||||
registerCloudflaredInbound(registry)
|
||||
registerStubForRemovedInbounds(registry)
|
||||
|
||||
return registry
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package option
|
||||
|
||||
import "github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
type CloudflaredInboundOptions struct {
|
||||
Token string `json:"token,omitempty"`
|
||||
HAConnections int `json:"ha_connections,omitempty"`
|
||||
Protocol string `json:"protocol,omitempty"`
|
||||
PostQuantum bool `json:"post_quantum,omitempty"`
|
||||
ControlDialer DialerOptions `json:"control_dialer,omitempty"`
|
||||
TunnelDialer DialerOptions `json:"tunnel_dialer,omitempty"`
|
||||
EdgeIPVersion int `json:"edge_ip_version,omitempty"`
|
||||
DatagramVersion string `json:"datagram_version,omitempty"`
|
||||
GracePeriod *badoption.Duration `json:"grace_period,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
}
|
||||
@@ -19,7 +19,6 @@ type Hysteria2InboundOptions struct {
|
||||
IgnoreClientBandwidth bool `json:"ignore_client_bandwidth,omitempty"`
|
||||
InboundTLSOptionsContainer
|
||||
Masquerade *Hysteria2Masquerade `json:"masquerade,omitempty"`
|
||||
BBRProfile string `json:"bbr_profile,omitempty"`
|
||||
BrutalDebug bool `json:"brutal_debug,omitempty"`
|
||||
}
|
||||
|
||||
@@ -113,15 +112,13 @@ type Hysteria2MasqueradeString struct {
|
||||
type Hysteria2OutboundOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
ServerPorts badoption.Listable[string] `json:"server_ports,omitempty"`
|
||||
HopInterval badoption.Duration `json:"hop_interval,omitempty"`
|
||||
HopIntervalMax badoption.Duration `json:"hop_interval_max,omitempty"`
|
||||
UpMbps int `json:"up_mbps,omitempty"`
|
||||
DownMbps int `json:"down_mbps,omitempty"`
|
||||
Obfs *Hysteria2Obfs `json:"obfs,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
ServerPorts badoption.Listable[string] `json:"server_ports,omitempty"`
|
||||
HopInterval badoption.Duration `json:"hop_interval,omitempty"`
|
||||
UpMbps int `json:"up_mbps,omitempty"`
|
||||
DownMbps int `json:"down_mbps,omitempty"`
|
||||
Obfs *Hysteria2Obfs `json:"obfs,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
OutboundTLSOptionsContainer
|
||||
BBRProfile string `json:"bbr_profile,omitempty"`
|
||||
BrutalDebug bool `json:"brutal_debug,omitempty"`
|
||||
BrutalDebug bool `json:"brutal_debug,omitempty"`
|
||||
}
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
//go:build with_cloudflared
|
||||
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
cloudflared "github.com/sagernet/sing-cloudflared"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/inbound"
|
||||
boxDialer "github.com/sagernet/sing-box/common/dialer"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/pipe"
|
||||
tun "github.com/sagernet/sing-tun"
|
||||
)
|
||||
|
||||
func RegisterInbound(registry *inbound.Registry) {
|
||||
inbound.Register[option.CloudflaredInboundOptions](registry, C.TypeCloudflared, NewInbound)
|
||||
}
|
||||
|
||||
func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.CloudflaredInboundOptions) (adapter.Inbound, error) {
|
||||
controlDialer, err := boxDialer.NewWithOptions(boxDialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.ControlDialer,
|
||||
RemoteIsDomain: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "build cloudflared control dialer")
|
||||
}
|
||||
tunnelDialer, err := boxDialer.NewWithOptions(boxDialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.TunnelDialer,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "build cloudflared tunnel dialer")
|
||||
}
|
||||
|
||||
service, err := cloudflared.NewService(cloudflared.ServiceOptions{
|
||||
Logger: logger,
|
||||
ConnectionDialer: &routerDialer{router: router, tag: tag},
|
||||
ControlDialer: controlDialer,
|
||||
TunnelDialer: tunnelDialer,
|
||||
ICMPHandler: &icmpRouterHandler{router: router, tag: tag},
|
||||
ConnContext: func(ctx context.Context) context.Context {
|
||||
return adapter.WithContext(ctx, &adapter.InboundContext{
|
||||
Inbound: tag,
|
||||
InboundType: C.TypeCloudflared,
|
||||
})
|
||||
},
|
||||
Token: options.Token,
|
||||
HAConnections: options.HAConnections,
|
||||
Protocol: options.Protocol,
|
||||
PostQuantum: options.PostQuantum,
|
||||
EdgeIPVersion: options.EdgeIPVersion,
|
||||
DatagramVersion: options.DatagramVersion,
|
||||
GracePeriod: resolveGracePeriod(options.GracePeriod),
|
||||
Region: options.Region,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Inbound{
|
||||
Adapter: inbound.NewAdapter(C.TypeCloudflared, tag),
|
||||
service: service,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Inbound struct {
|
||||
inbound.Adapter
|
||||
service *cloudflared.Service
|
||||
}
|
||||
|
||||
func (i *Inbound) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return i.service.Start()
|
||||
}
|
||||
|
||||
func (i *Inbound) Close() error {
|
||||
return i.service.Close()
|
||||
}
|
||||
|
||||
func resolveGracePeriod(value *badoption.Duration) time.Duration {
|
||||
if value == nil {
|
||||
return 0
|
||||
}
|
||||
return time.Duration(*value)
|
||||
}
|
||||
|
||||
// routerDialer bridges N.Dialer to the sing-box router for origin connections.
|
||||
type routerDialer struct {
|
||||
router adapter.Router
|
||||
tag string
|
||||
}
|
||||
|
||||
func (d *routerDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
input, output := pipe.Pipe()
|
||||
done := make(chan struct{})
|
||||
metadata := adapter.InboundContext{
|
||||
Inbound: d.tag,
|
||||
InboundType: C.TypeCloudflared,
|
||||
Network: N.NetworkTCP,
|
||||
Destination: destination,
|
||||
}
|
||||
var closeOnce sync.Once
|
||||
closePipe := func() {
|
||||
closeOnce.Do(func() {
|
||||
common.Close(input, output)
|
||||
})
|
||||
}
|
||||
go d.router.RouteConnectionEx(ctx, output, metadata, N.OnceClose(func(it error) {
|
||||
closePipe()
|
||||
close(done)
|
||||
}))
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (d *routerDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
originDialer, ok := d.router.(routedOriginPacketDialer)
|
||||
if !ok {
|
||||
return nil, E.New("router does not support cloudflare routed packet dialing")
|
||||
}
|
||||
packetConn, err := originDialer.DialRoutePacketConnection(ctx, adapter.InboundContext{
|
||||
Inbound: d.tag,
|
||||
InboundType: C.TypeCloudflared,
|
||||
Network: N.NetworkUDP,
|
||||
Destination: destination,
|
||||
UDPConnect: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bufio.NewNetPacketConn(packetConn), nil
|
||||
}
|
||||
|
||||
type routedOriginPacketDialer interface {
|
||||
DialRoutePacketConnection(ctx context.Context, metadata adapter.InboundContext) (N.PacketConn, error)
|
||||
}
|
||||
|
||||
// icmpRouterHandler bridges cloudflared.ICMPHandler to router.PreMatch.
|
||||
type icmpRouterHandler struct {
|
||||
router adapter.Router
|
||||
tag string
|
||||
}
|
||||
|
||||
func (h *icmpRouterHandler) RouteICMPConnection(ctx context.Context, session tun.DirectRouteSession, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
|
||||
var ipVersion uint8
|
||||
if session.Source.Is4() {
|
||||
ipVersion = 4
|
||||
} else {
|
||||
ipVersion = 6
|
||||
}
|
||||
metadata := adapter.InboundContext{
|
||||
Inbound: h.tag,
|
||||
InboundType: C.TypeCloudflared,
|
||||
IPVersion: ipVersion,
|
||||
Network: N.NetworkICMP,
|
||||
Source: M.SocksaddrFrom(session.Source, 0),
|
||||
Destination: M.SocksaddrFrom(session.Destination, 0),
|
||||
OriginDestination: M.SocksaddrFrom(session.Destination, 0),
|
||||
}
|
||||
return h.router.PreMatch(metadata, routeContext, timeout, false)
|
||||
}
|
||||
@@ -125,7 +125,6 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
UDPTimeout: udpTimeout,
|
||||
Handler: inbound,
|
||||
MasqueradeHandler: masqueradeHandler,
|
||||
BBRProfile: options.BBRProfile,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -73,14 +73,12 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
ServerAddress: options.ServerOptions.Build(),
|
||||
ServerPorts: options.ServerPorts,
|
||||
HopInterval: time.Duration(options.HopInterval),
|
||||
HopIntervalMax: time.Duration(options.HopIntervalMax),
|
||||
SendBPS: uint64(options.UpMbps * hysteria.MbpsToBps),
|
||||
ReceiveBPS: uint64(options.DownMbps * hysteria.MbpsToBps),
|
||||
SalamanderPassword: salamanderPassword,
|
||||
Password: options.Password,
|
||||
TLSConfig: tlsConfig,
|
||||
UDPDisabled: !common.Contains(networkList, N.NetworkUDP),
|
||||
BBRProfile: options.BBRProfile,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -29,10 +29,7 @@ import (
|
||||
"golang.org/x/net/http2/h2c"
|
||||
)
|
||||
|
||||
var (
|
||||
ConfigureHTTP3ListenerFunc func(ctx context.Context, logger logger.Logger, listener *listener.Listener, handler http.Handler, tlsConfig tls.ServerConfig, options option.NaiveInboundOptions) (io.Closer, error)
|
||||
WrapError func(error) error
|
||||
)
|
||||
var ConfigureHTTP3ListenerFunc func(ctx context.Context, logger logger.Logger, listener *listener.Listener, handler http.Handler, tlsConfig tls.ServerConfig, options option.NaiveInboundOptions) (io.Closer, error)
|
||||
|
||||
func RegisterInbound(registry *inbound.Registry) {
|
||||
inbound.Register[option.NaiveInboundOptions](registry, C.TypeNaive, NewInbound)
|
||||
|
||||
@@ -179,18 +179,18 @@ type naiveConn struct {
|
||||
|
||||
func (c *naiveConn) Read(p []byte) (n int, err error) {
|
||||
n, err = c.readWithPadding(c.Conn, p)
|
||||
return n, wrapError(err)
|
||||
return n, baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveConn) Write(p []byte) (n int, err error) {
|
||||
n, err = c.writeChunked(c.Conn, p)
|
||||
return n, wrapError(err)
|
||||
return n, baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveConn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
defer buffer.Release()
|
||||
err := c.writeBufferWithPadding(c.Conn, buffer)
|
||||
return wrapError(err)
|
||||
return baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveConn) FrontHeadroom() int { return c.frontHeadroom() }
|
||||
@@ -210,7 +210,7 @@ type naiveH2Conn struct {
|
||||
|
||||
func (c *naiveH2Conn) Read(p []byte) (n int, err error) {
|
||||
n, err = c.readWithPadding(c.reader, p)
|
||||
return n, wrapError(err)
|
||||
return n, baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) Write(p []byte) (n int, err error) {
|
||||
@@ -218,7 +218,7 @@ func (c *naiveH2Conn) Write(p []byte) (n int, err error) {
|
||||
if err == nil {
|
||||
c.flusher.Flush()
|
||||
}
|
||||
return n, wrapError(err)
|
||||
return n, baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
@@ -227,15 +227,7 @@ func (c *naiveH2Conn) WriteBuffer(buffer *buf.Buffer) error {
|
||||
if err == nil {
|
||||
c.flusher.Flush()
|
||||
}
|
||||
return wrapError(err)
|
||||
}
|
||||
|
||||
func wrapError(err error) error {
|
||||
err = baderror.WrapH2(err)
|
||||
if WrapError != nil {
|
||||
err = WrapError(err)
|
||||
}
|
||||
return err
|
||||
return baderror.WrapH2(err)
|
||||
}
|
||||
|
||||
func (c *naiveH2Conn) Close() error {
|
||||
|
||||
@@ -124,5 +124,4 @@ func init() {
|
||||
|
||||
return quicListener, nil
|
||||
}
|
||||
naive.WrapError = qtls.WrapError
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_naive_outbound,badlinkname,tfogo_checklinkname0
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_naive_outbound,badlinkname,tfogo_checklinkname0
|
||||
@@ -1 +1 @@
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,badlinkname,tfogo_checklinkname0
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,badlinkname,tfogo_checklinkname0
|
||||
@@ -1 +1 @@
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_cloudflared,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0
|
||||
with_gvisor,with_quic,with_dhcp,with_wireguard,with_utls,with_acme,with_clash_api,with_tailscale,with_ccm,with_ocm,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0
|
||||
109
route/dial.go
109
route/dial.go
@@ -1,109 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
R "github.com/sagernet/sing-box/route/rule"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
// DialRoutePacketConnection dials a routed connected UDP packet connection for metadata.
|
||||
func (r *Router) DialRoutePacketConnection(ctx context.Context, metadata adapter.InboundContext) (N.PacketConn, error) {
|
||||
metadata.Network = N.NetworkUDP
|
||||
metadata.UDPConnect = true
|
||||
ctx = adapter.WithContext(ctx, &metadata)
|
||||
|
||||
selectedRule, selectedOutbound, err := r.selectRoutedOutbound(ctx, &metadata, N.NetworkUDP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var remoteConn net.Conn
|
||||
if len(metadata.DestinationAddresses) > 0 || metadata.Destination.IsIP() {
|
||||
remoteConn, err = dialer.DialSerialNetwork(
|
||||
ctx,
|
||||
selectedOutbound,
|
||||
N.NetworkUDP,
|
||||
metadata.Destination,
|
||||
metadata.DestinationAddresses,
|
||||
metadata.NetworkStrategy,
|
||||
metadata.NetworkType,
|
||||
metadata.FallbackNetworkType,
|
||||
metadata.FallbackDelay,
|
||||
)
|
||||
} else {
|
||||
remoteConn, err = selectedOutbound.DialContext(ctx, N.NetworkUDP, metadata.Destination)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var packetConn N.PacketConn = bufio.NewUnbindPacketConn(remoteConn)
|
||||
for _, tracker := range r.trackers {
|
||||
packetConn = tracker.RoutedPacketConnection(ctx, packetConn, metadata, selectedRule, selectedOutbound)
|
||||
}
|
||||
if metadata.FakeIP {
|
||||
packetConn = bufio.NewNATPacketConn(bufio.NewNetPacketConn(packetConn), metadata.OriginDestination, metadata.Destination)
|
||||
}
|
||||
return packetConn, nil
|
||||
}
|
||||
|
||||
func (r *Router) selectRoutedOutbound(
|
||||
ctx context.Context,
|
||||
metadata *adapter.InboundContext,
|
||||
network string,
|
||||
) (adapter.Rule, adapter.Outbound, error) {
|
||||
selectedRule, _, buffers, packetBuffers, err := r.matchRule(ctx, metadata, false, false, nil, nil)
|
||||
if len(buffers) > 0 {
|
||||
buf.ReleaseMulti(buffers)
|
||||
}
|
||||
if len(packetBuffers) > 0 {
|
||||
N.ReleaseMultiPacketBuffer(packetBuffers)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var selectedOutbound adapter.Outbound
|
||||
if selectedRule != nil {
|
||||
switch action := selectedRule.Action().(type) {
|
||||
case *R.RuleActionRoute:
|
||||
var loaded bool
|
||||
selectedOutbound, loaded = r.outbound.Outbound(action.Outbound)
|
||||
if !loaded {
|
||||
return nil, nil, E.New("outbound not found: ", action.Outbound)
|
||||
}
|
||||
case *R.RuleActionBypass:
|
||||
if action.Outbound != "" {
|
||||
var loaded bool
|
||||
selectedOutbound, loaded = r.outbound.Outbound(action.Outbound)
|
||||
if !loaded {
|
||||
return nil, nil, E.New("outbound not found: ", action.Outbound)
|
||||
}
|
||||
}
|
||||
case *R.RuleActionReject:
|
||||
if action.Method == C.RuleActionRejectMethodReply {
|
||||
return nil, nil, E.New("reject method `reply` is not supported for dialed connections")
|
||||
}
|
||||
return nil, nil, action.Error(ctx)
|
||||
case *R.RuleActionHijackDNS:
|
||||
return nil, nil, E.New("DNS hijack is not supported for dialed connections")
|
||||
}
|
||||
}
|
||||
|
||||
if selectedOutbound == nil {
|
||||
selectedOutbound = r.outbound.Default()
|
||||
}
|
||||
if !common.Contains(selectedOutbound.Network(), network) {
|
||||
return nil, nil, E.New(network, " is not supported by outbound: ", selectedOutbound.Tag())
|
||||
}
|
||||
return selectedRule, selectedOutbound, nil
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package rule
|
||||
|
||||
import "github.com/sagernet/sing-box/adapter"
|
||||
|
||||
type ruleMatchState uint8
|
||||
|
||||
const (
|
||||
ruleMatchSourceAddress ruleMatchState = 1 << iota
|
||||
ruleMatchSourcePort
|
||||
ruleMatchDestinationAddress
|
||||
ruleMatchDestinationPort
|
||||
)
|
||||
|
||||
type ruleMatchStateSet uint16
|
||||
|
||||
func singleRuleMatchState(state ruleMatchState) ruleMatchStateSet {
|
||||
return 1 << state
|
||||
}
|
||||
|
||||
func emptyRuleMatchState() ruleMatchStateSet {
|
||||
return singleRuleMatchState(0)
|
||||
}
|
||||
|
||||
func (s ruleMatchStateSet) isEmpty() bool {
|
||||
return s == 0
|
||||
}
|
||||
|
||||
func (s ruleMatchStateSet) contains(state ruleMatchState) bool {
|
||||
return s&(1<<state) != 0
|
||||
}
|
||||
|
||||
func (s ruleMatchStateSet) add(state ruleMatchState) ruleMatchStateSet {
|
||||
return s | singleRuleMatchState(state)
|
||||
}
|
||||
|
||||
func (s ruleMatchStateSet) merge(other ruleMatchStateSet) ruleMatchStateSet {
|
||||
return s | other
|
||||
}
|
||||
|
||||
func (s ruleMatchStateSet) combine(other ruleMatchStateSet) ruleMatchStateSet {
|
||||
if s.isEmpty() || other.isEmpty() {
|
||||
return 0
|
||||
}
|
||||
var combined ruleMatchStateSet
|
||||
for left := ruleMatchState(0); left < 16; left++ {
|
||||
if !s.contains(left) {
|
||||
continue
|
||||
}
|
||||
for right := ruleMatchState(0); right < 16; right++ {
|
||||
if !other.contains(right) {
|
||||
continue
|
||||
}
|
||||
combined = combined.add(left | right)
|
||||
}
|
||||
}
|
||||
return combined
|
||||
}
|
||||
|
||||
func (s ruleMatchStateSet) withBase(base ruleMatchState) ruleMatchStateSet {
|
||||
if s.isEmpty() {
|
||||
return 0
|
||||
}
|
||||
var withBase ruleMatchStateSet
|
||||
for state := ruleMatchState(0); state < 16; state++ {
|
||||
if !s.contains(state) {
|
||||
continue
|
||||
}
|
||||
withBase = withBase.add(state | base)
|
||||
}
|
||||
return withBase
|
||||
}
|
||||
|
||||
func (s ruleMatchStateSet) filter(allowed func(ruleMatchState) bool) ruleMatchStateSet {
|
||||
var filtered ruleMatchStateSet
|
||||
for state := ruleMatchState(0); state < 16; state++ {
|
||||
if !s.contains(state) {
|
||||
continue
|
||||
}
|
||||
if allowed(state) {
|
||||
filtered = filtered.add(state)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
type ruleStateMatcher interface {
|
||||
matchStates(metadata *adapter.InboundContext) ruleMatchStateSet
|
||||
}
|
||||
|
||||
type ruleStateMatcherWithBase interface {
|
||||
matchStatesWithBase(metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet
|
||||
}
|
||||
|
||||
func matchHeadlessRuleStates(rule adapter.HeadlessRule, metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return matchHeadlessRuleStatesWithBase(rule, metadata, 0)
|
||||
}
|
||||
|
||||
func matchHeadlessRuleStatesWithBase(rule adapter.HeadlessRule, metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
||||
if matcher, isStateMatcher := rule.(ruleStateMatcherWithBase); isStateMatcher {
|
||||
return matcher.matchStatesWithBase(metadata, base)
|
||||
}
|
||||
if matcher, isStateMatcher := rule.(ruleStateMatcher); isStateMatcher {
|
||||
return matcher.matchStates(metadata).withBase(base)
|
||||
}
|
||||
if rule.Match(metadata) {
|
||||
return emptyRuleMatchState().withBase(base)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func matchRuleItemStates(item RuleItem, metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return matchRuleItemStatesWithBase(item, metadata, 0)
|
||||
}
|
||||
|
||||
func matchRuleItemStatesWithBase(item RuleItem, metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
||||
if matcher, isStateMatcher := item.(ruleStateMatcherWithBase); isStateMatcher {
|
||||
return matcher.matchStatesWithBase(metadata, base)
|
||||
}
|
||||
if matcher, isStateMatcher := item.(ruleStateMatcher); isStateMatcher {
|
||||
return matcher.matchStates(metadata).withBase(base)
|
||||
}
|
||||
if item.Match(metadata) {
|
||||
return emptyRuleMatchState().withBase(base)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -52,124 +52,88 @@ func (r *abstractDefaultRule) Close() error {
|
||||
}
|
||||
|
||||
func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool {
|
||||
return !r.matchStates(metadata).isEmpty()
|
||||
}
|
||||
|
||||
func (r *abstractDefaultRule) destinationIPCIDRMatchesSource(metadata *adapter.InboundContext) bool {
|
||||
return !metadata.IgnoreDestinationIPCIDRMatch && metadata.IPCIDRMatchSource && len(r.destinationIPCIDRItems) > 0
|
||||
}
|
||||
|
||||
func (r *abstractDefaultRule) destinationIPCIDRMatchesDestination(metadata *adapter.InboundContext) bool {
|
||||
return !metadata.IgnoreDestinationIPCIDRMatch && !metadata.IPCIDRMatchSource && len(r.destinationIPCIDRItems) > 0
|
||||
}
|
||||
|
||||
func (r *abstractDefaultRule) requiresSourceAddressMatch(metadata *adapter.InboundContext) bool {
|
||||
return len(r.sourceAddressItems) > 0 || r.destinationIPCIDRMatchesSource(metadata)
|
||||
}
|
||||
|
||||
func (r *abstractDefaultRule) requiresDestinationAddressMatch(metadata *adapter.InboundContext) bool {
|
||||
return len(r.destinationAddressItems) > 0 || r.destinationIPCIDRMatchesDestination(metadata)
|
||||
}
|
||||
|
||||
func (r *abstractDefaultRule) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return r.matchStatesWithBase(metadata, 0)
|
||||
}
|
||||
|
||||
func (r *abstractDefaultRule) matchStatesWithBase(metadata *adapter.InboundContext, inheritedBase ruleMatchState) ruleMatchStateSet {
|
||||
if len(r.allItems) == 0 {
|
||||
return emptyRuleMatchState().withBase(inheritedBase)
|
||||
return true
|
||||
}
|
||||
evaluationBase := inheritedBase
|
||||
if r.invert {
|
||||
evaluationBase = 0
|
||||
}
|
||||
baseState := evaluationBase
|
||||
if len(r.sourceAddressItems) > 0 {
|
||||
|
||||
if len(r.sourceAddressItems) > 0 && !metadata.SourceAddressMatch {
|
||||
metadata.DidMatch = true
|
||||
if matchAnyItem(r.sourceAddressItems, metadata) {
|
||||
baseState |= ruleMatchSourceAddress
|
||||
for _, item := range r.sourceAddressItems {
|
||||
if item.Match(metadata) {
|
||||
metadata.SourceAddressMatch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if r.destinationIPCIDRMatchesSource(metadata) && !baseState.has(ruleMatchSourceAddress) {
|
||||
|
||||
if len(r.sourcePortItems) > 0 && !metadata.SourcePortMatch {
|
||||
metadata.DidMatch = true
|
||||
if matchAnyItem(r.destinationIPCIDRItems, metadata) {
|
||||
baseState |= ruleMatchSourceAddress
|
||||
}
|
||||
} else if r.destinationIPCIDRMatchesSource(metadata) {
|
||||
metadata.DidMatch = true
|
||||
}
|
||||
if len(r.sourcePortItems) > 0 {
|
||||
metadata.DidMatch = true
|
||||
if matchAnyItem(r.sourcePortItems, metadata) {
|
||||
baseState |= ruleMatchSourcePort
|
||||
for _, item := range r.sourcePortItems {
|
||||
if item.Match(metadata) {
|
||||
metadata.SourcePortMatch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(r.destinationAddressItems) > 0 {
|
||||
|
||||
if len(r.destinationAddressItems) > 0 && !metadata.DestinationAddressMatch {
|
||||
metadata.DidMatch = true
|
||||
if matchAnyItem(r.destinationAddressItems, metadata) {
|
||||
baseState |= ruleMatchDestinationAddress
|
||||
for _, item := range r.destinationAddressItems {
|
||||
if item.Match(metadata) {
|
||||
metadata.DestinationAddressMatch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if r.destinationIPCIDRMatchesDestination(metadata) && !baseState.has(ruleMatchDestinationAddress) {
|
||||
|
||||
if !metadata.IgnoreDestinationIPCIDRMatch && len(r.destinationIPCIDRItems) > 0 && !metadata.DestinationAddressMatch {
|
||||
metadata.DidMatch = true
|
||||
if matchAnyItem(r.destinationIPCIDRItems, metadata) {
|
||||
baseState |= ruleMatchDestinationAddress
|
||||
}
|
||||
} else if r.destinationIPCIDRMatchesDestination(metadata) {
|
||||
metadata.DidMatch = true
|
||||
}
|
||||
if len(r.destinationPortItems) > 0 {
|
||||
metadata.DidMatch = true
|
||||
if matchAnyItem(r.destinationPortItems, metadata) {
|
||||
baseState |= ruleMatchDestinationPort
|
||||
for _, item := range r.destinationIPCIDRItems {
|
||||
if item.Match(metadata) {
|
||||
metadata.DestinationAddressMatch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.destinationPortItems) > 0 && !metadata.DestinationPortMatch {
|
||||
metadata.DidMatch = true
|
||||
for _, item := range r.destinationPortItems {
|
||||
if item.Match(metadata) {
|
||||
metadata.DestinationPortMatch = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, item := range r.items {
|
||||
metadata.DidMatch = true
|
||||
if !item.Match(metadata) {
|
||||
return r.invertedFailure(inheritedBase)
|
||||
return r.invert
|
||||
}
|
||||
}
|
||||
var stateSet ruleMatchStateSet
|
||||
if r.ruleSetItem != nil {
|
||||
metadata.DidMatch = true
|
||||
stateSet = matchRuleItemStatesWithBase(r.ruleSetItem, metadata, baseState)
|
||||
} else {
|
||||
stateSet = singleRuleMatchState(baseState)
|
||||
}
|
||||
stateSet = stateSet.filter(func(state ruleMatchState) bool {
|
||||
if r.requiresSourceAddressMatch(metadata) && !state.has(ruleMatchSourceAddress) {
|
||||
return false
|
||||
}
|
||||
if len(r.sourcePortItems) > 0 && !state.has(ruleMatchSourcePort) {
|
||||
return false
|
||||
}
|
||||
if r.requiresDestinationAddressMatch(metadata) && !state.has(ruleMatchDestinationAddress) {
|
||||
return false
|
||||
}
|
||||
if len(r.destinationPortItems) > 0 && !state.has(ruleMatchDestinationPort) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if stateSet.isEmpty() {
|
||||
return r.invertedFailure(inheritedBase)
|
||||
}
|
||||
if r.invert {
|
||||
// DNS pre-lookup defers destination address-limit checks until the response phase.
|
||||
if metadata.IgnoreDestinationIPCIDRMatch && stateSet == emptyRuleMatchState() && !metadata.DidMatch && len(r.destinationIPCIDRItems) > 0 {
|
||||
return emptyRuleMatchState().withBase(inheritedBase)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return stateSet
|
||||
}
|
||||
|
||||
func (r *abstractDefaultRule) invertedFailure(base ruleMatchState) ruleMatchStateSet {
|
||||
if r.invert {
|
||||
return emptyRuleMatchState().withBase(base)
|
||||
if len(r.sourceAddressItems) > 0 && !metadata.SourceAddressMatch {
|
||||
return r.invert
|
||||
}
|
||||
return 0
|
||||
|
||||
if len(r.sourcePortItems) > 0 && !metadata.SourcePortMatch {
|
||||
return r.invert
|
||||
}
|
||||
|
||||
if ((!metadata.IgnoreDestinationIPCIDRMatch && len(r.destinationIPCIDRItems) > 0) || len(r.destinationAddressItems) > 0) && !metadata.DestinationAddressMatch {
|
||||
return r.invert
|
||||
}
|
||||
|
||||
if len(r.destinationPortItems) > 0 && !metadata.DestinationPortMatch {
|
||||
return r.invert
|
||||
}
|
||||
|
||||
if !metadata.DidMatch {
|
||||
return true
|
||||
}
|
||||
|
||||
return !r.invert
|
||||
}
|
||||
|
||||
func (r *abstractDefaultRule) Action() adapter.RuleAction {
|
||||
@@ -227,50 +191,17 @@ func (r *abstractLogicalRule) Close() error {
|
||||
}
|
||||
|
||||
func (r *abstractLogicalRule) Match(metadata *adapter.InboundContext) bool {
|
||||
return !r.matchStates(metadata).isEmpty()
|
||||
}
|
||||
|
||||
func (r *abstractLogicalRule) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return r.matchStatesWithBase(metadata, 0)
|
||||
}
|
||||
|
||||
func (r *abstractLogicalRule) matchStatesWithBase(metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
||||
evaluationBase := base
|
||||
if r.invert {
|
||||
evaluationBase = 0
|
||||
}
|
||||
var stateSet ruleMatchStateSet
|
||||
if r.mode == C.LogicalTypeAnd {
|
||||
stateSet = emptyRuleMatchState().withBase(evaluationBase)
|
||||
for _, rule := range r.rules {
|
||||
nestedMetadata := *metadata
|
||||
nestedMetadata.ResetRuleCache()
|
||||
nestedStateSet := matchHeadlessRuleStatesWithBase(rule, &nestedMetadata, evaluationBase)
|
||||
if nestedStateSet.isEmpty() {
|
||||
if r.invert {
|
||||
return emptyRuleMatchState().withBase(base)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
stateSet = stateSet.combine(nestedStateSet)
|
||||
}
|
||||
return common.All(r.rules, func(it adapter.HeadlessRule) bool {
|
||||
metadata.ResetRuleCache()
|
||||
return it.Match(metadata)
|
||||
}) != r.invert
|
||||
} else {
|
||||
for _, rule := range r.rules {
|
||||
nestedMetadata := *metadata
|
||||
nestedMetadata.ResetRuleCache()
|
||||
stateSet = stateSet.merge(matchHeadlessRuleStatesWithBase(rule, &nestedMetadata, evaluationBase))
|
||||
}
|
||||
if stateSet.isEmpty() {
|
||||
if r.invert {
|
||||
return emptyRuleMatchState().withBase(base)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return common.Any(r.rules, func(it adapter.HeadlessRule) bool {
|
||||
metadata.ResetRuleCache()
|
||||
return it.Match(metadata)
|
||||
}) != r.invert
|
||||
}
|
||||
if r.invert {
|
||||
return 0
|
||||
}
|
||||
return stateSet
|
||||
}
|
||||
|
||||
func (r *abstractLogicalRule) Action() adapter.RuleAction {
|
||||
@@ -291,13 +222,3 @@ func (r *abstractLogicalRule) String() string {
|
||||
return "!(" + strings.Join(F.MapToString(r.rules), " "+op+" ") + ")"
|
||||
}
|
||||
}
|
||||
|
||||
func matchAnyItem(items []RuleItem, metadata *adapter.InboundContext) bool {
|
||||
return common.Any(items, func(it RuleItem) bool {
|
||||
return it.Match(metadata)
|
||||
})
|
||||
}
|
||||
|
||||
func (s ruleMatchState) has(target ruleMatchState) bool {
|
||||
return s&target != 0
|
||||
}
|
||||
|
||||
@@ -78,9 +78,9 @@ func newRuleSetOnlyRule(ruleSetMatched bool, invert bool) *DefaultRule {
|
||||
}
|
||||
return &DefaultRule{
|
||||
abstractDefaultRule: abstractDefaultRule{
|
||||
ruleSetItem: ruleSetItem,
|
||||
allItems: []RuleItem{ruleSetItem},
|
||||
invert: invert,
|
||||
items: []RuleItem{ruleSetItem},
|
||||
allItems: []RuleItem{ruleSetItem},
|
||||
invert: invert,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,10 +47,6 @@ type DefaultRule struct {
|
||||
abstractDefaultRule
|
||||
}
|
||||
|
||||
func (r *DefaultRule) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return r.abstractDefaultRule.matchStates(metadata)
|
||||
}
|
||||
|
||||
type RuleItem interface {
|
||||
Match(metadata *adapter.InboundContext) bool
|
||||
String() string
|
||||
@@ -289,7 +285,7 @@ func NewDefaultRule(ctx context.Context, logger log.ContextLogger, options optio
|
||||
matchSource = true
|
||||
}
|
||||
item := NewRuleSetItem(router, options.RuleSet, matchSource, false)
|
||||
rule.ruleSetItem = item
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
return rule, nil
|
||||
@@ -301,10 +297,6 @@ type LogicalRule struct {
|
||||
abstractLogicalRule
|
||||
}
|
||||
|
||||
func (r *LogicalRule) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return r.abstractLogicalRule.matchStates(metadata)
|
||||
}
|
||||
|
||||
func NewLogicalRule(ctx context.Context, logger log.ContextLogger, options option.LogicalRule) (*LogicalRule, error) {
|
||||
action, err := NewRuleAction(ctx, logger, options.RuleAction)
|
||||
if err != nil {
|
||||
|
||||
@@ -47,10 +47,6 @@ type DefaultDNSRule struct {
|
||||
abstractDefaultRule
|
||||
}
|
||||
|
||||
func (r *DefaultDNSRule) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return r.abstractDefaultRule.matchStates(metadata)
|
||||
}
|
||||
|
||||
func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options option.DefaultDNSRule) (*DefaultDNSRule, error) {
|
||||
rule := &DefaultDNSRule{
|
||||
abstractDefaultRule: abstractDefaultRule{
|
||||
@@ -285,7 +281,7 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
|
||||
matchSource = true
|
||||
}
|
||||
item := NewRuleSetItem(router, options.RuleSet, matchSource, options.RuleSetIPCIDRAcceptEmpty)
|
||||
rule.ruleSetItem = item
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
return rule, nil
|
||||
@@ -299,9 +295,12 @@ func (r *DefaultDNSRule) WithAddressLimit() bool {
|
||||
if len(r.destinationIPCIDRItems) > 0 {
|
||||
return true
|
||||
}
|
||||
if r.ruleSetItem != nil {
|
||||
ruleSet, isRuleSet := r.ruleSetItem.(*RuleSetItem)
|
||||
if isRuleSet && ruleSet.ContainsDestinationIPCIDRRule() {
|
||||
for _, rawRule := range r.items {
|
||||
ruleSet, isRuleSet := rawRule.(*RuleSetItem)
|
||||
if !isRuleSet {
|
||||
continue
|
||||
}
|
||||
if ruleSet.ContainsDestinationIPCIDRRule() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -313,11 +312,11 @@ func (r *DefaultDNSRule) Match(metadata *adapter.InboundContext) bool {
|
||||
defer func() {
|
||||
metadata.IgnoreDestinationIPCIDRMatch = false
|
||||
}()
|
||||
return !r.matchStates(metadata).isEmpty()
|
||||
return r.abstractDefaultRule.Match(metadata)
|
||||
}
|
||||
|
||||
func (r *DefaultDNSRule) MatchAddressLimit(metadata *adapter.InboundContext) bool {
|
||||
return !r.matchStates(metadata).isEmpty()
|
||||
return r.abstractDefaultRule.Match(metadata)
|
||||
}
|
||||
|
||||
var _ adapter.DNSRule = (*LogicalDNSRule)(nil)
|
||||
@@ -326,10 +325,6 @@ type LogicalDNSRule struct {
|
||||
abstractLogicalRule
|
||||
}
|
||||
|
||||
func (r *LogicalDNSRule) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return r.abstractLogicalRule.matchStates(metadata)
|
||||
}
|
||||
|
||||
func NewLogicalDNSRule(ctx context.Context, logger log.ContextLogger, options option.LogicalDNSRule) (*LogicalDNSRule, error) {
|
||||
r := &LogicalDNSRule{
|
||||
abstractLogicalRule: abstractLogicalRule{
|
||||
@@ -377,13 +372,29 @@ func (r *LogicalDNSRule) WithAddressLimit() bool {
|
||||
}
|
||||
|
||||
func (r *LogicalDNSRule) Match(metadata *adapter.InboundContext) bool {
|
||||
metadata.IgnoreDestinationIPCIDRMatch = true
|
||||
defer func() {
|
||||
metadata.IgnoreDestinationIPCIDRMatch = false
|
||||
}()
|
||||
return !r.matchStates(metadata).isEmpty()
|
||||
if r.mode == C.LogicalTypeAnd {
|
||||
return common.All(r.rules, func(it adapter.HeadlessRule) bool {
|
||||
metadata.ResetRuleCache()
|
||||
return it.(adapter.DNSRule).Match(metadata)
|
||||
}) != r.invert
|
||||
} else {
|
||||
return common.Any(r.rules, func(it adapter.HeadlessRule) bool {
|
||||
metadata.ResetRuleCache()
|
||||
return it.(adapter.DNSRule).Match(metadata)
|
||||
}) != r.invert
|
||||
}
|
||||
}
|
||||
|
||||
func (r *LogicalDNSRule) MatchAddressLimit(metadata *adapter.InboundContext) bool {
|
||||
return !r.matchStates(metadata).isEmpty()
|
||||
if r.mode == C.LogicalTypeAnd {
|
||||
return common.All(r.rules, func(it adapter.HeadlessRule) bool {
|
||||
metadata.ResetRuleCache()
|
||||
return it.(adapter.DNSRule).MatchAddressLimit(metadata)
|
||||
}) != r.invert
|
||||
} else {
|
||||
return common.Any(r.rules, func(it adapter.HeadlessRule) bool {
|
||||
metadata.ResetRuleCache()
|
||||
return it.(adapter.DNSRule).MatchAddressLimit(metadata)
|
||||
}) != r.invert
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,6 @@ type DefaultHeadlessRule struct {
|
||||
abstractDefaultRule
|
||||
}
|
||||
|
||||
func (r *DefaultHeadlessRule) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return r.abstractDefaultRule.matchStates(metadata)
|
||||
}
|
||||
|
||||
func NewDefaultHeadlessRule(ctx context.Context, options option.DefaultHeadlessRule) (*DefaultHeadlessRule, error) {
|
||||
networkManager := service.FromContext[adapter.NetworkManager](ctx)
|
||||
rule := &DefaultHeadlessRule{
|
||||
@@ -45,11 +41,6 @@ func NewDefaultHeadlessRule(ctx context.Context, options option.DefaultHeadlessR
|
||||
invert: options.Invert,
|
||||
},
|
||||
}
|
||||
if len(options.QueryType) > 0 {
|
||||
item := NewQueryTypeItem(options.QueryType)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.Network) > 0 {
|
||||
item := NewNetworkItem(options.Network)
|
||||
rule.items = append(rule.items, item)
|
||||
@@ -208,10 +199,6 @@ type LogicalHeadlessRule struct {
|
||||
abstractLogicalRule
|
||||
}
|
||||
|
||||
func (r *LogicalHeadlessRule) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return r.abstractLogicalRule.matchStates(metadata)
|
||||
}
|
||||
|
||||
func NewLogicalHeadlessRule(ctx context.Context, options option.LogicalHeadlessRule) (*LogicalHeadlessRule, error) {
|
||||
r := &LogicalHeadlessRule{
|
||||
abstractLogicalRule{
|
||||
|
||||
@@ -41,23 +41,16 @@ func (r *RuleSetItem) Start() error {
|
||||
}
|
||||
|
||||
func (r *RuleSetItem) Match(metadata *adapter.InboundContext) bool {
|
||||
return !r.matchStates(metadata).isEmpty()
|
||||
}
|
||||
|
||||
func (r *RuleSetItem) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return r.matchStatesWithBase(metadata, 0)
|
||||
}
|
||||
|
||||
func (r *RuleSetItem) matchStatesWithBase(metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
||||
var stateSet ruleMatchStateSet
|
||||
for _, ruleSet := range r.setList {
|
||||
nestedMetadata := *metadata
|
||||
nestedMetadata.ResetRuleMatchCache()
|
||||
nestedMetadata.IPCIDRMatchSource = r.ipCidrMatchSource
|
||||
nestedMetadata.IPCIDRAcceptEmpty = r.ipCidrAcceptEmpty
|
||||
stateSet = stateSet.merge(matchHeadlessRuleStatesWithBase(ruleSet, &nestedMetadata, base))
|
||||
if ruleSet.Match(&nestedMetadata) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return stateSet
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *RuleSetItem) ContainsDestinationIPCIDRRule() bool {
|
||||
|
||||
@@ -202,19 +202,12 @@ func (s *LocalRuleSet) Close() error {
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) Match(metadata *adapter.InboundContext) bool {
|
||||
return !s.matchStates(metadata).isEmpty()
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return s.matchStatesWithBase(metadata, 0)
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) matchStatesWithBase(metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
||||
var stateSet ruleMatchStateSet
|
||||
for _, rule := range s.rules {
|
||||
nestedMetadata := *metadata
|
||||
nestedMetadata.ResetRuleMatchCache()
|
||||
stateSet = stateSet.merge(matchHeadlessRuleStatesWithBase(rule, &nestedMetadata, base))
|
||||
if rule.Match(&nestedMetadata) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return stateSet
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -322,19 +322,12 @@ func (s *RemoteRuleSet) Close() error {
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) Match(metadata *adapter.InboundContext) bool {
|
||||
return !s.matchStates(metadata).isEmpty()
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) matchStates(metadata *adapter.InboundContext) ruleMatchStateSet {
|
||||
return s.matchStatesWithBase(metadata, 0)
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) matchStatesWithBase(metadata *adapter.InboundContext, base ruleMatchState) ruleMatchStateSet {
|
||||
var stateSet ruleMatchStateSet
|
||||
for _, rule := range s.rules {
|
||||
nestedMetadata := *metadata
|
||||
nestedMetadata.ResetRuleMatchCache()
|
||||
stateSet = stateSet.merge(matchHeadlessRuleStatesWithBase(rule, &nestedMetadata, base))
|
||||
if rule.Match(&nestedMetadata) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return stateSet
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,852 +0,0 @@
|
||||
package rule
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/convertor/adguard"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
slogger "github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRouteRuleSetMergeDestinationAddressGroup(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := []struct {
|
||||
name string
|
||||
metadata adapter.InboundContext
|
||||
inner adapter.HeadlessRule
|
||||
}{
|
||||
{
|
||||
name: "domain",
|
||||
metadata: testMetadata("www.example.com"),
|
||||
inner: headlessDefaultRule(t, func(rule *abstractDefaultRule) { addDestinationAddressItem(t, rule, []string{"www.example.com"}, nil) }),
|
||||
},
|
||||
{
|
||||
name: "domain_suffix",
|
||||
metadata: testMetadata("www.example.com"),
|
||||
inner: headlessDefaultRule(t, func(rule *abstractDefaultRule) { addDestinationAddressItem(t, rule, nil, []string{"example.com"}) }),
|
||||
},
|
||||
{
|
||||
name: "domain_keyword",
|
||||
metadata: testMetadata("www.example.com"),
|
||||
inner: headlessDefaultRule(t, func(rule *abstractDefaultRule) { addDestinationKeywordItem(rule, []string{"example"}) }),
|
||||
},
|
||||
{
|
||||
name: "domain_regex",
|
||||
metadata: testMetadata("www.example.com"),
|
||||
inner: headlessDefaultRule(t, func(rule *abstractDefaultRule) { addDestinationRegexItem(t, rule, []string{`^www\.example\.com$`}) }),
|
||||
},
|
||||
{
|
||||
name: "ip_cidr",
|
||||
metadata: func() adapter.InboundContext {
|
||||
metadata := testMetadata("lookup.example")
|
||||
metadata.DestinationAddresses = []netip.Addr{netip.MustParseAddr("8.8.8.8")}
|
||||
return metadata
|
||||
}(),
|
||||
inner: headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationIPCIDRItem(t, rule, []string{"8.8.8.0/24"})
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ruleSet := newLocalRuleSetForTest("merge-destination", testCase.inner)
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.True(t, rule.Match(&testCase.metadata))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouteRuleSetMergeSourceAndPortGroups(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("source address", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("merge-source-address", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addSourceAddressItem(t, rule, []string{"10.0.0.0/8"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addSourceAddressItem(t, rule, []string{"198.51.100.0/24"})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("source address via ruleset ipcidr match source", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("merge-source-address-ipcidr", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationIPCIDRItem(t, rule, []string{"10.0.0.0/8"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{
|
||||
setList: []adapter.RuleSet{ruleSet},
|
||||
ipCidrMatchSource: true,
|
||||
})
|
||||
addSourceAddressItem(t, rule, []string{"198.51.100.0/24"})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("destination port", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("merge-destination-port", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationPortItem(rule, []uint16{443})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addDestinationPortItem(rule, []uint16{8443})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("destination port range", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("merge-destination-port-range", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationPortRangeItem(t, rule, []string{"400:500"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addDestinationPortItem(rule, []uint16{8443})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("source port", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("merge-source-port", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addSourcePortItem(rule, []uint16{1000})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addSourcePortItem(rule, []uint16{2000})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("source port range", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("merge-source-port-range", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addSourcePortRangeItem(t, rule, []string{"900:1100"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addSourcePortItem(rule, []uint16{2000})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouteRuleSetOuterGroupedStateMergesIntoSameGroup(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := []struct {
|
||||
name string
|
||||
metadata adapter.InboundContext
|
||||
buildOuter func(*testing.T, *abstractDefaultRule)
|
||||
buildInner func(*testing.T, *abstractDefaultRule)
|
||||
}{
|
||||
{
|
||||
name: "destination address",
|
||||
metadata: testMetadata("www.example.com"),
|
||||
buildOuter: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
},
|
||||
buildInner: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addDestinationAddressItem(t, rule, nil, []string{"google.com"})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "source address",
|
||||
metadata: testMetadata("www.example.com"),
|
||||
buildOuter: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addSourceAddressItem(t, rule, []string{"10.0.0.0/8"})
|
||||
},
|
||||
buildInner: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addSourceAddressItem(t, rule, []string{"198.51.100.0/24"})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "source port",
|
||||
metadata: testMetadata("www.example.com"),
|
||||
buildOuter: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addSourcePortItem(rule, []uint16{1000})
|
||||
},
|
||||
buildInner: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addSourcePortItem(rule, []uint16{2000})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "destination port",
|
||||
metadata: testMetadata("www.example.com"),
|
||||
buildOuter: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addDestinationPortItem(rule, []uint16{443})
|
||||
},
|
||||
buildInner: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addDestinationPortItem(rule, []uint16{8443})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "destination ip cidr",
|
||||
metadata: func() adapter.InboundContext {
|
||||
metadata := testMetadata("lookup.example")
|
||||
metadata.DestinationAddresses = []netip.Addr{netip.MustParseAddr("203.0.113.1")}
|
||||
return metadata
|
||||
}(),
|
||||
buildOuter: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
},
|
||||
buildInner: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addDestinationIPCIDRItem(t, rule, []string{"198.51.100.0/24"})
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ruleSet := newLocalRuleSetForTest("outer-merge-"+testCase.name, headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
testCase.buildInner(t, rule)
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
testCase.buildOuter(t, rule)
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.True(t, rule.Match(&testCase.metadata))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouteRuleSetOtherFieldsStayAnd(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("other-fields-and", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkUDP}))
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
}
|
||||
|
||||
func TestRouteRuleSetMergedBranchKeepsAndConstraints(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("outer group does not bypass inner non grouped condition", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("network-and", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkUDP}))
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("outer group does not satisfy different grouped branch", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("different-group", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"google.com"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addSourcePortItem(rule, []uint16{1000})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouteRuleSetOrSemantics(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("later ruleset can satisfy outer group", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
emptyStateSet := newLocalRuleSetForTest("network-only", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkTCP}))
|
||||
}))
|
||||
destinationStateSet := newLocalRuleSetForTest("domain-only", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{emptyStateSet, destinationStateSet}})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("later rule in same set can satisfy outer group", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest(
|
||||
"rule-set-or",
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkTCP}))
|
||||
}),
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
}),
|
||||
)
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("cross ruleset union is not allowed", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
sourceStateSet := newLocalRuleSetForTest("source-only", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addSourcePortItem(rule, []uint16{1000})
|
||||
}))
|
||||
destinationStateSet := newLocalRuleSetForTest("destination-only", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{sourceStateSet, destinationStateSet}})
|
||||
addSourcePortItem(rule, []uint16{2000})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouteRuleSetLogicalSemantics(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("logical or keeps all successful branch states", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("logical-or", headlessLogicalRule(
|
||||
C.LogicalTypeOr,
|
||||
false,
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkTCP}))
|
||||
}),
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
}),
|
||||
))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("logical and unions child states", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("logical-and", headlessLogicalRule(
|
||||
C.LogicalTypeAnd,
|
||||
false,
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
}),
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addSourcePortItem(rule, []uint16{1000})
|
||||
}),
|
||||
))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
addSourcePortItem(rule, []uint16{2000})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("invert success does not contribute positive state", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("invert", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
rule.invert = true
|
||||
addDestinationAddressItem(t, rule, nil, []string{"cn"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouteRuleSetInvertMergedBranchSemantics(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("default invert keeps inherited group outside grouped predicate", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("invert-grouped", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
rule.invert = true
|
||||
addDestinationAddressItem(t, rule, nil, []string{"google.com"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("default invert keeps inherited group after negation succeeds", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("invert-network", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
rule.invert = true
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkUDP}))
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("logical invert keeps inherited group outside grouped predicate", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("logical-invert-grouped", headlessLogicalRule(
|
||||
C.LogicalTypeOr,
|
||||
true,
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"google.com"})
|
||||
}),
|
||||
))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("logical invert keeps inherited group after negation succeeds", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("logical-invert-network", headlessLogicalRule(
|
||||
C.LogicalTypeOr,
|
||||
true,
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkUDP}))
|
||||
}),
|
||||
))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRouteRuleSetNoLeakageRegressions(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("same ruleset failed branch does not leak", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest(
|
||||
"same-set",
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
addSourcePortItem(rule, []uint16{1})
|
||||
}),
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
addSourcePortItem(rule, []uint16{1000})
|
||||
}),
|
||||
)
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("adguard exclusion remains isolated across rulesets", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("im.qq.com")
|
||||
excludeSet := newLocalRuleSetForTest("adguard", mustAdGuardRule(t, "@@||im.qq.com^\n||whatever1.com^\n"))
|
||||
otherSet := newLocalRuleSetForTest("other", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"whatever2.com"})
|
||||
}))
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{excludeSet, otherSet}})
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
})
|
||||
}
|
||||
|
||||
func TestDefaultRuleDoesNotReuseGroupedMatchCacheAcrossEvaluations(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
|
||||
metadata.Destination.Fqdn = "www.example.org"
|
||||
require.False(t, rule.Match(&metadata))
|
||||
}
|
||||
|
||||
func TestRouteRuleSetRemoteUsesSameSemantics(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newRemoteRuleSetForTest(
|
||||
"remote",
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkTCP}))
|
||||
}),
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
}),
|
||||
)
|
||||
rule := routeRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
}
|
||||
|
||||
func TestDNSRuleSetSemantics(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("outer destination group merges into matching ruleset branch", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.baidu.com")
|
||||
ruleSet := newLocalRuleSetForTest("dns-merged-branch", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"google.com"})
|
||||
}))
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"baidu.com"})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("outer destination group does not bypass ruleset non grouped condition", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("dns-network-and", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkUDP}))
|
||||
}))
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("outer destination group stays outside inverted grouped branch", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.baidu.com")
|
||||
ruleSet := newLocalRuleSetForTest("dns-invert-grouped", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
rule.invert = true
|
||||
addDestinationAddressItem(t, rule, nil, []string{"google.com"})
|
||||
}))
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"baidu.com"})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("outer destination group stays outside inverted logical branch", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("dns-logical-invert-network", headlessLogicalRule(
|
||||
C.LogicalTypeOr,
|
||||
true,
|
||||
headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkUDP}))
|
||||
}),
|
||||
))
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.True(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("match address limit merges destination group", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("dns-merge", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
}))
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.True(t, rule.MatchAddressLimit(&metadata))
|
||||
})
|
||||
t.Run("dns keeps ruleset or semantics", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
emptyStateSet := newLocalRuleSetForTest("dns-empty", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkTCP}))
|
||||
}))
|
||||
destinationStateSet := newLocalRuleSetForTest("dns-destination", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationAddressItem(t, rule, nil, []string{"example.com"})
|
||||
}))
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{emptyStateSet, destinationStateSet}})
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.True(t, rule.MatchAddressLimit(&metadata))
|
||||
})
|
||||
t.Run("ruleset ip cidr flags stay scoped", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("www.example.com")
|
||||
ruleSet := newLocalRuleSetForTest("dns-ipcidr", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
}))
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
addRuleSetItem(rule, &RuleSetItem{
|
||||
setList: []adapter.RuleSet{ruleSet},
|
||||
ipCidrAcceptEmpty: true,
|
||||
})
|
||||
})
|
||||
require.True(t, rule.MatchAddressLimit(&metadata))
|
||||
require.False(t, metadata.IPCIDRMatchSource)
|
||||
require.False(t, metadata.IPCIDRAcceptEmpty)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSInvertAddressLimitPreLookupRegression(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := []struct {
|
||||
name string
|
||||
build func(*testing.T, *abstractDefaultRule)
|
||||
matchedAddrs []netip.Addr
|
||||
unmatchedAddrs []netip.Addr
|
||||
}{
|
||||
{
|
||||
name: "ip_cidr",
|
||||
build: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
},
|
||||
matchedAddrs: []netip.Addr{netip.MustParseAddr("203.0.113.1")},
|
||||
unmatchedAddrs: []netip.Addr{netip.MustParseAddr("8.8.8.8")},
|
||||
},
|
||||
{
|
||||
name: "ip_is_private",
|
||||
build: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addDestinationIPIsPrivateItem(rule)
|
||||
},
|
||||
matchedAddrs: []netip.Addr{netip.MustParseAddr("10.0.0.1")},
|
||||
unmatchedAddrs: []netip.Addr{netip.MustParseAddr("8.8.8.8")},
|
||||
},
|
||||
{
|
||||
name: "ip_accept_any",
|
||||
build: func(t *testing.T, rule *abstractDefaultRule) {
|
||||
t.Helper()
|
||||
addDestinationIPAcceptAnyItem(rule)
|
||||
},
|
||||
matchedAddrs: []netip.Addr{netip.MustParseAddr("203.0.113.1")},
|
||||
},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
rule.invert = true
|
||||
testCase.build(t, rule)
|
||||
})
|
||||
|
||||
preLookupMetadata := testMetadata("lookup.example")
|
||||
require.True(t, rule.Match(&preLookupMetadata))
|
||||
|
||||
matchedMetadata := testMetadata("lookup.example")
|
||||
matchedMetadata.DestinationAddresses = testCase.matchedAddrs
|
||||
require.False(t, rule.MatchAddressLimit(&matchedMetadata))
|
||||
|
||||
unmatchedMetadata := testMetadata("lookup.example")
|
||||
unmatchedMetadata.DestinationAddresses = testCase.unmatchedAddrs
|
||||
require.True(t, rule.MatchAddressLimit(&unmatchedMetadata))
|
||||
})
|
||||
}
|
||||
t.Run("mixed resolved and deferred fields keep old pre lookup false", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("lookup.example")
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
rule.invert = true
|
||||
addOtherItem(rule, NewNetworkItem([]string{N.NetworkTCP}))
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
})
|
||||
t.Run("ruleset only deferred fields keep old pre lookup false", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
metadata := testMetadata("lookup.example")
|
||||
ruleSet := newLocalRuleSetForTest("dns-ruleset-ipcidr", headlessDefaultRule(t, func(rule *abstractDefaultRule) {
|
||||
addDestinationIPCIDRItem(t, rule, []string{"203.0.113.0/24"})
|
||||
}))
|
||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||
rule.invert = true
|
||||
addRuleSetItem(rule, &RuleSetItem{setList: []adapter.RuleSet{ruleSet}})
|
||||
})
|
||||
require.False(t, rule.Match(&metadata))
|
||||
})
|
||||
}
|
||||
|
||||
func routeRuleForTest(build func(*abstractDefaultRule)) *DefaultRule {
|
||||
rule := &DefaultRule{}
|
||||
build(&rule.abstractDefaultRule)
|
||||
return rule
|
||||
}
|
||||
|
||||
func dnsRuleForTest(build func(*abstractDefaultRule)) *DefaultDNSRule {
|
||||
rule := &DefaultDNSRule{}
|
||||
build(&rule.abstractDefaultRule)
|
||||
return rule
|
||||
}
|
||||
|
||||
func headlessDefaultRule(t *testing.T, build func(*abstractDefaultRule)) *DefaultHeadlessRule {
|
||||
t.Helper()
|
||||
rule := &DefaultHeadlessRule{}
|
||||
build(&rule.abstractDefaultRule)
|
||||
return rule
|
||||
}
|
||||
|
||||
func headlessLogicalRule(mode string, invert bool, rules ...adapter.HeadlessRule) *LogicalHeadlessRule {
|
||||
return &LogicalHeadlessRule{
|
||||
abstractLogicalRule: abstractLogicalRule{
|
||||
rules: rules,
|
||||
mode: mode,
|
||||
invert: invert,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newLocalRuleSetForTest(tag string, rules ...adapter.HeadlessRule) *LocalRuleSet {
|
||||
return &LocalRuleSet{
|
||||
tag: tag,
|
||||
rules: rules,
|
||||
}
|
||||
}
|
||||
|
||||
func newRemoteRuleSetForTest(tag string, rules ...adapter.HeadlessRule) *RemoteRuleSet {
|
||||
return &RemoteRuleSet{
|
||||
options: option.RuleSet{Tag: tag},
|
||||
rules: rules,
|
||||
}
|
||||
}
|
||||
|
||||
func mustAdGuardRule(t *testing.T, content string) adapter.HeadlessRule {
|
||||
t.Helper()
|
||||
rules, err := adguard.ToOptions(strings.NewReader(content), slogger.NOP())
|
||||
require.NoError(t, err)
|
||||
require.Len(t, rules, 1)
|
||||
rule, err := NewHeadlessRule(context.Background(), rules[0])
|
||||
require.NoError(t, err)
|
||||
return rule
|
||||
}
|
||||
|
||||
func testMetadata(domain string) adapter.InboundContext {
|
||||
return adapter.InboundContext{
|
||||
Network: N.NetworkTCP,
|
||||
Source: M.Socksaddr{
|
||||
Addr: netip.MustParseAddr("10.0.0.1"),
|
||||
Port: 1000,
|
||||
},
|
||||
Destination: M.Socksaddr{
|
||||
Fqdn: domain,
|
||||
Port: 443,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func addRuleSetItem(rule *abstractDefaultRule, item *RuleSetItem) {
|
||||
rule.ruleSetItem = item
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addOtherItem(rule *abstractDefaultRule, item RuleItem) {
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addSourceAddressItem(t *testing.T, rule *abstractDefaultRule, cidrs []string) {
|
||||
t.Helper()
|
||||
item, err := NewIPCIDRItem(true, cidrs)
|
||||
require.NoError(t, err)
|
||||
rule.sourceAddressItems = append(rule.sourceAddressItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addDestinationAddressItem(t *testing.T, rule *abstractDefaultRule, domains []string, suffixes []string) {
|
||||
t.Helper()
|
||||
item, err := NewDomainItem(domains, suffixes)
|
||||
require.NoError(t, err)
|
||||
rule.destinationAddressItems = append(rule.destinationAddressItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addDestinationKeywordItem(rule *abstractDefaultRule, keywords []string) {
|
||||
item := NewDomainKeywordItem(keywords)
|
||||
rule.destinationAddressItems = append(rule.destinationAddressItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addDestinationRegexItem(t *testing.T, rule *abstractDefaultRule, regexes []string) {
|
||||
t.Helper()
|
||||
item, err := NewDomainRegexItem(regexes)
|
||||
require.NoError(t, err)
|
||||
rule.destinationAddressItems = append(rule.destinationAddressItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addDestinationIPCIDRItem(t *testing.T, rule *abstractDefaultRule, cidrs []string) {
|
||||
t.Helper()
|
||||
item, err := NewIPCIDRItem(false, cidrs)
|
||||
require.NoError(t, err)
|
||||
rule.destinationIPCIDRItems = append(rule.destinationIPCIDRItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addDestinationIPIsPrivateItem(rule *abstractDefaultRule) {
|
||||
item := NewIPIsPrivateItem(false)
|
||||
rule.destinationIPCIDRItems = append(rule.destinationIPCIDRItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addDestinationIPAcceptAnyItem(rule *abstractDefaultRule) {
|
||||
item := NewIPAcceptAnyItem()
|
||||
rule.destinationIPCIDRItems = append(rule.destinationIPCIDRItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addSourcePortItem(rule *abstractDefaultRule, ports []uint16) {
|
||||
item := NewPortItem(true, ports)
|
||||
rule.sourcePortItems = append(rule.sourcePortItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addSourcePortRangeItem(t *testing.T, rule *abstractDefaultRule, ranges []string) {
|
||||
t.Helper()
|
||||
item, err := NewPortRangeItem(true, ranges)
|
||||
require.NoError(t, err)
|
||||
rule.sourcePortItems = append(rule.sourcePortItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addDestinationPortItem(rule *abstractDefaultRule, ports []uint16) {
|
||||
item := NewPortItem(false, ports)
|
||||
rule.destinationPortItems = append(rule.destinationPortItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
||||
func addDestinationPortRangeItem(t *testing.T, rule *abstractDefaultRule, ranges []string) {
|
||||
t.Helper()
|
||||
item, err := NewPortRangeItem(false, ranges)
|
||||
require.NoError(t, err)
|
||||
rule.destinationPortItems = append(rule.destinationPortItems, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
120
test/go.mod
120
test/go.mod
@@ -7,18 +7,18 @@ require github.com/sagernet/sing-box v0.0.0
|
||||
replace github.com/sagernet/sing-box => ../
|
||||
|
||||
require (
|
||||
github.com/docker/docker v27.3.1+incompatible
|
||||
github.com/docker/docker v28.0.0+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/gofrs/uuid/v5 v5.4.0
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.2
|
||||
github.com/sagernet/sing v0.8.0-beta.16
|
||||
github.com/sagernet/sing-quic v0.6.0-beta.11
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4
|
||||
github.com/sagernet/sing v0.8.3-0.20260315153529-ed51f65fbfde
|
||||
github.com/sagernet/sing-quic v0.6.0
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/spyzhov/ajson v0.9.4
|
||||
github.com/stretchr/testify v1.11.1
|
||||
go.uber.org/goleak v1.3.0
|
||||
golang.org/x/net v0.48.0
|
||||
golang.org/x/net v0.50.0
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -28,16 +28,17 @@ require (
|
||||
github.com/akutz/memconn v0.1.0 // indirect
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/anthropics/anthropic-sdk-go v1.19.0 // indirect
|
||||
github.com/anthropics/anthropic-sdk-go v1.26.0 // indirect
|
||||
github.com/anytls/sing-anytls v0.0.11 // indirect
|
||||
github.com/caddyserver/certmagic v0.25.0 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||
github.com/caddyserver/certmagic v0.25.2 // indirect
|
||||
github.com/caddyserver/zerossl v0.1.5 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/coder/websocket v1.8.14 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect
|
||||
github.com/cretz/bine v0.2.0 // indirect
|
||||
github.com/database64128/netx-go v0.1.1 // indirect
|
||||
github.com/database64128/tfo-go/v2 v2.3.1 // indirect
|
||||
github.com/database64128/tfo-go/v2 v2.3.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect
|
||||
github.com/distribution/reference v0.5.0 // indirect
|
||||
@@ -48,7 +49,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gaissmai/bart v0.18.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.3 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.5 // indirect
|
||||
github.com/go-chi/render v1.0.3 // indirect
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
@@ -56,7 +57,7 @@ require (
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/godbus/dbus/v5 v5.2.1 // indirect
|
||||
github.com/godbus/dbus/v5 v5.2.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
@@ -65,26 +66,26 @@ require (
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
||||
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91 // indirect
|
||||
github.com/jsimonetti/rtnetlink v1.4.0 // indirect
|
||||
github.com/keybase/go-keychain v0.0.1 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/libdns/acmedns v0.5.0 // indirect
|
||||
github.com/libdns/alidns v1.0.6-beta.3 // indirect
|
||||
github.com/libdns/alidns v1.0.6 // indirect
|
||||
github.com/libdns/cloudflare v0.2.2 // indirect
|
||||
github.com/libdns/libdns v1.1.1 // indirect
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect
|
||||
github.com/mdlayher/netlink v1.9.0 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/metacubex/utls v1.8.4 // indirect
|
||||
github.com/mholt/acmez/v3 v3.1.4 // indirect
|
||||
github.com/miekg/dns v1.1.69 // indirect
|
||||
github.com/mholt/acmez/v3 v3.1.6 // indirect
|
||||
github.com/miekg/dns v1.1.72 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/openai/openai-go/v3 v3.15.0 // indirect
|
||||
github.com/openai/openai-go/v3 v3.26.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
@@ -96,41 +97,48 @@ require (
|
||||
github.com/safchain/ethtool v0.3.0 // indirect
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect
|
||||
github.com/sagernet/cors v1.2.1 // indirect
|
||||
github.com/sagernet/cronet-go v0.0.0-20260117110918-dc1cda1fe287 // indirect
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260117110918-dc1cda1fe287 // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260117110516-f21660bef13f // indirect
|
||||
github.com/sagernet/cronet-go v0.0.0-20260309100020-c128886ff3fc // indirect
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260309100020-c128886ff3fc // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260309101654-0cbdcfddded9 // indirect
|
||||
github.com/sagernet/fswatch v0.1.1 // indirect
|
||||
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 // indirect
|
||||
github.com/sagernet/sing-mux v0.3.4 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect
|
||||
github.com/sagernet/sing-tun v0.8.0-beta.17 // indirect
|
||||
github.com/sagernet/sing-tun v0.8.7-0.20260323120017-8eb4e8acfc2d // indirect
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 // indirect
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1 // indirect
|
||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 // indirect
|
||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c // indirect
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
|
||||
@@ -149,29 +157,29 @@ require (
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.39.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.1 // indirect
|
||||
go.uber.org/zap/exp v0.3.0 // indirect
|
||||
go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/crypto v0.46.0 // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
|
||||
golang.org/x/mod v0.31.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/mod v0.33.0 // indirect
|
||||
golang.org/x/oauth2 v0.34.0 // indirect
|
||||
golang.org/x/sync v0.19.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/term v0.38.0 // indirect
|
||||
golang.org/x/text v0.32.0 // indirect
|
||||
golang.org/x/sys v0.41.0 // indirect
|
||||
golang.org/x/term v0.40.0 // indirect
|
||||
golang.org/x/text v0.34.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.40.0 // indirect
|
||||
golang.org/x/tools v0.42.0 // indirect
|
||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
|
||||
google.golang.org/grpc v1.77.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||
google.golang.org/grpc v1.79.1 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gotest.tools/v3 v3.5.1 // indirect
|
||||
|
||||
264
test/go.sum
264
test/go.sum
@@ -1,3 +1,5 @@
|
||||
code.pfad.fr/check v1.1.0 h1:GWvjdzhSEgHvEHe2uJujDcpmZoySKuHQNrZMfzfO0bE=
|
||||
code.pfad.fr/check v1.1.0/go.mod h1:NiUH13DtYsb7xp5wll0U4SXx7KhXQVCtRgdC96IPfoM=
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
@@ -12,16 +14,18 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/anthropics/anthropic-sdk-go v1.19.0 h1:mO6E+ffSzLRvR/YUH9KJC0uGw0uV8GjISIuzem//3KE=
|
||||
github.com/anthropics/anthropic-sdk-go v1.19.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE=
|
||||
github.com/anthropics/anthropic-sdk-go v1.26.0 h1:oUTzFaUpAevfuELAP1sjL6CQJ9HHAfT7CoSYSac11PY=
|
||||
github.com/anthropics/anthropic-sdk-go v1.26.0/go.mod h1:qUKmaW+uuPB64iy1l+4kOSvaLqPXnHTTBKH6RVZ7q5Q=
|
||||
github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc=
|
||||
github.com/anytls/sing-anytls v0.0.11/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
|
||||
github.com/caddyserver/certmagic v0.25.0 h1:VMleO/XA48gEWes5l+Fh6tRWo9bHkhwAEhx63i+F5ic=
|
||||
github.com/caddyserver/certmagic v0.25.0/go.mod h1:m9yB7Mud24OQbPHOiipAoyKPn9pKHhpSJxXR1jydBxA=
|
||||
github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA=
|
||||
github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
||||
github.com/caddyserver/certmagic v0.25.2 h1:D7xcS7ggX/WEY54x0czj7ioTkmDWKIgxtIi2OcQclUc=
|
||||
github.com/caddyserver/certmagic v0.25.2/go.mod h1:llW/CvsNmza8S6hmsuggsZeiX+uS27dkqY27wDIuBWg=
|
||||
github.com/caddyserver/zerossl v0.1.5 h1:dkvOjBAEEtY6LIGAHei7sw2UgqSD6TrWweXpV7lvEvE=
|
||||
github.com/caddyserver/zerossl v0.1.5/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
|
||||
github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
|
||||
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
|
||||
@@ -34,8 +38,8 @@ github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
|
||||
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
|
||||
github.com/database64128/netx-go v0.1.1 h1:dT5LG7Gs7zFZBthFBbzWE6K8wAHjSNAaK7wCYZT7NzM=
|
||||
github.com/database64128/netx-go v0.1.1/go.mod h1:LNlYVipaYkQArRFDNNJ02VkNV+My9A5XR/IGS7sIBQc=
|
||||
github.com/database64128/tfo-go/v2 v2.3.1 h1:EGE+ELd5/AQ0X6YBlQ9RgKs8+kciNhgN3d8lRvfEJQw=
|
||||
github.com/database64128/tfo-go/v2 v2.3.1/go.mod h1:k9wcpg/8i5zenspBkc9jUEYehpZZccBnCElzOJB++bU=
|
||||
github.com/database64128/tfo-go/v2 v2.3.2 h1:UhZMKiMq3swZGUiETkLBDzQnZBPSAeBMClpJGlnJ5Fw=
|
||||
github.com/database64128/tfo-go/v2 v2.3.2/go.mod h1:GC3uB5oa4beGpCUbRb2ZOWP73bJJFmMyAVgQSO7r724=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -43,8 +47,10 @@ github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbww
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
|
||||
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/docker v28.0.0+incompatible h1:Olh0KS820sJ7nPsBKChVhk5pzqcwDR15fumfAd/p9hM=
|
||||
github.com/docker/docker v28.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
@@ -63,10 +69,12 @@ github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo=
|
||||
github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY=
|
||||
github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I=
|
||||
github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo=
|
||||
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
||||
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
|
||||
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
|
||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I=
|
||||
github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
@@ -80,8 +88,8 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/godbus/dbus/v5 v5.2.1 h1:I4wwMdWSkmI57ewd+elNGwLRf2/dtSaFz1DujfWYvOk=
|
||||
github.com/godbus/dbus/v5 v5.2.1/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
||||
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
|
||||
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
|
||||
github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=
|
||||
github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
@@ -104,8 +112,8 @@ github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8
|
||||
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
|
||||
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
|
||||
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167 h1:MEufgJohwIjFi2n3eJv4c/8UdRLQVUwPwSWQPoER+eU=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91 h1:u9i04mGE3iliBh0EFuWaKsmcwrLacqGmq1G3XoaM7gY=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo=
|
||||
github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I=
|
||||
github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E=
|
||||
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
|
||||
@@ -120,26 +128,30 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh5YzC3JVwU=
|
||||
github.com/letsencrypt/challtestsrv v1.4.2/go.mod h1:GhqMqcSoeGpYd5zX5TgwA6er/1MbWzx/o7yuuVya+Wk=
|
||||
github.com/letsencrypt/pebble/v2 v2.10.0 h1:Wq6gYXlsY6ubqI3hhxsTzdyotvfdjFBxuwYqCLCnj/U=
|
||||
github.com/letsencrypt/pebble/v2 v2.10.0/go.mod h1:Sk8cmUIPcIdv2nINo+9PB4L+ZBhzY+F9A1a/h/xmWiQ=
|
||||
github.com/libdns/acmedns v0.5.0 h1:5pRtmUj4Lb/QkNJSl1xgOGBUJTWW7RjpNaIhjpDXjPE=
|
||||
github.com/libdns/acmedns v0.5.0/go.mod h1:X7UAFP1Ep9NpTwWpVlrZzJLR7epynAy0wrIxSPFgKjQ=
|
||||
github.com/libdns/alidns v1.0.6-beta.3 h1:KAmb7FQ1tRzKsaAUGa7ZpGKAMRANwg7+1c7tUbSELq8=
|
||||
github.com/libdns/alidns v1.0.6-beta.3/go.mod h1:RECwyQ88e9VqQVtSrvX76o1ux3gQUKGzMgxICi+u7Ec=
|
||||
github.com/libdns/alidns v1.0.6 h1:/Ii428ty6WHFJmE24rZxq2taq++gh7rf9jhgLfp8PmM=
|
||||
github.com/libdns/alidns v1.0.6/go.mod h1:RECwyQ88e9VqQVtSrvX76o1ux3gQUKGzMgxICi+u7Ec=
|
||||
github.com/libdns/cloudflare v0.2.2 h1:XWHv+C1dDcApqazlh08Q6pjytYLgR2a+Y3xrXFu0vsI=
|
||||
github.com/libdns/cloudflare v0.2.2/go.mod h1:w9uTmRCDlAoafAsTPnn2nJ0XHK/eaUMh86DUk8BWi60=
|
||||
github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U=
|
||||
github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg=
|
||||
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o=
|
||||
github.com/mdlayher/netlink v1.9.0 h1:G8+GLq2x3v4D4MVIqDdNUhTUC7TKiCy/6MDkmItfKco=
|
||||
github.com/mdlayher/netlink v1.9.0/go.mod h1:YBnl5BXsCoRuwBjKKlZ+aYmEoq0r12FDA/3JC+94KDg=
|
||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/metacubex/utls v1.8.4 h1:HmL9nUApDdWSkgUyodfwF6hSjtiwCGGdyhaSpEejKpg=
|
||||
github.com/metacubex/utls v1.8.4/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/mholt/acmez/v3 v3.1.4 h1:DyzZe/RnAzT3rpZj/2Ii5xZpiEvvYk3cQEN/RmqxwFQ=
|
||||
github.com/mholt/acmez/v3 v3.1.4/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
|
||||
github.com/miekg/dns v1.1.69 h1:Kb7Y/1Jo+SG+a2GtfoFUfDkG//csdRPwRLkCsxDG9Sc=
|
||||
github.com/miekg/dns v1.1.69/go.mod h1:7OyjD9nEba5OkqQ/hB4fy3PIoxafSZJtducccIelz3g=
|
||||
github.com/mholt/acmez/v3 v3.1.6 h1:eGVQNObP0pBN4sxqrXeg7MYqTOWyoiYpQqITVWlrevk=
|
||||
github.com/mholt/acmez/v3 v3.1.6/go.mod h1:5nTPosTGosLxF3+LU4ygbgMRFDhbAVpqMI4+a4aHLBY=
|
||||
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
|
||||
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
|
||||
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
@@ -150,8 +162,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/openai/openai-go/v3 v3.15.0 h1:hk99rM7YPz+M99/5B/zOQcVwFRLLMdprVGx1vaZ8XMo=
|
||||
github.com/openai/openai-go/v3 v3.15.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
|
||||
github.com/openai/openai-go/v3 v3.26.0 h1:bRt6H/ozMNt/dDkN4gobnLqaEGrRGBzmbVs0xxJEnQE=
|
||||
github.com/openai/openai-go/v3 v3.26.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
@@ -177,54 +189,68 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM=
|
||||
github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ=
|
||||
github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI=
|
||||
github.com/sagernet/cronet-go v0.0.0-20260117110918-dc1cda1fe287 h1:0BYNmr0ptjsII948U0oBFmrbo4qEaCFcrE2JPRg3Zlk=
|
||||
github.com/sagernet/cronet-go v0.0.0-20260117110918-dc1cda1fe287/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260117110918-dc1cda1fe287 h1:ghxhYSBQpzkakqWqJDvXr/Zmxe0WjTjKuALEGbjGiGY=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260117110918-dc1cda1fe287/go.mod h1:M+4ZjPhLJXIvoxcQsbDofmc19Wrig59hZ+hLvj6S3To=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260117110516-f21660bef13f h1:8jZbZ4KBTdcXDFLwUBNQt5Xci6ZuAKh255S8TwuBCaM=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260117110516-f21660bef13f/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260117110516-f21660bef13f h1:tG0hCx+0u5zca7qQ7AMkcv4DCrBG/DKW1ggs/P+BRRI=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260117110516-f21660bef13f h1:ZXp5hKJIA7iJ52ZShJCKMQEPLpp/7dDIVZmPGV9Il40=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260117110516-f21660bef13f/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260117110516-f21660bef13f h1:gL7H8HS8s38adz4/HZtRHh79qMwsbLTRRPz4GQ9LcWI=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260117110516-f21660bef13f h1:Dchgc0pAY5Jwb5lzUlE+1nhHIzqLx+YOurXLHgvWd/0=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260117110516-f21660bef13f h1:+MOLSQoduuKDxF410i1LcSPaQGaiP0eZb0INvMlmjM4=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260117110516-f21660bef13f h1:lIZna05Vn6n8k21p8OpSUnhwGm+E57PrMjiI4ZUfMSg=
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260117110516-f21660bef13f h1:B2aFQ5CRHI20t8YsEizvtguS5W2QfK7D5XV/NzTIxPE=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260117110516-f21660bef13f h1:qpSwJ1rFGYCfJDenNCZoWYjoG7N+xEa6ke+E7/JO1i4=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260117110516-f21660bef13f h1:cx7Ipg0tSvTDjS4maMEYz4vuzz93BMPAysmZ1YLrz80=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260117110516-f21660bef13f/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260117110516-f21660bef13f h1:4jOHuUiBxD8pJEpBBVQfJqyLmxjpd3t4MLRzU7YLFyg=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260117110516-f21660bef13f h1:OpXBa2WlRU+Mam9oRe9Nn4/zf7gQ+qiBTNK8A5RwbfQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260117110516-f21660bef13f h1:nJpGFi+6hI85tl4zoyNFEnFEQ5+xEV5gyvsUoMvd8g0=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260117110516-f21660bef13f h1:SEy2rpmgOJgrqcEryJI/RSnqUWIsEsp0cfYoA8y21jc=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260117110516-f21660bef13f/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260117110516-f21660bef13f h1:EW2TuFMLm0iBGqRZtuGwIZdeYmDtDsDmRcRRJQOMxUo=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260117110516-f21660bef13f h1:3U5woxrNCkzfv1+UX+mVoWh1228AE1qAiMG02F9oFbY=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260117110516-f21660bef13f h1:YwFTfuWG3mmctroeDYtFZ6LHjGsedVO+5wInYbbUuUY=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260117110516-f21660bef13f/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260117110516-f21660bef13f h1:r4V0ddPCRLgGu0VdgR3aUsO9NjpmyjAf+h+3oTD9D6E=
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260117110516-f21660bef13f h1:B8yf4gFvEYUnwWmtVK9sdwUsflYZ387MhYmlOP2ohFQ=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260117110516-f21660bef13f h1:9YyaMg4rO1/jIgrxmNb0LKH+X7frSYWfX2pFgW5JUVM=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260117110516-f21660bef13f/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260117110516-f21660bef13f h1:B0fnGu0sh9yT/9JDN5u/GqThGoOzNN/daOAuGWFLXEk=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260117110516-f21660bef13f h1:lxPcIXKSSI5JDhc7rx/6yufISWM4vtBS2FY9PavWQTs=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260117110516-f21660bef13f/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
|
||||
github.com/sagernet/cronet-go v0.0.0-20260309100020-c128886ff3fc h1:YK7PwJT0irRAEui9ASdXSxcE2BOVQipWMF/A1Ogt+7c=
|
||||
github.com/sagernet/cronet-go v0.0.0-20260309100020-c128886ff3fc/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260309100020-c128886ff3fc h1:EJPHOqk23IuBsTjXK9OXqkNxPbKOBWKRmviQoCcriAs=
|
||||
github.com/sagernet/cronet-go/all v0.0.0-20260309100020-c128886ff3fc/go.mod h1:8aty0RW96DrJSMWXO6bRPMBJEjuqq5JWiOIi4bCRzFA=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260309101654-0cbdcfddded9 h1:Qi0IKBpoPP3qZqIXuOKMsT2dv+l/MLWMyBHDMLRw2EA=
|
||||
github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260309101654-0cbdcfddded9 h1:p+wCMjOhj46SpSD/AJeTGgkCcbyA76FyH631XZatyU8=
|
||||
github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260309101654-0cbdcfddded9 h1:Y7lWrZwEhC/HX8Pb5C92CrQihuaE7hrHmWB2ykst3iQ=
|
||||
github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:3Ggy5wiyjA6t+aVVPnXlSEIVj9zkxd4ybH3NsvsNefs=
|
||||
github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260309101654-0cbdcfddded9 h1:DuFTCnZloblY+7olXiZoRdueWfxi34EV5UheTFKM2rA=
|
||||
github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:x/6T2gjpLw9yNdCVR6xBlzMUzED9fxNFNt6U6A6SOh8=
|
||||
github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0=
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9 h1:Lx9PExM70rg8aNxPm0JPeSr5SWC3yFiCz4wIq86ugx8=
|
||||
github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:BTEpw7/vKR9BNBsHebfpiGHDCPpjVJ3vLIbHNU3VUfM=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9 h1:hdEph9nQXRnKwc/lIDwo15rmzbC6znXF5jJWHPN1Fiw=
|
||||
github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260309101654-0cbdcfddded9 h1:Iq++oYV7dtRJHTpu8yclHJdn+1oj2t1e84/YpdXYWW8=
|
||||
github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260309101654-0cbdcfddded9 h1:Y43fuLL8cgwRHpEKwxh0O3vYp7g/SZGvbkJj3cQ6USA=
|
||||
github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260309101654-0cbdcfddded9 h1:bX2GJmF0VCC+tBrVAa49YEsmJ4A9dLmwoA6DJUxRtCY=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260309101654-0cbdcfddded9 h1:gQTR/2azUCInE0r3kmesZT9xu+x801+BmtDY0d0Tw9Y=
|
||||
github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260309101654-0cbdcfddded9 h1:X4mP3jlYvxgrKpZLOKMmc/O8T5/zP83/23pgfQOc3tY=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:c6xj2nXr/65EDiRFddUKQIBQ/b/lAPoH8WFYlgadaPc=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260309101654-0cbdcfddded9 h1:ahbl7yjOvGVVNUwk9TcQk+xejVfoYAYFRlhWnby0/YM=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260309101654-0cbdcfddded9 h1:JC5Zv5+J85da6g5G56VhdaK53fmo6Os2q/wWi5QlxOw=
|
||||
github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260309101654-0cbdcfddded9 h1:4bt7Go588BoM4VjNYMxx0MrvbwlFQn3DdRDCM7BmkRo=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:Wt5uFdU3tnmm8YzobYewwdF7Mt6SucRQg6xeTNWC3Tk=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260309101654-0cbdcfddded9 h1:E1z0BeLUh8EZfCjIyS9BrfCocZrt+0KPS0bzop3Sxf4=
|
||||
github.com/sagernet/cronet-go/lib/linux_loong64_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:lyIF6wKBLwWa5ZXaAKbAoewewl+yCHo2iYev39Mbj4E=
|
||||
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260309101654-0cbdcfddded9 h1:d8ejxRHO7Vi9JqR/6DxR7RyI/swA2JfDWATR4T7otBw=
|
||||
github.com/sagernet/cronet-go/lib/linux_mips64le v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:H46PnSTTZNcZokLLiDeMDaHiS1l14PH3tzWi0eykjD8=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260309101654-0cbdcfddded9 h1:iUDVEVu3RxL5ArPIY72BesbuX5zQ1la/ZFwKpQcGc5c=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:RBhSUDAKWq7fswtV4nQUQhuaTLcX3ettR7teA7/yf2w=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260309101654-0cbdcfddded9 h1:xB6ikOC/R3n3hjy68EJ0sbZhH4vwEhd6JM9jZ1U2SVY=
|
||||
github.com/sagernet/cronet-go/lib/linux_mipsle_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:wRzoIOGG4xbpp3Gh3triLKwMwYriScXzFtunLYhY4w0=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260309101654-0cbdcfddded9 h1:mBOuLCPOOMMq8N1+dUM5FqZclqga1+u6fAbPqQcbIhc=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:LNiZXmWil1OPwKCheqQjtakZlJuKGFz+iv2eGF76Hhs=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260309101654-0cbdcfddded9 h1:cwPyDfj+ZNFE7kvcWbayQJyeC/KQA16HTXOxgHphL0w=
|
||||
github.com/sagernet/cronet-go/lib/linux_riscv64_musl v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:YFDGKTkpkJGc5+hnX/RYosZyTWg9h+68VB55fYRRLYc=
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9 h1:Zk9zG8kt3mXAboclUXQlvvxKQuhnI8u5NdDEl8uotNY=
|
||||
github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:Lu05srGqddQRMnl1MZtGAReln2yJljeGx9b1IadlMJ8=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9 h1:Tk9bDywUmOtc0iMjjCVIwMlAQNsxCy+bK+bTNA0OaBE=
|
||||
github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260309101654-0cbdcfddded9 h1:tQqDQw3tEHdQpt7NTdAwF3UvZ3CjNIj/IJKMRFmm388=
|
||||
github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260309101654-0cbdcfddded9 h1:biUIbI2YxUrcQikEfS/bwPA8NsHp/WO+VZUG4morUmE=
|
||||
github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20260309101654-0cbdcfddded9/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw=
|
||||
github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs=
|
||||
github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o=
|
||||
github.com/sagernet/gvisor v0.0.0-20250822052253-5558536cf237 h1:SUPFNB+vSP4RBPrSEgNII+HkfqC8hKMpYLodom4o4EU=
|
||||
@@ -233,30 +259,30 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.2 h1:hJUL+HtxEOjxsa0CsucbBVqI/AMS4k52NwNU637zmdw=
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.2/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4=
|
||||
github.com/sagernet/sing v0.8.0-beta.16 h1:Fe+6E9VHYky9Mx4cf0ugbZPWDcXRflpAu7JQ5bWXvaA=
|
||||
github.com/sagernet/sing v0.8.0-beta.16/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4 h1:6qvrUW79S+CrPwWz6cMePXohgjHoKxLo3c+MDhNwc3o=
|
||||
github.com/sagernet/quic-go v0.59.0-sing-box-mod.4/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4=
|
||||
github.com/sagernet/sing v0.8.3-0.20260315153529-ed51f65fbfde h1:RNQzlpnsXIuu1HGts/fIzJ1PR7RhrzaNlU52MDyiX1c=
|
||||
github.com/sagernet/sing v0.8.3-0.20260315153529-ed51f65fbfde/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s=
|
||||
github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
|
||||
github.com/sagernet/sing-quic v0.6.0-beta.11 h1:eUusxITKKRedhWC2ScUYFUvD96h/QfbKLaS3N6/7in4=
|
||||
github.com/sagernet/sing-quic v0.6.0-beta.11/go.mod h1:K5bWvITOm4vE10fwLfrWpw27bCoVJ+tfQ79tOWg+Ko8=
|
||||
github.com/sagernet/sing-quic v0.6.0 h1:dhrFnP45wgVKEOT1EvtsToxdzRnHIDIAgj6WHV9pLyM=
|
||||
github.com/sagernet/sing-quic v0.6.0/go.mod h1:K5bWvITOm4vE10fwLfrWpw27bCoVJ+tfQ79tOWg+Ko8=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-tun v0.8.0-beta.17 h1:6DdbNXeTFYj8Tb4FCh8Mp2boA3rVY6VNqzTOObj7Xis=
|
||||
github.com/sagernet/sing-tun v0.8.0-beta.17/go.mod h1:+HAK/y9GZljdT0KYKMYDR8MjjqnqDDQZYp5ZZQoRzS8=
|
||||
github.com/sagernet/sing-tun v0.8.7-0.20260323120017-8eb4e8acfc2d h1:vi0j6301f6H8t2GYgAC2PA2AdnGdMwkP34B4+N03Qt4=
|
||||
github.com/sagernet/sing-tun v0.8.7-0.20260323120017-8eb4e8acfc2d/go.mod h1:pLCo4o+LacXEzz0bhwhJkKBjLlKOGPBNOAZ97ZVZWzs=
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o=
|
||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
|
||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6 h1:eYz/OpMqWCvO2++iw3dEuzrlfC2xv78GdlGvprIM6O8=
|
||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6/go.mod h1:m87GAn4UcesHQF3leaPFEINZETO5za1LGn1GJdNDgNc=
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 h1:E2tZFeg9mGYGQ7E7BbxMv1cU35HxwgRm6tPKI2Pp7DA=
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0=
|
||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7 h1:8zc1Aph1+ElqF9/7aSPkO0o4vTd+AfQC+CO324mLWGg=
|
||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7/go.mod h1:m87GAn4UcesHQF3leaPFEINZETO5za1LGn1GJdNDgNc=
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c h1:f9cXNB+IOOPnR8DOLMTpr42jf7naxh5Un5Y09BBf5Cg=
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0=
|
||||
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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
@@ -312,20 +338,20 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
@@ -344,26 +370,26 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
|
||||
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
|
||||
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
|
||||
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
|
||||
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
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.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
|
||||
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -379,24 +405,24 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
|
||||
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
|
||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -407,17 +433,19 @@ golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
|
||||
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -229,13 +229,12 @@ func (e *Endpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
}
|
||||
|
||||
func (e *Endpoint) Close() error {
|
||||
if e.device != nil {
|
||||
e.device.Close()
|
||||
}
|
||||
if e.pauseCallback != nil {
|
||||
e.pause.UnregisterCallback(e.pauseCallback)
|
||||
}
|
||||
if e.device != nil {
|
||||
e.device.Down()
|
||||
e.device.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user