Linux – Difference between iptables -A and -I option

iptableslinux

I've been trying (for hours) to configure iptables to allow DNS queries to my DNS server and just found out that my iptables kept blocking access due to the rule add option that I had been using. Most forums suggest a rule similar to the following:

iptables -A INPUT -p udp -m udp --dport 53 -j ACCEPT

However, in my case, I had to change the rule to an insert type in order for it to work:

iptables -I INPUT -p udp -m udp --dport 53 -j ACCEPT

I know that one rule is for appending and the other for inserting and also what both terms mean, but could someone please explain the difference between the two and also when to use which option? I looked up Ubuntu's iptables how to but don't see much info there.

Best Answer

iptables -A appends rules at the end of the ruleset whereas iptables -I inserts the rule at a specific position in the ruleset as you've pointed out.

Looking at the man entry for iptables shows this:

-I, --insert chain [rulenum] rule-specification Insert one or more rules in the selected chain as the given rule number. So, if the rule number is 1, the rule or rules are inserted at the head of the chain. This is also the default if no rule number is specified.

And here is the reason why -I worked for you and -A doesn't. If you don't supply any rulenum, your rule is inserted at the very first position. That means in your case, that somewhere in your ruleset there must be a rule that's forbidding DNS packets (maybe a rule that forbids UDP generally?) because iptables processes all rules from the first to the last, applies the first matching and stops.
Btw, that's also the reason why you should put the rules that are intended to match most packets at the top: if you put the most used rule at the and, the packet is checked against each rule which may consume a lot of ressources.

And for the usage: You can savely use -A when you want to append a rule at the end or when it doesn't matter where your rule will be. If you want your rule at a specific position, use -I like this for example: iptables -I INPUT 6 -p tcp -j DROP (this will add a DROP statement for all tcp packets addressed to the host itself on position 6 in the INPUT ruleset.)