Tag Archive - perl

GeoIP CSV to Bind ACL

Simple perl script for converting a GeoIP CSV file (latest version) to Bind ACL definitions.

#!/usr/bin/perl
 
use strict;
use warnings;
 
use Net::CIDR::Lite;
 
# Get files
my $infile  = $ARGV[0];
my $outfile = $ARGV[1];
 
# Open infile for reading
open(FILE, '<', $infile);
 
# Define iplist array
my %iplist;
 
# Loop infile
while(<FILE>) {
        # Set start, end and country variables
        my @line = split(/\"/, $_);
        my $start_ip = $line[1];
        my $end_ip   = $line[3];
        my $country  = $line[9];
 
        # Use the CIDR class to get networks in the range
        my $cidr = Net::CIDR::Lite->new;
        $cidr->add_range("$start_ip-$end_ip");
        my @networks = $cidr->list;
 
        # Put networks in the iplist array
        foreach(@networks) {
                $iplist{$country} .= "\t" . $_ . ';' . "\n";
        }
}
 
# Close the infile file handle
close FILE;
 
# Open outfile for writing
open(FILE, '>', $outfile);
 
# Loop iplist array
foreach my $country (sort keys %iplist) {
        # Write to outfile
        print FILE 'acl "' . $country . '" {' . "\n";
        print FILE $iplist{$country};
        print FILE '};' . "\n";
}
 
# Close the outfile file handle
close FILE;
 
# We're done

Simple usage:

$ ./geoip.pl GeoIPCountryWhois.csv countries.acl

You’ll need the Net::CIDR::Lite extension for Perl, in Debian/Ubuntu the package is called libnet-cidr-lite-perl.

Using Notifo with Nagios

Notifo is a great service for sending notifications, in this case to a phone using the mobile app.

To use Notifo with Nagios there’s two solutions. The first (and the easiest one), is to configure Nagios to send emails to the email address provided by Notify. The other (and the one described here), is to configure Nagios to execute a scripts that sends a POST request to the Notifo API.

I’ll asume that you have a working Nagios setup, a Notify account, the client installed and configured on your phone, and your Notifo API key handy.

Lets start by adding two commands to the Nagios configuration, depending on your setup this can be done in many places. If there’s a commands.cfg file present that’s probably a good place to put it. Open the file and add the following:

define command {
    command_name    notify-host-by-notifo
    command_line    /usr/bin/perl /usr/local/bin/notifo -username="$_CONTACTNOTIFO_USERNAME$" -apikey="$_CONTACTNOTIFO_APIKEY$" -title="Host" -msg="$HOSTNAME$ $HOSTSTATE$ '$HOSTOUTPUT$'"
}

define command {
    command_name    notify-service-by-notifo
    command_line    /usr/bin/perl /usr/local/bin/notifo -username="$_CONTACTNOTIFO_USERNAME$" -apikey="$_CONTACTNOTIFO_APIKEY$" -title="Service" -msg="$HOSTNAME$ $SERVICEDESC$ $SERVICESTATE$ '$SERVICEOUTPUT$'"
}

Then find the file containing the contact you want to use, and add the Notify username and password. Also modify the host and service notification commands. The result should be something like this:

define contact {
    contact_name                    admin
    alias                           Administrator
    service_notification_period     24x7
    host_notification_period        24x7
    service_notification_options    w,u,c,r
    host_notification_options       d,r
    service_notification_commands   notify-service-by-email,notify-service-by-notifo
    host_notification_commands      notify-host-by-email,notify-host-by-notifo
    email                           <EMAIL>
    _notifo_username                <USERNAME>
    _notifo_apikey                  <APIKEY>
}

Of course, make sure you use your own name, email and Notifo credentials.

Then save the following script as /usr/local/bin/notifo (or whatever you want, make sure it’s the same path as the one configured above).

#!/usr/bin/perl
 
use strict;
use warnings;
 
use HTTP::Request::Common qw(POST);
use LWP::UserAgent;
use Getopt::Long;
 
# Get options
my %options = ();
GetOptions(\%options, 'username=s', 'apikey=s', 'title=s', 'msg=s');
 
# URL encode msg
$options{'msg'} =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
 
# The request
my $req = POST 'https://api.notifo.com/v1/send_notification',
	[ 'msg' => $options{'msg'}, 'label' => 'Nagios', 'title' => $options{'title'} ];
 
# Add auth to the request
$req->authorization_basic($options{'username'}, $options{'apikey'});
 
# Do it
my $ua = LWP::UserAgent->new;
$ua->request($req);

Make the script executable.

# chmod +x /usr/local/bin/notifo

Try the script to make sure it works.

# /usr/bin/perl /usr/local/bin/notifo -username=<USERNAME> -apikey=<APIKEY> -title=Test -msg=Test

Reload Nagios, depending on your configuration this can be done in many ways, usually it’s the following command.

# /etc/init.d/nagios3 restart

That’s it.


Now, when something goes wrong, you’ll be notified immediately.

Net::DNS and gethostbyname

I was trying out DNS resolvers for perl and made these two scripts. test.poller.se returns 3 A records, the scripts print out 2 of them.

netdns.pl

#!/usr/bin/perl
 
use warnings;
use strict;
 
use Net::DNS;
 
my $resolver = new Net::DNS::Resolver;
my $query = $resolver->query("test.poller.se", "A", "IN");
 
my @hosts;
my $rr;
foreach $rr ($query->answer) {
        push(@hosts, $rr->address);
}
 
print $hosts[0] . "\n";
print $hosts[1] . "\n";

gethostbyname.pl

#!/usr/bin/perl
 
use warnings;
use strict;
 
use Socket;
 
my @hosts;
my ($name, $aliases, $addrtype, $length, @addrs) = gethostbyname("test.poller.se");
$hosts[0] = inet_ntoa($addrs[0]);
$hosts[1] = inet_ntoa($addrs[1]);
 
print $hosts[0] . "\n";
print $hosts[1] . "\n";

Performance difference for the two is quite big. Of course, Net::DNS is more then just a simple resolver.

$ time for i in `seq 1 1000`; do ./netdns.pl > /dev/null; done
real	1m18.185s
user	0m46.203s
sys	0m29.418s

$ time for i in `seq 1 1000`; do ./gethostbyname.pl > /dev/null; done
real	0m26.886s
user	0m7.784s
sys	0m17.969s