#!/usr/bin/perl

# blackwing, 050303
# generate FW settings for ipv6
# to-do: different fw presets via db firewall column

use DBI;
if ($ARGV[0] eq "-v") { $VERBOSE = true; }
# datenbase stuff
my $DB_HOST = "";
my $DB_NAME = "";
my $DB_USER = "";
my $DB_PASS = "";
my $i;

# other stuff
my $FW_HEADER = "/etc/ipt6.static";
my $FW_RULES = "/etc/ipt6.rules";
my $IP6_PREFIX = "2001:638:a00:f00b";
my @modi = ("unrestricted","closed <1024, but ssh","stateful");
my $incoming = "-A FORWARD --in-interface 6win --out-interface eth0";
my $outgoing = "-A FORWARD --in-interface eth0 --out-interface 6win";

if ($VERBOSE) { print "Preparing Database\n"; }
my $db_conn=DBI->connect("dbi:Pg:dbname=$DB_NAME;host=$DB_HOST",$DB_USER,$DB_PASS,{ PrintError => 0, AutoCommit => 1, ShowErrorStatement => 1 }) or die("Connect failed: $DBI::errstr\n");

if ($VERBOSE) { print "Fetching Data\n";}
my $db_query = $db_conn->prepare('SELECT hostname,mac,firewall FROM t_ipv6, t_computer WHERE t_computer.id=t_ipv6.computer_id ORDER BY hostname ASC') or die("Select failed: $DBI::errstr\n");
$db_query->execute();


if ($VERBOSE) { print "Preparing Rules\n";}
system("cp $FW_HEADER $FW_RULES");
open(FW,">>$FW_RULES");
if ($VERBOSE) { print "Inserting Rules\n";}
unless (my @temp=$db_query->fetchrow_array()) {
 print "Huh?! No firewall settings in database?\n";
}
else
{
 $temp[0] =~ s/\s+$//;
 while (my($hostname,$mac,$firewall)=@temp)
 {
  $i++;
  my @parts = split(":",$mac);
  # mac is: AA:BB:CC:DD:EE:FF
  # part AA needs a OR  with 0x02 (EUI64 Universal bit)
  # so eui64 is: 2001:638:a00:f00b:AABB:CCff:feDD:EEFF
  $parts[0] = sprintf("%lx",$parts[0] | 0x02);
  my $eui64 = $IP6_PREFIX.":".$parts[0].$parts[1].":".$parts[2]."ff:fe".$parts[3].":".$parts[4].$parts[5];

  # To be inserted: different firewall policies:
  # 0 = completely open
  # 1 = closed < 1024 but ssh is open
  # 2 = stateful firewall
 
if ($VERBOSE) {  print "- Adding ".$hostname." w/ ".$eui64." ($modi[$firewall])\n";}
  print FW "# ".$hostname." -> ".$eui64." ($modi[$firewall])\n";
  if ($firewall == 0)
  {
	print FW "$outgoing --source $eui64 -j ACCEPT\n";
	print FW "$incoming --destination $eui64 -j ACCEPT\n";
  }
  elsif ($firewall == 1)
  {
	print FW "$outgoing --source $eui64 -m state --state NEW -j ACCEPT\n";
	print FW "$incoming --destination $eui64 --protocol ipv6-icmp --icmpv6-type echo-request -m state --state NEW -j ACCEPT\n";
	print FW "$incoming --destination $eui64 --protocol tcp --destination-port ssh -m state --state NEW -j ACCEPT\n";
	print FW "$incoming --destination $eui64 --protocol tcp --destination-port 1024:65535 -m state --state NEW -j ACCEPT\n";
	print FW "$incoming --destination $eui64 --protocol udp --destination-port 1024:65535 -m state --state NEW -j ACCEPT\n";
  }
  else
  {
       print FW "$outgoing --source $eui64 -m state --state NEW -j ACCEPT\n"; 
  }
  print FW "\n"; 
  @temp=$db_query->fetchrow_array();
 }
}
if ($VERBOSE) { 
	print "Added $i Hosts.\n";
}

if ($VERBOSE) { print "Adding REJECT target to FORWARD / INPUT.\n";}
print FW "-A FORWARD -j finalize\n";
print FW "-A INPUT -j finalize\n";

print "Cleaning up...";
$db_query->finish();
print FW "COMMIT\n";
close(FW);
$db_conn->disconnect(); 
if ($VERBOSE) { print "done.\n";}

if ($VERBOSE) { print "Committing rules..."; }
system("ip6tables-restore < $FW_RULES"); 
if ($VERBOSE) { print "done.\n"; }

exit(0);
