How to Completely Remove an iptables Chain and All Associated Rules


12 views

When working with iptables, you might encounter situations where you need to delete an entire chain along with all its references. The standard approach of using iptables -X chain_name often fails with the "Too many links" error when jump rules still reference the chain.

In your case, you have a chain i_XXXXX_i that's referenced in multiple rules across INPUT and OUTPUT chains. The error occurs because:

1. References exist in other chains (INPUT/OUTPUT)
2. Simply flushing (-F) doesn't remove these references
3. The chain cannot be deleted while being referenced

Here's the proper sequence to completely remove a chain:

# First, list all rules referencing the chain
iptables-save | grep i_XXXXX_i

# Then delete all referencing rules
iptables -D INPUT -s 282.202.203.83/32 -j i_XXXXX_i
iptables -D INPUT -s 222.202.62.253/32 -j i_XXXXX_i
iptables -D OUTPUT -d 282.202.203.83/32 -j i_XXXXX_i
# ... repeat for all references

# Flush the chain itself
iptables -F i_XXXXX_i

# Finally delete the chain
iptables -X i_XXXXX_i

For chains with many references, use this bash script:

#!/bin/bash
CHAIN="i_XXXXX_i"

# Delete all rules referencing the chain
for rule_num in $(iptables -L INPUT --line-numbers | grep "$CHAIN" | awk '{print $1}' | sort -rn); do
    iptables -D INPUT $rule_num
done

for rule_num in $(iptables -L OUTPUT --line-numbers | grep "$CHAIN" | awk '{print $1}' | sort -rn); do
    iptables -D OUTPUT $rule_num
done

# Flush and delete the chain
iptables -F "$CHAIN"
iptables -X "$CHAIN"

You can also use iptables-save/restore for complex cases:

iptables-save | grep -v "i_XXXXX_i" | iptables-restore

This method removes all rules mentioning the chain in one operation.


When working with iptables firewall rules in Linux, you might encounter a situation where you need to completely remove a custom chain along with all its associated rules. The error iptables: Too many links typically occurs when you attempt to delete a chain that still has references from other rules.

In your case, you have a chain named i_XXXXX_i with multiple jump rules from both INPUT and OUTPUT chains. Simply running:

iptables -F i_XXXXX_i  # Flush chain rules
iptables -X i_XXXXX_i  # Delete the chain

won't work because the chain is still being referenced by other rules.

Here's the proper sequence to completely remove a chain and all its references:

# First, list all rules referencing the chain
iptables-save | grep i_XXXXX_i

# Then delete all referencing rules
iptables -D INPUT -s 282.202.203.83/32 -j i_XXXXX_i
iptables -D INPUT -s 222.202.62.253/32 -j i_XXXXX_i
iptables -D INPUT -s 222.202.60.62/32 -j i_XXXXX_i
iptables -D INPUT -s 224.93.27.235/32 -j i_XXXXX_i
iptables -D OUTPUT -d 282.202.203.83/32 -j i_XXXXX_i
iptables -D OUTPUT -d 222.202.62.253/32 -j i_XXXXX_i
iptables -D OUTPUT -d 222.202.60.62/32 -j i_XXXXX_i
iptables -D OUTPUT -d 224.93.27.235/32 -j i_XXXXX_i

# Flush the chain's rules
iptables -F i_XXXXX_i

# Finally, delete the chain
iptables -X i_XXXXX_i

For frequently performing this task, consider creating a bash function:

function delete_iptables_chain() {
    local chain_name="$1"
    
    # Delete all rules referencing the chain
    iptables-save | grep -E "\-j ${chain_name}\>" | \
    while read -r rule; do
        iptables -D ${rule#*-A }
    done
    
    # Flush and delete the chain
    iptables -F "$chain_name"
    iptables -X "$chain_name"
}

# Usage
delete_iptables_chain i_XXXXX_i

For complex rule sets, this method is more reliable:

# Create a backup
iptables-save > iptables.backup

# Filter out unwanted chain and references
grep -vE "(^-A.*-j i_XXXXX_i|^:i_XXXXX_i)" iptables.backup > iptables.new

# Restore cleaned rules
iptables-restore < iptables.new
  • Always backup your iptables rules before making changes
  • Consider using iptables-persistent package to save changes
  • For complex firewalls, investigate using nftables as iptables' successor