#! /usr/bin/perl -wT
#----------------------------------------------------------------------
#
# Author: Martin Fuerstenau, Oce Printing Systems, martin.fuerstenau_at_oce.com
# Date:   01.08.2006
#
#
# Purpose:
# Checking the status of a given website.
#
# Version 1.0
# - The site can be on the LAN or within the internet.
# - The site can be behind a proxy with or without authentication.
# - The plugin can handle proxy authentication on a user/password basis.
#   Therefore a user and a password has to be submitted when calling the plugin
# - The site can be whith or without authentication
# - The plugin can handle website authentication.
#   Therefore a user and a password has to be submitted when calling the plugin
# - For easier use the commandline options of the plugin are based on the 
#   syntax of wget.
#
# Changes:
# 
# - Version 1.1
#   Martin Fuerstenau, Oce Printing Systems, martin.fuerstenau_at_oce.com, 13.6.2008
#   - Added -o, --outout for giving  back the checked URL
#
# - Version 1.2
#   Martin Fuerstenau, Oce Printing Systems, martin.fuerstenau_at_oce.com, 13.7.2010
#   - Bugfix - proxy without user/password failed. Fixed
#   - Cleaned up the code a little bit.
#   - Removed the usage of utils.pm
#   - Removed the usage of global variables. my will do the work too. You can easily
#     place comments after the definition and/or assign values to the variables at 
#     time of creating them.
#   - Redirected STDERR to /dev/null. Due testing I recognized that there are websites in UTF-8
#     causing an error like:
#
#     "Parsing of undecoded UTF-8 will give garbage when decoding entities at
#      /usr/lib/perl5/vendor_perl/5.8.8/LWP/Protocol.pm line 114."
#
#     because this is a little bit confusing to users it is redirected. this warning is caused by
#     libwww-perl itself and therefore it can not be covered by this program
#   - New switch -n | --negate to negate the result. For example a 200 is critical and a 500 is good
# 
# Synopsis:
# 
# check_url_status -U <URL> [--http-user=<user> [--http-passwd=<password>]] [-Y proxy[:port] [--proxy-user=<user> [--proxy-passwd=<password>]] [-T <timeout>] [-n, --negate] [-o ,--output]";
#
#----------------------------------------------------------------------

use strict;
use Getopt::Long;
use LWP::Simple;
use HTTP::Status;
use LWP::UserAgent;

my $whatsup;                        # Returncodes
my $version;                        # For displaying the version number
my $help;                           # For displaying the help message
my $progname="check_url_status";    # As it says
my $prgversion="1.2";               # Version number
my $url2check;                      # The URL to check
my $output;                         # The checked URL as output for Nagios
                                    # (Do we check the right one?)
my $time_to_wait;                   # Timeout for the user agent.
my $time_to_wait_default=30;        # Default timeout for the user agent.
my $proxy;                          # The proxy and port if used
my $user;                           # Website user for authentication
my $pass;                           # Website user password for authentication
my $puser;                          # Proxy user for authentication
my $ppass;                          # Proxy user password for authentication
my $negate;                         # If set results will be negated and the output
                                    # will be adapted. This is opposite to Nagios negate
                                    # because nagios negte can't turn an OK (string) to CRITICAL
                                    # and vice versa
my $ok;                             # Contains the return value for ok (normally 0)
my $crit;                           # Contains the return value for critical.(normally 2)
                                    # These values are switched (0->2 and 2> 0) if negate is set.

$ENV{'PATH'}='';
$ENV{'BASH_ENV'}=''; 
$ENV{'ENV'}='';

# Any arguments passed to the script?

if ( $#ARGV <= 0 )
   {
   $help = "h";
   }
   		    
Getopt::Long::Configure('bundling');
GetOptions
	("v"    => \$version,        "version"          => \$version,
	 "Y=s"  => \$proxy,          "proxy=s"          => \$proxy,
	 "T=s"  => \$time_to_wait,   "timeout=s"        => \$time_to_wait,
	 "h"    => \$help,           "help"             => \$help,
	 "o"    => \$output,         "output"           => \$output,
	 "n"    => \$negate,         "negate"           => \$negate,
	 "U=s"  => \$url2check,      "url=s"            => \$url2check,
                                     "http-user=s"      => \$user ,
                                     "http-passwd=s"    => \$pass,
                                     "proxy-user=s"     => \$puser,
                                     "proxy-passwd=s"   => \$ppass);

if ($version)
   {
   version();
   exit 0;
   }

if ($help)
   {
   print_help();
   exit 0;
   }

if (!$negate)
   {
   $negate=0;
   }
else
   {
   $negate=1;
   }

if ($negate == 0)
   {
   $ok=0;
   $crit=2;
   }

if ($negate == 1)
   {
   $ok=2;
   $crit=0;
   }

if ($output)
   {
   $output = " ".$url2check." -";
   }
else
   {
   $output = "";
   }

# A password without a user really does not make sense

if ($pass)
   {
   if (!$user)
      {
      print_usage();
      usage("You can not supply a user password without a user!\n");
      }
   }

# A proxy-user or password without a proxy would not make any sense either.
# The same with a proxy password without the appropriate user

if (!$proxy)
   {
   if ($ppass)
      {
      print_usage();
      usage("You can not supply a proxy-password without a proxy!\n");
      }
   if ($puser)
      {
      print_usage();
      usage("You can not supply a proxy-user without a proxy!\n");
      }
   }
else
   {
   if ($ppass)
      {
      if (!$puser)
         {
         print_usage();
         usage("You can not supply a proxy-password without a proxy-user!\n");
         }
      }
   }

$whatsup=get_url_status();

if ($whatsup == 0 )
   {
   exit 0;
   }
   
if ($whatsup == 2 )
   {
   exit 2;
   }


# --------------- Begin subroutines ----------------------------------------

sub get_url_status
    {
    my $WarnMe = $ok;
    my $url_status = 100;
    my $status_string = "bla";
    my $UserAgent;
    my $request;
    my $result;

    $UserAgent = LWP::UserAgent->new;
    $UserAgent->agent('Mozilla/5.0');

    # If the timeout is not submitted via commandline the default value is used

    if ($time_to_wait)
       {
       $UserAgent->timeout($time_to_wait);
       }
    else
       {
       $UserAgent->timeout($time_to_wait_default);
       }

    # If we use a proxy we have to prepare. Especially if we use authentiction
    
    if ($proxy)
       {
       if ($puser)
          {
          $proxy =~ s/^htt.*\/\///;
          $proxy = "http://"."$puser".":"."$ppass"."\@"."$proxy";
          $UserAgent->proxy(['http', 'https', 'ftp'] => $proxy);
          }
       else
          {
          $proxy = "http://"."$proxy";
          $UserAgent->proxy(['http', 'https', 'ftp'] => $proxy);
          }
       }
  
    open (STDERR,">/dev/null");

    $request = new HTTP::Request 'GET' => $url2check;

    if ($user)
       {
       $request->authorization_basic("$user" => "$pass");
       }

    $result = $UserAgent->request($request);
    $url_status = $result->code();

    # Get the status message from the status code

    $status_string=status_message($url_status);
    
    close STDERR;

    # The usual shit. Make the output messages for Nagios
    
    if ($url_status =~ m/^1.*/ )
       {
       print "Information:$output HTTP Statuscode $url_status - $status_string";
       }

    if ($url_status =~ m/^2.*/ )
       {
       print "URL: $output HTTP Statuscode $url_status - $status_string";
       }

    if ($url_status =~ m/^3.*/ )
       {
       print "Redirect:$output HTTP Statuscode $url_status - $status_string";
       }

    if ($url_status =~ m/^4.*/ )
       {
       if ($url_status =~ m/^401/ )
          {
          print "URL: $output HTTP Statuscode $url_status - $status_string";
	  }
       else
	  {
          print "Client Error:$output HTTP Statuscode $url_status - $status_string";
          $WarnMe = $crit;
	  }
       }

    if ($url_status =~ m/^5.*/ )
       {
       print "Server Error:$output HTTP Statuscode $url_status - $status_string \n";
       $WarnMe = $crit;
       }

    return $WarnMe; 
    }

sub version
    {
    print "\n$progname - version $prgversion\n\n";
    }

sub print_usage
    {
    print "\nUsage: $progname check_url_status -U <URL> [--http-user=<user> [--http-passwd=<password>]] [-Y proxy[:port] [--proxy-user=<user> [--proxy-passwd=<password>]] [-T <timeout>] [-n, --negate] [-o ,--output]\n";
    print "or\n";
    print "Usage: $progname -v for version.\n";
    print "or\n";
    print "Usage: $progname -h for help.\n\n";
    }

sub print_help
    {
    version();
    print "Copyright (c) 2010 Martin Fuerstenau - Oce Printing Systems\n";
    print "This plugin monitors website and return the status of page requests according to RFC2616.\n";
    print_usage();
    print "       -U, --url=URL               URL to check\n";
    print "       --http-user=user            Supplies a user for logging into a website.\n";
    print "       --http-passwd=password      The password for the website-user.\n";
    print "       -Y proxy[:port]             Supplies the proxy and the port if necessary.\n";
    print "       --proxy-user=user           Supplies a user for prox authentication.\n";
    print "       --proxy-passwd=password     Supplies a user for prox authentication.\n";
    print "       -T <timeout>                Sets the timeout for the request. Default is 30 sec..\n";
    print "       -n, --negate                If set results will be negated and the output  will\n";
    print "                                   be adapted. This is opposite to Nagios negate because\n";
    print "                                   nagios negte can't turn an OK (string) to CRITICAL and\n";
    print "                                   vice versa.\n";
    print "       -h, --help                  Short help message\n";
    print "       -v, --version               Prints version of the plugin\n";
    print "       -o, --output                Gives back the checked URL in the answer string\n\n";
    print "This plugin uses the libwww-perl.If you don't have the package installed, you will need to ";
    print "download it from http://www.cpan.org before you can use this plugin.\n\n";
    }
