Complete markdown files cleanup and organization
- Organized 252 files across project - Root directory: 187 → 2 files (98.9% reduction) - Moved configuration guides to docs/04-configuration/ - Moved troubleshooting guides to docs/09-troubleshooting/ - Moved quick start guides to docs/01-getting-started/ - Moved reports to reports/ directory - Archived temporary files - Generated comprehensive reports and documentation - Created maintenance scripts and guides All files organized according to established standards.
This commit is contained in:
389
scripts/query-omada-cloud-firewall-blockscout.js
Executable file
389
scripts/query-omada-cloud-firewall-blockscout.js
Executable file
@@ -0,0 +1,389 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Query Omada Cloud Controller firewall rules for Blockscout access
|
||||
* Uses cloud controller API if credentials are available
|
||||
*/
|
||||
|
||||
import https from 'https';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { homedir } from 'os';
|
||||
|
||||
const BLOCKSCOUT_IP = '192.168.11.140';
|
||||
const BLOCKSCOUT_PORT = '80';
|
||||
|
||||
// Load environment variables
|
||||
const envPath = join(homedir(), '.env');
|
||||
let envVars = {};
|
||||
|
||||
try {
|
||||
const envFile = readFileSync(envPath, 'utf8');
|
||||
envFile.split('\n').forEach(line => {
|
||||
if (line.includes('=') && !line.trim().startsWith('#')) {
|
||||
const [key, ...values] = line.split('=');
|
||||
if (key && /^[A-Z_][A-Z0-9_]*$/.test(key.trim())) {
|
||||
let value = values.join('=').trim();
|
||||
if ((value.startsWith('"') && value.endsWith('"')) ||
|
||||
(value.startsWith("'") && value.endsWith("'"))) {
|
||||
value = value.slice(1, -1);
|
||||
}
|
||||
envVars[key.trim()] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error loading .env file:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Try to detect cloud controller URL
|
||||
// Omada Cloud Controller typically uses: https://controller.tplinkcloud.com or specific domain
|
||||
const cloudControllerUrl = envVars.OMADA_CLOUD_CONTROLLER_URL ||
|
||||
envVars.OMADA_CONTROLLER_URL ||
|
||||
envVars.OMADA_CONTROLLER_BASE_URL ||
|
||||
'https://192.168.11.8:8043'; // Fallback to local
|
||||
|
||||
// Check if this is a cloud URL (contains tplinkcloud.com or is not a local IP)
|
||||
const isCloudController = cloudControllerUrl.includes('tplinkcloud.com') ||
|
||||
cloudControllerUrl.includes('cloud') ||
|
||||
(!cloudControllerUrl.match(/^https?:\/\/192\.168\./) &&
|
||||
!cloudControllerUrl.match(/^https?:\/\/10\./) &&
|
||||
!cloudControllerUrl.match(/^https?:\/\/172\.(1[6-9]|2[0-9]|3[01])\./));
|
||||
|
||||
const username = envVars.OMADA_ADMIN_USERNAME || envVars.OMADA_API_KEY || envVars.OMADA_CLIENT_ID;
|
||||
const password = envVars.OMADA_ADMIN_PASSWORD || envVars.OMADA_API_SECRET || envVars.OMADA_CLIENT_SECRET;
|
||||
const siteId = envVars.OMADA_SITE_ID || '090862bebcb1997bb263eea9364957fe';
|
||||
const verifySSL = envVars.OMADA_VERIFY_SSL !== 'false';
|
||||
|
||||
if (!username || !password) {
|
||||
console.error('Error: Missing credentials');
|
||||
console.error('Required: OMADA_ADMIN_USERNAME/OMADA_API_KEY and OMADA_ADMIN_PASSWORD/OMADA_API_SECRET');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Parse base URL
|
||||
const urlObj = new URL(cloudControllerUrl);
|
||||
const hostname = urlObj.hostname;
|
||||
const port = urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80);
|
||||
|
||||
console.log('════════════════════════════════════════');
|
||||
console.log('Omada Firewall Rules Check for Blockscout');
|
||||
console.log(isCloudController ? '(Cloud Controller)' : '(Local Controller)');
|
||||
console.log('════════════════════════════════════════');
|
||||
console.log('');
|
||||
console.log(`Controller URL: ${cloudControllerUrl}`);
|
||||
console.log(`Controller Type: ${isCloudController ? 'Cloud' : 'Local'}`);
|
||||
console.log(`Site ID: ${siteId}`);
|
||||
console.log(`Blockscout IP: ${BLOCKSCOUT_IP}`);
|
||||
console.log(`Blockscout Port: ${BLOCKSCOUT_PORT}`);
|
||||
console.log('');
|
||||
|
||||
// Create HTTPS agent
|
||||
const agent = new https.Agent({
|
||||
rejectUnauthorized: verifySSL,
|
||||
});
|
||||
|
||||
// Function to make API request
|
||||
function apiRequest(method, path, data = null, token = null, cookies = null) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = {
|
||||
hostname,
|
||||
port,
|
||||
path,
|
||||
method,
|
||||
agent,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
};
|
||||
|
||||
if (token) {
|
||||
options.headers['Csrf-Token'] = token;
|
||||
}
|
||||
|
||||
if (cookies) {
|
||||
options.headers['Cookie'] = cookies;
|
||||
}
|
||||
|
||||
const req = https.request(options, (res) => {
|
||||
let body = '';
|
||||
res.on('data', (chunk) => {
|
||||
body += chunk;
|
||||
});
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const json = JSON.parse(body);
|
||||
resolve(json);
|
||||
} catch (e) {
|
||||
resolve({ raw: body, statusCode: res.statusCode, headers: res.headers });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
|
||||
if (data) {
|
||||
req.write(JSON.stringify(data));
|
||||
}
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log('1. Authenticating to Omada Controller...');
|
||||
|
||||
// Try login endpoint
|
||||
let loginResponse;
|
||||
try {
|
||||
loginResponse = await apiRequest('POST', '/api/v2/login', {
|
||||
username,
|
||||
password,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(` ✗ Login failed: ${error.message}`);
|
||||
console.error('');
|
||||
console.error('Note: Cloud controllers may use different authentication endpoints.');
|
||||
console.error('Please check Omada Controller documentation for cloud API endpoints.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (loginResponse.errorCode !== 0) {
|
||||
console.error(` ✗ Login failed: ${loginResponse.msg || 'Unknown error'}`);
|
||||
console.error(` Error Code: ${loginResponse.errorCode}`);
|
||||
|
||||
// If cloud controller, suggest alternative authentication
|
||||
if (isCloudController) {
|
||||
console.error('');
|
||||
console.error('Cloud Controller Authentication Notes:');
|
||||
console.error(' - Cloud controllers may require different authentication');
|
||||
console.error(' - May need to use OAuth token endpoint instead of /api/v2/login');
|
||||
console.error(' - Check Omada Cloud Controller documentation');
|
||||
}
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const token = loginResponse.result?.token || loginResponse.token;
|
||||
if (!token) {
|
||||
console.error(' ✗ No token received');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(' ✓ Login successful');
|
||||
console.log('');
|
||||
|
||||
// Build cookie string for subsequent requests
|
||||
const cookies = `TOKEN=${token}`;
|
||||
const effectiveSiteId = siteId;
|
||||
|
||||
console.log(`2. Querying firewall rules for site: ${effectiveSiteId}...`);
|
||||
console.log('');
|
||||
|
||||
// Try multiple endpoint paths for firewall rules
|
||||
const endpointPaths = [
|
||||
`/api/v2/sites/${effectiveSiteId}/firewall/rules`,
|
||||
`/sites/${effectiveSiteId}/firewall/rules`,
|
||||
`/api/firewall/rules?siteId=${effectiveSiteId}`,
|
||||
`/api/v2/firewall/rules?siteId=${effectiveSiteId}`,
|
||||
];
|
||||
|
||||
let rulesResponse;
|
||||
let rulesFound = false;
|
||||
|
||||
for (const path of endpointPaths) {
|
||||
try {
|
||||
rulesResponse = await apiRequest('GET', path, null, token, cookies);
|
||||
|
||||
// Check if we got a valid response
|
||||
if (rulesResponse.errorCode === 0 && Array.isArray(rulesResponse.result)) {
|
||||
rulesFound = true;
|
||||
break;
|
||||
} else if (Array.isArray(rulesResponse)) {
|
||||
rulesResponse = { errorCode: 0, result: rulesResponse };
|
||||
rulesFound = true;
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rulesFound) {
|
||||
console.error(` ✗ Could not query firewall rules via API`);
|
||||
console.error('');
|
||||
console.error('Note: Firewall rules may need to be checked via Omada Controller web interface:');
|
||||
console.error(` ${cloudControllerUrl}`);
|
||||
console.error(' Navigate to: Settings → Firewall → Firewall Rules');
|
||||
console.error('');
|
||||
console.error('Or firewall rules API may not be available for this controller type.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const rules = Array.isArray(rulesResponse.result) ? rulesResponse.result : [];
|
||||
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 ||
|
||||
(typeof rule.dstIp === 'string' && rule.dstIp.includes('192.168.11')) ||
|
||||
rule.dstIp === '192.168.11.0/24';
|
||||
|
||||
const affectsPort80 =
|
||||
!rule.dstPort ||
|
||||
rule.dstPort === BLOCKSCOUT_PORT ||
|
||||
(typeof rule.dstPort === 'string' && 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('════════════════════════════════════════');
|
||||
console.log(`🔍 Found ${relevantRules.length} rule(s) that might affect Blockscout:`);
|
||||
console.log('════════════════════════════════════════');
|
||||
console.log('');
|
||||
|
||||
relevantRules.forEach((rule, index) => {
|
||||
console.log(`Rule ${index + 1}: ${rule.name || rule.id || 'Unnamed'}`);
|
||||
console.log(` ID: ${rule.id || 'N/A'}`);
|
||||
console.log(` Enabled: ${rule.enable ? 'Yes ✓' : 'No ✗'}`);
|
||||
console.log(` Action: ${rule.action || 'N/A'}`);
|
||||
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 !== undefined ? 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('');
|
||||
console.log('✅ Recommended Action:');
|
||||
console.log(' Create an allow rule in Omada Controller with HIGH priority:');
|
||||
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 (above deny rules)');
|
||||
console.log('');
|
||||
} else if (allowRules.length > 0 && denyRules.length > 0) {
|
||||
const highestAllowPriority = Math.max(...allowRules.map((r) => r.priority || 0));
|
||||
const lowestDenyPriority = Math.min(...denyRules.map((r) => r.priority || 9999));
|
||||
|
||||
if (highestAllowPriority < lowestDenyPriority) {
|
||||
console.log('✅ Priority order looks correct (allow rules above deny rules).');
|
||||
} else {
|
||||
console.log('❌ Issue: Some deny rules have higher priority than allow rules.');
|
||||
console.log(' Adjust rule priority so allow rules are 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('════════════════════════════════════════');
|
||||
console.log('ℹ️ No firewall rules found that specifically target Blockscout.');
|
||||
console.log('════════════════════════════════════════');
|
||||
console.log('');
|
||||
|
||||
// Check for deny rules
|
||||
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 in total:`);
|
||||
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 IP: ${rule.dstIp}`);
|
||||
if (rule.dstPort) console.log(` Dest Port: ${rule.dstPort}`);
|
||||
});
|
||||
if (denyRules.length > 10) {
|
||||
console.log(` ... and ${denyRules.length - 10} more`);
|
||||
}
|
||||
console.log('');
|
||||
}
|
||||
|
||||
console.log('✅ Recommendation:');
|
||||
console.log(' Create an explicit allow rule to ensure Blockscout access.');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Show all rules summary
|
||||
console.log('════════════════════════════════════════');
|
||||
console.log('All Firewall Rules Summary');
|
||||
console.log('════════════════════════════════════════');
|
||||
console.log('');
|
||||
|
||||
const enabledRules = rules.filter((r) => r.enable);
|
||||
const allowCount = enabledRules.filter((r) => r.action === 'allow').length;
|
||||
const denyCount = enabledRules.filter((r) => r.action === 'deny' || r.action === 'reject').length;
|
||||
|
||||
console.log(`Total Rules: ${rules.length}`);
|
||||
console.log(` Enabled: ${enabledRules.length}`);
|
||||
console.log(` Allow Actions: ${allowCount}`);
|
||||
console.log(` Deny/Reject Actions: ${denyCount}`);
|
||||
console.log('');
|
||||
|
||||
console.log('════════════════════════════════════════');
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ Error:');
|
||||
console.error('');
|
||||
if (error.message) {
|
||||
console.error(` ${error.message}`);
|
||||
} else {
|
||||
console.error(' ', error);
|
||||
}
|
||||
if (error.stack) {
|
||||
console.error('');
|
||||
console.error('Stack trace:');
|
||||
console.error(error.stack);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
Reference in New Issue
Block a user