如何在perl中

时间:2016-04-10 08:55:35

标签: regex perl

这是我的第一篇帖子所以请耐心等待我,我想计算与ssh日志文件不同的时间,其格式如下

Jan 10 hr:min:sec Failed password for invalid user root from "ip" port xxx ssh2
Jan 10 hr:min:sec sshd[]: User root from "ip" not allowed because none of user's groups are listed in AllowGroups

当用户在10分钟内未能登录x次时,脚本会发出警报,有什么可以教我怎么做?

谢谢!

1 个答案:

答案 0 :(得分:0)

您的规范有点含糊不清 - 可能在您的日志文件中会有两行以上 - 您想要连续行之间的时差吗?您是否希望解析一行搜索关键字(例如“登录失败”),然后将时间差分别解析为另一条线?

由于我无法判断你提供的是什么,我只是假设文件中有两行在每行的开头都有一个日期,你想要这些日期之间的时差。然后你可以操纵做你想做的事。或者,添加到您的问题并准确定义“登录失败”是什么。

有很多方法可以对这只猫进行皮肤处理,但我更喜欢DateTime::Format::Strptime中的strptime函数,该函数被描述为;

对于DateTime,该模块实现了大部分strptime(3),即与strftime(3)相反的POSIX函数。虽然strftime采用DateTime和模式并返回一个字符串,但strptime接受一个字符串和一个模式并返回相关的DateTime对象。

这将如上所述;

use v5.12;
use DateTime::Format::Strptime;

my $logfile = "ssh.log";
open(my $fh, '<', $logfile) or die "$logfile: $!";

my $strp = DateTime::Format::Strptime->new(
    pattern   => '%h %d %T ',
    time_zone => 'local',
    on_error  => 'croak',
);

my $dt1 = $strp->parse_datetime(scalar <$fh>);
my $dt2 = $strp->parse_datetime(scalar <$fh>);

my $duration = $dt2->subtract_datetime_absolute($dt1);
say "Number of seconds difference is: ", $duration->seconds ;
#
# Input
# Jan 10 14:03:18 Failed password for invalid user root from "ip" port xxx ssh2
# Jan 10 14:03:22 sshd[]: User root from "ip" not allowed because none of user's groups are listed in AllowGroups
#
# Outputs:
# Number of seconds difference is: 4

更全面的答案(做出更多假设)如下:

use v5.12;
use DateTime::Format::Strptime;
use DateTime::Duration;

my $logfile = "ssh.log";
my $maximum_failures_allowed = 3 ;
my $minimum_time_frame = 10 * 60;  # in seconds

my $limit = $maximum_failures_allowed - 1 ;

# The following is a list of rules indicating a
# failed login for the username captured in $1
my @rules = (
      qr/Failed password for user (\S+) / ,
      qr/User (\S+) from [\d\.]+ not allowed/
   );

my $strp = DateTime::Format::Strptime->new(
    pattern   => '%h %d %T ',
    time_zone => 'local',
    on_error  => 'croak',
);

my %usernames ;

open(my $fh, '<', $logfile) or die "$logfile: $!";
while (<$fh>) {
    for my $rx (@rules) {
        if ( /$rx/ )  {
            # rule matched -> login fail for $1.  Save log line.
            my $user = $1 ;
            push  @{ $usernames{$user} }  ,  $_ ;

            # No point checking other rules...
            last ;
        }
    }
}
close $fh ;

for my $user (keys %usernames) {
    my @failed_logins = @{ $usernames{$user} };

    # prime the loop; we know there is at least one failed login
    my $this_line  = shift @failed_logins ;

    while ( @failed_logins > $limit )  {
        my $other_line = $failed_logins[ $limit ] ;
        my $this_time  = $strp->parse_datetime($this_line) ;
        my $other_time = $strp->parse_datetime($other_line) ;

        #  this produces a DateTime::Duration object with the difference in seconds
        my $time_frame = $other_time->subtract_datetime_absolute( $this_time );

        if ($time_frame->seconds < $minimum_time_frame) {
            say   "User $user had login failures at the following times:" ;
            print "  $_" for $this_line, @failed_logins[ 0 .. $limit ] ;

            # (s)he may have more failures but let's not labour the point
            last ;
        }

        # Here if user had too many failures but within a reasonable time frame
        # Continue to move through the array of failures checking time frames
        $this_line  = shift @failed_logins ;
    }
}
exit 0;

掌握这些数据;

Jan 10 14:03:18 sshd[15798]: Failed password for user root from "ip" port xxx ssh2
Jan 10 14:03:22 sshd[15798]: User root from 188.124.3.41 not allowed because none of user's groups are listed in AllowGroups
Jan 10 20:31:12 sshd[15798]: Connection from 188.124.3.41 port 32889
Jan 10 20:31:14 sshd[15798]: Failed password for user root from 188.124.3.41 port 32889 ssh2
Jan 10 20:31:14 sshd[29323]: Received disconnect from 188.124.3.41: 11: Bye Bye
Jan 10 22:04:56 sshd[25438]: Connection from 200.54.84.233 port 45196
Jan 10 22:04:58 sshd[25438]: Failed password for user root from 200.54.84.233 port 45196 ssh2
Jan 10 22:04:58 sshd[30487]: Received disconnect from 200.54.84.233: 11: Bye Bye
Jan 10 22:04:59 sshd[21358]: Connection from 200.54.84.233 port 45528
Jan 10 22:05:01 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
Jan 10 22:05:02 sshd[2624]: Received disconnect from 200.54.84.233: 11: Bye Bye
Jan 10 22:05:29 sshd[21358]: Connection from 200.54.84.233 port 45528
Jan 10 22:05:30 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
Jan 10 22:05:33 sshd[2624]: Received disconnect from 200.54.84.233: 11: Bye Bye
Jan 10 22:06:49 sshd[21358]: Connection from 200.54.84.233 port 45528
Jan 10 22:06:51 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
Jan 10 22:06:51 sshd[2624]: Received disconnect from 200.54.84.233: 11: Bye Bye

...它产生了这个输出;

User root had login failures at the following times:
  Jan 10 22:04:58 sshd[25438]: Failed password for user root from 200.54.84.233 port 45196 ssh2
  Jan 10 22:05:01 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
  Jan 10 22:05:30 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2
  Jan 10 22:06:51 sshd[21358]: Failed password for user root from 200.54.84.233 port 45528 ssh2

请注意,日志文件数据中不存在时区和/或偏移量 - 因此,此脚本无法在您输入或保留“夏令时”的当天正常工作。