Iptables: Invert IP, Protocol, Or Interface Test With !

last updated in Categories

How do I invert a protocol or ip address test while writing iptables based shell scripts?

The iptables command comes with ! operator. The most of these rules can be preceded by a ! to invert the sense of the match. A match can be:


  1. Source or dest ip address
  2. Interface name
  3. Protocol name etc


The following will match all protocol except UDP:

iptables -A INPUT -p ! UDP

The following match allows IP address range matching and it can be inverted using the ! sign:

iptables -A INPUT -d -j DROP
iptables -A OUTPUT -d ! -J ACCEPT
# we trust so skip it
iptables -A OUTPUT -s ! -J DROP

The exclamation mark inverts the match so this will result is a match if the IP is anything except one in the given range

iptables -A INPUT -s ! -p tcp --dport 80 -J DROP

You can skip your own ip from string test:

iptables -A FORWARD -i eth0 -p tcp ! -s --sport 80 -m string --string '|7F|ELF' -j DROP

Accept port 22 traffic on all interfaces except for eth1 which is connected to the Internet:

iptables -A INPUT -i !eth1 -p tcp --dport 22  -j ACCEPT

Recommended readings:

man iptables


Posted by: Vivek Gite

The author is the creator of nixCraft and a seasoned sysadmin, DevOps engineer, and a trainer for the Linux operating system/Unix shell scripting. Get the latest tutorials on SysAdmin, Linux/Unix and open source topics via RSS/XML feed or weekly email newsletter.

6 comment

  1. Recently, iptables changed syntax in favor of prefixing, so:
    iptables -A INPUT ! -s; << correct
    iptables -A INPUT -s !; << also correct, but iptables warns you this is a deprecated way to do. so it's question for how long is it going to work.
    This prefixing applies for everything, not just source IP address.

  2. Zdenek,

    You may be right about syntax but most of our systems are running on RHEL 4/5 or CentOS 4/5 and it is not updated by Red Hat. I guess RHEL 6 will come with latest version.

  3. Wouldn’t you know it? It’s now three years and some days later and now only the prefix ! version of syntax works (squid3). :-P

  4. Now it’s 2015

    iptables -A MYCHAIN -i !eth1 -s -j DROP; iptables -L MYCHAIN -n -v


        0     0 DROP       all  --  !eth1  *

    no errors but it doesn’t work

    iptables -A MYCHAIN ! -i eth1 -s -j DROP; iptables -L MYCHAIN -n -v

    also yields:

        0     0 DROP       all  --  !eth1  *

    but this time itworks!

    This is a very bitchy pitfall, take care. Only if you do iptables -L -n -vv with double v, you’ll be able to see the difference between “-i !eth1” and “! -i eth1”.

  5. iptables -A INPUT -m set –set ! geoblock src -j DROP
    Using intrapositioned negation (`–option ! this`) is deprecated in favor of extrapositioned (`! –option this`).

    Somebody have any idea what I’m doing worng here ?

    Still, have a question? Get help on our forum!