Enable connectivity diagnostics in Connect mode
This commit is contained in:
+1
-2
@@ -135,7 +135,7 @@ const deviceInventory = settings.appMode === 'gateway'
|
||||
vendor: createVendorLookup(),
|
||||
})
|
||||
: null;
|
||||
const localConnectivityDiagnostics = settings.appMode === 'gateway' && !remoteDataplane
|
||||
const localConnectivityDiagnostics = !remoteDataplane
|
||||
? createConnectivityDiagnosticsService({ proxyPort: settings.diagnosticsProxyPort })
|
||||
: null;
|
||||
let subscriptionRefreshPromise = null;
|
||||
@@ -699,7 +699,6 @@ async function handleApi(req, res) {
|
||||
}
|
||||
|
||||
if (req.method === 'POST' && req.url === '/api/diagnostics/connectivity') {
|
||||
if (settings.appMode !== 'gateway') throw new HarborError('ENDPOINT_NOT_FOUND');
|
||||
const { services = [] } = await readBody(req);
|
||||
const state = stateStore.read();
|
||||
const appliedServerId = state.appliedServerId || state.selectedServerId;
|
||||
|
||||
+12
-10
@@ -25,12 +25,10 @@ export function buildGatewayConfig(subscriptionConfig, selectedTag, {
|
||||
} = {}) {
|
||||
const clientMode = settings.appMode === 'client';
|
||||
const directClient = clientMode && clientDirect;
|
||||
const vpnOutbound = directClient
|
||||
? null
|
||||
: structuredClone(findOutbound(subscriptionConfig, selectedTag));
|
||||
if (!directClient && !vpnOutbound) throw new HarborError('SERVER_NOT_FOUND');
|
||||
if (vpnOutbound && !vpnOutbound.tag) vpnOutbound.tag = 'vpn-out';
|
||||
if (vpnOutbound?.type === 'vless' && !vpnOutbound.packet_encoding) {
|
||||
const vpnOutbound = structuredClone(findOutbound(subscriptionConfig, selectedTag));
|
||||
if (!vpnOutbound) throw new HarborError('SERVER_NOT_FOUND');
|
||||
if (!vpnOutbound.tag) vpnOutbound.tag = 'vpn-out';
|
||||
if (vpnOutbound.type === 'vless' && !vpnOutbound.packet_encoding) {
|
||||
vpnOutbound.packet_encoding = 'xudp';
|
||||
}
|
||||
const outboundTag = directClient ? 'direct' : vpnOutbound.tag;
|
||||
@@ -52,20 +50,24 @@ export function buildGatewayConfig(subscriptionConfig, selectedTag, {
|
||||
sniff: true,
|
||||
set_system_proxy: false,
|
||||
},
|
||||
...(!clientMode ? [{
|
||||
{
|
||||
type: 'mixed',
|
||||
tag: DIAGNOSTICS_INBOUND,
|
||||
listen: '127.0.0.1',
|
||||
listen_port: settings.diagnosticsProxyPort,
|
||||
sniff: true,
|
||||
set_system_proxy: false,
|
||||
}] : []),
|
||||
},
|
||||
];
|
||||
const directRules = normalizeRouteRules(routeRules)
|
||||
.filter((rule) => rule.enabled)
|
||||
.map((rule) => ({ [rule.type]: [rule.value], outbound: 'direct' }));
|
||||
const rules = clientMode
|
||||
? [...directRules, { inbound: [MIXED_INBOUND], outbound: outboundTag }]
|
||||
? [
|
||||
{ inbound: [DIAGNOSTICS_INBOUND], outbound: vpnOutbound.tag },
|
||||
...directRules,
|
||||
{ inbound: [MIXED_INBOUND], outbound: outboundTag },
|
||||
]
|
||||
: [
|
||||
{ inbound: [DIAGNOSTICS_INBOUND], outbound: outboundTag },
|
||||
...directRules,
|
||||
@@ -81,7 +83,7 @@ export function buildGatewayConfig(subscriptionConfig, selectedTag, {
|
||||
dns: { independent_cache: true },
|
||||
inbounds,
|
||||
outbounds: [
|
||||
...(vpnOutbound ? [vpnOutbound] : []),
|
||||
vpnOutbound,
|
||||
{ type: 'direct', tag: 'direct' },
|
||||
{ type: 'block', tag: 'block' },
|
||||
],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const HARBOR_VERSIONS = Object.freeze({
|
||||
macClient: '0.16.2',
|
||||
gatewayClient: '0.17.2',
|
||||
gatewayBackend: '0.17.1',
|
||||
macClient: '0.17.1',
|
||||
gatewayClient: '0.18.1',
|
||||
gatewayBackend: '0.18.0',
|
||||
});
|
||||
|
||||
export function parseVersion(value) {
|
||||
|
||||
@@ -1168,13 +1168,13 @@ export function ClientOverviewPage({
|
||||
</svg>
|
||||
<span>Устройства</span>
|
||||
</button>}
|
||||
{isGateway && <button
|
||||
<button
|
||||
ref={diagnosticsToggleRef}
|
||||
className={`client-instructions-toggle client-diagnostics-toggle${diagnosticsOpen ? ' is-open' : ''}`}
|
||||
type="button"
|
||||
aria-expanded={diagnosticsOpen}
|
||||
aria-controls="client-diagnostics"
|
||||
aria-label={diagnosticsOpen ? 'Закрыть диагностику' : 'Проверить маршруты Gateway'}
|
||||
aria-label={diagnosticsOpen ? 'Закрыть диагностику' : 'Проверить маршруты'}
|
||||
onClick={() => {
|
||||
if (localRulesOpen && !requestCloseLocalRules()) return;
|
||||
setInstructionsOpen(false);
|
||||
@@ -1186,7 +1186,7 @@ export function ClientOverviewPage({
|
||||
<path d="M3 12h4l2.2-5 4.2 10 2.1-5H21" />
|
||||
</svg>
|
||||
<span>Диагностика</span>
|
||||
</button>}
|
||||
</button>
|
||||
<button
|
||||
ref={localRulesToggleRef}
|
||||
className={`client-local-rules-toggle${localRulesOpen ? ' is-open' : ''}${localRulesPendingRestart ? ' has-pending' : ''}`}
|
||||
@@ -1536,7 +1536,8 @@ export function ClientOverviewPage({
|
||||
onClose={() => setDevicesOpen(false)}
|
||||
/>}
|
||||
|
||||
{hasSubscription && subscriptionContentReady && isGateway && <ConnectivityDiagnosticsPanel
|
||||
{hasSubscription && subscriptionContentReady && <ConnectivityDiagnosticsPanel
|
||||
isGateway={isGateway}
|
||||
open={diagnosticsOpen}
|
||||
panelRef={diagnosticsPanelRef}
|
||||
closeRef={diagnosticsCloseRef}
|
||||
|
||||
@@ -63,7 +63,7 @@ function IpCell({ path, source, pending, route }) {
|
||||
return <code aria-label={`${route}: ${value.address}`}>{value.address}</code>;
|
||||
}
|
||||
|
||||
export function ConnectivityDiagnosticsPanel({ open, panelRef, closeRef, onClose }) {
|
||||
export function ConnectivityDiagnosticsPanel({ isGateway, open, panelRef, closeRef, onClose }) {
|
||||
const [result, setResult] = useState(null);
|
||||
const [status, setStatus] = useState('idle');
|
||||
const [error, setError] = useState(null);
|
||||
@@ -138,7 +138,7 @@ export function ConnectivityDiagnosticsPanel({ open, panelRef, closeRef, onClose
|
||||
onClick={onClose}
|
||||
>×</button>
|
||||
<header className="client-instructions-header client-diagnostics-header">
|
||||
<span>Gateway · Direct ↔ VPN</span>
|
||||
<span>{isGateway ? 'Gateway' : 'Connect'} · Direct ↔ VPN</span>
|
||||
<div className="client-diagnostics-title-row">
|
||||
<h2 id="client-diagnostics-title">Маршруты</h2>
|
||||
<span className="client-diagnostics-refresh-wrap client-tooltip-anchor">
|
||||
|
||||
@@ -589,7 +589,7 @@ export function DevicesPanel({ open, panelRef, closeRef, onClose }) {
|
||||
onClick={() => copyDeviceIp(device)}
|
||||
>{device.ip}</button> : !hasName && <span>Неизвестное устройство</span>}
|
||||
</h3>
|
||||
<span className="client-device-edit-wrap client-tooltip-anchor">
|
||||
{!hasName && <span className="client-device-edit-wrap client-tooltip-anchor">
|
||||
<button
|
||||
className={`client-device-edit${pencilAnimationId === device.id ? ' is-writing' : ''}`}
|
||||
type="button"
|
||||
@@ -607,7 +607,7 @@ export function DevicesPanel({ open, panelRef, closeRef, onClose }) {
|
||||
</svg>
|
||||
</button>
|
||||
<Tooltip>Изменить название</Tooltip>
|
||||
</span>
|
||||
</span>}
|
||||
</>
|
||||
)}
|
||||
<span className={`client-device-last-seen${online ? ' is-online' : ''}`} tabIndex="0">
|
||||
|
||||
+9
-2
@@ -946,7 +946,11 @@ p {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
padding: 11px 27px 0 0;
|
||||
padding: 11px 0 0;
|
||||
}
|
||||
|
||||
.client-device-main:has(.client-device-edit-wrap) {
|
||||
padding-right: 27px;
|
||||
}
|
||||
|
||||
.client-device-main > h3 {
|
||||
@@ -1396,7 +1400,10 @@ p {
|
||||
.client-device-traffic-plot {
|
||||
grid-column: 1 / -1;
|
||||
grid-row: 1;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
@@ -1408,7 +1415,7 @@ p {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
overflow: visible;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.client-device-traffic-grid line {
|
||||
|
||||
Reference in New Issue
Block a user