Skip to main content
Glama

OPNSense MCP Server

validate-nfs-connectivity.ts9.25 kB
#!/usr/bin/env tsx /** * NFS Connectivity Validation Script * Validates and tests NFS connectivity between DMZ and TrueNAS */ import { config } from 'dotenv'; import { OPNSenseAPIClient } from '../src/api/client.js'; import { FirewallRuleResource } from '../src/resources/firewall/rule.js'; // Load environment variables config(); // Network configuration const NETWORK_CONFIG = { DMZ: { interface: process.env.DMZ_INTERFACE || 'igc3_vlan6', network: '10.0.6.0/24', testNode: '10.0.6.2' }, TRUENAS: { ip: '10.0.0.14', nfsPath: '/mnt/tank/kubernetes' } }; class NFSValidator { private client: OPNSenseAPIClient; private firewall: FirewallRuleResource; constructor() { this.client = new OPNSenseAPIClient({ host: process.env.OPNSENSE_HOST!, apiKey: process.env.OPNSENSE_API_KEY!, apiSecret: process.env.OPNSENSE_API_SECRET!, verifySsl: false }); this.firewall = new FirewallRuleResource(this.client); } /** * Check existing NFS rules */ async checkExistingRules() { console.log('📋 Checking Existing NFS Rules'); console.log('================================\n'); const validation = await this.firewall.validateNFSConnectivity(); if (!validation.rulesExist) { console.log('❌ No NFS rules found!\n'); return false; } console.log(`✅ Found ${validation.details.nfsRules} NFS-related rules:\n`); validation.details.rules.forEach((rule: any, index: number) => { console.log(`Rule ${index + 1}: ${rule.description}`); console.log(` UUID: ${rule.uuid}`); console.log(` Interface: ${rule.interface}`); console.log(` Direction: IN`); console.log(` Protocol: ${rule.protocol}`); console.log(` Source: ${rule.source}`); console.log(` Destination: ${rule.destination}`); console.log(` Ports: ${rule.ports}`); console.log(` Status: ${rule.enabled ? '✅ Enabled' : '❌ Disabled'}`); console.log(''); }); return true; } /** * Create missing NFS rules */ async createMissingRules() { console.log('🔧 Creating NFS Rules'); console.log('======================\n'); const validation = await this.firewall.validateNFSConnectivity(); if (validation.rulesExist) { console.log('ℹ️ NFS rules already exist. Skipping creation.\n'); return; } console.log('Creating NFS connectivity rules...\n'); try { const rules = await this.firewall.createNFSRules({ interface: NETWORK_CONFIG.DMZ.interface, sourceNetwork: NETWORK_CONFIG.DMZ.network, truenasIP: NETWORK_CONFIG.TRUENAS.ip }); console.log('✅ NFS rules created successfully:'); console.log(` TCP Rule: ${rules.tcp}`); console.log(` UDP Rule: ${rules.udp}\n`); } catch (error) { console.error('❌ Failed to create NFS rules:', error); throw error; } } /** * Generate test commands */ generateTestCommands() { console.log('🧪 Test Commands'); console.log('=================\n'); console.log('Run these commands from the DMZ node to test NFS connectivity:\n'); console.log('1. Test basic connectivity:'); console.log(` ping ${NETWORK_CONFIG.TRUENAS.ip}\n`); console.log('2. Test RPC portmapper (port 111):'); console.log(` nc -zv ${NETWORK_CONFIG.TRUENAS.ip} 111`); console.log(` rpcinfo -p ${NETWORK_CONFIG.TRUENAS.ip}\n`); console.log('3. Test NFS port (2049):'); console.log(` nc -zv ${NETWORK_CONFIG.TRUENAS.ip} 2049\n`); console.log('4. List available NFS exports:'); console.log(` showmount -e ${NETWORK_CONFIG.TRUENAS.ip}\n`); console.log('5. Test NFS mount:'); console.log(` mkdir -p /mnt/test-nfs`); console.log(` mount -t nfs ${NETWORK_CONFIG.TRUENAS.ip}:${NETWORK_CONFIG.TRUENAS.nfsPath} /mnt/test-nfs`); console.log(` ls -la /mnt/test-nfs`); console.log(` umount /mnt/test-nfs\n`); console.log('6. For Kubernetes nodes, add to /etc/fstab:'); console.log(` ${NETWORK_CONFIG.TRUENAS.ip}:${NETWORK_CONFIG.TRUENAS.nfsPath} /mnt/nfs nfs defaults,_netdev 0 0\n`); } /** * Check firewall rule status */ async checkRuleStatus() { console.log('📊 Firewall Rule Status'); console.log('========================\n'); try { // Get all rules const allRules = await this.firewall.list(); console.log(`Total firewall rules: ${allRules.length}\n`); // Check DMZ interface rules const dmzRules = allRules.filter(r => r.interface === NETWORK_CONFIG.DMZ.interface || r.interface?.toLowerCase().includes('dmz') || r.interface?.includes('vlan6') ); console.log(`DMZ Interface (${NETWORK_CONFIG.DMZ.interface}) rules: ${dmzRules.length}`); if (dmzRules.length > 0) { console.log('\nDMZ Rules Summary:'); dmzRules.forEach(rule => { const status = rule.enabled === '1' ? '✅' : '❌'; console.log(` ${status} ${rule.action.toUpperCase()} ${rule.protocol} ${rule.source_net} -> ${rule.destination_net}:${rule.destination_port || 'any'}`); if (rule.description) { console.log(` "${rule.description}"`); } }); } // Check for potential issues console.log('\n🔍 Diagnostics:'); // Check if interface is recognized const options = await this.firewall.getOptions(); if (options?.interface?.values) { const validInterfaces = Object.keys(options.interface.values); const interfaceValid = validInterfaces.some(i => i === NETWORK_CONFIG.DMZ.interface || options.interface.values[i]?.value?.includes(NETWORK_CONFIG.DMZ.interface) ); console.log(` Interface "${NETWORK_CONFIG.DMZ.interface}" recognized: ${interfaceValid ? '✅' : '❌'}`); if (!interfaceValid) { console.log('\n ⚠️ Interface not recognized! Valid interfaces:'); validInterfaces.forEach(i => { console.log(` - ${i}: ${options.interface.values[i]?.value}`); }); } } // Check for blocking rules const blockingRules = allRules.filter(r => r.action === 'block' && r.enabled === '1' && (r.source_net === 'any' || r.source_net === NETWORK_CONFIG.DMZ.network) && (r.destination_net === 'any' || r.destination_net === NETWORK_CONFIG.TRUENAS.ip) ); if (blockingRules.length > 0) { console.log(`\n ⚠️ Found ${blockingRules.length} potentially blocking rules!`); blockingRules.forEach(rule => { console.log(` - ${rule.description || 'Unnamed rule'} (${rule.uuid})`); }); } } catch (error) { console.error('❌ Error checking rule status:', error); } } /** * Run full validation */ async runValidation() { console.log('🚀 NFS Connectivity Validation Tool'); console.log('===================================='); console.log(`OPNsense Host: ${process.env.OPNSENSE_HOST}`); console.log(`DMZ Interface: ${NETWORK_CONFIG.DMZ.interface}`); console.log(`DMZ Network: ${NETWORK_CONFIG.DMZ.network}`); console.log(`TrueNAS Server: ${NETWORK_CONFIG.TRUENAS.ip}`); console.log(`NFS Path: ${NETWORK_CONFIG.TRUENAS.nfsPath}\n`); // Check existing rules const hasRules = await this.checkExistingRules(); if (!hasRules) { // Prompt to create rules console.log('💡 Would you like to create the missing NFS rules?'); console.log(' Run with --create flag to automatically create rules.\n'); if (process.argv.includes('--create')) { await this.createMissingRules(); // Re-check after creation await this.checkExistingRules(); } } // Check overall status await this.checkRuleStatus(); // Generate test commands console.log(''); this.generateTestCommands(); // Final recommendations console.log('📝 Troubleshooting Tips'); console.log('========================\n'); console.log('If NFS mount fails after rules are in place:'); console.log('1. Check if rules are actually applied (not just created)'); console.log('2. Verify no higher-priority blocking rules exist'); console.log('3. Check TrueNAS NFS service is running'); console.log('4. Verify TrueNAS allows connections from DMZ network'); console.log('5. Check for any NAT rules affecting traffic'); console.log('6. Review OPNsense live firewall logs during connection attempt'); console.log('\nTo view live firewall logs:'); console.log(' OPNsense UI → System → Log Files → Live View → Firewall'); } } // Main execution async function main() { const validator = new NFSValidator(); await validator.runValidation(); } // Run if executed directly if (import.meta.url === `file://${process.argv[1]}`) { main().catch(error => { console.error('Fatal error:', error); process.exit(1); }); } export { NFSValidator };

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vespo92/OPNSenseMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server