Skip to main content
Glama
index.ts•13.6 kB
/** * IDS/IPS Plugin (Suricata) * * Manages Suricata IDS/IPS for threat detection and prevention */ import { BasePlugin } from '../../../core/plugin-system/base-plugin.js'; import { PluginCategory, PluginMetadata, MCPTool, MCPResource, MCPPrompt } from '../../../core/types/plugin.js'; import { EventType, EventSeverity } from '../../../core/types/events.js'; export default class IDSPlugin extends BasePlugin { readonly metadata: PluginMetadata = { id: 'security-ids', name: 'IDS/IPS Plugin (Suricata)', version: '1.0.0', description: 'Intrusion Detection and Prevention System using Suricata', category: PluginCategory.SECURITY, author: 'OPNsense MCP Team', enabled: true, }; private alertMonitorTimer?: NodeJS.Timeout; private alertCache = new Map<string, any>(); protected async onInitialize(): Promise<void> { this.logger.info('Initializing IDS/IPS Plugin'); } protected async onStart(): Promise<void> { this.logger.info('Starting IDS/IPS Plugin'); if (this.context.config.enableAlertMonitoring) { this.startAlertMonitoring(); } } protected async onStop(): Promise<void> { if (this.alertMonitorTimer) { clearInterval(this.alertMonitorTimer); } } getTools(): MCPTool[] { return [ { name: 'ids_get_status', description: 'Get IDS/IPS service status', inputSchema: { type: 'object', properties: {} }, handler: this.getStatus.bind(this), }, { name: 'ids_start', description: 'Start IDS/IPS service', inputSchema: { type: 'object', properties: {} }, handler: this.startService.bind(this), }, { name: 'ids_stop', description: 'Stop IDS/IPS service', inputSchema: { type: 'object', properties: {} }, handler: this.stopService.bind(this), }, { name: 'ids_restart', description: 'Restart IDS/IPS service', inputSchema: { type: 'object', properties: {} }, handler: this.restartService.bind(this), }, { name: 'ids_list_alerts', description: 'List recent IDS alerts', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number of alerts' }, severity: { type: 'string', enum: ['low', 'medium', 'high', 'critical'] }, category: { type: 'string', description: 'Alert category' }, }, }, handler: this.listAlerts.bind(this), }, { name: 'ids_get_alert', description: 'Get detailed alert information', inputSchema: { type: 'object', properties: { alertId: { type: 'string', description: 'Alert ID' }, }, required: ['alertId'], }, handler: this.getAlert.bind(this), }, { name: 'ids_update_rules', description: 'Update IDS/IPS rule sets', inputSchema: { type: 'object', properties: {} }, handler: this.updateRules.bind(this), }, { name: 'ids_list_rule_sets', description: 'List available rule sets', inputSchema: { type: 'object', properties: {} }, handler: this.listRuleSets.bind(this), }, { name: 'ids_enable_rule_set', description: 'Enable a rule set', inputSchema: { type: 'object', properties: { ruleSetId: { type: 'string' }, }, required: ['ruleSetId'], }, handler: this.enableRuleSet.bind(this), }, { name: 'ids_disable_rule_set', description: 'Disable a rule set', inputSchema: { type: 'object', properties: { ruleSetId: { type: 'string' }, }, required: ['ruleSetId'], }, handler: this.disableRuleSet.bind(this), }, { name: 'ids_get_statistics', description: 'Get IDS/IPS statistics', inputSchema: { type: 'object', properties: {} }, handler: this.getStatistics.bind(this), }, { name: 'ids_block_ip', description: 'Block an IP address detected by IDS', inputSchema: { type: 'object', properties: { ipAddress: { type: 'string', description: 'IP address to block' }, duration: { type: 'number', description: 'Block duration in seconds' }, }, required: ['ipAddress'], }, handler: this.blockIP.bind(this), }, ]; } getResources(): MCPResource[] { return [ { uri: 'security://ids/alerts', name: 'IDS Alerts', description: 'Recent IDS/IPS alerts', handler: async () => ({ content: JSON.stringify(await this.listAlerts({ limit: 100 }), null, 2), }), }, { uri: 'security://ids/statistics', name: 'IDS Statistics', description: 'IDS/IPS statistics and metrics', handler: async () => ({ content: JSON.stringify(await this.getStatistics({}), null, 2), }), }, ]; } getPrompts(): MCPPrompt[] { return [ { name: 'ids_analyze_alerts', description: 'Analyze recent IDS alerts for patterns', handler: async () => ({ messages: [ { role: 'user' as const, content: { type: 'text' as const, text: 'Analyze recent IDS alerts for attack patterns, trends, and recommended actions.', }, }, ], }), }, ]; } getDependencies(): string[] { return ['core-firewall']; } private async getStatus(params: {}): Promise<any> { try { const response = await this.api.get('/api/ids/service/status'); return { running: response.data?.running === 'true', enabled: response.data?.enabled === 'true', status: response.data, }; } catch (error) { this.logger.error('Error getting IDS status:', error); throw error; } } private async startService(params: {}): Promise<any> { try { const response = await this.api.post('/api/ids/service/start'); this.emit('service.started', { service: 'ids' }); return { success: true, message: 'IDS/IPS service started', status: response.data, }; } catch (error) { this.logger.error('Error starting IDS:', error); throw error; } } private async stopService(params: {}): Promise<any> { try { const response = await this.api.post('/api/ids/service/stop'); this.emit('service.stopped', { service: 'ids' }); return { success: true, message: 'IDS/IPS service stopped', status: response.data, }; } catch (error) { this.logger.error('Error stopping IDS:', error); throw error; } } private async restartService(params: {}): Promise<any> { try { const response = await this.api.post('/api/ids/service/restart'); this.emit('service.restarted', { service: 'ids' }); return { success: true, message: 'IDS/IPS service restarted', status: response.data, }; } catch (error) { this.logger.error('Error restarting IDS:', error); throw error; } } private async listAlerts(params: { limit?: number; severity?: string; category?: string }): Promise<any> { try { // In real implementation, this would call OPNsense IDS alerts API const alerts = Array.from(this.alertCache.values()); let filtered = alerts; if (params.severity) { filtered = filtered.filter(a => a.severity === params.severity); } if (params.category) { filtered = filtered.filter(a => a.category === params.category); } if (params.limit) { filtered = filtered.slice(0, params.limit); } return { alerts: filtered, count: filtered.length, total: alerts.length, }; } catch (error) { this.logger.error('Error listing alerts:', error); throw error; } } private async getAlert(params: { alertId: string }): Promise<any> { try { const alert = this.alertCache.get(params.alertId); if (!alert) { throw new Error(`Alert not found: ${params.alertId}`); } return alert; } catch (error) { this.logger.error(`Error getting alert ${params.alertId}:`, error); throw error; } } private async updateRules(params: {}): Promise<any> { try { const response = await this.api.post('/api/ids/service/updateRules'); this.emit('ids.rules.updated', { timestamp: new Date() }); return { success: true, message: 'IDS rules updated successfully', status: response.data, }; } catch (error) { this.logger.error('Error updating IDS rules:', error); throw error; } } private async listRuleSets(params: {}): Promise<any> { try { const response = await this.api.get('/api/ids/settings/searchInstalledRules'); return { ruleSets: response.data?.rows || [], count: response.data?.rowCount || 0, }; } catch (error) { this.logger.error('Error listing rule sets:', error); throw error; } } private async enableRuleSet(params: { ruleSetId: string }): Promise<any> { try { const response = await this.api.post(`/api/ids/settings/toggleRule/${params.ruleSetId}/1`); this.emit('ids.ruleset.enabled', { ruleSetId: params.ruleSetId }); return { success: true, message: `Rule set ${params.ruleSetId} enabled`, }; } catch (error) { this.logger.error(`Error enabling rule set ${params.ruleSetId}:`, error); throw error; } } private async disableRuleSet(params: { ruleSetId: string }): Promise<any> { try { const response = await this.api.post(`/api/ids/settings/toggleRule/${params.ruleSetId}/0`); this.emit('ids.ruleset.disabled', { ruleSetId: params.ruleSetId }); return { success: true, message: `Rule set ${params.ruleSetId} disabled`, }; } catch (error) { this.logger.error(`Error disabling rule set ${params.ruleSetId}:`, error); throw error; } } private async getStatistics(params: {}): Promise<any> { try { // Get statistics from cache and live data const alerts = await this.listAlerts({ limit: 1000 }); const stats = { totalAlerts: alerts.total, bySeverity: {} as Record<string, number>, byCategory: {} as Record<string, number>, topSourceIPs: [] as Array<{ ip: string; count: number }>, topDestIPs: [] as Array<{ ip: string; count: number }>, timestamp: new Date(), }; for (const alert of alerts.alerts) { stats.bySeverity[alert.severity] = (stats.bySeverity[alert.severity] || 0) + 1; stats.byCategory[alert.category] = (stats.byCategory[alert.category] || 0) + 1; } return stats; } catch (error) { this.logger.error('Error getting IDS statistics:', error); throw error; } } private async blockIP(params: { ipAddress: string; duration?: number }): Promise<any> { try { // Get firewall plugin to create blocking rule const firewallPlugin = this.context.getPlugin('core-firewall'); if (!firewallPlugin) { throw new Error('Firewall plugin not available'); } // Create blocking rule const tools = firewallPlugin.getTools(); const createRuleTool = tools.find(t => t.name === 'firewall_create_rule'); if (createRuleTool) { await createRuleTool.handler({ enabled: '1', action: 'block', interface: 'wan', direction: 'in', ipprotocol: 'inet', source_net: params.ipAddress, destination_net: 'any', description: `IDS Auto-block: ${params.ipAddress}`, log: '1', }); } this.emit('ids.ip.blocked', { ipAddress: params.ipAddress, duration: params.duration, timestamp: new Date(), }); return { success: true, message: `IP address ${params.ipAddress} blocked`, ipAddress: params.ipAddress, }; } catch (error) { this.logger.error(`Error blocking IP ${params.ipAddress}:`, error); throw error; } } private startAlertMonitoring(): void { const interval = this.context.config.monitorInterval || 30000; this.alertMonitorTimer = setInterval(async () => { try { // Simulate alert monitoring (in real impl, would poll IDS API) const stats = await this.getStatistics({}); this.context.eventBus.createEvent( 'ids.metrics.collected' as any, this.metadata.id, stats, EventSeverity.DEBUG, 'security' ); // Check for critical alerts if (stats.bySeverity.critical > 0) { this.context.eventBus.createEvent( EventType.IDS_ALERT, this.metadata.id, { severity: 'critical', count: stats.bySeverity.critical }, EventSeverity.CRITICAL, 'security' ); } } catch (error) { this.logger.error('Error in alert monitoring:', error); } }, interval); this.logger.info(`Started IDS alert monitoring (interval: ${interval}ms)`); } }

Latest Blog Posts

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