On the web there are plenty of guides related to iptables, the firewall included in all the latest Linux distributions.
iptables is a user space application program that allows a system administrator to configure the tables provided by the Linux kernel firewall (implemented as different Netfilter modules) and the chains and rules it stores. Different kernel modules and programs are currently used for different protocols; iptables applies to IPv4, ip6tables to IPv6, arptables to ARP, and ebtables as a special for Ethernet frames.
Iptables requires elevated privileges to operate and must be executed by user root, otherwise it fails to function. On most Linux systems, iptables is installed as /usr/sbin/iptables and documented in its man page, which can be opened using `man iptables` when installed.
For a basic guide to iptables, I suggest the excellent Ubuntu guide: https://help.ubuntu.com/community/IptablesHowTo
In this article I will try to show some unusual use of the command.
Task 1 Block known dirty hosts from reaching your machine
wget -qO - http://infiltrated.net/blacklisted|awk '!/#|[a-z]/&&/./{print "iptables -A INPUT -s "$1" -j DROP"}'
Blacklisted is a compiled list of all known dirty hosts (botnets, spammers, bruteforcers, etc.) which is updated on an hourly basis. This command will get the list and create the rules for you, if you want them automatically blocked, append |sh to the end of the command line. It’s a more practical solution to block all and allow in specifics however, there are many who don’t or can’t do this which is where this script will come in handy.
Task 2 unlock a determined port, once someone “knock”
knock < host > 3000 4000 5000 && ssh -p
user@host && knock < host > 5000 4000 3000
In this example, you do not see the direct use of iptables, but iptables is used in the configuration file of knockd, You have to install knockd.
See example config file below for sshd (port 22).
[options]
logfile = /var/log/knockd.log
[openSSH]
sequence = 3000,4000,5000
seq_timeout = 5
command = /sbin/iptables -A INPUT -i eth0 -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
[closeSSH]
sequence = 5000,4000,3000
seq_timeout = 5
command = /sbin/iptables -D INPUT -i eth0 -s %IP% -p tcp --dport 22 -j ACCEPT
tcpflags = syn
Task 3 Redirect an high port to port 80
iptables -t nat -A PREROUTING -p tcp –dport 80 -j REDIRECT –to-port 9001
This is really useful when you want to give to a normal user the possibility to run a daemon on an high port, but show that service on a standard port. In this example you can give to a normal user the start/stop of an apache that listen to port 9001 and show his website on port 80.
Task 4 use your proxy only for IP not in the local LAN
iptables -t nat -A OUTPUT -d ! 10.0.0.0/8 -p tcp --dport 80 -j DNAT --to-destination 10.1.1.123:3128
Replace 10.0.0.0/8 with your largest local subnet. replace 10.1.1.123:3128 with your proxy information.. Note this only works with a proxy server configured for passive setup..
Now your firefox transparently proxy’s stuff destined outside your network.. and Doesn’t proxy stuff inside your network. as well as all your other favorite web applications. curl, wget.
Task 5 – Limit to 10 the number of ssh connections
/sbin/iptables -A INPUT -p tcp --syn --dport 22 -m connlimit --connlimit-above 10 -j REJECT
With this command you can limit the number of access to a determinate port, it can be useful also to limit the number of connections toward a port of Apache:
Task 6 – Limit ssh to have just 1 session every 15 seconds
iptables -A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --update --seconds 15 -j DROP
iptables -A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --set -j ACCEPT
These two rules makes iptables require 15 seconds between new connections from the same IP on port 22 (the SSH port). Use ACCEPT instead if you are using a firewall that has it’s own rule for accepting ssh.
Task 7 – Give multiple directive with 1 command
iptables -A INPUT -p tcp -m multiport --dports 22,80,143,6000:6003 -j ACCEPT
The Multiport extension allows you to specify multiple ports and ranges and makes it possible to create complex rules in one line
The multiport directive saves you a lot of lines to maintain and requires less system processing.
Popular Posts:
- None Found
The black list isn’t that comprehensive, because most of the spam still gets through. Having a script that puts each IP address in its own command, instead of using the comma separator makes iptables unnecessarily long. Analyzing a month worth of data only provides 2 unique matches against this list on port 25. Checking all incoming traffic only has about 18 unique matches in a month.
iptables –list
now takes a crazy amount of time because we didn’t list at least 5 ip’s per line
iptables.save is now 30000+ lines long because of above.
script doesn’t integrate well with an existing rules set.
If this could be worked into an integrated script/process and then use cron to download it once an hour that would be awesome.
the firewall starting using 100% of the cpu and my bandwidth dropped in half with 3ghz of cpu processing power. Doesn’t anybody verify these tips are good idea before sharing them with others.
The listed usages are not “uncommon”.
Thanks forr the visit,
And well the “common” use it’s, for me, the plain firewall usage that most of the people do of Iptables…wait no, most of the people don’t even use it 😉
Bye
[…] Have you ever wanted to block brute force attacks, blacklist IP addresses, send “knocks” to open secret ports on your server, reroute port 9001 to 80, limit the number of connections to a port, or limit the amount of time a port is open? Iptables can do all of this and more. […]
I was really motivated by your blacklist example. ipset(8) is really fast in comparison to blocking individual IP CIDRs or IP addresses. Here are my iptables rules for working with the ipset:
iptables –new-chain BLACKLISTLOG
# create the ipset so the below iptables rules work
ipset create -exist BLACKLIST_DROP hash:ip 2>/dev/null
# ensure no incoming packets are in the hash:ip space
iptables –append INPUT –in-interface $IN –match set –match-set BLACKLIST_DROP src –jump BLACKLISTLOG
iptables –append BLACKLISTLOG –match limit –limit 1/s –jump LOG –log-prefix “[BLACKLIST] ”
iptables –append BLACKLISTLOG –jump DROP
Here is my cron script to create the BLACKLIST_DROP ipset … it installs the blacklist above in about 60 seconds
on my firewall:
// —- start installIpsetFromNet.sh
#!/bin/bash
###############################################################################
# File:
#
# Description:
#
# History:
# Brian Micek – March 2012
###############################################################################
readonly ME=$( basename $0 )
# —————————————————————————–
# – help() – prints help
# —————————————————————————–
function help() {
cat – <<EOF
$ME $ME
NAME
$ME – Installs an ipset(8) address space in your kernel for iptables(8)
SYNOPSIS
$ME list-URL kernel-list-name [hash:net|hash:ip]
TYPICAL USAGE
$ME "http://www.ipdeny.com/ipblocks/data/countries/us.zone" \\
"us_cidrs" hash:net
DESCRIPTION
This bash script installs an ipset(8) IP address space in your kernel. The
purpose of an ipset address space is to discriminate (typically incoming)
IP packets against the list for ACCEPT, REJECT or DROP dispositions
OPTIONS
None
NOTES:
Logging by this program is sent to syslog(8) and also stderr.
$ME $ME
EOF
}
# —————————————————————————–
# – log() – delivers log messages to stderr and syslogd
# —————————————————————————–
function log() { #<– variable arguments for logging
logger -s -t $ME $@
}
# —————————————————————————–
# – getList() – gets an IP or CIDR list from the net
# —————————————————————————–
function getList() { #<– 1 argument of URL
log Fetching and parsing $@
wget -qO – $@ |
awk -F "." '/^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/ {
if ( NF == 4 ) {
for ( i = 1; i = 1 ) {
if ( ar[ 1 ] 255 ) {
next
}
}
if ( n >= 2 ) {
if ( ar[ 2 ] 32 ) {
next
}
}
}
print
}
}’
}
# —————————————————————————–
# – appendList() – Inserts rules into the custom chain to accept and log
# – the candidate IP address
# —————————————————————————–
function appendList() { #<– 2 arguments, list-name, cidr
local listname=$1
local cidr=$2
ipset add -exist $listname $cidr
return $?
}
# —————————————————————————–
# – addList() – Reads records from stdin and add them to the ipset IP space
# —————————————————————————–
function addList() { #<– 2 args, type and name
local type=$1
local name=$2
readonly TEMP_SET=TEMP_$2
log Creating temporary ipset $TEMP_SET
ipset create -exist $TEMP_SET $type
# in case it already existed, flush it
ipset flush $TEMP_SET
local c=0
# Insert each successful CIDR into iptables. W
while read cidr
do
c=$[ $c + 1 ]
local v=$[ c % 1000 ]
if [ $v -eq 0 ]
then
log Installed $c rules on $TEMP_SET
fi
appendList $TEMP_SET $cidr
if [ $? -ne 0 ]
then
log List append error
break
fi
done
if [ $c -gt 1 ]
then
log Finished, installed $c CIDRs on $TEMP_SET
log Swapping new list $TEMP_SET with $name
ipset swap $TEMP_SET $name
if [ $? -ne 0 ]
then
# Probably this is the first time this program was run
# and the destination does not exist yet.
log IP set doesnt apprear to exist, renaming
ipset rename $TEMP_SET $name
if [ $? -ne 0 ]
then
log ERROR ERROR ERROR issuing ipset swap $TEMP_SET $name $type
# I'm not quite sure what to do here, most likely the
# new set was created with a differing type
exit 1
fi
else
# else the swap worked and TEMP_SET now holds old data
log Flushing old data in $TEMP_SET
ipset flush $TEMP_SET
log Deleting old data in $TEMP_SET
ipset destroy $TEMP_SET
fi
else
# Else we were not able to install any darn rules
log ERROR did not install any rules destined for $name
# Leave the old chain intact and flush and delete TEMP_SET
log Flushing old data in $TEMP_SET
ipset flush $TEMP_SET
log Deleting old data in $TEMP_SET
ipset destroy $TEMP_SET
fi
log $( ipset list -terse $name )
}
# —————————————————————————–
# MAIN
# —————————————————————————–
# installChain "http://www.ipdeny.com/ipblocks/data/countries/us.zone" "us_cidrs" hash:net
#
if [ $# -lt 2 ]
then
help
exit 1
elif [ $# -eq 2 ]
then
type="hash:net"
else
type=$3
fi
case "$type" in
"hash:net") ;;
"hash:ip") ;;
*) help ;;
esac
url="$1"
name="$2"
start=$( date +%s )
installChain $type $url $name
stop=$( date +%s )
delta=$[ $stop – $start ]
log Finished, took $delta seconds for $name
// —- end installIpsetFromNet.sh
Now in /etc/cron.daily, something like this will update the blacklist every night
installIpsetFromNet.sh http://infiltrated.net/blacklisted BLACKLIST_DROP hash:ip
I’m sorry about the indentation, whitespace was stripped from my upload
No problem.
And thanks for the feedback, i’m thinking to use it for anothet article 😉