So before I begin (or technically, just after I’ve begun), let me remind you that my perl skills are shockingly bad.  All my perl scripts are written in the same style as the script I was copying from at the time I wrote them.

Introduction

I’ve recently set up an IRC server, partly to mess about with it and partly to consider using it to keep in touch with friends.  I’m acutely aware that it’s the kind of thing that gets attacked, so I’ve made sure ngIRCd (the daemon I chose) is logging everything, and then I started looking for a logwatch (homepage) script to monitor the logs and alert me of anything suspicious going on.

Sadly, I couldn’t find one, so I decided to do the only sensible thing and write my own, which is fine, but as you’ll see if you search the web for ‘writing custom logwatch scripts’, it’s sort of both easy and hard.  It’s easy once all the bits fall into place, but sometimes the terminology gets in the way.  So, here’s how I did it.

Detail

You absolutely need two files, one which describes which logs you’re going to handle, and another which is the script which does the handling.  You should name them in some way which makes sense (after the service you’re monitoring for example).  Once you put them in the right place, logwatch will execute your script and you’re away.  There are some optional files, if you want to do some logfile pre-processing (I think) but as I never used those, I can’t comment.

So, I want to monitor ngIRCd which on my server logs everything it does to /var/log/messages under the service name ngircd.  Here’s an example line,

Aug 13 08:01:54 hostname ngircd[10898]: User "bob!~ident@some.machine" registered (connection 8).

The first thing I did was create a file describing which logs to monitor and how to filter the data, and I stole various bits of information from the other files distributed with logwatch.  I called my file ngircd.conf and place it in,

/etc/logwatch/conf/services/

That’s the default location on Debian.  Here’s the content of my file with some comments,

# set the title for the reports
Title = "ngIRCd"
# set the logfile to the messages log file *group*
LogFile = messages
# only return entries made by ngIRCd which reduces our effort in the script
*OnlyService = ngircd
# remove the date / time stamp, hostname, service name, etc.
*RemoveHeaders

Line 3 is important and took me a little while to work out.  In the config file for your service, you describe the log file group that is used, which in turn tells logwatch which file in the /logfiles/ directory structure describes the actual log files which are scanned.  So the above line tells logwatch (in the case of Debian) to use the log files described in /usr/share/logwatch/default.conf/logfiles/messages.conf.  That file handles the log file names, how to deal with date/time stamps, archived logs, etc.

If the log files for your new service don’t already have a matching log file group configuration file, you should create one in /etc/logwatch/conf/logfiles, using an example from /usr/share/logwatch/default.conf/logfiles.  Anyway, in my case, since I was using /var/log/messages which is already described in /usr/share/logwatch/default.conf/logfiles/messages.conf I didn’t need to create one.

Now that you’ve got the service configuration covered, you need a script, and it needs to be named after the config file (so if you call your config file foo.conf, then your script needs to be called foo).  You can write this script in any language that can read from STDIN and write to STDOUT, but like other folk before me I made the joyful error of sticking to perl.

You place this file in

/etc/logwatch/scripts/services

The important things to remember are,

  1. your script will receive the content of the appropriate logs via STDIN
  2. it should write output to STDOUT and should use the environment variable LOGWATCH_DETAIL_LEVEL to determine the detail level passed to the logwatch program
  3. the output should be tidy and should avoid being verbose
  4. if you’ve configured the service conf script correctly you won’t need to worry about parsing dates, stripping headers, or other rubbish.  This does depend on the log file in question though and the application.
  5. To keep in line with other scripts, you should capture everything you know you don’t care about and ignore it, process stuff you do care about, and report stuff you don’t recognise.

The link below is the script I cobbled together to handle ngIRCd so far.  At the moment, I ignore my own advice and don’t check the detail level, I just wanted initially to get my data out.  I have no idea if the regexp’s are correct or efficient, but at present, it displays what I care about. Is that enough caveats?  I’m not looking for feedback on the quality of my perl! I’m just trying to show how it can be done.

ngircd

#!/usr/bin/perl
##########################################################################
# ngircd
##########################################################################

use Logwatch ':all';

my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0;

my %FailedLogin = ();
my %FailedOpers = ();
my $FailedOpCommands;
my %TriedConnections = ();
my %GoodConnectionsi = ();
my %GoodOper = () ;
my %BadOpCommands = ();
my %OtherList = ();

if ( $Debug >= 5 ) {
        print STDERR "\n\nDEBUG: Inside ngircd Filter \n\n";
        $DebugCounter = 1;
}

while (defined(my $ThisLine = <STDIN>)) {
   if ( $Debug >= 5 ) {
      print STDERR "DEBUG($DebugCounter): $ThisLine";
      $DebugCounter++;
   }

   chomp($ThisLine);
   if ( # We don't care about these
      ( $ThisLine =~ m/connection .* shutting down / ) or
      ( $ThisLine =~ m/^New TLSv1 connection using cipher/ ) or
      ( $ThisLine =~ m/^Now listening on/ ) or
      ( $ThisLine =~ m/^IO subsystem: epoll/ ) or
      ( $ThisLine =~ m/^Reading configuration from/ ) or
      ( $ThisLine =~ m/^ngircd .* started/ ) or
      ( $ThisLine =~ m/^Created pre-defined channel/ ) or
      ( $ThisLine =~ m/^Not running with changed root directory/ ) or
      ( $ThisLine =~ m/^Notice: Can't change working directory to/ ) or
      ( $ThisLine =~ m/^getnameinfo: Can't resolve address/ ) or
      ( $ThisLine =~ m/^Shutting down all listening sockets/ ) or
      ( $ThisLine =~ m/^ServerUID must not be 0, using/ ) or
      ( $ThisLine =~ m/^OpenSSL .* initialized/ ) or
      ( $ThisLine =~ m/^Configuration option .* not set/ ) or
      ( $ThisLine =~ m/^User .* unregistered/ ) or
      ( $ThisLine =~ m/^Server restarting NOW/ ) or
      ( $ThisLine =~ m/^Server going down NOW/ ) or
      ( $ThisLine =~ m/^Shutting down connection .* \(Got QUIT command\.\)/ ) or
      ( $ThisLine =~ m/^Connection .* with .* closed / ) or
      ( $ThisLine =~ m/^Running as user/ ) or
      ( $ThisLine =~ m/^Shutting down connection .* \(Server going down/ ) or
      ( $ThisLine =~ m/^Shutting down connection .* \(Socket closed/ ) or
      ( $ThisLine =~ m/^Shutting down connection .* \(Ping timeout/ ) or
      ( $ThisLine =~ m/is closing the connection/ ) or
      ( $ThisLine =~ m/^ngircd done/ ) or
      ( $ThisLine =~ m/^Client unregistered/ ) or
      ( $ThisLine =~ m/^Client .* unregistered/ ) or
      ( $ThisLine =~ m/^User .* changed nick/ )
   ) {
      # We don't care, do nothing
   } elsif ( my ($Host) = ($ThisLine =~ /Accepted connection .* from ([\d\.]+)/ )) {
      $TriedConnections{$Host}++;
   } elsif ( my ($User,$Connection) = ($ThisLine =~ /^User \"([^ ]+)!([^ ]+)\" registered /)) {
      $GoodConnections{$Connection}++;
   } elsif ( my ($User,$Connection) = ($ThisLine =~ /^Got invalid OPER from \"([^ ]+)!([^ ]+)\": / )) {
      $FailedOpers{$Connection}++;
   } elsif ( my ($User,$Connection) = ($ThisLine =~ /^No privileges: client \"([^ ]+)!([^ ]+)\", command / )) {
      $BadOpCommands{$Connection}++;
   } elsif ( my ($Host) = ($ThisLine =~ /^Shutting down connection .* \(Bad password\) with ([^ ]*):/)) {
      $FailedLogin{$Host}++;
   } elsif ( my ($User,$Connection) = ($ThisLine =~ /^Got valid OPER from \"([^ ]+)!([^ ]+)\", user is an IRC operator now/ )) {
      $GoodOper{$Connection}++;
   } else {
      # Report any unmatched entries...
      $OtherList{$ThisLine}++;
   }
}

#######################################################

if (keys %BadOpCommands) {
   print "\nIRCOp commands from regular users:\n";
   foreach my $key (keys %BadOpCommands) {
      my $totcount = 0;
      $totcount += $BadOpCommands{$key};
      my $plural = ($totcount > 1) ? "s" : "";
      print "   $key: $totcount time$plural\n";
   }
}

if (keys %FailedLogin) {
   print "\nFailed logins from:\n";
   foreach my $key (keys %FailedLogin) {
      my $totcount = 0;
      $totcount += $FailedLogin{$key};
      my $plural = ($totcount > 1) ? "s" : "";
      print "   $key: $totcount time$plural\n";
   }
}

if (keys %FailedOpers) {
   print "\nFailed attempts to become IRCOps from:\n";
   foreach my $key (keys %FailedOpers) {
      my $totcount = 0;
      $totcount += $FailedOpers{$key};
      my $plural = ($totcount > 1) ? "s" : "";
      print "   $key: $totcount time$plural\n";
   }
}

if (keys %GoodOper) {
   print "\nGood attempts to become IRCOps from:\n";
   foreach my $key (keys %GoodOper) {
      my $totcount = 0;
      $totcount += $GoodOper{$key};
      my $plural = ($totcount > 1) ? "s" : "";
      print "   $key: $totcount time$plural\n";
   }
}

if (keys %TriedConnections) {
   print "\nAttempted connections from:\n";
   foreach my $ip (sort SortIP keys %TriedConnections) {
      my $name = LookupIP($ip);
      my $totcount = 0;
      $totcount += $TriedConnections{$ip};
      my $plural = ($totcount > 1) ? "s" : "";
      print "   $name: $totcount time$plural\n";
   }
}

if (keys %GoodConnections) {
   print "\nGood connections from:\n";
   foreach my $key (keys %GoodConnections) {
      my $totcount = 0;
      $totcount += $GoodConnections{$key};
      my $plural = ($totcount > 1) ? "s" : "";
      print "   $key: $totcount time$plural\n";
   }
}

if (keys %OtherList) {
   print "\n**Unmatched Entries**\n";
   foreach $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) {
      print "   $line: $OtherList{$line} Time(s)\n";
   }
}

exit(0);

If I have the inclination, I plan to update this to display different levels of detail based on the logwatch detail option, format the output a little nicer, handle some different bits of information and split the input lines up into more fields.  But you know, now it does 90% of what I want, that might never happen.

Summary

  • Pick a name (based on the service you’re reporting on)
  • Create /etc/logwatch/conf/services/myname.conf and describe the log file group to use, and any other options
  • Create a script /etc/logwatch/scripts/services/myname in your favourite language and parse STDIN, sending useful information to STDOUT
  • Bingo
Aug 072010

Hopefully no one’s noticed that I’ve moved my websites (including this one) to a new hosting provider (well, new for this site, but not new to me in general).  When I first decided to move away from shared hosting at Gradwell, I wanted to find a VPS solution to give me more control over the sites.  At the time, I was hosting an EverQuest guild website which got a reasonable amount of traffic, and so I chose a VPS solution that would definitely have enough oomph and bandwidth to deliver that.  Not a huge amount, but enough.  It was my first time in the VPS market and I wasn’t really sure who were best, what was good value and what the different offerings resulted in.

The 1and1 service I went with was pretty good, but not what I would call cheap.  Over the 18 months or so I’ve had the service it’s been pretty reliable, a few unexplained outages, and a couple of periods of downtime that were longer than I would have liked.  But the VPS was powerful, had plenty of memory and lots of network capacity and easily delivered the 7 or so domains I hosted on it.

Not long after I moved the sites though, the EverQuest guild site dropped off dramatically in terms of load (lots of people left the game), and after 18 months it’s become apparent that the 5 or 6 vanity domains I host really don’t justify the cost and performance of the 1and1 VPS.

I looked again at shared hosting, because I’m a pretty good example of who should use it.  I tried tsohosts and while they’re excellent value and I have nothing bad to say about them, I really don’t get on with cPanel and the shared hosting mentality, especially after running my own VPS for so long.  I wanted to get into the config files and set things up ‘just so’, and after only 2 or 3 days fighting with cPanel I gave up and bought another VPS from Gandi.

I love the Gandi system (I already have another VPS from them hosting a usenet server), and although a single share VPS is pretty low resource you can deliver quite a lot from a Linux machine with not much in the way of power these days, especially when what you’re delivering are vanity domains with almost no traffic.

So I’ve got a single share (256MB memory) VPS from Gandi and over the last couple of days I’ve moved everything over, and I’m pleased at how easy it was.  The 1and1 VPS was running CentOS but I’ve gone for Debian with Gandi (I prefer Debian) so not everything could be simply copied over, but the content (static and mysql data) was easy enough to transfer, so now it’s just a case of making sure the VPS is secure and managed properly.

If you’re looking for some domains or a VPS, I really can’t recommend Gandi enough, my only gripe is there’s no easy way to pay monthly (no direct debit facility, so you have to top up a pre-pay account when you remember), but it’s a small issue when the service is so excellent.

So, although it’s hard to believe (for me), 1990 was twenty years ago.  Here’s the movies that did well in 1990 (top US grossing movies that year, source IMDB, full list).

  • Home Alone
  • Ghost
  • Dances with Wolves
  • Pretty Woman
  • The Hunt for Red October
  • Total Recall
  • Die Hard 2
  • Dick Tracey
  • Kindergarten Cop
  • Back to the Future Part III
  • Days of Thunder
  • Another 48 Hrs

Ten years ago in 2000, this is the list (or part of it, full list here).

  • How the Grinch Stole Christmas
  • Cast Away
  • Mission Impossible II
  • Gladiator
  • X-Men
  • Charlie’s Angels
  • Unbreakable
  • Space Cowboys

Doesn’t feel like 20 years since Home Alone, or even 10 since X-Men.

This episode reminds me – I don’t blog enough.

Grete went ‘awwww’ at the end.  I said ‘you knew it was going to happen’.  She replied, ‘yes, but it’s like knowing the puppy is going to get shot’, which I can’t disagree with.

Jul 142010

Trailer contains swearing!

Aha, they removed the trailer :) Shame!

Which is exactly how it fucking should be.

Jul 102010

There was something moving about in the lounge, near the bin in the corner.  Fizz was really interested but I couldn’t see anything and forgot about it.  Just been in there now, and there was a cricket about 3cm long hanging on the net curtain.  I grabbed a cup and slip of paper to get it back outside.  There’s just one thing – when crickets move, they jump, and they jump vertically.  However, vertically to a cricket which is hanging on your net curtain is essentially horizontally straight at your face.

I’m not nervous or scared of insects, but a 3cm cricket jumping for your face is always cause for a sudden involuntary grunt and duck.

Anyway, it’s safely outside now!

Jul 092010

Finally have some aphid eatin’ Ladybirds on the Willow.  During the day, they’re fast little buggers, this one was hoovering up aphids as fast as it could!

I have about 50 shots of it, blurry, running all over the leaves, it paused here just long enough for the autofocus to get it.  And then a moment later, it took off, this next shot was pretty lucky timing.

Went out a bit later, and there’s another one sleeping on the tree (looks asleep), which is good news for me, and bad news for the aphids.  Also, I think this ant was interested in me too.

And this one, I’m really pleased with, very pleased with this shot indeed.

Myself and Grete, we both like trees.  We were sad when we had to fund cutting down a very large tree in the garden (for various reasons) and we promised we’d plant some to make up for it.  We tried a cherry tree, but got it badly wrong and the tree it was grafted onto was the only thing grown (and would have been huge, so that had to come up).  Then we saw a miniature willow tree and that sounded perfect.

So this year we got it, planted it and cared for it, within only two days it had sprouted a load of extra leaves and branches (more than the cherry tree ever did) and we thought we were onto a winner, and then it went wrong.

We’ve got several large ants nests in the garden, and either I plant the tree in one, or they moved into the soft earth shortly after.  They swarmed all over the tree, and although I couldn’t see them doing any specific damage, they weren’t helping the root ball settle in.  We also got a spot of super-hot weather (just two or three days) and the tree didn’t get enough water.  The new foliage died.  We were sad, we were killing another tree.

But I took some corrective measures, more top soil, and some solid application of the end of a lump of wood on the ground left the tree solidly bedded in.  I watered it every day.  I tried to kill the ants (but failed, as usual).  I watered it some more.  And it stuck it out, survived a few weeks of miserable weather and made it to the long strip of hot weather we’ve had.  I’ve been out every day making sure that tree has enough water (even if the rest of the garden is turning into a desert).

I think it’s paid off – it flourished, new leaves, new branches, thickening of the branches already there.  I think it might pull through.

But now we have aphids.  Not one or two, but billions.  We’ve never had aphids in the garden that I can remember seeing in any number, so it looks like we’ve brought them in with the willow and they may well be a specific willow based aphid.  I’ve just been out to squish them, again.  The ants look like they’re milking them.

I need a ladybird infestation!

Anyway, I don’t think the aphids will kill the willow, but they do generate some annoying issues (honeydew and the stuff that feeds on it, including wasps and mold).

So I’ll be out making sure they stay as dead as I can for the next few weeks, washing them off and squishing the hangers on.

I’m rootin’ for you miniature willow (pun intended), we can do this.

Willow when we got it in April:

Willow in mid-June:

Willow now:

My hands are too shaky, I don’t own a big enough tripod and the camera is really not good enough to take photo’s of  ants and aphids, but I tried anyway.

Just aphids.

Ant vs Aphid (I think it’s milking them)

And last, but not least, more aphids.

© 2010 tony Suffusion WordPress theme by Sayontan Sinha