search_rules
Search firewall rules by target, action, or status using Firewalla syntax to manage network security policies and identify specific configurations.
Instructions
Search firewall rules by target, action or status. Supports all rule fields.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Search query using Firewalla syntax. Supported fields: action:allow/block/timelimit, target.type:domain/ip/device, target.value:*.facebook.com, status:active/paused, direction:bidirection/inbound/outbound, protocol:tcp/udp, gid:box_id, scope.type:device/network, notes:"description text". Examples: "action:block AND target.value:*.social.com", "status:paused", "target.type:domain AND action:block" |
Implementation Reference
- src/tools/handlers/search.ts:941-1107 (handler)The SearchRulesHandler class that implements the core logic for the 'search_rules' tool. Handles input validation using validateCommonSearchParameters, calls the Firewalla search_rules API via searchTools, processes NetworkRule results into standardized format, creates search metadata, and returns a unified ToolResponse.export class SearchRulesHandler extends BaseToolHandler { name = 'search_rules'; description = `Firewall rule searching with comprehensive filtering for actions, targets, and status. Search through firewall rules to manage policies, troubleshoot blocking issues, and analyze rule effectiveness. QUERY EXAMPLES: - Action filtering: "action:block", "action:allow", "action:timelimit" - Target searches: "target_value:*.facebook.com", "target_type:domain", "target_value:192.168.*" - Status queries: "enabled:true", "paused:false", "active:true" - Direction: "direction:inbound", "direction:outbound", "direction:bidirection" - Combined filters: "action:block AND target_value:*.social.* AND enabled:true" RULE MANAGEMENT EXAMPLES: - Social media blocks: "action:block AND (target_value:*.facebook.com OR target_value:*.twitter.com)" - Gaming restrictions: "action:timelimit AND target_category:gaming" - Security rules: "action:block AND target_type:malware_domain" - Active blocking rules: "action:block AND enabled:true AND paused:false" TROUBLESHOOTING: - Find conflicting rules: "target_value:example.com" (then check different actions) - Identify inactive rules: "enabled:false OR paused:true" - Review recent changes: "modified:>=yesterday" PERFORMANCE NOTES: - Rules are cached for 10 minutes for optimal performance - Use specific target_value searches for fastest results - Group by action or target_type for rule analysis For rule management operations, see pause_rule and resume_rule tools.`; category = 'search' as const; constructor() { // Enable field normalization for firewall rules (no geographic enrichment needed) super({ enableGeoEnrichment: false, // Firewall rules don't typically contain IP addresses enableFieldNormalization: true, // Ensure consistent snake_case field naming across all responses additionalMeta: { data_source: 'rules', entity_type: 'firewall_rules', supports_geographic_enrichment: false, supports_field_normalization: true, standardization_version: '2.0.0', }, }); } async execute( args: ToolArgs, firewalla: FirewallaClient ): Promise<ToolResponse> { const searchArgs = args as SearchRulesArgs; const startTime = Date.now(); try { // Validate common search parameters const validation = validateCommonSearchParameters( searchArgs, this.name, 'rules' ); if (!validation.isValid) { return validation.response; } const searchTools = createSearchTools(firewalla); const searchParams: SearchParams = { query: searchArgs.query, limit: searchArgs.limit, offset: searchArgs.offset, cursor: searchArgs.cursor, sort_by: searchArgs.sort_by, sort_order: searchArgs.sort_order, group_by: searchArgs.group_by, aggregate: searchArgs.aggregate, }; const result = await withToolTimeout( async () => searchTools.search_rules(searchParams), this.name ); const executionTime = Date.now() - startTime; // Process rule data const processedRules = SafeAccess.safeArrayMap( (result as any).results, (rule: NetworkRule) => ({ id: SafeAccess.getNestedValue(rule as any, 'id', 'unknown'), action: SafeAccess.getNestedValue(rule as any, 'action', 'unknown'), target_type: SafeAccess.getNestedValue( rule as any, 'target.type', 'unknown' ), target_value: SafeAccess.getNestedValue( rule as any, 'target.value', 'unknown' ), direction: SafeAccess.getNestedValue( rule as any, 'direction', 'unknown' ), status: SafeAccess.getNestedValue(rule as any, 'status', 'unknown'), hit_count: SafeAccess.getNestedValue(rule as any, 'hit.count', 0), }) ); // Create metadata for standardized response const metadata: SearchMetadata = { query: SafeAccess.getNestedValue( result as any, 'query', searchArgs.query || '' ) as string, entityType: 'rules', executionTime: SafeAccess.getNestedValue( result as any, 'execution_time_ms', executionTime ) as number, cached: false, cursor: (result as any).next_cursor, hasMore: !!(result as any).next_cursor, limit: searchArgs.limit, aggregations: SafeAccess.getNestedValue( result as any, 'aggregations', null ) as Record<string, any> | undefined, }; // Create unified response with standardized metadata const unifiedResponseData = { rules: processedRules, metadata, query_info: { original_query: searchArgs.query, applied_filters: { grouping: !!searchArgs.group_by, sorting: !!searchArgs.sort_by, aggregation: !!searchArgs.aggregate, }, }, }; // Return unified response return this.createUnifiedResponse(unifiedResponseData, { executionTimeMs: executionTime, }); } catch (error: unknown) { if (error instanceof TimeoutError) { return createTimeoutErrorResponse(this.name, error.duration, 10000); } const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred'; return createErrorResponse( this.name, `Failed to search rules: ${errorMessage}`, ErrorType.SEARCH_ERROR ); } } }
- src/server.ts:509-522 (schema)MCP tool schema definition for 'search_rules' including inputSchema with query parameter description and validation rules, registered in the server tools list.name: 'search_rules', description: 'Search firewall rules by target, action or status. Supports all rule fields.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query using Firewalla syntax. Supported fields: action:allow/block/timelimit, target.type:domain/ip/device, target.value:*.facebook.com, status:active/paused, direction:bidirection/inbound/outbound, protocol:tcp/udp, gid:box_id, scope.type:device/network, notes:"description text". Examples: "action:block AND target.value:*.social.com", "status:paused", "target.type:domain AND action:block"', }, }, required: [], },
- src/tools/registry.ts:158-158 (registration)Registration of the SearchRulesHandler instance in the central ToolRegistry during automatic handler registration in the constructor.this.register(new SearchRulesHandler());
- src/tools/handlers/search.ts:83-83 (schema)TypeScript interface defining the input arguments for SearchRulesHandler, extending BaseSearchArgs which includes query, limit, offset, cursor, sort_by, etc.export interface SearchRulesArgs extends BaseSearchArgs {}
- src/tools/handlers/search.ts:155-304 (helper)Shared validation helper function used by all search handlers including search_rules for parameter validation, query syntax checking, field validation, and limit enforcement.function validateCommonSearchParameters( args: BaseSearchArgs, toolName: string, entityType: 'flows' | 'alarms' | 'rules' | 'devices' | 'target_lists' ): CommonSearchValidationResult { // Validate optional limit parameter with default const limitValidation = ParameterValidator.validateNumber( args.limit, 'limit', { required: false, defaultValue: 200, ...getLimitValidationConfig(toolName), } ); if (!limitValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Parameter validation failed', ErrorType.VALIDATION_ERROR, undefined, limitValidation.errors ), }; } // Validate required query parameter const queryValidation = ParameterValidator.validateRequiredString( args.query, 'query' ); if (!queryValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Query parameter validation failed', ErrorType.VALIDATION_ERROR, undefined, queryValidation.errors ), }; } // Validate query syntax const querySyntaxValidation = validateFirewallaQuerySyntax(args.query); if (!querySyntaxValidation.isValid) { const examples = getExampleQueries(entityType); return { isValid: false, response: createErrorResponse( toolName, 'Invalid query syntax', ErrorType.VALIDATION_ERROR, { query: args.query, syntax_errors: querySyntaxValidation.errors, examples: examples.slice(0, 3), hint: 'Use field:value syntax with logical operators (AND, OR, NOT)', }, querySyntaxValidation.errors ), }; } // Validate field names in the query const fieldValidation = QuerySanitizer.validateQueryFields( args.query, entityType ); if (!fieldValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Query contains invalid field names', ErrorType.VALIDATION_ERROR, { query: args.query, documentation: entityType === 'alarms' ? 'See /docs/error-handling-guide.md for troubleshooting' : 'See /docs/query-syntax-guide.md for valid field names', }, fieldValidation.errors ), }; } // Validate cursor format if provided if (args.cursor !== undefined) { const cursorValidation = ParameterValidator.validateCursor( args.cursor, 'cursor' ); if (!cursorValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Invalid cursor format', ErrorType.VALIDATION_ERROR, undefined, cursorValidation.errors ), }; } } // Validate group_by parameter if provided if (args.group_by !== undefined) { const groupByValidation = ParameterValidator.validateEnum( args.group_by, 'group_by', SEARCH_FIELDS[entityType], false ); if (!groupByValidation.isValid) { return { isValid: false, response: createErrorResponse( toolName, 'Invalid group_by field', ErrorType.VALIDATION_ERROR, { group_by: args.group_by, valid_fields: SEARCH_FIELDS[entityType], documentation: 'See /docs/query-syntax-guide.md for valid fields', }, groupByValidation.errors ), }; } } return { isValid: true, limit: args.limit, query: args.query, cursor: args.cursor, groupBy: args.group_by, }; }