Skip to main content
Glama

OPNSense MCP Server

interfaces.ts12.6 kB
// Interface Configuration Resource Implementation // Manages OPNsense network interface settings including VLAN routing configuration import { OPNSenseAPIClient } from '../../api/client.js'; export interface InterfaceConfig { uuid?: string; name?: string; descr?: string; device?: string; enable?: string; // '1' or '0' ipaddr?: string; subnet?: string; gateway?: string; spoofmac?: string; mtu?: string; media?: string; mediaopt?: string; // Inter-VLAN routing related settings blockpriv?: string; // '0' to allow private networks (RFC1918) blockbogons?: string; // '0' to allow bogons disableftpproxy?: string; // VLAN specific vlan?: string; vlanpcp?: string; if?: string; // Parent interface for VLANs } export interface InterfaceOverview { name: string; device: string; status: string; ipaddr?: string; subnet?: string; gateway?: string; media?: string; statistics?: { packets_in: number; packets_out: number; bytes_in: number; bytes_out: number; errors_in: number; errors_out: number; }; } export class InterfaceConfigResource { private client: OPNSenseAPIClient; private debugMode: boolean = process.env.MCP_DEBUG === 'true' || process.env.DEBUG_INTERFACES === 'true'; private interfaceCache: Map<string, InterfaceConfig> = new Map(); constructor(client: OPNSenseAPIClient) { this.client = client; } /** * List all interfaces with their overview */ async listOverview(): Promise<InterfaceOverview[]> { if (this.debugMode) { console.log('[InterfaceConfig] Getting interface overview'); } try { const response = await this.client.get('/interfaces/overview/list'); if (this.debugMode) { console.log('[InterfaceConfig] Overview response:', { isArray: Array.isArray(response), hasRows: !!response?.rows, keys: response ? Object.keys(response) : [] }); } // Handle different response formats if (Array.isArray(response)) { return response; } if (response?.rows && Array.isArray(response.rows)) { return response.rows; } // Convert object format to array if (response && typeof response === 'object') { return Object.entries(response).map(([name, config]: [string, any]) => ({ name, ...config })); } } catch (error) { console.error('Error listing interface overview:', error); } return []; } /** * Get detailed configuration for a specific interface */ async getInterfaceConfig(interfaceName: string): Promise<InterfaceConfig | null> { if (this.debugMode) { console.log(`[InterfaceConfig] Getting config for interface: ${interfaceName}`); } try { // Try multiple endpoints const endpoints = [ `/interfaces/settings/get/${interfaceName}`, `/interfaces/${interfaceName}/get`, `/interfaces/vlan_settings/getItem/${interfaceName}` ]; for (const endpoint of endpoints) { try { const response = await this.client.get(endpoint); if (this.debugMode) { console.log(`[InterfaceConfig] ${endpoint} response:`, { hasInterface: !!response?.interface, hasSettings: !!response?.settings, keys: Object.keys(response || {}) }); } const config = response?.interface || response?.settings || response; if (config && typeof config === 'object') { // Cache the configuration this.interfaceCache.set(interfaceName, config); return config; } } catch (error) { if (this.debugMode) { console.log(`[InterfaceConfig] ${endpoint} failed:`, error); } } } } catch (error) { console.error(`Error getting interface config for ${interfaceName}:`, error); } return null; } /** * Update interface configuration */ async updateInterfaceConfig(interfaceName: string, config: Partial<InterfaceConfig>): Promise<boolean> { if (this.debugMode) { console.log(`[InterfaceConfig] Updating interface ${interfaceName}:`, config); } try { // Try multiple endpoints const endpoints = [ { path: `/interfaces/settings/set/${interfaceName}`, wrapper: 'interface' }, { path: `/interfaces/${interfaceName}/set`, wrapper: 'settings' }, { path: `/interfaces/vlan_settings/setItem/${interfaceName}`, wrapper: 'vlan' } ]; for (const endpoint of endpoints) { try { const payload = endpoint.wrapper ? { [endpoint.wrapper]: config } : config; const response = await this.client.post(endpoint.path, payload); if (this.debugMode) { console.log(`[InterfaceConfig] ${endpoint.path} response:`, response); } if (response?.result === 'saved' || response?.status === 'ok') { // Apply the changes await this.applyChanges(); // Update cache this.interfaceCache.set(interfaceName, { ...this.interfaceCache.get(interfaceName), ...config }); return true; } } catch (error) { if (this.debugMode) { console.log(`[InterfaceConfig] ${endpoint.path} failed:`, error); } } } } catch (error) { console.error(`Error updating interface ${interfaceName}:`, error); } return false; } /** * Enable inter-VLAN routing on a specific interface * This removes the "Block private networks" and "Block bogons" settings */ async enableInterVLANRoutingOnInterface(interfaceName: string): Promise<boolean> { console.log(`[InterfaceConfig] Enabling inter-VLAN routing on ${interfaceName}...`); try { // Get current configuration const currentConfig = await this.getInterfaceConfig(interfaceName); if (!currentConfig) { console.error(`Interface ${interfaceName} not found`); return false; } if (this.debugMode) { console.log('[InterfaceConfig] Current interface config:', { name: interfaceName, blockpriv: currentConfig.blockpriv, blockbogons: currentConfig.blockbogons }); } // Update settings to enable inter-VLAN routing const updatedConfig: Partial<InterfaceConfig> = { blockpriv: '0', // Don't block private networks (RFC1918) blockbogons: '0' // Don't block bogons }; const success = await this.updateInterfaceConfig(interfaceName, updatedConfig); if (success) { console.log(`[InterfaceConfig] Inter-VLAN routing enabled on ${interfaceName}`); } else { console.log(`[InterfaceConfig] Failed to enable inter-VLAN routing on ${interfaceName}`); } return success; } catch (error) { console.error(`Error enabling inter-VLAN routing on ${interfaceName}:`, error); return false; } } /** * Enable inter-VLAN routing on all interfaces */ async enableInterVLANRoutingOnAllInterfaces(): Promise<{ success: boolean; details: any[] }> { console.log('[InterfaceConfig] Enabling inter-VLAN routing on all interfaces...'); const results: any[] = []; const interfaces = await this.listOverview(); for (const iface of interfaces) { const result = { interface: iface.name, success: false, message: '' }; try { const success = await this.enableInterVLANRoutingOnInterface(iface.name); result.success = success; result.message = success ? 'Enabled' : 'Failed'; } catch (error: any) { result.message = error.message || 'Unknown error'; } results.push(result); } const allSuccess = results.every(r => r.success); return { success: allSuccess, details: results }; } /** * Find interface by IP subnet */ async findInterfaceBySubnet(subnet: string): Promise<InterfaceOverview | null> { const interfaces = await this.listOverview(); for (const iface of interfaces) { if (iface.ipaddr && iface.subnet) { const ifaceNetwork = `${iface.ipaddr.split('.').slice(0, 3).join('.')}.0/${iface.subnet}`; if (ifaceNetwork === subnet || iface.ipaddr.startsWith(subnet.split('/')[0].split('.').slice(0, 3).join('.'))) { return iface; } } } return null; } /** * Configure DMZ interface for inter-VLAN routing */ async configureDMZInterface(dmzInterface: string = 'opt8'): Promise<boolean> { console.log(`[InterfaceConfig] Configuring DMZ interface ${dmzInterface} for inter-VLAN routing...`); try { // Enable inter-VLAN routing on DMZ interface const success = await this.enableInterVLANRoutingOnInterface(dmzInterface); if (success) { // Additional DMZ-specific configuration if needed const dmzConfig: Partial<InterfaceConfig> = { enable: '1', // Ensure interface is enabled blockpriv: '0', // Allow private networks blockbogons: '0', // Allow bogons disableftpproxy: '1' // Disable FTP proxy for better routing }; await this.updateInterfaceConfig(dmzInterface, dmzConfig); } return success; } catch (error) { console.error(`Error configuring DMZ interface ${dmzInterface}:`, error); return false; } } /** * Apply interface changes */ async applyChanges(): Promise<void> { if (this.debugMode) { console.log('[InterfaceConfig] Applying interface changes'); } const applyEndpoints = [ '/interfaces/reconfigure', '/interfaces/vlan_settings/reconfigure' ]; for (const endpoint of applyEndpoints) { try { await this.client.post(endpoint); if (this.debugMode) { console.log(`[InterfaceConfig] Applied changes via ${endpoint}`); } } catch (error) { if (this.debugMode) { console.log(`[InterfaceConfig] ${endpoint} failed:`, error); } } } // Add delay for changes to propagate await new Promise(resolve => setTimeout(resolve, 1000)); } /** * Debug method to discover interface endpoints */ async debugDiscoverEndpoints(): Promise<void> { console.log('\n[InterfaceConfig] Discovering interface endpoints...'); const testEndpoints = [ '/interfaces/overview/list', '/interfaces/overview/status', '/interfaces/settings/get', '/interfaces/lan/get', '/interfaces/wan/get', '/interfaces/opt1/get', '/interfaces/opt8/get', '/interfaces/vlan_settings/get', '/interfaces/vlan_settings/searchItem' ]; for (const endpoint of testEndpoints) { try { const response = await this.client.get(endpoint); console.log(`\n${endpoint}:`); console.log(' Success - Response structure:', { isArray: Array.isArray(response), keys: Object.keys(response || {}).slice(0, 10), hasRows: !!response?.rows, rowCount: response?.rows?.length }); // Check for interface-specific settings if (response && typeof response === 'object') { const interfaces = Array.isArray(response) ? response : response.rows ? response.rows : [response]; for (const iface of interfaces.slice(0, 2)) { if (iface.blockpriv !== undefined || iface.blockbogons !== undefined) { console.log(' Found interface settings:', { name: iface.name || iface.descr, blockpriv: iface.blockpriv, blockbogons: iface.blockbogons }); } } } } catch (error: any) { console.log(`\n${endpoint}:`); console.log(' Failed:', error?.message || error); } } } /** * Get interface statistics */ async getInterfaceStatistics(interfaceName: string): Promise<any> { try { const response = await this.client.get(`/interfaces/overview/getInterface/${interfaceName}`); return response?.statistics || response; } catch (error) { console.error(`Error getting statistics for ${interfaceName}:`, error); return null; } } } export default InterfaceConfigResource;

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