General Firewall Information

Maybe you don’t really need to use iptables which is very fancy and can be somewhat complex. Maybe you need TCPWrappers which is a lot easier to do simple things like banning certain services or certain hosts on a specific machine.

DenyHosts

More Automatic blacklist via DenyHosts. This helps cut down attempts from known ranges without even giving them the chance even at a slow rate. DenyHost website.

  • Sshguard - TCPWrappers, iptables, others.

  • fail2ban - situation specific control of TCPWrappers or iptables.

  • sshblack - for Perl fans.

  • fwknowp - encrypted port knocking.

Professor Killian’s Rate Limiting Iptables Rules

So this is my [Chip’s] basic setup:

-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 --source 137.0.0.0/8 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -m limit --limit 20/h --limit-burst 5 -j ACCEPT
-A INPUT -i lo -j ACCEPT

So I rate-limit the new ssh connections to 20/hour, with a burst of 5. To make sure I can get in during an attack, I whitelist some addresses. Packets on established connections are accepted by the first rule.

Other ssh brute force blocking ideas

Limit incoming SSH attempts to a low number. In my case I limit to 2 connections in 60 seconds. I can tighten it even more but this did a lot to kill brute force attempts.

iptables -I INPUT -p tcp -i vlan1 --dport 2242 -j DROP
iptables -I INPUT -p tcp -i vlan1 --dport 2242 -m state --state NEW -m limit --limit 2/min -j ACCEPT
iptables -I INPUT -p tcp -i vlan1 --dport 2242 -m state --state RELATED,ESTABLISHED -j ACCEPT
  • Explore "TARPIT" instead of "DROP"

Xed’s Firewall Clearing Script

This script basically takes out any firewall rules and resets network access to be completely unrestricted. One use of this is to put this in a cron job every so often so that while you’re working on sketchy rule changes, you don’t lock yourself out.

#!/bin/bash
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Written by Chris X Edwards 11.07.28
# Script to clear firewall rules. Use this in a cron job to ensure you
# don't lock yourself out while working on rule changes.
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
VERBOSE=1
IPTABLES="/sbin/iptables" # iptables path and command

function rule_setup {
    message $FUNCNAME
    # Try global flush/delete to clear anything already here.
    $IPTABLES --table filter --flush  # Try to get any
    $IPTABLES --table filter --delete-chain  # Try to get any user-def'd
    # flush any existing rules in built-in chains
    $IPTABLES --table filter --flush INPUT
    $IPTABLES --table filter --flush OUTPUT
    # set default policies
    $IPTABLES --policy INPUT ACCEPT
    $IPTABLES --policy OUTPUT ACCEPT
    $IPTABLES --policy FORWARD ACCEPT
    return
} # end function rule_setup

function message {
    if [ $VERBOSE ]; then echo " + Xed Custom Firewall: Executing $1";
    fi
} # end function message

rule_setup

Deleting A Firewall Rule

To get rid of a rule that is mistakenly added, you can run the same command that added the rule but change the -I to -D. This is useful if you just inserted a rule that, in immediate retrospect, doesn’t make sense.

Added:

iptables -I OUTPUT -m state --state NEW -p tcp -d 10.0.0.111 --dport 636 -j ACCEPT

Ooops:

iptables -D OUTPUT -m state --state NEW -p tcp -d 10.0.0.111 --dport 636 -j ACCEPT

Now it’s gone.

A tougher problem is if there is a rule there that you didn’t put there and you need to weed it out. In this case, it’s often easiest to just delete it by it’s rule number. That brings up the next question of how do you know the rule number. Do this:

iptables -vnL --line-numbers

Then delete the offending rule with something like this:

iptables -D INPUT 1

Careful to get the right rule in the right chain because if you don’t, you can lock yourself out. Ahem…

Xed’s Simple Firewall Rules For Hosts

Here is a template for a simple set of rules that can be deployed to do the normal things done by iptables on a single machine. This includes blocking certain services, rate limiting connection attempts, logging, etc.

#!/bin/bash
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Simple Single Machine Firewall
# Written by Chris X Edwards 11.07.28
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

#==========================DEFINITIONS==========================
IPTABLES="echo /sbin/iptables" # iptables path and command

# ---- DNS
DNS1="132.239.0.252" # ns.ucsd.edu
DNS2="132.239.1.51" #  ns0.ucsd.edu
DNS3="128.54.16.2" #   ns1.ucsd.edu
DNS="${DNS1} ${DNS2} ${DNS3}"

# ---- FRIENDS
#SSPPS [u-720]skaggs-abagyan-lab VLAN 890
VLAN890="137.110.138.160/27 172.19.138.160/27"

# SDSC Abagyan Office VLAN 796
VLAN796="137.110.243.96/27"

# SDSC Machine Room VLAN 3252
VLAN3252="169.228.63.60 169.228.63.61 169.228.63.62 169.228.63.63 169.228.63.64"

FRIENDS="${VLAN890} ${VLAN796} ${VLAN3252}"

function rule_setup {
    message $FUNCNAME
    # Try global flush/delete to clear anything already here.
    $IPTABLES --table filter --flush  # Try to get any
    $IPTABLES --table filter --delete-chain  # Try to get any user-def'd
    # flush any existing rules in built-in chains
    $IPTABLES --table filter --flush INPUT
    $IPTABLES --table filter --flush OUTPUT
    # set default policies
    $IPTABLES --policy INPUT DROP
    $IPTABLES --policy OUTPUT DROP
    return
} # end function rule_setup

# This controls packets sent to and from firewall itself.
function core_rules {
    # Rules that are a good idea in most cases.
    message $FUNCNAME
    # Always allow loopback
    $IPTABLES -A INPUT --in-interface lo -j ACCEPT
    $IPTABLES -A OUTPUT --out-interface lo -j ACCEPT
    # Allow all firewall pings for the moment
    $IPTABLES -A INPUT --protocol icmp -j ACCEPT
    $IPTABLES -A OUTPUT --protocol icmp -j ACCEPT
    # Allow machine to get portage cache with rsync
    $IPTABLES -A OUTPUT --protocol tcp --dport 873 -j ACCEPT
    $IPTABLES -A INPUT --protocol tcp ! --syn --sport 873 -j ACCEPT

    # Allow machine to get and receive DNS
    for D in DNS
    do
        $IPTABLES -A INPUT  --protocol tcp ! --syn --src $D --sport domain -j ACCEPT
        $IPTABLES -A OUTPUT --protocol tcp ! --syn --dst $D --dport domain -j ACCEPT
        $IPTABLES -A INPUT  --protocol udp --src $D --sport domain -j ACCEPT
        $IPTABLES -A OUTPUT --protocol udp --dst $D --dport domain -j ACCEPT
    done
    return
} # end function core_rules

Xed’s Firewall Machine Template

Here’s a simple firewall script that will serve as a template for creating a dedicated firewall machine which can arbitrate connections for other machines. The nice thing about this format is that it can be scaled to complex applications in an organized way..

#!/bin/bash
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Simple Custom Firewall Server Rules
# Written by Chris X Edwards 08.12.17
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

#==========================DEFINITIONS==========================
VERBOSE=1  # Comment this out to hide debugging information
IPTABLES="/sbin/iptables" # iptables path and command

# ---- DNS
DNS1="132.239.0.252" # ns0.ucsd.edu
DNS2="128.54.16.2" #   ns1.ucsd.edu

# ---- FRIENDS
XED="10.0.243.108"
PRO="10.0.50.3 10.0.50.2 10.0.50.1"

FRIENDS="${PRO} ${XED}"

function rule_setup {
    message $FUNCNAME
    # Try global flush/delete to clear anything already here.
    $IPTABLES --table filter --flush  # Try to get any
    $IPTABLES --table filter --delete-chain  # Try to get any user-def'd
    # flush any existing rules in built-in chains
    $IPTABLES --table filter --flush INPUT
    $IPTABLES --table filter --flush OUTPUT
    # set default policies
    $IPTABLES --policy INPUT DROP
    $IPTABLES --policy OUTPUT DROP
    return
} # end function rule_setup

# This controls packets sent to and from firewall itself.
function core_rules {
    # Rules that are a good idea in most cases.
    message $FUNCNAME
    # Always allow loopback
    $IPTABLES -A INPUT --in-interface lo -j ACCEPT
    $IPTABLES -A OUTPUT --out-interface lo -j ACCEPT
    # Allow all firewall pings for the moment
    $IPTABLES -A INPUT --protocol icmp -j ACCEPT
    $IPTABLES -A OUTPUT --protocol icmp -j ACCEPT
    # Allow machine to get portage cache with rsync
    $IPTABLES -A OUTPUT --protocol tcp --dport 873 -j ACCEPT
    $IPTABLES -A INPUT --protocol tcp ! --syn --sport 873 -j ACCEPT
    # Allow machine to get and receive DNS
    $IPTABLES -A INPUT --protocol tcp ! --syn --src $DNS1 --sport domain -j ACCEPT
    $IPTABLES -A INPUT --protocol tcp ! --syn --src $DNS2 --sport domain -j ACCEPT
    $IPTABLES -A INPUT --protocol udp --src $DNS1 --sport domain -j ACCEPT
    $IPTABLES -A INPUT --protocol udp --src $DNS2 --sport domain -j ACCEPT
    $IPTABLES -A OUTPUT --protocol tcp ! --syn --dst $DNS1 --dport domain -j ACCEPT
    $IPTABLES -A OUTPUT --protocol tcp ! --syn --dst $DNS2 --dport domain -j ACCEPT
    $IPTABLES -A OUTPUT --protocol udp --dst $DNS1 --dport domain -j ACCEPT
    $IPTABLES -A OUTPUT --protocol udp --dst $DNS2 --dport domain -j ACCEPT
    return
} # end function core_rules

function special_rules {
    # Rules that are specific to the mission of this host.
    message $FUNCNAME
    # Allow httpd proxy server to access the web
    ##$IPTABLES -A OUTPUT --protocol tcp --dport 80 -j ACCEPT
    ##$IPTABLES -A INPUT --protocol tcp ! --syn --sport 80 -j ACCEPT
    ##$IPTABLES -A OUTPUT --protocol tcp --dport 443 -j ACCEPT
    ##$IPTABLES -A INPUT --protocol tcp ! --syn --sport 443 -j ACCEPT
    #Allow a connection to Xed's personal machine for external testing.
    # Uncomment if other protocols besides ssh are needed.
        #$IPTABLES -A INPUT --protocol tcp --src $XED -j ACCEPT
        #$IPTABLES -A OUTPUT --protocol tcp --dst $XED -j ACCEPT
        #$IPTABLES -A INPUT --protocol udp --src $XED -j ACCEPT
        #$IPTABLES -A OUTPUT --protocol udp --dst $XED -j ACCEPT
    return
} # end function special_rules

function rules_for_friends {
    if [ $1 ]; then local MACHINE=$1; fi
    message "$FUNCNAME on $MACHINE"
    # Allow ssh connections from the machine
    $IPTABLES -A INPUT --protocol tcp --src ${MACHINE} --dport ssh -j ACCEPT
    $IPTABLES -A OUTPUT --protocol tcp --dst ${MACHINE} --sport ssh -j ACCEPT
    $IPTABLES -A INPUT --protocol udp --src ${MACHINE} --dport ssh -j ACCEPT
    $IPTABLES -A OUTPUT --protocol udp --dst ${MACHINE} --sport ssh -j ACCEPT
    # Allow this host to ssh to the machine
    $IPTABLES -A OUTPUT --protocol tcp --dst ${MACHINE} --dport ssh -j ACCEPT
    $IPTABLES -A INPUT --protocol tcp ! --syn --src ${MACHINE} --sport ssh -j ACCEPT
    # Allow httpd proxy server access from this machine
    $IPTABLES -A INPUT --protocol tcp --src ${MACHINE} --dport 8080 -j ACCEPT
    $IPTABLES -A OUTPUT --protocol tcp ! --syn --dst ${MACHINE} --sport 8080 -j ACCEPT
    return
} # end rules_for_friends

# This is a super simple test of basic firewall functionality.
# This can be used to troubleshoot firewall problems and to assist
# in initial configuration. Once everything proves that it works,
# make sure this is disabled by making it false:
TEST=false
#TEST=true
function simple_test_of_rules {
    message $FUNCNAME
    # For a simple test, reset the policies to be very permissive
    $IPTABLES --policy INPUT ACCEPT
    $IPTABLES --policy OUTPUT ACCEPT
    #$IPTABLES --policy FORWARD ACCEPT
    # Test the logging. Ping packets should be logged.
    #$IPTABLES -A FORWARD --protocol all -j LOG --log-prefix "| FORWARD |"
    #$IPTABLES -A INPUT --protocol all -j LOG --log-prefix "| I |"
    #$IPTABLES -A OUTPUT --protocol all -j LOG --log-prefix "| O |"
    # These test rules exclude SSH so you can test stuff over SSH without
    # filling up the logs with your own connection.
    $IPTABLES -A INPUT --protocol tcp --dport ! 22  -j LOG --log-prefix "| I |"
    $IPTABLES -A OUTPUT --protocol tcp --sport ! 22  -j LOG --log-prefix "| O |"
    $IPTABLES -A INPUT --protocol udp --dport ! 22  -j LOG --log-prefix "| I |"
    $IPTABLES -A OUTPUT --protocol udp --sport ! 22  -j LOG --log-prefix "| O |"
    return
} # end function simple_test_of_rules

function message {
    if [ $VERBOSE ]; then echo " + Xed Custom Firewall: Executing $1"; fi
} # end function message
#==========================MAIN SCRIPT==========================
# Clean up built-in rules and set policy
rule_setup

# Provide a function to do basic testing of iptables functionality
if $TEST ; then simple_test_of_rules; exit; fi

# Establish rules for this host
core_rules
special_rules

# Set up rules for each FRIEND who needs access
for X in $FRIENDS
do
    rules_for_friends $X;
done