#!/usr/bin/perl use strict; # Usage variables my $execname; # Name of script my $usage; # Usage info # Configuration variables my $badport; # List of ports to give extra warning about my $lastdeny; # Last DENY entry from the last run my $blankrep; # If TRUE, send a report even if nothing happened my $ignoreport; # Comma separated list of ports to ignore my $mailto; # Address to mail report to # Parts of the DENY message my $destport; # Destination port in DENY message my $sourceaddr; # Source address in DENY message # Variables used for creating report my $lenaddr; # Length of an address my $lencount; # Length of a port count my $lenport; # Length of a port my $port; # A single port from %addr hash my $addr; # A single address from %addr hash # Other variables my $i; # Index my $numdenies; # Total number of deny entries since last run my $msgfiles; # All "message" files in /var/log, in reverse order # Lists and hashes my @denies; # List of DENY entries my %addr; # All source addresses that have been found my %badport; # "Bad" ports, and number of times found my %ignoreport; # Ports to ignore, and number of times found my %ports; # All ports for a given address # Initialize variables $numdenies = 0; $execname = $0; $execname =~ s/^.+\/(.+)$/\1/; $usage = " Usage: $execname The \"$execname\" script checks for DENY entries in /var/log/messages* and mails a report with any new entries since the last run to the address specified in /etc/deniesrc. This file also has an optional list of destination ports to ignore, \"bad\" ports to flag in the report (such as ports used by Back Orifice and the ilk), and other parameters: LASTDENY: The last DENY entry from the last run. This is used to determine where to start for the next run. Do not edit this unless you know what you are doing. BLANKREP: If this is \"True\", mail a report even if there are no new DENY entries. If this is \"False\", only mail a report if there are new DENY entries. IGNOREPORT: List of ports to ignore. The format is \"68, 113, 137\". BADPORT: List of ports to give special attention to. The format is \"27374, 31337\". MAILTO: Address to mail the report to. For example \"root\". Richard Griswold, griswold\@acm.org - 25 JUL 2000 "; # Get settings ( $lastdeny, $blankrep, $ignoreport, $badport, $mailto ) = &getSettings(); # Get list of DENY messages $msgfiles = join ' ', sort { $b cmp $a } split /\n/, `ls /var/log/messages*`; @denies = split /\n/, `grep -h DENY $msgfiles`; # Check if any denies if ( $#denies == -1 ) { if ( $blankrep eq "TRUE" ) { &mailBlank( $mailto, $ignoreport, $badport, $lastdeny ); } exit; } # Build ignore and bad port hashes %badport = &createHash( $badport ); %ignoreport = &createHash( $ignoreport ); # Not run previously if $lastdeny is zero if ( $lastdeny eq "NONE" ) { $i = 0; } else { # Find $lastdeny in @denies for ( $i = 0; $i <= $#denies; $i++ ) { if ( $denies[$i] eq $lastdeny ) { last; } } # Adjust index if ( $i < $#denies ) { # Go to next entry, if there is one $i++; } elsif ( $i == $#denies ) { # No new entries if at end of list if ( $blankrep eq "TRUE" ) { &mailBlank( $mailto, $ignoreport, $badport, $lastdeny ); } exit; } else { # Past end of list, so all entries are new $i = 0; } } # Run through all entries since $lastdeny for ( ; $i <= $#denies; $i++, $numdenies++ ) { # Get destination port for this DENY entry $destport = $denies[$i]; $destport =~ s/^.+:[0-9]+ [0-9\.]+:([0-9]+) .+$/$1/; # If $destport is one to ignore, increment count # and skip to next port if ( $ignoreport{$destport} ne '' ) { $ignoreport{$destport}++; next; } # If $destport is a bad port, increment count if ( $badport{$destport} ne '' ) { $badport{$destport}++; } # Get source address $sourceaddr = $denies[$i]; $sourceaddr =~ s/^.+ ([0-9\.]+):[0-9]+ [0-9\.]+.+$/$1/; # Add port to list for this address $addr{$sourceaddr}{$destport}++; # A hash of hashes :) } # Write last entry to /etc/deniesrc &writeEntry( $denies[$#denies] ); # ---------- Print report ---------- # Heading open PROC, "| mail -s\"Denies report for ".localtime()."\" $mailto"; # Total number of DENY entries print PROC "There were $numdenies new entries since the last run\n\n"; # Ignored ports $lenport = 4; $lencount = 5; foreach ( keys %ignoreport ) { $i = length $_; if ( $i>$lenport ) { $lenport =$i; } $i = length $ignoreport{$_}; if ( $i>$lencount ) { $lencount=$i; } } print PROC "Ignored ports:" . ' ' x ( $lenport - 3 ) . "Port" . ' ' x ( $lencount - 2 ) . "Times\n"; foreach ( sort {$a <=> $b} ( keys %ignoreport ) ) { print PROC ' ' x ( 15 + $lenport - length $_ ) . $_ . ' ' x ( 3 + $lencount - length $ignoreport{$_} ) . "$ignoreport{$_}\n"; } print PROC "\n"; # "Bad" ports $lenport = 4; $lencount = 5; foreach ( keys %badport ) { $i = length $_; if ( $i>$lenport ) { $lenport = $i; } $i = length $badport{$_}; if ( $i>$lencount ) { $lencount = $i; } } print PROC "Bad ports:" . ' ' x ( $lenport + 1 ) . "Port" . ' ' x ( $lencount - 2 ) . "Times\n"; foreach ( sort {$a <=> $b} ( keys %badport ) ) { print PROC ' ' x ( 15 + $lenport - length $_ ) . $_ . ' ' x ( 3 + $lencount - length $badport{$_} ) . "$badport{$_}\n"; } print PROC "\n"; # Non-ignored addresses and ports $lenaddr = 7; $lenport = 4; $lencount = 5; foreach ( keys %addr ) { $i = length $_; if ( $i > $lenaddr ) { $lenaddr = $i; } foreach $port ( keys %{ $addr{$_} } ) { $i = length $port; if ( $i>$lenport ){$lenport =$i;} $i = length $addr{$_}{$port}; if ( $i>$lencount ){$lencount=$i;} } } print PROC "Address" . ' ' x ( $lenaddr + $lenport - 8 ) . "Port" . ' ' x ( $lencount - 2 ) . "Times\n"; foreach ( sort sortAddr ( keys %addr ) ) { $addr = $_; foreach $port ( sort {$a <=> $b} ( keys %{ $addr{$_} } ) ) { print PROC $addr . ' ' x ( 3 + $lenaddr + $lenport - length( $addr ) - length $port ) . $port . ' ' x ( 3 + $lencount - length $addr{$_}{$port} ) . "$addr{$_}{$port}\n"; # Blank out address for subsequent ports $addr = ' ' x length $addr; } print PROC "\n"; } # Settings print PROC "\nSettings:\n"; print PROC " Ignored ports: $ignoreport\n"; print PROC " Bad ports: $badport\n"; print PROC " Mail blank reports: $blankrep\n"; print PROC " Mail report to: $mailto\n"; print PROC " Last DENY entry: $lastdeny\n\n"; # Raw DENY entries print PROC "\nRaw DENY entries:\n"; for ( $i = $#denies - $numdenies + 1; $i <= $#denies; $i++ ) { print PROC " $denies[$i]\n"; } print PROC "--- End of report ---\n"; #-------------- # getSettings | #------------------------------------------------------------------- # Get settings from /etc/deniesrc file #------------------------------------------------------------------- sub getSettings { my $ignoreport; # List of ports to ignore my $badport; # List of ports to give extra warning about my $lastdeny; # Last DENY entry from the last run my $blankrep; # If TRUE, send a report even if nothing happened my $mailto; # Address to mail report to # Defaults $blankrep = "TRUE"; $ignoreport = $badport = $lastdeny = $mailto = "NONE"; # Create RC file if necessary if ( not -e "/etc/deniesrc" ) { &createRCFile(); $mailto = "root"; return $lastdeny, $blankrep, $ignoreport, $badport, $mailto; } # Check if we can read and write RC file -r "/etc/deniesrc" or die "Cannot read /etc/deniesrc\n"; -w "/etc/deniesrc" or die "Cannot write /etc/deniesrc\n"; # Open RC file open( RCFILE, "</etc/deniesrc" ) or die "Cannot open resource file /etc/deniesrc for reading\n"; # Get options foreach ( <RCFILE> ) { chop; if ( ( $_ =~ /^ *#.+$/ ) or ( $_ eq "" ) ) { next; } elsif ( $_ =~ /^LASTDENY:/ ) { $lastdeny = $_; $lastdeny =~ s/^LASTDENY: +(.+)$/$1/; } elsif ( $_ =~ /^BLANKREP:/ ) { $blankrep = $_; $blankrep =~ s/^BLANKREP: +(.+)$/$1/; } elsif ( $_ =~ /^IGNOREPORT:/ ) { $ignoreport = $_; $ignoreport =~ s/^IGNOREPORT: +(.+[0-9]+) *$/$1/; } elsif ( $_ =~ /^BADPORT:/ ) { $badport = $_; $badport =~ s/^BADPORT: +(.+[0-9]+) *$/$1/; } elsif ( $_ =~ /^MAILTO:/ ) { $mailto = $_; $mailto =~ s/^MAILTO: +(.+)$/$1/; } else { print "Line \"$_\" is not valid in /etc/deniesrc. Ignoring.\n"; } } close RCFILE; # Validate options if ( $blankrep ne "NONE" ) { if ( ( uc( $blankrep ) ne "TRUE" ) and ( uc( $blankrep ) ne "FALSE" ) ) { print "Keyword \"$blankrep\" is not valid for option \"BLANKREP:\".\n"; print " Ignoring.\n"; } $blankrep = uc $blankrep; } if ( $ignoreport ne "NONE" ) { if ( &validPortList( $ignoreport ) < 0 ) { print "List \"$ignoreport\" is not valid for option \"IGNOREPORT:\".\n"; print " Ignoring.\n"; $ignoreport = ""; } } if ( $badport ne "NONE" ) { if ( &validPortList( $badport ) < 0 ) { print "List \"$badport\" is not valid for option \"BADPORT:\".\n"; print " Ignoring.\n"; $badport = ""; } } if ( $mailto eq "NONE" ) { $mailto = "root"; } return $lastdeny, $blankrep, $ignoreport, $badport, $mailto; } #--------------- # createRCFile | #------------------------------------------------------------------- # Create the /etc/deniesrc file #------------------------------------------------------------------- sub createRCFile { open FILE ,">/etc/deniesrc" or die "Cannot create /etc/deniesrc file\n"; print FILE "# RC file for \"denies\" script\n\n"; print FILE "# NOTE: Do not edit the following line:\n"; print FILE "LASTDENY:\n\n"; print FILE "# Set this line to \"False\" if you do not want to get blank\n"; print FILE "# reports (reports when there are no DENY entries).\n"; print FILE "BLANKREP: True\n\n"; print FILE "# Put the list of ports to ignore on this line.\n"; print FILE "# Use the format \"68, 113, 137\".\n"; print FILE "IGNOREPORT: NONE\n\n"; print FILE "# Put the list of \"bad\" ports on this line. These are \n"; print FILE "# ports you want extra notification about, such as the \n"; print FILE "# Back Orifice 31337 port. Use the same format as above.\n"; print FILE "BADPORT: NONE\n\n"; print FILE "# Put the address you want to send the report to here.\n"; print FILE "MAILTO: root\n"; close FILE; chmod 0600, "/etc/deniesrc"; } #---------------- # validPortList | #------------------------------------------------------------------- # Check if a port list is in a valid format (ie 10, 31, 138, ...) #------------------------------------------------------------------- sub validPortList { foreach ( split /, /, shift ) { if ( $_ !~ /^[0-9]+$/ ) { return -1; } } return 0; } #------------ # mailBlank | #------------------------------------------------------------------- # Mail a blank report #------------------------------------------------------------------- sub mailBlank { my $mailto = shift; my $ignoreport = shift; my $badport = shift; my $lastdeny = shift; open PROC, "| mail -s\"Denies report for ".localtime()."\" $mailto"; print PROC "There were no new entries for since the last run\n\n"; print PROC "Settings:\n"; print PROC " Ignored ports: $ignoreport\n"; print PROC " Bad ports: $badport\n"; print PROC " Mail blank reports: $blankrep\n"; print PROC " Mail report to: $mailto\n"; print PROC " Last DENY entry: $lastdeny\n\n"; print PROC "--- End of report ---\n"; close PROC; } #------------- # createHash | #------------------------------------------------------------------- # Create a hash from a comma separated list #------------------------------------------------------------------- sub createHash { my $list = shift; $list =~ s/, /, 0, /g; $list .= ", 0"; return split /, /, $list; } #------------- # writeEntry | #------------------------------------------------------------------- # Write last DENY entry inot /etc/deniesrc #------------------------------------------------------------------- sub writeEntry { my $lastdeny = shift; my @rcfile; open FILE, "</etc/deniesrc" or die "Cannot open resource file /etc/deniesrc for reading\n"; foreach ( <FILE> ) { if ( $_ =~ /^LASTDENY:/ ) { $_ =~ s/^(LASTDENY:)$/$1 /; # Put in spaces if none $_ =~ s/^(LASTDENY: +).*$/$1$lastdeny/; } push @rcfile, $_; } close FILE; open FILE ,">/etc/deniesrc" or die "Cannot open resource file /etc/deniesrc for writing\n"; foreach ( @rcfile ) { print FILE $_; } close FILE; } #----------- # sortAddr | #------------------------------------------------------------------- # Sort IP addresses #------------------------------------------------------------------- sub sortAddr { my @a = split /\./, $a; my @b = split /\./, $b; my $i; for ( $i = 0; $i < 4; $i++ ) { if ( $a[$i] < $b[$i] ) { return -1; } elsif ( $a[$i] > $b[$i] ) { return 1; } } return 0; }

In reply to report ipchains DENY entries in /var/log/messages* files by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.