Algorithm-ToNumberMunger

 view release on metacpan or  search on metacpan

lib/Algorithm/ToNumberMunger.pm  view on Meta::CPAN


Named-map enum (lookup rules as L</dns_rcode_enum>) for Suricata's
C<flow.reason>, why a flow was logged out: C<timeout> 0, C<forced> 1,
C<shutdown> 2, C<unknown> 3. Numeric inputs are not passed through.

=head2 suricata_action_enum

    { munger => 'suricata_action_enum', default => -1 }

Named-map enum (lookup rules as L</dns_rcode_enum>) for Suricata's
C<alert.action> and the related rule/drop actions: C<allowed> 0, C<blocked>
1, C<pass> 2, C<drop> 3, C<reject> 4, C<alert> 5. In IDS mode the field is
C<allowed>/C<blocked>; the rule-action names are accepted too for IPS feeds
and C<drop> events. Numeric inputs are not passed through.

=head2 postfix_status_enum

    { munger => 'postfix_status_enum', default => -1 }

Named-map enum (lookup rules as L</dns_rcode_enum>) for Postfix's delivery
C<status=> disposition, numbered in a rough sent-to-failed severity order so
a threshold split is meaningful: C<sent> 0, C<deferred> 1, C<bounced> 2,
C<expired> 3, C<deliverable> 4, C<undeliverable> 5, C<hold> 6, C<discard> 7,

lib/Algorithm/ToNumberMunger.pm  view on Meta::CPAN

feature; the ordering is a judgement call, not a registry. Numeric inputs are
not passed through.

=head2 amavis_category_enum

    { munger => 'amavis_category_enum', default => -1 }

Named-map enum (lookup rules as L</dns_rcode_enum>) for the amavisd-new
content category, ordered clean-to-worst: C<clean> 0, C<oversized> 1,
C<unchecked> 2, C<spammy> 3, C<spam> 4, C<badheader> 5, C<banned> 6,
C<infected> 7, C<mtablocked> 8. The hyphenated spellings (C<bad-header>,
C<mta-blocked>) and the legacy C<virus> (for C<infected>) are accepted as
aliases. The Passed/Blocked I<action> itself is a L</bool>; this is the
finer-grained reason. Numeric inputs are not passed through.

=head2 systemd_result_enum

    { munger => 'systemd_result_enum', default => -1 }

Named-map enum (lookup rules as L</dns_rcode_enum>) for a systemd unit
C<result> (as in C<Failed with result 'timeout'>): C<success> 0, C<protocol>
1, C<timeout> 2, C<exit-code> 3, C<signal> 4, C<core-dump> 5, C<watchdog> 6,
C<start-limit-hit> 7, C<oom-kill> 8, C<resources> 9. The underscore spellings

lib/Algorithm/ToNumberMunger.pm  view on Meta::CPAN


    { munger => 'windows_logon_status_enum', default => -1 }

Named-map enum (lookup rules as L</dns_rcode_enum>) for the NTSTATUS
sub-status on a failed Windows logon (events 4625/4776), collapsed to a
compact B<reason category> rather than the raw 32-bit code: C<0xC0000064>
(no such user) 0, C<0xC000006A> (bad password) 1, C<0xC000006D> (generic bad
user/pass) 2, C<0xC000006F> (outside hours) 3, C<0xC0000070> (workstation
restriction) 4, C<0xC0000071> (password expired) 5, C<0xC0000072> (disabled)
6, C<0xC0000193> (account expired) 7, C<0xC0000133> (clock skew) 8,
C<0xC0000224> (must change password) 9, C<0xC0000234> (locked out) 10,
C<0xC000015B> (logon type not granted) 11. Keys are the hex codes exactly as
logged (matched case-insensitively); only the common logon subset is baked in,
so an unlisted code croaks unless a numeric C<default> is given. Numeric
inputs are not passed through.

=head2 windows_impersonation_level_enum

    { munger => 'windows_impersonation_level_enum', default => -1 }

Named-map enum (lookup rules as L</dns_rcode_enum>) for the event 4624

lib/Algorithm/ToNumberMunger.pm  view on Meta::CPAN

Windows often emits in place of the words (Identification / Impersonation) are
accepted as aliases. Numeric inputs are not passed through.

=head2 aad_signin_error_enum

    { munger => 'aad_signin_error_enum', default => -1 }

Named-map enum for the Azure AD / Entra sign-in C<ResultType> error code,
collapsed to a compact B<reason category> rather than the raw code: C<0>
(success) 0, invalid-password (C<50126>, C<50056>) 1, no-such-user (C<50034>)
2, disabled (C<50057>) 3, locked / smart-lockout (C<50053>) 4, password-expired
(C<50055>, C<50144>) 5, MFA-required (C<50074>, C<50076>, C<50079>) 6,
MFA-failed (C<500121>, C<50158>) 7, blocked-by-conditional-access (C<53003>,
C<53000>, C<53001>, C<530032>) 8, session-expired (C<50173>) 9. Although
C<ResultType> is already numeric, the code space is huge and sparse and its
magnitude carries no signal -- this maps the common codes onto a handful of
meaningful buckets (and, unlike L</hash>, keeps related codes together). Keys
are the codes as logged; only the common subset is baked in, so an unlisted
code croaks unless a numeric C<default> is given. Because the output is a
category of our own numbering, numeric inputs are B<not> passed through.

=head2 risk_level_enum

lib/Algorithm/ToNumberMunger.pm  view on Meta::CPAN

			timeout  => 0,
			forced   => 1,
			shutdown => 2,
			unknown  => 3,
		},
	},
	suricata_action => {
		numeric => 0,
		map     => {
			allowed => 0,
			blocked => 1,
			pass    => 2,
			drop    => 3,
			reject  => 4,
			alert   => 5,
		},
	},
	postfix_status => {
		numeric => 0,
		map     => {
			sent          => 0,

lib/Algorithm/ToNumberMunger.pm  view on Meta::CPAN

			},
		},
	},
	amavis_category => {
		numeric => 0,
		map     => {
			# amavisd-new content category, ordered clean -> worst.
			do {
				my @o = qw(
					clean oversized unchecked spammy spam
					badheader banned infected mtablocked
				);
				my %m = map { $o[$_] => $_ } 0 .. $#o;
				$m{'bad-header'}  = $m{'badheader'};
				$m{'virus'}       = $m{'infected'};
				$m{'mta-blocked'} = $m{'mtablocked'};
				%m;
			},
		},
	},
	systemd_result => {
		numeric => 0,
		map     => {
			# systemd unit "result" (e.g. "Failed with result 'timeout'").
			do {
				my @o = qw(

lib/Algorithm/ToNumberMunger.pm  view on Meta::CPAN

			'0xc0000064' => 0,     # user name does not exist
			'0xc000006a' => 1,     # bad password
			'0xc000006d' => 2,     # bad user name or password (generic)
			'0xc000006f' => 3,     # outside authorized hours
			'0xc0000070' => 4,     # workstation restriction
			'0xc0000071' => 5,     # password expired
			'0xc0000072' => 6,     # account disabled
			'0xc0000193' => 7,     # account expired
			'0xc0000133' => 8,     # clock skew between client and server
			'0xc0000224' => 9,     # must change password at next logon
			'0xc0000234' => 10,    # account locked out
			'0xc000015b' => 11,    # logon type not granted
		},
	},
	windows_impersonation_level => {
		numeric => 0,
		map     => {
			# 4624 ImpersonationLevel; ordinal by reach. Text labels plus the
			# two "%%18xx" message tokens Windows most often emits in place.
			anonymous      => 0,
			identification => 1,

lib/Algorithm/ToNumberMunger.pm  view on Meta::CPAN

			# Azure AD / Entra sign-in ResultType codes collapsed to a compact
			# reason category -- the raw code is a huge sparse space whose
			# magnitude carries no signal. Keys are the numeric codes as
			# logged; only the common subset is baked in, the rest take the
			# default.
			'0'      => 0,    # success
			'50126'  => 1,    # invalid username or password
			'50056'  => 1,    # invalid or null password
			'50034'  => 2,    # user does not exist in directory
			'50057'  => 3,    # account disabled
			'50053'  => 4,    # account locked / smart lockout
			'50055'  => 5,    # password expired
			'50144'  => 5,    # AD password expired
			'50074'  => 6,    # strong auth (MFA) required
			'50076'  => 6,    # MFA required by conditional access
			'50079'  => 6,    # user must enroll for MFA
			'500121' => 7,    # MFA denied / authentication failed
			'50158'  => 7,    # external security challenge not satisfied
			'53003'  => 8,    # blocked by conditional access
			'53000'  => 8,    # device not compliant (CA)
			'53001'  => 8,    # device not domain joined (CA)
			'530032' => 8,    # blocked by security policy (CA)
			'50173'  => 9,    # fresh auth token required (session expired)
		},
	},
	risk_level => {
		numeric => 0,
		map     => {
			# Entra Identity Protection riskLevel, ordinal. hidden /
			# unknownFutureValue are left to the default.
			none   => 0,
			low    => 1,

t/mungers.t  view on Meta::CPAN

	my $fs = $M->build( { munger => 'flow_state_enum' } );
	is( $fs->('new'),          0, 'flow_state new' );
	is( $fs->('local_bypass'), 4, 'flow_state local_bypass' );

	my $fr = $M->build( { munger => 'flow_reason_enum' } );
	is( $fr->('timeout'),  0, 'flow_reason timeout' );
	is( $fr->('shutdown'), 2, 'flow_reason shutdown' );

	my $ac = $M->build( { munger => 'suricata_action_enum' } );
	is( $ac->('allowed'), 0, 'suricata_action allowed' );
	is( $ac->('blocked'), 1, 'suricata_action blocked' );
	is( $ac->('drop'),    3, 'suricata_action drop (IPS)' );
}

# ---- Postfix / mail named enums ---------------------------------------------
{
	my $ps = $M->build( { munger => 'postfix_status_enum', default => -1 } );
	is( $ps->('sent'),          0,  'postfix_status sent' );
	is( $ps->('DEFERRED'),      1,  'postfix_status is case-insensitive' );
	is( $ps->('bounced'),       2,  'postfix_status bounced' );
	is( $ps->('undeliverable'), 5,  'postfix_status undeliverable (verify)' );

t/mungers.t  view on Meta::CPAN

	is( $il->('Medium'),      2,  'integrity medium' );
	is( $il->('System'),      4,  'integrity system' );
	is( $il->('mediumplus'),  2,  'integrity mediumplus folds into medium' );
	is( $il->('S-1-16-12288'), 3, 'integrity high mandatory-label SID' );
	ok( $il->('Low') < $il->('System'), 'windows_integrity_level is ordinal' );
	is( $il->('bogus'),       -1, 'integrity default for unlisted' );

	my $ls = $M->build( { munger => 'windows_logon_status_enum', default => -1 } );
	is( $ls->('0xC0000064'),  0,  'logon_status no-such-user (case-insensitive hex)' );
	is( $ls->('0xc000006a'),  1,  'logon_status bad password' );
	is( $ls->('0xc0000234'),  10, 'logon_status locked out' );
	is( $ls->('0xc000015b'),  11, 'logon_status type not granted' );
	is( $ls->('0x0'),         -1, 'logon_status default for a success/unlisted code' );

	my $im = $M->build( { munger => 'windows_impersonation_level_enum', default => -1 } );
	is( $im->('Anonymous'),      0, 'impersonation anonymous' );
	is( $im->('Impersonation'),  2, 'impersonation impersonation' );
	is( $im->('Delegation'),     3, 'impersonation delegation' );
	is( $im->('%%1832'),         1, 'impersonation %%1832 token is identification' );
	is( $im->('%%1833'),         2, 'impersonation %%1833 token is impersonation' );
	ok( $im->('anonymous') < $im->('delegation'), 'windows_impersonation_level ordered by reach' );

t/mungers.t  view on Meta::CPAN

}

# ---- O365 / Azure AD / AWS cloud named enums --------------------------------
{
	# aad_signin_error: the sparse ResultType code space collapsed to reasons.
	my $se = $M->build( { munger => 'aad_signin_error_enum', default => -1 } );
	is( $se->('0'),        0,  'aad_signin_error 0 is success' );
	is( $se->('50126'),    1,  'aad_signin_error 50126 bad-password' );
	is( $se->('50056'),    $se->('50126'), 'aad_signin_error 50056 shares bad-password bucket' );
	is( $se->('50144'),    $se->('50055'), 'aad_signin_error 50144 shares password-expired bucket' );
	is( $se->('53000'),    8,  'aad_signin_error 53000 blocked-by-CA bucket' );
	is( $se->(50053),      4,  'aad_signin_error accepts an integer code' );
	is( $se->('99999'),    -1, 'aad_signin_error default for an unlisted code' );

	my $rl = $M->build( { munger => 'risk_level_enum', default => -1 } );
	is( $rl->('none'),   0,  'risk_level none' );
	is( $rl->('High'),   3,  'risk_level high (case-insensitive)' );
	is( $rl->('hidden'), -1, 'risk_level hidden is off-scale (default)' );
	ok( $rl->('low') < $rl->('high'), 'risk_level is ordinal' );

	my $pt = $M->build( { munger => 'aws_principal_type_enum', default => -1 } );



( run in 2.795 seconds using v1.01-cache-2.11-cpan-800906f7e73 )