mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-05 09:54:11 +08:00
update 2026-10-07 18:47:42
This commit is contained in:
1 parent
617f7ca2a6
commit
bd061545ed
4832 files changed
+1693456
No files matched your search
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env node
|
||||
// Use the real LuCI CBI dependency evaluator, including checkbox empty values.
|
||||
const fs = require('fs');
|
||||
const vm = require('vm');
|
||||
const assert = require('assert');
|
||||
const path = require('path');
|
||||
const cbi = fs.readFileSync(process.argv[2], 'utf8');
|
||||
const client = fs.readFileSync(path.join(__dirname, '../luasrc/model/cbi/shadowsocksr/client.lua'), 'utf8');
|
||||
const filter = client.slice(client.indexOf('o = s:option(Flag, "filter_aaaa"'), client.indexOf('if is_finded("chinadns-ng") then', client.indexOf('o = s:option(Flag, "filter_aaaa"')));
|
||||
const deps = [...filter.matchAll(/o:depends\(\{pdnsd_enable = "(\d+)", ipv6_support = (false|"0")\}\)/g)]
|
||||
.map(m => ({ pdnsd_enable: m[1], ipv6_support: m[2] === 'false' ? false : '0' }));
|
||||
assert.strictEqual(deps.length, 3);
|
||||
const fields = { pdnsd_enable: { type: 'select', value: '1' }, ipv6_support: { type: 'checkbox', value: '1', checked: false } };
|
||||
const ctx = { document: { querySelectorAll: query => [fields[query.match(/id="([^"]+)"/)[1]]] } };
|
||||
vm.createContext(ctx);
|
||||
vm.runInContext(cbi.slice(cbi.indexOf('function cbi_d_checkvalue('), cbi.indexOf('function cbi_d_update(')), ctx);
|
||||
for (const mode of ['0', '1', '4', '6', '7']) {
|
||||
fields.pdnsd_enable.value = mode;
|
||||
for (const checked of [false, true, false]) {
|
||||
fields.ipv6_support.checked = checked;
|
||||
assert.strictEqual(ctx.cbi_d_check(deps), !checked && ['1', '4', '7'].includes(mode));
|
||||
}
|
||||
}
|
||||
assert.match(filter, /function o\.remove\(self, section\)\s*end/);
|
||||
console.log('PASS: actual CBI checkbox dependencies toggle immediately and preserve the saved filter');
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Exercise DNS generation with BusyBox awk, both backends and all run modes."""
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
source = Path(__file__).resolve().parents[1] / 'root/usr/share/shadowsocksr/gfw2ipset.sh'
|
||||
with tempfile.TemporaryDirectory(prefix='ssr6-dns-') as tmp:
|
||||
root = Path(tmp)
|
||||
config = root / 'config'
|
||||
output = root / 'output'
|
||||
init = root / 'etc/init.d'
|
||||
for directory in (config, output, init, root / 'bin'):
|
||||
directory.mkdir(parents=True)
|
||||
for name in ('gfw_base.conf', 'gfw_list.conf'):
|
||||
(config / name).write_text(''.join(
|
||||
f'server=/{domain}/127.0.0.1#5335\nipset=/{domain}/gfwlist\n'
|
||||
for domain in ('proxy.example', 'white.example', 'black.example', 'deny.example')))
|
||||
for name, domain in [('white', 'white'), ('black', 'black'), ('deny', 'deny')]:
|
||||
(config / f'{name}.list').write_text(f'# comment\n\n{domain}.example\n')
|
||||
(init / 'shadowsocksr').write_text('''
|
||||
check_run_environment() { USE_TABLES="$BACKEND"; }
|
||||
echolog() { :; }
|
||||
normalize_run_mode() { echo "$MODE"; }
|
||||
ipv6_enabled() { [ "$V6" = 1 ] && [ "$USE_TABLES" = nftables ]; }
|
||||
uci_get_by_type() { echo 0; }
|
||||
TMP_DNSMASQ_PATH="$TEST_OUTPUT"
|
||||
dns_port=5335
|
||||
''')
|
||||
script = root / 'generate.sh'
|
||||
script.write_text(source.read_text().replace('/etc/ssrplus/', str(config) + '/'))
|
||||
busybox = shutil.which('busybox')
|
||||
if not busybox:
|
||||
raise SystemExit('BusyBox is required to test the OpenWrt awk dialect')
|
||||
(root / 'bin/awk').symlink_to(busybox)
|
||||
count = 0
|
||||
for backend in ('nftables', 'iptables'):
|
||||
for mode in ('gfw', 'router', 'all'):
|
||||
for ipv6 in ('0', '1'):
|
||||
env = dict(os.environ, BACKEND=backend, MODE=mode, V6=ipv6,
|
||||
IPKG_INSTROOT=tmp, TEST_OUTPUT=str(output),
|
||||
PATH=str(root / 'bin') + ':' + os.environ['PATH'])
|
||||
subprocess.run([busybox, 'sh', str(script)], env=env, check=True)
|
||||
gfw = (output / 'gfw_list.conf').read_text()
|
||||
white = (output / 'whitelist_forward.conf').read_text()
|
||||
black = (output / 'blacklist_forward.conf').read_text()
|
||||
assert 'proxy.example' in gfw
|
||||
for domain in ('white.example', 'black.example', 'deny.example'):
|
||||
assert domain not in gfw, (backend, mode, ipv6, domain)
|
||||
assert 'server=' not in white
|
||||
assert 'server=/black.example/127.0.0.1#5335' in black
|
||||
if backend == 'nftables':
|
||||
assert '4#inet#ss_spec#whitelist_domain' in white
|
||||
assert ('6#inet#ss_spec#whitelist_domain6' in white) == (ipv6 == '1')
|
||||
assert ('6#inet#ss_spec#blacklist6' in black) == (ipv6 == '1')
|
||||
if mode == 'gfw':
|
||||
assert '4#inet#ss_spec#gfwlist' in gfw
|
||||
assert ('6#inet#ss_spec#gfwlist6' in gfw) == (ipv6 == '1')
|
||||
else:
|
||||
assert 'nftset=' not in gfw and 'ipset=' not in gfw
|
||||
else:
|
||||
assert 'nftset=' not in gfw + white + black
|
||||
assert ('ipset=/proxy.example/gfwlist' in gfw) == (mode == 'gfw')
|
||||
count += 1
|
||||
print(f'PASS: {count} DNS generation combinations, domain overrides and AAAA sets')
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
# Run as root on OpenWrt with the package installed. Rules stay in a new netns.
|
||||
set -eu
|
||||
ns="ssr6-check-$$"
|
||||
tmp=$(mktemp -d)
|
||||
cleanup() {
|
||||
ip netns del "$ns" 2>/dev/null || true
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
ip netns add "$ns"
|
||||
. /usr/share/shadowsocksr/ipv6.sh
|
||||
uci_get_by_type() { :; }
|
||||
uci_get_by_name() { :; }
|
||||
FWMARK=0x53535250
|
||||
local_port=1234
|
||||
LOCAL_PORT=301
|
||||
Interface=""
|
||||
LAN_AC_IP="w192.0.2.1 2001:db8::1"
|
||||
WAN_BP_IP="192.0.2.2 2001:db8:1::/64"
|
||||
WAN_FW_IP="192.0.2.3 2001:db8:2::/64"
|
||||
LAN_BP_IP="2001:db8::2"
|
||||
LAN_FP_IP="2001:db8::3"
|
||||
LAN_GM_IP="2001:db8::4"
|
||||
count=0
|
||||
for RUNMODE in gfw router all; do
|
||||
for OUTPUT in 0 1 2; do
|
||||
for udp in tproxy quic disabled; do
|
||||
TPROXY=""
|
||||
DISABLE_UDP_RULES=0
|
||||
case "$udp" in
|
||||
tproxy) TPROXY=2 ;;
|
||||
disabled) DISABLE_UDP_RULES=1 ;;
|
||||
esac
|
||||
for PROXY_PORTS in "" "-m multiport --dports 53,80,443,8000:8100"; do
|
||||
ip netns exec "$ns" nft flush ruleset
|
||||
ip netns exec "$ns" nft add table inet ss_spec
|
||||
ipv6_rules_generate > "$tmp/rules"
|
||||
ip netns exec "$ns" nft -f "$tmp/rules"
|
||||
# Validate the serialized form used during a firewall reload.
|
||||
ip netns exec "$ns" nft list ruleset > "$tmp/snapshot"
|
||||
ip netns exec "$ns" nft flush ruleset
|
||||
ip netns exec "$ns" nft -f "$tmp/snapshot"
|
||||
count=$((count + 1))
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
printf 'PASS: %s IPv6 mode/OUTPUT/UDP/port combinations and snapshot reloads\n' "$count"
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/lua
|
||||
-- Run on OpenWrt with the installed Lua dependencies; reads UCI, never updates it.
|
||||
-- lua subscribe-ss.lua /path/to/subscribe.lua
|
||||
local path = arg[1] or "/usr/share/shadowsocksr/subscribe.lua"
|
||||
local file = assert(io.open(path))
|
||||
local source = file:read("*a")
|
||||
file:close()
|
||||
source = source:gsub("^#![^\n]*", "")
|
||||
local boundary = assert(source:find("\nlocal function md5_string", 1, true))
|
||||
-- Load only the parser definitions, stopping before subscription execution.
|
||||
local parse = assert(loadstring(source:sub(1, boundary - 1) .. [[
|
||||
has_xray, has_ss_rust, has_mihomo = true, false, false
|
||||
return processData
|
||||
]], "@" .. path))()
|
||||
local b64 = require("nixio").bin.b64encode
|
||||
local count = 0
|
||||
local function check(label, link, expected)
|
||||
local ok, node = pcall(parse, "ss", link)
|
||||
assert(ok, label .. ": parser raised an error")
|
||||
if expected then
|
||||
assert(node, label .. ": node rejected")
|
||||
assert(node.type == "v2ray" and node.v2ray_protocol == "shadowsocks", label .. ": wrong backend")
|
||||
for key, value in pairs(expected) do
|
||||
assert(tostring(node[key]) == tostring(value), label .. ": incorrect " .. key)
|
||||
end
|
||||
else
|
||||
assert(node == nil, label .. ": malformed node accepted")
|
||||
end
|
||||
count = count + 1
|
||||
end
|
||||
local expected = {server="ss.example.com", server_port=20070, encrypt_method_ss="aes-256-gcm", password="test-password", alias="乌克兰W01"}
|
||||
local suffix = "#%E4%B9%8C%E5%85%8B%E5%85%B0W01"
|
||||
local full = b64("aes-256-gcm:test-password@ss.example.com:20070")
|
||||
check("whole-link base64", full .. suffix, expected)
|
||||
check("unpadded whole-link base64", full:gsub("=+$", "") .. suffix, expected)
|
||||
check("SIP002", b64("aes-256-gcm:test-password") .. "@ss.example.com:20070" .. suffix, expected)
|
||||
check("plaintext credentials", "aes-256-gcm:test-password@ss.example.com:20070" .. suffix, expected)
|
||||
local password = "p@ss:word+/%?#"
|
||||
local credentials = "aes-256-gcm:" .. password
|
||||
for _,link in ipairs({b64(credentials .. "@ss.example.com:20070"), b64(credentials) .. "@ss.example.com:20070", b64(credentials):gsub("+", "-"):gsub("/", "_"):gsub("=+$", "") .. "@ss.example.com:20070"}) do
|
||||
check("reserved password characters", link, {password=password, server="ss.example.com", server_port=20070})
|
||||
end
|
||||
check("percent-encoded plaintext", "aes-256-gcm:p%40ss%3Aword+%2F%25%3F%23@ss.example.com:20070", {password=password})
|
||||
check("legacy query", full .. "?type=ws&host=cdn.example.com&path=%2Fsocket&security=tls&sni=tls.example.com", {transport="ws", ws_path="/socket", tls="1", tls_host="tls.example.com"})
|
||||
check("UUID extension", "12345678-1234-1234-1234-123456789abc@ss.example.com:443?encryption=none&type=ws", {password="12345678-1234-1234-1234-123456789abc", encrypt_method_ss="none", transport="ws"})
|
||||
check("IPv6", b64("aes-256-gcm:test-password@[2001:db8::1]:443"), {server="2001:db8::1", server_port=443})
|
||||
for _,link in ipairs({"", "invalid", b64("missing-separator"), b64("aes-256-gcm:password@ss.example.com"), "aes-256-gcm:password@:443", b64(":password@ss.example.com:443")}) do
|
||||
check("malformed input", link, nil)
|
||||
end
|
||||
print("SS subscription parser: " .. count .. " cases passed")
|
||||
Reference in new issue
Block a user