A script using ipset with Shorewall



Overview


In my work, we manage filtering to many servers of different projects (nearly 60). Clients can have access or not from their PCs. Moreover, we avoid that PCs with non referenced DHCP addresses have permissions to these servers.
So, we use Shorewall to ACCEPT or REJECT traffic.

BEFORE : Suppose you give access for clients (variable $ADMIN_PROJECT="10.144.123.36,10.144.123.36 etc..." in params)
$ADM_PROJECT0n as a server.
  • In file /etc/shorewall/rules

ACCEPT zone1:$ADMIN_PROJECT zone2:$ADM_PROJECT01 all
ACCEPT zone1:$ADMIN_PROJECT zone2:$ADM_PROJECT02 all
ACCEPT zone1:$ADMIN_PROJECT zone2:$ADM_PROJECT03 all
ACCEPT zone1:$ADMIN_PROJECT zone2:$ADM_PROJECT04 all
ACCEPT zone1:$ADMIN_PROJECT zone2:$ADM_PROJECT05 all

Indeed, you disassemble these lines to do (N client adresses in "$ADMIN_PROJECT" x M servers) iptables rules: for each client accessing one server.
=> Too much rules...Shorewall LOW restart !!)

AFTER :
  • In file /etc/shorewall/rules_ipset (created,non default Shorewall)
zone1:$ADMIN_PROJECT zone2:$ADM_PROJECT

  • which is "script-written" in file /etc/shorewall/rules
    (just a small part of what script does)
ACCEPT zone1 zone2:+ADM_PROJECT [dst,src]

One iptables rule and QUICK restart !

So,using the script : from 12 000 iptables rules, we manage to obtain only 400 iptables rules !!!!!

I made this doc to explain the script I made which allows to use ipset with Shorewall to dynamically filter access by IP (and later by port : if someone is interested ..).
The great benefit is that restarting/ reloading Shorewall is faster and iptables rules are less.
As basis, I have used FEDORA Core 6 with a kernel > 2.6.19 and these packages
  1. perl 5.8.8
  2. Shorewall 3.2.7

Visit these URLs


To use ipset with netfilter, you' ve got to patch the kernel as explained

FYI, you can see too the specifc page related to ipset with Shorewall & Debian specific

In the same order, there is an interesting article using NFQUEUE


Used perl modules

(visit http://search.cpan.org/):

  • Data::Validate::IP (version 0.05) which validates IP adresses.
  • Tie::File (version 1.9015) which permits dynamic file modification.
  • Acme-Comment (version1.02) which allows multi-line comments in perl files. (NOT REALLY NECESSARY !)

Well-known files in Shorewall are (by default in /etc/shorewall) are :
  • rules
  • params

Architecture


ipset_shorewall.png
Typical architecture

Explanations of the script


For the ease of exploitation, I've created a file named rules_ipset which generates dynamically ipset specific lines in file rules.
rules_ipset lines are in the kind of : (one by project)
zone1:$ADMIN_X zone2:$ADM_X (*)
where $ADMIN_X is the variable defining clients and $ADM_X is the variable defining servers.

This line (*) means (keeping the Shorewall terminology) :
"zone1" clients referenced by $ADMIN_X are allowed to access "zone2" servers (referenced by the variable $ADM_X).
Theses variables are in params.

In ipset_shorewall, I use mainly bindings between servers & clients. See http://ipset.netfilter.org/ipset.man.html for more information
-B, --bind setname IP --binding to-setname Bind the IP in setname to to-setname.
**CAUTION**
 
$ADM_X is defined in params in a block framed like this :
#[ProjectZ]
ADM_Z1=X.Y.Z.W
ADMIN_...Z1=X.Y.Z.W
ADM_Z6=X.Y.Z.W
ADMIN_Z6=X.Y.Z.W
#[/ProjectZ]
 
in order :
 
- to not interfer with initial Shorewall configuration.
- to allow to come back to initial configuration.
 


Exple 1:
In params, we have :
ADMIN_ProjectT="10.156.7.111,10.156.133.75,10.156.139.36"
and
#[$ADM_ProjectT] --> Block beginning
ADM_ProjectT1=192.168.50.39
NAT_ProjectT1=10.156.4.39
ADM_ProjectT2=192.168.50.40
NAT_ProjectT2=10.156.4.40
ADM_ProjectT3=192.168.50.41
NAT_ProjectT3=10.156.4.41
#[/$ADM_ProjectT] --> Block end (1st possibillity)
or [$ADM_ProjectT] --> Next block beginning (2nd possibility)
(2) ADMIN_ProjectX="ADMIN_ProjectX1,ADMIN_ProjectX2,ADMIN_ProjectX3"
The script generates this:
 
In rules:
ACCEPT zone1 zone2:+ADM_ProjectT[dst,src]
 
 
Doing this command line
[#root] ipset -L:
Name: ADM_ProjectT
Type: iphash
References: 1
Default binding:
Header: hashsize: 1024 probes: 4 resize: 50
Members:
192.168.50.41
192.168.50.40
192.168.50.39
Bindings:
192.168.50.40 -> ADMIN_ProjectT
192.168.50.41 -> ADMIN_ProjectT
192.168.50.39 -> ADMIN_ProjectT
Name: ADMIN_ProjectT
Type: iphash
References: 3
Default binding:
Header: hashsize: 1024 probes: 4 resize: 50
Members:
10.156.133.75
10.156.139.36
10.156.7.111
Bindings:


I made the choice that a variable can be used only once in file rules_ipset to avoid doubles.
Only for clients, It is possible to define a variable using other(s) one(s) in the file params.
Accordingly, if we want to bind same clients to servers of different projects, we can use :
ADMIN_ProjectZ="ADMIN_ProjectY"

Exple 2:
Dans rules_ipset
zone1:$ADMIN_ ProjectY zone2:$ADM_ProjectY
zone1:$ADMIN_ ProjectZ zone2:$ADM_ProjectZ
We get:
Name: ADM_ ProjectY
..........
Members:
192.168.51.64
192.168.51.43
.....
Bindings:
192.168.51.64 -> ADMIN_ ProjectY
192.168.51.43 -> ADMIN_ ProjectY
 
Name: ADM_ ProjectZ
Members:
192.168.51.22
192.168.50.5
Bindings:
192.168.51.22 -> ADMIN_ ProjectZ
192.168.50.5 -> ADMIN_ ProjectZ
Name: ADMIN_ ProjectY
Members:
10.156.48.131
Name: ADMIN_ ProjectZ
Members:
10.156.48.131
 

Then, ipset rules are saved in /etc/shorewall/ipsets taken into account when shorewall starts/restarts
Hidden files created :
  • .tmp_ipset
  • .ipset_s

Validation


For our platform, in the script ipset_shorewall, I chose to prepend

  • server variables with ADM_
  • client variables with ADMIN_
(you can change this choice easily)


The script checks server and client ip adresses are private and unique. If this is not the case, it doesn't take into account eventual doubles and other adresses (public, broadcast, prints a warning !!)
In rules_ipset, for the binding clients -> serveurs, the script checks variables do exist and are unique (if no, prints a WARNING)
Checking is done for variable definitions related to other(s) (WARNING if auto-referentiel LOOP)

Usage : ipset_iria [ -h | -t | -d | -w PATHw | -p PATHp | -r PATHr ]
 
Parameters :
-h : for help
-t : for testing (doesn't apply new rules)
-d : Mode debug
-w : path for configuration files (default : /etc/shorewall/)
-p : path of params (default : /etc/shorewall/params)
-r : path of rules (default : /etc/shorewall/rules)
 

BONUS : A script to manage IP adresses in params.


Used modules

  • Arrays_tools (created)
  • File::Basename
  • Data::Validate::IP (version 0.05) which validates IP adresses.
  • Tie::File (version 1.9015) which permits dynamic file modification.
  • Acme-Comment (version1.02) which allows multi-line comments in perl files.
  • Term::ANSIColor (to add color for terminal output)

This script allows to :

  • add
  • remove
  • or swap one (or more) IP adresses to the a client variable without entering the params file.

The script validates adresse(s)
° must be valide one(s)
° and in the fixed range of IP (i.e. no DHCP) : for my personal needs.

[root] # manageip_by_project -h
Usage : manageip_by_project { -a <add> | -r <remove> | -s <swap> } {-p project1(comma separated)}
{ ip adresses (blank separated)}
 
Exple :
-h help
-s 10.156.7.112 10.156.7.111
manageip_by_project -a -p ADMIN_ProjectQ, ADMIN_ProjectR 10.156.20.20 10.156.20.21 10.156.20.22
manageip_by_project (without option) : checks all the file.
 
Typically, we add, remove, swap adresses using manageip_by_project and then issue an ipset_shorewall.

Installation


DOWNLOAD
BEFORE, you need to have, of course :

- Shorewall (3.2 sh-based), I hope in the future, it can be integrated in Shorewall-perl series. (>4)
- Patch the kernel with ipset : http://ipset.netfilter.org/
- All the modules :

  • Arrays_tools (that I created : is in the above gzipped tarball)
  • File::Basename
  • Data::Validate::IP which validates IP adresses.
  • Tie::File which permits dynamic file modification.
  • Acme-Comment which allows comments in perl files.
  • Term::ANSIColor (to add color for terminal output)

For root, In your ~/.bash_profile (or other *profile), you put this :

  1. (scripts : manageip_by_project, ipset_shorewall)
    PATH=$PATH:<Directory_where_you_put_scripts>
  2. (module Arrays_tools.pm )
    export PERL5LIB=<Directory_where_you_put_modules_Arrays_tools.pm>

Last modification was made by - iballo iballo on Oct 31, 2007 10:45 am.
Created on October 2007.
Feel free to post comments !
broken.png