Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am hosting special HTTP and HTTPS services on the ports 8006 and 8007 respectively. I use IPTABLES to 'active' 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. restores IPTABLES to the state it was before running the lines above. However I am having a hard time figuring out the syntax to remove these 6 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.

share|improve this question
    
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. –  Mark Lakata Jul 30 '14 at 20:30

3 Answers 3

up vote 163 down vote accepted

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

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

becomes

iptables -D INPUT -i eth0 -p tcp --dport 443 -j ACCEPT
share|improve this answer
4  
If you have several rules of a kind, it will not remove all of them. –  GOST Mar 27 '14 at 8:22
1  
try to execute this -D command multiple times, and it will delete all of them. –  Zhenyu Li Sep 17 '14 at 11:09
1  
Thanks for saving me days! –  tobe Oct 16 '14 at 9:09
    
i executed the same command, but with -D instead of -I. But i get BAD RULE (does a matching rule exists)... –  Ben Feb 27 at 11:33
    
If you added a rule with -I or -R, you can still delete it with -D. –  David Xia Mar 6 at 4:03

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
share|improve this answer
7  
This is more convenient :) –  Sadjad Oct 16 '13 at 15:38
3  
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. –  Jeroen Nov 17 '13 at 5:14
2  
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" " -f1 –  domi27 Nov 24 '13 at 18:44
2  
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". –  Nick May 13 '14 at 10:18
4  
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. –  TomOnTime Oct 2 '14 at 16:58

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

share|improve this answer
1  
In case you don't have iptables-save/restore: iptables -S | grep "${comment}" | sed 's/^-A //' | while read rule; do iptables -D $rule; done –  Mansour Aug 5 '14 at 15:45
    
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" –  Xeoncross Jan 15 at 20:26
1  
@Mansour Or iptables -S | sed "/$comment/s/-A/iptables -D/e" ;) like this –  hek2mgl Mar 15 at 18:41
    
@hek2mgl sed doesn't give up, does it? =] Thanks, I'll keep this capability in mind (I'll be forgetting the syntax in a day). –  Mansour Mar 15 at 21:52
    
@Mansour Yeah! sed rocks! :) –  hek2mgl Mar 15 at 21:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.