Haraka 2.8.28 → 3.0.1
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 +2 -10
- package/Changes.md +84 -2
- package/Dockerfile +1 -1
- package/Plugins.md +9 -4
- package/README.md +2 -6
- package/bin/haraka +5 -4
- package/config/outbound.ini +0 -7
- package/config/plugins +1 -1
- package/config/smtp.ini +1 -1
- package/config/smtp_forward.ini +2 -8
- package/config/smtp_proxy.ini +0 -6
- package/connection.js +178 -204
- package/coverage/lcov.info +13863 -0
- package/coverage/tmp/coverage-42958-1658373250585-0.json +1 -0
- package/coverage/tmp/coverage-42961-1658373250529-0.json +1 -0
- package/dkim.js +66 -73
- package/docs/Body.md +1 -22
- package/docs/CoreConfig.md +2 -2
- package/docs/Header.md +1 -47
- package/docs/Outbound.md +8 -36
- package/endpoint.js +1 -1
- package/haraka.js +1 -1
- package/host_pool.js +8 -12
- package/logger.js +25 -32
- package/outbound/client_pool.js +11 -153
- package/outbound/config.js +5 -11
- package/outbound/hmail.js +109 -143
- package/outbound/index.js +13 -25
- package/outbound/mx_lookup.js +10 -7
- package/outbound/queue.js +8 -12
- package/outbound/timer_queue.js +2 -4
- package/outbound/tls.js +17 -18
- package/outbound/todo.js +1 -0
- package/package.json +57 -55
- package/plugins/auth/auth_base.js +39 -63
- package/plugins/auth/auth_bridge.js +3 -4
- package/plugins/auth/auth_proxy.js +16 -16
- package/plugins/auth/auth_vpopmaild.js +30 -37
- package/plugins/auth/flat_file.js +9 -13
- package/plugins/avg.js +9 -11
- package/plugins/backscatterer.js +1 -1
- package/plugins/block_me.js +2 -6
- package/plugins/bounce.js +106 -124
- package/plugins/clamd.js +59 -63
- package/plugins/data.signatures.js +6 -6
- package/plugins/data.uribl.js +1 -415
- package/plugins/delay_deny.js +19 -20
- package/plugins/dkim_sign.js +56 -62
- package/plugins/dkim_verify.js +9 -8
- package/plugins/dns_list_base.js +43 -42
- package/plugins/dnsbl.js +41 -46
- package/plugins/dnswl.js +23 -26
- package/plugins/early_talker.js +24 -28
- package/plugins/esets.js +8 -11
- package/plugins/greylist.js +161 -190
- package/plugins/helo.checks.js +175 -197
- package/plugins/mail_from.is_resolvable.js +38 -38
- package/plugins/messagesniffer.js +33 -40
- package/plugins/prevent_credential_leaks.js +7 -5
- package/plugins/process_title.js +16 -17
- package/plugins/queue/deliver.js +2 -2
- package/plugins/queue/lmtp.js +5 -6
- package/plugins/queue/qmail-queue.js +11 -13
- package/plugins/queue/quarantine.js +25 -34
- package/plugins/queue/rabbitmq.js +3 -2
- package/plugins/queue/rabbitmq_amqplib.js +9 -9
- package/plugins/queue/smtp_bridge.js +5 -4
- package/plugins/queue/smtp_forward.js +81 -89
- package/plugins/queue/smtp_proxy.js +21 -22
- package/plugins/queue/test.js +2 -1
- package/plugins/rcpt_to.host_list_base.js +20 -30
- package/plugins/rcpt_to.in_host_list.js +12 -14
- package/plugins/rcpt_to.max_count.js +7 -5
- package/plugins/record_envelope_addresses.js +4 -6
- package/plugins/relay.js +64 -74
- package/plugins/reseed_rng.js +1 -2
- package/plugins/spamassassin.js +56 -68
- package/plugins/status.js +2 -3
- package/plugins/tarpit.js +8 -11
- package/plugins/tls.js +14 -17
- package/plugins/toobusy.js +6 -8
- package/plugins/xclient.js +14 -25
- package/plugins.js +24 -29
- package/rfc1869.js +2 -2
- package/server.js +3 -13
- package/smtp_client.js +138 -215
- package/tests/config/smtp_forward.ini +0 -6
- package/tests/fixtures/line_socket.js +1 -1
- package/tests/fixtures/util_hmailitem.js +5 -7
- package/tests/fixtures/vm_harness.js +2 -2
- package/tests/host_pool.js +13 -14
- package/tests/installation/plugins/inherits.js +1 -2
- package/tests/logger.js +2 -2
- package/tests/plugins/bounce.js +6 -8
- package/tests/plugins/dkim_signer.js +7 -7
- package/tests/plugins/dns_list_base.js +7 -7
- package/tests/plugins/helo.checks.js +1 -1
- package/tests/plugins/mail_from.is_resolvable.js +10 -54
- package/tests/plugins/queue/smtp_forward.js +11 -11
- package/tests/plugins/rcpt_to.host_list_base.js +1 -1
- package/tests/plugins/rcpt_to.in_host_list.js +1 -1
- package/tests/plugins/spamassassin.js +1 -1
- package/tests/queue/multibyte +0 -0
- package/tests/queue/plain +0 -0
- package/tests/rfc1869.js +4 -1
- package/tests/server.js +15 -9
- package/tests/smtp_client/auth.js +4 -14
- package/tests/smtp_client/basic.js +5 -15
- package/tests/smtp_client.js +7 -3
- package/tests/transaction.js +72 -19
- package/tls_socket.js +75 -85
- package/transaction.js +7 -9
- package/attachment_stream.js +0 -118
- package/bin/spf +0 -48
- package/chunkemitter.js +0 -75
- package/config/data.uribl.excludes +0 -202
- package/config/data.uribl.ini +0 -37
- package/config/spf.ini +0 -1
- package/docs/plugins/attachment.md +0 -92
- package/docs/plugins/data.uribl.md +0 -120
- package/docs/plugins/spf.md +0 -142
- package/mailbody.js +0 -502
- package/mailheader.js +0 -304
- package/messagestream.js +0 -441
- package/plugins/aliases.js +0 -120
- package/plugins/attachment.js +0 -503
- package/plugins/connect.p0f.js +0 -5
- package/plugins/spf.js +0 -327
- package/spf.js +0 -689
- package/tests/mailbody.js +0 -348
- package/tests/mailheader.js +0 -138
- package/tests/messagestream.js +0 -34
- package/tests/plugins/aliases.js +0 -376
- package/tests/plugins/spf.js +0 -251
- package/tests/spf.js +0 -96
|
@@ -3,24 +3,21 @@
|
|
|
3
3
|
const net = require('net');
|
|
4
4
|
|
|
5
5
|
exports.register = function () {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
plugin.load_vpop_ini();
|
|
6
|
+
this.inherits('auth/auth_base');
|
|
7
|
+
this.load_vpop_ini();
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
exports.load_vpop_ini = function () {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
plugin.load_vpop_ini();
|
|
11
|
+
this.cfg = this.config.get('auth_vpopmaild.ini', () => {
|
|
12
|
+
this.load_vpop_ini();
|
|
15
13
|
});
|
|
16
14
|
}
|
|
17
15
|
|
|
18
16
|
exports.hook_capabilities = function (next, connection) {
|
|
19
17
|
if (!connection.tls.enabled) { return next(); }
|
|
20
|
-
const plugin = this;
|
|
21
18
|
|
|
22
19
|
const methods = [ 'PLAIN', 'LOGIN' ];
|
|
23
|
-
if (
|
|
20
|
+
if (this.cfg.main.sysadmin) { methods.push('CRAM-MD5'); }
|
|
24
21
|
|
|
25
22
|
connection.capabilities.push(`AUTH ${methods.join(' ')}`);
|
|
26
23
|
connection.notes.allowed_auth_methods = methods;
|
|
@@ -29,12 +26,11 @@ exports.hook_capabilities = function (next, connection) {
|
|
|
29
26
|
}
|
|
30
27
|
|
|
31
28
|
exports.check_plain_passwd = function (connection, user, passwd, cb) {
|
|
32
|
-
const plugin = this;
|
|
33
29
|
|
|
34
30
|
let chunk_count = 0;
|
|
35
31
|
let auth_success = false;
|
|
36
32
|
|
|
37
|
-
const socket =
|
|
33
|
+
const socket = this.get_vpopmaild_socket(user);
|
|
38
34
|
socket.setEncoding('utf8');
|
|
39
35
|
|
|
40
36
|
socket.on('data', chunk => {
|
|
@@ -55,94 +51,91 @@ exports.check_plain_passwd = function (connection, user, passwd, cb) {
|
|
|
55
51
|
}
|
|
56
52
|
});
|
|
57
53
|
socket.on('end', () => {
|
|
58
|
-
connection.loginfo(
|
|
54
|
+
connection.loginfo(this, `AUTH user="${user}" success=${auth_success}`);
|
|
59
55
|
return cb(auth_success);
|
|
60
56
|
});
|
|
61
57
|
}
|
|
62
58
|
|
|
63
59
|
exports.get_sock_opts = function (user) {
|
|
64
|
-
const plugin = this;
|
|
65
60
|
|
|
66
|
-
|
|
61
|
+
this.sock_opts = {
|
|
67
62
|
port: 89,
|
|
68
63
|
host: '127.0.0.1',
|
|
69
64
|
sysadmin: undefined,
|
|
70
65
|
};
|
|
71
66
|
|
|
72
67
|
const domain = (user.split('@'))[1];
|
|
73
|
-
let sect =
|
|
74
|
-
if (domain &&
|
|
75
|
-
sect =
|
|
68
|
+
let sect = this.cfg.main;
|
|
69
|
+
if (domain && this.cfg[domain]) {
|
|
70
|
+
sect = this.cfg[domain];
|
|
76
71
|
}
|
|
77
72
|
|
|
78
|
-
if (sect.port) {
|
|
79
|
-
if (sect.host) {
|
|
80
|
-
if (sect.sysadmin) {
|
|
73
|
+
if (sect.port) { this.sock_opts.port = sect.port; }
|
|
74
|
+
if (sect.host) { this.sock_opts.host = sect.host; }
|
|
75
|
+
if (sect.sysadmin) { this.sock_opts.sysadmin = sect.sysadmin; }
|
|
81
76
|
|
|
82
|
-
|
|
83
|
-
return
|
|
77
|
+
this.logdebug(`sock: ${this.sock_opts.host}:${this.sock_opts.port}`);
|
|
78
|
+
return this.sock_opts;
|
|
84
79
|
}
|
|
85
80
|
|
|
86
81
|
exports.get_vpopmaild_socket = function (user) {
|
|
87
|
-
|
|
88
|
-
plugin.get_sock_opts(user);
|
|
82
|
+
this.get_sock_opts(user);
|
|
89
83
|
|
|
90
84
|
const socket = new net.Socket();
|
|
91
|
-
socket.connect(
|
|
85
|
+
socket.connect(this.sock_opts.port, this.sock_opts.host);
|
|
92
86
|
socket.setTimeout(300 * 1000);
|
|
93
87
|
socket.setEncoding('utf8');
|
|
94
88
|
|
|
95
89
|
socket.on('timeout', () => {
|
|
96
|
-
|
|
90
|
+
this.logerror("vpopmaild connection timed out");
|
|
97
91
|
socket.end();
|
|
98
92
|
});
|
|
99
93
|
socket.on('error', err => {
|
|
100
|
-
|
|
94
|
+
this.logerror(`vpopmaild connection failed: ${err}`);
|
|
101
95
|
socket.end();
|
|
102
96
|
});
|
|
103
97
|
socket.on('connect', () => {
|
|
104
|
-
|
|
98
|
+
this.logdebug('vpopmail connected');
|
|
105
99
|
});
|
|
106
100
|
return socket;
|
|
107
101
|
}
|
|
108
102
|
|
|
109
103
|
exports.get_plain_passwd = function (user, connection, cb) {
|
|
110
|
-
const plugin = this;
|
|
111
104
|
|
|
112
|
-
const socket =
|
|
113
|
-
if (!
|
|
114
|
-
|
|
105
|
+
const socket = this.get_vpopmaild_socket(user);
|
|
106
|
+
if (!this.sock_opts.sysadmin) {
|
|
107
|
+
this.logerror("missing sysadmin credentials");
|
|
115
108
|
return cb(null);
|
|
116
109
|
}
|
|
117
110
|
|
|
118
|
-
const sys =
|
|
111
|
+
const sys = this.sock_opts.sysadmin.split(':');
|
|
119
112
|
let plain_pass = null;
|
|
120
113
|
let chunk_count = 0;
|
|
121
114
|
|
|
122
115
|
socket.on('data', chunk => {
|
|
123
116
|
chunk_count++;
|
|
124
|
-
|
|
117
|
+
this.logdebug(`${chunk_count}\t${chunk}`);
|
|
125
118
|
if (chunk_count === 1) {
|
|
126
119
|
if (/^\+OK/.test(chunk)) {
|
|
127
120
|
socket.write(`slogin ${sys[0]} ${sys[1]}\n\r`);
|
|
128
121
|
return;
|
|
129
122
|
}
|
|
130
|
-
|
|
123
|
+
this.logerror("no ok to start");
|
|
131
124
|
socket.end(); // disconnect
|
|
132
125
|
}
|
|
133
126
|
// slogin reply
|
|
134
127
|
if (chunk_count === 2) {
|
|
135
128
|
if (/^\+OK/.test(chunk)) {
|
|
136
|
-
|
|
129
|
+
this.logdebug('login success, getting user info');
|
|
137
130
|
socket.write(`user_info ${user}\n\r`);
|
|
138
131
|
return;
|
|
139
132
|
}
|
|
140
|
-
|
|
133
|
+
this.logerror("syadmin login failed");
|
|
141
134
|
socket.end(); // disconnect
|
|
142
135
|
}
|
|
143
136
|
if (chunk_count > 2) {
|
|
144
137
|
if (/^-ERR/.test(chunk)) {
|
|
145
|
-
|
|
138
|
+
this.lognotice(`get_plain failed: ${chunk}`);
|
|
146
139
|
socket.end(); // disconnect
|
|
147
140
|
return;
|
|
148
141
|
}
|
|
@@ -1,30 +1,27 @@
|
|
|
1
1
|
// Auth against a flat file
|
|
2
2
|
|
|
3
3
|
exports.register = function () {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
plugin.load_flat_ini();
|
|
4
|
+
this.inherits('auth/auth_base');
|
|
5
|
+
this.load_flat_ini();
|
|
7
6
|
}
|
|
8
7
|
|
|
9
8
|
exports.load_flat_ini = function () {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
plugin.load_flat_ini();
|
|
9
|
+
this.cfg = this.config.get('auth_flat_file.ini', () => {
|
|
10
|
+
this.load_flat_ini();
|
|
13
11
|
});
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
exports.hook_capabilities = function (next, connection) {
|
|
17
|
-
const plugin = this;
|
|
18
15
|
// don't allow AUTH unless private IP or encrypted
|
|
19
16
|
if (!connection.remote.is_private && !connection.tls.enabled) {
|
|
20
|
-
connection.logdebug(
|
|
17
|
+
connection.logdebug(this,
|
|
21
18
|
"Auth disabled for insecure public connection");
|
|
22
19
|
return next();
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
let methods = null;
|
|
26
|
-
if (
|
|
27
|
-
methods =
|
|
23
|
+
if (this.cfg.core?.methods ) {
|
|
24
|
+
methods = this.cfg.core.methods.split(',');
|
|
28
25
|
}
|
|
29
26
|
if (methods && methods.length > 0) {
|
|
30
27
|
connection.capabilities.push(`AUTH ${methods.join(' ')}`);
|
|
@@ -34,9 +31,8 @@ exports.hook_capabilities = function (next, connection) {
|
|
|
34
31
|
}
|
|
35
32
|
|
|
36
33
|
exports.get_plain_passwd = function (user, connection, cb) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return cb(plugin.cfg.users[user].toString());
|
|
34
|
+
if (this.cfg.users[user]) {
|
|
35
|
+
return cb(this.cfg.users[user].toString());
|
|
40
36
|
}
|
|
41
37
|
return cb();
|
|
42
38
|
}
|
package/plugins/avg.js
CHANGED
|
@@ -7,37 +7,35 @@ const fs = require('fs');
|
|
|
7
7
|
const path = require('path');
|
|
8
8
|
|
|
9
9
|
const sock = require('./line_socket');
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
const smtp_regexp = /^(\d{3})([ -])(.*)/;
|
|
11
12
|
|
|
12
13
|
exports.register = function () {
|
|
13
|
-
const plugin = this;
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
this.load_avg_ini();
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
exports.load_avg_ini = function () {
|
|
19
|
-
const plugin = this;
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
this.cfg = this.config.get('avg.ini', {
|
|
22
21
|
booleans: [
|
|
23
22
|
'+defer.timeout',
|
|
24
23
|
'+defer.error',
|
|
25
24
|
],
|
|
26
25
|
}, () => {
|
|
27
|
-
|
|
26
|
+
this.load_avg_ini();
|
|
28
27
|
});
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
exports.get_tmp_file = function (transaction) {
|
|
32
|
-
const
|
|
33
|
-
const tmpdir = plugin.cfg.main.tmpdir || '/tmp';
|
|
31
|
+
const tmpdir = this.cfg.main.tmpdir || '/tmp';
|
|
34
32
|
return path.join(tmpdir, `${transaction.uuid}.tmp`);
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
exports.hook_data_post = function (next, connection) {
|
|
38
|
-
|
|
39
|
-
if (!connection.transaction) return next();
|
|
36
|
+
if (!connection?.transaction) return next()
|
|
40
37
|
|
|
38
|
+
const plugin = this;
|
|
41
39
|
const tmpfile = plugin.get_tmp_file(connection.transaction);
|
|
42
40
|
const ws = fs.createWriteStream(tmpfile);
|
|
43
41
|
|
|
@@ -103,7 +101,7 @@ exports.hook_data_post = function (next, connection) {
|
|
|
103
101
|
const cont = matches[2];
|
|
104
102
|
const rest = matches[3];
|
|
105
103
|
response.push(rest);
|
|
106
|
-
if (cont !== ' ')
|
|
104
|
+
if (cont !== ' ') return;
|
|
107
105
|
|
|
108
106
|
switch (command) {
|
|
109
107
|
case 'connect':
|
package/plugins/backscatterer.js
CHANGED
|
@@ -5,7 +5,7 @@ exports.register = function () {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
exports.hook_mail = function (next, connection, params) {
|
|
8
|
-
const user = ((params[0]
|
|
8
|
+
const user = ((params[0]?.user) ?
|
|
9
9
|
params[0].user.toLowerCase() : null);
|
|
10
10
|
if (!(!user || user === 'postmaster')) return next();
|
|
11
11
|
// Check remote IP on ips.backscatterer.org
|
package/plugins/block_me.js
CHANGED
|
@@ -13,15 +13,11 @@ exports.hook_data = (next, connection) => {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
exports.hook_data_post = function (next, connection) {
|
|
16
|
-
if (!connection
|
|
17
|
-
return next();
|
|
18
|
-
}
|
|
16
|
+
if (!connection?.relaying || !connection?.transaction) return next();
|
|
19
17
|
|
|
20
18
|
const recip = (this.config.get('block_me.recipient') || '').toLowerCase();
|
|
21
19
|
const senders = this.config.get('block_me.senders', 'list');
|
|
22
20
|
|
|
23
|
-
const self = this;
|
|
24
|
-
|
|
25
21
|
// Make sure only 1 recipient
|
|
26
22
|
if (connection.transaction.rcpt_to.length != 1) {
|
|
27
23
|
return next();
|
|
@@ -52,7 +48,7 @@ exports.hook_data_post = function (next, connection) {
|
|
|
52
48
|
// add to mail_from.blocklist
|
|
53
49
|
fs.open('./config/mail_from.blocklist', 'a', (err, fd) => {
|
|
54
50
|
if (err) {
|
|
55
|
-
connection.logerror(
|
|
51
|
+
connection.logerror(this, `Unable to append to mail_from.blocklist: ${err}`);
|
|
56
52
|
return;
|
|
57
53
|
}
|
|
58
54
|
fs.write(fd, `${to_block}\n`, null, 'UTF-8', (err2, written) => {
|