Add optional SOCKS server authentication

This commit is contained in:
ushan0v
2026-07-13 02:39:35 +03:00
parent 416c367f81
commit ec936a675a
12 changed files with 134 additions and 10 deletions
+50
View File
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -eo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SERVER_JS="$ROOT_DIR/luci-app-forkop/htdocs/luci-static/resources/view/forkop/server.js"
node - "$SERVER_JS" <<'NODE'
const fs = require("fs");
const source = fs.readFileSync(process.argv[2], "utf8");
function fail(message) {
console.error(`FAIL: ${message}`);
process.exit(1);
}
function requiredIndex(needle, from = 0) {
const index = source.indexOf(needle, from);
if (index < 0) fail(`missing source contract: ${needle}`);
return index;
}
const flag = requiredIndex('"socks_auth_enabled"');
const username = requiredIndex('"server_username", _("Username")', flag);
const password = requiredIndex('"server_password", _("Password")', username);
const nextOption = requiredIndex('"vmess_alter_id", _("Alter ID")', password);
const flagBlock = source.slice(flag, username);
if (!flagBlock.includes('_("Enable authentication")') ||
!flagBlock.includes('o.default = "1"') ||
!flagBlock.includes('o.depends("protocol", "socks")')) {
fail("SOCKS authentication switch must be enabled by default and limited to SOCKS servers");
}
for (const block of [source.slice(username, password), source.slice(password, nextOption)]) {
if (!block.includes('o.depends({ protocol: "socks", socks_auth_enabled: "1" })')) {
fail("SOCKS credentials must only be required while authentication is enabled");
}
}
const link = source.slice(
requiredIndex("function buildSocksLink"),
requiredIndex("function normalizeSha256"),
);
if (!link.includes("isSocksAuthenticationEnabled(sectionId)") ||
!link.includes('socks5://${userInfo}${uriHost}:${port}')) {
fail("SOCKS share links must omit credentials when authentication is disabled");
}
NODE
printf 'LuCI SOCKS server authentication checks passed\n'
+8
View File
@@ -78,6 +78,10 @@ forkop.vless.server_users=client|22222222-2222-4222-8222-222222222222|xtls-rprx-
forkop.socks=server
forkop.socks.protocol=socks
forkop.socks.label=desk
forkop.socks_open=server
forkop.socks_open.protocol=socks
forkop.socks_open.label=guest
forkop.socks_open.socks_auth_enabled=0
forkop.tailscale=server
forkop.tailscale.protocol=tailscale
forkop.json=server
@@ -111,8 +115,12 @@ assert_value forkop.vless.reality_short_id abcd1234
assert_value forkop.vless.reality_private_key private-key
assert_value forkop.vless.reality_public_key public-key
assert_value forkop.socks.security none
assert_value forkop.socks.socks_auth_enabled 1
assert_value forkop.socks.server_username desk
assert_value forkop.socks.server_password generated-password
assert_value forkop.socks_open.socks_auth_enabled 0
assert_value forkop.socks_open.server_username guest
assert_value forkop.socks_open.server_password generated-password
assert_value forkop.tailscale.security none
assert_value forkop.tailscale.tailscale_control_url https://controlplane.tailscale.com
assert_value forkop.tailscale.tailscale_hostname forkop-tailscale
+16 -1
View File
@@ -278,6 +278,18 @@ cat >"$WORK_DIR/server-inbound-fixture.json" <<'JSON'
"server_username": "tester",
"server_password": "secret",
"routing_mode": "direct"
},
{
".name": "open",
".type": "server",
"enabled": "1",
"protocol": "socks",
"listen": "0.0.0.0",
"listen_port": "18081",
"socks_auth_enabled": "0",
"server_username": "ignored",
"server_password": "ignored",
"routing_mode": "direct"
}
]
}
@@ -1136,7 +1148,10 @@ assert(defaults.dns.strategy == "prefer_ipv4", "missing DNS strategy keeps the p
let server = cfg("server");
let socks = inbound(server, "server-edge-in");
assert(socks && socks.type == "socks" && socks.listen_port == 18080, "server socks inbound");
assert(socks.users && socks.users[0].username == "tester", "server socks auth");
assert(socks.users && socks.users[0].username == "tester", "legacy server socks auth defaults to enabled");
let open_socks = inbound(server, "server-open-in");
assert(open_socks && open_socks.type == "socks" && open_socks.listen_port == 18081, "server open socks inbound");
assert(open_socks.users == null, "disabled server socks auth omits users");
assert(route_rule(server, r => r.inbound == "server-edge-in" && r.outbound == "direct-out") != null, "server direct route");
let matchers = cfg("matchers");