Haraka 3.0.2 → 3.0.4
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 +5 -9
- package/.prettierrc.yml +1 -0
- package/CONTRIBUTORS.md +11 -0
- package/Changes.md +1393 -1211
- package/Dockerfile +3 -3
- package/Plugins.md +119 -106
- package/README.md +7 -16
- package/TODO +1 -24
- package/bin/haraka +197 -298
- package/config/auth_flat_file.ini +2 -0
- package/config/auth_vpopmaild.ini +4 -2
- 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 +36 -35
- package/config/rabbitmq_amqplib.ini +8 -1
- package/config/smtp.ini +0 -1
- package/config/smtp.json +17 -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/Connection.md +1 -1
- package/docs/CoreConfig.md +2 -2
- package/docs/Logging.md +7 -21
- package/docs/Outbound.md +104 -210
- package/docs/Plugins.md +47 -40
- package/docs/Transaction.md +59 -82
- package/docs/{plugins → deprecated}/connect.rdns_access.md +1 -1
- package/docs/{plugins → deprecated}/mail_from.access.md +1 -1
- package/docs/{plugins → deprecated}/rcpt_to.access.md +1 -1
- package/docs/plugins/auth/auth_vpopmaild.md +15 -19
- package/docs/plugins/auth/flat_file.md +23 -30
- package/docs/plugins/queue/rabbitmq_amqplib.md +7 -0
- package/docs/plugins/queue/smtp_forward.md +1 -1
- package/docs/plugins/queue/smtp_proxy.md +5 -10
- package/docs/plugins/relay.md +2 -2
- package/docs/plugins/tls.md +29 -9
- package/endpoint.js +16 -13
- package/haraka.js +10 -14
- package/host_pool.js +5 -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 +180 -220
- package/outbound/index.js +86 -99
- package/outbound/qfile.js +1 -1
- package/outbound/queue.js +55 -43
- package/outbound/timer_queue.js +3 -2
- package/outbound/tls.js +19 -7
- package/package.json +66 -55
- package/plugins/.eslintrc.yaml +0 -6
- package/plugins/auth/auth_base.js +30 -12
- package/plugins/auth/auth_proxy.js +14 -12
- package/plugins/auth/auth_vpopmaild.js +30 -20
- package/plugins/auth/flat_file.js +17 -12
- 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 -14
- 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/rabbitmq_amqplib.js +1 -1
- package/plugins/queue/smtp_forward.js +6 -6
- 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 +51 -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 +1 -1
- package/test/config/tls/example.com/_.example.com.key +28 -0
- package/test/config/tls/example.com/example.com.crt +25 -0
- 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/{tests → test}/queue/multibyte +0 -0
- package/{tests → test}/queue/plain +0 -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 +273 -0
- package/test/transaction.js +270 -0
- package/tls_socket.js +202 -252
- package/transaction.js +9 -24
- 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/lookup_rdns.strict.ini +0 -12
- package/config/lookup_rdns.strict.timeout +0 -1
- package/config/lookup_rdns.strict.whitelist +0 -1
- package/config/lookup_rdns.strict.whitelist_regex +0 -5
- package/config/messagesniffer.ini +0 -18
- package/config/rcpt_to.blocklist +0 -1
- package/config/rdns.allow_regexps +0 -0
- package/config/rdns.deny_regexps +0 -0
- package/config/spamassassin.ini +0 -56
- package/config.js +0 -6
- 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/relay_acl.md +0 -29
- package/docs/plugins/relay_all.md +0 -15
- package/docs/plugins/relay_force_routing.md +0 -33
- 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 -381
- package/plugins/data.headers.js +0 -4
- 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/relay_all.js +0 -13
- 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/docs/{plugins → deprecated}/rcpt_to.routes.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.ini +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/zero-length +0 -0
- /package/{tests → test}/test-queue/delete-me +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// Check MAIL FROM domain is resolvable to an MX
|
|
4
|
-
const
|
|
5
|
-
const net = require('net');
|
|
4
|
+
const net = require('node:net');
|
|
6
5
|
|
|
7
6
|
const net_utils = require('haraka-net-utils');
|
|
8
7
|
|
|
@@ -14,12 +13,17 @@ exports.load_ini = function () {
|
|
|
14
13
|
this.cfg = this.config.get('mail_from.is_resolvable.ini', {
|
|
15
14
|
booleans: [
|
|
16
15
|
'-main.allow_mx_ip',
|
|
17
|
-
'+
|
|
16
|
+
'+reject.no_mx',
|
|
18
17
|
],
|
|
19
18
|
}, () => {
|
|
20
19
|
this.load_ini();
|
|
21
20
|
});
|
|
22
21
|
|
|
22
|
+
// compat. Sunset 4.0
|
|
23
|
+
if (this.cfg.main.reject_no_mx) {
|
|
24
|
+
this.cfg.reject.no_mx = this.cfg.main.reject_no_mx
|
|
25
|
+
}
|
|
26
|
+
|
|
23
27
|
if (isNaN(this.cfg.main.timeout)) {
|
|
24
28
|
this.cfg.main.timeout = 29;
|
|
25
29
|
}
|
|
@@ -40,163 +44,89 @@ exports.hook_mail = function (next, connection, params) {
|
|
|
40
44
|
const mail_from = params[0];
|
|
41
45
|
const txn = connection?.transaction;
|
|
42
46
|
if (!txn) return next();
|
|
43
|
-
const { results }
|
|
47
|
+
const { results } = txn;
|
|
44
48
|
|
|
45
|
-
//
|
|
49
|
+
// ignore MAIL FROM without an @
|
|
46
50
|
if (!mail_from.host) {
|
|
47
51
|
results.add(plugin, {skip: 'null host'});
|
|
48
52
|
return next();
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
let called_next = 0;
|
|
52
|
-
const domain
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
// DNS answer didn't return (UDP)
|
|
56
|
-
connection.loginfo(plugin, `timed out resolving MX for ${domain}`);
|
|
56
|
+
const domain = mail_from.host;
|
|
57
|
+
const timeout_id = setTimeout(() => {
|
|
58
|
+
connection.logdebug(plugin, `DNS timeout resolving MX for ${domain}`);
|
|
57
59
|
called_next++;
|
|
58
60
|
if (txn) results.add(plugin, {err: `timeout(${domain})`});
|
|
59
61
|
next(DENYSOFT, 'Temporary resolver error (timeout)');
|
|
60
|
-
},
|
|
62
|
+
}, this.cfg.main.timeout * 1000);
|
|
61
63
|
|
|
62
64
|
function mxDone (code, reply) {
|
|
63
65
|
if (called_next) return;
|
|
64
66
|
clearTimeout(timeout_id);
|
|
65
67
|
called_next++;
|
|
66
|
-
next(
|
|
68
|
+
next(...arguments);
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
function mxErr (err) {
|
|
72
|
+
if (!connection.transaction) return;
|
|
73
|
+
results.add(plugin, {err: `${domain}:${err.message}`});
|
|
74
|
+
mxDone(DENYSOFT, `Temp. resolver error (${err.code})`);
|
|
75
|
+
}
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
// Check for implicit MX 0 record
|
|
76
|
-
return plugin.implicit_mx(connection, domain, mxDone);
|
|
77
|
-
}
|
|
77
|
+
connection.logdebug(plugin, `resolving MX for domain ${domain}`)
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (pending_queries !== 0) return;
|
|
84
|
-
|
|
85
|
-
records = Object.keys(records);
|
|
86
|
-
if (records?.length) {
|
|
87
|
-
connection.logdebug(plugin, `${domain}: ${records}`);
|
|
88
|
-
results.add(plugin, {pass: 'has_fwd_dns'});
|
|
89
|
-
return mxDone();
|
|
90
|
-
}
|
|
91
|
-
results.add(plugin, {fail: 'has_fwd_dns'});
|
|
92
|
-
return mxDone(((c.reject_no_mx) ? DENY : DENYSOFT),
|
|
93
|
-
'MX without A/AAAA records');
|
|
94
|
-
}
|
|
79
|
+
net_utils
|
|
80
|
+
.get_mx(domain)
|
|
81
|
+
.then((exchanges) => {
|
|
82
|
+
if (!txn) return;
|
|
95
83
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return;
|
|
84
|
+
connection.logdebug(plugin, `${domain}: MX => ${JSON.stringify(exchanges)}`)
|
|
85
|
+
|
|
86
|
+
if (!exchanges || !exchanges.length) {
|
|
87
|
+
results.add(this, {fail: 'has_fwd_dns'});
|
|
88
|
+
return mxDone(
|
|
89
|
+
((this.cfg.reject.no_mx) ? DENY : DENYSOFT),
|
|
90
|
+
'No MX for your FROM address'
|
|
91
|
+
);
|
|
105
92
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
connection.logdebug(plugin, `${domain}: MX ${addr.priority} ${addr.exchange} => ${err2[0].message}`);
|
|
113
|
-
check_results();
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
connection.logdebug(plugin, `${domain}: MX ${addr.priority} ${addr.exchange} => ${addresses2}`);
|
|
117
|
-
for (const element of addresses2) {
|
|
118
|
-
// Ignore anything obviously bogus
|
|
119
|
-
if (net.isIPv4(element)){
|
|
120
|
-
if (plugin.re_bogus_ip.test(element)) {
|
|
121
|
-
connection.logdebug(plugin, `${addr.exchange}: discarding ${element}`);
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
93
|
+
|
|
94
|
+
if (this.cfg.main.allow_mx_ip) {
|
|
95
|
+
for (const mx of exchanges) {
|
|
96
|
+
if (net.isIPv4(mx.exchange) && !this.re_bogus_ip.test(mx.exchange)) {
|
|
97
|
+
txn.results.add(this, {pass: 'implicit_mx', emit: true});
|
|
98
|
+
return mxDone()
|
|
124
99
|
}
|
|
125
|
-
if (net.isIPv6(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
100
|
+
if (net.isIPv6(mx.exchange) && !net_utils.ipv6_bogus(mx.exchange)) {
|
|
101
|
+
txn.results.add(this, {pass: 'implicit_mx', emit: true});
|
|
102
|
+
return mxDone()
|
|
130
103
|
}
|
|
131
|
-
records[element] = 1;
|
|
132
|
-
}
|
|
133
|
-
check_results();
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
// In case we don't run any queries
|
|
137
|
-
check_results();
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
exports.mxErr = function (connection, domain, type, err, mxDone) {
|
|
142
|
-
|
|
143
|
-
const txn = connection?.transaction;
|
|
144
|
-
if (!txn) return;
|
|
145
|
-
|
|
146
|
-
txn.results.add(this, {msg: `${domain}:${type}:${err.message}`});
|
|
147
|
-
connection.logdebug(this, `${domain}:${type} => ${err.message}`);
|
|
148
|
-
switch (err.code) {
|
|
149
|
-
case dns.NXDOMAIN:
|
|
150
|
-
case dns.NOTFOUND:
|
|
151
|
-
case dns.NODATA:
|
|
152
|
-
// Ignore
|
|
153
|
-
break;
|
|
154
|
-
default:
|
|
155
|
-
mxDone(DENYSOFT, `Temp. resolver error (${err.code})`);
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// IS: IPv6 compatible
|
|
162
|
-
exports.implicit_mx = function (connection, domain, mxDone) {
|
|
163
|
-
const txn = connection?.transaction;
|
|
164
|
-
if (!txn) return;
|
|
165
|
-
|
|
166
|
-
net_utils.get_ips_by_host(domain, (err, addresses) => {
|
|
167
|
-
if (!txn) return;
|
|
168
|
-
if (!addresses || !addresses.length) {
|
|
169
|
-
txn.results.add(this, {fail: 'has_fwd_dns'});
|
|
170
|
-
return mxDone(((this.cfg.main.reject_no_mx) ? DENY : DENYSOFT),
|
|
171
|
-
'No MX for your FROM address');
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
connection.logdebug(this, `${domain}: A/AAAA => ${addresses}`);
|
|
175
|
-
let records = {};
|
|
176
|
-
for (const addr of addresses) {
|
|
177
|
-
// Ignore anything obviously bogus
|
|
178
|
-
if (net.isIPv4(addr)) {
|
|
179
|
-
if (this.re_bogus_ip.test(addr)) {
|
|
180
|
-
connection.logdebug(this, `${domain}: discarding ${addr}`);
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (net.isIPv6(addr)) {
|
|
185
|
-
if (net_utils.ipv6_bogus(addr)) {
|
|
186
|
-
connection.logdebug(this, `${domain}: discarding ${addr}`);
|
|
187
|
-
continue;
|
|
188
104
|
}
|
|
189
105
|
}
|
|
190
|
-
records[addr] = true;
|
|
191
|
-
}
|
|
192
106
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
107
|
+
// filter out the implicit MX and resolve the MX hostnames
|
|
108
|
+
net_utils
|
|
109
|
+
.resolve_mx_hosts(exchanges.filter(a => !net.isIP(a.exchange)))
|
|
110
|
+
.then(resolved => {
|
|
111
|
+
connection.logdebug(plugin, `resolved MX => ${JSON.stringify(resolved)}`);
|
|
198
112
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
113
|
+
for (const mx of resolved) {
|
|
114
|
+
if (net.isIPv4(mx.exchange) && !this.re_bogus_ip.test(mx.exchange)) {
|
|
115
|
+
txn.results.add(this, {pass: 'has_fwd_dns', emit: true});
|
|
116
|
+
return mxDone()
|
|
117
|
+
}
|
|
118
|
+
if (net.isIPv6(mx.exchange) && !net_utils.ipv6_bogus(mx.exchange)) {
|
|
119
|
+
txn.results.add(this, {pass: 'has_fwd_dns', emit: true});
|
|
120
|
+
return mxDone()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
mxDone(
|
|
125
|
+
((this.cfg.main.reject_no_mx) ? DENY : DENYSOFT),
|
|
126
|
+
'No valid MX for your FROM address'
|
|
127
|
+
);
|
|
128
|
+
})
|
|
129
|
+
.catch(mxErr)
|
|
130
|
+
})
|
|
131
|
+
.catch(mxErr)
|
|
202
132
|
}
|
package/plugins/queue/deliver.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
// This plugin is
|
|
1
|
+
// This plugin is entirely redundant. The core will queue outbound mails
|
|
2
2
|
// automatically just like this. It is kept here for backwards compatibility
|
|
3
3
|
// purposes only.
|
|
4
4
|
|
|
5
5
|
const outbound = require('./outbound');
|
|
6
6
|
|
|
7
7
|
exports.hook_queue_outbound = (next, connection) => {
|
|
8
|
-
if
|
|
9
|
-
|
|
10
|
-
}
|
|
8
|
+
// if not relaying, don't deliver outbound
|
|
9
|
+
if (!connection?.relaying) return next();
|
|
11
10
|
|
|
12
|
-
outbound.
|
|
11
|
+
outbound.send_trans_email(connection?.transaction, next);
|
|
13
12
|
}
|
package/plugins/queue/lmtp.js
CHANGED
|
@@ -19,29 +19,26 @@ exports.hook_get_mx = function (next, hmail, domain) {
|
|
|
19
19
|
|
|
20
20
|
if (!hmail.todo.notes.using_lmtp) return next();
|
|
21
21
|
|
|
22
|
-
const mx = { using_lmtp: true, priority: 0, exchange: '127.0.0.1' };
|
|
23
|
-
|
|
24
22
|
const section = this.cfg[domain] || this.cfg.main;
|
|
25
|
-
if (section.path) {
|
|
26
|
-
Object.assign(mx, { path: section.path });
|
|
27
|
-
return next(OK, mx);
|
|
28
|
-
}
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
const mx = {
|
|
25
|
+
using_lmtp: true,
|
|
26
|
+
priority: 0,
|
|
27
|
+
exchange: section.host ?? '127.0.0.1',
|
|
28
|
+
port: section.port ?? 24,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
if (section.path) mx.path = section.path;
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
next(OK, mx);
|
|
36
34
|
}
|
|
37
35
|
|
|
38
36
|
exports.hook_queue = (next, connection) => {
|
|
39
37
|
const txn = connection?.transaction;
|
|
40
38
|
if (!txn) return next();
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
if (q_wants && q_wants !== 'lmtp') return next();
|
|
40
|
+
if (txn.notes.get('queue.wants') !== 'lmtp') return next();
|
|
44
41
|
|
|
45
42
|
txn.notes.using_lmtp = true;
|
|
46
|
-
outbound.
|
|
43
|
+
outbound.send_trans_email(txn, next);
|
|
47
44
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const amqp = require('amqp');
|
|
2
|
-
const logger = require('./logger');
|
|
3
2
|
|
|
4
3
|
let rabbitqueue;
|
|
5
4
|
let exchangeName;
|
|
@@ -12,41 +11,41 @@ exports.exchangeMapping = {}
|
|
|
12
11
|
|
|
13
12
|
//This method registers the hook and try to initialize the connection to rabbitmq server for later use.
|
|
14
13
|
exports.register = function () {
|
|
15
|
-
|
|
14
|
+
this.logdebug("About to connect and initialize queue object");
|
|
16
15
|
this.init_rabbitmq_server();
|
|
17
|
-
|
|
16
|
+
this.logdebug(`Finished initiating : ${exports.exchangeMapping[exchangeName + queueName]}`);
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
|
|
21
20
|
//Actual magic of publishing message to rabbit when email comes happen here.
|
|
22
|
-
exports.hook_queue = (next, connection)
|
|
21
|
+
exports.hook_queue = function (next, connection) {
|
|
23
22
|
if (!connection?.transaction) return next();
|
|
24
23
|
|
|
25
24
|
//Calling the get_data method and when it gets the data on callback, publish the message to queue with routing key.
|
|
26
25
|
connection.transaction.message_stream.get_data(buffere => {
|
|
27
26
|
const exchangeData = exports.exchangeMapping[exchangeName + queueName]
|
|
28
|
-
|
|
27
|
+
this.logdebug(`Sending the data: ${ queueName} Routing : ${exchangeData} exchange :${connExchange_}`);
|
|
29
28
|
if (connExchange_ && routing_) {
|
|
30
29
|
//This is publish function of rabbitmq amqp library, currently direct queue is configured and routing is fixed.
|
|
31
30
|
//Needs to be changed.
|
|
32
31
|
connExchange_.publish(routing_, buffere,{deliveryMode}, error => {
|
|
33
32
|
if (error) {
|
|
34
33
|
//There was some error while sending the email to queue.
|
|
35
|
-
|
|
34
|
+
this.logdebug("queueFailure: #{JSON.stringify(error)}");
|
|
36
35
|
exports.init_rabbitmq_server();
|
|
37
|
-
|
|
36
|
+
next();
|
|
38
37
|
}
|
|
39
38
|
else {
|
|
40
39
|
//Queueing was successful, send ok as reply
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
this.logdebug( "queueSuccess");
|
|
41
|
+
next(OK,"Successfully Queued! in rabbitmq");
|
|
43
42
|
}
|
|
44
43
|
});
|
|
45
44
|
}
|
|
46
45
|
else {
|
|
47
46
|
//Seems like connExchange is not defined , lets create one for next call
|
|
48
47
|
exports.init_rabbitmq_server();
|
|
49
|
-
|
|
48
|
+
next();
|
|
50
49
|
}
|
|
51
50
|
});
|
|
52
51
|
}
|
|
@@ -88,18 +87,18 @@ exports.init_rabbitmq_server = function () {
|
|
|
88
87
|
|
|
89
88
|
|
|
90
89
|
//Create connection to the rabbitmq server
|
|
91
|
-
|
|
90
|
+
this.logdebug("About to Create connection with server");
|
|
92
91
|
rabbitqueue = amqp.createConnection(options);
|
|
93
92
|
|
|
94
93
|
|
|
95
94
|
//Declaring listerner on error on connection.
|
|
96
95
|
rabbitqueue.on('error', error => {
|
|
97
|
-
|
|
96
|
+
this.logerror(`There was some error on the connection : ${error}`);
|
|
98
97
|
});
|
|
99
98
|
|
|
100
99
|
//Declaring listerner on close on connection.
|
|
101
100
|
rabbitqueue.on('close', close => {
|
|
102
|
-
|
|
101
|
+
this.logdebug(` Connection is being closed : ${close}`);
|
|
103
102
|
});
|
|
104
103
|
|
|
105
104
|
|
|
@@ -111,16 +110,16 @@ exports.init_rabbitmq_server = function () {
|
|
|
111
110
|
*/
|
|
112
111
|
|
|
113
112
|
rabbitqueue.on('ready', () => {
|
|
114
|
-
|
|
113
|
+
this.logdebug("Connection is ready, will try making exchange");
|
|
115
114
|
// Now connection is ready will try to open exchange with config data.
|
|
116
115
|
rabbitqueue.exchange(exchangeName, { type: exchangeType, confirm, durable }, connExchange => {
|
|
117
116
|
|
|
118
117
|
|
|
119
|
-
|
|
118
|
+
this.logdebug(`connExchange with server ${connExchange} autoDelete : ${autoDelete}`);
|
|
120
119
|
|
|
121
120
|
//Exchange is now open, will try to open queue.
|
|
122
121
|
return rabbitqueue.queue(queueName,{autoDelete, durable }, connQueue => {
|
|
123
|
-
|
|
122
|
+
this.logdebug(`connQueue with server ${connQueue}`);
|
|
124
123
|
|
|
125
124
|
//Creating the Routing key to bind the queue and exchange.
|
|
126
125
|
const routing = `${queueName}Routing`;
|
|
@@ -142,7 +141,7 @@ exports.init_rabbitmq_server = function () {
|
|
|
142
141
|
routing : routing_,
|
|
143
142
|
queueName
|
|
144
143
|
});
|
|
145
|
-
|
|
144
|
+
this.logdebug(`exchange: ${exchangeName}, queue: ${queueName} exchange : ${connExchange_} queue : ${connQueue_}` );
|
|
146
145
|
});
|
|
147
146
|
});
|
|
148
147
|
});
|
|
@@ -58,7 +58,7 @@ exports.init_amqp_connection = function () {
|
|
|
58
58
|
return conn.close();
|
|
59
59
|
}
|
|
60
60
|
ch.assertQueue(queueName,
|
|
61
|
-
{durable, autoDelete},
|
|
61
|
+
{durable, autoDelete, arguments: this.config.get("rabbitmq.ini").queue_args},
|
|
62
62
|
(err4, ok2) => {
|
|
63
63
|
if (err4) {
|
|
64
64
|
this.logerror(`Error asserting rabbitmq queue: ${err4}`);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// and passes back any errors seen on the ongoing server to the
|
|
5
5
|
// originating server.
|
|
6
6
|
|
|
7
|
-
const url = require('url');
|
|
7
|
+
const url = require('node:url');
|
|
8
8
|
|
|
9
9
|
const smtp_client_mod = require('./smtp_client');
|
|
10
10
|
|
|
@@ -28,10 +28,10 @@ exports.register = function () {
|
|
|
28
28
|
if (this.cfg.main.enable_outbound) {
|
|
29
29
|
// deliver local message via smtp forward when relaying=true
|
|
30
30
|
this.register_hook('queue_outbound', 'queue_forward');
|
|
31
|
-
|
|
32
|
-
// may specify more specific routes for outbound
|
|
33
|
-
this.register_hook('get_mx', 'get_mx');
|
|
34
31
|
}
|
|
32
|
+
|
|
33
|
+
// may specify more specific [per-domain] outbound routes
|
|
34
|
+
this.register_hook('get_mx', 'get_mx');
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
exports.load_smtp_forward_ini = function () {
|
|
@@ -230,6 +230,7 @@ exports.forward_enabled = function (conn, dom_cfg) {
|
|
|
230
230
|
|
|
231
231
|
exports.queue_forward = function (next, connection) {
|
|
232
232
|
const plugin = this;
|
|
233
|
+
if (connection.remote.closed) return
|
|
233
234
|
const txn = connection?.transaction;
|
|
234
235
|
|
|
235
236
|
const cfg = plugin.get_config(connection);
|
|
@@ -247,8 +248,7 @@ exports.queue_forward = function (next, connection) {
|
|
|
247
248
|
);
|
|
248
249
|
|
|
249
250
|
function get_rs () {
|
|
250
|
-
|
|
251
|
-
return connection.results;
|
|
251
|
+
return connection?.transaction?.results ? connection.transaction.results : connection.results
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
function dead_sender () {
|
|
@@ -79,6 +79,10 @@ exports.hook_mail = function (next, connection, params) {
|
|
|
79
79
|
exports.hook_rcpt_ok = (next, connection, recipient) => {
|
|
80
80
|
const { smtp_client } = connection.notes;
|
|
81
81
|
if (!smtp_client) return next();
|
|
82
|
+
if (smtp_client.is_dead_sender(this, connection)) {
|
|
83
|
+
delete connection.notes.smtp_client;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
82
86
|
smtp_client.next = next;
|
|
83
87
|
smtp_client.send_command('RCPT', `TO:${recipient.format(!smtp_client.smtp_utf8)}`);
|
|
84
88
|
}
|
|
@@ -86,6 +90,11 @@ exports.hook_rcpt_ok = (next, connection, recipient) => {
|
|
|
86
90
|
exports.hook_data = (next, connection) => {
|
|
87
91
|
const { smtp_client } = connection.notes;
|
|
88
92
|
if (!smtp_client) return next();
|
|
93
|
+
|
|
94
|
+
if (smtp_client.is_dead_sender(this, connection)) {
|
|
95
|
+
delete connection.notes.smtp_client;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
89
98
|
smtp_client.next = next;
|
|
90
99
|
smtp_client.send_command("DATA");
|
|
91
100
|
}
|
|
@@ -96,11 +105,11 @@ exports.hook_queue = function (next, connection) {
|
|
|
96
105
|
const { smtp_client } = connection.notes;
|
|
97
106
|
if (!smtp_client) return next();
|
|
98
107
|
|
|
99
|
-
smtp_client.next = next;
|
|
100
108
|
if (smtp_client.is_dead_sender(this, connection)) {
|
|
101
109
|
delete connection.notes.smtp_client;
|
|
102
110
|
return;
|
|
103
111
|
}
|
|
112
|
+
smtp_client.next = next;
|
|
104
113
|
smtp_client.start_data(connection.transaction.message_stream);
|
|
105
114
|
}
|
|
106
115
|
|
package/plugins/queue/test.js
CHANGED
|
@@ -40,7 +40,7 @@ exports.hook_mail = function (next, connection, params) {
|
|
|
40
40
|
|
|
41
41
|
const anti_spoof = this.config.get('host_list.anti_spoof') || false;
|
|
42
42
|
|
|
43
|
-
if (this.in_host_list(domain) || this.in_host_regex(domain)) {
|
|
43
|
+
if (this.in_host_list(domain, connection) || this.in_host_regex(domain, connection)) {
|
|
44
44
|
if (anti_spoof && !connection.relaying) {
|
|
45
45
|
txn.results.add(this, {fail: 'mail_from.anti_spoof'});
|
|
46
46
|
return next(DENY, `Mail from domain '${domain}' is not allowed from your host`);
|
|
@@ -54,16 +54,16 @@ exports.hook_mail = function (next, connection, params) {
|
|
|
54
54
|
return next();
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
exports.in_host_list = function (domain) {
|
|
58
|
-
this.logdebug(`checking ${domain} in config/host_list`);
|
|
57
|
+
exports.in_host_list = function (domain, connection) {
|
|
58
|
+
this.logdebug(connection, `checking ${domain} in config/host_list`);
|
|
59
59
|
return !!(this.host_list[domain]);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
exports.in_host_regex = function (domain) {
|
|
62
|
+
exports.in_host_regex = function (domain, connection) {
|
|
63
63
|
if (!this.host_list_regex) return false;
|
|
64
64
|
if (!this.host_list_regex.length) return false;
|
|
65
65
|
|
|
66
|
-
this.logdebug(`checking ${domain} against config/host_list_regex `);
|
|
66
|
+
this.logdebug(connection, `checking ${domain} against config/host_list_regex `);
|
|
67
67
|
|
|
68
68
|
return !!(this.hl_re.test(domain));
|
|
69
69
|
}
|
|
@@ -32,12 +32,12 @@ exports.hook_rcpt = function (next, connection, params) {
|
|
|
32
32
|
|
|
33
33
|
const domain = rcpt.host.toLowerCase();
|
|
34
34
|
|
|
35
|
-
if (this.in_host_list(domain)) {
|
|
35
|
+
if (this.in_host_list(domain, connection)) {
|
|
36
36
|
txn.results.add(this, {pass: 'rcpt_to'});
|
|
37
37
|
return next(OK);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
if (this.in_host_regex(domain)) {
|
|
40
|
+
if (this.in_host_regex(domain, connection)) {
|
|
41
41
|
txn.results.add(this, {pass: 'rcpt_to'});
|
|
42
42
|
return next(OK);
|
|
43
43
|
}
|
package/plugins/relay.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
//
|
|
3
3
|
// documentation via: haraka -h relay
|
|
4
4
|
|
|
5
|
+
const net = require('node:net');
|
|
6
|
+
|
|
5
7
|
const ipaddr = require('ipaddr.js');
|
|
6
|
-
const net = require('net');
|
|
7
8
|
|
|
8
9
|
exports.register = function () {
|
|
9
10
|
|
|
@@ -89,11 +90,9 @@ exports.acl = function (next, connection) {
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
exports.pass_relaying = (next, connection) => {
|
|
92
|
-
if (connection.relaying)
|
|
93
|
-
return next(OK);
|
|
94
|
-
}
|
|
93
|
+
if (connection.relaying) return next(OK);
|
|
95
94
|
|
|
96
|
-
|
|
95
|
+
next();
|
|
97
96
|
}
|
|
98
97
|
|
|
99
98
|
exports.is_acl_allowed = function (connection) {
|
|
@@ -172,7 +171,7 @@ exports.dest_domains = function (next, connection, params) {
|
|
|
172
171
|
}
|
|
173
172
|
|
|
174
173
|
transaction.results.add(this, {fail: 'relay_dest_domain'});
|
|
175
|
-
|
|
174
|
+
next(DENY, "Mail for that recipient is not accepted here.");
|
|
176
175
|
}
|
|
177
176
|
|
|
178
177
|
exports.force_routing = function (next, hmail, domain) {
|
|
@@ -196,7 +195,7 @@ exports.force_routing = function (next, hmail, domain) {
|
|
|
196
195
|
}
|
|
197
196
|
|
|
198
197
|
this.logdebug(this, `using ${nexthop} for: ${domain}`);
|
|
199
|
-
|
|
198
|
+
next(OK, nexthop);
|
|
200
199
|
}
|
|
201
200
|
|
|
202
201
|
exports.all = function (next, connection, params) {
|
package/plugins/reseed_rng.js
CHANGED