A.2. proxy-manager

Der Proxy-Manager verwaltet die Internet-Freigaben und wird vom Firewall-Script aus gestartet.

Dateiname: /usr/local/sbin/proxy-manager.

#!/usr/bin/perl -w
#
# /usr/local/sbin/proxy-manager
#
# proxy-manager Programm zum Verwalten der Internetfreigaben
#
# (c) 2001 Thomas Bleher <ThomasBleher@gmx.de>
# (c) 2002,2003 Andreas Dangel <adabolo@adabolo.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#


use Fcntl;   # for sysopen, file modes
use Fcntl qw(:flock);
use strict;

## Konfiguration
my $version = "1.2 (2003-08-21)";
my $pidfile = '/var/run/proxy-manager.pid';
my $logfile = '/var/log/internet-freigabe';
my $iptables = '/sbin/iptables';
my $actives = '/var/state/internet-freigabe';
my $lockfile = '/var/lock/proxy-manager.lck';
my $lockfile2 = '/var/lock/proxy-manager2.lck';
my $pid;


#########################
##### SUBPROCEDURES #####
#########################
sub usage() {
    print <<EOF;
Syntax: $0 [-hdocak] [login] [ip-adresse] [zeitsekunden]

    -h   Dieser Hilfetext
    -d   der eigentliche proxy-manager wird im Hintergrund gestartet
    -o   öffnet eine Verbindung für "ip-adresse" und schließt sie
         automatisch, wenn "zeitsekunden" erreicht sind
    -c   schließt die Verbindung für "ip-adresse" manuell
    -a   prüft, ob für "ip-adresse" eine Verbindung besteht
    -k   beendet den proxy-manager und löscht alle Verbindungen
    -t   tested, ob der proxy-manager im Hintergrund läuft
         (siehe /var/run/proxy-manager.pid).

    [login]
         Der Benutzer, der eine Verbindung öffnet, etc. wird geloggt.

    [ip-adresse]
         Jede beliebige Form ist erlaubt:
         Beispiel: 192.168.0.168
         Es kann auch 'all' verwendet werden.

    [zeitsekunden]
         Anzahl der vergangenen Sekunden seit seit 00:00:00, Jan 1, 1970.
         Zu ermitteln z.B. durch "date +%s".

    Hinweise:
       Falls Fehler beim Start des proxy-managers auftreten
       sollten: die Zugriffsrechte überprüfen:
       $logfile
       $actives


    proxy-manager $version
    (c) 2001 Thomas Bleher <ThomasBleher\@gmx.de>
    (c) 2002,2003 Andreas Dangel <adabolo\@adabolo.de>

    proxy-manager comes with ABSOLUTELY NO WARRANTY.
    This is free software, and you are welcome to redistribute it
    under certain conditions; see the GNU GPL.
EOF

    exit;
}

sub log() {
    my $data = shift;
    chomp($data);
    my $datum = localtime(time);
    open(S, ">>$lockfile");
    flock(S, LOCK_EX);
    open(LOG, ">>$logfile");
    print LOG "$datum: $data\n";
    close(LOG);
    close(S);
}

sub open_proxy() {
    &log("open_proxy()");
}

sub close_proxy() {
    &log("close_proxy()");
}

sub kill_proxymanager() {
    &close_proxy();
    unlink $actives;
    system("touch $actives");

    unlink($pidfile);

    exit;
}

sub open_connection() {
    my $login;
    my $ip;
    my $time;
    if (not (($login, $ip, $time) = @_)) {
        &log("open_connection(): missing arguments!");
        return;
    }
    if ($ip =~ /[^\w.]/) {
        &log("open_connection(): invalid argument! $ip");
        return;
    }

    &log("open_connection(): $login: $ip, $time");

    &add_actives($ip, $time);
}

sub active_connection() {
    my $ip;
    if (not ($ip = shift)) {
        &log("active_connection(): missing arguments!");
        return;
    }
    if ($ip =~ /[^\w.]/) {
        &log("active_connection(): invalid argument! $ip");
        return;
    }


    return &find_actives($ip);
}

sub close_connection() {
    my $ip;
    if (not ($ip = shift)) {
        &log("close_connection(): missing arguments!");
        return;
    }
    if ($ip =~ /[^\w.]/) {
        &log("close_connection(): invalid argument! $ip");
        return;
    }

    &log("close_connection() for $ip");

    &remove_actives($ip);
}

sub check_daemon() {
    if (-e $pidfile) {
        return 0;
    }
    return 1;
}

sub start_daemon() {
    if (not defined($pid = fork)) {
        die "Couldn't fork!";
    }

    if ($pid) {  #parent
        exit;
    } else {     #child
        sysopen(PIDFILE, $pidfile, O_WRONLY | O_CREAT | O_EXCL)
            || die "Instance of proxy-manager already running! See $pidfile";
        print PIDFILE $$;
        close PIDFILE;

        while(1) {
            sleep(60);
            my $time = time;
            &remove_actives_by_time($time);
        }
    }
}

sub add_actives() {
    my $ip = shift;
    my $time = shift;

    open(S, ">>$lockfile2");
    flock(S, LOCK_EX);
    open(FILE, "<$actives");
    my @data = <FILE>;
    close(FILE);

    push @data, "$ip:$time";

    open(FILE, ">$actives");
    print FILE join("\n", @data);
    close(FILE);

    close(S);

}

sub find_actives() {
    my $ip = shift;

    #&log("find_actives() for $ip");

    open(S, ">>$lockfile2");
    flock(S, LOCK_EX);
    open(FILE, "<$actives");
    my @data = <FILE>;
    close(FILE);

    my @found = grep(/$ip/, @data);
    my @found2 = grep(/all/, @data);
    push(@found, @found2);
    close(S);

    if (@found != 0) {
      my @fields = split(/:/, $found[0]);
      return $fields[0];
    }

    return;
}

sub remove_actives() {
    my $ip = shift;

    open(S, ">>$lockfile2");
    flock(S, LOCK_EX);
    open(FILE, "<$actives");
    my @data = <FILE>;
    close(FILE);

    my @data_new = grep(!/$ip/, @data);

    open(FILE, ">$actives");
    print FILE join("\n", @data_new);
    close(FILE);
    close(S);
}

sub remove_actives_by_time() {
    my $time = shift;

    open(S, ">>$lockfile2");
    flock(S, LOCK_EX);
    open(FILE, "<$actives");
    my @data = <FILE>;
    close(FILE);

    my @data_new;

    my $line;
    while ($line = shift @data) {
      chomp($line);
      my @fields = split(/:/, $line);
      my $time2 = $fields[1];
      if ($time >= $time2) {
        # nicht mehr hinzufügen
        &log("remove_actives_by_time: $fields[0]");
      } else {
        push(@data_new, $line);
      }
    }

    open(FILE, ">$actives");
    print FILE join("\n",@data_new);
    close(FILE);

    close(S);
}

sub handler {
  my $sig = shift;
  &log("Caught SIG$sig...");
  &kill_proxymanager();
  exit 0;
}

$SIG{'TERM'} = \&handler;

########################
##### MAIN PROGRAM #####
########################

# Argumente prüfen
if (@ARGV < 1) {
    &usage();
}

if ($ARGV[0] eq "-h") {
    &usage();
}



if ($ARGV[0] eq "-d") {
    die "Instance of proxy-manager already running! see $pidfile"
        if (&check_daemon() == 0);

    &open_proxy();
    &start_daemon();

} elsif ($ARGV[0] eq "-o") {
    die "missing arguments! try \"$0 -h\"" if (@ARGV != 4);

    if (&check_daemon() == 1) {
        die "no instance of proxy-manager running! see \"$0 -h\"";
    }
    &open_connection($ARGV[1], $ARGV[2], $ARGV[3]);

} elsif ($ARGV[0] eq "-c") {
    die "missing arguments! try \"$0 -h\"" if (@ARGV != 2);

    if (&check_daemon() == 1) {
        die "no instance of proxy-manager running! see \"$0 -h\"";
    }
    &close_connection($ARGV[1]);

} elsif ($ARGV[0] eq "-a") {
    die "missing arguments! try \"$0 -h\"" if (@ARGV != 2);

    if (&check_daemon() == 1) {
        die "no instance of proxy-manager running! see \"$0 -h\"";
    }
    if (my $ret = &active_connection($ARGV[1])) {
        print $ret;
    }

} elsif ($ARGV[0] eq "-k") {
    if (&check_daemon() == 1) {
        die "no instance of proxy-manager running! see \"$0 -h\"";
    }

    # sending SIGTERM(15)
    my $opid = `cat $pidfile`;
    kill 15, $opid;
    
    #&kill_proxymanager();

} elsif ($ARGV[0] eq "-t") {
    if (&check_daemon() == 0) {
        print "Der proxy-manager läuft...\n";
        exit 0;
    } else {
        print "Der proxy-manager läuft nicht...\n";
        exit 1;
    }

} else {
    &usage();
}

exit;

A.2.1. squid-redirector

Dateiname: /usr/local/sbin/squid-redirector.

#!/usr/bin/perl
use FileHandle;
use IPC::Open2;
use Fcntl qw(:flock);
$|=1;

## Konfiguration
my $squidGuard = "/usr/bin/squidGuard";
my $proxymanager = "/usr/local/sbin/proxy-manager";
my $redirecturl = "http://server/cgi-bin/inactive.cgi";
my $logfile = "/var/log/squid/squid-redirector";

my $pid = open2(*Reader, *Writer, $squidGuard);

&log("[$$,$pid] started");

while (<>) {
    my $request = $_;
    my @fields = split / /, $request;
    my @fields2 = split /\//, $fields[1];
    my $ip = $fields2[0];

    chomp($request);
    chomp($ip);

    #&log("request: $request ($ip)");
    
    print &check_ip($ip, $request) . "\n";
}

&log("[$$,$pid] stopped");

exit 0;

sub log {
  my $msg = shift;
  my $date = localtime(time);
  chomp($msg);
  system("echo \"$date $msg\" >> $logfile");
}

sub check_ip {
  my $ip = shift;
  my $request = shift;

  if ($ip eq "127.0.0.1") {
      return;
  }

  my $active = `$proxymanager -a $ip`;

  #&log("proxymanager: $active");
  
  if ($active eq "") {
      return "$redirecturl";
  }

  print Writer "$request\n";
  my $response = <Reader>;
  chomp($response);
  return $response;
}

A.2.2. internet/index.cgi

Das ist das Front-End zum proxy-manager. Damit kann man das Internet freischalten usw.

Dateiname: /usr/local/httpd/htdocs/internet/index.cgi.

#!/usr/bin/perl -w
#
# /usr/local/httpd/internet/index.cgi
#
# browser-frontend für proxy-manager
#
# (c) 2001 Thomas Bleher <ThomasBleher@gmx.de>
# (c) 2002 Andreas Dangel
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

use strict;
use CGI;

my $q = new CGI;

my $login;
my $user;
my $lehrer;
my $ip;
my $welche;
my $dauer;
my $status1;
my $status2;
my $status3;

$login = $q->remote_user;
if (not $user = (getpwnam($login))[6]) {
    die "Unauthorized access to internet/index.cgi! Username: $login";
}
$lehrer = ((getgrnam('lehrer'))[3] =~ /\b\Q$login\E\b/);
$ip = $ENV{REMOTE_ADDR} or die "No REMOTE_ADDR!";

if ($q->param()) {

    if ($q->param('aktivieren')) {
        if ($lehrer) {
            if ($q->param('welche') eq 'alle') {
                $welche = 'all';
            } else {
                $welche = $ip;
            }
        } else {
            $welche = $ip;
        }

        $dauer = $q->param('dauer');
        $dauer += 0;  # In Zahl umwandeln
        if (($dauer < 1) or ($dauer > 180)) {
            $dauer = 45;
        }
        $dauer *= 60;
        $dauer += time;

# IPs freischalten
system("/usr/bin/sudo /usr/local/sbin/proxy-manager -o $login $welche $dauer");

    } elsif ($q->param('deaktivieren')) {
        if ($lehrer) {
            if ($q->param('welche') eq 'alle') {
                $welche = 'all';
            } else {
                $welche = $ip;
            }
        } else {
            $welche = $ip;
        }

        system("/usr/bin/sudo /usr/local/sbin/proxy-manager -c $welche");
    }
} else {
    # keine Parameter gegeben:
}


$status1 = `/usr/bin/sudo /usr/local/sbin/proxy-manager -a $ip`;
$status2 = `/usr/bin/sudo /usr/local/sbin/proxy-manager -a all`;
`/usr/bin/sudo /usr/local/sbin/firewall status > /dev/null 2>&1`;
$status3 = $?;

#######################
##### AUSGABEN ########
#######################

print $q->header;

if ( $status3 != "0" ) {
    print
        $q->start_html( -title=>'Internet-Einwahl - Internet aktiviert',
                        -author=>'webmaster@gm.rt.schule-bw.de'),
        $q->h1('Internet-Einwahl - Internet aktiviert'),
        "Da die Firewall deaktiviert ist, ist das Internet
         <strong>immer</strong> und für <strong>jeden</strong> Computer
         aktiviert!!";
} elsif ($status1 eq $ip) {
    print
        $q->start_html( -title=>'Internet-Einwahl - Internet aktiviert',
                        -author=>'webmaster@gm.rt.schule-bw.de'),
        $q->h1('Internet-Einwahl - Internet aktiviert'),
        $q->p, $q->startform,
        $q->em("Hallo $user, der Internetzugang ist <b>für diesen Computer
                aktiviert</b>.");
    if ($status2 eq "all") {
        print $q->br, $q->em("Außerdem ist der Internetzugang <b>für alle
                              aktiviert</b>.");
    }
    print $q->p;

    if ($status2 && $lehrer) {
        print $q->popup_menu('welche',['eigener', 'alle'], 'eigener'),
                'Computer';
    } elsif (not $lehrer) {
        print $q->popup_menu('welche',['eigener'], 'eigener'), 'Computer';
    }

    print $q->br, $q->submit(-name=>'deaktivieren',
                             -value=>'Zugang deaktivieren');
} elsif ($status2 eq "all") {
    print
        $q->start_html(-title=>'Internet-Einwahl - Internet für alle aktiviert',
                       -author=>'webmaster@gm.rt.schule-bw.de'),
        $q->h1('Internet-Einwahl - Internet für alle aktiviert'),
        $q->p, $q->startform,
        $q->em("Hallo $user, der Internetzugang ist <b>für alle
                aktiviert</b>.");
 
    if ($lehrer) {
        print $q->p;
        print $q->popup_menu('welche', ['alle'], 'alle'), 'Computer';
        print $q->br, $q->submit(-name=>'deaktivieren',
                                 -value=>'Zugang deaktivieren');
    }
} else {
    print
        $q->start_html( -title=>'Internet-Einwahl - Internet deaktiviert',
                        -author=>'webmaster@gm.rt.schule-bw.de'),
        $q->h1('Internet-Einwahl - Internet deaktiviert'),
        $q->p, $q->startform,
        $q->em("Hallo $user, der Internetzugang ist nicht aktiviert."),
        $q->p;

    print "<br>Dauer: ", $q->popup_menu('dauer',
                            [5,10,15,20,30,45,60,75,90,120,150,180],45),
                            "min.";
    print $q->br;
    if ($lehrer) {
        print $q->popup_menu('welche',['eigener', 'alle'], 'eigener'),
              'Computer';
    } else {
        print $q->popup_menu('welche',['eigener'], 'eigener'), 'Computer';
    }
    print $q->br,$q->submit(-name=>'aktivieren', -value=>'Zugang aktivieren');
}

print '<p><strong>Zur&uuml;ck zur <a href="../">Startseite</a></strong>';
print <<HERE;
<hr><strong>Anmerkung zum Internetzugang</strong>: Dass der Internetzugang
eingeschaltet ist bedeutet nicht notwendigerweise, dass eine
Verbindung ins Internet besteht. Vielmehr wird die Verbindung nur
aufgebaut, wenn Daten aus dem Internet angefordert werden und die
Verbindung wird nach einiger Zeit der Inaktivit&auml;t (zur Zeit 120
Sekunden) von selbst wieder abgebaut. Die Zeitangabe gibt an, wie lange
der Internetzugang maximal aktiv sein darf, bevor er zwangsweise beendet wird.
Er kann natürlich auch früher beendet werden.
HERE

print $q->endform,
      $q->end_html;

A.2.3. inactive.cgi

Dieses Programm wird angezeigt, wenn das Internet nicht freigeschaltet sein sollte.

Dateiname: /usr/local/httpd/cgi-bin/inactive.cgi.

#!/usr/bin/perl

print "Expires: Fri, 31 Dec 1990 23:59:59 GMT\n";
print "Cache-Control: no-cache\n";
print "Content-type: text/html\n\n";

print "<html>\n";
print "<head>\n";
print "    <title>Internet nicht aktiviert!</title>\n";
print "</head>\n";
print "<body>\n";
print "<h1>Das Internet ist nicht aktiviert!</h1>\n";
print "<h3><a href=\"http://server/\">Zurück zur Startseite</a></h3>\n";
print "</body>\n";
print "</html>\n";