fix(ipsec): показывать неопределённый статус при общих Remote ID

This commit is contained in:
Denozordec committed 2026-10-10 10:33:54 +07:00
1 parent 7815e00a1c
commit cb6ec09312
20 files changed
+1077 -15

No files matched your search

+21
View File
@@ -286,6 +286,13 @@ export function mapClients(state: IpsecServerState): IpsecClientDto[] {
}
const out: IpsecClientDto[] = []
const sessionClaims = new Map<RosIpsecActivePeer, IpsecClientDto[]>()
const claimSession = (active: RosIpsecActivePeer | undefined) => {
if (!active) return
const claims = sessionClaims.get(active) ?? []
claims.push(out[out.length - 1]!)
sessionClaims.set(active, claims)
}
// 1. Клиентские сертификаты (роль client), подписанные нашим CA / выданные менеджером / referenced identity.
for (const cert of state.certs) {
@@ -332,6 +339,7 @@ export function mapClients(state: IpsecServerState): IpsecClientDto[] {
comment: comment || undefined,
managed: isUser || isIpsecManagedComment(comment),
})
claimSession(active)
}
// 2. PSK-identity (managed или IKEv2 remote-access).
@@ -363,8 +371,20 @@ export function mapClients(state: IpsecServerState): IpsecClientDto[] {
comment: i.comment || undefined,
managed,
})
claimSession(active)
}
// The native snapshot does not identify the configured identity/auth type.
// Never assign one observed session/address to multiple catalog clients.
for (const claims of sessionClaims.values()) {
if (claims.length < 2) continue
for (const client of claims) {
client.online = false
client.sessionAmbiguous = true
client.activeAddress = undefined
client.activeSince = undefined
}
}
return out.sort((a, b) => a.name.localeCompare(b.name))
}
@@ -443,6 +463,7 @@ export function mapServerSummary(state: IpsecServerState, clients: IpsecClientDt
natRuleManaged,
clientsTotal: clients.length,
clientsOnline: clients.filter((c) => c.online).length,
...(clients.some(c => c.sessionAmbiguous) ? { clientsSessionAmbiguous: clients.filter(c => c.sessionAmbiguous).length } : {}),
certs: relevantCerts.map((c) => mapCertificate(c, roleCtx)),
}
}
+17
View File
@@ -152,4 +152,21 @@ namespaceState.active[0]!.id = "explicit.example"
assert.equal(mapClients(namespaceState).find(c => c.certName === "ipsec-user-plain")?.online, true); checks++
namespaceState.identities[0]!["remote-id"] = "unknown:explicit.example"
assert.equal(mapClients(namespaceState).find(c => c.certName === "ipsec-user-plain")?.online, false); checks++
const aliasesState = { ...sessionState, active: [{ ".id": "*ALIASED", id: "shared.example", state: "established", "dynamic-address": "198.18.112.250", uptime: "1m" }] } as typeof state
for (const secondId of ["fqdn:shared.example", "key-id:shared.example"]) {
aliasesState.identities = ["fqdn:shared.example", secondId].map((remoteId, n) => ({ ".id": "*PSK" + n, peer: "ike", "auth-method": "pre-shared-key", "remote-id": remoteId, comment: ipsecManagedComment("user=PSK" + n) }))
const clients = mapClients(aliasesState)
assert.equal(clients.length, 2)
assert(clients.every(c => c.sessionAmbiguous && !c.online && !c.activeAddress && !c.activeSince)); checks++
const summary = mapServerSummary(aliasesState, clients)
assert.equal(summary.clientsOnline, 0); assert.equal(summary.clientsSessionAmbiguous, 2); checks++
}
aliasesState.certs = [{ ".id": "*CERTALIAS", name: "ipsec-user-aliased", "common-name": "certificate", ca: "ca", "key-usage": "tls-client" }]
aliasesState.identities[0] = { ".id": "*CERTIDENTITY", peer: "ike", "auth-method": "digital-signature", "remote-certificate": "ipsec-user-aliased", "remote-id": "fqdn:shared.example" }
assert(mapClients(aliasesState).every(c => c.sessionAmbiguous && !c.online && !c.activeAddress)); checks++
aliasesState.identities[1]!["remote-id"] = "key-id:unrelated"
const uniqueClients = mapClients(aliasesState)
assert.equal(uniqueClients.find(c => c.kind === "cert")?.online, true)
assert.equal(uniqueClients.find(c => c.kind === "psk")?.online, false)
assert(uniqueClients.every(c => !c.sessionAmbiguous)); checks++
console.log(`ipsec-state: ${checks} checks passed`)