I wrote a small script to parse my log files, retrieve ip addresses, add them to a blacklist and append rules to my firewall (iptables).

My first question is, in the first "while loop" I used some regex's to get the data that I wanted. Is there a better way to perhaps combine them on fewer lines?

My second question is, the second "while loop" opens the file that I just appended to, and filters out blank lines, IP addresses on my network and duplicate entries. Is there a way that I can do that possibly within the first "while loop"?

I guess what I'm trying to accomplish with my second question is cut down on the number of times I open and close the same file.

I am still learning and am open to any suggestions. Here is what I have now.

#!/usr/bin/perl -w # # This script grabs ip addresses from my firewall log file # and adds them to a blacklist for my iptables ruleset. # ## NOTE - This script must be run as root use strict; # Check to make sure root is running this if ($< != 0) { print "You must run this program as root!\n"; exit } my $log = "/var/log/iptables.log"; my $blacklist = "/var/log/blacklist"; my @list; my %seen; my @sorted; # Open log file, retrieve list of ip addresses and write them # to the blacklist open(IN, "<", $log) || die "Can not open $log $!"; open(BL, ">>", $blacklist) || die "Can not open $blacklist $!"; while (<IN>) { s/.*(SRC)/$1/; s/(DST).*/$1/; s/ DST//; s/SRC=//; print BL ; } close IN; close BL; # Read blacklist into an array while eliminating blank lines, # IP's from my network and duplicates open(BL, "<", $blacklist) || die "can not open $blacklist $!"; while (<BL>) { next if /\A\s*\z/ ; # skip blank lines next if /192.168*/; $seen{$_}++; next if $seen{$_} > 1; push(@list, $_); } close BL; # Sort my list of IP addresses @sorted = sort { pack('C4' => $a =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) cmp pack('C4' => $b =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/) } @list; # Create clean blacklist file and append iptables rules open(BL, ">", $blacklist) || die "Cannot open $blacklist $!"; foreach my $ip(@sorted) { print BL "$ip"; chomp($ip); system("/sbin/iptables -A BLACKLIST -p all -s $ip -d 0/0 -j LOG -- +log-prefix \"IPTABLES:Blacklist: \""); system("/sbin/iptables -A BLACKLIST -p all -s $ip -d 0/0 -j DROP") +; } close BL; chmod 0600, "$blacklist";

In reply to Questions regarding regular expressions and arrays by at2marty

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.