Docker images / prepare-release (push) Successful in 9s
Docker images / backend-image (push) Successful in 1m43s
Docker images / frontend-image (push) Successful in 2m58s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 39s
Docker images / publish-release (push) Successful in 8s
Replaced existing KPI display implementations across multiple pages with the new KpiStatGrid component for a more consistent and visually appealing presentation of statistics. Updated the Backups, BGP, Certificates, Communities, Containers, Dashboard, and Data Collection pages to utilize the KpiStatGrid, improving the overall user experience and maintainability of the codebase. Additionally, added new dependencies in package.json for required libraries.
846 lines
42 KiB
TypeScript
846 lines
42 KiB
TypeScript
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 {
|
||
id?: string
|
||
rosId?: string
|
||
publicKey: string
|
||
allowedIps: string[]
|
||
endpoint?: string // "1.2.3.4:13231"
|
||
latestHandshake?: string // "2 минуты назад"
|
||
transferRx?: number // bytes
|
||
transferTx?: number // bytes
|
||
persistentKeepalive?: number
|
||
persistent?: boolean
|
||
comment?: string
|
||
disabled?: boolean
|
||
name?: string
|
||
clientAddress?: string
|
||
clientDns?: string
|
||
clientEndpoint?: string
|
||
}
|
||
|
||
export interface WireGuardInterface {
|
||
id: string
|
||
rosId?: string
|
||
name: string // e.g. "wg-msk-spb"
|
||
listenPort: number // default 13231
|
||
mtu: number // 1420 default in ROS 7.x
|
||
publicKey?: string
|
||
privateKey?: string
|
||
address?: string
|
||
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 (как GET /api/servers — последний poll MikroTik)
|
||
uptime?: string
|
||
cpuLoad?: number
|
||
/** байты, поля RouterOS resource */
|
||
freeMemory?: number
|
||
totalMemory?: 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 type FirewallTable = "filter" | "nat" | "mangle" | "raw"
|
||
|
||
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
|
||
family?: "ip" | "ip6" | "any"
|
||
table?: FirewallTable
|
||
serverId?: string
|
||
serverName?: string
|
||
rosId?: string
|
||
tlsHost?: string
|
||
connRateLimit?: string
|
||
layer7Proto?: string
|
||
nfqueueId?: number
|
||
log?: boolean
|
||
logPrefix?: string
|
||
}
|
||
|
||
export interface FirewallAddressListEntry {
|
||
id: string
|
||
list: string
|
||
address: string
|
||
comment: string
|
||
disabled: boolean
|
||
timeout?: string
|
||
family?: "ip" | "ip6"
|
||
serverId?: string
|
||
serverName?: string
|
||
rosId?: 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 // 0–16777215
|
||
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
|
||
/** Показывать в блоке «Активные пробы» на дашборде (звезда в мониторинге) */
|
||
showOnDashboard?: 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", table: "filter", family: "ip", serverId: "srv1", serverName: "mt-msk-core-01", rosId: "*1", 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", table: "mangle", family: "ip", serverId: "srv1", serverName: "mt-msk-core-01", rosId: "*1", 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", table: "nat", family: "ip", serverId: "srv1", serverName: "mt-msk-core-01", rosId: "*1", 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", table: "filter", family: "ip", serverId: "srv1", serverName: "mt-msk-core-01", rosId: "*2", 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", table: "filter", family: "ip", serverId: "srv1", serverName: "mt-msk-core-01", rosId: "*3", 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", table: "filter", family: "ip", serverId: "srv1", serverName: "mt-msk-core-01", rosId: "*4", 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 },
|
||
{ id: "fw7", table: "filter", family: "ip6", serverId: "srv1", serverName: "mt-msk-core-01", rosId: "*1", chain: "input", action: "accept", proto: "icmpv6", src: "fe80::/10", dst: "—", port: "—", iface: "—", comment: "IPv6 link-local ICMPv6", enabled: true, hits: 1204 },
|
||
{ id: "fw8", table: "filter", family: "ip6", serverId: "srv1", serverName: "mt-msk-core-01", rosId: "*2", chain: "forward", action: "accept", proto: "tcp", src: "2a01:4f8::/32", dst: "::/0", port: "443", iface: "wan-bgp", comment: "IPv6 HTTPS forward", enabled: true, hits: 88421 },
|
||
]
|
||
|
||
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 // next-hop IP for filter rule; empty for blackhole
|
||
/** GRE: id туннеля / имя интерфейса; рекурсивный маршрут: `rec:<id>` строки recursive_routes на сервере */
|
||
gatewayTunnelId: string
|
||
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: "MikrotikManager 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: "MikrotikManager Internal CA",
|
||
sans: [],
|
||
issuedBy: "MikrotikManager 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: "MikrotikManager 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: "MikrotikManager 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: "MikrotikManager 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: "MikrotikManager Internal CA", validFrom: "2025-09-01",
|
||
validUntil: "2026-09-01", daysLeft: 125,
|
||
keySize: 4096, usage: ["server"], trusted: true, status: "valid",
|
||
},
|
||
]
|