Haraka 3.0.3 → 3.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.yaml +4 -9
- package/CONTRIBUTORS.md +11 -0
- package/Changes.md +1397 -1213
- package/Plugins.md +117 -105
- package/README.md +4 -13
- package/bin/haraka +198 -298
- package/config/auth_flat_file.ini +1 -0
- package/config/dhparams.pem +8 -0
- package/config/mail_from.is_resolvable.ini +4 -2
- package/config/me +1 -0
- package/config/outbound.ini +0 -2
- package/config/plugins +35 -36
- package/config/smtp.ini +1 -1
- package/config/smtp.json +17 -0
- package/config/tls.ini +2 -0
- package/config/tls_cert.pem +23 -0
- package/config/tls_key.pem +28 -0
- package/connection.js +46 -73
- package/contrib/bsd-rc.d/haraka +3 -1
- package/contrib/plugin2npm.sh +6 -36
- package/docs/CoreConfig.md +2 -2
- package/docs/Logging.md +7 -21
- package/docs/Outbound.md +104 -201
- package/docs/Plugins.md +2 -2
- package/docs/Transaction.md +59 -82
- package/docs/plugins/queue/smtp_proxy.md +5 -10
- package/docs/plugins/tls.md +37 -9
- package/endpoint.js +16 -13
- package/haraka.js +10 -14
- package/host_pool.js +5 -5
- package/http/html/index.html +6 -5
- package/line_socket.js +3 -4
- package/logger.js +44 -28
- package/outbound/client_pool.js +27 -23
- package/outbound/config.js +4 -6
- package/outbound/fsync_writestream.js +1 -1
- package/outbound/hmail.js +178 -218
- package/outbound/index.js +86 -99
- package/outbound/qfile.js +1 -1
- package/outbound/queue.js +51 -44
- package/outbound/timer_queue.js +3 -2
- package/outbound/tls.js +19 -7
- package/package.json +60 -51
- package/plugins/.eslintrc.yaml +0 -6
- package/plugins/auth/auth_base.js +4 -2
- package/plugins/auth/auth_proxy.js +14 -12
- package/plugins/auth/auth_vpopmaild.js +1 -1
- package/plugins/block_me.js +1 -1
- package/plugins/data.signatures.js +2 -4
- package/plugins/early_talker.js +2 -1
- package/plugins/mail_from.is_resolvable.js +65 -135
- package/plugins/queue/deliver.js +4 -5
- package/plugins/queue/lmtp.js +11 -12
- package/plugins/queue/qmail-queue.js +2 -2
- package/plugins/queue/quarantine.js +2 -2
- package/plugins/queue/rabbitmq.js +16 -17
- package/plugins/queue/smtp_forward.js +3 -3
- package/plugins/queue/smtp_proxy.js +10 -1
- package/plugins/queue/test.js +2 -2
- package/plugins/rcpt_to.host_list_base.js +5 -5
- package/plugins/rcpt_to.in_host_list.js +2 -2
- package/plugins/relay.js +6 -7
- package/plugins/reseed_rng.js +1 -1
- package/plugins/status.js +37 -33
- package/plugins/tls.js +2 -2
- package/plugins/xclient.js +3 -2
- package/plugins.js +50 -54
- package/run_tests +3 -30
- package/server.js +190 -190
- package/smtp_client.js +30 -23
- package/{tests → test}/config/plugins +0 -2
- package/{tests → test}/config/smtp.ini +3 -1
- package/test/config/tls/example.com/_.example.com.key +28 -0
- package/test/config/tls/example.com/example.com.crt +25 -0
- package/{tests/loud → test}/config/tls.ini +4 -2
- package/test/connection.js +302 -0
- package/test/endpoint.js +94 -0
- package/{tests → test}/fixtures/line_socket.js +1 -1
- package/{tests → test}/fixtures/util_hmailitem.js +19 -25
- package/{tests → test}/host_pool.js +42 -57
- package/test/logger.js +258 -0
- package/test/outbound/hmail.js +141 -0
- package/test/outbound/index.js +220 -0
- package/test/outbound/qfile.js +126 -0
- package/test/outbound_bounce_net_errors.js +142 -0
- package/{tests → test}/outbound_bounce_rfc3464.js +110 -122
- package/test/plugins/auth/auth_base.js +484 -0
- package/test/plugins/auth/auth_vpopmaild.js +83 -0
- package/test/plugins/early_talker.js +104 -0
- package/test/plugins/mail_from.is_resolvable.js +35 -0
- package/test/plugins/queue/smtp_forward.js +206 -0
- package/test/plugins/rcpt_to.host_list_base.js +122 -0
- package/test/plugins/rcpt_to.in_host_list.js +193 -0
- package/test/plugins/relay.js +303 -0
- package/test/plugins/status.js +130 -0
- package/test/plugins/tls.js +70 -0
- package/test/plugins.js +228 -0
- package/test/rfc1869.js +73 -0
- package/test/server.js +491 -0
- package/test/smtp_client.js +299 -0
- package/test/tls_socket.js +277 -0
- package/test/transaction.js +270 -0
- package/tls_socket.js +202 -252
- package/transaction.js +8 -23
- package/CONTRIBUTING.md +0 -1
- package/bin/dkimverify +0 -40
- package/config/access.domains +0 -13
- package/config/attachment.ctype.regex +0 -2
- package/config/attachment.filename.regex +0 -1
- package/config/avg.ini +0 -5
- package/config/bounce.ini +0 -15
- package/config/data.headers.ini +0 -61
- package/config/dkim/dkim_key_gen.sh +0 -78
- package/config/dkim_sign.ini +0 -4
- package/config/dkim_verify.ini +0 -7
- package/config/dnsbl.ini +0 -23
- package/config/greylist.ini +0 -43
- package/config/helo.checks.ini +0 -52
- package/config/messagesniffer.ini +0 -18
- package/config/spamassassin.ini +0 -56
- package/dkim.js +0 -614
- package/docs/plugins/avg.md +0 -35
- package/docs/plugins/bounce.md +0 -69
- package/docs/plugins/clamd.md +0 -147
- package/docs/plugins/esets.md +0 -8
- package/docs/plugins/greylist.md +0 -90
- package/docs/plugins/helo.checks.md +0 -135
- package/docs/plugins/messagesniffer.md +0 -163
- package/docs/plugins/spamassassin.md +0 -180
- package/outbound/mx_lookup.js +0 -70
- package/plugins/auth/auth_ldap.js +0 -3
- package/plugins/avg.js +0 -162
- package/plugins/backscatterer.js +0 -25
- package/plugins/bounce.js +0 -381
- package/plugins/clamd.js +0 -382
- package/plugins/data.uribl.js +0 -4
- package/plugins/dkim_sign.js +0 -395
- package/plugins/dkim_verify.js +0 -62
- package/plugins/dns_list_base.js +0 -221
- package/plugins/dnsbl.js +0 -146
- package/plugins/dnswl.js +0 -58
- package/plugins/esets.js +0 -71
- package/plugins/graph.js +0 -5
- package/plugins/greylist.js +0 -645
- package/plugins/helo.checks.js +0 -533
- package/plugins/messagesniffer.js +0 -381
- package/plugins/rcpt_to.ldap.js +0 -3
- package/plugins/rcpt_to.max_count.js +0 -24
- package/plugins/spamassassin.js +0 -384
- package/tests/config/dkim/example.com/dns +0 -29
- package/tests/config/dkim/example.com/private +0 -6
- package/tests/config/dkim/example.com/public +0 -4
- package/tests/config/dkim/example.com/selector +0 -1
- package/tests/config/dkim.private.key +0 -6
- package/tests/config/dkim_sign.ini +0 -4
- package/tests/config/helo.checks.ini +0 -52
- package/tests/connection.js +0 -327
- package/tests/endpoint.js +0 -128
- package/tests/fixtures/vm_harness.js +0 -59
- package/tests/logger.js +0 -327
- package/tests/outbound/hmail.js +0 -112
- package/tests/outbound/index.js +0 -324
- package/tests/outbound/qfile.js +0 -67
- package/tests/outbound_bounce_net_errors.js +0 -173
- package/tests/plugins/auth/auth_base.js +0 -463
- package/tests/plugins/auth/auth_vpopmaild.js +0 -91
- package/tests/plugins/bounce.js +0 -307
- package/tests/plugins/clamd.js +0 -224
- package/tests/plugins/deprecated/relay_acl.js +0 -140
- package/tests/plugins/deprecated/relay_all.js +0 -59
- package/tests/plugins/dkim_sign.js +0 -315
- package/tests/plugins/dkim_signer.js +0 -108
- package/tests/plugins/dns_list_base.js +0 -259
- package/tests/plugins/dnsbl.js +0 -101
- package/tests/plugins/early_talker.js +0 -115
- package/tests/plugins/greylist.js +0 -58
- package/tests/plugins/helo.checks.js +0 -525
- package/tests/plugins/mail_from.is_resolvable.js +0 -116
- package/tests/plugins/queue/smtp_forward.js +0 -221
- package/tests/plugins/rcpt_to.host_list_base.js +0 -132
- package/tests/plugins/rcpt_to.in_host_list.js +0 -218
- package/tests/plugins/relay.js +0 -339
- package/tests/plugins/spamassassin.js +0 -171
- package/tests/plugins/status.js +0 -138
- package/tests/plugins/tls.js +0 -84
- package/tests/plugins.js +0 -247
- package/tests/rfc1869.js +0 -61
- package/tests/server.js +0 -510
- package/tests/smtp_client/auth.js +0 -105
- package/tests/smtp_client/basic.js +0 -101
- package/tests/smtp_client.js +0 -80
- package/tests/tls_socket.js +0 -333
- package/tests/transaction.js +0 -284
- /package/docs/{plugins → deprecated}/dkim_sign.md +0 -0
- /package/docs/{plugins → deprecated}/dkim_verify.md +0 -0
- /package/docs/{plugins → deprecated}/dnsbl.md +0 -0
- /package/docs/{plugins → deprecated}/dnswl.md +0 -0
- /package/{tests → test}/.eslintrc.yaml +0 -0
- /package/{tests → test}/config/auth_flat_file.ini +0 -0
- /package/{tests → test}/config/dhparams.pem +0 -0
- /package/{tests → test}/config/host_list +0 -0
- /package/{tests → test}/config/outbound_tls_cert.pem +0 -0
- /package/{tests → test}/config/outbound_tls_key.pem +0 -0
- /package/{tests → test}/config/smtp_forward.ini +0 -0
- /package/{tests → test}/config/tls/ec.pem +0 -0
- /package/{tests → test}/config/tls/haraka.local.pem +0 -0
- /package/{tests → test}/config/tls/mismatched.pem +0 -0
- /package/{tests → test}/config/tls_cert.pem +0 -0
- /package/{tests → test}/config/tls_key.pem +0 -0
- /package/{tests → test}/fixtures/todo_qfile.txt +0 -0
- /package/{tests → test}/installation/config/test-plugin-flat +0 -0
- /package/{tests → test}/installation/config/test-plugin.ini +0 -0
- /package/{tests → test}/installation/config/tls.ini +0 -0
- /package/{tests → test}/installation/node_modules/load_first/index.js +0 -0
- /package/{tests → test}/installation/node_modules/load_first/package.json +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin-flat +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin.ini +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/package.json +0 -0
- /package/{tests → test}/installation/node_modules/test-plugin/test-plugin.js +0 -0
- /package/{tests → test}/installation/plugins/base_plugin.js +0 -0
- /package/{tests → test}/installation/plugins/folder_plugin/index.js +0 -0
- /package/{tests → test}/installation/plugins/folder_plugin/package.json +0 -0
- /package/{tests → test}/installation/plugins/inherits.js +0 -0
- /package/{tests → test}/installation/plugins/load_first.js +0 -0
- /package/{tests → test}/installation/plugins/plugin.js +0 -0
- /package/{tests → test}/installation/plugins/tls.js +0 -0
- /package/{tests → test}/loud/config/dhparams.pem +0 -0
- /package/{tests → test}/loud/config/tls/goobered.pem +0 -0
- /package/{tests → test/loud}/config/tls.ini +0 -0
- /package/{tests → test}/mail_specimen/base64-root-part.txt +0 -0
- /package/{tests → test}/mail_specimen/varied-fold-lengths-preserve-data.txt +0 -0
- /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
- /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
- /package/{tests → test}/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
- /package/{tests → test}/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
- /package/{tests → test}/queue/multibyte +0 -0
- /package/{tests → test}/queue/plain +0 -0
- /package/{tests → test}/queue/zero-length +0 -0
- /package/{tests → test}/test-queue/delete-me +0 -0
|
@@ -1,381 +0,0 @@
|
|
|
1
|
-
// messagesniffer
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const net = require('net');
|
|
5
|
-
const plugin = exports;
|
|
6
|
-
|
|
7
|
-
// Defaults
|
|
8
|
-
let port = 9001;
|
|
9
|
-
|
|
10
|
-
exports.register = function () {
|
|
11
|
-
const cfg = this.config.get('messagesniffer.ini');
|
|
12
|
-
if (cfg.main.port) port = parseInt(cfg.main.port);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
exports.hook_connect = function (next, connection) {
|
|
16
|
-
const cfg = this.config.get('messagesniffer.ini');
|
|
17
|
-
// Skip any private IP ranges
|
|
18
|
-
// Skip connection.transaction undefined
|
|
19
|
-
if (connection?.remote?.is_private || !connection?.transaction) return next();
|
|
20
|
-
|
|
21
|
-
// Retrieve GBUdb information for the connecting IP
|
|
22
|
-
SNFClient(`<snf><xci><gbudb><test ip='${connection.remote.ip}'/></gbudb></xci></snf>`, (err, result) => {
|
|
23
|
-
if (err) {
|
|
24
|
-
connection.logerror(this, err.message);
|
|
25
|
-
return next();
|
|
26
|
-
}
|
|
27
|
-
let match;
|
|
28
|
-
if ((match = /<result ((?:(?!\/>)[^])+)\/>/.exec(result))) {
|
|
29
|
-
// Log result
|
|
30
|
-
connection.loginfo(this, match[1]);
|
|
31
|
-
// Populate result
|
|
32
|
-
const gbudb = {};
|
|
33
|
-
const split = match[1].toString().split(/\s+/);
|
|
34
|
-
for (const element of split) {
|
|
35
|
-
const split2 = element.split(/=/);
|
|
36
|
-
gbudb[split2[0]] = split2[1].replace(/(?:^'|'$)/g,'');
|
|
37
|
-
}
|
|
38
|
-
// Set notes for other plugins
|
|
39
|
-
connection.notes.gbudb = gbudb;
|
|
40
|
-
// Handle result
|
|
41
|
-
switch (gbudb.range) {
|
|
42
|
-
case 'new':
|
|
43
|
-
case 'normal':
|
|
44
|
-
return next();
|
|
45
|
-
case 'white':
|
|
46
|
-
// Default for white if no configuration
|
|
47
|
-
if (!cfg.gbudb || (cfg.gbudb && !cfg.gbudb[gbudb.range])) {
|
|
48
|
-
return next(OK);
|
|
49
|
-
}
|
|
50
|
-
// fall through
|
|
51
|
-
case 'caution':
|
|
52
|
-
case 'black':
|
|
53
|
-
case 'truncate':
|
|
54
|
-
if (cfg.gbudb?.[gbudb.range]) {
|
|
55
|
-
connection.loginfo(this, `range=${gbudb.range} action=${cfg.gbudb[gbudb.range]}`);
|
|
56
|
-
switch (cfg.gbudb[gbudb.range]) {
|
|
57
|
-
case 'accept':
|
|
58
|
-
// Whitelist
|
|
59
|
-
connection.notes.gbudb.action = 'accept';
|
|
60
|
-
return next(OK);
|
|
61
|
-
case 'allow':
|
|
62
|
-
case 'continue':
|
|
63
|
-
// Continue to next plugin
|
|
64
|
-
connection.notes.gbudb.action = 'allow';
|
|
65
|
-
return next();
|
|
66
|
-
case 'retry':
|
|
67
|
-
case 'tempfail':
|
|
68
|
-
return next(DENYSOFT, `Poor GBUdb reputation for [${connection.remote.ip}]`);
|
|
69
|
-
case 'reject':
|
|
70
|
-
return next(DENY, `Poor GBUdb reputation for [${connection.remote.ip}]`);
|
|
71
|
-
case 'quarantine':
|
|
72
|
-
connection.notes.gbudb.action = 'quarantine';
|
|
73
|
-
connection.notes.quarantine = true;
|
|
74
|
-
connection.notes.quarantine_action = [ OK, `Message quarantined (${connection.transaction.uuid})` ];
|
|
75
|
-
break;
|
|
76
|
-
case 'tag':
|
|
77
|
-
connection.notes.gbudb.action = 'tag';
|
|
78
|
-
break;
|
|
79
|
-
default:
|
|
80
|
-
// Unknown action
|
|
81
|
-
return next();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
else if (gbudb.range === 'truncate') {
|
|
85
|
-
// Default for truncate
|
|
86
|
-
return next(DENY, `Poor GBUdb reputation for [${connection.remote.ip}]`);
|
|
87
|
-
}
|
|
88
|
-
return next();
|
|
89
|
-
default:
|
|
90
|
-
// Unknown
|
|
91
|
-
connection.logerror(this, `Unknown GBUdb range: ${gbudb.range}`);
|
|
92
|
-
next();
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
next();
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
exports.hook_data_post = function (next, connection) {
|
|
102
|
-
const cfg = this.config.get('messagesniffer.ini');
|
|
103
|
-
const txn = connection?.transaction;
|
|
104
|
-
if (!txn) return next();
|
|
105
|
-
|
|
106
|
-
function tag_subject (){
|
|
107
|
-
const tag = cfg.main.tag_string || '[SPAM]';
|
|
108
|
-
const subj = txn.header.get_decoded('Subject');
|
|
109
|
-
// Try and prevent any double subject modifications
|
|
110
|
-
const subject_re = new RegExp(`^${tag}`);
|
|
111
|
-
if (!subject_re.test(subj)) {
|
|
112
|
-
txn.remove_header('Subject');
|
|
113
|
-
txn.add_header('Subject', `${tag} ${subj}`);
|
|
114
|
-
}
|
|
115
|
-
// Add spam flag
|
|
116
|
-
txn.remove_header('X-Spam-Flag');
|
|
117
|
-
txn.add_header('X-Spam-Flag', 'YES');
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Check GBUdb results
|
|
121
|
-
if (connection.notes.gbudb?.action) {
|
|
122
|
-
switch (connection.notes.gbudb.action) {
|
|
123
|
-
case 'accept':
|
|
124
|
-
case 'quarantine':
|
|
125
|
-
return next(OK);
|
|
126
|
-
case 'tag':
|
|
127
|
-
// Tag message
|
|
128
|
-
tag_subject();
|
|
129
|
-
return next();
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const tmpdir = cfg.main.tmpdir || '/tmp';
|
|
134
|
-
const tmpfile = `${tmpdir}/${txn.uuid}.tmp`;
|
|
135
|
-
const ws = fs.createWriteStream(tmpfile);
|
|
136
|
-
|
|
137
|
-
ws.once('error', err => {
|
|
138
|
-
connection.logerror(this, `Error writing temporary file: ${err.message}`);
|
|
139
|
-
next();
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
ws.once('close', () => {
|
|
143
|
-
const start_time = Date.now();
|
|
144
|
-
SNFClient(`<snf><xci><scanner><scan file='${tmpfile}' xhdr='yes'/></scanner></xci></snf>`, (err, result) => {
|
|
145
|
-
const end_time = Date.now();
|
|
146
|
-
const elapsed = end_time - start_time;
|
|
147
|
-
// Delete the tempfile
|
|
148
|
-
fs.unlink(tmpfile, () => {});
|
|
149
|
-
let match;
|
|
150
|
-
// Make sure we actually got a result
|
|
151
|
-
if ((match = /<result code='(\d+)'/.exec(result))) {
|
|
152
|
-
const code = parseInt(match[1]);
|
|
153
|
-
let group;
|
|
154
|
-
let rules;
|
|
155
|
-
let gbudb_ip;
|
|
156
|
-
// Make a note that we actually ran
|
|
157
|
-
connection.notes.snf_run = true;
|
|
158
|
-
// Get the returned headers
|
|
159
|
-
if ((match = /<xhdr>((?:(?!<\/xhdr>)[^])+)/.exec(result,'m'))) {
|
|
160
|
-
// Parse the returned headers and add them to the message
|
|
161
|
-
const xhdr = match[1].split('\r\n');
|
|
162
|
-
const headers = [];
|
|
163
|
-
for (const line of xhdr) {
|
|
164
|
-
// Check for continuation
|
|
165
|
-
if (/^\s/.test(line)) {
|
|
166
|
-
// Continuation; add to previous header value
|
|
167
|
-
if (headers[headers.length-1]) {
|
|
168
|
-
headers[headers.length-1].value += `${line}\r\n`;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
// Must be a header
|
|
173
|
-
match = /^([^: ]+):(?:\s*(.+))?$/.exec(line);
|
|
174
|
-
if (match) {
|
|
175
|
-
headers.push({ header: match[1], value: (match[2] ? `${match[2]}\r\n` : '\r\n') });
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
// Add headers to message
|
|
180
|
-
for (const header of headers) {
|
|
181
|
-
// If present save the group for logging purposes
|
|
182
|
-
if (header.header === 'X-MessageSniffer-SNF-Group') {
|
|
183
|
-
group = header.value.replace(/\r?\n/gm, '');
|
|
184
|
-
}
|
|
185
|
-
// Log GBUdb analysis
|
|
186
|
-
if (header.header === 'X-GBUdb-Analysis') {
|
|
187
|
-
// Retrieve IP address determined by GBUdb
|
|
188
|
-
const gbudb_split = header.value.split(/,\s*/);
|
|
189
|
-
gbudb_ip = gbudb_split[1];
|
|
190
|
-
connection.logdebug(this, `GBUdb: ${header.value.replace(/\r?\n/gm, '')}`);
|
|
191
|
-
}
|
|
192
|
-
if (header.header === 'X-MessageSniffer-Rules') {
|
|
193
|
-
rules = header.value.replace(/\r?\n/gm, '').replace(/\s+/g,' ').trim();
|
|
194
|
-
connection.logdebug(this, `rules: ${rules}`);
|
|
195
|
-
}
|
|
196
|
-
// Remove any existing headers
|
|
197
|
-
txn.remove_header(header.header);
|
|
198
|
-
txn.add_header(header.header, header.value);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
// Summary log
|
|
202
|
-
connection.loginfo(this, `result: time=${elapsed}ms code=${code
|
|
203
|
-
}${gbudb_ip ? ` ip="${gbudb_ip}"` : ''
|
|
204
|
-
}${group ? ` group="${group}"` : ''
|
|
205
|
-
}${rules ? ` rule_count=${rules.split(/\s+/).length}` : ''
|
|
206
|
-
}${rules ? ` rules="${rules}"` : ''}`);
|
|
207
|
-
// Result code MUST in the 0-63 range otherwise we got an error
|
|
208
|
-
// http://www.armresearch.com/support/articles/software/snfServer/errors.jsp
|
|
209
|
-
if (code === 0 || (code && code <= 63)) {
|
|
210
|
-
// Handle result
|
|
211
|
-
let action;
|
|
212
|
-
if (cfg.message) {
|
|
213
|
-
if (code === 0 && cfg.message.white) {
|
|
214
|
-
action = cfg.message.white;
|
|
215
|
-
}
|
|
216
|
-
else if (code === 1) {
|
|
217
|
-
if (cfg.message.local_white) {
|
|
218
|
-
action = cfg.message.local_white;
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
return next(OK);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
else if (code === 20) {
|
|
225
|
-
if (cfg.message.truncate) {
|
|
226
|
-
action = cfg.message.truncate;
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
return next(DENY, `Poor GBUdb reputation for IP [${connection.remote.ip}]`);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
else if (code === 40 && cfg.message.caution) {
|
|
233
|
-
action = cfg.message.caution;
|
|
234
|
-
}
|
|
235
|
-
else if (code === 63 && cfg.message.black) {
|
|
236
|
-
action = cfg.message.black;
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
if (cfg.message[`code_${code}`]) {
|
|
240
|
-
action = cfg.message[`code_${code}`];
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
if (code > 1 && code !== 40) {
|
|
244
|
-
if (cfg.message.nonzero) {
|
|
245
|
-
action = cfg.message.nonzero;
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
return next(DENY, `Spam detected by MessageSniffer (code=${code} group=${group})`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
// Default with no configuration
|
|
256
|
-
if (code > 1 && code !== 40) {
|
|
257
|
-
return next(DENY, `Spam detected by MessageSniffer (code=${code} group=${group})`);
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
return next();
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
switch (action) {
|
|
264
|
-
case 'accept':
|
|
265
|
-
// Whitelist
|
|
266
|
-
return next(OK);
|
|
267
|
-
case 'allow':
|
|
268
|
-
case 'continue':
|
|
269
|
-
// Continue to next plugin
|
|
270
|
-
return next();
|
|
271
|
-
case 'retry':
|
|
272
|
-
case 'tempfail':
|
|
273
|
-
return next(DENYSOFT, `Spam detected by MessageSniffer (code=${code} group=${group})`);
|
|
274
|
-
case 'reject':
|
|
275
|
-
return next(DENY, `Spam detected by MessageSniffer (code=${code} group=${group})`);
|
|
276
|
-
case 'quarantine':
|
|
277
|
-
// Set flag for queue/quarantine plugin
|
|
278
|
-
txn.notes.quarantine = true;
|
|
279
|
-
txn.notes.quarantine_action = [ OK, `Message quarantined (${txn.uuid})` ];
|
|
280
|
-
break;
|
|
281
|
-
case 'tag':
|
|
282
|
-
tag_subject();
|
|
283
|
-
// fall through
|
|
284
|
-
default:
|
|
285
|
-
return next();
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
// Out-of-band code returned
|
|
290
|
-
// Handle Bulk/Noisy special rule by re-writing the Precedence header
|
|
291
|
-
if (code === 100) {
|
|
292
|
-
let precedence = txn.header.get('precedence');
|
|
293
|
-
if (precedence) {
|
|
294
|
-
// We already have a precedence header
|
|
295
|
-
precedence = precedence.trim().toLowerCase();
|
|
296
|
-
switch (precedence) {
|
|
297
|
-
case 'bulk':
|
|
298
|
-
case 'list':
|
|
299
|
-
case 'junk':
|
|
300
|
-
// Leave these as they are
|
|
301
|
-
break;
|
|
302
|
-
default:
|
|
303
|
-
// Remove anything else and replace it with 'bulk'
|
|
304
|
-
txn.remove_header('precedence');
|
|
305
|
-
txn.add_header('Precedence', 'bulk');
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
309
|
-
txn.add_header('Precedence', 'bulk');
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
return next();
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
// Something must have gone wrong
|
|
317
|
-
connection.logwarn(this, `unexpected response: ${result}`);
|
|
318
|
-
}
|
|
319
|
-
return next();
|
|
320
|
-
});
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
// TODO: we only need the first 64Kb of the message
|
|
324
|
-
txn.message_stream.pipe(ws, { line_endings: '\r\n' });
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
exports.hook_disconnect = function (next, connection) {
|
|
328
|
-
const cfg = this.config.get('messagesniffer.ini');
|
|
329
|
-
|
|
330
|
-
// Train GBUdb on rejected messages and recipients
|
|
331
|
-
if (cfg.main.gbudb_report_deny && !connection.notes.snf_run &&
|
|
332
|
-
(connection.rcpt_count.reject > 0 || connection.msg_count.reject > 0)) {
|
|
333
|
-
const snfreq = `<snf><xci><gbudb><bad ip='${connection.remote.ip}'/></gbudb></xci></snf>`;
|
|
334
|
-
SNFClient(snfreq, (err, result) => {
|
|
335
|
-
if (err) {
|
|
336
|
-
connection.logerror(this, err.message);
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
339
|
-
connection.logdebug(this, `GBUdb bad encounter added for ${connection.remote.ip}`);
|
|
340
|
-
}
|
|
341
|
-
next();
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
else {
|
|
345
|
-
next();
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function SNFClient (req, cb) {
|
|
350
|
-
let result;
|
|
351
|
-
const sock = new net.Socket();
|
|
352
|
-
sock.setTimeout(30 * 1000); // Connection timeout
|
|
353
|
-
sock.once('timeout', function () {
|
|
354
|
-
this.destroy();
|
|
355
|
-
cb(new Error('connection timed out'));
|
|
356
|
-
});
|
|
357
|
-
sock.once('error', err => cb(err));
|
|
358
|
-
sock.once('connect', function () {
|
|
359
|
-
// Connected, send request
|
|
360
|
-
plugin.logprotocol(`> ${req}`);
|
|
361
|
-
this.write(`${req}\n`);
|
|
362
|
-
});
|
|
363
|
-
sock.on('data', data => {
|
|
364
|
-
plugin.logprotocol(`< ${data}`);
|
|
365
|
-
// Buffer all the received lines
|
|
366
|
-
(result ? result += data : result = data);
|
|
367
|
-
});
|
|
368
|
-
sock.once('end', () => {
|
|
369
|
-
// Check for result
|
|
370
|
-
if (/<result /.exec(result)) return cb(null, result);
|
|
371
|
-
|
|
372
|
-
let match;
|
|
373
|
-
if ((match = /<error message='([^']+)'/.exec(result))) {
|
|
374
|
-
return cb(new Error(match[1]));
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
cb(new Error(`unexpected result: ${result}`));
|
|
378
|
-
});
|
|
379
|
-
// Start the sequence
|
|
380
|
-
sock.connect(port);
|
|
381
|
-
}
|
package/plugins/rcpt_to.ldap.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// Implement a maximum number of recipients per mail
|
|
2
|
-
// this helps guard against some spammers who send RCPT TO a gazillion times
|
|
3
|
-
// as a way of probing for a working address
|
|
4
|
-
|
|
5
|
-
// Consider using the karma plugin. It supports limiting the number
|
|
6
|
-
// of recipients based on past behavior (good, bad, unknown)
|
|
7
|
-
|
|
8
|
-
exports.hook_rcpt = function (next, connection = {}) {
|
|
9
|
-
const { notes } = connection.transaction
|
|
10
|
-
|
|
11
|
-
if (notes?.rcpt_to_count) {
|
|
12
|
-
notes.rcpt_to_count++;
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
notes.rcpt_to_count = 1;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const max_count = this.config.get('rcpt_to.max_count') || 40;
|
|
19
|
-
|
|
20
|
-
if (notes.rcpt_to_count > max_count) {
|
|
21
|
-
return next(DENYDISCONNECT, "Too many recipient attempts");
|
|
22
|
-
}
|
|
23
|
-
return next();
|
|
24
|
-
}
|