3
# supporting tests for: Bug 6362 - Change urirhssub mask syntax
8
use lib '.'; use lib 't';
10
use SATest; sa_t_init("dnsbl_subtests");
13
use vars qw(%patterns %anti_patterns);
14
use constant num_tests => 46;
15
use constant DO_RUN => 1;
18
plan tests => (DO_RUN ? num_tests : 0);
24
if (-e 'test_dir') { # running from test directory, not ..
28
use Errno qw(EADDRINUSE EACCES);
29
use Net::DNS::Nameserver;
30
use Mail::SpamAssassin;
32
# Bug 5761 (no 127.0.0.1 in jail, use SPAMD_LOCALHOST if specified)
33
my $dns_server_localaddr = $ENV{'SPAMD_LOCALHOST'};
34
if (!$dns_server_localaddr) {
35
$dns_server_localaddr = $have_inet4 ? '127.0.0.1' : '::1';
40
($have_inet4 && $dns_server_localaddr =~ /^\d+\.\d+\.\d+\.\d+\z/);
42
sub find_free_port($); # prototype
43
my($dns_server_localport, $sock_udp, $sock_tcp) =
44
find_free_port($dns_server_localaddr);
46
$dns_server_localport or die "Failed to obtain a free port number";
48
printf("Using %s [%s]:%s for a spawned test DNS server\n",
49
$use_inet4 ? 'inet' : 'inet6',
50
$dns_server_localaddr, $dns_server_localport);
52
# test zone names (lowercase!)
53
my $z = 'sa1-dbl-test.spamassassin.org';
54
my $z2 = 'sa2-dbl-test.spamassassin.org';
56
my $local_conf = <<"EOD";
60
# use_auto_whitelist 0
64
score TVD_SPACE_RATIO 0
69
dns_server [$dns_server_localaddr]:$dns_server_localport
72
urirhssub X_URIBL_Y_2A $z A 127.0.1.2
73
body X_URIBL_Y_2A eval:check_uridnsbl('X_URIBL_Y_2A')
74
tflags X_URIBL_Y_2A domains_only
76
urirhssub X_URIBL_Y_2B $z A 127.0.1.2-127.0.1.2
77
body X_URIBL_Y_2B eval:check_uridnsbl('X_URIBL_Y_2B')
78
tflags X_URIBL_Y_2B domains_only
80
urirhssub X_URIBL_Y_2C $z A 127.0.1.2/0xffffffff
81
body X_URIBL_Y_2C eval:check_uridnsbl('X_URIBL_Y_2C')
82
tflags X_URIBL_Y_2C domains_only
84
urirhssub X_URIBL_Y_2D $z A 127.0.1.2/255.255.255.255
85
body X_URIBL_Y_2D eval:check_uridnsbl('X_URIBL_Y_2D')
86
tflags X_URIBL_Y_2D domains_only
88
urirhssub X_URIBL_Y_2E $z A 127.0.1.2/127.0.1.2
89
body X_URIBL_Y_2E eval:check_uridnsbl('X_URIBL_Y_2E')
90
tflags X_URIBL_Y_2E domains_only
92
urirhssub X_URIBL_Y_2F $z A 0/128.255.254.253
93
body X_URIBL_Y_2F eval:check_uridnsbl('X_URIBL_Y_2F')
94
tflags X_URIBL_Y_2F domains_only
96
urirhssub X_URIBL_Y_2G $z A 2
97
body X_URIBL_Y_2G eval:check_uridnsbl('X_URIBL_Y_2G')
98
tflags X_URIBL_Y_2G domains_only
100
urirhssub X_URIBL_N_2G $z A 5
101
body X_URIBL_N_2G eval:check_uridnsbl('X_URIBL_N_2G')
102
tflags X_URIBL_N_2G domains_only
104
urirhssub X_URIBL_Y_ANY $z A 127.0.1.1-127.0.1.254
105
body X_URIBL_Y_ANY eval:check_uridnsbl('X_URIBL_Y_ANY')
106
tflags X_URIBL_Y_ANY domains_only
108
urirhssub X_URIBL_Y_3 $z A 127.0.1.3-127.0.1.19
109
body X_URIBL_Y_3 eval:check_uridnsbl('X_URIBL_Y_3')
110
tflags X_URIBL_Y_3 domains_only
112
urirhssub X_URIBL_N_3 $z A 127.0.1.4-127.0.1.18
113
body X_URIBL_N_3 eval:check_uridnsbl('X_URIBL_Y_3')
114
tflags X_URIBL_N_3 domains_only
116
urirhssub X_URIBL_Y_FFA $z A 255.255.255.0
117
body X_URIBL_Y_FFA eval:check_uridnsbl('X_URIBL_Y_FFA')
118
tflags X_URIBL_Y_FFA domains_only
120
urirhssub X_URIBL_Y_FFB $z A 255.0.255.0/0xFF00FFff
121
body X_URIBL_Y_FFB eval:check_uridnsbl('X_URIBL_Y_FFB')
122
tflags X_URIBL_Y_FFB domains_only
124
urirhssub X_URIBL_Y_FFC $z A 0xFFffFF00/0xFFffFFff
125
body X_URIBL_Y_FFC eval:check_uridnsbl('X_URIBL_Y_FFC')
126
tflags X_URIBL_Y_FFC domains_only
128
urirhssub X_URIBL_Y_FFD $z A 0x80000000
129
body X_URIBL_Y_FFD eval:check_uridnsbl('X_URIBL_Y_FFD')
130
tflags X_URIBL_Y_FFD domains_only
132
urirhssub X_URIBL_N_0A $z A 127.0.0.0
133
body X_URIBL_N_0A eval:check_uridnsbl('X_URIBL_N_0A')
134
tflags X_URIBL_N_0A domains_only
136
urirhssub X_URIBL_N_0B $z A 127.0.1.0
137
body X_URIBL_N_0B eval:check_uridnsbl('X_URIBL_N_0B')
138
tflags X_URIBL_N_0B domains_only
140
urirhssub X_URIBL_N_255A $z A 127.0.1.255
141
body X_URIBL_N_255A eval:check_uridnsbl('X_URIBL_N_255A')
142
tflags X_URIBL_N_255A domains_only
144
urirhssub X_URIBL_N_255B $z A 0.0.0.255/0.0.0.255
145
body X_URIBL_N_255B eval:check_uridnsbl('X_URIBL_N_255B')
146
tflags X_URIBL_N_255B domains_only
149
urirhssub X_URIBL_Y_2AZ2 $z2 A 127.0.1.2
150
body X_URIBL_Y_2AZ2 eval:check_uridnsbl('X_URIBL_Y_2AZ2')
152
urirhssub X_URIBL_Y_255A $z2 A 127.0.1.255
153
body X_URIBL_Y_255A eval:check_uridnsbl('X_URIBL_Y_255A')
155
urirhssub X_URIBL_Y_255B $z2 A 0.0.0.255/0.0.0.255
156
body X_URIBL_Y_255B eval:check_uridnsbl('X_URIBL_Y_255B')
159
my(@testzone) = map { chomp; s/[ \t]+//; $_ } split(/^/, <<"EOD");
160
$z 3600 IN SOA ns.$z hostmaster.$z (1 10800 1800 2419200 3600)
163
ns.$z 3600 IN A 127.0.0.1
164
ns.$z 3600 IN AAAA ::1
165
dbltest.com.$z 3600 IN A 127.0.1.2
166
dbltest.com.$z 3600 IN TXT "test answer on dbltest.com"
167
dbltest03.com.$z 3600 IN A 127.0.1.3
168
dbltest19.com.$z 3600 IN A 127.0.1.19
169
dbltest20.com.$z 3600 IN A 127.0.1.20
170
dbltest21.com.$z 3600 IN A 127.0.1.21
171
dbltest39.com.$z 3600 IN A 127.0.1.39
172
dbltest40.com.$z 3600 IN A 127.0.1.40
173
dbltest50.com.$z 3600 IN A 127.0.1.50
174
dbltest59.com.$z 3600 IN A 127.0.1.59
175
dbltest99.com.$z 3600 IN A 127.0.1.99
176
dbltestff.com.$z 3600 IN A 255.255.255.0
177
dbltestER.com.$z 3600 IN A 127.0.1.255
178
dbltestER.com.$z 3600 IN TXT "No IP queries allowed"
180
$z2 3600 IN SOA ns.$z2 master.$z2 (1 10800 1800 2419200 3600)
181
$z2 3600 IN NS ns.$z2
183
ns.$z2 3600 IN A 127.0.0.1
184
ns.$z2 3600 IN AAAA ::1
185
dbltest.com.$z2 3600 IN A 127.0.1.2
188
# ---------------------------------------------------------------------------
191
my($qname, $qclass, $qtype, $peerhost,$query,$conn) = @_;
192
my($rcode, @ans, @auth, @add);
193
my $qclass_uc = uc $qclass;
194
my $qtype_uc = uc $qtype;
195
# print "Received query from $peerhost to ". $conn->{"sockhost"}. "\n";
198
for my $rec_str (@testzone) {
199
next if $rec_str =~ /^#/ || $rec_str =~ /^\s*$/;
200
my($rrname,$rrttl,$rrclass,$rrtype,$rrdata) = split(' ',$rec_str,5);
201
if ($qclass_uc eq uc($rrclass) && lc($rrname) eq lc($qname)) {
203
if ($qtype_uc eq uc($rrtype) || $qtype_uc eq 'ANY') {
204
push(@ans, Net::DNS::RR->new(
205
join(' ', $qname, $rrttl, $qclass, $rrtype, $rrdata)));
209
# special DBL test case - numerical IP query handling
210
# Bug 6983: Uninitialized value in lc in t/dnsbl_subtests for X_URIBL_Y_255A
211
# Unicode case folding bug present in at least perl-5.8.[678], fixed 5.8.9
212
# avoid case-insensitive regexp match, $z and $z2 are already in lowercase
213
if ($qclass_uc eq 'IN' && lc $qname =~ /^[0-9.]+\.(?:\Q$z\E|\Q$z2\E)\z/s) {
215
if ($qtype_uc eq 'A' || $qtype_uc eq 'ANY') {
216
push(@ans, Net::DNS::RR->new(join(' ',
217
$qname, '3600', $qclass, 'A', '127.0.1.255')));
219
if ($qtype_uc eq 'TXT' || $qtype_uc eq 'ANY') {
220
push(@ans, Net::DNS::RR->new(join(' ',
221
$qname, '3600', $qclass, 'TXT', '"No IP queries allowed"')));
224
return ($rcode, \@ans, \@auth, \@add);
228
my($local_addr, $local_port) = @_;
229
my $ns = Net::DNS::Nameserver->new(
230
LocalAddr => $local_addr, LocalPort => $local_port,
231
ReplyHandler => \&reply_handler, Verbose => 0);
232
$ns or die "Cannot create a nameserver object";
236
sub find_free_port($) {
238
my($port, $sock_udp, $sock_tcp);
239
for (1..20) { # choose a pair of free tcp & udp ports
240
$port = 11001 + int(rand(65536-11001));
241
my %args = (LocalAddr => $addr, LocalPort => $port);
242
$sock_udp = $use_inet4 ? IO::Socket::INET->new(%args, Proto => 'udp')
243
: IO::Socket::INET6->new(%args, Proto => 'udp');
244
$sock_udp || $! == EADDRINUSE || $! == EACCES
245
or printf("Error creating UDP socket [%s]:%s: %s\n", $addr, $port, $!);
246
$sock_tcp = $use_inet4 ? IO::Socket::INET->new(%args, Proto => 'tcp')
247
: IO::Socket::INET6->new(%args, Proto => 'tcp');
248
$sock_tcp || $! == EADDRINUSE || $! == EACCES
249
or printf("Error creating %s TCP socket [%s]:%s: %s\n",
250
$use_inet4 ? 'inet' : 'inet6', $addr, $port, $!);
251
last if $sock_tcp && $sock_udp;
253
undef $port if !$sock_tcp || !$sock_udp;
254
return ($port, $sock_udp, $sock_tcp);
257
# ---------------------------------------------------------------------------
259
my $spamassassin_obj;
261
sub process_sample_urls(@) {
263
my($mail_obj, $per_msg_status, $spam_report);
264
$spamassassin_obj->timer_reset;
267
From: "DNSBL Testing" <ab@example.org>
268
To: someone@example.org
270
Date: Mon, 8 Mar 2010 15:10:44 +0100
271
Message-Id: <test.123.test@example.org>
274
$msg .= $_."\n" for @url_list;
276
$mail_obj = $spamassassin_obj->parse($msg,0);
278
local($1,$2,$3,$4,$5,$6); # avoid Perl 5.8.x bug, $1 can get tainted
279
$per_msg_status = $spamassassin_obj->check($mail_obj);
281
if ($per_msg_status) {
282
$spam_report = $per_msg_status->get_tag('REPORT');
283
$per_msg_status->finish;
288
$spam_report =~ s/\A(\s*\n)+//s;
289
# print "\t$spam_report\n";
293
sub test_samples($$) {
294
my($patt_antipatt_list,$url_list_ref) = @_;
295
my $el = $patt_antipatt_list->[0];
296
shift @$patt_antipatt_list if @$patt_antipatt_list > 1; # last autorepeats
297
my($patt,$anti) = split(m{\s* / \s*}x, $el, 2);
298
%patterns = map { (" $_ ", $_) } split(' ',$patt);
299
%anti_patterns = map { (" $_ ", $_) } split(' ',$anti);
300
my $spam_report = process_sample_urls(@$url_list_ref);
301
clear_pattern_counters();
302
patterns_run_cb($spam_report);
303
my $status = ok_all_patterns();
304
printf("\nTest on %s failed:\n%s\n",
305
join(', ',@$url_list_ref), $spam_report) if !$status;
309
# there is a time gap between closing sockets and reusing them by a spawned
310
# DNS server - if we are very unlucky and the port is acquired by some other
311
# process during this short interval, our spawned DNS server will fail to start
314
$sock_udp->close() or die "Error closing UDP socket: $!";
317
$sock_tcp->close() or die "Error closing TCP socket: $!";
320
# detach a DNS server process
322
defined $pid or die "Cannot fork: $!";
324
dns_server($dns_server_localaddr, $dns_server_localport);
329
# print STDERR "Forked a DNS server process [$pid]\n";
332
$spamassassin_obj = Mail::SpamAssassin->new({
333
# rules_filename => "$prefix/t/log/test_rules_copy",
334
# require_rules => 1,
335
rules_filename => "/dev/null",
336
site_rules_filename => "$prefix/t/log/localrules.tmp",
337
userprefs_filename => "$prefix/masses/spamassassin/user_prefs",
338
post_config_text => $local_conf,
339
dont_copy_prefs => 1,
340
# debug => 'dns,async,uridnsbl',
342
ok($spamassassin_obj);
343
$spamassassin_obj->compile_now; # try to preload most modules
346
[q{ X_URIBL_Y_2A X_URIBL_Y_2B X_URIBL_Y_2C X_URIBL_Y_2D X_URIBL_Y_2E
347
X_URIBL_Y_2F X_URIBL_Y_2G X_URIBL_Y_ANY / X_URIBL_N_2E X_URIBL_N_2G
348
X_URIBL_N_3 X_URIBL_N_0A X_URIBL_N_0B X_URIBL_N_255A X_URIBL_N_255B }],
349
[qw( http://dbltest.com/ )]);
352
[q{ X_URIBL_Y_2A X_URIBL_Y_2B X_URIBL_Y_2C X_URIBL_Y_2D X_URIBL_Y_2E
353
X_URIBL_Y_2F X_URIBL_Y_2G X_URIBL_Y_ANY X_URIBL_Y_3 / X_URIBL_N_3
354
X_URIBL_N_0A X_URIBL_N_0B X_URIBL_N_255A X_URIBL_N_255B }],
355
[qw( http://dbltest.com/ http://dbltest03.com/ http://dbltest19.com/ )]);
358
[q{ X_URIBL_Y_2A X_URIBL_Y_2B X_URIBL_Y_2C X_URIBL_Y_2D X_URIBL_Y_2E
359
X_URIBL_Y_2F X_URIBL_Y_2G X_URIBL_Y_FFA X_URIBL_Y_FFB X_URIBL_Y_FFC
360
X_URIBL_Y_255A X_URIBL_Y_255B / X_URIBL_N_0A X_URIBL_N_0B
361
X_URIBL_N_255A X_URIBL_N_255B }],
362
[qw( http://DBLtest.COM/ http://dbltestFF.CoM/ http://140.211.11.130/ )]);
363
# X_URIBL_Y_FFD no longer hits intentionally (not in the 127.0.0.0/8 range),
367
kill('TERM',$pid) or die "Cannot stop a DNS server [$pid]: $!";
373
$spamassassin_obj->finish if $spamassassin_obj;
374
kill('KILL',$pid) if $pid; # ignoring status