Init 2
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
const IPV4 = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
|
||||
|
||||
/** Нормализация IP/endpoint из RouterOS (CIDR, zone id) — как в network-map-layout. */
|
||||
export function normalizeGreEndpointAddr(addr: string): string {
|
||||
return addr.trim().split("/")[0].split("%")[0].trim()
|
||||
}
|
||||
|
||||
/** Явный IPv4 (для отличия от FQDN в remote-address GRE). */
|
||||
export function isIpv4String(s: string): boolean {
|
||||
return IPV4.test(s.trim())
|
||||
}
|
||||
|
||||
/**
|
||||
* Сопоставление IP WAN в каталоге с outer GRE: прямой IP или FQDN,
|
||||
* зарезолвенный в API (hostname lower-case → A-запись).
|
||||
*/
|
||||
export function wanUplinkIpMatchesGreOuter(
|
||||
wanIp: string,
|
||||
greOuter: string,
|
||||
resolvedIpv4ByHost?: ReadonlyMap<string, string>,
|
||||
): boolean {
|
||||
const a = normalizeGreEndpointAddr(wanIp)
|
||||
const b = normalizeGreEndpointAddr(greOuter)
|
||||
if (!a || !b) return false
|
||||
if (a === b) return true
|
||||
if (resolvedIpv4ByHost) {
|
||||
const r = resolvedIpv4ByHost.get(b.toLowerCase())
|
||||
if (r && a === normalizeGreEndpointAddr(r)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/** Все варианты внешнего IP для сопоставления с каталогом (IP и зарезолвенный FQDN). */
|
||||
export function greOuterComparableIps(
|
||||
outer: string,
|
||||
resolvedIpv4ByHost?: ReadonlyMap<string, string>,
|
||||
): string[] {
|
||||
const n = normalizeGreEndpointAddr(outer)
|
||||
if (!n || n === "0.0.0.0") return []
|
||||
const out: string[] = []
|
||||
if (isIpv4String(n)) out.push(n)
|
||||
const r = resolvedIpv4ByHost?.get(n.toLowerCase())
|
||||
if (r) {
|
||||
const ip = normalizeGreEndpointAddr(r)
|
||||
if (ip && isIpv4String(ip) && !out.includes(ip)) out.push(ip)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/** Собрать уникальные FQDN из local/remote-address (без чистых IPv4). */
|
||||
export function collectGreEndpointHostnames(
|
||||
tunnels: Array<{ localAddress: string; remoteAddress: string }>,
|
||||
): string[] {
|
||||
const set = new Set<string>()
|
||||
for (const t of tunnels) {
|
||||
for (const a of [t.localAddress, t.remoteAddress]) {
|
||||
const n = normalizeGreEndpointAddr(a)
|
||||
if (!n || n === "0.0.0.0") continue
|
||||
if (!isIpv4String(n)) set.add(n.toLowerCase())
|
||||
}
|
||||
}
|
||||
return [...set]
|
||||
}
|
||||
|
||||
/** Ответ POST /api/network/resolve-hosts → Map для матчинга. */
|
||||
export function greResolvedMapFromApi(
|
||||
results: Record<string, string | null> | undefined,
|
||||
): ReadonlyMap<string, string> {
|
||||
const m = new Map<string, string>()
|
||||
if (!results) return m
|
||||
for (const [k, v] of Object.entries(results)) {
|
||||
if (v && isIpv4String(v)) m.set(k.toLowerCase(), normalizeGreEndpointAddr(v))
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
/** Подпись outer на карте: при FQDN дополнительно показываем разрешённый IPv4. */
|
||||
export function formatGreOuterForDisplay(
|
||||
addr: string,
|
||||
resolvedIpv4ByHost?: ReadonlyMap<string, string>,
|
||||
): string {
|
||||
const n = normalizeGreEndpointAddr(addr) || "?"
|
||||
if (isIpv4String(n)) return n
|
||||
const r = resolvedIpv4ByHost?.get(n.toLowerCase())
|
||||
return r ? `${n} (${r})` : n
|
||||
}
|
||||
Reference in New Issue
Block a user