221 lines
7.9 KiB
JavaScript
221 lines
7.9 KiB
JavaScript
const express = require('express');
|
|
const http = require('http');
|
|
const { Server } = require('socket.io');
|
|
const cors = require('cors');
|
|
const ping = require('ping');
|
|
const snmp = require('net-snmp');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const app = express();
|
|
const server = http.createServer(app);
|
|
const io = new Server(server, {
|
|
cors: {
|
|
origin: "*",
|
|
methods: ["GET", "POST"]
|
|
}
|
|
});
|
|
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
|
|
const DATA_FILE = path.join(__dirname, 'monitor_data.json');
|
|
const OIDS = {
|
|
name: "1.3.6.1.2.1.1.5.0",
|
|
location: "1.3.6.1.2.1.1.6.0"
|
|
};
|
|
|
|
// Initial Data
|
|
const initialIPs = [
|
|
"10.131.213.65", "10.131.213.95", "10.131.213.124", "10.131.213.90", "10.131.213.92",
|
|
"10.131.213.88", "10.131.213.67", "10.131.213.120", "10.131.213.121", "10.131.213.171",
|
|
"10.131.213.170", "10.131.213.161", "10.131.213.162", "10.131.213.74", "10.131.213.125",
|
|
"10.131.213.69", "10.131.213.75", "10.131.213.102", "10.131.213.155", "10.131.213.85",
|
|
"10.131.213.123", "10.131.213.140", "10.131.213.142", "10.131.213.143", "10.131.213.180",
|
|
"10.131.213.181", "10.131.213.103", "10.131.213.104", "10.131.213.105", "10.131.213.106",
|
|
"10.131.213.107", "10.131.213.108", "10.131.213.110", "10.131.213.111", "10.131.213.122",
|
|
"10.131.213.126", "10.131.213.127", "10.131.213.128", "10.131.213.129", "10.131.213.130",
|
|
"10.131.213.132", "10.131.213.133", "10.131.213.134", "10.131.213.135", "10.131.213.136",
|
|
"10.131.213.137", "10.131.213.138", "10.131.213.141", "10.131.213.144", "10.131.213.145",
|
|
"10.131.213.146", "10.131.213.148", "10.131.213.150", "10.131.213.153", "10.131.213.154",
|
|
"10.131.213.156", "10.131.213.157", "10.131.213.191", "10.131.213.192", "10.131.213.200",
|
|
"10.131.213.202", "10.131.213.250", "10.131.213.249", "10.131.213.51", "10.131.213.52",
|
|
"10.131.213.53", "10.131.213.54", "10.131.213.55", "10.131.213.56", "10.131.213.57",
|
|
"10.131.213.58", "10.131.213.59", "10.131.213.61", "10.131.213.62", "10.131.213.63",
|
|
"10.131.213.64", "10.131.213.66", "10.131.213.68", "10.131.213.71", "10.131.213.72",
|
|
"10.131.213.73", "10.131.213.76", "10.131.213.77", "10.131.213.78", "10.131.213.79",
|
|
"10.131.213.81", "10.131.213.82", "10.131.213.84", "10.131.213.86", "10.131.213.87",
|
|
"10.131.213.93", "10.131.213.94", "10.131.213.96", "10.131.213.97", "10.131.213.99",
|
|
"10.131.213.147", "10.131.213.146", "10.131.213.155", "10.131.213.141", "10.131.213.131",
|
|
"10.131.213.152", "10.131.213.154", "10.131.213.145", "10.131.213.151", "10.131.213.148",
|
|
"10.131.213.149", "10.131.213.153", "10.131.213.201", "10.131.213.35", "10.131.213.32",
|
|
"10.131.213.24", "10.131.213.25", "10.131.213.31", "10.131.213.34", "10.131.213.41",
|
|
"10.131.213.254", "10.131.213.11", "10.131.213.12", "10.131.213.50", "10.131.213.113",
|
|
"10.131.213.112", "10.131.213.115", "10.131.213.114", "10.131.213.117", "10.131.213.118",
|
|
"10.131.213.119", "10.131.213.101"
|
|
];
|
|
|
|
// Remove duplicates
|
|
const uniqueIPs = [...new Set(initialIPs)];
|
|
|
|
let store = {
|
|
ips: uniqueIPs,
|
|
communities: ['public', 'private'], // Default communities
|
|
results: {}, // { ip: { alive: bool, name: str, location: str, community: str, lastCheck: timestamp } }
|
|
};
|
|
|
|
// Load data
|
|
if (fs.existsSync(DATA_FILE)) {
|
|
try {
|
|
store = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
|
|
} catch (e) {
|
|
console.error("Failed to load data", e);
|
|
}
|
|
} else {
|
|
// If starting fresh, initialize results structure
|
|
store.ips.forEach(ip => {
|
|
store.results[ip] = { alive: false, name: null, location: null, community: null, lastCheck: 0 };
|
|
});
|
|
}
|
|
|
|
const saveData = () => {
|
|
fs.writeFileSync(DATA_FILE, JSON.stringify(store, null, 2));
|
|
};
|
|
|
|
// Helper for SNMP
|
|
const getSnmpData = (ip, community) => {
|
|
return new Promise((resolve, reject) => {
|
|
// User requested v2c
|
|
const session = snmp.createSession(ip, community, {
|
|
timeout: 5000,
|
|
retries: 1,
|
|
version: snmp.Version2c
|
|
});
|
|
session.get([OIDS.name, OIDS.location], (error, varbinds) => {
|
|
session.close();
|
|
if (error) {
|
|
reject(error);
|
|
} else {
|
|
const name = snmp.isVarbindError(varbinds[0]) ? null : varbinds[0].value.toString();
|
|
const location = snmp.isVarbindError(varbinds[1]) ? null : varbinds[1].value.toString();
|
|
resolve({ name, location });
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
// Check a single IP
|
|
const checkIp = async (ip) => {
|
|
const timestamp = Date.now();
|
|
// Ping with slightly higher timeout
|
|
let isAlive = false;
|
|
try {
|
|
const res = await ping.promise.probe(ip, { timeout: 2 });
|
|
isAlive = res.alive;
|
|
} catch (e) {
|
|
console.error(`Ping error ${ip}:`, e);
|
|
}
|
|
|
|
const currentResult = store.results[ip] || {};
|
|
let newResult = { ...currentResult, alive: isAlive, lastCheck: timestamp };
|
|
|
|
if (isAlive) {
|
|
// SNMP
|
|
// Try last successful community first
|
|
let community = currentResult.community;
|
|
let pdu = null;
|
|
|
|
if (community) {
|
|
try {
|
|
pdu = await getSnmpData(ip, community);
|
|
} catch (e) {
|
|
console.log(`[${ip}] Community '${community}' failed (${e.message}), trying others...`);
|
|
community = null; // Reset if failed
|
|
}
|
|
}
|
|
|
|
// If no community or failed, try all global communities
|
|
if (!community) {
|
|
console.log(`[${ip}] Probing ${store.communities.length} communities...`);
|
|
for (const c of store.communities) {
|
|
try {
|
|
pdu = await getSnmpData(ip, c);
|
|
community = c;
|
|
console.log(`[${ip}] Found new community: '${c}'`);
|
|
break;
|
|
} catch (e) {
|
|
console.log(`[${ip}] '${c}' failed: ${e.message}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pdu) {
|
|
newResult = { ...newResult, name: pdu.name, location: pdu.location, community: community };
|
|
} else {
|
|
console.log(`[${ip}] No valid community found (Alive: true).`);
|
|
}
|
|
}
|
|
|
|
store.results[ip] = newResult;
|
|
io.emit('update', { ip, data: newResult });
|
|
};
|
|
|
|
const monitorLoop = async () => {
|
|
console.log(`Starting monitoring cycle for ${store.ips.length} IPs using ${store.communities.length} communities...`);
|
|
|
|
// Process in batches to speed up (parallelism) but avoid network congestion
|
|
const BATCH_SIZE = 10;
|
|
for (let i = 0; i < store.ips.length; i += BATCH_SIZE) {
|
|
const batch = store.ips.slice(i, i + BATCH_SIZE);
|
|
await Promise.all(batch.map(ip => checkIp(ip)));
|
|
}
|
|
|
|
saveData();
|
|
console.log("Cycle finished.");
|
|
setTimeout(monitorLoop, 5000); // Run every 5 seconds
|
|
};
|
|
|
|
// API
|
|
app.get('/api/status', (req, res) => {
|
|
res.json({
|
|
ips: store.ips,
|
|
results: store.results,
|
|
communities: store.communities
|
|
});
|
|
});
|
|
|
|
app.post('/api/communities', (req, res) => {
|
|
const { communities } = req.body;
|
|
if (Array.isArray(communities)) {
|
|
store.communities = communities;
|
|
saveData();
|
|
res.json({ success: true });
|
|
} else {
|
|
res.status(400).json({ error: "Invalid format" });
|
|
}
|
|
});
|
|
|
|
app.post('/api/ips', (req, res) => {
|
|
const { ips } = req.body;
|
|
if (Array.isArray(ips)) {
|
|
// Sync results
|
|
store.ips = ips;
|
|
// Clean up old results
|
|
const newResults = {};
|
|
ips.forEach(ip => {
|
|
newResults[ip] = store.results[ip] || { alive: false, name: null, location: null, community: null, lastCheck: 0 };
|
|
});
|
|
store.results = newResults;
|
|
saveData();
|
|
res.json({ success: true });
|
|
} else {
|
|
res.status(400).json({ error: "Invalid format" });
|
|
}
|
|
});
|
|
|
|
const PORT = 3001;
|
|
server.listen(PORT, () => {
|
|
console.log(`Backend listening on port ${PORT}`);
|
|
monitorLoop();
|
|
});
|