How can I remove specific rules from iptables?

LinuxFirewallIptables

Linux Problem Overview


I am hosting special HTTP and HTTPS services on the ports 8006 and 8007 respectively. I use iptables to "activate" the server; i.e. to route the incoming HTTP and HTTPS ports:

iptables -A INPUT -i eth0 -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 8006 -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport 8007 -j ACCEPT
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8006 
iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8007  
iptables -A OUTPUT -t nat -d 127.0.0.1 -p tcp --dport 80 -j REDIRECT --to-ports 8006
iptables -A OUTPUT -t nat -d 127.0.0.1 -p tcp --dport 443 -j REDIRECT --to-ports 8007 

This works like a charm. However I would like to create another script that disables my server again; i.e. restore iptables to the state it was in before running the lines above. However I am having a hard time figuring out the syntax to remove these rules. The only thing that seems to work is a complete flush:

iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

But that will also delete other iptables rules which is undesired.

Linux Solutions


Solution 1 - Linux

Execute the same commands but replace the "-A" with "-D". For example:

iptables -A ...

becomes

iptables -D ...

Solution 2 - Linux

You may also use the rule's number (--line-numbers):

iptables -L INPUT --line-numbers

Example output :

Chain INPUT (policy ACCEPT) 
    num  target prot opt source destination
    1    ACCEPT     udp  --  anywhere  anywhere             udp dpt:domain 
    2    ACCEPT     tcp  --  anywhere  anywhere             tcp dpt:domain 
    3    ACCEPT     udp  --  anywhere  anywhere             udp dpt:bootps 
    4    ACCEPT     tcp  --  anywhere  anywhere             tcp dpt:bootps

So if you would like to delete second rule :

iptables -D INPUT 2

Update

If you use(d) a specific table (eg nat), you have to add it to the delete command (thx to @ThorSummoner for the comment)

sudo iptables -t nat -D PREROUTING 1

Solution 3 - Linux

The best solution that works for me without any problems looks this way:

  1. Add temporary rule with some comment:

    comment=$(cat /proc/sys/kernel/random/uuid | sed 's/-//g') iptables -A ..... -m comment --comment "${comment}" -j REQUIRED_ACTION

  2. When the rule added and you wish to remove it (or everything with this comment), do:

    iptables-save | grep -v "${comment}" | iptables-restore

So, you'll 100% delete all rules that match the $comment and leave other lines untouched. This solution works for last 2 months with about 100 changes of rules per day - no issues.Hope, it helps

Solution 4 - Linux

First list all iptables rules with this command:

iptables -S

it lists like:

-A XYZ -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT

Then copy the desired line, and just replace -A with -D to delete that:

iptables -D XYZ -p ...

Solution 5 - Linux

Use -D command, this is how man page explains it:

-D, --delete chain rule-specification
-D, --delete chain rulenum
    Delete  one  or more rules from the selected chain.  
    There are two versions of this command: 
    the rule can be specified as a number in the chain (starting at 1 for the first rule) or a rule to match.

Do realize this command, like all other command(-A, -I) works on certain table. If you'are not working on the default table(filter table), use -t TABLENAME to specify that target table.

Delete a rule to match

iptables -D INPUT -i eth0 -p tcp --dport 443 -j ACCEPT

Note: This only deletes the first rule matched. If you have many rules matched(this can happen in iptables), run this several times.

Delete a rule specified as a number

iptables -D INPUT 2

Other than counting the number you can list the line-number with --line-number parameter, for example:

iptables -t nat -nL --line-number

Solution 6 - Linux

Assume that, if you want to remove NAT rules,

List the appended IPtables using the command below,

# sudo iptables -L -t nat -v

Chain PREROUTING (policy ACCEPT 18 packets, 1382 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    7   420 DNAT       tcp  --  any    any     anywhere             saltmaster           tcp dpt:http to:172.31.5.207:80
    0     0 DNAT       tcp  --  eth0   any     anywhere             anywhere             tcp dpt:http to:172.31.5.207:8080

If you would like to remove the nat rule from the IPtables, just execute the command,

# sudo iptables -F -t nat -v

Flushing chain `PREROUTING'
Flushing chain `INPUT'
Flushing chain `OUTPUT'
Flushing chain `POSTROUTING'

Then, you can verify that,

# sudo iptables -L -t nat -v

Solution 7 - Linux

You can also use the following syntax

 iptables -D <chain name> <rule number>

For example

Chain HTTPS 
    target     prot opt source               destination
    ACCEPT     all  --  anywhere             anywhere
    ACCEPT     all  --  10.0.0.0/8           anywhere
    ACCEPT     all  --  182.162.0.0/16       anywhere

To delete the rule

> ACCEPT all -- 10.0.0.0/8 anywhere

iptables -D HTTPS 2

Solution 8 - Linux

Here is a one liner that deletes the iptables rules that match a search. This example searches for all the rules that match the IP address 192.168.1.27 and removes all of them. You would edit in your own search criteria in place of that IP address.

eval `iptables --list-rules | grep '192.168.1.27' | sed 's/^-A /iptables -D /g;s/$/;/g'`
How it works:

It uses the accepted answer to this question and to run rules with -D rather than -A.

  • iptables --list-rules lists all the existing rules. Even if you added them with -I or -R, this list shows them all with -A
  • | grep '192.168.1.27' filters the list to just the rules that you want removed (in this case the rules for some specific IP address.)
  • | sed does a search and replace
    • s/^-A /iptables -D /g replaces the -A at the start of each rule with iptables -D so that it becomes an executable command to remove the rule.
    • s/$/;/g replaces the end of each rule with a semi-colon to separate multiple commands when they are run
  • eval ... takes all that output and runs it as a script.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJeroen OomsView Question on Stackoverflow
Solution 1 - LinuxEli RosencruftView Answer on Stackoverflow
Solution 2 - Linuxdomi27View Answer on Stackoverflow
Solution 3 - LinuxETechView Answer on Stackoverflow
Solution 4 - LinuxWladdy LopezView Answer on Stackoverflow
Solution 5 - LinuxcizixsView Answer on Stackoverflow
Solution 6 - LinuxLakshmikandanView Answer on Stackoverflow
Solution 7 - LinuxGautham SreenivasanView Answer on Stackoverflow
Solution 8 - LinuxStephen OstermillerView Answer on Stackoverflow