Files
NexusGate/scripts/hy2-smoke.sh
T

72 lines
3.7 KiB
Bash

#!/usr/bin/env bash
set -Eeuo pipefail
xray="${NG_XRAY_BIN:-/usr/local/bin/xray}"
singbox="${NG_SINGBOX_BIN:-/usr/local/bin/nexusgate-sing-box}"
command -v "$xray" >/dev/null || { printf 'Xray binary missing\n' >&2; exit 1; }
command -v "$singbox" >/dev/null || { printf 'sing-box binary missing\n' >&2; exit 1; }
tmp="$(mktemp -d /tmp/nexusgate-hy2-smoke.XXXXXX)"
server_pid='' client_pid='' http_pid=''
cleanup() {
for pid in "$client_pid" "$server_pid" "$http_pid"; do
[[ -n "$pid" ]] && kill "$pid" 2>/dev/null || true
done
rm -rf -- "$tmp"
}
trap cleanup EXIT
openssl req -x509 -newkey rsa:2048 -nodes -days 1 -keyout "$tmp/key.pem" -out "$tmp/cert.pem" \
-subj '/CN=node.test' -addext 'subjectAltName=DNS:node.test' >/dev/null 2>&1
NG_SMOKE_DIR="$tmp" node <<'NODE'
const fs = require('node:fs');
const path = require('node:path');
const root = process.env.NG_SMOKE_DIR;
const { newCredentialSet, buildDirectResource } = require('./lib/protocols');
const { combinedConfig } = require('./agent/agent');
const credentials = newCredentialSet('hysteria2');
const resource = buildDirectResource({ resourceId:'res_hy2_smoke', tagPrefix:'smoke', port:23460,
protocol:'hysteria2', credentials, customer:{ id:'smoke-customer' }, tlsDomain:'node.test' });
resource.inbounds[0].listen = '127.0.0.1';
const certificate = resource.inbounds[0].streamSettings.tlsSettings.certificates[0];
certificate.certificateFile = path.join(root, 'cert.pem');
certificate.keyFile = path.join(root, 'key.pem');
const server = combinedConfig([resource]);
server.inbounds[0].port = 23461;
server.log.access = path.join(root, 'access.log');
server.log.error = path.join(root, 'error.log');
fs.writeFileSync(path.join(root, 'server.json'), JSON.stringify(server));
const client = { log:{ level:'warn' },
inbounds:[{ type:'mixed', listen:'127.0.0.1', listen_port:23462, tag:'local' }],
outbounds:[{ type:'hysteria2', tag:'server', server:'127.0.0.1', server_port:23460,
password:credentials.relayPassword, tls:{ enabled:true, server_name:'node.test', insecure:true, alpn:['h3'] } }],
route:{ final:'server' } };
fs.writeFileSync(path.join(root, 'client.json'), JSON.stringify(client));
NODE
"$xray" run -test -config "$tmp/server.json"
"$singbox" check -c "$tmp/client.json"
node -e 'require("http").createServer((_,res)=>res.end("NexusGate HY2 smoke OK")).listen(23463,"127.0.0.1")' & http_pid=$!
"$xray" run -config "$tmp/server.json" > "$tmp/server.out" 2>&1 & server_pid=$!
"$singbox" run -c "$tmp/client.json" > "$tmp/client.out" 2>&1 & client_pid=$!
for _ in {1..40}; do
if curl -fsS --max-time 2 --noproxy '' --socks5-hostname 127.0.0.1:23462 http://127.0.0.1:23463/ > "$tmp/response" 2>/dev/null; then break; fi
sleep 0.25
done
if [[ "$(cat "$tmp/response" 2>/dev/null || true)" != 'NexusGate HY2 smoke OK' ]]; then
cat "$tmp/server.out" "$tmp/client.out" "$tmp/error.log" >&2
exit 1
fi
NG_SMOKE_PID="$server_pid" node <<'NODE'
const { udpPortsForPid } = require('./agent/agent');
if (!udpPortsForPid(Number(process.env.NG_SMOKE_PID)).has(23460)) throw new Error('Xray has no UDP listener on the HY2 port');
NODE
"$xray" api statsquery --server=127.0.0.1:23461 -pattern 'inbound>>>' > "$tmp/stats.json"
NG_SMOKE_STATS="$tmp/stats.json" node <<'NODE'
const stats = JSON.parse(require('node:fs').readFileSync(process.env.NG_SMOKE_STATS));
const counters = new Map((stats.stat || []).map((item) => [item.name, Number(item.value)]));
for (const direction of ['uplink','downlink']) {
const value = counters.get(`inbound>>>smoke-in>>>traffic>>>${direction}`);
if (!(value > 0)) throw new Error(`missing HY2 ${direction} counter`);
}
console.log('HY2 UDP listener, sing-box handshake, round trip, and dual direction stats OK');
NODE