feat: добавлена поддержка отображения устройства в журнале трафика
Refs: None
This commit is contained in:
@@ -100,9 +100,9 @@ const trafficSubscribers = new Set();
|
||||
// [router] match[N][rule-name] => outbound/direct[tag]
|
||||
// outbound/direct[tag]: dial tcp connection to host:port
|
||||
|
||||
// Назначение после --> (основной формат sing-box)
|
||||
// Назначение после --> (старый формат sing-box)
|
||||
const DEST_ARROW_RE = /-->\s*([\w.\-]+):(\d{1,5})/;
|
||||
// Назначение в старом словесном стиле
|
||||
// Назначение в словесном стиле
|
||||
const DEST_WORD_RE =
|
||||
/(?:connection\s+to|dial(?:ing)?|connect(?:ing)?\s+to)\s+([\w.\-]+):(\d{1,5})/i;
|
||||
// Тип аутбаунда: outbound/TYPE[tag] или outbound/TYPE
|
||||
@@ -110,6 +110,21 @@ const OUTBOUND_RE = /outbound\/([a-z0-9_\-]+)/i;
|
||||
// Строка роутера: [router] match[N][rule-name] => outbound/TYPE[tag]
|
||||
const ROUTER_MATCH_LINE_RE =
|
||||
/\[router\].*\bmatch\[\d+\]\[([^\]]+)\].*outbound\/([a-z0-9_\-]+)/i;
|
||||
// ID соединения: [CONN_ID Nms]
|
||||
const CONN_ID_RE = /\[(\d{5,12})\s+\d+ms\]/;
|
||||
// Входящее соединение от устройства: inbound [packet] connection from IP:PORT
|
||||
const INBOUND_FROM_RE = /inbound(?:\s+packet)?\s+connection\s+from\s+([\d.]+):\d+/i;
|
||||
// Source IP из --> формата: IP:PORT -->
|
||||
const SOURCE_ARROW_RE = /\b([\d.]+):\d+\s+-->/;
|
||||
// Карта source IP по ID соединения
|
||||
const CONN_TTL_MS = 10_000;
|
||||
const connSourceMap = new Map();
|
||||
setInterval(() => {
|
||||
const now = Date.now();
|
||||
for (const [id, v] of connSourceMap) {
|
||||
if (now - v.at > CONN_TTL_MS) connSourceMap.delete(id);
|
||||
}
|
||||
}, 30_000);
|
||||
|
||||
// Хранит имя последнего правила из [router] строки (для следующей строки с dest)
|
||||
let _pendingRuleName = null;
|
||||
@@ -117,7 +132,8 @@ let _pendingRuleAt = 0;
|
||||
const RULE_CONTEXT_TTL_MS = 500;
|
||||
|
||||
function parseTrafficLine(line) {
|
||||
const clean = line.replace(/\x1b\[\d+m/g, "").trim();
|
||||
// Расширенная очистка ANSI (включая многопараметрические: \x1b[38;5;Nm)
|
||||
const clean = line.replace(/\x1b\[[0-9;]*m/g, "").trim();
|
||||
|
||||
// Детектируем строку роутера — содержит правило, но не dest
|
||||
const routerM = clean.match(ROUTER_MATCH_LINE_RE);
|
||||
@@ -127,6 +143,17 @@ function parseTrafficLine(line) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Извлекаем ID соединения для корреляции
|
||||
const connM = clean.match(CONN_ID_RE);
|
||||
const connId = connM ? connM[1] : null;
|
||||
|
||||
// Строка "inbound connection from IP:PORT" — сохраняем source IP и выходим
|
||||
const inboundFromM = clean.match(INBOUND_FROM_RE);
|
||||
if (inboundFromM) {
|
||||
if (connId) connSourceMap.set(connId, { sourceIp: inboundFromM[1], at: Date.now() });
|
||||
return null;
|
||||
}
|
||||
|
||||
// Берём накопленное имя правила, если свежее
|
||||
let inheritedRule = null;
|
||||
if (_pendingRuleName && Date.now() - _pendingRuleAt < RULE_CONTEXT_TTL_MS) {
|
||||
@@ -150,19 +177,31 @@ function parseTrafficLine(line) {
|
||||
category = "block";
|
||||
else category = "vpn";
|
||||
|
||||
// Ищем назначение: --> (основной формат), потом словесный
|
||||
// Ищем назначение: --> (старый формат), потом словесный (inbound/outbound connection to)
|
||||
const destM = clean.match(DEST_ARROW_RE) || clean.match(DEST_WORD_RE);
|
||||
if (!destM) return null;
|
||||
|
||||
const host = destM[1];
|
||||
const port = parseInt(destM[2], 10);
|
||||
|
||||
// Source IP: из корреляционной карты (новый формат) или из --> (старый формат)
|
||||
let sourceIp = null;
|
||||
if (connId) {
|
||||
const stored = connSourceMap.get(connId);
|
||||
if (stored && Date.now() - stored.at < CONN_TTL_MS) sourceIp = stored.sourceIp;
|
||||
}
|
||||
if (!sourceIp) {
|
||||
const srcM = clean.match(SOURCE_ARROW_RE);
|
||||
if (srcM) sourceIp = srcM[1];
|
||||
}
|
||||
|
||||
return {
|
||||
ts: new Date().toISOString(),
|
||||
outbound: outboundRaw,
|
||||
category,
|
||||
host,
|
||||
port,
|
||||
sourceIp,
|
||||
matchedRule: inheritedRule,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user