CrackedRuby CrackedRuby

Overview

Network firewalls function as barrier devices between trusted internal networks and untrusted external networks, making decisions about which traffic to allow or block based on configured rule sets. The firewall examines each network packet and applies rules to determine whether the packet should pass through, be rejected, or be dropped silently.

Firewalls operate at various layers of the OSI model, from basic packet filtering at the network layer to deep packet inspection at the application layer. The placement of a firewall within network architecture determines which traffic flows it can control and what level of protection it provides.

A firewall ruleset defines the security policy, specifying which source addresses, destination addresses, ports, and protocols are permitted or denied. Rules execute in order, and the first matching rule determines the packet's fate. This ordering requirement makes firewall configuration both powerful and error-prone.

Modern network infrastructure relies on firewalls as a fundamental security control, but firewalls alone cannot provide complete protection. They work alongside intrusion detection systems, application security controls, and network segmentation strategies to create defense in depth.

[Internet] ---> [Firewall] ---> [Internal Network]
                    |
                    | Rule Evaluation:
                    | 1. Check source IP
                    | 2. Check destination IP
                    | 3. Check port/protocol
                    | 4. Apply first matching rule
                    |    - ACCEPT
                    |    - REJECT
                    |    - DROP

Key Principles

Network firewalls implement several core filtering mechanisms that determine how traffic gets processed. Packet filtering examines individual packets in isolation, checking header information against rules without maintaining connection state. This stateless approach offers high performance but limited security context.

Stateful inspection tracks the state of network connections, maintaining a connection table that records established sessions. When a packet arrives, the firewall checks whether it belongs to an existing connection or attempts to initiate a new one. This state awareness allows the firewall to permit return traffic for outbound connections without explicit rules and detect invalid packet sequences that might indicate attacks.

Connection tracking maintains records with source address, source port, destination address, destination port, protocol type, connection state, and sequence numbers. The firewall updates these records as packets flow, transitioning connections through states like NEW, ESTABLISHED, RELATED, and INVALID.

Application layer filtering inspects packet payloads to understand application protocols. Instead of just checking that traffic uses port 80, an application firewall verifies that the traffic actually contains valid HTTP and can block specific HTTP methods, examine URLs, or filter based on content types. This deep packet inspection enables more precise control but requires more processing resources.

Default policies determine how the firewall handles traffic that matches no explicit rules. A default-deny policy blocks everything unless explicitly permitted, providing security by default. A default-allow policy permits everything unless explicitly blocked, offering convenience but weaker security. Default-deny with explicit allow rules represents the standard security approach.

Network Address Translation (NAT) often integrates with firewall functionality, translating private internal addresses to public external addresses. This translation obscures internal network structure while conserving public IP addresses. NAT configurations include source NAT (SNAT) for outbound traffic, destination NAT (DNAT) for inbound traffic, and port forwarding for service exposure.

Zone-based firewalls segment networks into security zones with different trust levels. Traffic between zones requires explicit policy definitions, while traffic within a zone may flow freely or face different rules. Common zones include untrusted (Internet), DMZ (public services), and trusted (internal network).

# Conceptual firewall rule structure
class FirewallRule
  attr_reader :source, :destination, :port, :protocol, :action
  
  def initialize(source:, destination:, port:, protocol:, action:)
    @source = source
    @destination = destination
    @port = port
    @protocol = protocol
    @action = action # :accept, :reject, :drop
  end
  
  def matches?(packet)
    ip_matches?(packet.source_ip, @source) &&
      ip_matches?(packet.dest_ip, @destination) &&
      port_matches?(packet.dest_port, @port) &&
      @protocol == packet.protocol
  end
  
  private
  
  def ip_matches?(ip, pattern)
    return true if pattern == :any
    return true if pattern.include?('/') && ip_in_cidr?(ip, pattern)
    ip == pattern
  end
  
  def port_matches?(port, pattern)
    return true if pattern == :any
    return true if pattern.is_a?(Range) && pattern.include?(port)
    port == pattern
  end
end

Security Implications

Firewall rule ordering creates critical security vulnerabilities when misconfigured. Since firewalls apply the first matching rule, an overly permissive rule early in the ruleset can bypass more restrictive rules below it. A common mistake places a broad allow rule before specific deny rules, effectively nullifying the security policy.

Outbound filtering prevents compromised internal systems from communicating with external command and control servers or exfiltrating data. Many organizations focus on inbound filtering while neglecting outbound rules, allowing malware to operate freely once inside the perimeter. Restrictive outbound policies limit which internal systems can initiate external connections and to which destinations.

Logging and monitoring transform firewalls from passive filters into security intelligence sources. Dropped packets indicate potential attacks, policy violations, or misconfigurations. Connection logs reveal traffic patterns, identify unused rules, and provide forensic evidence. Without adequate logging, security teams operate blind to network threats.

Firewall evasion techniques exploit weaknesses in rule configurations or filtering mechanisms. Fragmentation attacks split malicious packets across multiple fragments that individually pass filters but reconstruct into attacks. Protocol tunneling encapsulates prohibited protocols inside permitted ones, such as tunneling SSH over HTTP. Application layer attacks use valid protocols to deliver malicious payloads that network firewalls cannot detect.

Denial of service protection requires careful firewall configuration. SYN flood attacks consume connection table resources by initiating thousands of incomplete TCP handshakes. Rate limiting rules can mitigate these attacks but must balance protection against legitimate traffic degradation. Connection limits per source IP address prevent individual attackers from exhausting firewall resources.

Egress filtering validates that outbound packets have source addresses from the internal network's address space, preventing IP spoofing attacks originating from compromised internal systems. This configuration protects both the organization's reputation and helps prevent participation in distributed attacks.

Network segmentation uses internal firewalls to isolate sensitive systems from general network traffic. Database servers, payment systems, and other critical infrastructure should exist in protected network segments with strict firewall rules controlling access. Lateral movement attacks become more difficult when internal firewalls restrict communication between segments.

# Firewall rule validation for security issues
class FirewallRuleValidator
  def validate_ruleset(rules)
    issues = []
    
    # Check for overly permissive rules before specific ones
    rules.each_with_index do |rule, index|
      if overly_permissive?(rule)
        subsequent_blocked = rules[(index + 1)..-1].any? { |r| r.action == :drop }
        if subsequent_blocked
          issues << {
            severity: :high,
            rule_index: index,
            message: "Permissive rule may bypass subsequent deny rules"
          }
        end
      end
    end
    
    # Check for missing outbound filtering
    has_outbound_rules = rules.any? { |r| r.direction == :outbound }
    unless has_outbound_rules
      issues << {
        severity: :medium,
        message: "No outbound filtering rules detected"
      }
    end
    
    # Check for default deny policy
    last_rule = rules.last
    unless last_rule.action == :drop && last_rule.matches_all?
      issues << {
        severity: :high,
        message: "Missing default deny policy"
      }
    end
    
    issues
  end
  
  private
  
  def overly_permissive?(rule)
    rule.action == :accept &&
      rule.source == :any &&
      rule.destination == :any
  end
end

Firewall management interfaces require strong authentication and encryption. Administrative access to firewall configuration represents a critical security control point. Weak credentials, unencrypted management protocols, or exposed management interfaces enable attackers to disable protection or modify rules. Multi-factor authentication and IP-based access restrictions limit management access to authorized administrators only.

Implementation Approaches

Host-based firewalls run on individual servers and workstations, filtering traffic specific to that system. Operating systems include built-in firewall capabilities that applications can configure through system APIs. Host-based firewalls provide defense in depth by protecting systems even when network firewalls fail or when systems move between networks.

Network-based firewalls operate as dedicated devices or services positioned at network boundaries. These firewalls protect multiple systems simultaneously and provide centralized policy management. Network appliances handle high traffic volumes and offer features like hardware acceleration, while software firewalls run on general-purpose servers with more flexibility but potentially lower performance.

Cloud-based firewalls integrate with cloud provider infrastructure, offering elastic scaling and integration with cloud-native services. Security groups in AWS define firewall rules for EC2 instances, while network ACLs provide subnet-level filtering. Cloud firewalls automatically scale with application load and integrate with infrastructure-as-code deployment practices.

Distributed firewall architectures push filtering capabilities to hypervisors or network switches, enabling micro-segmentation where individual workloads have dedicated firewall policies regardless of physical network location. This approach supports dynamic environments where systems frequently move between physical hosts while maintaining consistent security policies.

Next-generation firewalls combine traditional packet filtering with intrusion prevention, application identification, SSL inspection, and threat intelligence integration. These unified threat management devices provide multiple security functions in a single platform but introduce complexity and potential performance bottlenecks when all features activate simultaneously.

# Host-based firewall management interface
module HostFirewall
  class Manager
    def initialize(backend: detect_backend)
      @backend = backend
    end
    
    def add_rule(rule)
      case @backend
      when :iptables
        add_iptables_rule(rule)
      when :nftables
        add_nftables_rule(rule)
      when :pf
        add_pf_rule(rule)
      else
        raise "Unsupported firewall backend: #{@backend}"
      end
    end
    
    def list_rules
      case @backend
      when :iptables
        parse_iptables_output
      when :nftables
        parse_nftables_output
      else
        raise "Unsupported firewall backend: #{@backend}"
      end
    end
    
    private
    
    def detect_backend
      return :iptables if system('which iptables > /dev/null 2>&1')
      return :nftables if system('which nft > /dev/null 2>&1')
      return :pf if system('which pfctl > /dev/null 2>&1')
      raise "No supported firewall backend found"
    end
    
    def add_iptables_rule(rule)
      chain = rule.direction == :inbound ? 'INPUT' : 'OUTPUT'
      cmd = "iptables -A #{chain}"
      cmd += " -s #{rule.source}" unless rule.source == :any
      cmd += " -d #{rule.destination}" unless rule.destination == :any
      cmd += " -p #{rule.protocol}"
      cmd += " --dport #{rule.port}" unless rule.port == :any
      cmd += " -j #{rule.action.to_s.upcase}"
      
      system(cmd)
    end
  end
end

Web application firewalls (WAF) specialize in protecting HTTP/HTTPS applications by understanding web protocols and common attack patterns. WAFs inspect HTTP requests and responses, blocking SQL injection, cross-site scripting, and other application-layer attacks that network firewalls cannot detect. WAFs deploy as reverse proxies, load balancer plugins, or cloud services.

Container firewalls enforce network policies for containerized applications, integrating with orchestration platforms like Kubernetes. These firewalls understand container networking models and can apply policies based on container labels, namespaces, or service identities rather than just IP addresses. As containers dynamically start and stop, the firewall automatically updates rules.

Ruby Implementation

Ruby applications interact with host firewalls through system commands or higher-level abstractions. Direct execution of firewall commands requires appropriate permissions, typically root access on Unix-like systems. Production applications rarely modify firewall rules directly, but configuration management tools and deployment scripts often manage firewall state.

# Wrapper for iptables commands
class IptablesManager
  class Error < StandardError; end
  
  def initialize
    verify_iptables_available
  end
  
  def allow_port(port, protocol: 'tcp', source: nil)
    rule = "-A INPUT -p #{protocol} --dport #{port}"
    rule += " -s #{source}" if source
    rule += " -j ACCEPT"
    
    execute_rule(rule)
  end
  
  def block_ip(ip_address)
    rule = "-A INPUT -s #{ip_address} -j DROP"
    execute_rule(rule)
  end
  
  def list_rules(chain: 'INPUT')
    output = `iptables -L #{chain} -n --line-numbers 2>&1`
    raise Error, "Failed to list rules: #{output}" unless $?.success?
    
    parse_iptables_list(output)
  end
  
  def save_rules(file_path)
    output = `iptables-save > #{file_path} 2>&1`
    raise Error, "Failed to save rules: #{output}" unless $?.success?
  end
  
  def restore_rules(file_path)
    output = `iptables-restore < #{file_path} 2>&1`
    raise Error, "Failed to restore rules: #{output}" unless $?.success?
  end
  
  private
  
  def verify_iptables_available
    unless system('which iptables > /dev/null 2>&1')
      raise Error, "iptables not found in system PATH"
    end
  end
  
  def execute_rule(rule)
    output = `iptables #{rule} 2>&1`
    raise Error, "Rule failed: #{output}" unless $?.success?
  end
  
  def parse_iptables_list(output)
    lines = output.split("\n").drop(2) # Skip header lines
    lines.map do |line|
      parse_rule_line(line)
    end.compact
  end
  
  def parse_rule_line(line)
    parts = line.split(/\s+/)
    return nil if parts.empty?
    
    {
      num: parts[0].to_i,
      target: parts[1],
      protocol: parts[2],
      source: parts[4],
      destination: parts[5]
    }
  end
end

# Usage
firewall = IptablesManager.new
firewall.allow_port(443, protocol: 'tcp')
firewall.block_ip('192.168.1.100')
rules = firewall.list_rules

Ruby HTTP clients must handle firewall-related connectivity failures gracefully. Connection timeouts indicate that firewalls silently dropped packets, while connection refused errors suggest the destination system actively rejected the connection. Applications should implement retry logic with exponential backoff for transient firewall or network issues.

require 'net/http'
require 'uri'

class FirewallAwareHttpClient
  class FirewallBlockedError < StandardError; end
  
  MAX_RETRIES = 3
  INITIAL_TIMEOUT = 5
  
  def get(url, retries: 0)
    uri = URI.parse(url)
    
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = (uri.scheme == 'https')
    http.open_timeout = INITIAL_TIMEOUT * (2 ** retries)
    http.read_timeout = INITIAL_TIMEOUT * (2 ** retries)
    
    request = Net::HTTP::Get.new(uri.request_uri)
    response = http.request(request)
    
    response
  rescue Net::OpenTimeout, Net::ReadTimeout => e
    if retries < MAX_RETRIES
      sleep(2 ** retries)
      get(url, retries: retries + 1)
    else
      raise FirewallBlockedError, "Connection timed out after #{MAX_RETRIES} retries. " \
                                   "Possible firewall blocking access to #{uri.host}:#{uri.port}"
    end
  rescue Errno::ECONNREFUSED => e
    raise FirewallBlockedError, "Connection refused to #{uri.host}:#{uri.port}. " \
                                 "Firewall or service may be blocking access"
  rescue SocketError => e
    raise FirewallBlockedError, "DNS resolution failed for #{uri.host}. " \
                                 "DNS traffic may be blocked by firewall"
  end
end

Cloud provider SDKs offer Ruby libraries for managing cloud-based firewalls. AWS security groups, Azure network security groups, and Google Cloud firewall rules all have Ruby APIs for programmatic configuration.

require 'aws-sdk-ec2'

class AwsSecurityGroupManager
  def initialize(region: 'us-east-1')
    @ec2 = Aws::EC2::Client.new(region: region)
  end
  
  def create_security_group(name:, description:, vpc_id:)
    response = @ec2.create_security_group({
      group_name: name,
      description: description,
      vpc_id: vpc_id
    })
    
    response.group_id
  end
  
  def authorize_ingress(group_id:, port:, protocol: 'tcp', cidr: '0.0.0.0/0')
    @ec2.authorize_security_group_ingress({
      group_id: group_id,
      ip_permissions: [{
        ip_protocol: protocol,
        from_port: port,
        to_port: port,
        ip_ranges: [{ cidr_ip: cidr }]
      }]
    })
  end
  
  def authorize_from_security_group(group_id:, source_group_id:, port:, protocol: 'tcp')
    @ec2.authorize_security_group_ingress({
      group_id: group_id,
      ip_permissions: [{
        ip_protocol: protocol,
        from_port: port,
        to_port: port,
        user_id_group_pairs: [{ group_id: source_group_id }]
      }]
    })
  end
  
  def list_rules(group_id:)
    response = @ec2.describe_security_groups({
      group_ids: [group_id]
    })
    
    group = response.security_groups.first
    {
      ingress: group.ip_permissions,
      egress: group.ip_permissions_egress
    }
  end
  
  def revoke_ingress(group_id:, ip_permission:)
    @ec2.revoke_security_group_ingress({
      group_id: group_id,
      ip_permissions: [ip_permission]
    })
  end
end

# Usage
manager = AwsSecurityGroupManager.new(region: 'us-west-2')
sg_id = manager.create_security_group(
  name: 'web-servers',
  description: 'Security group for web servers',
  vpc_id: 'vpc-12345678'
)

manager.authorize_ingress(
  group_id: sg_id,
  port: 443,
  protocol: 'tcp',
  cidr: '0.0.0.0/0'
)

manager.authorize_ingress(
  group_id: sg_id,
  port: 80,
  protocol: 'tcp',
  cidr: '0.0.0.0/0'
)

Network socket programming in Ruby respects firewall rules automatically. When firewalls block traffic, socket operations raise exceptions that applications must handle. Testing network code requires considering firewall scenarios and implementing appropriate error handling.

require 'socket'

class FirewallAwareTcpClient
  def connect(host, port, timeout: 10)
    addr = Socket.getaddrinfo(host, nil)
    sockaddr = Socket.pack_sockaddr_in(port, addr[0][3])
    
    socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
    socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, [timeout, 0].pack('l_2'))
    socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, [timeout, 0].pack('l_2'))
    
    begin
      socket.connect_nonblock(sockaddr)
    rescue IO::WaitWritable
      if IO.select(nil, [socket], nil, timeout)
        begin
          socket.connect_nonblock(sockaddr)
        rescue Errno::EISCONN
          # Connected successfully
        end
      else
        socket.close
        raise Errno::ETIMEDOUT, "Connection timeout - firewall may be dropping packets"
      end
    end
    
    socket
  rescue Errno::ECONNREFUSED
    raise "Connection refused - firewall or service blocking port #{port}"
  rescue Errno::EHOSTUNREACH
    raise "Host unreachable - network or firewall routing issue"
  rescue SocketError => e
    raise "Socket error: #{e.message} - possible DNS or firewall issue"
  end
end

Tools & Ecosystem

iptables provides the classic Linux firewall interface, organizing rules into tables (filter, nat, mangle, raw) and chains (INPUT, OUTPUT, FORWARD). The filter table handles packet filtering decisions, while the nat table manages network address translation. iptables commands modify kernel netfilter rules immediately without requiring service restarts.

# Common iptables patterns
iptables -A INPUT -p tcp --dport 22 -j ACCEPT      # Allow SSH
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT      # Allow HTTP
iptables -A INPUT -j DROP                           # Default deny
iptables-save > /etc/iptables/rules.v4             # Persist rules

nftables replaces iptables with improved syntax, better performance, and simplified configuration. The nft command provides a unified interface for IPv4, IPv6, and bridge filtering. nftables uses a more intuitive rule syntax and atomic rule replacement, avoiding the ordering complexities of iptables modifications.

# nftables equivalent configuration
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input tcp dport 22 accept
nft add rule inet filter input tcp dport 80 accept

firewalld provides a dynamic firewall daemon with D-Bus interface, commonly used on Red Hat and Fedora systems. firewalld introduces zones for different network trust levels and services for common port configurations. Changes take effect immediately without dropping existing connections.

ufw (Uncomplicated Firewall) simplifies iptables management on Ubuntu and Debian systems. The ufw command offers straightforward syntax for common firewall tasks while maintaining iptables as the underlying implementation. ufw profiles define service-specific rules that applications can install.

Windows Firewall provides host-based filtering on Windows systems with separate profiles for domain, private, and public networks. PowerShell cmdlets enable programmatic configuration, while Group Policy allows centralized management in Active Directory environments.

pf (Packet Filter) serves as the firewall system for OpenBSD, FreeBSD, and macOS. The pf.conf configuration file defines rules using clear syntax with strong performance characteristics. pf includes advanced features like adaptive state timeouts and traffic shaping.

cloud-firewall-manager represents a category of tools for managing firewall rules across cloud providers. These tools abstract provider-specific APIs and enable infrastructure-as-code approaches to firewall configuration. Popular tools include Terraform, CloudFormation, and provider-specific CLI utilities.

Firewall testing tools verify that firewall rules work as intended. nmap scans ports to determine which services appear open or filtered. hping3 crafts custom packets for testing specific firewall behaviors. netcat (nc) establishes simple TCP/UDP connections for connectivity testing.

# Ruby wrapper for common firewall testing operations
class FirewallTester
  def port_open?(host, port, timeout: 5)
    begin
      socket = Socket.tcp(host, port, connect_timeout: timeout)
      socket.close
      true
    rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ETIMEDOUT
      false
    end
  end
  
  def scan_ports(host, ports)
    results = {}
    ports.each do |port|
      results[port] = port_open?(host, port)
    end
    results
  end
  
  def test_connectivity(host, port)
    start_time = Time.now
    
    begin
      socket = Socket.tcp(host, port, connect_timeout: 10)
      elapsed = Time.now - start_time
      socket.close
      
      { status: :open, time: elapsed }
    rescue Errno::ECONNREFUSED
      { status: :filtered_rejected, time: Time.now - start_time }
    rescue Errno::ETIMEDOUT
      { status: :filtered_dropped, time: Time.now - start_time }
    rescue => e
      { status: :error, message: e.message }
    end
  end
end

# Usage
tester = FirewallTester.new
result = tester.test_connectivity('example.com', 443)
# => {:status=>:open, :time=>0.234}

Configuration management tools like Ansible, Chef, and Puppet include modules for managing firewall rules across server fleets. These tools ensure consistent firewall configuration and integrate with version control for audit trails and change management.

Common Pitfalls

Rule order mistakes create security vulnerabilities when administrators add rules without considering existing rule precedence. A common error places a specific deny rule after a broad allow rule, resulting in the deny rule never executing. Firewall rule processors stop at the first match, making bottom-to-top rule review critical.

# Dangerous rule ordering
rules = [
  { source: 'any', destination: 'any', port: 'any', action: :accept },  # Too broad!
  { source: '192.168.1.100', destination: 'any', port: 22, action: :drop }  # Never reached
]

# Correct rule ordering  
rules = [
  { source: '192.168.1.100', destination: 'any', port: 22, action: :drop },
  { source: 'any', destination: 'any', port: 22, action: :accept },
  { source: 'any', destination: 'any', port: 'any', action: :drop }  # Default deny
]

Return traffic blocking occurs when administrators configure strict inbound rules without accounting for established connections. Blocking all inbound traffic prevents responses to legitimate outbound requests. Stateful firewalls solve this with connection tracking, but configuration must explicitly allow established connections.

Service disruption from firewall changes happens when administrators modify production firewall rules without testing. Adding a deny rule that matches critical traffic immediately breaks services. Safe firewall management requires change windows, rollback procedures, and pre-production testing environments that mirror production firewall configurations.

Logging configuration oversights result in missing security events or excessive log volume. Logging every accepted packet overwhelms log storage and analysis systems, while logging no dropped packets hides attack attempts. Selective logging of denied traffic, new connections, and suspicious patterns provides security value without overwhelming infrastructure.

Forgotten rules accumulate as services change and systems decommission. Old allow rules for decommissioned services create unnecessary attack surface. Regular firewall audits compare active rules against current service inventory, removing rules for non-existent systems.

ICMP filtering that blocks all ICMP traffic breaks network diagnostics and path MTU discovery. While blocking some ICMP types makes sense, completely blocking ICMP causes connection failures for services that rely on ICMP error messages. Path MTU discovery failures result in silent connection hangs that are difficult to diagnose.

IPv6 configuration neglect leaves systems vulnerable when administrators configure only IPv4 firewall rules. Systems with IPv6 enabled but no IPv6 firewall rules allow unrestricted IPv6 traffic. Comprehensive firewall configurations must address both IP versions or explicitly disable IPv6.

class FirewallConfigAuditor
  def audit_rules(rules)
    issues = []
    
    issues.concat(check_rule_ordering(rules))
    issues.concat(check_stateful_rules(rules))
    issues.concat(check_icmp_handling(rules))
    issues.concat(check_ipv6_coverage(rules))
    issues.concat(check_default_policy(rules))
    
    issues
  end
  
  private
  
  def check_rule_ordering(rules)
    issues = []
    
    rules.each_with_index do |rule, idx|
      if overly_permissive?(rule)
        subsequent_denies = rules[(idx + 1)..-1].count { |r| r[:action] == :drop }
        if subsequent_denies > 0
          issues << {
            type: :rule_ordering,
            severity: :critical,
            rule_index: idx,
            message: "Permissive rule at position #{idx} may shadow #{subsequent_denies} deny rules"
          }
        end
      end
    end
    
    issues
  end
  
  def check_stateful_rules(rules)
    has_established_rule = rules.any? do |rule|
      rule[:state]&.include?(:established) && rule[:action] == :accept
    end
    
    return [] if has_established_rule
    
    [{
      type: :missing_stateful,
      severity: :high,
      message: "No rule found for established connections - return traffic will be blocked"
    }]
  end
  
  def check_icmp_handling(rules)
    icmp_rules = rules.select { |r| r[:protocol] == :icmp }
    
    if icmp_rules.all? { |r| r[:action] == :drop }
      [{
        type: :icmp_blocked,
        severity: :medium,
        message: "All ICMP traffic blocked - breaks path MTU discovery and diagnostics"
      }]
    else
      []
    end
  end
  
  def check_ipv6_coverage(rules)
    has_ipv4 = rules.any? { |r| r[:ip_version] == 4 }
    has_ipv6 = rules.any? { |r| r[:ip_version] == 6 }
    
    if has_ipv4 && !has_ipv6
      [{
        type: :ipv6_coverage,
        severity: :high,
        message: "IPv4 rules defined but no IPv6 rules - IPv6 traffic unfiltered"
      }]
    else
      []
    end
  end
  
  def check_default_policy(rules)
    last_rule = rules.last
    
    if last_rule.nil? || last_rule[:action] != :drop || !matches_all?(last_rule)
      [{
        type: :default_policy,
        severity: :critical,
        message: "Missing explicit default-deny rule - undefined traffic handling"
      }]
    else
      []
    end
  end
  
  def overly_permissive?(rule)
    rule[:action] == :accept &&
      rule[:source] == :any &&
      rule[:destination] == :any &&
      rule[:port] == :any
  end
  
  def matches_all?(rule)
    rule[:source] == :any &&
      rule[:destination] == :any &&
      rule[:port] == :any
  end
end

Backup and recovery failures leave administrators unable to restore working configurations after misconfigurations. Firewall rule backups should occur before changes and periodically on schedule. Automated backup systems ensure recovery capability when manual processes fail.

Reference

Firewall Types Comparison

Type OSI Layer Connection State Performance Use Case
Packet Filter Network (Layer 3) Stateless Highest Basic perimeter filtering
Stateful Firewall Network/Transport (Layer 3-4) Stateful High Standard network protection
Application Firewall Application (Layer 7) Stateful Medium Web application protection
Next-Gen Firewall All layers Stateful Low-Medium Comprehensive threat prevention
Host-Based Firewall All layers Stateful High Individual system protection

Common Rule Actions

Action Behavior Response to Sender Use Case
ACCEPT Allow packet through Packet delivered Permit legitimate traffic
DROP Silently discard packet No response Reject without revealing firewall
REJECT Discard with notification ICMP error or TCP RST Inform sender of rejection
LOG Record packet details Continue processing Audit traffic patterns
QUEUE Send to userspace Application decides Custom processing

Connection States

State Description Typical Usage
NEW First packet of new connection Evaluate against ruleset
ESTABLISHED Packets in established connection Usually permit automatically
RELATED Related to existing connection FTP data, ICMP errors
INVALID Packet doesn't match any connection Usually drop
UNTRACKED Packet not tracked Bypass connection tracking

Standard Service Ports

Service Port Protocol Security Note
SSH 22 TCP Restrict source IPs
HTTP 80 TCP Redirect to HTTPS
HTTPS 443 TCP Standard web traffic
SMTP 25 TCP Outbound only typically
DNS 53 UDP/TCP Both protocols required
MySQL 3306 TCP Internal networks only
PostgreSQL 5432 TCP Internal networks only
Redis 6379 TCP Never expose publicly

Iptables Chain Types

Chain Direction Hook Point Purpose
INPUT Inbound To local system Filter incoming packets
OUTPUT Outbound From local system Filter outgoing packets
FORWARD Through system Routed packets Filter forwarded packets
PREROUTING Before routing All inbound DNAT, marking
POSTROUTING After routing All outbound SNAT, masquerading

Cloud Provider Firewall Comparison

Provider Service Name Scope Stateful Default Policy
AWS Security Groups Instance Yes Deny all inbound
AWS Network ACLs Subnet No Custom
Azure Network Security Groups NIC/Subnet Yes Deny all inbound
GCP Firewall Rules Network/Instance Yes Deny all inbound
GCP Hierarchical Firewall Organization Yes Custom

ICMP Types for Filtering

Type Code Name Allow/Block
0 0 Echo Reply Allow
3 3 Destination Port Unreachable Allow
3 4 Fragmentation Needed Allow (critical)
8 0 Echo Request Allow (rate-limited)
11 0 Time Exceeded Allow
All All All other types Block

Firewall Testing Commands

Command Purpose Example
nmap -p Scan specific ports nmap -p 22,80,443 target.com
nc -zv Test connectivity nc -zv target.com 443
telnet Test port access telnet target.com 22
curl -v Test HTTP/HTTPS curl -v https://target.com
traceroute Show network path traceroute target.com
hping3 Custom packet crafting hping3 -S -p 80 target.com

Firewall Management Ruby Gems

Gem Purpose Platform
aws-sdk-ec2 AWS security groups AWS
azure-armrest Azure network security Azure
google-cloud-compute GCP firewall rules GCP
net-ssh Remote firewall management Linux/Unix
ufw-helper UFW configuration Ubuntu/Debian