Overview

The Linux firewall has evolved from ipfwadm → ipchains → iptables → nftables. All are based on the Netfilter framework, but the higher-level syntax and management approach have continuously improved. This article starts from the Netfilter architecture and dives into iptables’ five chains and four tables, nftables’ advantages and usage, NAT/port forwarding, connection tracking, and production performance optimization.

Netfilter Framework

Architecture Overview

Netfilter is a packet processing framework in the Linux kernel that implements packet filtering, address translation, connection tracking, and other functions by mounting hooks at key positions in the kernel network stack.

                           Netfilter Hook Points

  [Packet enters] → PREROUTING → [Routing decision] →─┬─→ FORWARD → POSTROUTING → [Packet leaves]
                                                         └─→ INPUT → [Local process] → OUTPUT → POSTROUTING → [Packet leaves]

Five Hook Points

Hook PointTrigger TimingDescription
NF_INET_PRE_ROUTINGPacket enters network stack, before routingPre-routing
NF_INET_LOCAL_INPacket destination is this hostInput
NF_INET_FORWARDPacket needs forwarding to another interfaceForward
NF_INET_LOCAL_OUTPacket generated by this hostOutput
NF_INET_POST_ROUTINGPacket about to leave the network stackPost-routing

Packet Flow

Inbound (to this host):
  NIC → PREROUTING → INPUT → local process

Outbound (from this host):
  Local process → OUTPUT → POSTROUTING → NIC

Forward (through this host):
  NIC → PREROUTING → FORWARD → POSTROUTING → NIC

iptables Five Chains and Four Tables

Four Tables

iptables organizes rule chains of different functions through “tables”:

TableFunctionChains
rawProcess before connection tracking (before CONNTRACK)PREROUTING, OUTPUT
mangleModify packet TTL/TOS/Mark etc.All five chains
natAddress translation (DNAT/SNAT)PREROUTING, OUTPUT, POSTROUTING, INPUT
filterPacket filtering (ACCEPT/DROP/REJECT)INPUT, FORWARD, OUTPUT

Table priority: raw → mangle → nat → filter. When a packet passes through a hook point, rules from each table are matched in this order.

Five Chains

ChainBelonging TablesDescription
INPUTfilter, mangle, natInbound packets
OUTPUTraw, mangle, nat, filterOutbound packets
FORWARDfilter, mangleForwarded packets
PREROUTINGraw, mangle, natPre-routing
POSTROUTINGmangle, natPost-routing

Rule Matching Flow

Packet enters hook point
[raw table] ──→ [mangle table] ──→ [nat table] ──→ [filter table]
    │              │              │              │
    │              │              │              ├─→ ACCEPT
    │              │              │              ├─→ DROP (no response)
    │              │              │              ├─→ REJECT (returns ICMP)
    │              │              │              └─→ RETURN (return to previous chain)
    │              │              └─→ DNAT/SNAT
    │              └─→ Modify TTL/TOS/Mark
    └─→ NOTRACK (do not track connection)

Basic iptables Commands

# View rules
$ iptables -L -n -v --line-numbers
$ iptables -t nat -L -n -v

# Append rule
$ iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Insert rule (before rule 1)
$ iptables -I INPUT 1 -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT

# Delete rule
$ iptables -D INPUT 3              # Delete rule 3
$ iptables -D INPUT -p tcp --dport 22 -j ACCEPT  # Delete by content

# Set default policy
$ iptables -P INPUT DROP
$ iptables -P FORWARD DROP
$ iptables -P OUTPUT ACCEPT

Common Match Conditions

# Protocol matching
$ iptables -A INPUT -p tcp ...
$ iptables -A INPUT -p udp ...
$ iptables -A INPUT -p icmp ...

# Port matching
$ iptables -A INPUT -p tcp --dport 80        # Destination port
$ iptables -A INPUT -p tcp --sport 1024:65535 # Source port range

# IP matching
$ iptables -A INPUT -s 10.0.0.0/8            # Source address
$ iptables -A INPUT -d 192.168.1.1           # Destination address

# Interface matching
$ iptables -A INPUT -i eth0                  # Inbound interface
$ iptables -A OUTPUT -o eth1                 # Outbound interface

# Connection state matching
$ iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Rate limiting
$ iptables -A INPUT -p tcp --dport 22 -m limit --limit 5/min --limit-burst 10 -j ACCEPT

# IP sets
$ iptables -A INPUT -m set --match-set blacklist src -j DROP

# String matching
$ iptables -A INPUT -p tcp --dport 80 -m string --string "GET /admin" --algo bm -j DROP

# Time matching
$ iptables -A INPUT -p tcp --dport 22 -m time --timestart 09:00 --timestop 18:00 --weekdays Mon,Tue,Wed,Thu,Fri -j ACCEPT

Production Baseline Rule Set

#!/bin/bash
# /etc/iptables/rules.sh - Production firewall rules

# Flush all rules
iptables -F
iptables -t nat -F
iptables -t mangle -F
iptables -X

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Allow established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow ICMP (rate-limited)
iptables -A INPUT -p icmp -m limit --limit 1/s -j ACCEPT

# SSH: allow internal network, rate-limit external
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m limit --limit 3/min --limit-burst 5 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP

# Web services
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# Monitoring (Prometheus node_exporter)
iptables -A INPUT -p tcp --dport 9100 -s 10.0.0.100 -j ACCEPT

# Log rejected connections
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables-dropped: " --log-level 4
iptables -A INPUT -j DROP

# Save rules
iptables-save > /etc/iptables/rules.v4

nftables

nftables Advantages

Featureiptablesnftables
SyntaxFragmented (iptables/ip6tables/arptables/ebtables)Unified
PerformanceEach rule independentBatch rule set loading
Rule updatesAppend one by one, race conditionsAtomic replacement
Data typesUntypedStrongly typed
SetsLimited (ipset)Native support
MapsNot supportedSupported
Tables/chainsFixedCustomizable
Connection trackingconntrack moduleNative ct object

nftables Basic Concepts

# Install
$ apt install nftables    # Debian/Ubuntu
$ dnf install nftables     # RHEL/CentOS

# View rule set
$ nft list ruleset

Tables and Chains

# Create table (specify protocol family)
$ nft add table inet filter          # IPv4+IPv6
$ nft add table ip nat               # IPv4 only
$ nft add table ip6 filter           # IPv6 only
$ nft add table bridge filter        # Bridge

# Protocol families
# inet: IPv4 + IPv6 (recommended)
# ip:   IPv4
# ip6:  IPv6
# arp:  ARP
# bridge: Bridge
# netdev: Ingress (earliest, before routing)

# Create chain
$ nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
$ nft add chain inet filter forward '{ type filter hook forward priority 0; policy drop; }'
$ nft add chain inet filter output '{ type filter hook output priority 0; policy accept; }'

# Create custom chain
$ nft add chain inet filter log_drop
$ nft add rule inet filter log_drop log prefix "nft-dropped: " counter drop

Rule Writing

# Basic rules
$ nft add rule inet filter input iifname "lo" accept
$ nft add rule inet filter input ct state established,related accept
$ nft add rule inet filter input icmp type echo-request limit rate 1/second accept

# Port rules
$ nft add rule inet filter input tcp dport 22 accept
$ nft add rule inet filter input tcp dport { 80, 443 } accept
$ nft add rule inet filter input tcp dport 1000-2000 accept

# Source address
$ nft add rule inet filter input ip saddr 10.0.0.0/8 tcp dport 22 accept
$ nft add rule inet filter input ip6 saddr fd00::/8 tcp dport 22 accept

# Counters
$ nft add rule inet filter input tcp dport 80 counter accept
$ nft list ruleset
# tcp dport 80 counter packets 12345 bytes 6789012 accept

Sets and Maps

# Create set
$ nft add set inet filter blacklist '{ type ipv4_addr; flags interval; }'
$ nft add element inet filter blacklist '{ 192.168.1.100, 10.0.0.0/8 }'

# Use set
$ nft add rule inet filter input ip saddr @blacklist drop

# Create map
$ nft add map inet filter port_map '{ type inet_service : verdict; }'
$ nft add element inet filter port_map '{ 22 : accept, 80 : accept, 443 : accept }'

# Use map
$ nft add rule inet filter input tcp dport vmap @port_map

nftables Configuration File

# /etc/nftables.conf

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    set blacklist {
        type ipv4_addr
        flags interval
        elements = { 10.0.0.0/8, 192.168.1.100 }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        # Loopback
        iifname "lo" accept

        # Established connections
        ct state established,related accept

        # ICMP
        icmp type echo-request limit rate 1/second accept
        icmpv6 type { echo-request, nd-neighbor-solicit, nd-router-advert } accept

        # SSH
        tcp dport 22 ip saddr 10.0.0.0/8 accept
        tcp dport 22 limit rate 3/minute burst 5 packets accept

        # Web
        tcp dport { 80, 443 } accept

        # Monitoring
        tcp dport 9100 ip saddr 10.0.0.100 accept

        # Blacklist
        ip saddr @blacklist drop

        # Log and drop
        limit rate 5/minute log prefix "nft-dropped: " level warn
        counter drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}
# Load configuration
$ nft -f /etc/nftables.conf

# Enable on boot
$ systemctl enable nftables

iptables to nftables Migration

# Use iptables-nft backend (compatibility layer)
$ update-alternatives --set iptables /usr/sbin/iptables-nft
$ update-alternatives --set ip6tables /usr/sbin/ip6tables-nft

# Convert iptables rules to nftables
$ iptables-save > rules.v4
$ iptables-restore-translate -f rules.v4 > rules.nft
$ nft -f rules.nft

# RHEL 8+ uses nftables backend by default
# firewalld backend configuration
# /etc/firewalld/firewalld.conf
FirewallBackend=nftables

NAT and Port Forwarding

SNAT (Source Address Translation)

# iptables: Change source address of internal 10.0.0.0/8 to public IP
$ iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth0 -j SNAT --to-source 203.0.113.1

# MASQUERADE (dynamic IP, e.g., DHCP/PPPoE)
$ iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -o eth0 -j MASQUERADE

# nftables
$ nft add table ip nat
$ nft 'add chain ip nat postrouting { type nat hook postrouting priority 100; }'
$ nft add rule ip nat postrouting ip saddr 10.0.0.0/8 oifname "eth0" masquerade

DNAT (Destination Address Translation / Port Forwarding)

# iptables: Forward traffic to 203.0.113.1:80 to 10.0.0.10:8080
$ iptables -t nat -A PREROUTING -d 203.0.113.1 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.10:8080
$ iptables -t nat -A POSTROUTING -d 10.0.0.10 -p tcp --dport 8080 -j SNAT --to-source 10.0.0.1
$ iptables -A FORWARD -p tcp -d 10.0.0.10 --dport 8080 -j ACCEPT

# Local port forwarding
$ iptables -t nat -A OUTPUT -d 127.0.0.1 -p tcp --dport 80 -j REDIRECT --to-ports 8080

# nftables
$ nft 'add chain ip nat prerouting { type nat hook prerouting priority -100; }'
$ nft add rule ip nat prerouting tcp dport 80 dnat to 10.0.0.10:8080

Port Range Forwarding

# Forward ports 20000-30000 to internal server
$ iptables -t nat -A PREROUTING -p tcp --dport 20000:30000 -j DNAT --to-destination 10.0.0.10
$ iptables -A FORWARD -p tcp -d 10.0.0.10 --dport 20000:30000 -j ACCEPT

Transparent Proxy

# Redirect all HTTP traffic to Squid proxy (port 3128)
$ iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-ports 3128
$ iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner squid -j RETURN
$ iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-ports 3128

Connection Tracking

How It Works

Connection tracking (conntrack) records the state of each network connection, used for state matching (-m conntrack --ctstate) and NAT.

Connection States

StateDescription
NEWFirst packet of a new connection
ESTABLISHEDConnection established (bidirectional communication)
RELATEDRelated to an existing connection (e.g., FTP data connection, ICMP error)
INVALIDUnrecognized packet
SNAT/DNATConnection that has undergone SNAT/DNAT

conntrack Table Management

# View conntrack table size
$ cat /proc/sys/net/netfilter/nf_conntrack_max
262144

# View current connection count
$ cat /proc/sys/net/netfilter/nf_conntrack_count
12345

# View connection tracking statistics
$ cat /proc/net/nf_conntrack | head -20
# src=10.0.0.1 dst=93.184.216.34 sport=54321 dport=443 protocol=tcp state=ESTABLISHED ...

# Count connections by state
$ cat /proc/net/nf_conntrack | awk '{print $4}' | sort | uniq -c | sort -rn

conntrack Timeout Parameters

# View timeout parameters
$ ls /proc/sys/net/netfilter/nf_conntrack_*_timeout_*
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established    # 432000 (5 days)
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_sent       # 120
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_recv       # 60
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_fin_wait       # 120
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait      # 120
/proc/sys/net/netfilter/nf_conntrack_udp_timeout                # 30
/proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream         # 180

# Adjust TCP established timeout (default 5 days is too long)
$ sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=86400  # 1 day
$ sysctl -w net.netfilter.nf_conntrack_udp_timeout=15

Consequences of conntrack Table Full

When the conntrack table is full, new connections are dropped, and the log shows:

nf_conntrack: table full, dropping packet

Solution:

# Temporarily increase table size
$ sysctl -w net.netfilter.nf_conntrack_max=524288

# Permanent configuration
# /etc/sysctl.d/conntrack.conf
net.netfilter.nf_conntrack_max = 524288
net.netfilter.nf_conntrack_buckets = 131072  # Must be power of 2, typically = max/4

conntrack Tools

# conntrack command-line tool
$ apt install conntrack

# View connections
$ conntrack -L

# View statistics
$ conntrack -S

# Delete specific connection
$ conntrack -D -s 10.0.0.1 -p tcp --dport 443

# Flush all connections
$ conntrack -F

# Real-time monitoring
$ conntrack -E

Performance Optimization

Rule Order Optimization

iptables rules match in order — place high-hit rules first:

# Bad order: SSH after Web
$ iptables -A INPUT -p tcp --dport 80 -j ACCEPT    # High frequency but placed later
$ iptables -A INPUT -p tcp --dport 443 -j ACCEPT
$ iptables -A INPUT -p tcp --dport 22 -j ACCEPT    # Low frequency but placed first

# Good order: by traffic volume, high to low
$ iptables -A INPUT -p tcp --dport 443 -j ACCEPT   # Highest frequency
$ iptables -A INPUT -p tcp --dport 80 -j ACCEPT
$ iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT  # Highest frequency
$ iptables -A INPUT -p tcp --dport 22 -j ACCEPT

Using ipset/nftables Sets

# iptables + ipset: replace multiple rules
$ ipset create whitelist hash:net
$ ipset add whitelist 10.0.0.0/8
$ ipset add whitelist 192.168.0.0/16

# One rule replaces many
$ iptables -A INPUT -m set --match-set whitelist src -j ACCEPT
# Instead of
# iptables -A INPUT -s 10.0.0.0/8 -j ACCEPT
# iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT

Disabling Unneeded Connection Tracking

# Skip connection tracking for traffic that doesn't need NAT
$ iptables -t raw -A PREROUTING -i lo -j NOTRACK
$ iptables -t raw -A OUTPUT -o lo -j NOTRACK

# Skip connection tracking for internal traffic
$ iptables -t raw -A PREROUTING -s 10.0.0.0/8 -d 10.0.0.0/8 -j NOTRACK

# nftables
$ nft add table inet raw
$ nft 'add chain inet raw prerouting { type filter hook prerouting priority -300; }'
$ nft add rule inet raw prerouting iifname "lo" notrack

Using SYNPROXY to Defend Against SYN Flood

# Use SYNPROXY for inbound TCP connections
$ iptables -t raw -A PREROUTING -p tcp -m tcp --syn -j CT --notrack
$ iptables -A INPUT -p tcp -m tcp --syn -m conntrack --ctstate INVALID,UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
$ iptables -A INPUT -p tcp -m conntrack --ctstate INVALID -j DROP

Analyzing Rule Hit Rates

# View hit count per rule
$ iptables -L -n -v --line-numbers

# Example output
Chain INPUT (policy DROP 56789 packets, 1234KB)
 num   pkts bytes target  prot opt in   out  source     destination
 1     9876  456K ACCEPT  tcp  --  *    *    0.0.0.0/0  0.0.0.0/0  tcp dpt:443
 2     1234   56K ACCEPT  tcp  --  *    *    0.0.0.0/0  0.0.0.0/0  tcp dpt:80
 3    87654  12M  ACCEPT  all  --  *    *    0.0.0.0/0  0.0.0.0/0  ctstate RELATED,ESTABLISHED

# Adjust rule order based on hit rate: high-hit rules go first

Real-World Cases

Case 1: Kubernetes Node Firewall

#!/bin/bash
# K8s node firewall rules

iptables -F
iptables -t nat -F
iptables -X

# Default policies
iptables -P INPUT DROP
iptables -P FORWARD ACCEPT  # K8s needs forwarding
iptables -P OUTPUT ACCEPT

# Loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -i cni0 -j ACCEPT          # CNI bridge
iptables -A INPUT -i docker0 -j ACCEPT       # Docker bridge

# Established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# K8s components
iptables -A INPUT -p tcp --dport 6443 -s 10.0.0.0/8 -j ACCEPT  # API Server
iptables -A INPUT -p tcp --dport 10250 -s 10.0.0.0/8 -j ACCEPT # kubelet
iptables -A INPUT -p tcp --dport 10257 -s 10.0.0.0/8 -j ACCEPT # controller-manager
iptables -A INPUT -p tcp --dport 10259 -s 10.0.0.0/8 -j ACCEPT # scheduler

# NodePort range
iptables -A INPUT -p tcp --dport 30000:32767 -j ACCEPT

# ICMP
iptables -A INPUT -p icmp -j ACCEPT

# SSH
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT

Case 2: Container Port Mapping Internals

Docker port mapping uses iptables NAT rules under the hood:

# Rules generated by: docker run -p 8080:80 nginx

# DNAT: forward host port 8080 to container port 80
$ iptables -t nat -L -n -v | grep 8080
DNAT  tcp  --  *  *  0.0.0.0/0  0.0.0.0/0  tcp dpt:8080 to:172.17.0.2:80

# SNAT: change container outbound source address to host IP
$ iptables -t nat -L POSTROUTING -n -v
MASQUERADE  tcp  --  *  *  172.17.0.2  0.0.0.0/0  masq ports: 80

Case 3: High-Concurrency Web Server Firewall Optimization

#!/bin/bash
# High-concurrency web server (100K+ connections)

# 1. Increase conntrack table
echo 1048576 > /proc/sys/net/netfilter/nf_conntrack_max
echo 262144 > /sys/module/nf_conntrack/parameters/hashsize

# 2. Shorten timeouts
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600
sysctl -w net.netfilter.nf_conntrack_udp_timeout=15

# 3. Skip connection tracking for web traffic (filter only, no tracking)
iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK
iptables -t raw -A PREROUTING -p tcp --dport 443 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --sport 80 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --sport 443 -j NOTRACK

# 4. Use stateless filtering (with NOTRACK)
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 443 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 80 -j ACCEPT

# 5. Limit SYN rate
iptables -A INPUT -p tcp --syn --dport 443 -m limit --limit 1000/s --limit-burst 2000 -j ACCEPT
iptables -A INPUT -p tcp --syn --dport 443 -j DROP

Case 4: Load Balancing with nftables

# Use nftables nat module for round-robin load balancing
$ nft add table ip nat
$ nft 'add chain ip nat prerouting { type nat hook prerouting priority -100; }'

# Distribute port 80 traffic across 3 backend servers (round-robin)
$ nft add rule ip nat prerouting tcp dport 80 dnat to 10.0.0.{10,11,12}
# Or with explicit weights
$ nft add rule ip nat prerouting tcp dport 80 dnat numgen inc mod 3 map { 0: 10.0.0.10, 1: 10.0.0.11, 2: 10.0.0.12 }

Rule Persistence

iptables Persistence

# Debian/Ubuntu
$ apt install iptables-persistent
$ netfilter-persistent save
# Rules saved in /etc/iptables/rules.v4 and rules.v6

# RHEL/CentOS
$ iptables-save > /etc/sysconfig/iptables
$ systemctl enable iptables

# Manual save/restore
$ iptables-save > /path/to/rules.v4
$ iptables-restore < /path/to/rules.v4

nftables Persistence

# Save current rule set
$ nft list ruleset > /etc/nftables.conf

# Enable on boot
$ systemctl enable nftables

Summary

The evolution of Linux firewalls from iptables to nftables reflects a design direction of “unification, simplification, and high performance.” Key takeaways:

  1. Understand the five Netfilter hook points: PREROUTING → INPUT/OUTPUT/FORWARD → POSTROUTING is the foundation of all rule design.
  2. iptables four tables have priority: raw → mangle → nat → filter; higher-priority tables match first.
  3. Rule order is critical: Place high-hit rules first; use counters to analyze hit rates and optimize order.
  4. nftables is the future direction: Unified syntax, native sets/maps, atomic rule replacement, better performance.
  5. Connection tracking is a performance bottleneck: In high-concurrency scenarios, increase nf_conntrack_max, shorten timeouts, and use NOTRACK for traffic that doesn’t need tracking.
  6. ipset/nftables sets can drastically reduce rule count: One rule + one set replaces dozens of individual rules.
  7. NAT port forwarding is a common function: Understanding the DNAT + SNAT + FORWARD combination is necessary to correctly configure port forwarding.
  8. SYNPROXY is a powerful SYN Flood defense: It proxies the three-way handshake at the kernel level, filtering out forged-source SYN packets.

Golden rule of firewall configuration: allow first, then block. Before configuring a firewall, ensure SSH connections won’t be accidentally blocked, or you may lock yourself out. Setting up a cron job to automatically flush rules after 5 minutes as a safety net is recommended.