check_asterisk.pl 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use IO::Socket;
  4. use Getopt::Long;
  5. $|=1;
  6. my (
  7. $host, $username, $password, $verbose, $help, $command, $mode,
  8. $ipaddr, $respaddr, $sendto, $msg, $recvfrom,
  9. $version, $response, $message, $line,
  10. $sock, $port, $reply,
  11. $warning, $critical,
  12. %warnval, %critval,
  13. %channels,
  14. $runmode,
  15. $key,
  16. $s,
  17. );
  18. my $stop = 0;
  19. my $mgr_port = 5038;
  20. my $iax_port = 4569;
  21. my $exitcode = 0;
  22. my $cause = "";
  23. my $iax_answer = 0;
  24. my $iax_maxlen = 1024;
  25. my $iax_timeout = 5;
  26. my $iax_src_call = "8000"; #8000 most siginificant bit is IAX packet type full ... required for a poke etc...
  27. my $iax_dst_call = "0000";
  28. my $iax_timestamp = "00000000";
  29. my $iax_outbound_seq = "00";
  30. my $iax_inbound_seq = "00";
  31. my $iax_type = "06"; #IAX_Control
  32. sub ok {
  33. $s = shift;
  34. $s =~ s/[\r\n]//g;
  35. print "OK: $s\n";
  36. exit(0);
  37. }
  38. sub warning {
  39. $s = shift;
  40. $s =~ s/[\r\n]//g;
  41. print "WARNING: $s\n";
  42. exit(1);
  43. }
  44. sub error {
  45. $s = shift;
  46. $s =~ s/[\r\n]//g;
  47. print "ERROR: $s\n";
  48. exit(2);
  49. }
  50. sub unknown {
  51. $s = shift;
  52. $s =~ s/[\r\n]//g;
  53. print "UNKNOWN: $s\n";
  54. exit(3);
  55. }
  56. sub syntax {
  57. $s = shift;
  58. unless ($s =~ m/Help:/) {
  59. $s = "Error: (".$s.")" or $s = 'Unknown';
  60. }
  61. print "$s\n" unless ($help);
  62. print "Syntax: $0 -m mgr -h <host> -u <username> -p <password> [-cwv]\n";
  63. print "Syntax: $0 -m iax -h <host> [-v]\n";
  64. print "* --host -h Host\n";
  65. print "* --mode -m Mode - eithr 'mgr' or 'iax'\n";
  66. print " --username -u Username\n";
  67. print " --password -p Password\n";
  68. print " --port -P n Port (if not using $mgr_port for manager or $iax_port for IAX)\n";
  69. print " --warning xxx=n Return warning if > n channels of type xxx.\n";
  70. print " --critical xxx=n Return critical if > n channels of type xxx.\n";
  71. print " --verbose -v Verbose\n";
  72. print " --help -h This help\n";
  73. exit(3);
  74. }
  75. Getopt::Long::Configure('bundling');
  76. GetOptions
  77. ("p=s" => \$password, "password=s" => \$password,
  78. "u=s" => \$username, "username=s" => \$username,
  79. "h=s" => \$host, "host=s" => \$host,
  80. "P=i" => \$port, "port=i" => \$port,
  81. "H" => \$help, "help" => \$help,
  82. "v" => \$verbose, "verbose" => \$verbose,
  83. "m=s" => \$mode, "mode=s" => \$mode,
  84. "critical=s" => \$critical, "warning=s" => \$warning);
  85. syntax("Help:") if ($help);
  86. syntax("Missing host") unless (defined($host));
  87. syntax("Missing mode") unless (defined($mode));
  88. if ($mode =~ /^iax$/i) {
  89. print "Running in IAX mode\n" if ($verbose);
  90. $runmode = 1;
  91. } elsif ($mode =~ /^mgr$/i) {
  92. print "Running in Manager mode\n" if ($verbose);
  93. $runmode = 2;
  94. } else {
  95. syntax("Unknown mode $mode")
  96. }
  97. ##############################################################################
  98. if ($runmode == 2) {
  99. $port = $mgr_port;
  100. syntax("Missing username") unless (defined($username));
  101. syntax("Missing password") unless (defined($password));
  102. if (defined($warning)) {
  103. foreach $s (split(/,/, $warning)) {
  104. syntax("Warning value given, $s, is invalid")
  105. unless ($s =~ /^(\w+)=(\d+)$/);
  106. $warnval{$1} = $2;
  107. print "Clear to give WARNING after $2 connections on $1\n" if ($verbose);
  108. }
  109. }
  110. if (defined($critical)) {
  111. foreach $s (split(/,/, $critical)) {
  112. syntax("Critical value given, $s, is invalid")
  113. unless ($s =~ /^(\w+)=(\d+)$/);
  114. $critval{$1} = $2;
  115. print "Clear to give CRITICAL after $2 connections on $1\n" if ($verbose);
  116. }
  117. }
  118. print "Connecting to $host:$port\n" if ($verbose);
  119. unless ($sock = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, Proto => 'tcp')) {
  120. print("Could not connect to asterisk server ".$host.":".$port."\n");
  121. exit(2);
  122. }
  123. print "Connected to $host:$port\n" if ($verbose);
  124. $version = <$sock>;
  125. print $version if ($verbose);
  126. print $sock "Action: Login\r\nUsername: $username\r\nSecret: $password\r\nEvents: off\r\n\r\n";
  127. print "Action: Login\r\nUsername: $username\r\nSecret: $password\r\n\r\n" if ($verbose);
  128. $response = <$sock>;
  129. $message = <$sock>;
  130. $s = <$sock>;
  131. print $response.$message if ($verbose);
  132. print $s if ($verbose);
  133. exit(1) unless ($response =~ m/^Response:\s+(.*)$/i);
  134. exit(1) unless ($1 =~ m/Success/i);
  135. print $sock "Action: Status\r\n\r\n";
  136. print "Action: Status\r\n\r\n" if ($verbose);
  137. $response = <$sock>;
  138. $message = <$sock>;
  139. print $response.$message if ($verbose);
  140. &unknown("Unknown answer $response (wanted Response: something)") unless ($response =~ m/^Response:\s+(.*)$/i);
  141. &unknown("$response didn't say Success") unless ($1 =~ m/Success/i);
  142. &unknown("Unknown answer $response (wanted Message: something)") unless ($message =~ m/^Message:\s+(.*)$/i);
  143. &unknown("didn't understand message $message") unless ($1 =~ m/Channel status will follow/i);
  144. $stop=0;
  145. while (($stop == 0) && ($line = <$sock>)) {
  146. print "$line" if ($verbose);
  147. if ($line =~ m/Channel:\s+(\w+)\//) {
  148. $channels{$1}++;
  149. print "Found $1 channel\n" if ($verbose);
  150. }
  151. if ($line =~ m/Event:\s*StatusComplete/i) {
  152. $stop++;
  153. }
  154. }
  155. # Log out
  156. print $sock "Action: Logoff\r\n\r\n";
  157. undef($s);
  158. foreach $key (keys %channels) {
  159. $s .= " " . $key . " (" . $channels{$key} . ")";
  160. }
  161. foreach $key (keys %critval) {
  162. print "key = $key\n" if ($verbose);
  163. if (defined($channels{$key}) && ($channels{$key} > $critval{$key})) {
  164. $exitcode = 2;
  165. $cause .= $channels{$key} . " $key channels detected. ";
  166. }
  167. }
  168. if ($exitcode < 2) {
  169. foreach $key (keys %warnval) {
  170. print "key = $key\n" if ($verbose);
  171. if (defined($channels{$key}) && ($channels{$key} > $warnval{$key})) {
  172. $exitcode = 1;
  173. $cause .= $channels{$key} . " $key channels detected. ";
  174. }
  175. }
  176. }
  177. if ($exitcode == 0) {
  178. print "OK ";
  179. } elsif ($exitcode == 1) {
  180. print "WARNING ";
  181. } elsif ($exitcode == 2) {
  182. print "CRITICAL ";
  183. } elsif ($exitcode > 2) {
  184. print "UNKNOWN ";
  185. }
  186. if (defined($s)) {
  187. $cause .= " Channels:$s";
  188. } else {
  189. $cause .= " (idle)";
  190. }
  191. print $cause;
  192. print "\n" if ($verbose);
  193. exit($exitcode);
  194. } elsif ($runmode == 1) {
  195. $port = $iax_port;
  196. socket(PING, PF_INET, SOCK_DGRAM, getprotobyname("udp"));
  197. $msg = pack "H24", $iax_src_call . $iax_dst_call . $iax_timestamp .
  198. $iax_outbound_seq . $iax_inbound_seq . $iax_type . $iax_type;
  199. $ipaddr = inet_aton($host);
  200. $sendto = sockaddr_in($port,$ipaddr);
  201. send(PING, $msg, 0, $sendto) == length($msg) or die "cannot send to $host : $port : $!\n";
  202. eval {
  203. local $SIG{ALRM} = sub { die("alarm time out"); };
  204. alarm $iax_timeout;
  205. while (1) {
  206. $recvfrom = recv(PING, $msg, $iax_maxlen, 0) or die "recv: $!";
  207. ($port, $ipaddr) = sockaddr_in($recvfrom);
  208. $respaddr = inet_ntoa($ipaddr);
  209. $iax_answer++;
  210. # print "Response from $respaddr : $port\n";
  211. }
  212. };
  213. if ($iax_answer) {
  214. if ($iax_answer == 1) {
  215. $reply = "reply";
  216. } else {
  217. $reply = "replies";
  218. }
  219. &ok("Got $iax_answer $reply");
  220. } else {
  221. &error("Got no reply");
  222. }
  223. }