修复泄露IP的严重BUG

This commit is contained in:
CN-JS-HuiBai
2026-04-04 22:43:42 +08:00
parent 0914881d26
commit e2dbf06601
3 changed files with 58 additions and 15 deletions

View File

@@ -489,7 +489,9 @@
{ key: 'swapUsedPct', label: 'SWAP 使用率', value: formatPercent(data.swapUsedPct) },
{ key: 'rootFsUsedPct', label: '根分区使用率 (/)', value: formatPercent(data.rootFsUsedPct) },
{ key: 'netRx', label: '网络接收速率 (RX)', value: formatBandwidth(data.netRx) },
{ key: 'netTx', label: '网络发送速率 (TX)', value: formatBandwidth(data.netTx) }
{ key: 'netTx', label: '网络发送速率 (TX)', value: formatBandwidth(data.netTx) },
{ key: 'sockstatTcp', label: 'TCP 链接数 (Sockstat)', value: data.sockstatTcp.toFixed(0) },
{ key: 'sockstatTcpMem', label: 'TCP 内存占用', value: formatBytes(data.sockstatTcpMem) }
];
dom.detailMetricsList.innerHTML = metrics.map(m => `
@@ -565,7 +567,8 @@
let unit = '';
if (metricKey.includes('Pct') || metricKey === 'cpuBusy') unit = '%';
if (metricKey.startsWith('net')) unit = 'B/s';
if (metricKey === 'sockstatTcpMem') unit = 'B';
chart = new MetricChart(canvas, unit);
currentServerDetail.charts[metricKey] = chart;
}

View File

@@ -380,8 +380,15 @@ class MetricChart {
ctx.textAlign = 'right';
let label = '';
if (this.unit === 'B/s') {
label = window.formatBandwidth ? window.formatBandwidth(v) : v.toFixed(0);
if (this.unit === 'B/s' || this.unit === 'B') {
const isRate = this.unit === 'B/s';
if (window.formatBandwidth && isRate) {
label = window.formatBandwidth(v);
} else if (window.formatBytes) {
label = window.formatBytes(v) + (isRate ? '/s' : '');
} else {
label = v.toFixed(0) + this.unit;
}
} else {
label = (v >= 1000 ? (v / 1000).toFixed(1) + 'k' : v.toFixed(v < 10 && v > 0 ? 1 : 0)) + this.unit;
}

View File

@@ -5,9 +5,21 @@ const https = require('https');
const QUERY_TIMEOUT = 10000;
// Reusable agents to handle potential redirect issues and protocol mismatches
const crypto = require('crypto');
const httpAgent = new http.Agent({ keepAlive: true });
const httpsAgent = new https.Agent({ keepAlive: true, rejectUnauthorized: false });
const serverIdMap = new Map(); // token -> { instance, job, source }
const SECRET = crypto.randomBytes(16).toString('hex');
function getServerToken(instance) {
const hash = crypto.createHmac('sha256', SECRET)
.update(instance)
.digest('hex')
.substring(0, 16);
return hash;
}
/**
* Normalize URL and ensure protocol
*/
@@ -180,10 +192,16 @@ async function getOverviewMetrics(url, sourceName) {
const instances = new Map();
const getOrCreate = (metric) => {
const key = metric.instance;
if (!instances.has(key)) {
instances.set(key, {
instance: key,
const originalInstance = metric.instance;
const token = getServerToken(originalInstance, sourceName);
// Store mapping for detail queries
serverIdMap.set(token, { instance: originalInstance, source: sourceName, job: metric.job });
if (!instances.has(token)) {
instances.set(token, {
instance: token, // This is the masked IP SENT TO FRONTEND
originalInstance, // Keep internal for aggregation/parsing
job: metric.job || 'Unknown',
source: sourceName,
cpuPercent: 0,
@@ -197,7 +215,7 @@ async function getOverviewMetrics(url, sourceName) {
up: false
});
}
const inst = instances.get(key);
const inst = instances.get(token);
// If job was Unknown but we now have a job name, update it
if (inst.job === 'Unknown' && metric.job) {
inst.job = metric.job;
@@ -311,9 +329,13 @@ async function getOverviewMetrics(url, sourceName) {
},
traffic24h: {
rx: totalTraffic24hRx,
tx: totalTraffic24hTx
tx: totalTraffic24hTx,
total: totalTraffic24hRx + totalTraffic24hTx
},
servers: Array.from(instances.values())
servers: Array.from(instances.values()).map(s => {
const { originalInstance, ...rest } = s;
return rest;
})
};
}
@@ -412,12 +434,19 @@ function mergeCpuHistories(histories) {
}
function resolveToken(token) {
if (serverIdMap.has(token)) {
return serverIdMap.get(token).instance;
}
return token;
}
/**
* Get detailed metrics for a specific server (node)
*/
async function getServerDetails(baseUrl, instance, job) {
const url = normalizeUrl(baseUrl);
const node = instance;
const node = resolveToken(instance);
// Queries based on the requested dashboard structure
const queries = {
@@ -438,7 +467,9 @@ async function getServerDetails(baseUrl, instance, job) {
memTotal: `node_memory_MemTotal_bytes{instance="${node}",job="${job}"}`,
uptime: `node_time_seconds{instance="${node}",job="${job}"} - node_boot_time_seconds{instance="${node}",job="${job}"}`,
netRx: `sum(rate(node_network_receive_bytes_total{instance="${node}",job="${job}",device!~'tap.*|veth.*|br.*|docker.*|virbr*|podman.*|lo.*|vmbr.*|fwbr.|ip.*|gre.*|virbr.*|vnet.*'}[1m]))`,
netTx: `sum(rate(node_network_transmit_bytes_total{instance="${node}",job="${job}",device!~'tap.*|veth.*|br.*|docker.*|virbr*|podman.*|lo.*|vmbr.*|fwbr.|ip.*|gre.*|virbr.*|vnet.*'}[1m]))`
netTx: `sum(rate(node_network_transmit_bytes_total{instance="${node}",job="${job}",device!~'tap.*|veth.*|br.*|docker.*|virbr*|podman.*|lo.*|vmbr.*|fwbr.|ip.*|gre.*|virbr.*|vnet.*'}[1m]))`,
sockstatTcp: `node_sockstat_TCP_inuse{instance="${node}",job="${job}"}`,
sockstatTcpMem: `node_sockstat_TCP_mem{instance="${node}",job="${job}"} * 4096` // Converting pages to bytes (assuming 4KB pages)
};
const results = {};
@@ -461,7 +492,7 @@ async function getServerDetails(baseUrl, instance, job) {
*/
async function getServerHistory(baseUrl, instance, job, metric, range = '1h', start = null, end = null) {
const url = normalizeUrl(baseUrl);
const node = instance;
const node = resolveToken(instance);
// Custom multi-metric handler for CPU Busy
if (metric === 'cpuBusy') {
@@ -504,7 +535,9 @@ async function getServerHistory(baseUrl, instance, job, metric, range = '1h', st
swapUsedPct: `((node_memory_SwapTotal_bytes{instance="${node}",job="${job}"} - node_memory_SwapFree_bytes{instance="${node}",job="${job}"}) / (node_memory_SwapTotal_bytes{instance="${node}",job="${job}"})) * 100`,
rootFsUsedPct: `100 - ((node_filesystem_avail_bytes{instance="${node}",job="${job}",mountpoint="/",fstype!="rootfs"} * 100) / node_filesystem_size_bytes{instance="${node}",job="${job}",mountpoint="/",fstype!="rootfs"})`,
netRx: `sum(rate(node_network_receive_bytes_total{instance="${node}",job="${job}",device!~'tap.*|veth.*|br.*|docker.*|virbr*|podman.*|lo.*|vmbr.*|fwbr.|ip.*|gre.*|virbr.*|vnet.*'}[1m]))`,
netTx: `sum(rate(node_network_transmit_bytes_total{instance="${node}",job="${job}",device!~'tap.*|veth.*|br.*|docker.*|virbr*|podman.*|lo.*|vmbr.*|fwbr.|ip.*|gre.*|virbr.*|vnet.*'}[1m]))`
netTx: `sum(rate(node_network_transmit_bytes_total{instance="${node}",job="${job}",device!~'tap.*|veth.*|br.*|docker.*|virbr*|podman.*|lo.*|vmbr.*|fwbr.|ip.*|gre.*|virbr.*|vnet.*'}[1m]))`,
sockstatTcp: `node_sockstat_TCP_inuse{instance="${node}",job="${job}"}`,
sockstatTcpMem: `node_sockstat_TCP_mem{instance="${node}",job="${job}"} * 4096`
};
const expr = metricMap[metric];