mirror of
https://github.com/bolucat/Archive.git
synced 2026-04-22 16:07:49 +08:00
Update On Sat Feb 7 19:47:43 CET 2026
This commit is contained in:
@@ -1264,3 +1264,4 @@ Update On Tue Feb 3 20:07:51 CET 2026
|
||||
Update On Wed Feb 4 20:03:26 CET 2026
|
||||
Update On Thu Feb 5 20:02:24 CET 2026
|
||||
Update On Fri Feb 6 20:02:22 CET 2026
|
||||
Update On Sat Feb 7 19:47:34 CET 2026
|
||||
|
||||
@@ -178,7 +178,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) {
|
||||
},
|
||||
}
|
||||
outbound.dialer = option.NewDialer(outbound.DialOptions())
|
||||
singDialer := proxydialer.NewSlowDownSingDialer(proxydialer.NewSingDialer(outbound.dialer), slowdown.New())
|
||||
singDialer := proxydialer.NewSingDialer(proxydialer.NewSlowDownDialer(outbound.dialer, slowdown.New()))
|
||||
|
||||
var reserved [3]uint8
|
||||
if len(option.Reserved) > 0 {
|
||||
|
||||
@@ -58,6 +58,11 @@ func Main(args []string) {
|
||||
fmt.Println("Seed: " + seedBase64)
|
||||
fmt.Println("Client: " + clientBase64)
|
||||
fmt.Println("Hash32: " + hash32Base64)
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println(" Lazy-Config ")
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Printf("[Server] decryption: \"mlkem768x25519plus.native.600s.%s\"\n", seedBase64)
|
||||
fmt.Printf("[Client] encryption: \"mlkem768x25519plus.native.0rtt.%s\"\n", clientBase64)
|
||||
case "vless-x25519":
|
||||
var privateKey string
|
||||
if len(args) > 1 {
|
||||
@@ -70,6 +75,11 @@ func Main(args []string) {
|
||||
fmt.Println("PrivateKey: " + privateKeyBase64)
|
||||
fmt.Println("Password: " + passwordBase64)
|
||||
fmt.Println("Hash32: " + hash32Base64)
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println(" Lazy-Config ")
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Printf("[Server] decryption: \"mlkem768x25519plus.native.600s.%s\"\n", privateKeyBase64)
|
||||
fmt.Printf("[Client] encryption: \"mlkem768x25519plus.native.0rtt.%s\"\n", passwordBase64)
|
||||
case "sudoku-keypair":
|
||||
privateKey, publicKey, err := sudoku.GenKeyPair()
|
||||
if err != nil {
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"strings"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/metacubex/mihomo/common/utils"
|
||||
"github.com/metacubex/mihomo/component/resolver/hosts"
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
"github.com/metacubex/randv2"
|
||||
@@ -66,37 +65,35 @@ type HostValue struct {
|
||||
Domain string
|
||||
}
|
||||
|
||||
func NewHostValue(value any) (HostValue, error) {
|
||||
func NewHostValue(value []string) (HostValue, error) {
|
||||
isDomain := true
|
||||
ips := make([]netip.Addr, 0)
|
||||
ips := make([]netip.Addr, 0, len(value))
|
||||
domain := ""
|
||||
if valueArr, err := utils.ToStringSlice(value); err != nil {
|
||||
return HostValue{}, err
|
||||
} else {
|
||||
if len(valueArr) > 1 {
|
||||
switch len(value) {
|
||||
case 0:
|
||||
return HostValue{}, errors.New("value is empty")
|
||||
case 1:
|
||||
host := value[0]
|
||||
if ip, err := netip.ParseAddr(host); err == nil {
|
||||
ips = append(ips, ip.Unmap())
|
||||
isDomain = false
|
||||
for _, str := range valueArr {
|
||||
if ip, err := netip.ParseAddr(str); err == nil {
|
||||
ips = append(ips, ip.Unmap())
|
||||
} else {
|
||||
return HostValue{}, err
|
||||
}
|
||||
}
|
||||
} else if len(valueArr) == 1 {
|
||||
host := valueArr[0]
|
||||
if ip, err := netip.ParseAddr(host); err == nil {
|
||||
} else {
|
||||
domain = host
|
||||
}
|
||||
default: // > 1
|
||||
isDomain = false
|
||||
for _, str := range value {
|
||||
if ip, err := netip.ParseAddr(str); err == nil {
|
||||
ips = append(ips, ip.Unmap())
|
||||
isDomain = false
|
||||
} else {
|
||||
domain = host
|
||||
return HostValue{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if isDomain {
|
||||
return NewHostValueByDomain(domain)
|
||||
} else {
|
||||
return NewHostValueByIPs(ips)
|
||||
}
|
||||
return NewHostValueByIPs(ips)
|
||||
}
|
||||
|
||||
func NewHostValueByIPs(ips []netip.Addr) (HostValue, error) {
|
||||
|
||||
@@ -1115,22 +1115,23 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) {
|
||||
|
||||
if len(cfg.Hosts) != 0 {
|
||||
for domain, anyValue := range cfg.Hosts {
|
||||
if str, ok := anyValue.(string); ok && str == "lan" {
|
||||
hosts, err := utils.ToStringSlice(anyValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(hosts) == 1 && hosts[0] == "lan" {
|
||||
if addrs, err := net.InterfaceAddrs(); err != nil {
|
||||
log.Errorln("insert lan to host error: %s", err)
|
||||
} else {
|
||||
ips := make([]netip.Addr, 0)
|
||||
hosts = make([]string, 0, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsLinkLocalUnicast() {
|
||||
if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
hosts = append(hosts, ipnet.IP.String())
|
||||
}
|
||||
}
|
||||
anyValue = ips
|
||||
}
|
||||
}
|
||||
value, err := resolver.NewHostValue(anyValue)
|
||||
value, err := resolver.NewHostValue(hosts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s is not a valid value", anyValue)
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ require (
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20260105030934-d0c8756d3141
|
||||
github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443
|
||||
github.com/metacubex/tls v0.1.3
|
||||
github.com/metacubex/tls v0.1.4
|
||||
github.com/metacubex/utls v1.8.4
|
||||
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f
|
||||
github.com/mroth/weightedrand/v2 v2.1.0
|
||||
|
||||
+2
-2
@@ -141,8 +141,8 @@ github.com/metacubex/smux v0.0.0-20260105030934-d0c8756d3141 h1:DK2l6m2Fc85H2Bhi
|
||||
github.com/metacubex/smux v0.0.0-20260105030934-d0c8756d3141/go.mod h1:/yI4OiGOSn0SURhZdJF3CbtPg3nwK700bG8TZLMBvAg=
|
||||
github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 h1:H6TnfM12tOoTizYE/qBHH3nEuibIelmHI+BVSxVJr8o=
|
||||
github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/tls v0.1.3 h1:nyjA8GNYGaLVSNRSqWoNNdXSCCFiQABTyrPJmkuSL20=
|
||||
github.com/metacubex/tls v0.1.3/go.mod h1:0XeVdL0cBw+8i5Hqy3lVeP9IyD/LFTq02ExvHM6rzEM=
|
||||
github.com/metacubex/tls v0.1.4 h1:Gm5GrkyMUh52gYOMIAQ1kHIym4v4M3Qb87Wsmd8Kpdc=
|
||||
github.com/metacubex/tls v0.1.4/go.mod h1:0XeVdL0cBw+8i5Hqy3lVeP9IyD/LFTq02ExvHM6rzEM=
|
||||
github.com/metacubex/utls v1.8.4 h1:HmL9nUApDdWSkgUyodfwF6hSjtiwCGGdyhaSpEejKpg=
|
||||
github.com/metacubex/utls v1.8.4/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk=
|
||||
|
||||
Generated
+23
-10
@@ -326,9 +326,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.99"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||
checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
@@ -4469,6 +4469,20 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interprocess"
|
||||
version = "2.3.0"
|
||||
source = "git+https://github.com/libnyanpasu/interprocess.git?branch=fix/linux-32bit-build#33b6a835833ca7fe5276c7dd8a13bfbdac7a80a2"
|
||||
dependencies = [
|
||||
"doctest-file",
|
||||
"futures-core",
|
||||
"libc",
|
||||
"recvmsg",
|
||||
"tokio",
|
||||
"widestring 1.2.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intrusive-collections"
|
||||
version = "0.9.7"
|
||||
@@ -5627,8 +5641,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nyanpasu-ipc"
|
||||
version = "1.4.1"
|
||||
source = "git+https://github.com/libnyanpasu/nyanpasu-service.git#8f2eada8c8625a6453bdb7a6e617455cf04d857d"
|
||||
version = "1.4.2"
|
||||
source = "git+https://github.com/libnyanpasu/nyanpasu-service.git#3742aaaebc475f90d8ed7774aa7b6c6ff263b90e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -5639,7 +5653,7 @@ dependencies = [
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"indexmap 2.12.1",
|
||||
"interprocess",
|
||||
"interprocess 2.3.0 (git+https://github.com/libnyanpasu/interprocess.git?branch=fix/linux-32bit-build)",
|
||||
"nyanpasu-utils",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
@@ -8217,7 +8231,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "serde_yaml_ng"
|
||||
version = "0.10.0"
|
||||
source = "git+https://github.com/libnyanpasu/serde-yaml-ng.git?branch=feat/specta#3078760ab9e9a3a9e18ebb4c5d3e577eb74c4a5c"
|
||||
source = "git+https://github.com/libnyanpasu/serde-yaml-ng.git?branch=feat/specta-update#363da138dc97f90ef0a356f971c2dc1d8fe04c9e"
|
||||
dependencies = [
|
||||
"indexmap 2.12.1",
|
||||
"itoa",
|
||||
@@ -8378,11 +8392,10 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "simd-json"
|
||||
version = "0.15.1"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c962f626b54771990066e5435ec8331d1462576cd2d1e62f24076ae014f92112"
|
||||
checksum = "90daf33666402178ddbb5d595e6d5e6d7d372da948e23ea26762f5a23e02a04e"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"halfbrown",
|
||||
"ref-cast",
|
||||
"serde",
|
||||
@@ -9136,7 +9149,7 @@ name = "tauri-plugin-deep-link"
|
||||
version = "0.1.2"
|
||||
dependencies = [
|
||||
"dirs 6.0.0",
|
||||
"interprocess",
|
||||
"interprocess 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log",
|
||||
"objc2 0.6.3",
|
||||
"once_cell",
|
||||
|
||||
@@ -20,7 +20,7 @@ once_cell = "1"
|
||||
tauri-utils = { version = "2" }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
interprocess = { version = "2" }
|
||||
interprocess = { version = "2", features = ["tokio"] }
|
||||
windows-sys = { version = "0.60", features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_UI_Input_KeyboardAndMouse",
|
||||
|
||||
@@ -97,7 +97,7 @@ sysproxy = { git = "https://github.com/libnyanpasu/sysproxy-rs.git", version = "
|
||||
# Serialization
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||
serde_yaml = { version = "0.10", package = "serde_yaml_ng", branch = "feat/specta", git = "https://github.com/libnyanpasu/serde-yaml-ng.git", features = [
|
||||
serde_yaml = { version = "0.10", package = "serde_yaml_ng", branch = "feat/specta-update", git = "https://github.com/libnyanpasu/serde-yaml-ng.git", features = [
|
||||
"specta",
|
||||
] }
|
||||
bincode = { version = "2.0.1", default-features = false, features = [
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"lodash-es": "4.17.23",
|
||||
"ofetch": "1.5.1",
|
||||
"react": "19.2.4",
|
||||
"swr": "2.3.8"
|
||||
"swr": "2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash-es": "4.17.12",
|
||||
|
||||
@@ -48,11 +48,11 @@
|
||||
"country-emoji": "1.5.6",
|
||||
"dayjs": "1.11.19",
|
||||
"framer-motion": "12.33.0",
|
||||
"i18next": "25.7.3",
|
||||
"i18next": "25.8.4",
|
||||
"jotai": "2.17.1",
|
||||
"json-schema": "0.4.0",
|
||||
"material-react-table": "3.2.1",
|
||||
"monaco-editor": "0.54.0",
|
||||
"monaco-editor": "0.55.1",
|
||||
"mui-color-input": "7.0.0",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
@@ -65,7 +65,7 @@
|
||||
"react-split-grid": "1.0.4",
|
||||
"react-use": "17.6.0",
|
||||
"rxjs": "7.8.2",
|
||||
"swr": "2.3.8",
|
||||
"swr": "2.4.0",
|
||||
"virtua": "0.46.6",
|
||||
"vite-bundle-visualizer": "1.2.1"
|
||||
},
|
||||
@@ -76,9 +76,9 @@
|
||||
"@iconify/json": "2.2.436",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@tanstack/react-query": "5.90.20",
|
||||
"@tanstack/react-router": "1.158.1",
|
||||
"@tanstack/react-router-devtools": "1.158.1",
|
||||
"@tanstack/router-plugin": "1.158.1",
|
||||
"@tanstack/react-router": "1.158.4",
|
||||
"@tanstack/react-router-devtools": "1.158.4",
|
||||
"@tanstack/router-plugin": "1.158.4",
|
||||
"@tauri-apps/plugin-clipboard-manager": "2.3.0",
|
||||
"@tauri-apps/plugin-dialog": "2.4.0",
|
||||
"@tauri-apps/plugin-fs": "2.4.2",
|
||||
@@ -110,6 +110,6 @@
|
||||
"vite-plugin-sass-dts": "1.3.35",
|
||||
"vite-plugin-svgr": "4.5.0",
|
||||
"vite-tsconfig-paths": "5.1.4",
|
||||
"zod": "4.2.1"
|
||||
"zod": "4.3.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ import { type JSONSchema7 } from 'json-schema'
|
||||
import nyanpasuMergeSchema from 'meta-json-schema/schemas/clash-nyanpasu-merge-json-schema.json'
|
||||
import clashMetaSchema from 'meta-json-schema/schemas/meta-json-schema.json'
|
||||
import { type editor } from 'monaco-editor'
|
||||
import * as monaco from 'monaco-editor'
|
||||
import { configureMonacoYaml } from 'monaco-yaml'
|
||||
import { nanoid } from 'nanoid'
|
||||
import { useCallback, useMemo, useRef } from 'react'
|
||||
// schema
|
||||
import { themeMode } from '@/store'
|
||||
import MonacoEditor, { type Monaco } from '@monaco-editor/react'
|
||||
import MonacoEditor from '@monaco-editor/react'
|
||||
import { openThat } from '@nyanpasu/interface'
|
||||
import { cn } from '@nyanpasu/ui'
|
||||
|
||||
@@ -30,10 +31,10 @@ export interface ProfileMonacoViewRef {
|
||||
|
||||
let initd = false
|
||||
|
||||
export const beforeEditorMount = (monaco: Monaco) => {
|
||||
export const beforeEditorMount = () => {
|
||||
if (!initd) {
|
||||
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
|
||||
target: monaco.languages.typescript.ScriptTarget.ES2020,
|
||||
monaco.typescript.javascriptDefaults.setCompilerOptions({
|
||||
target: monaco.typescript.ScriptTarget.ES2020,
|
||||
allowNonTsExtensions: true,
|
||||
allowJs: true,
|
||||
})
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import nyanpasuMergeSchema from 'meta-json-schema/schemas/clash-nyanpasu-merge-json-schema.json'
|
||||
import clashMetaSchema from 'meta-json-schema/schemas/meta-json-schema.json'
|
||||
import * as monaco from 'monaco-editor'
|
||||
import { configureMonacoYaml } from 'monaco-yaml'
|
||||
import { OS } from '@/consts'
|
||||
import { Monaco } from '@monaco-editor/react'
|
||||
|
||||
export const MONACO_FONT_FAMILY =
|
||||
'"Cascadia Code NF",' +
|
||||
@@ -19,13 +19,13 @@ export const MONACO_FONT_FAMILY =
|
||||
|
||||
let initd = false
|
||||
|
||||
export const beforeEditorMount = (monaco: Monaco) => {
|
||||
export const beforeEditorMount = () => {
|
||||
if (initd) {
|
||||
return
|
||||
}
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
|
||||
target: monaco.languages.typescript.ScriptTarget.ES2020,
|
||||
monaco.typescript.javascriptDefaults.setCompilerOptions({
|
||||
target: monaco.typescript.ScriptTarget.ES2020,
|
||||
allowNonTsExtensions: true,
|
||||
allowJs: true,
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution.js'
|
||||
import 'monaco-editor/esm/vs/editor/editor.all.js'
|
||||
import 'monaco-editor/esm/vs/editor/contrib/links/browser/links.js'
|
||||
// language services
|
||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
|
||||
import * as monaco from 'monaco-editor'
|
||||
import 'monaco-editor/esm/vs/language/typescript/monaco.contribution.js'
|
||||
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
|
||||
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
|
||||
|
||||
@@ -70,10 +70,10 @@
|
||||
"cross-env": "10.1.0",
|
||||
"dedent": "1.7.1",
|
||||
"globals": "16.5.0",
|
||||
"knip": "5.83.0",
|
||||
"knip": "5.83.1",
|
||||
"lint-staged": "16.2.7",
|
||||
"npm-run-all2": "8.0.4",
|
||||
"oxlint": "^1.43.0",
|
||||
"oxlint": "1.43.0",
|
||||
"postcss": "8.5.6",
|
||||
"postcss-html": "1.8.1",
|
||||
"postcss-import": "16.1.1",
|
||||
|
||||
Generated
+103
-90
@@ -59,8 +59,8 @@ importers:
|
||||
specifier: 16.5.0
|
||||
version: 16.5.0
|
||||
knip:
|
||||
specifier: 5.83.0
|
||||
version: 5.83.0(@types/node@24.10.11)(typescript@5.9.3)
|
||||
specifier: 5.83.1
|
||||
version: 5.83.1(@types/node@24.10.11)(typescript@5.9.3)
|
||||
lint-staged:
|
||||
specifier: 16.2.7
|
||||
version: 16.2.7
|
||||
@@ -68,7 +68,7 @@ importers:
|
||||
specifier: 8.0.4
|
||||
version: 8.0.4
|
||||
oxlint:
|
||||
specifier: ^1.43.0
|
||||
specifier: 1.43.0
|
||||
version: 1.43.0
|
||||
postcss:
|
||||
specifier: 8.5.6
|
||||
@@ -149,8 +149,8 @@ importers:
|
||||
specifier: 19.2.4
|
||||
version: 19.2.4
|
||||
swr:
|
||||
specifier: 2.3.8
|
||||
version: 2.3.8(react@19.2.4)
|
||||
specifier: 2.4.0
|
||||
version: 2.4.0(react@19.2.4)
|
||||
devDependencies:
|
||||
'@types/lodash-es':
|
||||
specifier: 4.17.12
|
||||
@@ -241,7 +241,7 @@ importers:
|
||||
version: 3.13.18(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@tanstack/router-zod-adapter':
|
||||
specifier: 1.81.5
|
||||
version: 1.81.5(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.2.1)
|
||||
version: 1.81.5(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.3.6)
|
||||
'@tauri-apps/api':
|
||||
specifier: 2.8.0
|
||||
version: 2.8.0
|
||||
@@ -276,8 +276,8 @@ importers:
|
||||
specifier: 12.33.0
|
||||
version: 12.33.0(@emotion/is-prop-valid@1.3.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
i18next:
|
||||
specifier: 25.7.3
|
||||
version: 25.7.3(typescript@5.9.3)
|
||||
specifier: 25.8.4
|
||||
version: 25.8.4(typescript@5.9.3)
|
||||
jotai:
|
||||
specifier: 2.17.1
|
||||
version: 2.17.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.13)(react@19.2.4)
|
||||
@@ -288,8 +288,8 @@ importers:
|
||||
specifier: npm:@greenhat616/material-react-table@4.0.0
|
||||
version: '@greenhat616/material-react-table@4.0.0(ea8a682ce6028a634854fb53683ad162)'
|
||||
monaco-editor:
|
||||
specifier: 0.54.0
|
||||
version: 0.54.0
|
||||
specifier: 0.55.1
|
||||
version: 0.55.1
|
||||
mui-color-input:
|
||||
specifier: 7.0.0
|
||||
version: 7.0.0(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@mui/material@7.3.7(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
@@ -313,7 +313,7 @@ importers:
|
||||
version: 8.2.0(5eba25cbc188b715a2272e829a88aafa)
|
||||
react-i18next:
|
||||
specifier: 15.7.4
|
||||
version: 15.7.4(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)
|
||||
version: 15.7.4(i18next@25.8.4(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)
|
||||
react-markdown:
|
||||
specifier: 10.1.0
|
||||
version: 10.1.0(@types/react@19.2.13)(react@19.2.4)
|
||||
@@ -327,8 +327,8 @@ importers:
|
||||
specifier: 7.8.2
|
||||
version: 7.8.2
|
||||
swr:
|
||||
specifier: 2.3.8
|
||||
version: 2.3.8(react@19.2.4)
|
||||
specifier: 2.4.0
|
||||
version: 2.4.0(react@19.2.4)
|
||||
virtua:
|
||||
specifier: 0.46.6
|
||||
version: 0.46.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.5)
|
||||
@@ -350,19 +350,19 @@ importers:
|
||||
version: 2.2.436
|
||||
'@monaco-editor/react':
|
||||
specifier: 4.7.0
|
||||
version: 4.7.0(monaco-editor@0.54.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@tanstack/react-query':
|
||||
specifier: 5.90.20
|
||||
version: 5.90.20(react@19.2.4)
|
||||
'@tanstack/react-router':
|
||||
specifier: 1.158.1
|
||||
version: 1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
specifier: 1.158.4
|
||||
version: 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@tanstack/react-router-devtools':
|
||||
specifier: 1.158.1
|
||||
version: 1.158.1(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.1)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
specifier: 1.158.4
|
||||
version: 1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.4)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@tanstack/router-plugin':
|
||||
specifier: 1.158.1
|
||||
version: 1.158.1(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.11)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.97.3)(sass@1.97.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||
specifier: 1.158.4
|
||||
version: 1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.11)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.97.3)(sass@1.97.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||
'@tauri-apps/plugin-clipboard-manager':
|
||||
specifier: 2.3.0
|
||||
version: 2.3.0
|
||||
@@ -422,7 +422,7 @@ importers:
|
||||
version: 1.19.19
|
||||
monaco-yaml:
|
||||
specifier: 5.4.0
|
||||
version: 5.4.0(monaco-editor@0.54.0)
|
||||
version: 5.4.0(monaco-editor@0.55.1)
|
||||
nanoid:
|
||||
specifier: 5.1.6
|
||||
version: 5.1.6
|
||||
@@ -457,8 +457,8 @@ importers:
|
||||
specifier: 5.1.4
|
||||
version: 5.1.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.11)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.97.3)(sass@1.97.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))
|
||||
zod:
|
||||
specifier: 4.2.1
|
||||
version: 4.2.1
|
||||
specifier: 4.3.6
|
||||
version: 4.3.6
|
||||
|
||||
frontend/ui:
|
||||
dependencies:
|
||||
@@ -512,7 +512,7 @@ importers:
|
||||
version: 6.0.0(react@19.2.4)
|
||||
react-i18next:
|
||||
specifier: 15.7.4
|
||||
version: 15.7.4(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)
|
||||
version: 15.7.4(i18next@25.8.4(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3)
|
||||
react-use:
|
||||
specifier: 17.6.0
|
||||
version: 17.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
@@ -575,8 +575,8 @@ importers:
|
||||
specifier: 7.7.4
|
||||
version: 7.7.4
|
||||
zod:
|
||||
specifier: 4.2.1
|
||||
version: 4.2.1
|
||||
specifier: 4.3.6
|
||||
version: 4.3.6
|
||||
devDependencies:
|
||||
'@octokit/types':
|
||||
specifier: 16.0.0
|
||||
@@ -612,8 +612,8 @@ importers:
|
||||
specifier: 2.26.22
|
||||
version: 2.26.22
|
||||
undici:
|
||||
specifier: 7.20.0
|
||||
version: 7.20.0
|
||||
specifier: 7.21.0
|
||||
version: 7.21.0
|
||||
yargs:
|
||||
specifier: 18.0.0
|
||||
version: 18.0.0
|
||||
@@ -3366,20 +3366,20 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^18 || ^19
|
||||
|
||||
'@tanstack/react-router-devtools@1.158.1':
|
||||
resolution: {integrity: sha512-H0iTfsLNkadF/JhJnu/pUxlxOiLjE0866vFqXK/7EYVcyYwx2uWQuGxEkyF7a04oXXrbEImAOoXDRBQcZ9T5Zw==}
|
||||
'@tanstack/react-router-devtools@1.158.4':
|
||||
resolution: {integrity: sha512-/EkrrJGTPC7MwLfcYYmZM71ANDMLbwcYvBtDA+48LqHUKal8mpWlaodiWdFFnVQ7ny/unbUxljgdrNV9YZiyFQ==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
'@tanstack/react-router': ^1.158.1
|
||||
'@tanstack/router-core': ^1.158.1
|
||||
'@tanstack/react-router': ^1.158.4
|
||||
'@tanstack/router-core': ^1.158.4
|
||||
react: '>=18.0.0 || >=19.0.0'
|
||||
react-dom: '>=18.0.0 || >=19.0.0'
|
||||
peerDependenciesMeta:
|
||||
'@tanstack/router-core':
|
||||
optional: true
|
||||
|
||||
'@tanstack/react-router@1.158.1':
|
||||
resolution: {integrity: sha512-ZRBhs0tJDPeYGVrBhXPkGs+mOKqKKMM4OfvYSNvWIYZGfs8KQcqxPaN8OnUvKsnAGtzwusVWDpBipqVZWJd0lA==}
|
||||
'@tanstack/react-router@1.158.4':
|
||||
resolution: {integrity: sha512-i15xXumgvpuM+4NSuIwgouGezuj9eHjZsgpTZSQ7E9pa8rYmhZbWnf8xU68qaLmaKIol/e75o/YzVH2QWHs3iQ==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
react: '>=18.0.0 || >=19.0.0'
|
||||
@@ -3410,30 +3410,30 @@ packages:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
'@tanstack/router-core@1.158.1':
|
||||
resolution: {integrity: sha512-8B9X3GzN1JWsqa+OTgg2k+LrayLQYmgtv26b96difyrRS32DaDBvEpU3xXDaLNmi/+zoqG1ffAcDT4D6tyC2hw==}
|
||||
'@tanstack/router-core@1.158.4':
|
||||
resolution: {integrity: sha512-KikgYdyrEFqsjjgv9pMhDTMmASMAyFRvUiKFdQPQtXq3aD1qv/zck4CbA4bfzp9N9nYu/qvWwU1mlYU4u5JeXg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@tanstack/router-devtools-core@1.158.1':
|
||||
resolution: {integrity: sha512-iGCqmIJ5NXMIuyFwJgfikEmRrceT3tmynMTMSuVxFiv9+Dlk1tsp8bsYS+UGhyY4beoASsRnlikAeNAMsCjhwA==}
|
||||
'@tanstack/router-devtools-core@1.158.4':
|
||||
resolution: {integrity: sha512-9MKzstYp/6sNRSwJY2b9ipVW8b8/x1iSFNfLhOJur2tnjB3RhwCDfy0u+to70BrRpBEWeq7jvJoVdP029gzUUg==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
'@tanstack/router-core': ^1.158.1
|
||||
'@tanstack/router-core': ^1.158.4
|
||||
csstype: ^3.0.10
|
||||
peerDependenciesMeta:
|
||||
csstype:
|
||||
optional: true
|
||||
|
||||
'@tanstack/router-generator@1.158.1':
|
||||
resolution: {integrity: sha512-geBpsIxJNvdjw2kt/Ii/j68hIUvfGnra0HKlGrDZw8/Ny4AJ2nnOcszUlZRbuQyxByk05r4lneOShKy5V5MUCQ==}
|
||||
'@tanstack/router-generator@1.158.4':
|
||||
resolution: {integrity: sha512-RQmqMTT0oV8dS/3Glcq9SPzDZqOPyKb/LVFUkNoTfMwW88WyGnQcYqZAkmVk/CGBWWDfwObOUZoGq5jTF7bG8w==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@tanstack/router-plugin@1.158.1':
|
||||
resolution: {integrity: sha512-IPCnf1CBc0jnczuy65+3iBaoABv5TKhOJ1YLzwel4kb9D8Abcq0vF8ooR5FiPmaGnree/z3SvjgHe5eQtgcsSQ==}
|
||||
'@tanstack/router-plugin@1.158.4':
|
||||
resolution: {integrity: sha512-g2sytAhljw6Jd6Klu37OZ75+o+vhiGdbWtnBy/4rYLC4NN6hSnjgJQRI3+h1CI1KQ4EUgsZYZr/hgE1KHoiWYQ==}
|
||||
engines: {node: '>=12'}
|
||||
peerDependencies:
|
||||
'@rsbuild/core': '>=1.0.2'
|
||||
'@tanstack/react-router': ^1.158.1
|
||||
'@tanstack/react-router': ^1.158.4
|
||||
vite: '>=5.0.0 || >=6.0.0 || >=7.0.0'
|
||||
vite-plugin-solid: ^2.11.10
|
||||
webpack: '>=5.92.0'
|
||||
@@ -3791,6 +3791,9 @@ packages:
|
||||
'@types/semver@7.7.1':
|
||||
resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==}
|
||||
|
||||
'@types/trusted-types@2.0.7':
|
||||
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
||||
|
||||
'@types/unist@2.0.10':
|
||||
resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==}
|
||||
|
||||
@@ -4781,8 +4784,8 @@ packages:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
dompurify@3.1.7:
|
||||
resolution: {integrity: sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==}
|
||||
dompurify@3.2.7:
|
||||
resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==}
|
||||
|
||||
domutils@2.8.0:
|
||||
resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
|
||||
@@ -5182,8 +5185,8 @@ packages:
|
||||
hyphenate-style-name@1.1.0:
|
||||
resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
|
||||
|
||||
i18next@25.7.3:
|
||||
resolution: {integrity: sha512-2XaT+HpYGuc2uTExq9TVRhLsso+Dxym6PWaKpn36wfBmTI779OQ7iP/XaZHzrnGyzU4SHpFrTYLKfVyBfAhVNA==}
|
||||
i18next@25.8.4:
|
||||
resolution: {integrity: sha512-a9A0MnUjKvzjEN/26ZY1okpra9kA8MEwzYEz1BNm+IyxUKPRH6ihf0p7vj8YvULwZHKHl3zkJ6KOt4hewxBecQ==}
|
||||
peerDependencies:
|
||||
typescript: ^5
|
||||
peerDependenciesMeta:
|
||||
@@ -5461,8 +5464,8 @@ packages:
|
||||
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
knip@5.83.0:
|
||||
resolution: {integrity: sha512-FfmaHMntpZB13B1oJQMSs1hTOZxd0TOn+FYB3oWEI02XlxTW3RH4H7d8z5Us3g0ziHCYyl7z0B1xi8ENP3QEKA==}
|
||||
knip@5.83.1:
|
||||
resolution: {integrity: sha512-av3ZG/Nui6S/BNL8Tmj12yGxYfTnwWnslouW97m40him7o8MwiMjZBY9TPvlEWUci45aVId0/HbgTwSKIDGpMw==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -5819,8 +5822,8 @@ packages:
|
||||
mlly@1.8.0:
|
||||
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
||||
|
||||
monaco-editor@0.54.0:
|
||||
resolution: {integrity: sha512-hx45SEUoLatgWxHKCmlLJH81xBo0uXP4sRkESUpmDQevfi+e7K1VuiSprK6UpQ8u4zOcKNiH0pMvHvlMWA/4cw==}
|
||||
monaco-editor@0.55.1:
|
||||
resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==}
|
||||
|
||||
monaco-languageserver-types@0.4.0:
|
||||
resolution: {integrity: sha512-QQ3BZiU5LYkJElGncSNb5AKoJ/LCs6YBMCJMAz9EA7v+JaOdn3kx2cXpPTcZfKA5AEsR0vc97sAw+5mdNhVBmw==}
|
||||
@@ -6958,8 +6961,8 @@ packages:
|
||||
svg-tags@1.0.0:
|
||||
resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
|
||||
|
||||
swr@2.3.8:
|
||||
resolution: {integrity: sha512-gaCPRVoMq8WGDcWj9p4YWzCMPHzE0WNl6W8ADIx9c3JBEIdMkJGMzW+uzXvxHMltwcYACr9jP+32H8/hgwMR7w==}
|
||||
swr@2.4.0:
|
||||
resolution: {integrity: sha512-sUlC20T8EOt1pHmDiqueUWMmRRX03W7w5YxovWX7VR2KHEPCTMly85x05vpkP5i6Bu4h44ePSMD9Tc+G2MItFw==}
|
||||
peerDependencies:
|
||||
react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
@@ -7109,8 +7112,8 @@ packages:
|
||||
resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==}
|
||||
engines: {node: '>=14.0'}
|
||||
|
||||
undici@7.20.0:
|
||||
resolution: {integrity: sha512-MJZrkjyd7DeC+uPZh+5/YaMDxFiiEEaDgbUSVMXayofAkDWF1088CDo+2RPg7B1BuS1qf1vgNE7xqwPxE0DuSQ==}
|
||||
undici@7.21.0:
|
||||
resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==}
|
||||
engines: {node: '>=20.18.1'}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.1:
|
||||
@@ -7506,6 +7509,9 @@ packages:
|
||||
zod@4.2.1:
|
||||
resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==}
|
||||
|
||||
zod@4.3.6:
|
||||
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||
|
||||
zwitch@2.0.4:
|
||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||
|
||||
@@ -8921,10 +8927,10 @@ snapshots:
|
||||
dependencies:
|
||||
state-local: 1.0.7
|
||||
|
||||
'@monaco-editor/react@4.7.0(monaco-editor@0.54.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
'@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
dependencies:
|
||||
'@monaco-editor/loader': 1.5.0
|
||||
monaco-editor: 0.54.0
|
||||
monaco-editor: 0.55.1
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
|
||||
@@ -10357,22 +10363,22 @@ snapshots:
|
||||
'@tanstack/query-core': 5.90.20
|
||||
react: 19.2.4
|
||||
|
||||
'@tanstack/react-router-devtools@1.158.1(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.1)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
'@tanstack/react-router-devtools@1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.158.4)(csstype@3.2.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
dependencies:
|
||||
'@tanstack/react-router': 1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@tanstack/router-devtools-core': 1.158.1(@tanstack/router-core@1.158.1)(csstype@3.2.3)
|
||||
'@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@tanstack/router-devtools-core': 1.158.4(@tanstack/router-core@1.158.4)(csstype@3.2.3)
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
optionalDependencies:
|
||||
'@tanstack/router-core': 1.158.1
|
||||
'@tanstack/router-core': 1.158.4
|
||||
transitivePeerDependencies:
|
||||
- csstype
|
||||
|
||||
'@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
'@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||
dependencies:
|
||||
'@tanstack/history': 1.154.14
|
||||
'@tanstack/react-store': 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@tanstack/router-core': 1.158.1
|
||||
'@tanstack/router-core': 1.158.4
|
||||
isbot: 5.1.28
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
@@ -10404,7 +10410,7 @@ snapshots:
|
||||
react: 19.2.4
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
|
||||
'@tanstack/router-core@1.158.1':
|
||||
'@tanstack/router-core@1.158.4':
|
||||
dependencies:
|
||||
'@tanstack/history': 1.154.14
|
||||
'@tanstack/store': 0.8.0
|
||||
@@ -10414,18 +10420,18 @@ snapshots:
|
||||
tiny-invariant: 1.3.3
|
||||
tiny-warning: 1.0.3
|
||||
|
||||
'@tanstack/router-devtools-core@1.158.1(@tanstack/router-core@1.158.1)(csstype@3.2.3)':
|
||||
'@tanstack/router-devtools-core@1.158.4(@tanstack/router-core@1.158.4)(csstype@3.2.3)':
|
||||
dependencies:
|
||||
'@tanstack/router-core': 1.158.1
|
||||
'@tanstack/router-core': 1.158.4
|
||||
clsx: 2.1.1
|
||||
goober: 2.1.16(csstype@3.2.3)
|
||||
tiny-invariant: 1.3.3
|
||||
optionalDependencies:
|
||||
csstype: 3.2.3
|
||||
|
||||
'@tanstack/router-generator@1.158.1':
|
||||
'@tanstack/router-generator@1.158.4':
|
||||
dependencies:
|
||||
'@tanstack/router-core': 1.158.1
|
||||
'@tanstack/router-core': 1.158.4
|
||||
'@tanstack/router-utils': 1.158.0
|
||||
'@tanstack/virtual-file-routes': 1.154.7
|
||||
prettier: 3.8.1
|
||||
@@ -10436,7 +10442,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@tanstack/router-plugin@1.158.1(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.11)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.97.3)(sass@1.97.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))':
|
||||
'@tanstack/router-plugin@1.158.4(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@7.3.1(@types/node@24.10.11)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.97.3)(sass@1.97.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
'@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.0)
|
||||
@@ -10444,15 +10450,15 @@ snapshots:
|
||||
'@babel/template': 7.28.6
|
||||
'@babel/traverse': 7.29.0
|
||||
'@babel/types': 7.29.0
|
||||
'@tanstack/router-core': 1.158.1
|
||||
'@tanstack/router-generator': 1.158.1
|
||||
'@tanstack/router-core': 1.158.4
|
||||
'@tanstack/router-generator': 1.158.4
|
||||
'@tanstack/router-utils': 1.158.0
|
||||
'@tanstack/virtual-file-routes': 1.154.7
|
||||
chokidar: 3.6.0
|
||||
unplugin: 2.3.11
|
||||
zod: 3.25.76
|
||||
optionalDependencies:
|
||||
'@tanstack/react-router': 1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
'@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
vite: 7.3.1(@types/node@24.10.11)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.97.3)(sass@1.97.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -10471,10 +10477,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.2.1)':
|
||||
'@tanstack/router-zod-adapter@1.81.5(@tanstack/react-router@1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@tanstack/react-router': 1.158.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
zod: 4.2.1
|
||||
'@tanstack/react-router': 1.158.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
zod: 4.3.6
|
||||
|
||||
'@tanstack/store@0.8.0': {}
|
||||
|
||||
@@ -10814,6 +10820,9 @@ snapshots:
|
||||
|
||||
'@types/semver@7.7.1': {}
|
||||
|
||||
'@types/trusted-types@2.0.7':
|
||||
optional: true
|
||||
|
||||
'@types/unist@2.0.10': {}
|
||||
|
||||
'@types/unist@3.0.2': {}
|
||||
@@ -11858,7 +11867,9 @@ snapshots:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
|
||||
dompurify@3.1.7: {}
|
||||
dompurify@3.2.7:
|
||||
optionalDependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
|
||||
domutils@2.8.0:
|
||||
dependencies:
|
||||
@@ -12290,7 +12301,7 @@ snapshots:
|
||||
|
||||
hyphenate-style-name@1.1.0: {}
|
||||
|
||||
i18next@25.7.3(typescript@5.9.3):
|
||||
i18next@25.8.4(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.4
|
||||
optionalDependencies:
|
||||
@@ -12492,7 +12503,7 @@ snapshots:
|
||||
|
||||
kind-of@6.0.3: {}
|
||||
|
||||
knip@5.83.0(@types/node@24.10.11)(typescript@5.9.3):
|
||||
knip@5.83.1(@types/node@24.10.11)(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@nodelib/fs.walk': 1.2.8
|
||||
'@types/node': 24.10.11
|
||||
@@ -12967,9 +12978,9 @@ snapshots:
|
||||
pkg-types: 1.3.1
|
||||
ufo: 1.6.1
|
||||
|
||||
monaco-editor@0.54.0:
|
||||
monaco-editor@0.55.1:
|
||||
dependencies:
|
||||
dompurify: 3.1.7
|
||||
dompurify: 3.2.7
|
||||
marked: 14.0.0
|
||||
|
||||
monaco-languageserver-types@0.4.0:
|
||||
@@ -12984,18 +12995,18 @@ snapshots:
|
||||
|
||||
monaco-types@0.1.0: {}
|
||||
|
||||
monaco-worker-manager@2.0.1(monaco-editor@0.54.0):
|
||||
monaco-worker-manager@2.0.1(monaco-editor@0.55.1):
|
||||
dependencies:
|
||||
monaco-editor: 0.54.0
|
||||
monaco-editor: 0.55.1
|
||||
|
||||
monaco-yaml@5.4.0(monaco-editor@0.54.0):
|
||||
monaco-yaml@5.4.0(monaco-editor@0.55.1):
|
||||
dependencies:
|
||||
jsonc-parser: 3.3.1
|
||||
monaco-editor: 0.54.0
|
||||
monaco-editor: 0.55.1
|
||||
monaco-languageserver-types: 0.4.0
|
||||
monaco-marker-data-provider: 1.2.3
|
||||
monaco-types: 0.1.0
|
||||
monaco-worker-manager: 2.0.1(monaco-editor@0.54.0)
|
||||
monaco-worker-manager: 2.0.1(monaco-editor@0.55.1)
|
||||
path-browserify: 1.0.1
|
||||
prettier: 3.8.1
|
||||
vscode-languageserver-textdocument: 1.0.12
|
||||
@@ -13444,11 +13455,11 @@ snapshots:
|
||||
dependencies:
|
||||
react: 19.2.4
|
||||
|
||||
react-i18next@15.7.4(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3):
|
||||
react-i18next@15.7.4(i18next@25.8.4(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.28.3
|
||||
html-parse-stringify: 3.0.1
|
||||
i18next: 25.7.3(typescript@5.9.3)
|
||||
i18next: 25.8.4(typescript@5.9.3)
|
||||
react: 19.2.4
|
||||
optionalDependencies:
|
||||
react-dom: 19.2.4(react@19.2.4)
|
||||
@@ -14125,7 +14136,7 @@ snapshots:
|
||||
|
||||
svg-tags@1.0.0: {}
|
||||
|
||||
swr@2.3.8(react@19.2.4):
|
||||
swr@2.4.0(react@19.2.4):
|
||||
dependencies:
|
||||
dequal: 2.0.3
|
||||
react: 19.2.4
|
||||
@@ -14289,7 +14300,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@fastify/busboy': 2.1.1
|
||||
|
||||
undici@7.20.0: {}
|
||||
undici@7.21.0: {}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.1: {}
|
||||
|
||||
@@ -14682,4 +14693,6 @@ snapshots:
|
||||
|
||||
zod@4.2.1: {}
|
||||
|
||||
zod@4.3.6: {}
|
||||
|
||||
zwitch@2.0.4: {}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"filesize": "11.0.13",
|
||||
"p-retry": "7.1.1",
|
||||
"semver": "7.7.4",
|
||||
"zod": "4.2.1"
|
||||
"zod": "4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@octokit/types": "16.0.0",
|
||||
@@ -24,7 +24,7 @@
|
||||
"picocolors": "1.1.1",
|
||||
"tar": "7.5.7",
|
||||
"telegram": "2.26.22",
|
||||
"undici": "7.20.0",
|
||||
"undici": "7.21.0",
|
||||
"yargs": "18.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -785,6 +785,6 @@
|
||||
lockdep_is_held(&nf_ct_ecache_mutex));
|
||||
- WARN_ON_ONCE(notify);
|
||||
+ /* WARN_ON_ONCE(notify); */
|
||||
rcu_assign_pointer(net->ct.nf_conntrack_event_cb, new);
|
||||
mutex_unlock(&nf_ct_ecache_mutex);
|
||||
}
|
||||
if (notify != NULL) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock;
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/enfein/mieru/v3/pkg/common"
|
||||
"github.com/enfein/mieru/v3/pkg/protocol"
|
||||
"github.com/enfein/mieru/v3/pkg/stderror"
|
||||
"github.com/enfein/mieru/v3/pkg/trafficpattern"
|
||||
)
|
||||
|
||||
// ValidateClientConfigSingleProfile validates a single client config profile.
|
||||
@@ -79,7 +80,7 @@ func ValidateClientConfigSingleProfile(profile *pb.ClientProfile) error {
|
||||
if profile.GetMtu() != 0 && (profile.GetMtu() < 1280 || profile.GetMtu() > 1500) {
|
||||
return fmt.Errorf("MTU value %d is out of range, valid range is [1280, 1500]", profile.GetMtu())
|
||||
}
|
||||
if err := ValidateTrafficPattern(profile.GetTrafficPattern()); err != nil {
|
||||
if err := trafficpattern.Validate(profile.GetTrafficPattern()); err != nil {
|
||||
return fmt.Errorf("invalid traffic pattern: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
// Copyright (C) 2026 mieru authors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package appctlcommon
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
pb "github.com/enfein/mieru/v3/pkg/appctl/appctlpb"
|
||||
)
|
||||
|
||||
func ValidateTrafficPattern(pattern *pb.TrafficPattern) error {
|
||||
if pattern == nil {
|
||||
return nil
|
||||
}
|
||||
if err := validateTCPFragment(pattern.GetTcpFragment()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateNoncePattern(pattern.GetNonce()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateTCPFragment(fragment *pb.TCPFragment) error {
|
||||
if fragment == nil {
|
||||
return nil
|
||||
}
|
||||
if fragment.MaxSleepMs != nil {
|
||||
if fragment.GetMaxSleepMs() < 0 {
|
||||
return fmt.Errorf("TCPFragment maxSleepMs %d is negative", fragment.GetMaxSleepMs())
|
||||
}
|
||||
if fragment.GetMaxSleepMs() > 100 {
|
||||
return fmt.Errorf("TCPFragment maxSleepMs %d exceeds maximum value 100", fragment.GetMaxSleepMs())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateNoncePattern(nonce *pb.NoncePattern) error {
|
||||
if nonce == nil {
|
||||
return nil
|
||||
}
|
||||
if nonce.MinLen != nil {
|
||||
if nonce.GetMinLen() < 0 {
|
||||
return fmt.Errorf("NoncePattern minLen %d is negative", nonce.GetMinLen())
|
||||
}
|
||||
if nonce.GetMinLen() > 12 {
|
||||
return fmt.Errorf("NoncePattern minLen %d exceeds maximum value 12", nonce.GetMinLen())
|
||||
}
|
||||
}
|
||||
if nonce.MaxLen != nil {
|
||||
if nonce.GetMaxLen() < 0 {
|
||||
return fmt.Errorf("NoncePattern maxLen %d is negative", nonce.GetMaxLen())
|
||||
}
|
||||
if nonce.GetMaxLen() > 12 {
|
||||
return fmt.Errorf("NoncePattern maxLen %d exceeds maximum value 12", nonce.GetMaxLen())
|
||||
}
|
||||
}
|
||||
if nonce.MinLen != nil && nonce.MaxLen != nil {
|
||||
if nonce.GetMinLen() > nonce.GetMaxLen() {
|
||||
return fmt.Errorf("NoncePattern minLen %d is greater than maxLen %d", nonce.GetMinLen(), nonce.GetMaxLen())
|
||||
}
|
||||
}
|
||||
for i, hexStr := range nonce.GetCustomHexStrings() {
|
||||
decoded, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("NoncePattern customHexStrings[%d] %q is not a valid hex string: %w", i, hexStr, err)
|
||||
}
|
||||
if len(decoded) > 12 {
|
||||
return fmt.Errorf("NoncePattern customHexStrings[%d] decoded length %d exceeds maximum 12 bytes", i, len(decoded))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
// Copyright (C) 2026 mieru authors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package appctlcommon
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
pb "github.com/enfein/mieru/v3/pkg/appctl/appctlpb"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestValidateTrafficPattern(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
pattern *pb.TrafficPattern
|
||||
wantErrString string
|
||||
}{
|
||||
{
|
||||
name: "nil_pattern",
|
||||
pattern: nil,
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "empty_pattern",
|
||||
pattern: &pb.TrafficPattern{},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "valid_tcp_fragment",
|
||||
pattern: &pb.TrafficPattern{
|
||||
TcpFragment: &pb.TCPFragment{
|
||||
Enable: proto.Bool(true),
|
||||
MaxSleepMs: proto.Int32(100),
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "tcp_fragment_max_sleep_exceeds_100",
|
||||
pattern: &pb.TrafficPattern{
|
||||
TcpFragment: &pb.TCPFragment{
|
||||
Enable: proto.Bool(true),
|
||||
MaxSleepMs: proto.Int32(101),
|
||||
},
|
||||
},
|
||||
wantErrString: "exceeds maximum value 100",
|
||||
},
|
||||
{
|
||||
name: "tcp_fragment_max_sleep_negative",
|
||||
pattern: &pb.TrafficPattern{
|
||||
TcpFragment: &pb.TCPFragment{
|
||||
MaxSleepMs: proto.Int32(-1),
|
||||
},
|
||||
},
|
||||
wantErrString: "is negative",
|
||||
},
|
||||
{
|
||||
name: "valid_nonce_pattern",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
MinLen: proto.Int32(12),
|
||||
MaxLen: proto.Int32(12),
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "nonce_max_len_exceeds_12",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
MaxLen: proto.Int32(13),
|
||||
},
|
||||
},
|
||||
wantErrString: "maxLen 13 exceeds maximum value 12",
|
||||
},
|
||||
{
|
||||
name: "nonce_min_len_exceeds_12",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
MinLen: proto.Int32(13),
|
||||
},
|
||||
},
|
||||
wantErrString: "minLen 13 exceeds maximum value 12",
|
||||
},
|
||||
{
|
||||
name: "nonce_max_len_negative",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
MaxLen: proto.Int32(-1),
|
||||
},
|
||||
},
|
||||
wantErrString: "maxLen -1 is negative",
|
||||
},
|
||||
{
|
||||
name: "nonce_min_len_negative",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
MinLen: proto.Int32(-1),
|
||||
},
|
||||
},
|
||||
wantErrString: "minLen -1 is negative",
|
||||
},
|
||||
{
|
||||
name: "nonce_min_len_greater_than_max_len",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
MinLen: proto.Int32(8),
|
||||
MaxLen: proto.Int32(4),
|
||||
},
|
||||
},
|
||||
wantErrString: "minLen 8 is greater than maxLen 4",
|
||||
},
|
||||
{
|
||||
name: "valid_custom_hex_strings",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
Type: pb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"00010203", "aabbccdd"},
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "valid_custom_hex_strings_max_length",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
Type: pb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"000102030405060708090a0b"},
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "custom_hex_string_exceeds_12_bytes",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
Type: pb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"000102030405060708090a0b0c"},
|
||||
},
|
||||
},
|
||||
wantErrString: "exceeds maximum 12 bytes",
|
||||
},
|
||||
{
|
||||
name: "custom_hex_string_invalid",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
Type: pb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"not_valid_hex"},
|
||||
},
|
||||
},
|
||||
wantErrString: "is not a valid hex string",
|
||||
},
|
||||
{
|
||||
name: "custom_hex_string_odd_length",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Nonce: &pb.NoncePattern{
|
||||
Type: pb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"abc"},
|
||||
},
|
||||
},
|
||||
wantErrString: "is not a valid hex string",
|
||||
},
|
||||
{
|
||||
name: "valid_full_pattern",
|
||||
pattern: &pb.TrafficPattern{
|
||||
Seed: proto.Int32(12345),
|
||||
TcpFragment: &pb.TCPFragment{
|
||||
Enable: proto.Bool(true),
|
||||
MaxSleepMs: proto.Int32(50),
|
||||
},
|
||||
Nonce: &pb.NoncePattern{
|
||||
Type: pb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
ApplyToAllUDPPacket: proto.Bool(true),
|
||||
MinLen: proto.Int32(4),
|
||||
MaxLen: proto.Int32(8),
|
||||
CustomHexStrings: []string{"00010203"},
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
err := ValidateTrafficPattern(c.pattern)
|
||||
if c.wantErrString == "" {
|
||||
if err != nil {
|
||||
t.Errorf("ValidateTrafficPattern() returned unexpected error: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err == nil {
|
||||
t.Errorf("ValidateTrafficPattern() expected error to contain %q, got nil", c.wantErrString)
|
||||
} else if !strings.Contains(err.Error(), c.wantErrString) {
|
||||
t.Errorf("ValidateTrafficPattern() error = %q, want error to contain %q", err.Error(), c.wantErrString)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import (
|
||||
"github.com/enfein/mieru/v3/pkg/protocol"
|
||||
"github.com/enfein/mieru/v3/pkg/socks5"
|
||||
"github.com/enfein/mieru/v3/pkg/stderror"
|
||||
"github.com/enfein/mieru/v3/pkg/trafficpattern"
|
||||
"github.com/enfein/mieru/v3/pkg/version"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
@@ -656,7 +657,7 @@ func ValidateServerConfigPatch(patch *pb.ServerConfig) error {
|
||||
return fmt.Errorf("metrics logging interval %q is less than 1 second", patch.GetAdvancedSettings().GetMetricsLoggingInterval())
|
||||
}
|
||||
}
|
||||
if err := appctlcommon.ValidateTrafficPattern(patch.GetTrafficPattern()); err != nil {
|
||||
if err := trafficpattern.Validate(patch.GetTrafficPattern()); err != nil {
|
||||
return fmt.Errorf("invalid traffic pattern: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
package trafficpattern
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
@@ -26,30 +28,78 @@ import (
|
||||
|
||||
// Config stores the traffic pattern configuration.
|
||||
type Config struct {
|
||||
origin *appctlpb.TrafficPattern
|
||||
original *appctlpb.TrafficPattern
|
||||
effective *appctlpb.TrafficPattern
|
||||
}
|
||||
|
||||
// NewConfig creates a new traffic pattern configuration from a protobuf message.
|
||||
// Assume the origin protobuf message is valid.
|
||||
func NewConfig(origin *appctlpb.TrafficPattern) *Config {
|
||||
if origin == nil {
|
||||
// It assumes the original protobuf message is valid.
|
||||
func NewConfig(original *appctlpb.TrafficPattern) *Config {
|
||||
if original == nil {
|
||||
panic("TrafficPattern is nil")
|
||||
}
|
||||
c := &Config{
|
||||
origin: origin,
|
||||
effective: proto.Clone(origin).(*appctlpb.TrafficPattern),
|
||||
original: original,
|
||||
effective: proto.Clone(original).(*appctlpb.TrafficPattern),
|
||||
}
|
||||
c.generateImplicitTrafficPattern()
|
||||
return c
|
||||
}
|
||||
|
||||
// Original returns the original traffic pattern.
|
||||
func (c *Config) Original() *appctlpb.TrafficPattern {
|
||||
return c.original
|
||||
}
|
||||
|
||||
// Effective returns the effective traffic pattern.
|
||||
func (c *Config) Effective() *appctlpb.TrafficPattern {
|
||||
return c.effective
|
||||
}
|
||||
|
||||
// Encode returns the base64 encoded string of the traffic pattern
|
||||
// from the protobuf message binary.
|
||||
func Encode(pattern *appctlpb.TrafficPattern) string {
|
||||
b, err := proto.Marshal(pattern)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
// Decode decodes the base64 encoded string of the traffic pattern
|
||||
// into the protobuf message.
|
||||
func Decode(encoded string) (*appctlpb.TrafficPattern, error) {
|
||||
b, err := base64.StdEncoding.DecodeString(encoded)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decode base64 string failed: %w", err)
|
||||
}
|
||||
pattern := &appctlpb.TrafficPattern{}
|
||||
if err := proto.Unmarshal(b, pattern); err != nil {
|
||||
return nil, fmt.Errorf("proto.Unmarshal() failed: %w", err)
|
||||
}
|
||||
return pattern, nil
|
||||
}
|
||||
|
||||
// Validate validates the traffic pattern protobuf message.
|
||||
func Validate(pattern *appctlpb.TrafficPattern) error {
|
||||
if pattern == nil {
|
||||
return nil
|
||||
}
|
||||
if err := validateTCPFragment(pattern.GetTcpFragment()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateNoncePattern(pattern.GetNonce()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) generateImplicitTrafficPattern() {
|
||||
seed := int(c.origin.GetSeed())
|
||||
if c.origin.Seed == nil {
|
||||
seed := int(c.original.GetSeed())
|
||||
if c.original.Seed == nil {
|
||||
seed = rng.FixedIntVH(math.MaxInt32)
|
||||
}
|
||||
unlockAll := c.origin.GetUnlockAll()
|
||||
unlockAll := c.original.GetUnlockAll()
|
||||
c.generateTCPFragment(seed, unlockAll)
|
||||
c.generateNoncePattern(seed, unlockAll)
|
||||
}
|
||||
@@ -60,7 +110,7 @@ func (c *Config) generateTCPFragment(seed int, unlockAll bool) {
|
||||
}
|
||||
f := c.effective.TcpFragment
|
||||
|
||||
if c.origin.TcpFragment == nil || c.origin.TcpFragment.Enable == nil {
|
||||
if c.original.TcpFragment == nil || c.original.TcpFragment.Enable == nil {
|
||||
if unlockAll {
|
||||
f.Enable = proto.Bool(rng.FixedInt(2, fmt.Sprintf("%d:tcpFragment.enable", seed)) == 1)
|
||||
} else {
|
||||
@@ -68,7 +118,7 @@ func (c *Config) generateTCPFragment(seed int, unlockAll bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if c.origin.TcpFragment == nil || c.origin.TcpFragment.MaxSleepMs == nil {
|
||||
if c.original.TcpFragment == nil || c.original.TcpFragment.MaxSleepMs == nil {
|
||||
maxRange := 100
|
||||
// Generate a random number in [1, 100]
|
||||
f.MaxSleepMs = proto.Int32(int32(rng.FixedInt(maxRange, fmt.Sprintf("%d:tcpFragment.maxSleepMs", seed))) + 1)
|
||||
@@ -81,7 +131,7 @@ func (c *Config) generateNoncePattern(seed int, unlockAll bool) {
|
||||
}
|
||||
n := c.effective.Nonce
|
||||
|
||||
if c.origin.Nonce == nil || c.origin.Nonce.Type == nil {
|
||||
if c.original.Nonce == nil || c.original.Nonce.Type == nil {
|
||||
// Never generate NONCE_TYPE_FIXED (3) since it requires customHexStrings.
|
||||
if unlockAll {
|
||||
// Generate a random number in [0, 2]
|
||||
@@ -94,7 +144,7 @@ func (c *Config) generateNoncePattern(seed int, unlockAll bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if c.origin.Nonce == nil || c.origin.Nonce.ApplyToAllUDPPacket == nil {
|
||||
if c.original.Nonce == nil || c.original.Nonce.ApplyToAllUDPPacket == nil {
|
||||
if unlockAll {
|
||||
n.ApplyToAllUDPPacket = proto.Bool(rng.FixedInt(2, fmt.Sprintf("%d:nonce.applyToAllUDPPacket", seed)) == 1)
|
||||
} else {
|
||||
@@ -102,7 +152,7 @@ func (c *Config) generateNoncePattern(seed int, unlockAll bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if c.origin.Nonce == nil || c.origin.Nonce.MinLen == nil {
|
||||
if c.original.Nonce == nil || c.original.Nonce.MinLen == nil {
|
||||
if unlockAll {
|
||||
// Generate a random number in [0, 12]
|
||||
minRange := 13
|
||||
@@ -114,8 +164,60 @@ func (c *Config) generateNoncePattern(seed int, unlockAll bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if c.origin.Nonce == nil || c.origin.Nonce.MaxLen == nil {
|
||||
if c.original.Nonce == nil || c.original.Nonce.MaxLen == nil {
|
||||
minLen := int(n.GetMinLen())
|
||||
n.MaxLen = proto.Int32(int32(minLen + rng.FixedInt(13-minLen, fmt.Sprintf("%d:nonce.maxLen", seed))))
|
||||
}
|
||||
}
|
||||
|
||||
func validateTCPFragment(fragment *appctlpb.TCPFragment) error {
|
||||
if fragment == nil {
|
||||
return nil
|
||||
}
|
||||
if fragment.MaxSleepMs != nil {
|
||||
if fragment.GetMaxSleepMs() < 0 {
|
||||
return fmt.Errorf("TCPFragment maxSleepMs %d is negative", fragment.GetMaxSleepMs())
|
||||
}
|
||||
if fragment.GetMaxSleepMs() > 100 {
|
||||
return fmt.Errorf("TCPFragment maxSleepMs %d exceeds maximum value 100", fragment.GetMaxSleepMs())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateNoncePattern(nonce *appctlpb.NoncePattern) error {
|
||||
if nonce == nil {
|
||||
return nil
|
||||
}
|
||||
if nonce.MinLen != nil {
|
||||
if nonce.GetMinLen() < 0 {
|
||||
return fmt.Errorf("NoncePattern minLen %d is negative", nonce.GetMinLen())
|
||||
}
|
||||
if nonce.GetMinLen() > 12 {
|
||||
return fmt.Errorf("NoncePattern minLen %d exceeds maximum value 12", nonce.GetMinLen())
|
||||
}
|
||||
}
|
||||
if nonce.MaxLen != nil {
|
||||
if nonce.GetMaxLen() < 0 {
|
||||
return fmt.Errorf("NoncePattern maxLen %d is negative", nonce.GetMaxLen())
|
||||
}
|
||||
if nonce.GetMaxLen() > 12 {
|
||||
return fmt.Errorf("NoncePattern maxLen %d exceeds maximum value 12", nonce.GetMaxLen())
|
||||
}
|
||||
}
|
||||
if nonce.MinLen != nil && nonce.MaxLen != nil {
|
||||
if nonce.GetMinLen() > nonce.GetMaxLen() {
|
||||
return fmt.Errorf("NoncePattern minLen %d is greater than maxLen %d", nonce.GetMinLen(), nonce.GetMaxLen())
|
||||
}
|
||||
}
|
||||
for i, hexStr := range nonce.GetCustomHexStrings() {
|
||||
decoded, err := hex.DecodeString(hexStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("NoncePattern customHexStrings[%d] %q is not a valid hex string: %w", i, hexStr, err)
|
||||
}
|
||||
if len(decoded) > 12 {
|
||||
return fmt.Errorf("NoncePattern customHexStrings[%d] decoded length %d exceeds maximum 12 bytes", i, len(decoded))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package trafficpattern
|
||||
|
||||
import (
|
||||
mrand "math/rand"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/enfein/mieru/v3/pkg/appctl/appctlpb"
|
||||
@@ -209,3 +210,246 @@ func TestMinLenMaxLen(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecode(t *testing.T) {
|
||||
origin := &appctlpb.TrafficPattern{
|
||||
UnlockAll: proto.Bool(true),
|
||||
TcpFragment: &appctlpb.TCPFragment{
|
||||
Enable: proto.Bool(true),
|
||||
MaxSleepMs: proto.Int32(50),
|
||||
},
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
Type: appctlpb.NonceType_NONCE_TYPE_PRINTABLE.Enum(),
|
||||
ApplyToAllUDPPacket: proto.Bool(true),
|
||||
MinLen: proto.Int32(6),
|
||||
MaxLen: proto.Int32(8),
|
||||
},
|
||||
}
|
||||
|
||||
encoded := Encode(origin)
|
||||
|
||||
if encoded == "" {
|
||||
t.Fatal("Encode() returned empty string")
|
||||
}
|
||||
t.Logf("Encoded traffic pattern: %s", encoded)
|
||||
|
||||
restored, err := Decode(encoded)
|
||||
if err != nil {
|
||||
t.Fatalf("Decode() failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify restored values match effective config
|
||||
if restored.GetSeed() != origin.GetSeed() {
|
||||
t.Errorf("seed mismatch: expected %d, got %d", origin.GetSeed(), restored.GetSeed())
|
||||
}
|
||||
if restored.GetUnlockAll() != origin.GetUnlockAll() {
|
||||
t.Errorf("unlockAll mismatch: expected %v, got %v", origin.GetUnlockAll(), restored.GetUnlockAll())
|
||||
}
|
||||
if restored.TcpFragment.GetEnable() != origin.TcpFragment.GetEnable() {
|
||||
t.Errorf("tcpFragment.enable mismatch: expected %v, got %v", origin.TcpFragment.GetEnable(), restored.TcpFragment.GetEnable())
|
||||
}
|
||||
if restored.TcpFragment.GetMaxSleepMs() != origin.TcpFragment.GetMaxSleepMs() {
|
||||
t.Errorf("tcpFragment.maxSleepMs mismatch: expected %d, got %d", origin.TcpFragment.GetMaxSleepMs(), restored.TcpFragment.GetMaxSleepMs())
|
||||
}
|
||||
if restored.Nonce.GetType() != origin.Nonce.GetType() {
|
||||
t.Errorf("nonce.type mismatch: expected %v, got %v", origin.Nonce.GetType(), restored.Nonce.GetType())
|
||||
}
|
||||
if restored.Nonce.GetApplyToAllUDPPacket() != origin.Nonce.GetApplyToAllUDPPacket() {
|
||||
t.Errorf("nonce.applyToAllUDPPacket mismatch: expected %v, got %v", origin.Nonce.GetApplyToAllUDPPacket(), restored.Nonce.GetApplyToAllUDPPacket())
|
||||
}
|
||||
if restored.Nonce.GetMinLen() != origin.Nonce.GetMinLen() {
|
||||
t.Errorf("nonce.minLen mismatch: expected %d, got %d", origin.Nonce.GetMinLen(), restored.Nonce.GetMinLen())
|
||||
}
|
||||
if restored.Nonce.GetMaxLen() != origin.Nonce.GetMaxLen() {
|
||||
t.Errorf("nonce.maxLen mismatch: expected %d, got %d", origin.Nonce.GetMaxLen(), restored.Nonce.GetMaxLen())
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateTrafficPattern(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
pattern *appctlpb.TrafficPattern
|
||||
wantErrString string
|
||||
}{
|
||||
{
|
||||
name: "nil_pattern",
|
||||
pattern: nil,
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "empty_pattern",
|
||||
pattern: &appctlpb.TrafficPattern{},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "valid_tcp_fragment",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
TcpFragment: &appctlpb.TCPFragment{
|
||||
Enable: proto.Bool(true),
|
||||
MaxSleepMs: proto.Int32(100),
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "tcp_fragment_max_sleep_exceeds_100",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
TcpFragment: &appctlpb.TCPFragment{
|
||||
Enable: proto.Bool(true),
|
||||
MaxSleepMs: proto.Int32(101),
|
||||
},
|
||||
},
|
||||
wantErrString: "exceeds maximum value 100",
|
||||
},
|
||||
{
|
||||
name: "tcp_fragment_max_sleep_negative",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
TcpFragment: &appctlpb.TCPFragment{
|
||||
MaxSleepMs: proto.Int32(-1),
|
||||
},
|
||||
},
|
||||
wantErrString: "is negative",
|
||||
},
|
||||
{
|
||||
name: "valid_nonce_pattern",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
MinLen: proto.Int32(12),
|
||||
MaxLen: proto.Int32(12),
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "nonce_max_len_exceeds_12",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
MaxLen: proto.Int32(13),
|
||||
},
|
||||
},
|
||||
wantErrString: "maxLen 13 exceeds maximum value 12",
|
||||
},
|
||||
{
|
||||
name: "nonce_min_len_exceeds_12",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
MinLen: proto.Int32(13),
|
||||
},
|
||||
},
|
||||
wantErrString: "minLen 13 exceeds maximum value 12",
|
||||
},
|
||||
{
|
||||
name: "nonce_max_len_negative",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
MaxLen: proto.Int32(-1),
|
||||
},
|
||||
},
|
||||
wantErrString: "maxLen -1 is negative",
|
||||
},
|
||||
{
|
||||
name: "nonce_min_len_negative",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
MinLen: proto.Int32(-1),
|
||||
},
|
||||
},
|
||||
wantErrString: "minLen -1 is negative",
|
||||
},
|
||||
{
|
||||
name: "nonce_min_len_greater_than_max_len",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
MinLen: proto.Int32(8),
|
||||
MaxLen: proto.Int32(4),
|
||||
},
|
||||
},
|
||||
wantErrString: "minLen 8 is greater than maxLen 4",
|
||||
},
|
||||
{
|
||||
name: "valid_custom_hex_strings",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
Type: appctlpb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"00010203", "aabbccdd"},
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "valid_custom_hex_strings_max_length",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
Type: appctlpb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"000102030405060708090a0b"},
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
{
|
||||
name: "custom_hex_string_exceeds_12_bytes",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
Type: appctlpb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"000102030405060708090a0b0c"},
|
||||
},
|
||||
},
|
||||
wantErrString: "exceeds maximum 12 bytes",
|
||||
},
|
||||
{
|
||||
name: "custom_hex_string_invalid",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
Type: appctlpb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"not_valid_hex"},
|
||||
},
|
||||
},
|
||||
wantErrString: "is not a valid hex string",
|
||||
},
|
||||
{
|
||||
name: "custom_hex_string_odd_length",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
Type: appctlpb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
CustomHexStrings: []string{"abc"},
|
||||
},
|
||||
},
|
||||
wantErrString: "is not a valid hex string",
|
||||
},
|
||||
{
|
||||
name: "valid_full_pattern",
|
||||
pattern: &appctlpb.TrafficPattern{
|
||||
Seed: proto.Int32(12345),
|
||||
TcpFragment: &appctlpb.TCPFragment{
|
||||
Enable: proto.Bool(true),
|
||||
MaxSleepMs: proto.Int32(50),
|
||||
},
|
||||
Nonce: &appctlpb.NoncePattern{
|
||||
Type: appctlpb.NonceType_NONCE_TYPE_FIXED.Enum(),
|
||||
ApplyToAllUDPPacket: proto.Bool(true),
|
||||
MinLen: proto.Int32(4),
|
||||
MaxLen: proto.Int32(8),
|
||||
CustomHexStrings: []string{"00010203"},
|
||||
},
|
||||
},
|
||||
wantErrString: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
err := Validate(c.pattern)
|
||||
if c.wantErrString == "" {
|
||||
if err != nil {
|
||||
t.Errorf("Validate() returned unexpected error: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err == nil {
|
||||
t.Errorf("Validate() expected error to contain %q, got nil", c.wantErrString)
|
||||
} else if !strings.Contains(err.Error(), c.wantErrString) {
|
||||
t.Errorf("Validate() error = %q, want error to contain %q", err.Error(), c.wantErrString)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) {
|
||||
},
|
||||
}
|
||||
outbound.dialer = option.NewDialer(outbound.DialOptions())
|
||||
singDialer := proxydialer.NewSlowDownSingDialer(proxydialer.NewSingDialer(outbound.dialer), slowdown.New())
|
||||
singDialer := proxydialer.NewSingDialer(proxydialer.NewSlowDownDialer(outbound.dialer, slowdown.New()))
|
||||
|
||||
var reserved [3]uint8
|
||||
if len(option.Reserved) > 0 {
|
||||
|
||||
@@ -58,6 +58,11 @@ func Main(args []string) {
|
||||
fmt.Println("Seed: " + seedBase64)
|
||||
fmt.Println("Client: " + clientBase64)
|
||||
fmt.Println("Hash32: " + hash32Base64)
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println(" Lazy-Config ")
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Printf("[Server] decryption: \"mlkem768x25519plus.native.600s.%s\"\n", seedBase64)
|
||||
fmt.Printf("[Client] encryption: \"mlkem768x25519plus.native.0rtt.%s\"\n", clientBase64)
|
||||
case "vless-x25519":
|
||||
var privateKey string
|
||||
if len(args) > 1 {
|
||||
@@ -70,6 +75,11 @@ func Main(args []string) {
|
||||
fmt.Println("PrivateKey: " + privateKeyBase64)
|
||||
fmt.Println("Password: " + passwordBase64)
|
||||
fmt.Println("Hash32: " + hash32Base64)
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Println(" Lazy-Config ")
|
||||
fmt.Println("-----------------------")
|
||||
fmt.Printf("[Server] decryption: \"mlkem768x25519plus.native.600s.%s\"\n", privateKeyBase64)
|
||||
fmt.Printf("[Client] encryption: \"mlkem768x25519plus.native.0rtt.%s\"\n", passwordBase64)
|
||||
case "sudoku-keypair":
|
||||
privateKey, publicKey, err := sudoku.GenKeyPair()
|
||||
if err != nil {
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"strings"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/metacubex/mihomo/common/utils"
|
||||
"github.com/metacubex/mihomo/component/resolver/hosts"
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
"github.com/metacubex/randv2"
|
||||
@@ -66,37 +65,35 @@ type HostValue struct {
|
||||
Domain string
|
||||
}
|
||||
|
||||
func NewHostValue(value any) (HostValue, error) {
|
||||
func NewHostValue(value []string) (HostValue, error) {
|
||||
isDomain := true
|
||||
ips := make([]netip.Addr, 0)
|
||||
ips := make([]netip.Addr, 0, len(value))
|
||||
domain := ""
|
||||
if valueArr, err := utils.ToStringSlice(value); err != nil {
|
||||
return HostValue{}, err
|
||||
} else {
|
||||
if len(valueArr) > 1 {
|
||||
switch len(value) {
|
||||
case 0:
|
||||
return HostValue{}, errors.New("value is empty")
|
||||
case 1:
|
||||
host := value[0]
|
||||
if ip, err := netip.ParseAddr(host); err == nil {
|
||||
ips = append(ips, ip.Unmap())
|
||||
isDomain = false
|
||||
for _, str := range valueArr {
|
||||
if ip, err := netip.ParseAddr(str); err == nil {
|
||||
ips = append(ips, ip.Unmap())
|
||||
} else {
|
||||
return HostValue{}, err
|
||||
}
|
||||
}
|
||||
} else if len(valueArr) == 1 {
|
||||
host := valueArr[0]
|
||||
if ip, err := netip.ParseAddr(host); err == nil {
|
||||
} else {
|
||||
domain = host
|
||||
}
|
||||
default: // > 1
|
||||
isDomain = false
|
||||
for _, str := range value {
|
||||
if ip, err := netip.ParseAddr(str); err == nil {
|
||||
ips = append(ips, ip.Unmap())
|
||||
isDomain = false
|
||||
} else {
|
||||
domain = host
|
||||
return HostValue{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if isDomain {
|
||||
return NewHostValueByDomain(domain)
|
||||
} else {
|
||||
return NewHostValueByIPs(ips)
|
||||
}
|
||||
return NewHostValueByIPs(ips)
|
||||
}
|
||||
|
||||
func NewHostValueByIPs(ips []netip.Addr) (HostValue, error) {
|
||||
|
||||
@@ -1115,22 +1115,23 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) {
|
||||
|
||||
if len(cfg.Hosts) != 0 {
|
||||
for domain, anyValue := range cfg.Hosts {
|
||||
if str, ok := anyValue.(string); ok && str == "lan" {
|
||||
hosts, err := utils.ToStringSlice(anyValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(hosts) == 1 && hosts[0] == "lan" {
|
||||
if addrs, err := net.InterfaceAddrs(); err != nil {
|
||||
log.Errorln("insert lan to host error: %s", err)
|
||||
} else {
|
||||
ips := make([]netip.Addr, 0)
|
||||
hosts = make([]string, 0, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsLinkLocalUnicast() {
|
||||
if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
hosts = append(hosts, ipnet.IP.String())
|
||||
}
|
||||
}
|
||||
anyValue = ips
|
||||
}
|
||||
}
|
||||
value, err := resolver.NewHostValue(anyValue)
|
||||
value, err := resolver.NewHostValue(hosts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s is not a valid value", anyValue)
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ require (
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f
|
||||
github.com/metacubex/smux v0.0.0-20260105030934-d0c8756d3141
|
||||
github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443
|
||||
github.com/metacubex/tls v0.1.3
|
||||
github.com/metacubex/tls v0.1.4
|
||||
github.com/metacubex/utls v1.8.4
|
||||
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f
|
||||
github.com/mroth/weightedrand/v2 v2.1.0
|
||||
|
||||
+2
-2
@@ -141,8 +141,8 @@ github.com/metacubex/smux v0.0.0-20260105030934-d0c8756d3141 h1:DK2l6m2Fc85H2Bhi
|
||||
github.com/metacubex/smux v0.0.0-20260105030934-d0c8756d3141/go.mod h1:/yI4OiGOSn0SURhZdJF3CbtPg3nwK700bG8TZLMBvAg=
|
||||
github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 h1:H6TnfM12tOoTizYE/qBHH3nEuibIelmHI+BVSxVJr8o=
|
||||
github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/tls v0.1.3 h1:nyjA8GNYGaLVSNRSqWoNNdXSCCFiQABTyrPJmkuSL20=
|
||||
github.com/metacubex/tls v0.1.3/go.mod h1:0XeVdL0cBw+8i5Hqy3lVeP9IyD/LFTq02ExvHM6rzEM=
|
||||
github.com/metacubex/tls v0.1.4 h1:Gm5GrkyMUh52gYOMIAQ1kHIym4v4M3Qb87Wsmd8Kpdc=
|
||||
github.com/metacubex/tls v0.1.4/go.mod h1:0XeVdL0cBw+8i5Hqy3lVeP9IyD/LFTq02ExvHM6rzEM=
|
||||
github.com/metacubex/utls v1.8.4 h1:HmL9nUApDdWSkgUyodfwF6hSjtiwCGGdyhaSpEejKpg=
|
||||
github.com/metacubex/utls v1.8.4/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk=
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-openclash
|
||||
PKG_VERSION:=0.47.052
|
||||
PKG_VERSION:=0.47.055
|
||||
PKG_MAINTAINER:=vernesong <https://github.com/vernesong/OpenClash>
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||
@@ -137,7 +137,6 @@ define Package/$(PKG_NAME)/postrm
|
||||
rm -rf /tmp/openclash.log >/dev/null 2>&1
|
||||
rm -rf /tmp/openclash_start.log >/dev/null 2>&1
|
||||
rm -rf /tmp/openclash_last_version >/dev/null 2>&1
|
||||
rm -rf /tmp/openclash_config.tmp >/dev/null 2>&1
|
||||
rm -rf /tmp/openclash.change >/dev/null 2>&1
|
||||
rm -rf /tmp/Proxy_Group >/dev/null 2>&1
|
||||
rm -rf /tmp/rules_name >/dev/null 2>&1
|
||||
|
||||
@@ -29,6 +29,7 @@ START_LOG="/tmp/openclash_start.log"
|
||||
PROXY_FWMARK="0x162"
|
||||
PROXY_ROUTE_TABLE="0x162"
|
||||
QUICK_START_CHECK=false
|
||||
QUICK_START=true
|
||||
|
||||
add_cron()
|
||||
{
|
||||
@@ -456,43 +457,34 @@ check_run_quick()
|
||||
fi
|
||||
|
||||
QUICK_START_CHECK=true
|
||||
quick_start=true
|
||||
check_file="$(cat /tmp/openclash.change 2>/dev/null |awk '{print $1}')"
|
||||
if [ -z "$check_file" ] || [ ! -f "/tmp/openclash_config.tmp" ]; then
|
||||
quick_start=false
|
||||
return
|
||||
fi
|
||||
cmp -s "/etc/config/openclash" "/tmp/openclash_config.tmp"
|
||||
if [ "$?" -ne "0" ]; then
|
||||
LOG_OUT "Tip: Because of the file【 /etc/config/openclash 】modificated, Pause quick start..."
|
||||
quick_start=false
|
||||
else
|
||||
if [ -s "/tmp/openclash.change" ]; then
|
||||
for i in $check_file; do
|
||||
if [ -z "$(grep "$i $(date -r "$i")$" "/tmp/openclash.change")" ]; then
|
||||
LOG_OUT "Tip: Because of the file【 $i 】modificated, Pause quick start..."
|
||||
quick_start=false
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
cat "/tmp/openclash.change" | while read -r i; do
|
||||
file_path=$(echo "$i" |awk -F ' #edited time# ' '{print $1}')
|
||||
if [ -z "$(grep "$file_path #edited time# $(date -r "$file_path")$" "/tmp/openclash.change")" ]; then
|
||||
LOG_OUT "Tip: Because of the file【 $file_path 】modificated, Pause quick start..."
|
||||
rm -rf /tmp/openclash.change
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ! -f "/tmp/openclash.change" ]; then
|
||||
QUICK_START=false
|
||||
fi
|
||||
} >/dev/null 2>&1
|
||||
|
||||
write_run_quick()
|
||||
{
|
||||
check_file="$(echo $RAW_CONFIG_FILE | tr " " "?") $(echo $CONFIG_FILE | tr " " "?") $(ls -d /etc/openclash/custom/*) $(ls -d /etc/openclash/overwrite/*) /usr/share/openclash/res/lhie1.yaml"
|
||||
cmp -s "/etc/config/openclash" "/tmp/openclash_config.tmp"
|
||||
if [ "$?" -ne "0" ]; then
|
||||
cp "/etc/config/openclash" "/tmp/openclash_config.tmp"
|
||||
fi
|
||||
if [ "$quick_start" != "true" ]; then
|
||||
: > "/tmp/openclash.change"
|
||||
for i in $check_file; do
|
||||
echo "$i $(date -r "$i")" >> "/tmp/openclash.change"
|
||||
done
|
||||
fi
|
||||
: > "/tmp/openclash.change"
|
||||
{
|
||||
echo "/etc/config/openclash"
|
||||
echo "$RAW_CONFIG_FILE"
|
||||
echo "$CONFIG_FILE"
|
||||
ls -d /etc/openclash/custom/* 2>/dev/null
|
||||
ls -d /etc/openclash/overwrite/* 2>/dev/null
|
||||
echo "/usr/share/openclash/res/lhie1.yaml"
|
||||
} | while read -r file; do
|
||||
echo "$file #edited time# $(date -r "$file")" >> "/tmp/openclash.change"
|
||||
done
|
||||
} >/dev/null 2>&1
|
||||
|
||||
#运行模式处理
|
||||
@@ -747,7 +739,6 @@ check_core_status()
|
||||
while ( [ -n "$(pidof clash)" ] && [ -z "$($ip_ route list |grep utun)" ] && [ "$TUN_RESTART" -le 3 ] )
|
||||
do
|
||||
LOG_OUT "Warning: TUN Interface Start Failed, Try to Restart Again..."
|
||||
kill_clash
|
||||
start_run_core
|
||||
sleep 120
|
||||
let TUN_RESTART++
|
||||
@@ -759,17 +750,16 @@ check_core_status()
|
||||
fi
|
||||
|
||||
if [ -n "$(pidof clash)" ]; then
|
||||
ip -6 rule del oif utun table 2022
|
||||
ip -6 route del default dev utun table 2022
|
||||
if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
|
||||
ip -6 rule del oif utun table 2022
|
||||
ip -6 route del default dev utun table 2022
|
||||
ip -6 route add default dev utun table "$PROXY_ROUTE_TABLE"
|
||||
ip -6 rule add fwmark "$PROXY_FWMARK" ipproto icmp table main pref 1888
|
||||
ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" pref 1889
|
||||
ip -6 rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" pref 1888
|
||||
fi
|
||||
if [ -n "$en_mode_tun" ]; then
|
||||
ip route add default dev utun table "$PROXY_ROUTE_TABLE"
|
||||
ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" pref 1888
|
||||
fi
|
||||
|
||||
ip route add default dev utun table "$PROXY_ROUTE_TABLE"
|
||||
ip rule add fwmark "$PROXY_FWMARK" ipproto icmp table main pref 1888
|
||||
ip rule add fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE" pref 1889
|
||||
fi
|
||||
else
|
||||
reg4='^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$'
|
||||
@@ -812,7 +802,7 @@ start_run_core()
|
||||
ulimit -v unlimited
|
||||
ulimit -u unlimited
|
||||
|
||||
if [ "$quick_start" != "true" ]; then
|
||||
if ! $QUICK_START; then
|
||||
mv "$TMP_CONFIG_FILE" "$CONFIG_FILE"
|
||||
rm -rf "$TMP_CONFIG_FILE"
|
||||
fi
|
||||
@@ -2229,10 +2219,27 @@ if [ -n "$FW4" ]; then
|
||||
fi
|
||||
|
||||
#icmp
|
||||
if [ -n "$en_mode_tun" ]; then
|
||||
nft insert rule inet fw4 mangle_prerouting position 0 meta nfproto {ipv4} ip protocol icmp icmp type echo-request mark set "$PROXY_FWMARK" counter accept comment \"OpenClash ICMP Redirect\"
|
||||
fi
|
||||
if [ "$ipv6_enable" -eq 1 ]; then
|
||||
if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
|
||||
nft insert rule inet fw4 mangle_prerouting position 0 meta nfproto {ipv6} ip6 nexthdr icmpv6 icmpv6 type echo-request mark set "$PROXY_FWMARK" counter accept comment \"OpenClash ICMPv6 Redirect\"
|
||||
fi
|
||||
fi
|
||||
if [ "$en_mode" = "fake-ip" ]; then
|
||||
nft insert rule inet fw4 input position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } counter reject comment \"OpenClash ICMP INPUT REJECT\"
|
||||
nft insert rule inet fw4 forward position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } counter reject comment \"OpenClash ICMP FORWARD REJECT\"
|
||||
nft insert rule inet fw4 output position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } $noowner counter reject comment \"OpenClash ICMP OUTPUT REJECT\"
|
||||
if [ -z "$en_mode_tun" ]; then
|
||||
nft insert rule inet fw4 input position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } counter reject comment \"OpenClash ICMP INPUT REJECT\"
|
||||
nft insert rule inet fw4 forward position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } counter reject comment \"OpenClash ICMP FORWARD REJECT\"
|
||||
nft insert rule inet fw4 output position 0 ip protocol icmp icmp type echo-request ip daddr { $fakeip_range } $noowner counter reject comment \"OpenClash ICMP OUTPUT REJECT\"
|
||||
fi
|
||||
if [ "$ipv6_enable" -eq 1 ] || [ "$ipv6_dns" -eq 1 ]; then
|
||||
if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then
|
||||
nft insert rule inet fw4 input position 0 ip6 nexthdr icmpv6 icmpv6 type echo-request ip6 daddr { $fakeip_range6 } counter reject with icmpv6 admin-prohibited comment \"OpenClash ICMPv6 INPUT REJECT\"
|
||||
nft insert rule inet fw4 forward position 0 ip6 nexthdr icmpv6 icmpv6 type echo-request ip6 daddr { $fakeip_range6 } counter reject with icmpv6 admin-prohibited comment \"OpenClash ICMPv6 FORWARD REJECT\"
|
||||
nft insert rule inet fw4 output position 0 ip6 nexthdr icmpv6 icmpv6 type echo-request ip6 daddr { $fakeip_range6 } $noowner counter reject with icmpv6 admin-prohibited comment \"OpenClash ICMPv6 OUTPUT REJECT\"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -3009,10 +3016,27 @@ if [ -z "$FW4" ]; then
|
||||
fi
|
||||
|
||||
#icmp
|
||||
if [ -n "$en_mode_tun" ]; then
|
||||
iptables -t mangle -I PREROUTING -p icmp --icmp-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "OpenClash ICMP Redirect"
|
||||
fi
|
||||
if [ "$ipv6_enable" -eq 1 ]; then
|
||||
if [ "$ipv6_mode" -eq 2 ] || [ "$ipv6_mode" -eq 3 ]; then
|
||||
ip6tables -t mangle -I PREROUTING -p icmpv6 --icmpv6-type echo-request -j MARK --set-xmark "$PROXY_FWMARK" -m comment --comment "OpenClash ICMPv6 Redirect"
|
||||
fi
|
||||
fi
|
||||
if [ "$en_mode" = "fake-ip" ]; then
|
||||
iptables -t filter -I INPUT -p icmp --icmp-type echo-request -d "$fakeip_range" -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "OpenClash ICMP INPUT REJECT"
|
||||
iptables -t filter -I FORWARD -p icmp --icmp-type echo-request -d "$fakeip_range" -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "OpenClash ICMP FORWARD REJECT"
|
||||
iptables -t filter -I OUTPUT -p icmp --icmp-type echo-request -d "$fakeip_range" $noowner -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "OpenClash ICMP OUTPUT REJECT"
|
||||
if [ -z "$en_mode_tun" ]; then
|
||||
iptables -t filter -I INPUT -p icmp --icmp-type echo-request -d "$fakeip_range" -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "OpenClash ICMP INPUT REJECT"
|
||||
iptables -t filter -I FORWARD -p icmp --icmp-type echo-request -d "$fakeip_range" -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "OpenClash ICMP FORWARD REJECT"
|
||||
iptables -t filter -I OUTPUT -p icmp --icmp-type echo-request -d "$fakeip_range" $noowner -j REJECT --reject-with icmp-admin-prohibited -m comment --comment "OpenClash ICMP OUTPUT REJECT"
|
||||
fi
|
||||
if [ "$ipv6_enable" -eq 1 ] || [ "$ipv6_dns" -eq 1 ]; then
|
||||
if [ "$ipv6_mode" -ne 2 ] && [ "$ipv6_mode" -ne 3 ]; then
|
||||
ip6tables -t filter -I INPUT -p icmpv6 --icmpv6-type echo-request -d "$fakeip_range6" -j REJECT --reject-with icmp6-adm-prohibited -m comment --comment "OpenClash ICMPv6 INPUT REJECT"
|
||||
ip6tables -t filter -I FORWARD -p icmpv6 --icmpv6-type echo-request -d "$fakeip_range6" -j REJECT --reject-with icmp6-adm-prohibited -m comment --comment "OpenClash ICMPv6 FORWARD REJECT"
|
||||
ip6tables -t filter -I OUTPUT -p icmpv6 --icmpv6-type echo-request -d "$fakeip_range6" $noowner -j REJECT --reject-with icmp6-adm-prohibited -m comment --comment "OpenClash ICMPv6 OUTPUT REJECT"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -3045,10 +3069,8 @@ revert_firewall()
|
||||
|
||||
#TUN
|
||||
ip rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
|
||||
ip rule del fwmark "$PROXY_FWMARK" ipproto icmp table main
|
||||
ip route del default dev utun table "$PROXY_ROUTE_TABLE"
|
||||
ip -6 rule del fwmark "$PROXY_FWMARK" table "$PROXY_ROUTE_TABLE"
|
||||
ip -6 rule del fwmark "$PROXY_FWMARK" ipproto icmp table main
|
||||
ip -6 route del default dev utun table "$PROXY_ROUTE_TABLE"
|
||||
|
||||
if [ -n "$FW4" ]; then
|
||||
@@ -3067,7 +3089,7 @@ revert_firewall()
|
||||
nft delete set inet fw4 handle ${handle}
|
||||
done
|
||||
else
|
||||
for ipt in "iptables -nvL INPUT" "iptables -nvL FORWARD" "iptables -nvL OUTPUT" "iptables -nvL POSTROUTING -t nat" "iptables -nvL OUTPUT -t nat" "iptables -nvL OUTPUT -t mangle" "iptables -nvL PREROUTING -t nat" "iptables -nvL PREROUTING -t mangle" "ip6tables -nvL PREROUTING -t mangle" "ip6tables -nvL OUTPUT -t mangle" "ip6tables -nvL PREROUTING -t nat" "ip6tables -nvL INPUT" "ip6tables -nvL POSTROUTING -t nat" "ip6tables -nvL FORWARD" "ip6tables -nvL OUTPUT -t nat"; do
|
||||
for ipt in "iptables -nvL INPUT" "iptables -nvL FORWARD" "iptables -nvL OUTPUT" "iptables -nvL POSTROUTING -t nat" "iptables -nvL OUTPUT -t nat" "iptables -nvL OUTPUT -t mangle" "iptables -nvL PREROUTING -t nat" "iptables -nvL PREROUTING -t mangle" "ip6tables -nvL OUTPUT" "ip6tables -nvL INPUT" "ip6tables -nvL FORWARD" "ip6tables -nvL OUTPUT -t mangle" "ip6tables -nvL PREROUTING -t nat" "ip6tables -nvL PREROUTING -t mangle" "ip6tables -nvL POSTROUTING -t nat" "ip6tables -nvL OUTPUT -t nat"; do
|
||||
for comment in "openclash" "OpenClash"; do
|
||||
local lines=$($ipt |sed 1,2d |sed -n "/${comment}/=" 2>/dev/null |sort -rn)
|
||||
if [ -n "$lines" ]; then
|
||||
@@ -3619,10 +3641,6 @@ start_service()
|
||||
enable=$(uci_get_config "enable")
|
||||
[ "$enable" != "1" ] && LOG_OUT "Warning: OpenClash Now Disabled, Need Start From Luci Page, Exit..." && SLOG_CLEAN && exit 0
|
||||
|
||||
if pidof clash >/dev/null 2>&1; then
|
||||
stop
|
||||
fi
|
||||
|
||||
LOG_OUT "Tip: OpenClash Start Running..."
|
||||
|
||||
{
|
||||
@@ -3637,7 +3655,7 @@ start_service()
|
||||
LOG_OUT "Step 2: Check The Components..."
|
||||
do_run_file "$RAW_CONFIG_FILE" "$BACKUP_FILE"
|
||||
|
||||
if [ "$quick_start" != "true" ]; then
|
||||
if ! $QUICK_START; then
|
||||
LOG_OUT "Step 3: Modify The Config File..."
|
||||
config_check
|
||||
/usr/share/openclash/yml_change.sh \
|
||||
@@ -3749,7 +3767,6 @@ stop_service()
|
||||
/tmp/rules_name \
|
||||
/tmp/rule_providers_name \
|
||||
/tmp/openclash_last_version \
|
||||
/tmp/openclash_config.tmp \
|
||||
/tmp/openclash.change \
|
||||
/tmp/openclash_debug.log \
|
||||
/tmp/openclash_edit_file_name \
|
||||
@@ -3846,7 +3863,8 @@ reload_service()
|
||||
if pidof clash >/dev/null && [ "$enable" == "1" ] && [ "$1" == "restore" ]; then
|
||||
do_run_mode
|
||||
get_config
|
||||
check_core_status &
|
||||
# used for config subscribe, not background for avoiding system unready
|
||||
check_core_status
|
||||
fi
|
||||
} >/dev/null 2>&1
|
||||
|
||||
|
||||
@@ -504,8 +504,8 @@ sub_info_get()
|
||||
LOG_OUT "Config File Format Validation Failed, Trying To Download Without Agent..."
|
||||
config_download_direct
|
||||
elif ! "$(ruby_read "$CFG_FILE" ".key?('proxies')")" && ! "$(ruby_read "$CFG_FILE" ".key?('proxy-providers')")" ; then
|
||||
LOG_OUT "Error: Updated Config【$name】Has No Proxy Field, Trying To Download Without Agent..."
|
||||
config_download_direct
|
||||
LOG_OUT "Error: Updated Config【$name】Has No Proxy Field, Trying To Download Without Agent..."
|
||||
config_download_direct
|
||||
else
|
||||
config_su_check
|
||||
fi
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/bin/bash
|
||||
. /lib/functions.sh
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
|
||||
set_lock() {
|
||||
exec 872>"/tmp/lock/openclash_core.lock" 2>/dev/null
|
||||
@@ -16,7 +16,9 @@ del_lock() {
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
restart=0
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
if [ "$github_address_mod" = "0" ] && [ -z "$(echo $2 2>/dev/null |grep -E 'http|one_key_update')" ] && [ -z "$(echo $3 2>/dev/null |grep 'http')" ]; then
|
||||
LOG_OUT "Tip: If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options"
|
||||
@@ -72,7 +74,7 @@ else
|
||||
CORE_LV=$(sed -n 1p /tmp/clash_last_version 2>/dev/null)
|
||||
fi
|
||||
|
||||
[ "$C_CORE_TYPE" = "$CORE_TYPE" ] || [ -z "$C_CORE_TYPE" ] && if_restart=1
|
||||
[ "$C_CORE_TYPE" = "$CORE_TYPE" ] || [ -z "$C_CORE_TYPE" ] && restart=1
|
||||
|
||||
if [ "$CORE_CV" != "$CORE_LV" ] || [ -z "$CORE_CV" ]; then
|
||||
if [ "$CPU_MODEL" != 0 ]; then
|
||||
@@ -131,17 +133,8 @@ if [ "$CORE_CV" != "$CORE_LV" ] || [ -z "$CORE_CV" ]; then
|
||||
|
||||
if [ "$?" == "0" ]; then
|
||||
LOG_OUT "Tip:【"$CORE_TYPE"】Core Update Successful!"
|
||||
if [ "$if_restart" -eq 1 ]; then
|
||||
uci -q set openclash.config.restart=1
|
||||
uci -q commit openclash
|
||||
if ([ -z "$2" ] || ([ -n "$2" ] && [ "$2" != "one_key_update" ])) && [ "$(unify_ps_prevent)" -eq 0 ]; then
|
||||
uci -q set openclash.config.restart=0
|
||||
uci -q commit openclash
|
||||
/etc/init.d/openclash restart >/dev/null 2>&1 &
|
||||
fi
|
||||
else
|
||||
SLOG_CLEAN
|
||||
fi
|
||||
SLOG_CLEAN
|
||||
restart=1
|
||||
break
|
||||
else
|
||||
if [ "$retry_count" -lt "$max_retries" ]; then
|
||||
@@ -187,4 +180,5 @@ else
|
||||
fi
|
||||
|
||||
rm -rf "$TMP_FILE" >/dev/null 2>&1
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
|
||||
@@ -39,9 +39,10 @@ inc_job_counter() {
|
||||
exec 999>"/tmp/lock/openclash_jobs.lock"
|
||||
flock -x 999
|
||||
local cnt=0
|
||||
[ -f "$JOB_COUNTER_FILE" ] && cnt=$(cat "$JOB_COUNTER_FILE")
|
||||
local restart=0
|
||||
[ -f "$JOB_COUNTER_FILE" ] && cnt=$(cat "$JOB_COUNTER_FILE" | awk '{print $1}') && restart=$(cat "$JOB_COUNTER_FILE" | awk '{print $2}')
|
||||
cnt=$((cnt+1))
|
||||
echo "$cnt" > "$JOB_COUNTER_FILE"
|
||||
echo "$cnt $restart" > "$JOB_COUNTER_FILE"
|
||||
flock -u 999
|
||||
}
|
||||
|
||||
@@ -50,23 +51,19 @@ dec_job_counter_and_restart() {
|
||||
exec 999>"/tmp/lock/openclash_jobs.lock"
|
||||
flock -x 999
|
||||
local cnt=0
|
||||
[ -f "$JOB_COUNTER_FILE" ] && cnt=$(cat "$JOB_COUNTER_FILE")
|
||||
local restart=0
|
||||
[ -f "$JOB_COUNTER_FILE" ] && cnt=$(cat "$JOB_COUNTER_FILE" | awk '{print $1}') && restart=$(cat "$JOB_COUNTER_FILE" | awk '{print $2}')
|
||||
cnt=$((cnt-1))
|
||||
[ $cnt -lt 0 ] && cnt=0
|
||||
|
||||
echo "$cnt" > "$JOB_COUNTER_FILE"
|
||||
|
||||
if [ "$restart_flag" -eq 1 ]; then
|
||||
uci -q set openclash.config.restart=1
|
||||
uci -q commit openclash
|
||||
restart=1
|
||||
fi
|
||||
|
||||
if [ $cnt -eq 0 ]; then
|
||||
if [ "$(uci_get_config "restart")" -eq 1 ] && [ "$(unify_ps_prevent)" -eq 0 ]; then
|
||||
/etc/init.d/openclash restart >/dev/null 2>&1 &
|
||||
uci -q set openclash.config.restart=0
|
||||
uci -q commit openclash
|
||||
fi
|
||||
echo "$cnt $restart" > "$JOB_COUNTER_FILE"
|
||||
|
||||
if [ $cnt -eq 0 ] && [ "$restart" -eq 1 ] && [ "$(unify_ps_prevent)" -eq 0 ]; then
|
||||
/etc/init.d/openclash restart >/dev/null 2>&1 &
|
||||
rm -rf "$JOB_COUNTER_FILE" >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
|
||||
set_lock() {
|
||||
exec 878>"/tmp/lock/openclash_update.lock" 2>/dev/null
|
||||
@@ -14,6 +15,8 @@ del_lock() {
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
restart=0
|
||||
|
||||
if [ -n "$1" ] && [ "$1" != "one_key_update" ]; then
|
||||
[ ! -f "/tmp/openclash_last_version" ] && /usr/share/openclash/openclash_version.sh "$1" 2>/dev/null
|
||||
@@ -26,6 +29,7 @@ fi
|
||||
if [ ! -f "/tmp/openclash_last_version" ]; then
|
||||
LOG_OUT "Error: Failed to get version information, please try again later..."
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
@@ -61,8 +65,6 @@ github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
|
||||
#一键更新
|
||||
if [ "$1" = "one_key_update" ]; then
|
||||
uci -q set openclash.config.enable=1
|
||||
uci -q commit openclash
|
||||
if [ "$github_address_mod" = "0" ] && [ -z "$2" ]; then
|
||||
LOG_OUT "Tip: If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options"
|
||||
fi
|
||||
@@ -173,13 +175,9 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
LOG_OUT "Error:【OpenClash - v$LAST_VER】Pre update test failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】"
|
||||
fi
|
||||
if [ "$(uci_get_config "restart")" -eq 1 ]; then
|
||||
uci -q set openclash.config.restart=0
|
||||
uci -q commit openclash
|
||||
/etc/init.d/openclash restart >/dev/null 2>&1 &
|
||||
else
|
||||
SLOG_CLEAN
|
||||
fi
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
@@ -193,13 +191,8 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
LOG_OUT "Error:【OpenClash - v$LAST_VER】Download Failed after 3 attempts, please check the network or try again later!"
|
||||
rm -rf /tmp/openclash.ipk >/dev/null 2>&1
|
||||
rm -rf /tmp/openclash.apk >/dev/null 2>&1
|
||||
if [ "$(uci_get_config "restart")" -eq 1 ]; then
|
||||
uci -q set openclash.config.restart=0
|
||||
uci -q commit openclash
|
||||
/etc/init.d/openclash restart >/dev/null 2>&1 &
|
||||
else
|
||||
SLOG_CLEAN
|
||||
fi
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
@@ -411,12 +404,8 @@ else
|
||||
else
|
||||
LOG_OUT "Tip: OpenClash has not been updated, stop continuing!"
|
||||
fi
|
||||
if [ "$(uci_get_config "restart")" -eq 1 ]; then
|
||||
uci -q set openclash.config.restart=0
|
||||
uci -q commit openclash
|
||||
/etc/init.d/openclash restart >/dev/null 2>&1 &
|
||||
else
|
||||
SLOG_CLEAN
|
||||
fi
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
fi
|
||||
|
||||
del_lock
|
||||
|
||||
@@ -505,7 +505,7 @@ threads << Thread.new do
|
||||
'enable' => true, 'stack' => stack_type, 'device' => 'utun',
|
||||
'dns-hijack' => ['127.0.0.1:53'], 'endpoint-independent-nat' => true,
|
||||
'auto-route' => false, 'auto-detect-interface' => false,
|
||||
'auto-redirect' => false, 'strict-route' => false
|
||||
'auto-redirect' => false, 'strict-route' => false, 'disable-icmp-forwarding' => false
|
||||
}
|
||||
Value['tun'].delete('iproute2-table-index')
|
||||
else
|
||||
|
||||
@@ -195,41 +195,6 @@ get_jump_ipt() {
|
||||
esac
|
||||
}
|
||||
|
||||
gen_lanlist() {
|
||||
cat $RULES_PATH/lanlist_ipv4 | tr -s '\n' | grep -v "^#"
|
||||
}
|
||||
|
||||
gen_lanlist_6() {
|
||||
cat $RULES_PATH/lanlist_ipv6 | tr -s '\n' | grep -v "^#"
|
||||
}
|
||||
|
||||
get_wan_ips() {
|
||||
local family="$1"
|
||||
local NET_ADDR
|
||||
local iface
|
||||
local INTERFACES=$(ubus call network.interface dump | jsonfilter -e '@.interface[!(@.interface ~ /lan/) && @.route[0]].interface')
|
||||
for iface in $INTERFACES; do
|
||||
local addr
|
||||
if [ "$family" = "ip6" ]; then
|
||||
network_get_ipaddr6 addr "$iface"
|
||||
case "$addr" in
|
||||
""|fe80*) continue ;;
|
||||
esac
|
||||
else
|
||||
network_get_ipaddr addr "$iface"
|
||||
case "$addr" in
|
||||
""|"0.0.0.0") continue ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case " $NET_ADDR " in
|
||||
*" $addr "*) ;;
|
||||
*) NET_ADDR="${NET_ADDR:+$NET_ADDR }$addr" ;;
|
||||
esac
|
||||
done
|
||||
echo "$NET_ADDR"
|
||||
}
|
||||
|
||||
load_acl() {
|
||||
([ "$ENABLED_ACLS" == 1 ] || ([ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ])) && echolog " - 访问控制:"
|
||||
[ "$ENABLED_ACLS" == 1 ] && {
|
||||
|
||||
@@ -228,41 +228,6 @@ get_jump_ipt() {
|
||||
esac
|
||||
}
|
||||
|
||||
gen_lanlist() {
|
||||
cat $RULES_PATH/lanlist_ipv4 | tr -s '\n' | grep -v "^#"
|
||||
}
|
||||
|
||||
gen_lanlist_6() {
|
||||
cat $RULES_PATH/lanlist_ipv6 | tr -s '\n' | grep -v "^#"
|
||||
}
|
||||
|
||||
get_wan_ips() {
|
||||
local family="$1"
|
||||
local NET_ADDR
|
||||
local iface
|
||||
local INTERFACES=$(ubus call network.interface dump | jsonfilter -e '@.interface[!(@.interface ~ /lan/) && @.route[0]].interface')
|
||||
for iface in $INTERFACES; do
|
||||
local addr
|
||||
if [ "$family" = "ip6" ]; then
|
||||
network_get_ipaddr6 addr "$iface"
|
||||
case "$addr" in
|
||||
""|fe80*) continue ;;
|
||||
esac
|
||||
else
|
||||
network_get_ipaddr addr "$iface"
|
||||
case "$addr" in
|
||||
""|"0.0.0.0") continue ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case " $NET_ADDR " in
|
||||
*" $addr "*) ;;
|
||||
*) NET_ADDR="${NET_ADDR:+$NET_ADDR }$addr" ;;
|
||||
esac
|
||||
done
|
||||
echo "$NET_ADDR"
|
||||
}
|
||||
|
||||
load_acl() {
|
||||
([ "$ENABLED_ACLS" == 1 ] || ([ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ])) && echolog " - 访问控制:"
|
||||
[ "$ENABLED_ACLS" == 1 ] && {
|
||||
|
||||
@@ -64,7 +64,8 @@ get_enabled_anonymous_secs() {
|
||||
get_geoip() {
|
||||
local geoip_code="$1"
|
||||
local geoip_type_flag=""
|
||||
local geoip_path="${V2RAY_LOCATION_ASSET%*/}/geoip.dat"
|
||||
local geoip_path="$(config_t_get global_rules v2ray_location_asset "/usr/share/v2ray/")"
|
||||
geoip_path="${geoip_path%*/}/geoip.dat"
|
||||
local bin="$(first_type $(config_t_get global_app geoview_file) geoview)"
|
||||
[ -n "$bin" ] && [ -s "$geoip_path" ] || { echo ""; return 1; }
|
||||
case "$2" in
|
||||
@@ -441,3 +442,38 @@ get_subscribe_host(){
|
||||
echo "$url"
|
||||
done
|
||||
}
|
||||
|
||||
gen_lanlist() {
|
||||
cat $RULES_PATH/lanlist_ipv4 | tr -s '\n' | grep -v "^#"
|
||||
}
|
||||
|
||||
gen_lanlist_6() {
|
||||
cat $RULES_PATH/lanlist_ipv6 | tr -s '\n' | grep -v "^#"
|
||||
}
|
||||
|
||||
get_wan_ips() {
|
||||
local family="$1"
|
||||
local NET_ADDR
|
||||
local iface
|
||||
local INTERFACES=$(ubus call network.interface dump | jsonfilter -e \
|
||||
'@.interface[!(@.interface ~ /lan/) && !(@.l3_device ~ /\./) && @.route[0]].interface')
|
||||
for iface in $INTERFACES; do
|
||||
local addr
|
||||
if [ "$family" = "ip6" ]; then
|
||||
network_get_ipaddr6 addr "$iface"
|
||||
case "$addr" in
|
||||
""|fe80*) continue ;;
|
||||
esac
|
||||
else
|
||||
network_get_ipaddr addr "$iface"
|
||||
case "$addr" in
|
||||
""|"0.0.0.0") continue ;;
|
||||
esac
|
||||
fi
|
||||
case " $NET_ADDR " in
|
||||
*" $addr "*) ;;
|
||||
*) NET_ADDR="${NET_ADDR:+$NET_ADDR }$addr" ;;
|
||||
esac
|
||||
done
|
||||
echo "$NET_ADDR"
|
||||
}
|
||||
|
||||
@@ -168,65 +168,6 @@ get_redirect_ip6t() {
|
||||
echo "$(REDIRECT $2 $3)"
|
||||
}
|
||||
|
||||
gen_lanlist() {
|
||||
cat <<-EOF
|
||||
0.0.0.0/8
|
||||
10.0.0.0/8
|
||||
100.64.0.0/10
|
||||
127.0.0.0/8
|
||||
169.254.0.0/16
|
||||
172.16.0.0/12
|
||||
192.168.0.0/16
|
||||
224.0.0.0/4
|
||||
240.0.0.0/4
|
||||
EOF
|
||||
}
|
||||
|
||||
gen_lanlist_6() {
|
||||
cat <<-EOF
|
||||
::/128
|
||||
::1/128
|
||||
::ffff:0:0/96
|
||||
::ffff:0:0:0/96
|
||||
64:ff9b::/96
|
||||
100::/64
|
||||
2001::/32
|
||||
2001:20::/28
|
||||
2001:db8::/32
|
||||
2002::/16
|
||||
fc00::/7
|
||||
fe80::/10
|
||||
ff00::/8
|
||||
EOF
|
||||
}
|
||||
|
||||
get_wan_ips() {
|
||||
local family="$1"
|
||||
local NET_ADDR
|
||||
local iface
|
||||
local INTERFACES=$(ubus call network.interface dump | jsonfilter -e '@.interface[@.route[0]].interface')
|
||||
for iface in $INTERFACES; do
|
||||
local addr
|
||||
if [ "$family" = "ip6" ]; then
|
||||
network_get_ipaddr6 addr "$iface"
|
||||
case "$addr" in
|
||||
""|fe80*) continue ;;
|
||||
esac
|
||||
else
|
||||
network_get_ipaddr addr "$iface"
|
||||
case "$addr" in
|
||||
""|"0.0.0.0") continue ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case " $NET_ADDR " in
|
||||
*" $addr "*) ;;
|
||||
*) NET_ADDR="${NET_ADDR:+$NET_ADDR }$addr" ;;
|
||||
esac
|
||||
done
|
||||
echo "$NET_ADDR"
|
||||
}
|
||||
|
||||
gen_shunt_list() {
|
||||
local node=${1}
|
||||
local shunt_list4_var_name=${2}
|
||||
|
||||
@@ -201,65 +201,6 @@ gen_nftset() {
|
||||
[ $# -gt 0 ] || [ ! -t 0 ] && insert_nftset "$nftset_name" "$timeout_argument_element" "$@"
|
||||
}
|
||||
|
||||
gen_lanlist() {
|
||||
cat <<-EOF
|
||||
0.0.0.0/8
|
||||
10.0.0.0/8
|
||||
100.64.0.0/10
|
||||
127.0.0.0/8
|
||||
169.254.0.0/16
|
||||
172.16.0.0/12
|
||||
192.168.0.0/16
|
||||
224.0.0.0/4
|
||||
240.0.0.0/4
|
||||
EOF
|
||||
}
|
||||
|
||||
gen_lanlist_6() {
|
||||
cat <<-EOF
|
||||
::/128
|
||||
::1/128
|
||||
::ffff:0:0/96
|
||||
::ffff:0:0:0/96
|
||||
64:ff9b::/96
|
||||
100::/64
|
||||
2001::/32
|
||||
2001:20::/28
|
||||
2001:db8::/32
|
||||
2002::/16
|
||||
fc00::/7
|
||||
fe80::/10
|
||||
ff00::/8
|
||||
EOF
|
||||
}
|
||||
|
||||
get_wan_ips() {
|
||||
local family="$1"
|
||||
local NET_ADDR
|
||||
local iface
|
||||
local INTERFACES=$(ubus call network.interface dump | jsonfilter -e '@.interface[@.route[0]].interface')
|
||||
for iface in $INTERFACES; do
|
||||
local addr
|
||||
if [ "$family" = "ip6" ]; then
|
||||
network_get_ipaddr6 addr "$iface"
|
||||
case "$addr" in
|
||||
""|fe80*) continue ;;
|
||||
esac
|
||||
else
|
||||
network_get_ipaddr addr "$iface"
|
||||
case "$addr" in
|
||||
""|"0.0.0.0") continue ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case " $NET_ADDR " in
|
||||
*" $addr "*) ;;
|
||||
*) NET_ADDR="${NET_ADDR:+$NET_ADDR }$addr" ;;
|
||||
esac
|
||||
done
|
||||
echo "$NET_ADDR"
|
||||
}
|
||||
|
||||
gen_shunt_list() {
|
||||
local node=${1}
|
||||
local shunt_list4_var_name=${2}
|
||||
|
||||
@@ -151,16 +151,13 @@ get_geoip() {
|
||||
local geoip_type_flag=""
|
||||
local geoip_path="$(config_t_get global_rules v2ray_location_asset)"
|
||||
geoip_path="${geoip_path%*/}/geoip.dat"
|
||||
[ -e "$geoip_path" ] || { echo ""; return; }
|
||||
local bin="$(first_type $(config_t_get global_app geoview_file) geoview)"
|
||||
[ -n "$bin" ] && [ -s "$geoip_path" ] || { echo ""; return; }
|
||||
case "$2" in
|
||||
"ipv4") geoip_type_flag="-ipv6=false" ;;
|
||||
"ipv6") geoip_type_flag="-ipv4=false" ;;
|
||||
esac
|
||||
if type geoview &> /dev/null; then
|
||||
geoview -input "$geoip_path" -list "$geoip_code" $geoip_type_flag -lowmem=true
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
"$bin" -input "$geoip_path" -list "$geoip_code" $geoip_type_flag -lowmem=true
|
||||
}
|
||||
|
||||
get_host_ip() {
|
||||
@@ -386,3 +383,62 @@ ln_run() {
|
||||
kill_all() {
|
||||
kill -9 $(pidof "$@") >/dev/null 2>&1
|
||||
}
|
||||
|
||||
gen_lanlist() {
|
||||
cat <<-EOF
|
||||
0.0.0.0/8
|
||||
10.0.0.0/8
|
||||
100.64.0.0/10
|
||||
127.0.0.0/8
|
||||
169.254.0.0/16
|
||||
172.16.0.0/12
|
||||
192.168.0.0/16
|
||||
224.0.0.0/4
|
||||
240.0.0.0/4
|
||||
EOF
|
||||
}
|
||||
|
||||
gen_lanlist_6() {
|
||||
cat <<-EOF
|
||||
::/128
|
||||
::1/128
|
||||
::ffff:0:0/96
|
||||
::ffff:0:0:0/96
|
||||
64:ff9b::/96
|
||||
100::/64
|
||||
2001::/32
|
||||
2001:20::/28
|
||||
2001:db8::/32
|
||||
2002::/16
|
||||
fc00::/7
|
||||
fe80::/10
|
||||
ff00::/8
|
||||
EOF
|
||||
}
|
||||
|
||||
get_wan_ips() {
|
||||
local family="$1"
|
||||
local NET_ADDR
|
||||
local iface
|
||||
local INTERFACES=$(ubus call network.interface dump | jsonfilter -e \
|
||||
'@.interface[!(@.interface ~ /lan/) && !(@.l3_device ~ /\./) && @.route[0]].interface')
|
||||
for iface in $INTERFACES; do
|
||||
local addr
|
||||
if [ "$family" = "ip6" ]; then
|
||||
network_get_ipaddr6 addr "$iface"
|
||||
case "$addr" in
|
||||
""|fe80*) continue ;;
|
||||
esac
|
||||
else
|
||||
network_get_ipaddr addr "$iface"
|
||||
case "$addr" in
|
||||
""|"0.0.0.0") continue ;;
|
||||
esac
|
||||
fi
|
||||
case " $NET_ADDR " in
|
||||
*" $addr "*) ;;
|
||||
*) NET_ADDR="${NET_ADDR:+$NET_ADDR }$addr" ;;
|
||||
esac
|
||||
done
|
||||
echo "$NET_ADDR"
|
||||
}
|
||||
|
||||
+35
-40
@@ -2,51 +2,46 @@ name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- v*
|
||||
- latest
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2.3.4
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
submodules: recursive
|
||||
|
||||
- uses: docker/setup-qemu-action@v1.1.0
|
||||
- uses: docker/setup-buildx-action@v1.3.0
|
||||
- uses: docker/login-action@v1.9.0
|
||||
with:
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
|
||||
- name: check and set image version
|
||||
id: prepare
|
||||
- name: Install dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
case ${{ github.ref }} in
|
||||
refs/heads/master)
|
||||
echo ::set-output name=version::edge
|
||||
echo ::set-output name=push::true
|
||||
;;
|
||||
refs/tags/*)
|
||||
echo ::set-output name=version::$(echo ${{ github.ref }} | sed -E 's|refs/tags/||')
|
||||
echo ::set-output name=push::true
|
||||
;;
|
||||
*)
|
||||
echo ::set-output name=version::${{ github.sha }}
|
||||
echo ::set-output name=push::false
|
||||
;;
|
||||
esac;
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libpcre2-dev libmbedtls-dev libsodium-dev libev-dev libc-ares-dev
|
||||
|
||||
- name: build & push image
|
||||
uses: docker/build-push-action@v2.4.0
|
||||
with:
|
||||
context: .
|
||||
file: docker/alpine/Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ steps.prepare.outputs.push }}
|
||||
tags: ${{ github.repository }}:${{ steps.prepare.outputs.version }}
|
||||
- name: Install dependencies (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: brew install mbedtls@3 libsodium libev c-ares pcre2
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
mkdir -p build && cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DWITH_STATIC=OFF
|
||||
make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu)
|
||||
|
||||
- name: Unit tests
|
||||
run: |
|
||||
cd build
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: ss-setup TUI tests
|
||||
run: bash tests/test_ss_setup.sh
|
||||
|
||||
- name: Stress test
|
||||
run: |
|
||||
python3 tests/stress_test.py --bin build/shared/bin/ --size 10
|
||||
|
||||
@@ -15,7 +15,7 @@ before_install:
|
||||
- |
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
# All dependencies for macOS build. Some packages has been installed by travis so use reinstall.
|
||||
brew reinstall autoconf automake xmlto c-ares libev mbedtls libsodium asciidoc >> /dev/null 2>&1;
|
||||
brew reinstall cmake xmlto c-ares libev mbedtls libsodium asciidoc >> /dev/null 2>&1;
|
||||
else
|
||||
wget https://github.com/jedisct1/libsodium/releases/download/$LIBSODIUM_VER/libsodium-$LIBSODIUM_VER.tar.gz;
|
||||
tar xvf libsodium-$LIBSODIUM_VER.tar.gz;
|
||||
@@ -39,19 +39,17 @@ addons:
|
||||
sources:
|
||||
- george-edison55-precise-backports # cmake 3.2.3 / doxygen 1.8.3
|
||||
packages:
|
||||
- cmake
|
||||
- libc-ares-dev
|
||||
- libev-dev
|
||||
- asciidoc
|
||||
- xmlto
|
||||
script:
|
||||
- ./autogen.sh
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
./configure --disable-documentation --with-mbedtls=/usr/local/opt/mbedtls --with-sodium=/usr/local/opt/libsodium;
|
||||
else
|
||||
./configure;
|
||||
fi
|
||||
- git submodule update --init --recursive
|
||||
- mkdir -p build && cd build
|
||||
- cmake ..
|
||||
- make
|
||||
- cd build && cmake ../ && make
|
||||
- ctest --output-on-failure
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(PROJECT_NAME shadowsocks-libev)
|
||||
set(RELEASE_DATE 2020-09-15)
|
||||
@@ -8,9 +8,14 @@ set(PROJECT_URL "https://shadowsocks.org")
|
||||
set(PROJECT_ISSUES_URL "https://github.com/shadowsocks/shadowsocks-libev")
|
||||
project(${PROJECT_NAME} VERSION ${PROJECT_VERSION})
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# Compiler flags matching autotools
|
||||
# Note: -Werror is applied per-target in src/CMakeLists.txt to avoid
|
||||
# breaking bundled submodules (libcork, libipset, libbloom)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -D_GNU_SOURCE")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -Wall -Wno-deprecated-declarations -fno-strict-aliasing")
|
||||
|
||||
#set(PROJECT_BINARY_DIR ${PROJECT_SOURCE_DIR}/out)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
@@ -33,15 +38,48 @@ message(STATUS "Running cmake version ${CMAKE_VERSION}")
|
||||
|
||||
option(WITH_STATIC "build with static libraries." ON)
|
||||
option(WITH_EMBEDDED_SRC "build with embedded libcork, libipset, and libbloom source." ON)
|
||||
|
||||
# Will set GIT_EXECUTABLE and GIT_FOUND
|
||||
# find_package(Git)
|
||||
option(ENABLE_CONNMARKTOS "Enable saved connmark to IP TOS QoS feature" OFF)
|
||||
option(ENABLE_NFTABLES "Report malicious IP to nftables" OFF)
|
||||
|
||||
# When choose to not use embedded libcork, libipset and libbloom, use libs shipped by system
|
||||
if (NOT WITH_EMBEDDED_SRC)
|
||||
set(USE_SYSTEM_SHARED_LIB TRUE)
|
||||
endif ()
|
||||
|
||||
# Find dependencies via Find modules
|
||||
find_package(PCRE2 REQUIRED)
|
||||
find_package(MbedTLS REQUIRED)
|
||||
find_package(Sodium REQUIRED)
|
||||
find_package(Cares REQUIRED)
|
||||
|
||||
# Connmarktos support
|
||||
if(ENABLE_CONNMARKTOS)
|
||||
if(NOT LINUX)
|
||||
message(FATAL_ERROR "connmarktos is only supported on Linux")
|
||||
endif()
|
||||
find_library(NETFILTER_CONNTRACK_LIB netfilter_conntrack)
|
||||
find_library(NFNETLINK_LIB nfnetlink)
|
||||
if(NOT NETFILTER_CONNTRACK_LIB)
|
||||
message(FATAL_ERROR "--enable-connmarktos specified but libnetfilter_conntrack not found")
|
||||
endif()
|
||||
set(USE_NFCONNTRACK_TOS 1)
|
||||
message(STATUS "Connmarktos enabled")
|
||||
endif()
|
||||
|
||||
# Nftables support
|
||||
if(ENABLE_NFTABLES)
|
||||
if(NOT LINUX)
|
||||
message(FATAL_ERROR "nftables is only supported on Linux")
|
||||
endif()
|
||||
find_library(MNL_LIB mnl)
|
||||
find_library(NFTNL_LIB nftnl)
|
||||
if(NOT MNL_LIB OR NOT NFTNL_LIB)
|
||||
message(FATAL_ERROR "--enable-nftables specified but libmnl or libnftnl not found")
|
||||
endif()
|
||||
set(USE_NFTABLES 1)
|
||||
message(STATUS "Nftables enabled")
|
||||
endif()
|
||||
|
||||
# Run platform tests
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/configure.cmake)
|
||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/config.h.cmake ${PROJECT_BINARY_DIR}/src/config.h)
|
||||
@@ -56,7 +94,7 @@ configure_file(
|
||||
)
|
||||
install(FILES
|
||||
${PROJECT_BINARY_DIR}/pkgconfig/shadowsocks-libev.pc
|
||||
DESTINATION lib/pkgconfig
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
)
|
||||
|
||||
if (WITH_EMBEDDED_SRC)
|
||||
@@ -158,3 +196,16 @@ endif ()
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(doc)
|
||||
|
||||
# Testing
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
# Install ss-nat on Linux
|
||||
if(LINUX)
|
||||
install(PROGRAMS src/ss-nat DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
# Install ss-setup TUI tool
|
||||
install(PROGRAMS scripts/ss-setup.sh DESTINATION ${CMAKE_INSTALL_BINDIR} RENAME ss-setup)
|
||||
|
||||
@@ -1,365 +0,0 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
||||
2006, 2007, 2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell commands `./configure; make; make install' should
|
||||
configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
`INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the `make install' phase executed with root
|
||||
privileges.
|
||||
|
||||
5. Optionally, type `make installcheck' to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior `make install' required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
6. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
7. Often, you can also type `make uninstall' to remove the installed
|
||||
files again. In practice, not all packages have tested that
|
||||
uninstallation works correctly, even though it is required by the
|
||||
GNU Coding Standards.
|
||||
|
||||
8. Some packages, particularly those that use Automake, provide `make
|
||||
distcheck', which can by used by developers to test that all other
|
||||
targets like `make install' and `make uninstall' work correctly.
|
||||
This target is generally not run by end users.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'. This
|
||||
is known as a "VPATH" build.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
On MacOS X 10.5 and later systems, you can create libraries and
|
||||
executables that work on multiple system types--known as "fat" or
|
||||
"universal" binaries--by specifying multiple `-arch' options to the
|
||||
compiler but only a single `-arch' option to the preprocessor. Like
|
||||
this:
|
||||
|
||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CPP="gcc -E" CXXCPP="g++ -E"
|
||||
|
||||
This is not guaranteed to produce working output in all cases, you
|
||||
may have to build one architecture at a time and combine the results
|
||||
using the `lipo' tool if you have problems.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
|
||||
absolute file name.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the
|
||||
default for these options is expressed in terms of `${prefix}', so that
|
||||
specifying just `--prefix' will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to `configure'; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
`make install' command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, `make install
|
||||
prefix=/alternate/directory' will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
`${prefix}'. Any directories that were specified during `configure',
|
||||
but not in terms of `${prefix}', must each be overridden at install
|
||||
time for the entire installation to be relocated. The approach of
|
||||
makefile variable overrides for each directory variable is required by
|
||||
the GNU Coding Standards, and ideally causes no recompilation.
|
||||
However, some platforms have known limitations with the semantics of
|
||||
shared libraries that end up requiring recompilation when using this
|
||||
method, particularly noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the `DESTDIR' variable. For
|
||||
example, `make install DESTDIR=/alternate/directory' will prepend
|
||||
`/alternate/directory' before all installation names. The approach of
|
||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of `${prefix}'
|
||||
at `configure' time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of `make' will be. For these packages, running `./configure
|
||||
--enable-silent-rules' sets the default to minimal output, which can be
|
||||
overridden with `make V=1'; while running `./configure
|
||||
--disable-silent-rules' sets the default to verbose, which can be
|
||||
overridden with `make V=0'.
|
||||
|
||||
Particular systems
|
||||
==================
|
||||
|
||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
||||
CC is not installed, it is recommended to use the following options in
|
||||
order to use an ANSI C compiler:
|
||||
|
||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
||||
a workaround. If GNU CC is not installed, it is therefore recommended
|
||||
to try
|
||||
|
||||
./configure CC="cc"
|
||||
|
||||
and if that doesn't work, try
|
||||
|
||||
./configure CC="cc -nodtk"
|
||||
|
||||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
|
||||
directory contains several dysfunctional programs; working variants of
|
||||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
|
||||
in your `PATH', put it _after_ `/usr/bin'.
|
||||
|
||||
On Haiku, software installed for all users goes in `/boot/common',
|
||||
not `/usr/local'. It is recommended to use the following options:
|
||||
|
||||
./configure --prefix=/boot/common
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out
|
||||
automatically, but needs to determine by the type of machine the package
|
||||
will run on. Usually, assuming the package is built to be run on the
|
||||
_same_ architectures, `configure' can figure that out, but if it prints
|
||||
a message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS
|
||||
KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of all of the options to `configure', and exit.
|
||||
|
||||
`--help=short'
|
||||
`--help=recursive'
|
||||
Print a summary of the options unique to this package's
|
||||
`configure', and exit. The `short' variant lists options used
|
||||
only in the top level, while the `recursive' variant lists options
|
||||
also present in any nested packages.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--prefix=DIR'
|
||||
Use DIR as the installation prefix. *note Installation Names::
|
||||
for more details, including other options available for fine-tuning
|
||||
the installation locations.
|
||||
|
||||
`--no-create'
|
||||
`-n'
|
||||
Run the configure checks, but stop before creating any output
|
||||
files.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
if USE_SYSTEM_SHARED_LIB
|
||||
SUBDIRS = src
|
||||
else
|
||||
SUBDIRS = libcork libipset libbloom src
|
||||
endif
|
||||
|
||||
if ENABLE_DOCUMENTATION
|
||||
SUBDIRS += doc
|
||||
endif
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
pkgconfiglibdir = $(libdir)/pkgconfig
|
||||
pkgconfiglib_DATA = shadowsocks-libev.pc
|
||||
|
||||
EXTRA_DIST = acl Changes completions debian docker rpm scripts README.md
|
||||
EXTRA_DIST += libbloom
|
||||
EXTRA_DIST += libcork/include libipset/include
|
||||
EXTRA_DIST += libipset/src/libipset/map/inspection-template.c.in
|
||||
EXTRA_DIST += libipset/src/libipset/set/inspection-template.c.in
|
||||
+21
-11
@@ -79,8 +79,8 @@ git submodule update --init --recursive
|
||||
|
||||
### Pre-build configure guide
|
||||
|
||||
For a complete list of available configure-time option,
|
||||
try `configure --help`.
|
||||
For a complete list of available configure-time options,
|
||||
try `cmake -LH` from a build directory.
|
||||
|
||||
### Debian & Ubuntu
|
||||
|
||||
@@ -203,12 +203,12 @@ nix-env -iA nixpkgs.shadowsocks-libev
|
||||
|
||||
In general, you need the following build dependencies:
|
||||
|
||||
* autotools (autoconf, automake, libtool)
|
||||
* gettext
|
||||
* cmake (>= 3.2)
|
||||
* a C compiler (gcc or clang)
|
||||
* pkg-config
|
||||
* libmbedtls
|
||||
* libsodium
|
||||
* libpcre3 (old pcre library)
|
||||
* libsodium (>= 1.0.4)
|
||||
* libpcre2
|
||||
* libev
|
||||
* libc-ares
|
||||
* asciidoc (for documentation only)
|
||||
@@ -218,18 +218,18 @@ Notes: Fedora 26 libsodium version >= 1.0.12, so you can install via dnf instal
|
||||
|
||||
If your system is too old to provide libmbedtls and libsodium (later than **v1.0.8**), you will need to either install those libraries manually or upgrade your system.
|
||||
|
||||
If your system provides with those libraries, you **should not** install them from source.You should jump to this section and install them from the distribution repository instead.
|
||||
If your system provides with those libraries, you **should not** install them from source. You should jump to this section and install them from the distribution repository instead.
|
||||
|
||||
For some of the distributions, you might install build dependencies like this:
|
||||
|
||||
```bash
|
||||
# Installation of basic build dependencies
|
||||
## Debian / Ubuntu
|
||||
sudo apt-get install --no-install-recommends gettext build-essential autoconf libtool libpcre3-dev asciidoc xmlto libev-dev libc-ares-dev automake libmbedtls-dev libsodium-dev pkg-config
|
||||
sudo apt-get install --no-install-recommends build-essential cmake libpcre2-dev asciidoc xmlto libev-dev libc-ares-dev libmbedtls-dev libsodium-dev pkg-config
|
||||
## CentOS / Fedora / RHEL
|
||||
sudo yum install gettext gcc autoconf libtool automake make asciidoc xmlto c-ares-devel libev-devel
|
||||
sudo yum install gcc cmake make asciidoc xmlto c-ares-devel libev-devel
|
||||
## Arch
|
||||
sudo pacman -S gettext gcc autoconf libtool automake make asciidoc xmlto c-ares libev
|
||||
sudo pacman -S gcc cmake make asciidoc xmlto c-ares libev
|
||||
|
||||
# Installation of libsodium
|
||||
export LIBSODIUM_VER=1.0.16
|
||||
@@ -252,10 +252,20 @@ popd
|
||||
sudo ldconfig
|
||||
|
||||
# Start building
|
||||
./autogen.sh && ./configure && make
|
||||
git submodule update --init --recursive
|
||||
mkdir -p build && cd build
|
||||
cmake ..
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
To run unit tests:
|
||||
|
||||
```bash
|
||||
cd build
|
||||
ctest --output-on-failure
|
||||
```
|
||||
|
||||
You may need to manually install missing softwares.
|
||||
|
||||
### FreeBSD
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
autoreconf --install --force
|
||||
@@ -0,0 +1,44 @@
|
||||
# FindCares.cmake - Find c-ares library
|
||||
#
|
||||
# Sets:
|
||||
# CARES_FOUND
|
||||
# CARES_INCLUDE_DIRS
|
||||
# CARES_LIBRARIES
|
||||
|
||||
find_path(CARES_INCLUDE_DIR
|
||||
NAMES ares.h
|
||||
HINTS
|
||||
/opt/homebrew/include
|
||||
/usr/local/include
|
||||
/opt/homebrew/opt/c-ares/include
|
||||
/usr/local/opt/c-ares/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
find_library(CARES_LIBRARY
|
||||
NAMES cares
|
||||
HINTS
|
||||
/opt/homebrew/lib
|
||||
/usr/local/lib
|
||||
/opt/homebrew/opt/c-ares/lib
|
||||
/usr/local/opt/c-ares/lib
|
||||
/usr/lib
|
||||
)
|
||||
|
||||
if(CARES_INCLUDE_DIR AND CARES_LIBRARY)
|
||||
set(CARES_FOUND TRUE)
|
||||
set(CARES_INCLUDE_DIRS ${CARES_INCLUDE_DIR})
|
||||
set(CARES_LIBRARIES ${CARES_LIBRARY})
|
||||
|
||||
# Verify ares_library_init exists
|
||||
include(CheckLibraryExists)
|
||||
check_library_exists(cares ares_library_init "" CARES_HAS_INIT)
|
||||
if(NOT CARES_HAS_INIT)
|
||||
message(WARNING "c-ares found but ares_library_init not detected. Proceeding anyway.")
|
||||
endif()
|
||||
|
||||
message(STATUS "Found c-ares: ${CARES_LIBRARY}")
|
||||
else()
|
||||
set(CARES_FOUND FALSE)
|
||||
message(FATAL_ERROR "Could not find c-ares library. Install libc-ares-dev or equivalent.")
|
||||
endif()
|
||||
@@ -0,0 +1,88 @@
|
||||
# FindMbedTLS.cmake - Find mbedTLS library with feature detection
|
||||
#
|
||||
# Sets:
|
||||
# MBEDTLS_FOUND
|
||||
# MBEDTLS_INCLUDE_DIRS
|
||||
# MBEDTLS_CRYPTO_LIBRARY
|
||||
# MBEDTLS_TLS_LIBRARY
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
# mbedtls@3 is keg-only on Homebrew; also check versioned opt paths
|
||||
find_path(MBEDTLS_INCLUDE_DIR
|
||||
NAMES mbedtls/cipher.h
|
||||
HINTS
|
||||
/opt/homebrew/opt/mbedtls@3/include
|
||||
/usr/local/opt/mbedtls@3/include
|
||||
/opt/homebrew/opt/mbedtls/include
|
||||
/usr/local/opt/mbedtls/include
|
||||
/opt/homebrew/include
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
find_library(MBEDTLS_CRYPTO_LIBRARY
|
||||
NAMES mbedcrypto
|
||||
HINTS
|
||||
/opt/homebrew/opt/mbedtls@3/lib
|
||||
/usr/local/opt/mbedtls@3/lib
|
||||
/opt/homebrew/opt/mbedtls/lib
|
||||
/usr/local/opt/mbedtls/lib
|
||||
/opt/homebrew/lib
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
)
|
||||
|
||||
find_library(MBEDTLS_TLS_LIBRARY
|
||||
NAMES mbedtls
|
||||
HINTS
|
||||
/opt/homebrew/opt/mbedtls@3/lib
|
||||
/usr/local/opt/mbedtls@3/lib
|
||||
/opt/homebrew/opt/mbedtls/lib
|
||||
/usr/local/opt/mbedtls/lib
|
||||
/opt/homebrew/lib
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
)
|
||||
|
||||
if(MBEDTLS_INCLUDE_DIR AND MBEDTLS_CRYPTO_LIBRARY)
|
||||
set(MBEDTLS_FOUND TRUE)
|
||||
set(MBEDTLS_INCLUDE_DIRS ${MBEDTLS_INCLUDE_DIR})
|
||||
|
||||
# Check for required CFB mode support
|
||||
set(CMAKE_REQUIRED_INCLUDES ${MBEDTLS_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${MBEDTLS_CRYPTO_LIBRARY})
|
||||
|
||||
check_c_source_compiles("
|
||||
#include <mbedtls/cipher.h>
|
||||
#if !defined(MBEDTLS_CIPHER_MODE_CFB)
|
||||
#error CFB mode not supported
|
||||
#endif
|
||||
int main(void) { return 0; }
|
||||
" MBEDTLS_HAS_CFB)
|
||||
|
||||
if(NOT MBEDTLS_HAS_CFB)
|
||||
# Try mbedtls 3.x config path
|
||||
check_c_source_compiles("
|
||||
#include <mbedtls/build_info.h>
|
||||
#include <mbedtls/cipher.h>
|
||||
#if !defined(MBEDTLS_CIPHER_MODE_CFB)
|
||||
#error CFB mode not supported
|
||||
#endif
|
||||
int main(void) { return 0; }
|
||||
" MBEDTLS_HAS_CFB_V3)
|
||||
|
||||
if(NOT MBEDTLS_HAS_CFB_V3)
|
||||
message(FATAL_ERROR "mbedTLS found but MBEDTLS_CIPHER_MODE_CFB is not enabled. "
|
||||
"Please enable CFB mode in your mbedTLS configuration.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
unset(CMAKE_REQUIRED_INCLUDES)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
|
||||
message(STATUS "Found mbedTLS: ${MBEDTLS_CRYPTO_LIBRARY}")
|
||||
else()
|
||||
set(MBEDTLS_FOUND FALSE)
|
||||
message(FATAL_ERROR "Could not find mbedTLS library. Install libmbedtls-dev or equivalent.")
|
||||
endif()
|
||||
@@ -0,0 +1,63 @@
|
||||
# FindPCRE2.cmake - Find PCRE2 library (8-bit)
|
||||
#
|
||||
# Sets:
|
||||
# PCRE2_FOUND
|
||||
# PCRE2_INCLUDE_DIRS
|
||||
# PCRE2_LIBRARIES
|
||||
|
||||
include(FindPkgConfig)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(_PCRE2 QUIET libpcre2-8)
|
||||
endif()
|
||||
|
||||
if(_PCRE2_FOUND)
|
||||
set(PCRE2_INCLUDE_DIRS ${_PCRE2_INCLUDE_DIRS})
|
||||
set(PCRE2_LIBRARIES ${_PCRE2_LIBRARIES})
|
||||
set(PCRE2_FOUND TRUE)
|
||||
else()
|
||||
# Try pcre2-config
|
||||
find_program(PCRE2_CONFIG pcre2-config)
|
||||
if(PCRE2_CONFIG)
|
||||
execute_process(COMMAND ${PCRE2_CONFIG} --cflags
|
||||
OUTPUT_VARIABLE PCRE2_CFLAGS
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${PCRE2_CONFIG} --libs8
|
||||
OUTPUT_VARIABLE PCRE2_LDFLAGS
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(REGEX REPLACE "-I" "" PCRE2_INCLUDE_DIRS "${PCRE2_CFLAGS}")
|
||||
set(PCRE2_LIBRARIES ${PCRE2_LDFLAGS})
|
||||
set(PCRE2_FOUND TRUE)
|
||||
else()
|
||||
# Manual search
|
||||
find_path(PCRE2_INCLUDE_DIR
|
||||
NAMES pcre2.h
|
||||
HINTS
|
||||
/opt/homebrew/include
|
||||
/usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
find_library(PCRE2_LIBRARY
|
||||
NAMES pcre2-8
|
||||
HINTS
|
||||
/opt/homebrew/lib
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
)
|
||||
|
||||
if(PCRE2_INCLUDE_DIR AND PCRE2_LIBRARY)
|
||||
set(PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIR})
|
||||
set(PCRE2_LIBRARIES ${PCRE2_LIBRARY})
|
||||
set(PCRE2_FOUND TRUE)
|
||||
else()
|
||||
set(PCRE2_FOUND FALSE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(PCRE2_FOUND)
|
||||
message(STATUS "Found PCRE2: ${PCRE2_LIBRARIES}")
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find PCRE2 library. Install libpcre2-dev or equivalent.")
|
||||
endif()
|
||||
@@ -0,0 +1,57 @@
|
||||
# FindSodium.cmake - Find libsodium with version check
|
||||
#
|
||||
# Sets:
|
||||
# SODIUM_FOUND
|
||||
# SODIUM_INCLUDE_DIRS
|
||||
# SODIUM_LIBRARIES
|
||||
|
||||
find_path(SODIUM_INCLUDE_DIR
|
||||
NAMES sodium.h
|
||||
HINTS
|
||||
/opt/homebrew/include
|
||||
/usr/local/include
|
||||
/usr/local/opt/libsodium/include
|
||||
/opt/homebrew/opt/libsodium/include
|
||||
/usr/include
|
||||
$ENV{LIBSODIUM_INCLUDE_DIR}
|
||||
$ENV{LIBSODIUM_DIR}/include
|
||||
)
|
||||
|
||||
find_library(SODIUM_LIBRARY
|
||||
NAMES sodium
|
||||
HINTS
|
||||
/opt/homebrew/lib
|
||||
/usr/local/lib
|
||||
/usr/local/opt/libsodium/lib
|
||||
/opt/homebrew/opt/libsodium/lib
|
||||
/usr/lib
|
||||
)
|
||||
|
||||
if(SODIUM_INCLUDE_DIR AND SODIUM_LIBRARY)
|
||||
set(SODIUM_FOUND TRUE)
|
||||
set(SODIUM_INCLUDE_DIRS ${SODIUM_INCLUDE_DIR})
|
||||
set(SODIUM_LIBRARIES ${SODIUM_LIBRARY})
|
||||
|
||||
# Version check: require SODIUM_LIBRARY_VERSION_MAJOR >= 7 (libsodium >= 1.0.4)
|
||||
include(CheckCSourceCompiles)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${SODIUM_INCLUDE_DIR})
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${SODIUM_LIBRARY})
|
||||
check_c_source_compiles("
|
||||
#include <sodium.h>
|
||||
#if SODIUM_LIBRARY_VERSION_MAJOR < 7
|
||||
#error libsodium too old
|
||||
#endif
|
||||
int main(void) { return 0; }
|
||||
" SODIUM_VERSION_OK)
|
||||
unset(CMAKE_REQUIRED_INCLUDES)
|
||||
unset(CMAKE_REQUIRED_LIBRARIES)
|
||||
|
||||
if(NOT SODIUM_VERSION_OK)
|
||||
message(FATAL_ERROR "libsodium found but version is too old. Require >= 1.0.4 (SODIUM_LIBRARY_VERSION_MAJOR >= 7)")
|
||||
endif()
|
||||
|
||||
message(STATUS "Found libsodium: ${SODIUM_LIBRARY}")
|
||||
else()
|
||||
set(SODIUM_FOUND FALSE)
|
||||
message(FATAL_ERROR "Could not find libsodium. Install libsodium-dev or equivalent.")
|
||||
endif()
|
||||
@@ -87,11 +87,8 @@
|
||||
/* Define to 1 if you have the <net/if.h> header file. */
|
||||
#cmakedefine HAVE_NET_IF_H 1
|
||||
|
||||
/* Define to 1 if you have the <pcre.h> header file. */
|
||||
#cmakedefine HAVE_PCRE_H 1
|
||||
|
||||
/* Define to 1 if you have the <pcre/pcre.h> header file. */
|
||||
#cmakedefine HAVE_PCRE_PCRE_H 1
|
||||
/* Define to 1 if you have the <pcre2.h> header file. */
|
||||
#cmakedefine HAVE_PCRE2_H 1
|
||||
|
||||
/* Have PTHREAD_PRIO_INHERIT. */
|
||||
#cmakedefine HAVE_PTHREAD_PRIO_INHERIT 1
|
||||
@@ -236,6 +233,21 @@
|
||||
#endif
|
||||
|
||||
|
||||
/* Enable support for QOS netfilter mark preservation */
|
||||
#cmakedefine USE_NFCONNTRACK_TOS 1
|
||||
|
||||
/* Enable support for nftables firewall */
|
||||
#cmakedefine USE_NFTABLES 1
|
||||
|
||||
/* Define to 1 if you have the <linux/random.h> header file. */
|
||||
#cmakedefine HAVE_LINUX_RANDOM_H 1
|
||||
|
||||
/* Define to 1 if you have the `get_current_dir_name' function. */
|
||||
#cmakedefine HAVE_GET_CURRENT_DIR_NAME 1
|
||||
|
||||
/* Define to 1 if you have the `posix_memalign' function. */
|
||||
#cmakedefine HAVE_POSIX_MEMALIGN 1
|
||||
|
||||
/* Define if use system shared lib. */
|
||||
#cmakedefine USE_SYSTEM_SHARED_LIB 1
|
||||
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
# -------------------------------------------------------------
|
||||
# config.h
|
||||
|
||||
# If we generate config.h by automake
|
||||
#include_directories(.)
|
||||
|
||||
# Use cmake to generate config.h
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckFunctionExists)
|
||||
@@ -12,14 +9,20 @@ include(CheckSymbolExists)
|
||||
include(CheckLibraryExists)
|
||||
include(CheckTypeSize)
|
||||
include(CheckCSourceCompiles)
|
||||
include(CheckCCompilerFlag)
|
||||
|
||||
# Define if building universal (internal helper macro)
|
||||
# AC_APPLE_UNIVERSAL_BUILD
|
||||
set(CONNECT_IN_PROGRESS "EINPROGRESS")
|
||||
set(CONNECT_IN_PROGRESS "EINPROGRESS" CACHE STRING "")
|
||||
|
||||
# Set CONNECT_IN_PROGRESS based on platform
|
||||
if(MINGW)
|
||||
set(CONNECT_IN_PROGRESS "WSAEWOULDBLOCK")
|
||||
else()
|
||||
set(CONNECT_IN_PROGRESS "EINPROGRESS")
|
||||
endif()
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Darwin)
|
||||
set(CMAKE_REQUIRED_INCLUDES "/usr/local/include" "/usr/include")
|
||||
set(CMAKE_REQUIRED_INCLUDES "/usr/local/include" "/usr/include" "/opt/homebrew/include")
|
||||
endif ()
|
||||
|
||||
check_include_files(dlfcn.h HAVE_DLFCN_H)
|
||||
@@ -53,8 +56,10 @@ else ()
|
||||
endif ()
|
||||
check_include_files(linux/tcp.h HAVE_LINUX_TCP_H)
|
||||
check_include_files(net/if.h HAVE_NET_IF_H)
|
||||
check_include_files(pcre.h HAVE_PCRE_H)
|
||||
check_include_files(pcre/pcre.h HAVE_PCRE_PCRE_H)
|
||||
set(CMAKE_REQUIRED_DEFINITIONS_SAVE ${CMAKE_REQUIRED_DEFINITIONS})
|
||||
set(CMAKE_REQUIRED_DEFINITIONS "-DPCRE2_CODE_UNIT_WIDTH=8")
|
||||
check_include_files(pcre2.h HAVE_PCRE2_H)
|
||||
set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS_SAVE})
|
||||
check_symbol_exists(PTHREAD_PRIO_INHERIT pthread.h HAVE_PTHREAD_PRIO_INHERIT)
|
||||
|
||||
check_function_exists(select HAVE_SELECT)
|
||||
@@ -78,6 +83,8 @@ check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_files(sys/wait.h HAVE_SYS_WAIT_H)
|
||||
check_include_files(ares.h HAVE_ARES_H)
|
||||
check_include_files(unistd.h HAVE_UNISTD_H)
|
||||
check_include_files(arpa/inet.h HAVE_ARPA_INET_H)
|
||||
check_include_files(linux/random.h HAVE_LINUX_RANDOM_H)
|
||||
|
||||
check_function_exists(fork HAVE_FORK)
|
||||
check_function_exists(vfork HAVE_VFORK)
|
||||
@@ -89,6 +96,9 @@ if (HAVE_FORK)
|
||||
set(HAVE_WORKING_FORK 1)
|
||||
endif ()
|
||||
|
||||
# Additional function checks
|
||||
check_function_exists(get_current_dir_name HAVE_GET_CURRENT_DIR_NAME)
|
||||
check_function_exists(posix_memalign HAVE_POSIX_MEMALIGN)
|
||||
|
||||
# Define to the sub-directory where libtool stores uninstalled libraries.
|
||||
set(LT_OBJDIR ".libs/")
|
||||
@@ -101,8 +111,6 @@ set(PACKAGE_STRING "${PROJECT_NAME} ${PACKAGE_VERSION}")
|
||||
set(PACKAGE_TARNAME ${PROJECT_NAME})
|
||||
set(PACKAGE_URL "")
|
||||
|
||||
#message(${PACKAGE_NAME} - v${PACKAGE_VERSION} - v${PROJECT_VERSION})
|
||||
|
||||
# PTHREAD_CREATE_JOINABLE
|
||||
|
||||
# Define as the return type of signal handlers (`int' or `void').
|
||||
@@ -140,31 +148,7 @@ set(_TANDEM_SOURCE 1)
|
||||
set(__EXTENSIONS__ 1)
|
||||
# USE_SYSTEM_SHARED_LIB
|
||||
set(VERSION ${PACKAGE_VERSION})
|
||||
# TODO WORDS_BIGENDIAN
|
||||
# _MINIX
|
||||
# _POSIX_1_SOURCE
|
||||
# _POSIX_SOURCE
|
||||
# _UINT8_T
|
||||
|
||||
# Define to empty if `const' does not conform to ANSI C.
|
||||
# undef const
|
||||
|
||||
# Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
# calls it, or to nothing if 'inline' is not supported under any name.
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
# TODO Assume we got inline support
|
||||
# https://cmake.org/Wiki/CMakeTestInline
|
||||
|
||||
# Define to `int' if <sys/types.h> does not define.
|
||||
# undef pid_t
|
||||
# Define to the type of an unsigned integer type of width exactly 16 bits if
|
||||
# such a type exists and the standard includes do not define it.
|
||||
# undef uint16_t
|
||||
# Define to the type of an unsigned integer type of width exactly 8 bits if
|
||||
# such a type exists and the standard includes do not define it.
|
||||
# undef uint8_t
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES sys/types.h)
|
||||
check_type_size(pid_t PID_T)
|
||||
check_type_size(size_t SIZE_T)
|
||||
@@ -197,3 +181,18 @@ endif ()
|
||||
if (NOT HAVE_WORKING_VFORK)
|
||||
set(vfork fork)
|
||||
endif ()
|
||||
|
||||
# Stack protector detection
|
||||
option(DISABLE_SSP "Disable -fstack-protector" OFF)
|
||||
if(NOT DISABLE_SSP)
|
||||
check_c_compiler_flag(-fstack-protector HAS_STACK_PROTECTOR)
|
||||
if(HAS_STACK_PROTECTOR)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
|
||||
message(STATUS "Stack protector enabled")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# MinGW/Cygwin compiler flags
|
||||
if(MINGW OR CYGWIN)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mno-ms-bitfields")
|
||||
endif()
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=${prefix}/@CMAKE_INSTALL_BINDIR@
|
||||
libdir=${exec_prefix}/@CMAKE_INSTALL_FULL_LIBDIR@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=${prefix}
|
||||
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
|
||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
||||
sharedir=${prefix}/@CMAKE_INSTALL_DATAROOTDIR@
|
||||
mandir=${prefix}/@CMAKE_INSTALL_MANDIR@
|
||||
|
||||
Name: @PROJECT_NAME@
|
||||
Description: @PROJECT_DESC@
|
||||
@@ -11,4 +9,4 @@ URL: @PROJECT_URL@
|
||||
Version: @PROJECT_VERSION@
|
||||
Requires:
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lshadowsocks-libev -lcrypto
|
||||
Libs: -L${libdir} -lshadowsocks-libev
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
dnl -*- Autoconf -*-
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.67])
|
||||
AC_INIT([shadowsocks-libev], [3.3.5], [max.c.lv@gmail.com])
|
||||
AC_CONFIG_SRCDIR([src/crypto.c])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_AUX_DIR(auto)
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
|
||||
AM_INIT_AUTOMAKE([subdir-objects foreign -Wno-gnu -Werror])
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
AM_MAINTAINER_MODE
|
||||
AM_DEP_TRACK
|
||||
|
||||
dnl Checks for lib
|
||||
AC_DISABLE_STATIC
|
||||
AC_DISABLE_SHARED
|
||||
LT_INIT([dlopen])
|
||||
|
||||
dnl Check for pcre library
|
||||
TS_CHECK_PCRE
|
||||
if test "x${enable_pcre}" != "xyes"; then
|
||||
AC_MSG_ERROR([Cannot find pcre library. Configure --with-pcre=DIR])
|
||||
fi
|
||||
|
||||
dnl Checks for using shared libraries from system
|
||||
AC_ARG_ENABLE(
|
||||
[system-shared-lib],
|
||||
AS_HELP_STRING([--enable-system-shared-lib], [build against shared libraries when possible]),
|
||||
[
|
||||
case "${enableval}" in
|
||||
yes) enable_system_shared_lib=true ;;
|
||||
no) enable_system_shared_lib=false ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-system-shared-lib]) ;;
|
||||
esac], [enable_system_shared_lib=false])
|
||||
AM_CONDITIONAL([USE_SYSTEM_SHARED_LIB], [test x$enable_system_shared_lib = xtrue])
|
||||
|
||||
AC_ARG_ENABLE([documentation],
|
||||
AS_HELP_STRING([--disable-documentation], [do not build documentation]),
|
||||
[disable_documentation=true],
|
||||
[disable_documentation=false])
|
||||
AM_CONDITIONAL([ENABLE_DOCUMENTATION], [test x$disable_documentation = xfalse])
|
||||
|
||||
AM_COND_IF([ENABLE_DOCUMENTATION], [
|
||||
AC_PATH_PROG([ASCIIDOC], [asciidoc])
|
||||
test x"${ASCIIDOC}" != x || AC_MSG_ERROR([Cannot find `asciidoc` in PATH.])
|
||||
AC_PATH_PROG([XMLTO], [xmlto])
|
||||
test x"$XMLTO" != x || AC_MSG_ERROR([Cannot find `xmlto` in PATH.])
|
||||
AC_PATH_PROG([GZIP], [gzip], [gzip])
|
||||
AC_PATH_PROG([MV], [mv], [mv])
|
||||
AC_PROG_SED
|
||||
])
|
||||
|
||||
dnl Checks for programs.
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_LANG_SOURCE
|
||||
|
||||
dnl Add library for mingw
|
||||
case $host in
|
||||
*-mingw*)
|
||||
CFLAGS="$CFLAGS -mno-ms-bitfields"
|
||||
LIBS="$LIBS -lws2_32 -liphlpapi"
|
||||
;;
|
||||
*-cygwin*)
|
||||
CFLAGS="$CFLAGS -mno-ms-bitfields"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl Checks for TLS
|
||||
AX_TLS([:], [:])
|
||||
|
||||
dnl Checks for crypto libraries
|
||||
ss_MBEDTLS
|
||||
ss_SODIUM
|
||||
ss_CARES
|
||||
|
||||
dnl Checks for inet_ntop
|
||||
ss_FUNC_INET_NTOP
|
||||
|
||||
dnl Checks for host.
|
||||
AC_MSG_CHECKING(for what kind of host)
|
||||
case $host in
|
||||
*-linux*)
|
||||
os_support=linux
|
||||
AC_MSG_RESULT(Linux)
|
||||
;;
|
||||
*-mingw*)
|
||||
os_support=mingw
|
||||
AC_MSG_RESULT(MinGW)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT(transparent proxy does not support for $host)
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl Checks for pthread
|
||||
AX_PTHREAD([LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
CC="$PTHREAD_CC"], AC_MSG_ERROR(Can not find pthreads. This is required.))
|
||||
|
||||
dnl Checks for stack protector
|
||||
GGL_CHECK_STACK_PROTECTOR([has_stack_protector=yes], [has_stack_protector=no])
|
||||
# XXX - disable -fstack-protector due to missing libssp_nonshared
|
||||
case "$host_os" in
|
||||
*aix*)
|
||||
AC_MSG_NOTICE([-fstack-protector disabled on AIX])
|
||||
has_stack_protector=no
|
||||
;;
|
||||
*sunos*)
|
||||
AC_MSG_NOTICE([-fstack-protector disabled on SunOS])
|
||||
has_stack_protector=no
|
||||
;;
|
||||
*solaris*)
|
||||
AC_MSG_NOTICE([-fstack-protector disabled on Solaris])
|
||||
has_stack_protector=no
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_ARG_ENABLE(ssp,
|
||||
[AS_HELP_STRING(--disable-ssp,Do not compile with -fstack-protector)],
|
||||
[
|
||||
enable_ssp="no"
|
||||
],
|
||||
[
|
||||
enable_ssp="yes"
|
||||
])
|
||||
|
||||
if test x$has_stack_protector = xyes && test x$enable_ssp = xyes; then
|
||||
CFLAGS="$CFLAGS -fstack-protector"
|
||||
AC_MSG_NOTICE([-fstack-protector enabled in CFLAGS])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_REDIRECTOR, test "$os_support" = "linux")
|
||||
AM_CONDITIONAL(BUILD_WINCOMPAT, test "$os_support" = "mingw")
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_CHECK_HEADERS([limits.h stdint.h inttypes.h arpa/inet.h fcntl.h langinfo.h locale.h linux/tcp.h netinet/tcp.h netdb.h netinet/in.h stdlib.h string.h strings.h unistd.h sys/ioctl.h linux/random.h])
|
||||
|
||||
dnl A special check required for <net/if.h> on Darwin. See
|
||||
dnl http://www.gnu.org/software/autoconf/manual/html_node/Header-Portability.html.
|
||||
AC_CHECK_HEADERS([sys/socket.h])
|
||||
AC_CHECK_HEADERS([net/if.h], [], [],
|
||||
[
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
case $host in
|
||||
*-mingw*)
|
||||
AC_DEFINE([CONNECT_IN_PROGRESS], [WSAEWOULDBLOCK], [errno for incomplete non-blocking connect(2)])
|
||||
AC_CHECK_HEADERS([winsock2.h ws2tcpip.h mswsock.h], [], [AC_MSG_ERROR([Missing MinGW headers])], [])
|
||||
;;
|
||||
*-linux*)
|
||||
AC_DEFINE([CONNECT_IN_PROGRESS], [EINPROGRESS], [errno for incomplete non-blocking connect(2)])
|
||||
dnl Checks for netfilter headers
|
||||
AC_CHECK_HEADERS([linux/if.h linux/netfilter_ipv4.h linux/netfilter_ipv6/ip6_tables.h],
|
||||
[], [AC_MSG_ERROR([Missing netfilter headers])],
|
||||
[[
|
||||
#if HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
/* Netfilter ip(6)tables v1.4.0 has broken headers */
|
||||
#if HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#if HAVE_LINUX_IF_H
|
||||
#include <linux/if.h>
|
||||
#endif
|
||||
#if HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
]])
|
||||
;;
|
||||
*)
|
||||
# These are POSIX-like systems using BSD-like sockets API.
|
||||
AC_DEFINE([CONNECT_IN_PROGRESS], [EINPROGRESS], [errno for incomplete non-blocking connect(2)])
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_C_BIGENDIAN
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_INLINE
|
||||
AC_TYPE_SSIZE_T
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_ASSERT
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT8_T
|
||||
AC_HEADER_TIME
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_FUNC_FORK
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
AC_TYPE_SIGNAL
|
||||
AC_CHECK_FUNCS([memset select setresuid setreuid strerror get_current_dir_name getpwnam_r setrlimit])
|
||||
|
||||
AC_CHECK_LIB(socket, connect)
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_CHECK_FUNCS([malloc memset posix_memalign socket])
|
||||
|
||||
AC_ARG_WITH(ev,
|
||||
AS_HELP_STRING([--with-ev=DIR], [use a specific libev library]),
|
||||
[CFLAGS="$CFLAGS -I$withval/include"
|
||||
CPPFLAGS="$CPPFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
||||
)
|
||||
AC_CHECK_HEADERS([ev.h libev/ev.h], [], [])
|
||||
AC_CHECK_LIB([ev], [ev_loop_destroy], [LIBS="-lev $LIBS"], [AC_MSG_ERROR([Couldn't find libev. Try installing libev-dev@<:@el@:>@.])])
|
||||
|
||||
AC_CONFIG_FILES([shadowsocks-libev.pc
|
||||
Makefile
|
||||
doc/Makefile
|
||||
src/Makefile])
|
||||
|
||||
AM_COND_IF([USE_SYSTEM_SHARED_LIB],
|
||||
[AC_DEFINE([USE_SYSTEM_SHARED_LIB], [1], [Define if use system shared lib.])],
|
||||
[AC_CONFIG_FILES([libbloom/Makefile libcork/Makefile libipset/Makefile])])
|
||||
|
||||
AC_ARG_ENABLE(connmarktos,
|
||||
[AS_HELP_STRING(--enable-connmarktos, Enable saved connmark to IP TOS QoS feature)],
|
||||
[ enable_connmarktos="$enableval" ])
|
||||
|
||||
if test x"$enable_connmarktos" = "xyes" ; then
|
||||
AC_MSG_NOTICE([Linux Netfilter Conntrack support requested by --enable-connmarktos: ${enable_connmarktos}])
|
||||
if test "x$enable_connmarktos" != "xno"; then
|
||||
PKG_CHECK_MODULES([NETFILTER_CONNTRACK], [libnetfilter_conntrack],,
|
||||
[AC_SEARCH_LIBS([nfct_query], [netfilter_conntrack],,[
|
||||
if test x"$enable_connmarktos" = "xyes"; then
|
||||
AC_MSG_ERROR([--enable-connmarktos specified but libnetfilter-conntrack library not found])
|
||||
fi
|
||||
with_netfilter_conntrack=no], [-lnfnetlink])
|
||||
AC_CHECK_HEADERS([libnetfilter_conntrack/libnetfilter_conntrack.h \
|
||||
libnetfilter_conntrack/libnetfilter_conntrack_tcp.h],,[
|
||||
if test x"$enable_connmarktos" = "xyes"; then
|
||||
AC_MSG_ERROR([--enable-connmarktos specified but libnetfilter-conntrack headers not found])
|
||||
fi
|
||||
with_netfilter_conntrack=no])])
|
||||
# If nothing is broken; enable the libraries usage.
|
||||
if test "x$with_netfilter_conntrack" != "xno"; then
|
||||
with_netfilter_conntrack=yes
|
||||
AC_DEFINE(USE_NFCONNTRACK_TOS, 1, [Enable support for QOS netfilter mark preservation])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(nftables,
|
||||
[AS_HELP_STRING(--enable-nftables, report malicious IP to nftables)],
|
||||
[ enable_nftables="$enableval" ])
|
||||
|
||||
if test x"$enable_nftables" = "xyes" ; then
|
||||
AC_MSG_NOTICE([Linux nftables support requested by --enable-nftables: ${enable_nftables}])
|
||||
if test "x$enable_nftables" != "xno"; then
|
||||
PKG_CHECK_MODULES([NFTABLES], [libmnl libnftnl],,
|
||||
[AC_SEARCH_LIBS([mnl_socket_open], [mnl],,[
|
||||
if test x"$enable_nftables" = "xyes"; then
|
||||
AC_MSG_ERROR([--enable-nftables specified but libmnl library not found])
|
||||
fi
|
||||
with_nftables=no], [-lmnl])
|
||||
AC_CHECK_HEADERS([libmnl/libmnl.h],,[
|
||||
if test x"$enable_nftables" = "xyes"; then
|
||||
AC_MSG_ERROR([--enable-nftables specified but libmnl headers not found])
|
||||
fi
|
||||
with_nftables=no])
|
||||
AC_SEARCH_LIBS([nftnl_nlmsg_build_hdr], [nftnl],,[
|
||||
if test x"$enable_nftables" = "xyes"; then
|
||||
AC_MSG_ERROR([--enable-nftables specified but libnftnl library not found])
|
||||
fi
|
||||
with_nftables=no], [-lnftnl])
|
||||
AC_CHECK_HEADERS([libnftnl/common.h],,[
|
||||
if test x"$enable_nftables" = "xyes"; then
|
||||
AC_MSG_ERROR([--enable-nftables specified but libnftnl headers not found])
|
||||
fi
|
||||
with_nftables=no])])
|
||||
# If nothing is broken; enable the libraries usage.
|
||||
if test "x$with_nftables" != "xno"; then
|
||||
with_nftables=yes
|
||||
AC_DEFINE(USE_NFTABLES, 1, [Enable support for nftables firewall])
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_OUTPUT
|
||||
@@ -1,60 +0,0 @@
|
||||
ASCIIDOC = @ASCIIDOC@
|
||||
ASCIIDOC_EXTRA =
|
||||
MANPAGE_XSL = $(srcdir)/manpage-normal.xsl
|
||||
XMLTO = @XMLTO@
|
||||
XMLTO_EXTRA = -m $(srcdir)/manpage-bold-literal.xsl
|
||||
GZIPCMD = @GZIP@
|
||||
INSTALL = @INSTALL@
|
||||
RM = @RM@
|
||||
MV = @MV@
|
||||
SED = @SED@
|
||||
VERSION = `$(SED) -n 's/.*PACKAGE_VERSION "\(.*\)"/\1/p'\
|
||||
../config.h`
|
||||
|
||||
# Guard against environment variables
|
||||
MAN1_DOC =
|
||||
MAN1_DOC += ss-local.1
|
||||
MAN1_DOC += ss-manager.1
|
||||
MAN1_DOC += ss-nat.1
|
||||
MAN1_DOC += ss-redir.1
|
||||
MAN1_DOC += ss-server.1
|
||||
MAN1_DOC += ss-tunnel.1
|
||||
|
||||
MAN8_DOC =
|
||||
MAN8_DOC += shadowsocks-libev.8
|
||||
|
||||
MAN8_XML = $(MAN8_DOC:%.8=%.xml)
|
||||
MAN1_XML = $(MAN1_DOC:%.1=%.xml)
|
||||
MAN_XML = $(MAN8_XML) $(MAN1_XML)
|
||||
|
||||
MAN8_HTML = $(MAN8_DOC:%.8=%.html)
|
||||
MAN1_HTML = $(MAN1_DOC:%.1=%.html)
|
||||
MAN_HTML = $(MAN8_HTML) $(MAN1_HTML)
|
||||
|
||||
MAN8_TXT = $(MAN8_DOC:%.8=%.asciidoc)
|
||||
MAN1_TXT = $(MAN1_DOC:%.1=%.asciidoc)
|
||||
MAN_TXT = $(MAN8_TXT) $(MAN1_TXT)
|
||||
|
||||
man_MANS = $(MAN8_DOC) $(MAN1_DOC)
|
||||
|
||||
html-local: $(MAN_HTML)
|
||||
|
||||
%.1: %.xml
|
||||
$(AM_V_GEN)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
|
||||
|
||||
%.8: %.xml
|
||||
$(AM_V_GEN)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
|
||||
|
||||
%.xml: %.asciidoc
|
||||
$(AM_V_GEN)$(ASCIIDOC) -b docbook -d manpage -f $(srcdir)/asciidoc.conf \
|
||||
-aversion=$(VERSION) $(ASCIIDOC_EXTRA) -o $@ $<
|
||||
|
||||
%.html: %.asciidoc
|
||||
$(AM_V_GEN)$(ASCIIDOC) -b html4 -d article -f $(srcdir)/asciidoc.conf \
|
||||
-aversion=$(VERSION) $(ASCIIDOC_EXTRA) -o $@ $<
|
||||
|
||||
doc_DATA = $(MAN_HTML)
|
||||
|
||||
CLEANFILES = $(MAN_XML) $(man_MANS) $(MAN_HTML)
|
||||
|
||||
EXTRA_DIST = *.asciidoc asciidoc.conf *.xsl
|
||||
@@ -151,6 +151,26 @@ Only available with Linux kernel > 3.9.0.
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
Set TCP send buffer size for incoming connections.
|
||||
+
|
||||
Not available in manager mode.
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
+
|
||||
Not available in manager mode.
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
+
|
||||
Not available in manager mode.
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
+
|
||||
Not available in manager mode.
|
||||
|
||||
--acl <acl_config>::
|
||||
Enable ACL (Access Control List) and specify config file.
|
||||
+
|
||||
@@ -166,6 +186,17 @@ Specify the executable path of `ss-server`.
|
||||
+
|
||||
Only available in manager mode.
|
||||
|
||||
-D <path>::
|
||||
--workdir <path>::
|
||||
Specify the working directory of ss-manager.
|
||||
+
|
||||
Only available in manager mode.
|
||||
|
||||
--nftables-sets <family:table:set>::
|
||||
Specify nftables sets for reporting malicious IPs.
|
||||
+
|
||||
Only available in server mode, when built with nftables support.
|
||||
|
||||
-v::
|
||||
Enable verbose mode.
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ Enable UDP relay.
|
||||
Enable UDP relay and disable TCP relay.
|
||||
|
||||
-6::
|
||||
Resovle hostname to IPv6 address first.
|
||||
Resolve hostname to IPv6 address first.
|
||||
|
||||
--fast-open::
|
||||
Enable TCP fast open.
|
||||
@@ -130,6 +130,18 @@ Only available with MPTCP enabled Linux kernel.
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
Set TCP send buffer size for incoming connections.
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
|
||||
--plugin <plugin_name>::
|
||||
Enable SIP003 plugin. (Experimental)
|
||||
|
||||
|
||||
@@ -117,7 +117,8 @@ Specify the executable path of ss-server.
|
||||
+
|
||||
Only available in manager mode.
|
||||
|
||||
--executable <path_to_server_executable>::
|
||||
-D <path>::
|
||||
--workdir <path>::
|
||||
Specify the working directory of ss-manager.
|
||||
+
|
||||
Only available in manager mode.
|
||||
|
||||
@@ -99,7 +99,7 @@ Enable UDP relay and disable TCP relay.
|
||||
Use tproxy instead of redirect. (for tcp)
|
||||
|
||||
-6::
|
||||
Resovle hostname to IPv6 address first.
|
||||
Resolve hostname to IPv6 address first.
|
||||
|
||||
--mtu <MTU>::
|
||||
Specify the MTU of your network interface.
|
||||
@@ -117,6 +117,18 @@ Only available with Linux kernel > 3.9.0.
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
Set TCP send buffer size for incoming connections.
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
|
||||
--plugin <plugin_name>::
|
||||
Enable SIP003 plugin. (Experimental)
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ Enable UDP relay.
|
||||
Enable UDP relay and disable TCP relay.
|
||||
|
||||
-6::
|
||||
Resovle hostname to IPv6 address first.
|
||||
Resolve hostname to IPv6 address first.
|
||||
|
||||
-d <addr>::
|
||||
Setup name servers for internal DNS resolver (libc-ares).
|
||||
@@ -118,6 +118,18 @@ Only available with Linux kernel > 3.9.0.
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
Set TCP send buffer size for incoming connections.
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
|
||||
--acl <acl_config>::
|
||||
Enable ACL (Access Control List) and specify config file.
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ Enable UDP relay.
|
||||
Enable UDP relay and disable TCP relay.
|
||||
|
||||
-6::
|
||||
Resovle hostname to IPv6 address first.
|
||||
Resolve hostname to IPv6 address first.
|
||||
|
||||
-L <addr:port>::
|
||||
Specify destination server address and port for local port forwarding.
|
||||
@@ -126,6 +126,18 @@ Only available with Linux kernel > 3.9.0.
|
||||
--no-delay::
|
||||
Enable TCP_NODELAY.
|
||||
|
||||
--tcp-incoming-sndbuf <size>::
|
||||
Set TCP send buffer size for incoming connections.
|
||||
|
||||
--tcp-incoming-rcvbuf <size>::
|
||||
Set TCP receive buffer size for incoming connections.
|
||||
|
||||
--tcp-outgoing-sndbuf <size>::
|
||||
Set TCP send buffer size for outgoing connections.
|
||||
|
||||
--tcp-outgoing-rcvbuf <size>::
|
||||
Set TCP receive buffer size for outgoing connections.
|
||||
|
||||
--plugin <plugin_name>::
|
||||
Enable SIP003 plugin. (Experimental)
|
||||
|
||||
@@ -138,6 +150,19 @@ Enable verbose mode.
|
||||
-h|--help::
|
||||
Print help message.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
`ss-tunnel`(1) can be used to forward DNS queries to a remote DNS server
|
||||
through the shadowsocks tunnel. Here is an example:
|
||||
|
||||
....
|
||||
# Forward local UDP port 5353 to 8.8.8.8:53 through the ss-server
|
||||
ss-tunnel -s example.com -p 12345 -l 5353 -k foobar -m aes-256-cfb -L 8.8.8.8:53 -u
|
||||
|
||||
# Then configure your system to use 127.0.0.1:5353 as the DNS server
|
||||
dig @127.0.0.1 -p 5353 www.google.com
|
||||
....
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
`ss-local`(1),
|
||||
|
||||
@@ -14,21 +14,19 @@ COPY . /tmp/repo
|
||||
RUN set -x \
|
||||
# Build environment setup
|
||||
&& apk add --no-cache --virtual .build-deps \
|
||||
autoconf \
|
||||
automake \
|
||||
build-base \
|
||||
cmake \
|
||||
c-ares-dev \
|
||||
libcap \
|
||||
libev-dev \
|
||||
libtool \
|
||||
libsodium-dev \
|
||||
linux-headers \
|
||||
mbedtls-dev \
|
||||
pcre-dev \
|
||||
pcre2-dev \
|
||||
# Build & install
|
||||
&& cd /tmp/repo \
|
||||
&& ./autogen.sh \
|
||||
&& ./configure --prefix=/usr/local --disable-documentation \
|
||||
&& mkdir -p build && cd build \
|
||||
&& cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_TESTING=OFF -DWITH_STATIC=OFF -DCMAKE_BUILD_TYPE=Release \
|
||||
&& make -j$(getconf _NPROCESSORS_ONLN) \
|
||||
&& make install \
|
||||
&& cd /usr/local/bin \
|
||||
|
||||
@@ -1,485 +0,0 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro figures out how to build C programs using POSIX threads. It
|
||||
# sets the PTHREAD_LIBS output variable to the threads library and linker
|
||||
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
|
||||
# flags that are needed. (The user can also force certain compiler
|
||||
# flags/libs to be tested by setting these environment variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also to link with them as well. For example, you might link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threaded programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
|
||||
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
||||
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
||||
# PTHREAD_CFLAGS.
|
||||
#
|
||||
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
|
||||
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
|
||||
# is not found. If ACTION-IF-FOUND is not specified, the default action
|
||||
# will define HAVE_PTHREAD.
|
||||
#
|
||||
# Please let the authors know if this macro fails on any platform, or if
|
||||
# you have any other suggestions or comments. This macro was based on work
|
||||
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
|
||||
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
|
||||
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
|
||||
# grateful for the helpful feedback of numerous users.
|
||||
#
|
||||
# Updated for Autoconf 2.68 by Daniel Richard G.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 23
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_PROG_SED])
|
||||
AC_LANG_PUSH([C])
|
||||
ax_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on Tru64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
|
||||
ax_pthread_save_CC="$CC"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
CC="$ax_pthread_save_CC"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
# names; the ordering is very important because some systems
|
||||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
|
||||
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
||||
# pthreads: AIX (must check this before -lpthread)
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
|
||||
# (Note: HP C rejects this with "bad form for `-t' option")
|
||||
# -pthreads: Solaris/gcc (Note: HP C also rejects)
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads and
|
||||
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
|
||||
# is present but should not be used directly; and before -mthreads,
|
||||
# because the compiler interprets this as "-mt" + "-hreads")
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case $host_os in
|
||||
|
||||
freebsd*)
|
||||
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
|
||||
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
hpux*)
|
||||
|
||||
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
|
||||
# multi-threading and also sets -lpthread."
|
||||
|
||||
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
openedition*)
|
||||
|
||||
# IBM z/OS requires a feature-test macro to be defined in order to
|
||||
# enable POSIX threads at all, so give the user a hint if this is
|
||||
# not set. (We don't define these ourselves, as they can affect
|
||||
# other portions of the system API in unpredictable ways.)
|
||||
|
||||
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
|
||||
[
|
||||
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
|
||||
AX_PTHREAD_ZOS_MISSING
|
||||
# endif
|
||||
],
|
||||
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
|
||||
;;
|
||||
|
||||
solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (N.B.: The stubs are missing
|
||||
# pthread_cleanup_push, or rather a function called by this macro,
|
||||
# so we could check for that, but who knows whether they'll stub
|
||||
# that too in a future libc.) So we'll check first for the
|
||||
# standard Solaris way of linking pthreads (-mt -lpthread).
|
||||
|
||||
ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
|
||||
|
||||
AS_IF([test "x$GCC" = "xyes"],
|
||||
[ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
|
||||
|
||||
# The presence of a feature test macro requesting re-entrant function
|
||||
# definitions is, on some systems, a strong hint that pthreads support is
|
||||
# correctly enabled
|
||||
|
||||
case $host_os in
|
||||
darwin* | hpux* | linux* | osf* | solaris*)
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
;;
|
||||
|
||||
aix*)
|
||||
ax_pthread_check_macro="_THREAD_SAFE"
|
||||
;;
|
||||
|
||||
*)
|
||||
ax_pthread_check_macro="--"
|
||||
;;
|
||||
esac
|
||||
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
|
||||
[ax_pthread_check_cond=0],
|
||||
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
|
||||
|
||||
# Are we compiling with Clang?
|
||||
|
||||
AC_CACHE_CHECK([whether $CC is Clang],
|
||||
[ax_cv_PTHREAD_CLANG],
|
||||
[ax_cv_PTHREAD_CLANG=no
|
||||
# Note that Autoconf sets GCC=yes for Clang as well as GCC
|
||||
if test "x$GCC" = "xyes"; then
|
||||
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
|
||||
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
|
||||
# if defined(__clang__) && defined(__llvm__)
|
||||
AX_PTHREAD_CC_IS_CLANG
|
||||
# endif
|
||||
],
|
||||
[ax_cv_PTHREAD_CLANG=yes])
|
||||
fi
|
||||
])
|
||||
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
|
||||
|
||||
ax_pthread_clang_warning=no
|
||||
|
||||
# Clang needs special handling, because older versions handle the -pthread
|
||||
# option in a rather... idiosyncratic way
|
||||
|
||||
if test "x$ax_pthread_clang" = "xyes"; then
|
||||
|
||||
# Clang takes -pthread; it has never supported any other flag
|
||||
|
||||
# (Note 1: This will need to be revisited if a system that Clang
|
||||
# supports has POSIX threads in a separate library. This tends not
|
||||
# to be the way of modern systems, but it's conceivable.)
|
||||
|
||||
# (Note 2: On some systems, notably Darwin, -pthread is not needed
|
||||
# to get POSIX threads support; the API is always present and
|
||||
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
|
||||
# -pthread does define _REENTRANT, and while the Darwin headers
|
||||
# ignore this macro, third-party headers might not.)
|
||||
|
||||
PTHREAD_CFLAGS="-pthread"
|
||||
PTHREAD_LIBS=
|
||||
|
||||
ax_pthread_ok=yes
|
||||
|
||||
# However, older versions of Clang make a point of warning the user
|
||||
# that, in an invocation where only linking and no compilation is
|
||||
# taking place, the -pthread option has no effect ("argument unused
|
||||
# during compilation"). They expect -pthread to be passed in only
|
||||
# when source code is being compiled.
|
||||
#
|
||||
# Problem is, this is at odds with the way Automake and most other
|
||||
# C build frameworks function, which is that the same flags used in
|
||||
# compilation (CFLAGS) are also used in linking. Many systems
|
||||
# supported by AX_PTHREAD require exactly this for POSIX threads
|
||||
# support, and in fact it is often not straightforward to specify a
|
||||
# flag that is used only in the compilation phase and not in
|
||||
# linking. Such a scenario is extremely rare in practice.
|
||||
#
|
||||
# Even though use of the -pthread flag in linking would only print
|
||||
# a warning, this can be a nuisance for well-run software projects
|
||||
# that build with -Werror. So if the active version of Clang has
|
||||
# this misfeature, we search for an option to squash it.
|
||||
|
||||
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
|
||||
# Create an alternate version of $ac_link that compiles and
|
||||
# links in two steps (.c -> .o, .o -> exe) instead of one
|
||||
# (.c -> exe), because the warning occurs only in the second
|
||||
# step
|
||||
ax_pthread_save_ac_link="$ac_link"
|
||||
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
|
||||
ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
|
||||
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
|
||||
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
|
||||
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[ac_link="$ax_pthread_2step_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[break])
|
||||
])
|
||||
done
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
|
||||
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
|
||||
])
|
||||
|
||||
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
|
||||
no | unknown) ;;
|
||||
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
|
||||
esac
|
||||
|
||||
fi # $ax_pthread_clang = yes
|
||||
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
for ax_pthread_try_flag in $ax_pthread_flags; do
|
||||
|
||||
case $ax_pthread_try_flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-mt,pthread)
|
||||
AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
|
||||
PTHREAD_CFLAGS="-mt"
|
||||
PTHREAD_LIBS="-lpthread"
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
|
||||
PTHREAD_CFLAGS="$ax_pthread_try_flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
|
||||
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
|
||||
PTHREAD_LIBS="-l$ax_pthread_try_flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
# need a special flag -Kthread to make this header compile.)
|
||||
# We check for pthread_join because it is in -lpthread on IRIX
|
||||
# while pthread_create is in libc. We check for pthread_attr_init
|
||||
# due to DEC craziness with -lpthreads. We check for
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
|
||||
# if $ax_pthread_check_cond
|
||||
# error "$ax_pthread_check_macro must be defined"
|
||||
# endif
|
||||
static void routine(void *a) { a = 0; }
|
||||
static void *start_routine(void *a) { return a; }],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
pthread_create(&th, 0, start_routine, 0);
|
||||
pthread_join(th, 0);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_cleanup_push(routine, 0);
|
||||
pthread_cleanup_pop(0) /* ; */])],
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_CACHE_CHECK([for joinable pthread attribute],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
|
||||
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $ax_pthread_attr; return attr /* ; */])],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
|
||||
[])
|
||||
done
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
|
||||
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
|
||||
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
|
||||
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
|
||||
[$ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
ax_pthread_joinable_attr_defined=yes
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([whether more special flags are required for pthreads],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
|
||||
case $host_os in
|
||||
solaris*)
|
||||
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
|
||||
;;
|
||||
esac
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
|
||||
test "x$ax_pthread_special_flags_added" != "xyes"],
|
||||
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
|
||||
ax_pthread_special_flags_added=yes])
|
||||
|
||||
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
|
||||
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
|
||||
ax_pthread_prio_inherit_defined=yes
|
||||
])
|
||||
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
# More AIX lossage: compile with *_r variant
|
||||
if test "x$GCC" != "xyes"; then
|
||||
case $host_os in
|
||||
aix*)
|
||||
AS_CASE(["x/$CC"],
|
||||
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
||||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
|
||||
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
|
||||
|
||||
AC_SUBST([PTHREAD_LIBS])
|
||||
AC_SUBST([PTHREAD_CFLAGS])
|
||||
AC_SUBST([PTHREAD_CC])
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
|
||||
:
|
||||
else
|
||||
ax_pthread_ok=no
|
||||
$2
|
||||
fi
|
||||
AC_LANG_POP
|
||||
])dnl AX_PTHREAD
|
||||
@@ -1,74 +0,0 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_tls.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_TLS([action-if-found], [action-if-not-found])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Provides a test for the compiler support of thread local storage (TLS)
|
||||
# extensions. Defines TLS if it is found. Currently knows about GCC/ICC
|
||||
# and MSVC. I think SunPro uses the same as GCC, and Borland apparently
|
||||
# supports either.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Alan Woodland <ajw05@aber.ac.uk>
|
||||
# Copyright (c) 2010 Diego Elio Petteno` <flameeyes@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 11
|
||||
|
||||
AC_DEFUN([AX_TLS], [
|
||||
AC_MSG_CHECKING([for thread local storage (TLS) class])
|
||||
AC_CACHE_VAL([ac_cv_tls],
|
||||
[for ax_tls_keyword in __thread '__declspec(thread)' none; do
|
||||
AS_CASE([$ax_tls_keyword],
|
||||
[none], [ac_cv_tls=none ; break],
|
||||
[AC_TRY_COMPILE(
|
||||
[#include <stdlib.h>
|
||||
static void
|
||||
foo(void) {
|
||||
static ] $ax_tls_keyword [ int bar;
|
||||
exit(1);
|
||||
}],
|
||||
[],
|
||||
[ac_cv_tls=$ax_tls_keyword ; break],
|
||||
ac_cv_tls=none
|
||||
)])
|
||||
done
|
||||
])
|
||||
AC_MSG_RESULT([$ac_cv_tls])
|
||||
|
||||
AS_IF([test "$ac_cv_tls" != "none"],
|
||||
[AC_DEFINE_UNQUOTED([TLS],[$ac_cv_tls],[If the compiler supports a TLS storage class define it to that here])
|
||||
m4_ifnblank([$1],[$1])],
|
||||
[m4_ifnblank([$2],[$2])])
|
||||
])
|
||||
@@ -1,30 +0,0 @@
|
||||
dnl Check to find the libcares headers/libraries
|
||||
|
||||
AC_DEFUN([ss_CARES],
|
||||
[
|
||||
|
||||
AC_ARG_WITH(cares,
|
||||
AS_HELP_STRING([--with-cares=DIR], [The c-ares library base directory, or:]),
|
||||
[cares="$withval"
|
||||
CFLAGS="$CFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(cares-include,
|
||||
AS_HELP_STRING([--with-cares-include=DIR], [The c-ares library headers directory (without trailing /cares)]),
|
||||
[cares_include="$withval"
|
||||
CFLAGS="$CFLAGS -I$withval"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(cares-lib,
|
||||
AS_HELP_STRING([--with-cares-lib=DIR], [The c-ares library library directory]),
|
||||
[cares_lib="$withval"
|
||||
LDFLAGS="$LDFLAGS -L$withval"]
|
||||
)
|
||||
|
||||
AC_CHECK_LIB(cares, ares_library_init,
|
||||
[LIBS="-lcares $LIBS"],
|
||||
[AC_MSG_ERROR([The c-ares library libraries not found.])]
|
||||
)
|
||||
|
||||
])
|
||||
@@ -1,41 +0,0 @@
|
||||
# inet_ntop.m4 serial 19
|
||||
dnl Copyright (C) 2005-2006, 2008-2013 Free Software Foundation, Inc.
|
||||
dnl This file is free software; the Free Software Foundation
|
||||
dnl gives unlimited permission to copy and/or distribute it,
|
||||
dnl with or without modifications, as long as this notice is preserved.
|
||||
|
||||
AC_DEFUN([ss_FUNC_INET_NTOP],
|
||||
[
|
||||
AC_REQUIRE([AC_C_RESTRICT])
|
||||
|
||||
dnl Most platforms that provide inet_ntop define it in libc.
|
||||
dnl Solaris 8..10 provide inet_ntop in libnsl instead.
|
||||
dnl Solaris 2.6..7 provide inet_ntop in libresolv instead.
|
||||
HAVE_INET_NTOP=1
|
||||
INET_NTOP_LIB=
|
||||
ss_save_LIBS=$LIBS
|
||||
AC_SEARCH_LIBS([inet_ntop], [nsl resolv], [],
|
||||
[AC_CHECK_FUNCS([inet_ntop])
|
||||
if test $ac_cv_func_inet_ntop = no; then
|
||||
HAVE_INET_NTOP=0
|
||||
fi
|
||||
])
|
||||
LIBS=$ss_save_LIBS
|
||||
|
||||
if test "$ac_cv_search_inet_ntop" != "no" \
|
||||
&& test "$ac_cv_search_inet_ntop" != "none required"; then
|
||||
INET_NTOP_LIB="$ac_cv_search_inet_ntop"
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS_ONCE([netdb.h])
|
||||
AC_CHECK_DECLS([inet_ntop],,,
|
||||
[[#include <arpa/inet.h>
|
||||
#if HAVE_NETDB_H
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
]])
|
||||
if test $ac_cv_have_decl_inet_ntop = no; then
|
||||
HAVE_DECL_INET_NTOP=0
|
||||
fi
|
||||
AC_SUBST([INET_NTOP_LIB])
|
||||
])
|
||||
@@ -1,114 +0,0 @@
|
||||
dnl Check to find the mbed TLS headers/libraries
|
||||
|
||||
AC_DEFUN([ss_MBEDTLS],
|
||||
[
|
||||
|
||||
AC_ARG_WITH(mbedtls,
|
||||
AS_HELP_STRING([--with-mbedtls=DIR], [mbed TLS base directory, or:]),
|
||||
[mbedtls="$withval"
|
||||
CFLAGS="$CFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(mbedtls-include,
|
||||
AS_HELP_STRING([--with-mbedtls-include=DIR], [mbed TLS headers directory (without trailing /mbedtls)]),
|
||||
[mbedtls_include="$withval"
|
||||
CFLAGS="$CFLAGS -I$withval"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(mbedtls-lib,
|
||||
AS_HELP_STRING([--with-mbedtls-lib=DIR], [mbed TLS library directory]),
|
||||
[mbedtls_lib="$withval"
|
||||
LDFLAGS="$LDFLAGS -L$withval"]
|
||||
)
|
||||
|
||||
AC_CHECK_LIB(mbedcrypto, mbedtls_cipher_setup,
|
||||
[LIBS="-lmbedcrypto $LIBS"],
|
||||
[AC_MSG_ERROR([mbed TLS libraries not found.])]
|
||||
)
|
||||
|
||||
AC_MSG_CHECKING([whether mbedtls supports Cipher Feedback mode or not])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#include <mbedtls/version.h>
|
||||
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
#include <mbedtls/mbedtls_config.h>
|
||||
#else
|
||||
#include <mbedtls/config.h>
|
||||
#endif
|
||||
]],
|
||||
[[
|
||||
#ifndef MBEDTLS_CIPHER_MODE_CFB
|
||||
#error Cipher Feedback mode a.k.a CFB not supported by your mbed TLS.
|
||||
#endif
|
||||
]]
|
||||
)],
|
||||
[AC_MSG_RESULT([ok])],
|
||||
[AC_MSG_ERROR([MBEDTLS_CIPHER_MODE_CFB required])]
|
||||
)
|
||||
|
||||
|
||||
AC_MSG_CHECKING([whether mbedtls supports the ARC4 stream cipher or not])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#include <mbedtls/version.h>
|
||||
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
#include <mbedtls/mbedtls_config.h>
|
||||
#else
|
||||
#include <mbedtls/config.h>
|
||||
#endif
|
||||
]],
|
||||
[[
|
||||
#ifndef MBEDTLS_ARC4_C
|
||||
#error the ARC4 stream cipher not supported by your mbed TLS.
|
||||
#endif
|
||||
]]
|
||||
)],
|
||||
[AC_MSG_RESULT([ok])],
|
||||
[AC_MSG_WARN([We will continue without ARC4 stream cipher support, MBEDTLS_ARC4_C required])]
|
||||
)
|
||||
|
||||
AC_MSG_CHECKING([whether mbedtls supports the Blowfish block cipher or not])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#include <mbedtls/version.h>
|
||||
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
#include <mbedtls/mbedtls_config.h>
|
||||
#else
|
||||
#include <mbedtls/config.h>
|
||||
#endif
|
||||
]],
|
||||
[[
|
||||
#ifndef MBEDTLS_BLOWFISH_C
|
||||
#error the Blowfish block cipher not supported by your mbed TLS.
|
||||
#endif
|
||||
]]
|
||||
)],
|
||||
[AC_MSG_RESULT([ok])],
|
||||
[AC_MSG_WARN([We will continue without Blowfish block cipher support, MBEDTLS_BLOWFISH_C required])]
|
||||
)
|
||||
|
||||
AC_MSG_CHECKING([whether mbedtls supports the Camellia block cipher or not])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#include <mbedtls/version.h>
|
||||
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
|
||||
#include <mbedtls/mbedtls_config.h>
|
||||
#else
|
||||
#include <mbedtls/config.h>
|
||||
#endif
|
||||
]],
|
||||
[[
|
||||
#ifndef MBEDTLS_CAMELLIA_C
|
||||
#error the Camellia block cipher not supported by your mbed TLS.
|
||||
#endif
|
||||
]]
|
||||
)],
|
||||
[AC_MSG_RESULT([ok])],
|
||||
[AC_MSG_WARN([We will continue without Camellia block cipher support, MBEDTLS_CAMELLIA_C required])]
|
||||
)
|
||||
])
|
||||
@@ -1,152 +0,0 @@
|
||||
dnl -------------------------------------------------------- -*- autoconf -*-
|
||||
dnl Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
dnl contributor license agreements. See the NOTICE file distributed with
|
||||
dnl this work for additional information regarding copyright ownership.
|
||||
dnl The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
dnl (the "License"); you may not use this file except in compliance with
|
||||
dnl the License. You may obtain a copy of the License at
|
||||
dnl
|
||||
dnl http://www.apache.org/licenses/LICENSE-2.0
|
||||
dnl
|
||||
dnl Unless required by applicable law or agreed to in writing, software
|
||||
dnl distributed under the License is distributed on an "AS IS" BASIS,
|
||||
dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
dnl See the License for the specific language governing permissions and
|
||||
dnl limitations under the License.
|
||||
|
||||
dnl
|
||||
dnl TS_ADDTO(variable, value)
|
||||
dnl
|
||||
dnl Add value to variable
|
||||
dnl
|
||||
AC_DEFUN([TS_ADDTO], [
|
||||
if test "x$$1" = "x"; then
|
||||
test "x$verbose" = "xyes" && echo " setting $1 to \"$2\""
|
||||
$1="$2"
|
||||
else
|
||||
ats_addto_bugger="$2"
|
||||
for i in $ats_addto_bugger; do
|
||||
ats_addto_duplicate="0"
|
||||
for j in $$1; do
|
||||
if test "x$i" = "x$j"; then
|
||||
ats_addto_duplicate="1"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test $ats_addto_duplicate = "0"; then
|
||||
test "x$verbose" = "xyes" && echo " adding \"$i\" to $1"
|
||||
$1="$$1 $i"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
])dnl
|
||||
|
||||
dnl
|
||||
dnl TS_ADDTO_RPATH(path)
|
||||
dnl
|
||||
dnl Adds path to variable with the '-rpath' directive.
|
||||
dnl
|
||||
AC_DEFUN([TS_ADDTO_RPATH], [
|
||||
AC_MSG_NOTICE([adding $1 to RPATH])
|
||||
TS_ADDTO(LIBTOOL_LINK_FLAGS, [-R$1])
|
||||
])dnl
|
||||
|
||||
dnl
|
||||
dnl pcre.m4: Trafficserver's pcre autoconf macros
|
||||
dnl
|
||||
|
||||
dnl
|
||||
dnl TS_CHECK_PCRE: look for pcre libraries and headers
|
||||
dnl
|
||||
AC_DEFUN([TS_CHECK_PCRE], [
|
||||
enable_pcre=no
|
||||
AC_ARG_WITH(pcre, [AC_HELP_STRING([--with-pcre=DIR],[use a specific pcre library])],
|
||||
[
|
||||
if test "x$withval" != "xyes" && test "x$withval" != "x"; then
|
||||
pcre_base_dir="$withval"
|
||||
if test "$withval" != "no"; then
|
||||
enable_pcre=yes
|
||||
case "$withval" in
|
||||
*":"*)
|
||||
pcre_include="`echo $withval |sed -e 's/:.*$//'`"
|
||||
pcre_ldflags="`echo $withval |sed -e 's/^.*://'`"
|
||||
AC_MSG_CHECKING(checking for pcre includes in $pcre_include libs in $pcre_ldflags )
|
||||
;;
|
||||
*)
|
||||
pcre_include="$withval/include"
|
||||
pcre_ldflags="$withval/lib"
|
||||
AC_MSG_CHECKING(checking for pcre includes in $withval)
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
],
|
||||
[
|
||||
AC_CHECK_PROG(PCRE_CONFIG, pcre-config, pcre-config)
|
||||
if test "x$PCRE_CONFIG" != "x"; then
|
||||
enable_pcre=yes
|
||||
pcre_base_dir="`$PCRE_CONFIG --prefix`"
|
||||
pcre_include="`$PCRE_CONFIG --cflags | sed -es/-I//`"
|
||||
pcre_ldflags="`$PCRE_CONFIG --libs | sed -es/-lpcre// -es/-L//`"
|
||||
fi
|
||||
])
|
||||
|
||||
if test "x$pcre_base_dir" = "x"; then
|
||||
AC_MSG_CHECKING([for pcre location])
|
||||
AC_CACHE_VAL(ats_cv_pcre_dir,[
|
||||
for dir in /usr/local /usr ; do
|
||||
if test -d $dir && ( test -f $dir/include/pcre.h || test -f $dir/include/pcre/pcre.h ); then
|
||||
ats_cv_pcre_dir=$dir
|
||||
break
|
||||
fi
|
||||
done
|
||||
])
|
||||
pcre_base_dir=$ats_cv_pcre_dir
|
||||
if test "x$pcre_base_dir" = "x"; then
|
||||
enable_pcre=no
|
||||
AC_MSG_RESULT([not found])
|
||||
else
|
||||
enable_pcre=yes
|
||||
pcre_include="$pcre_base_dir/include"
|
||||
pcre_ldflags="$pcre_base_dir/lib"
|
||||
AC_MSG_RESULT([$pcre_base_dir])
|
||||
fi
|
||||
else
|
||||
AC_MSG_CHECKING(for pcre headers in $pcre_include)
|
||||
if test -d $pcre_include && test -d $pcre_ldflags && ( test -f $pcre_include/pcre.h || test -f $pcre_include/pcre/pcre.h ); then
|
||||
AC_MSG_RESULT([ok])
|
||||
else
|
||||
AC_MSG_RESULT([not found])
|
||||
fi
|
||||
fi
|
||||
|
||||
pcreh=0
|
||||
pcre_pcreh=0
|
||||
if test "$enable_pcre" != "no"; then
|
||||
saved_ldflags=$LDFLAGS
|
||||
saved_cppflags=$CFLAGS
|
||||
pcre_have_headers=0
|
||||
pcre_have_libs=0
|
||||
if test "$pcre_base_dir" != "/usr"; then
|
||||
TS_ADDTO(CFLAGS, [-I${pcre_include}])
|
||||
TS_ADDTO(CFLAGS, [-DPCRE_STATIC])
|
||||
TS_ADDTO(LDFLAGS, [-L${pcre_ldflags}])
|
||||
TS_ADDTO_RPATH(${pcre_ldflags})
|
||||
fi
|
||||
AC_SEARCH_LIBS([pcre_exec], [pcre], [pcre_have_libs=1])
|
||||
if test "$pcre_have_libs" != "0"; then
|
||||
AC_CHECK_HEADERS(pcre.h, [pcre_have_headers=1])
|
||||
AC_CHECK_HEADERS(pcre/pcre.h, [pcre_have_headers=1])
|
||||
fi
|
||||
if test "$pcre_have_headers" != "0"; then
|
||||
AC_DEFINE(HAVE_LIBPCRE,1,[Compiling with pcre support])
|
||||
AC_SUBST(LIBPCRE, [-lpcre])
|
||||
else
|
||||
enable_pcre=no
|
||||
CFLAGS=$saved_cppflags
|
||||
LDFLAGS=$saved_ldflags
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(pcreh)
|
||||
AC_SUBST(pcre_pcreh)
|
||||
])
|
||||
@@ -1,40 +0,0 @@
|
||||
dnl Check to find the libsodium headers/libraries
|
||||
|
||||
AC_DEFUN([ss_SODIUM],
|
||||
[
|
||||
|
||||
AC_ARG_WITH(sodium,
|
||||
AS_HELP_STRING([--with-sodium=DIR], [The Sodium crypto library base directory, or:]),
|
||||
[sodium="$withval"
|
||||
CFLAGS="$CFLAGS -I$withval/include"
|
||||
LDFLAGS="$LDFLAGS -L$withval/lib"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(sodium-include,
|
||||
AS_HELP_STRING([--with-sodium-include=DIR], [The Sodium crypto library headers directory (without trailing /sodium)]),
|
||||
[sodium_include="$withval"
|
||||
CFLAGS="$CFLAGS -I$withval"]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(sodium-lib,
|
||||
AS_HELP_STRING([--with-sodium-lib=DIR], [The Sodium crypto library library directory]),
|
||||
[sodium_lib="$withval"
|
||||
LDFLAGS="$LDFLAGS -L$withval"]
|
||||
)
|
||||
|
||||
AC_CHECK_LIB(sodium, sodium_init,
|
||||
[LIBS="-lsodium $LIBS"],
|
||||
[AC_MSG_ERROR([The Sodium crypto library libraries not found.])]
|
||||
)
|
||||
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
|
||||
#include <sodium.h>
|
||||
], [
|
||||
#if SODIUM_LIBRARY_VERSION_MAJOR < 7 || SODIUM_LIBRARY_VERSION_MAJOR ==7 && SODIUM_LIBRARY_VERSION_MINOR < 6
|
||||
# error
|
||||
#endif
|
||||
])],
|
||||
[AC_MSG_RESULT([checking for version of libsodium... yes])],
|
||||
[AC_MSG_ERROR([Wrong libsodium: version >= 1.0.4 required])])
|
||||
|
||||
])
|
||||
@@ -1,58 +0,0 @@
|
||||
#
|
||||
# Copyright 2007 Google Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# GGL_CHECK_STACK_PROTECTOR([ACTION-IF-OK], [ACTION-IF-NOT-OK])
|
||||
# Check if c compiler supports -fstack-protector and -fstack-protector-all
|
||||
# options.
|
||||
|
||||
AC_DEFUN([GGL_CHECK_STACK_PROTECTOR], [
|
||||
ggl_check_stack_protector_save_CXXFLAGS="$CXXFLAGS"
|
||||
ggl_check_stack_protector_save_CFLAGS="$CFLAGS"
|
||||
|
||||
AC_MSG_CHECKING([if -fstack-protector and -fstack-protector-all are supported.])
|
||||
|
||||
CXXFLAGS="$CXXFLAGS -fstack-protector"
|
||||
CFLAGS="$CFLAGS -fstack-protector"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
])],
|
||||
[ggl_check_stack_protector_ok=yes],
|
||||
[ggl_check_stack_protector_ok=no])
|
||||
|
||||
CXXFLAGS="$ggl_check_stack_protector_save_CXXFLAGS -fstack-protector-all"
|
||||
CFLAGS="$ggl_check_stack_protector_save_CFLAGS -fstack-protector-all"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
])],
|
||||
[ggl_check_stack_protector_all_ok=yes],
|
||||
[ggl_check_stack_protector_all_ok=no])
|
||||
|
||||
if test "x$ggl_check_stack_protector_ok" = "xyes" -a \
|
||||
"x$ggl_check_stack_protector_all_ok" = "xyes"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
ifelse([$1], , :, [$1])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
ifelse([$2], , :, [$2])
|
||||
fi
|
||||
|
||||
CXXFLAGS="$ggl_check_stack_protector_save_CXXFLAGS"
|
||||
CFLAGS="$ggl_check_stack_protector_save_CFLAGS"
|
||||
|
||||
]) # GGL_CHECK_STACK_PROTECTOR
|
||||
Executable
+1367
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: shadowsocks-libev
|
||||
Description: a lightweight secured socks5 proxy
|
||||
URL: https://shadowsocks.org
|
||||
Version: @VERSION@
|
||||
Requires:
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -lshadowsocks-libev
|
||||
@@ -84,25 +84,29 @@ set(SS_REDIR_SOURCE
|
||||
${SS_PLUGIN_SOURCE}
|
||||
)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Darwin)
|
||||
find_path(LIBSODIUM_INCLUDE_DIR sodium.h
|
||||
PATHS
|
||||
$ENV{LIBSODIUM_INCLUDE_DIR}
|
||||
$ENV{LIBSODIUM_DIR}/include
|
||||
/usr/local/libsodium/include
|
||||
/opt/libsodium/include
|
||||
/usr/local/include
|
||||
)
|
||||
include_directories(${LIBSODIUM_INCLUDE_DIR})
|
||||
endif ()
|
||||
# Apply -Werror only to project sources (not bundled submodules)
|
||||
set(SS_WERROR_FLAGS -Werror)
|
||||
|
||||
# Include directories from Find modules
|
||||
# MbedTLS must come first to avoid conflicts with other mbedtls versions
|
||||
# that may be in /opt/homebrew/include (e.g. mbedtls 4.x vs 3.x)
|
||||
include_directories(BEFORE ${MBEDTLS_INCLUDE_DIRS})
|
||||
include_directories(${SODIUM_INCLUDE_DIRS})
|
||||
include_directories(${PCRE2_INCLUDE_DIRS})
|
||||
include_directories(${CARES_INCLUDE_DIRS})
|
||||
|
||||
# Extract mbedTLS lib dir to ensure static/shared libs come from same version
|
||||
get_filename_component(_MBEDTLS_LIB_DIR "${MBEDTLS_CRYPTO_LIBRARY}" DIRECTORY)
|
||||
|
||||
if (WITH_STATIC)
|
||||
find_library(LIBSODIUM libsodium.a)
|
||||
find_library(LIBMBEDTLS libmbedtls.a HINTS ${_MBEDTLS_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(LIBMBEDTLS libmbedtls.a)
|
||||
find_library(LIBMBEDCRYPTO libmbedcrypto.a HINTS ${_MBEDTLS_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(LIBMBEDCRYPTO libmbedcrypto.a)
|
||||
find_library(LIBEV libev.a)
|
||||
find_library(LIBUDNS libcares.a)
|
||||
find_library(LIBPCRE libpcre.a)
|
||||
find_library(LIBPCRE2 libpcre2-8.a)
|
||||
|
||||
# Dependencies we need for static and shared
|
||||
list(APPEND DEPS
|
||||
@@ -110,7 +114,7 @@ list(APPEND DEPS
|
||||
bloom
|
||||
${LIBEV}
|
||||
${LIBUDNS}
|
||||
${LIBPCRE}
|
||||
${LIBPCRE2}
|
||||
${LIBSODIUM}
|
||||
${LIBMBEDTLS}
|
||||
${LIBMBEDCRYPTO}
|
||||
@@ -118,16 +122,18 @@ list(APPEND DEPS
|
||||
|
||||
if (MINGW)
|
||||
list(APPEND DEPS ws2_32 iphlpapi)
|
||||
add_compile_definitions(CARES_STATICLIB PCRE_STATIC)
|
||||
add_compile_definitions(CARES_STATICLIB PCRE2_STATIC)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
find_library(LIBSODIUM_SHARED sodium)
|
||||
find_library(LIBMBEDTLS_SHARED mbedtls HINTS ${_MBEDTLS_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(LIBMBEDTLS_SHARED mbedtls)
|
||||
find_library(LIBMBEDCRYPTO_SHARED mbedcrypto HINTS ${_MBEDTLS_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(LIBMBEDCRYPTO_SHARED mbedcrypto)
|
||||
find_library(LIBEV_SHARED ev)
|
||||
find_library(LIBUDNS_SHARED cares)
|
||||
find_library(LIBPCRE_SHARED pcre)
|
||||
find_library(LIBPCRE2_SHARED pcre2-8)
|
||||
|
||||
if (WITH_EMBEDDED_SRC)
|
||||
list(APPEND DEPS_SHARED
|
||||
@@ -137,7 +143,7 @@ list(APPEND DEPS_SHARED
|
||||
ipset-shared
|
||||
${LIBEV_SHARED}
|
||||
${LIBUDNS_SHARED}
|
||||
${LIBPCRE_SHARED}
|
||||
${LIBPCRE2_SHARED}
|
||||
${LIBSODIUM_SHARED}
|
||||
${LIBMBEDTLS_SHARED}
|
||||
${LIBMBEDCRYPTO_SHARED}
|
||||
@@ -153,13 +159,24 @@ list(APPEND DEPS_SHARED
|
||||
${LIBCORKIPSET_SHARED}
|
||||
${LIBEV_SHARED}
|
||||
${LIBUDNS_SHARED}
|
||||
${LIBPCRE_SHARED}
|
||||
${LIBPCRE2_SHARED}
|
||||
${LIBSODIUM_SHARED}
|
||||
${LIBMBEDTLS_SHARED}
|
||||
${LIBMBEDCRYPTO_SHARED}
|
||||
)
|
||||
endif ()
|
||||
|
||||
# Connmarktos/nftables libraries for ss-server
|
||||
if(ENABLE_CONNMARKTOS)
|
||||
list(APPEND DEPS_CONNMARKTOS ${NETFILTER_CONNTRACK_LIB})
|
||||
if(NFNETLINK_LIB)
|
||||
list(APPEND DEPS_CONNMARKTOS ${NFNETLINK_LIB})
|
||||
endif()
|
||||
endif()
|
||||
if(ENABLE_NFTABLES)
|
||||
list(APPEND DEPS_NFTABLES ${MNL_LIB} ${NFTNL_LIB})
|
||||
endif()
|
||||
|
||||
find_package (Threads)
|
||||
|
||||
if (WITH_STATIC)
|
||||
@@ -189,9 +206,24 @@ target_compile_definitions(ss-local PUBLIC -DMODULE_LOCAL)
|
||||
target_compile_definitions(ss-redir PUBLIC -DMODULE_REDIR)
|
||||
target_compile_definitions(shadowsocks-libev PUBLIC -DMODULE_LOCAL -DLIB_ONLY)
|
||||
|
||||
target_compile_options(ss-server PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(ss-tunnel PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(ss-manager PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(ss-local PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(ss-redir PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(shadowsocks-libev PRIVATE ${SS_WERROR_FLAGS})
|
||||
|
||||
# Connmarktos/nftables compile definitions
|
||||
if(ENABLE_CONNMARKTOS)
|
||||
target_compile_definitions(ss-server PUBLIC -DUSE_NFCONNTRACK_TOS)
|
||||
endif()
|
||||
if(ENABLE_NFTABLES)
|
||||
target_compile_definitions(ss-server PUBLIC -DUSE_NFTABLES)
|
||||
endif()
|
||||
|
||||
target_include_directories(shadowsocks-libev PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(ss-server cork ipset ${DEPS})
|
||||
target_link_libraries(ss-server cork ipset ${DEPS} ${DEPS_CONNMARKTOS} ${DEPS_NFTABLES})
|
||||
target_link_libraries(ss-tunnel cork ${DEPS})
|
||||
target_link_libraries(ss-manager m bloom cork ${LIBEV} ${LIBUDNS})
|
||||
target_link_libraries(ss-local cork ipset ${DEPS})
|
||||
@@ -226,9 +258,24 @@ target_compile_definitions(ss-local-shared PUBLIC -DMODULE_LOCAL)
|
||||
target_compile_definitions(ss-redir-shared PUBLIC -DMODULE_REDIR)
|
||||
target_compile_definitions(shadowsocks-libev-shared PUBLIC -DMODULE_LOCAL -DLIB_ONLY)
|
||||
|
||||
target_compile_options(ss-server-shared PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(ss-tunnel-shared PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(ss-manager-shared PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(ss-local-shared PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(ss-redir-shared PRIVATE ${SS_WERROR_FLAGS})
|
||||
target_compile_options(shadowsocks-libev-shared PRIVATE ${SS_WERROR_FLAGS})
|
||||
|
||||
# Connmarktos/nftables compile definitions for shared
|
||||
if(ENABLE_CONNMARKTOS)
|
||||
target_compile_definitions(ss-server-shared PUBLIC -DUSE_NFCONNTRACK_TOS)
|
||||
endif()
|
||||
if(ENABLE_NFTABLES)
|
||||
target_compile_definitions(ss-server-shared PUBLIC -DUSE_NFTABLES)
|
||||
endif()
|
||||
|
||||
target_include_directories(shadowsocks-libev-shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries(ss-server-shared ${DEPS_SHARED})
|
||||
target_link_libraries(ss-server-shared ${DEPS_SHARED} ${DEPS_CONNMARKTOS} ${DEPS_NFTABLES})
|
||||
target_link_libraries(ss-tunnel-shared ${DEPS_SHARED})
|
||||
target_link_libraries(ss-manager-shared ${CMAKE_THREAD_LIBS_INIT} ${LIBEV_SHARED} ${LIBUDNS_SHARED} ${DEPS_SHARED})
|
||||
target_link_libraries(ss-local-shared ${DEPS_SHARED})
|
||||
@@ -247,6 +294,7 @@ set_target_properties(ss-server-shared ss-tunnel-shared ss-manager-shared ss-loc
|
||||
)
|
||||
|
||||
set_target_properties(shadowsocks-libev-shared PROPERTIES OUTPUT_NAME shadowsocks-libev)
|
||||
set_target_properties(shadowsocks-libev-shared PROPERTIES VERSION 2.0.0 SOVERSION 2)
|
||||
target_compile_definitions(shadowsocks-libev-shared PUBLIC -DMODULE_LOCAL)
|
||||
target_link_libraries(shadowsocks-libev-shared ${DEPS_SHARED})
|
||||
|
||||
@@ -255,17 +303,17 @@ target_link_libraries(shadowsocks-libev-shared ${DEPS_SHARED})
|
||||
# Recommend to install shared by default
|
||||
install(DIRECTORY ${RUNTIME_SHARED_OUTPUT_DIRECTORY}/
|
||||
USE_SOURCE_PERMISSIONS
|
||||
DESTINATION bin)
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
if (WITH_STATIC)
|
||||
install(TARGETS shadowsocks-libev
|
||||
ARCHIVE DESTINATION lib)
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif ()
|
||||
|
||||
install(TARGETS shadowsocks-libev-shared
|
||||
LIBRARY DESTINATION lib)
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
install(FILES shadowsocks.h DESTINATION include)
|
||||
install(FILES shadowsocks.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
|
||||
add_custom_target(distclean
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
VERSION_INFO = 2:0:0
|
||||
|
||||
AM_CFLAGS = -g -O2 -Wall -Werror -Wno-deprecated-declarations -fno-strict-aliasing -std=gnu99 -D_GNU_SOURCE
|
||||
AM_CFLAGS += $(PTHREAD_CFLAGS)
|
||||
if !USE_SYSTEM_SHARED_LIB
|
||||
AM_CFLAGS += -I$(top_srcdir)/libbloom
|
||||
AM_CFLAGS += -I$(top_srcdir)/libipset/include
|
||||
AM_CFLAGS += -I$(top_srcdir)/libcork/include
|
||||
endif
|
||||
AM_CFLAGS += $(LIBPCRE_CFLAGS)
|
||||
|
||||
SS_COMMON_LIBS = $(INET_NTOP_LIB) $(LIBPCRE_LIBS) $(NETFILTER_CONNTRACK_LIBS) $(NFTABLES_LIBS)
|
||||
if !USE_SYSTEM_SHARED_LIB
|
||||
SS_COMMON_LIBS += $(top_builddir)/libbloom/libbloom.la \
|
||||
$(top_builddir)/libipset/libipset.la \
|
||||
$(top_builddir)/libcork/libcork.la
|
||||
else
|
||||
SS_COMMON_LIBS += -lbloom -lcork -lcorkipset
|
||||
endif
|
||||
SS_COMMON_LIBS += -lev -lsodium -lm
|
||||
|
||||
bin_PROGRAMS = ss-local ss-tunnel ss-server
|
||||
if !BUILD_WINCOMPAT
|
||||
bin_PROGRAMS += ss-manager
|
||||
endif
|
||||
|
||||
acl_src = rule.c \
|
||||
acl.c
|
||||
|
||||
crypto_src = crypto.c \
|
||||
aead.c \
|
||||
stream.c \
|
||||
ppbloom.c \
|
||||
base64.c
|
||||
|
||||
plugin_src = plugin.c
|
||||
|
||||
common_src = utils.c \
|
||||
jconf.c \
|
||||
json.c \
|
||||
udprelay.c \
|
||||
cache.c \
|
||||
netutils.c
|
||||
|
||||
if BUILD_WINCOMPAT
|
||||
common_src += winsock.c
|
||||
endif
|
||||
|
||||
ss_local_SOURCES = local.c \
|
||||
$(common_src) \
|
||||
$(crypto_src) \
|
||||
$(plugin_src) \
|
||||
$(acl_src)
|
||||
|
||||
ss_tunnel_SOURCES = tunnel.c \
|
||||
$(common_src) \
|
||||
$(crypto_src) \
|
||||
$(plugin_src)
|
||||
|
||||
ss_server_SOURCES = resolv.c \
|
||||
server.c \
|
||||
$(common_src) \
|
||||
$(crypto_src) \
|
||||
$(plugin_src) \
|
||||
${acl_src}
|
||||
|
||||
ss_manager_SOURCES = utils.c \
|
||||
jconf.c \
|
||||
json.c \
|
||||
netutils.c \
|
||||
manager.c
|
||||
|
||||
ss_local_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_tunnel_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_server_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_manager_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_local_LDADD += -lcares
|
||||
ss_tunnel_LDADD += -lcares
|
||||
ss_server_LDADD += -lcares
|
||||
ss_manager_LDADD += -lcares
|
||||
|
||||
ss_local_CFLAGS = $(AM_CFLAGS) -DMODULE_LOCAL
|
||||
ss_tunnel_CFLAGS = $(AM_CFLAGS) -DMODULE_TUNNEL
|
||||
ss_server_CFLAGS = $(AM_CFLAGS) -DMODULE_REMOTE
|
||||
ss_manager_CFLAGS = $(AM_CFLAGS) -DMODULE_MANAGER
|
||||
|
||||
if BUILD_REDIRECTOR
|
||||
bin_SCRIPTS = ss-nat
|
||||
bin_PROGRAMS += ss-redir
|
||||
ss_redir_SOURCES = utils.c \
|
||||
jconf.c \
|
||||
json.c \
|
||||
netutils.c \
|
||||
cache.c \
|
||||
udprelay.c \
|
||||
redir.c \
|
||||
$(crypto_src) \
|
||||
$(plugin_src)
|
||||
|
||||
ss_redir_CFLAGS = $(AM_CFLAGS) -DMODULE_REDIR
|
||||
ss_redir_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_redir_LDADD += -lcares
|
||||
endif
|
||||
|
||||
lib_LTLIBRARIES = libshadowsocks-libev.la
|
||||
libshadowsocks_libev_la_SOURCES = $(ss_local_SOURCES)
|
||||
libshadowsocks_libev_la_CFLAGS = $(ss_local_CFLAGS) -DLIB_ONLY
|
||||
libshadowsocks_libev_la_LDFLAGS = -version-info $(VERSION_INFO)
|
||||
libshadowsocks_libev_la_LIBADD = $(ss_local_LDADD)
|
||||
include_HEADERS = shadowsocks.h
|
||||
|
||||
noinst_HEADERS = acl.h crypto.h stream.h aead.h json.h netutils.h redir.h server.h uthash.h \
|
||||
cache.h local.h plugin.h resolv.h tunnel.h utils.h base64.h ppbloom.h \
|
||||
common.h jconf.h manager.h rule.h socks5.h udprelay.h winsock.h
|
||||
EXTRA_DIST = ss-nat
|
||||
@@ -78,16 +78,21 @@ int
|
||||
init_rule(rule_t *rule)
|
||||
{
|
||||
if (rule->pattern_re == NULL) {
|
||||
const char *reerr;
|
||||
int reerroffset;
|
||||
int errcode;
|
||||
PCRE2_SIZE erroffset;
|
||||
|
||||
rule->pattern_re =
|
||||
pcre_compile(rule->pattern, 0, &reerr, &reerroffset, NULL);
|
||||
pcre2_compile((PCRE2_SPTR)rule->pattern, PCRE2_ZERO_TERMINATED,
|
||||
0, &errcode, &erroffset, NULL);
|
||||
if (rule->pattern_re == NULL) {
|
||||
PCRE2_UCHAR errbuf[256];
|
||||
pcre2_get_error_message(errcode, errbuf, sizeof(errbuf));
|
||||
LOGE("Regex compilation of \"%s\" failed: %s, offset %d",
|
||||
rule->pattern, reerr, reerroffset);
|
||||
rule->pattern, errbuf, (int)erroffset);
|
||||
return 0;
|
||||
}
|
||||
rule->match_data = pcre2_match_data_create_from_pattern(
|
||||
rule->pattern_re, NULL);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -105,8 +110,8 @@ lookup_rule(const struct cork_dllist *rules, const char *name, size_t name_len)
|
||||
|
||||
cork_dllist_foreach_void(rules, curr, next) {
|
||||
rule_t *rule = cork_container_of(curr, rule_t, entries);
|
||||
if (pcre_exec(rule->pattern_re, NULL,
|
||||
name, name_len, 0, 0, NULL, 0) >= 0)
|
||||
if (pcre2_match(rule->pattern_re, (PCRE2_SPTR)name,
|
||||
name_len, 0, 0, rule->match_data, NULL) >= 0)
|
||||
return rule;
|
||||
}
|
||||
|
||||
@@ -127,7 +132,9 @@ free_rule(rule_t *rule)
|
||||
return;
|
||||
|
||||
ss_free(rule->pattern);
|
||||
if (rule->match_data != NULL)
|
||||
pcre2_match_data_free(rule->match_data);
|
||||
if (rule->pattern_re != NULL)
|
||||
pcre_free(rule->pattern_re);
|
||||
pcre2_code_free(rule->pattern_re);
|
||||
ss_free(rule);
|
||||
}
|
||||
|
||||
@@ -33,17 +33,15 @@
|
||||
|
||||
#include <libcork/ds.h>
|
||||
|
||||
#ifdef HAVE_PCRE_H
|
||||
#include <pcre.h>
|
||||
#elif HAVE_PCRE_PCRE_H
|
||||
#include <pcre/pcre.h>
|
||||
#endif
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include <pcre2.h>
|
||||
|
||||
typedef struct rule {
|
||||
char *pattern;
|
||||
|
||||
/* Runtime fields */
|
||||
pcre *pattern_re;
|
||||
pcre2_code *pattern_re;
|
||||
pcre2_match_data *match_data;
|
||||
|
||||
struct cork_dllist_item entries;
|
||||
} rule_t;
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
# Unit tests using CTest
|
||||
include_directories(BEFORE ${MBEDTLS_INCLUDE_DIRS})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||
include_directories(${PROJECT_BINARY_DIR}/src)
|
||||
include_directories(${SODIUM_INCLUDE_DIRS})
|
||||
include_directories(${PCRE2_INCLUDE_DIRS})
|
||||
include_directories(${CARES_INCLUDE_DIRS})
|
||||
|
||||
if(WITH_EMBEDDED_SRC)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/libcork/include)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/libipset/include)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/libbloom/murmur2)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/libbloom)
|
||||
endif()
|
||||
|
||||
# Helper function to add a unit test
|
||||
function(ss_add_test name sources libs)
|
||||
add_executable(${name} ${sources})
|
||||
target_compile_definitions(${name} PRIVATE -DHAVE_CONFIG_H)
|
||||
target_link_libraries(${name} ${libs})
|
||||
add_test(NAME ${name} COMMAND ${name})
|
||||
endfunction()
|
||||
|
||||
# test_base64 - no external deps
|
||||
ss_add_test(test_base64
|
||||
"test_base64.c;${PROJECT_SOURCE_DIR}/src/base64.c"
|
||||
"")
|
||||
|
||||
# test_utils - needs sodium (for ss_malloc -> uses sodium in utils.c)
|
||||
ss_add_test(test_utils
|
||||
"test_utils.c;${PROJECT_SOURCE_DIR}/src/utils.c"
|
||||
"${LIBSODIUM_SHARED}")
|
||||
|
||||
# test_json - standalone json parser
|
||||
ss_add_test(test_json
|
||||
"test_json.c;${PROJECT_SOURCE_DIR}/src/json.c"
|
||||
"m")
|
||||
|
||||
# test_netutils - needs cork for ip address parsing
|
||||
set(TEST_NETUTILS_LIBS
|
||||
${LIBSODIUM_SHARED}
|
||||
${LIBEV_SHARED}
|
||||
${LIBUDNS_SHARED}
|
||||
)
|
||||
if(WITH_EMBEDDED_SRC)
|
||||
list(APPEND TEST_NETUTILS_LIBS cork-shared)
|
||||
else()
|
||||
list(APPEND TEST_NETUTILS_LIBS ${LIBCORK_SHARED})
|
||||
endif()
|
||||
ss_add_test(test_netutils
|
||||
"test_netutils.c;${PROJECT_SOURCE_DIR}/src/netutils.c;${PROJECT_SOURCE_DIR}/src/utils.c"
|
||||
"${TEST_NETUTILS_LIBS}")
|
||||
|
||||
# test_cache - needs libev for ev_time()
|
||||
ss_add_test(test_cache
|
||||
"test_cache.c;${PROJECT_SOURCE_DIR}/src/cache.c;${PROJECT_SOURCE_DIR}/src/utils.c"
|
||||
"${LIBEV_SHARED};${LIBSODIUM_SHARED}")
|
||||
|
||||
# test_ppbloom - needs bloom
|
||||
set(TEST_PPBLOOM_LIBS "")
|
||||
if(WITH_EMBEDDED_SRC)
|
||||
list(APPEND TEST_PPBLOOM_LIBS bloom-shared)
|
||||
else()
|
||||
list(APPEND TEST_PPBLOOM_LIBS ${LIBBLOOM_SHARED})
|
||||
endif()
|
||||
ss_add_test(test_ppbloom
|
||||
"test_ppbloom.c;${PROJECT_SOURCE_DIR}/src/ppbloom.c;${PROJECT_SOURCE_DIR}/src/utils.c"
|
||||
"${TEST_PPBLOOM_LIBS};${LIBSODIUM_SHARED};m")
|
||||
|
||||
# test_rule - needs pcre and cork
|
||||
set(TEST_RULE_LIBS
|
||||
${LIBPCRE2_SHARED}
|
||||
${LIBSODIUM_SHARED}
|
||||
)
|
||||
if(WITH_EMBEDDED_SRC)
|
||||
list(APPEND TEST_RULE_LIBS cork-shared)
|
||||
else()
|
||||
list(APPEND TEST_RULE_LIBS ${LIBCORK_SHARED})
|
||||
endif()
|
||||
ss_add_test(test_rule
|
||||
"test_rule.c;${PROJECT_SOURCE_DIR}/src/rule.c;${PROJECT_SOURCE_DIR}/src/utils.c"
|
||||
"${TEST_RULE_LIBS}")
|
||||
|
||||
# test_jconf - needs cork and json
|
||||
set(TEST_JCONF_LIBS
|
||||
${LIBSODIUM_SHARED}
|
||||
${LIBEV_SHARED}
|
||||
${LIBUDNS_SHARED}
|
||||
)
|
||||
if(WITH_EMBEDDED_SRC)
|
||||
list(APPEND TEST_JCONF_LIBS cork-shared)
|
||||
else()
|
||||
list(APPEND TEST_JCONF_LIBS ${LIBCORK_SHARED})
|
||||
endif()
|
||||
ss_add_test(test_jconf
|
||||
"test_jconf.c;${PROJECT_SOURCE_DIR}/src/jconf.c;${PROJECT_SOURCE_DIR}/src/json.c;${PROJECT_SOURCE_DIR}/src/utils.c;${PROJECT_SOURCE_DIR}/src/netutils.c"
|
||||
"${TEST_JCONF_LIBS};m")
|
||||
|
||||
# test_buffer - needs sodium and mbedtls for crypto.c buffer functions
|
||||
ss_add_test(test_buffer
|
||||
"test_buffer.c;${PROJECT_SOURCE_DIR}/src/crypto.c;${PROJECT_SOURCE_DIR}/src/utils.c;${PROJECT_SOURCE_DIR}/src/base64.c;${PROJECT_SOURCE_DIR}/src/aead.c;${PROJECT_SOURCE_DIR}/src/stream.c;${PROJECT_SOURCE_DIR}/src/ppbloom.c;${PROJECT_SOURCE_DIR}/src/cache.c"
|
||||
"${LIBSODIUM_SHARED};${LIBMBEDTLS_SHARED};${LIBMBEDCRYPTO_SHARED};${LIBEV_SHARED};${TEST_PPBLOOM_LIBS};m")
|
||||
|
||||
# test_crypto - full crypto test
|
||||
set(TEST_CRYPTO_LIBS
|
||||
${LIBSODIUM_SHARED}
|
||||
${LIBMBEDTLS_SHARED}
|
||||
${LIBMBEDCRYPTO_SHARED}
|
||||
${LIBEV_SHARED}
|
||||
)
|
||||
if(WITH_EMBEDDED_SRC)
|
||||
list(APPEND TEST_CRYPTO_LIBS bloom-shared)
|
||||
else()
|
||||
list(APPEND TEST_CRYPTO_LIBS ${LIBBLOOM_SHARED})
|
||||
endif()
|
||||
ss_add_test(test_crypto
|
||||
"test_crypto.c;${PROJECT_SOURCE_DIR}/src/crypto.c;${PROJECT_SOURCE_DIR}/src/aead.c;${PROJECT_SOURCE_DIR}/src/stream.c;${PROJECT_SOURCE_DIR}/src/ppbloom.c;${PROJECT_SOURCE_DIR}/src/cache.c;${PROJECT_SOURCE_DIR}/src/base64.c;${PROJECT_SOURCE_DIR}/src/utils.c"
|
||||
"${TEST_CRYPTO_LIBS};m")
|
||||
|
||||
# test_ss_setup - bash unit tests for the ss-setup TUI tool
|
||||
add_test(NAME test_ss_setup
|
||||
COMMAND bash "${PROJECT_SOURCE_DIR}/tests/test_ss_setup.sh"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}")
|
||||
Executable
+445
@@ -0,0 +1,445 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Stress test for shadowsocks-libev: measures bandwidth on loopback
|
||||
with different ciphers using ss-server and ss-tunnel, and monitors
|
||||
for memory leaks.
|
||||
|
||||
Usage:
|
||||
python3 tests/stress_test.py --bin build/bin/
|
||||
python3 tests/stress_test.py --bin build/bin/ --size 50 --duration 10
|
||||
python3 tests/stress_test.py --bin build/bin/ --cipher aes-256-gcm
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import signal
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from subprocess import Popen
|
||||
|
||||
# Ciphers to test: AEAD (recommended) + common stream ciphers
|
||||
AEAD_CIPHERS = [
|
||||
"aes-128-gcm",
|
||||
"aes-256-gcm",
|
||||
"chacha20-ietf-poly1305",
|
||||
]
|
||||
|
||||
STREAM_CIPHERS = [
|
||||
"aes-128-cfb",
|
||||
"aes-256-cfb",
|
||||
"aes-256-ctr",
|
||||
"chacha20-ietf",
|
||||
]
|
||||
|
||||
ALL_CIPHERS = AEAD_CIPHERS + STREAM_CIPHERS
|
||||
|
||||
# Ports (picked high to avoid conflicts)
|
||||
SERVER_PORT = 18388
|
||||
TUNNEL_LOCAL_PORT = 18389
|
||||
SINK_PORT = 18390
|
||||
|
||||
|
||||
def get_rss_kb(pid):
|
||||
"""Get resident set size in KB for a process."""
|
||||
system = platform.system()
|
||||
try:
|
||||
if system == "Linux":
|
||||
with open("/proc/%d/status" % pid) as f:
|
||||
for line in f:
|
||||
if line.startswith("VmRSS:"):
|
||||
return int(line.split()[1])
|
||||
elif system == "Darwin":
|
||||
import subprocess
|
||||
out = subprocess.check_output(
|
||||
["ps", "-o", "rss=", "-p", str(pid)],
|
||||
stderr=subprocess.DEVNULL
|
||||
).decode().strip()
|
||||
if out:
|
||||
return int(out)
|
||||
except (IOError, OSError, ValueError):
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
class SinkServer:
|
||||
"""A simple TCP server that accepts connections and discards all data.
|
||||
Sends back a small acknowledgement per chunk so the sender knows
|
||||
data was received (for accurate bandwidth measurement)."""
|
||||
|
||||
def __init__(self, port):
|
||||
self.port = port
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.sock.bind(("127.0.0.1", port))
|
||||
self.sock.listen(5)
|
||||
self.sock.settimeout(1.0)
|
||||
self.running = True
|
||||
self.bytes_received = 0
|
||||
self.thread = threading.Thread(target=self._run, daemon=True)
|
||||
self.thread.start()
|
||||
|
||||
def _run(self):
|
||||
while self.running:
|
||||
try:
|
||||
conn, addr = self.sock.accept()
|
||||
t = threading.Thread(
|
||||
target=self._handle, args=(conn,), daemon=True
|
||||
)
|
||||
t.start()
|
||||
except socket.timeout:
|
||||
continue
|
||||
except OSError:
|
||||
break
|
||||
|
||||
def _handle(self, conn):
|
||||
conn.settimeout(5.0)
|
||||
try:
|
||||
while self.running:
|
||||
data = conn.recv(65536)
|
||||
if not data:
|
||||
break
|
||||
self.bytes_received += len(data)
|
||||
except (socket.timeout, OSError):
|
||||
pass
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
self.sock.close()
|
||||
self.thread.join(timeout=3)
|
||||
|
||||
|
||||
def server_args(ss_server, cipher, password, server_port):
|
||||
"""Build command-line args for ss-server."""
|
||||
return [
|
||||
ss_server,
|
||||
"-s", "127.0.0.1",
|
||||
"-p", str(server_port),
|
||||
"-k", password,
|
||||
"-m", cipher,
|
||||
]
|
||||
|
||||
|
||||
def tunnel_args(ss_tunnel, cipher, password, server_port, local_port, fwd_host, fwd_port):
|
||||
"""Build command-line args for ss-tunnel."""
|
||||
return [
|
||||
ss_tunnel,
|
||||
"-s", "127.0.0.1",
|
||||
"-p", str(server_port),
|
||||
"-l", str(local_port),
|
||||
"-k", password,
|
||||
"-m", cipher,
|
||||
"-L", "%s:%d" % (fwd_host, fwd_port),
|
||||
]
|
||||
|
||||
|
||||
def kill_proc(proc):
|
||||
"""Kill a process gracefully."""
|
||||
if proc and proc.poll() is None:
|
||||
try:
|
||||
proc.send_signal(signal.SIGTERM)
|
||||
proc.wait(timeout=5)
|
||||
except Exception:
|
||||
try:
|
||||
proc.kill()
|
||||
proc.wait(timeout=3)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def run_bandwidth_test(bin_dir, cipher, data_size_mb, password="stress_test_pw"):
|
||||
"""Run a single bandwidth test with the given cipher.
|
||||
|
||||
Returns dict with: cipher, bandwidth_mbps, duration_sec,
|
||||
server_rss_before_kb, server_rss_after_kb, tunnel_rss_before_kb,
|
||||
tunnel_rss_after_kb, bytes_transferred, error
|
||||
"""
|
||||
result = {
|
||||
"cipher": cipher,
|
||||
"bandwidth_mbps": 0,
|
||||
"duration_sec": 0,
|
||||
"bytes_transferred": 0,
|
||||
"server_rss_before_kb": None,
|
||||
"server_rss_after_kb": None,
|
||||
"tunnel_rss_before_kb": None,
|
||||
"tunnel_rss_after_kb": None,
|
||||
"error": None,
|
||||
}
|
||||
|
||||
ss_server_bin = os.path.join(bin_dir, "ss-server")
|
||||
ss_tunnel_bin = os.path.join(bin_dir, "ss-tunnel")
|
||||
|
||||
if not os.path.isfile(ss_server_bin) or not os.path.isfile(ss_tunnel_bin):
|
||||
result["error"] = "binaries not found in %s" % bin_dir
|
||||
return result
|
||||
|
||||
server_proc = None
|
||||
tunnel_proc = None
|
||||
sink = None
|
||||
devnull = open(os.devnull, "w")
|
||||
|
||||
try:
|
||||
# Start sink server (the destination ss-tunnel forwards to)
|
||||
sink = SinkServer(SINK_PORT)
|
||||
|
||||
# Start ss-server
|
||||
server_proc = Popen(
|
||||
server_args(ss_server_bin, cipher, password, SERVER_PORT),
|
||||
stdout=devnull, stderr=devnull, close_fds=True
|
||||
)
|
||||
|
||||
# Start ss-tunnel forwarding to the sink
|
||||
tunnel_proc = Popen(
|
||||
tunnel_args(ss_tunnel_bin, cipher, password, SERVER_PORT,
|
||||
TUNNEL_LOCAL_PORT, "127.0.0.1", SINK_PORT),
|
||||
stdout=devnull, stderr=devnull, close_fds=True
|
||||
)
|
||||
|
||||
# Wait for processes to start and bind ports
|
||||
# Don't probe the ports as ss-tunnel crashes on empty connections
|
||||
time.sleep(3.0)
|
||||
|
||||
if server_proc.poll() is not None:
|
||||
result["error"] = "ss-server exited prematurely (code %d)" % server_proc.returncode
|
||||
return result
|
||||
|
||||
if tunnel_proc.poll() is not None:
|
||||
result["error"] = "ss-tunnel exited prematurely (code %d)" % tunnel_proc.returncode
|
||||
return result
|
||||
|
||||
# Record RSS before
|
||||
result["server_rss_before_kb"] = get_rss_kb(server_proc.pid)
|
||||
result["tunnel_rss_before_kb"] = get_rss_kb(tunnel_proc.pid)
|
||||
|
||||
# Send data through the tunnel
|
||||
chunk_size = 64 * 1024 # 64KB chunks
|
||||
total_bytes = data_size_mb * 1024 * 1024
|
||||
data_chunk = b"\x00" * chunk_size
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.settimeout(30)
|
||||
try:
|
||||
sock.connect(("127.0.0.1", TUNNEL_LOCAL_PORT))
|
||||
except (socket.error, OSError) as e:
|
||||
result["error"] = "connect to tunnel failed: %s" % e
|
||||
return result
|
||||
|
||||
sent = 0
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
while sent < total_bytes:
|
||||
remaining = total_bytes - sent
|
||||
to_send = min(chunk_size, remaining)
|
||||
if to_send < chunk_size:
|
||||
data_chunk = b"\x00" * to_send
|
||||
sock.sendall(data_chunk)
|
||||
sent += to_send
|
||||
except (socket.error, OSError) as e:
|
||||
result["error"] = "send error at %d bytes: %s" % (sent, e)
|
||||
finally:
|
||||
elapsed = time.time() - start_time
|
||||
try:
|
||||
sock.shutdown(socket.SHUT_WR)
|
||||
except OSError:
|
||||
pass
|
||||
sock.close()
|
||||
|
||||
# Wait a bit for data to flow through
|
||||
time.sleep(0.5)
|
||||
|
||||
result["bytes_transferred"] = sent
|
||||
result["duration_sec"] = elapsed
|
||||
if elapsed > 0:
|
||||
result["bandwidth_mbps"] = (sent * 8) / (elapsed * 1e6)
|
||||
|
||||
# Record RSS after
|
||||
result["server_rss_after_kb"] = get_rss_kb(server_proc.pid)
|
||||
result["tunnel_rss_after_kb"] = get_rss_kb(tunnel_proc.pid)
|
||||
|
||||
except Exception as e:
|
||||
result["error"] = str(e)
|
||||
finally:
|
||||
kill_proc(tunnel_proc)
|
||||
kill_proc(server_proc)
|
||||
if sink:
|
||||
sink.stop()
|
||||
devnull.close()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def format_size(nbytes):
|
||||
if nbytes >= 1024 * 1024 * 1024:
|
||||
return "%.1f GB" % (nbytes / (1024 * 1024 * 1024))
|
||||
elif nbytes >= 1024 * 1024:
|
||||
return "%.1f MB" % (nbytes / (1024 * 1024))
|
||||
elif nbytes >= 1024:
|
||||
return "%.1f KB" % (nbytes / 1024)
|
||||
return "%d B" % nbytes
|
||||
|
||||
|
||||
def format_rss(kb):
|
||||
if kb is None:
|
||||
return "N/A"
|
||||
if kb >= 1024:
|
||||
return "%.1f MB" % (kb / 1024.0)
|
||||
return "%d KB" % kb
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Stress test ss-server + ss-tunnel bandwidth on loopback"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--bin", type=str, required=True,
|
||||
help="Path to directory containing ss-server and ss-tunnel binaries"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--size", type=int, default=100,
|
||||
help="Data size to transfer per cipher in MB (default: 100)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cipher", type=str, default=None,
|
||||
help="Test only this specific cipher"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--repeat", type=int, default=1,
|
||||
help="Number of times to repeat each cipher test (default: 1)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--stream", action="store_true",
|
||||
help="Include stream ciphers (deprecated, insecure)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--leak-threshold", type=int, default=10240,
|
||||
help="RSS growth threshold in KB to flag as potential leak (default: 10240)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--json", type=str, default=None,
|
||||
help="Write results as JSON to this file"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# Determine ciphers to test
|
||||
if args.cipher:
|
||||
ciphers = [args.cipher]
|
||||
elif args.stream:
|
||||
ciphers = ALL_CIPHERS
|
||||
else:
|
||||
ciphers = AEAD_CIPHERS
|
||||
|
||||
print("=" * 72)
|
||||
print("shadowsocks-libev stress test")
|
||||
print("=" * 72)
|
||||
print(" Binaries : %s" % os.path.abspath(args.bin))
|
||||
print(" Data size: %d MB per cipher" % args.size)
|
||||
print(" Ciphers : %s" % ", ".join(ciphers))
|
||||
print(" Repeats : %d" % args.repeat)
|
||||
print("=" * 72)
|
||||
print()
|
||||
|
||||
all_results = []
|
||||
leak_warnings = []
|
||||
|
||||
for cipher in ciphers:
|
||||
for run in range(args.repeat):
|
||||
label = cipher
|
||||
if args.repeat > 1:
|
||||
label = "%s (run %d/%d)" % (cipher, run + 1, args.repeat)
|
||||
|
||||
sys.stdout.write("Testing %-35s ... " % label)
|
||||
sys.stdout.flush()
|
||||
|
||||
result = run_bandwidth_test(args.bin, cipher, args.size)
|
||||
all_results.append(result)
|
||||
|
||||
if result["error"]:
|
||||
print("FAILED: %s" % result["error"])
|
||||
continue
|
||||
|
||||
bw = result["bandwidth_mbps"]
|
||||
dur = result["duration_sec"]
|
||||
print("%8.1f Mbps (%5.2fs, %s)" % (
|
||||
bw, dur, format_size(result["bytes_transferred"])
|
||||
))
|
||||
|
||||
# Check for memory leaks
|
||||
for role in ["server", "tunnel"]:
|
||||
before = result["%s_rss_before_kb" % role]
|
||||
after = result["%s_rss_after_kb" % role]
|
||||
if before is not None and after is not None:
|
||||
growth = after - before
|
||||
if growth > args.leak_threshold:
|
||||
msg = (
|
||||
" WARNING: ss-%s RSS grew by %s "
|
||||
"(%s -> %s) during %s test"
|
||||
% (role, format_rss(growth),
|
||||
format_rss(before), format_rss(after), cipher)
|
||||
)
|
||||
print(msg)
|
||||
leak_warnings.append(msg)
|
||||
|
||||
# Summary
|
||||
print()
|
||||
print("=" * 72)
|
||||
print("RESULTS SUMMARY")
|
||||
print("=" * 72)
|
||||
print()
|
||||
print("%-30s %10s %8s %12s %12s" % (
|
||||
"Cipher", "Bandwidth", "Time", "Server RSS", "Tunnel RSS"
|
||||
))
|
||||
print("-" * 72)
|
||||
|
||||
for r in all_results:
|
||||
if r["error"]:
|
||||
print("%-30s %10s" % (r["cipher"], "FAILED"))
|
||||
continue
|
||||
|
||||
srv_rss = ""
|
||||
tun_rss = ""
|
||||
if r["server_rss_before_kb"] and r["server_rss_after_kb"]:
|
||||
srv_rss = "%s->%s" % (
|
||||
format_rss(r["server_rss_before_kb"]),
|
||||
format_rss(r["server_rss_after_kb"])
|
||||
)
|
||||
if r["tunnel_rss_before_kb"] and r["tunnel_rss_after_kb"]:
|
||||
tun_rss = "%s->%s" % (
|
||||
format_rss(r["tunnel_rss_before_kb"]),
|
||||
format_rss(r["tunnel_rss_after_kb"])
|
||||
)
|
||||
print("%-30s %7.1f Mbps %6.2fs %12s %12s" % (
|
||||
r["cipher"], r["bandwidth_mbps"], r["duration_sec"],
|
||||
srv_rss or "N/A", tun_rss or "N/A"
|
||||
))
|
||||
|
||||
if leak_warnings:
|
||||
print()
|
||||
print("MEMORY LEAK WARNINGS:")
|
||||
for w in leak_warnings:
|
||||
print(w)
|
||||
print()
|
||||
sys.exit(1)
|
||||
|
||||
print()
|
||||
passed = [r for r in all_results if not r["error"]]
|
||||
failed = [r for r in all_results if r["error"]]
|
||||
print("%d passed, %d failed" % (len(passed), len(failed)))
|
||||
|
||||
if args.json:
|
||||
with open(args.json, "w") as f:
|
||||
json.dump(all_results, f, indent=2)
|
||||
print("Results written to %s" % args.json)
|
||||
|
||||
if failed:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,116 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
static void
|
||||
test_encode_decode(void)
|
||||
{
|
||||
/* Known test vector: "Hello" */
|
||||
const uint8_t input[] = "Hello";
|
||||
char encoded[BASE64_SIZE(5)];
|
||||
uint8_t decoded[5];
|
||||
|
||||
char *ret = base64_encode(encoded, sizeof(encoded), input, 5);
|
||||
assert(ret != NULL);
|
||||
assert(strlen(encoded) > 0);
|
||||
|
||||
int decoded_len = base64_decode(decoded, encoded, sizeof(decoded));
|
||||
assert(decoded_len == 5);
|
||||
assert(memcmp(decoded, input, 5) == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_empty_input(void)
|
||||
{
|
||||
char encoded[BASE64_SIZE(0)];
|
||||
char *ret = base64_encode(encoded, sizeof(encoded), (const uint8_t *)"", 0);
|
||||
assert(ret != NULL);
|
||||
assert(strlen(encoded) == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_single_byte(void)
|
||||
{
|
||||
const uint8_t input[] = { 0x41 }; /* 'A' */
|
||||
char encoded[BASE64_SIZE(1)];
|
||||
uint8_t decoded[1];
|
||||
|
||||
char *ret = base64_encode(encoded, sizeof(encoded), input, 1);
|
||||
assert(ret != NULL);
|
||||
|
||||
int decoded_len = base64_decode(decoded, encoded, sizeof(decoded));
|
||||
assert(decoded_len == 1);
|
||||
assert(decoded[0] == 0x41);
|
||||
}
|
||||
|
||||
static void
|
||||
test_two_bytes(void)
|
||||
{
|
||||
const uint8_t input[] = { 0x41, 0x42 }; /* "AB" */
|
||||
char encoded[BASE64_SIZE(2)];
|
||||
uint8_t decoded[2];
|
||||
|
||||
char *ret = base64_encode(encoded, sizeof(encoded), input, 2);
|
||||
assert(ret != NULL);
|
||||
|
||||
int decoded_len = base64_decode(decoded, encoded, sizeof(decoded));
|
||||
assert(decoded_len == 2);
|
||||
assert(decoded[0] == 0x41);
|
||||
assert(decoded[1] == 0x42);
|
||||
}
|
||||
|
||||
static void
|
||||
test_three_bytes(void)
|
||||
{
|
||||
const uint8_t input[] = { 0x00, 0xFF, 0x80 };
|
||||
char encoded[BASE64_SIZE(3)];
|
||||
uint8_t decoded[3];
|
||||
|
||||
char *ret = base64_encode(encoded, sizeof(encoded), input, 3);
|
||||
assert(ret != NULL);
|
||||
|
||||
int decoded_len = base64_decode(decoded, encoded, sizeof(decoded));
|
||||
assert(decoded_len == 3);
|
||||
assert(decoded[0] == 0x00);
|
||||
assert(decoded[1] == 0xFF);
|
||||
assert(decoded[2] == 0x80);
|
||||
}
|
||||
|
||||
static void
|
||||
test_roundtrip_binary(void)
|
||||
{
|
||||
const uint8_t input[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
10, 11, 12, 13, 14, 15, 16 };
|
||||
char encoded[BASE64_SIZE(17)];
|
||||
uint8_t decoded[17];
|
||||
|
||||
char *ret = base64_encode(encoded, sizeof(encoded), input, 17);
|
||||
assert(ret != NULL);
|
||||
|
||||
int decoded_len = base64_decode(decoded, encoded, sizeof(decoded));
|
||||
assert(decoded_len == 17);
|
||||
assert(memcmp(decoded, input, 17) == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_chars(void)
|
||||
{
|
||||
/* Character '!' (ASCII 33) is below the base64 range start ('+' = 43) */
|
||||
int decoded_len = base64_decode((uint8_t[4]){}, "!!!!", 4);
|
||||
assert(decoded_len == -1);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_encode_decode();
|
||||
test_empty_input();
|
||||
test_single_byte();
|
||||
test_two_bytes();
|
||||
test_three_bytes();
|
||||
test_roundtrip_binary();
|
||||
test_invalid_chars();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
/* Provide nonce_cache symbol needed by crypto.c */
|
||||
struct cache *nonce_cache = NULL;
|
||||
|
||||
static void
|
||||
test_balloc(void)
|
||||
{
|
||||
buffer_t buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
int ret = balloc(&buf, 100);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
assert(buf.data != NULL);
|
||||
assert(buf.capacity >= 100);
|
||||
assert(buf.len == 0);
|
||||
assert(buf.idx == 0);
|
||||
|
||||
bfree(&buf);
|
||||
assert(buf.data == NULL);
|
||||
assert(buf.capacity == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_brealloc(void)
|
||||
{
|
||||
buffer_t buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
balloc(&buf, 50);
|
||||
buf.len = 10;
|
||||
|
||||
/* Grow the buffer */
|
||||
int ret = brealloc(&buf, 10, 200);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
assert(buf.capacity >= 200);
|
||||
assert(buf.len == 10);
|
||||
|
||||
bfree(&buf);
|
||||
}
|
||||
|
||||
static void
|
||||
test_bprepend(void)
|
||||
{
|
||||
buffer_t dst, src;
|
||||
memset(&dst, 0, sizeof(dst));
|
||||
memset(&src, 0, sizeof(src));
|
||||
|
||||
balloc(&dst, 100);
|
||||
balloc(&src, 100);
|
||||
|
||||
/* Put some data in src */
|
||||
memcpy(src.data, "HEADER", 6);
|
||||
src.len = 6;
|
||||
|
||||
/* Put some data in dst */
|
||||
memcpy(dst.data, "BODY", 4);
|
||||
dst.len = 4;
|
||||
|
||||
int ret = bprepend(&dst, &src, 200);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
assert(dst.len == 10);
|
||||
assert(memcmp(dst.data, "HEADERBODY", 10) == 0);
|
||||
|
||||
bfree(&dst);
|
||||
bfree(&src);
|
||||
}
|
||||
|
||||
static void
|
||||
test_balloc_zero(void)
|
||||
{
|
||||
buffer_t buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
int ret = balloc(&buf, 0);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
/* A zero-capacity buffer should still succeed */
|
||||
bfree(&buf);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_balloc();
|
||||
test_brealloc();
|
||||
test_bprepend();
|
||||
test_balloc_zero();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
#include "cache.h"
|
||||
|
||||
static void
|
||||
test_create_delete(void)
|
||||
{
|
||||
struct cache *c = NULL;
|
||||
int ret = cache_create(&c, 100, NULL);
|
||||
assert(ret == 0);
|
||||
assert(c != NULL);
|
||||
|
||||
ret = cache_delete(c, 0);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
static void
|
||||
test_create_null(void)
|
||||
{
|
||||
int ret = cache_create(NULL, 100, NULL);
|
||||
assert(ret == EINVAL);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
static void
|
||||
test_insert_lookup(void)
|
||||
{
|
||||
struct cache *c = NULL;
|
||||
cache_create(&c, 100, NULL);
|
||||
|
||||
char *data = strdup("test_data");
|
||||
cache_insert(c, "key1", 4, data);
|
||||
|
||||
char *result = NULL;
|
||||
cache_lookup(c, "key1", 4, &result);
|
||||
assert(result != NULL);
|
||||
assert(strcmp(result, "test_data") == 0);
|
||||
|
||||
cache_delete(c, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_key_exist(void)
|
||||
{
|
||||
struct cache *c = NULL;
|
||||
cache_create(&c, 100, NULL);
|
||||
|
||||
char *data = strdup("value");
|
||||
cache_insert(c, "mykey", 5, data);
|
||||
|
||||
assert(cache_key_exist(c, "mykey", 5) == 1);
|
||||
assert(cache_key_exist(c, "nokey", 5) == 0);
|
||||
|
||||
cache_delete(c, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_remove(void)
|
||||
{
|
||||
struct cache *c = NULL;
|
||||
cache_create(&c, 100, NULL);
|
||||
|
||||
char *data = strdup("to_remove");
|
||||
cache_insert(c, "rmkey", 5, data);
|
||||
assert(cache_key_exist(c, "rmkey", 5) == 1);
|
||||
|
||||
cache_remove(c, "rmkey", 5);
|
||||
assert(cache_key_exist(c, "rmkey", 5) == 0);
|
||||
|
||||
cache_delete(c, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_lookup_missing(void)
|
||||
{
|
||||
struct cache *c = NULL;
|
||||
cache_create(&c, 100, NULL);
|
||||
|
||||
char *result = (char *)0xdeadbeef;
|
||||
cache_lookup(c, "missing", 7, &result);
|
||||
assert(result == NULL);
|
||||
|
||||
cache_delete(c, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_eviction(void)
|
||||
{
|
||||
struct cache *c = NULL;
|
||||
cache_create(&c, 3, NULL);
|
||||
|
||||
/* Insert 3 entries to fill cache */
|
||||
cache_insert(c, "k1", 2, strdup("v1"));
|
||||
cache_insert(c, "k2", 2, strdup("v2"));
|
||||
cache_insert(c, "k3", 2, strdup("v3"));
|
||||
|
||||
/* This should trigger eviction of the oldest entry */
|
||||
cache_insert(c, "k4", 2, strdup("v4"));
|
||||
|
||||
/* k1 should have been evicted */
|
||||
assert(cache_key_exist(c, "k1", 2) == 0);
|
||||
/* k4 should exist */
|
||||
assert(cache_key_exist(c, "k4", 2) == 1);
|
||||
|
||||
cache_delete(c, 0);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_create_delete();
|
||||
test_create_null();
|
||||
test_insert_lookup();
|
||||
test_key_exist();
|
||||
test_remove();
|
||||
test_lookup_missing();
|
||||
test_eviction();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sodium.h>
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
/* Provide nonce_cache symbol needed by crypto.c */
|
||||
struct cache *nonce_cache = NULL;
|
||||
|
||||
static void
|
||||
test_crypto_md5(void)
|
||||
{
|
||||
/* MD5("") = d41d8cd98f00b204e9800998ecf8427e */
|
||||
unsigned char result[16];
|
||||
crypto_md5((const unsigned char *)"", 0, result);
|
||||
|
||||
unsigned char expected[] = {
|
||||
0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
|
||||
0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e
|
||||
};
|
||||
assert(memcmp(result, expected, 16) == 0);
|
||||
(void)expected;
|
||||
|
||||
/* MD5("abc") = 900150983cd24fb0d6963f7d28e17f72 */
|
||||
crypto_md5((const unsigned char *)"abc", 3, result);
|
||||
unsigned char expected_abc[] = {
|
||||
0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
|
||||
0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72
|
||||
};
|
||||
assert(memcmp(result, expected_abc, 16) == 0);
|
||||
(void)expected_abc;
|
||||
}
|
||||
|
||||
static void
|
||||
test_crypto_derive_key(void)
|
||||
{
|
||||
uint8_t key[32];
|
||||
|
||||
/* derive_key should produce deterministic output from a password */
|
||||
int ret = crypto_derive_key("password", key, 32);
|
||||
assert(ret == 32);
|
||||
|
||||
/* Same password should produce same key */
|
||||
uint8_t key2[32];
|
||||
ret = crypto_derive_key("password", key2, 32);
|
||||
assert(ret == 32);
|
||||
assert(memcmp(key, key2, 32) == 0);
|
||||
|
||||
/* Different password should produce different key */
|
||||
uint8_t key3[32];
|
||||
ret = crypto_derive_key("different", key3, 32);
|
||||
assert(ret == 32);
|
||||
assert(memcmp(key, key3, 32) != 0);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
static void
|
||||
test_crypto_hkdf(void)
|
||||
{
|
||||
/* RFC 5869 Test Case 1 */
|
||||
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
assert(md != NULL);
|
||||
|
||||
unsigned char ikm[22];
|
||||
memset(ikm, 0x0b, 22);
|
||||
|
||||
unsigned char salt[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c
|
||||
};
|
||||
|
||||
unsigned char info[] = {
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9
|
||||
};
|
||||
|
||||
unsigned char okm[42];
|
||||
int ret = crypto_hkdf(md, salt, sizeof(salt), ikm, sizeof(ikm),
|
||||
info, sizeof(info), okm, sizeof(okm));
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
|
||||
unsigned char expected_okm[] = {
|
||||
0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
|
||||
0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
|
||||
0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
|
||||
0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
|
||||
0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
|
||||
0x58, 0x65
|
||||
};
|
||||
assert(memcmp(okm, expected_okm, 42) == 0);
|
||||
(void)expected_okm;
|
||||
}
|
||||
|
||||
static void
|
||||
test_crypto_hkdf_extract(void)
|
||||
{
|
||||
const mbedtls_md_info_t *md = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
|
||||
assert(md != NULL);
|
||||
|
||||
unsigned char ikm[22];
|
||||
memset(ikm, 0x0b, 22);
|
||||
|
||||
unsigned char salt[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c
|
||||
};
|
||||
|
||||
unsigned char prk[32];
|
||||
int ret = crypto_hkdf_extract(md, salt, sizeof(salt), ikm, sizeof(ikm), prk);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
|
||||
/* RFC 5869 Test Case 1 PRK */
|
||||
unsigned char expected_prk[] = {
|
||||
0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
|
||||
0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
|
||||
0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
|
||||
0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5
|
||||
};
|
||||
assert(memcmp(prk, expected_prk, 32) == 0);
|
||||
(void)expected_prk;
|
||||
}
|
||||
|
||||
static void
|
||||
test_crypto_parse_key(void)
|
||||
{
|
||||
/* base64_encode uses URL-safe base64 with -_ instead of +/ */
|
||||
uint8_t key[32];
|
||||
|
||||
/* A known base64-encoded 32-byte key (all zeros) */
|
||||
/* 32 zero bytes = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" in standard base64 */
|
||||
/* With URL-safe: same since no +/ needed */
|
||||
int ret = crypto_parse_key("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", key, 32);
|
||||
assert(ret == 32);
|
||||
(void)ret;
|
||||
|
||||
/* All bytes should be 0 */
|
||||
for (int i = 0; i < 32; i++) {
|
||||
assert(key[i] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
if (sodium_init() < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
test_crypto_md5();
|
||||
test_crypto_derive_key();
|
||||
test_crypto_hkdf();
|
||||
test_crypto_hkdf_extract();
|
||||
test_crypto_parse_key();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
#include "netutils.h"
|
||||
#include "jconf.h"
|
||||
|
||||
static void
|
||||
test_parse_addr_ipv4_with_port(void)
|
||||
{
|
||||
ss_addr_t addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
parse_addr("192.168.1.1:8080", &addr);
|
||||
assert(addr.host != NULL);
|
||||
assert(addr.port != NULL);
|
||||
assert(strcmp(addr.host, "192.168.1.1") == 0);
|
||||
assert(strcmp(addr.port, "8080") == 0);
|
||||
free_addr(&addr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_addr_ipv6_with_port(void)
|
||||
{
|
||||
ss_addr_t addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
parse_addr("[::1]:443", &addr);
|
||||
assert(addr.host != NULL);
|
||||
assert(addr.port != NULL);
|
||||
assert(strcmp(addr.host, "::1") == 0);
|
||||
assert(strcmp(addr.port, "443") == 0);
|
||||
free_addr(&addr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_addr_hostname_with_port(void)
|
||||
{
|
||||
ss_addr_t addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
parse_addr("example.com:1234", &addr);
|
||||
assert(addr.host != NULL);
|
||||
assert(addr.port != NULL);
|
||||
assert(strcmp(addr.host, "example.com") == 0);
|
||||
assert(strcmp(addr.port, "1234") == 0);
|
||||
free_addr(&addr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_addr_no_port(void)
|
||||
{
|
||||
ss_addr_t addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
parse_addr("10.0.0.1", &addr);
|
||||
assert(addr.host != NULL);
|
||||
assert(strcmp(addr.host, "10.0.0.1") == 0);
|
||||
/* Port may be NULL when no port is specified */
|
||||
free_addr(&addr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_addr_ipv6_no_port(void)
|
||||
{
|
||||
ss_addr_t addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
parse_addr("::1", &addr);
|
||||
assert(addr.host != NULL);
|
||||
assert(strcmp(addr.host, "::1") == 0);
|
||||
free_addr(&addr);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_parse_addr_ipv4_with_port();
|
||||
test_parse_addr_ipv6_with_port();
|
||||
test_parse_addr_hostname_with_port();
|
||||
test_parse_addr_no_port();
|
||||
test_parse_addr_ipv6_no_port();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "json.h"
|
||||
|
||||
static void
|
||||
test_parse_simple_object(void)
|
||||
{
|
||||
const char *json_str = "{\"key\": \"value\", \"num\": 42}";
|
||||
json_value *val = json_parse(json_str, strlen(json_str));
|
||||
assert(val != NULL);
|
||||
assert(val->type == json_object);
|
||||
assert(val->u.object.length == 2);
|
||||
|
||||
/* Check first entry */
|
||||
assert(strcmp(val->u.object.values[0].name, "key") == 0);
|
||||
assert(val->u.object.values[0].value->type == json_string);
|
||||
assert(strcmp(val->u.object.values[0].value->u.string.ptr, "value") == 0);
|
||||
|
||||
/* Check second entry */
|
||||
assert(strcmp(val->u.object.values[1].name, "num") == 0);
|
||||
assert(val->u.object.values[1].value->type == json_integer);
|
||||
assert(val->u.object.values[1].value->u.integer == 42);
|
||||
|
||||
json_value_free(val);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_array(void)
|
||||
{
|
||||
const char *json_str = "[1, 2, 3]";
|
||||
json_value *val = json_parse(json_str, strlen(json_str));
|
||||
assert(val != NULL);
|
||||
assert(val->type == json_array);
|
||||
assert(val->u.array.length == 3);
|
||||
assert(val->u.array.values[0]->type == json_integer);
|
||||
assert(val->u.array.values[0]->u.integer == 1);
|
||||
assert(val->u.array.values[1]->u.integer == 2);
|
||||
assert(val->u.array.values[2]->u.integer == 3);
|
||||
|
||||
json_value_free(val);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_nested(void)
|
||||
{
|
||||
const char *json_str = "{\"outer\": {\"inner\": true}}";
|
||||
json_value *val = json_parse(json_str, strlen(json_str));
|
||||
assert(val != NULL);
|
||||
assert(val->type == json_object);
|
||||
assert(val->u.object.length == 1);
|
||||
|
||||
json_value *outer = val->u.object.values[0].value;
|
||||
assert(outer->type == json_object);
|
||||
assert(outer->u.object.length == 1);
|
||||
|
||||
assert(outer->u.object.values[0].value->type == json_boolean);
|
||||
assert(outer->u.object.values[0].value->u.boolean != 0);
|
||||
|
||||
json_value_free(val);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_types(void)
|
||||
{
|
||||
const char *json_str = "{\"s\": \"hello\", \"i\": -5, \"d\": 3.14, \"b\": false, \"n\": null}";
|
||||
json_value *val = json_parse(json_str, strlen(json_str));
|
||||
assert(val != NULL);
|
||||
assert(val->type == json_object);
|
||||
assert(val->u.object.length == 5);
|
||||
|
||||
assert(val->u.object.values[0].value->type == json_string);
|
||||
assert(val->u.object.values[1].value->type == json_integer);
|
||||
assert(val->u.object.values[1].value->u.integer == -5);
|
||||
assert(val->u.object.values[2].value->type == json_double);
|
||||
assert(val->u.object.values[3].value->type == json_boolean);
|
||||
assert(val->u.object.values[3].value->u.boolean == 0);
|
||||
assert(val->u.object.values[4].value->type == json_null);
|
||||
|
||||
json_value_free(val);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_invalid(void)
|
||||
{
|
||||
/* Missing closing brace */
|
||||
assert(json_parse("{\"key\": 1", 9) == NULL);
|
||||
|
||||
/* Empty string */
|
||||
assert(json_parse("", 0) == NULL);
|
||||
|
||||
/* Just garbage */
|
||||
assert(json_parse("not json", 8) == NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_empty_object(void)
|
||||
{
|
||||
const char *json_str = "{}";
|
||||
json_value *val = json_parse(json_str, strlen(json_str));
|
||||
assert(val != NULL);
|
||||
assert(val->type == json_object);
|
||||
assert(val->u.object.length == 0);
|
||||
json_value_free(val);
|
||||
}
|
||||
|
||||
static void
|
||||
test_parse_empty_array(void)
|
||||
{
|
||||
const char *json_str = "[]";
|
||||
json_value *val = json_parse(json_str, strlen(json_str));
|
||||
assert(val != NULL);
|
||||
assert(val->type == json_array);
|
||||
assert(val->u.array.length == 0);
|
||||
json_value_free(val);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_parse_simple_object();
|
||||
test_parse_array();
|
||||
test_parse_nested();
|
||||
test_parse_types();
|
||||
test_parse_invalid();
|
||||
test_parse_empty_object();
|
||||
test_parse_empty_array();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
#include "netutils.h"
|
||||
|
||||
static void
|
||||
test_get_sockaddr_len(void)
|
||||
{
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
struct sockaddr_storage unknown;
|
||||
|
||||
memset(&addr4, 0, sizeof(addr4));
|
||||
addr4.sin_family = AF_INET;
|
||||
assert(get_sockaddr_len((struct sockaddr *)&addr4) == sizeof(struct sockaddr_in));
|
||||
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
addr6.sin6_family = AF_INET6;
|
||||
assert(get_sockaddr_len((struct sockaddr *)&addr6) == sizeof(struct sockaddr_in6));
|
||||
|
||||
memset(&unknown, 0, sizeof(unknown));
|
||||
unknown.ss_family = AF_UNSPEC;
|
||||
assert(get_sockaddr_len((struct sockaddr *)&unknown) == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sockaddr_cmp(void)
|
||||
{
|
||||
struct sockaddr_storage a, b;
|
||||
struct sockaddr_in *a4 = (struct sockaddr_in *)&a;
|
||||
struct sockaddr_in *b4 = (struct sockaddr_in *)&b;
|
||||
|
||||
/* Same address and port */
|
||||
memset(&a, 0, sizeof(a));
|
||||
memset(&b, 0, sizeof(b));
|
||||
a4->sin_family = AF_INET;
|
||||
b4->sin_family = AF_INET;
|
||||
a4->sin_port = htons(80);
|
||||
b4->sin_port = htons(80);
|
||||
inet_pton(AF_INET, "127.0.0.1", &a4->sin_addr);
|
||||
inet_pton(AF_INET, "127.0.0.1", &b4->sin_addr);
|
||||
assert(sockaddr_cmp(&a, &b, sizeof(struct sockaddr_in)) == 0);
|
||||
|
||||
/* Different port */
|
||||
b4->sin_port = htons(81);
|
||||
assert(sockaddr_cmp(&a, &b, sizeof(struct sockaddr_in)) != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sockaddr_cmp_addr(void)
|
||||
{
|
||||
struct sockaddr_storage a, b;
|
||||
struct sockaddr_in *a4 = (struct sockaddr_in *)&a;
|
||||
struct sockaddr_in *b4 = (struct sockaddr_in *)&b;
|
||||
|
||||
memset(&a, 0, sizeof(a));
|
||||
memset(&b, 0, sizeof(b));
|
||||
a4->sin_family = AF_INET;
|
||||
b4->sin_family = AF_INET;
|
||||
a4->sin_port = htons(80);
|
||||
b4->sin_port = htons(443);
|
||||
inet_pton(AF_INET, "10.0.0.1", &a4->sin_addr);
|
||||
inet_pton(AF_INET, "10.0.0.1", &b4->sin_addr);
|
||||
|
||||
/* Same address, different port - should be equal */
|
||||
assert(sockaddr_cmp_addr(&a, &b, sizeof(struct sockaddr_in)) == 0);
|
||||
|
||||
/* Different address */
|
||||
inet_pton(AF_INET, "10.0.0.2", &b4->sin_addr);
|
||||
assert(sockaddr_cmp_addr(&a, &b, sizeof(struct sockaddr_in)) != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_validate_hostname(void)
|
||||
{
|
||||
/* Valid hostnames */
|
||||
assert(validate_hostname("example.com", 11) == 1);
|
||||
assert(validate_hostname("sub.example.com", 15) == 1);
|
||||
assert(validate_hostname("a", 1) == 1);
|
||||
assert(validate_hostname("a-b", 3) == 1);
|
||||
assert(validate_hostname("123.456", 7) == 1);
|
||||
|
||||
/* Invalid hostnames */
|
||||
assert(validate_hostname(NULL, 0) == 0);
|
||||
assert(validate_hostname("", 0) == 0);
|
||||
assert(validate_hostname(".example.com", 12) == 0); /* starts with dot */
|
||||
assert(validate_hostname("-example.com", 12) == 0); /* label starts with hyphen */
|
||||
assert(validate_hostname("example-.com", 12) == 0); /* label ends with hyphen */
|
||||
|
||||
/* Too long hostname (> 255) */
|
||||
char long_name[260];
|
||||
memset(long_name, 'a', 259);
|
||||
long_name[259] = '\0';
|
||||
assert(validate_hostname(long_name, 259) == 0);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_get_sockaddr_len();
|
||||
test_sockaddr_cmp();
|
||||
test_sockaddr_cmp_addr();
|
||||
test_validate_hostname();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
#include "ppbloom.h"
|
||||
|
||||
static void
|
||||
test_init_free(void)
|
||||
{
|
||||
int ret = ppbloom_init(1000, 0.01);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
ppbloom_free();
|
||||
}
|
||||
|
||||
static void
|
||||
test_add_check(void)
|
||||
{
|
||||
ppbloom_init(1000, 0.01);
|
||||
|
||||
const char *item1 = "hello";
|
||||
const char *item2 = "world";
|
||||
const char *item3 = "missing";
|
||||
|
||||
/* Not in filter initially */
|
||||
assert(ppbloom_check(item1, strlen(item1)) == 0);
|
||||
assert(ppbloom_check(item2, strlen(item2)) == 0);
|
||||
|
||||
/* Add items */
|
||||
ppbloom_add(item1, strlen(item1));
|
||||
ppbloom_add(item2, strlen(item2));
|
||||
|
||||
/* Should be found */
|
||||
assert(ppbloom_check(item1, strlen(item1)) == 1);
|
||||
assert(ppbloom_check(item2, strlen(item2)) == 1);
|
||||
|
||||
/* Should not be found */
|
||||
assert(ppbloom_check(item3, strlen(item3)) == 0);
|
||||
(void)item3;
|
||||
|
||||
ppbloom_free();
|
||||
}
|
||||
|
||||
static void
|
||||
test_binary_data(void)
|
||||
{
|
||||
ppbloom_init(1000, 0.01);
|
||||
|
||||
const uint8_t data1[] = { 0x00, 0x01, 0x02, 0x03 };
|
||||
const uint8_t data2[] = { 0xFF, 0xFE, 0xFD, 0xFC };
|
||||
|
||||
ppbloom_add(data1, sizeof(data1));
|
||||
assert(ppbloom_check(data1, sizeof(data1)) == 1);
|
||||
assert(ppbloom_check(data2, sizeof(data2)) == 0);
|
||||
(void)data2;
|
||||
|
||||
ppbloom_free();
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_init_free();
|
||||
test_add_check();
|
||||
test_binary_data();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
#include "rule.h"
|
||||
#include "utils.h"
|
||||
|
||||
static void
|
||||
test_new_rule(void)
|
||||
{
|
||||
rule_t *rule = new_rule();
|
||||
assert(rule != NULL);
|
||||
assert(rule->pattern == NULL);
|
||||
assert(rule->pattern_re == NULL);
|
||||
free(rule);
|
||||
}
|
||||
|
||||
static void
|
||||
test_accept_rule_arg(void)
|
||||
{
|
||||
rule_t *rule = new_rule();
|
||||
assert(rule != NULL);
|
||||
|
||||
int ret = accept_rule_arg(rule, "^example\\.com$");
|
||||
assert(ret == 1);
|
||||
assert(rule->pattern != NULL);
|
||||
assert(strcmp(rule->pattern, "^example\\.com$") == 0);
|
||||
|
||||
/* Second call should fail - pattern already set */
|
||||
ret = accept_rule_arg(rule, "another");
|
||||
assert(ret == -1);
|
||||
(void)ret;
|
||||
|
||||
free(rule->pattern);
|
||||
free(rule);
|
||||
}
|
||||
|
||||
static void
|
||||
test_init_rule(void)
|
||||
{
|
||||
rule_t *rule = new_rule();
|
||||
accept_rule_arg(rule, "^test.*$");
|
||||
|
||||
int ret = init_rule(rule);
|
||||
assert(ret == 1);
|
||||
(void)ret;
|
||||
assert(rule->pattern_re != NULL);
|
||||
|
||||
if (rule->match_data)
|
||||
pcre2_match_data_free(rule->match_data);
|
||||
if (rule->pattern_re)
|
||||
pcre2_code_free(rule->pattern_re);
|
||||
free(rule->pattern);
|
||||
free(rule);
|
||||
}
|
||||
|
||||
static void
|
||||
test_init_rule_invalid(void)
|
||||
{
|
||||
rule_t *rule = new_rule();
|
||||
accept_rule_arg(rule, "[invalid"); /* Unclosed bracket */
|
||||
|
||||
int ret = init_rule(rule);
|
||||
assert(ret == 0); /* Should fail */
|
||||
(void)ret;
|
||||
|
||||
free(rule->pattern);
|
||||
free(rule);
|
||||
}
|
||||
|
||||
static void
|
||||
test_lookup_rule(void)
|
||||
{
|
||||
struct cork_dllist rules;
|
||||
cork_dllist_init(&rules);
|
||||
|
||||
rule_t *rule1 = new_rule();
|
||||
accept_rule_arg(rule1, "^google\\.com$");
|
||||
init_rule(rule1);
|
||||
add_rule(&rules, rule1);
|
||||
|
||||
rule_t *rule2 = new_rule();
|
||||
accept_rule_arg(rule2, ".*\\.example\\.com$");
|
||||
init_rule(rule2);
|
||||
add_rule(&rules, rule2);
|
||||
|
||||
/* Should match rule1 */
|
||||
rule_t *found = lookup_rule(&rules, "google.com", 10);
|
||||
assert(found == rule1);
|
||||
|
||||
/* Should match rule2 */
|
||||
found = lookup_rule(&rules, "sub.example.com", 15);
|
||||
assert(found == rule2);
|
||||
|
||||
/* Should not match */
|
||||
found = lookup_rule(&rules, "other.net", 9);
|
||||
assert(found == NULL);
|
||||
(void)found;
|
||||
|
||||
/* Clean up */
|
||||
if (rule1->match_data) pcre2_match_data_free(rule1->match_data);
|
||||
if (rule1->pattern_re) pcre2_code_free(rule1->pattern_re);
|
||||
free(rule1->pattern);
|
||||
free(rule1);
|
||||
if (rule2->match_data) pcre2_match_data_free(rule2->match_data);
|
||||
if (rule2->pattern_re) pcre2_code_free(rule2->pattern_re);
|
||||
free(rule2->pattern);
|
||||
free(rule2);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_new_rule();
|
||||
test_accept_rule_arg();
|
||||
test_init_rule();
|
||||
test_init_rule_invalid();
|
||||
test_lookup_rule();
|
||||
return 0;
|
||||
}
|
||||
Executable
+881
@@ -0,0 +1,881 @@
|
||||
#!/usr/bin/env bash
|
||||
###############################################################################
|
||||
# test_ss_setup.sh -- Unit tests for ss-setup.sh utility functions
|
||||
#
|
||||
# Sources ss-setup.sh (which skips main() due to BASH_SOURCE guard) and
|
||||
# exercises every pure/utility function that doesn't require a TUI backend.
|
||||
###############################################################################
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
SS_SETUP="${PROJECT_ROOT}/scripts/ss-setup.sh"
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
TMPDIR_TEST=""
|
||||
|
||||
cleanup_test() {
|
||||
if [[ -n "$TMPDIR_TEST" && -d "$TMPDIR_TEST" ]]; then
|
||||
rm -rf "$TMPDIR_TEST"
|
||||
fi
|
||||
}
|
||||
trap cleanup_test EXIT
|
||||
|
||||
TMPDIR_TEST=$(mktemp -d)
|
||||
|
||||
# Source the script under test (main() won't run due to BASH_SOURCE guard)
|
||||
# shellcheck source=../scripts/ss-setup.sh
|
||||
source "$SS_SETUP"
|
||||
|
||||
###############################################################################
|
||||
# Test helpers
|
||||
###############################################################################
|
||||
|
||||
assert_eq() {
|
||||
local test_name="$1" expected="$2" actual="$3"
|
||||
if [[ "$expected" == "$actual" ]]; then
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: ${test_name}" >&2
|
||||
echo " expected: '${expected}'" >&2
|
||||
echo " actual: '${actual}'" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
assert_match() {
|
||||
local test_name="$1" pattern="$2" actual="$3"
|
||||
if [[ "$actual" =~ $pattern ]]; then
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: ${test_name}" >&2
|
||||
echo " expected match: '${pattern}'" >&2
|
||||
echo " actual: '${actual}'" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
assert_ok() {
|
||||
local test_name="$1"
|
||||
shift
|
||||
if "$@" 2>/dev/null; then
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: ${test_name} (command returned non-zero)" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
assert_fail() {
|
||||
local test_name="$1"
|
||||
shift
|
||||
if "$@" 2>/dev/null; then
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: ${test_name} (expected failure but got success)" >&2
|
||||
else
|
||||
PASS=$((PASS + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_contains() {
|
||||
local test_name="$1" needle="$2" haystack="$3"
|
||||
if [[ "$haystack" == *"$needle"* ]]; then
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: ${test_name}" >&2
|
||||
echo " expected to contain: '${needle}'" >&2
|
||||
echo " actual: '${haystack}'" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_contains() {
|
||||
local test_name="$1" needle="$2" haystack="$3"
|
||||
if [[ "$haystack" != *"$needle"* ]]; then
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: ${test_name}" >&2
|
||||
echo " expected NOT to contain: '${needle}'" >&2
|
||||
echo " actual: '${haystack}'" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: AEAD_CIPHERS constant
|
||||
###############################################################################
|
||||
|
||||
test_aead_ciphers_count() {
|
||||
assert_eq "AEAD_CIPHERS has 5 entries" "5" "${#AEAD_CIPHERS[@]}"
|
||||
}
|
||||
|
||||
test_aead_ciphers_contains_chacha20() {
|
||||
local found=0
|
||||
for c in "${AEAD_CIPHERS[@]}"; do
|
||||
[[ "$c" == "chacha20-ietf-poly1305" ]] && found=1
|
||||
done
|
||||
assert_eq "AEAD_CIPHERS contains chacha20-ietf-poly1305" "1" "$found"
|
||||
}
|
||||
|
||||
test_aead_ciphers_contains_aes256gcm() {
|
||||
local found=0
|
||||
for c in "${AEAD_CIPHERS[@]}"; do
|
||||
[[ "$c" == "aes-256-gcm" ]] && found=1
|
||||
done
|
||||
assert_eq "AEAD_CIPHERS contains aes-256-gcm" "1" "$found"
|
||||
}
|
||||
|
||||
test_aead_ciphers_contains_aes128gcm() {
|
||||
local found=0
|
||||
for c in "${AEAD_CIPHERS[@]}"; do
|
||||
[[ "$c" == "aes-128-gcm" ]] && found=1
|
||||
done
|
||||
assert_eq "AEAD_CIPHERS contains aes-128-gcm" "1" "$found"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: validate_port
|
||||
###############################################################################
|
||||
|
||||
test_validate_port_valid() {
|
||||
assert_ok "validate_port 1" validate_port "1"
|
||||
assert_ok "validate_port 80" validate_port "80"
|
||||
assert_ok "validate_port 443" validate_port "443"
|
||||
assert_ok "validate_port 8388" validate_port "8388"
|
||||
assert_ok "validate_port 65535" validate_port "65535"
|
||||
}
|
||||
|
||||
test_validate_port_invalid() {
|
||||
assert_fail "validate_port 0" validate_port "0"
|
||||
assert_fail "validate_port 65536" validate_port "65536"
|
||||
assert_fail "validate_port -1" validate_port "-1"
|
||||
assert_fail "validate_port abc" validate_port "abc"
|
||||
assert_fail "validate_port empty" validate_port ""
|
||||
assert_fail "validate_port 99999" validate_port "99999"
|
||||
assert_fail "validate_port 8.8" validate_port "8.8"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: validate_instance_name
|
||||
###############################################################################
|
||||
|
||||
test_validate_instance_name_valid() {
|
||||
assert_ok "instance: config" validate_instance_name "config"
|
||||
assert_ok "instance: my-server" validate_instance_name "my-server"
|
||||
assert_ok "instance: server_1" validate_instance_name "server_1"
|
||||
assert_ok "instance: Test123" validate_instance_name "Test123"
|
||||
assert_ok "instance: a" validate_instance_name "a"
|
||||
assert_ok "instance: A-B_c-1" validate_instance_name "A-B_c-1"
|
||||
}
|
||||
|
||||
test_validate_instance_name_invalid() {
|
||||
assert_fail "instance: empty" validate_instance_name ""
|
||||
assert_fail "instance: has space" validate_instance_name "has space"
|
||||
assert_fail "instance: has.dot" validate_instance_name "has.dot"
|
||||
assert_fail "instance: has/slash" validate_instance_name "has/slash"
|
||||
assert_fail "instance: has@at" validate_instance_name "has@at"
|
||||
assert_fail "instance: has:colon" validate_instance_name "has:colon"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: generate_password
|
||||
###############################################################################
|
||||
|
||||
test_generate_password_nonempty() {
|
||||
local pw
|
||||
pw=$(generate_password 32)
|
||||
assert_match "password is non-empty" ".+" "$pw"
|
||||
}
|
||||
|
||||
test_generate_password_length() {
|
||||
# base64 of 16 bytes = 24 chars (before newline strip)
|
||||
local pw
|
||||
pw=$(generate_password 16)
|
||||
# Should be at least 20 chars (base64 encoding of 16 bytes)
|
||||
local len=${#pw}
|
||||
if (( len >= 20 )); then
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: password length too short: ${len} chars" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
test_generate_password_no_newlines() {
|
||||
local pw
|
||||
pw=$(generate_password 32)
|
||||
assert_not_contains "password has no newline" $'\n' "$pw"
|
||||
}
|
||||
|
||||
test_generate_password_different() {
|
||||
local pw1 pw2
|
||||
pw1=$(generate_password 32)
|
||||
pw2=$(generate_password 32)
|
||||
if [[ "$pw1" != "$pw2" ]]; then
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: two passwords are identical: '${pw1}'" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: generate_random_port
|
||||
###############################################################################
|
||||
|
||||
test_generate_random_port_range() {
|
||||
local port
|
||||
for _ in $(seq 1 10); do
|
||||
port=$(generate_random_port)
|
||||
if (( port >= 10000 && port <= 65000 )); then
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: random port ${port} out of range 10000-65000" >&2
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
test_generate_random_port_numeric() {
|
||||
local port
|
||||
port=$(generate_random_port)
|
||||
assert_match "random port is numeric" "^[0-9]+$" "$port"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: json_escape
|
||||
###############################################################################
|
||||
|
||||
test_json_escape_plain() {
|
||||
local result
|
||||
result=$(json_escape "hello world")
|
||||
assert_eq "json_escape plain" "hello world" "$result"
|
||||
}
|
||||
|
||||
test_json_escape_quotes() {
|
||||
local result
|
||||
result=$(json_escape 'say "hi"')
|
||||
assert_eq "json_escape quotes" 'say \"hi\"' "$result"
|
||||
}
|
||||
|
||||
test_json_escape_backslash() {
|
||||
local result
|
||||
result=$(json_escape 'path\to\file')
|
||||
assert_eq "json_escape backslash" 'path\\to\\file' "$result"
|
||||
}
|
||||
|
||||
test_json_escape_tab() {
|
||||
local result
|
||||
result=$(json_escape "col1 col2")
|
||||
assert_eq "json_escape tab" 'col1\tcol2' "$result"
|
||||
}
|
||||
|
||||
test_json_escape_newline() {
|
||||
local result
|
||||
result=$(json_escape "line1
|
||||
line2")
|
||||
assert_eq "json_escape newline" 'line1\nline2' "$result"
|
||||
}
|
||||
|
||||
test_json_escape_empty() {
|
||||
local result
|
||||
result=$(json_escape "")
|
||||
assert_eq "json_escape empty" "" "$result"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: urlencode
|
||||
###############################################################################
|
||||
|
||||
test_urlencode_plain() {
|
||||
local result
|
||||
result=$(urlencode "hello")
|
||||
assert_eq "urlencode plain" "hello" "$result"
|
||||
}
|
||||
|
||||
test_urlencode_space() {
|
||||
local result
|
||||
result=$(urlencode "hello world")
|
||||
assert_eq "urlencode space" "hello%20world" "$result"
|
||||
}
|
||||
|
||||
test_urlencode_special() {
|
||||
local result
|
||||
result=$(urlencode "a=b&c=d")
|
||||
assert_eq "urlencode special" "a%3Db%26c%3Dd" "$result"
|
||||
}
|
||||
|
||||
test_urlencode_semicolon() {
|
||||
local result
|
||||
result=$(urlencode "obfs-local;obfs=http")
|
||||
assert_eq "urlencode semicolon" "obfs-local%3Bobfs%3Dhttp" "$result"
|
||||
}
|
||||
|
||||
test_urlencode_safe_chars() {
|
||||
local result
|
||||
result=$(urlencode "a-b_c.d~e")
|
||||
assert_eq "urlencode safe chars" "a-b_c.d~e" "$result"
|
||||
}
|
||||
|
||||
test_urlencode_empty() {
|
||||
local result
|
||||
result=$(urlencode "")
|
||||
assert_eq "urlencode empty" "" "$result"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: generate_ss_uri
|
||||
###############################################################################
|
||||
|
||||
test_ss_uri_basic() {
|
||||
local uri
|
||||
uri=$(generate_ss_uri "aes-256-gcm" "testpass" "1.2.3.4" "8388" "" "")
|
||||
# Should start with ss://
|
||||
assert_match "ss uri starts with ss://" "^ss://" "$uri"
|
||||
# Should contain @host:port
|
||||
assert_contains "ss uri has host:port" "@1.2.3.4:8388" "$uri"
|
||||
# Should NOT have plugin query
|
||||
assert_not_contains "ss uri no plugin query" "/?plugin=" "$uri"
|
||||
}
|
||||
|
||||
test_ss_uri_with_plugin() {
|
||||
local uri
|
||||
uri=$(generate_ss_uri "chacha20-ietf-poly1305" "mypass" "example.com" "443" "v2ray-plugin" "server;tls;host=example.com")
|
||||
assert_match "ss uri+plugin starts with ss://" "^ss://" "$uri"
|
||||
assert_contains "ss uri+plugin has host:port" "@example.com:443" "$uri"
|
||||
assert_contains "ss uri+plugin has plugin param" "/?plugin=" "$uri"
|
||||
# v2ray-plugin should be URL-encoded with the opts
|
||||
assert_contains "ss uri+plugin has v2ray" "v2ray-plugin" "$uri"
|
||||
}
|
||||
|
||||
test_ss_uri_with_plugin_no_opts() {
|
||||
local uri
|
||||
uri=$(generate_ss_uri "aes-128-gcm" "pw" "10.0.0.1" "9000" "obfs-local" "")
|
||||
assert_contains "ss uri plugin-no-opts has plugin" "/?plugin=" "$uri"
|
||||
assert_contains "ss uri plugin-no-opts has obfs-local" "obfs-local" "$uri"
|
||||
}
|
||||
|
||||
test_ss_uri_base64_encoding() {
|
||||
# Verify the userinfo part is valid base64url
|
||||
local uri
|
||||
uri=$(generate_ss_uri "aes-256-gcm" "test" "1.2.3.4" "8388" "" "")
|
||||
# Extract the base64 part between ss:// and @
|
||||
local b64_part
|
||||
b64_part=$(echo "$uri" | sed 's|^ss://\([^@]*\)@.*|\1|')
|
||||
# base64url should only contain [A-Za-z0-9_-]
|
||||
assert_match "ss uri base64url valid chars" "^[A-Za-z0-9_-]+$" "$b64_part"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: write_json_config (server)
|
||||
###############################################################################
|
||||
|
||||
test_write_json_config_basic() {
|
||||
local outfile="${TMPDIR_TEST}/server_basic.json"
|
||||
CFG_SERVER="0.0.0.0"
|
||||
CFG_SERVER_PORT="8388"
|
||||
CFG_PASSWORD="testpassword123"
|
||||
CFG_TIMEOUT="300"
|
||||
CFG_METHOD="aes-256-gcm"
|
||||
CFG_MODE="tcp_and_udp"
|
||||
CFG_FAST_OPEN="false"
|
||||
CFG_PLUGIN=""
|
||||
CFG_PLUGIN_OPTS=""
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
assert_contains "server json has server" '"server": "0.0.0.0"' "$content"
|
||||
assert_contains "server json has port" '"server_port": 8388' "$content"
|
||||
assert_contains "server json has password" '"password": "testpassword123"' "$content"
|
||||
assert_contains "server json has timeout" '"timeout": 300' "$content"
|
||||
assert_contains "server json has method" '"method": "aes-256-gcm"' "$content"
|
||||
assert_contains "server json has mode" '"mode": "tcp_and_udp"' "$content"
|
||||
assert_contains "server json has fast_open false" '"fast_open": false' "$content"
|
||||
assert_not_contains "server json no plugin" '"plugin"' "$content"
|
||||
# No trailing comma before closing brace
|
||||
assert_not_contains "server json no trailing comma" ',
|
||||
}' "$content"
|
||||
}
|
||||
|
||||
test_write_json_config_fast_open_true() {
|
||||
local outfile="${TMPDIR_TEST}/server_tfo.json"
|
||||
CFG_SERVER="0.0.0.0"
|
||||
CFG_SERVER_PORT="443"
|
||||
CFG_PASSWORD="pw"
|
||||
CFG_TIMEOUT="60"
|
||||
CFG_METHOD="chacha20-ietf-poly1305"
|
||||
CFG_MODE="tcp_only"
|
||||
CFG_FAST_OPEN="true"
|
||||
CFG_PLUGIN=""
|
||||
CFG_PLUGIN_OPTS=""
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
assert_contains "server json fast_open true" '"fast_open": true' "$content"
|
||||
assert_not_contains "server json fast_open not quoted" '"fast_open": "true"' "$content"
|
||||
}
|
||||
|
||||
test_write_json_config_with_plugin() {
|
||||
local outfile="${TMPDIR_TEST}/server_plugin.json"
|
||||
CFG_SERVER="0.0.0.0"
|
||||
CFG_SERVER_PORT="443"
|
||||
CFG_PASSWORD="pw"
|
||||
CFG_TIMEOUT="300"
|
||||
CFG_METHOD="aes-256-gcm"
|
||||
CFG_MODE="tcp_and_udp"
|
||||
CFG_FAST_OPEN="false"
|
||||
CFG_PLUGIN="v2ray-plugin"
|
||||
CFG_PLUGIN_OPTS="server;tls;host=example.com"
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
assert_contains "server json has plugin" '"plugin": "v2ray-plugin"' "$content"
|
||||
assert_contains "server json has plugin_opts" '"plugin_opts": "server;tls;host=example.com"' "$content"
|
||||
}
|
||||
|
||||
test_write_json_config_with_plugin_no_opts() {
|
||||
local outfile="${TMPDIR_TEST}/server_plugin_noopts.json"
|
||||
CFG_SERVER="0.0.0.0"
|
||||
CFG_SERVER_PORT="8388"
|
||||
CFG_PASSWORD="pw"
|
||||
CFG_TIMEOUT="300"
|
||||
CFG_METHOD="aes-256-gcm"
|
||||
CFG_MODE="tcp_and_udp"
|
||||
CFG_FAST_OPEN="false"
|
||||
CFG_PLUGIN="obfs-local"
|
||||
CFG_PLUGIN_OPTS=""
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
assert_contains "server json plugin no opts has plugin" '"plugin": "obfs-local"' "$content"
|
||||
assert_not_contains "server json plugin no opts has no plugin_opts" '"plugin_opts"' "$content"
|
||||
}
|
||||
|
||||
test_write_json_config_password_special_chars() {
|
||||
local outfile="${TMPDIR_TEST}/server_special.json"
|
||||
CFG_SERVER="0.0.0.0"
|
||||
CFG_SERVER_PORT="8388"
|
||||
CFG_PASSWORD='pass"word\with/special'
|
||||
CFG_TIMEOUT="300"
|
||||
CFG_METHOD="aes-256-gcm"
|
||||
CFG_MODE="tcp_and_udp"
|
||||
CFG_FAST_OPEN="false"
|
||||
CFG_PLUGIN=""
|
||||
CFG_PLUGIN_OPTS=""
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
# Quotes and backslashes should be escaped
|
||||
assert_contains "special password escaped quote" '\"' "$content"
|
||||
assert_contains "special password escaped backslash" '\\' "$content"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: write_client_json_config
|
||||
###############################################################################
|
||||
|
||||
test_write_client_json_config_basic() {
|
||||
local outfile="${TMPDIR_TEST}/client_basic.json"
|
||||
CFG_CLIENT_SERVER="1.2.3.4"
|
||||
CFG_CLIENT_SERVER_PORT="8388"
|
||||
CFG_CLIENT_LOCAL_PORT="1080"
|
||||
CFG_CLIENT_PASSWORD="clientpw"
|
||||
CFG_CLIENT_METHOD="aes-256-gcm"
|
||||
CFG_CLIENT_PLUGIN=""
|
||||
CFG_CLIENT_PLUGIN_OPTS=""
|
||||
|
||||
write_client_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
assert_contains "client json has server" '"server": "1.2.3.4"' "$content"
|
||||
assert_contains "client json has server_port" '"server_port": 8388' "$content"
|
||||
assert_contains "client json has local_address" '"local_address": "127.0.0.1"' "$content"
|
||||
assert_contains "client json has local_port" '"local_port": 1080' "$content"
|
||||
assert_contains "client json has password" '"password": "clientpw"' "$content"
|
||||
assert_contains "client json has method" '"method": "aes-256-gcm"' "$content"
|
||||
assert_contains "client json has timeout" '"timeout": 300' "$content"
|
||||
assert_contains "client json has mode" '"mode": "tcp_and_udp"' "$content"
|
||||
assert_not_contains "client json no plugin" '"plugin"' "$content"
|
||||
}
|
||||
|
||||
test_write_client_json_config_with_plugin() {
|
||||
local outfile="${TMPDIR_TEST}/client_plugin.json"
|
||||
CFG_CLIENT_SERVER="example.com"
|
||||
CFG_CLIENT_SERVER_PORT="443"
|
||||
CFG_CLIENT_LOCAL_PORT="1080"
|
||||
CFG_CLIENT_PASSWORD="pw"
|
||||
CFG_CLIENT_METHOD="chacha20-ietf-poly1305"
|
||||
CFG_CLIENT_PLUGIN="v2ray-plugin"
|
||||
CFG_CLIENT_PLUGIN_OPTS="tls;host=example.com"
|
||||
|
||||
write_client_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
assert_contains "client json plugin" '"plugin": "v2ray-plugin"' "$content"
|
||||
assert_contains "client json plugin_opts" '"plugin_opts": "tls;host=example.com"' "$content"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: parse_existing_config (round-trip)
|
||||
###############################################################################
|
||||
|
||||
test_parse_existing_config_roundtrip() {
|
||||
local outfile="${TMPDIR_TEST}/roundtrip.json"
|
||||
|
||||
# Set known values
|
||||
CFG_SERVER="10.20.30.40"
|
||||
CFG_SERVER_PORT="9999"
|
||||
CFG_PASSWORD="roundtrip_pw"
|
||||
CFG_TIMEOUT="600"
|
||||
CFG_METHOD="aes-128-gcm"
|
||||
CFG_MODE="udp_only"
|
||||
CFG_FAST_OPEN="true"
|
||||
CFG_PLUGIN="obfs-local"
|
||||
CFG_PLUGIN_OPTS="obfs=http;obfs-host=example.com"
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
# Reset globals
|
||||
CFG_SERVER=""
|
||||
CFG_SERVER_PORT=""
|
||||
CFG_PASSWORD=""
|
||||
CFG_TIMEOUT=""
|
||||
CFG_METHOD=""
|
||||
CFG_MODE=""
|
||||
CFG_FAST_OPEN=""
|
||||
CFG_PLUGIN=""
|
||||
CFG_PLUGIN_OPTS=""
|
||||
|
||||
# Parse back
|
||||
parse_existing_config "$outfile"
|
||||
|
||||
assert_eq "roundtrip server" "10.20.30.40" "$CFG_SERVER"
|
||||
assert_eq "roundtrip port" "9999" "$CFG_SERVER_PORT"
|
||||
assert_eq "roundtrip password" "roundtrip_pw" "$CFG_PASSWORD"
|
||||
assert_eq "roundtrip timeout" "600" "$CFG_TIMEOUT"
|
||||
assert_eq "roundtrip method" "aes-128-gcm" "$CFG_METHOD"
|
||||
assert_eq "roundtrip mode" "udp_only" "$CFG_MODE"
|
||||
assert_eq "roundtrip fast_open" "true" "$CFG_FAST_OPEN"
|
||||
assert_eq "roundtrip plugin" "obfs-local" "$CFG_PLUGIN"
|
||||
assert_eq "roundtrip plugin_opts" "obfs=http;obfs-host=example.com" "$CFG_PLUGIN_OPTS"
|
||||
}
|
||||
|
||||
test_parse_existing_config_no_plugin() {
|
||||
local outfile="${TMPDIR_TEST}/roundtrip_noplugin.json"
|
||||
|
||||
CFG_SERVER="0.0.0.0"
|
||||
CFG_SERVER_PORT="8388"
|
||||
CFG_PASSWORD="simplepw"
|
||||
CFG_TIMEOUT="300"
|
||||
CFG_METHOD="aes-256-gcm"
|
||||
CFG_MODE="tcp_and_udp"
|
||||
CFG_FAST_OPEN="false"
|
||||
CFG_PLUGIN=""
|
||||
CFG_PLUGIN_OPTS=""
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
# Reset and parse
|
||||
CFG_SERVER=""
|
||||
CFG_SERVER_PORT=""
|
||||
CFG_PASSWORD=""
|
||||
CFG_METHOD=""
|
||||
CFG_MODE=""
|
||||
CFG_PLUGIN="should_be_cleared_if_found"
|
||||
|
||||
parse_existing_config "$outfile"
|
||||
|
||||
assert_eq "roundtrip-noplugin server" "0.0.0.0" "$CFG_SERVER"
|
||||
assert_eq "roundtrip-noplugin port" "8388" "$CFG_SERVER_PORT"
|
||||
assert_eq "roundtrip-noplugin password" "simplepw" "$CFG_PASSWORD"
|
||||
assert_eq "roundtrip-noplugin method" "aes-256-gcm" "$CFG_METHOD"
|
||||
assert_eq "roundtrip-noplugin mode" "tcp_and_udp" "$CFG_MODE"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: detect_os
|
||||
###############################################################################
|
||||
|
||||
test_detect_os() {
|
||||
local os
|
||||
os=$(detect_os)
|
||||
# Should be one of the known values
|
||||
assert_match "detect_os returns known value" "^(linux|darwin|freebsd|openbsd|netbsd)$" "$os"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: detect_arch
|
||||
###############################################################################
|
||||
|
||||
test_detect_arch() {
|
||||
local arch
|
||||
arch=$(detect_arch)
|
||||
# Should be one of the known mapped values or raw uname -m
|
||||
assert_match "detect_arch returns a value" ".+" "$arch"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: KNOWN_PLUGINS constant
|
||||
###############################################################################
|
||||
|
||||
test_known_plugins_count() {
|
||||
assert_eq "KNOWN_PLUGINS has 4 entries" "4" "${#KNOWN_PLUGINS[@]}"
|
||||
}
|
||||
|
||||
test_known_plugins_entries() {
|
||||
local found_simpleobfs=0 found_v2ray=0 found_xray=0 found_kcptun=0
|
||||
for p in "${KNOWN_PLUGINS[@]}"; do
|
||||
case "$p" in
|
||||
simple-obfs) found_simpleobfs=1 ;;
|
||||
v2ray-plugin) found_v2ray=1 ;;
|
||||
xray-plugin) found_xray=1 ;;
|
||||
kcptun) found_kcptun=1 ;;
|
||||
esac
|
||||
done
|
||||
assert_eq "KNOWN_PLUGINS has simple-obfs" "1" "$found_simpleobfs"
|
||||
assert_eq "KNOWN_PLUGINS has v2ray-plugin" "1" "$found_v2ray"
|
||||
assert_eq "KNOWN_PLUGINS has xray-plugin" "1" "$found_xray"
|
||||
assert_eq "KNOWN_PLUGINS has kcptun" "1" "$found_kcptun"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: plugin_repo function
|
||||
###############################################################################
|
||||
|
||||
test_plugin_repos() {
|
||||
assert_eq "plugin_repo simple-obfs" "shadowsocks/simple-obfs" "$(plugin_repo simple-obfs)"
|
||||
assert_eq "plugin_repo v2ray-plugin" "shadowsocks/v2ray-plugin" "$(plugin_repo v2ray-plugin)"
|
||||
assert_eq "plugin_repo xray-plugin" "teddysun/xray-plugin" "$(plugin_repo xray-plugin)"
|
||||
assert_eq "plugin_repo kcptun" "xtaci/kcptun" "$(plugin_repo kcptun)"
|
||||
assert_eq "plugin_repo unknown" "" "$(plugin_repo unknown)"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: SS_SETUP_VERSION
|
||||
###############################################################################
|
||||
|
||||
test_version_set() {
|
||||
assert_match "SS_SETUP_VERSION is semver" "^[0-9]+\.[0-9]+\.[0-9]+$" "$SS_SETUP_VERSION"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: Config directory constant
|
||||
###############################################################################
|
||||
|
||||
test_config_dir() {
|
||||
assert_eq "CONFIG_DIR" "/etc/shadowsocks-libev" "$CONFIG_DIR"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: JSON output is valid (no trailing commas, booleans unquoted)
|
||||
###############################################################################
|
||||
|
||||
test_json_no_trailing_comma() {
|
||||
local outfile="${TMPDIR_TEST}/no_trailing.json"
|
||||
CFG_SERVER="0.0.0.0"
|
||||
CFG_SERVER_PORT="8388"
|
||||
CFG_PASSWORD="pw"
|
||||
CFG_TIMEOUT="300"
|
||||
CFG_METHOD="aes-256-gcm"
|
||||
CFG_MODE="tcp_and_udp"
|
||||
CFG_FAST_OPEN="false"
|
||||
CFG_PLUGIN=""
|
||||
CFG_PLUGIN_OPTS=""
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
# Check that the file doesn't have ",\n}" pattern (trailing comma)
|
||||
if grep -qP ',\s*\}' "$outfile" 2>/dev/null || grep -q ',$' "$outfile" 2>/dev/null; then
|
||||
# Try a more portable check
|
||||
local last_data_line
|
||||
last_data_line=$(grep -v '^[[:space:]]*[{}]' "$outfile" | tail -1)
|
||||
if [[ "$last_data_line" == *"," ]]; then
|
||||
FAIL=$((FAIL + 1))
|
||||
echo "FAIL: JSON has trailing comma on last data line: ${last_data_line}" >&2
|
||||
else
|
||||
PASS=$((PASS + 1))
|
||||
fi
|
||||
else
|
||||
PASS=$((PASS + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
test_json_booleans_unquoted() {
|
||||
local outfile="${TMPDIR_TEST}/bool_check.json"
|
||||
CFG_SERVER="0.0.0.0"
|
||||
CFG_SERVER_PORT="8388"
|
||||
CFG_PASSWORD="pw"
|
||||
CFG_TIMEOUT="300"
|
||||
CFG_METHOD="aes-256-gcm"
|
||||
CFG_MODE="tcp_and_udp"
|
||||
CFG_FAST_OPEN="true"
|
||||
CFG_PLUGIN=""
|
||||
CFG_PLUGIN_OPTS=""
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
assert_not_contains "boolean not quoted string" '"fast_open": "true"' "$content"
|
||||
assert_contains "boolean is unquoted true" '"fast_open": true' "$content"
|
||||
}
|
||||
|
||||
test_json_integers_unquoted() {
|
||||
local outfile="${TMPDIR_TEST}/int_check.json"
|
||||
CFG_SERVER="0.0.0.0"
|
||||
CFG_SERVER_PORT="8388"
|
||||
CFG_PASSWORD="pw"
|
||||
CFG_TIMEOUT="300"
|
||||
CFG_METHOD="aes-256-gcm"
|
||||
CFG_MODE="tcp_and_udp"
|
||||
CFG_FAST_OPEN="false"
|
||||
CFG_PLUGIN=""
|
||||
CFG_PLUGIN_OPTS=""
|
||||
|
||||
write_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
assert_contains "server_port is unquoted int" '"server_port": 8388' "$content"
|
||||
assert_not_contains "server_port not quoted string" '"server_port": "8388"' "$content"
|
||||
assert_contains "timeout is unquoted int" '"timeout": 300' "$content"
|
||||
assert_not_contains "timeout not quoted string" '"timeout": "300"' "$content"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Tests: Client JSON integers unquoted
|
||||
###############################################################################
|
||||
|
||||
test_client_json_integers_unquoted() {
|
||||
local outfile="${TMPDIR_TEST}/client_int_check.json"
|
||||
CFG_CLIENT_SERVER="1.2.3.4"
|
||||
CFG_CLIENT_SERVER_PORT="443"
|
||||
CFG_CLIENT_LOCAL_PORT="1080"
|
||||
CFG_CLIENT_PASSWORD="pw"
|
||||
CFG_CLIENT_METHOD="aes-256-gcm"
|
||||
CFG_CLIENT_PLUGIN=""
|
||||
CFG_CLIENT_PLUGIN_OPTS=""
|
||||
|
||||
write_client_json_config "$outfile"
|
||||
|
||||
local content
|
||||
content=$(cat "$outfile")
|
||||
|
||||
assert_contains "client server_port unquoted" '"server_port": 443' "$content"
|
||||
assert_contains "client local_port unquoted" '"local_port": 1080' "$content"
|
||||
assert_contains "client timeout unquoted" '"timeout": 300' "$content"
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Run all tests
|
||||
###############################################################################
|
||||
|
||||
echo "Running ss-setup unit tests..."
|
||||
echo
|
||||
|
||||
# Constants
|
||||
test_aead_ciphers_count
|
||||
test_aead_ciphers_contains_chacha20
|
||||
test_aead_ciphers_contains_aes256gcm
|
||||
test_aead_ciphers_contains_aes128gcm
|
||||
test_known_plugins_count
|
||||
test_known_plugins_entries
|
||||
test_plugin_repos
|
||||
test_version_set
|
||||
test_config_dir
|
||||
|
||||
# Validation
|
||||
test_validate_port_valid
|
||||
test_validate_port_invalid
|
||||
|
||||
test_validate_instance_name_valid
|
||||
test_validate_instance_name_invalid
|
||||
|
||||
# Password generation
|
||||
test_generate_password_nonempty
|
||||
test_generate_password_length
|
||||
test_generate_password_no_newlines
|
||||
test_generate_password_different
|
||||
|
||||
# Random port
|
||||
test_generate_random_port_range
|
||||
test_generate_random_port_numeric
|
||||
|
||||
# JSON escaping
|
||||
test_json_escape_plain
|
||||
test_json_escape_quotes
|
||||
test_json_escape_backslash
|
||||
test_json_escape_tab
|
||||
test_json_escape_newline
|
||||
test_json_escape_empty
|
||||
|
||||
# URL encoding
|
||||
test_urlencode_plain
|
||||
test_urlencode_space
|
||||
test_urlencode_special
|
||||
test_urlencode_semicolon
|
||||
test_urlencode_safe_chars
|
||||
test_urlencode_empty
|
||||
|
||||
# ss:// URI
|
||||
test_ss_uri_basic
|
||||
test_ss_uri_with_plugin
|
||||
test_ss_uri_with_plugin_no_opts
|
||||
test_ss_uri_base64_encoding
|
||||
|
||||
# Server JSON config
|
||||
test_write_json_config_basic
|
||||
test_write_json_config_fast_open_true
|
||||
test_write_json_config_with_plugin
|
||||
test_write_json_config_with_plugin_no_opts
|
||||
test_write_json_config_password_special_chars
|
||||
|
||||
# Client JSON config
|
||||
test_write_client_json_config_basic
|
||||
test_write_client_json_config_with_plugin
|
||||
test_client_json_integers_unquoted
|
||||
|
||||
# Parse existing config (round-trip)
|
||||
test_parse_existing_config_roundtrip
|
||||
test_parse_existing_config_no_plugin
|
||||
|
||||
# Platform detection
|
||||
test_detect_os
|
||||
test_detect_arch
|
||||
|
||||
# JSON validity
|
||||
test_json_no_trailing_comma
|
||||
test_json_booleans_unquoted
|
||||
test_json_integers_unquoted
|
||||
|
||||
echo
|
||||
echo "================================="
|
||||
echo "Results: ${PASS} passed, ${FAIL} failed"
|
||||
echo "================================="
|
||||
|
||||
if [[ $FAIL -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
static void
|
||||
test_ss_itoa(void)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = ss_itoa(0);
|
||||
assert(s != NULL);
|
||||
assert(strcmp(s, "0") == 0);
|
||||
|
||||
s = ss_itoa(42);
|
||||
assert(s != NULL);
|
||||
assert(strcmp(s, "42") == 0);
|
||||
|
||||
s = ss_itoa(-1);
|
||||
assert(s != NULL);
|
||||
assert(strcmp(s, "-1") == 0);
|
||||
|
||||
s = ss_itoa(12345);
|
||||
assert(s != NULL);
|
||||
assert(strcmp(s, "12345") == 0);
|
||||
(void)s;
|
||||
}
|
||||
|
||||
static void
|
||||
test_ss_isnumeric(void)
|
||||
{
|
||||
assert(ss_isnumeric("12345") == 1);
|
||||
assert(ss_isnumeric("0") == 1);
|
||||
assert(ss_isnumeric("") == 0);
|
||||
assert(ss_isnumeric("abc") == 0);
|
||||
assert(ss_isnumeric("123abc") == 0);
|
||||
assert(ss_isnumeric("12.34") == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ss_strndup(void)
|
||||
{
|
||||
char *s;
|
||||
|
||||
s = ss_strndup("hello world", 5);
|
||||
assert(s != NULL);
|
||||
assert(strcmp(s, "hello") == 0);
|
||||
assert(strlen(s) == 5);
|
||||
free(s);
|
||||
|
||||
s = ss_strndup("short", 10);
|
||||
assert(s != NULL);
|
||||
assert(strcmp(s, "short") == 0);
|
||||
free(s);
|
||||
|
||||
s = ss_strndup("", 0);
|
||||
assert(s != NULL);
|
||||
assert(strcmp(s, "") == 0);
|
||||
free(s);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
test_ss_itoa();
|
||||
test_ss_isnumeric();
|
||||
test_ss_strndup();
|
||||
return 0;
|
||||
}
|
||||
Generated
+13
-13
@@ -863,7 +863,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -976,7 +976,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1506,7 +1506,7 @@ dependencies = [
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.2",
|
||||
"socket2 0.5.10",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
@@ -2196,7 +2196,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2527,7 +2527,7 @@ dependencies = [
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2 0.6.2",
|
||||
"socket2 0.5.10",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -2565,9 +2565,9 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2 0.6.2",
|
||||
"socket2 0.5.10",
|
||||
"tracing",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2680,9 +2680,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.13.1"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62"
|
||||
checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
@@ -2827,7 +2827,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2886,7 +2886,7 @@ dependencies = [
|
||||
"security-framework 3.5.1",
|
||||
"security-framework-sys",
|
||||
"webpki-root-certs",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3532,7 +3532,7 @@ dependencies = [
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4190,7 +4190,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -44,7 +44,7 @@ Can be `domain` or `ipcidr` or `classical`. Rule file behavior.
|
||||
|
||||
#### interval
|
||||
|
||||
The update interval for the Rule set, in seconds or /^(\d+)(s|m|h|d)?$/.
|
||||
The update interval for the Rule set, in seconds or `/^(\d+)(s|m|h|d)?$/`.
|
||||
|
||||
#### rawQuery
|
||||
|
||||
|
||||
@@ -276,6 +276,12 @@ return view.extend({
|
||||
so.depends({type: /^(hysteria|hysteria2)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'hysteria_hop_interval', _('Port hop interval'),
|
||||
_('In seconds. <code>%s</code> will be used if empty.').format('30'));
|
||||
so.datatype = 'uinteger';
|
||||
so.depends('type', 'hysteria2');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'),
|
||||
_('In Mbps.'));
|
||||
so.datatype = 'uinteger';
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user