#!/usr/bin/env perl -w # Based on the work of Gephorian [[drunkserver.com]] (11/15/2012) # taken from http://my.reddit.com/r/admincraft/comments/13de6m/has_anyone_else_gotten_the_query_function_to_work/ # Adapted to nagios and some bugfixes by Megge [[yerendar.de]] (25/01/2013) # # Released under GPL Licence # use strict; use warnings; use Getopt::Long; use IO::Socket; use Time::HiRes qw( time ); use Try::Tiny; use Data::Dumper; my $OK = 0; my $WARNING = 1; my $ERROR = 2; my $UNKNOWN = 3; my $OUTPUT_OK = "MINECRAFT OK|time=%7fs;%i;%i;0.0;0.0 player=%i;;;0;%i"; my $OUTPUT_WARNING = "MINECRAFT WARNING|time=%is;%i;%i;0.0;0.0 player=%i;;;0;%i"; my $OUTPUT_CRITICAL = "MINECRAFT CRITICAL|time=%is;%i;%i;0.0;0.0 player=%i;;;0;%i"; my $OUTPUT_NO_CONNECTION = "MINECRAFT CRITICAL|time=%is;%i;%i;0.0;0.0"; my $OUTPUT_EXCEPTION = "MINECRAFT CRITICAL"; my $OUTPUT_UNKNOWN = "MINECRAFT UNKNOWN: Invalid arguments"; my $querymode = 2; my $serverhostname = ""; my $serverport = 25565; # Default is 25565 my $verbose = 0; my $warnOnFull = 1; my $warnTime = 0; my $critTime = 0; GetOptions("host=s" => \$serverhostname, "port=i" => \$serverport, "warn-on-full" => \$warnOnFull, "verbose!" => \$verbose, "warn=i" => \$warnTime, "crit=i" => \$critTime, ); if ($warnTime > $critTime or not $serverhostname) { print $OUTPUT_UNKNOWN; exit $UNKNOWN; } sub getInfo; my $time = 0; my $motd = ""; my $gametype = 0; my $gameid = ""; my $plugins = ""; my $numplayers = 0; my $maxplayers = 0; my $hostport = ""; my $hostip = ""; my $players = 0; my $map = ""; my $version = ""; my $status = 0; try { getInfo(); } catch { print sprintf($OUTPUT_EXCEPTION); exit $UNKNOWN; }; if ($verbose) { print "motd: " . $motd ."\n"; print "gametype: " . $gametype ."\n"; print "gameid: " . $gameid ."\n"; print "plugins: " . $plugins ."\n"; print "numplayers: " . $numplayers ."\n"; print "maxplayers: " . $maxplayers ."\n"; print "hostport: " . $hostport ."\n"; print "hostip: " . $hostip ."\n"; print "players: " . $players ."\n"; print "map: " . $map ."\n"; print "version: " . $version ."\n"; print "time: " . $time ."\n"; } unless ($status) { print sprintf($OUTPUT_NO_CONNECTION, $time, $warnTime, $critTime); exit $ERROR; } if ($critTime && $time > $critTime) { print sprintf($OUTPUT_CRITICAL, $time, $warnTime, $critTime, $numplayers, $maxplayers); exit $ERROR; } if ($warnTime && $time > $warnTime) { print sprintf($OUTPUT_WARNING, $time, $warnTime, $critTime, $numplayers, $maxplayers); exit $WARNING; } if ($warnOnFull && $maxplayers == $numplayers) { print sprintf($OUTPUT_WARNING, $time, $warnTime, $critTime, $numplayers, $maxplayers); exit $WARNING; } print sprintf($OUTPUT_OK, $time, $warnTime, $critTime, $numplayers, $maxplayers); exit $OK; sub getInfo { my ($data, $packet, $packetheader); my $magic = "\xFE\xFD"; my $stat = "\x00"; my $handshake = "\x09"; my $sessionid = "\x00\x00\x00\x01"; my $padding = "\x00\x00\x00\x00"; my $token = ""; $time = time(); my $sock = new IO::Socket::INET ( PeerAddr => $serverhostname, PeerPort => $serverport, Proto => 'udp', Timeout => 1, ); if ( $sock ) { $packetheader = $magic . $handshake . $sessionid; $sock->send($packetheader); $sock->recv($data, 1024); $token = pack("N", $1) if ($data =~ m/(\d{6,8})\0/); $data = $token; $packetheader = $magic . $stat . $sessionid; $packet = $packetheader . $token . $padding; $sock->send($packet); $sock->recv($data, 4096); $sock->close(); $status = 1 if $data; } $time = time() - $time; return unless $status; $motd = $1 if($data =~ s/hostname\x00(.*?)\x00//); $gametype = $1 if($data =~ s/gametype\x00(.*?)\x00//); $gameid = $1 if($data =~ s/game_id\x00(.*?)\x00//); $version = $1 if($data =~ s/version\x00(.*?)\x00//); $plugins = $1 if($data =~ s/plugins\x00(.*?)\x00//); $map = $1 if($data =~ s/map\x00(.*?)\x00//); $numplayers = $1 + 0 if($data =~ s/numplayers\x00(.*?)\x00//); $maxplayers = $1 + 0 if($data =~ s/maxplayers\x00(.*?)\x00//); $hostport = $1 if($data =~ s/hostport\x00(.*?)\x00//); $hostip = $1 if($data =~ s/hostip\x00(.*?)\x00//); $players = $1 if($data =~ s/player_\x00\x00(.*?)\x00\x00//); }