]> git.pld-linux.org Git - packages/nagios-plugin-check_rbl.git/blob - mdns.patch
- apply mdns.patch
[packages/nagios-plugin-check_rbl.git] / mdns.patch
1 --- check_rbl-1.1.0/check_rbl   2010-04-06 20:26:18.598337785 +0300
2 +++ check_rbl-1.2.0/check_rbl   2010-04-06 20:40:42.858468257 +0300
3 @@ -2,8 +2,9 @@
4  # check_rbl is a Nagios plugin to check if an SMTP server is blacklisted
5  #
6  # See  the INSTALL file for installation instructions
7  #
8  # Copyright (c) 2007, ETH Zurich.
9 +# Copyright (c) 2010, Elan Ruusamäe <glen@delfi.ee>.
10  #
11  # This module is free software; you can redistribute it and/or modify it
12  # under the terms of GNU general public license (gpl) version 3.
13 @@ -22,14 +23,12 @@
14  use strict;
15  use warnings;
16  
17 -use Carp;
18 -use English '-no_match_vars';
19  use Nagios::Plugin::Threshold;
20  use Nagios::Plugin;
21  use Nagios::Plugin::Getopt;
22  use Net::DNS;
23 -use Parallel::Iterator qw(iterate);
24 +use IO::Select;
25  use Readonly;
26  
27  Readonly my $DEFAULT_RETRIES => 4;
28  Readonly my $DEFAULT_WORKERS => 20;
29 @@ -47,48 +46,15 @@
30  #
31  use vars qw(
32    @BLACKLISTED
33 +  @TIMEOUTS
34    $IP
35    $OPTIONS
36    $PLUGIN
37    $THRESHOLD
38 +  $res
39  );
40  
41  ##############################################################################
42 -# Usage     : my $ip = lookup( $hostname );
43 -# Purpose   : DNS lookup
44 -# Returns   : $ip if found; undef if not found
45 -# Arguments : $hostname : the FQDN to resolve
46 -# Throws    : n/a
47 -# Comments  : n/a
48 -# See also  : n/a
49 -sub lookup {
50 -
51 -    my ($hostname) = @_;
52 -
53 -    require Net::DNS;
54 -
55 -    my $res = Net::DNS::Resolver->new;
56 -
57 -    $res->retry( $OPTIONS->retry() );
58 -
59 -    my $query = $res->search($hostname);
60 -
61 -    if ($query) {
62 -        foreach my $rr ( $query->answer ) {
63 -            if ( $rr->type eq 'A' ) {
64 -                return $rr->address;
65 -            }
66 -        }
67 -    }
68 -    else {
69 -        return;
70 -    }
71 -
72 -    return;    # dead code to make perlcritic happy
73 -
74 -}
75 -
76 -##############################################################################
77  # Usage     : verbose("some message string", $optional_verbosity_level);
78  # Purpose   : write a message if the verbosity level is high enough
79  # Returns   : n/a
80 @@ -122,37 +88,119 @@
81  
82  }
83  
84 -##############################################################################
85 -# Usage     : check_server( $ip, $server )
86 -# Purpose   : checks if $ip is blacklisted by $server
87 -# Returns   : n/a
88 -# Arguments : $ip     : host IP
89 -#             $server : RBL server
90 -# Throws    : n/a
91 -# Comments  : if blacklisted pushed $server onto @blacklisted
92 -# See also  : n/a
93 -sub check_server {
94 -
95 -    my ($server) = @_;
96 -
97 -    my $lookup_ip = $IP;
98 +=item B<mdns(\@addresses, $callback)>
99  
100 -    $lookup_ip =~
101 -s/(\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3})/$4.$3.$2.$1.$server/mxs;
102 -
103 -    verbose " -> $lookup_ip\n";
104 -
105 -    if ( lookup($lookup_ip) ) {
106 -
107 -        verbose "LISTED: $lookup_ip\n";
108 -        return $lookup_ip;
109 -
110 -    }
111 +Resolves all IPs in C<@addresses> in parallel.
112 +If answer is found C<$callback> is called with arguments as: $name, $host.
113  
114 -    verbose "OK: $lookup_ip\n";
115 +Perform multiple DNS lookups in parallel. Based on Perl Net-DNS/mresolv.
116 +Elan Ruusamäe <glen@delfi.ee>, (c) 1999-2010
117  
118 -    return 0;
119 +=cut
120 +sub mdns {
121 +       my $data = shift;
122 +       my $callback = shift;
123 +
124 +       # number of requests to have outstanding at any time
125 +       my $opt_n = $OPTIONS->workers;
126 +       # timeout per query (seconds)
127 +       my $opt_t = 15;
128 +       my $opt_d = $OPTIONS->verbose;
129 +
130 +       my $sel = IO::Select->new;
131 +       my $eof = 0;
132 +
133 +       my @addrs = @$data;
134 +       my %addrs;
135 +       while (1) {
136 +               my ($name, $sock);
137 +
138 +               #----------------------------------------------------------------------
139 +               # Read names until we've filled our quota of outstanding requests.
140 +               #----------------------------------------------------------------------
141 +
142 +               while (!$eof && $sel->count < $opt_n) {
143 +                       print "DEBUG: reading..." if $opt_d;
144 +                       $name = shift @addrs;
145 +                       unless (defined $name) {
146 +                               print "EOF.\n" if $opt_d;
147 +                               $eof = 1;
148 +                               last;
149 +                       }
150 +                       print "NAME: $name\n" if $opt_d;
151 +                       $sock = $res->bgsend($name);
152 +
153 +                       # we store in a hash the query we made, as parsing it back from
154 +                       # response gives different ip for ips with multiple hosts
155 +                       $addrs{$sock} = $name;
156 +                       $sel->add($sock);
157 +                       print "name = $name, outstanding = ", $sel->count, "\n" if $opt_d;
158 +               }
159 +
160 +               #----------------------------------------------------------------------
161 +               # Wait for any replies.  Remove any replies from the outstanding pool.
162 +               #----------------------------------------------------------------------
163 +
164 +               my @ready;
165 +               my $timed_out = 1;
166 +
167 +               print "DEBUG: waiting for replies\n" if $opt_d;
168 +
169 +               for (@ready = $sel->can_read($opt_t);
170 +                        @ready;
171 +                        @ready = $sel->can_read(0)) {
172 +
173 +                       $timed_out = 0;
174 +
175 +                       print "DEBUG: replies received: ", scalar @ready, "\n" if $opt_d;
176 +
177 +                       foreach $sock (@ready) {
178 +                               print "DEBUG: handling a reply\n" if $opt_d;
179 +                               my $addr = $addrs{$sock};
180 +                               delete $addrs{$sock};
181 +                               $sel->remove($sock);
182 +
183 +                               my $ans = $res->bgread($sock);
184 +                               my $host;
185 +                               if ($ans) {
186 +                                       foreach my $rr ($ans->answer) {
187 +                                               next unless $rr->type eq 'A';
188 +                                               $host = $rr->address;
189 +                                               # take just first answer
190 +                                               last;
191 +                                       }
192 +                               } else {
193 +                                       print "DEBUG: no answer: ". $res->errorstring. "\n" if $opt_d;
194 +                               }
195 +                               &$callback($addr, $host);
196 +                       }
197 +               }
198 +
199 +               #----------------------------------------------------------------------
200 +               # If we timed out waiting for replies, remove all entries from the
201 +               # outstanding pool.
202 +               #----------------------------------------------------------------------
203 +
204 +               if ($timed_out) {
205 +                       print "DEBUG: timeout: clearing the outstanding pool.\n" if $opt_d;
206 +                       my $sock;
207 +                       foreach $sock ($sel->handles) {
208 +                               my $addr = $addrs{$sock};
209 +                               delete $addrs{$sock};
210 +                               $sel->remove($sock);
211 +                               # callback for hosts that timed out
212 +                               &$callback($addr, '');
213 +                       }
214 +               }
215 +
216 +               print "DEBUG: outstanding = ", $sel->count, ", eof = $eof\n" if $opt_d;
217 +
218 +               #----------------------------------------------------------------------
219 +               # We're done if there are no outstanding queries and we've read EOF.
220 +               #----------------------------------------------------------------------
221  
222 +               last if ($sel->count == 0) && $eof;
223 +       }
224  }
225  
226  ##############################################################################
227 @@ -232,9 +280,16 @@
228          'critical has to be greater or equal warning' );
229  }
230  
231 +$res = new Net::DNS::Resolver;
232 +$res->force_v4(1) if $res->can('force_v4');
233 +$res->retry($OPTIONS->retry());
234 +
235  $IP = $OPTIONS->host;
236 -if ( $IP =~ m/[[:lower:]]/mxs ) {
237 -    $IP = lookup( $OPTIONS->host );
238 +if ($IP =~ m/[[:lower:]]/mxs) {
239 +       mdns([ $OPTIONS->host ], sub {
240 +               my ($addr, $host) = @_;
241 +               $IP = $host;
242 +       });
243  }
244  
245  if ( !$IP ) {
246 @@ -259,28 +314,37 @@
247  
248  verbose 'Checking ' . $OPTIONS->host . " ($IP) on $nservers server(s)\n";
249  
250 -my $iter = iterate(
251 -    { workers => $OPTIONS->workers },
252 -    \&check_server,
253 -    sub {
254 -        while ( my $server = pop @servers ) {
255 -            return $server;
256 -        }
257 -        return;
258 -    }
259 -);
260 -
261 -while ( my ( $server, $result ) = $iter->() ) {
262 -    if ($result) {
263 -        push @BLACKLISTED, $server;
264 -    }
265 +# build address lists
266 +my @addrs;
267 +foreach my $server (@servers) {
268 +       (my $ip = $IP) =~ s/(\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3}) [.] (\d{1,3})/$4.$3.$2.$1.$server/x;
269 +       push(@addrs, $ip);
270  }
271  
272 +mdns(\@addrs, sub {
273 +       my ($addr, $host) = @_;
274 +       # extract RBL we checked
275 +       $addr =~ s/^(?:\d+\.){4}//;
276 +       if (defined $host) {
277 +               if ($host eq '') {
278 +                       push @TIMEOUTS, $addr;
279 +               } else {
280 +                       verbose "listed in $addr as $host\n";
281 +                       push @BLACKLISTED, $addr;
282 +               }
283 +       }
284 +});
285 +
286  my $total = scalar @BLACKLISTED;
287  
288  my $status =
289    $OPTIONS->host. " BLACKLISTED on $total " . ( ( $total == 1 ) ? 'server' : 'servers' ) . " of $nservers";
290  
291 +# append timeout info, but do not account these in status
292 +if (@TIMEOUTS) {
293 +       $status .= sprintf(" (%d servers timeout: %s)", scalar @TIMEOUTS, join(', ', @TIMEOUTS));
294 +}
295 +
296  if ( $total > 0 ) {
297      $status .= " (@BLACKLISTED)";
298  }
This page took 0.076062 seconds and 3 git commands to generate.