diff --git a/app/(main)/gre/page.tsx b/app/(main)/gre/page.tsx index 85765a0..06364ce 100644 --- a/app/(main)/gre/page.tsx +++ b/app/(main)/gre/page.tsx @@ -68,6 +68,10 @@ const STATUS_MAP: Record = { down: { label: "Down", dot: "bg-red-500" }, } +function greStatusMeta(status: GreStatus | undefined) { + return STATUS_MAP[status ?? "degraded"] ?? STATUS_MAP.degraded +} + // ─── RouterOS code generator ───────────────────────────────────────────────── function generateRosCommands(t: GreTunnel, serverById: Record): string { @@ -103,10 +107,10 @@ function generateRosCommands(t: GreTunnel, serverById: Record): lines.push(` address=${t.localInnerIp} \\`) lines.push(` interface=${t.name}`) - // IPsec manual equivalent - if (t.ipsec) { - const ikeMode = t.ipsec.ikeVersion === "ikev2" ? "ike2" : "ike1" - const pfsGroup = t.ipsec.pfs ? t.ipsec.dhGroup : "none" + // IPsec: live CHR имеет только ipsec-secret; proposal — у моков/формы + if (t.ipsec?.encAlg && t.ipsec.authAlg) { + const ikeMode = t.ipsec.ikeVersion === "ikev1" ? "ike1" : "ike2" + const pfsGroup = t.ipsec.pfs ? (t.ipsec.dhGroup ?? "none") : "none" lines.push("") lines.push("# ── IPsec (авто через ipsec-secret; ручной эквивалент) ───────") @@ -123,13 +127,16 @@ function generateRosCommands(t: GreTunnel, serverById: Record): lines.push(` enc-algorithms=${ENC_ROS[t.ipsec.encAlg]} \\`) lines.push(` auth-algorithms=${AUTH_ROS[t.ipsec.authAlg]} \\`) lines.push(` pfs-group=${pfsGroup} \\`) - lines.push(` lifetime=${t.ipsec.lifetime}`) + lines.push(` lifetime=${t.ipsec.lifetime ?? "1d"}`) lines.push("") lines.push(`/ip ipsec policy add \\`) lines.push(` src-address=${t.localAddress !== "0.0.0.0" ? t.localAddress + "/32" : "0.0.0.0/0"} \\`) lines.push(` dst-address=${t.remoteAddress}/32 \\`) lines.push(` proposal=${t.name} \\`) lines.push(` tunnel=yes`) + } else if (t.ipsec) { + lines.push("") + lines.push("# IPsec: peer/policy создаёт RouterOS по ipsec-secret") } return lines.join("\n") @@ -138,7 +145,7 @@ function generateRosCommands(t: GreTunnel, serverById: Record): // ─── small ui helpers ──────────────────────────────────────────────────────── function TunnelStatus({ status }: { status: GreStatus }) { - const s = STATUS_MAP[status] + const s = greStatusMeta(status) return ( @@ -737,7 +744,7 @@ export default function GrePage() {
{poolTunnels.map((t, tunnelIndex) => (
- + {t.name} {t.localInnerIp} ↔ {t.remoteInnerIp} {t.ipsec && } @@ -798,8 +805,8 @@ export default function GrePage() { codePreviewTunnel ? (
- - {STATUS_MAP[codePreviewTunnel.status].label} + + {greStatusMeta(codePreviewTunnel.status).label} · {serverById[codePreviewTunnel.serverId]?.name} @@ -814,7 +821,7 @@ export default function GrePage() { · - IPsec {IKE_LABELS[codePreviewTunnel.ipsec.ikeVersion]} + IPsec {codePreviewTunnel.ipsec.ikeVersion ? IKE_LABELS[codePreviewTunnel.ipsec.ikeVersion] : "PSK"} ) : null} diff --git a/components/data-grids/gre-tunnels-data-grid.tsx b/components/data-grids/gre-tunnels-data-grid.tsx index 08722e8..6095a9f 100644 --- a/components/data-grids/gre-tunnels-data-grid.tsx +++ b/components/data-grids/gre-tunnels-data-grid.tsx @@ -75,7 +75,7 @@ const STATUS_MAP: Record = { } function TunnelStatus({ status }: { status: GreStatus }) { - const s = STATUS_MAP[status] + const s = STATUS_MAP[status] ?? STATUS_MAP.degraded return ( @@ -208,14 +208,21 @@ function GreTunnelsDataGrid({ cell: ({ row }) => { const t = row.original if (!t.ipsec) return + const enc = t.ipsec.encAlg ? ENC_LABELS[t.ipsec.encAlg] : undefined + const auth = t.ipsec.authAlg ? AUTH_LABELS[t.ipsec.authAlg] : undefined + const dh = t.ipsec.dhGroup ? DH_LABELS[t.ipsec.dhGroup] : undefined + const ike = t.ipsec.ikeVersion ? IKE_LABELS[t.ipsec.ikeVersion] : undefined + if (!enc && !auth && !dh && !ike) { + return PSK · auto + } return (
- {ENC_LABELS[t.ipsec.encAlg]} / {AUTH_LABELS[t.ipsec.authAlg]} + {[enc, auth].filter(Boolean).join(" / ") || "PSK"} - {DH_LABELS[t.ipsec.dhGroup].split(" ")[0]} · {IKE_LABELS[t.ipsec.ikeVersion]} - {t.ipsec.pfs && " · PFS"} + {[dh?.split(" ")[0], ike].filter(Boolean).join(" · ")} + {t.ipsec.pfs ? " · PFS" : ""}
) diff --git a/lib/data.ts b/lib/data.ts index bd66021..e002fb8 100644 --- a/lib/data.ts +++ b/lib/data.ts @@ -531,12 +531,13 @@ export type DscpMode = "inherit" | number export interface GreIpsec { secret: string // ipsec-secret → auto-creates peer+policy+proposal - encAlg: IpsecEncAlg // proposal enc-algorithms - authAlg: IpsecAuthAlg // proposal auth-algorithms - dhGroup: IpsecDhGroup // proposal pfs-group / peer dh-group - ikeVersion: IkeVersion // peer exchange-mode - lifetime: string // proposal lifetime (e.g. "1d 00:00:00") - pfs: boolean // perfect forward secrecy + /** Live CHR отдаёт только secret; proposal-поля есть у моков / формы */ + encAlg?: IpsecEncAlg + authAlg?: IpsecAuthAlg + dhGroup?: IpsecDhGroup + ikeVersion?: IkeVersion + lifetime?: string + pfs?: boolean } export interface GreTunnel {