whistler has asked for the wisdom of the Perl Monks concerning the following question:

This started out as a way to help a friend out with a project and quickly morphed in to a desire to learn a whole lot more about perl, but right at the moment my brain's hurting and feeling bruised from all the wall-induced blunt trauma.

Basically, there's a log file that's going to be dumped from a network monitoring tool which will be updating in real time. The objective is to read the logfile every 30 seconds (or even better when it's updated) and use the win32::GUI module to display the IP addresses in an alert window.

There are several problems, just begining to work out various ways to control when the loop repeats looking for new events was painful but I stumbled upon the idea of using the file data and comparing the modified time to the system time, so that's in there.

The other big problem is that it will only display one alert window and then just runs indefinitely without giving out any other perls of wisdom.

The third potential issue (if I get that far) is to make sure that it doesn't re-notify about events that have been previously noted. Deleting the events as the window occurs is an acceptable solution as I can generate two copies of the log file.

Now I'm going to include The various mashups of code and a few few events from the text file.

code snippet 1:

use warnings; use Win32::GUI(); use Win32::Sound; while(1) { $filename="log2.txt"; open(TXT, $filename)||die("Could not open file!"); @filedata = <TXT>; close(TXT); @alert = qw(a b c); $i=0; foreach $element (@filedata) { if($element =~ /(\s+)(\d{1,4})(\.\d{1,4}){3}(\s+)/) { $datetime = localtime(); $alert[$i] = new Win32::GUI::Window(-name => 'Alert', -width => + 500, -height => 200); $font = Win32::GUI::Font -> new(-name => "Arial", size => 46, - +bold => 1); $alert[$i] -> AddLabel(-text => $datetime, -font => $font); $alert[$i] -> AddLabel(-text => $element, -font => $font, -top +=> 50); $alert[$i] -> AddButton(-name => "CloseButton", -text => "OK", +-pos => [ 200, 100 ]); Win32::Sound::Play("SystemExclamation"); $alert[$i] -> Show(); Win32::GUI::Dialog(); ++$i; sub CloseButton_Click { $alert[$i] -> Hide(); } sub Alert_Terminate{ -1; } #open out, ">$filename"; } } }
this was my starting point but it doesn't display more than one window, it's just stuck in a loop.
snippet 2:
use warnings; use Win32::GUI(); use Win32::Sound; # Update interval in seconds $interval = 30; # current time $now = time; #if the file exists, get it's properties if ( -f "log2.txt") { $lastUpdate = (stat("log2.txt"))[9]; $difference = $now - $lastUpdate; } while ($difference > $interval) { $filename="log2.txt"; open(TXT, $filename)||die("Could not open file!"); @filedata = <TXT>; close(TXT); @alert = qw(a b c); $i=0; $datetime = localtime(); $alert = new Win32::GUI::Window( -left => 341, -top => 218, -width => 500, -height => 200, -name => "alert", -text => "alert window" ); $font = Win32::GUI::Font -> new( -name => "Arial", size => 46, -bold => 1); $alert[$i] -> AddLabel( -text => $datetime, -font => $font); $alert[$i] -> AddLabel( -text => $element, -font => $font, -top => 50); $alert->AddButton( -text => "OK", -name => "CloseButton", -left => 200, -top => 100, ); Win32::Sound::Play("SystemExclamation"); $alert[$i] -> Show(); Win32::GUI::Dialog(); ++$i; sub CloseButton_Click { $alert[$i] -> Hide(); } sub Alert_Terminate{ -1; } foreach ($element =~ /(\s+)(\d{1,4})(\.\d{1,4}){3}(\s+)/) {&show_win } }
I realize there are gapping holes in this logic, but I'm tired and I need to go to bed, so that's what I have so far and I'll fall on my knees and praise anyone who can help get me sorted out.

and finally log2.txt:
Time: 10/31-13:36:10.802641 event_ref: 0 192.168.0.203 -> 208.16.3.7 (portscan) TCP Portsweep Priority Count: 5 Connection Count: 8 IP Count: 13 Scanned IP Range: 208.16.3.2:208.16.3.9 Port/Proto Count: 3 Port/Proto Range: 22:3389 Time: 10/31-13:37:58.075795 event_ref: 0 192.168.0.203 -> 208.16.3.4 (portscan) TCP Portsweep Priority Count: 5 Connection Count: 9 IP Count: 13 Scanned IP Range: 208.16.3.2:208.16.3.9 Port/Proto Count: 3 Port/Proto Range: 25:3389 Time: 10/31-13:38:10.031849 event_ref: 0 192.168.0.203 -> 208.16.3.9 (portscan) ICMP Sweep Priority Count: 5 Connection Count: 13 IP Count: 12 Scanned IP Range: 208.16.3.2:208.16.3.10 Port/Proto Count: 0 Port/Proto Range: 0:0 Time: 10/31-13:38:10.032141 event_ref: 0 192.168.0.203 -> 208.16.3.7 (portscan) TCP Portscan Priority Count: 5 Connection Count: 6 IP Count: 1 Scanner IP Range: 192.168.0.203:192.168.0.203 Port/Proto Count: 7 Port/Proto Range: 21:3389
There're about 500 entries in the file I'm currently using for testing, but here're a few to play with and so you can see the format.

P.S. if I missed a bit of forum etiquette or write-up formatting I apologize and blame it on the lack of sleep and lack of experience on this forum. I accept full responsibility.

Replies are listed 'Best First'.
Re: read from network security log file and display lines as alert boxes
by puudeli (Pilgrim) on Dec 30, 2008 at 09:33 UTC

    In order to avoid repeating old alerts you tell how far you have read the file and keep that as a reference so that every time you read the file you can seek to the last position and avoid reading of old lines. This way you can also avoid storing huge amount of lines in the memory as you only read the latest additions. Of course you have to be aware that most of the logs are rotated sometimes so you need to reset the file pointer occasionally. You can use stat to find out when the file has changed (the file size usually shrinks when it is rotated).

    And you really should sleep at least for a second to avoid busy loops and to allow Ctrl-C to arrive faster.

    What if the log has 5000 new lines since the last time you read it? Do you fill the screen with 5000 alerts?

    --
    seek $her, $from, $everywhere if exists $true{love};
Re: read from network security log file and display lines as alert boxes
by lostjimmy (Chaplain) on Dec 30, 2008 at 15:16 UTC
    You might want to have a look at File::Tail. By tailing the file, you won't have to keep track of the last line read or worry about repeating alerts. You also won't have to run your script every 30 seconds, you can just have it run continuously, and your alerts will show up in real time.
Re: read from network security log file and display lines as alert boxes
by Perlbotics (Archbishop) on Dec 30, 2008 at 17:37 UTC

    As other monks have already noticed, it would be annoying to pop-up a new alert-box every time a new incident occurred. Maybe it would be more convenient to have just a single scrollable window, so you can see all incidents that occurred during the last check-interval together with the history of previous events? The window would pop-up or would otherwise call for attention when new incidents happen.

    As suggested by lostjimmy, File::Tail would be suitable to check for new lines only and even cope with log-rotation. Thus, re-reading the whole log file is not necessary at all. Furthermore, busy waiting is reduced/avoided.

    The following Perl/Tk snippet (partly borrowed from Adding the output of tailf -f filename to Tk widget (scrolled)) may give an impression. I hope, the File::Tail::select stuffs works under Windows (sorry, cannot test this here). You might need to tweak the timeouts according to your needs (see: File::Tail). It would have been nice to use Tk::fileevent, but I couldn't manage to make it work with File::Tail :( - anyway, it's a demo. OTOH, the current polling-approach allows you to define a minimum time period uninterrupted from this log watcher (currently: 5s).

    BTW: Your sample log format looks like snort output? In that case, POE::Filter::Snort looks promising, although it might be overkill for your task - you decide...

Re: read from network security log file and display lines as alert boxes
by Sagacity (Monk) on Dec 30, 2008 at 15:46 UTC

    Hi whistler

    At first glance on snippet 1, your increment of $i should be placed after the closing bracket of the IF block.
    It appears that your $i value is too early which throws off your HIDE statement. Also, I would change ++$i to $i++.

    Here's a reference for that Auto-Increment-and-Decrement

    This is just at a glance , Hope this helps
    Good Luck

Re: read from network security log file and display lines as alert boxes
by Anonymous Monk on Dec 31, 2008 at 02:40 UTC
    That's awesome guys, you all gave us a lot to run with!
    Really appreciate it!

    having a million pop up windows obviously wasn't ideal, but it was the idea we were working with at the the time with limited knowledge so I really appreciate the pointers.

    this should keep us going for a while.

    thanks again!