Compare commits
22 Commits
v1.13.11-e
...
v1.13.12-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a47bdbe2ae | ||
|
|
8e8eca01fe | ||
|
|
41e815e18b | ||
|
|
1086ab2563 | ||
|
|
2b995ea10a | ||
|
|
5e7fd7ad78 | ||
|
|
338aa551d1 | ||
|
|
b6f7d62bb6 | ||
|
|
76880eb46b | ||
|
|
b4c625543a | ||
|
|
2f139af2d1 | ||
|
|
383a1824c1 | ||
|
|
d166f0da8b | ||
|
|
6475a5e036 | ||
|
|
6548c17110 | ||
|
|
d1c53d21fe | ||
|
|
b586c4f313 | ||
|
|
3bd162ed6f | ||
|
|
652e0baf57 | ||
|
|
8be5c8fabe | ||
|
|
eb36c934a7 | ||
|
|
ddb757a25c |
2
.github/CRONET_GO_VERSION
vendored
@@ -1 +1 @@
|
||||
e4926ba205fae5351e3d3eeafff7e7029654424a
|
||||
2faf34666c2cc8234f10f2ab6d4c4d6104d34ae2
|
||||
|
||||
43
.github/workflows/lint.yml
vendored
@@ -18,21 +18,60 @@ on:
|
||||
- testing
|
||||
- unstable
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}-${{ inputs.build }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
name: Lint ${{ matrix.goos }}/${{ matrix.goarch }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- goos: windows
|
||||
goarch: amd64
|
||||
- goos: windows
|
||||
goarch: '386'
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
- goos: linux
|
||||
goarch: amd64
|
||||
- goos: linux
|
||||
goarch: arm64
|
||||
- goos: linux
|
||||
goarch: arm
|
||||
- goos: linux
|
||||
goarch: '386'
|
||||
- goos: darwin
|
||||
goarch: amd64
|
||||
- goos: darwin
|
||||
goarch: arm64
|
||||
- goos: android
|
||||
goarch: arm64
|
||||
# - goos: freebsd
|
||||
# goarch: amd64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25
|
||||
- name: Cache go module
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
key: go-${{ hashFiles('**/go.sum') }}
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
with:
|
||||
version: latest
|
||||
args: --timeout=30m
|
||||
|
||||
2
.gitignore
vendored
@@ -21,3 +21,5 @@
|
||||
CLAUDE.md
|
||||
AGENTS.md
|
||||
/.claude/
|
||||
dist
|
||||
logs
|
||||
@@ -1,6 +1,6 @@
|
||||
version: "2"
|
||||
run:
|
||||
go: "1.25"
|
||||
go: "1.24"
|
||||
build-tags:
|
||||
- with_gvisor
|
||||
- with_quic
|
||||
@@ -17,30 +17,29 @@ run:
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- govet
|
||||
- ineffassign
|
||||
- paralleltest
|
||||
- staticcheck
|
||||
- unused
|
||||
- modernize
|
||||
settings:
|
||||
modernize:
|
||||
disable:
|
||||
- omitzero # nested struct omitempty -> omitzero changes JSON output semantics
|
||||
staticcheck:
|
||||
checks:
|
||||
- all
|
||||
- -S1000
|
||||
- -S1008
|
||||
- -S1017
|
||||
- -ST1003
|
||||
- -QF1001
|
||||
- -QF1003
|
||||
- -QF1008
|
||||
- -QF1008 # could remove embedded field "<interface>" from selector
|
||||
- -ST1003 # should not use ALL_CAPS in Go names; use CamelCase instead
|
||||
- -QF1001 # could apply De Morgan's law
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
paths:
|
||||
- transport/simple-obfs
|
||||
- \.pb\.go$
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
@@ -55,10 +54,3 @@ formatters:
|
||||
- prefix(github.com/sagernet/)
|
||||
- default
|
||||
custom-order: true
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- transport/simple-obfs
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
@@ -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,11 +54,13 @@ builds:
|
||||
- with_tailscale
|
||||
- with_masque
|
||||
- with_mtproxy
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
targets:
|
||||
- windows_amd64_v1
|
||||
- windows_386
|
||||
- linux_mips
|
||||
- linux_mips_softfloat
|
||||
- linux_mipsle
|
||||
- linux_mipsle_softfloat
|
||||
- linux_mips64
|
||||
- linux_mips64le
|
||||
- id: android
|
||||
<<: *template
|
||||
env:
|
||||
@@ -146,6 +99,7 @@ archives:
|
||||
id: archive
|
||||
builds:
|
||||
- main
|
||||
- mips
|
||||
- android
|
||||
formats:
|
||||
- tar.gz
|
||||
@@ -157,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:
|
||||
|
||||
59
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)
|
||||
@@ -36,23 +59,17 @@ install:
|
||||
go build -o $(PREFIX)/bin/$(NAME) $(MAIN_PARAMS) $(MAIN)
|
||||
|
||||
fmt:
|
||||
@gofumpt -l -w .
|
||||
@gofmt -s -w .
|
||||
@gci write --custom-order -s standard -s "prefix(github.com/sagernet/)" -s "default" .
|
||||
@golangci-lint fmt
|
||||
|
||||
fmt_docs:
|
||||
go run ./cmd/internal/format_docs
|
||||
|
||||
fmt_install:
|
||||
go install -v mvdan.cc/gofumpt@latest
|
||||
go install -v github.com/daixiang0/gci@latest
|
||||
|
||||
lint:
|
||||
GOOS=linux golangci-lint run ./...
|
||||
GOOS=android golangci-lint run ./...
|
||||
GOOS=windows golangci-lint run ./...
|
||||
GOOS=darwin golangci-lint run ./...
|
||||
GOOS=freebsd golangci-lint run ./...
|
||||
# GOOS=freebsd golangci-lint run ./...
|
||||
|
||||
lint_install:
|
||||
go install -v github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||
@@ -84,6 +101,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
|
||||
|
||||
@@ -170,14 +196,31 @@ upload_macos_pkg:
|
||||
ghr --replace --draft --prerelease "v${VERSION}" "dist/SFM/SFM-${VERSION}-Intel.pkg"
|
||||
ghr --replace --draft --prerelease "v${VERSION}" "dist/SFM/SFM-${VERSION}-Universal.pkg"
|
||||
|
||||
replace_macos_pkg:
|
||||
mkdir -p dist/SFM
|
||||
cp ../sing-box-for-apple/build/SFM-Apple.pkg "dist/SFM/SFM-${VERSION}-Apple.pkg"
|
||||
cp ../sing-box-for-apple/build/SFM-Intel.pkg "dist/SFM/SFM-${VERSION}-Intel.pkg"
|
||||
cp ../sing-box-for-apple/build/SFM-Universal.pkg "dist/SFM/SFM-${VERSION}-Universal.pkg"
|
||||
ghr --replace "v${VERSION}" "dist/SFM/SFM-${VERSION}-Apple.pkg"
|
||||
ghr --replace "v${VERSION}" "dist/SFM/SFM-${VERSION}-Intel.pkg"
|
||||
ghr --replace "v${VERSION}" "dist/SFM/SFM-${VERSION}-Universal.pkg"
|
||||
|
||||
upload_macos_dsyms:
|
||||
mkdir -p dist/SFM
|
||||
cd ../sing-box-for-apple/build/SFM.System-universal.xcarchive && zip -r SFM.dSYMs.zip dSYMs
|
||||
cp ../sing-box-for-apple/build/SFM.System-universal.xcarchive/SFM.dSYMs.zip "dist/SFM/SFM-${VERSION}.dSYMs.zip"
|
||||
ghr --replace --draft --prerelease "v${VERSION}" "dist/SFM/SFM-${VERSION}.dSYMs.zip"
|
||||
|
||||
replace_macos_dsyms:
|
||||
mkdir -p dist/SFM
|
||||
cd ../sing-box-for-apple/build/SFM.System-universal.xcarchive && zip -r SFM.dSYMs.zip dSYMs
|
||||
cp ../sing-box-for-apple/build/SFM.System-universal.xcarchive/SFM.dSYMs.zip "dist/SFM/SFM-${VERSION}.dSYMs.zip"
|
||||
ghr --replace "v${VERSION}" "dist/SFM/SFM-${VERSION}.dSYMs.zip"
|
||||
|
||||
release_macos_standalone: build_macos_pkg notarize_macos_pkg upload_macos_pkg upload_macos_dsyms
|
||||
|
||||
replace_macos_standalone: build_macos_pkg notarize_macos_pkg upload_macos_pkg upload_macos_dsyms
|
||||
|
||||
build_tvos:
|
||||
cd ../sing-box-for-apple && \
|
||||
rm -rf build/SFT.xcarchive && \
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -48,8 +48,8 @@ func GetRuntimeEnv(key string) (string, error) {
|
||||
if readErr != nil {
|
||||
return "", readErr
|
||||
}
|
||||
envStrings := strings.Split(string(data), "\n")
|
||||
for _, envItem := range envStrings {
|
||||
envStrings := strings.SplitSeq(string(data), "\n")
|
||||
for envItem := range envStrings {
|
||||
envItem = strings.TrimSuffix(envItem, "\r")
|
||||
envKeyValue := strings.Split(envItem, "=")
|
||||
if strings.EqualFold(strings.TrimSpace(envKeyValue[0]), key) {
|
||||
|
||||
@@ -39,7 +39,7 @@ func main() {
|
||||
common.Must(os.Chdir(androidPath))
|
||||
localProps := common.Must1(os.ReadFile("version.properties"))
|
||||
var propsList [][]string
|
||||
for _, propLine := range strings.Split(string(localProps), "\n") {
|
||||
for propLine := range strings.SplitSeq(string(localProps), "\n") {
|
||||
propsList = append(propsList, strings.Split(propLine, "="))
|
||||
}
|
||||
var (
|
||||
|
||||
@@ -45,10 +45,8 @@ package certificate
|
||||
|
||||
import "crypto/x509"
|
||||
|
||||
var mozillaIncluded *x509.CertPool
|
||||
|
||||
func init() {
|
||||
mozillaIncluded = x509.NewCertPool()
|
||||
func newMozillaIncluded() *x509.CertPool {
|
||||
pool := x509.NewCertPool()
|
||||
`)
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
@@ -63,14 +61,14 @@ func init() {
|
||||
generated.WriteString("\n // ")
|
||||
generated.WriteString(record[nameIndex])
|
||||
generated.WriteString("\n")
|
||||
generated.WriteString(" mozillaIncluded.AppendCertsFromPEM([]byte(`")
|
||||
generated.WriteString(" pool.AppendCertsFromPEM([]byte(`")
|
||||
cert := record[certIndex]
|
||||
// Remove single quotes
|
||||
cert = cert[1 : len(cert)-1]
|
||||
generated.WriteString(cert)
|
||||
generated.WriteString("`))\n")
|
||||
}
|
||||
generated.WriteString("}\n")
|
||||
generated.WriteString("\treturn pool\n}\n")
|
||||
return os.WriteFile("common/certificate/mozilla.go", []byte(generated.String()), 0o644)
|
||||
}
|
||||
|
||||
@@ -131,10 +129,8 @@ package certificate
|
||||
|
||||
import "crypto/x509"
|
||||
|
||||
var chromeIncluded *x509.CertPool
|
||||
|
||||
func init() {
|
||||
chromeIncluded = x509.NewCertPool()
|
||||
func newChromeIncluded() *x509.CertPool {
|
||||
pool := x509.NewCertPool()
|
||||
`)
|
||||
for {
|
||||
record, err := reader.Read()
|
||||
@@ -152,7 +148,7 @@ func init() {
|
||||
generated.WriteString("\n // ")
|
||||
generated.WriteString(record[subjectIndex])
|
||||
generated.WriteString("\n")
|
||||
generated.WriteString(" chromeIncluded.AppendCertsFromPEM([]byte(`")
|
||||
generated.WriteString(" pool.AppendCertsFromPEM([]byte(`")
|
||||
cert := record[certIndex]
|
||||
// Remove single quotes if present
|
||||
if len(cert) > 0 && cert[0] == '\'' {
|
||||
@@ -161,6 +157,6 @@ func init() {
|
||||
generated.WriteString(cert)
|
||||
generated.WriteString("`))\n")
|
||||
}
|
||||
generated.WriteString("}\n")
|
||||
generated.WriteString("\treturn pool\n}\n")
|
||||
return os.WriteFile("common/certificate/chrome.go", []byte(generated.String()), 0o644)
|
||||
}
|
||||
|
||||
@@ -61,16 +61,17 @@ func geoipExport(countryCode string) error {
|
||||
outputFile *os.File
|
||||
outputWriter io.Writer
|
||||
)
|
||||
if flagGeoipExportOutput == "stdout" {
|
||||
switch flagGeoipExportOutput {
|
||||
case "stdout":
|
||||
outputWriter = os.Stdout
|
||||
} else if flagGeoipExportOutput == flagGeoipExportDefaultOutput {
|
||||
case flagGeoipExportDefaultOutput:
|
||||
outputFile, err = os.Create("geoip-" + countryCode + ".json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outputFile.Close()
|
||||
outputWriter = outputFile
|
||||
} else {
|
||||
default:
|
||||
outputFile, err = os.Create(flagGeoipExportOutput)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -43,16 +43,17 @@ func geositeExport(category string) error {
|
||||
outputFile *os.File
|
||||
outputWriter io.Writer
|
||||
)
|
||||
if commandGeositeExportOutput == "stdout" {
|
||||
switch commandGeositeExportOutput {
|
||||
case "stdout":
|
||||
outputWriter = os.Stdout
|
||||
} else if commandGeositeExportOutput == commandGeositeExportDefaultOutput {
|
||||
case commandGeositeExportDefaultOutput:
|
||||
outputFile, err = os.Create("geosite-" + category + ".json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outputFile.Close()
|
||||
outputWriter = outputFile
|
||||
} else {
|
||||
default:
|
||||
outputFile, err = os.Create(commandGeositeExportOutput)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build with_quic
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -112,9 +112,7 @@ func IsValid(versionName string) bool {
|
||||
}
|
||||
|
||||
func Parse(versionName string) (version Version) {
|
||||
if strings.HasPrefix(versionName, "v") {
|
||||
versionName = versionName[1:]
|
||||
}
|
||||
versionName = strings.TrimPrefix(versionName, "v")
|
||||
if strings.Contains(versionName, "-") {
|
||||
parts := strings.Split(versionName, "-")
|
||||
versionName = parts[0]
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,11 @@ package certificate
|
||||
|
||||
import "crypto/x509"
|
||||
|
||||
var chromeIncluded *x509.CertPool
|
||||
|
||||
func init() {
|
||||
chromeIncluded = x509.NewCertPool()
|
||||
func newChromeIncluded() *x509.CertPool {
|
||||
pool := x509.NewCertPool()
|
||||
|
||||
// CN=Actalis Authentication Root CA; O=Actalis S.p.A./03358520967; L=Milan; C=IT
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
|
||||
BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
|
||||
MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
|
||||
@@ -45,7 +43,7 @@ LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=TunTrust Root CA; O=Agence Nationale de Certification Electronique; C=TN
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL
|
||||
BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg
|
||||
Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv
|
||||
@@ -80,7 +78,7 @@ d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Amazon Root CA 4; O=Amazon; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
|
||||
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||
Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||
@@ -95,7 +93,7 @@ CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Amazon Root CA 1; O=Amazon; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
|
||||
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||
b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
|
||||
@@ -117,7 +115,7 @@ rqXRfboQnoZsG4q5WTP468SQvvG5
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Amazon Root CA 2; O=Amazon; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
|
||||
ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
|
||||
b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
|
||||
@@ -150,7 +148,7 @@ n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Amazon Root CA 3; O=Amazon; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
|
||||
MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
|
||||
Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
|
||||
@@ -164,7 +162,7 @@ YyRIHN8wfdVoOw==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Certum Trusted Network CA; OU=Certum Certification Authority; O=Unizeto Technologies S.A.; C=PL
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM
|
||||
MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D
|
||||
ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU
|
||||
@@ -188,7 +186,7 @@ VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Certum EC-384 CA; OU=Certum Certification Authority; O=Asseco Data Systems S.A.; C=PL
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw
|
||||
CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw
|
||||
JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT
|
||||
@@ -205,7 +203,7 @@ nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Certum Trusted Root CA; OU=Certum Certification Authority; O=Asseco Data Systems S.A.; C=PL
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6
|
||||
MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu
|
||||
MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV
|
||||
@@ -240,7 +238,7 @@ E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Certum Trusted Network CA 2; OU=Certum Certification Authority; O=Unizeto Technologies S.A.; C=PL
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB
|
||||
gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu
|
||||
QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG
|
||||
@@ -276,7 +274,7 @@ DrW5viSP
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Autoridad de Certificacion Firmaprofesional CIF A62634068; C=ES
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE
|
||||
BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h
|
||||
cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1
|
||||
@@ -313,7 +311,7 @@ GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=ANF Secure Server Root CA; OU=ANF CA Raiz; O=ANF Autoridad de Certificacion; C=ES; SerialNumber=G63287510
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV
|
||||
BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk
|
||||
YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV
|
||||
@@ -349,7 +347,7 @@ tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Buypass Class 2 Root CA; O=Buypass AS-983163327; C=NO
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
|
||||
MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
|
||||
Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow
|
||||
@@ -382,7 +380,7 @@ Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Buypass Class 3 Root CA; O=Buypass AS-983163327; C=NO
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
|
||||
MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
|
||||
Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow
|
||||
@@ -415,7 +413,7 @@ u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Certainly Root R1; O=Certainly; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw
|
||||
PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy
|
||||
dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9
|
||||
@@ -448,7 +446,7 @@ OV+KmalBWQewLK8=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Certainly Root E1; O=Certainly; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw
|
||||
CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu
|
||||
bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ
|
||||
@@ -463,7 +461,7 @@ BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Certigna; O=Dhimyotis; C=FR
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
|
||||
BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X
|
||||
DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ
|
||||
@@ -487,7 +485,7 @@ WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Certigna Root CA; OU=0002 48146308100036; O=Dhimyotis; C=FR
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw
|
||||
WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw
|
||||
MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x
|
||||
@@ -525,7 +523,7 @@ jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// OU=certSIGN ROOT CA; O=certSIGN; C=RO
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT
|
||||
AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD
|
||||
QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP
|
||||
@@ -547,7 +545,7 @@ i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// OU=certSIGN ROOT CA G2; O=CERTSIGN SA; C=RO
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV
|
||||
BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g
|
||||
Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ
|
||||
@@ -580,7 +578,7 @@ QRBdJ3NghVdJIgc=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=HiPKI Root CA - G1; O=Chunghwa Telecom Co., Ltd.; C=TW
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP
|
||||
MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
|
||||
ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa
|
||||
@@ -613,7 +611,7 @@ YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// OU=ePKI Root Certification Authority; O=Chunghwa Telecom Co., Ltd.; C=TW
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe
|
||||
MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
|
||||
ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
|
||||
@@ -648,7 +646,7 @@ hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=D-TRUST BR Root CA 1 2020; O=D-Trust GmbH; C=DE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw
|
||||
CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS
|
||||
VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5
|
||||
@@ -668,7 +666,7 @@ dWNbFJWcHwHP2NVypw87
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=D-TRUST EV Root CA 1 2020; O=D-Trust GmbH; C=DE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw
|
||||
CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS
|
||||
VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5
|
||||
@@ -688,7 +686,7 @@ gfM0agPnIjhQW+0ZT0MW
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=D-TRUST Root Class 3 CA 2 EV 2009; O=D-Trust GmbH; C=DE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF
|
||||
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD
|
||||
bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw
|
||||
@@ -715,7 +713,7 @@ KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=D-TRUST Root Class 3 CA 2 2009; O=D-Trust GmbH; C=DE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
|
||||
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
|
||||
bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
|
||||
@@ -742,7 +740,7 @@ Johw1+qRzT65ysCQblrGXnRl11z+o+I=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=T-TeleSec GlobalRoot Class 3; OU=T-Systems Trust Center; O=T-Systems Enterprise Services GmbH; C=DE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
|
||||
KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
|
||||
BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
|
||||
@@ -767,7 +765,7 @@ TpPDpFQUWw==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=T-TeleSec GlobalRoot Class 2; OU=T-Systems Trust Center; O=T-Systems Enterprise Services GmbH; C=DE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
|
||||
KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
|
||||
BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
|
||||
@@ -792,7 +790,7 @@ BSeOE6Fuwg==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert TLS RSA4096 Root G5; O=DigiCert, Inc.; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN
|
||||
MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT
|
||||
HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN
|
||||
@@ -825,7 +823,7 @@ ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert TLS ECC P384 Root G5; O=DigiCert, Inc.; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw
|
||||
CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp
|
||||
Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2
|
||||
@@ -841,7 +839,7 @@ DXZDjC5Ty3zfDBeWUA==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert Assured ID Root CA; OU=www.digicert.com; O=DigiCert Inc; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
|
||||
@@ -865,7 +863,7 @@ H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert Assured ID Root G2; OU=www.digicert.com; O=DigiCert Inc; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
|
||||
@@ -889,7 +887,7 @@ IhNzbM8m9Yop5w==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert Assured ID Root G3; OU=www.digicert.com; O=DigiCert Inc; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw
|
||||
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
|
||||
ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg
|
||||
@@ -906,7 +904,7 @@ JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert Global Root CA; OU=www.digicert.com; O=DigiCert Inc; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
||||
@@ -930,7 +928,7 @@ CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert Global Root G2; OU=www.digicert.com; O=DigiCert Inc; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
|
||||
@@ -954,7 +952,7 @@ MrY=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert Global Root G3; OU=www.digicert.com; O=DigiCert Inc; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw
|
||||
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
|
||||
ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe
|
||||
@@ -971,7 +969,7 @@ sycX
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert High Assurance EV Root CA; OU=www.digicert.com; O=DigiCert Inc; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
|
||||
@@ -996,7 +994,7 @@ vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=DigiCert Trusted Root G4; OU=www.digicert.com; O=DigiCert Inc; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
|
||||
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
||||
d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg
|
||||
@@ -1030,7 +1028,7 @@ gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=QuoVadis Root CA 2; O=QuoVadis Limited; C=BM
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
|
||||
GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
|
||||
b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV
|
||||
@@ -1065,7 +1063,7 @@ ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=QuoVadis Root CA 2 G3; O=QuoVadis Limited; C=BM
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL
|
||||
BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
|
||||
BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00
|
||||
@@ -1098,7 +1096,7 @@ WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=QuoVadis Root CA 3 G3; O=QuoVadis Limited; C=BM
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL
|
||||
BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
|
||||
BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00
|
||||
@@ -1131,7 +1129,7 @@ ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=CA Disig Root R2; O=Disig a.s.; L=Bratislava; C=SK
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV
|
||||
BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu
|
||||
MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy
|
||||
@@ -1164,7 +1162,7 @@ L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=emSign ECC Root CA - G3; OU=emSign PKI; O=eMudhra Technologies Limited; C=IN
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG
|
||||
EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo
|
||||
bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g
|
||||
@@ -1181,7 +1179,7 @@ CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=emSign Root CA - G1; OU=emSign PKI; O=eMudhra Technologies Limited; C=IN
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD
|
||||
VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU
|
||||
ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH
|
||||
@@ -1205,7 +1203,7 @@ iN66zB+Afko=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=AffirmTrust Commercial; O=AffirmTrust; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
|
||||
BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
|
||||
dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
|
||||
@@ -1227,7 +1225,7 @@ nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Atos TrustedRoot 2011; O=Atos; C=DE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
|
||||
AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
|
||||
EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM
|
||||
@@ -1250,7 +1248,7 @@ KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Atos TrustedRoot Root CA ECC TLS 2021; O=Atos; C=DE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w
|
||||
LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w
|
||||
CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0
|
||||
@@ -1266,7 +1264,7 @@ CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Atos TrustedRoot Root CA RSA TLS 2021; O=Atos; C=DE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM
|
||||
MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx
|
||||
MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00
|
||||
@@ -1299,7 +1297,7 @@ oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GlobalSign; OU=GlobalSign Root CA - R6; O=GlobalSign
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg
|
||||
MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh
|
||||
bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx
|
||||
@@ -1333,7 +1331,7 @@ JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GlobalSign Root E46; O=GlobalSign nv-sa; C=BE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx
|
||||
CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD
|
||||
ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw
|
||||
@@ -1348,7 +1346,7 @@ DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GlobalSign Root R46; O=GlobalSign nv-sa; C=BE
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA
|
||||
MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD
|
||||
VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy
|
||||
@@ -1381,7 +1379,7 @@ vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GlobalSign; OU=GlobalSign ECC Root CA - R5; O=GlobalSign
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk
|
||||
MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH
|
||||
bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
|
||||
@@ -1397,7 +1395,7 @@ xwy8p2Fp8fc74SrL+SvzZpA3
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GlobalSign; OU=GlobalSign Root CA - R3; O=GlobalSign
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
|
||||
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
|
||||
Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
|
||||
@@ -1420,7 +1418,7 @@ WD9f
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Starfield Root Certificate Authority - G2; O=Starfield Technologies, Inc.; L=Scottsdale; ST=Arizona; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
|
||||
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
|
||||
HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
|
||||
@@ -1445,7 +1443,7 @@ mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Go Daddy Root Certificate Authority - G2; O=GoDaddy.com, Inc.; L=Scottsdale; ST=Arizona; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
|
||||
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
|
||||
EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
|
||||
@@ -1470,7 +1468,7 @@ LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GlobalSign; OU=GlobalSign ECC Root CA - R4; O=GlobalSign
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD
|
||||
VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh
|
||||
bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw
|
||||
@@ -1484,7 +1482,7 @@ bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GTS Root R4; O=Google Trust Services LLC; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD
|
||||
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
|
||||
A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
|
||||
@@ -1499,7 +1497,7 @@ p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GTS Root R2; O=Google Trust Services LLC; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
|
||||
@@ -1532,7 +1530,7 @@ JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GTS Root R1; O=Google Trust Services LLC; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
|
||||
CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
|
||||
MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
|
||||
@@ -1565,7 +1563,7 @@ bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=GTS Root R3; O=Google Trust Services LLC; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD
|
||||
VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
|
||||
A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
|
||||
@@ -1580,7 +1578,7 @@ ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=ACCVRAIZ1; OU=PKIACCV; O=ACCV; C=ES
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE
|
||||
AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw
|
||||
CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ
|
||||
@@ -1626,7 +1624,7 @@ pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// OU=AC RAIZ FNMT-RCM; O=FNMT-RCM; C=ES
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx
|
||||
CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ
|
||||
WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ
|
||||
@@ -1660,7 +1658,7 @@ uu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS; OU=Ceres; O=FNMT-RCM; C=ES; OrganizationIdentifier=VATES-Q2826004J
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw
|
||||
CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw
|
||||
FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S
|
||||
@@ -1678,7 +1676,7 @@ v+c=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1; OU=Kamu Sertifikasyon Merkezi - Kamu SM; O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK; L=Gebze - Kocaeli; C=TR
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx
|
||||
GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp
|
||||
bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w
|
||||
@@ -1706,7 +1704,7 @@ lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=HARICA TLS RSA Root CA 2021; O=Hellenic Academic and Research Institutions CA; C=GR
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs
|
||||
MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
|
||||
c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg
|
||||
@@ -1741,7 +1739,7 @@ xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=HARICA TLS ECC Root CA 2021; O=Hellenic Academic and Research Institutions CA; C=GR
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw
|
||||
CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh
|
||||
cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v
|
||||
@@ -1758,7 +1756,7 @@ nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=IdenTrust Commercial Root CA 1; O=IdenTrust; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK
|
||||
MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu
|
||||
VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw
|
||||
@@ -1791,7 +1789,7 @@ mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=ISRG Root X1; O=Internet Security Research Group; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
||||
@@ -1824,7 +1822,7 @@ emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=ISRG Root X2; O=Internet Security Research Group; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw
|
||||
CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg
|
||||
R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00
|
||||
@@ -1840,7 +1838,7 @@ tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Izenpe.com; O=IZENPE S.A.; C=ES
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
|
||||
MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
|
||||
ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD
|
||||
@@ -1876,7 +1874,7 @@ QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=SZAFIR ROOT CA2; O=Krajowa Izba Rozliczeniowa S.A.; C=PL
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL
|
||||
BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6
|
||||
ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw
|
||||
@@ -1899,7 +1897,7 @@ LvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=e-Szigno Root CA 2017; O=Microsec Ltd.; L=Budapest; C=HU; OrganizationIdentifier=VATHU-23584497
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV
|
||||
BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk
|
||||
LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv
|
||||
@@ -1916,7 +1914,7 @@ jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Microsec e-Szigno Root CA 2009; O=Microsec Ltd.; L=Budapest; C=HU; EmailAddress=info@e-szigno.hu
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
|
||||
VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0
|
||||
ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G
|
||||
@@ -1942,7 +1940,7 @@ HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Microsoft ECC Root Certificate Authority 2017; O=Microsoft Corporation; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw
|
||||
CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD
|
||||
VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw
|
||||
@@ -1959,7 +1957,7 @@ iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Microsoft RSA Root Certificate Authority 2017; O=Microsoft Corporation; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl
|
||||
MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw
|
||||
NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
|
||||
@@ -1994,7 +1992,7 @@ RA+GsCyRxj3qrg+E
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=NAVER Global Root Certification Authority; O=NAVER BUSINESS PLATFORM Corp.; C=KR
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM
|
||||
BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG
|
||||
T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0
|
||||
@@ -2029,7 +2027,7 @@ dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=NetLock Arany (Class Gold) Főtanúsítvány; OU=Tanúsítványkiadók (Certification Services); O=NetLock Kft.; L=Budapest; C=HU
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG
|
||||
EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3
|
||||
MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl
|
||||
@@ -2055,7 +2053,7 @@ XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=OISTE WISeKey Global Root GC CA; OU=OISTE Foundation Endorsed; O=WISeKey; C=CH
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw
|
||||
CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91
|
||||
bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg
|
||||
@@ -2072,7 +2070,7 @@ Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=OISTE WISeKey Global Root GB CA; OU=OISTE Foundation Endorsed; O=WISeKey; C=CH
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt
|
||||
MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg
|
||||
Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i
|
||||
@@ -2096,7 +2094,7 @@ Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Security Communication ECC RootCA1; O=SECOM Trust Systems CO.,LTD.; C=JP
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT
|
||||
AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD
|
||||
VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx
|
||||
@@ -2112,7 +2110,7 @@ be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// OU=Security Communication RootCA2; O=SECOM Trust Systems CO.,LTD.; C=JP
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl
|
||||
MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe
|
||||
U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX
|
||||
@@ -2135,7 +2133,7 @@ SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Entrust Root Certification Authority; OU=www.entrust.net/CPS is incorporated by reference, (c) 2006 Entrust, Inc.; O=Entrust, Inc.; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
|
||||
VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
|
||||
Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
|
||||
@@ -2164,7 +2162,7 @@ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Sectigo Public Server Authentication Root E46; O=Sectigo Limited; C=GB
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw
|
||||
CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
|
||||
ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN
|
||||
@@ -2180,7 +2178,7 @@ qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=COMODO ECC Certification Authority; O=COMODO CA Limited; L=Salford; ST=Greater Manchester; C=GB
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
|
||||
MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
|
||||
BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
|
||||
@@ -2198,7 +2196,7 @@ GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=COMODO Certification Authority; O=COMODO CA Limited; L=Salford; ST=Greater Manchester; C=GB
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIID0DCCArigAwIBAgIQIKTEf93f4cdTYwcTiHdgEjANBgkqhkiG9w0BAQUFADCB
|
||||
gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
|
||||
@@ -2223,7 +2221,7 @@ R1uUq27UlTMdphVx8fiUylQ5PsE=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=COMODO RSA Certification Authority; O=COMODO CA Limited; L=Salford; ST=Greater Manchester; C=GB
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
|
||||
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
|
||||
@@ -2259,7 +2257,7 @@ NVOFBkpdn627G190
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=USERTrust RSA Certification Authority; O=The USERTRUST Network; L=Jersey City; ST=New Jersey; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
@@ -2295,7 +2293,7 @@ jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=USERTrust ECC Certification Authority; O=The USERTRUST Network; L=Jersey City; ST=New Jersey; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL
|
||||
MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl
|
||||
eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT
|
||||
@@ -2313,7 +2311,7 @@ RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Sectigo Public Server Authentication Root R46; O=Sectigo Limited; C=GB
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf
|
||||
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD
|
||||
Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw
|
||||
@@ -2347,7 +2345,7 @@ QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Entrust Root Certification Authority - G2; OU=See www.entrust.net/legal-terms, (c) 2009 Entrust, Inc. - for authorized use only; O=Entrust, Inc.; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC
|
||||
VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50
|
||||
cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs
|
||||
@@ -2374,7 +2372,7 @@ VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Entrust Root Certification Authority - EC1; OU=See www.entrust.net/legal-terms, (c) 2012 Entrust, Inc. - for authorized use only; O=Entrust, Inc.; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG
|
||||
A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3
|
||||
d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu
|
||||
@@ -2394,7 +2392,7 @@ hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=SSL.com Root Certification Authority RSA; O=SSL Corporation; L=Houston; ST=Texas; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE
|
||||
BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK
|
||||
DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp
|
||||
@@ -2430,7 +2428,7 @@ Ic2wBlX7Jz9TkHCpBB5XJ7k=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=SSL.com TLS ECC Root CA 2022; O=SSL Corporation; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw
|
||||
CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT
|
||||
U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2
|
||||
@@ -2446,7 +2444,7 @@ b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=SSL.com TLS RSA Root CA 2022; O=SSL Corporation; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO
|
||||
MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD
|
||||
DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX
|
||||
@@ -2480,7 +2478,7 @@ Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=SSL.com Root Certification Authority ECC; O=SSL Corporation; L=Houston; ST=Texas; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC
|
||||
VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
|
||||
U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0
|
||||
@@ -2498,7 +2496,7 @@ gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=SSL.com EV Root Certification Authority RSA R2; O=SSL Corporation; L=Houston; ST=Texas; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV
|
||||
BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE
|
||||
CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy
|
||||
@@ -2534,7 +2532,7 @@ mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=SSL.com EV Root Certification Authority ECC; O=SSL Corporation; L=Houston; ST=Texas; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC
|
||||
VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
|
||||
U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp
|
||||
@@ -2552,7 +2550,7 @@ h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=SwissSign Gold CA - G2; O=SwissSign AG; C=CH
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
|
||||
BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln
|
||||
biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF
|
||||
@@ -2587,7 +2585,7 @@ Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=TWCA CYBER Root CA; OU=Root CA; O=TAIWAN-CA; C=TW
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ
|
||||
MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290
|
||||
IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5
|
||||
@@ -2621,7 +2619,7 @@ t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=TWCA Global Root CA; OU=Root CA; O=TAIWAN-CA; C=TW
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx
|
||||
EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT
|
||||
VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5
|
||||
@@ -2654,7 +2652,7 @@ KwbQBM0=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=TeliaSonera Root CA v1; O=TeliaSonera
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw
|
||||
NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv
|
||||
b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD
|
||||
@@ -2686,7 +2684,7 @@ SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Telia Root CA v2; O=Telia Finland Oyj; C=FI
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx
|
||||
CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE
|
||||
AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1
|
||||
@@ -2720,7 +2718,7 @@ rBPuUBQemMc=
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Trustwave Global ECC P384 Certification Authority; O=Trustwave Holdings, Inc.; L=Chicago; ST=Illinois; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD
|
||||
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf
|
||||
BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3
|
||||
@@ -2739,7 +2737,7 @@ Sw==
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Trustwave Global ECC P256 Certification Authority; O=Trustwave Holdings, Inc.; L=Chicago; ST=Illinois; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD
|
||||
VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf
|
||||
BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3
|
||||
@@ -2756,7 +2754,7 @@ DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=SecureTrust CA; O=SecureTrust Corporation; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
|
||||
MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
|
||||
FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz
|
||||
@@ -2780,7 +2778,7 @@ CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
|
||||
-----END CERTIFICATE-----`))
|
||||
|
||||
// CN=Trustwave Global Certification Authority; O=Trustwave Holdings, Inc.; L=Chicago; ST=Illinois; C=US
|
||||
chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
pool.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw
|
||||
CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x
|
||||
ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1
|
||||
@@ -2814,4 +2812,5 @@ h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9
|
||||
EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK
|
||||
yeC2nOnOcXHebD8WpHk=
|
||||
-----END CERTIFICATE-----`))
|
||||
return pool
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ var _ adapter.CertificateStore = (*Store)(nil)
|
||||
|
||||
type Store struct {
|
||||
access sync.RWMutex
|
||||
storeType string
|
||||
systemPool *x509.CertPool
|
||||
currentPool *x509.CertPool
|
||||
certificate string
|
||||
@@ -31,9 +32,13 @@ type Store struct {
|
||||
}
|
||||
|
||||
func NewStore(ctx context.Context, logger logger.Logger, options option.CertificateOptions) (*Store, error) {
|
||||
storeType := options.Store
|
||||
if storeType == "" {
|
||||
storeType = C.CertificateStoreSystem
|
||||
}
|
||||
var systemPool *x509.CertPool
|
||||
switch options.Store {
|
||||
case C.CertificateStoreSystem, "":
|
||||
switch storeType {
|
||||
case C.CertificateStoreSystem:
|
||||
systemPool = x509.NewCertPool()
|
||||
platformInterface := service.FromContext[adapter.PlatformInterface](ctx)
|
||||
var systemValid bool
|
||||
@@ -51,16 +56,13 @@ func NewStore(ctx context.Context, logger logger.Logger, options option.Certific
|
||||
}
|
||||
systemPool = certPool
|
||||
}
|
||||
case C.CertificateStoreMozilla:
|
||||
systemPool = mozillaIncluded
|
||||
case C.CertificateStoreChrome:
|
||||
systemPool = chromeIncluded
|
||||
case C.CertificateStoreMozilla, C.CertificateStoreChrome:
|
||||
case C.CertificateStoreNone:
|
||||
systemPool = nil
|
||||
default:
|
||||
return nil, E.New("unknown certificate store: ", options.Store)
|
||||
}
|
||||
store := &Store{
|
||||
storeType: storeType,
|
||||
systemPool: systemPool,
|
||||
certificate: strings.Join(options.Certificate, "\n"),
|
||||
certificatePaths: options.CertificatePath,
|
||||
@@ -124,13 +126,9 @@ func (s *Store) Pool() *x509.CertPool {
|
||||
}
|
||||
|
||||
func (s *Store) update() error {
|
||||
s.access.Lock()
|
||||
defer s.access.Unlock()
|
||||
var currentPool *x509.CertPool
|
||||
if s.systemPool == nil {
|
||||
currentPool = x509.NewCertPool()
|
||||
} else {
|
||||
currentPool = s.systemPool.Clone()
|
||||
currentPool, err := s.newBasePool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s.certificate != "" {
|
||||
if !currentPool.AppendCertsFromPEM([]byte(s.certificate)) {
|
||||
@@ -165,10 +163,30 @@ func (s *Store) update() error {
|
||||
if firstErr != nil {
|
||||
return firstErr
|
||||
}
|
||||
s.access.Lock()
|
||||
defer s.access.Unlock()
|
||||
s.currentPool = currentPool
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) newBasePool() (*x509.CertPool, error) {
|
||||
switch s.storeType {
|
||||
case C.CertificateStoreSystem:
|
||||
if s.systemPool == nil {
|
||||
return x509.NewCertPool(), nil
|
||||
}
|
||||
return s.systemPool.Clone(), nil
|
||||
case C.CertificateStoreMozilla:
|
||||
return newMozillaIncluded(), nil
|
||||
case C.CertificateStoreChrome:
|
||||
return newChromeIncluded(), nil
|
||||
case C.CertificateStoreNone:
|
||||
return x509.NewCertPool(), nil
|
||||
default:
|
||||
return nil, E.New("unknown certificate store: ", s.storeType)
|
||||
}
|
||||
}
|
||||
|
||||
func readUniqueDirectoryEntries(dir string) ([]fs.DirEntry, error) {
|
||||
files, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
|
||||
@@ -63,9 +63,7 @@ parseLine:
|
||||
}
|
||||
continue
|
||||
}
|
||||
if strings.HasSuffix(ruleLine, "|") {
|
||||
ruleLine = ruleLine[:len(ruleLine)-1]
|
||||
}
|
||||
ruleLine = strings.TrimSuffix(ruleLine, "|")
|
||||
var (
|
||||
isExclude bool
|
||||
isSuffix bool
|
||||
@@ -76,7 +74,7 @@ parseLine:
|
||||
)
|
||||
if !strings.HasPrefix(ruleLine, "/") && strings.Contains(ruleLine, "$") {
|
||||
params := common.SubstringAfter(ruleLine, "$")
|
||||
for _, param := range strings.Split(params, ",") {
|
||||
for param := range strings.SplitSeq(params, ",") {
|
||||
paramParts := strings.Split(param, "=")
|
||||
var ignored bool
|
||||
if len(paramParts) > 0 && len(paramParts) <= 2 {
|
||||
@@ -106,9 +104,7 @@ parseLine:
|
||||
ruleLine = ruleLine[2:]
|
||||
isExclude = true
|
||||
}
|
||||
if strings.HasSuffix(ruleLine, "|") {
|
||||
ruleLine = ruleLine[:len(ruleLine)-1]
|
||||
}
|
||||
ruleLine = strings.TrimSuffix(ruleLine, "|")
|
||||
if strings.HasPrefix(ruleLine, "||") {
|
||||
ruleLine = ruleLine[2:]
|
||||
isSuffix = true
|
||||
@@ -414,18 +410,18 @@ func ignoreIPCIDRRegexp(ruleLine string) bool {
|
||||
}
|
||||
|
||||
func parseAdGuardHostLine(ruleLine string) (string, error) {
|
||||
idx := strings.Index(ruleLine, " ")
|
||||
if idx == -1 {
|
||||
before, after, ok := strings.Cut(ruleLine, " ")
|
||||
if !ok {
|
||||
return "", os.ErrInvalid
|
||||
}
|
||||
address, err := netip.ParseAddr(ruleLine[:idx])
|
||||
address, err := netip.ParseAddr(before)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !address.IsUnspecified() {
|
||||
return "", nil
|
||||
}
|
||||
domain := ruleLine[idx+1:]
|
||||
domain := after
|
||||
if !M.IsDomainName(domain) {
|
||||
return "", E.New("invalid domain name: ", domain)
|
||||
}
|
||||
|
||||
@@ -136,18 +136,16 @@ func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, d
|
||||
go startRacer(fallbackCtx, false, iif)
|
||||
}
|
||||
var errors []error
|
||||
for {
|
||||
select {
|
||||
case res := <-results:
|
||||
if res.error == nil {
|
||||
return res.Conn, res.primary, nil
|
||||
}
|
||||
errors = append(errors, res.error)
|
||||
if len(errors) == len(primaryInterfaces)+len(fallbackInterfaces) {
|
||||
return nil, false, E.Errors(errors...)
|
||||
}
|
||||
for res := range results {
|
||||
if res.error == nil {
|
||||
return res.Conn, res.primary, nil
|
||||
}
|
||||
errors = append(errors, res.error)
|
||||
if len(errors) == len(primaryInterfaces)+len(fallbackInterfaces) {
|
||||
return nil, false, E.Errors(errors...)
|
||||
}
|
||||
}
|
||||
return nil, false, E.Errors(errors...)
|
||||
}
|
||||
|
||||
func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listener net.ListenConfig, network string, addr string, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) {
|
||||
|
||||
@@ -19,11 +19,6 @@ func oldWriteString(writer varbin.Writer, value string) error {
|
||||
return varbin.Write(writer, binary.BigEndian, value)
|
||||
}
|
||||
|
||||
func oldWriteItem(writer varbin.Writer, item Item) error {
|
||||
//nolint:staticcheck
|
||||
return varbin.Write(writer, binary.BigEndian, item)
|
||||
}
|
||||
|
||||
func oldReadString(reader varbin.Reader) (string, error) {
|
||||
//nolint:staticcheck
|
||||
return varbin.ReadValue[string](reader, binary.BigEndian)
|
||||
@@ -224,7 +219,7 @@ func TestGeositeWriteReadCompat(t *testing.T) {
|
||||
|
||||
func generateLargeItems(count int) map[string][]Item {
|
||||
items := make([]Item, count)
|
||||
for i := 0; i < count; i++ {
|
||||
for i := range count {
|
||||
items[i] = Item{
|
||||
Type: ItemType(i % 4),
|
||||
Value: strings.Repeat("x", i%200) + ".com",
|
||||
|
||||
@@ -48,12 +48,6 @@ func NewReader(readSeeker io.ReadSeeker) (*Reader, []string, error) {
|
||||
return reader, codes, nil
|
||||
}
|
||||
|
||||
type geositeMetadata struct {
|
||||
Code string
|
||||
Index uint64
|
||||
Length uint64
|
||||
}
|
||||
|
||||
func (r *Reader) readMetadata() error {
|
||||
counter := &readCounter{Reader: r.reader}
|
||||
reader := bufio.NewReader(counter)
|
||||
@@ -101,6 +95,9 @@ func (r *Reader) readMetadata() error {
|
||||
}
|
||||
|
||||
func (r *Reader) Read(code string) ([]Item, error) {
|
||||
r.access.Lock()
|
||||
defer r.access.Unlock()
|
||||
|
||||
index, exists := r.domainIndex[code]
|
||||
if !exists {
|
||||
return nil, E.New("code ", code, " not exists!")
|
||||
|
||||
@@ -131,7 +131,7 @@ func (j *ClientHello) parseHandshake(hs []byte) error {
|
||||
return &ParseError{LengthErr, 7}
|
||||
}
|
||||
|
||||
for i := 0; i < numCiphers; i++ {
|
||||
for i := range numCiphers {
|
||||
cipherSuite := uint16(cs[2+i<<1])<<8 | uint16(cs[3+i<<1])
|
||||
cipherSuites = append(cipherSuites, cipherSuite)
|
||||
}
|
||||
@@ -234,7 +234,7 @@ func (j *ClientHello) parseExtensions(exs []byte) error {
|
||||
return &ParseError{LengthErr, 16}
|
||||
}
|
||||
|
||||
for i := 0; i < numCurves; i++ {
|
||||
for i := range numCurves {
|
||||
ecType := uint16(sex[i*2])<<8 | uint16(sex[1+i*2])
|
||||
ellipticCurves = append(ellipticCurves, ecType)
|
||||
}
|
||||
@@ -256,7 +256,7 @@ func (j *ClientHello) parseExtensions(exs []byte) error {
|
||||
return &ParseError{LengthErr, 18}
|
||||
}
|
||||
|
||||
for i := 0; i < numPF; i++ {
|
||||
for i := range numPF {
|
||||
ellipticCurvePF[i] = uint8(sex[i])
|
||||
}
|
||||
case versionExtensionType:
|
||||
|
||||
@@ -6,48 +6,7 @@
|
||||
|
||||
package ktls
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
)
|
||||
|
||||
// The marshalingFunction type is an adapter to allow the use of ordinary
|
||||
// functions as cryptobyte.MarshalingValue.
|
||||
type marshalingFunction func(b *cryptobyte.Builder) error
|
||||
|
||||
func (f marshalingFunction) Marshal(b *cryptobyte.Builder) error {
|
||||
return f(b)
|
||||
}
|
||||
|
||||
// addBytesWithLength appends a sequence of bytes to the cryptobyte.Builder. If
|
||||
// the length of the sequence is not the value specified, it produces an error.
|
||||
func addBytesWithLength(b *cryptobyte.Builder, v []byte, n int) {
|
||||
b.AddValue(marshalingFunction(func(b *cryptobyte.Builder) error {
|
||||
if len(v) != n {
|
||||
return fmt.Errorf("invalid value length: expected %d, got %d", n, len(v))
|
||||
}
|
||||
b.AddBytes(v)
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
// addUint64 appends a big-endian, 64-bit value to the cryptobyte.Builder.
|
||||
func addUint64(b *cryptobyte.Builder, v uint64) {
|
||||
b.AddUint32(uint32(v >> 32))
|
||||
b.AddUint32(uint32(v))
|
||||
}
|
||||
|
||||
// readUint64 decodes a big-endian, 64-bit value into out and advances over it.
|
||||
// It reports whether the read was successful.
|
||||
func readUint64(s *cryptobyte.String, out *uint64) bool {
|
||||
var hi, lo uint32
|
||||
if !s.ReadUint32(&hi) || !s.ReadUint32(&lo) {
|
||||
return false
|
||||
}
|
||||
*out = uint64(hi)<<32 | uint64(lo)
|
||||
return true
|
||||
}
|
||||
import "golang.org/x/crypto/cryptobyte"
|
||||
|
||||
// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a
|
||||
// []byte instead of a cryptobyte.String.
|
||||
@@ -61,12 +20,6 @@ func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
|
||||
return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out))
|
||||
}
|
||||
|
||||
// readUint24LengthPrefixed acts like s.ReadUint24LengthPrefixed, but targets a
|
||||
// []byte instead of a cryptobyte.String.
|
||||
func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
|
||||
return s.ReadUint24LengthPrefixed((*cryptobyte.String)(out))
|
||||
}
|
||||
|
||||
type keyUpdateMsg struct {
|
||||
updateRequested bool
|
||||
}
|
||||
@@ -125,11 +78,6 @@ const (
|
||||
typeMessageHash uint8 = 254 // synthetic message
|
||||
)
|
||||
|
||||
// TLS compression types.
|
||||
const (
|
||||
compressionNone uint8 = 0
|
||||
)
|
||||
|
||||
// TLS extension numbers
|
||||
const (
|
||||
extensionServerName uint16 = 0
|
||||
|
||||
@@ -77,78 +77,5 @@ func (c *Conn) writeRecordLocked(typ uint16, data []byte) (n int, err error) {
|
||||
if !c.kernelTx {
|
||||
return c.rawConn.WriteRecordLocked(typ, data)
|
||||
}
|
||||
/*for len(data) > 0 {
|
||||
m := len(data)
|
||||
if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload {
|
||||
m = maxPayload
|
||||
}
|
||||
_, err = c.writeKernelRecord(typ, data[:m])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n += m
|
||||
data = data[m:]
|
||||
}*/
|
||||
return c.writeKernelRecord(typ, data)
|
||||
}
|
||||
|
||||
const (
|
||||
// tcpMSSEstimate is a conservative estimate of the TCP maximum segment
|
||||
// size (MSS). A constant is used, rather than querying the kernel for
|
||||
// the actual MSS, to avoid complexity. The value here is the IPv6
|
||||
// minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40
|
||||
// bytes) and a TCP header with timestamps (32 bytes).
|
||||
tcpMSSEstimate = 1208
|
||||
|
||||
// recordSizeBoostThreshold is the number of bytes of application data
|
||||
// sent after which the TLS record size will be increased to the
|
||||
// maximum.
|
||||
recordSizeBoostThreshold = 128 * 1024
|
||||
)
|
||||
|
||||
func (c *Conn) maxPayloadSizeForWrite(typ uint16) int {
|
||||
if /*c.config.DynamicRecordSizingDisabled ||*/ typ != recordTypeApplicationData {
|
||||
return maxPlaintext
|
||||
}
|
||||
|
||||
if *c.rawConn.PacketsSent >= recordSizeBoostThreshold {
|
||||
return maxPlaintext
|
||||
}
|
||||
|
||||
// Subtract TLS overheads to get the maximum payload size.
|
||||
payloadBytes := tcpMSSEstimate - recordHeaderLen - c.rawConn.Out.ExplicitNonceLen()
|
||||
if rawCipher := *c.rawConn.Out.Cipher; rawCipher != nil {
|
||||
switch ciph := rawCipher.(type) {
|
||||
case cipher.Stream:
|
||||
payloadBytes -= (*c.rawConn.Out.Mac).Size()
|
||||
case cipher.AEAD:
|
||||
payloadBytes -= ciph.Overhead()
|
||||
/*case cbcMode:
|
||||
blockSize := ciph.BlockSize()
|
||||
// The payload must fit in a multiple of blockSize, with
|
||||
// room for at least one padding byte.
|
||||
payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1
|
||||
// The RawMac is appended before padding so affects the
|
||||
// payload size directly.
|
||||
payloadBytes -= c.out.mac.Size()*/
|
||||
default:
|
||||
panic("unknown cipher type")
|
||||
}
|
||||
}
|
||||
if *c.rawConn.Vers == tls.VersionTLS13 {
|
||||
payloadBytes-- // encrypted ContentType
|
||||
}
|
||||
|
||||
// Allow packet growth in arithmetic progression up to max.
|
||||
pkt := *c.rawConn.PacketsSent
|
||||
*c.rawConn.PacketsSent++
|
||||
if pkt > 1000 {
|
||||
return maxPlaintext // avoid overflow in multiply below
|
||||
}
|
||||
|
||||
n := payloadBytes * int(pkt+1)
|
||||
if n > maxPlaintext {
|
||||
n = maxPlaintext
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func (f *darwinConnectionFinder) find(network string, source netip.AddrPort, des
|
||||
source = normalizeDarwinAddrPort(source)
|
||||
destination = normalizeDarwinAddrPort(destination)
|
||||
var lastOwner *adapter.ConnectionOwner
|
||||
for attempt := 0; attempt < 2; attempt++ {
|
||||
for attempt := range 2 {
|
||||
snapshot, fromCache, err := f.loadSnapshot(networkName, attempt > 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -261,7 +261,8 @@ func getExecPathFromPID(pid uint32) (string, error) {
|
||||
procpidpathinfo,
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
procpidpathinfosize)
|
||||
procpidpathinfosize,
|
||||
)
|
||||
if errno != 0 {
|
||||
return "", errno
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//go:build linux
|
||||
|
||||
//nolint:unused
|
||||
package process
|
||||
|
||||
import (
|
||||
@@ -117,7 +118,7 @@ func (c *socketDiagConn) query(source netip.AddrPort, destination netip.AddrPort
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
request := packSocketDiagRequest(c.family, c.protocol, source, destination, false)
|
||||
for attempt := 0; attempt < 2; attempt++ {
|
||||
for range 2 {
|
||||
err = c.ensureOpenLocked()
|
||||
if err != nil {
|
||||
return 0, 0, E.Cause(err, "dial netlink")
|
||||
|
||||
@@ -109,7 +109,7 @@ func getInterfaceDisplayName(name string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, deviceSpan := range strings.Split(string(content), "Ethernet Address") {
|
||||
for deviceSpan := range strings.SplitSeq(string(content), "Ethernet Address") {
|
||||
if strings.Contains(deviceSpan, "Device: "+name) {
|
||||
substr := "Hardware Port: "
|
||||
deviceSpan = deviceSpan[strings.Index(deviceSpan, substr)+len(substr):]
|
||||
|
||||
@@ -40,14 +40,14 @@ func (m *connmanMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
defer cancel()
|
||||
|
||||
cmObj := m.conn.Object("net.connman", "/")
|
||||
var services []interface{}
|
||||
var services []any
|
||||
err := cmObj.CallWithContext(ctx, "net.connman.Manager.GetServices", 0).Store(&services)
|
||||
if err != nil {
|
||||
return adapter.WIFIState{}
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
servicePair, ok := service.([]interface{})
|
||||
servicePair, ok := service.([]any)
|
||||
if !ok || len(servicePair) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//nolint:unused
|
||||
package settings
|
||||
|
||||
import (
|
||||
@@ -73,13 +74,13 @@ func (m *wpaSupplicantMonitor) ReadWIFIState() adapter.WIFIState {
|
||||
scanner := bufio.NewScanner(strings.NewReader(status))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "wpa_state=") {
|
||||
state := strings.TrimPrefix(line, "wpa_state=")
|
||||
if after, ok := strings.CutPrefix(line, "wpa_state="); ok {
|
||||
state := after
|
||||
connected = state == "COMPLETED"
|
||||
} else if strings.HasPrefix(line, "ssid=") {
|
||||
ssid = strings.TrimPrefix(line, "ssid=")
|
||||
} else if strings.HasPrefix(line, "bssid=") {
|
||||
bssid = strings.TrimPrefix(line, "bssid=")
|
||||
} else if after, ok := strings.CutPrefix(line, "ssid="); ok {
|
||||
ssid = after
|
||||
} else if after, ok := strings.CutPrefix(line, "bssid="); ok {
|
||||
bssid = after
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//go:build !linux && !windows
|
||||
|
||||
//nolint:unused
|
||||
package settings
|
||||
|
||||
import (
|
||||
|
||||
@@ -54,9 +54,8 @@ type xorNonceAEAD struct {
|
||||
aead cipher.AEAD
|
||||
}
|
||||
|
||||
func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
|
||||
func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
||||
func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
|
||||
func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
|
||||
func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
||||
|
||||
func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
||||
for i, b := range nonce {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package sniff
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"github.com/sagernet/sing-box/common/ja3"
|
||||
)
|
||||
|
||||
@@ -15,15 +17,8 @@ const (
|
||||
// Note: uQUIC with Chromium mimicry cannot be reliably distinguished from real Chromium
|
||||
// since it uses the same TLS fingerprint, so it will be identified as Chromium.
|
||||
func isQUICGo(fingerprint *ja3.ClientHello) bool {
|
||||
for _, curve := range fingerprint.EllipticCurves {
|
||||
if curve == x25519Kyber768Draft00 {
|
||||
return true
|
||||
}
|
||||
if slices.Contains(fingerprint.EllipticCurves, x25519Kyber768Draft00) {
|
||||
return true
|
||||
}
|
||||
for _, ext := range fingerprint.Extensions {
|
||||
if ext == extensionRenegotiationInfo {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(fingerprint.Extensions, extensionRenegotiationInfo)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func TestSniffQUICQuicGoFingerprint(t *testing.T) {
|
||||
go func() {
|
||||
var packets [][]byte
|
||||
udpConn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||
for i := 0; i < 10; i++ {
|
||||
for range 10 {
|
||||
buf := make([]byte, 2048)
|
||||
n, _, err := udpConn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
@@ -104,7 +104,7 @@ func TestSniffQUICInitialFromQuicGo(t *testing.T) {
|
||||
go func() {
|
||||
var packets [][]byte
|
||||
udpConn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||
for i := 0; i < 5; i++ { // Capture up to 5 packets
|
||||
for range 5 { // Capture up to 5 packets
|
||||
buf := make([]byte, 2048)
|
||||
n, _, err := udpConn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
|
||||
@@ -78,7 +78,7 @@ func Read(reader io.Reader, recover bool) (ruleSetCompat option.PlainRuleSetComp
|
||||
}
|
||||
ruleSetCompat.Version = version
|
||||
ruleSetCompat.Options.Rules = make([]option.HeadlessRule, length)
|
||||
for i := uint64(0); i < length; i++ {
|
||||
for i := range length {
|
||||
ruleSetCompat.Options.Rules[i], err = readRule(bReader, recover)
|
||||
if err != nil {
|
||||
err = E.Cause(err, "read rule[", i, "]")
|
||||
@@ -644,7 +644,7 @@ func readLogicalRule(reader varbin.Reader, recovery bool) (logicalRule option.Lo
|
||||
return
|
||||
}
|
||||
logicalRule.Rules = make([]option.HeadlessRule, length)
|
||||
for i := uint64(0); i < length; i++ {
|
||||
for i := range length {
|
||||
logicalRule.Rules[i], err = readRule(reader, recovery)
|
||||
if err != nil {
|
||||
err = E.Cause(err, "read logical rule [", i, "]")
|
||||
|
||||
@@ -450,7 +450,7 @@ func buildIPSet(cidrs ...string) *netipx.IPSet {
|
||||
|
||||
func buildLargeIPSet(count int) *netipx.IPSet {
|
||||
var builder netipx.IPSetBuilder
|
||||
for i := 0; i < count; i++ {
|
||||
for i := range count {
|
||||
prefix := netip.PrefixFrom(netip.AddrFrom4([4]byte{10, byte(i / 256), byte(i % 256), 0}), 24)
|
||||
builder.AddPrefix(prefix)
|
||||
}
|
||||
|
||||
@@ -267,8 +267,8 @@ type realityVerifier struct {
|
||||
}
|
||||
|
||||
func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
|
||||
certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset))
|
||||
p, _ := reflect.TypeFor[utls.Conn]().FieldByName("peerCertificates")
|
||||
certs := *(*([]*x509.Certificate))(unsafe.Add(unsafe.Pointer(c.Conn), p.Offset))
|
||||
if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
|
||||
h := hmac.New(sha512.New, c.authKey)
|
||||
h.Write(pub)
|
||||
|
||||
@@ -141,13 +141,14 @@ func (c *STDServerConfig) startWatcher() error {
|
||||
|
||||
func (c *STDServerConfig) certificateUpdated(path string) error {
|
||||
if path == c.certificatePath || path == c.keyPath {
|
||||
if path == c.certificatePath {
|
||||
switch path {
|
||||
case c.certificatePath:
|
||||
certificate, err := os.ReadFile(c.certificatePath)
|
||||
if err != nil {
|
||||
return E.Cause(err, "reload certificate from ", c.certificatePath)
|
||||
}
|
||||
c.certificate = certificate
|
||||
} else if path == c.keyPath {
|
||||
case c.keyPath:
|
||||
key, err := os.ReadFile(c.keyPath)
|
||||
if err != nil {
|
||||
return E.Cause(err, "reload key from ", c.keyPath)
|
||||
@@ -338,9 +339,10 @@ func NewSTDServer(ctx context.Context, logger log.ContextLogger, options option.
|
||||
}
|
||||
tlsConfig.ClientCAs = clientCertificateCA
|
||||
} else if len(options.ClientCertificatePublicKeySHA256) > 0 {
|
||||
if tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
|
||||
switch tlsConfig.ClientAuth {
|
||||
case tls.RequireAndVerifyClientCert:
|
||||
tlsConfig.ClientAuth = tls.RequireAnyClientCert
|
||||
} else if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven {
|
||||
case tls.VerifyClientCertIfGiven:
|
||||
tlsConfig.ClientAuth = tls.RequestClientCert
|
||||
}
|
||||
tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
|
||||
@@ -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,290 @@
|
||||
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
|
||||
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)
|
||||
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)
|
||||
}
|
||||
minorVersion := safariMinorMap[(anchoredTime.Unix()-splitPoint.Unix())/1296000]
|
||||
return strconv.Itoa(releaseYear-1999) + "." + strconv.Itoa(minorVersion)
|
||||
}
|
||||
|
||||
// The full Chromium brand GREASE implementation
|
||||
var (
|
||||
clientHintGreaseNA = []string{" ", "(", ":", "-", ".", "/", ")", ";", "=", "?", "_"}
|
||||
clientHintVersionNA = []string{"8", "99", "24"}
|
||||
clientHintShuffle3 = [][3]int{{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}}
|
||||
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()
|
||||
AnchoredFirefoxVersion = strconv.Itoa(FirefoxVersion())
|
||||
FirefoxUA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:" + AnchoredFirefoxVersion + ".0) Gecko/20100101 Firefox/" + AnchoredFirefoxVersion + ".0"
|
||||
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()
|
||||
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"
|
||||
ChromeUACH = getGreasedChUa(AnchoredChromeVersion, "chrome")
|
||||
MSEdgeUA = ChromeUA + "Edg/" + strconv.Itoa(AnchoredChromeVersion) + ".0.0.0"
|
||||
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"
|
||||
}
|
||||
|
||||
@@ -603,10 +603,7 @@ func (s *StartedService) URLTest(ctx context.Context, request *URLTestRequest) (
|
||||
return false
|
||||
}
|
||||
_, isGroup := it.(adapter.OutboundGroup)
|
||||
if isGroup {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return !isGroup
|
||||
})
|
||||
b, _ := batch.New(boxService.ctx, batch.WithConcurrencyNum[any](10))
|
||||
for _, detour := range outbounds {
|
||||
|
||||
@@ -1952,9 +1952,9 @@ 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
|
||||
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
|
||||
@@ -1984,7 +1984,6 @@ var (
|
||||
(*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
|
||||
|
||||
@@ -70,10 +70,7 @@ func NewClient(options ClientOptions) *Client {
|
||||
if client.timeout == 0 {
|
||||
client.timeout = C.DNSTimeout
|
||||
}
|
||||
cacheCapacity := options.CacheCapacity
|
||||
if cacheCapacity < 1024 {
|
||||
cacheCapacity = 1024
|
||||
}
|
||||
cacheCapacity := max(options.CacheCapacity, 1024)
|
||||
if !client.disableCache {
|
||||
if !client.independentCache {
|
||||
client.cache = common.Must1(freelru.NewSharded[dns.Question, *dns.Msg](cacheCapacity, maphash.NewHasher[dns.Question]().Hash32))
|
||||
@@ -334,9 +331,10 @@ func (c *Client) Lookup(ctx context.Context, transport adapter.DNSTransport, dom
|
||||
if options.LookupStrategy != C.DomainStrategyAsIS {
|
||||
lookupOptions.Strategy = strategy
|
||||
}
|
||||
if strategy == C.DomainStrategyIPv4Only {
|
||||
switch strategy {
|
||||
case C.DomainStrategyIPv4Only:
|
||||
return c.lookupToExchange(ctx, transport, dnsName, dns.TypeA, lookupOptions, responseChecker)
|
||||
} else if strategy == C.DomainStrategyIPv6Only {
|
||||
case C.DomainStrategyIPv6Only:
|
||||
return c.lookupToExchange(ctx, transport, dnsName, dns.TypeAAAA, lookupOptions, responseChecker)
|
||||
}
|
||||
var response4 []netip.Addr
|
||||
@@ -500,10 +498,7 @@ func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransp
|
||||
}
|
||||
}
|
||||
}
|
||||
nowTTL := int(expireAt.Sub(timeNow).Seconds())
|
||||
if nowTTL < 0 {
|
||||
nowTTL = 0
|
||||
}
|
||||
nowTTL := max(int(expireAt.Sub(timeNow).Seconds()), 0)
|
||||
response = response.Copy()
|
||||
if originTTL > 0 {
|
||||
duration := uint32(originTTL - nowTTL)
|
||||
@@ -551,18 +546,6 @@ func MessageToAddresses(response *dns.Msg) []netip.Addr {
|
||||
return addresses
|
||||
}
|
||||
|
||||
func wrapError(err error) error {
|
||||
switch dnsErr := err.(type) {
|
||||
case *net.DNSError:
|
||||
if dnsErr.IsNotFound {
|
||||
return RcodeNameError
|
||||
}
|
||||
case *net.AddrError:
|
||||
return RcodeNameError
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type transportKey struct{}
|
||||
|
||||
func contextWithTransportTag(ctx context.Context, transportTag string) context.Context {
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
type ConnPoolMode int
|
||||
@@ -17,14 +18,18 @@ const (
|
||||
)
|
||||
|
||||
type ConnPoolOptions[T comparable] struct {
|
||||
Mode ConnPoolMode
|
||||
IsAlive func(T) bool
|
||||
Close func(T, error)
|
||||
Mode ConnPoolMode
|
||||
// MaxInflight caps concurrent in-progress dials. Only honored in ConnPoolOrdered mode.
|
||||
MaxInflight int
|
||||
IsAlive func(T) bool
|
||||
Close func(T, error)
|
||||
}
|
||||
|
||||
type ConnPool[T comparable] struct {
|
||||
options ConnPoolOptions[T]
|
||||
|
||||
sem *semaphore.Weighted
|
||||
|
||||
access sync.Mutex
|
||||
closed bool
|
||||
state *connPoolState[T]
|
||||
@@ -53,24 +58,15 @@ type connPoolConnect[T comparable] struct {
|
||||
err error
|
||||
}
|
||||
|
||||
type connPoolDialContext struct {
|
||||
context.Context
|
||||
parent context.Context
|
||||
}
|
||||
|
||||
func (c connPoolDialContext) Deadline() (time.Time, bool) {
|
||||
return c.parent.Deadline()
|
||||
}
|
||||
|
||||
func (c connPoolDialContext) Value(key any) any {
|
||||
return c.parent.Value(key)
|
||||
}
|
||||
|
||||
func NewConnPool[T comparable](options ConnPoolOptions[T]) *ConnPool[T] {
|
||||
return &ConnPool[T]{
|
||||
p := &ConnPool[T]{
|
||||
options: options,
|
||||
state: newConnPoolState[T](options.Mode),
|
||||
}
|
||||
if options.Mode == ConnPoolOrdered && options.MaxInflight > 0 {
|
||||
p.sem = semaphore.NewWeighted(int64(options.MaxInflight))
|
||||
}
|
||||
p.state = newConnPoolState[T](options.Mode)
|
||||
return p
|
||||
}
|
||||
|
||||
func newConnPoolState[T comparable](mode ConnPoolMode) *connPoolState[T] {
|
||||
@@ -108,67 +104,27 @@ func (p *ConnPool[T]) AcquireShared(ctx context.Context, dial func(context.Conte
|
||||
}
|
||||
|
||||
func (p *ConnPool[T]) Release(conn T, reuse bool) {
|
||||
var (
|
||||
closeConn bool
|
||||
closeErr error
|
||||
)
|
||||
|
||||
p.access.Lock()
|
||||
if p.closed || p.state == nil {
|
||||
closeConn = true
|
||||
closeErr = net.ErrClosed
|
||||
if p.closed {
|
||||
p.access.Unlock()
|
||||
if closeConn {
|
||||
p.options.Close(conn, closeErr)
|
||||
}
|
||||
p.options.Close(conn, net.ErrClosed)
|
||||
return
|
||||
}
|
||||
|
||||
currentState := p.state
|
||||
_, tracked := currentState.all[conn]
|
||||
if !tracked {
|
||||
closeConn = true
|
||||
closeErr = p.closeCause(currentState)
|
||||
state := p.state
|
||||
if _, tracked := state.all[conn]; !tracked {
|
||||
p.access.Unlock()
|
||||
if closeConn {
|
||||
p.options.Close(conn, closeErr)
|
||||
}
|
||||
p.options.Close(conn, net.ErrClosed)
|
||||
return
|
||||
}
|
||||
|
||||
if !reuse || !p.options.IsAlive(conn) {
|
||||
delete(currentState.all, conn)
|
||||
switch p.options.Mode {
|
||||
case ConnPoolSingle:
|
||||
if currentState.hasShared && currentState.shared == conn {
|
||||
var zero T
|
||||
currentState.shared = zero
|
||||
currentState.hasShared = false
|
||||
currentState.sharedClaimed = false
|
||||
currentState.sharedCtx = nil
|
||||
if currentState.sharedCancel != nil {
|
||||
currentState.sharedCancel(net.ErrClosed)
|
||||
currentState.sharedCancel = nil
|
||||
}
|
||||
}
|
||||
case ConnPoolOrdered:
|
||||
if element, loaded := currentState.idleElements[conn]; loaded {
|
||||
currentState.idle.Remove(element)
|
||||
delete(currentState.idleElements, conn)
|
||||
}
|
||||
}
|
||||
closeConn = true
|
||||
closeErr = net.ErrClosed
|
||||
p.removeConn(state, conn, net.ErrClosed)
|
||||
p.access.Unlock()
|
||||
if closeConn {
|
||||
p.options.Close(conn, closeErr)
|
||||
}
|
||||
p.options.Close(conn, net.ErrClosed)
|
||||
return
|
||||
}
|
||||
|
||||
if p.options.Mode == ConnPoolOrdered {
|
||||
if _, loaded := currentState.idleElements[conn]; !loaded {
|
||||
currentState.idleElements[conn] = currentState.idle.PushBack(conn)
|
||||
if _, idle := state.idleElements[conn]; !idle {
|
||||
state.idleElements[conn] = state.idle.PushBack(conn)
|
||||
}
|
||||
}
|
||||
p.access.Unlock()
|
||||
@@ -176,42 +132,68 @@ func (p *ConnPool[T]) Release(conn T, reuse bool) {
|
||||
|
||||
func (p *ConnPool[T]) Invalidate(conn T, cause error) {
|
||||
p.access.Lock()
|
||||
if p.closed || p.state == nil {
|
||||
if p.closed {
|
||||
p.access.Unlock()
|
||||
p.options.Close(conn, cause)
|
||||
return
|
||||
}
|
||||
|
||||
currentState := p.state
|
||||
_, tracked := currentState.all[conn]
|
||||
if !tracked {
|
||||
state := p.state
|
||||
if _, tracked := state.all[conn]; !tracked {
|
||||
p.access.Unlock()
|
||||
return
|
||||
}
|
||||
p.removeConn(state, conn, cause)
|
||||
p.access.Unlock()
|
||||
p.options.Close(conn, cause)
|
||||
}
|
||||
|
||||
delete(currentState.all, conn)
|
||||
func (p *ConnPool[T]) acquireSlot(ctx context.Context, state *connPoolState[T]) error {
|
||||
if p.sem == nil {
|
||||
return nil
|
||||
}
|
||||
acquireCtx, cancel := context.WithCancel(ctx)
|
||||
stopStateCancel := context.AfterFunc(state.ctx, cancel)
|
||||
err := p.sem.Acquire(acquireCtx, 1)
|
||||
stopStateCancel()
|
||||
cancel()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
ctxErr := ctx.Err()
|
||||
if ctxErr != nil {
|
||||
return ctxErr
|
||||
}
|
||||
return context.Cause(state.ctx)
|
||||
}
|
||||
|
||||
func (p *ConnPool[T]) releaseSlot() {
|
||||
if p.sem != nil {
|
||||
p.sem.Release(1)
|
||||
}
|
||||
}
|
||||
|
||||
// removeConn must be called with p.access held.
|
||||
func (p *ConnPool[T]) removeConn(state *connPoolState[T], conn T, cause error) {
|
||||
delete(state.all, conn)
|
||||
switch p.options.Mode {
|
||||
case ConnPoolSingle:
|
||||
if currentState.hasShared && currentState.shared == conn {
|
||||
if state.hasShared && state.shared == conn {
|
||||
var zero T
|
||||
currentState.shared = zero
|
||||
currentState.hasShared = false
|
||||
currentState.sharedClaimed = false
|
||||
currentState.sharedCtx = nil
|
||||
if currentState.sharedCancel != nil {
|
||||
currentState.sharedCancel(cause)
|
||||
currentState.sharedCancel = nil
|
||||
state.shared = zero
|
||||
state.hasShared = false
|
||||
state.sharedClaimed = false
|
||||
state.sharedCtx = nil
|
||||
if state.sharedCancel != nil {
|
||||
state.sharedCancel(cause)
|
||||
state.sharedCancel = nil
|
||||
}
|
||||
}
|
||||
case ConnPoolOrdered:
|
||||
if element, loaded := currentState.idleElements[conn]; loaded {
|
||||
currentState.idle.Remove(element)
|
||||
delete(currentState.idleElements, conn)
|
||||
if element, loaded := state.idleElements[conn]; loaded {
|
||||
state.idle.Remove(element)
|
||||
delete(state.idleElements, conn)
|
||||
}
|
||||
}
|
||||
p.access.Unlock()
|
||||
|
||||
p.options.Close(conn, cause)
|
||||
}
|
||||
|
||||
func (p *ConnPool[T]) Reset() {
|
||||
@@ -220,7 +202,6 @@ func (p *ConnPool[T]) Reset() {
|
||||
p.access.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
oldState := p.state
|
||||
p.state = newConnPoolState[T](p.options.Mode)
|
||||
p.access.Unlock()
|
||||
@@ -234,7 +215,6 @@ func (p *ConnPool[T]) Close() error {
|
||||
p.access.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
p.closed = true
|
||||
oldState := p.state
|
||||
p.state = nil
|
||||
@@ -247,77 +227,83 @@ func (p *ConnPool[T]) Close() error {
|
||||
func (p *ConnPool[T]) acquireOrdered(ctx context.Context, dial func(context.Context) (T, error)) (T, bool, error) {
|
||||
var zero T
|
||||
for {
|
||||
var (
|
||||
staleConn T
|
||||
hasStale bool
|
||||
)
|
||||
|
||||
p.access.Lock()
|
||||
if p.closed {
|
||||
p.access.Unlock()
|
||||
return zero, false, net.ErrClosed
|
||||
}
|
||||
|
||||
currentState := p.state
|
||||
if element := currentState.idle.Front(); element != nil {
|
||||
conn := currentState.idle.Remove(element)
|
||||
delete(currentState.idleElements, conn)
|
||||
if p.options.IsAlive(conn) {
|
||||
current := p.state
|
||||
if element := current.idle.Front(); element != nil {
|
||||
idleConn := current.idle.Remove(element)
|
||||
delete(current.idleElements, idleConn)
|
||||
if p.options.IsAlive(idleConn) {
|
||||
p.access.Unlock()
|
||||
return conn, false, nil
|
||||
return idleConn, false, nil
|
||||
}
|
||||
delete(currentState.all, conn)
|
||||
staleConn = conn
|
||||
hasStale = true
|
||||
}
|
||||
p.access.Unlock()
|
||||
|
||||
if hasStale {
|
||||
p.options.Close(staleConn, net.ErrClosed)
|
||||
delete(current.all, idleConn)
|
||||
p.access.Unlock()
|
||||
p.options.Close(idleConn, net.ErrClosed)
|
||||
continue
|
||||
}
|
||||
|
||||
conn, err := p.dial(ctx, currentState, dial)
|
||||
if err != nil {
|
||||
return zero, false, err
|
||||
}
|
||||
|
||||
p.access.Lock()
|
||||
if p.closed {
|
||||
p.access.Unlock()
|
||||
p.options.Close(conn, net.ErrClosed)
|
||||
return zero, false, net.ErrClosed
|
||||
}
|
||||
if p.state != currentState {
|
||||
cause := p.closeCause(currentState)
|
||||
p.access.Unlock()
|
||||
p.options.Close(conn, cause)
|
||||
return zero, false, cause
|
||||
}
|
||||
currentState.all[conn] = struct{}{}
|
||||
p.access.Unlock()
|
||||
return conn, true, nil
|
||||
return p.dialAndInstall(ctx, current, dial)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ConnPool[T]) dialAndInstall(ctx context.Context, current *connPoolState[T], dial func(context.Context) (T, error)) (T, bool, error) {
|
||||
var zero T
|
||||
err := p.acquireSlot(ctx, current)
|
||||
if err != nil {
|
||||
return zero, false, err
|
||||
}
|
||||
defer p.releaseSlot()
|
||||
dialCtx, dialCancel := context.WithCancelCause(ctx)
|
||||
stopStateCancel := context.AfterFunc(current.ctx, func() {
|
||||
dialCancel(context.Cause(current.ctx))
|
||||
})
|
||||
conn, err := dial(dialCtx)
|
||||
stateCancelStopped := stopStateCancel()
|
||||
dialErr := context.Cause(dialCtx)
|
||||
if dialErr == nil && !stateCancelStopped {
|
||||
dialErr = context.Cause(current.ctx)
|
||||
}
|
||||
dialCancel(nil)
|
||||
if err != nil {
|
||||
if dialErr != nil {
|
||||
return zero, false, dialErr
|
||||
}
|
||||
return zero, false, err
|
||||
}
|
||||
if dialErr != nil {
|
||||
p.options.Close(conn, dialErr)
|
||||
return zero, false, dialErr
|
||||
}
|
||||
|
||||
p.access.Lock()
|
||||
if p.closed {
|
||||
p.access.Unlock()
|
||||
p.options.Close(conn, net.ErrClosed)
|
||||
return zero, false, net.ErrClosed
|
||||
}
|
||||
if p.state != current {
|
||||
p.access.Unlock()
|
||||
p.options.Close(conn, net.ErrClosed)
|
||||
return zero, false, net.ErrClosed
|
||||
}
|
||||
current.all[conn] = struct{}{}
|
||||
p.access.Unlock()
|
||||
return conn, true, nil
|
||||
}
|
||||
|
||||
func (p *ConnPool[T]) acquireShared(ctx context.Context, dial func(context.Context) (T, error)) (T, context.Context, bool, error) {
|
||||
var zero T
|
||||
for {
|
||||
var (
|
||||
staleConn T
|
||||
hasStale bool
|
||||
state *connPoolConnect[T]
|
||||
current *connPoolState[T]
|
||||
startDial bool
|
||||
)
|
||||
|
||||
p.access.Lock()
|
||||
if p.closed {
|
||||
p.access.Unlock()
|
||||
return zero, nil, false, net.ErrClosed
|
||||
}
|
||||
|
||||
current = p.state
|
||||
current := p.state
|
||||
if current.hasShared {
|
||||
conn := current.shared
|
||||
if p.options.IsAlive(conn) {
|
||||
@@ -327,35 +313,19 @@ func (p *ConnPool[T]) acquireShared(ctx context.Context, dial func(context.Conte
|
||||
p.access.Unlock()
|
||||
return conn, connCtx, created, nil
|
||||
}
|
||||
delete(current.all, conn)
|
||||
var zeroConn T
|
||||
current.shared = zeroConn
|
||||
current.hasShared = false
|
||||
current.sharedClaimed = false
|
||||
current.sharedCtx = nil
|
||||
if current.sharedCancel != nil {
|
||||
current.sharedCancel(net.ErrClosed)
|
||||
current.sharedCancel = nil
|
||||
}
|
||||
staleConn = conn
|
||||
hasStale = true
|
||||
p.removeConn(current, conn, net.ErrClosed)
|
||||
p.access.Unlock()
|
||||
p.options.Close(staleConn, net.ErrClosed)
|
||||
p.options.Close(conn, net.ErrClosed)
|
||||
continue
|
||||
}
|
||||
|
||||
if current.connecting == nil {
|
||||
current.connecting = &connPoolConnect[T]{
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
startDial = true
|
||||
startDial := current.connecting == nil
|
||||
if startDial {
|
||||
current.connecting = &connPoolConnect[T]{done: make(chan struct{})}
|
||||
}
|
||||
state = current.connecting
|
||||
state := current.connecting
|
||||
p.access.Unlock()
|
||||
|
||||
if hasStale {
|
||||
continue
|
||||
}
|
||||
if startDial {
|
||||
go p.connectSingle(current, state, ctx, dial)
|
||||
}
|
||||
@@ -381,35 +351,39 @@ func (p *ConnPool[T]) acquireShared(ctx context.Context, dial func(context.Conte
|
||||
}
|
||||
|
||||
func (p *ConnPool[T]) connectSingle(current *connPoolState[T], state *connPoolConnect[T], ctx context.Context, dial func(context.Context) (T, error)) {
|
||||
conn, err := p.dial(ctx, current, dial)
|
||||
if err != nil {
|
||||
p.access.Lock()
|
||||
if current.connecting == state {
|
||||
current.connecting = nil
|
||||
dialCtx, dialCancel := context.WithCancelCause(ctx)
|
||||
stopStateCancel := context.AfterFunc(current.ctx, func() {
|
||||
dialCancel(context.Cause(current.ctx))
|
||||
})
|
||||
conn, err := dial(dialCtx)
|
||||
stateCancelStopped := stopStateCancel()
|
||||
dialErr := context.Cause(dialCtx)
|
||||
if dialErr == nil && !stateCancelStopped {
|
||||
dialErr = context.Cause(current.ctx)
|
||||
}
|
||||
dialCancel(nil)
|
||||
if dialErr != nil {
|
||||
if err == nil {
|
||||
p.options.Close(conn, dialErr)
|
||||
}
|
||||
state.err = err
|
||||
p.access.Unlock()
|
||||
close(state.done)
|
||||
return
|
||||
err = dialErr
|
||||
}
|
||||
|
||||
var closeErr error
|
||||
|
||||
p.access.Lock()
|
||||
if current.connecting == state {
|
||||
current.connecting = nil
|
||||
}
|
||||
if p.closed {
|
||||
current.connecting = nil
|
||||
if err != nil {
|
||||
state.err = err
|
||||
} else if p.closed {
|
||||
closeErr = net.ErrClosed
|
||||
state.err = closeErr
|
||||
} else if p.state != current {
|
||||
closeErr = p.closeCause(current)
|
||||
closeErr = net.ErrClosed
|
||||
state.err = closeErr
|
||||
} else {
|
||||
sharedCtx, sharedCancel := context.WithCancelCause(current.ctx)
|
||||
current.shared = conn
|
||||
current.hasShared = true
|
||||
current.sharedClaimed = false
|
||||
current.sharedCtx = sharedCtx
|
||||
current.sharedCancel = sharedCancel
|
||||
current.all[conn] = struct{}{}
|
||||
@@ -439,9 +413,8 @@ func (p *ConnPool[T]) collectShared(current *connPoolState[T], state *connPoolCo
|
||||
return zero, nil, false, false, net.ErrClosed
|
||||
}
|
||||
if p.state != current {
|
||||
cause := p.closeCause(current)
|
||||
p.access.Unlock()
|
||||
return zero, nil, false, false, cause
|
||||
return zero, nil, false, false, net.ErrClosed
|
||||
}
|
||||
if !current.hasShared {
|
||||
p.access.Unlock()
|
||||
@@ -450,16 +423,7 @@ func (p *ConnPool[T]) collectShared(current *connPoolState[T], state *connPoolCo
|
||||
|
||||
conn := current.shared
|
||||
if !p.options.IsAlive(conn) {
|
||||
delete(current.all, conn)
|
||||
var zeroConn T
|
||||
current.shared = zeroConn
|
||||
current.hasShared = false
|
||||
current.sharedClaimed = false
|
||||
current.sharedCtx = nil
|
||||
if current.sharedCancel != nil {
|
||||
current.sharedCancel(net.ErrClosed)
|
||||
current.sharedCancel = nil
|
||||
}
|
||||
p.removeConn(current, conn, net.ErrClosed)
|
||||
p.access.Unlock()
|
||||
p.options.Close(conn, net.ErrClosed)
|
||||
return zero, nil, false, true, nil
|
||||
@@ -472,76 +436,9 @@ func (p *ConnPool[T]) collectShared(current *connPoolState[T], state *connPoolCo
|
||||
return conn, connCtx, created, false, nil
|
||||
}
|
||||
|
||||
func (p *ConnPool[T]) dial(ctx context.Context, current *connPoolState[T], dial func(context.Context) (T, error)) (T, error) {
|
||||
var zero T
|
||||
|
||||
if err := ctx.Err(); err != nil {
|
||||
return zero, err
|
||||
}
|
||||
if cause := context.Cause(current.ctx); cause != nil {
|
||||
return zero, cause
|
||||
}
|
||||
|
||||
dialCtx, cancel := context.WithCancelCause(current.ctx)
|
||||
var (
|
||||
stateAccess sync.Mutex
|
||||
dialComplete bool
|
||||
)
|
||||
stopCancel := context.AfterFunc(ctx, func() {
|
||||
stateAccess.Lock()
|
||||
if !dialComplete {
|
||||
cancel(context.Cause(ctx))
|
||||
}
|
||||
stateAccess.Unlock()
|
||||
})
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
stateAccess.Lock()
|
||||
dialComplete = true
|
||||
stateAccess.Unlock()
|
||||
stopCancel()
|
||||
cancel(context.Cause(ctx))
|
||||
return zero, ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
conn, err := dial(connPoolDialContext{
|
||||
Context: dialCtx,
|
||||
parent: ctx,
|
||||
})
|
||||
stateAccess.Lock()
|
||||
dialComplete = true
|
||||
stateAccess.Unlock()
|
||||
stopCancel()
|
||||
if err != nil {
|
||||
if cause := context.Cause(dialCtx); cause != nil {
|
||||
return zero, cause
|
||||
}
|
||||
return zero, err
|
||||
}
|
||||
if cause := context.Cause(dialCtx); cause != nil {
|
||||
p.options.Close(conn, cause)
|
||||
return zero, cause
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (p *ConnPool[T]) closeState(state *connPoolState[T], cause error) {
|
||||
if state == nil {
|
||||
return
|
||||
}
|
||||
|
||||
state.cancel(cause)
|
||||
if state.sharedCancel != nil {
|
||||
state.sharedCancel(cause)
|
||||
}
|
||||
for conn := range state.all {
|
||||
p.options.Close(conn, cause)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ConnPool[T]) closeCause(state *connPoolState[T]) error {
|
||||
_ = state
|
||||
return net.ErrClosed
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ func (t *Transport) fetchServers0(ctx context.Context, iface *control.Interface)
|
||||
packetConn net.PacketConn
|
||||
err error
|
||||
)
|
||||
for i := 0; i < 5; i++ {
|
||||
for range 5 {
|
||||
packetConn, err = listener.ListenPacket(t.ctx, "udp4", listenAddr)
|
||||
if err == nil || !errors.Is(err, syscall.EADDRINUSE) {
|
||||
break
|
||||
|
||||
@@ -72,7 +72,7 @@ func (t *Transport) tryOneName(ctx context.Context, servers []M.Socksaddr, fqdn
|
||||
sLen := len(servers)
|
||||
var lastErr error
|
||||
for i := 0; i < t.attempts; i++ {
|
||||
for j := 0; j < sLen; j++ {
|
||||
for j := range sLen {
|
||||
server := servers[j]
|
||||
question := message.Question[0]
|
||||
question.Name = fqdn
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
//go:build !linux
|
||||
|
||||
//nolint:unused
|
||||
package local
|
||||
|
||||
import (
|
||||
|
||||
@@ -82,7 +82,7 @@ func (t *Transport) tryOneName(ctx context.Context, config *dnsConfig, fqdn stri
|
||||
sLen := uint32(len(config.servers))
|
||||
var lastErr error
|
||||
for i := 0; i < config.attempts; i++ {
|
||||
for j := uint32(0); j < sLen; j++ {
|
||||
for j := range sLen {
|
||||
server := config.servers[(serverOffset+j)%sLen]
|
||||
question := message.Question[0]
|
||||
question.Name = fqdn
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//nolint:unused
|
||||
package local
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//nolint:unused
|
||||
package local
|
||||
|
||||
import (
|
||||
|
||||
@@ -100,7 +100,7 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
|
||||
err error
|
||||
response *mDNS.Msg
|
||||
)
|
||||
for i := 0; i < 2; i++ {
|
||||
for range 2 {
|
||||
conn, _, err = t.connection.Acquire(ctx, func(ctx context.Context) (*quic.Conn, error) {
|
||||
rawConn, err := t.dialer.DialContext(ctx, N.NetworkUDP, t.serverAddr)
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
@@ -13,6 +15,7 @@ import (
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio/deadline"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -71,6 +74,7 @@ func (t *TCPTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.M
|
||||
return nil, E.Cause(err, "dial TCP connection")
|
||||
}
|
||||
defer conn.Close()
|
||||
defer setConnDeadline(ctx, conn, deadline.NeedAdditionalReadDeadline(conn))()
|
||||
err = WriteMessage(conn, 0, message)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "write request")
|
||||
@@ -82,6 +86,20 @@ func (t *TCPTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.M
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func setConnDeadline(ctx context.Context, conn net.Conn, needClose bool) func() {
|
||||
if needClose {
|
||||
stop := context.AfterFunc(ctx, func() {
|
||||
conn.Close()
|
||||
})
|
||||
return func() { stop() }
|
||||
}
|
||||
if d, ok := ctx.Deadline(); ok {
|
||||
conn.SetDeadline(d)
|
||||
return func() { conn.SetDeadline(time.Time{}) }
|
||||
}
|
||||
return func() {}
|
||||
}
|
||||
|
||||
func ReadMessage(reader io.Reader) (*mDNS.Msg, error) {
|
||||
var responseLen uint16
|
||||
err := binary.Read(reader, binary.BigEndian, &responseLen)
|
||||
|
||||
@@ -2,7 +2,6 @@ package transport
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
@@ -12,6 +11,7 @@ import (
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/bufio/deadline"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
|
||||
var _ adapter.DNSTransport = (*TLSTransport)(nil)
|
||||
|
||||
const tlsDNSMaxInflight = 8
|
||||
|
||||
func RegisterTLS(registry *dns.TransportRegistry) {
|
||||
dns.RegisterTransport[option.RemoteTLSDNSServerOptions](registry, C.DNSTypeTLS, NewTLS)
|
||||
}
|
||||
@@ -38,7 +40,8 @@ type TLSTransport struct {
|
||||
|
||||
type tlsDNSConn struct {
|
||||
tls.Conn
|
||||
queryId uint16
|
||||
queryId uint16
|
||||
needDeadlineClose bool
|
||||
}
|
||||
|
||||
func NewTLS(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteTLSDNSServerOptions) (adapter.DNSTransport, error) {
|
||||
@@ -70,7 +73,8 @@ func NewTLSRaw(logger logger.ContextLogger, adapter dns.TransportAdapter, dialer
|
||||
serverAddr: serverAddr,
|
||||
tlsConfig: tlsConfig,
|
||||
connections: NewConnPool(ConnPoolOptions[*tlsDNSConn]{
|
||||
Mode: ConnPoolOrdered,
|
||||
Mode: ConnPoolOrdered,
|
||||
MaxInflight: tlsDNSMaxInflight,
|
||||
IsAlive: func(conn *tlsDNSConn) bool {
|
||||
return conn != nil
|
||||
},
|
||||
@@ -98,13 +102,16 @@ func (t *TLSTransport) Reset() {
|
||||
|
||||
func (t *TLSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
var lastErr error
|
||||
for attempt := 0; attempt < 2; attempt++ {
|
||||
for range 2 {
|
||||
conn, created, err := t.connections.Acquire(ctx, func(ctx context.Context) (*tlsDNSConn, error) {
|
||||
tlsConn, err := t.dialer.DialTLSContext(ctx, t.serverAddr)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "dial TLS connection")
|
||||
}
|
||||
return &tlsDNSConn{Conn: tlsConn}, nil
|
||||
return &tlsDNSConn{
|
||||
Conn: tlsConn,
|
||||
needDeadlineClose: deadline.NeedAdditionalReadDeadline(tlsConn.NetConn()),
|
||||
}, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -125,9 +132,7 @@ func (t *TLSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.M
|
||||
}
|
||||
|
||||
func (t *TLSTransport) exchange(ctx context.Context, message *mDNS.Msg, conn *tlsDNSConn) (*mDNS.Msg, error) {
|
||||
if deadline, ok := ctx.Deadline(); ok {
|
||||
conn.SetDeadline(deadline)
|
||||
}
|
||||
defer setConnDeadline(ctx, conn, conn.needDeadlineClose)()
|
||||
conn.queryId++
|
||||
err := WriteMessage(conn, conn.queryId, message)
|
||||
if err != nil {
|
||||
@@ -137,6 +142,5 @@ func (t *TLSTransport) exchange(ctx context.Context, message *mDNS.Msg, conn *tl
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "read response")
|
||||
}
|
||||
conn.SetDeadline(time.Time{})
|
||||
return response, nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio/deadline"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
@@ -130,6 +131,7 @@ func (t *UDPTransport) exchangeTCP(ctx context.Context, message *mDNS.Msg) (*mDN
|
||||
return nil, E.Cause(err, "dial TCP connection")
|
||||
}
|
||||
defer conn.Close()
|
||||
defer setConnDeadline(ctx, conn, deadline.NeedAdditionalReadDeadline(conn))()
|
||||
err = WriteMessage(conn, message.Id, message)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "write request")
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.13.12
|
||||
|
||||
* Update naiveproxy to v148.0.7778.96-1
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.13.11
|
||||
|
||||
* Fix process searcher failure introduced in 1.13.9
|
||||
|
||||
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"]
|
||||
}
|
||||
]
|
||||
}
|
||||