#!/usr/bin/perl
#
# Set up a firewall, for Linux 2.4 with iptables, depending
# on the hostname (could be bart, lisa or maggie).
# After running that script, when the configuration
# proved to be working, you should do a
#  iptables-save > /var/lib/iptables/active
# The purpose of this script is not to be run at system
# startup, but to rewrite easily rules.

use strict;
use Sys::Hostname;
use Getopt::Long;

my ($getopt, $save, $help);

eval {
    $getopt = GetOptions("help" => \$help,
                         "save" => \$save);
};

if ($help) {
    print "coupefeu.pl [OPTIONS]\n
\t--save\t\tReplace the previous iptables active rules\n";
    exit;

}

system("/etc/init.d/iptables",
       "clear");

# The policy will be:
#   - incoming connections are allowed only to local services
#     by allowed machines
#   - outgoing connections are only allowed to services used
#     by the system (DNS, web browsing, pop, email....) 
#   - the forward rule denies everything
#   - all other incoming or outgoing connections are denied

################### CONFIGURATION

# iport = input port
# oport = output port
my @open_iports_bart = ("22",    # ssh
			"25",    # smtp
			"80",    # http
			"443",   # https
#			"3306",  # mysql
			"8080",  # http
			"21",    # girls wanna have fun
			"23",    # girls wanna have fun
			"194");   # girls wanna have fun
my @open_iports_lisa = (
			"22",    # ssh
			"80",    # http
			"443",   # SSH behind stupid firewall
			"873",   # rsync
			"2401",  # pserver
			"3690",  # subversion
                        "21",    # girls wanna have fun
			"23",    # girls wanna have fun
			"194");  # girls wanna have fun
my @open_iports_maggie = ("22",  # ssh
			  "80",  # http
			  "123", # ntp
			  "443", # https
			  "21",    # girls wanna have fun
			  "23",    # girls wanna have fun
			  "194");  # girls wanna have fun

my @open_oports = ("53",     # dns
		   "22",     # ssh
		   "21",     # ftp
		   "25",     # smtp
		   "80",     # http
		   "123",    # ntp
		   "161",    # snmpd
		   "443",    # https
		   "2401",   # pserver
		   "2703",   # razor discover
		   "3306",   # mysql
		   "3690",   # svn
		   "4000",   # ssh lisa (TEMP)
		   "8080",
		   "808");

# ports only open from maggie to others hosts
my @management_ports = (
				"udp:161"
				);

my %logged_iports = (
#    22 => "1"  # do no longer log port 22, too many data
    );

################### RUN!

my @open_iports;
@open_iports = @open_iports_bart if hostname() eq "bart";
@open_iports = @open_iports_lisa if hostname() eq "lisa";
@open_iports = @open_iports_maggie if  hostname() eq "maggie";

die "Can't believe that no port in input at all should be opened. Exiting" unless @open_iports > 0;
die "Can't believe that no port at all in output should be opened. Exiting" unless @open_oports > 0; 

# default policy, close the door
`iptables -P INPUT DROP`;
`iptables -P FORWARD DROP`;
`iptables -P OUTPUT ACCEPT`;  # first, we close the input and
                             # forward ; output is a second
                             # matter
       
# accept traffic on the loopback device
`iptables -A INPUT -i lo -j ACCEPT`;
`iptables -A OUTPUT -o lo -j ACCEPT`; 
`iptables -A FORWARD -i lo -j ACCEPT`; 
`iptables -A FORWARD -o lo -j ACCEPT`;

# close anything that pretend to come from 127.0.0.1 over the network card
# (some virii do that)
# it must be a prerouting entry, otherwise it will be dropped after being
# logged by the kernel.
# (it requires iptables_nat to be loaded)
`iptables -t nat -I PREROUTING -s 127.0.0.0/8 -i ! lo -j DROP`;

# create rules for logging connection, we may need it at
# some point
#  - LOGACCEPT could be used to log accepted connections
#  - LOGDROP could be used to log dropped connections
`iptables -N LOGACCEPT`;
`iptables -A LOGACCEPT -j LOG`;
`iptables -A LOGACCEPT -j ACCEPT`;

`iptables -N LOGDROP`;
`iptables -A LOGDROP -j LOG`;
`iptables -A LOGDROP -j DROP`;

# open the wanted ports on input
foreach my $port (@open_iports) {
    unless (exists($logged_iports{$port})) {
	`iptables -A INPUT -p tcp --dport $port -j ACCEPT`;
	`iptables -A INPUT -p udp --dport $port -j ACCEPT`;
    } else {
	# special care some ports that get logged
	`iptables -A INPUT -p tcp --dport $port -j LOGACCEPT`;
	`iptables -A INPUT -p udp --dport $port -j LOGACCEPT`;
    }
}

# mangement ports
if (hostname() eq "bart" || hostname() eq "lisa") {
	foreach  my $mngt (@management_ports){
		my ($proto,$port) = split (':',$mngt,2);
		`iptables -A INPUT -p $proto --dport $port --source 88.191.250.60 -j ACCEPT`;
	}
}

# specific to bart: open the mysql port, but only to gna machines
if (hostname() eq "bart") {
    my $port = "3306";
    foreach my $ip ("88.191.250.50", 
		    "88.191.250.51",
		    "88.191.250.52",
		    "88.191.250.53",
		    "88.191.250.54",
		    "88.191.250.60") {
	`iptables -A INPUT -p tcp --dport $port --source $ip -j ACCEPT`;
	`iptables -A INPUT -p tcp --dport $port --source $ip -j ACCEPT`;
    }
}


# open the wanted ports on output, which means 
foreach my $port (@open_oports) {
    `iptables -A INPUT -p tcp --sport $port -m state --state ESTABLISHED,RELATED -j ACCEPT`;
    `iptables -A INPUT -p udp --sport $port -m state --state ESTABLISHED,RELATED -j ACCEPT`;

    `iptables -A OUTPUT -p tcp --dport $port -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT`;
    `iptables -A OUTPUT -p udp --dport $port -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT`;
}

# allow ping, only 10/m in input
`iptables -A OUTPUT -p icmp -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT`;
`iptables -A INPUT -p icmp -m state --state RELATED,ESTABLISHED -j ACCEPT`;
`iptables -A INPUT -p icmp -m state --state NEW -m limit --limit 10/min -j ACCEPT`;

if ($save) {
    # backup the original file
    `cp -fv /var/lib/iptables/active /var/lib/iptables/activebak`;
    # create the new file
    `iptables-save > /var/lib/iptables/active`;
}

# EOF
