NAME
Net::DNSBL::MultiDaemon - multiple DNSBL emulator
SYNOPSIS
use Net::DNSBL::MultiDaemon qw(
:debug
run
s_response
bl_lookup
not_found
write_stats
statinit
cntinit
open_udpNB
DO
);
run($BLzone,$L,$R,$DNSBL,$STATs,$Run,$Sfile,$StatStamp,$DEBUG)
s_response($mp,$resp,$id,$qdcount,$ancount,$nscount,$arcount);
bl_lookup($put,$mp,$rtp,$sinaddr,$alarm,$id,$rip,$type,$zone,@blist);
not_found($put,$name,$type,$id,$mp,$srp);
write_stats($sfile,$cp,$sinit);
$timestamp = statinit($Sfile,$cp);
cntinit($DNSBL,$cp);
$sock = open_udpNB();
$rv = DO($file)
DESCRIPTION
Net::DNSBL::MultiDaemon is the Perl module that implements the multi_dnsbl daemon.
multi_dnsbl is a DNS emulator daemon that increases the efficacy of DNSBL look-ups in a mail system. multi_dnsbl may be used as a stand-alone DNSBL or as a plug-in for a standard BIND 9 installation. multi_dnsbl shares a common configuration file format with the Mail::SpamCannibal sc_BLcheck.pl script so that DNSBL's can be maintained in a common configuration file for an entire mail installation.
Because DNSBL usefulness is dependent on the nature and source of spam sent to a specific site and because sometimes DNSBL's may provide intermittant service, multi_dnsbl interrogates them sorted in the order of greatest successful hits. DNSBL's that do not respond within the configured timeout period are not interrogated at all after 6 consecutive failures, and thereafter will be retried not more often than once every hour until they come back online. This eliminates the need to place DNSBL's in a particular order in your MTA's config file or periodically monitor the DNSBL statistics and/or update the MTA config file.
OPERATION
The configuration file for multi_dnsbl contains a list of DNSBL's to try when looking up an IP address for blacklisting. Internally, multi_dnsbl maintains this list in sorted order based on the number of responses that resulted in an acceptable A record being returned from the DNSBL query. For each IP address query sent to multi_dnsbl, a query is sent to each configured DNSBL sequentially until all DNSBL's have been queried or an acceptable A record is returned.
Let us say for example that blackholes.easynet.nl (below) will return an A record and list.dsbl.org, bl.spamcop.net, dynablock.easynet.nl, will not.
LIST
9451 list.dsbl.org
6516 bl.spamcop.net
2350 dynablock.easynet.nl
575 blackholes.easynet.nl
327 cbl.abuseat.org
309 dnsbl.sorbs.net
195 dnsbl.njabl.org
167 sbl.spamhaus.org
22 spews.dnsbl.net.au
6 relays.ordb.org
1 proxies.blackholes.easynet.nl
0 dsbl.org
A query to multi_dnsbl (pseudo.dnsbl in this example) looks like this
QUERY
1.2.3.4.pseudo.dnsbl
|
V
####################
# multi_dnsbl #
####################
| RESPONSE
+--> 1.2.3.4.list.dsbl.org NXDOMAIN
|
+--> 1.2.3.4.bl.spamcop.net NXDOMAIN
|
+--> 1.2.3.4.dynablock.easynet.nl NXDOMAIN
|
+--> 1.2.3.4.blackholes.easynet.nl A-127.0.0.2
The A record is returned to originator of the Query and the statistics count on blackholes.easynet.nl is incremented by one.
INSTALLATION / CONFIGURATION / OPERATION
multi_dnsbl can be installed as either a standalone DNSBL or as a plug-in to a BIND 9 installation on the same host. In either case, copy the rc.multi_daemon script to the appropriate startup directory on your host and modify the start, stop, restart scripts as required. Operation of the script is as follows:
Syntax: ./rc.multi_dnsbl start /path/to/config.file
./rc.multi_dnsbl start -v /path/to/config.file
./rc.multi_dnsbl stop /path/to/config.file
./rc.multi_dnsbl restart /path/to/config.file
The -v switch will print the scripts
actions verbosely to the STDERR.
CONFIGURATION FILE
The configuration file for multi_dnsbl shares a common format with the Mail::SpamCannibal sc_BLcheck.pl script, facilitating common maintenance of DNSBL's for your MTA installation.
The sample configuration file multi_dnsbl.conf.sample is heavily commented with the details for each configuration element. If you plan to use a common configuration file in a SpamCannibal installation, simply add the following elements to the sc_BlackList.conf file:
MDstatfile => '/path/to/statistics/file.txt',
MDpidpath => '/path/to/pidfiles', # /var/run
MDzone => 'pseudo.dnsbl',
# OPTIONAL
MDstatrefresh => 300, # seconds
MDipaddr => '0.0.0.0', # PROBABLY NOT WHAT YOU WANT
MDport => 9953,
STANDALONE OPERATION
For standalone operation, simply set MDport = 53, nothing more is required.
Interrogating the installation will then return the first match from the configured list of DNSBL servers.
i.e. dig 2.0.0.127.pseudo.dnsbl
.... results
Note that the results will contain all of the "authority" and "additional" (glue) records from the responding DNSBL placed into the additional section of the returned record that will have an authority record from of "localhost".
PLUGIN to BIND 9
multi_dnsbl may be used as a plugin helper for a standard bind 9 installation by adding a forward zone to the configuration file as follows:
//zone pseudo.dnsbl
zone "pseudo.dnsbl" in {
type forward;
forward only;
forwarders {
127.0.0.1 port 9953;
};
};
You may also wish to add one or more of the following statements with appropriate address_match_lists to restrict access to the facility.
allow-notify {};
allow-query { address_match_list };
allow-recursion { address_match_list };
allow-transfer {};
MTA CONFIGURATION
Access to DNSBL lookup is configured in the normal fashion for each MTA. Since MTA's generally must interrogate on port 53, multi_dnsbl must be installed on a stand-alone server or as a plugin for BIND 9.
A typical configuration line for sendmail M4 configuration file is shown below:
FEATURE(`dnsbl',`pseudo.dnsbl',
`554 Rejected $&{client_addr} found in http://www.spamcannibal.org')dnl
SYSTEM SIGNALS
multi_dnsbl responds to the following system signals:
TERM
Operations the statistics file is updated with the internal counts and the daemon then exits.
HUP
Operations are stopped including an update of the optional statistics file, the configuration file is re-read and operations are restarted.
USR1
The statistics file is updated on the next second tick.
USR2
The statistics file is deleted, internal statistics then a new (empty) statistics file is written on the next second tick.
PERL MODULE DESCRIPTION
Net::DNSBL::MultiDaemon provides most of the functions that implement multi_dnsbl which is an MTA helper that interrogates a list of DNSBL servers in preferential order based on their success rate.
The following describes the workings of individual functions used to implement multi_dnsbl.
run($BLzone,$L,$R,$DNSBL,$STATs,$Run,$Sfile,$StatStamp,$DEBUG);
This function is the 'run' portion for the DNSBL multidaemon
input: $BLzone zone name, $L local listen socket object pointer, $R remote socket object pointer, $DNSBL config hash pointer, $STATs statistics hash pointer $Run pointer to stats refresh time, # must be non-zero $Sfile statistics file path, $StatStamp stat file initial time stamp returns: nothing
$BLzone
The fully qualified domain name of the blacklist lookup
$L
A pointer to a UDP listener object
$R
A pointer to a unbound UDP socket used for interogation an receiving replies for the multiple DNSBL's
$DNSBL
A pointer to the zone configuration hash of the form:
$DNSBL = { 'domain.name' => { accept => { '127.0.0.2' => 'comment', '127.0.0.3' => 'comment', }, # timeout => 30, # default seconds to wait for dnsbl }, 'next.domain' = { etc.... # included but extracted external to B<run> MDzone => 'pseudo.dnsbl', MDstatfile => '/path/to/statistics/file.txt', MDpidpath => '/path/to/pidfiles # OPTIONAL, defaults shown # MDstatrefresh => 300, # max seconds for refresh # MDipaddr => '0.0.0.0', # PROBABLY NOT WHAT YOU WANT # MDport => 9953, # syslog. Specify the facility, one of: # LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG # MDsyslog => 'LOG_WARNING', };
Zone labels that are not of the form *.*... are ignored, making this hash table fully compatible with the SpamCannibal sc_Blacklist.conf file.
$STATs
A pointer to a statistics collection array of the form:
$STATs = { 'domain.name' => count, etc... };
Initialize this array with cntinit($DNSBL,$cp), then statinit($Sfile,$cp), below.
$Run
A POINTER to the time in seconds to refresh the $STATs backing file. Even if there is not backing file used, this value must be a positive integer. Setting this value to zero will stop the daemon and force a restart. It is used by $SIG{HUP} to restart the daemon.
$Sfile
The path to the STATISTICS backing file.
i.e. /some/path/to/filename.ext
If $Sfile is undefined, then the time stamp need not be defined
$StatTimestamp
Normally the value returned by statinit($Sfile,$cp), below.
s_response($mp,$resp,$id,$qdcount,$ancount,$nscount,$arcount);
Put a short response into the message buffer pointed to by $mp by sticking a new header on the EXISTING received query.
input: msg pointer, id of question, qd, an, ns, ar counts returns: nada
bl_lookup($put,$mp,$rtp,$sinaddr,$alarm,$id,$rip,$type,$zone,@blist);
Generates a query message for the first DNSBL in the @blist array. Creates a thread entry for the response and subsequent queries should the first one fail.
input: put, message pointer, remote thread pointer, sockinaddr, connection timeout, id of question, reverse IP address in text type of query received, (used in response) ORIGINAL zone (case preserved), array of remaining DNSBL's in sorted order returns: nothing, puts stuff in thread queue
not_found($put,$name,$type,$id,$mp,$srp);
Put a new 'not found' response in the buffer pointed to by $mp.
input: put, name, type, id, message buffer pointer, SOA record pointer returns: nothing
write_stats($sfile,$cp,$sinit);
Write out the contents of the accumulated statistics buffer to the STATs file.
input: statistics file path, pointer to count hash, initial timestamp line text returns: nothing
$timestamp = statinit($Sfile,$cp);
Initialize the contents of the statistics hash with the file contents of $Sfile, if $Sfile exists and there are corresponding entries in the statistics hash. i.e. the statistics hash keys must first be initialized with the DNSBL names.
input: statistics file path, pointer to count hash returns: timestamp line for file or undef on failure
cntinit($DNSBL,$cp);
Initialize the statistics count hash with DNSBL keys and set the counts to zero.
input: pointer to DNSBL hash, pointer to counts hash returns: nothing
$rv = DO($file);
This is a fancy 'do file'. It first checks that the file exists and is readable, then does a 'do file' to pull the variables and subroutines into the current name space.
input: file/path/name returns: last value in file or undef on error prints warning
$sock = open_udpNB();
Open and return a non-blocking UDP socket object
input: none returns: pointer to socket object or undef on failure
DEPENDENCIES
Unix::Syslog
Net::DNS::Codes
Net::DNS::ToolKit
EXPORT_OK
run
s_response
bl_lookup
not_found
write_stats
statinit
cntinit
open_udpNB
DO
EXPORT_TAGS :debug
DEBUG is a set of semaphores for the 'run' function
$D_CLRRUN = 0x1; # clear run flag and force unconditional return
$D_SHRTHD = 0x2; # return short header message
$D_TIMONLY = 0x4; # exit at end of timer section
$D_QRESP = 0x8; # return query response message
$D_NOTME = 0x10; # return received response not for me
$D_ANSTOP = 0x20; # clear run OK flag if ANSWER present
$D_VERBOSE = 0x40; # verbose debug statements to STDERR
AUTHOR
Michael Robinton, michael@bizsystems.com
COPYRIGHT
Copyright 2003, Michael Robinton & BizSystems This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.