Skip to content

Commit

Permalink
improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
msimerson committed Dec 27, 2023
1 parent f5a3d31 commit 0eb5602
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 70 deletions.
20 changes: 15 additions & 5 deletions config/dns-list.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,24 @@
; periodically check each DNS list, disabling ones that fail checks
periodic_checks = 30

; zones: a comma separated list of DNSBL zones
; zones: an array or a comma separated list of DNS zones
;
zones=b.barracudacentral.org, truncate.gbudb.net, psbl.surriel.com, bl.spamcop.net, dnsbl-1.uceprotect.net, zen.spamhaus.org, dnsbl.sorbs.net, dnsbl.justspam.org, list.dnswl.org, hostkarma.junkemailfilter.com
zones[]=b.barracudacentral.org
zones[]=truncate.gbudb.net
zones[]=psbl.surriel.com
zones[]=bl.spamcop.net
zones[]=dnsbl-1.uceprotect.net
zones[]=zen.spamhaus.org
zones[]=dnsbl.sorbs.net
zones[]=dnsbl.justspam.org
zones[]=list.dnswl.org
zones[]=hostkarma.junkemailfilter.com


; search: Default (first)
; first: consider first DNSBL response conclusive. End processing.
; all: process all DNSBL results
search=first
; first: consider first response conclusive. End processing.
; all: process all list results
search=all


[stats]
Expand Down
64 changes: 16 additions & 48 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
const dns = require('dns').promises;
const net = require('net');
const net_utils = require('haraka-net-utils');
const async = require('async');

exports.disable_allowed = false;
let redis_client;
Expand All @@ -18,13 +17,10 @@ exports.register = function () {

this.register_hook('connect', 'onConnect');

Check failure on line 18 in index.js

View workflow job for this annotation

GitHub Actions / lint / lint

Expected indentation of 2 spaces but found 4

// DNS allow
// IMPORTANT: don't run this on hook_rcpt otherwise we're an open relay...

Check failure on line 20 in index.js

View workflow job for this annotation

GitHub Actions / lint / lint

Expected indentation of 2 spaces but found 4
/*
['ehlo','helo','mail'].forEach(hook => {

Check failure on line 21 in index.js

View workflow job for this annotation

GitHub Actions / lint / lint

Expected indentation of 2 spaces but found 4
this.register_hook(hook, 'check_dnswl');

Check failure on line 22 in index.js

View workflow job for this annotation

GitHub Actions / lint / lint

Expected indentation of 4 spaces but found 8
});

Check failure on line 23 in index.js

View workflow job for this annotation

GitHub Actions / lint / lint

Expected indentation of 2 spaces but found 4
*/
}

exports.load_config = function () {
Expand All @@ -40,7 +36,12 @@ exports.load_config = function () {
this.load_config();
});

this.cfg.main.zones = new Set(this.cfg.main.zones.split(/[\s,;]+/));
if (Array.isArray(this.cfg.main.zones)) {
this.cfg.main.zones = new Set(this.cfg.main.zones);
}
else {
this.cfg.main.zones = new Set(this.cfg.main.zones.split(/[\s,;]+/));
}

// Compatibility with old-plugin
for (const z in this.config.get('dnsbl.zones', 'list')) {
Expand Down Expand Up @@ -93,9 +94,7 @@ exports.onConnect = function (next, connection) {
const plugin = this

async function eachActiveDnsList (ip, zone) {
// console.log(`eachActiveDnsList ip ${ip} zone ${zone}`)
const type = plugin.getListType(zone)
// console.log(`eachActiveDnsList ip ${ip} zone ${zone} type ${type}`)

const ips = await plugin.lookup(ip, zone)
// console.log(`eachActiveDnsList ip ${ip} zone ${zone} type ${type} ips ${ips}`)
Expand All @@ -106,12 +105,15 @@ exports.onConnect = function (next, connection) {
}

for (const i of ips) {
// console.log(`zone: ${zone} i: ${plugin.cfg[zone][i]}`)
if (plugin.cfg[zone][i]) connection.results.add(plugin, { msg: plugin.cfg[zone][i] })
if (plugin.cfg[zone] && plugin.cfg[zone][i]) {
// console.log(`zone: ${zone} i: ${plugin.cfg[zone][i]}`)
connection.results.add(plugin, { msg: plugin.cfg[zone][i] })
}
}

switch (type) {
case 'allow':
connection.notes.dnswl = true
connection.results.add(plugin, { pass: zone })
return nextOnce(OK, [zone])
case 'karma':
Expand All @@ -132,7 +134,7 @@ exports.onConnect = function (next, connection) {

Promise.all(promises).then(() => {
// console.log(`Promise.all`)
if (connection.results.get(plugin).fail.length) {
if (connection.results.get(plugin).fail?.length) {
nextOnce(DENY, connection.results.get(plugin).fail)
return
}
Expand Down Expand Up @@ -178,11 +180,10 @@ exports.lookup = async function (ip, zone) {

try {
const query = ipQuery(ip, zone)
// console.log(`lookup query ${query}`)
const a = await dns.resolve4(query, 'A')
// console.log(`lookup ${query} -> a: ${a}`)

// this.stats_incr_zone(err, zone, start); // Statistics
this.stats_incr_zone(null, zone, start); // Statistics

// Check for a result outside 127/8
// This should *never* happen on a proper DNS list
Expand All @@ -208,7 +209,8 @@ exports.lookup = async function (ip, zone) {
return a
}
catch (err) {
// console.log(`lookup err ${err}`)
this.stats_incr_zone(err, zone, start); // Statistics

if (err.code === dns.NOTFOUND) return; // unlisted, not an error

if (err.code === dns.TIMEOUT) { // list timed out
Expand All @@ -230,14 +232,12 @@ exports.stats_incr_zone = function (err, zone, start) {
const foo = (err) ? err.code : 'LISTED';
redis_client.hIncrBy(rkey, foo, 1);
redis_client.hGet(rkey, 'AVG_RT').then(rt => {
const avg = parseInt(rt) ? (parseInt(elapsed) + parseInt(rt))/2
: parseInt(elapsed);
const avg = parseInt(rt) ? (parseInt(elapsed) + parseInt(rt))/2 : parseInt(elapsed);
redis_client.hSet(rkey, 'AVG_RT', avg);
});
}

exports.init_redis = function () {
console.log(`init_redis`)
if (redis_client) return;

const redis = require('redis');
Expand All @@ -256,38 +256,6 @@ exports.init_redis = function () {
})
}

exports.multi = function (lookup, zones, cb) {
if (!lookup || !zones) return cb();
if (typeof zones === 'string') zones = [ `${zones}` ];
const self = this;
const listed = [];

function redis_incr (zone) {
if (!self.cfg.stats.enable) return;

// Statistics: check hit overlap
for (const element of listed) {
const foo = (element === zone) ? 'TOTAL' : element;
redis_client.hIncrBy(`dns-list-overlap:${zone}`, foo, 1);
}
}

function zoneIter (zone, done) {
self.lookup(lookup, zone, (err, a) => {
if (a) {
listed.push(zone);
redis_incr(zone);
}
cb(err, zone, a, true);
done();
})
}
function zonesDone (err) {
cb(err, null, null, false);
}
async.each(zones, zoneIter, zonesDone);
}

exports.getListType = function (zone) {
if (this.cfg[zone] === undefined) return 'block'
return this.cfg[zone]?.type || 'block' // default: block
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"mocha": "^10.2.0"
},
"dependencies": {
"async": "^3.2.5",
"haraka-net-utils": "^1.5.3"
}
}
38 changes: 22 additions & 16 deletions test/dns-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ describe('lookup', function () {

it('Spamcop, test IPv4', async function () {
const a = await this.plugin.lookup('127.0.0.2', 'bl.spamcop.net')
// assert.ok(a);
assert.deepEqual(['127.0.0.2'], a);
assert.deepStrictEqual(['127.0.0.2'], a);
})

it('Spamcop, unlisted IPv6', async function () {
Expand All @@ -66,7 +65,6 @@ describe('lookup', function () {

it('CBL', async function () {
const a = await this.plugin.lookup('127.0.0.2', 'xbl.spamhaus.org')
// console.log(a)
assert.deepStrictEqual(a, [ '127.0.0.4' ]);
})
})
Expand All @@ -89,6 +87,8 @@ describe('check_zone', function () {
})

describe('check_zones', function () {
this.timeout(7000)

it('tests each block list', async function () {
await this.plugin.check_zones(6000);
})
Expand All @@ -97,14 +97,12 @@ describe('check_zones', function () {
describe('onConnect', function () {

beforeEach(function () {
// this.plugin = new fixtures.plugin('index')
// this.plugin.load_config()
this.connection = fixtures.connection.createConnection()
})

it('onConnect 127.0.0.1', function (done) {
this.connection.set('remote.ip', '127.0.0.1')
this.plugin.zones=[ 'bl.spamcop.net', 'list.dnswl.org' ]
this.plugin.zones = new Set([ 'bl.spamcop.net', 'list.dnswl.org' ])
this.plugin.onConnect((code, msg) => {
assert.strictEqual(code, undefined);
assert.strictEqual(msg, undefined);
Expand All @@ -115,29 +113,37 @@ describe('onConnect', function () {

it('onConnect 127.0.0.2', function (done) {
this.connection.set('remote.ip', '127.0.0.2')
this.plugin.zones=[ 'bl.spamcop.net', 'list.dnswl.org' ]
this.plugin.zones = new Set([ 'bl.spamcop.net', 'list.dnswl.org' ])
this.plugin.onConnect((code, msg) => {
assert.strictEqual(code, DENY);
assert.strictEqual(msg, 'host [127.0.0.2] is listed on bl.spamcop.net');
// console.log(`code: ${code}, ${msg}`)
if (code === OK) {
assert.strictEqual(code, OK);
assert.strictEqual(msg, 'host [127.0.0.2] is listed on list.dnswl.org');
}
else {
assert.strictEqual(code, DENY);
assert.strictEqual(msg, 'host [127.0.0.2] is listed on bl.spamcop.net');
}
done()
},
this.connection)
})

it('Spamcop + CBL', function (done) {
this.connection.set('remote.ip', '127.0.0.2')
this.plugin.zones = [ 'bl.spamcop.net', 'xbl.spamhaus.org' ]
this.plugin.zones = new Set([ 'bl.spamcop.net', 'xbl.spamhaus.org' ])
this.plugin.onConnect((code, msg) => {
// console.log(`code: ${code}, ${msg}`)
assert.strictEqual(code, DENY);
assert.strictEqual(msg, 'host [127.0.0.2] is listed on bl.spamcop.net');
assert.ok(/is listed on/.test(msg));
done()
},
this.connection)
})

it('Spamcop + CBL + negative result', function (done) {
this.connection.set('remote.ip', '127.0.0.1')
this.plugin.zones = [ 'bl.spamcop.net', 'xbl.spamhaus.org' ]
this.plugin.zones = new Set([ 'bl.spamcop.net', 'xbl.spamhaus.org' ])
this.plugin.onConnect((code, msg) => {
// console.log(`test return ${code} ${msg}`)
assert.strictEqual(code, undefined);
Expand All @@ -148,7 +154,7 @@ describe('onConnect', function () {

it('IPv6 addresses supported', function (done) {
this.connection.set('remote.ip', '::1')
this.plugin.zones = ['bl.spamcop.net','xbl.spamhaus.org'];
this.plugin.zones = new Set(['bl.spamcop.net','xbl.spamhaus.org'])
this.plugin.onConnect((code, msg) => {
assert.strictEqual(code, undefined);
assert.strictEqual(msg, undefined);
Expand All @@ -161,16 +167,16 @@ describe('first', function () {

beforeEach(function () {
this.plugin.cfg.main.search='first'
this.plugin.zones = [ 'xbl.spamhaus.org', 'bl.spamcop.net' ];
this.plugin.zones = new Set([ 'xbl.spamhaus.org', 'bl.spamcop.net' ]);
this.connection = fixtures.connection.createConnection()
})

it('positive result', function (done) {
this.connection.set('remote.ip', '127.0.0.2')
this.plugin.onConnect((code, msg) => {
// console.log(`test return ${code} ${msg}`)
// console.log(`onConnect return ${code} ${msg}`)
assert.strictEqual(code, DENY);
assert.strictEqual(msg, 'host [127.0.0.2] is listed on bl.spamcop.net');
assert.ok(/is listed on/.test(msg));
done();
},
this.connection)
Expand Down

0 comments on commit 0eb5602

Please sign in to comment.