feat(ipsec): управление IKEv2/IPsec VPN и клиентами из одного окна
Docker images / prepare-release (push) Successful in 15s
Docker images / backend-test (push) Successful in 2m32s
Docker images / frontend-image (push) Successful in 4m19s
Docker images / updater-image (push) Successful in 50s
Docker images / backend-image (push) Successful in 2m40s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 8s
Docker images / prepare-release (push) Successful in 15s
Docker images / backend-test (push) Successful in 2m32s
Docker images / frontend-image (push) Successful in 4m19s
Docker images / updater-image (push) Successful in 50s
Docker images / backend-image (push) Successful in 2m40s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 8s
- мастер инициализации сервера: CA и серверный сертификаты, peer/profile/proposal, пул, mode-config, policy-template, managed NAT masquerade - клиенты по сертификату (RSA) и PSK: статический IP или из пула, онлайн-статус по active-peers - скачивание .p12 и strongSwan .sswan с инструкцией, перекачка с новой passphrase - история изменений (config_revisions, секция ipsec) и restore только managed-объектов - привязка IPsec-клиентов к пользователям приложения по Common Name - страница /ipsec с KPI и вкладками Клиенты/Сервер/CLI, сайдбар, command palette
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/** Клиентские хелперы IPsec (зеркало чистых функций бэкенда). */
|
||||
|
||||
function parseIpv4(s: string): number | null {
|
||||
const parts = s.trim().split(".")
|
||||
if (parts.length !== 4) return null
|
||||
const octets = parts.map((p) => Number(p))
|
||||
if (octets.some((o) => !Number.isInteger(o) || o < 0 || o > 255)) return null
|
||||
return (((octets[0]! << 24) | (octets[1]! << 16) | (octets[2]! << 8) | octets[3]!) >>> 0)
|
||||
}
|
||||
|
||||
function intToIp(n: number): string {
|
||||
return [(n >>> 24) & 255, (n >>> 16) & 255, (n >>> 8) & 255, n & 255].join(".")
|
||||
}
|
||||
|
||||
/** Первый свободный IP диапазона пула («a.b.c.d-a.b.c.e»), исключая занятые. */
|
||||
export function findFreePoolIp(range: string, taken: Iterable<string>): string | null {
|
||||
const takenSet = new Set(
|
||||
Array.from(taken, (t) => t.replace(/\/\d+$/, "").trim()),
|
||||
)
|
||||
const first = range.split(",").map((s) => s.trim()).filter(Boolean)[0] ?? ""
|
||||
const [fromRaw, toRaw] = first.split("-")
|
||||
const from = parseIpv4(fromRaw ?? "")
|
||||
const to = parseIpv4(toRaw ?? fromRaw ?? "")
|
||||
if (from == null) return null
|
||||
const last = to ?? from
|
||||
if (last < from) return null
|
||||
const cap = Math.min(last, from + 65_534)
|
||||
for (let n = from; n <= cap; n++) {
|
||||
const ip = intToIp(n)
|
||||
if (!takenSet.has(ip)) return ip
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -24,6 +24,9 @@ export function formatSidebarBadgeCount(n: number): string {
|
||||
return `${s}к`
|
||||
}
|
||||
|
||||
/** Мок-клиенты IKEv2 для демо-режима (см. MOCK_IPSEC_CLIENTS на странице /ipsec). */
|
||||
export const MOCK_IPSEC_CLIENTS_COUNT = 3
|
||||
|
||||
function mockWireGuardIfacesCount(): number {
|
||||
let n = 0
|
||||
for (const s of servers) n += s.wireGuardIfaces?.length ?? 0
|
||||
@@ -41,6 +44,7 @@ export function mockSidebarBadgesByUrl(): Record<string, string> {
|
||||
"/users": formatSidebarBadgeCount(INIT_USERS.length),
|
||||
"/filters": formatSidebarBadgeCount(filters.length),
|
||||
"/wireguard": formatSidebarBadgeCount(mockWireGuardIfacesCount()),
|
||||
"/ipsec": formatSidebarBadgeCount(MOCK_IPSEC_CLIENTS_COUNT),
|
||||
"/gre": formatSidebarBadgeCount(greTunnels.length),
|
||||
"/vxlan": formatSidebarBadgeCount(vxlanTunnels.length),
|
||||
"/containers": formatSidebarBadgeCount(routerContainers.length),
|
||||
@@ -58,6 +62,7 @@ export interface SidebarCountsDto {
|
||||
recursiveRoutes: number
|
||||
certificates?: number
|
||||
wireguard?: number
|
||||
ipsec?: number
|
||||
users?: number
|
||||
bgpSessions?: number
|
||||
vxlan?: number
|
||||
|
||||
+2
-1
@@ -79,10 +79,11 @@ export const IFACE_TYPE_LABEL: Record<InterfaceType, string> = {
|
||||
ether: "Ethernet",
|
||||
gre: "GRE",
|
||||
wg: "WireGuard",
|
||||
ipsec: "IPsec",
|
||||
other: "Прочие",
|
||||
}
|
||||
|
||||
export const IFACE_TYPE_ORDER: InterfaceType[] = ["ether", "gre", "wg", "other"]
|
||||
export const IFACE_TYPE_ORDER: InterfaceType[] = ["ether", "gre", "wg", "ipsec", "other"]
|
||||
|
||||
export const ROLE_LABEL: Record<Role, string> = {
|
||||
admin: "Администратор",
|
||||
|
||||
Reference in New Issue
Block a user