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 )