Captive-Portal
view release on metacpan or search on metacpan
lib/Captive/Portal/Role/Firewall.pm view on Meta::CPAN
}
# proper order of steps is essential for uninterrupted reloads
foreach my $step (qw/flush init mangle nat filter/) {
$self->$_fw_install_rules($step);
# after the init step prefill the capo_sessions
# with cached sessions from disk
$self->fw_reload_sessions if $step eq 'init';
}
}
=item $capo->fw_stop()
Calls the firewall template I<flush>, see the corresponding firewall template under I<templates/orig/firewall/>.
=cut
sub fw_stop {
my $self = shift;
if ( $self->cfg->{MOCK_FIREWALL} ) {
DEBUG 'MOCK_FIREWALL, mocking stop firewall';
return 1;
}
$self->$_fw_install_rules('flush');
}
=item $capo->fw_purge_sessions()
Detect idle sessions, mark them as IDLE in disk cache and remove entry in ipset.
=cut
sub fw_purge_sessions {
my $self = shift;
DEBUG 'running ' . __PACKAGE__ . ' fw_purge_sessions ...';
if ( $self->cfg->{MOCK_FIREWALL} ) {
DEBUG 'MOCK_FIREWALL, mocking purge';
return 1;
}
my $this_run = time();
######
# 3 sources of information about a session
#
# - session cache on disk with ip/mac/user/state/timestamps/...
# - ipset capo_sessions_ipset with ip address as key, mac address as value
# - ipset capo_activity_ipset with ip address as key, mac address as value
#
my $fw_sessions = $self->fw_list_sessions;
my $fw_activity = $self->fw_list_activity;
# Walk over all disk sessions, be aware, only current session is locked!
# There will be race conditions with running fcgi processes
# for sessions not currently handled (locked), but see below
# for handling these races.
#
# This is by intention not locking for a long time and delaying
# http responses!
foreach my $ip ( $self->list_sessions_from_disk ) {
my ( $lock_handle, $error );
try {
# get the EXCL lock for the session file
# hold this lock until next loop iteration
# via lexical scope of $lock_handle
#
$lock_handle = $self->get_session_lock_handle(
key => $ip,
blocking => 1,
shared => 0, # EXCL
timeout => 50_000, # 50_000 us -> 50ms
);
}
catch { $error = $_ };
if ($error) {
WARN $error; # could not get the EXCL lock, skip this session
next; # session
}
my $session = $self->read_session_handle($lock_handle);
unless ($session) {
DEBUG "delete empty or malformed session: $ip";
$self->delete_session_from_disk($ip);
next; # session
}
# The session ip must also be in the ipset capo_sessions_ipset.
# fetch and delete it. If there are still ipset entries
# left after the loop over all sessions, handle it as error
# or as race condition at end of the purger
my $fw_session_entry = delete $fw_sessions->{$ip};
# tmp store for easier logging, no other functionality
my $mac = $session->{MAC};
my $user = $session->{USERNAME};
######## let's start
###########################################################
# remove old sessions with STATES like (logout, idle, max-session-...)
# after KEEP_OLD_STATE_PERIOD
###########################################################
if ( $session->{STATE} ne 'active' ) {
# remove really old sessions not in active STATE
if ( $this_run - $session->{STOP_TIME} >
( run in 3.644 seconds using v1.01-cache-2.11-cpan-ad19def0cd9 )