#!/usr/bin/perl

use MLDBM::Sync;
use MLDBM qw(DB_File Storable);
use MLDBM qw(MLDBM::Sync::SDBM_File);
use Fcntl qw(:DEFAULT);
use Config;

my $prefix = "10.0.30";
my $gw = "10.0.30.1";
my $timeout = 60 * 60; # 60 min
my $file = "/var/auth";
my %current;
$ipfw = "/sbin/ipfw";
$verbose = 1;

open(LOG, ">/var/log/wireless_auth.log") || die $!;

gen_firewall();
while (true) 
{
    my %ips;

    my $time = time();
    $time = $time - $timeout;

    my %cache;

    my $sync_dbm_obj = tie (%cache,'MLDBM::Sync',$file,O_CREAT|O_RDWR,0666);
    $sync_dbm_obj->Lock;

    #
    # Create a cache hash based on the IPs in the file at this time
    #
    $cache_hash = 0;
    foreach my $ip (keys %cache) 
    {
        if ($cache{$ip} < $time) 
        {
            delete ($cache{$ip});
            print LOG "$ip has expired.\n" if ($verbose);
        } 
        else 
        { 
            if ($ip =~ /\d+\.\d+\.\d+\.(\d+)/)
            {
                $cache_hash ^= $1;
            }
            $ips{$ip} = 1;
        }
    }

    #
    # Create a current hash based on the rules in the firewall at this
    # time.
    #
    $current_hash = 0;
    if (open(IPFW, "$ipfw show |"))
    {
        while(<IPFW>)
        {
            if (/\d+\s+\d+\s+\d+\s+skipto\s+20000\s+ip\s+from\s+\d+\.\d+\.\d+\.(\d+)\s/)
            {
                $current_hash ^= $1;
            }
        }
        close(IPFW);
    }
    else
    {
        foreach my $ip (keys %current)
        {
            if ($ip =~ /\d+\.\d+\.\d+\.(\d+)/)
            {
                $current_hash ^= $1;
            }
        }
    }

    if ($current_hash != $cache_hash)
    {
        #
        # Rebuild the firewall...
        #
        print LOG "Detected a change on the firewall...\n" if ($verbose);
        gen_firewall(keys %ips);

        #
        # Update current
        #
        foreach my $key (keys %current) 
        {
            delete $current{$key};
        }
        foreach my $key (keys %ips) 
        {
            $current{$key} = 1;
        }
    }
    $sync_dbm_obj->UnLock;
    untie(%cache);
    sleep (5);
}


sub gen_firewall 
{
    my (@ips) = @_;
    my $start_range = 9000;
    my $date = `date`;

    system "$ipfw -q delete set 1";
    foreach my $ip (@ips) 
    {
        print LOG "$date: $ip is authorized.\n" if ($verbose);
        $ips{$ip} = 1;
        system "$ipfw -q add $start_range set 1 skipto 20000 ip from $ip to any in via sis0";
        $start_range++;
    }
}
