1

This question already has an answer here:

I'm writing a script in bash and I need to check if iptables are set...I have this:

if [ `iptables-save | grep '^\-' | wc -l` > 0 ]
then
    echo "Iptables already set, skipping..........!"
else
    Here the iptables get set

But it's not working as expected....

PROBLEM:

I did iptables-save and it created this:

$iptables-save
# Generated by iptables-save v1.6.0 on Tue Oct 16 02:48:41 2018
*filter
:INPUT ACCEPT [2:266]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [2:116]
COMMIT
# Completed on Tue Oct 16 02:48:41 2018

So if I run the test it finds that they are already set.... like here:

(root@notemDEB78)-(03:12:20)-(/home/something78/Bash_Programming_2018)
$s.sh
Iptables already set....skipping!!!!!
(root@notemDEB78)-(03:12:25)-(/home/something78/Bash_Programming_2018)
$iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination 

(root@notemDEB78)-(03:16:41)-(/home/something78/Bash_Programming_2018)
$iptables-save | grep '^\-' | wc -l
0

QUESTION:

  • Why does it always find the that iptables are set when the obviously are not
  • Do you have a better/working way of checking if iptables are set....my system is Debian 9

    bash -version GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu) Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html

AS TO POSSIBLE DUPLICATE:

This question is also asking if anyone has a better way to check if iptables are set for a script in bash....

EDIT:

By set I mean that iptables have been set like this:

if [[ `iptables-save | grep '^\-' | wc -l` > 0 ]]
    then
        echo "Iptables already set....skipping!!!!!"
    else
        if [ "$PORT" = "" ]
        then
            echo "Port not set for iptables exiting"
            echo -n "Setting port now, insert portnumber: "
            read port
            PORT=$port
        fi
        if [ ! -f /etc/iptables.test.rules ]
        then
            touch /etc/iptables.test.rules
        else
            cat /dev/null > /etc/iptables.test.rules
        fi

        cat << EOT >> /etc/iptables.test.rules
        *filter

        # Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
        -A INPUT -i lo -j ACCEPT
        -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT

        # Accepts all established inOAUTH_TOKEN=d6637f7ccf109a0171a2f55d21b6ca43ff053616bound connections
        -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

        # Allows all outbound traffic
        # You could modify this to only allow certain traffic
        -A OUTPUT -j ACCEPT

        # Allows HTTP and HTTPS connections from anywhere (the normal ports for websites)
        -A INPUT -p tcp --dport 80 -j ACCEPT
        -A INPUT -p tcp --dport 443 -j ACCEPT

        # Allows SSH connections
        # The --dport number is the same as in /etc/ssh/sshd_config
        -A INPUT -p tcp -m state --state NEW --dport $PORT -j ACCEPT

        # Now you should read up on iptables rules and consider whether ssh access
        # for everyone is really desired. Most likely you will only allow access from certain IPs.

        # Allow ping
        #  note that blocking other types of icmp packets is considered a bad idea by some
        #  remove -m icmp --icmp-type 8 from this line to allow all kinds of icmp:
        #  https://security.stackexchange.com/questions/22711
        -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

        # log iptables denied calls (access via dmesg command)
        -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

        # Reject all other inbound - default deny unless explicitly allowed policy:
        -A INPUT -j REJECT
        -A FORWARD -j REJECT

        COMMIT
EOT
        sed "s/^[ \t]*//" -i /etc/iptables.test.rules ## remove tabs and spaces
        /sbin/iptables-restore < /etc/iptables.test.rules || echo "iptables-restore failed"; exit 127
        /sbin/iptables-save > /etc/iptables.up.rules || echo "iptables-save failed"; exit 127
        printf "#!/bin/bash\n/sbin/iptables-restore < /etc/iptables.up.rules" > /etc/network/if-pre-up.d/iptables ## create a script to run iptables on startup
        chmod +x /etc/network/if-pre-up.d/iptables || echo "cmod +x failed"; exit 127
    fi

marked as duplicate by muru, user88036, Romeo Ninov, Archemar, Luciano Andress Martini Oct 16 '18 at 14:51

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 2
    The > in [ `iptables-save | grep '^\-' | wc -l` > 0 ] is for redirection. You redirected the output of [ ... ] to a file named 0. If you want to compare, use -gt or \>. – muru Oct 16 '18 at 2:23
  • @muru the question is also if there is anyone with a better way to check if iptables are set like in the title – somethingSomething Oct 16 '18 at 2:29
  • Meh. At any rate, the problem with the existing script is handled in the duplicate, so just edit it out. – muru Oct 16 '18 at 2:35
  • @somethingSomething It depends on what "already set" means to you... Can you clarify? Are you looking for any rules at all or specific rules? – filbranden Oct 16 '18 at 3:06
  • 1
    I agree this question has almost nothing in common with suggested duplicate. Yesterday I've voted to reopen it; still one vote is needed. – jimmij Oct 17 '18 at 8:00
2

One possible simplification is to use the return of grep itself as the condition, grep will exit with code 0 (for "success") only if there are matches. No need to count lines since you're looking for any match.

Also, you don't need to escape the - with a \, since it's not a meta-character for grep regular expressions.

You can pass grep a -q argument, so it doesn't print the lines that match (only exits with an appropriate exit code depending on whether any lines matched.)

if /sbin/iptables-save | grep -q '^-'; then
    echo "Iptables already set....skipping!!!!!"
else
    # set up iptables here
fi

I think checking output of iptables-save to check whether any rules were set up is OK, I can't think of another way that's as reliable or that's simpler.

  • Thanks a bunch for the answer....... greatly appreciated – somethingSomething Oct 16 '18 at 8:59
1

The iptables command has its own way of checking the existence of a particular rule with -C option:

-C, --check chain rule-specification

Check whether a rule matching the specification does exist in the selected chain. This command uses the same logic as -D to find a matching entry, but does not alter the existing iptables configuration and uses its exit code to indicate success or failure.

Example:

if ! iptables -C INPUT ! -i lo -d 127.0.0.0/8 -j REJECT; then
     iptables -A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
fi

Your current script checks if there are any rules in the table, but if you want to write reliable script you may want/need to check all rules one by one since other programs can interact with iptables too.

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