NAME
Ereshkigal::Kur - FW handler for Ereshkigal.
VERSION
Version 0.0.1
SYNOPSIS
use Ereshkigal::Kur;
my $kur = Ereshkigal::Kur->new(
'name' => 'sshd',
'backend' => 'ipfw',
'ports' => ['22'],
'protocols' => ['tcp'],
);
$kur->start_server;
Each Kur instance wraps a single Net::Firewall::BlockerHelper instance and serves it up via a POE::Component::Server::JSONUnix server listening on a unix socket under $run_base_dir/kur/.
METHODS
new
Initiates the object. All errors are considered fatal, meaning if new fails it will die.
- name :: Name of this specific instance. Must match /^[a-zA-Z0-9\-]+$/.
Default :: undef
- backend :: The backend to use for Net::Firewall::BlockerHelper.
Default :: undef
- ports :: An array of ports to block, passed to Net::Firewall::BlockerHelper.
Default :: []
- protocols :: An array of protocols to block, passed to Net::Firewall::BlockerHelper.
Default :: []
- prefix :: Prefix to use, passed to Net::Firewall::BlockerHelper.
Default :: undef, left for the backend to default to kur
- options :: Backend specific options hash, passed to Net::Firewall::BlockerHelper.
Default :: undef, left for the backend to default to {}
- self_heal :: Self heal setting, passed to Net::Firewall::BlockerHelper.
Default :: undef, left for the backend to default to 1
- ban_time :: How long bans should last in seconds. 0 means bans never
time out. May be overridden per ban request.
Default :: 600
- checkpoint :: Seconds between periodic rewrites of the ban state CSV.
0 disables the periodic rewrite... ban/unban, stop, and on demand
checkpoints still happen.
Default :: 60
- enable_cidr :: Boolean for whether CIDR banning is enabled for this
instance. Even when set, CIDR commands only work if the backend
supports CIDR bans. Config files carry strings rather than
booleans, so the value is folded... undef, the empty string, 0,
false, no, and off are all off, and anything else at all is on.
Default :: 0
- cidr_silent_drop :: Boolean for how a CIDR command is handled when CIDR
banning is not available for this instance, either because
enable_cidr is off or the backend does not support it. When set the
command is silently dropped, returning dropped => 1, rather than
erroring, which is the point when fanning out to a mix of CIDR
capable and incapable instances. Folded the same way enable_cidr
is.
Default :: 0
- run_base_dir :: Base dir for run files. The socket and PID for this
instance live under C<$run_base_dir/kur/> named for this instance.
Default :: /var/run/ereshkigal
- cache_base_dir :: Base dir for cache files. The ban state and the
unban retry state for this instance are persisted as CSVs under
here, named for the instance, so timed bans and unbans still owed
to the firewall both survive a restart. See L</state_path>,
L</cidr_state_path>, L</retry_state_path>, and
L</cidr_retry_state_path> for the four.
Default :: /var/cache/ereshkigal
socket_path
Returns the path of the unix socket for this instance.
my $socket_path = $kur->socket_path;
pid_path
Returns the path of the PID file for this instance.
my $pid_path = $kur->pid_path;
state_path
Returns the path of the ban state CSV for this instance.
my $state_path = $kur->state_path;
cidr_state_path
Returns the path of the CIDR ban state CSV for this instance. This is kept separate from "state_path" so the single IP state format stays untouched.
my $cidr_state_path = $kur->cidr_state_path;
retry_state_path
Returns the path of the unban retry state CSV for this instance, the tablet carrying entries whose unban at expiry failed and is still owed to the firewall.
my $retry_state_path = $kur->retry_state_path;
cidr_retry_state_path
Returns the path of the CIDR unban retry state CSV for this instance, the CIDR counterpart of "retry_state_path".
my $cidr_retry_state_path = $kur->cidr_retry_state_path;
start_server
Starts up the POE::Component::Server::JSONUnix server for this instance, calling $poe_kernel->run.
This should not be expected to return till the server is told to stop.
The socket is chmoded to 0600 given only the manager, running as the same user, talks to it.
A ban sweeper is also started, which checks once a second for timed bans that have expired and unbans them, and handles the periodic checkpointing of the ban state CSVs. SIGTERM and SIGINT are handled, checkpointing and tearing the backend down the same as the stop command before exiting.
IPs passed to ban and unban are validated and normalized to their canonical string form, so variant spellings of the same IP, most notably IPv6 long form vs short form as well as case, are all treated as the same IP. For ban anything failing to validate errors per IP without disturbing the rest of the request, while for unban it is fatal to the request.
The JSON commands handled are as below.
- ban :: Ban the IPs specified via the array args.ips. args.ban_time,
if defined, overrides the instance default for how long the bans
should last in seconds, with 0 meaning never time out. Banning an
already banned IP just refreshes its timer.
- unban :: Check if the IP, args.ip, is banned and if so unban it.
- cidr_ban :: Ban the CIDR ranges specified via the array args.cidrs,
otherwise behaving like ban. Only handled when enable_cidr is set
and the backend supports CIDR bans, otherwise it is either dropped
or refused per cidr_silent_drop.
- cidr_unban :: Check if the CIDR, args.cidr, is banned and if so unban
it. Gated the same as cidr_ban.
- banned :: Return a list of banned IPs along with an expires map of
when each times out, 0 meaning never. banned_cidr and cidr_expires
carry the same for CIDR bans. unban_retries and cidr_unban_retries
carry the per entry book keeping for unbans still owed to the
firewall.
- status :: Return instance status info and stats, including ban_time,
counts of timed and permanent bans, the next expiry, and how many
unbans are still owed to the firewall along with how long the
longest owed has been outstanding.
- flush :: Unban everything currently banned, ranges as well as single
IPs, emptying both ban books and both unban retry books with them.
- re_init :: Have the backend tear its firewall setup down and build it
again, re-banning everything the ban books carry. Bans are not
enforced while that is happening. Tearing down takes any rule a
failed unban left behind, so the retry books are emptied too.
- checkpoint :: Write the ban state CSVs out now.
- clear_retries :: Forget unbans still owed to the firewall, either the
single one named by args.ip or args.cidr, or all of them when
neither is given. Only the book keeping is forgotten, nothing is
asked of the firewall, so anything genuinely still banished there
stays that way.
- stop :: Checkpoint, teardown the backend, and exit.
ERROR CODES / ERROR FLAGS
Error handling is provided by Error::Helper. All errors are considered fatal.
1, NErunBaseDir
The run base dir or the kur dir under it does not exist or is not a directory.
2, invalidName
Name not defined or does not match /^[a-zA-Z0-9\-]+$/.
3, backendInitFailed
Failed to initialize the backend.
4, nonRWrunBaseDir
The run base dir or the kur dir under it is not readable or writable by the current user.
5, NEcacheBaseDir
The cache base dir does not exist or is not a directory.
6, nonRWcacheBaseDir
The cache base dir is not readable or writable by the current user.
7, invalidBanTime
ban_time is not a non-negative int of seconds.
8, invalidCheckpoint
checkpoint is not a non-negative int of seconds.