Add native traffic inspection to Harbor Connect and Gateway
This commit is contained in:
Executable
+123
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
readonly RC_VERSION='1.14.0-rc.5'
|
||||
readonly IMAGE="harbor-singbox-client-rc-test:${RC_VERSION}"
|
||||
FIXTURES="$(mktemp -d)"
|
||||
SUFFIX="${FIXTURES##*/}"
|
||||
readonly SUFFIX="${SUFFIX//[^[:alnum:]]/}"
|
||||
readonly NETWORK="harbor-singbox-rc-${SUFFIX}"
|
||||
readonly TARGET="harbor-singbox-rc-target-${SUFFIX}"
|
||||
readonly PROXY="harbor-singbox-rc-proxy-${SUFFIX}"
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
NETWORK_CREATED=false
|
||||
TARGET_CREATED=false
|
||||
PROXY_CREATED=false
|
||||
|
||||
cleanup() {
|
||||
[[ "$PROXY_CREATED" == true ]] && docker rm -f "$PROXY" >/dev/null 2>&1 || true
|
||||
[[ "$TARGET_CREATED" == true ]] && docker rm -f "$TARGET" >/dev/null 2>&1 || true
|
||||
[[ "$NETWORK_CREATED" == true ]] && docker network rm "$NETWORK" >/dev/null 2>&1 || true
|
||||
docker image rm "$IMAGE" >/dev/null 2>&1 || true
|
||||
rm -rf "$FIXTURES"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
check_config() {
|
||||
local name="$1"
|
||||
local output
|
||||
local unexpected
|
||||
|
||||
if ! output="$(docker run --rm \
|
||||
-v "$FIXTURES:/fixtures:ro" \
|
||||
--entrypoint sing-box \
|
||||
"$IMAGE" check -c "/fixtures/${name}.json" 2>&1)"; then
|
||||
printf '%s\n' "$output" >&2
|
||||
return 1
|
||||
fi
|
||||
unexpected="$(printf '%s\n' "$output" \
|
||||
| grep -Ei 'warn|deprecated' \
|
||||
| grep -Evi 'independent_cache.*DNS option is deprecated' || true)"
|
||||
if [[ -n "$unexpected" ]]; then
|
||||
printf 'unexpected warning for %s:\n%s\n' "$name" "$unexpected" >&2
|
||||
return 1
|
||||
fi
|
||||
printf 'PASS config %s\n' "$name"
|
||||
}
|
||||
|
||||
docker build \
|
||||
--build-arg "SINGBOX_VERSION=${RC_VERSION}" \
|
||||
-t "$IMAGE" \
|
||||
-f "$ROOT/Dockerfile.client" \
|
||||
"$ROOT"
|
||||
|
||||
version_output="$(docker run --rm --entrypoint sing-box "$IMAGE" version)"
|
||||
printf '%s\n' "$version_output"
|
||||
grep -Fxq "sing-box version ${RC_VERSION}" <<< "$version_output"
|
||||
|
||||
cat > "$FIXTURES/generate-configs.mjs" <<'EOF'
|
||||
import fs from 'node:fs';
|
||||
import { parseSubscriptionBody } from '/app/dist/server/subscription.js';
|
||||
import { buildGatewayConfig } from '/app/dist/server/singbox.js';
|
||||
|
||||
const reality = 'vless://00000000-0000-4000-8000-000000000001@reality.example.test:443?security=reality&type=tcp&pbk=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&sid=0123456789abcdef&sni=cover.example.test&fp=chrome#Reality';
|
||||
const websocket = 'vless://00000000-0000-4000-8000-000000000002@ws.example.test:8443?encryption=none&security=tls&sni=edge.example.test&fp=firefox&alpn=h2%2Chttp%2F1.1&type=ws&host=edge.example.test&path=%2Fsocket%3Fed%3D2048#TLS%20WS';
|
||||
|
||||
function generated(link, clientDirect = false) {
|
||||
const parsed = parseSubscriptionBody(Buffer.from(link).toString('base64'));
|
||||
return buildGatewayConfig(parsed.config, parsed.servers[0].id, { clientDirect });
|
||||
}
|
||||
|
||||
for (const [name, config] of [
|
||||
['local-vpn', generated(websocket)],
|
||||
['gateway-direct', generated(websocket, true)],
|
||||
['vless-reality', generated(reality)],
|
||||
['vless-tls-websocket', generated(websocket)],
|
||||
]) {
|
||||
fs.writeFileSync(`/fixtures/${name}.json`, JSON.stringify(config));
|
||||
}
|
||||
EOF
|
||||
|
||||
docker run --rm \
|
||||
-e APP_MODE=client \
|
||||
-e PROXY_PORT=18081 \
|
||||
-e DIAGNOSTICS_PROXY_PORT=18082 \
|
||||
-e DATA_DIR=/tmp/harbor-rc \
|
||||
-e SING_BOX_CACHE=/tmp/harbor-rc-cache.db \
|
||||
-v "$FIXTURES:/fixtures" \
|
||||
--entrypoint node \
|
||||
"$IMAGE" /fixtures/generate-configs.mjs
|
||||
|
||||
check_config local-vpn
|
||||
check_config gateway-direct
|
||||
check_config vless-reality
|
||||
check_config vless-tls-websocket
|
||||
|
||||
docker network create "$NETWORK" >/dev/null
|
||||
NETWORK_CREATED=true
|
||||
docker create --name "$TARGET" --network "$NETWORK" --entrypoint node "$IMAGE" \
|
||||
-e 'require("node:http").createServer((request,response)=>response.end(request.url)).listen(18080,"0.0.0.0")' >/dev/null
|
||||
TARGET_CREATED=true
|
||||
docker start "$TARGET" >/dev/null
|
||||
docker create --name "$PROXY" --network "$NETWORK" \
|
||||
-v "$FIXTURES:/fixtures:ro" --entrypoint sing-box "$IMAGE" run -c /fixtures/gateway-direct.json >/dev/null
|
||||
PROXY_CREATED=true
|
||||
docker start "$PROXY" >/dev/null
|
||||
|
||||
for _ in {1..30}; do
|
||||
if docker run --rm --network "$NETWORK" --entrypoint curl "$IMAGE" \
|
||||
--noproxy '' -fsS -x "http://${PROXY}:18081" "http://${TARGET}:18080/http" | grep -Fxq '/http'; then
|
||||
break
|
||||
fi
|
||||
sleep 0.2
|
||||
done
|
||||
|
||||
http_body="$(docker run --rm --network "$NETWORK" --entrypoint curl "$IMAGE" \
|
||||
--noproxy '' -fsS -x "http://${PROXY}:18081" "http://${TARGET}:18080/http")"
|
||||
socks_body="$(docker run --rm --network "$NETWORK" --entrypoint curl "$IMAGE" \
|
||||
--noproxy '' -fsS --socks5-hostname "${PROXY}:18081" "http://${TARGET}:18080/socks")"
|
||||
|
||||
[[ "$http_body" == '/http' ]]
|
||||
[[ "$socks_body" == '/socks' ]]
|
||||
printf 'PASS mixed inbound HTTP\nPASS mixed inbound SOCKS5\n'
|
||||
Reference in New Issue
Block a user