Thursday, July 23, 2009

Firewall - Blocking a specific IP

This week I needed a solution to block and unblock certain IPs from accessing the internet at certain times.
I didn't want to change my firewall script too much and didn't want to change it every time the rules changed (which change a lot due to variable circumstances).

So I created a two-part solution. In this post I will describe how I changed my firewall and show a simple script that can block or unblock a specific IP address.

In a following post I will describe how I created a script with a configuration file where I can define when to do what.

iptables and chains
Firewalls in Linux are built with iptables and "chains". Check this article for some basics about writing your own firewall script.

In a chain you can put several rules to filter network packets. It is possible to call a chain from another chain. If the called chain does not filter the packet, it automatically returns to the calling chain.

For instance, we have the standard "FORWARD" chain in a firewall.
In the beginning of this chain, we can always call a user-defined chain called "f_ip".

We create the user-defined chain with:

iptables -N f_ip

And pass all forwarded packets through this chain by including this line as one of our first rules in the FORWARD chain:

iptables -A FORWARD -j f_ip


If the "f_ip" chain is empty, or none of the rules filter the packet to be forwarded, the "FORWARD" chain takes over again:



Now I also want to know if a blocked IP address tried to use the internet, so I created another user-defined chain to log & drop packets:

iptables -N f_ip_drop
iptables -A f_ip_drop -j LOG --log-level 6 --log-prefix "FW: ip: "
iptables -A f_ip_drop -j DROP

Take note that for the time being, nothing goes to the f_ip_drop chain!

But now I can use an external script to add rules to the f_ip chain to filter a specific address without having to change my firewall script.
This external script could contain something like:

iptables -A f_ip -s a.b.c.d -j f_ip_drop

(where "a.b.c.d" is substituted by a real IP address of course)

This part of the firewall then works as follows:



The external script
So now I had my firewall altered and I was ready to write my script to block and unblock specific IP addresses.

The result is here:

#!/bin/bash
#
# fw_ipfilt Filter specific IP addresses
# Needs rc.firewall 0.2.3 or newer
#
# Version: 0.0.1 - Thursday, Jul 23, 2009
#
# Author: Niels Horn (niels.horn@gmail.com)


###################
## Configuration ##
###################

IPT=iptables


######################
## Clear IP filters ##
######################
ip_clear() {
  # flush f_ip chain
  $IPT -F f_ip
}


######################
## Add IP to filter ##
######################
ip_addip() {
  ip=$1
  # send all packets from or to $ip to f_ip_drop chain
  $IPT -A f_ip -s $ip -j f_ip_drop
  $IPT -A f_ip -d $ip -j f_ip_drop
}


###########################
## Remove IP from filter ##
###########################
ip_delip() {
  ip=$1
  # delete rules for $ip from f_ip chain
  $IPT -D f_ip -s $ip -j f_ip_drop
  $IPT -D f_ip -d $ip -j f_ip_drop
}


###################
## Check Command ##
###################

case "$1" in
  'add')
    ip_addip $2
    ;;
  'clear')
    ip_clear
    ;;
  'del')
    ip_delip $2
    ;;
  *)
    echo "use $0 add|del <ip> or $0 clear"
esac

I saved this script as /usr/local/sbin/fw_ipfilt and made it executable and readable only for root (chmod 700).
Now I can block an IP address at any time with:

fw_ipfilt add 192.168.1.123

and unblock it with>

fw_ipfilt del 192.168.1.123

To unblock all previously blocked addresses use:

fw_ipfilt clear



As always, if you have any questions or suggestions, feel free to comment on this post!

Labels: , , ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home