Files
ai-xray/test_xray_connection.sh
2026-03-08 07:09:56 +00:00

264 lines
8.4 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# test_xray_connection.sh — Test xray juris-xhttp outbound
# Tests: connectivity, latency (SLA), throughput
#
set -euo pipefail
XRAY_BIN="/usr/local/x-ui/bin/xray-linux-amd64"
TEST_CONFIG="/tmp/test-juris-sla.json"
SOCKS_PORT=11080
REMOTE_IP="83.99.190.32"
XRAY_PID=""
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
cleanup() {
if [[ -n "$XRAY_PID" ]] && kill -0 "$XRAY_PID" 2>/dev/null; then
kill "$XRAY_PID" 2>/dev/null
wait "$XRAY_PID" 2>/dev/null || true
fi
rm -f "$TEST_CONFIG"
}
trap cleanup EXIT
header() {
echo ""
echo -e "${BOLD}${CYAN}=== $1 ===${NC}"
}
pass() { echo -e " ${GREEN}PASS${NC} $1"; }
fail() { echo -e " ${RED}FAIL${NC} $1"; }
info() { echo -e " ${YELLOW}INFO${NC} $1"; }
# ── Write temporary xray config ──────────────────────────────────────────────
cat > "$TEST_CONFIG" << 'EOF'
{
"log": { "loglevel": "error" },
"inbounds": [{
"listen": "127.0.0.1",
"port": 11080,
"protocol": "socks",
"settings": { "auth": "noauth", "udp": true },
"tag": "test-socks"
}],
"outbounds": [{
"tag": "juris-xhttp",
"protocol": "vless",
"settings": {
"vnext": [{
"address": "share.alogins.net",
"port": 443,
"users": [{
"id": "6e422ab5-070a-43f6-8241-38cd56d23d24",
"flow": "",
"encryption": "none"
}]
}]
},
"streamSettings": {
"network": "xhttp",
"security": "reality",
"realitySettings": {
"fingerprint": "chrome",
"serverName": "www.delfi.lv",
"publicKey": "58Iqd6LuWXgvjAgo92-7KURhTp0Vj79yGF81l_iuvTw",
"shortId": "6036d37d12c443c4",
"spiderX": "/"
},
"xhttpSettings": {
"path": "/xt-6036d37d",
"host": "",
"mode": "auto",
"extra": {
"xPaddingBytes": "100-1000",
"xmux": {
"maxConcurrency": "16-32",
"maxConnections": 0,
"cMaxReuseTimes": "64-128",
"cMaxLifetimeMs": 0,
"hMaxRequestTimes": "600-900",
"hMaxReusableSecs": "1800-3000"
}
}
}
}
}]
}
EOF
# ── Start xray ───────────────────────────────────────────────────────────────
header "Starting test xray instance (SOCKS on 127.0.0.1:$SOCKS_PORT)"
$XRAY_BIN -test -config "$TEST_CONFIG" > /dev/null 2>&1
pass "Config validation OK"
$XRAY_BIN -config "$TEST_CONFIG" > /dev/null 2>&1 &
XRAY_PID=$!
sleep 2
if kill -0 "$XRAY_PID" 2>/dev/null; then
pass "Xray started (PID $XRAY_PID)"
else
fail "Xray failed to start"
exit 1
fi
# ── 1. Connectivity test ─────────────────────────────────────────────────────
header "1. Connectivity"
PROXY="socks5h://127.0.0.1:$SOCKS_PORT"
ERRORS=0
# Test: exit IP
EXIT_IP=$(curl -s --connect-timeout 10 --max-time 15 -x "$PROXY" https://ifconfig.me 2>/dev/null || echo "FAIL")
if [[ "$EXIT_IP" == "$REMOTE_IP" ]]; then
pass "Exit IP: $EXIT_IP (matches remote server)"
else
fail "Exit IP: '$EXIT_IP' (expected $REMOTE_IP)"
ERRORS=$((ERRORS + 1))
fi
# Test: HTTPS connectivity
HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 --max-time 15 -x "$PROXY" https://www.google.com 2>/dev/null || echo "000")
if [[ "$HTTP_CODE" == "200" ]]; then
pass "HTTPS to google.com: HTTP $HTTP_CODE"
else
fail "HTTPS to google.com: HTTP $HTTP_CODE"
ERRORS=$((ERRORS + 1))
fi
# Test: DNS resolution through tunnel
DNS_IP=$(curl -s --connect-timeout 10 --max-time 15 -x "$PROXY" https://dns.google/resolve?name=example.com\&type=A 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin)['Answer'][0]['data'])" 2>/dev/null || echo "FAIL")
if [[ "$DNS_IP" != "FAIL" ]]; then
pass "DNS resolution through tunnel: example.com → $DNS_IP"
else
fail "DNS resolution through tunnel"
ERRORS=$((ERRORS + 1))
fi
# ── 2. Latency (SLA) ─────────────────────────────────────────────────────────
header "2. Latency (SLA)"
LATENCIES=()
LATENCY_ERRORS=0
SAMPLES=10
info "Running $SAMPLES requests to measure round-trip time..."
for i in $(seq 1 $SAMPLES); do
T=$(curl -s -o /dev/null -w '%{time_total}' --connect-timeout 10 --max-time 15 -x "$PROXY" https://www.gstatic.com/generate_204 2>/dev/null || echo "0")
MS=$(echo "$T * 1000" | bc 2>/dev/null | cut -d. -f1)
if [[ -n "$MS" && "$MS" -gt 0 ]]; then
LATENCIES+=("$MS")
printf " [%2d/%d] %s ms\n" "$i" "$SAMPLES" "$MS"
else
LATENCY_ERRORS=$((LATENCY_ERRORS + 1))
printf " [%2d/%d] ${RED}timeout${NC}\n" "$i" "$SAMPLES"
fi
done
if [[ ${#LATENCIES[@]} -gt 0 ]]; then
# Calculate min/avg/max/p95
SORTED=($(printf '%s\n' "${LATENCIES[@]}" | sort -n))
COUNT=${#SORTED[@]}
MIN=${SORTED[0]}
MAX=${SORTED[$((COUNT - 1))]}
SUM=0
for v in "${SORTED[@]}"; do SUM=$((SUM + v)); done
AVG=$((SUM / COUNT))
P95_IDX=$(echo "($COUNT * 95 + 99) / 100 - 1" | bc)
[[ $P95_IDX -ge $COUNT ]] && P95_IDX=$((COUNT - 1))
P95=${SORTED[$P95_IDX]}
echo ""
info "Latency summary ($COUNT/$SAMPLES successful):"
echo -e " ${BOLD} Min: ${MIN} ms${NC}"
echo -e " ${BOLD} Avg: ${AVG} ms${NC}"
echo -e " ${BOLD} P95: ${P95} ms${NC}"
echo -e " ${BOLD} Max: ${MAX} ms${NC}"
if [[ $AVG -lt 300 ]]; then
pass "Average latency ${AVG}ms < 300ms threshold"
elif [[ $AVG -lt 500 ]]; then
info "Average latency ${AVG}ms — acceptable but elevated"
else
fail "Average latency ${AVG}ms exceeds 500ms"
ERRORS=$((ERRORS + 1))
fi
else
fail "All latency samples failed"
ERRORS=$((ERRORS + 1))
fi
# ── 3. Throughput ─────────────────────────────────────────────────────────────
header "3. Throughput"
info "Downloading 10MB test file through tunnel..."
DL_RESULT=$(curl -s -o /dev/null -w '%{size_download} %{time_total} %{speed_download}' \
--connect-timeout 15 --max-time 60 \
-x "$PROXY" \
"http://speedtest.tele2.net/10MB.zip" 2>/dev/null || echo "0 0 0")
DL_BYTES=$(echo "$DL_RESULT" | awk '{print $1}')
DL_TIME=$(echo "$DL_RESULT" | awk '{print $2}')
DL_SPEED=$(echo "$DL_RESULT" | awk '{print $3}')
if [[ "$DL_BYTES" -gt 0 ]] 2>/dev/null; then
DL_MB=$(echo "scale=2; $DL_BYTES / 1048576" | bc)
DL_MBPS=$(echo "scale=2; $DL_SPEED * 8 / 1048576" | bc)
DL_TIME_S=$(echo "scale=2; $DL_TIME" | bc)
pass "Downloaded ${DL_MB} MB in ${DL_TIME_S}s"
echo -e " ${BOLD} Download speed: ${DL_MBPS} Mbps${NC}"
else
fail "Download test failed"
ERRORS=$((ERRORS + 1))
fi
info "Uploading 5MB test payload through tunnel..."
# Generate 5MB of random data and POST it
UL_RESULT=$(dd if=/dev/urandom bs=1M count=5 2>/dev/null | \
curl -s -o /dev/null -w '%{size_upload} %{time_total} %{speed_upload}' \
--connect-timeout 15 --max-time 60 \
-x "$PROXY" \
-X POST -H "Content-Type: application/octet-stream" \
--data-binary @- \
"http://speedtest.tele2.net/upload.php" 2>/dev/null || echo "0 0 0")
UL_BYTES=$(echo "$UL_RESULT" | awk '{print $1}')
UL_TIME=$(echo "$UL_RESULT" | awk '{print $2}')
UL_SPEED=$(echo "$UL_RESULT" | awk '{print $3}')
if [[ "$UL_BYTES" -gt 0 ]] 2>/dev/null; then
UL_MB=$(echo "scale=2; $UL_BYTES / 1048576" | bc)
UL_MBPS=$(echo "scale=2; $UL_SPEED * 8 / 1048576" | bc)
UL_TIME_S=$(echo "scale=2; $UL_TIME" | bc)
pass "Uploaded ${UL_MB} MB in ${UL_TIME_S}s"
echo -e " ${BOLD} Upload speed: ${UL_MBPS} Mbps${NC}"
else
fail "Upload test failed"
ERRORS=$((ERRORS + 1))
fi
# ── Summary ───────────────────────────────────────────────────────────────────
header "Summary"
if [[ $ERRORS -eq 0 ]]; then
echo -e " ${GREEN}${BOLD}ALL TESTS PASSED${NC}"
else
echo -e " ${RED}${BOLD}$ERRORS TEST(S) FAILED${NC}"
fi
echo ""
exit $ERRORS