feat(traffic): показать аналитику IPFIX по серверам и интерфейсам
Docker images / prepare-release (push) Successful in 12s
Docker images / backend-image (push) Successful in 2m10s
Docker images / frontend-image (push) Successful in 2m53s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 48s
Docker images / publish-release (push) Successful in 11s

Резолвить ifIndex в имена RouterOS, дать вкладке Потоки ту же оболочку сервер/клиент/iface, что у обычного трафика, и обновлять срезы live без перезагрузки.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-09-07 01:21:12 +07:00
co-authored by Cursor
parent cf68b59b3f
commit 37167f78e3
20 changed files with 1686 additions and 53 deletions
+12 -1
View File
@@ -7,6 +7,7 @@ export interface ParsedFlow {
bytes: number
packets: number
inIface: string
outIface: string
}
interface FieldSpec {
@@ -95,6 +96,7 @@ function parseNetflowV5(buf: Buffer): ParsedFlow[] {
dstPort: buf.readUInt16BE(off + 34),
proto: buf.readUInt8(off + 38),
inIface: String(buf.readUInt16BE(off + 12)),
outIface: String(buf.readUInt16BE(off + 14)),
})
off += 48
}
@@ -144,6 +146,8 @@ function recordFromFields(
let bytes = 0
let packets = 0
let inIface = ""
let outIface = ""
let ifaceName = ""
for (const f of fields) {
const field = consumeField(buf, off, f.length, limit)
if (!field) return null
@@ -191,12 +195,19 @@ function recordFromFields(
case 10:
inIface = String(readUint(data, 0, data.length))
break
case 14:
outIface = String(readUint(data, 0, data.length))
break
case 82:
ifaceName = data.toString("utf8").replace(/\0/g, "").trim()
break
default:
break
}
off = field.next
}
return { flow: { src, dst, proto, srcPort, dstPort, bytes, packets, inIface }, next: off }
if (!inIface && ifaceName) inIface = ifaceName
return { flow: { src, dst, proto, srcPort, dstPort, bytes, packets, inIface, outIface }, next: off }
}
function parseDataRecords(