1 --- check_rbl-1.2.0/check_rbl 2010-04-06 20:40:42.858468257 +0300
2 +++ check_rbl-1.1.0/check_rbl 2010-04-06 21:00:56.970381943 +0300
4 # See the INSTALL file for installation instructions
6 # Copyright (c) 2007, ETH Zurich.
7 +# Copyright (c) 2010, Elan Ruusamäe <glen@delfi.ee>.
9 # This module is free software; you can redistribute it and/or modify it
10 # under the terms of GNU general public license (gpl) version 3.
16 -use English '-no_match_vars';
17 use Nagios::Plugin::Threshold;
19 use Nagios::Plugin::Getopt;
21 -use Parallel::Iterator qw(iterate);
25 Readonly my $DEFAULT_RETRIES => 4;
38 ##############################################################################
39 -# Usage : my $ip = lookup( $hostname );
40 -# Purpose : DNS lookup
41 -# Returns : $ip if found; undef if not found
42 -# Arguments : $hostname : the FQDN to resolve
48 - my ($hostname) = @_;
52 - my $res = Net::DNS::Resolver->new;
54 - $res->retry( $OPTIONS->retry() );
56 - my $query = $res->search($hostname);
59 - foreach my $rr ( $query->answer ) {
60 - if ( $rr->type eq 'A' ) {
61 - return $rr->address;
69 - return; # dead code to make perlcritic happy
73 -##############################################################################
74 # Usage : verbose("some message string", $optional_verbosity_level);
75 # Purpose : write a message if the verbosity level is high enough
80 ##############################################################################
81 -# Usage : check_server( $ip, $server )
82 -# Purpose : checks if $ip is blacklisted by $server
83 +# Usage : mdns(\@addresses, $callback)
84 +# Purpose : Perform multiple DNS lookups in parallel
86 -# Arguments : $ip : host IP
87 -# $server : RBL server
89 -# Comments : if blacklisted pushed $server onto @blacklisted
95 - my $lookup_ip = $IP;
98 -s/(\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3})/$4.$3.$2.$1.$server/mxs;
100 - verbose " -> $lookup_ip\n";
102 - if ( lookup($lookup_ip) ) {
104 - verbose "LISTED: $lookup_ip\n";
109 - verbose "OK: $lookup_ip\n";
112 +# See also : Perl Net::DNS module mresolv in examples
114 +# Resolves all IPs in C<@addresses> in parallel.
115 +# If answer is found C<$callback> is called with arguments as: $name, $host.
117 +# Author: Elan Ruusamäe <glen@delfi.ee>, (c) 1999-2010
120 + my $callback = shift;
122 + # number of requests to have outstanding at any time
123 + my $opt_n = $OPTIONS->workers;
124 + # timeout per query (seconds)
126 + my $opt_d = $OPTIONS->verbose;
128 + my $sel = IO::Select->new;
131 + my @addrs = @$data;
134 + #----------------------------------------------------------------------
135 + # Read names until we've filled our quota of outstanding requests.
136 + #----------------------------------------------------------------------
138 + while (!$eof && $sel->count < $opt_n) {
139 + print "DEBUG: reading..." if $opt_d;
140 + my $name = shift @addrs;
141 + unless (defined $name) {
142 + print "EOF.\n" if $opt_d;
146 + print "NAME: $name\n" if $opt_d;
147 + my $sock = $res->bgsend($name);
149 + # we store in a hash the query we made, as parsing it back from
150 + # response gives different ip for ips with multiple hosts
151 + $addrs{$sock} = $name;
153 + print "name = $name, outstanding = ", $sel->count, "\n" if $opt_d;
156 + #----------------------------------------------------------------------
157 + # Wait for any replies. Remove any replies from the outstanding pool.
158 + #----------------------------------------------------------------------
163 + print "DEBUG: waiting for replies\n" if $opt_d;
165 + for (@ready = $sel->can_read($opt_t);
167 + @ready = $sel->can_read(0)) {
171 + print "DEBUG: replies received: ", scalar @ready, "\n" if $opt_d;
173 + foreach my $sock (@ready) {
174 + print "DEBUG: handling a reply\n" if $opt_d;
175 + my $addr = $addrs{$sock};
176 + delete $addrs{$sock};
177 + $sel->remove($sock);
179 + my $ans = $res->bgread($sock);
182 + foreach my $rr ($ans->answer) {
183 + next unless $rr->type eq 'A';
184 + $host = $rr->address;
185 + # take just first answer
189 + print "DEBUG: no answer: ". $res->errorstring. "\n" if $opt_d;
191 + &$callback($addr, $host);
195 + #----------------------------------------------------------------------
196 + # If we timed out waiting for replies, remove all entries from the
197 + # outstanding pool.
198 + #----------------------------------------------------------------------
201 + print "DEBUG: timeout: clearing the outstanding pool.\n" if $opt_d;
202 + foreach my $sock ($sel->handles) {
203 + my $addr = $addrs{$sock};
204 + delete $addrs{$sock};
205 + $sel->remove($sock);
206 + # callback for hosts that timed out
207 + &$callback($addr, '');
211 + print "DEBUG: outstanding = ", $sel->count, ", eof = $eof\n" if $opt_d;
213 + #----------------------------------------------------------------------
214 + # We're done if there are no outstanding queries and we've read EOF.
215 + #----------------------------------------------------------------------
217 + last if ($sel->count == 0) && $eof;
221 ##############################################################################
223 'critical has to be greater or equal warning' );
226 +$res = new Net::DNS::Resolver;
227 +$res->force_v4(1) if $res->can('force_v4');
228 +$res->retry($OPTIONS->retry());
230 $IP = $OPTIONS->host;
231 -if ( $IP =~ m/[[:lower:]]/mxs ) {
232 - $IP = lookup( $OPTIONS->host );
233 +if ($IP =~ m/[[:lower:]]/mxs) {
234 + mdns([ $OPTIONS->host ], sub {
235 + my ($addr, $host) = @_;
241 @@ -259,28 +312,37 @@
243 verbose 'Checking ' . $OPTIONS->host . " ($IP) on $nservers server(s)\n";
246 - { workers => $OPTIONS->workers },
249 - while ( my $server = pop @servers ) {
256 -while ( my ( $server, $result ) = $iter->() ) {
258 - push @BLACKLISTED, $server;
260 +# build address lists
262 +foreach my $server (@servers) {
263 + (my $ip = $IP) =~ s/(\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3})/$4.$3.$2.$1.$server/x;
268 + my ($addr, $host) = @_;
269 + # extract RBL we checked
270 + $addr =~ s/^(?:\d+\.){4}//;
271 + if (defined $host) {
273 + push @TIMEOUTS, $addr;
275 + verbose "listed in $addr as $host\n";
276 + push @BLACKLISTED, $addr;
281 my $total = scalar @BLACKLISTED;
284 $OPTIONS->host. " BLACKLISTED on $total " . ( ( $total == 1 ) ? 'server' : 'servers' ) . " of $nservers";
286 +# append timeout info, but do not account these in status
288 + $status .= sprintf(" (%d servers timeout: %s)", scalar @TIMEOUTS, join(', ', @TIMEOUTS));
292 $status .= " (@BLACKLISTED)";