Files
proxmox/scripts/query-omada-firewall-blockscout.js

271 lines
9.7 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* Query Omada Controller firewall rules for Blockscout access
* Uses direct API calls with admin credentials
*/
import dotenv from 'dotenv';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Load environment variables
dotenv.config({ path: join(__dirname, '..', '.env') });
const BLOCKSCOUT_IP = '192.168.11.140';
const BLOCKSCOUT_PORT = '80';
// Get configuration from environment
const controllerUrl = process.env.OMADA_CONTROLLER_URL || process.env.OMADA_CONTROLLER_BASE_URL || 'https://192.168.11.8:8043';
const username = process.env.OMADA_ADMIN_USERNAME || process.env.OMADA_API_KEY || process.env.OMADA_CLIENT_ID;
const password = process.env.OMADA_ADMIN_PASSWORD || process.env.OMADA_API_SECRET || process.env.OMADA_CLIENT_SECRET;
const siteId = process.env.OMADA_SITE_ID || '090862bebcb1997bb263eea9364957fe';
const verifySSL = process.env.OMADA_VERIFY_SSL !== 'false';
// Disable SSL verification if needed
if (!verifySSL) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
}
async function login() {
const url = `${controllerUrl}/api/v2/login`;
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: username,
password: password,
}),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Login failed: ${response.status} ${response.statusText} - ${errorText}`);
}
const data = await response.json();
if (data.errorCode !== 0) {
throw new Error(`Login failed: ${data.msg || 'Unknown error'}`);
}
const token = data.result?.token || data.token;
if (!token) {
throw new Error('No token received from server');
}
return token;
}
async function requestWithToken(token, endpoint, method = 'GET', body = null) {
const url = `${controllerUrl}${endpoint}`;
const options = {
method,
headers: {
'Content-Type': 'application/json',
'Csrf-Token': token,
'Cookie': `TOKEN=${token}`,
},
};
if (body) {
options.body = JSON.stringify(body);
}
const response = await fetch(url, options);
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API request failed: ${response.status} ${response.statusText} - ${errorText}`);
}
const data = await response.json();
if (data.errorCode !== 0) {
throw new Error(`API error: ${data.msg || 'Unknown error'}`);
}
return data.result || data;
}
async function main() {
console.log('════════════════════════════════════════');
console.log('Omada Firewall Rules Check for Blockscout');
console.log('════════════════════════════════════════');
console.log('');
console.log(`Controller: ${controllerUrl}`);
console.log(`Site ID: ${siteId}`);
console.log(`Blockscout IP: ${BLOCKSCOUT_IP}`);
console.log(`Blockscout Port: ${BLOCKSCOUT_PORT}`);
console.log('');
if (!username || !password) {
console.error('❌ Missing Omada credentials in .env file');
console.error('');
console.error('Required environment variables:');
console.error(' OMADA_ADMIN_USERNAME (or OMADA_API_KEY/OMADA_CLIENT_ID)');
console.error(' OMADA_ADMIN_PASSWORD (or OMADA_API_SECRET/OMADA_CLIENT_SECRET)');
console.error('');
console.error('Optional:');
console.error(' OMADA_CONTROLLER_URL (default: https://192.168.11.8:8043)');
console.error(' OMADA_SITE_ID (default: auto-detect)');
process.exit(1);
}
try {
console.log('Authenticating to Omada Controller...');
const token = await login();
console.log('✓ Authentication successful');
console.log('');
console.log('Fetching firewall rules...');
const rules = await requestWithToken(token, `/api/v2/sites/${siteId}/firewall/rules`);
console.log(`✓ Found ${rules.length} firewall rules`);
console.log('');
// Filter rules that might affect Blockscout
const relevantRules = rules.filter((rule) => {
const affectsBlockscoutIP =
!rule.dstIp ||
rule.dstIp === BLOCKSCOUT_IP ||
rule.dstIp.includes(BLOCKSCOUT_IP.split('.').slice(0, 3).join('.')) ||
rule.dstIp === '192.168.11.0/24' ||
rule.dstIp === '192.168.11.0/255.255.255.0';
const affectsPort80 =
!rule.dstPort ||
rule.dstPort === BLOCKSCOUT_PORT ||
rule.dstPort.includes(BLOCKSCOUT_PORT) ||
rule.dstPort === 'all' ||
rule.dstPort === '0-65535';
const isTCP =
!rule.protocol ||
rule.protocol === 'tcp' ||
rule.protocol === 'tcp/udp' ||
rule.protocol === 'all';
return rule.enable && (affectsBlockscoutIP || affectsPort80) && isTCP;
});
if (relevantRules.length > 0) {
console.log(`🔍 Found ${relevantRules.length} rule(s) that might affect Blockscout:`);
console.log('');
relevantRules.forEach((rule) => {
console.log(`Rule: ${rule.name || rule.id}`);
console.log(` ID: ${rule.id}`);
console.log(` Enabled: ${rule.enable ? 'Yes ✓' : 'No ✗'}`);
console.log(` Action: ${rule.action}`);
console.log(` Direction: ${rule.direction || 'N/A'}`);
console.log(` Protocol: ${rule.protocol || 'all'}`);
console.log(` Source IP: ${rule.srcIp || 'Any'}`);
console.log(` Source Port: ${rule.srcPort || 'Any'}`);
console.log(` Destination IP: ${rule.dstIp || 'Any'}`);
console.log(` Destination Port: ${rule.dstPort || 'Any'}`);
console.log(` Priority: ${rule.priority || 'N/A'}`);
console.log('');
if (rule.action === 'deny' || rule.action === 'reject') {
console.log(' ⚠️ WARNING: This rule BLOCKS traffic!');
console.log('');
}
});
// Separate allow and deny rules
const allowRules = relevantRules.filter((rule) => rule.action === 'allow');
const denyRules = relevantRules.filter((rule) => rule.action === 'deny' || rule.action === 'reject');
console.log('════════════════════════════════════════');
console.log('Analysis');
console.log('════════════════════════════════════════');
console.log('');
if (denyRules.length > 0 && allowRules.length === 0) {
console.log('❌ Issue Found:');
console.log(' Deny rules exist that block Blockscout, but no allow rules found.');
console.log(' This explains the "No route to host" error.');
console.log('');
} else if (allowRules.length > 0 && denyRules.length > 0) {
console.log('⚠️ Both allow and deny rules exist.');
console.log(' Check rule priority - allow rules must be above deny rules.');
console.log('');
} else if (allowRules.length > 0) {
console.log('✅ Allow rules exist for Blockscout.');
console.log(' If issues persist, check rule priority or default policies.');
console.log('');
}
} else {
console.log(' No firewall rules found that specifically target Blockscout.');
console.log('');
console.log('Checking all deny/reject rules...');
console.log('');
const denyRules = rules.filter(
(rule) => rule.enable && (rule.action === 'deny' || rule.action === 'reject')
);
if (denyRules.length > 0) {
console.log(`⚠️ Found ${denyRules.length} deny/reject rules:`);
console.log('');
denyRules.slice(0, 10).forEach((rule) => {
console.log(` - ${rule.name || rule.id} (Priority: ${rule.priority || 'N/A'})`);
if (rule.dstIp) console.log(` Dest: ${rule.dstIp}`);
if (rule.dstPort) console.log(` Port: ${rule.dstPort}`);
});
if (denyRules.length > 10) {
console.log(` ... and ${denyRules.length - 10} more`);
}
console.log('');
}
}
console.log('════════════════════════════════════════');
console.log('Recommendations');
console.log('════════════════════════════════════════');
console.log('');
if (relevantRules.length === 0 || relevantRules.filter(r => r.action === 'allow').length === 0) {
console.log('✅ Recommended Action:');
console.log(' Create an allow rule in Omada Controller:');
console.log('');
console.log(' Name: Allow Internal to Blockscout HTTP');
console.log(' Enable: Yes');
console.log(' Action: Allow');
console.log(' Direction: Forward');
console.log(' Protocol: TCP');
console.log(' Source IP: 192.168.11.0/24 (or leave blank for Any)');
console.log(' Destination IP: 192.168.11.140');
console.log(' Destination Port: 80');
console.log(' Priority: High (ensure it\'s above any deny rules)');
console.log('');
console.log(' Then apply the configuration.');
console.log('');
}
console.log('════════════════════════════════════════');
} catch (error) {
console.error('❌ Error:');
console.error('');
if (error.message) {
console.error(` ${error.message}`);
} else {
console.error(' ', error);
}
console.error('');
process.exit(1);
}
}
main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});