line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
2
|
|
|
|
|
|
|
package Net::DNSBL::MultiDaemon; |
3
|
|
|
|
|
|
|
|
4
|
16
|
|
|
16
|
|
19045
|
use strict; |
|
16
|
|
|
|
|
28
|
|
|
16
|
|
|
|
|
672
|
|
5
|
|
|
|
|
|
|
#use diagnostics; |
6
|
|
|
|
|
|
|
|
7
|
16
|
|
|
|
|
5247
|
use vars qw( |
8
|
|
|
|
|
|
|
$VERSION @ISA @EXPORT_OK %EXPORT_TAGS *R_Sin |
9
|
|
|
|
|
|
|
$D_CLRRUN $D_SHRTHD $D_TIMONLY $D_QRESP $D_NOTME $D_ANSTOP $D_VERBOSE |
10
|
16
|
|
|
16
|
|
75
|
); |
|
16
|
|
|
|
|
24
|
|
11
|
|
|
|
|
|
|
require Exporter; |
12
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# DEBUG is a set of semaphores |
15
|
|
|
|
|
|
|
$D_CLRRUN = 0x1; # clear run flag and force unconditional return |
16
|
|
|
|
|
|
|
$D_SHRTHD = 0x2; # return short header message |
17
|
|
|
|
|
|
|
$D_TIMONLY = 0x4; # exit at end of timer section |
18
|
|
|
|
|
|
|
$D_QRESP = 0x8; # return query response message |
19
|
|
|
|
|
|
|
$D_NOTME = 0x10; # return received response not for me |
20
|
|
|
|
|
|
|
$D_ANSTOP = 0x20; # clear run OK flag if ANSWER present |
21
|
|
|
|
|
|
|
$D_VERBOSE = 0x40; # verbose debug statements to STDERR |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
$VERSION = do { my @r = (q$Revision: 0.39 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r }; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
@EXPORT_OK = qw( |
26
|
|
|
|
|
|
|
run |
27
|
|
|
|
|
|
|
bl_lookup |
28
|
|
|
|
|
|
|
set_extension |
29
|
|
|
|
|
|
|
); |
30
|
|
|
|
|
|
|
%EXPORT_TAGS = ( |
31
|
|
|
|
|
|
|
debug => [qw($D_CLRRUN $D_SHRTHD $D_TIMONLY $D_QRESP $D_NOTME $D_ANSTOP $D_VERBOSE uniqueID)], |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
Exporter::export_ok_tags('debug'); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
my $FATans = 0; # this causes a response size overflow from some DNSBLS that have |
36
|
|
|
|
|
|
|
# many mirrors, so only the local host authority record is returned |
37
|
|
|
|
|
|
|
|
38
|
6
|
|
|
6
|
0
|
5136
|
sub fatreturn { return $FATans }; # for testing |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
my $eXT = undef; # extension code for "Private Use" as defined in outlined in RFC-6195 |
41
|
|
|
|
|
|
|
# Query types |
42
|
|
|
|
|
|
|
# Classes |
43
|
|
|
|
|
|
|
# Types |
44
|
|
|
|
|
|
|
|
45
|
16
|
|
|
16
|
|
16935
|
use Socket; |
|
16
|
|
|
|
|
74202
|
|
|
16
|
|
|
|
|
10355
|
|
46
|
16
|
|
|
|
|
4553
|
use Net::DNS::Codes qw( |
47
|
|
|
|
|
|
|
TypeTxt |
48
|
|
|
|
|
|
|
T_A |
49
|
|
|
|
|
|
|
T_AAAA |
50
|
|
|
|
|
|
|
T_ANY |
51
|
|
|
|
|
|
|
T_MX |
52
|
|
|
|
|
|
|
T_CNAME |
53
|
|
|
|
|
|
|
T_NS |
54
|
|
|
|
|
|
|
T_TXT |
55
|
|
|
|
|
|
|
T_SOA |
56
|
|
|
|
|
|
|
T_AXFR |
57
|
|
|
|
|
|
|
T_PTR |
58
|
|
|
|
|
|
|
C_IN |
59
|
|
|
|
|
|
|
PACKETSZ |
60
|
|
|
|
|
|
|
HFIXEDSZ |
61
|
|
|
|
|
|
|
QUERY |
62
|
|
|
|
|
|
|
NOTIMP |
63
|
|
|
|
|
|
|
FORMERR |
64
|
|
|
|
|
|
|
NOERROR |
65
|
|
|
|
|
|
|
REFUSED |
66
|
|
|
|
|
|
|
NXDOMAIN |
67
|
|
|
|
|
|
|
SERVFAIL |
68
|
|
|
|
|
|
|
BITS_QUERY |
69
|
|
|
|
|
|
|
RD |
70
|
|
|
|
|
|
|
QR |
71
|
|
|
|
|
|
|
CD |
72
|
16
|
|
|
16
|
|
17038
|
); |
|
16
|
|
|
|
|
29332
|
|
73
|
16
|
|
|
|
|
1696
|
use Net::DNS::ToolKit 0.16 qw( |
74
|
|
|
|
|
|
|
newhead |
75
|
|
|
|
|
|
|
gethead |
76
|
|
|
|
|
|
|
get_ns |
77
|
16
|
|
|
16
|
|
15500
|
); |
|
16
|
|
|
|
|
621377
|
|
78
|
16
|
|
|
16
|
|
16870
|
use Net::DNS::ToolKit::RR; |
|
16
|
|
|
|
|
68339
|
|
|
16
|
|
|
|
|
752
|
|
79
|
|
|
|
|
|
|
#use Net::DNS::ToolKit::Debug qw( |
80
|
|
|
|
|
|
|
# print_head |
81
|
|
|
|
|
|
|
# print_buf |
82
|
|
|
|
|
|
|
#); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
#use Data::Dumper; |
85
|
|
|
|
|
|
|
|
86
|
16
|
|
|
|
|
30860
|
use Net::DNSBL::Utilities 0.07 qw( |
87
|
|
|
|
|
|
|
s_response |
88
|
|
|
|
|
|
|
not_found |
89
|
|
|
|
|
|
|
write_stats |
90
|
|
|
|
|
|
|
statinit |
91
|
|
|
|
|
|
|
A1271 |
92
|
|
|
|
|
|
|
A1272 |
93
|
|
|
|
|
|
|
A1274 |
94
|
|
|
|
|
|
|
A1275 |
95
|
|
|
|
|
|
|
A1276 |
96
|
|
|
|
|
|
|
A1277 |
97
|
|
|
|
|
|
|
list2NetAddr |
98
|
|
|
|
|
|
|
matchNetAddr |
99
|
|
|
|
|
|
|
setAUTH |
100
|
|
|
|
|
|
|
setRA |
101
|
16
|
|
|
16
|
|
9358
|
); |
|
16
|
|
|
|
|
369
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# target for queries about DNSBL zones, create once per session |
104
|
|
|
|
|
|
|
# this is a global so it can be altered during testing |
105
|
|
|
|
|
|
|
*R_Sin = \scalar sockaddr_in(53,scalar get_ns()); |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head1 NAME |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
Net::DNSBL::MultiDaemon - multi DNSBL prioritization |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head1 SYNOPSIS |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
use Net::DNSBL::MultiDaemon qw( |
114
|
|
|
|
|
|
|
:debug |
115
|
|
|
|
|
|
|
run |
116
|
|
|
|
|
|
|
bl_lookup |
117
|
|
|
|
|
|
|
set_extension |
118
|
|
|
|
|
|
|
); |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
run($BLzone,$L,$R,$DNSBL,$STATs,$Run,$Sfile,$StatStamp,$DEBUG) |
121
|
|
|
|
|
|
|
bl_lookup($put,$mp,$rtp,$sinaddr,$alarm,$rid,$id,$rip,$type,$zone,@blist); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=head1 DESCRIPTION |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
B is the Perl module that implements the B |
126
|
|
|
|
|
|
|
daemon. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
B is a DNS emulator daemon that increases the efficacy of DNSBL |
129
|
|
|
|
|
|
|
look-ups in a mail system. B may be used as a stand-alone DNSBL |
130
|
|
|
|
|
|
|
or as a plug-in for a standard BIND 9 installation. |
131
|
|
|
|
|
|
|
B shares a common configuration file format with the |
132
|
|
|
|
|
|
|
Mail::SpamCannibal sc_BLcheck.pl script so that DNSBL's can be maintained in |
133
|
|
|
|
|
|
|
a common configuration file for an entire mail installation. |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
Because DNSBL usefulness is dependent on the nature and source of spam sent to a |
136
|
|
|
|
|
|
|
specific site and because sometimes DNSBL's may provide intermittant |
137
|
|
|
|
|
|
|
service, B interrogates them sorted in the order of B
|
138
|
|
|
|
|
|
|
successful hits>. DNSBL's that do not respond within the configured timeout |
139
|
|
|
|
|
|
|
period are not interrogated at all after 6 consecutive failures, and |
140
|
|
|
|
|
|
|
thereafter will be retried not more often than once every hour until they |
141
|
|
|
|
|
|
|
come back online. This eliminates the need to place DNSBL's in a particular order in |
142
|
|
|
|
|
|
|
your MTA's config file or periodically monitor the DNSBL statistics and/or update |
143
|
|
|
|
|
|
|
the MTA config file. |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
In addition to optimizing DNSBL interrogation, B may be |
146
|
|
|
|
|
|
|
configured to locally accept or reject specified IP's, IP ranges and to |
147
|
|
|
|
|
|
|
reject specified countries by 2 character country code. By adding a DNSBL |
148
|
|
|
|
|
|
|
entry of B, IP's will be rejected that do not return some kind |
149
|
|
|
|
|
|
|
of valid reverse DNS lookup. In addition, IP's can be rejected that have a |
150
|
|
|
|
|
|
|
PTR record that matchs a configurable GENERIC 'regexp' set. |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
Reject codes are as follows: |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
query 2.0.0.127.{zonename} 127.0.0.2 |
155
|
|
|
|
|
|
|
blocked by configured DNSBL 127.0.0.2 |
156
|
|
|
|
|
|
|
no reverse DNS 127.0.0.4 |
157
|
|
|
|
|
|
|
BLOCKED (local blacklist) 127.0.0.5 |
158
|
|
|
|
|
|
|
Blocked by Country 127.0.0.6 |
159
|
|
|
|
|
|
|
Blocked GENERIC 127.0.0.7 |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=head1 OPERATION |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
The configuration file for B contains optional IGNORE (always |
164
|
|
|
|
|
|
|
pass), optional BLOCK (always reject), and optional BBC (block by country) entries against |
165
|
|
|
|
|
|
|
which all received queries are checked before external DNSBL's are queried. |
166
|
|
|
|
|
|
|
IP's which pass IGNORE, BLOCK, and BBC test are then checked against the |
167
|
|
|
|
|
|
|
prioritized list of DNSBL's to try when looking up an IP address for blacklisting. |
168
|
|
|
|
|
|
|
Internally, B maintains this list in sorted order (including |
169
|
|
|
|
|
|
|
'in-addr.arpa') based on the number of responses that |
170
|
|
|
|
|
|
|
resulted in an acceptable A record being returned from the DNSBL query. For |
171
|
|
|
|
|
|
|
each IP address query sent to B, a query is sent to each |
172
|
|
|
|
|
|
|
configured DNSBL sequentially until all DNSBL's have been queried or an |
173
|
|
|
|
|
|
|
acceptable A record is returned. |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
Let us say for example that blackholes.easynet.nl (below) will return an A record |
176
|
|
|
|
|
|
|
and list.dsbl.org, bl.spamcop.net, dynablock.easynet.nl, will not. |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
LIST |
179
|
|
|
|
|
|
|
9451 list.dsbl.org |
180
|
|
|
|
|
|
|
6516 bl.spamcop.net |
181
|
|
|
|
|
|
|
2350 dynablock.easynet.nl |
182
|
|
|
|
|
|
|
575 blackholes.easynet.nl |
183
|
|
|
|
|
|
|
327 cbl.abuseat.org |
184
|
|
|
|
|
|
|
309 dnsbl.sorbs.net |
185
|
|
|
|
|
|
|
195 dnsbl.njabl.org |
186
|
|
|
|
|
|
|
167 sbl.spamhaus.org |
187
|
|
|
|
|
|
|
22 spews.dnsbl.net.au |
188
|
|
|
|
|
|
|
6 relays.ordb.org |
189
|
|
|
|
|
|
|
1 proxies.blackholes.easynet.nl |
190
|
|
|
|
|
|
|
0 dsbl.org |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
A query to B (pseudo.dnsbl in this example) looks like this |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
QUERY |
195
|
|
|
|
|
|
|
1.2.3.4.pseudo.dnsbl |
196
|
|
|
|
|
|
|
| |
197
|
|
|
|
|
|
|
V |
198
|
|
|
|
|
|
|
#################### |
199
|
|
|
|
|
|
|
# multi_dnsbl # |
200
|
|
|
|
|
|
|
#################### |
201
|
|
|
|
|
|
|
| RESPONSE |
202
|
|
|
|
|
|
|
+--> 1.2.3.4.list.dsbl.org NXDOMAIN |
203
|
|
|
|
|
|
|
| |
204
|
|
|
|
|
|
|
+--> 1.2.3.4.bl.spamcop.net NXDOMAIN |
205
|
|
|
|
|
|
|
| |
206
|
|
|
|
|
|
|
+--> 1.2.3.4.dynablock.easynet.nl NXDOMAIN |
207
|
|
|
|
|
|
|
| |
208
|
|
|
|
|
|
|
+--> 1.2.3.4.blackholes.easynet.nl A-127.0.0.2 |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
The A record is returned to originator of the Query and the statistics count |
211
|
|
|
|
|
|
|
on blackholes.easynet.nl is incremented by one. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 INSTALLATION / CONFIGURATION / OPERATION |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
B can be installed as either a standalone DNSBL or as a plug-in |
216
|
|
|
|
|
|
|
to a BIND 9 installation on the same host. In either case, copy the |
217
|
|
|
|
|
|
|
rc.multi_daemon script to the appropriate startup directory on your host and |
218
|
|
|
|
|
|
|
modify the start, stop, restart scripts as required. Operation of the script |
219
|
|
|
|
|
|
|
is as follows: |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Syntax: ./rc.multi_dnsbl start /path/to/config.file |
222
|
|
|
|
|
|
|
./rc.multi_dnsbl start -v /path/to/config.file |
223
|
|
|
|
|
|
|
./rc.multi_dnsbl stop /path/to/config.file |
224
|
|
|
|
|
|
|
./rc.multi_dnsbl restart /path/to/config.file |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
The -v switch will print the scripts |
227
|
|
|
|
|
|
|
actions verbosely to the STDERR. |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
=head2 CONFIGURATION FILE |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
The configuration file for B shares a common format with the |
232
|
|
|
|
|
|
|
Mail::SpamCannibal sc_BLcheck.pl script, facilitating common maintenance of |
233
|
|
|
|
|
|
|
DNSBL's for your MTA installation. |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
The sample configuration file |
236
|
|
|
|
|
|
|
B is heavily commented with the details for each |
237
|
|
|
|
|
|
|
configuration element. If you plan to use a common configuration file in a |
238
|
|
|
|
|
|
|
SpamCannibal installation, simply add the following elements to the |
239
|
|
|
|
|
|
|
B file: |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
MDstatfile => '/path/to/statistics/file.txt', |
242
|
|
|
|
|
|
|
MDpidpath => '/path/to/pidfiles', # /var/run |
243
|
|
|
|
|
|
|
MDzone => 'pseudo.dnsbl', |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# OPTIONAL |
246
|
|
|
|
|
|
|
MDstatrefresh => 300, # seconds |
247
|
|
|
|
|
|
|
MDipaddr => '0.0.0.0', # PROBABLY NOT WHAT YOU WANT |
248
|
|
|
|
|
|
|
MDport => 9953, |
249
|
|
|
|
|
|
|
MDcache => 10000, # an entry takes ~400 bytes |
250
|
|
|
|
|
|
|
# default 10000 (to small) |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
### WARNING ### |
253
|
|
|
|
|
|
|
failure to set MDipaddr to a valid ip address will result |
254
|
|
|
|
|
|
|
in the authority section return an NS record of INADDR_ANY |
255
|
|
|
|
|
|
|
This will return an invalid NS record in stand alone operation |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=head2 STANDALONE OPERATION |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
For standalone operation, simply set B, nothing more is |
260
|
|
|
|
|
|
|
required. |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
Interrogating the installation will then return the first |
263
|
|
|
|
|
|
|
match from the configured list of DNSBL servers. |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
i.e. dig 2.0.0.127.pseudo.dnsbl |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
.... results |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=head2 PLUGIN to BIND 9 |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
B may be used as a plugin helper for a standard bind 9 |
272
|
|
|
|
|
|
|
installation by adding a B zone to the configuration file as |
273
|
|
|
|
|
|
|
follows: |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
//zone pseudo.dnsbl |
276
|
|
|
|
|
|
|
zone "pseudo.dnsbl" in { |
277
|
|
|
|
|
|
|
type forward; |
278
|
|
|
|
|
|
|
forward only; |
279
|
|
|
|
|
|
|
forwarders { |
280
|
|
|
|
|
|
|
127.0.0.1 port 9953; |
281
|
|
|
|
|
|
|
}; |
282
|
|
|
|
|
|
|
}; |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
You may also wish to add one or more of the following statements with |
285
|
|
|
|
|
|
|
appropriate address_match_lists to restrict access to the facility. |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
allow-notify {}; |
288
|
|
|
|
|
|
|
allow-query { address_match_list }; |
289
|
|
|
|
|
|
|
allow-recursion { address_match_list }; |
290
|
|
|
|
|
|
|
allow-transfer {}; |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=head2 MTA CONFIGURATION |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
Access to DNSBL lookup is configured in the normal fashion for each MTA. |
295
|
|
|
|
|
|
|
Since MTA's generally must interrogate on port 53, B must be |
296
|
|
|
|
|
|
|
installed on a stand-alone server or as a plugin for BIND 9. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
A typical configuration line for B configuration file is shown |
299
|
|
|
|
|
|
|
below: |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
FEATURE(`dnsbl',`pseudo.dnsbl', |
302
|
|
|
|
|
|
|
`554 Rejected $&{client_addr} found in http://www.my.blacklist.org')dnl |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=head1 SYSTEM SIGNALS |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
B responds to the following system signals: |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=over 4 |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=item * TERM |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
Operations the statistics file is updated with the internal counts and the |
313
|
|
|
|
|
|
|
daemon then exits. |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=item * HUP |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
Operations are stopped including an update of the optional statistics file, |
318
|
|
|
|
|
|
|
the configuration file is re-read and operations are restarted. |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=item * USR1 |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
The statistics file is updated on the next second tick. |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=item * USR2 |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
The statistics file is deleted, internal statistics then a new (empty) |
327
|
|
|
|
|
|
|
statistics file is written on the next second tick. |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=back |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=head1 PERL MODULE DESCRIPTION |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
B provides most of the functions that implement |
334
|
|
|
|
|
|
|
B which is an MTA helper that interrogates a list of |
335
|
|
|
|
|
|
|
DNSBL servers in preferential order based on their success rate. |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
The following describes the workings of individual functions |
338
|
|
|
|
|
|
|
used to implement B. |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=over 4 |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=item * run($BLzone,$L,$R,$DNSBL,$STATs,$Run,$Sfile,$StatStamp,$DEBUG); |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
This function is the 'run' portion for the DNSBL multidaemon |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
input: |
347
|
|
|
|
|
|
|
$BLzone zone name, |
348
|
|
|
|
|
|
|
$L local listen socket object pointer, |
349
|
|
|
|
|
|
|
$R remote socket object pointer, |
350
|
|
|
|
|
|
|
$DNSBL config hash pointer, |
351
|
|
|
|
|
|
|
$STATs statistics hash pointer |
352
|
|
|
|
|
|
|
$Run pointer to stats refresh time, # must be non-zero |
353
|
|
|
|
|
|
|
$Sfile statistics file path, |
354
|
|
|
|
|
|
|
$StatStamp stat file initial time stamp |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
returns: nothing |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
=over 2 |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
=item * $BLzone |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
The fully qualified domain name of the blacklist lookup |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
=item * $L |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
A pointer to a UDP listener object |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=item * $R |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
A pointer to a unbound UDP socket |
371
|
|
|
|
|
|
|
used for interogation and receiving replies for the multiple DNSBL's |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=item * $DNSBL |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
A pointer to the configuration hash of the form: |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
$DNSBL = { |
378
|
|
|
|
|
|
|
# Always allow these addresses |
379
|
|
|
|
|
|
|
'IGNORE' => [ # OPTIONAL |
380
|
|
|
|
|
|
|
# a single address |
381
|
|
|
|
|
|
|
'11.22.33.44', |
382
|
|
|
|
|
|
|
# a range of ip's, ONLY VALID WITHIN THE SAME CLASS 'C' |
383
|
|
|
|
|
|
|
'22.33.44.55 - 22.33.44.65', |
384
|
|
|
|
|
|
|
# a CIDR range |
385
|
|
|
|
|
|
|
'5.6.7.16/28', |
386
|
|
|
|
|
|
|
# a range specified with a netmask |
387
|
|
|
|
|
|
|
'7.8.9.128/255.255.255.240', |
388
|
|
|
|
|
|
|
# you may want these |
389
|
|
|
|
|
|
|
'10.0.0.0/8', |
390
|
|
|
|
|
|
|
'172.16.0.0/12', |
391
|
|
|
|
|
|
|
'192.168.0.0/16', |
392
|
|
|
|
|
|
|
# this should ALWAYS be here |
393
|
|
|
|
|
|
|
'127.0.0.0/8', # ignore all test entries and localhost |
394
|
|
|
|
|
|
|
], |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
# Do rhbl lookups only, default false |
397
|
|
|
|
|
|
|
# all other rejection classes are disabled, IGNORE, BLOCK, BBC, in-addr.arpa |
398
|
|
|
|
|
|
|
# RHBL need only be "true" for operation. If OPTIONAL URBL conditioning |
399
|
|
|
|
|
|
|
# is needed, then the parameters in the has must be added |
400
|
|
|
|
|
|
|
RHBL => { # optional URBL preparation |
401
|
|
|
|
|
|
|
urblwhite => [ |
402
|
|
|
|
|
|
|
'/path/to/cached/whitefile', |
403
|
|
|
|
|
|
|
'/path/to/local/file' # see format of spamassassin file |
404
|
|
|
|
|
|
|
], |
405
|
|
|
|
|
|
|
urblblack => [ |
406
|
|
|
|
|
|
|
'/path/to/local/blacklist' |
407
|
|
|
|
|
|
|
], |
408
|
|
|
|
|
|
|
# NOTE: level 3 tld's should be first before level 2 tld's |
409
|
|
|
|
|
|
|
urbltlds => [ |
410
|
|
|
|
|
|
|
'/path/to/cached/tld3file', |
411
|
|
|
|
|
|
|
'/path/to/cached/tld2file' |
412
|
|
|
|
|
|
|
], |
413
|
|
|
|
|
|
|
urlwhite => [ |
414
|
|
|
|
|
|
|
'http://spamassasin.googlecode.com/svn-history/r6/trunk/share/spamassassin/25_uribl.cf', |
415
|
|
|
|
|
|
|
'/path/to/cached/whitefile' |
416
|
|
|
|
|
|
|
], |
417
|
|
|
|
|
|
|
urltld3 => [ |
418
|
|
|
|
|
|
|
'http://george.surbl.org/three-level-tlds', |
419
|
|
|
|
|
|
|
'/path/to/cached/tld3file' |
420
|
|
|
|
|
|
|
], |
421
|
|
|
|
|
|
|
urltld2 => [ |
422
|
|
|
|
|
|
|
'http://george.surbl.org/two-level-tlds', |
423
|
|
|
|
|
|
|
'/path/to/cached/tld2file' |
424
|
|
|
|
|
|
|
], |
425
|
|
|
|
|
|
|
}, |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
# Authoratative answers |
428
|
|
|
|
|
|
|
'AUTH' => 0, |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
# Always reject these addresses |
431
|
|
|
|
|
|
|
'BLOCK' => [ # OPTIONAL |
432
|
|
|
|
|
|
|
# same format as above |
433
|
|
|
|
|
|
|
], |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
# Always block these countries |
436
|
|
|
|
|
|
|
'BBC' => [qw(CN TW RO )], |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# Check for reverse lookup failures - OPTIONAL |
439
|
|
|
|
|
|
|
'in-addr.arpa' => { |
440
|
|
|
|
|
|
|
timeout => 15, # default timeout is 30 |
441
|
|
|
|
|
|
|
}, |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
# RBL zones as follows: OPTIONAL |
444
|
|
|
|
|
|
|
'domain.name' => { |
445
|
|
|
|
|
|
|
# mark this dnsbl to require right hand side domain processing |
446
|
|
|
|
|
|
|
# requires URBL::Prepare |
447
|
|
|
|
|
|
|
# NOT IMPLEMENTED |
448
|
|
|
|
|
|
|
# urbl => 1, |
449
|
|
|
|
|
|
|
acceptany => 'comment - treat any response as valid', |
450
|
|
|
|
|
|
|
# or |
451
|
|
|
|
|
|
|
accept => { |
452
|
|
|
|
|
|
|
'127.0.0.2' => 'comment', |
453
|
|
|
|
|
|
|
'127.0.0.3' => 'comment', |
454
|
|
|
|
|
|
|
}, |
455
|
|
|
|
|
|
|
# or |
456
|
|
|
|
|
|
|
# mask the low 8 bits and accept any true result |
457
|
|
|
|
|
|
|
acceptmask => 0x3D, # accepts 0011 1101 |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
# timeout => 30, # default seconds to wait for dnsbl |
460
|
|
|
|
|
|
|
}, |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
'next.domain' = { |
463
|
|
|
|
|
|
|
etc.... |
464
|
|
|
|
|
|
|
# included but extracted external to B |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
MDzone => 'pseudo.dnsbl', |
467
|
|
|
|
|
|
|
MDstatfile => '/path/to/statistics/file.txt', |
468
|
|
|
|
|
|
|
MDpidpath => '/path/to/pidfiles |
469
|
|
|
|
|
|
|
# OPTIONAL, defaults shown |
470
|
|
|
|
|
|
|
# MDstatrefresh => 300, # max seconds for refresh |
471
|
|
|
|
|
|
|
# MDipaddr => '0.0.0.0', # PROBABLY NOT WHAT YOU WANT |
472
|
|
|
|
|
|
|
# MDport => 9953, |
473
|
|
|
|
|
|
|
# syslog. Specify the facility, one of: |
474
|
|
|
|
|
|
|
# LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG |
475
|
|
|
|
|
|
|
# MDsyslog => 'LOG_WARNING', |
476
|
|
|
|
|
|
|
# |
477
|
|
|
|
|
|
|
# cache lookups using the TTL of the providing DNSBL |
478
|
|
|
|
|
|
|
# each cache entry takes about 400 bytes, minimum size = 1000 |
479
|
|
|
|
|
|
|
# MDcache => 1000, # 1000 is too small |
480
|
|
|
|
|
|
|
}; |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Zone labels that are not of the form *.*... are ignored, making this hash |
483
|
|
|
|
|
|
|
table fully compatible with the SpamCannibal sc_Blacklist.conf file. |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=item * $STATs |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
A pointer to a statistics collection array of the form: |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
$STATs = { |
490
|
|
|
|
|
|
|
'domain.name' => count, |
491
|
|
|
|
|
|
|
etc..., |
492
|
|
|
|
|
|
|
'CountryCode' => count, |
493
|
|
|
|
|
|
|
etc... |
494
|
|
|
|
|
|
|
}; |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
Initialize this array with |
497
|
|
|
|
|
|
|
cntinit($DNSBL,$cp) L/cntinit, then |
498
|
|
|
|
|
|
|
list2hash($BBC,$cp) L/list2hash, then |
499
|
|
|
|
|
|
|
statinit($Sfile,$cp) L/statinit, below. |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=item * $Run |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
A POINTER to the time in seconds to refresh the $STATs backing file. Even if |
504
|
|
|
|
|
|
|
there is not backing file used, this value must be a positive integer. |
505
|
|
|
|
|
|
|
Setting this value to zero will stop the daemon and force a restart. It is |
506
|
|
|
|
|
|
|
used by $SIG{HUP} to restart the daemon. |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=item * $Sfile |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
The path to the STATISTICS backing file. |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
i.e. /some/path/to/filename.ext |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
If $Sfile is undefined, then the time stamp need not be defined |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=item * $StatTimestamp |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
Normally the value returned by |
519
|
|
|
|
|
|
|
statinit($Sfile,$cp) L/statinit, below. |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=back |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=cut |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
my %AVGs = (); # averages |
526
|
|
|
|
|
|
|
my %CNTs = (); # current counts |
527
|
|
|
|
|
|
|
my $tick = 0; # second ticker |
528
|
|
|
|
|
|
|
my $interval = 300; # averaging interval |
529
|
|
|
|
|
|
|
my $bucket = 24 * 60 * 60; # 24 hours for now... |
530
|
|
|
|
|
|
|
my $weight = 5; # weight new stuff higher than old stuff |
531
|
|
|
|
|
|
|
my $csize = 0; # cache size and switch |
532
|
|
|
|
|
|
|
my $cused = 0; # cache in use |
533
|
|
|
|
|
|
|
my ($now, $next); |
534
|
|
|
|
|
|
|
my $newstat; # new statistics flag, used by run |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
sub average { |
537
|
578
|
|
|
578
|
0
|
3611
|
my $STATs = shift; |
538
|
578
|
|
|
|
|
963
|
my $multiplier = $bucket / ($bucket + (($now + $interval - $next) * $weight)); |
539
|
578
|
|
|
|
|
584
|
$next = $now + $interval; # next average event |
540
|
578
|
|
|
|
|
1188
|
foreach (keys %$STATs) { |
541
|
1734
|
50
|
|
|
|
3803
|
next unless $_ =~ /\./; # only real domains |
542
|
1734
|
50
|
|
|
|
3037
|
next unless exists $CNTs{"$_"}; |
543
|
1734
|
|
|
|
|
3852
|
$AVGs{"$_"} = ($AVGs{"$_"} + ($weight * $CNTs{"$_"})) * $multiplier; |
544
|
1734
|
|
|
|
|
6591
|
$CNTs{"$_"} = 0; |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
# increment statistics for "real" DNSBL's |
549
|
|
|
|
|
|
|
# input: STATS pointer |
550
|
|
|
|
|
|
|
# DNSBL string |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
sub bump_stats { |
553
|
1
|
|
|
1
|
0
|
4
|
my($STATs, $blist_0) = @_; |
554
|
1
|
|
|
|
|
4
|
$STATs->{"$blist_0"} += 1; # bump statistics count |
555
|
1
|
50
|
|
|
|
6
|
if (exists $CNTs{"$blist_0"}) { |
556
|
0
|
|
|
|
|
0
|
$CNTs{"$blist_0"} += 1; |
557
|
|
|
|
|
|
|
} else { |
558
|
1
|
|
|
|
|
3
|
$CNTs{"$blist_0"} = 1; |
559
|
1
|
|
|
|
|
3
|
$AVGs{"$blist_0"} = 1; |
560
|
|
|
|
|
|
|
} |
561
|
1
|
50
|
|
|
|
6
|
$newstat = 1 unless $newstat; # notify refresh that update may be needed |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
sub by_average { |
565
|
198
|
|
|
198
|
0
|
447
|
my($STATs,$a,$b) = @_;; |
566
|
198
|
100
|
100
|
|
|
1007
|
if (exists $AVGs{"$b"} && exists $AVGs{"$a"}) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
567
|
4
|
|
33
|
|
|
27
|
return ($AVGs{"$b"} <=> $AVGs{"$a"}) |
568
|
|
|
|
|
|
|
|| |
569
|
|
|
|
|
|
|
($STATs->{"$b"} <=> $STATs->{"$a"}); |
570
|
|
|
|
|
|
|
} |
571
|
|
|
|
|
|
|
elsif (exists $AVGs{"$b"}) { |
572
|
2
|
|
|
|
|
9
|
return 1; |
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
elsif (exists $AVGs{"$a"}) { |
575
|
2
|
|
|
|
|
7
|
return -1; |
576
|
|
|
|
|
|
|
} else { |
577
|
190
|
|
|
|
|
693
|
return ($STATs->{"$b"} <=> $STATs->{"$a"}); |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
# reverse digits in ipV4 address |
582
|
|
|
|
|
|
|
# |
583
|
|
|
|
|
|
|
# input: ip |
584
|
|
|
|
|
|
|
# returns: reversed ip |
585
|
|
|
|
|
|
|
# |
586
|
|
|
|
|
|
|
sub revIP { |
587
|
0
|
|
|
0
|
0
|
0
|
join('.',reverse split /\./,$_[0]); |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
# cache takes about 400 bytes per entry |
591
|
|
|
|
|
|
|
# |
592
|
|
|
|
|
|
|
my %cache = ( |
593
|
|
|
|
|
|
|
# |
594
|
|
|
|
|
|
|
# ip address => { |
595
|
|
|
|
|
|
|
# expires => time, now + TTL from response or 3600 minimum |
596
|
|
|
|
|
|
|
# used => time, time cache item was last used |
597
|
|
|
|
|
|
|
# who => $blist[0], which DNSBL caused caching |
598
|
|
|
|
|
|
|
# txt => 'string', txt from our config file or empty |
599
|
|
|
|
|
|
|
# }, |
600
|
|
|
|
|
|
|
); |
601
|
|
|
|
|
|
|
my @topurge; # working array |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
# for testing |
604
|
|
|
|
|
|
|
# set now and next, csize return pointers to internal averaging arrays and cache |
605
|
|
|
|
|
|
|
# |
606
|
|
|
|
|
|
|
sub set_nownext { |
607
|
580
|
|
|
580
|
0
|
9724
|
($now,$next,$csize) = @_; |
608
|
580
|
|
|
|
|
1085
|
return($interval,\%AVGs,\%CNTs,\%cache,\@topurge); |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
# purge cache when called from "run" |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
my $prp = -1; # run pointer, see "mode" below |
614
|
|
|
|
|
|
|
my $pai; # array index |
615
|
|
|
|
|
|
|
my $pnd; # array end |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
# piecewise purge of expired cache items performs gnome sort while purging |
618
|
|
|
|
|
|
|
# |
619
|
|
|
|
|
|
|
# followed by conditional purge of cache size overrun of oldest touched |
620
|
|
|
|
|
|
|
# cache items or those that will expire the soonest |
621
|
|
|
|
|
|
|
# |
622
|
|
|
|
|
|
|
# input: nothing |
623
|
|
|
|
|
|
|
# returns: mode |
624
|
|
|
|
|
|
|
# -1 waiting to be initialized |
625
|
|
|
|
|
|
|
# 0 purging expired elements + gnome sort |
626
|
|
|
|
|
|
|
# 1 purging cache overrun |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub purge_cache { |
629
|
339
|
100
|
|
339
|
0
|
3791
|
if ($prp == 0) { # run state to purge expired elements |
|
|
100
|
|
|
|
|
|
630
|
323
|
|
|
|
|
396
|
my $k1 = $topurge[$pai]; |
631
|
|
|
|
|
|
|
#print STDERR "$pnd, $pai"; |
632
|
323
|
100
|
|
|
|
494
|
if (exists $cache{$k1}) { |
633
|
322
|
|
|
|
|
335
|
my $j = $pai +1; |
634
|
322
|
|
|
|
|
335
|
my $k2 = $topurge[$j]; |
635
|
322
|
100
|
|
|
|
765
|
if ($cache{$k1}->{expires} < $now) { |
|
|
100
|
|
|
|
|
|
636
|
1
|
|
|
|
|
4
|
delete $cache{$k1}; |
637
|
1
|
|
|
|
|
3
|
splice(@topurge,$pai,1); # remove element from cache array |
638
|
1
|
|
|
|
|
3
|
$pnd--; |
639
|
|
|
|
|
|
|
#print STDERR " delete k1 = $k1\n"; |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
elsif (exists $cache{$k2}) { |
642
|
320
|
100
|
33
|
|
|
1435
|
if ($cache{$k2}->{expires} < $now) { |
|
|
100
|
66
|
|
|
|
|
643
|
5
|
|
|
|
|
13
|
delete $cache{$k2}; |
644
|
5
|
|
|
|
|
9
|
splice(@topurge,$j,1); # remove element from cache array |
645
|
5
|
|
|
|
|
8
|
$pnd--; |
646
|
|
|
|
|
|
|
#print STDERR " delete k2 = $k2\n"; |
647
|
|
|
|
|
|
|
} |
648
|
|
|
|
|
|
|
elsif ( $cache{$k1}->{used} > $cache{$k2}->{used} # oldest use |
649
|
|
|
|
|
|
|
|| ($cache{$k1}->{used} == $cache{$k2}->{used} # or if equal, |
650
|
|
|
|
|
|
|
&& $cache{$k1}->{expires} > $cache{$k2}->{expires}) # expires soonest |
651
|
|
|
|
|
|
|
) { |
652
|
140
|
|
|
|
|
270
|
@topurge[$pai,$j] = @topurge[$j,$pai]; |
653
|
140
|
|
|
|
|
153
|
$pai--; |
654
|
140
|
100
|
|
|
|
296
|
$pai = 0 if $pai < 0; |
655
|
|
|
|
|
|
|
#print STDERR " swap k1, k2 - $k1 <=> $k2\n"; |
656
|
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
else { |
658
|
175
|
|
|
|
|
236
|
$pai++; |
659
|
|
|
|
|
|
|
#print STDERR " k1, k2 ok - $k1 : $k2\n"; |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
else { |
663
|
1
|
|
|
|
|
2
|
splice(@topurge,$j,1); # remove element from cache array |
664
|
1
|
|
|
|
|
2
|
$pnd--; |
665
|
|
|
|
|
|
|
#print STDERR " remove k2 = $k2\n"; |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
else { |
669
|
1
|
|
|
|
|
4
|
splice(@topurge,$pai,1); # remove element from cache array |
670
|
1
|
|
|
|
|
3
|
$pnd--; |
671
|
|
|
|
|
|
|
#print STDERR " remove k1 = $k1\n"; |
672
|
|
|
|
|
|
|
} |
673
|
323
|
100
|
|
|
|
877
|
return $prp if $pai < $pnd; # reached end? |
674
|
|
|
|
|
|
|
# done, set next state |
675
|
4
|
|
|
|
|
6
|
$pnd++; |
676
|
4
|
|
|
|
|
6
|
$pnd -= $csize; |
677
|
4
|
100
|
|
|
|
9
|
if ($pnd > 0) { # must delete overrun elements |
678
|
2
|
|
|
|
|
3
|
$prp = 1; |
679
|
2
|
|
|
|
|
6
|
$pai = 0; |
680
|
|
|
|
|
|
|
} else { |
681
|
2
|
|
|
|
|
4
|
$prp = -1; # set to initialization state |
682
|
|
|
|
|
|
|
} |
683
|
|
|
|
|
|
|
} |
684
|
|
|
|
|
|
|
elsif ($prp > 0) { # remove cache over run |
685
|
12
|
|
|
|
|
17
|
my $k = $topurge[$pai]; |
686
|
12
|
50
|
|
|
|
43
|
delete $cache{$k} if exists $cache{$k}; |
687
|
12
|
|
|
|
|
14
|
$pai++; |
688
|
12
|
100
|
|
|
|
24
|
unless ($pai < $pnd) { |
689
|
2
|
|
|
|
|
4
|
$prp = -1; |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
else { |
693
|
4
|
50
|
|
|
|
17
|
return $prp unless $csize; # not enabled |
694
|
4
|
|
|
|
|
35
|
$pnd = @topurge = keys %cache; |
695
|
4
|
|
|
|
|
8
|
$cused = $pnd; # update amount of cache in use |
696
|
4
|
50
|
|
|
|
14
|
return $prp unless $pnd; # nothing to do |
697
|
4
|
|
|
|
|
5
|
$pnd--; # end of array |
698
|
4
|
|
|
|
|
6
|
$pai = 0; # array index |
699
|
4
|
|
|
|
|
7
|
$prp = 0; # run state sort |
700
|
|
|
|
|
|
|
} |
701
|
20
|
|
|
|
|
37
|
return $prp; |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
# setURBLdom |
705
|
|
|
|
|
|
|
# |
706
|
|
|
|
|
|
|
# sets breadcrumbs for stripped domain for URBL's |
707
|
|
|
|
|
|
|
# |
708
|
|
|
|
|
|
|
# input: remote IP or domain |
709
|
|
|
|
|
|
|
# remote ID |
710
|
|
|
|
|
|
|
# notRHBL |
711
|
|
|
|
|
|
|
# ubl method pointer |
712
|
|
|
|
|
|
|
# blacklist host array pointer UNUSED |
713
|
|
|
|
|
|
|
# remoteThreads ptr |
714
|
|
|
|
|
|
|
# return: |
715
|
|
|
|
|
|
|
# SCALAR $rid |
716
|
|
|
|
|
|
|
# ARRAY ($rid,$whitelistedDomain,$SURBLookupDomain) |
717
|
|
|
|
|
|
|
# or false or false |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
# $bap is unused |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
sub setURBLdom { |
722
|
23
|
|
|
23
|
0
|
85
|
my($rip,$rid,$notRHBL,$ubl,$bap,$rtp,$n) = @_; |
723
|
23
|
50
|
33
|
|
|
134
|
if ($notRHBL || ! $ubl) { # don't even need to check |
724
|
23
|
50
|
|
|
|
178
|
return wantarray ? ($rid) : $rid; # or URBL::Prepare not loaded |
725
|
|
|
|
|
|
|
} |
726
|
0
|
0
|
|
|
|
0
|
$rid = uniqueID() unless $rid; # set $rid if it is empty |
727
|
0
|
0
|
|
|
|
0
|
$rtp->{$rid} = {} unless exists $rtp->{$rid}; |
728
|
|
|
|
|
|
|
|
729
|
0
|
|
|
|
|
0
|
my $domain = ''; |
730
|
0
|
|
|
|
|
0
|
my $white = $ubl->urblwhite($rip); |
731
|
0
|
0
|
|
|
|
0
|
unless ($white) { |
732
|
0
|
|
|
|
|
0
|
$domain = $ubl->urbldomain($rip); |
733
|
|
|
|
|
|
|
} |
734
|
|
|
|
|
|
|
|
735
|
0
|
|
|
|
|
0
|
$rtp->{$rid}->{urbl} = $domain; |
736
|
0
|
|
|
|
|
0
|
$rtp->{$rid}->{N} = $n; |
737
|
0
|
0
|
|
|
|
0
|
return wantarray ? ($rid,$white,$domain) : $rid; |
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
sub run { |
741
|
43
|
|
|
43
|
1
|
17930186
|
my ($BLzone,$L,$R,$DNSBL,$STATs,$Run,$Sfile,$StatStamp,$DEBUG) = @_; |
742
|
|
|
|
|
|
|
#open(Tmp,'>>/tmp/multidnsbl.log'); |
743
|
|
|
|
|
|
|
#print Tmp "---------------------------\n"; |
744
|
43
|
|
100
|
26
|
|
1459
|
local *_alarm = sub {return $DNSBL->{"$_[0]"}->{timeout} || 30}; |
|
26
|
|
|
|
|
786
|
|
745
|
43
|
|
|
|
|
222
|
$BLzone = lc $BLzone; |
746
|
43
|
|
50
|
|
|
1075
|
my $myip = $DNSBL->{MDipaddr} || ''; |
747
|
43
|
50
|
33
|
|
|
349
|
if ($myip && $myip ne '0.0.0.0') { |
748
|
0
|
|
|
|
|
0
|
$myip = inet_aton($myip); |
749
|
|
|
|
|
|
|
} else { |
750
|
43
|
|
|
|
|
6069
|
$myip = A1271; |
751
|
|
|
|
|
|
|
} |
752
|
43
|
50
|
|
|
|
149
|
$DEBUG = 0 unless $DEBUG; |
753
|
43
|
100
|
|
|
|
199
|
my $ROK = ($DEBUG & $D_CLRRUN) ? 0:1; |
754
|
|
|
|
|
|
|
|
755
|
43
|
|
|
|
|
354
|
my ( $msg, $t, $targetIP, $cc, $comment, |
756
|
|
|
|
|
|
|
$Oname,$Otype,$Oclass,$Ottl,$Ordlength,$Odata, |
757
|
|
|
|
|
|
|
$off,$id,$qr,$opcode,$aa,$tc,$rd,$ra,$mbz,$ad,$cd,$rcode, |
758
|
|
|
|
|
|
|
$qdcount,$ancount,$nscount,$arcount, |
759
|
|
|
|
|
|
|
$name,$type,$class, |
760
|
|
|
|
|
|
|
$ttl,$rdl,@rdata, |
761
|
|
|
|
|
|
|
$l_Sin,$rip,$zone,@blist, |
762
|
|
|
|
|
|
|
%remoteThreads,$rid, |
763
|
|
|
|
|
|
|
$rin,$rout,$nfound, |
764
|
|
|
|
|
|
|
$BBC,@NAignore,@NAblock, |
765
|
|
|
|
|
|
|
$notRHBL,$ubl); |
766
|
|
|
|
|
|
|
|
767
|
43
|
|
|
|
|
104
|
my $LogLevel = 0; |
768
|
43
|
50
|
|
|
|
224
|
if ($DNSBL->{MDsyslog}) { # if logging requested |
769
|
0
|
|
|
|
|
0
|
require Unix::Syslog; |
770
|
0
|
|
|
|
|
0
|
import Unix::Syslog @Unix::Syslog::EXPORT_OK; |
771
|
0
|
|
|
|
|
0
|
$LogLevel = eval "$DNSBL->{MDsyslog}"; |
772
|
|
|
|
|
|
|
## NOTE, logging must be initiated by the caller |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
# generate NetAddr objects for addresses to always pass |
776
|
43
|
50
|
66
|
|
|
500
|
if ($DNSBL->{IGNORE} && ref $DNSBL->{IGNORE} eq 'ARRAY' && @{$DNSBL->{IGNORE}}) { |
|
2
|
|
66
|
|
|
8
|
|
777
|
2
|
|
|
|
|
31
|
list2NetAddr($DNSBL->{IGNORE},\@NAignore); |
778
|
|
|
|
|
|
|
} |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
# generate NetAddr objects for addresses to always reject |
781
|
43
|
50
|
66
|
|
|
254
|
if ($DNSBL->{BLOCK} && ref $DNSBL->{BLOCK} eq 'ARRAY' && @{$DNSBL->{BLOCK}}) { |
|
1
|
|
66
|
|
|
6
|
|
782
|
1
|
|
|
|
|
42
|
list2NetAddr($DNSBL->{BLOCK},\@NAblock); |
783
|
|
|
|
|
|
|
} |
784
|
|
|
|
|
|
|
|
785
|
|
|
|
|
|
|
# fetch pointer to Geo::IP methods |
786
|
43
|
50
|
33
|
|
|
360
|
if ($DNSBL->{BBC} && ref $DNSBL->{BBC} eq 'ARRAY' && @{$DNSBL->{BBC}} && eval { require Geo::IP::PurePerl }) { |
|
0
|
|
33
|
|
|
0
|
|
|
0
|
|
0
|
|
|
0
|
|
787
|
0
|
|
|
|
|
0
|
$BBC = new Geo::IP::PurePerl; |
788
|
|
|
|
|
|
|
} else { |
789
|
43
|
|
|
|
|
799
|
$DNSBL->{BBC} = ''; |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
# check for caching |
793
|
43
|
50
|
|
|
|
185
|
if (exists $DNSBL->{MDcache}) { |
794
|
0
|
|
|
|
|
0
|
$csize = $DNSBL->{MDcache}; |
795
|
0
|
0
|
|
|
|
0
|
$csize = 10000 if $DNSBL->{MDcache} < 10000; |
796
|
|
|
|
|
|
|
} |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
# check for right hand side block list operation |
799
|
43
|
50
|
|
|
|
153
|
if ($DNSBL->{RHBL}) { |
800
|
0
|
|
|
|
|
0
|
$notRHBL = 0; |
801
|
0
|
0
|
0
|
|
|
0
|
if (ref $DNSBL->{RHBL} && |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
802
|
|
|
|
|
|
|
((exists $DNSBL->{RHBL}->{urbltlds} && ref($DNSBL->{RHBL}->{urbltlds}) eq 'ARRAY') || |
803
|
|
|
|
|
|
|
(exists $DNSBL->{RHBL}->{urblwhite} && ref($DNSBL->{RHBL}->{urblwhite}) eq 'ARRAY') || |
804
|
|
|
|
|
|
|
(exists $DNSBL->{RHBL}->{urblblack} && ref($DNSBL->{RHBL}->{urblblack}) eq 'ARRAY')) && |
805
|
|
|
|
|
|
|
eval { |
806
|
16
|
|
|
16
|
|
137
|
no warnings; |
|
16
|
|
|
|
|
24
|
|
|
16
|
|
|
|
|
416774
|
|
807
|
0
|
|
|
|
|
0
|
require URBL::Prepare; |
808
|
|
|
|
|
|
|
} |
809
|
|
|
|
|
|
|
) { |
810
|
0
|
|
|
|
|
0
|
$ubl = new URBL::Prepare; |
811
|
0
|
0
|
0
|
|
|
0
|
if (exists $DNSBL->{RHBL}->{urlwhite} && ref($DNSBL->{RHBL}->{urlwhite}) eq 'ARRAY') { |
812
|
0
|
|
|
|
|
0
|
$ubl->loadcache(@{$DNSBL->{RHBL}->{urlwhite}}); # cache whitelist file |
|
0
|
|
|
|
|
0
|
|
813
|
|
|
|
|
|
|
} |
814
|
0
|
0
|
0
|
|
|
0
|
if (exists $DNSBL->{RHBL}->{urltld3} && ref($DNSBL->{RHBL}->{urltld3}) eq 'ARRAY') { |
815
|
0
|
|
|
|
|
0
|
$ubl->loadcache(@{$DNSBL->{RHBL}->{urltld3}}); # cache tld3 file |
|
0
|
|
|
|
|
0
|
|
816
|
|
|
|
|
|
|
} |
817
|
0
|
0
|
0
|
|
|
0
|
if (exists $DNSBL->{RHBL}->{urltld2} && ref($DNSBL->{RHBL}->{urltld2}) eq 'ARRAY') { |
818
|
0
|
|
|
|
|
0
|
$ubl->loadcache(@{$DNSBL->{RHBL}->{urltld2}}); # cache tld2 file |
|
0
|
|
|
|
|
0
|
|
819
|
|
|
|
|
|
|
} |
820
|
0
|
|
|
|
|
0
|
$ubl->cachetlds($DNSBL->{RHBL}->{urbltlds}); |
821
|
0
|
|
|
|
|
0
|
$ubl->cachewhite($DNSBL->{RHBL}->{urblwhite}); |
822
|
0
|
|
|
|
|
0
|
$ubl->cacheblack($DNSBL->{RHBL}->{urblblack}); |
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
} else { |
825
|
43
|
|
|
|
|
106
|
$notRHBL = 1; |
826
|
|
|
|
|
|
|
} |
827
|
|
|
|
|
|
|
#select Tmp; |
828
|
|
|
|
|
|
|
#$| = 1; |
829
|
|
|
|
|
|
|
#print Tmp "running $$\n"; |
830
|
|
|
|
|
|
|
#select STDOUT; |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
# set up GENERIC PTR tests |
834
|
43
|
|
|
|
|
110
|
my($iptr,$regexptr); |
835
|
43
|
50
|
33
|
|
|
247
|
if ( exists $DNSBL->{GENERIC} && |
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
836
|
|
|
|
|
|
|
ref $DNSBL->{GENERIC} eq 'HASH' && |
837
|
|
|
|
|
|
|
($regexptr = $DNSBL->{GENERIC}->{regexp}) && |
838
|
|
|
|
|
|
|
ref $regexptr eq 'ARRAY' && |
839
|
|
|
|
|
|
|
@$regexptr > 0 ) { |
840
|
|
|
|
|
|
|
#print Tmp "regexptr setup, @$regexptr\n"; |
841
|
0
|
0
|
0
|
|
|
0
|
unless ( $DNSBL->{GENERIC}->{ignore} && |
|
|
|
0
|
|
|
|
|
842
|
|
|
|
|
|
|
'ARRAY' eq ref ($iptr = $DNSBL->{GENERIC}->{ignore}) && |
843
|
|
|
|
|
|
|
@$iptr > 0 ) { |
844
|
0
|
|
|
|
|
0
|
undef $iptr; |
845
|
|
|
|
|
|
|
} |
846
|
|
|
|
|
|
|
} else { |
847
|
|
|
|
|
|
|
#print Tmp "regexptr FAILED\n"; |
848
|
43
|
|
|
|
|
98
|
undef $regexptr; |
849
|
|
|
|
|
|
|
} |
850
|
|
|
|
|
|
|
|
851
|
43
|
|
|
|
|
206
|
my $filenoL = fileno($L); |
852
|
43
|
|
|
|
|
187
|
my $filenoR = fileno($R); |
853
|
|
|
|
|
|
|
|
854
|
43
|
|
|
|
|
262
|
$now = time; |
855
|
43
|
|
|
|
|
138
|
$next = $now + $interval; |
856
|
43
|
|
|
|
|
74
|
$newstat = 0; # new statistics flag |
857
|
43
|
|
|
|
|
105
|
my $refresh = $now + $$Run; # update statistics "then" |
858
|
|
|
|
|
|
|
|
859
|
43
|
|
|
0
|
|
2092
|
local $SIG{USR1} = sub {$newstat = 2}; # force write of stats now |
|
0
|
|
|
|
|
0
|
|
860
|
|
|
|
|
|
|
local $SIG{USR2} = sub { # kill and regenerate statfile |
861
|
0
|
0
|
|
0
|
|
0
|
return unless $Sfile; |
862
|
0
|
|
|
|
|
0
|
unlink $Sfile; |
863
|
0
|
|
|
|
|
0
|
foreach(keys %$STATs) { |
864
|
0
|
|
|
|
|
0
|
$STATs->{"$_"} = 0; |
865
|
0
|
|
|
|
|
0
|
%AVGs = (); |
866
|
0
|
|
|
|
|
0
|
%CNTs = (); |
867
|
|
|
|
|
|
|
} |
868
|
0
|
|
|
|
|
0
|
$StatStamp = statinit($Sfile,$STATs); |
869
|
0
|
0
|
|
|
|
0
|
syslog($LogLevel,"received USR2, clear stats\n") |
870
|
|
|
|
|
|
|
if $LogLevel; |
871
|
0
|
|
|
|
|
0
|
$newstat = 2; # re-write on next second tick |
872
|
43
|
|
|
|
|
1296
|
}; |
873
|
|
|
|
|
|
|
|
874
|
43
|
|
|
|
|
404
|
my $SOAptr = [ # set up bogus SOA |
875
|
|
|
|
|
|
|
$BLzone, |
876
|
|
|
|
|
|
|
&T_SOA, |
877
|
|
|
|
|
|
|
&C_IN, |
878
|
|
|
|
|
|
|
0, # ttl of SOA record |
879
|
|
|
|
|
|
|
$BLzone, |
880
|
|
|
|
|
|
|
'root.'. $BLzone, |
881
|
|
|
|
|
|
|
$now, |
882
|
|
|
|
|
|
|
86400, |
883
|
|
|
|
|
|
|
43200, |
884
|
|
|
|
|
|
|
172800, |
885
|
|
|
|
|
|
|
3600, # cache negative TTL's for an hour |
886
|
|
|
|
|
|
|
]; |
887
|
|
|
|
|
|
|
|
888
|
43
|
|
|
|
|
1920
|
my ($get,$put,$parse) = new Net::DNS::ToolKit::RR; |
889
|
|
|
|
|
|
|
|
890
|
43
|
|
|
|
|
2628
|
my $numberoftries = 6; |
891
|
|
|
|
|
|
|
|
892
|
43
|
|
|
|
|
91
|
my %deadDNSBL; |
893
|
43
|
|
|
|
|
724
|
foreach(keys %$STATs) { |
894
|
216
|
100
|
|
|
|
1416
|
next unless $_ =~ /\./; # only real domains |
895
|
87
|
|
|
|
|
572
|
$deadDNSBL{"$_"} = 1; # initialize dead DNSBL timers |
896
|
|
|
|
|
|
|
} |
897
|
|
|
|
|
|
|
|
898
|
43
|
|
66
|
|
|
119
|
do { |
899
|
70
|
|
|
|
|
315
|
$rin = ''; |
900
|
70
|
|
|
|
|
528
|
vec($rin,$filenoL,1) = 1; # always listening to local port |
901
|
70
|
100
|
|
|
|
344
|
(vec($rin,$filenoR,1) = 1) # listen to remote only if traffic expected |
902
|
|
|
|
|
|
|
if %remoteThreads; |
903
|
70
|
|
|
|
|
24142740
|
$nfound = select($rout=$rin,undef,undef,1); # tick each second |
904
|
70
|
100
|
|
|
|
416
|
if ($nfound > 0) { |
905
|
|
|
|
|
|
|
###################### IF PROCESS REQUEST ######################## |
906
|
60
|
|
|
|
|
340
|
while (vec($rout,$filenoL,1)) { # process request |
907
|
45
|
50
|
|
|
|
358
|
last unless ($l_Sin = recv($L,$msg,PACKETSZ,0)); # ignore receive errors |
908
|
45
|
100
|
|
|
|
5120
|
if (length($msg) < HFIXEDSZ) { # ignore if less then header size |
909
|
3
|
50
|
|
|
|
272
|
return 'short header' if $DEBUG & $D_SHRTHD; |
910
|
0
|
|
|
|
|
0
|
last; |
911
|
|
|
|
|
|
|
} |
912
|
42
|
|
|
|
|
853
|
($off,$id,$qr,$opcode,$aa,$tc,$rd,$ra,$mbz,$ad,$cd,$rcode, |
913
|
|
|
|
|
|
|
$qdcount,$ancount,$nscount,$arcount) |
914
|
|
|
|
|
|
|
= gethead(\$msg); |
915
|
42
|
100
|
|
|
|
193
|
if ($qr) { |
916
|
1
|
50
|
|
|
|
34
|
return 'query response' if $DEBUG & $D_QRESP; |
917
|
0
|
|
|
|
|
0
|
last; |
918
|
|
|
|
|
|
|
} |
919
|
41
|
|
|
|
|
102
|
$comment = 'no bl'; |
920
|
41
|
|
|
|
|
1578
|
setAUTH(0); # clear authority |
921
|
41
|
|
|
|
|
1421
|
setRA($rd); |
922
|
|
|
|
|
|
|
# if OPCODE |
923
|
41
|
50
|
33
|
|
|
338
|
if ($eXT && exists $eXT->{OPCODE} && $eXT->{OPCODE}->($eXT,$get,$put,\$msg, |
|
|
100
|
33
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
924
|
|
|
|
|
|
|
$off,$id,$qr,$opcode,$aa,$tc,$rd,$ra,$mbz,$ad,$cd,$rcode,$qdcount,$ancount,$nscount,$arcount)) { |
925
|
|
|
|
|
|
|
; # message updated |
926
|
0
|
|
|
|
|
0
|
$comment = 'mdextension opcode'; |
927
|
|
|
|
|
|
|
} elsif ($opcode != QUERY) { |
928
|
1
|
|
|
|
|
25
|
s_response(\$msg,NOTIMP,$id,1,0,0,0); |
929
|
1
|
|
|
|
|
3
|
$comment = 'not implemented'; |
930
|
|
|
|
|
|
|
} elsif ( |
931
|
|
|
|
|
|
|
$qdcount != 1 || |
932
|
|
|
|
|
|
|
$ancount || |
933
|
|
|
|
|
|
|
$nscount || |
934
|
|
|
|
|
|
|
$arcount |
935
|
|
|
|
|
|
|
) { |
936
|
4
|
|
|
|
|
53
|
s_response(\$msg,FORMERR,$id,$qdcount,$ancount,$nscount,$arcount); |
937
|
4
|
|
|
|
|
16
|
$comment = 'format error 1'; |
938
|
|
|
|
|
|
|
} elsif ( |
939
|
|
|
|
|
|
|
(($off,$name,$type,$class) = $get->Question(\$msg,$off)) && |
940
|
|
|
|
|
|
|
! $name) { # name must exist |
941
|
1
|
|
|
|
|
66
|
s_response(\$msg,FORMERR,$id,1,0,0,0); |
942
|
1
|
|
|
|
|
4
|
$comment = 'format error 2'; |
943
|
|
|
|
|
|
|
# if CLASS |
944
|
|
|
|
|
|
|
} elsif (!($eXT && exists $eXT->{CLASS} && $eXT->{CLASS}->($eXT,$get,$put,$id,$opcode,\$name,\$type,\$class)) && |
945
|
|
|
|
|
|
|
$class != C_IN) { # class must be C_IN |
946
|
1
|
|
|
|
|
68
|
s_response(\$msg,REFUSED,$id,$qdcount,$ancount,$nscount,$arcount); |
947
|
1
|
|
|
|
|
4
|
$comment = 'refused'; |
948
|
|
|
|
|
|
|
# if NAME |
949
|
|
|
|
|
|
|
} elsif (($eXT && exists $eXT->{NAME} && $eXT->{NAME}->($eXT,$get,$put,$id,$opcode,\$name,\$type,\$class)) || |
950
|
|
|
|
|
|
|
$name !~ /$BLzone$/i) { # question must be for this zone |
951
|
1
|
|
|
|
|
128
|
s_response(\$msg,NXDOMAIN,$id,1,0,0,0); |
952
|
1
|
|
|
|
|
4
|
$comment = 'not this zone'; |
953
|
|
|
|
|
|
|
} else { |
954
|
|
|
|
|
|
|
# THIS IS OUR ZONE request, generate a thread to handle it |
955
|
|
|
|
|
|
|
|
956
|
33
|
50
|
|
|
|
3426
|
print STDERR $name,' ',TypeTxt->{$type},' ' if $DEBUG & $D_VERBOSE; |
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
# if TYPE |
959
|
33
|
50
|
33
|
|
|
278
|
if ($eXT && exists $eXT->{TYPE} && (my $rv = $eXT->{TYPE}->($eXT,$get,$put,$id,$opcode,\$name,\$type,\$class))) { |
|
|
100
|
33
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
960
|
0
|
|
|
|
|
0
|
$msg = $rv; |
961
|
0
|
|
|
|
|
0
|
$comment = 'Extension type'; |
962
|
|
|
|
|
|
|
} elsif ( $type == T_A || |
963
|
|
|
|
|
|
|
$type == T_ANY || |
964
|
|
|
|
|
|
|
$type == T_TXT) { |
965
|
27
|
100
|
66
|
|
|
13774
|
if (( $notRHBL && |
|
|
50
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
966
|
|
|
|
|
|
|
$name =~ /^((\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3}))\.(.+)/ && |
967
|
|
|
|
|
|
|
($rip = $1) && |
968
|
|
|
|
|
|
|
($targetIP = "$5.$4.$3.$2") && |
969
|
|
|
|
|
|
|
($zone = $6) && |
970
|
|
|
|
|
|
|
$BLzone eq lc $zone) || |
971
|
|
|
|
|
|
|
# check for valid RFC1034 domain name, but allow digits in the first character |
972
|
|
|
|
|
|
|
(!$notRHBL && # check RHBL zones |
973
|
|
|
|
|
|
|
###### CHANGE this REGEXP to alter permissible domain name patterns |
974
|
|
|
|
|
|
|
$name =~ /^([a-zA-Z0-9][a-zA-Z0-9\.\-]+[a-zA-Z0-9])\.$BLzone$/ && # valid domain name |
975
|
|
|
|
|
|
|
($rip = $1) && |
976
|
|
|
|
|
|
|
($targetIP = '' || 1) && |
977
|
|
|
|
|
|
|
($zone = $BLzone))) { |
978
|
25
|
|
|
|
|
53
|
my $expires; |
979
|
|
|
|
|
|
|
# if CACHE |
980
|
25
|
50
|
33
|
|
|
723
|
if ($eXT && exists $eXT->{CACHE} && (my $rv = $eXT->{CACHE}->($eXT,$get,$put,$id,$opcode,$rip,\$name,\$type,\$class,$ubl))) { |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
981
|
0
|
|
|
|
|
0
|
$msg = $rv; |
982
|
|
|
|
|
|
|
} |
983
|
|
|
|
|
|
|
# if local white/black lists |
984
|
|
|
|
|
|
|
elsif (!$notRHBL && $ubl && # right side checking and local white/black lists |
985
|
|
|
|
|
|
|
do { |
986
|
0
|
0
|
|
|
|
0
|
if ($ubl->urblwhite($rip)) { |
|
|
0
|
|
|
|
|
|
987
|
0
|
|
|
|
|
0
|
not_found($put,$name,$type,$id,\$msg,$SOAptr); |
988
|
0
|
|
|
|
|
0
|
$rv = 'whitelisted'; |
989
|
|
|
|
|
|
|
} |
990
|
|
|
|
|
|
|
elsif ($ubl->urblblack($rip)) { |
991
|
0
|
|
|
|
|
0
|
($msg) = _ansrbak($put,$id,1,$rip,$zone,$type,3600,A1272,$BLzone,$myip,'blacklisted'); |
992
|
0
|
|
|
|
|
0
|
$rv = 'blacklisted'; |
993
|
|
|
|
|
|
|
} |
994
|
|
|
|
|
|
|
} |
995
|
|
|
|
|
|
|
) { |
996
|
0
|
|
|
|
|
0
|
$comment = $rv; |
997
|
|
|
|
|
|
|
} |
998
|
|
|
|
|
|
|
elsif ($rip eq '2.0.0.127') { # checkfor DNSBL test |
999
|
0
|
|
|
|
|
0
|
($msg) = _ansrbak($put,$id,1,$rip,$zone,$type,3600,A1272,$BLzone,$myip,'DNSBL test response to 127.0.0.2'); |
1000
|
0
|
|
|
|
|
0
|
$comment = 'just testing'; |
1001
|
|
|
|
|
|
|
} |
1002
|
|
|
|
|
|
|
### NOTE, $now does not get updated very often if the host is busy processing in this routine, but at least every 5 minutes.... good enough |
1003
|
|
|
|
|
|
|
elsif ( $csize && # cacheing enabled |
1004
|
|
|
|
|
|
|
exists $cache{$rip} && # item exists in cache |
1005
|
|
|
|
|
|
|
($expires = $cache{$rip}->{expires}) > $now ) { # cache not expired |
1006
|
0
|
|
|
|
|
0
|
$cache{$rip}->{used} = $now; # update last used time |
1007
|
0
|
|
|
|
|
0
|
my $blist_0 = $cache{$rip}->{who}; |
1008
|
0
|
|
|
|
|
0
|
my $txt = $cache{$rip}->{txt}; |
1009
|
0
|
0
|
|
|
|
0
|
$txt = $txt ? $txt . $targetIP : ''; |
1010
|
0
|
|
|
|
|
0
|
($msg) = _ansrbak($put,$id,1,$rip,$zone,$type,$expires - $now,A1272,$BLzone,$myip,$txt); # send cached record |
1011
|
0
|
|
|
|
|
0
|
$comment = 'cache record'; |
1012
|
0
|
|
|
|
|
0
|
bump_stats($STATs,$blist_0); |
1013
|
|
|
|
|
|
|
} |
1014
|
|
|
|
|
|
|
elsif ($type == T_TXT) { # none of the rest of static stuff has TXT records |
1015
|
0
|
|
|
|
|
0
|
not_found($put,$name,$type,$id,\$msg,$SOAptr); |
1016
|
0
|
|
|
|
|
0
|
$comment = 'no TXT'; |
1017
|
|
|
|
|
|
|
} |
1018
|
|
|
|
|
|
|
elsif ($notRHBL && @NAignore && matchNetAddr($targetIP,\@NAignore)) { # check for IP's to always pass |
1019
|
1
|
|
|
|
|
152
|
not_found($put,$name,$type,$id,\$msg,$SOAptr); # return unconditional NOT FOUND |
1020
|
1
|
|
|
|
|
1997
|
$STATs->{WhiteList} += 1; # bump WhiteList count |
1021
|
1
|
|
|
|
|
3
|
$comment = 'IGNORE'; |
1022
|
|
|
|
|
|
|
} |
1023
|
0
|
|
|
|
|
0
|
elsif ($notRHBL && @NAblock && matchNetAddr($targetIP,\@NAblock)) { # check for IP's to always block |
1024
|
1
|
|
|
|
|
44
|
($msg) = _ansrbak($put,$id,1,$rip,$zone,$type,3600,A1275,$BLzone,$myip); # answer 127.0.0.5 |
1025
|
1
|
|
|
|
|
6
|
$STATs->{BlackList} += 1; # bump BlackList count |
1026
|
1
|
|
|
|
|
2
|
$comment = 'BLOCK'; |
1027
|
|
|
|
|
|
|
} |
1028
|
|
|
|
|
|
|
elsif ($notRHBL && $BBC && # check for IP's to block by country |
1029
|
|
|
|
|
|
|
($cc = $BBC->country_code_by_addr($targetIP)) && |
1030
|
|
|
|
|
|
|
(grep($cc eq $_,@{$DNSBL->{BBC}}))) { |
1031
|
0
|
|
|
|
|
0
|
($msg) = _ansrbak($put,$id,1,$rip,$zone,$type,3600,A1276,$BLzone,$myip); # answer 127.0.0.6 |
1032
|
0
|
|
|
|
|
0
|
$STATs->{$cc} += 1; # bump statistics count |
1033
|
0
|
0
|
|
|
|
0
|
$newstat = 1 unless $newstat; # notify refresh that update may be needed |
1034
|
0
|
|
|
|
|
0
|
$comment = "block $cc"; |
1035
|
|
|
|
|
|
|
} |
1036
|
|
|
|
|
|
|
else { |
1037
|
|
|
|
|
|
|
#test here for GENERIC |
1038
|
23
|
|
|
|
|
3173
|
@blist = (); |
1039
|
23
|
|
|
|
|
823
|
foreach(sort { by_average($STATs,$a,$b) } keys %$STATs) { |
|
186
|
|
|
|
|
516
|
|
1040
|
116
|
100
|
|
|
|
8749
|
next unless $_ =~ /\./; # drop passed,white,black,bbc entries |
1041
|
47
|
|
|
|
|
93
|
push @blist, $_; |
1042
|
|
|
|
|
|
|
} |
1043
|
23
|
50
|
|
|
|
104
|
push @blist, 'genericPTR' if $regexptr; |
1044
|
|
|
|
|
|
|
# add bread crumbs for Extensions if necessary |
1045
|
23
|
|
|
|
|
39
|
$rid = undef; # trial remote ID |
1046
|
23
|
50
|
33
|
|
|
90
|
if ($eXT && exists $eXT->{LOOKUP}) { |
1047
|
0
|
|
|
|
|
0
|
$rid = uniqueID(); |
1048
|
0
|
|
|
|
|
0
|
$rid = $eXT->{LOOKUP}->($eXT,$get,$put,$rid,$id,$opcode,\$name,\$type,\$class,\%remoteThreads); |
1049
|
|
|
|
|
|
|
} |
1050
|
23
|
|
|
|
|
139
|
$rid = setURBLdom($rip,$rid,$notRHBL,$ubl,$DNSBL->{$blist[0]},\%remoteThreads,0); # initialize urbl domain lookup name |
1051
|
23
|
|
|
|
|
107
|
bl_lookup($put,\$msg,\%remoteThreads,$l_Sin,_alarm($blist[0]),$rid,$id,$rip,$type,$zone,@blist); |
1052
|
23
|
|
|
|
|
1791
|
send($R,$msg,0,$R_Sin); # udp may not block |
1053
|
23
|
50
|
|
|
|
114
|
print STDERR $blist[0] if $DEBUG & $D_VERBOSE; |
1054
|
23
|
|
|
|
|
91
|
last; |
1055
|
|
|
|
|
|
|
} |
1056
|
|
|
|
|
|
|
} |
1057
|
|
|
|
|
|
|
elsif ($BLzone eq lc $name && $type != T_TXT) { |
1058
|
0
|
|
|
|
|
0
|
my $noff = newhead(\$msg, |
1059
|
|
|
|
|
|
|
$id, |
1060
|
|
|
|
|
|
|
BITS_QUERY | QR, |
1061
|
|
|
|
|
|
|
1,1,1,0, |
1062
|
|
|
|
|
|
|
); |
1063
|
0
|
|
|
|
|
0
|
($noff,my @dnptrs) = $put->Question(\$msg,$noff, # 1 question |
1064
|
|
|
|
|
|
|
$name,$type,C_IN); # type is T_A |
1065
|
0
|
|
|
|
|
0
|
($noff,@dnptrs) = $put->A(\$msg,$noff,\@dnptrs, # 1 answer |
1066
|
|
|
|
|
|
|
$name,T_A,C_IN,86400,$myip); |
1067
|
0
|
|
|
|
|
0
|
($noff,@dnptrs) = $put->NS(\$msg,$noff,\@dnptrs, # 1 authority |
1068
|
|
|
|
|
|
|
$name,T_NS,C_IN,86400,$BLzone); |
1069
|
|
|
|
|
|
|
} |
1070
|
|
|
|
|
|
|
else { |
1071
|
2
|
|
|
|
|
51
|
not_found($put,$name,$type,$id,\$msg,$SOAptr); |
1072
|
|
|
|
|
|
|
} |
1073
|
|
|
|
|
|
|
} elsif ($type == T_NS && $BLzone eq lc $name) { # respond with myip address |
1074
|
0
|
|
|
|
|
0
|
my $noff = newhead(\$msg, |
1075
|
|
|
|
|
|
|
$id, |
1076
|
|
|
|
|
|
|
BITS_QUERY | QR, |
1077
|
|
|
|
|
|
|
1,1,0,1, |
1078
|
|
|
|
|
|
|
); |
1079
|
0
|
|
|
|
|
0
|
($noff,my @dnptrs) = $put->Question(\$msg,$noff, # 1 question |
1080
|
|
|
|
|
|
|
$name,$type,C_IN); # type is T_NS |
1081
|
0
|
|
|
|
|
0
|
($noff,@dnptrs) = $put->NS(\$msg,$noff,\@dnptrs, # 1 answer |
1082
|
|
|
|
|
|
|
$name,T_NS,C_IN,$86400,$BLzone); |
1083
|
0
|
|
|
|
|
0
|
($noff,@dnptrs) = $put->A(\$msg,$noff,\@dnptrs, # 1 additional glue |
1084
|
|
|
|
|
|
|
$BLzone,T_A,C_IN,86400,$myip); |
1085
|
|
|
|
|
|
|
} elsif ($type == T_NS || # answer common queries with a not found |
1086
|
|
|
|
|
|
|
$type == T_MX || |
1087
|
|
|
|
|
|
|
$type == T_SOA || |
1088
|
|
|
|
|
|
|
$type == T_CNAME || |
1089
|
|
|
|
|
|
|
$type == T_TXT) { |
1090
|
4
|
|
|
|
|
327
|
not_found($put,$name,$type,$id,\$msg,$SOAptr); |
1091
|
|
|
|
|
|
|
} elsif ($type == T_AXFR) { |
1092
|
1
|
|
|
|
|
132
|
s_response(\$msg,REFUSED,$id,1,0,0,0); |
1093
|
1
|
|
|
|
|
11
|
$comment = 'refused AXFR'; |
1094
|
|
|
|
|
|
|
} else { |
1095
|
1
|
|
|
|
|
71
|
s_response(\$msg,NOTIMP,$id,1,0,0,0); |
1096
|
1
|
|
|
|
|
7
|
$comment = 'not implemented'; |
1097
|
|
|
|
|
|
|
} |
1098
|
|
|
|
|
|
|
} |
1099
|
18
|
|
|
|
|
22460
|
send($L,$msg,0,$l_Sin); # udp may not block on send |
1100
|
18
|
50
|
|
|
|
86
|
print STDERR " $comment\n" if $DEBUG & $D_VERBOSE; |
1101
|
|
|
|
|
|
|
#print Tmp "$comment\n"; |
1102
|
18
|
|
|
|
|
47
|
last; |
1103
|
|
|
|
|
|
|
} |
1104
|
|
|
|
|
|
|
##################### IF RESPONSE ############################### |
1105
|
56
|
|
|
|
|
895
|
while (vec($rout,$filenoR,1)) { # A response |
1106
|
15
|
|
|
|
|
783
|
undef $msg; |
1107
|
15
|
50
|
|
|
|
489
|
last unless recv($R,$msg,,PACKETSZ,0); # ignore receive errors |
1108
|
15
|
100
|
|
|
|
975
|
if (length($msg) < HFIXEDSZ) { # ignore if less then header size |
1109
|
5
|
50
|
|
|
|
925
|
return 'short header' if $DEBUG & $D_SHRTHD; |
1110
|
0
|
|
|
|
|
0
|
last; |
1111
|
|
|
|
|
|
|
} |
1112
|
10
|
|
|
|
|
450
|
($off,$rid,$qr,$opcode,$aa,$tc,$rd,$ra,$mbz,$ad,$cd,$rcode, |
1113
|
|
|
|
|
|
|
$qdcount,$ancount,$nscount,$arcount) |
1114
|
|
|
|
|
|
|
= gethead(\$msg); |
1115
|
|
|
|
|
|
|
#print Tmp "GOT $rid, rcode=$rcode\n"; |
1116
|
10
|
100
|
33
|
|
|
646
|
unless ( $tc == 0 && |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
1117
|
|
|
|
|
|
|
$qr == 1 && |
1118
|
|
|
|
|
|
|
$opcode == QUERY && |
1119
|
|
|
|
|
|
|
($rcode == NOERROR || $rcode == NXDOMAIN || $rcode == SERVFAIL) && |
1120
|
|
|
|
|
|
|
$qdcount == 1 && |
1121
|
|
|
|
|
|
|
exists $remoteThreads{$rid}) { # must not be my question! |
1122
|
4
|
50
|
|
|
|
1632
|
return 'not me 1' if $DEBUG & $D_NOTME; |
1123
|
0
|
|
|
|
|
0
|
last; |
1124
|
|
|
|
|
|
|
} |
1125
|
6
|
|
|
|
|
164
|
($l_Sin,$rip,$id,$type,$zone,@blist) = @{$remoteThreads{$rid}->{args}}; |
|
6
|
|
|
|
|
141
|
|
1126
|
6
|
50
|
|
|
|
130
|
my $urbldom = exists $remoteThreads{$rid}->{urbl} ? $remoteThreads{$rid}->{urbl} : ''; |
1127
|
6
|
|
|
|
|
100
|
($off,$name,$t,$class) = $get->Question(\$msg,$off); |
1128
|
6
|
|
|
|
|
171
|
my($answer,$attl,@generic); |
1129
|
6
|
50
|
33
|
|
|
124
|
if ($ancount && $rcode == &NOERROR) { |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1130
|
6
|
50
|
|
|
|
231
|
$name =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\.(.+)$/ || $name =~ /^([a-zA-Z0-9][a-zA-Z0-9\.\-]+[a-zA-Z0-9])\.($blist[0])$/; |
1131
|
6
|
|
|
|
|
56
|
my $z = lc $2; |
1132
|
|
|
|
|
|
|
#print Tmp "RESPONSE U $urbldom, R $rip, One $1, N $name, Z $z\n"; |
1133
|
6
|
50
|
33
|
|
|
137
|
$z = ($z eq lc $blist[0]) || ($z eq 'in-addr.arpa' && $blist[0] eq 'genericPTR') |
1134
|
|
|
|
|
|
|
? 1 : 0; |
1135
|
6
|
0
|
0
|
|
|
100
|
unless ( $z && # not my question |
|
|
|
33
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1136
|
|
|
|
|
|
|
((!$urbldom && $rip eq $1) || |
1137
|
|
|
|
|
|
|
($urbldom && $urbldom eq $1)) && # not my question |
1138
|
|
|
|
|
|
|
($t == T_A || $t == T_PTR) && # not my question |
1139
|
|
|
|
|
|
|
$class == C_IN) { # not my question |
1140
|
6
|
50
|
|
|
|
497
|
return 'not me 2' if $DEBUG & $D_NOTME; |
1141
|
0
|
|
|
|
|
0
|
last; |
1142
|
|
|
|
|
|
|
} |
1143
|
0
|
|
|
|
|
0
|
undef $answer; |
1144
|
|
|
|
|
|
|
|
1145
|
0
|
|
|
|
|
0
|
setAUTH($aa); # mirror out authority state |
1146
|
0
|
|
|
|
|
0
|
setRA($rd); |
1147
|
|
|
|
|
|
|
|
1148
|
|
|
|
|
|
|
ANSWER: |
1149
|
0
|
|
|
|
|
0
|
foreach(0..$ancount -1) { |
1150
|
0
|
|
|
|
|
0
|
($off,$name,$t,$class,$ttl,$rdl,@rdata) = $get->next(\$msg,$off); |
1151
|
0
|
0
|
|
|
|
0
|
next if $answer; # throw away unneeded answers |
1152
|
0
|
0
|
0
|
|
|
0
|
if ($t == T_A) { |
|
|
0
|
|
|
|
|
|
1153
|
0
|
0
|
|
|
|
0
|
if (exists $DNSBL->{"$blist[0]"}->{acceptany}) { |
1154
|
0
|
|
|
|
|
0
|
$answer = A1272; |
1155
|
0
|
|
|
|
|
0
|
$attl = $ttl; |
1156
|
0
|
|
|
|
|
0
|
last ANSWER; |
1157
|
|
|
|
|
|
|
} |
1158
|
0
|
0
|
|
|
|
0
|
my $mask = (exists $DNSBL->{"$blist[0]"}->{acceptmask}) |
1159
|
|
|
|
|
|
|
? $DNSBL->{"$blist[0]"}->{acceptmask} : 0; |
1160
|
0
|
|
|
|
|
0
|
while($answer = shift @rdata) { # see if answer is on accept list |
1161
|
0
|
|
|
|
|
0
|
my $IP = inet_ntoa($answer); |
1162
|
0
|
0
|
0
|
|
|
0
|
if ($mask & unpack("N",$answer) || grep($IP eq $_,keys %{$DNSBL->{"$blist[0]"}->{accept}})) { |
|
0
|
|
|
|
|
0
|
|
1163
|
0
|
|
|
|
|
0
|
$answer = A1272; |
1164
|
0
|
|
|
|
|
0
|
$attl = $ttl; # preserve TTL of this responder |
1165
|
0
|
|
|
|
|
0
|
last ANSWER; |
1166
|
|
|
|
|
|
|
} |
1167
|
0
|
|
|
|
|
0
|
undef $answer; |
1168
|
|
|
|
|
|
|
} # end of rdata |
1169
|
|
|
|
|
|
|
} |
1170
|
|
|
|
|
|
|
elsif ($t == T_PTR && $blist[0] eq 'genericPTR') { # duplicates in-addr.arpa lookup, inefficient, but does not happen often |
1171
|
|
|
|
|
|
|
#print Tmp "add $rdata[0]\n"; |
1172
|
0
|
|
|
|
|
0
|
push @generic, $rdata[0]; |
1173
|
|
|
|
|
|
|
} |
1174
|
|
|
|
|
|
|
} # end of each ANSWER |
1175
|
0
|
|
|
|
|
0
|
$ttl = $attl; # restore responder TTL |
1176
|
|
|
|
|
|
|
} |
1177
|
|
|
|
|
|
|
elsif ($t == T_PTR && ($rcode == NXDOMAIN || $rcode == SERVFAIL)) { # no reverse lookup |
1178
|
|
|
|
|
|
|
#print Tmp "PTR w/ NXDOMAIN or SERVFAIL\n"; |
1179
|
0
|
|
|
|
|
0
|
$answer = A1274; |
1180
|
0
|
|
|
|
|
0
|
$ttl = 3600; |
1181
|
0
|
|
|
|
|
0
|
$nscount = $arcount = 0; |
1182
|
|
|
|
|
|
|
} |
1183
|
|
|
|
|
|
|
|
1184
|
0
|
0
|
|
|
|
0
|
if (@generic) { |
1185
|
0
|
|
|
|
|
0
|
my @names; |
1186
|
0
|
|
|
|
|
0
|
foreach my $g (@generic) { |
1187
|
0
|
0
|
0
|
|
|
0
|
last if $iptr && grep($g =~ /$_/i, @$iptr); |
1188
|
0
|
0
|
0
|
|
|
0
|
push @names, $g if $g && ! grep($g =~ /$_/i, @$regexptr); |
1189
|
|
|
|
|
|
|
} |
1190
|
0
|
0
|
|
|
|
0
|
$answer = A1277 unless @names; |
1191
|
0
|
|
|
|
|
0
|
$ttl = 3600; |
1192
|
|
|
|
|
|
|
} |
1193
|
0
|
0
|
|
|
|
0
|
if ($answer) { # if valid answer |
|
|
0
|
|
|
|
|
|
1194
|
0
|
|
|
|
|
0
|
my $txt = ''; |
1195
|
0
|
0
|
0
|
|
|
0
|
if ( $csize && # caching enabled && answer is from a real DSNBL |
|
|
|
0
|
|
|
|
|
1196
|
|
|
|
|
|
|
($answer == A1272 || $answer == A1274 || $answer == A1277) ) { |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
# ip address => { |
1199
|
|
|
|
|
|
|
# expires => time, now + TTL from response or 3600 minimum |
1200
|
|
|
|
|
|
|
# used => time, time cache item was last used |
1201
|
|
|
|
|
|
|
# who => $blist[0], which DNSBL caused caching |
1202
|
|
|
|
|
|
|
# txt => 'string', txt from our config file or empty |
1203
|
|
|
|
|
|
|
# }, |
1204
|
0
|
0
|
|
|
|
0
|
$txt = $DNSBL->{$blist[0]}->{error} if exists $DNSBL->{$blist[0]}; |
1205
|
0
|
0
|
|
|
|
0
|
my $trailer = $notRHBL ? revIP($rip) : ''; |
1206
|
0
|
0
|
|
|
|
0
|
$txt = $txt ? $txt . $trailer : ''; |
1207
|
0
|
|
|
|
|
0
|
$cache{$rip} = { |
1208
|
|
|
|
|
|
|
expires => $now + $ttl, # use responding DNSBL remaining ttl |
1209
|
|
|
|
|
|
|
used => $now, |
1210
|
|
|
|
|
|
|
who => $blist[0], |
1211
|
|
|
|
|
|
|
txt => $txt |
1212
|
|
|
|
|
|
|
}; |
1213
|
|
|
|
|
|
|
} |
1214
|
0
|
|
|
|
|
0
|
bump_stats($STATs,$blist[0]); |
1215
|
|
|
|
|
|
|
# $STATs->{"$blist[0]"} += 1; # bump statistics count |
1216
|
|
|
|
|
|
|
# if (exists $CNTs{"$blist[0]"}) { |
1217
|
|
|
|
|
|
|
# $CNTs{"$blist[0]"} += 1; |
1218
|
|
|
|
|
|
|
# } else { |
1219
|
|
|
|
|
|
|
# $CNTs{"$blist[0]"} = 1; |
1220
|
|
|
|
|
|
|
# $AVGs{"$blist[0]"} = 1; |
1221
|
|
|
|
|
|
|
# } |
1222
|
|
|
|
|
|
|
# $newstat = 1 unless $newstat; # notify refresh that update may be needed |
1223
|
|
|
|
|
|
|
|
1224
|
0
|
0
|
|
|
|
0
|
my($nmsg,$noff,@dnptrs) = ($FATans) # make proto answer |
1225
|
|
|
|
|
|
|
? _ansrbak($put,$id,$nscount + $arcount +1,$rip,$zone,$type,$ttl,$answer,$BLzone,$myip,$txt) |
1226
|
|
|
|
|
|
|
: _ansrbak($put,$id,1,$rip,$zone,$type,$ttl,$answer,$BLzone,$myip,$txt); |
1227
|
|
|
|
|
|
|
## add the ns section from original reply into the authority section so we can see where it came from, it won't hurt anything |
1228
|
0
|
0
|
|
|
|
0
|
if ($FATans) { |
1229
|
0
|
|
|
|
|
0
|
foreach(0..$nscount -1) { |
1230
|
0
|
|
|
|
|
0
|
($off,$Oname,$Otype,$Oclass,$Ottl,$Ordlength,$Odata) |
1231
|
|
|
|
|
|
|
= $get->next(\$msg,$off); |
1232
|
0
|
|
|
|
|
0
|
($noff,@dnptrs) = $put->NS(\$nmsg,$noff,\@dnptrs, |
1233
|
|
|
|
|
|
|
$Oname,$Otype,$Oclass,$Ottl,$Odata); |
1234
|
|
|
|
|
|
|
} |
1235
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
# add the authority section from original reply so we can see where it came from |
1237
|
0
|
|
|
|
|
0
|
foreach(0..$arcount -1) { |
1238
|
0
|
|
|
|
|
0
|
($off,$Oname,$Otype,$Oclass,$Ottl,$Ordlength,$Odata) |
1239
|
|
|
|
|
|
|
= $get->next(\$msg,$off); |
1240
|
0
|
0
|
|
|
|
0
|
if ($Otype == T_A) { |
|
|
0
|
|
|
|
|
|
1241
|
0
|
|
|
|
|
0
|
($noff,@dnptrs) = $put->A(\$nmsg,$noff,\@dnptrs, |
1242
|
|
|
|
|
|
|
$Oname,$Otype,$Oclass,$Ottl,$Odata); |
1243
|
|
|
|
|
|
|
} elsif ($Otype == T_AAAA) { |
1244
|
0
|
|
|
|
|
0
|
($noff,@dnptrs) = $put->AAAA(\$nmsg,$noff,\@dnptrs, |
1245
|
|
|
|
|
|
|
$Oname,$Otype,$Oclass,$Ottl,$Odata); |
1246
|
|
|
|
|
|
|
} else { |
1247
|
0
|
|
|
|
|
0
|
next; # skip unknown authority types |
1248
|
|
|
|
|
|
|
} |
1249
|
|
|
|
|
|
|
} |
1250
|
|
|
|
|
|
|
} # end FATans |
1251
|
|
|
|
|
|
|
# if ANSWER |
1252
|
0
|
0
|
0
|
|
|
0
|
if ($eXT && exists $eXT->{ANSWER} && $eXT->{ANSWER}->($eXT,$get,$put,$rid,$ttl,\$nmsg,\%remoteThreads)) { |
|
|
|
0
|
|
|
|
|
1253
|
|
|
|
|
|
|
; # will update $nmsg |
1254
|
|
|
|
|
|
|
} |
1255
|
0
|
|
|
|
|
0
|
delete $remoteThreads{$rid}; |
1256
|
0
|
|
|
|
|
0
|
$msg = $nmsg; |
1257
|
0
|
0
|
|
|
|
0
|
$ROK = 0 if $DEBUG & $D_ANSTOP; |
1258
|
|
|
|
|
|
|
} |
1259
|
|
|
|
|
|
|
# no answer |
1260
|
|
|
|
|
|
|
elsif (do { |
1261
|
0
|
0
|
|
|
|
0
|
print STDERR '+' if $DEBUG & $D_VERBOSE; |
1262
|
|
|
|
|
|
|
#print Tmp "While eliminate $rid $blist[0]\n"; |
1263
|
0
|
|
|
|
|
0
|
my $rv = 0; |
1264
|
0
|
|
|
|
|
0
|
while(!$rv) { |
1265
|
0
|
|
|
|
|
0
|
shift @blist; |
1266
|
0
|
0
|
|
|
|
0
|
unless (@blist) { |
1267
|
0
|
|
|
|
|
0
|
$rv = 1; |
1268
|
|
|
|
|
|
|
} else { |
1269
|
0
|
0
|
|
|
|
0
|
last unless $deadDNSBL{"$blist[0]"} > $numberoftries; # ignore hosts that don't answer |
1270
|
|
|
|
|
|
|
} |
1271
|
|
|
|
|
|
|
} |
1272
|
0
|
|
|
|
|
0
|
$rv; |
1273
|
|
|
|
|
|
|
}) { # if no more hosts |
1274
|
|
|
|
|
|
|
# if NOTFOUND |
1275
|
0
|
0
|
0
|
|
|
0
|
not_found($put,$rip .'.'. $zone,$type,$id,\$msg,$SOAptr) # send not found response |
|
|
|
0
|
|
|
|
|
1276
|
|
|
|
|
|
|
unless $eXT && exists $eXT->{NOTFOUND} && $eXT->{NOTFOUND}->($eXT,$get,$put,$rid,$rip,\$type,\$zone,\$msg,\%remoteThreads); |
1277
|
0
|
|
|
|
|
0
|
delete $remoteThreads{$rid}; |
1278
|
|
|
|
|
|
|
# endif |
1279
|
0
|
|
|
|
|
0
|
$STATs->{Passed} += 1; |
1280
|
0
|
0
|
|
|
|
0
|
$newstat = 1 unless $newstat; # notify refresh that update may be needed |
1281
|
|
|
|
|
|
|
} else { |
1282
|
0
|
|
|
|
|
0
|
$deadDNSBL{"$blist[0]"} = 1; # reset retry count |
1283
|
|
|
|
|
|
|
#print Tmp "NOTFOUND bl_lookup, R \n"; |
1284
|
0
|
|
|
|
|
0
|
$rid = setURBLdom($rip,$rid,$notRHBL,$ubl,$DNSBL->{$blist[0]},\%remoteThreads,1); # initialize urbl domain lookup name |
1285
|
0
|
|
|
|
|
0
|
bl_lookup($put,\$msg,\%remoteThreads,$l_Sin,_alarm($blist[0]),$rid,$id,$rip,$type,$zone,@blist); |
1286
|
0
|
0
|
|
|
|
0
|
print STDERR $blist[0] if $DEBUG & $D_VERBOSE; |
1287
|
0
|
|
|
|
|
0
|
send($R,$msg,0,$R_Sin); # udp may not block |
1288
|
0
|
|
|
|
|
0
|
last; |
1289
|
|
|
|
|
|
|
} |
1290
|
0
|
|
|
|
|
0
|
send($L,$msg,0,$l_Sin); |
1291
|
|
|
|
|
|
|
|
1292
|
0
|
0
|
|
|
|
0
|
if ($DEBUG & $D_VERBOSE) { |
1293
|
0
|
0
|
|
|
|
0
|
if ($answer) { |
1294
|
0
|
|
|
|
|
0
|
print STDERR ' ',inet_ntoa($answer),"\n"; |
1295
|
|
|
|
|
|
|
} else { |
1296
|
0
|
|
|
|
|
0
|
print STDERR " no bl\n"; |
1297
|
|
|
|
|
|
|
} |
1298
|
|
|
|
|
|
|
} |
1299
|
0
|
|
|
|
|
0
|
last; |
1300
|
|
|
|
|
|
|
} |
1301
|
|
|
|
|
|
|
} |
1302
|
|
|
|
|
|
|
##################### TIMEOUT, do busywork ####################### |
1303
|
|
|
|
|
|
|
else { # must be timeout |
1304
|
10
|
|
|
|
|
42
|
my $prpshadow = $prp; |
1305
|
10
|
|
|
|
|
30
|
$now = time; # check various alarm status |
1306
|
10
|
50
|
|
|
|
63
|
unless ($now < $next) { |
1307
|
0
|
|
|
|
|
0
|
average($STATs); |
1308
|
0
|
0
|
|
|
|
0
|
purge_cache() if $prp < 0; # initiate cache purge every 5 minutes or so |
1309
|
|
|
|
|
|
|
} |
1310
|
10
|
50
|
|
|
|
165
|
purge_cache() unless $prpshadow < 0; # run cache purge thread unless just initiated |
1311
|
10
|
|
|
|
|
117
|
foreach $rid (keys %remoteThreads) { |
1312
|
10
|
100
|
|
|
|
161
|
next unless $remoteThreads{$rid}->{expire} < $now; # expired?? |
1313
|
|
|
|
|
|
|
|
1314
|
5
|
|
|
|
|
17
|
($l_Sin,$rip,$id,$type,$zone,@blist) = @{$remoteThreads{$rid}->{args}}; |
|
5
|
|
|
|
|
206
|
|
1315
|
|
|
|
|
|
|
|
1316
|
5
|
50
|
|
|
|
43
|
if (++$deadDNSBL{"$blist[0]"} > $numberoftries) { |
1317
|
0
|
|
|
|
|
0
|
$deadDNSBL{"$blist[0]"} = 3600; # wait an hour to retry |
1318
|
0
|
0
|
|
|
|
0
|
if ($LogLevel) { |
1319
|
0
|
|
|
|
|
0
|
syslog($LogLevel, "timeout connecting to $blist[0]\n"); |
1320
|
|
|
|
|
|
|
} |
1321
|
|
|
|
|
|
|
} |
1322
|
|
|
|
|
|
|
|
1323
|
5
|
100
|
|
|
|
29
|
if ($blist[0] eq 'in-addr.arpa') { # expired reverse DNS lookup ? |
|
|
100
|
|
|
|
|
|
1324
|
1
|
|
|
|
|
9
|
delete $remoteThreads{$rid}; |
1325
|
1
|
|
|
|
|
5
|
$deadDNSBL{"$blist[0]"} = 0; # reset timeout (this one never expires) |
1326
|
1
|
50
|
|
|
|
30
|
my $txt = exists $DNSBL->{$blist[0]} |
1327
|
|
|
|
|
|
|
? $DNSBL->{$blist[0]}->{error} |
1328
|
|
|
|
|
|
|
: ''; |
1329
|
1
|
|
|
|
|
24
|
$cache{$rip} = { |
1330
|
|
|
|
|
|
|
expires => $now + 3600, # always an hour |
1331
|
|
|
|
|
|
|
used => $now, |
1332
|
|
|
|
|
|
|
who => $blist[0], |
1333
|
|
|
|
|
|
|
txt => $txt |
1334
|
|
|
|
|
|
|
}; |
1335
|
1
|
|
|
|
|
7
|
bump_stats($STATs,$blist[0]); |
1336
|
|
|
|
|
|
|
# $STATs->{"$blist[0]"} += 1; # bump statistics count |
1337
|
|
|
|
|
|
|
# if (exists $CNTs{"$blist[0]"}) { |
1338
|
|
|
|
|
|
|
# $CNTs{"$blist[0]"} += 1; |
1339
|
|
|
|
|
|
|
# } else { |
1340
|
|
|
|
|
|
|
# $CNTs{"$blist[0]"} = 1; |
1341
|
|
|
|
|
|
|
# $AVGs{"$blist[0]"} = 1; |
1342
|
|
|
|
|
|
|
# } |
1343
|
|
|
|
|
|
|
# $newstat = 1 unless $newstat; # notify refresh that update may be needed |
1344
|
1
|
|
|
|
|
18
|
($msg) = _ansrbak($put,$id,1,$rip,$zone,$type,3600,A1274,$BLzone,$myip,$txt); |
1345
|
1
|
|
|
|
|
63
|
send($L,$msg,0,$l_Sin); |
1346
|
1
|
50
|
|
|
|
8
|
print STDERR " expired Rdns\n" if $DEBUG & $D_VERBOSE; |
1347
|
|
|
|
|
|
|
} |
1348
|
|
|
|
|
|
|
elsif (do { |
1349
|
4
|
50
|
|
|
|
21
|
print STDERR '?' if $DEBUG & $D_VERBOSE; |
1350
|
4
|
|
|
|
|
10
|
my $rv = 0; |
1351
|
4
|
|
|
|
|
19
|
while(!$rv) { |
1352
|
4
|
|
|
|
|
9
|
shift @blist; |
1353
|
4
|
100
|
|
|
|
51
|
unless (@blist) { |
1354
|
1
|
|
|
|
|
83
|
$rv = 1; |
1355
|
|
|
|
|
|
|
} else { |
1356
|
3
|
50
|
|
|
|
19
|
last unless $deadDNSBL{"$blist[0]"} > $numberoftries; # ignore hosts that don't answer |
1357
|
|
|
|
|
|
|
} |
1358
|
|
|
|
|
|
|
} |
1359
|
4
|
|
|
|
|
19
|
$rv; |
1360
|
|
|
|
|
|
|
}) { # if no more hosts |
1361
|
|
|
|
|
|
|
# if NOTFOUND |
1362
|
1
|
0
|
33
|
|
|
33
|
not_found($put,$rip .'.'. $BLzone,$type,$id,\$msg,$SOAptr) # send not found response |
|
|
|
33
|
|
|
|
|
1363
|
|
|
|
|
|
|
unless $eXT && exists $eXT->{NOTFOUND} && $eXT->{NOTFOUND}->($eXT,$get,$put,$rid,$rip,\$type,\$BLzone,\$msg,\%remoteThreads); |
1364
|
1
|
|
|
|
|
4399
|
delete $remoteThreads{$rid}; |
1365
|
|
|
|
|
|
|
# endif |
1366
|
1
|
|
|
|
|
6
|
$STATs->{Passed} += 1; # count messages that pass thru this filter |
1367
|
1
|
50
|
|
|
|
7
|
$newstat = 1 unless $newstat; # notify refresh that update may be needed |
1368
|
1
|
|
|
|
|
71
|
send($L,$msg,0,$l_Sin); |
1369
|
1
|
50
|
|
|
|
12
|
print STDERR " no bl\n" if $DEBUG & $D_VERBOSE; |
1370
|
|
|
|
|
|
|
} else { |
1371
|
|
|
|
|
|
|
#print Tmp "second NOTFOUND\n"; |
1372
|
3
|
|
|
|
|
28
|
bl_lookup($put,\$msg,\%remoteThreads,$l_Sin,_alarm($blist[0]),$rid,$id,$rip,$type,$zone,@blist); |
1373
|
3
|
|
|
|
|
289
|
send($R,$msg,0,$R_Sin); # udp may not block |
1374
|
3
|
50
|
|
|
|
24
|
print STDERR $blist[0] if $DEBUG & $D_VERBOSE; |
1375
|
|
|
|
|
|
|
} |
1376
|
|
|
|
|
|
|
} |
1377
|
10
|
|
|
|
|
66
|
foreach(keys %deadDNSBL) { # eventually retry dead DNSBL |
1378
|
26
|
50
|
|
|
|
100
|
--$deadDNSBL{"$_"} if $deadDNSBL{"$_"} > $numberoftries; |
1379
|
|
|
|
|
|
|
} |
1380
|
10
|
100
|
66
|
|
|
123
|
if ($newstat > 1 || |
|
|
|
33
|
|
|
|
|
1381
|
|
|
|
|
|
|
($refresh < $now && $newstat)) { # update stats file |
1382
|
1
|
|
|
|
|
14
|
write_stats($Sfile,$STATs,$StatStamp,$csize,$cused); |
1383
|
1
|
|
|
|
|
4
|
$refresh = $now + $$Run; |
1384
|
1
|
|
|
|
|
4
|
$newstat = 0; |
1385
|
|
|
|
|
|
|
} |
1386
|
10
|
50
|
|
|
|
205
|
return 'caught timer' if $DEBUG & $D_TIMONLY; |
1387
|
|
|
|
|
|
|
} |
1388
|
|
|
|
|
|
|
} while($$Run && $ROK); |
1389
|
24
|
50
|
|
|
|
1372
|
write_stats($Sfile,$STATs,$StatStamp,$csize,$cused) if $newstat; # always update on exit if needed |
1390
|
|
|
|
|
|
|
} |
1391
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
# answer back prototype |
1393
|
|
|
|
|
|
|
# |
1394
|
|
|
|
|
|
|
# input: $put,$id,$arcount,$rip,$zone,$type,$ttl,$answer,$BLzone,$myip,$withtxt,$CD |
1395
|
|
|
|
|
|
|
# returns: $message,$off,@dnptrs |
1396
|
|
|
|
|
|
|
# |
1397
|
|
|
|
|
|
|
sub _ansrbak { |
1398
|
2
|
|
|
2
|
|
19
|
my($put,$id,$arc,$rip,$zone,$type,$ttl,$ans,$BLzone,$myip,$withtxt,$CD) = @_; |
1399
|
2
|
50
|
33
|
|
|
31
|
my $haveA = ($type == T_A || $type == T_ANY) ? 1 : 0; |
1400
|
2
|
50
|
33
|
|
|
33
|
my $haveT = (($type == T_ANY || $type == T_TXT) && $withtxt) ? 1 : 0; |
1401
|
2
|
50
|
|
|
|
151
|
$CD = $CD ? 0 : CD; |
1402
|
2
|
|
|
|
|
40
|
my $nmsg; |
1403
|
2
|
|
|
|
|
5
|
my $nans = $haveA + $haveT; |
1404
|
2
|
|
|
|
|
8
|
my $noff = newhead(\$nmsg, |
1405
|
|
|
|
|
|
|
$id, |
1406
|
|
|
|
|
|
|
BITS_QUERY | QR, |
1407
|
|
|
|
|
|
|
1,$nans,1,$arc, |
1408
|
|
|
|
|
|
|
); |
1409
|
2
|
|
|
|
|
138
|
($noff,my @dnptrs) = $put->Question(\$nmsg,$noff, # 1 question |
1410
|
|
|
|
|
|
|
$rip .'.'. $zone,$type,C_IN); # type is T_A or T_ANY or T_TXT |
1411
|
2
|
50
|
|
|
|
68
|
if ($haveA) { |
1412
|
2
|
|
|
|
|
10
|
($noff,@dnptrs) = $put->A(\$nmsg,$noff,\@dnptrs, # add 1 answer |
1413
|
|
|
|
|
|
|
$rip .'.'. $zone,T_A,C_IN,$ttl,$ans); |
1414
|
|
|
|
|
|
|
} |
1415
|
2
|
50
|
|
|
|
7407
|
if ($haveT) { |
1416
|
0
|
|
|
|
|
0
|
($noff,@dnptrs) = $put->TXT(\$nmsg,$noff,\@dnptrs, |
1417
|
|
|
|
|
|
|
$rip .'.'. $zone,T_TXT,C_IN,$ttl,$withtxt); |
1418
|
|
|
|
|
|
|
} |
1419
|
2
|
|
|
|
|
15
|
($noff,@dnptrs) = $put->NS(\$nmsg,$noff,\@dnptrs, # 1 authority |
1420
|
|
|
|
|
|
|
$zone,T_NS,C_IN,86400,$BLzone); |
1421
|
2
|
|
|
|
|
3304
|
($noff,@dnptrs) = $put->A(\$nmsg,$noff,\@dnptrs, # 1 additional glue |
1422
|
|
|
|
|
|
|
$BLzone,T_A,C_IN,86400,$myip); # show MYIP |
1423
|
2
|
|
|
|
|
144
|
return($nmsg,$noff,@dnptrs) |
1424
|
|
|
|
|
|
|
} |
1425
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
=item * bl_lookup($put,$mp,$rtp,$sinaddr,$alarm,$rid,$id,$rip,$type,$zone,@blist); |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
Generates a query message for the first DNSBL in the @blist array. Creates |
1429
|
|
|
|
|
|
|
a thread entry for the response and subsequent queries should the first one fail. |
1430
|
|
|
|
|
|
|
|
1431
|
|
|
|
|
|
|
input: put, |
1432
|
|
|
|
|
|
|
message pointer, |
1433
|
|
|
|
|
|
|
remote thread pointer, |
1434
|
|
|
|
|
|
|
sockinaddr, |
1435
|
|
|
|
|
|
|
connection timeout, |
1436
|
|
|
|
|
|
|
remote id or undef to create |
1437
|
|
|
|
|
|
|
id of question, |
1438
|
|
|
|
|
|
|
reverse IP address in text |
1439
|
|
|
|
|
|
|
type of query received, (used in response) |
1440
|
|
|
|
|
|
|
ORIGINAL zone (case preserved), |
1441
|
|
|
|
|
|
|
array of remaining DNSBL's in sorted order |
1442
|
|
|
|
|
|
|
returns: nothing, puts stuff in thread queue |
1443
|
|
|
|
|
|
|
|
1444
|
|
|
|
|
|
|
extra: if URBL processing is required, |
1445
|
|
|
|
|
|
|
$remoteThreads{$rid}->{urbl} |
1446
|
|
|
|
|
|
|
is set to the domain to look up |
1447
|
|
|
|
|
|
|
|
1448
|
|
|
|
|
|
|
=cut |
1449
|
|
|
|
|
|
|
|
1450
|
|
|
|
|
|
|
# This function returns an integer between 1 -> 65535 in a pseudo-random |
1451
|
|
|
|
|
|
|
# repeatable order. Seeds with $$ by default, can be seeded with any integer; |
1452
|
|
|
|
|
|
|
# |
1453
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
my $id = $$; |
1455
|
|
|
|
|
|
|
|
1456
|
|
|
|
|
|
|
sub uniqueID { |
1457
|
54
|
100
|
|
54
|
0
|
84806475
|
$id = $_[0] ? ($_[0] % 65536) : $id; |
1458
|
54
|
50
|
33
|
|
|
772
|
$id = 1 if $id < 1 || $id > 65534; |
1459
|
54
|
|
|
|
|
198
|
$id++; |
1460
|
|
|
|
|
|
|
} |
1461
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
sub bl_lookup { |
1463
|
27
|
|
|
27
|
1
|
501485
|
my($put,$mp,$rtp,$sinaddr,$alarm,$rid,$id,$rip,$type,$zone,@blist) = @_; |
1464
|
27
|
100
|
|
|
|
187
|
$rid = uniqueID unless $rid; |
1465
|
27
|
|
|
|
|
276
|
my $off = newhead($mp, |
1466
|
|
|
|
|
|
|
$rid, |
1467
|
|
|
|
|
|
|
BITS_QUERY | RD, |
1468
|
|
|
|
|
|
|
1,0,0,0, |
1469
|
|
|
|
|
|
|
); |
1470
|
27
|
50
|
|
|
|
3247
|
my $blist = ($blist[0] eq 'genericPTR') |
1471
|
|
|
|
|
|
|
? 'in-addr.arpa' |
1472
|
|
|
|
|
|
|
: $blist[0]; |
1473
|
|
|
|
|
|
|
|
1474
|
27
|
100
|
|
|
|
134
|
my $Qtype = ($blist eq 'in-addr.arpa') |
1475
|
|
|
|
|
|
|
? &T_PTR |
1476
|
|
|
|
|
|
|
: &T_A; |
1477
|
|
|
|
|
|
|
|
1478
|
|
|
|
|
|
|
# send conditioned URBL request if that is what is needed |
1479
|
27
|
50
|
|
|
|
532
|
if ($rtp->{$rid}->{urbl}) { |
1480
|
0
|
|
|
|
|
0
|
$put->Question($mp,$off,$rtp->{$rid}->{urbl}.'.'. $blist,$Qtype,C_IN); |
1481
|
|
|
|
|
|
|
} else { |
1482
|
27
|
|
|
|
|
140
|
$put->Question($mp,$off,$rip .'.'. $blist,$Qtype,C_IN); |
1483
|
|
|
|
|
|
|
} |
1484
|
27
|
50
|
|
|
|
2670
|
$rtp->{$rid} = {} unless exists $rtp->{$rid}; |
1485
|
27
|
|
|
|
|
364
|
$rtp->{$rid}->{args} = [$sinaddr,$rip,$id,$type,$zone,@blist]; |
1486
|
27
|
|
|
|
|
172
|
$rtp->{$rid}->{expire} = time + $alarm; |
1487
|
|
|
|
|
|
|
#print Tmp "$blist => ",Dumper($rtp); |
1488
|
|
|
|
|
|
|
} |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
=item * set_extension($pointer); |
1491
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
This function sets a pointer to user defined extensions to |
1493
|
|
|
|
|
|
|
Net::DNSBL::MultiDaemon. |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
Pointer is of the form: |
1496
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
$Extension ->{ |
1498
|
|
|
|
|
|
|
OPCODE => value, |
1499
|
|
|
|
|
|
|
CLASS => subref->($Extension,internal args), |
1500
|
|
|
|
|
|
|
NAME => subref->($Extension,internal args), |
1501
|
|
|
|
|
|
|
TYPE => subref->($Extension,internal args), |
1502
|
|
|
|
|
|
|
LOOKUP => subref->($Extension,internal args), |
1503
|
|
|
|
|
|
|
ANSWER => subref->($Extension,internal args), |
1504
|
|
|
|
|
|
|
NOTFOUND => subref->($Extension,internal args) |
1505
|
|
|
|
|
|
|
}; |
1506
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
The pointer should be blessed into the package of the caller if the calling |
1508
|
|
|
|
|
|
|
package needs to store persistant variables for its own instance. The subref |
1509
|
|
|
|
|
|
|
will be called with the first argument of $Extension. |
1510
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
Care should be taken to NOT instantiate a %remoteThreads in the CLASS, NAME, |
1512
|
|
|
|
|
|
|
TYPE section unless it is know that it will be found and expired/deleted. |
1513
|
|
|
|
|
|
|
|
1514
|
|
|
|
|
|
|
Read the code if you wish to add an extension |
1515
|
|
|
|
|
|
|
|
1516
|
|
|
|
|
|
|
=back |
1517
|
|
|
|
|
|
|
|
1518
|
|
|
|
|
|
|
=cut |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
sub set_extension { |
1521
|
0
|
|
|
0
|
1
|
|
$eXT = shift; |
1522
|
|
|
|
|
|
|
} |
1523
|
|
|
|
|
|
|
|
1524
|
|
|
|
|
|
|
=head1 DEPENDENCIES |
1525
|
|
|
|
|
|
|
|
1526
|
|
|
|
|
|
|
Unix::Syslog |
1527
|
|
|
|
|
|
|
Geo::IP::PurePerl [conditional for country codes] |
1528
|
|
|
|
|
|
|
NetAddr::IP |
1529
|
|
|
|
|
|
|
Net::DNS::Codes |
1530
|
|
|
|
|
|
|
Net::DNS::ToolKit |
1531
|
|
|
|
|
|
|
|
1532
|
|
|
|
|
|
|
=head1 EXPORT_OK |
1533
|
|
|
|
|
|
|
|
1534
|
|
|
|
|
|
|
run |
1535
|
|
|
|
|
|
|
bl_lookup |
1536
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
=head1 EXPORT_TAGS :debug |
1538
|
|
|
|
|
|
|
|
1539
|
|
|
|
|
|
|
DEBUG is a set of semaphores for the 'run' function |
1540
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
$D_CLRRUN = 0x1; # clear run flag and force unconditional return |
1542
|
|
|
|
|
|
|
$D_SHRTHD = 0x2; # return short header message |
1543
|
|
|
|
|
|
|
$D_TIMONLY = 0x4; # exit at end of timer section |
1544
|
|
|
|
|
|
|
$D_QRESP = 0x8; # return query response message |
1545
|
|
|
|
|
|
|
$D_NOTME = 0x10; # return received response not for me |
1546
|
|
|
|
|
|
|
$D_ANSTOP = 0x20; # clear run OK flag if ANSWER present |
1547
|
|
|
|
|
|
|
$D_VERBOSE = 0x40; # verbose debug statements to STDERR |
1548
|
|
|
|
|
|
|
|
1549
|
|
|
|
|
|
|
=head1 AUTHOR |
1550
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
Michael Robinton, michael@bizsystems.com |
1552
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
=head1 COPYRIGHT |
1554
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
Copyright 2003 - 2014, Michael Robinton & BizSystems |
1556
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
1557
|
|
|
|
|
|
|
it under the terms as Perl itself or the GNU General Public License |
1558
|
|
|
|
|
|
|
as published by the Free Software Foundation; either version 2 of |
1559
|
|
|
|
|
|
|
the License, or (at your option) any later version. |
1560
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
1562
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
1563
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1564
|
|
|
|
|
|
|
GNU General Public License for more details. |
1565
|
|
|
|
|
|
|
|
1566
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License |
1567
|
|
|
|
|
|
|
along with this program; if not, write to the Free Software |
1568
|
|
|
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
1569
|
|
|
|
|
|
|
|
1570
|
|
|
|
|
|
|
=head1 SEE ALSO |
1571
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
L, L, L, L, L, L |
1573
|
|
|
|
|
|
|
|
1574
|
|
|
|
|
|
|
=cut |
1575
|
|
|
|
|
|
|
|
1576
|
|
|
|
|
|
|
1; |