| 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; |