#!/usr/bin/env node /** * Create firewall rule to allow 192.168.0.0/24 (UDM Pro default network) to access VLAN 11 * This fixes the "Destination Host Unreachable" issue when pinging 192.168.11.10 from 192.168.0.23 */ import { readFileSync } from 'fs'; import { join } from 'path'; import { homedir } from 'os'; // Load environment variables const envPath = join(homedir(), '.env'); function loadEnvFile(filePath) { try { const envFile = readFileSync(filePath, 'utf8'); const envVars = envFile.split('\n').filter( (line) => line.includes('=') && !line.trim().startsWith('#') ); for (const line of envVars) { const [key, ...values] = line.split('='); if (key && values.length > 0 && /^[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); } process.env[key.trim()] = value; } } return true; } catch { return false; } } loadEnvFile(envPath); const baseUrl = process.env.UNIFI_UDM_URL || 'https://192.168.0.1'; const apiKey = process.env.UNIFI_API_KEY; const siteId = '88f7af54-98f8-306a-a1c7-c9349722b1f6'; if (!apiKey) { console.error('❌ UNIFI_API_KEY not set in environment'); process.exit(1); } console.log('Creating Firewall Rule: Allow 192.168.0.0/24 → VLAN 11'); console.log('================================================================'); console.log(''); // Fetch networks async function fetchNetworks() { const response = await fetch(`${baseUrl}/proxy/network/integration/v1/sites/${siteId}/networks`, { headers: { 'X-API-KEY': apiKey, 'Accept': 'application/json', }, }); if (!response.ok) { throw new Error(`Failed to fetch networks: ${response.status} ${response.statusText}`); } const data = await response.json(); const networks = data.data || []; const vlanMap = {}; for (const net of networks) { const vlanId = net.vlanId; if (vlanId && vlanId > 1) { vlanMap[vlanId] = { id: net.id, name: net.name, subnet: net.ipSubnet, }; } } return vlanMap; } // Create ACL rule using IP address filter async function createACLRule(ruleConfig) { const { name, description, action, index, sourceIP, destNetworkId, protocolFilter } = ruleConfig; const rule = { type: 'IPV4', enabled: true, name, description, action, index, sourceFilter: sourceIP ? { type: 'IP_ADDRESSES_OR_SUBNETS', ipAddressesOrSubnets: [sourceIP] } : null, destinationFilter: destNetworkId ? { type: 'NETWORKS', networkIds: [destNetworkId] } : null, protocolFilter: protocolFilter || null, enforcingDeviceFilter: null, }; const response = await fetch(`${baseUrl}/proxy/network/integration/v1/sites/${siteId}/acl-rules`, { method: 'POST', headers: { 'X-API-KEY': apiKey, 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify(rule), }); const responseText = await response.text(); let responseData; try { responseData = JSON.parse(responseText); } catch { responseData = responseText; } if (response.ok) { return { success: true, data: responseData }; } else { return { success: false, error: responseData, status: response.status }; } } // Main function async function main() { try { console.log('Fetching network IDs...'); const vlanMap = await fetchNetworks(); const vlan11Network = vlanMap[11]; if (!vlan11Network) { console.error('❌ VLAN 11 (MGMT-LAN) not found'); process.exit(1); } console.log(`✅ Found VLAN 11 (MGMT-LAN): ${vlan11Network.name}`); console.log(` Network ID: ${vlan11Network.id}`); console.log(` Subnet: ${vlan11Network.subnet}`); console.log(''); // Create rule to allow 192.168.0.0/24 → VLAN 11 console.log('Creating firewall rule...'); console.log(''); const ruleConfig = { name: 'Allow Default Network to Management VLAN', description: 'Allow 192.168.0.0/24 (UDM Pro default network) to access VLAN 11 (MGMT-LAN)', action: 'ALLOW', index: 5, // Higher priority than service VLAN rules sourceIP: '192.168.0.0/24', destNetworkId: vlan11Network.id, protocolFilter: null, // Allow all protocols (ICMP, TCP, UDP) }; console.log(`Rule: ${ruleConfig.name}`); console.log(`Source: ${ruleConfig.sourceIP}`); console.log(`Destination: VLAN 11 (${vlan11Network.name})`); console.log(`Protocol: All`); console.log(''); const result = await createACLRule(ruleConfig); if (result.success) { console.log('✅ Rule created successfully!'); console.log(''); console.log('This rule allows devices on 192.168.0.0/24 to access VLAN 11 (192.168.11.0/24)'); console.log('You should now be able to ping 192.168.11.10 from 192.168.0.23'); } else { console.log(`❌ Failed to create rule (HTTP ${result.status})`); if (result.error && typeof result.error === 'object') { console.log(`Error: ${JSON.stringify(result.error, null, 2)}`); } else { console.log(`Error: ${result.error}`); } process.exit(1); } } catch (error) { console.error('❌ Error:', error.message); if (error.stack) { console.error(error.stack); } process.exit(1); } } main();