Add new admin panel, failover, dns fallback, providers, limiters. Update XHTTP
2
.gitignore
vendored
@@ -21,3 +21,5 @@
|
||||
CLAUDE.md
|
||||
AGENTS.md
|
||||
/.claude/
|
||||
dist
|
||||
logs
|
||||
@@ -3,49 +3,6 @@ project_name: sing-box
|
||||
builds:
|
||||
- &template
|
||||
id: main
|
||||
main: ./cmd/sing-box
|
||||
flags:
|
||||
- -v
|
||||
- -trimpath
|
||||
ldflags:
|
||||
- -X github.com/sagernet/sing-box/constant.Version={{ .Version }}
|
||||
- -s
|
||||
- -buildid=
|
||||
tags:
|
||||
- with_gvisor
|
||||
- with_quic
|
||||
- with_dhcp
|
||||
- with_wireguard
|
||||
- with_utls
|
||||
- with_acme
|
||||
- with_clash_api
|
||||
- with_tailscale
|
||||
- with_masque
|
||||
- with_mtproxy
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
- GOTOOLCHAIN=local
|
||||
targets:
|
||||
- linux_386
|
||||
- linux_amd64_v1
|
||||
- linux_arm64
|
||||
- linux_arm_6
|
||||
- linux_arm_7
|
||||
- linux_s390x
|
||||
- linux_riscv64
|
||||
- linux_mips
|
||||
- linux_mips_softfloat
|
||||
- linux_mipsle
|
||||
- linux_mipsle_softfloat
|
||||
- linux_mips64
|
||||
- linux_mips64le
|
||||
- windows_amd64_v1
|
||||
- windows_386
|
||||
- windows_arm64
|
||||
- darwin_amd64_v1
|
||||
- darwin_arm64
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
- id: manager
|
||||
main: ./cmd/sing-box
|
||||
flags:
|
||||
- -v
|
||||
@@ -78,19 +35,13 @@ builds:
|
||||
- linux_arm_7
|
||||
- linux_s390x
|
||||
- linux_riscv64
|
||||
- linux_mips
|
||||
- linux_mips_softfloat
|
||||
- linux_mipsle
|
||||
- linux_mipsle_softfloat
|
||||
- linux_mips64
|
||||
- linux_mips64le
|
||||
- windows_amd64_v1
|
||||
- windows_386
|
||||
- windows_arm64
|
||||
- darwin_amd64_v1
|
||||
- darwin_arm64
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
- id: legacy
|
||||
- id: mips
|
||||
<<: *template
|
||||
tags:
|
||||
- with_gvisor
|
||||
@@ -103,13 +54,13 @@ builds:
|
||||
- with_tailscale
|
||||
- with_masque
|
||||
- with_mtproxy
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
- GOROOT={{ .Env.GOPATH }}/go_win7
|
||||
tool: "{{ .Env.GOPATH }}/go_win7/bin/go"
|
||||
targets:
|
||||
- windows_amd64_v1
|
||||
- windows_386
|
||||
- linux_mips
|
||||
- linux_mips_softfloat
|
||||
- linux_mipsle
|
||||
- linux_mipsle_softfloat
|
||||
- linux_mips64
|
||||
- linux_mips64le
|
||||
- id: android
|
||||
<<: *template
|
||||
env:
|
||||
@@ -148,6 +99,7 @@ archives:
|
||||
id: archive
|
||||
builds:
|
||||
- main
|
||||
- mips
|
||||
- android
|
||||
formats:
|
||||
- tar.gz
|
||||
@@ -159,19 +111,6 @@ archives:
|
||||
files:
|
||||
- LICENSE
|
||||
name_template: '{{ .ProjectName }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ if and .Mips (not (eq .Mips "hardfloat")) }}-{{ .Mips }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||
- id: archive_with_manager
|
||||
builds:
|
||||
- manager
|
||||
formats:
|
||||
- tar.gz
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
formats:
|
||||
- zip
|
||||
wrap_in_directory: true
|
||||
files:
|
||||
- LICENSE
|
||||
name_template: '{{ .ProjectName }}-{{ .Version }}-with-manager-{{ .Os }}-{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ if and .Mips (not (eq .Mips "hardfloat")) }}-{{ .Mips }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||
- id: archive-legacy
|
||||
<<: *template
|
||||
builds:
|
||||
|
||||
32
Makefile
@@ -14,12 +14,35 @@ PREFIX ?= $(shell go env GOPATH)
|
||||
SING_FFI ?= sing-ffi
|
||||
LIBBOX_FFI_CONFIG ?= ./experimental/libbox/ffi.json
|
||||
|
||||
ADMIN_PANEL_DIR = service/admin_panel
|
||||
ADMIN_PANEL_WEB = $(ADMIN_PANEL_DIR)/web
|
||||
ADMIN_PANEL_DIST = $(ADMIN_PANEL_DIR)/dist
|
||||
ADMIN_PANEL_TAGS = $(TAGS),with_admin_panel
|
||||
|
||||
DOCKER_IMAGE ?= shtorm7/sing-box-extended
|
||||
DOCKER_PLATFORMS ?= linux/amd64,linux/arm64
|
||||
|
||||
.PHONY: test release docs build
|
||||
|
||||
build:
|
||||
export GOTOOLCHAIN=local && \
|
||||
go build $(MAIN_PARAMS) $(MAIN)
|
||||
|
||||
admin_panel_web:
|
||||
cd $(ADMIN_PANEL_WEB) && \
|
||||
npm install --no-fund --no-audit && \
|
||||
npm run build
|
||||
|
||||
admin_panel_pack:
|
||||
go run ./cmd/internal/admin_panel_pack \
|
||||
-dir $(ADMIN_PANEL_DIST)
|
||||
|
||||
admin_panel_regen: admin_panel_web admin_panel_pack
|
||||
|
||||
build_admin_panel:
|
||||
export GOTOOLCHAIN=local && \
|
||||
go build $(PARAMS) -tags "$(ADMIN_PANEL_TAGS)" $(MAIN)
|
||||
|
||||
race:
|
||||
export GOTOOLCHAIN=local && \
|
||||
go build -race $(MAIN_PARAMS) $(MAIN)
|
||||
@@ -84,6 +107,15 @@ release_repo:
|
||||
release_install:
|
||||
go install -v github.com/tcnksm/ghr@latest
|
||||
|
||||
release_docker:
|
||||
sudo docker buildx build \
|
||||
--platform $(DOCKER_PLATFORMS) \
|
||||
-t $(DOCKER_IMAGE):latest \
|
||||
-t $(DOCKER_IMAGE):$(VERSION) \
|
||||
--push \
|
||||
--network=host \
|
||||
.
|
||||
|
||||
update_android_version:
|
||||
go run ./cmd/internal/update_android_version
|
||||
|
||||
|
||||
50
README.md
@@ -4,37 +4,45 @@ Sing-box with extended features.
|
||||
|
||||
## 🔥 Features
|
||||
|
||||
### Protocols
|
||||
- WARP
|
||||
- MASQUE
|
||||
- MTProxy
|
||||
- Mieru
|
||||
- VPN
|
||||
- Bond
|
||||
- Fallback
|
||||
### Outbounds
|
||||
- **WARP** — Cloudflare WARP integration through WireGuard
|
||||
- **MASQUE** — Cloudflare MASQUE proxy over QUIC / HTTP-2
|
||||
- **MTProxy** — Telegram MTProxy server with FakeTLS and domain fronting
|
||||
- **Mieru** — Secure, hard to classify, hard to probe network protocol
|
||||
- **VPN** — Routed tunnel over any TCP sing-box protocol
|
||||
- **Bond** — Link aggregation for increasing throughput
|
||||
- **Fallback** — Outbound group with priority-based switching
|
||||
- **Failover** — Automatic outbound switching with session recovery for high availability
|
||||
|
||||
### DNS
|
||||
- **SDNS (DNSCrypt)** — Encrypted DNS queries for enhanced privacy
|
||||
- **DNS Fallback** — Sequential / parallel queries across upstream resolvers
|
||||
|
||||
### Limiters
|
||||
- Bandwidth Limiter
|
||||
- Connection Limiter
|
||||
- **Bandwidth Limiter** — Upload / download / bidirectional rate limiting
|
||||
- **Connection Limiter** — Concurrent connection control
|
||||
- **Traffic Limiter** — Per-user traffic quotas
|
||||
- **Rate Limiter** — Request rate limiting
|
||||
|
||||
### Encryption & Obfuscation
|
||||
- Amnezia 2.0
|
||||
- VLESS encryption
|
||||
- **Amnezia 2.0** — WireGuard traffic obfuscation
|
||||
- **VLESS encryption** — XRAY encryption for VLESS protocol
|
||||
|
||||
### Transports
|
||||
- mKCP
|
||||
- XHTTP
|
||||
- **mKCP** — Reliable UDP-based transport
|
||||
- **XHTTP** — Modern XRAY transport
|
||||
|
||||
### Services
|
||||
- Admin Panel
|
||||
- Manager
|
||||
- Node Manager
|
||||
- **Admin Panel** — Web-based management interface
|
||||
- **Manager** — Management service for configuring users, nodes, limiters
|
||||
- **Manager API (HTTP/gRPC)** — HTTP and gRPC API for the Manager
|
||||
- **Node Manager API** — Service for connecting nodes to remote manager
|
||||
|
||||
### Miscellaneous
|
||||
- Link parser
|
||||
- SDNS (DNSCrypt)
|
||||
- Extended WireGuard options
|
||||
- Unified Delay
|
||||
- **Providers** — Outbound subscriptions from local files, inline lists, or remote URLs (sing-box JSON, Clash YAML, SIP008, share links)
|
||||
- **Link Parser** — Outbound configured from a share link (VLESS, VMess, Shadowsocks, Trojan, Hysteria, Hysteria2, TUIC)
|
||||
- **Extended WireGuard options** — Advanced configuration capabilities
|
||||
- **Unified Delay** — Unified latency measurement
|
||||
|
||||
## 📚 Examples
|
||||
|
||||
|
||||
194
cmd/internal/admin_panel_pack/main.go
Normal file
@@ -0,0 +1,194 @@
|
||||
// Command admin_panel_pack post-processes a directory of built SPA
|
||||
// assets so it can be served straight from the Go binary via //go:embed.
|
||||
// It does *not* generate any Go source any more — that responsibility
|
||||
// moved to the embed directive in service/admin_panel/service.go.
|
||||
//
|
||||
// Three transformations happen here, all in-place inside the supplied
|
||||
// directory:
|
||||
//
|
||||
// 1. Legacy WOFF (1.0) fallback fonts are deleted. Every browser made
|
||||
// after 2014 reads WOFF2 natively, so shipping both formats roughly
|
||||
// doubles the embedded font payload for no real-world benefit. The
|
||||
// matching `,url(*.woff) format("woff")` segments are stripped from
|
||||
// the bundled CSS in step (2) so the @font-face rules don't reference
|
||||
// files that aren't shipped.
|
||||
// 2. Bundled CSS is rewritten to drop those WOFF URL fragments.
|
||||
// 3. Compressible text assets (.html, .css, .js, .svg, .json, .map) are
|
||||
// pre-gzipped as companion `*.gz` files. The HTTP handler then either
|
||||
// passes those bytes through verbatim with Content-Encoding: gzip or
|
||||
// falls back to the raw file for the rare client that does not
|
||||
// advertise gzip support — no on-line compression, no surprises.
|
||||
// Already-compressed formats (.woff2, fonts, images) are skipped: gzip
|
||||
// can't shrink them and the duplicate would only inflate the binary.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dir := flag.String("dir", "service/admin_panel/dist", "directory of built SPA assets to post-process in place")
|
||||
flag.Parse()
|
||||
|
||||
woffDropped, err := pruneWoff(*dir)
|
||||
if err != nil {
|
||||
fail("prune woff: %v", err)
|
||||
}
|
||||
cssRewritten, err := rewriteCSS(*dir)
|
||||
if err != nil {
|
||||
fail("rewrite css: %v", err)
|
||||
}
|
||||
stats, err := gzipText(*dir)
|
||||
if err != nil {
|
||||
fail("gzip text: %v", err)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "post-processed %s: dropped %d woff, rewrote %d css, gzipped %d files (%d→%d bytes)\n",
|
||||
*dir, woffDropped, cssRewritten, stats.gzipped, stats.totalRaw, stats.totalGz)
|
||||
}
|
||||
|
||||
// pruneWoff deletes every legacy *.woff (WOFF 1.0) font under dir. The
|
||||
// bundled CSS still references them on entry; rewriteCSS drops those
|
||||
// references in a separate pass so the two operations stay independently
|
||||
// testable.
|
||||
func pruneWoff(dir string) (int, error) {
|
||||
var n int
|
||||
err := filepath.WalkDir(dir, func(p string, d fs.DirEntry, walkErr error) error {
|
||||
if walkErr != nil {
|
||||
return walkErr
|
||||
}
|
||||
if d.IsDir() || !strings.EqualFold(filepath.Ext(p), ".woff") {
|
||||
return nil
|
||||
}
|
||||
if err := os.Remove(p); err != nil {
|
||||
return err
|
||||
}
|
||||
n++
|
||||
return nil
|
||||
})
|
||||
return n, err
|
||||
}
|
||||
|
||||
// woffRefAfterRE / woffRefBeforeRE match a single WOFF 1.0 entry inside a
|
||||
// Vite-bundled CSS `src:` declaration. Vite minifies the rule to
|
||||
// `src:url(./X.woff2) format("woff2"),url(./X.woff) format("woff");` so the
|
||||
// "after" regex (the common case) eats the *leading* comma + woff entry,
|
||||
// leaving only the woff2 source. We also handle the rare reverse ordering
|
||||
// in a second pass.
|
||||
var (
|
||||
woffRefAfterRE = regexp.MustCompile(`,\s*url\([^)]*\.woff\)\s*format\(["']woff["']\)`)
|
||||
woffRefBeforeRE = regexp.MustCompile(`url\([^)]*\.woff\)\s*format\(["']woff["']\)\s*,\s*`)
|
||||
)
|
||||
|
||||
// rewriteCSS drops every reference to a *.woff URL from every *.css file
|
||||
// under dir. Pairs naturally with pruneWoff: after both passes, no font
|
||||
// URL in the bundle points at a file that isn't shipped.
|
||||
func rewriteCSS(dir string) (int, error) {
|
||||
var n int
|
||||
err := filepath.WalkDir(dir, func(p string, d fs.DirEntry, walkErr error) error {
|
||||
if walkErr != nil {
|
||||
return walkErr
|
||||
}
|
||||
if d.IsDir() || !strings.EqualFold(filepath.Ext(p), ".css") {
|
||||
return nil
|
||||
}
|
||||
data, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out := woffRefAfterRE.ReplaceAll(data, nil)
|
||||
out = woffRefBeforeRE.ReplaceAll(out, nil)
|
||||
if bytes.Equal(out, data) {
|
||||
return nil
|
||||
}
|
||||
if err := os.WriteFile(p, out, 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
n++
|
||||
return nil
|
||||
})
|
||||
return n, err
|
||||
}
|
||||
|
||||
// gzipExts is the set of file extensions for which a `.gz` companion is
|
||||
// generated. Anything not on this list is left alone — woff2/png/jpeg/etc.
|
||||
// are already compressed, so gzip can only inflate them slightly while
|
||||
// doubling the embedded payload.
|
||||
var gzipExts = map[string]bool{
|
||||
".html": true,
|
||||
".css": true,
|
||||
".js": true,
|
||||
".mjs": true,
|
||||
".svg": true,
|
||||
".json": true,
|
||||
".map": true,
|
||||
".txt": true,
|
||||
".xml": true,
|
||||
".wasm": true,
|
||||
}
|
||||
|
||||
type gzipStats struct {
|
||||
gzipped int
|
||||
totalRaw int64
|
||||
totalGz int64
|
||||
}
|
||||
|
||||
// gzipText produces a `<file>.gz` companion next to every text-like asset
|
||||
// in dir, using gzip.BestCompression. The companion is dropped if the
|
||||
// compressed bytes don't save at least 10 % over the raw file — same
|
||||
// heuristic we used in the previous (Go-source-emitting) generation, just
|
||||
// applied to disk files now.
|
||||
func gzipText(dir string) (gzipStats, error) {
|
||||
var stats gzipStats
|
||||
err := filepath.WalkDir(dir, func(p string, d fs.DirEntry, walkErr error) error {
|
||||
if walkErr != nil {
|
||||
return walkErr
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
ext := strings.ToLower(filepath.Ext(p))
|
||||
if ext == ".gz" || !gzipExts[ext] {
|
||||
return nil
|
||||
}
|
||||
raw, err := os.ReadFile(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
w, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Reproducible: no mtime, no OS marker.
|
||||
w.ModTime = time.Time{}
|
||||
w.OS = 0xff
|
||||
if _, err := w.Write(raw); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
if buf.Len() > len(raw)*9/10 {
|
||||
return nil
|
||||
}
|
||||
stats.gzipped++
|
||||
stats.totalRaw += int64(len(raw))
|
||||
stats.totalGz += int64(buf.Len())
|
||||
return os.WriteFile(p+".gz", buf.Bytes(), 0o644)
|
||||
})
|
||||
return stats, err
|
||||
}
|
||||
|
||||
func fail(format string, args ...any) {
|
||||
fmt.Fprintf(os.Stderr, "admin_panel_pack: "+format+"\n", args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
BIN
cmd/sing-box/cache.db
Normal file
@@ -29,7 +29,7 @@ type RawHalfConn struct {
|
||||
|
||||
func NewRawHalfConn(rawHalfConn reflect.Value, methods *Methods) (*RawHalfConn, error) {
|
||||
halfConn := &RawHalfConn{
|
||||
pointer: (unsafe.Pointer)(rawHalfConn.UnsafeAddr()),
|
||||
pointer: unsafe.Pointer(rawHalfConn.UnsafeAddr()),
|
||||
methods: methods,
|
||||
}
|
||||
|
||||
|
||||
74
common/byteformats/formats.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package byteformats
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
var (
|
||||
unitNames = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
|
||||
iUnitNames = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
|
||||
kUnitNames = []string{"kB", "MB", "GB", "TB", "PB", "EB"}
|
||||
kiUnitNames = []string{"KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
|
||||
)
|
||||
|
||||
func formatBytes(s uint64, base float64, sizes []string) string {
|
||||
if s < 10 {
|
||||
return fmt.Sprintf("%d B", s)
|
||||
}
|
||||
e := math.Floor(logn(float64(s), base))
|
||||
suffix := sizes[int(e)]
|
||||
val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10
|
||||
f := "%.0f %s"
|
||||
if val < 10 {
|
||||
f = "%.1f %s"
|
||||
}
|
||||
|
||||
return fmt.Sprintf(f, val, suffix)
|
||||
}
|
||||
|
||||
func formatKBytes(s uint64, base float64, sizes []string) string {
|
||||
if s == 0 {
|
||||
return fmt.Sprintf("0 %s", sizes[0])
|
||||
}
|
||||
e := math.Floor(logn(float64(s), base))
|
||||
if e < 1 {
|
||||
e = 1
|
||||
}
|
||||
suffix := sizes[int(e)-1]
|
||||
val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10
|
||||
f := "%.0f %s"
|
||||
if val < 10 {
|
||||
f = "%.1f %s"
|
||||
}
|
||||
|
||||
return fmt.Sprintf(f, val, suffix)
|
||||
}
|
||||
|
||||
func logn(n, b float64) float64 {
|
||||
return math.Log(n) / math.Log(b)
|
||||
}
|
||||
|
||||
func FormatBytes(s uint64) string {
|
||||
return formatBytes(s, 1000, unitNames)
|
||||
}
|
||||
|
||||
func FormatMemoryBytes(s uint64) string {
|
||||
return formatBytes(s, 1024, unitNames)
|
||||
}
|
||||
|
||||
func FormatIBytes(s uint64) string {
|
||||
return formatBytes(s, 1024, iUnitNames)
|
||||
}
|
||||
|
||||
func FormatKBytes(s uint64) string {
|
||||
return formatKBytes(s, 1000, kUnitNames)
|
||||
}
|
||||
|
||||
func FormatMemoryKBytes(s uint64) string {
|
||||
return formatKBytes(s, 1024, kUnitNames)
|
||||
}
|
||||
|
||||
func FormatKIBytes(s uint64) string {
|
||||
return formatKBytes(s, 1024, kiUnitNames)
|
||||
}
|
||||
218
common/byteformats/json.go
Normal file
@@ -0,0 +1,218 @@
|
||||
package byteformats
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
Byte = 1 << (iota * 10)
|
||||
KiByte
|
||||
MiByte
|
||||
GiByte
|
||||
TiByte
|
||||
PiByte
|
||||
EiByte
|
||||
)
|
||||
|
||||
const (
|
||||
KByte = Byte * 1000
|
||||
MByte = KByte * 1000
|
||||
GByte = MByte * 1000
|
||||
TByte = GByte * 1000
|
||||
PByte = TByte * 1000
|
||||
EByte = PByte * 1000
|
||||
)
|
||||
|
||||
var unitValueTable = map[string]uint64{
|
||||
"b": Byte,
|
||||
"k": KByte,
|
||||
"kb": KByte,
|
||||
"ki": KiByte,
|
||||
"kib": KiByte,
|
||||
"m": MByte,
|
||||
"mb": MByte,
|
||||
"mi": MiByte,
|
||||
"mib": MiByte,
|
||||
"g": GByte,
|
||||
"gb": GByte,
|
||||
"gi": GiByte,
|
||||
"gib": GiByte,
|
||||
"t": TByte,
|
||||
"tb": TByte,
|
||||
"ti": TiByte,
|
||||
"tib": TiByte,
|
||||
"p": PByte,
|
||||
"pb": PByte,
|
||||
"pi": PiByte,
|
||||
"pib": PiByte,
|
||||
"e": EByte,
|
||||
"eb": EByte,
|
||||
"ei": EiByte,
|
||||
"eib": EiByte,
|
||||
}
|
||||
|
||||
var memoryUnitValueTable = map[string]uint64{
|
||||
"b": Byte,
|
||||
"k": KiByte,
|
||||
"kb": KiByte,
|
||||
"m": MiByte,
|
||||
"mb": MiByte,
|
||||
"g": GiByte,
|
||||
"gb": GiByte,
|
||||
"t": TiByte,
|
||||
"tb": TiByte,
|
||||
"p": PiByte,
|
||||
"pb": PiByte,
|
||||
"e": EiByte,
|
||||
"eb": EiByte,
|
||||
}
|
||||
|
||||
var networkUnitValueTable = map[string]uint64{
|
||||
"Bps": Byte,
|
||||
"Kbps": KByte / 8,
|
||||
"KBps": KByte,
|
||||
"Mbps": MByte / 8,
|
||||
"MBps": MByte,
|
||||
"Gbps": GByte / 8,
|
||||
"GBps": GByte,
|
||||
"Tbps": TByte / 8,
|
||||
"TBps": TByte,
|
||||
"Pbps": PByte / 8,
|
||||
"PBps": PByte,
|
||||
"Ebps": EByte / 8,
|
||||
"EBps": EByte,
|
||||
}
|
||||
|
||||
type rawBytes struct {
|
||||
value uint64
|
||||
unit string
|
||||
unitValue uint64
|
||||
}
|
||||
|
||||
func (b rawBytes) MarshalJSON() ([]byte, error) {
|
||||
if b.unit == "" {
|
||||
return json.Marshal(b.value)
|
||||
}
|
||||
return json.Marshal(strconv.FormatUint(b.value/b.unitValue, 10) + b.unit)
|
||||
}
|
||||
|
||||
func parseUnit(b *rawBytes, unitTable map[string]uint64, caseSensitive bool, bytes []byte) error {
|
||||
var intValue int64
|
||||
err := json.Unmarshal(bytes, &intValue)
|
||||
if err == nil {
|
||||
b.value = uint64(intValue)
|
||||
b.unit = ""
|
||||
b.unitValue = 1
|
||||
return nil
|
||||
}
|
||||
var stringValue string
|
||||
err = json.Unmarshal(bytes, &stringValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.TrimSpace(stringValue) == "" {
|
||||
b.value = 0
|
||||
b.unit = ""
|
||||
b.unitValue = 1
|
||||
return nil
|
||||
}
|
||||
unitIndex := 0
|
||||
for i, c := range stringValue {
|
||||
if c < '0' || c > '9' {
|
||||
unitIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if unitIndex == 0 {
|
||||
return fmt.Errorf("invalid format: %s", stringValue)
|
||||
}
|
||||
value, err := strconv.ParseUint(stringValue[:unitIndex], 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse %s: %w", stringValue[:unitIndex], err)
|
||||
}
|
||||
rawUnit := stringValue[unitIndex:]
|
||||
var unit string
|
||||
if caseSensitive {
|
||||
unit = strings.TrimSpace(rawUnit)
|
||||
} else {
|
||||
unit = strings.TrimSpace(strings.ToLower(rawUnit))
|
||||
}
|
||||
unitValue, loaded := unitTable[unit]
|
||||
if !loaded {
|
||||
return fmt.Errorf("unsupported unit: %s", rawUnit)
|
||||
}
|
||||
b.value = value * unitValue
|
||||
b.unit = rawUnit
|
||||
b.unitValue = unitValue
|
||||
return nil
|
||||
}
|
||||
|
||||
type Bytes struct {
|
||||
rawBytes
|
||||
}
|
||||
|
||||
func (b *Bytes) Value() uint64 {
|
||||
if b == nil {
|
||||
return 0
|
||||
}
|
||||
return b.value
|
||||
}
|
||||
|
||||
func (b *Bytes) UnmarshalJSON(bytes []byte) error {
|
||||
return parseUnit(&b.rawBytes, unitValueTable, false, bytes)
|
||||
}
|
||||
|
||||
type MemoryBytes struct {
|
||||
rawBytes
|
||||
}
|
||||
|
||||
func (m *MemoryBytes) Value() uint64 {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
return m.value
|
||||
}
|
||||
|
||||
func (m *MemoryBytes) UnmarshalJSON(bytes []byte) error {
|
||||
return parseUnit(&m.rawBytes, memoryUnitValueTable, false, bytes)
|
||||
}
|
||||
|
||||
type NetworkBytes struct {
|
||||
rawBytes
|
||||
}
|
||||
|
||||
func (n *NetworkBytes) Value() uint64 {
|
||||
if n == nil {
|
||||
return 0
|
||||
}
|
||||
return n.value
|
||||
}
|
||||
|
||||
func (n *NetworkBytes) UnmarshalJSON(bytes []byte) error {
|
||||
return parseUnit(&n.rawBytes, networkUnitValueTable, true, bytes)
|
||||
}
|
||||
|
||||
type NetworkBytesCompat struct {
|
||||
rawBytes
|
||||
}
|
||||
|
||||
func (n *NetworkBytesCompat) Value() uint64 {
|
||||
if n == nil {
|
||||
return 0
|
||||
}
|
||||
return n.value
|
||||
}
|
||||
|
||||
func (n *NetworkBytesCompat) UnmarshalJSON(bytes []byte) error {
|
||||
err := parseUnit(&n.rawBytes, networkUnitValueTable, true, bytes)
|
||||
if err != nil {
|
||||
newErr := parseUnit(&n.rawBytes, unitValueTable, false, bytes)
|
||||
if newErr == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
114
common/byteformats/json_test.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package byteformats_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/sagernet/sing-box/common/byteformats"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNetworkBytes(t *testing.T) {
|
||||
t.Parallel()
|
||||
testMap := map[string]uint64{
|
||||
"1 Bps": byteformats.Byte,
|
||||
"1 Kbps": byteformats.KByte / 8,
|
||||
"1 KBps": byteformats.KByte,
|
||||
"1 Mbps": byteformats.MByte / 8,
|
||||
"1 MBps": byteformats.MByte,
|
||||
"1 Gbps": byteformats.GByte / 8,
|
||||
"1 GBps": byteformats.GByte,
|
||||
"1 Tbps": byteformats.TByte / 8,
|
||||
"1 TBps": byteformats.TByte,
|
||||
"1 Pbps": byteformats.PByte / 8,
|
||||
"1 PBps": byteformats.PByte,
|
||||
"1k": byteformats.KByte,
|
||||
"1m": byteformats.MByte,
|
||||
}
|
||||
for k, v := range testMap {
|
||||
var nb byteformats.NetworkBytesCompat
|
||||
require.NoError(t, json.Unmarshal([]byte("\""+k+"\""), &nb))
|
||||
require.Equal(t, v, nb.Value())
|
||||
b, err := json.Marshal(nb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "\""+k+"\"", string(b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemoryBytes(t *testing.T) {
|
||||
t.Parallel()
|
||||
testMap := map[string]uint64{
|
||||
"1 B": byteformats.Byte,
|
||||
"1 KB": byteformats.KiByte,
|
||||
"1 MB": byteformats.MiByte,
|
||||
"1 GB": byteformats.GiByte,
|
||||
"1 TB": byteformats.TiByte,
|
||||
"1 PB": byteformats.PiByte,
|
||||
}
|
||||
for k, v := range testMap {
|
||||
var mb byteformats.MemoryBytes
|
||||
require.NoError(t, json.Unmarshal([]byte("\""+k+"\""), &mb))
|
||||
require.Equal(t, v, mb.Value())
|
||||
b, err := json.Marshal(mb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "\""+k+"\"", string(b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultBytes(t *testing.T) {
|
||||
t.Parallel()
|
||||
testMap := map[string]uint64{
|
||||
"1 B": byteformats.Byte,
|
||||
"1 KB": byteformats.KByte,
|
||||
"1 KiB": byteformats.KiByte,
|
||||
"1 MB": byteformats.MByte,
|
||||
"1 MiB": byteformats.MiByte,
|
||||
"1 GB": byteformats.GByte,
|
||||
"1 GiB": byteformats.GiByte,
|
||||
"1 TB": byteformats.TByte,
|
||||
"1 TiB": byteformats.TiByte,
|
||||
"1 PB": byteformats.PByte,
|
||||
"1 PiB": byteformats.PiByte,
|
||||
"1 EB": byteformats.EByte,
|
||||
"1 EiB": byteformats.EiByte,
|
||||
"1k": byteformats.KByte,
|
||||
"1m": byteformats.MByte,
|
||||
"1g": byteformats.GByte,
|
||||
"1t": byteformats.TByte,
|
||||
"1p": byteformats.PByte,
|
||||
"1e": byteformats.EByte,
|
||||
"1K": byteformats.KByte,
|
||||
"1M": byteformats.MByte,
|
||||
"1G": byteformats.GByte,
|
||||
"1T": byteformats.TByte,
|
||||
"1P": byteformats.PByte,
|
||||
"1E": byteformats.EByte,
|
||||
"1Ki": byteformats.KiByte,
|
||||
"1Mi": byteformats.MiByte,
|
||||
"1Gi": byteformats.GiByte,
|
||||
"1Ti": byteformats.TiByte,
|
||||
"1Pi": byteformats.PiByte,
|
||||
"1Ei": byteformats.EiByte,
|
||||
"1KiB": byteformats.KiByte,
|
||||
"1MiB": byteformats.MiByte,
|
||||
"1GiB": byteformats.GiByte,
|
||||
"1TiB": byteformats.TiByte,
|
||||
"1PiB": byteformats.PiByte,
|
||||
"1EiB": byteformats.EiByte,
|
||||
"1kB": byteformats.KByte,
|
||||
"1mB": byteformats.MByte,
|
||||
"1gB": byteformats.GByte,
|
||||
"1tB": byteformats.TByte,
|
||||
"1pB": byteformats.PByte,
|
||||
"1eB": byteformats.EByte,
|
||||
}
|
||||
for k, v := range testMap {
|
||||
var mb byteformats.Bytes
|
||||
require.NoError(t, json.Unmarshal([]byte("\""+k+"\""), &mb))
|
||||
require.Equal(t, v, mb.Value())
|
||||
b, err := json.Marshal(mb)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "\""+k+"\"", string(b))
|
||||
}
|
||||
}
|
||||
@@ -261,7 +261,8 @@ func getExecPathFromPID(pid uint32) (string, error) {
|
||||
procpidpathinfo,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
procpidpathinfosize)
|
||||
procpidpathinfosize,
|
||||
)
|
||||
if errno != 0 {
|
||||
return "", errno
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@ package common
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
Xbadoption "github.com/sagernet/sing-box/common/xray/json/badoption"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
)
|
||||
|
||||
@@ -66,3 +68,12 @@ func DecodeBase64URLSafe(content string) (string, error) {
|
||||
}
|
||||
return string(result), nil
|
||||
}
|
||||
|
||||
func ParseXHTTPRange(value string) (Xbadoption.Range, error) {
|
||||
result := Xbadoption.Range{}
|
||||
encoded, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
return result, result.UnmarshalJSON(encoded)
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ func MergeMulti(dest MultiBuffer, src MultiBuffer) (MultiBuffer, MultiBuffer) {
|
||||
// MergeBytes merges the given bytes into MultiBuffer and return the new address of the merged MultiBuffer.
|
||||
func MergeBytes(dest MultiBuffer, src []byte) MultiBuffer {
|
||||
n := len(dest)
|
||||
if n > 0 && !(dest)[n-1].IsFull() {
|
||||
nBytes, _ := (dest)[n-1].Write(src)
|
||||
if n > 0 && !dest[n-1].IsFull() {
|
||||
nBytes, _ := dest[n-1].Write(src)
|
||||
src = src[nBytes:]
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ func New(opts ...Option) (*Reader, *Writer) {
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(&(p.option))
|
||||
opt(&p.option)
|
||||
}
|
||||
|
||||
return &Reader{
|
||||
|
||||
@@ -1,28 +1,256 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"hash/fnv"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
func ChromeVersion() int {
|
||||
// Use only CPU info as seed for PRNG
|
||||
seed := int64(cpuid.CPU.Family + cpuid.CPU.Model + cpuid.CPU.PhysicalCores + cpuid.CPU.LogicalCores + cpuid.CPU.CacheLine)
|
||||
rng := rand.New(rand.NewSource(seed))
|
||||
// Start from Chrome 144 released on 2026.1.13
|
||||
releaseDate := time.Date(2026, 1, 13, 0, 0, 0, 0, time.UTC)
|
||||
version := 144
|
||||
now := time.Now()
|
||||
// Each version has random 25-45 day interval
|
||||
for releaseDate.Before(now) {
|
||||
releaseDate = releaseDate.AddDate(0, 0, rng.Intn(21)+25)
|
||||
version++
|
||||
}
|
||||
return version - 1
|
||||
func GetRandomizer() *rand.Rand {
|
||||
// Seed the PRNG with the hash of CPU info, increasing the overall probable space.
|
||||
fnvHash := fnv.New64()
|
||||
fnvHash.Write([]byte(strconv.Itoa(cpuid.CPU.Family) + strconv.Itoa(cpuid.CPU.Model) + strconv.Itoa(cpuid.CPU.PhysicalCores) + strconv.Itoa(cpuid.CPU.LogicalCores) + strconv.Itoa(cpuid.CPU.CacheLine) + strconv.Itoa(cpuid.CPU.ThreadsPerCore)))
|
||||
return rand.New(rand.NewSource(int64(fnvHash.Sum64())))
|
||||
}
|
||||
|
||||
// ChromeUA provides default browser User-Agent based on CPU-seeded PRNG.
|
||||
var ChromeUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + strconv.Itoa(ChromeVersion()) + ".0.0.0 Safari/537.36"
|
||||
var globalRng *rand.Rand = GetRandomizer()
|
||||
|
||||
// The Chrome version generator will suffer from deviation of a normal distribution.
|
||||
func ChromeVersion() int {
|
||||
// Start from Chrome 144, released on 2026.1.13.
|
||||
var startVersion int = 144
|
||||
var timeStart int64 = time.Date(2026, 1, 13, 0, 0, 0, 0, time.UTC).Unix() / 86400
|
||||
var timeCurrent int64 = time.Now().Unix() / 86400
|
||||
var timeDiff int = int((timeCurrent - timeStart - 35)) - int(math.Floor(math.Pow(globalRng.Float64(), 2)*105))
|
||||
return startVersion + (timeDiff / 35) // It's 31.15 currently.
|
||||
}
|
||||
|
||||
var safariMinorMap [25]int = [25]int{0, 0, 0, 1, 1,
|
||||
1, 2, 2, 2, 2, 3, 3, 3, 4, 4,
|
||||
4, 5, 5, 5, 5, 5, 6, 6, 6, 6}
|
||||
|
||||
// The following version generators use deterministic generators, but with the distribution scaled by a curve.
|
||||
func CurlVersion() string {
|
||||
// curl 8.0.0 was released on 20/03/2023.
|
||||
var timeCurrent int64 = time.Now().Unix() / 86400
|
||||
var timeStart int64 = time.Date(2023, 3, 20, 0, 0, 0, 0, time.UTC).Unix() / 86400
|
||||
var timeDiff int = int((timeCurrent - timeStart - 60)) - int(math.Floor(math.Pow(globalRng.Float64(), 2)*165))
|
||||
var minorValue int = int(timeDiff / 57) // The release cadence is actually 56.67 days.
|
||||
return "8." + strconv.Itoa(minorValue) + ".0"
|
||||
}
|
||||
func FirefoxVersion() int {
|
||||
// Firefox 128 ESR was released on 09/07/2023.
|
||||
var timeCurrent int64 = time.Now().Unix() / 86400
|
||||
var timeStart int64 = time.Date(2024, 7, 29, 0, 0, 0, 0, time.UTC).Unix() / 86400
|
||||
var timeDiff = timeCurrent - timeStart - 25 - int64(math.Floor(math.Pow(globalRng.Float64(), 2)*50))
|
||||
return int(timeDiff/30) + 128
|
||||
}
|
||||
func SafariVersion() string {
|
||||
var anchoredTime time.Time = time.Now()
|
||||
var releaseYear int = anchoredTime.Year()
|
||||
var splitPoint time.Time = time.Date(releaseYear, 9, 23, 0, 0, 0, 0, time.UTC)
|
||||
var delayedDays = int(math.Floor(math.Pow(globalRng.Float64(), 3) * 75))
|
||||
splitPoint = splitPoint.AddDate(0, 0, delayedDays)
|
||||
if anchoredTime.Compare(splitPoint) < 0 {
|
||||
releaseYear--
|
||||
splitPoint = time.Date(releaseYear, 9, 23, 0, 0, 0, 0, time.UTC)
|
||||
splitPoint = splitPoint.AddDate(0, 0, delayedDays)
|
||||
}
|
||||
var minorVersion = safariMinorMap[(anchoredTime.Unix()-splitPoint.Unix())/1296000]
|
||||
return strconv.Itoa(releaseYear-1999) + "." + strconv.Itoa(minorVersion)
|
||||
}
|
||||
|
||||
// The full Chromium brand GREASE implementation
|
||||
var clientHintGreaseNA = []string{" ", "(", ":", "-", ".", "/", ")", ";", "=", "?", "_"}
|
||||
var clientHintVersionNA = []string{"8", "99", "24"}
|
||||
var clientHintShuffle3 = [][3]int{{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}}
|
||||
var clientHintShuffle4 = [][4]int{
|
||||
{0, 1, 2, 3}, {0, 1, 3, 2}, {0, 2, 1, 3}, {0, 2, 3, 1}, {0, 3, 1, 2}, {0, 3, 2, 1},
|
||||
{1, 0, 2, 3}, {1, 0, 3, 2}, {1, 2, 0, 3}, {1, 2, 3, 0}, {1, 3, 0, 2}, {1, 3, 2, 0},
|
||||
{2, 0, 1, 3}, {2, 0, 3, 1}, {2, 1, 0, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {2, 3, 1, 0},
|
||||
{3, 0, 1, 2}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 1, 2, 0}, {3, 2, 0, 1}, {3, 2, 1, 0}}
|
||||
|
||||
func getGreasedChInvalidBrand(seed int) string {
|
||||
return "\"Not" + clientHintGreaseNA[seed%len(clientHintGreaseNA)] + "A" + clientHintGreaseNA[(seed+1)%len(clientHintGreaseNA)] + "Brand\";v=\"" + clientHintVersionNA[seed%len(clientHintVersionNA)] + "\""
|
||||
}
|
||||
func getGreasedChOrder(brandLength int, seed int) []int {
|
||||
switch brandLength {
|
||||
case 1:
|
||||
return []int{0}
|
||||
case 2:
|
||||
return []int{seed % brandLength, (seed + 1) % brandLength}
|
||||
case 3:
|
||||
return clientHintShuffle3[seed%len(clientHintShuffle3)][:]
|
||||
default:
|
||||
return clientHintShuffle4[seed%len(clientHintShuffle4)][:]
|
||||
}
|
||||
//return []int{}
|
||||
}
|
||||
func getUngreasedChUa(majorVersion int, forkName string) []string {
|
||||
// Set the capacity to 4, the maximum allowed brand size, so Go will never allocate memory twice
|
||||
baseChUa := make([]string, 0, 4)
|
||||
baseChUa = append(baseChUa, getGreasedChInvalidBrand(majorVersion),
|
||||
"\"Chromium\";v=\""+strconv.Itoa(majorVersion)+"\"")
|
||||
switch forkName {
|
||||
case "chrome":
|
||||
baseChUa = append(baseChUa, "\"Google Chrome\";v=\""+strconv.Itoa(majorVersion)+"\"")
|
||||
case "edge":
|
||||
baseChUa = append(baseChUa, "\"Microsoft Edge\";v=\""+strconv.Itoa(majorVersion)+"\"")
|
||||
}
|
||||
return baseChUa
|
||||
}
|
||||
func getGreasedChUa(majorVersion int, forkName string) string {
|
||||
ungreasedCh := getUngreasedChUa(majorVersion, forkName)
|
||||
shuffleMap := getGreasedChOrder(len(ungreasedCh), majorVersion)
|
||||
shuffledCh := make([]string, len(ungreasedCh))
|
||||
for i, e := range shuffleMap {
|
||||
shuffledCh[e] = ungreasedCh[i]
|
||||
}
|
||||
return strings.Join(shuffledCh, ", ")
|
||||
}
|
||||
|
||||
// The code below provides a coherent default browser user agent string based on a CPU-seeded PRNG.
|
||||
var CurlUA = "curl/" + CurlVersion()
|
||||
var AnchoredFirefoxVersion = strconv.Itoa(FirefoxVersion())
|
||||
var FirefoxUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:" + AnchoredFirefoxVersion + ".0) Gecko/20100101 Firefox/" + AnchoredFirefoxVersion + ".0"
|
||||
var SafariUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/" + SafariVersion() + " Safari/605.1.15"
|
||||
|
||||
// Chromium browsers.
|
||||
var AnchoredChromeVersion = ChromeVersion()
|
||||
var ChromeUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + strconv.Itoa(AnchoredChromeVersion) + ".0.0.0 Safari/537.36"
|
||||
var ChromeUACH = getGreasedChUa(AnchoredChromeVersion, "chrome")
|
||||
var MSEdgeUA = ChromeUA + "Edg/" + strconv.Itoa(AnchoredChromeVersion) + ".0.0.0"
|
||||
var MSEdgeUACH = getGreasedChUa(AnchoredChromeVersion, "edge")
|
||||
|
||||
func applyMasqueradedHeaders(header http.Header, browser string, variant string) {
|
||||
// Browser-specific.
|
||||
switch browser {
|
||||
case "chrome":
|
||||
header["Sec-CH-UA"] = []string{ChromeUACH}
|
||||
header["Sec-CH-UA-Mobile"] = []string{"?0"}
|
||||
header["Sec-CH-UA-Platform"] = []string{"\"Windows\""}
|
||||
header["DNT"] = []string{"1"}
|
||||
header.Set("User-Agent", ChromeUA)
|
||||
header.Set("Accept-Language", "en-US,en;q=0.9")
|
||||
case "edge":
|
||||
header["Sec-CH-UA"] = []string{MSEdgeUACH}
|
||||
header["Sec-CH-UA-Mobile"] = []string{"?0"}
|
||||
header["Sec-CH-UA-Platform"] = []string{"\"Windows\""}
|
||||
header["DNT"] = []string{"1"}
|
||||
header.Set("User-Agent", MSEdgeUA)
|
||||
header.Set("Accept-Language", "en-US,en;q=0.9")
|
||||
case "firefox":
|
||||
header.Set("User-Agent", FirefoxUA)
|
||||
header["DNT"] = []string{"1"}
|
||||
header.Set("Accept-Language", "en-US,en;q=0.5")
|
||||
case "safari":
|
||||
header.Set("User-Agent", SafariUA)
|
||||
header.Set("Accept-Language", "en-US,en;q=0.9")
|
||||
case "golang":
|
||||
// Expose the default net/http header.
|
||||
header.Del("User-Agent")
|
||||
return
|
||||
case "curl":
|
||||
header.Set("User-Agent", CurlUA)
|
||||
return
|
||||
}
|
||||
// Context-specific.
|
||||
switch variant {
|
||||
case "nav":
|
||||
if header.Get("Cache-Control") == "" {
|
||||
switch browser {
|
||||
case "chrome", "edge":
|
||||
header.Set("Cache-Control", "max-age=0")
|
||||
}
|
||||
}
|
||||
header.Set("Upgrade-Insecure-Requests", "1")
|
||||
if header.Get("Accept") == "" {
|
||||
switch browser {
|
||||
case "chrome", "edge":
|
||||
header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
|
||||
case "firefox", "safari":
|
||||
header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||
}
|
||||
}
|
||||
header.Set("Sec-Fetch-Site", "none")
|
||||
header.Set("Sec-Fetch-Mode", "navigate")
|
||||
switch browser {
|
||||
case "safari":
|
||||
default:
|
||||
header.Set("Sec-Fetch-User", "?1")
|
||||
}
|
||||
header.Set("Sec-Fetch-Dest", "document")
|
||||
header.Set("Priority", "u=0, i")
|
||||
case "ws":
|
||||
header.Set("Sec-Fetch-Mode", "websocket")
|
||||
switch browser {
|
||||
case "safari":
|
||||
// Safari is NOT web-compliant here!
|
||||
header.Set("Sec-Fetch-Dest", "websocket")
|
||||
default:
|
||||
header.Set("Sec-Fetch-Dest", "empty")
|
||||
}
|
||||
header.Set("Sec-Fetch-Site", "same-origin")
|
||||
if header.Get("Cache-Control") == "" {
|
||||
header.Set("Cache-Control", "no-cache")
|
||||
}
|
||||
if header.Get("Pragma") == "" {
|
||||
header.Set("Pragma", "no-cache")
|
||||
}
|
||||
if header.Get("Accept") == "" {
|
||||
header.Set("Accept", "*/*")
|
||||
}
|
||||
case "fetch":
|
||||
header.Set("Sec-Fetch-Mode", "cors")
|
||||
header.Set("Sec-Fetch-Dest", "empty")
|
||||
header.Set("Sec-Fetch-Site", "same-origin")
|
||||
if header.Get("Priority") == "" {
|
||||
switch browser {
|
||||
case "chrome", "edge":
|
||||
header.Set("Priority", "u=1, i")
|
||||
case "firefox":
|
||||
header.Set("Priority", "u=4")
|
||||
case "safari":
|
||||
header.Set("Priority", "u=3, i")
|
||||
}
|
||||
}
|
||||
if header.Get("Cache-Control") == "" {
|
||||
header.Set("Cache-Control", "no-cache")
|
||||
}
|
||||
if header.Get("Pragma") == "" {
|
||||
header.Set("Pragma", "no-cache")
|
||||
}
|
||||
if header.Get("Accept") == "" {
|
||||
header.Set("Accept", "*/*")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TryDefaultHeadersWith(header http.Header, variant string) {
|
||||
// The global UA special value handler for transports. Used to be called HandleTransportUASettings.
|
||||
// Just a FYI to whoever needing to fix this piece of code after some spontaneous event, I tried to make the two methods separate to let the code be cleaner and more organized.
|
||||
if len(header.Values("User-Agent")) < 1 {
|
||||
applyMasqueradedHeaders(header, "chrome", variant)
|
||||
} else {
|
||||
switch header.Get("User-Agent") {
|
||||
case "chrome":
|
||||
applyMasqueradedHeaders(header, "chrome", variant)
|
||||
case "firefox":
|
||||
applyMasqueradedHeaders(header, "firefox", variant)
|
||||
case "safari":
|
||||
applyMasqueradedHeaders(header, "safari", variant)
|
||||
case "edge":
|
||||
applyMasqueradedHeaders(header, "edge", variant)
|
||||
case "curl":
|
||||
applyMasqueradedHeaders(header, "curl", variant)
|
||||
case "golang":
|
||||
applyMasqueradedHeaders(header, "golang", variant)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ const (
|
||||
DNSTypeDHCP = "dhcp"
|
||||
DNSTypeTailscale = "tailscale"
|
||||
DNSTypeSDNS = "sdns"
|
||||
DNSTypeFallback = "fallback"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
9
constant/manager_api.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package constant
|
||||
|
||||
const (
|
||||
ManagerAPIServer = "server"
|
||||
ManagerAPIClient = "client"
|
||||
|
||||
ManagerAPIProtocolHTTP = "http"
|
||||
ManagerAPIProtocolGrpc = "grpc"
|
||||
)
|
||||
6
constant/node_manager_api.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package constant
|
||||
|
||||
const (
|
||||
NodeManagerAPIServer = "server"
|
||||
NodeManagerAPIClient = "client"
|
||||
)
|
||||
@@ -30,15 +30,17 @@ const (
|
||||
TypeTUIC = "tuic"
|
||||
TypeHysteria2 = "hysteria2"
|
||||
TypeBond = "bond"
|
||||
TypeFailover = "failover"
|
||||
TypeVPNServer = "vpn-server"
|
||||
TypeVPNClient = "vpn-client"
|
||||
TypeTailscale = "tailscale"
|
||||
TypeConnectionLimiter = "connection-limiter"
|
||||
TypeBandwidthLimiter = "bandwidth-limiter"
|
||||
TypeTrafficLimiter = "traffic-limiter"
|
||||
TypeRateLimiter = "rate-limiter"
|
||||
TypeAdminPanel = "admin-panel"
|
||||
TypeNodeManagerServer = "node-manager-server"
|
||||
TypeNodeManagerClient = "node-manager-client"
|
||||
TypeManagerAPI = "manager-api"
|
||||
TypeNodeManagerAPI = "node-manager-api"
|
||||
TypeDERP = "derp"
|
||||
TypeManager = "manager"
|
||||
TypeNode = "node"
|
||||
@@ -47,6 +49,7 @@ const (
|
||||
TypeCCM = "ccm"
|
||||
TypeOCM = "ocm"
|
||||
TypeOOMKiller = "oom-killer"
|
||||
TypeProfiler = "profiler"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -111,6 +114,8 @@ func ProxyDisplayName(proxyType string) string {
|
||||
return "Hysteria2"
|
||||
case TypeBond:
|
||||
return "Bond"
|
||||
case TypeFailover:
|
||||
return "Failover"
|
||||
case TypeMieru:
|
||||
return "Mieru"
|
||||
case TypeAnyTLS:
|
||||
@@ -123,10 +128,20 @@ func ProxyDisplayName(proxyType string) string {
|
||||
return "Selector"
|
||||
case TypeURLTest:
|
||||
return "URLTest"
|
||||
case TypeConnectionLimiter:
|
||||
return "Connection Limiter"
|
||||
case TypeBandwidthLimiter:
|
||||
return "Bandwidth Limiter"
|
||||
case TypeTrafficLimiter:
|
||||
return "Traffic Limiter"
|
||||
case TypeRateLimiter:
|
||||
return "Rate Limiter"
|
||||
case TypeVPNClient:
|
||||
return "VPN Client"
|
||||
case TypeVPNServer:
|
||||
return "VPN Server"
|
||||
case TypeProfiler:
|
||||
return "Profiler"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -1948,43 +1947,40 @@ func file_daemon_started_service_proto_rawDescGZIP() []byte {
|
||||
return file_daemon_started_service_proto_rawDescData
|
||||
}
|
||||
|
||||
var (
|
||||
file_daemon_started_service_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
||||
file_daemon_started_service_proto_msgTypes = make([]protoimpl.MessageInfo, 26)
|
||||
file_daemon_started_service_proto_goTypes = []any{
|
||||
(LogLevel)(0), // 0: daemon.LogLevel
|
||||
(ConnectionEventType)(0), // 1: daemon.ConnectionEventType
|
||||
(ServiceStatus_Type)(0), // 2: daemon.ServiceStatus.Type
|
||||
(*ServiceStatus)(nil), // 3: daemon.ServiceStatus
|
||||
(*ReloadServiceRequest)(nil), // 4: daemon.ReloadServiceRequest
|
||||
(*SubscribeStatusRequest)(nil), // 5: daemon.SubscribeStatusRequest
|
||||
(*Log)(nil), // 6: daemon.Log
|
||||
(*DefaultLogLevel)(nil), // 7: daemon.DefaultLogLevel
|
||||
(*Status)(nil), // 8: daemon.Status
|
||||
(*Groups)(nil), // 9: daemon.Groups
|
||||
(*Group)(nil), // 10: daemon.Group
|
||||
(*GroupItem)(nil), // 11: daemon.GroupItem
|
||||
(*URLTestRequest)(nil), // 12: daemon.URLTestRequest
|
||||
(*SelectOutboundRequest)(nil), // 13: daemon.SelectOutboundRequest
|
||||
(*SetGroupExpandRequest)(nil), // 14: daemon.SetGroupExpandRequest
|
||||
(*ClashMode)(nil), // 15: daemon.ClashMode
|
||||
(*ClashModeStatus)(nil), // 16: daemon.ClashModeStatus
|
||||
(*SystemProxyStatus)(nil), // 17: daemon.SystemProxyStatus
|
||||
(*SetSystemProxyEnabledRequest)(nil), // 18: daemon.SetSystemProxyEnabledRequest
|
||||
(*SubscribeConnectionsRequest)(nil), // 19: daemon.SubscribeConnectionsRequest
|
||||
(*ConnectionEvent)(nil), // 20: daemon.ConnectionEvent
|
||||
(*ConnectionEvents)(nil), // 21: daemon.ConnectionEvents
|
||||
(*Connection)(nil), // 22: daemon.Connection
|
||||
(*ProcessInfo)(nil), // 23: daemon.ProcessInfo
|
||||
(*CloseConnectionRequest)(nil), // 24: daemon.CloseConnectionRequest
|
||||
(*DeprecatedWarnings)(nil), // 25: daemon.DeprecatedWarnings
|
||||
(*DeprecatedWarning)(nil), // 26: daemon.DeprecatedWarning
|
||||
(*StartedAt)(nil), // 27: daemon.StartedAt
|
||||
(*Log_Message)(nil), // 28: daemon.Log.Message
|
||||
(*emptypb.Empty)(nil), // 29: google.protobuf.Empty
|
||||
}
|
||||
)
|
||||
|
||||
var file_daemon_started_service_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
||||
var file_daemon_started_service_proto_msgTypes = make([]protoimpl.MessageInfo, 26)
|
||||
var file_daemon_started_service_proto_goTypes = []any{
|
||||
(LogLevel)(0), // 0: daemon.LogLevel
|
||||
(ConnectionEventType)(0), // 1: daemon.ConnectionEventType
|
||||
(ServiceStatus_Type)(0), // 2: daemon.ServiceStatus.Type
|
||||
(*ServiceStatus)(nil), // 3: daemon.ServiceStatus
|
||||
(*ReloadServiceRequest)(nil), // 4: daemon.ReloadServiceRequest
|
||||
(*SubscribeStatusRequest)(nil), // 5: daemon.SubscribeStatusRequest
|
||||
(*Log)(nil), // 6: daemon.Log
|
||||
(*DefaultLogLevel)(nil), // 7: daemon.DefaultLogLevel
|
||||
(*Status)(nil), // 8: daemon.Status
|
||||
(*Groups)(nil), // 9: daemon.Groups
|
||||
(*Group)(nil), // 10: daemon.Group
|
||||
(*GroupItem)(nil), // 11: daemon.GroupItem
|
||||
(*URLTestRequest)(nil), // 12: daemon.URLTestRequest
|
||||
(*SelectOutboundRequest)(nil), // 13: daemon.SelectOutboundRequest
|
||||
(*SetGroupExpandRequest)(nil), // 14: daemon.SetGroupExpandRequest
|
||||
(*ClashMode)(nil), // 15: daemon.ClashMode
|
||||
(*ClashModeStatus)(nil), // 16: daemon.ClashModeStatus
|
||||
(*SystemProxyStatus)(nil), // 17: daemon.SystemProxyStatus
|
||||
(*SetSystemProxyEnabledRequest)(nil), // 18: daemon.SetSystemProxyEnabledRequest
|
||||
(*SubscribeConnectionsRequest)(nil), // 19: daemon.SubscribeConnectionsRequest
|
||||
(*ConnectionEvent)(nil), // 20: daemon.ConnectionEvent
|
||||
(*ConnectionEvents)(nil), // 21: daemon.ConnectionEvents
|
||||
(*Connection)(nil), // 22: daemon.Connection
|
||||
(*ProcessInfo)(nil), // 23: daemon.ProcessInfo
|
||||
(*CloseConnectionRequest)(nil), // 24: daemon.CloseConnectionRequest
|
||||
(*DeprecatedWarnings)(nil), // 25: daemon.DeprecatedWarnings
|
||||
(*DeprecatedWarning)(nil), // 26: daemon.DeprecatedWarning
|
||||
(*StartedAt)(nil), // 27: daemon.StartedAt
|
||||
(*Log_Message)(nil), // 28: daemon.Log.Message
|
||||
(*emptypb.Empty)(nil), // 29: google.protobuf.Empty
|
||||
}
|
||||
var file_daemon_started_service_proto_depIdxs = []int32{
|
||||
2, // 0: daemon.ServiceStatus.status:type_name -> daemon.ServiceStatus.Type
|
||||
28, // 1: daemon.Log.messages:type_name -> daemon.Log.Message
|
||||
|
||||
@@ -2,7 +2,6 @@ package daemon
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
@@ -375,83 +374,63 @@ type UnimplementedStartedServiceServer struct{}
|
||||
func (UnimplementedStartedServiceServer) StopService(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method StopService not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) ReloadService(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ReloadService not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SubscribeServiceStatus(*emptypb.Empty, grpc.ServerStreamingServer[ServiceStatus]) error {
|
||||
return status.Error(codes.Unimplemented, "method SubscribeServiceStatus not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SubscribeLog(*emptypb.Empty, grpc.ServerStreamingServer[Log]) error {
|
||||
return status.Error(codes.Unimplemented, "method SubscribeLog not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) GetDefaultLogLevel(context.Context, *emptypb.Empty) (*DefaultLogLevel, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetDefaultLogLevel not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) ClearLogs(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ClearLogs not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SubscribeStatus(*SubscribeStatusRequest, grpc.ServerStreamingServer[Status]) error {
|
||||
return status.Error(codes.Unimplemented, "method SubscribeStatus not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SubscribeGroups(*emptypb.Empty, grpc.ServerStreamingServer[Groups]) error {
|
||||
return status.Error(codes.Unimplemented, "method SubscribeGroups not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) GetClashModeStatus(context.Context, *emptypb.Empty) (*ClashModeStatus, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetClashModeStatus not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SubscribeClashMode(*emptypb.Empty, grpc.ServerStreamingServer[ClashMode]) error {
|
||||
return status.Error(codes.Unimplemented, "method SubscribeClashMode not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SetClashMode(context.Context, *ClashMode) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SetClashMode not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) URLTest(context.Context, *URLTestRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method URLTest not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SelectOutbound(context.Context, *SelectOutboundRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SelectOutbound not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SetGroupExpand(context.Context, *SetGroupExpandRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SetGroupExpand not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) GetSystemProxyStatus(context.Context, *emptypb.Empty) (*SystemProxyStatus, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetSystemProxyStatus not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SetSystemProxyEnabled(context.Context, *SetSystemProxyEnabledRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SetSystemProxyEnabled not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) SubscribeConnections(*SubscribeConnectionsRequest, grpc.ServerStreamingServer[ConnectionEvents]) error {
|
||||
return status.Error(codes.Unimplemented, "method SubscribeConnections not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) CloseConnection(context.Context, *CloseConnectionRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CloseConnection not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) CloseAllConnections(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CloseAllConnections not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) GetDeprecatedWarnings(context.Context, *emptypb.Empty) (*DeprecatedWarnings, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetDeprecatedWarnings not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) GetStartedAt(context.Context, *emptypb.Empty) (*StartedAt, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetStartedAt not implemented")
|
||||
}
|
||||
|
||||
72
dns/transport/fallback/fallback.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package fallback
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
"github.com/sagernet/sing/service"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func RegisterTransport(registry *dns.TransportRegistry) {
|
||||
dns.RegisterTransport[option.FallbackDNSServerOptions](registry, C.DNSTypeFallback, NewTransport)
|
||||
}
|
||||
|
||||
var _ adapter.DNSTransport = (*Transport)(nil)
|
||||
|
||||
type Transport struct {
|
||||
dns.TransportAdapter
|
||||
ctx context.Context
|
||||
manager adapter.DNSTransportManager
|
||||
logger logger.ContextLogger
|
||||
tags []string
|
||||
strategy ExchangeStrategy
|
||||
}
|
||||
|
||||
func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.FallbackDNSServerOptions) (adapter.DNSTransport, error) {
|
||||
if len(options.Servers) == 0 {
|
||||
return nil, E.New("missing servers")
|
||||
}
|
||||
manager := service.FromContext[adapter.DNSTransportManager](ctx)
|
||||
servers := make([]adapter.DNSTransport, len(options.Servers))
|
||||
for i, tag := range options.Servers {
|
||||
server, loaded := manager.Transport(tag)
|
||||
if !loaded {
|
||||
return nil, E.New("server ", tag, " not found")
|
||||
}
|
||||
servers[i] = server
|
||||
}
|
||||
strategy, err := CreateStrategy(options.Strategy, servers, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Transport{
|
||||
TransportAdapter: dns.NewTransportAdapter(C.DNSTypeFallback, tag, options.Servers),
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
tags: options.Servers,
|
||||
strategy: strategy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) Reset() {
|
||||
}
|
||||
|
||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
return t.strategy(ctx, message)
|
||||
}
|
||||
73
dns/transport/fallback/strategy.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package fallback
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
)
|
||||
|
||||
type ExchangeStrategy = func(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error)
|
||||
|
||||
func parallelStrategy(servers []adapter.DNSTransport, logger logger.ContextLogger) ExchangeStrategy {
|
||||
return func(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
queryCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
type result struct {
|
||||
response *mDNS.Msg
|
||||
err error
|
||||
}
|
||||
results := make(chan result)
|
||||
for _, server := range servers {
|
||||
go func() {
|
||||
response, err := server.Exchange(queryCtx, message)
|
||||
select {
|
||||
case results <- result{response, err}:
|
||||
case <-queryCtx.Done():
|
||||
}
|
||||
}()
|
||||
}
|
||||
var lastErr error
|
||||
for range servers {
|
||||
select {
|
||||
case result := <-results:
|
||||
if result.err != nil {
|
||||
lastErr = result.err
|
||||
continue
|
||||
}
|
||||
return result.response, nil
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
return nil, lastErr
|
||||
}
|
||||
}
|
||||
|
||||
func sequentialStrategy(servers []adapter.DNSTransport, logger logger.ContextLogger) ExchangeStrategy {
|
||||
return func(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
var lastErr error
|
||||
for _, server := range servers {
|
||||
response, err := server.Exchange(ctx, message)
|
||||
if err != nil {
|
||||
lastErr = err
|
||||
continue
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
return nil, lastErr
|
||||
}
|
||||
}
|
||||
|
||||
func CreateStrategy(strategy string, servers []adapter.DNSTransport, logger logger.ContextLogger) (ExchangeStrategy, error) {
|
||||
switch strategy {
|
||||
case "parallel":
|
||||
return parallelStrategy(servers, logger), nil
|
||||
case "", "sequential":
|
||||
return sequentialStrategy(servers, logger), nil
|
||||
default:
|
||||
return nil, E.New("strategy not found: ", strategy)
|
||||
}
|
||||
}
|
||||
47
examples/admin_panel-manager-node/client.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "error"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen_port": 7897
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-out",
|
||||
"server": "0.0.0.0",
|
||||
"server_port": 443,
|
||||
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937",
|
||||
"transport": {
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"final": "vless-out",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
90
examples/admin_panel-manager-node/manager.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"final": "direct-out"
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"type": "manager",
|
||||
"tag": "my-manager",
|
||||
"database": {
|
||||
"driver": "sqlite",
|
||||
"dsn": "file:manager.db?_pragma=foreign_keys(on)&_pragma=journal_mode(wal)&_pragma=busy_timeout(5000)" // also supported Postgresql
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "manager-api",
|
||||
"tag": "my-manager-api",
|
||||
"api_type": "server",
|
||||
"protocol_type": "http",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 8080,
|
||||
"manager": "my-manager",
|
||||
"api_key": "change-me-secret",
|
||||
"cors": {
|
||||
"allowed_origins": ["*"],
|
||||
"max_age": 600
|
||||
},
|
||||
// Enable TLS for production deployments:
|
||||
// "tls": { // https://sing-box.sagernet.org/configuration/shared/tls/#inbound
|
||||
// "enabled": true,
|
||||
// "server_name": "manager.example.com",
|
||||
// "certificate_path": "fullchain.pem",
|
||||
// "key_path": "privkey.pem"
|
||||
// }
|
||||
},
|
||||
{
|
||||
"type": "node-manager-api",
|
||||
"tag": "my-node-manager-api",
|
||||
"api_type": "server",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 7000,
|
||||
"manager": "my-manager",
|
||||
"api_key": "change-me-secret",
|
||||
// Enable TLS for production deployments (the node connects via gRPC over h2):
|
||||
// "tls": { // https://sing-box.sagernet.org/configuration/shared/tls/#inbound
|
||||
// "enabled": true,
|
||||
// "server_name": "example.com",
|
||||
// "alpn": "h2", // h3 for QUIC
|
||||
// "certificate_path": "fullchain.pem",
|
||||
// "key_path": "privkey.pem"
|
||||
// }
|
||||
},
|
||||
{
|
||||
"type": "admin-panel",
|
||||
"tag": "admin",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 8081,
|
||||
// Enable TLS for production deployments:
|
||||
// "tls": { // https://sing-box.sagernet.org/configuration/shared/tls/#inbound
|
||||
// "enabled": true,
|
||||
// "server_name": "panel.example.com",
|
||||
// "certificate_path": "fullchain.pem",
|
||||
// "key_path": "privkey.pem"
|
||||
// }
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "error"
|
||||
"level": "debug"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
@@ -33,13 +33,29 @@
|
||||
"route": {
|
||||
"final": "direct-out"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "rate-limiter",
|
||||
"tag": "rate-limiter",
|
||||
"strategy": "manager",
|
||||
"route": {
|
||||
"final": "bandwidth-limiter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "connection-limiter",
|
||||
"tag": "connection-limiter",
|
||||
"strategy": "manager",
|
||||
"route": {
|
||||
"final": "bandwidth-limiter"
|
||||
"final": "rate-limiter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "traffic-limiter",
|
||||
"tag": "traffic-limiter",
|
||||
"strategy": "manager",
|
||||
"route": {
|
||||
"final": "connection-limiter"
|
||||
}
|
||||
},
|
||||
],
|
||||
@@ -59,19 +75,23 @@
|
||||
"uuid": "e6eceb84-ad66-474b-8641-142499db7c6e",
|
||||
"manager": "node-manager",
|
||||
"inbounds": ["vless-in"],
|
||||
"bandwidth_limiters": ["bandwidth-limiter"],
|
||||
"connection_limiters": ["connection-limiter"],
|
||||
"bandwidth_limiters": ["bandwidth-limiter"],
|
||||
"traffic_limiters": ["traffic-limiter"],
|
||||
"rate_limiters": ["rate-limiter"]
|
||||
},
|
||||
{
|
||||
"type": "node-manager-client",
|
||||
"type": "node-manager-api",
|
||||
"tag": "node-manager",
|
||||
"api_type": "client",
|
||||
"server": "example.com",
|
||||
"server_port": 7000,
|
||||
"tls": { // https://sing-box.sagernet.org/configuration/shared/tls/#outbound
|
||||
"enabled": true,
|
||||
"server_name": "example.com",
|
||||
"alpn": "h2" // h3 for QUIC
|
||||
},
|
||||
"api_key": "change-me-secret",
|
||||
// "tls": { // https://sing-box.sagernet.org/configuration/shared/tls/#outbound
|
||||
// "enabled": true,
|
||||
// "server_name": "example.com",
|
||||
// "alpn": "h2" // h3 for QUIC
|
||||
// }
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
examples/admin_panel-manager-node/screens/desktop/00-login.png
Normal file
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 103 KiB |
BIN
examples/admin_panel-manager-node/screens/desktop/02-squads.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
examples/admin_panel-manager-node/screens/desktop/03-nodes.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
examples/admin_panel-manager-node/screens/desktop/04-users.png
Normal file
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 106 KiB |
BIN
examples/admin_panel-manager-node/screens/mobile/00-login.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 747 KiB |
BIN
examples/admin_panel-manager-node/screens/mobile/02-squads.png
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
examples/admin_panel-manager-node/screens/mobile/03-nodes.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
examples/admin_panel-manager-node/screens/mobile/04-users.png
Normal file
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 233 KiB |
|
After Width: | Height: | Size: 213 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 209 KiB |
BIN
examples/admin_panel-manager-node/screens/mobile/09-nav-open.png
Normal file
|
After Width: | Height: | Size: 230 KiB |
@@ -15,13 +15,15 @@
|
||||
"type": "wireguard",
|
||||
"tag": "wireguard-out",
|
||||
"mtu": 1408,
|
||||
"address": null,
|
||||
"private_key": "",
|
||||
"address": ["10.0.0.2/32"],
|
||||
"private_key": "QGg8AFRn6qKfTB7cT3FWH1WGx3np+OKzlNuQUrqIBmI=",
|
||||
"listen_port": 10000,
|
||||
"peers": [
|
||||
{
|
||||
"address": "example.com",
|
||||
"port": 10001,
|
||||
"public_key": "3nk7jdnkcL95Fc/z+GCiH7jOovEKhFkLIGPT+U/uLEQ=",
|
||||
"allowed_ips": ["0.0.0.0/0"],
|
||||
"reserved": "AAAA"
|
||||
}
|
||||
],
|
||||
|
||||
62
examples/dns_fallback/client.json
Normal file
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "debug"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "udp",
|
||||
"tag": "dns-cloudflare",
|
||||
"server": "1.2.3.4"
|
||||
},
|
||||
{
|
||||
"type": "udp",
|
||||
"tag": "dns-google",
|
||||
"server": "1.2.3.4"
|
||||
},
|
||||
{
|
||||
"type": "https",
|
||||
"tag": "dns-quad9-doh",
|
||||
"server": "1.1.1.1"
|
||||
},
|
||||
{
|
||||
"type": "fallback",
|
||||
"tag": "dns-fallback",
|
||||
"servers": [
|
||||
"dns-cloudflare",
|
||||
"dns-google",
|
||||
"dns-quad9-doh"
|
||||
],
|
||||
// Strategies:
|
||||
// - "sequential" (default): query servers in order; on each error move
|
||||
// to the next one. Returns the first successful response, or the
|
||||
// last error if all servers failed.
|
||||
// - "parallel": query all servers concurrently. Returns
|
||||
// the first successful response (cancelling the rest), or the last
|
||||
// error if all servers failed.
|
||||
"strategy": "sequential"
|
||||
}
|
||||
],
|
||||
"disable_cache": true,
|
||||
"independent_cache": true,
|
||||
"final": "dns-fallback"
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen_port": 7897
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "direct",
|
||||
"default_domain_resolver": "dns-fallback",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
65
examples/failover/client.json
Normal file
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "error"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen_port": 7897
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "failover",
|
||||
"tag": "failover-out",
|
||||
// - "sequential" (default): try outbounds in order; return the last error
|
||||
// after exhausting them all.
|
||||
// - "cycle": keep retrying outbounds in round-robin forever
|
||||
// (useful for transient network outages on user devices).
|
||||
"strategy": "cycle",
|
||||
"delay": "2s", // wait between failed attempts; 0 = no delay
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-primary",
|
||||
"server": "primary.example.com",
|
||||
"server_port": 443,
|
||||
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937"
|
||||
},
|
||||
{
|
||||
"type": "trojan",
|
||||
"tag": "trojan-secondary",
|
||||
"server": "secondary.example.com",
|
||||
"server_port": 443,
|
||||
"password": "trojan-password"
|
||||
},
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "ss-tertiary",
|
||||
"server": "tertiary.example.com",
|
||||
"server_port": 8388,
|
||||
"method": "aes-128-gcm",
|
||||
"password": "ss-password"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "failover-out",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
58
examples/failover/server.json
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
// The "failover" inbound wraps several listeners. If any of them
|
||||
// panics or fails to accept, the parent supervises and restarts it
|
||||
// automatically without affecting the rest of the box.
|
||||
"type": "failover",
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "socks-in-1",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 10001
|
||||
},
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "socks-in-2",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 10002
|
||||
},
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-in",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 8443,
|
||||
"users": [
|
||||
{
|
||||
"name": "user",
|
||||
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "direct",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
@@ -40,9 +40,10 @@
|
||||
"type": "bandwidth-limiter",
|
||||
"tag": "bandwidth-limiter",
|
||||
"strategy": "connection",
|
||||
"mode": "duplex", // download, upload
|
||||
"mode": "bidirectional", // download, upload
|
||||
"connection_type": "hwid", // mux, ip
|
||||
"speed": "1MB", // 100KB, 1GB, etc.
|
||||
"flow_keys": ["user", "destination"], // values: user, destination, ip, hwid, mux
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
43
examples/limiters/bandwidth/global.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "socks",
|
||||
"tag": "socks-in",
|
||||
"listen_port": 7897
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "bandwidth-limiter",
|
||||
"tag": "bandwidth-limiter",
|
||||
"strategy": "global",
|
||||
"mode": "bidirectional", // download, upload
|
||||
"speed": "2MB", // 100KB, 1GB, etc.
|
||||
"flow_keys": ["user", "destination"], // values: user, destination, ip, hwid, mux
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "bandwidth-limiter",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
69
examples/limiters/bandwidth/manager.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-in",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 443,
|
||||
"transport": {
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "bandwidth-limiter",
|
||||
"tag": "bandwidth-limiter",
|
||||
// "manager" strategy: per-user bandwidth limits are loaded from the
|
||||
// manager database and updated live (no need to list users in this file).
|
||||
"strategy": "manager",
|
||||
"flow_keys": ["user", "destination"], // values: user, destination, ip, hwid, mux
|
||||
"route": {
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"final": "bandwidth-limiter"
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"type": "manager",
|
||||
"tag": "my-manager",
|
||||
"database": {
|
||||
"driver": "sqlite",
|
||||
"dsn": "file:manager.db?_pragma=foreign_keys(on)&_pragma=journal_mode(wal)&_pragma=busy_timeout(5000)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"tag": "my-node",
|
||||
"uuid": "e6eceb84-ad66-474b-8641-142499db7c6e",
|
||||
"manager": "my-manager",
|
||||
"inbounds": ["vless-in"],
|
||||
"bandwidth_limiters": ["bandwidth-limiter"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -38,10 +38,11 @@
|
||||
},
|
||||
{
|
||||
"type": "bandwidth-limiter",
|
||||
"tag": "duplex-bandwidth-limiter",
|
||||
"tag": "bidirectional-bandwidth-limiter",
|
||||
"strategy": "global",
|
||||
"mode": "duplex",
|
||||
"mode": "bidirectional",
|
||||
"speed": "5MB",
|
||||
"flow_keys": ["user", "destination"], // values: user, destination, ip, hwid, mux
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
@@ -53,9 +54,10 @@
|
||||
"strategy": "global",
|
||||
"mode": "upload",
|
||||
"speed": "3MB",
|
||||
"flow_keys": ["user", "destination"], // values: user, destination, ip, hwid, mux
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "duplex-bandwidth-limiter"
|
||||
"final": "bidirectional-bandwidth-limiter"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -64,6 +66,7 @@
|
||||
"strategy": "global",
|
||||
"mode": "download",
|
||||
"speed": "3MB",
|
||||
"flow_keys": ["user", "destination"], // values: user, destination, ip, hwid, mux
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "upload-bandwidth-limiter"
|
||||
@@ -40,21 +40,22 @@
|
||||
"type": "bandwidth-limiter",
|
||||
"tag": "bandwidth-limiter",
|
||||
"strategy": "users",
|
||||
"flow_keys": ["user", "destination"], // values: user, destination, ip, hwid, mux
|
||||
"users": [
|
||||
{
|
||||
"name": "user1",
|
||||
"strategy": "connection", // global
|
||||
"mode": "duplex", // download, upload
|
||||
"mode": "bidirectional", // download, upload
|
||||
"connection_type": "hwid", // mux, ip
|
||||
"speed": "5MB", // 100KB, 1GB, etc.
|
||||
"speed": "5MB" // 100KB, 1GB, etc.
|
||||
},
|
||||
{
|
||||
"name": "user2",
|
||||
"strategy": "connection", // global
|
||||
"mode": "duplex", // download, upload
|
||||
"mode": "bidirectional", // download, upload
|
||||
"connection_type": "hwid", // mux, ip
|
||||
"speed": "1MB", // 100KB, 1GB, etc.
|
||||
},
|
||||
"speed": "1MB" // 100KB, 1GB, etc.
|
||||
}
|
||||
],
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
@@ -40,7 +40,7 @@
|
||||
"type": "connection-limiter",
|
||||
"tag": "connection-limiter",
|
||||
"strategy": "connection",
|
||||
"connection_type": "hwid", // mux, ip
|
||||
"connection_type": "hwid", // mux, source_ip
|
||||
"count": 5,
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
68
examples/limiters/connection/manager.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-in",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 443,
|
||||
"transport": {
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "connection-limiter",
|
||||
"tag": "connection-limiter",
|
||||
// "manager" strategy: per-user connection caps are loaded from the
|
||||
// manager database and updated live (no need to list users in this file).
|
||||
"strategy": "manager",
|
||||
"route": {
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"final": "connection-limiter"
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"type": "manager",
|
||||
"tag": "my-manager",
|
||||
"database": {
|
||||
"driver": "sqlite",
|
||||
"dsn": "file:manager.db?_pragma=foreign_keys(on)&_pragma=journal_mode(wal)&_pragma=busy_timeout(5000)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"tag": "my-node",
|
||||
"uuid": "e6eceb84-ad66-474b-8641-142499db7c6e",
|
||||
"manager": "my-manager",
|
||||
"inbounds": ["vless-in"],
|
||||
"connection_limiters": ["connection-limiter"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -44,15 +44,15 @@
|
||||
{
|
||||
"name": "user1",
|
||||
"strategy": "connection",
|
||||
"connection_type": "hwid", // mux, ip
|
||||
"count": 5,
|
||||
"connection_type": "hwid", // mux, source_ip
|
||||
"count": 5
|
||||
},
|
||||
{
|
||||
"name": "user2",
|
||||
"strategy": "connection",
|
||||
"connection_type": "hwid", // mux, ip
|
||||
"count": 1,
|
||||
},
|
||||
"connection_type": "hwid", // mux, source_ip
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
@@ -23,10 +23,6 @@
|
||||
{
|
||||
"name": "user1",
|
||||
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937"
|
||||
},
|
||||
{
|
||||
"name": "user2",
|
||||
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -37,11 +33,12 @@
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "bandwidth-limiter",
|
||||
"tag": "bandwidth-limiter",
|
||||
"strategy": "global",
|
||||
"mode": "duplex", // download, upload
|
||||
"speed": "1MB", // 100KB, 1GB, etc.
|
||||
"type": "rate-limiter",
|
||||
"tag": "rate-limiter",
|
||||
"strategy": "token-bucket", // leaky-bucket, sliding-window, fixed-window
|
||||
"connection_type": "hwid", // mux, source_ip
|
||||
"count": 20, // max requests per interval per connection
|
||||
"interval": "1s",
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
@@ -49,7 +46,7 @@
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "bandwidth-limiter",
|
||||
"final": "rate-limiter",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
42
examples/limiters/rate/global.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "socks",
|
||||
"tag": "socks-in",
|
||||
"listen_port": 7897
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "rate-limiter",
|
||||
"tag": "rate-limiter",
|
||||
"strategy": "leaky-bucket", // token-bucket, sliding-window, fixed-window
|
||||
"count": 10, // max requests per interval
|
||||
"interval": "1s", // time window
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "rate-limiter",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
68
examples/limiters/rate/manager.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-in",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 443,
|
||||
"transport": {
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "rate-limiter",
|
||||
"tag": "rate-limiter",
|
||||
// "manager" strategy: per-user rate limits are loaded from the
|
||||
// manager database and updated live (no need to list users in this file).
|
||||
"strategy": "manager",
|
||||
"route": {
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"final": "rate-limiter"
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"type": "manager",
|
||||
"tag": "my-manager",
|
||||
"database": {
|
||||
"driver": "sqlite",
|
||||
"dsn": "file:manager.db?_pragma=foreign_keys(on)&_pragma=journal_mode(wal)&_pragma=busy_timeout(5000)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"tag": "my-node",
|
||||
"uuid": "e6eceb84-ad66-474b-8641-142499db7c6e",
|
||||
"manager": "my-manager",
|
||||
"inbounds": ["vless-in"],
|
||||
"rate_limiters": ["rate-limiter"]
|
||||
}
|
||||
]
|
||||
}
|
||||
70
examples/limiters/rate/users.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "error"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-in",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 443,
|
||||
"transport": {
|
||||
"type": "http"
|
||||
},
|
||||
"users": [
|
||||
{
|
||||
"name": "user1",
|
||||
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937"
|
||||
},
|
||||
{
|
||||
"name": "user2",
|
||||
"uuid": "6c8c7ffc-a909-4699-af34-e9d9bcb3e6d6"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "rate-limiter",
|
||||
"tag": "rate-limiter",
|
||||
"strategy": "users",
|
||||
"users": [
|
||||
{
|
||||
"name": "user1",
|
||||
"strategy": "leaky-bucket", // token-bucket, sliding-window, fixed-window
|
||||
"connection_type": "hwid", // mux, source_ip
|
||||
"count": 30,
|
||||
"interval": "1s"
|
||||
},
|
||||
{
|
||||
"name": "user2",
|
||||
"strategy": "sliding-window",
|
||||
"connection_type": "source_ip",
|
||||
"count": 5,
|
||||
"interval": "1s"
|
||||
}
|
||||
],
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "rate-limiter",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
42
examples/limiters/traffic/global.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "socks",
|
||||
"tag": "socks-in",
|
||||
"listen_port": 7897
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "traffic-limiter",
|
||||
"tag": "traffic-limiter",
|
||||
"strategy": "global",
|
||||
"mode": "bidirectional", // download, upload
|
||||
"total": "10GB", // 100MB, 1TB, etc.
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "traffic-limiter",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
68
examples/limiters/traffic/manager.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-in",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 443,
|
||||
"transport": {
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "traffic-limiter",
|
||||
"tag": "traffic-limiter",
|
||||
// "manager" strategy: per-user traffic quotas are loaded from the
|
||||
// manager database and updated live (no need to list users in this file).
|
||||
"strategy": "manager",
|
||||
"route": {
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"final": "traffic-limiter"
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"type": "manager",
|
||||
"tag": "my-manager",
|
||||
"database": {
|
||||
"driver": "sqlite",
|
||||
"dsn": "file:manager.db?_pragma=foreign_keys(on)&_pragma=journal_mode(wal)&_pragma=busy_timeout(5000)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"tag": "my-node",
|
||||
"uuid": "e6eceb84-ad66-474b-8641-142499db7c6e",
|
||||
"manager": "my-manager",
|
||||
"inbounds": ["vless-in"],
|
||||
"traffic_limiters": ["traffic-limiter"]
|
||||
}
|
||||
]
|
||||
}
|
||||
68
examples/limiters/traffic/users.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "error"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-in",
|
||||
"listen": "0.0.0.0",
|
||||
"listen_port": 443,
|
||||
"transport": {
|
||||
"type": "http"
|
||||
},
|
||||
"users": [
|
||||
{
|
||||
"name": "user1",
|
||||
"uuid": "9b65b7e1-04c8-4717-8f45-2aa61fd25937"
|
||||
},
|
||||
{
|
||||
"name": "user2",
|
||||
"uuid": "6c8c7ffc-a909-4699-af34-e9d9bcb3e6d6"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "traffic-limiter",
|
||||
"tag": "traffic-limiter",
|
||||
"strategy": "users",
|
||||
"users": [
|
||||
{
|
||||
"name": "user1",
|
||||
"strategy": "global",
|
||||
"mode": "bidirectional", // download, upload
|
||||
"total": "100GB" // 100MB, 1TB, etc.
|
||||
},
|
||||
{
|
||||
"name": "user2",
|
||||
"strategy": "global",
|
||||
"mode": "download",
|
||||
"total": "10GB"
|
||||
}
|
||||
],
|
||||
"route": { // https://sing-box.sagernet.org/configuration/route/#structure
|
||||
"rules": [],
|
||||
"final": "direct"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "traffic-limiter",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "error"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct-out"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "dns",
|
||||
"action": "hijack-dns"
|
||||
}
|
||||
],
|
||||
"final": "direct-out"
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"type": "manager",
|
||||
"tag": "my-manager",
|
||||
"database": {
|
||||
"driver": "postgresql",
|
||||
"dsn": "postgresql://postgres:postgres@localhost:5432/manager?sslmode=disable"
|
||||
}
|
||||
},
|
||||
{ // http://127.0.0.1:8000
|
||||
// Username: admin
|
||||
// Password: admin
|
||||
"type": "admin-panel",
|
||||
"tag": "my-admin-panel",
|
||||
"listen_port": 8000,
|
||||
"manager": "my-manager",
|
||||
"database": {
|
||||
"driver": "postgresql",
|
||||
"dsn": "postgresql://postgres:postgres@localhost:5432/adminpanel?sslmode=disable"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node-manager-server", // for connecting nodes
|
||||
"listen_port": 7000,
|
||||
"manager": "my-manager",
|
||||
"tls": { // https://sing-box.sagernet.org/configuration/shared/tls/#inbound
|
||||
"enabled": true,
|
||||
"server_name": "example.com",
|
||||
"certificate_path": "/path/to/fullchain.pem",
|
||||
"key_path": "/path/to/privkey.pem"
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -37,16 +37,14 @@
|
||||
"udp_keepalive_period": "30s",
|
||||
"udp_initial_packet_size": 0,
|
||||
"reconnect_delay": "5s",
|
||||
"tls": { // https://sing-box.sagernet.org/configuration/shared/tls/#fields
|
||||
"insecure": false,
|
||||
"cipher_suites": [],
|
||||
"curve_preferences": [],
|
||||
"fragment": false,
|
||||
"fragment_fallback_delay": "",
|
||||
"record_fragment": false,
|
||||
"kernel_tx": false,
|
||||
"kernel_rx": false,
|
||||
}
|
||||
// TLS fields for HTTP2
|
||||
"insecure": false,
|
||||
"cipher_suites": [],
|
||||
"curve_preferences": [],
|
||||
"fragment": false,
|
||||
"record_fragment": false,
|
||||
"kernel_tx": false,
|
||||
"kernel_rx": false
|
||||
// Dial Fields
|
||||
}
|
||||
],
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
"transport": "TCP",
|
||||
"username": "username",
|
||||
"password": "password",
|
||||
// valid: MULTIPLEXING_DEFAULT / MULTIPLEXING_OFF / MULTIPLEXING_LOW
|
||||
// MULTIPLEXING_MIDDLE / MULTIPLEXING_HIGH
|
||||
"multiplexing": "MULTIPLEXING_LOW"
|
||||
// Dial Fields
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "error"
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
@@ -73,10 +73,17 @@
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "socks",
|
||||
"tag": "socks-out",
|
||||
"server": "192.168.1.1",
|
||||
"server_port": 17085,
|
||||
"version": "5"
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "direct",
|
||||
"final": "socks-out",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
|
||||
91
examples/provider/inline.json
Normal file
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen_port": 7897
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "proxy",
|
||||
"outbounds": [
|
||||
"direct"
|
||||
],
|
||||
"providers": [
|
||||
"my-inline"
|
||||
],
|
||||
"default": "direct",
|
||||
"interrupt_exist_connections": true
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
{
|
||||
"type": "inline",
|
||||
"tag": "my-inline",
|
||||
// Outbounds are listed in-place. They are registered with the
|
||||
// provider on start and become available to any group that
|
||||
// references this provider via "providers" or
|
||||
// "use_all_providers".
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "shadowsocks",
|
||||
"tag": "ss-hk",
|
||||
"server": "hk.example.com",
|
||||
"server_port": 8388,
|
||||
"method": "aes-256-gcm",
|
||||
"password": "password"
|
||||
},
|
||||
{
|
||||
"type": "trojan",
|
||||
"tag": "trojan-jp",
|
||||
"server": "jp.example.com",
|
||||
"server_port": 443,
|
||||
"password": "password",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "jp.example.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "vless",
|
||||
"tag": "vless-sg",
|
||||
"server": "sg.example.com",
|
||||
"server_port": 443,
|
||||
"uuid": "00000000-0000-0000-0000-000000000000",
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"server_name": "sg.example.com"
|
||||
}
|
||||
}
|
||||
],
|
||||
"health_check": {
|
||||
"enabled": true,
|
||||
"url": "https://www.gstatic.com/generate_204",
|
||||
"interval": "5m",
|
||||
"timeout": "5s"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "proxy",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
64
examples/provider/local.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen_port": 7897
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
// A "selector" group that pulls all of its members from the
|
||||
// outbound provider tagged "my-local". The provider parses the
|
||||
// file at "path" on every change (fswatch-based hot reload).
|
||||
{
|
||||
"type": "selector",
|
||||
"tag": "proxy",
|
||||
"outbounds": [
|
||||
"direct"
|
||||
],
|
||||
"providers": [
|
||||
"my-local"
|
||||
],
|
||||
"default": "direct",
|
||||
"interrupt_exist_connections": true
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "my-local",
|
||||
// Subscription file. Supported formats are auto-detected:
|
||||
// - sing-box JSON ({ "outbounds": [...] })
|
||||
// - Clash YAML
|
||||
// - SIP008 (shadowsocks)
|
||||
// - Raw shareable links (vless://, vmess://, ss://, trojan://, ...)
|
||||
"path": "subscriptions/my-sub.txt",
|
||||
"health_check": {
|
||||
"enabled": true,
|
||||
"url": "https://www.gstatic.com/generate_204",
|
||||
"interval": "5m",
|
||||
"timeout": "5s"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "proxy",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
72
examples/provider/remote.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"log": {
|
||||
"level": "info"
|
||||
},
|
||||
"dns": {
|
||||
"servers": [
|
||||
{
|
||||
"type": "local",
|
||||
"tag": "default"
|
||||
}
|
||||
]
|
||||
},
|
||||
"inbounds": [
|
||||
{
|
||||
"type": "mixed",
|
||||
"tag": "mixed-in",
|
||||
"listen_port": 7897
|
||||
}
|
||||
],
|
||||
"outbounds": [
|
||||
{
|
||||
"type": "direct",
|
||||
"tag": "direct"
|
||||
},
|
||||
// The "urltest" group below uses every outbound exposed by every
|
||||
// registered provider thanks to "use_all_providers": true.
|
||||
// The fastest member is selected based on the URL test result.
|
||||
{
|
||||
"type": "urltest",
|
||||
"tag": "auto",
|
||||
"outbounds": [
|
||||
"direct"
|
||||
],
|
||||
"use_all_providers": true,
|
||||
"url": "https://www.gstatic.com/generate_204",
|
||||
"interval": "10m",
|
||||
"tolerance": 50,
|
||||
"interrupt_exist_connections": true
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
{
|
||||
"type": "remote",
|
||||
"tag": "my-remote",
|
||||
// Subscription URL. The response body can be any auto-detected
|
||||
// format: sing-box JSON, Clash YAML, SIP008, base64-encoded
|
||||
// shareable links, or plain link list.
|
||||
"url": "https://example.com/subscription.txt",
|
||||
"user_agent": "sing-box",
|
||||
// Fetch the subscription through this outbound instead of the
|
||||
// default route (useful when the subscription host is blocked).
|
||||
"download_detour": "direct",
|
||||
// Refresh interval. Minimum is 1 minute; default is 24h.
|
||||
"update_interval": "12h",
|
||||
// Optional regex filters applied after parsing the subscription.
|
||||
// "exclude" wins over "include" when both match.
|
||||
"exclude": "(?i)expire|流量|官网",
|
||||
"include": "(?i)hk|jp|sg|us",
|
||||
"health_check": {
|
||||
"enabled": true,
|
||||
"url": "https://www.gstatic.com/generate_204",
|
||||
"interval": "5m",
|
||||
"timeout": "5s"
|
||||
}
|
||||
}
|
||||
],
|
||||
"route": {
|
||||
"final": "auto",
|
||||
"default_domain_resolver": "default",
|
||||
"auto_detect_interface": true
|
||||
}
|
||||
}
|
||||
@@ -15,20 +15,22 @@
|
||||
"type": "wireguard",
|
||||
"tag": "wireguard-out",
|
||||
"mtu": 1408,
|
||||
"address": null,
|
||||
"private_key": "",
|
||||
"address": ["10.0.0.2/32"],
|
||||
"private_key": "QGg8AFRn6qKfTB7cT3FWH1WGx3np+OKzlNuQUrqIBmI=",
|
||||
"listen_port": 10000,
|
||||
"peers": [
|
||||
{
|
||||
"address": "example.com",
|
||||
"port": 10001,
|
||||
"public_key": "3nk7jdnkcL95Fc/z+GCiH7jOovEKhFkLIGPT+U/uLEQ=",
|
||||
"allowed_ips": ["0.0.0.0/0"],
|
||||
"reserved": "AAAA"
|
||||
}
|
||||
],
|
||||
"udp_timeout": "5m0s",
|
||||
// Extended options
|
||||
"preallocated_buffers_per_pool": 256, // Set limit for preallocated buffers (can be useful for devices with low RAM)
|
||||
"disable_pauses": true, // Disable pauses when android device in sleep mode
|
||||
"disable_pauses": true // Disable pauses when android device in sleep mode
|
||||
}
|
||||
],
|
||||
"inbounds": [
|
||||
|
||||
@@ -35,9 +35,10 @@
|
||||
},
|
||||
"transport": {
|
||||
"type": "xhttp",
|
||||
"mode": "stream-up",
|
||||
"mode": "stream-up", // packet-up, stream-one
|
||||
"host": "example.com",
|
||||
"path": "/xhttp",
|
||||
"headers": {},
|
||||
"domain_strategy": "prefer_ipv4",
|
||||
"x_padding_bytes": "100-1000",
|
||||
"no_grpc_header": false, // stream-up/one, client only
|
||||
@@ -69,6 +70,7 @@
|
||||
"download": {
|
||||
"host": "example.com",
|
||||
"path": "/xhttp",
|
||||
"headers": {},
|
||||
"domain_strategy": "prefer_ipv4",
|
||||
"x_padding_bytes": "100-1000",
|
||||
"no_grpc_header": false, // stream-up/one, client only
|
||||
|
||||
@@ -26,31 +26,31 @@
|
||||
"enabled": true,
|
||||
"server_name": "example.com",
|
||||
"alpn": "h2", // h3 for QUIC
|
||||
"certificate_path": "/path/to/fullchain.pem",
|
||||
"key_path": "/path/to/privkey.pem"
|
||||
},
|
||||
"transport": {
|
||||
"type": "xhttp",
|
||||
"mode": "stream-up",
|
||||
"mode": "stream-up", // packet-up, stream-one
|
||||
"host": "",
|
||||
"path": "/xhttp",
|
||||
"headers": {},
|
||||
"x_padding_bytes": "100-1000",
|
||||
"no_sse_header": false, // server only
|
||||
"sc_max_each_post_bytes": 1000000, // packet-up only
|
||||
"sc_max_buffered_posts": 30, // packet-up, server only
|
||||
"sc_stream_up_server_secs": "20-80", // stream-up, server only
|
||||
"server_max_header_bytes": 8192,
|
||||
"trusted_x_forwarded_for": [],
|
||||
"x_padding_obfs_mode": false,
|
||||
"x_padding_key": "",
|
||||
"x_padding_header": "",
|
||||
"x_padding_placement": "",
|
||||
"x_padding_method": "",
|
||||
"uplink_http_method": "",
|
||||
"session_placement": "",
|
||||
"session_key": "",
|
||||
"seq_placement": "",
|
||||
"seq_key": "",
|
||||
"uplink_data_placement": "",
|
||||
"uplink_data_key": "",
|
||||
"uplink_chunk_size": 0,
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -145,7 +145,7 @@ func (c *CacheFile) Start(stage adapter.StartStage) error {
|
||||
if name[0] == 0 {
|
||||
return b.ForEachBucket(func(k []byte) error {
|
||||
bucketName := string(k)
|
||||
if !(common.Contains(bucketNameList, bucketName)) {
|
||||
if !common.Contains(bucketNameList, bucketName) {
|
||||
_ = b.DeleteBucket(name)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -171,7 +171,7 @@ func (w *platformInterfaceWrapper) ReadWIFIState() adapter.WIFIState {
|
||||
if wifiState == nil {
|
||||
return adapter.WIFIState{}
|
||||
}
|
||||
return (adapter.WIFIState)(*wifiState)
|
||||
return adapter.WIFIState(*wifiState)
|
||||
}
|
||||
|
||||
func (w *platformInterfaceWrapper) SystemCertificates() []string {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package v2rayapi
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -484,19 +483,16 @@ func file_experimental_v2rayapi_stats_proto_rawDescGZIP() []byte {
|
||||
return file_experimental_v2rayapi_stats_proto_rawDescData
|
||||
}
|
||||
|
||||
var (
|
||||
file_experimental_v2rayapi_stats_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||
file_experimental_v2rayapi_stats_proto_goTypes = []any{
|
||||
(*GetStatsRequest)(nil), // 0: experimental.v2rayapi.GetStatsRequest
|
||||
(*Stat)(nil), // 1: experimental.v2rayapi.Stat
|
||||
(*GetStatsResponse)(nil), // 2: experimental.v2rayapi.GetStatsResponse
|
||||
(*QueryStatsRequest)(nil), // 3: experimental.v2rayapi.QueryStatsRequest
|
||||
(*QueryStatsResponse)(nil), // 4: experimental.v2rayapi.QueryStatsResponse
|
||||
(*SysStatsRequest)(nil), // 5: experimental.v2rayapi.SysStatsRequest
|
||||
(*SysStatsResponse)(nil), // 6: experimental.v2rayapi.SysStatsResponse
|
||||
}
|
||||
)
|
||||
|
||||
var file_experimental_v2rayapi_stats_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||
var file_experimental_v2rayapi_stats_proto_goTypes = []any{
|
||||
(*GetStatsRequest)(nil), // 0: experimental.v2rayapi.GetStatsRequest
|
||||
(*Stat)(nil), // 1: experimental.v2rayapi.Stat
|
||||
(*GetStatsResponse)(nil), // 2: experimental.v2rayapi.GetStatsResponse
|
||||
(*QueryStatsRequest)(nil), // 3: experimental.v2rayapi.QueryStatsRequest
|
||||
(*QueryStatsResponse)(nil), // 4: experimental.v2rayapi.QueryStatsResponse
|
||||
(*SysStatsRequest)(nil), // 5: experimental.v2rayapi.SysStatsRequest
|
||||
(*SysStatsResponse)(nil), // 6: experimental.v2rayapi.SysStatsResponse
|
||||
}
|
||||
var file_experimental_v2rayapi_stats_proto_depIdxs = []int32{
|
||||
1, // 0: experimental.v2rayapi.GetStatsResponse.stat:type_name -> experimental.v2rayapi.Stat
|
||||
1, // 1: experimental.v2rayapi.QueryStatsResponse.stat:type_name -> experimental.v2rayapi.Stat
|
||||
|
||||
@@ -2,7 +2,6 @@ package v2rayapi
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
@@ -86,11 +85,9 @@ type UnimplementedStatsServiceServer struct{}
|
||||
func (UnimplementedStatsServiceServer) GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetStats not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStatsServiceServer) QueryStats(context.Context, *QueryStatsRequest) (*QueryStatsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method QueryStats not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStatsServiceServer) GetSysStats(context.Context, *SysStatsRequest) (*SysStatsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetSysStats not implemented")
|
||||
}
|
||||
|
||||
42
go.mod
@@ -3,9 +3,8 @@ module github.com/sagernet/sing-box
|
||||
go 1.26.1
|
||||
|
||||
require (
|
||||
github.com/AliRizaAynaci/gorl/v2 v2.2.0
|
||||
github.com/Diniboy1123/connect-ip-go v0.0.0-20260409225322-8d7bb0a858a2
|
||||
github.com/GoAdminGroup/go-admin v1.2.26
|
||||
github.com/GoAdminGroup/themes v0.0.48
|
||||
github.com/anthropics/anthropic-sdk-go v1.26.0
|
||||
github.com/anytls/sing-anytls v0.0.11
|
||||
github.com/caddyserver/certmagic v0.25.2
|
||||
@@ -23,7 +22,6 @@ require (
|
||||
github.com/insomniacslk/dhcp v0.0.0-20260220084031-5adc3eb26f91
|
||||
github.com/jackc/pgx/v5 v5.8.0
|
||||
github.com/keybase/go-keychain v0.0.1
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/libdns/acmedns v0.5.0
|
||||
github.com/libdns/alidns v1.0.6
|
||||
github.com/libdns/cloudflare v0.2.2
|
||||
@@ -33,7 +31,6 @@ require (
|
||||
github.com/miekg/dns v1.1.72
|
||||
github.com/openai/openai-go/v3 v3.26.0
|
||||
github.com/oschwald/maxminddb-golang v1.13.1
|
||||
github.com/patrickmn/go-cache/v2 v2.0.0-00010101000000-000000000000
|
||||
github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1
|
||||
github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a
|
||||
github.com/sagernet/cors v1.2.1
|
||||
@@ -55,6 +52,7 @@ require (
|
||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.7
|
||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.0.2
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
@@ -71,23 +69,31 @@ require (
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/protobuf v1.36.11
|
||||
howett.net/plist v1.0.1
|
||||
modernc.org/sqlite v1.50.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dunglas/httpsfv v1.1.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
github.com/panjf2000/ants/v2 v2.12.0 // indirect
|
||||
github.com/quic-go/quic-go v0.59.0 // indirect
|
||||
github.com/redis/go-redis/v9 v9.8.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20260408064518-65a410b0d584 // indirect
|
||||
modernc.org/libc v1.72.0 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/360EntSecGroup-Skylar/excelize v1.4.1 // indirect
|
||||
github.com/AdguardTeam/golibs v0.32.7 // indirect
|
||||
github.com/GoAdminGroup/html v0.0.1 // indirect
|
||||
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e // indirect
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
github.com/akutz/memconn v0.1.0 // indirect
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
|
||||
@@ -108,8 +114,6 @@ require (
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.12 // indirect
|
||||
github.com/gaissmai/bart v0.18.0 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gin-gonic/gin v1.3.0 // 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/go-playground/locales v0.14.1 // indirect
|
||||
@@ -117,8 +121,6 @@ require (
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
@@ -133,20 +135,14 @@ require (
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jsimonetti/rtnetlink v1.4.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.18.3 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/libdns/libdns v1.1.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/mdlayher/netlink v1.9.0 // indirect
|
||||
github.com/mdlayher/socket v0.5.1 // indirect
|
||||
github.com/mitchellh/go-ps v1.0.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/nxadm/tail v1.4.11 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||
github.com/pires/go-proxyproto v0.11.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
@@ -185,7 +181,6 @@ require (
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/nftables v0.3.0-mod.2 // indirect
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.0 // indirect
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect
|
||||
github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect
|
||||
@@ -198,7 +193,6 @@ require (
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/zeebo/blake3 v0.2.4 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
@@ -213,14 +207,8 @@ require (
|
||||
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-20251202230838-ff82c1b0f217 // indirect
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
lukechampine.com/blake3 v1.4.1
|
||||
xorm.io/builder v0.3.7 // indirect
|
||||
xorm.io/xorm v1.0.2 // indirect
|
||||
)
|
||||
|
||||
replace github.com/sagernet/wireguard-go => github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.4.0
|
||||
@@ -233,10 +221,8 @@ replace github.com/ameshkov/dnscrypt/v2 => github.com/shtorm-7/dnscrypt/v2 v2.4.
|
||||
|
||||
replace github.com/sagernet/sing-vmess => github.com/starifly/sing-vmess v0.2.7-mod.9
|
||||
|
||||
replace github.com/patrickmn/go-cache/v2 => github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.0.2
|
||||
|
||||
replace github.com/dolonet/mtg-multi => github.com/shtorm-7/mtg-multi v1.8.0-extended-1.0.1
|
||||
|
||||
replace github.com/Diniboy1123/connect-ip-go => github.com/shtorm-7/connect-ip-go v1.0.0-extended-1.0.0
|
||||
|
||||
replace github.com/GoAdminGroup/go-admin => github.com/shtorm-7/go-admin v1.2.26-extended-1.0.0
|
||||
replace github.com/shtorm-7/go-cache/v2 => github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.1.0
|
||||
|
||||
235
go.sum
@@ -1,37 +1,21 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
|
||||
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=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
|
||||
github.com/360EntSecGroup-Skylar/excelize v1.4.1 h1:l55mJb6rkkaUzOpSsgEeKYtS6/0gHwBYyfo5Jcjv/Ks=
|
||||
github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE=
|
||||
github.com/AdguardTeam/golibs v0.32.7 h1:3dmGlAVgmvquCCwHsvEl58KKcRAK3z1UnjMnwSIeDH4=
|
||||
github.com/AdguardTeam/golibs v0.32.7/go.mod h1:bE8KV1zqTzgZjmjFyBJ9f9O5DEKO717r7e57j1HclJA=
|
||||
github.com/AliRizaAynaci/gorl/v2 v2.2.0 h1:E8oAwkordOwm9ItNNVJ5VKvGroDcHvWNvG11HaCVLZI=
|
||||
github.com/AliRizaAynaci/gorl/v2 v2.2.0/go.mod h1:13wcj/W736v44b6uygUuwypMY9N3RXJuhAYXukIIdCo=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/GoAdminGroup/html v0.0.1 h1:SdWNWl4OKPsvDk2GDp5ZKD6ceWoN8n4Pj6cUYxavUd0=
|
||||
github.com/GoAdminGroup/html v0.0.1/go.mod h1:A1laTJaOx8sQ64p2dE8IqtstDeCNBHEazrEp7hR5VvM=
|
||||
github.com/GoAdminGroup/themes v0.0.48 h1:OveEEoFBCBTU5kNicqnvs0e/pL6uZKNQU1RAP9kmNFA=
|
||||
github.com/GoAdminGroup/themes v0.0.48/go.mod h1:w/5P0WCmM8iv7DYE5scIT8AODYMoo6zj/bVlzAbgOaU=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e h1:n+DcnTNkQnHlwpsrHoQtkrJIO7CBx029fw6oR4vIob4=
|
||||
github.com/NebulousLabs/fastrand v0.0.0-20181203155948-6fb6489aac4e/go.mod h1:Bdzq+51GR4/0DIhaICZEOm+OHvXGwwB2trKZ8B4Y6eQ=
|
||||
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
|
||||
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A=
|
||||
github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/ameshkov/dnsstamps v1.0.3 h1:Srzik+J9mivH1alRACTbys2xOxs0lRH9qnTA7Y1OYVo=
|
||||
@@ -42,10 +26,12 @@ github.com/anthropics/anthropic-sdk-go v1.26.0 h1:oUTzFaUpAevfuELAP1sjL6CQJ9HHAf
|
||||
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/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0=
|
||||
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
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=
|
||||
@@ -56,7 +42,6 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
||||
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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
|
||||
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
@@ -80,11 +65,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk=
|
||||
github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e h1:LzwWXEScfcTu7vUZNlDDWDARoSGEtvlDKK2BYHowNeE=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU=
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4=
|
||||
github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
@@ -99,9 +83,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dunglas/httpsfv v1.1.0 h1:Jw76nAyKWKZKFrpMMcL76y35tOpYHqQPzHQiwDvpe54=
|
||||
github.com/dunglas/httpsfv v1.1.0/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=
|
||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/enfein/mieru/v3 v3.17.1 h1:pIKbspsKRYNyUrORVI33t1/yz2syaaUkIanskAbGBHY=
|
||||
@@ -110,8 +93,6 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/florianl/go-nfqueue/v2 v2.0.2 h1:FL5lQTeetgpCvac1TRwSfgaXUn0YSO7WzGvWNIp3JPE=
|
||||
github.com/florianl/go-nfqueue/v2 v2.0.2/go.mod h1:VA09+iPOT43OMoCKNfXHyzujQUty2xmzyCRkBOlmabc=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
@@ -120,10 +101,6 @@ github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCK
|
||||
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
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/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
|
||||
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||
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.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
|
||||
@@ -134,8 +111,6 @@ github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZR
|
||||
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-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
@@ -150,10 +125,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w=
|
||||
github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
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=
|
||||
@@ -162,50 +133,34 @@ 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.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
|
||||
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI=
|
||||
github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
|
||||
github.com/huandu/go-assert v1.1.6 h1:oaAfYxq9KNDi9qswn/6aE0EydfxSa+tWZC1KabNitYs=
|
||||
github.com/huandu/go-assert v1.1.6/go.mod h1:JuIfbmYG9ykwvuxoJ3V8TB5QP+3+ajIA54Y44TmkMxs=
|
||||
@@ -230,24 +185,14 @@ github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFr
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I=
|
||||
github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
|
||||
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.18.3 h1:9PJRvfbmTabkOX8moIpXPbMMbYN60bWImDDU7L+/6zw=
|
||||
github.com/klauspost/compress v1.18.3/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
@@ -256,7 +201,6 @@ github.com/letsencrypt/challtestsrv v1.4.2 h1:0ON3ldMhZyWlfVNYYpFuWRTmZNnyfiL9Hh
|
||||
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/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/libdns/acmedns v0.5.0 h1:5pRtmUj4Lb/QkNJSl1xgOGBUJTWW7RjpNaIhjpDXjPE=
|
||||
@@ -269,16 +213,10 @@ 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/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
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=
|
||||
@@ -295,46 +233,28 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
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/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
|
||||
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
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=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
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/panjf2000/ants/v2 v2.12.0 h1:u9JhESo83i/GkZnhfTNuFMMWcNt7mnV1bGJ6FT4wXH8=
|
||||
github.com/panjf2000/ants/v2 v2.12.0/go.mod h1:tSQuaNQ6r6NRhPt+IZVUevvDyFMTs+eS4ztZc52uJTY=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
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.11.0 h1:gUQpS85X/VJMdUsYyEgyn59uLJvGqPhJV5YvG68wXH4=
|
||||
github.com/pires/go-proxyproto v0.11.0/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -342,18 +262,14 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4=
|
||||
github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
|
||||
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
|
||||
github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/zerolog v1.35.0 h1:VD0ykx7HMiMJytqINBsKcbLS+BJ4WYjz+05us+LRTdI=
|
||||
@@ -461,10 +377,8 @@ github.com/shtorm-7/connect-ip-go v1.0.0-extended-1.0.0 h1:ws7BIsYLd31Wjifq88BYC
|
||||
github.com/shtorm-7/connect-ip-go v1.0.0-extended-1.0.0/go.mod h1:mRwx4w32qQxsWB2kThuHpbo7iNjJiq1jYWubgqEPjHA=
|
||||
github.com/shtorm-7/dnscrypt/v2 v2.4.0-extended-1.0.0 h1:e5s7RKBd2rIPR0StbvZ2vTVtJ5jDTsTk5wtIIapZTRg=
|
||||
github.com/shtorm-7/dnscrypt/v2 v2.4.0-extended-1.0.0/go.mod h1:WpEFV2uhebXb8Jhes/5/fSdpmhGV8TL22RDaeWwV6hI=
|
||||
github.com/shtorm-7/go-admin v1.2.26-extended-1.0.0 h1:TVXbEkAlk/b5Qb64zz5KjmFklVN8YdkTmS/dovVFxTk=
|
||||
github.com/shtorm-7/go-admin v1.2.26-extended-1.0.0/go.mod h1:k0z66Eq5OQKw2dVkS3iQ4kPRnN6JyA5Nm+h5BBnINN8=
|
||||
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.0.2 h1:+1tb8QNU0n2p/8Ct0A3/uHYImYXFhnN4lHOJoIdAV2s=
|
||||
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.0.2/go.mod h1:Ek4yz5OK6stwhLKgLsRRYDI+FA+ZWvRJiWLjsi/vMM4=
|
||||
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.1.0 h1:PLZ/YHqnApPx13wt6MX3ItqESp4ueBr1tGSi0bEGqYw=
|
||||
github.com/shtorm-7/go-cache/v2 v2.1.0-extended-1.1.0/go.mod h1:Ek4yz5OK6stwhLKgLsRRYDI+FA+ZWvRJiWLjsi/vMM4=
|
||||
github.com/shtorm-7/mtg-multi v1.8.0-extended-1.0.1 h1:UeJkrCJJmIjTBywErVMx7fCSoBf4gh6QgT9bp9o1ajM=
|
||||
github.com/shtorm-7/mtg-multi v1.8.0-extended-1.0.1/go.mod h1:3rvdhwdPABkwKBdvgMt3VwMn9uSq8hpoHRezZ5jRJU0=
|
||||
github.com/shtorm-7/sing-mux v0.3.4-extended-1.0.0 h1:a5OoXr3e2ACbM6vDIaaGL44IdHQ6wPjcSoU13vfC0Sw=
|
||||
@@ -473,7 +387,6 @@ github.com/shtorm-7/tailscale v1.92.4-sing-box-1.13-mod.7-extended-1.0.2 h1:hSMj
|
||||
github.com/shtorm-7/tailscale v1.92.4-sing-box-1.13-mod.7-extended-1.0.2/go.mod h1:TYIIqO5sZpWq873rLIeO2usszSMUpR3h6WdqVVs65ug=
|
||||
github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.4.0 h1:z25EapzvkpyLgaq2T0o7eeoshBR3U4AhqMOBq1gRtrA=
|
||||
github.com/shtorm-7/wireguard-go v0.0.2-beta.1-extended-1.4.0/go.mod h1:Me2JlCDYHxnd0mnuX7L5LXAeDHCltI7vSKq3eTE6SVE=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 h1:TG/diQgUe0pntT/2D9tmUCz4VNwm9MfrtPr0SU2qSX8=
|
||||
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E=
|
||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||
@@ -484,18 +397,13 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A
|
||||
github.com/starifly/sing-vmess v0.2.7-mod.9 h1:xobAmejSbBQ0A3f/EtJ9cJd3m6gK7dDPccPdeGz7tXY=
|
||||
github.com/starifly/sing-vmess v0.2.7-mod.9/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ=
|
||||
github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4=
|
||||
github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4=
|
||||
@@ -530,8 +438,6 @@ github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b h1:p+bJ3v5u
|
||||
github.com/tylertreat/BoomFilters v0.0.0-20251117164519-53813c36cc1b/go.mod h1:OYRfF6eb5wY9VRFkXJH8FFBi3plw2v+giaIu7P054pM=
|
||||
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/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY=
|
||||
github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
@@ -547,8 +453,6 @@ github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI=
|
||||
github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE=
|
||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
@@ -578,56 +482,28 @@ go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4
|
||||
go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
|
||||
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/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
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.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
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-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
@@ -635,20 +511,13 @@ golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU=
|
||||
golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -662,39 +531,16 @@ 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/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
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.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
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/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
@@ -703,16 +549,37 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gvisor.dev/gvisor v0.0.0-20260408064518-65a410b0d584 h1:QyFROp5Ew7XZWKPtp8ap78z4gpY6xHpJIEdHgVA4bzA=
|
||||
gvisor.dev/gvisor v0.0.0-20260408064518-65a410b0d584/go.mod h1:xQ2PWgHmWJA/Ph4i1q1jBm39BKhc3W0DXqWoDSyuBOY=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
|
||||
howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
||||
modernc.org/cc/v4 v4.27.3 h1:uNCgn37E5U09mTv1XgskEVUJ8ADKpmFMPxzGJ0TSo+U=
|
||||
modernc.org/cc/v4 v4.27.3/go.mod h1:3YjcbCqhoTTHPycJDRl2WZKKFj0nwcOIPBfEZK0Hdk8=
|
||||
modernc.org/ccgo/v4 v4.32.4 h1:L5OB8rpEX4ZsXEQwGozRfJyJSFHbbNVOoQ59DU9/KuU=
|
||||
modernc.org/ccgo/v4 v4.32.4/go.mod h1:lY7f+fiTDHfcv6YlRgSkxYfhs+UvOEEzj49jAn2TOx0=
|
||||
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
|
||||
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
|
||||
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.72.0 h1:IEu559v9a0XWjw0DPoVKtXpO2qt5NVLAnFaBbjq+n8c=
|
||||
modernc.org/libc v1.72.0/go.mod h1:tTU8DL8A+XLVkEY3x5E/tO7s2Q/q42EtnNWda/L5QhQ=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.50.0 h1:eMowQSWLK0MeiQTdmz3lqoF5dqclujdlIKeJA11+7oM=
|
||||
modernc.org/sqlite v1.50.0/go.mod h1:m0w8xhwYUVY3H6pSDwc3gkJ/irZT/0YEXwBlhaxQEew=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
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=
|
||||
xorm.io/builder v0.3.7 h1:2pETdKRK+2QG4mLX4oODHEhn5Z8j1m8sXa7jfu+/SZI=
|
||||
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
|
||||
xorm.io/xorm v1.0.2 h1:kZlCh9rqd1AzGwWitcrEEqHE1h1eaZE/ujU5/2tWEtg=
|
||||
xorm.io/xorm v1.0.2/go.mod h1:o4vnEsQ5V2F1/WK6w4XTwmiWJeGj82tqjAnHe44wVHY=
|
||||
|
||||
12
include/profiler.go
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build with_profiler
|
||||
|
||||
package include
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing-box/adapter/service"
|
||||
"github.com/sagernet/sing-box/service/profiler"
|
||||
)
|
||||
|
||||
func registerProfilerService(registry *service.Registry) {
|
||||
profiler.RegisterService(registry)
|
||||
}
|
||||
20
include/profiler_stub.go
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build !with_profiler
|
||||
|
||||
package include
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/service"
|
||||
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 registerProfilerService(registry *service.Registry) {
|
||||
service.Register[option.ProfilerServiceOptions](registry, C.TypeProfiler, func(ctx context.Context, logger log.ContextLogger, tag string, options option.ProfilerServiceOptions) (adapter.Service, error) {
|
||||
return nil, E.New(`Profiler is not included in this build, rebuild with -tags with_profiler`)
|
||||
})
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing-box/dns/transport"
|
||||
"github.com/sagernet/sing-box/dns/transport/fakeip"
|
||||
"github.com/sagernet/sing-box/dns/transport/fallback"
|
||||
"github.com/sagernet/sing-box/dns/transport/hosts"
|
||||
"github.com/sagernet/sing-box/dns/transport/local"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
@@ -22,10 +23,13 @@ import (
|
||||
"github.com/sagernet/sing-box/protocol/block"
|
||||
"github.com/sagernet/sing-box/protocol/bond"
|
||||
"github.com/sagernet/sing-box/protocol/direct"
|
||||
"github.com/sagernet/sing-box/protocol/failover"
|
||||
"github.com/sagernet/sing-box/protocol/group"
|
||||
"github.com/sagernet/sing-box/protocol/http"
|
||||
"github.com/sagernet/sing-box/protocol/limiter/bandwidth"
|
||||
"github.com/sagernet/sing-box/protocol/limiter/connection"
|
||||
"github.com/sagernet/sing-box/protocol/limiter/rate"
|
||||
"github.com/sagernet/sing-box/protocol/limiter/traffic"
|
||||
"github.com/sagernet/sing-box/protocol/mieru"
|
||||
"github.com/sagernet/sing-box/protocol/mixed"
|
||||
"github.com/sagernet/sing-box/protocol/naive"
|
||||
@@ -45,9 +49,9 @@ import (
|
||||
remoteProvider "github.com/sagernet/sing-box/provider/remote"
|
||||
"github.com/sagernet/sing-box/service/admin_panel"
|
||||
"github.com/sagernet/sing-box/service/manager"
|
||||
"github.com/sagernet/sing-box/service/manager_api"
|
||||
"github.com/sagernet/sing-box/service/node"
|
||||
nodeManagerClient "github.com/sagernet/sing-box/service/node_manager/client"
|
||||
nodeManagerServer "github.com/sagernet/sing-box/service/node_manager/server"
|
||||
"github.com/sagernet/sing-box/service/node_manager_api"
|
||||
"github.com/sagernet/sing-box/service/resolved"
|
||||
"github.com/sagernet/sing-box/service/ssmapi"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
@@ -78,6 +82,7 @@ func InboundRegistry() *inbound.Registry {
|
||||
anytls.RegisterInbound(registry)
|
||||
|
||||
bond.RegisterInbound(registry)
|
||||
failover.RegisterInbound(registry)
|
||||
|
||||
registerQUICInbounds(registry)
|
||||
registerStubForRemovedInbounds(registry)
|
||||
@@ -112,9 +117,12 @@ func OutboundRegistry() *outbound.Registry {
|
||||
registerMASQUEOutbound(registry)
|
||||
|
||||
bond.RegisterOutbound(registry)
|
||||
failover.RegisterOutbound(registry)
|
||||
|
||||
bandwidth.RegisterOutbound(registry)
|
||||
connection.RegisterOutbound(registry)
|
||||
traffic.RegisterOutbound(registry)
|
||||
rate.RegisterOutbound(registry)
|
||||
|
||||
parser.RegisterOutbound(registry)
|
||||
|
||||
@@ -157,6 +165,7 @@ func DNSTransportRegistry() *dns.TransportRegistry {
|
||||
hosts.RegisterTransport(registry)
|
||||
local.RegisterTransport(registry)
|
||||
fakeip.RegisterTransport(registry)
|
||||
fallback.RegisterTransport(registry)
|
||||
resolved.RegisterTransport(registry)
|
||||
|
||||
registerQUICTransports(registry)
|
||||
@@ -171,9 +180,9 @@ func ServiceRegistry() *service.Registry {
|
||||
|
||||
admin_panel.RegisterService(registry)
|
||||
manager.RegisterService(registry)
|
||||
manager_api.RegisterService(registry)
|
||||
node.RegisterService(registry)
|
||||
nodeManagerClient.RegisterService(registry)
|
||||
nodeManagerServer.RegisterService(registry)
|
||||
node_manager_api.RegisterService(registry)
|
||||
resolved.RegisterService(registry)
|
||||
ssmapi.RegisterService(registry)
|
||||
|
||||
@@ -181,6 +190,7 @@ func ServiceRegistry() *service.Registry {
|
||||
registerCCMService(registry)
|
||||
registerOCMService(registry)
|
||||
registerOOMKillerService(registry)
|
||||
registerProfilerService(registry)
|
||||
|
||||
return registry
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@ func init() {
|
||||
random.InitializeSeed()
|
||||
}
|
||||
|
||||
type idKey struct{}
|
||||
type muxIdKey struct{}
|
||||
type hwidKey struct{}
|
||||
type (
|
||||
idKey struct{}
|
||||
muxIdKey struct{}
|
||||
hwidKey struct{}
|
||||
)
|
||||
|
||||
type ID struct {
|
||||
ID uint32
|
||||
|
||||
@@ -2,12 +2,5 @@ package option
|
||||
|
||||
type AdminPanelServiceOptions struct {
|
||||
ListenOptions
|
||||
Manager string `json:"manager"`
|
||||
Database AdminPanelServiceDatabase `json:"database"`
|
||||
InboundTLSOptionsContainer
|
||||
}
|
||||
|
||||
type AdminPanelServiceDatabase struct {
|
||||
Driver string `json:"driver"`
|
||||
DSN string `json:"dsn"`
|
||||
}
|
||||
|
||||
@@ -332,10 +332,10 @@ func (o *DNSServerOptions) Upgrade(ctx context.Context) error {
|
||||
if !serverAddr.IsValid() {
|
||||
return E.New("invalid server address")
|
||||
}
|
||||
o.Options = &SDNSDNSServerOptions{
|
||||
RemoteDNSServerOptions: remoteOptions,
|
||||
Stamp: serverAddr.AddrString(),
|
||||
}
|
||||
o.Options = &SDNSDNSServerOptions{
|
||||
RemoteDNSServerOptions: remoteOptions,
|
||||
Stamp: serverAddr.AddrString(),
|
||||
}
|
||||
default:
|
||||
return E.New("unsupported DNS server scheme: ", serverType)
|
||||
}
|
||||
@@ -424,4 +424,9 @@ type DHCPDNSServerOptions struct {
|
||||
type SDNSDNSServerOptions struct {
|
||||
RemoteDNSServerOptions
|
||||
Stamp string `json:"stamp"`
|
||||
}
|
||||
}
|
||||
|
||||
type FallbackDNSServerOptions struct {
|
||||
Servers []string `json:"servers"`
|
||||
Strategy string `json:"strategy,omitempty"`
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package option
|
||||
|
||||
import "github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
type FailoverInboundOptions struct {
|
||||
Inbounds []Inbound `json:"inbounds"`
|
||||
}
|
||||
|
||||
type FailoverOutboundOptions struct {
|
||||
Outbounds []Outbound `json:"outbounds"`
|
||||
Strategy string `json:"strategy,omitempty"`
|
||||
Delay badoption.Duration `json:"delay,omitempty"`
|
||||
Outbounds []Outbound `json:"outbounds"`
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func (m Hysteria2Masquerade) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown masquerade type: ", m.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_Hysteria2Masquerade)(m), v)
|
||||
return badjson.MarshallObjects(_Hysteria2Masquerade(m), v)
|
||||
}
|
||||
|
||||
func (m *Hysteria2Masquerade) UnmarshalJSON(bytes []byte) error {
|
||||
|
||||
@@ -90,7 +90,7 @@ type ListenOptions struct {
|
||||
type UDPTimeoutCompat badoption.Duration
|
||||
|
||||
func (c UDPTimeoutCompat) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal((time.Duration)(c).String())
|
||||
return json.Marshal(time.Duration(c).String())
|
||||
}
|
||||
|
||||
func (c *UDPTimeoutCompat) UnmarshalJSON(data []byte) error {
|
||||
|
||||
@@ -2,12 +2,14 @@ package option
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing/common/byteformats"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
)
|
||||
|
||||
type BandwidthLimiterOutboundOptions struct {
|
||||
Strategy string `json:"strategy"`
|
||||
Mode string `json:"mode"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Mode string `json:"mode"`
|
||||
FlowKeys []string `json:"flow_keys,omitempty"`
|
||||
Speed *byteformats.NetworkBytesCompat `json:"speed"`
|
||||
Users []BandwidthLimiterUser `json:"users,omitempty"`
|
||||
Route RouteOptions `json:"route"`
|
||||
@@ -16,11 +18,26 @@ type BandwidthLimiterOutboundOptions struct {
|
||||
type BandwidthLimiterUser struct {
|
||||
Name string `json:"name"`
|
||||
Strategy string `json:"strategy"`
|
||||
Mode string `json:"mode"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Mode string `json:"mode"`
|
||||
Speed *byteformats.NetworkBytesCompat `json:"speed"`
|
||||
}
|
||||
|
||||
type TrafficLimiterOutboundOptions struct {
|
||||
Strategy string `json:"strategy"`
|
||||
Mode string `json:"mode"`
|
||||
Total *byteformats.Bytes `json:"total"`
|
||||
Users []TrafficLimiterUser `json:"users,omitempty"`
|
||||
Route RouteOptions `json:"route"`
|
||||
}
|
||||
|
||||
type TrafficLimiterUser struct {
|
||||
Name string `json:"name"`
|
||||
Strategy string `json:"strategy"`
|
||||
Mode string `json:"mode"`
|
||||
Total *byteformats.Bytes `json:"total"`
|
||||
}
|
||||
|
||||
type ConnectionLimiterOutboundOptions struct {
|
||||
Strategy string `json:"strategy"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
@@ -35,3 +52,20 @@ type ConnectionLimiterUser struct {
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Count uint32 `json:"count"`
|
||||
}
|
||||
|
||||
type RateLimiterOutboundOptions struct {
|
||||
Strategy string `json:"strategy"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Count uint32 `json:"count"`
|
||||
Interval badoption.Duration `json:"interval"`
|
||||
Users []RateLimiterUser `json:"users,omitempty"`
|
||||
Route RouteOptions `json:"route"`
|
||||
}
|
||||
|
||||
type RateLimiterUser struct {
|
||||
Name string `json:"name"`
|
||||
Strategy string `json:"strategy"`
|
||||
ConnectionType string `json:"connection_type,omitempty"`
|
||||
Count uint32 `json:"count"`
|
||||
Interval badoption.Duration `json:"interval"`
|
||||
}
|
||||
|
||||
77
option/manager_api.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package option
|
||||
|
||||
import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/json/badjson"
|
||||
)
|
||||
|
||||
type _ManagerAPIOptions struct {
|
||||
APIType string `json:"api_type"`
|
||||
ProtocolType string `json:"protocol_type"`
|
||||
ServerOptions ManagerAPIServerOptions `json:"-"`
|
||||
ClientOptions ManagerAPIClientOptions `json:"-"`
|
||||
}
|
||||
|
||||
type ManagerAPIOptions _ManagerAPIOptions
|
||||
|
||||
func (o ManagerAPIOptions) MarshalJSON() ([]byte, error) {
|
||||
var v any
|
||||
switch o.APIType {
|
||||
case C.ManagerAPIServer:
|
||||
v = o.ServerOptions
|
||||
case C.ManagerAPIClient:
|
||||
v = o.ClientOptions
|
||||
case "":
|
||||
return nil, E.New("missing api type")
|
||||
default:
|
||||
return nil, E.New("unknown api type: " + o.APIType)
|
||||
}
|
||||
return badjson.MarshallObjects(_ManagerAPIOptions(o), v)
|
||||
}
|
||||
|
||||
func (o *ManagerAPIOptions) UnmarshalJSON(bytes []byte) error {
|
||||
err := json.Unmarshal(bytes, (*_ManagerAPIOptions)(o))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var v any
|
||||
switch o.APIType {
|
||||
case C.ManagerAPIServer:
|
||||
v = &o.ServerOptions
|
||||
case C.ManagerAPIClient:
|
||||
v = &o.ClientOptions
|
||||
case "":
|
||||
return E.New("missing api type")
|
||||
default:
|
||||
return E.New("unknown api type: " + o.APIType)
|
||||
}
|
||||
|
||||
err = badjson.UnmarshallExcluded(bytes, (*_ManagerAPIOptions)(o), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ManagerAPIServerOptions struct {
|
||||
ListenOptions
|
||||
InboundTLSOptionsContainer
|
||||
Manager string `json:"manager"`
|
||||
APIKey string `json:"api_key"`
|
||||
CORS *ManagerAPICORSOptions `json:"cors,omitempty"`
|
||||
}
|
||||
|
||||
type ManagerAPICORSOptions struct {
|
||||
AllowedOrigins []string `json:"allowed_origins,omitempty"`
|
||||
ExposedHeaders []string `json:"exposed_headers,omitempty"`
|
||||
MaxAge int `json:"max_age,omitempty"`
|
||||
}
|
||||
|
||||
type ManagerAPIClientOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
OutboundTLSOptionsContainer
|
||||
APIKey string `json:"api_key"`
|
||||
}
|
||||
@@ -5,5 +5,7 @@ type NodeServiceOptions struct {
|
||||
Inbounds []string `json:"inbounds"`
|
||||
ConnectionLimiters []string `json:"connection_limiters"`
|
||||
BandwidthLimiters []string `json:"bandwidth_limiters"`
|
||||
TrafficLimiters []string `json:"traffic_limiters"`
|
||||
RateLimiters []string `json:"rate_limiters"`
|
||||
Manager string `json:"manager"`
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package option
|
||||
|
||||
type NodeManagerServerServiceOptions struct {
|
||||
ListenOptions
|
||||
InboundTLSOptionsContainer
|
||||
Manager string `json:"manager"`
|
||||
}
|
||||
|
||||
type NodeManagerClientServiceOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
OutboundTLSOptionsContainer
|
||||
}
|
||||
69
option/node_manager_api.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package option
|
||||
|
||||
import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/json/badjson"
|
||||
)
|
||||
|
||||
type _NodeManagerAPIOptions struct {
|
||||
APIType string `json:"api_type"`
|
||||
ServerOptions NodeManagerAPIServerOptions `json:"-"`
|
||||
ClientOptions NodeManagerAPIClientOptions `json:"-"`
|
||||
}
|
||||
|
||||
type NodeManagerAPIOptions _NodeManagerAPIOptions
|
||||
|
||||
func (o NodeManagerAPIOptions) MarshalJSON() ([]byte, error) {
|
||||
var v any
|
||||
switch o.APIType {
|
||||
case C.NodeManagerAPIServer:
|
||||
v = o.ServerOptions
|
||||
case C.NodeManagerAPIClient:
|
||||
v = o.ClientOptions
|
||||
case "":
|
||||
return nil, E.New("missing api type")
|
||||
default:
|
||||
return nil, E.New("unknown api type: " + o.APIType)
|
||||
}
|
||||
return badjson.MarshallObjects(_NodeManagerAPIOptions(o), v)
|
||||
}
|
||||
|
||||
func (o *NodeManagerAPIOptions) UnmarshalJSON(bytes []byte) error {
|
||||
err := json.Unmarshal(bytes, (*_NodeManagerAPIOptions)(o))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var v any
|
||||
switch o.APIType {
|
||||
case C.NodeManagerAPIServer:
|
||||
v = &o.ServerOptions
|
||||
case C.NodeManagerAPIClient:
|
||||
v = &o.ClientOptions
|
||||
case "":
|
||||
return E.New("missing api type")
|
||||
default:
|
||||
return E.New("unknown api type: " + o.APIType)
|
||||
}
|
||||
|
||||
err = badjson.UnmarshallExcluded(bytes, (*_NodeManagerAPIOptions)(o), v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NodeManagerAPIServerOptions struct {
|
||||
ListenOptions
|
||||
InboundTLSOptionsContainer
|
||||
Manager string `json:"manager"`
|
||||
APIKey string `json:"api_key"`
|
||||
}
|
||||
|
||||
type NodeManagerAPIClientOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
OutboundTLSOptionsContainer
|
||||
APIKey string `json:"api_key"`
|
||||
}
|
||||
@@ -111,7 +111,7 @@ func (o DomainResolveOptions) MarshalJSON() ([]byte, error) {
|
||||
o.ClientSubnet == nil {
|
||||
return json.Marshal(o.Server)
|
||||
} else {
|
||||
return json.Marshal((_DomainResolveOptions)(o))
|
||||
return json.Marshal(_DomainResolveOptions(o))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
9
option/profiler.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package option
|
||||
|
||||
import "github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
type ProfilerServiceOptions struct {
|
||||
Listen string `json:"listen,omitempty"`
|
||||
ReadTimeout badoption.Duration `json:"read_timeout,omitempty"`
|
||||
WriteTimeout badoption.Duration `json:"write_timeout,omitempty"`
|
||||
}
|
||||
@@ -16,7 +16,7 @@ type _ResolvedServiceOptions struct {
|
||||
type ResolvedServiceOptions _ResolvedServiceOptions
|
||||
|
||||
func (r ResolvedServiceOptions) MarshalJSONContext(ctx context.Context) ([]byte, error) {
|
||||
if r.Listen != nil && netip.Addr(*r.Listen) == (netip.AddrFrom4([4]byte{127, 0, 0, 53})) {
|
||||
if r.Listen != nil && netip.Addr(*r.Listen) == netip.AddrFrom4([4]byte{127, 0, 0, 53}) {
|
||||
r.Listen = nil
|
||||
}
|
||||
if r.ListenPort == 53 {
|
||||
|
||||
@@ -30,7 +30,7 @@ func (r Rule) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown rule type: " + r.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_Rule)(r), v)
|
||||
return badjson.MarshallObjects(_Rule(r), v)
|
||||
}
|
||||
|
||||
func (r *Rule) UnmarshalJSON(bytes []byte) error {
|
||||
|
||||
@@ -53,9 +53,9 @@ func (r RuleAction) MarshalJSON() ([]byte, error) {
|
||||
return nil, E.New("unknown rule action: " + r.Action)
|
||||
}
|
||||
if v == nil {
|
||||
return badjson.MarshallObjects((_RuleAction)(r))
|
||||
return badjson.MarshallObjects(_RuleAction(r))
|
||||
}
|
||||
return badjson.MarshallObjects((_RuleAction)(r), v)
|
||||
return badjson.MarshallObjects(_RuleAction(r), v)
|
||||
}
|
||||
|
||||
func (r *RuleAction) UnmarshalJSON(data []byte) error {
|
||||
@@ -124,7 +124,7 @@ func (r DNSRuleAction) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown DNS rule action: " + r.Action)
|
||||
}
|
||||
return badjson.MarshallObjects((_DNSRuleAction)(r), v)
|
||||
return badjson.MarshallObjects(_DNSRuleAction(r), v)
|
||||
}
|
||||
|
||||
func (r *DNSRuleAction) UnmarshalJSONContext(ctx context.Context, data []byte) error {
|
||||
@@ -281,7 +281,7 @@ func (r RejectActionOptions) MarshalJSON() ([]byte, error) {
|
||||
case C.RuleActionRejectMethodDefault:
|
||||
r.Method = ""
|
||||
}
|
||||
return json.Marshal((_RejectActionOptions)(r))
|
||||
return json.Marshal(_RejectActionOptions(r))
|
||||
}
|
||||
|
||||
func (r *RejectActionOptions) UnmarshalJSON(bytes []byte) error {
|
||||
|
||||
@@ -31,7 +31,7 @@ func (r DNSRule) MarshalJSON() ([]byte, error) {
|
||||
default:
|
||||
return nil, E.New("unknown rule type: " + r.Type)
|
||||
}
|
||||
return badjson.MarshallObjects((_DNSRule)(r), v)
|
||||
return badjson.MarshallObjects(_DNSRule(r), v)
|
||||
}
|
||||
|
||||
func (r *DNSRule) UnmarshalJSONContext(ctx context.Context, bytes []byte) error {
|
||||
|
||||