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
package/outbound/hmail.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const events = require('events');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const dns = require('dns');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const net = require('net');
|
|
3
|
+
const events = require('node:events');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const dns = require('node:dns');
|
|
6
|
+
const path = require('node:path');
|
|
8
7
|
|
|
9
|
-
const { Address }
|
|
8
|
+
const { Address } = require('address-rfc2821');
|
|
10
9
|
const config = require('haraka-config');
|
|
11
10
|
const constants = require('haraka-constants');
|
|
12
11
|
const DSN = require('haraka-dsn');
|
|
@@ -20,7 +19,6 @@ const plugins = require('../plugins');
|
|
|
20
19
|
|
|
21
20
|
const client_pool = require('./client_pool');
|
|
22
21
|
const _qfile = require('./qfile');
|
|
23
|
-
const mx_lookup = require('./mx_lookup');
|
|
24
22
|
const outbound = require('./index');
|
|
25
23
|
const obtls = require('./tls');
|
|
26
24
|
|
|
@@ -50,6 +48,9 @@ class HMailItem extends events.EventEmitter {
|
|
|
50
48
|
const parts = _qfile.parts(filename);
|
|
51
49
|
if (!parts) throw new Error(`Bad filename: ${filename}`);
|
|
52
50
|
|
|
51
|
+
this.cfg = obc.cfg;
|
|
52
|
+
this.obtls = obtls;
|
|
53
|
+
this.name = 'outbound';
|
|
53
54
|
this.path = filePath;
|
|
54
55
|
this.filename = filename;
|
|
55
56
|
this.next_process = parts.next_attempt;
|
|
@@ -103,7 +104,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
103
104
|
|
|
104
105
|
this._stream_bytes_from(this.path, {start: 4, end: todo_len + 3}, (err2, todo_bytes) => {
|
|
105
106
|
if (todo_bytes.length !== todo_len) {
|
|
106
|
-
const wrongLength = `Didn't find right amount of data in todo!: ${err2}`;
|
|
107
|
+
const wrongLength = `Didn't find right amount of data in todo!: ${err2} ${this.path}`;
|
|
107
108
|
this.logcrit(wrongLength);
|
|
108
109
|
fs.rename(this.path, path.join(queue_dir, `error.${this.filename}`), (err3) => {
|
|
109
110
|
if (err3) {
|
|
@@ -191,192 +192,132 @@ class HMailItem extends events.EventEmitter {
|
|
|
191
192
|
plugins.run_hooks('get_mx', this, domain);
|
|
192
193
|
}
|
|
193
194
|
|
|
194
|
-
get_mx_respond (retval, mx) {
|
|
195
|
+
async get_mx_respond (retval, mx) {
|
|
195
196
|
switch (retval) {
|
|
196
197
|
case constants.ok: {
|
|
198
|
+
this.logdebug(`MX from Plugin: ${this.todo.domain} => 0 ${JSON.stringify(mx)}`);
|
|
197
199
|
let mx_list;
|
|
198
200
|
if (Array.isArray(mx)) {
|
|
199
|
-
mx_list = mx;
|
|
200
|
-
}
|
|
201
|
-
else if (typeof mx === "object") {
|
|
202
|
-
mx_list = [mx];
|
|
201
|
+
mx_list = mx.map(m => new net_utils.HarakaMx(m));
|
|
203
202
|
}
|
|
204
203
|
else {
|
|
205
|
-
|
|
206
|
-
const matches = /^(.*?)(:(\d+))?$/.exec(mx);
|
|
207
|
-
if (!matches) {
|
|
208
|
-
throw ("get_mx returned something that doesn't match hostname or hostname:port");
|
|
209
|
-
}
|
|
210
|
-
mx_list = [{priority: 0, exchange: matches[1], port: matches[3]}];
|
|
204
|
+
mx_list = [new net_utils.HarakaMx(mx)];
|
|
211
205
|
}
|
|
212
|
-
|
|
213
|
-
return this.found_mx(null, mx_list);
|
|
206
|
+
return this.found_mx(mx_list);
|
|
214
207
|
}
|
|
215
208
|
case constants.deny:
|
|
216
209
|
this.logwarn(`get_mx plugin returned DENY: ${mx}`);
|
|
217
|
-
this.todo.rcpt_to
|
|
210
|
+
for (const rcpt of this.todo.rcpt_to) {
|
|
218
211
|
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`No MX for ${this.todo.domain}`));
|
|
219
|
-
}
|
|
212
|
+
}
|
|
220
213
|
return this.bounce(`No MX for ${this.todo.domain}`);
|
|
221
214
|
case constants.denysoft:
|
|
222
215
|
this.logwarn(`get_mx plugin returned DENYSOFT: ${mx}`);
|
|
223
|
-
this.todo.rcpt_to
|
|
216
|
+
for (const rcpt of this.todo.rcpt_to) {
|
|
224
217
|
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Temporary MX lookup error for ${this.todo.domain}`, 450));
|
|
225
|
-
}
|
|
218
|
+
}
|
|
226
219
|
return this.temp_fail(`Temporary MX lookup error for ${this.todo.domain}`);
|
|
227
220
|
}
|
|
228
221
|
|
|
229
|
-
//
|
|
230
|
-
|
|
231
|
-
this.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
found_mx (err, mxs) {
|
|
236
|
-
if (err) {
|
|
237
|
-
this.lognotice(`MX Lookup for ${this.todo.domain} failed: ${err}`);
|
|
238
|
-
if (err.code === dns.NXDOMAIN || err.code === dns.NOTFOUND) {
|
|
239
|
-
this.todo.rcpt_to.forEach(rcpt => {
|
|
240
|
-
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`No Such Domain: ${this.todo.domain}`));
|
|
241
|
-
});
|
|
242
|
-
this.bounce(`No Such Domain: ${this.todo.domain}`);
|
|
222
|
+
// none of the above return codes, drop through to DNS
|
|
223
|
+
try {
|
|
224
|
+
const exchanges = await net_utils.get_mx(this.todo.domain);
|
|
225
|
+
|
|
226
|
+
if (exchanges.length) {
|
|
227
|
+
this.found_mx(this.sort_mx(exchanges))
|
|
243
228
|
}
|
|
244
|
-
else
|
|
245
|
-
this.todo.rcpt_to
|
|
246
|
-
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Nowhere to deliver mail to for domain: ${this.todo.domain}`))
|
|
247
|
-
}
|
|
229
|
+
else {
|
|
230
|
+
for (const rcpt of this.todo.rcpt_to) {
|
|
231
|
+
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Nowhere to deliver mail to for domain: ${this.todo.domain}`))
|
|
232
|
+
}
|
|
248
233
|
this.bounce(`Nowhere to deliver mail to for domain: ${this.todo.domain}`);
|
|
249
234
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
235
|
+
} catch (e) {
|
|
236
|
+
this.get_mx_error(e);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
get_mx_error (err) {
|
|
241
|
+
this.lognotice(`MX Lookup for ${this.todo.domain} failed: ${err}`);
|
|
242
|
+
|
|
243
|
+
if (err.code === dns.NXDOMAIN || err.code === dns.NOTFOUND) {
|
|
244
|
+
for (const rcpt of this.todo.rcpt_to) {
|
|
245
|
+
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`No Such Domain: ${this.todo.domain}`));
|
|
256
246
|
}
|
|
247
|
+
this.bounce(`No Such Domain: ${this.todo.domain}`);
|
|
257
248
|
}
|
|
258
249
|
else {
|
|
259
|
-
//
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
if (mxlist.length === 1 && mxlist[0].priority === 0 && mxlist[0].exchange === '') {
|
|
263
|
-
this.todo.rcpt_to.forEach(rcpt => {
|
|
264
|
-
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Domain ${this.todo.domain} sends and receives no email (NULL MX)`));
|
|
265
|
-
});
|
|
266
|
-
return this.bounce(`Domain ${this.todo.domain} sends and receives no email (NULL MX)`);
|
|
267
|
-
}
|
|
268
|
-
// duplicate each MX for each ip address family
|
|
269
|
-
this.mxlist = [];
|
|
270
|
-
for (const mx in mxlist) {
|
|
271
|
-
// Handle UNIX sockets for LMTP
|
|
272
|
-
if (mxlist[mx].path) {
|
|
273
|
-
this.mxlist.push(mxlist[mx]);
|
|
274
|
-
}
|
|
275
|
-
else if (obc.cfg.ipv6_enabled) {
|
|
276
|
-
this.mxlist.push(
|
|
277
|
-
{ exchange: mxlist[mx].exchange, priority: mxlist[mx].priority, port: mxlist[mx].port, using_lmtp: mxlist[mx].using_lmtp, family: 'AAAA' },
|
|
278
|
-
{ exchange: mxlist[mx].exchange, priority: mxlist[mx].priority, port: mxlist[mx].port, using_lmtp: mxlist[mx].using_lmtp, family: 'A' }
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
|
-
else {
|
|
282
|
-
mxlist[mx].family = 'A';
|
|
283
|
-
this.mxlist.push(mxlist[mx]);
|
|
284
|
-
}
|
|
250
|
+
// every other error is transient
|
|
251
|
+
for (const rcpt of this.todo.rcpt_to) {
|
|
252
|
+
this.extend_rcpt_with_dsn(rcpt, DSN.addr_unspecified(`DNS lookup failure: ${this.todo.domain}`));
|
|
285
253
|
}
|
|
286
|
-
this.
|
|
254
|
+
this.temp_fail(`DNS lookup failure: ${err}`);
|
|
287
255
|
}
|
|
288
256
|
}
|
|
289
257
|
|
|
290
|
-
|
|
258
|
+
async found_mx (mxs) {
|
|
291
259
|
|
|
292
|
-
//
|
|
293
|
-
if (
|
|
294
|
-
this.todo.rcpt_to
|
|
295
|
-
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`
|
|
296
|
-
}
|
|
297
|
-
return this.
|
|
260
|
+
// support draft-delany-nullmx-02
|
|
261
|
+
if (mxs.length === 1 && mxs[0].priority === 0 && mxs[0].exchange === '') {
|
|
262
|
+
for (const rcpt of this.todo.rcpt_to) {
|
|
263
|
+
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Domain ${this.todo.domain} sends and receives no email (NULL MX)`));
|
|
264
|
+
}
|
|
265
|
+
return this.bounce(`Domain ${this.todo.domain} sends and receives no email (NULL MX)`);
|
|
298
266
|
}
|
|
299
267
|
|
|
300
|
-
|
|
301
|
-
|
|
268
|
+
// resolves the MX hostnames to IPs
|
|
269
|
+
this.mxlist = await net_utils.resolve_mx_hosts(mxs);
|
|
302
270
|
|
|
303
|
-
this.
|
|
304
|
-
|
|
305
|
-
if (net_utils.ip_in_list(obtls.cfg.force_tls_hosts, host)) {
|
|
306
|
-
this.logdebug(`Forcing TLS for host ${host}`);
|
|
307
|
-
this.force_tls = true;
|
|
308
|
-
}
|
|
309
|
-
if (net_utils.ip_in_list(obtls.cfg.force_tls_hosts, this.todo.domain)) {
|
|
310
|
-
this.logdebug(`Forcing TLS for domain ${this.todo.domain}`);
|
|
311
|
-
this.force_tls = true;
|
|
312
|
-
}
|
|
271
|
+
this.try_deliver();
|
|
272
|
+
}
|
|
313
273
|
|
|
314
|
-
|
|
315
|
-
if (net.isIP(host)) {
|
|
316
|
-
this.hostlist = [ host ];
|
|
317
|
-
return this.try_deliver_host(mx);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
274
|
+
async try_deliver () {
|
|
320
275
|
|
|
321
|
-
//
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
this.lognotice(`DNS (${mx.family}) for ${host} failed: ${err}`);
|
|
326
|
-
return this.try_deliver(); // try next MX
|
|
327
|
-
}
|
|
328
|
-
if (addresses.length === 0) {
|
|
329
|
-
// NODATA or empty host list
|
|
330
|
-
this.lognotice(`DNS (${mx.family}) for ${host} resulted in no data`);
|
|
331
|
-
return this.try_deliver(); // try next MX
|
|
276
|
+
// are any MXs left?
|
|
277
|
+
if (this.mxlist.length === 0) {
|
|
278
|
+
for (const rcpt of this.todo.rcpt_to) {
|
|
279
|
+
this.extend_rcpt_with_dsn(rcpt, DSN.addr_bad_dest_system(`Tried all MXs ${this.todo.domain}`));
|
|
332
280
|
}
|
|
333
|
-
this.
|
|
334
|
-
|
|
335
|
-
this.try_deliver_host(mx);
|
|
336
|
-
});
|
|
337
|
-
}
|
|
281
|
+
return this.temp_fail("Tried all MXs");
|
|
282
|
+
}
|
|
338
283
|
|
|
339
|
-
|
|
284
|
+
const mx = this.mxlist.shift();
|
|
340
285
|
|
|
341
|
-
if (
|
|
286
|
+
if (!obc.cfg.local_mx_ok && mx.from_dns && await net_utils.is_local_host(mx.exchange)) {
|
|
287
|
+
this.loginfo(`MX ${mx.exchange} is local, skipping since local_mx_ok=false`)
|
|
342
288
|
return this.try_deliver(); // try next MX
|
|
343
289
|
}
|
|
344
290
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
291
|
+
this.force_tls = this.get_force_tls(mx)
|
|
292
|
+
|
|
293
|
+
if (this.todo.notes.outbound_ip) {
|
|
294
|
+
this.logerror(`notes.outbound_ip is deprecated. Use get_mx.bind instead!`);
|
|
295
|
+
if (!mx.bind) mx.bind = this.todo.notes.outbound_ip;
|
|
348
296
|
}
|
|
349
297
|
|
|
350
298
|
// Allow transaction notes to set outbound IP helo
|
|
351
|
-
if (
|
|
352
|
-
|
|
353
|
-
mx.bind_helo = this.todo.notes.outbound_helo;
|
|
354
|
-
}
|
|
355
|
-
else {
|
|
356
|
-
mx.bind_helo = net_utils.get_primary_host_name();
|
|
357
|
-
}
|
|
299
|
+
if (this.todo.notes.outbound_helo) {
|
|
300
|
+
mx.bind_helo = this.todo.notes.outbound_helo;
|
|
358
301
|
}
|
|
359
302
|
|
|
360
|
-
|
|
361
|
-
const
|
|
303
|
+
const host = mx.path ? mx.path : mx.exchange;
|
|
304
|
+
const lmtp = mx.using_lmtp ? ' using LMTP' : ''
|
|
305
|
+
if (!mx.port) mx.port = mx.using_lmtp ? 24 : 25
|
|
306
|
+
const from_dns = mx.from_dns ? ' (via DNS)' : ''
|
|
362
307
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
this.logdebug(`delivering from: ${mx.bind_helo} to: ${host}:${port}${mx.using_lmtp ? " using LMTP" : ""} (${delivery_queue.length()}) (${temp_fail_queue.length()})`)
|
|
368
|
-
client_pool.get_client(port, host, mx.bind, !!mx.path, (err, socket) => {
|
|
308
|
+
this.logdebug(`deliver: ${mx.bind_helo} -> ${host}${lmtp}${from_dns} (${delivery_queue.length()}) (${temp_fail_queue.length()})`)
|
|
309
|
+
client_pool.get_client(mx, (err, socket) => {
|
|
369
310
|
if (err) {
|
|
370
311
|
if (/connection timed out|connect ECONNREFUSED/.test(err)) {
|
|
371
|
-
logger.
|
|
312
|
+
logger.notice(this, `Failed to get socket: ${err}`);
|
|
372
313
|
}
|
|
373
314
|
else {
|
|
374
|
-
logger.
|
|
315
|
+
logger.error(this, `Failed to get socket: ${err}`);
|
|
375
316
|
}
|
|
376
|
-
|
|
377
|
-
return this.
|
|
317
|
+
|
|
318
|
+
return this.try_deliver(); // try next MX
|
|
378
319
|
}
|
|
379
|
-
this.try_deliver_host_on_socket(mx, host, port, socket);
|
|
320
|
+
this.try_deliver_host_on_socket(mx, host, mx.port, socket);
|
|
380
321
|
});
|
|
381
322
|
}
|
|
382
323
|
|
|
@@ -385,10 +326,9 @@ class HMailItem extends events.EventEmitter {
|
|
|
385
326
|
let processing_mail = true;
|
|
386
327
|
let command = mx.using_lmtp ? 'connect_lmtp' : 'connect';
|
|
387
328
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
socket.removeAllListeners('end');
|
|
329
|
+
for (const l of ['error', 'timeout', 'close', 'end']) {
|
|
330
|
+
socket.removeAllListeners(l);
|
|
331
|
+
}
|
|
392
332
|
|
|
393
333
|
socket.once('timeout', function () {
|
|
394
334
|
socket.emit('error', `socket timeout waiting on ${command}`);
|
|
@@ -399,11 +339,10 @@ class HMailItem extends events.EventEmitter {
|
|
|
399
339
|
|
|
400
340
|
self.logerror(`Ongoing connection failed to ${host}:${port} : ${err}`);
|
|
401
341
|
processing_mail = false;
|
|
402
|
-
client_pool.release_client(socket,
|
|
342
|
+
client_pool.release_client(socket, mx);
|
|
403
343
|
if (err.source === 'tls') // exception thrown from tls_socket during tls upgrade
|
|
404
|
-
return obtls.mark_tls_nogo(host, () => { return self.
|
|
405
|
-
// try the next MX
|
|
406
|
-
self.try_deliver_host(mx);
|
|
344
|
+
return obtls.mark_tls_nogo(host, () => { return self.try_deliver(); });
|
|
345
|
+
self.try_deliver(); // try the next MX
|
|
407
346
|
})
|
|
408
347
|
|
|
409
348
|
socket.once('close', () => {
|
|
@@ -411,18 +350,14 @@ class HMailItem extends events.EventEmitter {
|
|
|
411
350
|
|
|
412
351
|
self.logerror(`Remote end ${host}:${port} closed connection while we were processing mail. Trying next MX.`);
|
|
413
352
|
processing_mail = false;
|
|
414
|
-
client_pool.release_client(socket,
|
|
415
|
-
self.
|
|
353
|
+
client_pool.release_client(socket, mx);
|
|
354
|
+
self.try_deliver();
|
|
416
355
|
});
|
|
417
356
|
|
|
418
|
-
let fin_sent = false;
|
|
419
357
|
socket.once('end', () => {
|
|
420
|
-
fin_sent = true;
|
|
421
358
|
socket.writable = false;
|
|
422
|
-
if (!processing_mail)
|
|
423
|
-
|
|
424
|
-
}
|
|
425
|
-
});
|
|
359
|
+
if (!processing_mail) client_pool.release_client(socket, mx);
|
|
360
|
+
})
|
|
426
361
|
|
|
427
362
|
let response = [];
|
|
428
363
|
|
|
@@ -450,16 +385,16 @@ class HMailItem extends events.EventEmitter {
|
|
|
450
385
|
self.logerror("Socket writability went away");
|
|
451
386
|
if (processing_mail) {
|
|
452
387
|
processing_mail = false;
|
|
453
|
-
client_pool.release_client(socket,
|
|
454
|
-
return self.
|
|
388
|
+
client_pool.release_client(socket, mx);
|
|
389
|
+
return self.try_deliver();
|
|
455
390
|
}
|
|
456
391
|
return;
|
|
457
392
|
}
|
|
458
|
-
if (self.force_tls &&
|
|
393
|
+
if (self.force_tls && !['EHLO', 'LHLO', 'STARTTLS'].includes(cmd.toUpperCase()) && !socket.isSecure()) {
|
|
459
394
|
// For safety against programming mistakes
|
|
460
395
|
self.logerror("Blocking attempt to send unencrypted data to forced TLS socket. This message indicates a programming error in the software.");
|
|
461
396
|
processing_mail = false;
|
|
462
|
-
client_pool.release_client(socket,
|
|
397
|
+
client_pool.release_client(socket, mx);
|
|
463
398
|
return;
|
|
464
399
|
}
|
|
465
400
|
|
|
@@ -475,7 +410,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
475
410
|
// We may want to release client here - but I want to get this
|
|
476
411
|
// line of code in before we do that so we might see some logging
|
|
477
412
|
// in case of errors.
|
|
478
|
-
// client_pool.release_client(socket,
|
|
413
|
+
// client_pool.release_client(socket, mx);
|
|
479
414
|
}
|
|
480
415
|
});
|
|
481
416
|
command = cmd.toLowerCase();
|
|
@@ -512,14 +447,26 @@ class HMailItem extends events.EventEmitter {
|
|
|
512
447
|
}
|
|
513
448
|
}
|
|
514
449
|
|
|
450
|
+
function get_reverse_path_with_params () {
|
|
451
|
+
const rp = self.todo.mail_from.format(!smtp_properties.smtp_utf8)
|
|
452
|
+
let rp_params = ''
|
|
453
|
+
if (smtp_properties.smtp_utf8 && has_non_ascii(rp)) rp_params += ' SMTPUTF8'
|
|
454
|
+
return `FROM:${rp}${rp_params}`
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function has_non_ascii (string) {
|
|
458
|
+
return [...string].some(char => char.charCodeAt(0) > 127)
|
|
459
|
+
}
|
|
460
|
+
|
|
515
461
|
function auth_and_mail_phase () {
|
|
516
462
|
if (!authenticated && (mx.auth_user && mx.auth_pass)) {
|
|
517
463
|
// We have AUTH credentials to send for this domain
|
|
464
|
+
|
|
518
465
|
if (!(Array.isArray(smtp_properties.auth) && smtp_properties.auth.length)) {
|
|
519
466
|
// AUTH not offered
|
|
520
467
|
self.logwarn(`AUTH configured for domain ${self.todo.domain} but host ${host} did not advertise AUTH capability`);
|
|
521
468
|
// Try and send the message without authentication
|
|
522
|
-
return send_command('MAIL',
|
|
469
|
+
return send_command('MAIL', get_reverse_path_with_params());
|
|
523
470
|
}
|
|
524
471
|
|
|
525
472
|
if (!mx.auth_type) {
|
|
@@ -543,7 +490,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
543
490
|
// No compatible authentication types offered by the server
|
|
544
491
|
self.logwarn(`AUTH configured for domain ${self.todo.domain} but host ${host}did not offer any compatible types${(mx.auth_type) ? ` (requested: ${mx.auth_type})` : ''} (offered: ${smtp_properties.auth.join(',')})`);
|
|
545
492
|
// Proceed without authentication
|
|
546
|
-
return send_command('MAIL',
|
|
493
|
+
return send_command('MAIL', get_reverse_path_with_params());
|
|
547
494
|
}
|
|
548
495
|
|
|
549
496
|
switch (mx.auth_type.toUpperCase()) {
|
|
@@ -558,12 +505,12 @@ class HMailItem extends events.EventEmitter {
|
|
|
558
505
|
default:
|
|
559
506
|
// Unsupported AUTH type
|
|
560
507
|
self.logwarn(`Unsupported authentication type ${mx.auth_type.toUpperCase()} requested for domain ${self.todo.domain}`);
|
|
561
|
-
return send_command('MAIL',
|
|
508
|
+
return send_command('MAIL', get_reverse_path_with_params());
|
|
562
509
|
}
|
|
563
510
|
}
|
|
564
511
|
|
|
565
|
-
return send_command('MAIL',
|
|
566
|
-
}
|
|
512
|
+
return send_command('MAIL', get_reverse_path_with_params());
|
|
513
|
+
}
|
|
567
514
|
|
|
568
515
|
// IMPORTANT: do STARTTLS before AUTH for security
|
|
569
516
|
function process_ehlo_data () {
|
|
@@ -579,7 +526,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
579
526
|
processing_mail = false;
|
|
580
527
|
socket.write("QUIT\r\n", "utf8"); // courtesy
|
|
581
528
|
socket.end();
|
|
582
|
-
client_pool.release_client(socket,
|
|
529
|
+
client_pool.release_client(socket, mx);
|
|
583
530
|
return self.temp_fail(`No TLS available but required by configuration.`);
|
|
584
531
|
}
|
|
585
532
|
|
|
@@ -591,7 +538,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
591
538
|
});
|
|
592
539
|
return send_command('STARTTLS');
|
|
593
540
|
}
|
|
594
|
-
if (!obc.cfg.enable_tls) return auth_and_mail_phase();
|
|
541
|
+
if (!obc.cfg.enable_tls) return auth_and_mail_phase(); // TLS not enabled
|
|
595
542
|
if (!smtp_properties.tls) return auth_and_mail_phase(); // TLS not advertised by remote
|
|
596
543
|
|
|
597
544
|
if (obtls.cfg === undefined) {
|
|
@@ -623,7 +570,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
623
570
|
return auth_and_mail_phase();
|
|
624
571
|
}
|
|
625
572
|
);
|
|
626
|
-
}
|
|
573
|
+
}
|
|
627
574
|
|
|
628
575
|
let fp_called = false;
|
|
629
576
|
|
|
@@ -673,7 +620,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
673
620
|
self.logerror(`Unrecognized response from upstream server: ${line}`);
|
|
674
621
|
processing_mail = false;
|
|
675
622
|
// Release back to the pool and instruct it to terminate this connection
|
|
676
|
-
client_pool.release_client(socket,
|
|
623
|
+
client_pool.release_client(socket, mx);
|
|
677
624
|
self.todo.rcpt_to.forEach(rcpt => {
|
|
678
625
|
self.extend_rcpt_with_dsn(rcpt, DSN.proto_invalid_command(`Unrecognized response from upstream server: ${line}`));
|
|
679
626
|
});
|
|
@@ -710,7 +657,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
710
657
|
// The response is our challenge
|
|
711
658
|
return send_command(cram_md5_response(mx.auth_user, mx.auth_pass, resp));
|
|
712
659
|
default:
|
|
713
|
-
|
|
660
|
+
// This shouldn't happen...
|
|
714
661
|
}
|
|
715
662
|
}
|
|
716
663
|
// Error
|
|
@@ -768,8 +715,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
768
715
|
else {
|
|
769
716
|
reason = response.join(' ');
|
|
770
717
|
self.lognotice(`Error - but not processing mail: ${code} ${((extc) ? `${extc} ` : '')}${reason}`);
|
|
771
|
-
|
|
772
|
-
return client_pool.release_client(socket, port, host, mx.bind, true);
|
|
718
|
+
return client_pool.release_client(socket, mx);
|
|
773
719
|
}
|
|
774
720
|
}
|
|
775
721
|
else if (code.match(/^5/)) {
|
|
@@ -780,7 +726,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
780
726
|
}
|
|
781
727
|
if (command === 'rset') {
|
|
782
728
|
// Broken server doesn't accept RSET, terminate the connection
|
|
783
|
-
return client_pool.release_client(socket,
|
|
729
|
+
return client_pool.release_client(socket, mx);
|
|
784
730
|
}
|
|
785
731
|
reason = `${code} ${(extc) ? `${extc} ` : ''}${response.join(' ')}`;
|
|
786
732
|
if (/^rcpt/.test(command) || command === 'dot_lmtp') {
|
|
@@ -856,7 +802,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
856
802
|
processing_mail = false;
|
|
857
803
|
socket.end();
|
|
858
804
|
self.temp_fail('Host failed TLS verification required by configuration.');
|
|
859
|
-
client_pool.release_client(socket,
|
|
805
|
+
client_pool.release_client(socket, mx);
|
|
860
806
|
}
|
|
861
807
|
});
|
|
862
808
|
break;
|
|
@@ -864,10 +810,10 @@ class HMailItem extends events.EventEmitter {
|
|
|
864
810
|
case 'auth':
|
|
865
811
|
authenticating = false;
|
|
866
812
|
authenticated = true;
|
|
867
|
-
send_command('MAIL',
|
|
813
|
+
send_command('MAIL', get_reverse_path_with_params());
|
|
868
814
|
break;
|
|
869
815
|
case 'helo':
|
|
870
|
-
send_command('MAIL',
|
|
816
|
+
send_command('MAIL', get_reverse_path_with_params());
|
|
871
817
|
break;
|
|
872
818
|
case 'mail':
|
|
873
819
|
last_recip = recipients[recip_index];
|
|
@@ -917,7 +863,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
917
863
|
break;
|
|
918
864
|
case 'quit':
|
|
919
865
|
case 'rset':
|
|
920
|
-
client_pool.release_client(socket,
|
|
866
|
+
client_pool.release_client(socket, mx);
|
|
921
867
|
break;
|
|
922
868
|
default:
|
|
923
869
|
// should never get here - means we did something
|
|
@@ -927,10 +873,10 @@ class HMailItem extends events.EventEmitter {
|
|
|
927
873
|
});
|
|
928
874
|
|
|
929
875
|
if (socket.__fromPool) {
|
|
930
|
-
logger.
|
|
876
|
+
logger.debug(this, 'got socket, trying to deliver');
|
|
931
877
|
secured = socket.isEncrypted();
|
|
932
|
-
logger.
|
|
933
|
-
send_command('MAIL',
|
|
878
|
+
logger.debug(this, `got ${secured ? 'TLS ' : '' }socket, trying to deliver`);
|
|
879
|
+
send_command('MAIL', get_reverse_path_with_params());
|
|
934
880
|
}
|
|
935
881
|
}
|
|
936
882
|
|
|
@@ -1062,7 +1008,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
1062
1008
|
"\r": '#10',
|
|
1063
1009
|
"\n": '#13'
|
|
1064
1010
|
};
|
|
1065
|
-
const escape_pattern = new RegExp(`[${Object.keys(escaped_chars).join()}]`, 'g');
|
|
1011
|
+
const escape_pattern = new RegExp(`[${Object.keys(escaped_chars).join('')}]`, 'g');
|
|
1066
1012
|
|
|
1067
1013
|
bounce_msg_html_.forEach(line => {
|
|
1068
1014
|
line = line.replace(/\{(\w+)\}/g, (i, word) => {
|
|
@@ -1334,7 +1280,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
1334
1280
|
}
|
|
1335
1281
|
|
|
1336
1282
|
temp_fail (err, extra) {
|
|
1337
|
-
logger.
|
|
1283
|
+
logger.debug(this, `Temp fail for: ${err}`);
|
|
1338
1284
|
this.num_failures++;
|
|
1339
1285
|
|
|
1340
1286
|
// Test for max failures which is configurable.
|
|
@@ -1379,7 +1325,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
1379
1325
|
});
|
|
1380
1326
|
}
|
|
1381
1327
|
|
|
1382
|
-
// The following handler
|
|
1328
|
+
// The following handler impacts outgoing mail. It removes the queue file.
|
|
1383
1329
|
delivered_respond (retval, msg) {
|
|
1384
1330
|
if (retval !== constants.cont && retval !== constants.ok) {
|
|
1385
1331
|
this.logwarn(
|
|
@@ -1390,6 +1336,51 @@ class HMailItem extends events.EventEmitter {
|
|
|
1390
1336
|
this.discard();
|
|
1391
1337
|
}
|
|
1392
1338
|
|
|
1339
|
+
get_force_tls (mx) {
|
|
1340
|
+
if (!mx.exchange) return false
|
|
1341
|
+
if (!obtls.cfg.force_tls_hosts) return false
|
|
1342
|
+
|
|
1343
|
+
if (net_utils.ip_in_list(obtls.cfg.force_tls_hosts, mx.exchange)) {
|
|
1344
|
+
this.logdebug(`Forcing TLS for host ${mx.exchange}`);
|
|
1345
|
+
return true;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
if (mx.from_dns) {
|
|
1349
|
+
// the MX was looked up in DNS and already resolved to IP(s).
|
|
1350
|
+
// This checks the hostname.
|
|
1351
|
+
if (net_utils.ip_in_list(obtls.cfg.force_tls_hosts, mx.from_dns)) {
|
|
1352
|
+
this.logdebug(`Forcing TLS for host ${mx.from_dns}`);
|
|
1353
|
+
return true;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
if (net_utils.ip_in_list(obtls.cfg.force_tls_hosts, this.todo.domain)) {
|
|
1358
|
+
this.logdebug(`Forcing TLS for domain ${this.todo.domain}`);
|
|
1359
|
+
return true;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
return false
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
sort_mx (mx_list) {
|
|
1366
|
+
// MXs must be sorted by priority.
|
|
1367
|
+
const sorted = mx_list.sort((a,b) => a.priority - b.priority);
|
|
1368
|
+
|
|
1369
|
+
// Matched priorities must be randomly shuffled.
|
|
1370
|
+
// This isn't a very good shuffle but it'll do for now.
|
|
1371
|
+
for (let i=0,l=sorted.length-1; i<l; i++) {
|
|
1372
|
+
if (sorted[i].priority === sorted[i+1].priority) {
|
|
1373
|
+
if (Math.round(Math.random())) { // 0 or 1
|
|
1374
|
+
const j = sorted[i];
|
|
1375
|
+
sorted[i] = sorted[i+1];
|
|
1376
|
+
sorted[i+1] = j;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
return sorted;
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1393
1384
|
split_to_new_recipients (recipients, response, cb) {
|
|
1394
1385
|
const hmail = this;
|
|
1395
1386
|
if (recipients.length === hmail.todo.rcpt_to.length) {
|
|
@@ -1401,7 +1392,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
1401
1392
|
const tmp_path = path.join(queue_dir, `${_qfile.platformDOT}${fname}`);
|
|
1402
1393
|
const ws = new FsyncWriteStream(tmp_path, { flags: constants.WRITE_EXCL });
|
|
1403
1394
|
function err_handler (err, location) {
|
|
1404
|
-
logger.
|
|
1395
|
+
logger.error(this, `Error while splitting to new recipients (${location}): ${err}`);
|
|
1405
1396
|
hmail.todo.rcpt_to.forEach(rcpt => {
|
|
1406
1397
|
hmail.extend_rcpt_with_dsn(rcpt, DSN.sys_unspecified(`Error splitting to new recipients: ${err}`));
|
|
1407
1398
|
});
|
|
@@ -1439,7 +1430,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
1439
1430
|
}
|
|
1440
1431
|
|
|
1441
1432
|
ws.on('error', err => {
|
|
1442
|
-
logger.
|
|
1433
|
+
logger.error(this, `Unable to write queue file (${fname}): ${err}`);
|
|
1443
1434
|
ws.destroy();
|
|
1444
1435
|
hmail.todo.rcpt_to.forEach(rcpt => {
|
|
1445
1436
|
hmail.extend_rcpt_with_dsn(rcpt, DSN.sys_unspecified(`Error re-queueing some recipients: ${err}`));
|
|
@@ -1456,38 +1447,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
1456
1447
|
module.exports = HMailItem;
|
|
1457
1448
|
module.exports.obtls = obtls;
|
|
1458
1449
|
|
|
1459
|
-
|
|
1460
|
-
for (const key in logger) {
|
|
1461
|
-
if (!/^log\w/.test(key)) continue;
|
|
1462
|
-
HMailItem.prototype[key] = (function (level) {
|
|
1463
|
-
return function () {
|
|
1464
|
-
// pass the HMailItem instance to logger
|
|
1465
|
-
const args = [ this ];
|
|
1466
|
-
for (let i=0, l=arguments.length; i<l; i++) {
|
|
1467
|
-
args.push(arguments[i]);
|
|
1468
|
-
}
|
|
1469
|
-
logger[level].apply(logger, args);
|
|
1470
|
-
};
|
|
1471
|
-
})(key);
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
// MXs must be sorted by priority order, but matched priorities must be
|
|
1475
|
-
// randomly shuffled in that list, so this is a bit complex.
|
|
1476
|
-
function sort_mx (mx_list) {
|
|
1477
|
-
const sorted = mx_list.sort((a,b) => a.priority - b.priority);
|
|
1478
|
-
|
|
1479
|
-
// This isn't a very good shuffle but it'll do for now.
|
|
1480
|
-
for (let i=0,l=sorted.length-1; i<l; i++) {
|
|
1481
|
-
if (sorted[i].priority === sorted[i+1].priority) {
|
|
1482
|
-
if (Math.round(Math.random())) { // 0 or 1
|
|
1483
|
-
const j = sorted[i];
|
|
1484
|
-
sorted[i] = sorted[i+1];
|
|
1485
|
-
sorted[i+1] = j;
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
return sorted;
|
|
1490
|
-
}
|
|
1450
|
+
logger.add_log_methods(HMailItem)
|
|
1491
1451
|
|
|
1492
1452
|
const smtp_regexp = /^([2345]\d\d)([ -])#?(?:(\d\.\d\.\d)\s)?(.*)/;
|
|
1493
1453
|
|