package My::parser::ssh_parser; use strict; use warnings; sub new { my $class = shift; my $self = {}; bless ($self, $class); return $self; } sub parser { my $self = shift; my $string = shift; my ($reply,$hostile,$host) = ('',0,''); my $re_host = qr/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/; my $re_user = qr/[\w\d_\-.]*/; if($string =~ m/Accepted publickey for/) { $reply = 'Accept publickey'; } elsif($string =~ m/Received disconnect from $re_host port [0-9]{1,5}:11: disconnected by user/) { $reply = 'Normal disconnect'; } elsif($string =~ m/Failed unknown for (invalid user |)$re_user from $re_host port [0-9]{1,5} ssh2/) { $reply = 'Log spam, also logged as a failure'; } elsif($string =~ m/Disconnected from user $re_user $re_host port [0-9]{1,5}$/) { $reply = 'Normal disconnect'; } elsif($string =~ m/Did not receive identification string from /) { $_ = $string; $reply = 'No identification string'; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/User $re_user from $re_host not allowed because /) { $_ = $string; $reply = 'Blocked user'; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/(i|I)nvalid user .* from $re_host port/) { $_ = $string; $reply = 'Invalid user'; $hostile = 1; PARSER: m/(from\ ($re_host)) /gcix && do { $host = $2; }; } elsif($string =~ m/(Disconnecting|Received disconnect from|Disconnected from|Connection closed by|Connection reset by) (authenticating |invalid |)(user .* |)$re_host port [0-9]{1,6}.*\[preauth\]/) { $_ = $string; $reply = 'Received disconnect'; $hostile = 1; PARSER: m/\ ($re_host)\ /gcix && do { $host = $1; }; } elsif($string =~ m/refused connect from .* \($re_host\)/) { $_ = $string; $reply = 'Blocked by tcpwrappers'; $hostile = 1; PARSER: m/ \(($re_host)\) /gcix && do { $host = $1; }; } elsif($string =~ m/error: maximum authentication attempts exceeded for (invalid user |)$re_user from ($re_host) port [0-9]{1,6} (ssh2 |)\[preauth\]/) { $_ = $string; $reply = 'Auth attempt limit exceeded'; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/fatal: Unable to negotiate with/) { $_ = $string; $reply = 'Unable to negotiate'; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/Bad protocol version identification/) { $_ = $string; $reply = 'Bad protocol'; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/Could not write ident string to/) { $_ = $string; $reply = 'Could not write ident string'; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/Disconnecting (authenticating|invalid) user.*Change of username or service not allowed/) { $_ = $string; $reply = "Change of username or service"; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/Failed publickey for $re_user from $re_host port [\d]{1,6}.*/) { $_ = $string; $reply = 'Failed publickey'; $hostile = 1; PARSER: m/\ ($re_host)\ /gcix && do { $host = $1; }; } elsif($string =~ m/ssh_dispatch_run_fatal/) { $_ = $string; $reply = 'ssh dispatch fatal'; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/Unable to negotiate with $re_host port/) { $_ = $string; $reply = 'Unable to negotiate. Weak key exchange'; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/Protocol major versions differ for/) { $_ = $string; $reply = 'Protocol major versions differ'; $hostile = 1; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/Unable to negotiate with .* no matching MAC found/) { $host = ''; $reply = 'no matching MAC, ancient client trying to connect'; } elsif($string =~ m/\/etc\/hosts\.allow/) { $host = ''; } elsif($string =~ m/Disconnecting: Too many authentication failures/) { $host = ''; } elsif($string =~ m/input_userauth_request: invalid user.*\[preauth\]/) { $host = ''; } elsif($string =~ m/user $re_user login class/) { $host = ''; $reply = 'Useless log info'; } elsif($string =~ m/(Disconnected|Connection closed) (from|by) (invalid|) user $re_user $re_host port [0-9]{1,6} \[preauth\]/) { $host = ''; $reply = 'Log info'; } elsif($string =~ m/Fssh_kex_exchange_identification/) { $hostile = 0; $reply = 'kex exchange identification problem'; } elsif($string =~ m/fatal: Timeout before authentication for $re_host port [0-9]{1,6}/) { $_ = $string; $hostile = 1; $reply = 'Timeout before auth'; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } elsif($string =~ m/banner exchange: Connection from $re_host port [0-9]{1,6}: (invalid format|Permission denied|could not read protocol version)/) { $_ = $string; $hostile = 1; $reply = 'Error during banner exchange'; PARSER: m/ ($re_host) /gcix && do { $host = $1; }; } else { $reply = 'No match for '.$string; } return { retval => 1, retmsg => $reply, hostile => $hostile, host => $host, string => $string }; } 1;