How can I remove specific rules from iptables? [closed]
Asked Answered
M

8

411

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.

Maclean answered 17/4, 2012 at 19:0 Comment(1)
I've found that it is better to use -I instead of -A for ACCEPT lines. This is because typically, the last line (for INPUT chain for example) is a DROP or REJECT and you want your rule to come before that. -A puts the new rule after the last rule, while -I puts it at the start.Sondrasone
C
580

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

iptables -A ...

becomes

iptables -D ...
Calender answered 17/4, 2012 at 19:4 Comment(7)
If you have several rules of a kind, it will not remove all of them.Sandbox
try to execute this -D command multiple times, and it will delete all of them.Jumbuck
i executed the same command, but with -D instead of -I. But i get BAD RULE (does a matching rule exists)...Enswathe
If you added a rule with -I or -R, you can still delete it with -D.Ginglymus
Just a note. I create a rule with 'iptables -A ...' and the rule appeared but was not effective. Upon using 'iptables -D ...' the response was Bad rule. Even so the rule was deleted. The rule was visible with 'sudo iptables -nvL'. The chain I used was 'INPUT'.Bast
Downvoting because other answers explain how to remove from specific tables, which is pretty important if the rule you're trying to remove is in a specific table.Nahum
Its not that easy. If there is a comment you cant just remove the same value, you have to adjust the command.Chadchadabe
G
537

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
Glaudia answered 25/1, 2013 at 11:37 Comment(9)
I Like this better than the chosen solution because it gives line numbers and it's easier to use. Thanks!Terrify
Both solutions are nice, but this one won't work in a scripted setting when the line number is unknown. So the other solution is more general, and therefore more correct, IMO.Maclean
Well if you don't know the line you may use a comment (like answer among) or do a grep for your rule : iptables -L INPUT --line-numbers | grep -oP "([0-9]{1,3}).*tcp.*domain" | cut -d" " -f1Glaudia
This is fine only if the table cannot have rules inserted at any point in time. Otherwise the line numbers could change between observing them and executing the delete rule. In such a case, it is unsafe to assume that the time window is so short that "it's unlikely ever to happen".Homology
Remember that if you delete one rule, the line numbers of the remainder change. So, if you need to delete rule 5, 10, and 12... delete them 12, 10, then 5.Pointing
When you created the rule yourself, it make sense to delete it in the same way as the choosen answer but when it's a rule that was created by someone else, this is a very nice way.Mink
When trying to delete PREROUTING rules I had to specify -t nat, eg: sudo iptables -t nat --line-numbers -L, and delete them with -t nat too, eg: sudo iptables -t nat -D PREROUTING 1 (May be worth adding to the answer?)Pah
Very well put together answer. I just made a question on iptables too, any chance you could give me your thoughts/wisdom on it? #43509241Egidio
How to delete a range of numbers by this syntax?Weighted
S
39

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

Sandbox answered 1/11, 2013 at 20:28 Comment(5)
In case you don't have iptables-save/restore: iptables -S | grep "${comment}" | sed 's/^-A //' | while read rule; do iptables -D $rule; doneGaseous
For a real-life usage: CRON 1) delete old spamhaus iptables bans, 2) grab spamhaus.org/drop, 3) grep for CIDR IP's and iptables -A INPUT -s $ip_cidr -j -m comment --comment "spamhaus"Gabrielgabriela
@Gaseous Or iptables -S | sed "/$comment/s/-A/iptables -D/e" ;) like thisInartistic
@Inartistic sed doesn't give up, does it? =] Thanks, I'll keep this capability in mind (I'll be forgetting the syntax in a day).Gaseous
sed is used just to remove "-" from uuid. In any case, once you got sed syntax - it will be never forgotten. ))Sandbox
T
36

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 ...
Tooling answered 21/8, 2015 at 21:30 Comment(4)
Be aware! This is incomplete answer. From manual about "-S": "Like every other iptables command, it applies to the specified table (filter is the default). ". So, in case of using this switch - should be repeated for all tables: nat, mangle, etcPrecinct
In my case, I get iptables: Bad rule (does a matching rule exist in that chain?). What now?Languedoc
Ah, figured it out - my delete command was missing the table specification. So in case you list all rules from table nat with sudo iptables -S -t nat and you want to delete one of the returned rules, copying is not enough. You have to add -t nat, e.g. sudo iptables -D ... -t nat.Languedoc
Easy to understand!Disseminate
S
18

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
Sandlin answered 7/4, 2017 at 9:32 Comment(2)
I found this one with --line-number is the bestBreena
Yes! Superb! Don't want whole iptables -FBengal
A
7

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
Animalcule answered 28/4, 2017 at 11:26 Comment(0)
C
4

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
Cheep answered 25/2, 2021 at 14:2 Comment(0)
S
1

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.
Sybyl answered 3/9, 2021 at 18:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.