Files
MikrotikManager/lib/data.ts
T
2026-05-02 01:17:08 +07:00

808 lines
40 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export type ServerStatus = "online" | "offline" | "degraded"
export type ServerType = "jump-host" | "exit-node" | "home-router"
export interface WanUplink {
id: string
name: string // "WAN1-RT"
isp: string // "Rostelecom"
iface: string // "ether1"
ip: string // external IP
maxDl: number // Mbps
maxUl: number // Mbps
}
// ─── WireGuard ───────────────────────────────────────────────────────────────
export interface WireGuardPeer {
publicKey: string
allowedIps: string[]
endpoint?: string // "1.2.3.4:13231"
latestHandshake?: string // "2 минуты назад"
transferRx?: number // bytes
transferTx?: number // bytes
persistent?: boolean
comment?: string
}
export interface WireGuardInterface {
id: string
name: string // e.g. "wg-msk-spb"
listenPort: number // default 13231
mtu: number // 1420 default in ROS 7.x
peers: WireGuardPeer[]
comment: string
enabled: boolean
status: "up" | "down"
}
export interface Server {
id: string
name: string
host: string // management IP / API address
model: string
os: string
site: string
country: string // ISO 3166-1 alpha-2, e.g. "RU", "DE"
asn: string
type: ServerType
enabled: boolean
status: ServerStatus
latency: number | null
sessions: number
comment?: string
// RouterOS 7.x extras
ipv6Address?: string // global or link-local
wireGuardIfaces?: WireGuardInterface[]
vrfNames?: string[] // VRF instances on this router
rpkiEnabled?: boolean
// home-router specific
wanUplinks?: WanUplink[]
lanSubnet?: string // e.g. "192.168.10.0/24"
// snapshot / poll data
uptime?: string
cpuLoad?: number
polledAt?: string
}
export interface FlowspecRule {
id: string
dstPrefix?: string
srcPrefix?: string
ipProto?: string
dstPort?: string
action: "rate-limit" | "discard" | "redirect"
rate?: number // Mbps, for rate-limit
comment?: string
}
export interface Filter {
id: string
name: string
domains: number
ips: number
asns: number
servers: string[]
enabled: boolean
updated: string
communities: string[]
gateway: string
// RouterOS 7.x extras
largeCommunities?: string[] // RFC 8092 format "AS:VALUE1:VALUE2"
rpkiValid?: boolean // filter only RPKI-valid routes
flowspecRules?: FlowspecRule[]
}
export interface Domain {
id: string
domain: string
resolvedIp: string
asn: string
purpose: string
filter: string
updated: string
enabled: boolean
}
export interface IpRange {
id: string
cidr: string
asn: string
country: string
purpose: string
filter: string
updated: string
enabled: boolean
}
export interface Asn {
id: string
asn: string
org: string
country: string
prefixes: number
filter: string
updated: string
enabled: boolean
}
export type FirewallAction =
| "accept" | "drop" | "reject" | "mark-routing" | "mark-conn"
| "masquerade" | "src-nat" | "dst-nat"
| "fasttrack-connection" | "nfqueue" | "passthrough" | "return"
| "add-src-to-address-list" | "add-dst-to-address-list"
export interface FirewallRule {
id: string
chain: string
action: FirewallAction | string
proto: string
src: string
dst: string
port: string
iface: string
comment: string
enabled: boolean
hits: number
// RouterOS 7.x extras
family?: "ip" | "ip6" | "any"
tlsHost?: string // tls-host matcher (SNI)
connRateLimit?: string // connection-rate e.g. "100/s"
layer7Proto?: string // /ip firewall layer7-protocol
nfqueueId?: number
log?: boolean
logPrefix?: string
}
export interface Backup {
id: string
server: string
filename: string
size: string
created: string
kind: "auto" | "manual"
notes: string
}
// ─── VXLAN ───────────────────────────────────────────────────────────────────
export interface VxlanTunnel {
id: string
name: string // "vxlan-overlay-1"
vni: number // 016777215
port: number // source port (default 0 = auto)
dstPort: number // destination port (default 8472)
serverId: string
vtepIp: string // VTEP address on the server
remoteVteps: string[] // remote VTEP IPs (unicast-flood)
l2mtu: number
arpProxy: boolean
macLearning: boolean
comment: string
enabled: boolean
status: "up" | "down"
}
// ─── VRF ─────────────────────────────────────────────────────────────────────
export interface VrfInstance {
id: string
name: string // VRF name
serverId: string
interfaces: string[] // list of interfaces in this VRF
routingTable: string // associated routing table
comment: string
}
// ─── Container (RouterOS 7.4+) ───────────────────────────────────────────────
export interface RouterContainer {
id: string
name: string
serverId: string
image: string // e.g. "nginx:alpine"
tag: string
status: "running" | "stopped" | "error"
envs: { key: string; value: string }[]
mounts: { dst: string; src?: string }[]
interfaces: string[] // veth interface names
cmd?: string
startOnBoot: boolean
comment: string
uptime?: string
cpu?: number // CPU % 0-100
memMb?: number // MB
}
// ─── Certificate ─────────────────────────────────────────────────────────────
export type CertUsage = "server" | "client" | "ca" | "crl-sign"
export type CertStatus = "valid" | "expired" | "revoked"
export interface RouterCertificate {
id: string
name: string
serverId: string
commonName: string
sans: string[]
issuedBy: string
validFrom: string
validUntil: string
daysLeft: number
keySize: number
usage: CertUsage[]
trusted: boolean
status: CertStatus
}
export interface PingProbe {
id: string
srcServerId: string // which server sends the ping
srcInterface?: string // optional interface name on source router
name: string
target: string
filter: string
rtt: number | null
loss: number
status: "up" | "warn" | "down"
series: number[]
enabled: boolean
}
export interface SystemEvent {
id: string
sev: "destructive" | "warning" | "info"
title: string
message: string
when: string
}
function spark(n: number, base: number, range: number): number[] {
let s = base * 1000 + range
return Array.from({ length: n }, () => {
s = (s * 9301 + 49297) % 233280
const r = s / 233280
return Math.max(1, Math.round(base + (r - 0.5) * range * 2))
})
}
export const servers: Server[] = [
{
id: "srv1", name: "mt-msk-core-01", host: "10.0.0.1", model: "CCR2004-1G-12S+2XS", os: "7.20.1",
site: "MSK", country: "RU", asn: "AS65001", type: "jump-host", enabled: true, status: "online", latency: 12, sessions: 4,
ipv6Address: "2a01:4f8:1c1c:a1b2::1",
rpkiEnabled: true,
vrfNames: ["mgmt", "bypass"],
wireGuardIfaces: [
{
id: "wg1", name: "wg-msk-spb", listenPort: 13231, mtu: 1420, comment: "MSK → SPB overlay", enabled: true, status: "up",
peers: [
{ publicKey: "SPBPublicKeyBase64AAAAAAAAAAAAAAAAAAAAAA=", allowedIps: ["10.210.0.2/32","192.168.20.0/24"], endpoint: "10.0.1.1:13231", latestHandshake: "2 мин назад", transferRx: 182_400_000, transferTx: 64_800_000, persistent: true },
],
},
{
id: "wg2", name: "wg-msk-fra", listenPort: 13232, mtu: 1420, comment: "MSK → FRA overlay", enabled: true, status: "up",
peers: [
{ publicKey: "FRAPublicKeyBase64AAAAAAAAAAAAAAAAAAAAAA=", allowedIps: ["10.210.0.6/32"], endpoint: "10.0.2.1:13231", latestHandshake: "1 мин назад", transferRx: 421_000_000, transferTx: 210_000_000, persistent: true },
],
},
],
},
{
id: "srv2", name: "mt-spb-edge-01", host: "10.0.1.1", model: "CCR2116-12G-4S+", os: "7.20.1",
site: "SPB", country: "RU", asn: "AS65002", type: "exit-node", enabled: true, status: "online", latency: 28, sessions: 6,
ipv6Address: "2a01:4f8:1c2c:b2c3::1",
rpkiEnabled: true,
wireGuardIfaces: [
{
id: "wg3", name: "wg-spb-msk", listenPort: 13231, mtu: 1420, comment: "SPB → MSK overlay", enabled: true, status: "up",
peers: [
{ publicKey: "MSKPublicKeyBase64AAAAAAAAAAAAAAAAAAAAAA=", allowedIps: ["10.210.0.1/32"], endpoint: "10.0.0.1:13231", latestHandshake: "2 мин назад", transferRx: 64_800_000, transferTx: 182_400_000, persistent: true },
],
},
],
},
{
id: "srv3", name: "mt-fra-edge-01", host: "10.0.2.1", model: "CCR2004-16G-2S+", os: "7.20.1",
site: "FRA", country: "DE", asn: "AS65003", type: "exit-node", enabled: true, status: "online", latency: 41, sessions: 3,
ipv6Address: "2a01:4f8:1c3c:c3d4::1",
rpkiEnabled: true,
wireGuardIfaces: [
{
id: "wg4", name: "wg-fra-msk", listenPort: 13231, mtu: 1420, comment: "FRA → MSK overlay", enabled: true, status: "up",
peers: [
{ publicKey: "MSKPublicKeyBase64AAAAAAAAAAAAAAAAAAAAAA=", allowedIps: ["10.210.0.1/32"], endpoint: "10.0.0.1:13232", latestHandshake: "1 мин назад", transferRx: 210_000_000, transferTx: 421_000_000, persistent: true },
],
},
],
},
{
id: "srv4", name: "mt-ams-edge-01", host: "10.0.3.1", model: "RB5009UG+S+IN", os: "7.19.3",
site: "AMS", country: "NL", asn: "AS65004", type: "exit-node", enabled: true, status: "degraded", latency: 88, sessions: 2,
},
{
id: "srv5", name: "mt-sgp-edge-01", host: "10.0.4.1", model: "CCR2004-1G-12S+2XS", os: "7.14.2",
site: "SGP", country: "SG", asn: "AS65005", type: "exit-node", enabled: false, status: "offline", latency: null, sessions: 0,
},
{
id: "srv6", name: "mt-ams-test-01", host: "10.0.3.2", model: "hEX S", os: "7.20.1",
site: "AMS", country: "NL", asn: "AS65006", type: "jump-host", enabled: true, status: "online", latency: 92, sessions: 1,
},
{
id: "srv7", name: "mt-msk-lab-01", host: "10.0.0.7", model: "RB5009UG+S+IN", os: "7.20.1",
site: "MSK", country: "RU", asn: "AS65007", type: "jump-host", enabled: true, status: "online", latency: 14, sessions: 2,
vrfNames: ["lab"],
},
{
id: "home1", name: "home-msk-01", host: "192.168.10.1", model: "hEX S (RB760iGS)", os: "7.20.1",
site: "MSK", country: "RU", asn: "", type: "home-router", enabled: true, status: "online", latency: 3, sessions: 0,
comment: "MSK офис — основной роутер",
lanSubnet: "192.168.10.0/24",
wanUplinks: [
{ id: "w1a", name: "WAN1-RT", isp: "Rostelecom", iface: "ether1", ip: "94.25.168.1", maxDl: 500, maxUl: 500 },
{ id: "w1b", name: "WAN2-BL", isp: "Beeline", iface: "ether2", ip: "85.174.12.1", maxDl: 100, maxUl: 100 },
],
},
{
id: "home2", name: "home-spb-01", host: "192.168.20.1", model: "RB5009UG+S+IN", os: "7.20.1",
site: "SPB", country: "RU", asn: "", type: "home-router", enabled: true, status: "online", latency: 5, sessions: 0,
comment: "SPB офис — основной роутер",
lanSubnet: "192.168.20.0/24",
wanUplinks: [
{ id: "w2a", name: "WAN1-MTS", isp: "МТС", iface: "ether1", ip: "178.214.4.1", maxDl: 300, maxUl: 300 },
{ id: "w2b", name: "WAN2-ERT", isp: "ЭР-Телеком", iface: "ether2", ip: "95.31.14.1", maxDl: 200, maxUl: 150 },
],
},
]
export const filters: Filter[] = [
{
id: "f1", name: "youtube-bypass", domains: 1842, ips: 4218, asns: 12,
servers: ["srv1","srv2","srv3","srv4"], enabled: true, updated: "12 мин назад",
communities: ["65001:100","65001:200"], gateway: "10.0.0.1",
largeCommunities: ["65001:100:1","65001:100:2"],
rpkiValid: true,
},
{
id: "f2", name: "streaming-eu", domains: 612, ips: 2104, asns: 8,
servers: ["srv2","srv3","srv4"], enabled: true, updated: "2 ч назад",
communities: ["65001:200"], gateway: "10.0.1.1",
largeCommunities: ["65001:200:1"],
rpkiValid: true,
},
{
id: "f3", name: "cdn-bypass", domains: 4218, ips: 18211, asns: 22,
servers: ["srv1","srv2","srv3","srv4","srv6"], enabled: true, updated: "1 ч назад",
communities: ["65001:300","65002:100"], gateway: "10.0.0.1",
flowspecRules: [
{ id: "fs1", dstPrefix: "104.16.0.0/12", ipProto: "tcp", dstPort: "443", action: "rate-limit", rate: 100, comment: "CF rate-limit" },
],
},
{ id: "f4", name: "social-block-school", domains: 84, ips: 412, asns: 4, servers: ["srv1","srv7"], enabled: false, updated: "3 дн назад", communities: ["65007:999"], gateway: "" },
{ id: "f5", name: "office-direct", domains: 142, ips: 884, asns: 6, servers: ["srv1","srv2","srv3","srv4","srv6","srv7"], enabled: true, updated: "4 ч назад", communities: ["65001:400"], gateway: "10.0.0.1" },
{ id: "f6", name: "gaming-low-latency", domains: 88, ips: 1212, asns: 14, servers: ["srv1","srv2","srv3","srv7"], enabled: true, updated: "24 мин назад", communities: ["65001:500","65002:200"], gateway: "10.0.2.1" },
]
export const domains: Domain[] = [
{ id: "d1", domain: "youtube.com", purpose: "streaming", filter: "youtube-bypass", resolvedIp: "142.250.74.110", asn: "AS15169", updated: "12 мин", enabled: true },
{ id: "d2", domain: "googlevideo.com", purpose: "streaming", filter: "youtube-bypass", resolvedIp: "142.250.74.142", asn: "AS15169", updated: "12 мин", enabled: true },
{ id: "d3", domain: "ytimg.com", purpose: "streaming", filter: "youtube-bypass", resolvedIp: "172.217.16.46", asn: "AS15169", updated: "12 мин", enabled: true },
{ id: "d4", domain: "netflix.com", purpose: "streaming", filter: "streaming-eu", resolvedIp: "54.246.79.9", asn: "AS2906", updated: "2 ч", enabled: true },
{ id: "d5", domain: "nflxvideo.net", purpose: "streaming", filter: "streaming-eu", resolvedIp: "45.57.32.18", asn: "AS2906", updated: "2 ч", enabled: true },
{ id: "d6", domain: "cloudflare.com", purpose: "cdn", filter: "cdn-bypass", resolvedIp: "104.16.132.229", asn: "AS13335", updated: "1 ч", enabled: true },
{ id: "d7", domain: "akamaized.net", purpose: "cdn", filter: "cdn-bypass", resolvedIp: "23.46.18.94", asn: "AS20940", updated: "1 ч", enabled: true },
{ id: "d8", domain: "fastly.net", purpose: "cdn", filter: "cdn-bypass", resolvedIp: "151.101.1.95", asn: "AS54113", updated: "1 ч", enabled: true },
{ id: "d9", domain: "twitch.tv", purpose: "streaming", filter: "streaming-eu", resolvedIp: "52.223.241.72", asn: "AS16509", updated: "2 ч", enabled: false },
{ id: "d10", domain: "discord.com", purpose: "voip", filter: "gaming-low-latency", resolvedIp: "162.159.135.232", asn: "AS13335", updated: "24 мин", enabled: true },
{ id: "d11", domain: "steam.com", purpose: "gaming", filter: "gaming-low-latency", resolvedIp: "23.45.139.40", asn: "AS20940", updated: "24 мин", enabled: true },
{ id: "d12", domain: "epicgames.com", purpose: "gaming", filter: "gaming-low-latency", resolvedIp: "34.205.247.51", asn: "AS16509", updated: "24 мин", enabled: true },
]
export const ipRanges: IpRange[] = [
{ id: "i1", cidr: "142.250.0.0/15", purpose: "streaming", filter: "youtube-bypass", asn: "AS15169", country: "US", updated: "12 мин", enabled: true },
{ id: "i2", cidr: "172.217.0.0/16", purpose: "streaming", filter: "youtube-bypass", asn: "AS15169", country: "US", updated: "12 мин", enabled: true },
{ id: "i3", cidr: "104.16.0.0/12", purpose: "cdn", filter: "cdn-bypass", asn: "AS13335", country: "US", updated: "1 ч", enabled: true },
{ id: "i4", cidr: "23.32.0.0/11", purpose: "cdn", filter: "cdn-bypass", asn: "AS20940", country: "US", updated: "1 ч", enabled: true },
{ id: "i5", cidr: "151.101.0.0/16", purpose: "cdn", filter: "cdn-bypass", asn: "AS54113", country: "US", updated: "1 ч", enabled: true },
{ id: "i6", cidr: "54.246.0.0/16", purpose: "streaming", filter: "streaming-eu", asn: "AS2906", country: "IE", updated: "2 ч", enabled: true },
{ id: "i7", cidr: "45.57.0.0/16", purpose: "streaming", filter: "streaming-eu", asn: "AS2906", country: "NL", updated: "2 ч", enabled: true },
{ id: "i8", cidr: "162.159.128.0/19", purpose: "voip", filter: "gaming-low-latency", asn: "AS13335", country: "US", updated: "24 мин", enabled: true },
{ id: "i9", cidr: "52.223.240.0/20", purpose: "streaming", filter: "streaming-eu", asn: "AS16509", country: "IE", updated: "2 ч", enabled: false },
]
export const asns: Asn[] = [
{ id: "a1", asn: "AS15169", org: "GOOGLE", country: "US", prefixes: 842, filter: "youtube-bypass", updated: "12 мин", enabled: true },
{ id: "a2", asn: "AS13335", org: "CLOUDFLARENET", country: "US", prefixes: 1284, filter: "cdn-bypass", updated: "1 ч", enabled: true },
{ id: "a3", asn: "AS16509", org: "AMAZON-02", country: "US", prefixes: 4128, filter: "streaming-eu", updated: "2 ч", enabled: true },
{ id: "a4", asn: "AS20940", org: "AKAMAI-ASN1", country: "US", prefixes: 614, filter: "cdn-bypass", updated: "1 ч", enabled: true },
{ id: "a5", asn: "AS54113", org: "FASTLY", country: "US", prefixes: 122, filter: "cdn-bypass", updated: "1 ч", enabled: true },
{ id: "a6", asn: "AS2906", org: "AS-SSI (Netflix)", country: "US", prefixes: 88, filter: "streaming-eu", updated: "2 ч", enabled: true },
{ id: "a7", asn: "AS32934", org: "FACEBOOK", country: "US", prefixes: 412, filter: "social-block-school",updated: "3 дн", enabled: false },
{ id: "a8", asn: "AS8075", org: "MICROSOFT-CORP", country: "US", prefixes: 882, filter: "office-direct", updated: "4 ч", enabled: true },
]
export const firewallRules: FirewallRule[] = [
{ id: "fw1", chain: "forward", action: "accept", proto: "tcp", src: "youtube-bypass", dst: "0.0.0.0/0", port: "443", iface: "wan-bgp", comment: "YouTube bypass traffic", enabled: true, hits: 188421 },
{ id: "fw2", chain: "forward", action: "mark-routing", proto: "tcp", src: "10.10.0.0/24", dst: "cdn-bypass", port: "—", iface: "lan", comment: "CDN routing mark", enabled: true, hits: 4128821 },
{ id: "fw3", chain: "srcnat", action: "masquerade", proto: "all", src: "10.10.0.0/16", dst: "0.0.0.0/0", port: "—", iface: "wan-msk", comment: "Main NAT rule", enabled: true, hits: 12889241 },
{ id: "fw4", chain: "forward", action: "drop", proto: "tcp", src: "0.0.0.0/0", dst: "social-block-school", port: "—", iface: "lan-school", comment: "School social block", enabled: true, hits: 4218 },
{ id: "fw5", chain: "input", action: "accept", proto: "tcp", src: "10.10.0.0/16", dst: "—", port: "22,443,8291",iface: "—", comment: "Management access", enabled: true, hits: 18412 },
{ id: "fw6", chain: "input", action: "drop", proto: "tcp", src: "0.0.0.0/0", dst: "—", port: "22", iface: "wan-msk", comment: "Block SSH from WAN", enabled: true, hits: 882412 },
]
export const backups: Backup[] = [
{ id: "b1", server: "mt-msk-core-01", filename: "mt-msk-core-01_2026-04-26_03-00.rsc", size: "124 КБ", created: "Сегодня, 03:00", kind: "auto", notes: "снапшот перед обновлением" },
{ id: "b2", server: "mt-msk-core-01", filename: "mt-msk-core-01_2026-04-25_03-00.rsc", size: "124 КБ", created: "Вчера, 03:00", kind: "auto", notes: "" },
{ id: "b3", server: "mt-spb-edge-01", filename: "mt-spb-edge-01_2026-04-26_03-00.rsc", size: "88 КБ", created: "Сегодня, 03:00", kind: "auto", notes: "" },
{ id: "b4", server: "mt-fra-edge-01", filename: "mt-fra-edge-01_2026-04-26_manual.rsc",size: "92 КБ", created: "Сегодня, 14:18", kind: "manual", notes: "перед изменением BGP" },
{ id: "b5", server: "mt-ams-edge-01", filename: "mt-ams-edge-01_2026-04-25_03-00.rsc", size: "64 КБ", created: "Вчера, 03:00", kind: "auto", notes: "" },
]
export const pingProbes: PingProbe[] = [
// srv1 — mt-msk-core-01 (JH, MSK) → основной мониторинг
{ id: "p1", srcServerId: "srv1", name: "youtube.com", target: "142.250.74.110", filter: "youtube-bypass", rtt: 18, loss: 0, status: "up", series: spark(40, 18, 4), enabled: true },
{ id: "p2", srcServerId: "srv1", name: "cloudflare.com", target: "104.16.132.229", filter: "cdn-bypass", rtt: 4, loss: 0, status: "up", series: spark(40, 4, 1), enabled: true },
{ id: "p3", srcServerId: "srv1", name: "netflix-eu", target: "54.246.79.9", filter: "streaming-eu", rtt: 28, loss: 0, status: "up", series: spark(40, 28, 5), enabled: true },
{ id: "p4", srcServerId: "srv1", name: "fastly-edge", target: "151.101.1.95", filter: "cdn-bypass", rtt: 8, loss: 0, status: "up", series: spark(40, 8, 2), enabled: true },
// srv7 — mt-msk-lab-01 (JH, MSK) → лаборатория
{ id: "p5", srcServerId: "srv7", name: "discord-voip", target: "162.159.135.232", filter: "gaming-low-latency", rtt: 12, loss: 0, status: "up", series: spark(40, 12, 2), enabled: true },
{ id: "p6", srcServerId: "srv7", name: "steam-cdn", target: "23.45.139.40", filter: "gaming-low-latency", rtt: 38, loss: 1.2, status: "warn", series: spark(40, 38, 12), enabled: true },
{ id: "p7", srcServerId: "srv7", name: "akamai-edge", target: "23.46.18.94", filter: "cdn-bypass", rtt: 22, loss: 0, status: "up", series: spark(40, 22, 4), enabled: true },
// srv2 — mt-spb-edge-01 (EN, SPB) → исходящий трафик SPB
{ id: "p8", srcServerId: "srv2", name: "youtube.com", target: "142.250.74.110", filter: "youtube-bypass", rtt: 22, loss: 0, status: "up", series: spark(40, 22, 5), enabled: true },
{ id: "p9", srcServerId: "srv2", name: "office-365", target: "104.47.0.22", filter: "office-direct", rtt: 31, loss: 0, status: "up", series: spark(40, 31, 6), enabled: false },
// srv3 — mt-fra-edge-01 (EN, FRA) → исходящий трафик Frankfurt
{ id: "p10", srcServerId: "srv3", name: "youtube.com", target: "142.250.74.110", filter: "youtube-bypass", rtt: 12, loss: 0, status: "up", series: spark(40, 12, 3), enabled: true },
{ id: "p11", srcServerId: "srv3", name: "netflix-eu", target: "54.246.79.9", filter: "streaming-eu", rtt: 9, loss: 0, status: "up", series: spark(40, 9, 2), enabled: true },
// srv4 — mt-ams-edge-01 (EN, AMS, degraded) → деградировавший узел
{ id: "p12", srcServerId: "srv4", name: "cloudflare.com", target: "104.16.132.229", filter: "cdn-bypass", rtt: 88, loss: 3.4, status: "warn", series: spark(40, 88, 22), enabled: true },
{ id: "p13", srcServerId: "srv4", name: "sgp-probe", target: "139.180.22.4", filter: "—", rtt: null,loss: 100, status: "down", series: Array(40).fill(0), enabled: true },
]
export const systemEvents: SystemEvent[] = [
{ id: "e1", sev: "destructive", title: "BGP-сессия упала", message: "mt-sgp-edge-01 · пир 139.180.22.4 · простой 2ч", when: "2ч" },
{ id: "e2", sev: "destructive", title: "Ошибка синхронизации фильтра", message: "cdn-bypass → mt-ams-edge-01 · таймаут", when: "14м" },
{ id: "e3", sev: "warning", title: "Высокая задержка на AMS", message: "среднее 88мс · порог 60мс", when: "8м" },
{ id: "e4", sev: "warning", title: "Бэкап просрочен", message: "mt-msk-lab-01 · последний 5д назад", when: "1ч" },
{ id: "e5", sev: "info", title: "Обновление BGP завершено", message: "+412 префиксов · −188 отозвано", when: "12м" },
{ id: "e6", sev: "info", title: "Фильтр youtube-bypass обновлён", message: "+88 доменов · ↑ 24 сервера", when: "12м" },
]
export const dashLatency = {
msk: spark(60, 12, 4),
spb: spark(60, 28, 6),
fra: spark(60, 41, 9),
ams: spark(60, 88, 18),
}
export const traffic = {
rx: Array.from({ length: 60 }, (_, i) => Math.round(280 + Math.sin(i / 6) * 60 + ((i * 7919) % 31))),
tx: Array.from({ length: 60 }, (_, i) => Math.round(220 + Math.sin(i / 5) * 50 + ((i * 6271) % 21))),
}
// ─── GRE ────────────────────────────────────────────────────────────────────
export type GreStatus = "up" | "down" | "degraded"
export type IpsecEncAlg = "aes-128" | "aes-192" | "aes-256"
export type IpsecAuthAlg = "sha1" | "sha256" | "sha512"
export type IpsecDhGroup = "modp1024" | "modp2048" | "modp4096" | "ecp256" | "ecp384" | "ecp521"
export type IkeVersion = "ikev1" | "ikev2"
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
}
export interface GreTunnel {
id: string
name: string // interface name, e.g. gre-msk-spb
serverId: string // which MikroTik runs this tunnel
localAddress: string // local GRE endpoint ("0.0.0.0" = auto)
remoteAddress: string // remote GRE endpoint (required)
localInnerIp: string // /ip address on this side, e.g. 10.200.0.1/30
remoteInnerIp: string // /ip address on remote side, e.g. 10.200.0.2/30
poolId: string // which IP pool the inner IPs come from
ipsec: GreIpsec | null // null = no IPsec (plain GRE)
mtu: number // default 1476
keepaliveInterval: number // seconds, 0 = disabled
keepaliveRetries: number
dscp: DscpMode // "inherit" or 0-63
clampTcpMss: boolean
allowFastPath: boolean
comment: string
enabled: boolean
status: GreStatus
}
export interface GrePool {
id: string
name: string
cidr: string
allocated: number
total: number
comment: string
}
const defaultIpsec = (secret: string, ikeVersion: IkeVersion = "ikev2"): GreIpsec => ({
secret,
encAlg: "aes-256",
authAlg: "sha256",
dhGroup: "modp2048",
ikeVersion,
lifetime: "1d 00:00:00",
pfs: true,
})
export const grePools: GrePool[] = [
{ id: "gp1", name: "pool-gre-core", cidr: "10.200.0.0/24", allocated: 16, total: 64, comment: "Ядровые межузловые туннели" },
{ id: "gp2", name: "pool-gre-mgmt", cidr: "10.201.0.0/24", allocated: 8, total: 64, comment: "Управляющие туннели (lab, test)" },
]
export const greTunnels: GreTunnel[] = [
{
id: "gre1", name: "gre-msk-spb", serverId: "srv1",
localAddress: "10.0.0.1", remoteAddress: "10.0.1.1",
localInnerIp: "10.200.0.1/30", remoteInnerIp: "10.200.0.2/30", poolId: "gp1",
ipsec: defaultIpsec("xK9#mQ2$vLp8nR4"),
mtu: 1476, keepaliveInterval: 10, keepaliveRetries: 10,
dscp: "inherit", clampTcpMss: true, allowFastPath: true,
comment: "MSK → SPB core interconnect", enabled: true, status: "up",
},
{
id: "gre2", name: "gre-msk-fra", serverId: "srv1",
localAddress: "10.0.0.1", remoteAddress: "10.0.2.1",
localInnerIp: "10.200.0.5/30", remoteInnerIp: "10.200.0.6/30", poolId: "gp1",
ipsec: defaultIpsec("pW3@jT7!hD5kYe1"),
mtu: 1476, keepaliveInterval: 10, keepaliveRetries: 10,
dscp: "inherit", clampTcpMss: true, allowFastPath: true,
comment: "MSK → FRA core interconnect", enabled: true, status: "up",
},
{
id: "gre3", name: "gre-msk-ams", serverId: "srv1",
localAddress: "10.0.0.1", remoteAddress: "10.0.3.1",
localInnerIp: "10.200.0.9/30", remoteInnerIp: "10.200.0.10/30", poolId: "gp1",
ipsec: defaultIpsec("rN6%bF2*cM8sZa0"),
mtu: 1476, keepaliveInterval: 10, keepaliveRetries: 10,
dscp: "inherit", clampTcpMss: true, allowFastPath: false,
comment: "MSK → AMS core interconnect", enabled: true, status: "degraded",
},
{
id: "gre4", name: "gre-msk-sgp", serverId: "srv1",
localAddress: "10.0.0.1", remoteAddress: "10.0.4.1",
localInnerIp: "10.200.0.13/30", remoteInnerIp: "10.200.0.14/30", poolId: "gp1",
ipsec: defaultIpsec("qA4^eU9#wG1oXi6"),
mtu: 1476, keepaliveInterval: 10, keepaliveRetries: 10,
dscp: "inherit", clampTcpMss: true, allowFastPath: true,
comment: "MSK → SGP core interconnect", enabled: false, status: "down",
},
{
id: "gre5", name: "gre-lab-core", serverId: "srv7",
localAddress: "10.0.0.7", remoteAddress: "10.0.0.1",
localInnerIp: "10.201.0.1/30", remoteInnerIp: "10.201.0.2/30", poolId: "gp2",
ipsec: null,
mtu: 1500, keepaliveInterval: 0, keepaliveRetries: 0,
dscp: "inherit", clampTcpMss: false, allowFastPath: true,
comment: "Lab → core (internal, no IPsec)", enabled: true, status: "up",
},
{
id: "gre6", name: "gre-ams-test", serverId: "srv6",
localAddress: "10.0.3.2", remoteAddress: "10.0.3.1",
localInnerIp: "10.201.0.5/30", remoteInnerIp: "10.201.0.6/30", poolId: "gp2",
ipsec: null,
mtu: 1476, keepaliveInterval: 5, keepaliveRetries: 5,
dscp: 0, clampTcpMss: true, allowFastPath: true,
comment: "AMS test → AMS edge", enabled: true, status: "up",
},
]
// ─── Filter Rules (Community → Gateway per server) ────────────────────────────
export interface FilterRule {
id: string
community: string // BGP community, e.g. "65001:100"
communityName?: string // optional human-readable name
action?: "route" | "blackhole" // default "route"; "blackhole" → null-route (RTBH)
gateway: string // remote inner IP of GRE tunnel; empty for blackhole
gatewayTunnelId: string // reference to greTunnel.id; empty for blackhole
description: string
}
export interface ServerFilterRuleset {
serverId: string
rules: FilterRule[]
}
export const serverFilterRulesets: ServerFilterRuleset[] = [
// srv1 — mt-msk-core-01 (jump-host, MSK): gre1=SPB, gre2=FRA, gre3=AMS(deg), gre4=SGP(down)
{
serverId: "srv1",
rules: [
{ id: "r1", community: "65001:100", communityName: "youtube-bypass", gateway: "10.200.0.6", gatewayTunnelId: "gre2", description: "YouTube/Google Video → Frankfurt (IX)" },
{ id: "r2", community: "65001:200", communityName: "streaming-eu", gateway: "10.200.0.6", gatewayTunnelId: "gre2", description: "Netflix, Twitch EU → Frankfurt" },
{ id: "r3", community: "65001:300", communityName: "cdn-bypass", gateway: "10.200.0.2", gatewayTunnelId: "gre1", description: "Cloudflare / Akamai / Fastly → SPB" },
{ id: "r4", community: "65002:100", communityName: "cdn-secondary", gateway: "10.200.0.10", gatewayTunnelId: "gre3", description: "CDN резерв → Amsterdam (degraded)" },
{ id: "r5", community: "65001:400", communityName: "office-direct", gateway: "10.200.0.2", gatewayTunnelId: "gre1", description: "MS Office 365 / Teams → SPB direct" },
{ id: "r6", community: "65001:500", communityName: "gaming-ll", gateway: "10.200.0.2", gatewayTunnelId: "gre1", description: "Discord / Steam / Epic — низкая задержка → SPB" },
{ id: "r10", community: "65535:666", communityName: "BLACKHOLE (RFC 7999)", action: "blackhole", gateway: "", gatewayTunnelId: "", description: "RTBH — null-route входящих маршрутов" },
{ id: "r11", community: "65001:666", communityName: "blackhole-local", action: "blackhole", gateway: "", gatewayTunnelId: "", description: "Локальная блокировка — сброс трафика" },
],
},
// srv7 — mt-msk-lab-01 (jump-host, MSK lab): gre5=core
{
serverId: "srv7",
rules: [
{ id: "r7", community: "65001:100", communityName: "youtube-bypass", gateway: "10.201.0.2", gatewayTunnelId: "gre5", description: "Lab: YouTube → core" },
{ id: "r8", community: "65007:999", communityName: "school-block", gateway: "10.201.0.2", gatewayTunnelId: "gre5", description: "Lab: школьная блокировка" },
],
},
// srv6 — mt-ams-test-01 (jump-host, AMS test): gre6=AMS edge
{
serverId: "srv6",
rules: [
{ id: "r9", community: "65001:300", communityName: "cdn-bypass", gateway: "10.201.0.6", gatewayTunnelId: "gre6", description: "AMS test: CDN → AMS edge" },
],
},
// Exit nodes — нет правил по умолчанию
{ serverId: "srv2", rules: [] },
{ serverId: "srv3", rules: [] },
{ serverId: "srv4", rules: [] },
{ serverId: "srv5", rules: [] },
]
// ─── VXLAN mock data ─────────────────────────────────────────────────────────
export const vxlanTunnels: VxlanTunnel[] = [
{
id: "vx1", name: "vxlan-overlay-msk", vni: 10010, port: 0, dstPort: 8472,
serverId: "srv1", vtepIp: "10.0.0.1", remoteVteps: ["10.0.1.1","10.0.2.1"],
l2mtu: 1500, arpProxy: true, macLearning: true,
comment: "MSK overlay — сегмент bypass", enabled: true, status: "up",
},
{
id: "vx2", name: "vxlan-overlay-spb", vni: 10010, port: 0, dstPort: 8472,
serverId: "srv2", vtepIp: "10.0.1.1", remoteVteps: ["10.0.0.1","10.0.2.1"],
l2mtu: 1500, arpProxy: true, macLearning: true,
comment: "SPB overlay — сегмент bypass", enabled: true, status: "up",
},
{
id: "vx3", name: "vxlan-overlay-fra", vni: 10010, port: 0, dstPort: 8472,
serverId: "srv3", vtepIp: "10.0.2.1", remoteVteps: ["10.0.0.1","10.0.1.1"],
l2mtu: 1500, arpProxy: true, macLearning: false,
comment: "FRA overlay — сегмент bypass", enabled: true, status: "up",
},
{
id: "vx4", name: "vxlan-mgmt-lab", vni: 20001, port: 0, dstPort: 4789,
serverId: "srv7", vtepIp: "10.0.0.7", remoteVteps: ["10.0.0.1"],
l2mtu: 1500, arpProxy: false, macLearning: true,
comment: "Lab management VXLAN", enabled: true, status: "up",
},
{
id: "vx5", name: "vxlan-overlay-ams", vni: 10010, port: 0, dstPort: 8472,
serverId: "srv4", vtepIp: "10.0.3.1", remoteVteps: ["10.0.0.1"],
l2mtu: 1500, arpProxy: true, macLearning: true,
comment: "AMS overlay (degraded)", enabled: true, status: "down",
},
]
// ─── Container mock data ─────────────────────────────────────────────────────
export const routerContainers: RouterContainer[] = [
{
id: "c1", name: "adguard-msk", serverId: "srv1",
image: "adguard/adguardhome", tag: "latest",
status: "running",
envs: [{ key: "AGH_CONFIG", value: "/opt/adguardhome/conf/AdGuardHome.yaml" }],
mounts: [{ dst: "/opt/adguardhome/conf", src: "/disk1/adguard" }, { dst: "/opt/adguardhome/work", src: "/disk1/adguard-work" }],
interfaces: ["veth-adguard"],
startOnBoot: true, comment: "AdGuard Home — DNS фильтрация",
uptime: "12д 4ч", cpu: 3, memMb: 64,
},
{
id: "c2", name: "prometheus-msk", serverId: "srv1",
image: "prom/prometheus", tag: "v2.52.0",
status: "running",
envs: [],
mounts: [{ dst: "/prometheus", src: "/disk1/prom-data" }],
interfaces: ["veth-prom"],
cmd: "--config.file=/etc/prometheus/prometheus.yml --storage.tsdb.retention.time=30d",
startOnBoot: true, comment: "Prometheus метрики",
uptime: "5д 11ч", cpu: 8, memMb: 256,
},
{
id: "c3", name: "grafana-msk", serverId: "srv1",
image: "grafana/grafana", tag: "10.4.2",
status: "running",
envs: [{ key: "GF_SECURITY_ADMIN_PASSWORD", value: "*** (hidden)" }],
mounts: [{ dst: "/var/lib/grafana", src: "/disk1/grafana" }],
interfaces: ["veth-grafana"],
startOnBoot: true, comment: "Grafana — дашборды мониторинга",
uptime: "5д 11ч", cpu: 5, memMb: 128,
},
{
id: "c4", name: "wg-portal-spb", serverId: "srv2",
image: "wgportal/wg-portal", tag: "v1.3.1",
status: "running",
envs: [{ key: "WG_PORTAL_ADMIN_USER", value: "admin" }],
mounts: [{ dst: "/app/data", src: "/disk1/wgportal" }],
interfaces: ["veth-wgportal"],
startOnBoot: true, comment: "WireGuard Portal — управление клиентами",
uptime: "3д 7ч", cpu: 1, memMb: 48,
},
{
id: "c5", name: "unbound-fra", serverId: "srv3",
image: "mvance/unbound", tag: "1.19.3",
status: "stopped",
envs: [],
mounts: [],
interfaces: ["veth-unbound"],
startOnBoot: false, comment: "Unbound DNS резолвер (в резерве)",
cpu: 0, memMb: 0,
},
]
// ─── Certificate mock data ────────────────────────────────────────────────────
export const routerCertificates: RouterCertificate[] = [
{
id: "cert1", name: "mt-msk-core-01-server", serverId: "srv1",
commonName: "mt-msk-core-01.routerlists.io",
sans: ["mt-msk-core-01.routerlists.io","10.0.0.1"],
issuedBy: "RouterLists Internal CA", validFrom: "2024-01-15",
validUntil: "2026-01-15", daysLeft: 261,
keySize: 4096, usage: ["server"], trusted: true, status: "valid",
},
{
id: "cert2", name: "routerlists-internal-ca", serverId: "srv1",
commonName: "RouterLists Internal CA",
sans: [],
issuedBy: "RouterLists Internal CA (self-signed)", validFrom: "2023-06-01",
validUntil: "2033-06-01", daysLeft: 2589,
keySize: 4096, usage: ["ca","crl-sign"], trusted: true, status: "valid",
},
{
id: "cert3", name: "mt-spb-edge-01-server", serverId: "srv2",
commonName: "mt-spb-edge-01.routerlists.io",
sans: ["mt-spb-edge-01.routerlists.io","10.0.1.1"],
issuedBy: "RouterLists Internal CA", validFrom: "2024-01-15",
validUntil: "2026-01-15", daysLeft: 261,
keySize: 4096, usage: ["server"], trusted: true, status: "valid",
},
{
id: "cert4", name: "mt-fra-edge-01-server", serverId: "srv3",
commonName: "mt-fra-edge-01.routerlists.io",
sans: ["mt-fra-edge-01.routerlists.io","10.0.2.1"],
issuedBy: "Let's Encrypt", validFrom: "2026-01-10",
validUntil: "2026-04-10", daysLeft: -19,
keySize: 2048, usage: ["server"], trusted: true, status: "expired",
},
{
id: "cert5", name: "wg-client-admin", serverId: "srv1",
commonName: "admin.routerlists.io",
sans: ["admin.routerlists.io"],
issuedBy: "RouterLists Internal CA", validFrom: "2025-06-01",
validUntil: "2026-06-01", daysLeft: 33,
keySize: 2048, usage: ["client"], trusted: true, status: "valid",
},
{
id: "cert6", name: "mt-ams-edge-01-server", serverId: "srv4",
commonName: "mt-ams-edge-01.routerlists.io",
sans: ["mt-ams-edge-01.routerlists.io"],
issuedBy: "RouterLists Internal CA", validFrom: "2024-04-01",
validUntil: "2026-05-15", daysLeft: 16,
keySize: 2048, usage: ["server"], trusted: false, status: "valid",
},
{
id: "cert7", name: "mt-msk-lab-01-server", serverId: "srv7",
commonName: "mt-msk-lab-01.routerlists.io",
sans: ["mt-msk-lab-01.routerlists.io","10.0.0.7"],
issuedBy: "RouterLists Internal CA", validFrom: "2025-09-01",
validUntil: "2026-09-01", daysLeft: 125,
keySize: 4096, usage: ["server"], trusted: true, status: "valid",
},
]