How to Completely Remove an iptables Chain and All Associated Rules


2 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