import type { GreTunnel, Server } from "./data" import { quoteRosString } from "./vxlan-export" const commentLine = (value: string) => value.replace(/[\r\n\x00-\x1f\x7f]/g, " ") const validKeepalive = (t: GreTunnel) => [t.keepaliveInterval, t.keepaliveRetries].every(value => Number.isInteger(value) && value >= 1 && value <= 4294967295) export function greExportWarnings(t: GreTunnel): string[] { return [ t.ipsec && !t.ipsec.secret ? "Шаблон: ключ IPsec скрыт. Укажите ключ перед применением." : "", !validKeepalive(t) ? "Шаблон: задайте допустимый интервал keepalive и число попыток перед применением." : "", t.ipsec && t.allowFastPath ? "Шаблон: IPsec несовместим с FastPath. Проверьте этот параметр перед применением." : "", ].filter(Boolean) } /** GRE/PSK fragment: https://help.mikrotik.com/docs/spaces/ROS/pages/24805531/GRE */ export function generateGreRsc(t: GreTunnel, servers: Record): string { const server = servers[t.serverId] const lines = ["# GRE — " + commentLine(t.name)] if (server) lines.push("# Сервер: " + commentLine(server.name) + " (" + commentLine(server.host) + ")") lines.push("# Фрагмент интерфейса и локального IP; удалённая сторона и маршруты не включены", "") if (!validKeepalive(t)) lines.push("# Шаблон: задайте KEEPALIVE_SECONDS и KEEPALIVE_RETRIES — целые значения от 1 до 4294967295.") if (t.ipsec && t.allowFastPath) lines.push("# Шаблон: IPsec несовместим с FastPath. Проверьте ALLOW_FAST_PATH перед применением.") const args = [ "name=" + quoteRosString(t.name), "remote-address=" + quoteRosString(t.remoteAddress), "mtu=" + t.mtu, "keepalive=" + (validKeepalive(t) ? t.keepaliveInterval + "s," + t.keepaliveRetries : "s,"), "dscp=" + t.dscp, "clamp-tcp-mss=" + (t.clampTcpMss ? "yes" : "no"), "allow-fast-path=" + (t.ipsec && t.allowFastPath ? "" : t.allowFastPath ? "yes" : "no"), "disabled=" + (t.enabled ? "no" : "yes"), "comment=" + quoteRosString(t.comment), ] if (t.localAddress && t.localAddress !== "0.0.0.0") args.push("local-address=" + quoteRosString(t.localAddress)) if (t.ipsec) { if (!t.ipsec.secret) lines.push("# Шаблон: ключ IPsec не раскрыт. Перед применением замените своим ключом.") args.push("ipsec-secret=" + quoteRosString(t.ipsec.secret || "")) } lines.push("/interface/gre/add " + args.join(" ")) if (t.localInnerIp) { const ipv6 = t.localInnerIp.includes(":") if (ipv6) lines.push("# IPv6: новый статический адрес без объявления префикса; pool/EUI-64 и остальные адреса не включены") lines.push((ipv6 ? "/ipv6/address/add" : "/ip/address/add") + " address=" + quoteRosString(t.localInnerIp) + " interface=" + quoteRosString(t.name) + (ipv6 ? " advertise=no" : "")) } if (t.ipsec) lines.push("# Peer/policy создаёт RouterOS по ipsec-secret; ручные объекты IPsec не экспортируются") if (t.ipsec && t.allowFastPath) lines.push("# В снимке включён FastPath: для GRE с IPsec документация RouterOS требует allow-fast-path=no") return lines.join("\n") + "\n" }