All checks were successful
Build and Deploy Gateway / build-and-deploy (push) Successful in 17s
94 lines
3.2 KiB
JavaScript
94 lines
3.2 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { api } from '../api.js';
|
|
|
|
export function RouteChecker() {
|
|
const [host, setHost] = useState('');
|
|
const [port, setPort] = useState('443');
|
|
const [network, setNetwork] = useState('tcp');
|
|
const [sourceIp, setSourceIp] = useState('');
|
|
const [inbound, setInbound] = useState('tproxy-in');
|
|
const [busy, setBusy] = useState(false);
|
|
const [result, setResult] = useState(null);
|
|
const [error, setError] = useState('');
|
|
|
|
async function check() {
|
|
setBusy(true);
|
|
setError('');
|
|
setResult(null);
|
|
try {
|
|
const data = await api.route.check({
|
|
host,
|
|
port: port || undefined,
|
|
network,
|
|
sourceIp: sourceIp || undefined,
|
|
inbound,
|
|
});
|
|
setResult(data);
|
|
} catch (err) {
|
|
setError(err.message);
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
}
|
|
|
|
const r = result?.result;
|
|
const kind = r?.outbound?.startsWith('direct') ? 'success'
|
|
: r?.outbound === 'block' ? 'danger'
|
|
: r?.outbound?.includes('VPN') || r?.outbound?.includes('vpn') ? 'info'
|
|
: 'warning';
|
|
|
|
return (
|
|
<div className="card flat compact">
|
|
<div className="card-header no-margin"><h3>Проверить маршрут</h3></div>
|
|
<div className="filter-bar" style={{ marginTop: 12 }}>
|
|
<input
|
|
className="input"
|
|
placeholder="домен или IP (riotgames.com)"
|
|
value={host}
|
|
onChange={(e) => setHost(e.target.value)}
|
|
onKeyDown={(e) => e.key === 'Enter' && check()}
|
|
style={{ minWidth: 220, flex: 1 }}
|
|
/>
|
|
<input
|
|
className="input"
|
|
placeholder="port"
|
|
value={port}
|
|
onChange={(e) => setPort(e.target.value)}
|
|
style={{ width: 90 }}
|
|
/>
|
|
<select className="select" value={network} onChange={(e) => setNetwork(e.target.value)} style={{ width: 90 }}>
|
|
<option value="tcp">tcp</option>
|
|
<option value="udp">udp</option>
|
|
</select>
|
|
<input
|
|
className="input"
|
|
placeholder="source IP"
|
|
value={sourceIp}
|
|
onChange={(e) => setSourceIp(e.target.value)}
|
|
style={{ width: 145 }}
|
|
/>
|
|
<select className="select" value={inbound} onChange={(e) => setInbound(e.target.value)} style={{ width: 130 }}>
|
|
<option value="tproxy-in">tproxy-in</option>
|
|
<option value="mixed-in">mixed-in</option>
|
|
</select>
|
|
<button className="btn btn-primary" onClick={check} disabled={busy || !host}>Проверить</button>
|
|
</div>
|
|
|
|
{error && <div className="field-error" style={{ marginTop: 10 }}>{error}</div>}
|
|
|
|
{r && (
|
|
<div className="route-result" style={{ marginTop: 12 }}>
|
|
<div className="flex-between">
|
|
<strong>{r.ruleIndex >= 0 ? `Правило #${r.ruleIndex + 1}: ${r.ruleName}` : r.ruleName}</strong>
|
|
<span className={`badge ${kind}`}>→ {r.outbound}</span>
|
|
</div>
|
|
{result.resolvedIp && result.resolvedFrom && (
|
|
<small className="muted text-mono">DNS: {result.resolvedFrom} → {result.resolvedIp}</small>
|
|
)}
|
|
<small className="muted">{r.reason}</small>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|