Haraka 3.1.1 → 3.1.2
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/.prettierignore +4 -0
- package/CONTRIBUTORS.md +5 -5
- package/Changes.md +62 -50
- package/Plugins.md +3 -1
- package/README.md +1 -1
- package/bin/haraka +475 -479
- package/config/outbound.ini +3 -0
- package/connection.js +1072 -1108
- package/docs/Connection.md +29 -30
- package/docs/CoreConfig.md +38 -39
- package/docs/CustomReturnCodes.md +0 -1
- package/docs/HAProxy.md +2 -2
- package/docs/Header.md +1 -1
- package/docs/Logging.md +29 -5
- package/docs/Outbound.md +93 -78
- package/docs/Plugins.md +103 -108
- package/docs/Transaction.md +49 -51
- package/docs/Tutorial.md +127 -143
- package/docs/deprecated/access.md +0 -1
- package/docs/deprecated/backscatterer.md +2 -3
- package/docs/deprecated/connect.rdns_access.md +18 -27
- package/docs/deprecated/data.headers.md +0 -1
- package/docs/deprecated/data.nomsgid.md +1 -2
- package/docs/deprecated/data.noreceived.md +1 -2
- package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
- package/docs/deprecated/dkim_sign.md +13 -17
- package/docs/deprecated/dkim_verify.md +9 -17
- package/docs/deprecated/dnsbl.md +36 -38
- package/docs/deprecated/dnswl.md +41 -43
- package/docs/deprecated/lookup_rdns.strict.md +21 -34
- package/docs/deprecated/mail_from.access.md +17 -25
- package/docs/deprecated/mail_from.blocklist.md +9 -12
- package/docs/deprecated/mail_from.nobounces.md +1 -2
- package/docs/deprecated/rcpt_to.access.md +20 -27
- package/docs/deprecated/rcpt_to.blocklist.md +10 -13
- package/docs/deprecated/rcpt_to.routes.md +0 -1
- package/docs/deprecated/rdns.regexp.md +13 -15
- package/docs/plugins/aliases.md +89 -89
- package/docs/plugins/auth/auth_bridge.md +5 -7
- package/docs/plugins/auth/auth_ldap.md +11 -14
- package/docs/plugins/auth/auth_proxy.md +10 -12
- package/docs/plugins/auth/auth_vpopmaild.md +5 -6
- package/docs/plugins/auth/flat_file.md +4 -4
- package/docs/plugins/block_me.md +3 -3
- package/docs/plugins/data.signatures.md +1 -2
- package/docs/plugins/delay_deny.md +3 -4
- package/docs/plugins/max_unrecognized_commands.md +4 -4
- package/docs/plugins/prevent_credential_leaks.md +6 -6
- package/docs/plugins/process_title.md +18 -18
- package/docs/plugins/queue/deliver.md +2 -3
- package/docs/plugins/queue/discard.md +4 -4
- package/docs/plugins/queue/lmtp.md +1 -3
- package/docs/plugins/queue/qmail-queue.md +7 -9
- package/docs/plugins/queue/quarantine.md +16 -21
- package/docs/plugins/queue/rabbitmq.md +8 -11
- package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
- package/docs/plugins/queue/smtp_bridge.md +7 -10
- package/docs/plugins/queue/smtp_forward.md +42 -34
- package/docs/plugins/queue/smtp_proxy.md +30 -29
- package/docs/plugins/queue/test.md +1 -3
- package/docs/plugins/rcpt_to.in_host_list.md +6 -6
- package/docs/plugins/rcpt_to.max_count.md +1 -1
- package/docs/plugins/record_envelope_addresses.md +3 -3
- package/docs/plugins/reseed_rng.md +6 -6
- package/docs/plugins/status.md +9 -8
- package/docs/plugins/tarpit.md +7 -11
- package/docs/plugins/tls.md +12 -17
- package/docs/plugins/toobusy.md +4 -4
- package/docs/plugins/xclient.md +3 -3
- package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
- package/docs/tutorials/SettingUpOutbound.md +6 -9
- package/endpoint.js +35 -38
- package/eslint.config.mjs +22 -19
- package/haraka.js +42 -47
- package/host_pool.js +75 -79
- package/http/html/404.html +45 -49
- package/http/html/index.html +39 -28
- package/http/package.json +2 -4
- package/line_socket.js +27 -28
- package/logger.js +182 -201
- package/outbound/client_pool.js +33 -33
- package/outbound/config.js +64 -59
- package/outbound/fsync_writestream.js +24 -25
- package/outbound/hmail.js +888 -835
- package/outbound/index.js +194 -187
- package/outbound/qfile.js +49 -52
- package/outbound/queue.js +197 -190
- package/outbound/timer_queue.js +41 -43
- package/outbound/tls.js +68 -61
- package/outbound/todo.js +11 -11
- package/package.json +32 -32
- package/plugins/.eslintrc.yaml +0 -1
- package/plugins/auth/auth_base.js +123 -127
- package/plugins/auth/auth_bridge.js +7 -7
- package/plugins/auth/auth_proxy.js +121 -126
- package/plugins/auth/auth_vpopmaild.js +84 -85
- package/plugins/auth/flat_file.js +18 -17
- package/plugins/block_me.js +31 -31
- package/plugins/data.signatures.js +13 -13
- package/plugins/delay_deny.js +65 -61
- package/plugins/prevent_credential_leaks.js +23 -23
- package/plugins/process_title.js +125 -128
- package/plugins/profile.js +5 -5
- package/plugins/queue/deliver.js +3 -3
- package/plugins/queue/discard.js +13 -14
- package/plugins/queue/lmtp.js +16 -17
- package/plugins/queue/qmail-queue.js +54 -55
- package/plugins/queue/quarantine.js +68 -70
- package/plugins/queue/rabbitmq.js +80 -87
- package/plugins/queue/rabbitmq_amqplib.js +75 -54
- package/plugins/queue/smtp_bridge.js +16 -16
- package/plugins/queue/smtp_forward.js +175 -179
- package/plugins/queue/smtp_proxy.js +69 -71
- package/plugins/queue/test.js +9 -9
- package/plugins/rcpt_to.host_list_base.js +30 -34
- package/plugins/rcpt_to.in_host_list.js +19 -19
- package/plugins/record_envelope_addresses.js +4 -4
- package/plugins/reseed_rng.js +4 -4
- package/plugins/status.js +90 -97
- package/plugins/tarpit.js +25 -14
- package/plugins/tls.js +68 -68
- package/plugins/toobusy.js +21 -23
- package/plugins/xclient.js +51 -53
- package/plugins.js +276 -293
- package/rfc1869.js +30 -35
- package/server.js +308 -299
- package/smtp_client.js +244 -228
- package/test/.eslintrc.yaml +0 -1
- package/test/connection.js +127 -134
- package/test/endpoint.js +53 -47
- package/test/fixtures/line_socket.js +12 -12
- package/test/fixtures/util_hmailitem.js +89 -85
- package/test/host_pool.js +90 -92
- package/test/installation/plugins/base_plugin.js +2 -2
- package/test/installation/plugins/folder_plugin/index.js +2 -3
- package/test/installation/plugins/inherits.js +3 -3
- package/test/installation/plugins/load_first.js +2 -3
- package/test/installation/plugins/plugin.js +1 -3
- package/test/installation/plugins/tls.js +2 -4
- package/test/logger.js +135 -116
- package/test/outbound/hmail.js +49 -35
- package/test/outbound/index.js +118 -101
- package/test/outbound/qfile.js +51 -53
- package/test/outbound_bounce_net_errors.js +84 -69
- package/test/outbound_bounce_rfc3464.js +235 -165
- package/test/plugins/auth/auth_base.js +420 -279
- package/test/plugins/auth/auth_vpopmaild.js +38 -39
- package/test/plugins/queue/smtp_forward.js +126 -104
- package/test/plugins/rcpt_to.host_list_base.js +85 -67
- package/test/plugins/rcpt_to.in_host_list.js +159 -112
- package/test/plugins/status.js +71 -64
- package/test/plugins/tls.js +37 -34
- package/test/plugins.js +97 -92
- package/test/rfc1869.js +19 -26
- package/test/server.js +293 -272
- package/test/smtp_client.js +180 -176
- package/test/tls_socket.js +62 -66
- package/test/transaction.js +159 -160
- package/tls_socket.js +331 -333
- package/transaction.js +129 -137
package/outbound/config.js
CHANGED
|
@@ -1,46 +1,51 @@
|
|
|
1
|
-
'use strict'
|
|
1
|
+
'use strict'
|
|
2
2
|
|
|
3
|
-
const config = require('haraka-config')
|
|
4
|
-
const logger = require('../logger')
|
|
3
|
+
const config = require('haraka-config')
|
|
4
|
+
const logger = require('../logger')
|
|
5
5
|
|
|
6
6
|
exports.name = 'outbound/config'
|
|
7
7
|
|
|
8
|
-
function load_config
|
|
9
|
-
const cfg = exports.cfg = config.get(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
'-always_split',
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
function load_config() {
|
|
9
|
+
const cfg = (exports.cfg = config.get(
|
|
10
|
+
'outbound.ini',
|
|
11
|
+
{
|
|
12
|
+
booleans: ['-disabled', '-always_split', '+enable_tls', '-local_mx_ok'],
|
|
13
|
+
},
|
|
14
|
+
() => {
|
|
15
|
+
load_config()
|
|
16
|
+
},
|
|
17
|
+
).main)
|
|
18
|
+
|
|
19
|
+
if (!cfg.inet_prefer) cfg.inet_prefer = 'default'
|
|
20
|
+
if (!cfg.inet_prefer.match(/^(v4|v6|default)$/)) {
|
|
21
|
+
logger.warn(exports, `inet_prefer is set to an invalid value: ${cfg.inet_prefer}`)
|
|
22
|
+
cfg.inet_prefer = 'default'
|
|
23
|
+
}
|
|
19
24
|
|
|
20
25
|
// legacy config file support. Remove in Haraka 4.0
|
|
21
26
|
if (!cfg.disabled && config.get('outbound.disabled')) {
|
|
22
|
-
cfg.disabled = true
|
|
27
|
+
cfg.disabled = true
|
|
23
28
|
}
|
|
24
29
|
if (!cfg.enable_tls && config.get('outbound.enable_tls')) {
|
|
25
|
-
cfg.enable_tls = true
|
|
30
|
+
cfg.enable_tls = true
|
|
26
31
|
}
|
|
27
32
|
if (!cfg.temp_fail_intervals) {
|
|
28
|
-
cfg.temp_fail_intervals = config.get('outbound.temp_fail_intervals')
|
|
33
|
+
cfg.temp_fail_intervals = config.get('outbound.temp_fail_intervals')
|
|
29
34
|
}
|
|
30
35
|
if (!cfg.maxTempFailures) {
|
|
31
|
-
cfg.maxTempFailures = config.get('outbound.maxTempFailures') || 13
|
|
36
|
+
cfg.maxTempFailures = config.get('outbound.maxTempFailures') || 13
|
|
32
37
|
}
|
|
33
38
|
if (!cfg.concurrency_max) {
|
|
34
|
-
cfg.concurrency_max = config.get('outbound.concurrency_max') || 10000
|
|
39
|
+
cfg.concurrency_max = config.get('outbound.concurrency_max') || 10000
|
|
35
40
|
}
|
|
36
41
|
if (!cfg.connect_timeout) {
|
|
37
|
-
cfg.connect_timeout = 30
|
|
42
|
+
cfg.connect_timeout = 30
|
|
38
43
|
}
|
|
39
44
|
if (!cfg.received_header) {
|
|
40
|
-
cfg.received_header = config.get('outbound.received_header') || 'Haraka outbound'
|
|
45
|
+
cfg.received_header = config.get('outbound.received_header') || 'Haraka outbound'
|
|
41
46
|
}
|
|
42
47
|
|
|
43
|
-
exports.set_temp_fail_intervals()
|
|
48
|
+
exports.set_temp_fail_intervals()
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
exports.set_temp_fail_intervals = function () {
|
|
@@ -50,80 +55,80 @@ exports.set_temp_fail_intervals = function () {
|
|
|
50
55
|
// it with the equivalent times of maxTempFailures using the original 2^N formula
|
|
51
56
|
// 3) the word "none" can be specified if you do not want to retry a temp failure,
|
|
52
57
|
// equivalent behavior of specifying maxTempFailures=1
|
|
53
|
-
const { cfg } = this
|
|
58
|
+
const { cfg } = this
|
|
54
59
|
|
|
55
60
|
// Fallback function to create an array of the original retry times
|
|
56
|
-
function set_old_defaults
|
|
57
|
-
cfg.temp_fail_intervals = []
|
|
58
|
-
for (let i=1; i<cfg.maxTempFailures; i++) {
|
|
59
|
-
cfg.temp_fail_intervals.push(2 ** (i + 5))
|
|
61
|
+
function set_old_defaults() {
|
|
62
|
+
cfg.temp_fail_intervals = []
|
|
63
|
+
for (let i = 1; i < cfg.maxTempFailures; i++) {
|
|
64
|
+
cfg.temp_fail_intervals.push(2 ** (i + 5))
|
|
60
65
|
}
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
// Helpful error function in case of parsing failure
|
|
64
|
-
function error
|
|
65
|
-
logger.error(exports, `temp_fail_intervals syntax error parsing element ${i}: ${msg}`)
|
|
66
|
-
logger.warn(exports, 'Setting outbound temp_fail_intervals to old defaults')
|
|
67
|
-
set_old_defaults()
|
|
69
|
+
function error(i, msg) {
|
|
70
|
+
logger.error(exports, `temp_fail_intervals syntax error parsing element ${i}: ${msg}`)
|
|
71
|
+
logger.warn(exports, 'Setting outbound temp_fail_intervals to old defaults')
|
|
72
|
+
set_old_defaults()
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
// If the new value isn't specified, then create the old defaults
|
|
71
76
|
if (!cfg.temp_fail_intervals) {
|
|
72
|
-
return set_old_defaults()
|
|
77
|
+
return set_old_defaults()
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
// If here then turn the text input into an expanded array of intervals (in seconds)
|
|
76
81
|
// i.e, turn "1m,5m*2,1h*3" into [60,300,300,3600,3600,3600]
|
|
77
82
|
// Parse manually to do better syntax checking and provide better failure messages
|
|
78
|
-
const times = []
|
|
79
|
-
let input = cfg.temp_fail_intervals.replace(/\s+/g, '').toLowerCase()
|
|
80
|
-
if (input.length === 0) return error(0, 'nothing specified')
|
|
83
|
+
const times = []
|
|
84
|
+
let input = cfg.temp_fail_intervals.replace(/\s+/g, '').toLowerCase()
|
|
85
|
+
if (input.length === 0) return error(0, 'nothing specified')
|
|
81
86
|
if (input === 'none') {
|
|
82
|
-
cfg.temp_fail_intervals = []
|
|
83
|
-
return
|
|
87
|
+
cfg.temp_fail_intervals = []
|
|
88
|
+
return
|
|
84
89
|
}
|
|
85
90
|
input = input.split(',')
|
|
86
91
|
|
|
87
|
-
for (let i=0; i<input.length; i++) {
|
|
88
|
-
const delay = input[i].split('*')
|
|
89
|
-
if (delay.length === 1) delay.push(1)
|
|
90
|
-
else if (delay.length === 2) delay[1] = Number(delay[1])
|
|
91
|
-
else return error(i, 'too many *')
|
|
92
|
-
if (!Number.isInteger(delay[1])) return error(i, 'multiplier is not an integer')
|
|
92
|
+
for (let i = 0; i < input.length; i++) {
|
|
93
|
+
const delay = input[i].split('*')
|
|
94
|
+
if (delay.length === 1) delay.push(1)
|
|
95
|
+
else if (delay.length === 2) delay[1] = Number(delay[1])
|
|
96
|
+
else return error(i, 'too many *')
|
|
97
|
+
if (!Number.isInteger(delay[1])) return error(i, 'multiplier is not an integer')
|
|
93
98
|
|
|
94
|
-
if (delay[0].length < 2) error(i, 'invalid time span')
|
|
95
|
-
const symbol = delay[0].charAt(delay[0].length - 1)
|
|
96
|
-
let num = Number(delay[0].slice(0, -1))
|
|
97
|
-
if (isNaN(num)) return error(i, 'invalid number or symbol')
|
|
99
|
+
if (delay[0].length < 2) error(i, 'invalid time span')
|
|
100
|
+
const symbol = delay[0].charAt(delay[0].length - 1)
|
|
101
|
+
let num = Number(delay[0].slice(0, -1))
|
|
102
|
+
if (isNaN(num)) return error(i, 'invalid number or symbol')
|
|
98
103
|
|
|
99
104
|
switch (symbol) {
|
|
100
105
|
case 's':
|
|
101
106
|
// do nothing, this is the base unit
|
|
102
|
-
break
|
|
107
|
+
break
|
|
103
108
|
case 'm':
|
|
104
|
-
num *= 60
|
|
105
|
-
break
|
|
109
|
+
num *= 60
|
|
110
|
+
break
|
|
106
111
|
case 'h':
|
|
107
|
-
num *= 3600
|
|
108
|
-
break
|
|
112
|
+
num *= 3600
|
|
113
|
+
break
|
|
109
114
|
case 'd':
|
|
110
|
-
num *= 86400
|
|
111
|
-
break
|
|
115
|
+
num *= 86400
|
|
116
|
+
break
|
|
112
117
|
default:
|
|
113
|
-
return error(i, 'invalid time span symbol')
|
|
118
|
+
return error(i, 'invalid time span symbol')
|
|
114
119
|
}
|
|
115
120
|
// Sanity check (what should this number be?)
|
|
116
121
|
if (num < 5) return error(i, 'delay time too small, should be >=5 seconds')
|
|
117
122
|
for (let j = 0; j < delay[1]; j++) {
|
|
118
|
-
times.push(num)
|
|
123
|
+
times.push(num)
|
|
119
124
|
}
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
// One last check, just in case...should never be true
|
|
123
|
-
if (times.length === 0) return error(0, 'unexpected parsing result')
|
|
128
|
+
if (times.length === 0) return error(0, 'unexpected parsing result')
|
|
124
129
|
|
|
125
130
|
// If here, success, so actually store the calculated array in the config
|
|
126
|
-
cfg.temp_fail_intervals = times
|
|
131
|
+
cfg.temp_fail_intervals = times
|
|
127
132
|
}
|
|
128
133
|
|
|
129
|
-
load_config()
|
|
134
|
+
load_config()
|
|
@@ -1,45 +1,44 @@
|
|
|
1
|
-
'use strict'
|
|
1
|
+
'use strict'
|
|
2
2
|
|
|
3
|
-
const fs = require('node:fs')
|
|
3
|
+
const fs = require('node:fs')
|
|
4
4
|
|
|
5
5
|
class FsyncWriteStream extends fs.WriteStream {
|
|
6
|
-
constructor
|
|
7
|
-
super(path, options)
|
|
6
|
+
constructor(path, options) {
|
|
7
|
+
super(path, options)
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
close
|
|
11
|
-
const self = this
|
|
12
|
-
if (cb) this.once('close', cb)
|
|
10
|
+
close(cb) {
|
|
11
|
+
const self = this
|
|
12
|
+
if (cb) this.once('close', cb)
|
|
13
13
|
|
|
14
14
|
if (this.closed || 'number' !== typeof this.fd) {
|
|
15
15
|
if ('number' !== typeof this.fd) {
|
|
16
|
-
this.once('open', close)
|
|
17
|
-
return
|
|
16
|
+
this.once('open', close)
|
|
17
|
+
return
|
|
18
18
|
}
|
|
19
|
-
return setImmediate(this.emit.bind(this, 'close'))
|
|
19
|
+
return setImmediate(this.emit.bind(this, 'close'))
|
|
20
20
|
}
|
|
21
|
-
this.closed = true
|
|
22
|
-
close()
|
|
21
|
+
this.closed = true
|
|
22
|
+
close()
|
|
23
23
|
|
|
24
|
-
function close
|
|
25
|
-
fs.fsync(fd || self.fd, er => {
|
|
24
|
+
function close(fd) {
|
|
25
|
+
fs.fsync(fd || self.fd, (er) => {
|
|
26
26
|
if (er) {
|
|
27
|
-
self.emit('error', er)
|
|
28
|
-
return
|
|
27
|
+
self.emit('error', er)
|
|
28
|
+
return
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
fs.close(fd || self.fd, err => {
|
|
31
|
+
fs.close(fd || self.fd, (err) => {
|
|
32
32
|
if (err) {
|
|
33
|
-
self.emit('error', err)
|
|
33
|
+
self.emit('error', err)
|
|
34
|
+
} else {
|
|
35
|
+
self.emit('close')
|
|
34
36
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
39
|
-
self.fd = null;
|
|
40
|
-
});
|
|
37
|
+
})
|
|
38
|
+
self.fd = null
|
|
39
|
+
})
|
|
41
40
|
}
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
module.exports = FsyncWriteStream
|
|
44
|
+
module.exports = FsyncWriteStream
|