Haraka 3.0.2 → 3.0.3
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/Changes.md +31 -0
- package/Dockerfile +3 -3
- package/Plugins.md +5 -4
- package/README.md +4 -4
- package/TODO +1 -24
- package/config/access.domains +1 -1
- package/config/auth_flat_file.ini +1 -0
- package/config/auth_vpopmaild.ini +4 -2
- package/config/helo.checks.ini +1 -1
- package/config/rabbitmq_amqplib.ini +8 -1
- package/docs/Connection.md +1 -1
- package/docs/Outbound.md +6 -15
- package/docs/Plugins.md +46 -39
- package/docs/Transaction.md +1 -1
- 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/relay.md +2 -2
- package/outbound/hmail.js +2 -2
- package/outbound/queue.js +5 -0
- package/package.json +26 -26
- package/plugins/auth/auth_base.js +27 -11
- package/plugins/auth/auth_vpopmaild.js +29 -19
- package/plugins/auth/flat_file.js +17 -12
- package/plugins/clamd.js +1 -0
- package/plugins/helo.checks.js +1 -1
- package/plugins/queue/rabbitmq_amqplib.js +1 -1
- package/plugins/queue/smtp_forward.js +3 -3
- package/plugins.js +1 -0
- package/tests/queue/multibyte +0 -0
- package/tests/queue/plain +0 -0
- package/transaction.js +1 -1
- 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/rcpt_to.blocklist +0 -1
- package/config/rdns.allow_regexps +0 -0
- package/config/rdns.deny_regexps +0 -0
- package/config.js +0 -6
- 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/plugins/data.headers.js +0 -4
- package/plugins/relay_all.js +0 -13
- /package/docs/{plugins → deprecated}/rcpt_to.routes.md +0 -0
package/Changes.md
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
|
|
2
2
|
### Unreleased
|
|
3
3
|
|
|
4
|
+
### [3.0.3] - 2024-02-07
|
|
5
|
+
|
|
6
|
+
#### Added
|
|
7
|
+
|
|
8
|
+
- feat(auth_vpopmaild): when outbound, assure the envelope domain matches AUTH domain #3265
|
|
9
|
+
- docs(outbound): remove example setting outbound_ip #3253
|
|
10
|
+
- doc(Plugins.md): add pi-queue-kafka #3247
|
|
11
|
+
- feat(rabbitmq_amqplib): configurable optional queue arguments #3239
|
|
12
|
+
- feat(clamd): add x-haraka-virus header #3207
|
|
13
|
+
|
|
14
|
+
#### Fixed
|
|
15
|
+
|
|
16
|
+
- Fix: add empty string as param to .join() on bounce. #3237
|
|
17
|
+
- Update links in documentation #3234
|
|
18
|
+
- fix(ob/hmail):Add filename to the error for easy debugging
|
|
19
|
+
- fix(ob/queue): Ignore 'error.' prefixed files in the queue because corrupted
|
|
20
|
+
|
|
21
|
+
#### Changed
|
|
22
|
+
|
|
23
|
+
- docs(outbound): remove example of outbound_ip #3253
|
|
24
|
+
- transaction: simplify else condition in add_data #3252
|
|
25
|
+
- q/smtp_forward: always register get_mx hook #3204
|
|
26
|
+
- dep(pi-es): bump version to 8.0.2 #3206
|
|
27
|
+
- dep(redis): bump version to 4.6.7 #3193
|
|
28
|
+
- dep(pi-spf): bump version to 1.2.4
|
|
29
|
+
- dep(net-utils): bump version to 1.5.3
|
|
30
|
+
- dep(pi-redis): bump version to 2.0.6
|
|
31
|
+
- dep(tld): bump version to 1.2.0
|
|
32
|
+
- remove defunct config files: lookup_rdns.strict.ini, lookup_rdns.strict.timeout, lookup_rdns.strict.whitelist, lookup_rdns.strict.whitelist_regex, rcpt_to.blocklist, rdns.allow_regexps, rdns.deny_regexps
|
|
33
|
+
|
|
4
34
|
|
|
5
35
|
### [3.0.2] - 2023-06-12
|
|
6
36
|
|
|
@@ -1370,3 +1400,4 @@
|
|
|
1370
1400
|
[3.0.0]: https://github.com/haraka/Haraka/releases/tag/3.0.0
|
|
1371
1401
|
[3.0.1]: https://github.com/haraka/Haraka/releases/tag/3.0.1
|
|
1372
1402
|
[3.0.2]: https://github.com/haraka/Haraka/releases/tag/3.0.2
|
|
1403
|
+
[3.0.3]: https://github.com/haraka/Haraka/releases/tag/3.0.3
|
package/Dockerfile
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# DOCKER-VERSION 0.5.3
|
|
14
14
|
|
|
15
15
|
# See http://phusion.github.io/baseimage-docker/
|
|
16
|
-
FROM phusion/baseimage:
|
|
16
|
+
FROM phusion/baseimage:focal-1.2.0
|
|
17
17
|
|
|
18
18
|
MAINTAINER Justin Plock <jplock@gmail.com>
|
|
19
19
|
|
|
@@ -23,8 +23,8 @@ RUN /etc/my_init.d/00_regen_ssh_host_keys.sh
|
|
|
23
23
|
|
|
24
24
|
RUN sed 's/main$/main universe/' -i /etc/apt/sources.list
|
|
25
25
|
RUN DEBIAN_FRONTEND=noninteractive apt-get -y -q update
|
|
26
|
-
RUN DEBIAN_FRONTEND=noninteractive apt-get -y -q install
|
|
27
|
-
RUN curl -sL https://deb.nodesource.com/
|
|
26
|
+
RUN DEBIAN_FRONTEND=noninteractive apt-get -y -q install software-properties-common g++ make git curl
|
|
27
|
+
RUN curl -sL https://deb.nodesource.com/setup_18.x | setuser root bash -
|
|
28
28
|
RUN DEBIAN_FRONTEND=noninteractive apt-get -y -q install nodejs && \
|
|
29
29
|
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
|
30
30
|
|
package/Plugins.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
To create your own plugin, see:
|
|
4
4
|
- the [plugin template][template] that includes all the boilerplate
|
|
5
5
|
- the [Write a Plugin][write-plugin] tutorial
|
|
6
|
-
- the [Plugins]
|
|
6
|
+
- the [Plugins][plugins-doc] section of [the manual](https://haraka.github.io)
|
|
7
7
|
|
|
8
8
|
## Installing NPM packaged plugins
|
|
9
9
|
|
|
@@ -40,7 +40,6 @@ Create a PR adding yours to this list.
|
|
|
40
40
|
| [block_me][url-blockme] | Populate block list via forwarded emails |
|
|
41
41
|
| [bounce][url-bounce] | Many options for bounce processing |
|
|
42
42
|
| [clamd][url-clamd] | Anti-Virus scanning with ClamAV |
|
|
43
|
-
| [connect.p0f][url-p0f] | TCP Fingerprinting |
|
|
44
43
|
| [data.signatures][url-sigs] | Block emails whose bodies match signatures |
|
|
45
44
|
| [uribl][url-uribl] | Block based on URI blacklists |
|
|
46
45
|
| [dcc][url-dcc] | Distributed Checksum Clearinghouse |
|
|
@@ -70,6 +69,7 @@ Create a PR adding yours to this list.
|
|
|
70
69
|
| [milter][url-milter] | milter support |
|
|
71
70
|
| [mongodb][mongo-url] | Queue emails to MongoDB |
|
|
72
71
|
| [outbound-logger][url-outbound-logger] | JSON logging of outbound email traffic. Logs useful metadata about delivered/bounced emails |
|
|
72
|
+
| [p0f][url-p0f] | TCP Fingerprinting |
|
|
73
73
|
| [prevent_credential_leaks][url-creds] | Prevent users from emailing their credentials |
|
|
74
74
|
| [process_title][url-proctitle] | Populate `ps` output with activity counters |
|
|
75
75
|
| queue/[discard][url-qdisc] | queues messages to /dev/null |
|
|
@@ -82,6 +82,7 @@ Create a PR adding yours to this list.
|
|
|
82
82
|
| queue/[smtp_bridge][url-qbridge] | Bridge SMTP sessions to another MTA |
|
|
83
83
|
| queue/[smtp_forward][url-qforward] | Forward emails to another MTA |
|
|
84
84
|
| queue/[smtp_proxy][url-qproxy] | Proxy SMTP connections to another MTA |
|
|
85
|
+
| [queue-kafka][url-kafka] | Queue inbound mail to a Kafka topic |
|
|
85
86
|
| [recipient-routes][url-rroutes] | Route emails based on their recipient(s) |
|
|
86
87
|
| [redis][url-redis] | multi-purpose Redis db connection(s) |
|
|
87
88
|
| [rcpt_to.in_host_list][url-rhost] | Define local email domains in a file |
|
|
@@ -109,7 +110,7 @@ Create a PR adding yours to this list.
|
|
|
109
110
|
|
|
110
111
|
[template]: https://github.com/haraka/haraka-plugin-template
|
|
111
112
|
[write-plugin]: https://github.com/haraka/Haraka/wiki/Write-a-Plugin
|
|
112
|
-
[plugins-doc]: https://haraka.github.io/
|
|
113
|
+
[plugins-doc]: https://haraka.github.io/core/Plugins
|
|
113
114
|
[url-access]: https://github.com/haraka/haraka-plugin-access
|
|
114
115
|
[url-acc-files]: https://github.com/acharkizakaria/haraka-plugin-accounting-files/blob/master/README.md
|
|
115
116
|
[url-action-mailbox]: https://guides.rubyonrails.org/action_mailbox_basics.html
|
|
@@ -192,4 +193,4 @@ Create a PR adding yours to this list.
|
|
|
192
193
|
[url-xclient]: https://github.com/haraka/Haraka/blob/master/docs/plugins/xclient.md
|
|
193
194
|
[mongo-url]: https://github.com/Helpmonks/haraka-plugin-mongodb
|
|
194
195
|
[url-outbound-logger]: https://github.com/mr-karan/haraka-plugin-outbound-logger
|
|
195
|
-
|
|
196
|
+
[url-kafka]: https://github.com/benjamonnguyen/haraka-plugin-queue-kafka
|
package/README.md
CHANGED
|
@@ -140,10 +140,10 @@ SpamAssassin and a hacker on [Qpsmtpd][13].
|
|
|
140
140
|
[6]: https://github.com/haraka/Haraka/blob/master/docs/plugins/dkim_sign.md
|
|
141
141
|
[7]: https://en.wikipedia.org/wiki/Mail_delivery_agent
|
|
142
142
|
[8]: mailto:haraka-sub@harakamail.com
|
|
143
|
-
[9]:
|
|
144
|
-
[10]: https://haraka.github.io/
|
|
145
|
-
[11]: https://haraka.github.io/
|
|
146
|
-
[12]: https://github.com/haraka/Haraka/
|
|
143
|
+
[9]: https://haraka.github.io/plugins/spamassassin
|
|
144
|
+
[10]: https://haraka.github.io/plugins/helo.checks
|
|
145
|
+
[11]: https://haraka.github.io/plugins/dnsbl
|
|
146
|
+
[12]: https://github.com/haraka/Haraka/blob/master/Plugins.md
|
|
147
147
|
[13]: https://github.com/smtpd/qpsmtpd/
|
|
148
148
|
[15]: https://github.com/haraka/Haraka/issues
|
|
149
149
|
[16]: https://github.com/haraka/Haraka/blob/master/LICENSE
|
package/TODO
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
- Milter support
|
|
2
2
|
- Ability to modify the body of email
|
|
3
3
|
- Done for banners. Modifying the rest, not so much.
|
|
4
|
-
- Plugins to copy from Qpsmtpd:
|
|
5
|
-
- dspam
|
|
6
4
|
|
|
7
5
|
Outbound improvements
|
|
8
6
|
- Provide better command line tools for manipulating/inspecting the queue
|
|
@@ -16,29 +14,8 @@ Plugin behavior changes
|
|
|
16
14
|
only when requested, with a sunset date.
|
|
17
15
|
- data.uribl; expand short URLs before lookups, add support for uri-a (sbl.spamhaus.org), uri-ns, uri-ns-a lookup types.
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
Remove the following deprecated plugins
|
|
21
|
-
- rdns.regexp
|
|
22
|
-
- data.nomsgid (subsumed into data.headers.js)
|
|
23
|
-
- data.noreceived ""
|
|
24
|
-
- data.rfc5322_header_checks ""
|
|
25
|
-
- daemonize
|
|
26
|
-
- mail_from.nobounces (subsumed into bounce.js)
|
|
27
|
-
- mail_from.blocklist
|
|
28
|
-
- rcpt_to.blocklist
|
|
29
|
-
- lookup_rdns_strict
|
|
30
|
-
- mail_from.access (replaced by access.js)
|
|
31
|
-
- rcpt_to.access ""
|
|
32
|
-
- connect.rdns_access ""
|
|
33
|
-
- relay_acl (replaced by relay.js)
|
|
34
|
-
- relay_all ""
|
|
35
|
-
- relay_force_routing ""
|
|
36
|
-
|
|
37
|
-
Move the following plugins:
|
|
38
|
-
- test_queue -> queue/test_queue
|
|
39
|
-
|
|
40
17
|
Built-in HTTP server
|
|
41
|
-
-
|
|
18
|
+
- use the same TLS/SSL certs as smtpd
|
|
42
19
|
- auth against SMTP-AUTH provider
|
|
43
20
|
|
|
44
21
|
Update tests to detect HARAKA_NETWORK_TESTS and skip network tests unless it's set
|
package/config/access.domains
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
[main]
|
|
1
2
|
host=127.0.0.6
|
|
2
3
|
port=89
|
|
3
|
-
;sysadmin=postmaster@example.com:sekret
|
|
4
|
+
; sysadmin=postmaster@example.com:sekret
|
|
5
|
+
; constrain_sender=true
|
|
4
6
|
|
|
5
7
|
[example.com]
|
|
6
8
|
host=127.0.0.10
|
|
7
|
-
;sysadmin=postmaster@example.com:sekret
|
|
9
|
+
; sysadmin=postmaster@example.com:sekret
|
package/config/helo.checks.ini
CHANGED
|
@@ -9,4 +9,11 @@ queueName = emails
|
|
|
9
9
|
deliveryMode = 2
|
|
10
10
|
confirm = true
|
|
11
11
|
durable = true
|
|
12
|
-
autoDelete = false
|
|
12
|
+
autoDelete = false
|
|
13
|
+
|
|
14
|
+
; Optional queue arguments
|
|
15
|
+
; [queue_args]
|
|
16
|
+
; x-dead-letter-exchange =
|
|
17
|
+
; x-dead-letter-routing-key = emails_dlq
|
|
18
|
+
; x-overflow = reject-publish
|
|
19
|
+
; x-queue-type = quorum
|
package/docs/Connection.md
CHANGED
|
@@ -63,5 +63,5 @@ For low level use. This value is set when the remote host drops the connection.
|
|
|
63
63
|
|
|
64
64
|
* connection.results
|
|
65
65
|
|
|
66
|
-
Store results of processing in a structured format. See [
|
|
66
|
+
Store results of processing in a structured format. See [haraka-results](https://github.com/haraka/haraka-results)
|
|
67
67
|
|
package/docs/Outbound.md
CHANGED
|
@@ -38,9 +38,9 @@ of CPUs that you have.
|
|
|
38
38
|
|
|
39
39
|
Default: true. Switch to false to disable TLS for outbound mail.
|
|
40
40
|
|
|
41
|
-
This uses the same `tls_key.pem` and `tls_cert.pem` files that the `
|
|
42
|
-
plugin uses, along with other values in `tls.ini`. See the [
|
|
43
|
-
docs](http://haraka.github.io/
|
|
41
|
+
This uses the same `tls_key.pem` and `tls_cert.pem` files that the `TLS`
|
|
42
|
+
plugin uses, along with other values in `tls.ini`. See the [TLS plugin
|
|
43
|
+
docs](http://haraka.github.io/plugins/tls) for information on generating those files.
|
|
44
44
|
|
|
45
45
|
Within `tls.ini` you can specify global options for the values `ciphers`, `minVersion`, `requestCert` and `rejectUnauthorized`, alternatively you can provide separate values by putting them under a key: `[outbound]`, such as:
|
|
46
46
|
|
|
@@ -117,7 +117,7 @@ you may be interested in are:
|
|
|
117
117
|
* domain - the domain this mail is going to (see `always_split` above)
|
|
118
118
|
* notes - the original transaction.notes for this mail, also contains the
|
|
119
119
|
following useful keys:
|
|
120
|
-
** outbound_ip - the IP address to bind to (
|
|
120
|
+
** outbound_ip - the IP address to bind to (do not set manually,
|
|
121
121
|
use the `get_mx` hook)
|
|
122
122
|
** outbound_helo - the EHLO domain to use (again, do not set manually)
|
|
123
123
|
* queue_time - the epoch milliseconds time when this mail was queued
|
|
@@ -240,19 +240,10 @@ different IP addresses based on sender, domain or some other identifier.
|
|
|
240
240
|
To do this, the IP address that you want to use *must* be bound to an
|
|
241
241
|
interface (or alias) on the local system.
|
|
242
242
|
|
|
243
|
-
As described above the outbound IP can be set using the `bind` parameter
|
|
243
|
+
As described above, the outbound IP can be set using the `bind` parameter
|
|
244
244
|
and also the outbound helo for the IP can be set using the `bind_ehlo`
|
|
245
|
-
parameter returned by the `get_mx` hook
|
|
246
|
-
you can set a transaction note in a plugin to tell Haraka which outbound IP
|
|
247
|
-
address you would like it to use when it tries to deliver the message:
|
|
245
|
+
parameter returned by the `get_mx` hook.
|
|
248
246
|
|
|
249
|
-
`````
|
|
250
|
-
connection.transaction.notes.outbound_ip = '1.2.3.4';
|
|
251
|
-
connection.transaction.notes.outbound_helo = 'mail-2.example.com';
|
|
252
|
-
`````
|
|
253
|
-
|
|
254
|
-
Note: if the `get_mx` hook returns a `bind` and `bind_helo` parameter, then
|
|
255
|
-
this will be used in preference to the transaction note.
|
|
256
247
|
|
|
257
248
|
AUTH
|
|
258
249
|
----
|
package/docs/Plugins.md
CHANGED
|
@@ -20,7 +20,6 @@ Display the help text for a plugin by running:
|
|
|
20
20
|
## Overview
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
## Anatomy of a Plugin
|
|
25
24
|
|
|
26
25
|
Plugins in Haraka are JS files in the `plugins` directory (legacy) and npm
|
|
@@ -42,37 +41,43 @@ There are two ways for plugins to register hooks. Both examples register a funct
|
|
|
42
41
|
|
|
43
42
|
1. The `register_hook` function in register():
|
|
44
43
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
```js
|
|
45
|
+
exports.register = function () {
|
|
46
|
+
this.register_hook('rcpt', 'my_rcpt_validate')
|
|
47
|
+
};
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
exports.my_rcpt_validate = function (next, connection, params) {
|
|
50
|
+
// do processing
|
|
51
|
+
next()
|
|
52
|
+
};
|
|
53
|
+
```
|
|
53
54
|
|
|
54
55
|
2. The hook_[$name] syntax:
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
```js
|
|
58
|
+
exports.hook_rcpt = function (next, connection, params) {
|
|
59
|
+
// do processing
|
|
60
|
+
next()
|
|
61
|
+
}
|
|
62
|
+
```
|
|
60
63
|
|
|
61
64
|
The register_hook function within `register()` offers a few advantages:
|
|
62
65
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
1. register a hook multiple times (see below)
|
|
67
|
+
2. a unique function name in stack traces
|
|
68
|
+
3. [a better function name](https://google.com/search?q=programming%20good%20function%20names)
|
|
69
|
+
4. hooks can be registered conditionally (ie, based on a config setting)
|
|
67
70
|
|
|
68
71
|
### Register a Hook Multiple Times
|
|
69
72
|
|
|
70
73
|
To register the same hook more than once, call `register_hook()` multiple times with the same hook name:
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
```js
|
|
76
|
+
exports.register = function () {
|
|
77
|
+
this.register_hook('queue', 'try_queue_my_way')
|
|
78
|
+
this.register_hook('queue', 'try_queue_highway')
|
|
79
|
+
};
|
|
80
|
+
```
|
|
76
81
|
|
|
77
82
|
When `try_queue_my_way()` calls `next()`, the next function registered on hook *queue* will be called, in this case, `try_queue_highway()`.
|
|
78
83
|
|
|
@@ -81,17 +86,18 @@ When `try_queue_my_way()` calls `next()`, the next function registered on hook *
|
|
|
81
86
|
When a single function runs on multiple hooks, the function can check the
|
|
82
87
|
*hook* property of the *connection* or *hmail* argument to determine which hook it is running on:
|
|
83
88
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
```js
|
|
90
|
+
exports.register = function () {
|
|
91
|
+
this.register_hook('rcpt', 'my_rcpt')
|
|
92
|
+
this.register_hook('rcpt_ok', 'my_rcpt')
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
exports.my_rcpt = function (next, connection, params) {
|
|
96
|
+
const hook_name = connection.hook; // rcpt or rcpt_ok
|
|
97
|
+
// email address is in params[0]
|
|
98
|
+
// do processing
|
|
99
|
+
}
|
|
100
|
+
```
|
|
95
101
|
|
|
96
102
|
### Next()
|
|
97
103
|
|
|
@@ -252,12 +258,11 @@ This is important as some plugins might rely on `results` or `notes` that have b
|
|
|
252
258
|
|
|
253
259
|
If you are writing a complex plugin, you may have to split it into multiple plugins to run in a specific order e.g. you want hook_deny to run last after all other plugins and hook_lookup_rdns to run first, then you can explicitly register your hooks and provide a `priority` value which is an integer between -100 (highest priority) to 100 (lowest priority) which defaults to 0 (zero) if not supplied. You can apply a priority to your hook in the following way:
|
|
254
260
|
|
|
255
|
-
|
|
256
|
-
exports.register = function() {
|
|
257
|
-
|
|
258
|
-
plugin.register_hook('connect', 'hook_connect', -100);
|
|
261
|
+
```js
|
|
262
|
+
exports.register = function () {
|
|
263
|
+
this.register_hook('connect', 'hook_connect', -100);
|
|
259
264
|
}
|
|
260
|
-
|
|
265
|
+
```
|
|
261
266
|
|
|
262
267
|
This would ensure that your hook_connect function will run before any other
|
|
263
268
|
plugins registered on the `connect` hook, regardless of the order it was
|
|
@@ -370,9 +375,11 @@ to remote servers. See [Issue 2024](https://github.com/haraka/Haraka/issues/2024
|
|
|
370
375
|
|
|
371
376
|
e.g.
|
|
372
377
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
378
|
+
```js
|
|
379
|
+
exports.shutdown = function () {
|
|
380
|
+
clearInterval(this._interval);
|
|
381
|
+
}
|
|
382
|
+
```
|
|
376
383
|
|
|
377
384
|
If you don't implement this in your plugin and have a connection open or a
|
|
378
385
|
timer running then Haraka will take 30 seconds to shut down and have to
|
package/docs/Transaction.md
CHANGED
|
@@ -160,6 +160,6 @@ body in the same encoding.
|
|
|
160
160
|
|
|
161
161
|
* transaction.results
|
|
162
162
|
|
|
163
|
-
Store results of processing in a structured format. See [
|
|
163
|
+
Store results of processing in a structured format. See [haraka-results](https://github.com/haraka/haraka-results)
|
|
164
164
|
|
|
165
165
|
[1]: `Address` objects are address-rfc2821 objects. See https://github.com/haraka/node-address-rfc2821
|
|
@@ -1,26 +1,20 @@
|
|
|
1
|
-
auth/auth\_vpopmaild
|
|
2
|
-
===============
|
|
1
|
+
# auth/auth\_vpopmaild
|
|
3
2
|
|
|
4
|
-
The `auth/vpopmaild` plugin allows
|
|
5
|
-
daemon.
|
|
3
|
+
The `auth/vpopmaild` plugin allows SMTP users to authenticate against a vpopmaild daemon.
|
|
6
4
|
|
|
7
5
|
## Configuration
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
style formatting.
|
|
7
|
+
The configuration file is stored in `config/auth_vpopmaild.ini`.
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
### settings
|
|
13
10
|
|
|
14
11
|
* host: The host/IP that vpopmaild is listening on (default: localhost).
|
|
15
12
|
|
|
16
13
|
* port: The TCP port that vpopmaild is listening on (default: 89).
|
|
17
14
|
|
|
18
|
-
* sysadmin: A colon separated username:password of a vpopmail user with
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
password. On new installs, it's best not to use CRAM-MD5, as it requires
|
|
22
|
-
storing clear text passwords. Legacy clients with MUAs configured
|
|
23
|
-
to authenticate with CRAM-MD5 will need this enabled.
|
|
15
|
+
* sysadmin: A colon separated username:password of a vpopmail user with SYSADMIN privileges (see vpopmail/bin/vmoduser -S). This is **only** necessary to support CRAM-MD5 which requires access to the clear text password. On new installs, it's best not to use CRAM-MD5, as it requires storing clear text passwords. Legacy clients with MUAs configured to authenticate with CRAM-MD5 will need this enabled.
|
|
16
|
+
|
|
17
|
+
* constrain_sender: (default: true). For outbound messages (due to successful AUTH), constrain the envelope sender (MAIL FROM) to the same domain as the authenticated user. This setting, combined with `rate_rcpt_sender` in the [limit](https://github.com/haraka/haraka-plugin-limit) plugin can dramatically reduce the amount of backscatter and spam sent when an email account is compromised.
|
|
24
18
|
|
|
25
19
|
|
|
26
20
|
### Per-domain Configuration
|
|
@@ -29,10 +23,12 @@ Additionally, domains can each have their own configuration for connecting
|
|
|
29
23
|
to vpopmaild. The defaults are the same, so only the differences needs to
|
|
30
24
|
be declared. Example:
|
|
31
25
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
```ini
|
|
27
|
+
[example.com]
|
|
28
|
+
host=192.168.0.1
|
|
29
|
+
port=999
|
|
35
30
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
[example2.com]
|
|
32
|
+
host=192.168.0.2
|
|
33
|
+
sysadmin=postmaster@example2.com:sekret
|
|
34
|
+
```
|
|
@@ -1,47 +1,40 @@
|
|
|
1
|
-
auth/flat\_file
|
|
2
|
-
==============
|
|
1
|
+
# auth/flat\_file
|
|
3
2
|
|
|
4
|
-
The `auth/flat_file` plugin allows you to create a file containing username
|
|
5
|
-
and password combinations, and have relaying users authenticate from that
|
|
6
|
-
file.
|
|
3
|
+
The `auth/flat_file` plugin allows you to create a file containing username and password combinations, and have relaying users authenticate from that file.
|
|
7
4
|
|
|
8
|
-
Note that passwords are stored in clear-text, so this may not be a great idea
|
|
9
|
-
for large scale systems. However the plugin would be a good start for someone
|
|
10
|
-
looking to implement authentication using some other form of auth.
|
|
5
|
+
Note that passwords are stored in clear-text, so this may not be a great idea for large scale systems. However the plugin would be a good start for someone looking to implement authentication using some other form of auth.
|
|
11
6
|
|
|
12
|
-
**Security** - it is recommended to switch to [auth-encfile][url-authencflat]
|
|
13
|
-
to protect your user credentials.
|
|
7
|
+
**Security** - it is recommended to switch to [auth-encfile][url-authencflat] to protect your user credentials.
|
|
14
8
|
|
|
15
|
-
**IMPORANT NOTE** - this plugin requires that STARTTLS be used via the tls plugin
|
|
16
|
-
|
|
17
|
-
improve security out-of-the-box. Localhost and any IP in RFC1918 ranges
|
|
18
|
-
are automatically exempt from this rule.
|
|
9
|
+
**IMPORANT NOTE** - this plugin requires that STARTTLS be used via the tls plugin before it will advertise AUTH capabilities by the EHLO command. Localhost and IPs in RFC1918 ranges
|
|
10
|
+
are exempt from this rule.
|
|
19
11
|
|
|
20
|
-
Configuration
|
|
21
|
-
-------------
|
|
12
|
+
## Configuration
|
|
22
13
|
|
|
23
|
-
Configuration is stored in `config/auth_flat_file.ini
|
|
24
|
-
style formatting.
|
|
14
|
+
Configuration is stored in `config/auth_flat_file.ini`.
|
|
25
15
|
|
|
26
|
-
|
|
27
|
-
parameter. Lists of authentification methods are comma separated. Currently
|
|
28
|
-
supported methods are: `CRAM-MD5`, `PLAIN` and `LOGIN`. The `PLAIN`
|
|
29
|
-
and `LOGIN` methods are not secure. That is why TLS is required before AUTH is
|
|
30
|
-
offered.
|
|
16
|
+
* [core]methods
|
|
31
17
|
|
|
32
|
-
|
|
18
|
+
Authentication methods are listed in the `[core]methods` parameter. Authentification methods are comma separated. Currently supported methods are: `CRAM-MD5`, `PLAIN` and `LOGIN`. The `PLAIN` and `LOGIN` methods are insecure and require TLS to be enabled.
|
|
19
|
+
|
|
20
|
+
* [core]constrain_sender: (default: true). For outbound messages (due to successful AUTH), constrain the envelope sender (MAIL FROM) to the same domain as the authenticated user. This setting, combined with `rate_rcpt_sender` in the [limit](https://github.com/haraka/haraka-plugin-limit) plugin can dramatically reduce the amount of backscatter and spam sent when an email account is compromised.
|
|
33
21
|
|
|
34
|
-
|
|
35
|
-
methods=PLAIN,LOGIN,CRAM-MD5
|
|
22
|
+
Example:
|
|
36
23
|
|
|
24
|
+
```ini
|
|
25
|
+
[core]
|
|
26
|
+
methods=PLAIN,LOGIN,CRAM-MD5
|
|
27
|
+
constrain_sender=true
|
|
28
|
+
```
|
|
37
29
|
|
|
38
30
|
Users are stored in the `[users]` section.
|
|
39
31
|
|
|
40
32
|
Example:
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
```ini
|
|
35
|
+
[users]
|
|
36
|
+
user1=password1
|
|
37
|
+
user@domain.com=password2
|
|
38
|
+
```
|
|
46
39
|
|
|
47
40
|
[url-authencflat]: https://github.com/AuspeXeu/haraka-plugin-auth-enc-file
|
|
@@ -36,5 +36,12 @@ Configuration
|
|
|
36
36
|
durable = true
|
|
37
37
|
autoDelete = false
|
|
38
38
|
|
|
39
|
+
; Optional queue arguments
|
|
40
|
+
; More information about x-arguments can be found at https://www.rabbitmq.com/queues.html#optional-arguments
|
|
41
|
+
[queue_args]
|
|
42
|
+
x-dead-letter-exchange =
|
|
43
|
+
x-dead-letter-routing-key = emails_dlq
|
|
44
|
+
x-overflow = reject-publish
|
|
45
|
+
x-queue-type = quorum
|
|
39
46
|
|
|
40
47
|
More information about RabbitMQ can be found at https://www.rabbitmq.com/
|
|
@@ -100,4 +100,4 @@ enable\_outbound can be set or unset on a per-domain level to enable or disable
|
|
|
100
100
|
|
|
101
101
|
# Split host forward routing
|
|
102
102
|
|
|
103
|
-
When an incoming email transaction has multiple recipients with different forward routes,
|
|
103
|
+
When an incoming email transaction has multiple recipients with different forward routes, recipients to subsequent forward routes are deferred. Example: an incoming email transaction has recipients user@example1.com, user@example2.com, and user@example3.com. The first two recipients will be accepted (they share the same forward destination) and the latter will be deferred. It will arrive in a future delivery attempt by the remote.
|
package/docs/plugins/relay.md
CHANGED
|
@@ -8,7 +8,7 @@ This **relay** plugin provides Haraka with options for managing relay permission
|
|
|
8
8
|
|
|
9
9
|
## Authentication
|
|
10
10
|
|
|
11
|
-
One way to enable relaying is [
|
|
11
|
+
One way to enable relaying is authentication via the [auth plugins](http://haraka.github.io/plugins). Successful authentication enables relaying during _that_ SMTP connection. To securely offer SMTP AUTH, the [tls](http://haraka.github.io/plugins/tls) plugin and at least one auth plugin must be enabled and properly configured. When that requirement is met, the AUTH SMTP extension will be advertised to SMTP clients.
|
|
12
12
|
|
|
13
13
|
% nc mail.example.com 587
|
|
14
14
|
220 mail.example.com ESMTP Haraka 2.4.0 ready
|
|
@@ -118,7 +118,7 @@ Example:
|
|
|
118
118
|
[domains]
|
|
119
119
|
test.com = { "action": "accept" }
|
|
120
120
|
|
|
121
|
-
|
|
121
|
+
Think of *accept* as the equivalent of qmail's *rcpthosts*, or a misplaced Haraka `rcpt_to.*` plugin. The *accept* mechanism is another way to tell Haraka that a particular domain is one we accept mail for. The difference between this and the [rcpt_to.in_host_list](http://haraka.github.io/plugins/rcpt_to.in_host_list) plugin is that this one also enables relaying.
|
|
122
122
|
|
|
123
123
|
* continue (mails are subject to further checks)
|
|
124
124
|
|
package/outbound/hmail.js
CHANGED
|
@@ -103,7 +103,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
103
103
|
|
|
104
104
|
this._stream_bytes_from(this.path, {start: 4, end: todo_len + 3}, (err2, todo_bytes) => {
|
|
105
105
|
if (todo_bytes.length !== todo_len) {
|
|
106
|
-
const wrongLength = `Didn't find right amount of data in todo!: ${err2}`;
|
|
106
|
+
const wrongLength = `Didn't find right amount of data in todo!: ${err2} ${this.path}`;
|
|
107
107
|
this.logcrit(wrongLength);
|
|
108
108
|
fs.rename(this.path, path.join(queue_dir, `error.${this.filename}`), (err3) => {
|
|
109
109
|
if (err3) {
|
|
@@ -1062,7 +1062,7 @@ class HMailItem extends events.EventEmitter {
|
|
|
1062
1062
|
"\r": '#10',
|
|
1063
1063
|
"\n": '#13'
|
|
1064
1064
|
};
|
|
1065
|
-
const escape_pattern = new RegExp(`[${Object.keys(escaped_chars).join()}]`, 'g');
|
|
1065
|
+
const escape_pattern = new RegExp(`[${Object.keys(escaped_chars).join('')}]`, 'g');
|
|
1066
1066
|
|
|
1067
1067
|
bounce_msg_html_.forEach(line => {
|
|
1068
1068
|
line = line.replace(/\{(\w+)\}/g, (i, word) => {
|
package/outbound/queue.js
CHANGED
|
@@ -103,6 +103,11 @@ exports.read_parts = file => {
|
|
|
103
103
|
return false;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
+
if (file.startsWith('error.')) {
|
|
107
|
+
logger.logwarn(`[outbound] 'Skipping' error file in queue folder: ${file}`);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
106
111
|
const parts = _qfile.parts(file);
|
|
107
112
|
if (!parts) {
|
|
108
113
|
logger.logerror(`[outbound] Unrecognized file in queue folder: ${file}`);
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"server",
|
|
10
10
|
"email"
|
|
11
11
|
],
|
|
12
|
-
"version": "3.0.
|
|
12
|
+
"version": "3.0.3",
|
|
13
13
|
"homepage": "http://haraka.github.io",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
@@ -20,28 +20,28 @@
|
|
|
20
20
|
"node": ">=16"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"address-rfc2821": "^2.
|
|
23
|
+
"address-rfc2821": "^2.1.1",
|
|
24
24
|
"address-rfc2822": "^2.1.0",
|
|
25
|
-
"async": "^3.2.
|
|
25
|
+
"async": "^3.2.5",
|
|
26
26
|
"daemon": "~1.1.0",
|
|
27
27
|
"ipaddr.js": "~2.1.0",
|
|
28
|
-
"node-gyp": "^
|
|
28
|
+
"node-gyp": "^10.0.1",
|
|
29
29
|
"nopt": "~7.2.0",
|
|
30
30
|
"npid": "~0.4.0",
|
|
31
|
-
"semver": "~7.
|
|
32
|
-
"sprintf-js": "~1.1.
|
|
31
|
+
"semver": "~7.6.0",
|
|
32
|
+
"sprintf-js": "~1.1.3",
|
|
33
33
|
"haraka-config": "^1.1.0",
|
|
34
34
|
"haraka-constants": "^1.0.6",
|
|
35
35
|
"haraka-dsn": "^1.0.4",
|
|
36
36
|
"haraka-email-message": "^1.2.0",
|
|
37
37
|
"haraka-message-stream": "^1.2.0",
|
|
38
|
-
"haraka-net-utils": "^1.5.
|
|
38
|
+
"haraka-net-utils": "^1.5.3",
|
|
39
39
|
"haraka-notes": "^1.0.6",
|
|
40
40
|
"haraka-plugin-attachment": "^1.0.7",
|
|
41
|
-
"haraka-plugin-spf": "1.2.
|
|
42
|
-
"haraka-plugin-redis": "^2.0.
|
|
41
|
+
"haraka-plugin-spf": "1.2.4",
|
|
42
|
+
"haraka-plugin-redis": "^2.0.6",
|
|
43
43
|
"haraka-results": "^2.2.3",
|
|
44
|
-
"haraka-tld": "^1.
|
|
44
|
+
"haraka-tld": "^1.2.0",
|
|
45
45
|
"haraka-utils": "^1.0.3",
|
|
46
46
|
"openssl-wrapper": "^0.3.4",
|
|
47
47
|
"sockaddr": "^1.0.1"
|
|
@@ -49,36 +49,36 @@
|
|
|
49
49
|
"optionalDependencies": {
|
|
50
50
|
"haraka-plugin-access": "^1.1.5",
|
|
51
51
|
"haraka-plugin-aliases": "^1.0.1",
|
|
52
|
-
"haraka-plugin-asn": "^2.0.
|
|
53
|
-
"haraka-plugin-auth-ldap": "^1.0
|
|
54
|
-
"haraka-plugin-dcc": "^1.0.
|
|
55
|
-
"haraka-plugin-elasticsearch": "^
|
|
52
|
+
"haraka-plugin-asn": "^2.0.2",
|
|
53
|
+
"haraka-plugin-auth-ldap": "^1.1.0",
|
|
54
|
+
"haraka-plugin-dcc": "^1.0.2",
|
|
55
|
+
"haraka-plugin-elasticsearch": "^8.0.2",
|
|
56
56
|
"haraka-plugin-fcrdns": "^1.1.0",
|
|
57
57
|
"haraka-plugin-graph": "^1.0.5",
|
|
58
58
|
"haraka-plugin-geoip": "^1.0.17",
|
|
59
59
|
"haraka-plugin-headers": "^1.0.3",
|
|
60
|
-
"haraka-plugin-karma": "^2.1.
|
|
61
|
-
"haraka-plugin-limit": "^1.1.
|
|
60
|
+
"haraka-plugin-karma": "^2.1.2",
|
|
61
|
+
"haraka-plugin-limit": "^1.1.1",
|
|
62
62
|
"haraka-plugin-p0f": "^1.0.9",
|
|
63
63
|
"haraka-plugin-qmail-deliverable": "^1.2.1",
|
|
64
|
-
"haraka-plugin-known-senders": "^1.0.
|
|
65
|
-
"haraka-plugin-rcpt-ldap": "^1.
|
|
66
|
-
"haraka-plugin-recipient-routes": "^1.0
|
|
67
|
-
"haraka-plugin-rspamd": "^1.
|
|
68
|
-
"haraka-plugin-syslog": "^1.0.
|
|
69
|
-
"haraka-plugin-uribl": "^1.0.
|
|
64
|
+
"haraka-plugin-known-senders": "^1.0.9",
|
|
65
|
+
"haraka-plugin-rcpt-ldap": "^1.1.0",
|
|
66
|
+
"haraka-plugin-recipient-routes": "^1.2.0",
|
|
67
|
+
"haraka-plugin-rspamd": "^1.3.1",
|
|
68
|
+
"haraka-plugin-syslog": "^1.0.5",
|
|
69
|
+
"haraka-plugin-uribl": "^1.0.8",
|
|
70
70
|
"haraka-plugin-watch": "^2.0.2",
|
|
71
71
|
"ocsp": "~1.2.0",
|
|
72
|
-
"redis": "
|
|
72
|
+
"redis": "~4.6.11",
|
|
73
73
|
"tmp": "~0.2.1"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"nodeunit-x": "^0.16.0",
|
|
77
|
-
"haraka-test-fixtures": "^1.3.
|
|
77
|
+
"haraka-test-fixtures": "^1.3.3",
|
|
78
78
|
"mock-require": "^3.0.3",
|
|
79
|
-
"eslint": "^8.
|
|
79
|
+
"eslint": "^8.56.0",
|
|
80
80
|
"eslint-plugin-haraka": "^1.0.15",
|
|
81
|
-
"nodemailer": "^6.9.
|
|
81
|
+
"nodemailer": "^6.9.9"
|
|
82
82
|
},
|
|
83
83
|
"bugs": {
|
|
84
84
|
"mail": "haraka.mail@gmail.com",
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
// Note: You can disable setting `connection.notes.auth_passwd` by `plugin.blankout_password = true`
|
|
6
6
|
|
|
7
7
|
const crypto = require('crypto');
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
const tlds = require('haraka-tld')
|
|
10
|
+
const utils = require('haraka-utils');
|
|
11
|
+
|
|
9
12
|
const AUTH_COMMAND = 'AUTH';
|
|
10
13
|
const AUTH_METHOD_CRAM_MD5 = 'CRAM-MD5';
|
|
11
14
|
const AUTH_METHOD_PLAIN = 'PLAIN';
|
|
@@ -15,7 +18,7 @@ const LOGIN_STRING2 = 'UGFzc3dvcmQ6'; //Password: base64 coded
|
|
|
15
18
|
|
|
16
19
|
exports.hook_capabilities = (next, connection) => {
|
|
17
20
|
// Don't offer AUTH capabilities unless session is encrypted
|
|
18
|
-
if (!connection.tls.enabled)
|
|
21
|
+
if (!connection.tls.enabled) return next();
|
|
19
22
|
|
|
20
23
|
const methods = [ 'PLAIN', 'LOGIN', 'CRAM-MD5' ];
|
|
21
24
|
connection.capabilities.push(`AUTH ${methods.join(' ')}`);
|
|
@@ -47,9 +50,7 @@ exports.hook_unrecognized_command = function (next, connection, params) {
|
|
|
47
50
|
|
|
48
51
|
exports.check_plain_passwd = function (connection, user, passwd, cb) {
|
|
49
52
|
function callback (plain_pw) {
|
|
50
|
-
|
|
51
|
-
if (plain_pw !== passwd) return cb(false);
|
|
52
|
-
cb(true);
|
|
53
|
+
cb(plain_pw === null ? false : plain_pw === passwd);
|
|
53
54
|
}
|
|
54
55
|
if (this.get_plain_passwd.length == 2) {
|
|
55
56
|
this.get_plain_passwd(user, callback);
|
|
@@ -71,7 +72,7 @@ exports.check_cram_md5_passwd = function (connection, user, passwd, cb) {
|
|
|
71
72
|
|
|
72
73
|
if (hmac.digest('hex') === passwd) return cb(true);
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
cb(false);
|
|
75
76
|
}
|
|
76
77
|
if (this.get_plain_passwd.length == 2) {
|
|
77
78
|
this.get_plain_passwd(user, callback);
|
|
@@ -117,7 +118,7 @@ exports.check_user = function (next, connection, credentials, method) {
|
|
|
117
118
|
connection.auth_results(`auth=pass (${method.toLowerCase()})`);
|
|
118
119
|
connection.notes.auth_user = credentials[0];
|
|
119
120
|
if (!plugin.blankout_password) connection.notes.auth_passwd = credentials[1];
|
|
120
|
-
|
|
121
|
+
next(OK);
|
|
121
122
|
});
|
|
122
123
|
return;
|
|
123
124
|
}
|
|
@@ -125,9 +126,7 @@ exports.check_user = function (next, connection, credentials, method) {
|
|
|
125
126
|
if (!connection.notes.auth_fails) connection.notes.auth_fails = 0;
|
|
126
127
|
|
|
127
128
|
connection.notes.auth_fails++;
|
|
128
|
-
connection.results.add({name: 'auth'}, {
|
|
129
|
-
fail:`${plugin.name}/${method}`,
|
|
130
|
-
});
|
|
129
|
+
connection.results.add({name: 'auth'}, { fail:`${plugin.name}/${method}` });
|
|
131
130
|
|
|
132
131
|
let delay = Math.pow(2, connection.notes.auth_fails - 1);
|
|
133
132
|
if (plugin.timeout && delay >= plugin.timeout) {
|
|
@@ -230,7 +229,7 @@ exports.auth_cram_md5 = function (next, connection, params) {
|
|
|
230
229
|
return this.check_user(next, connection, credentials, AUTH_METHOD_CRAM_MD5);
|
|
231
230
|
}
|
|
232
231
|
|
|
233
|
-
const ticket = `<${this.hexi(Math.floor(Math.random() * 1000000))}
|
|
232
|
+
const ticket = `<${this.hexi(Math.floor(Math.random() * 1000000))}.${this.hexi(Date.now())}@${connection.local.host}>`;
|
|
234
233
|
|
|
235
234
|
connection.loginfo(this, `ticket: ${ticket}`);
|
|
236
235
|
connection.respond(334, utils.base64(ticket), () => {
|
|
@@ -240,3 +239,20 @@ exports.auth_cram_md5 = function (next, connection, params) {
|
|
|
240
239
|
}
|
|
241
240
|
|
|
242
241
|
exports.hexi = number => String(Math.abs(parseInt(number)).toString(16))
|
|
242
|
+
|
|
243
|
+
exports.constrain_sender = function (next, connection, params) {
|
|
244
|
+
const au = connection.results.get('auth')?.user
|
|
245
|
+
if (!au) return next()
|
|
246
|
+
|
|
247
|
+
const ad = /@/.test(au) ? au.split('@').pop() : au
|
|
248
|
+
const ed = params[0].host
|
|
249
|
+
|
|
250
|
+
if (!ad || !ed) return next()
|
|
251
|
+
|
|
252
|
+
const auth_od = tlds.get_organizational_domain(ad)
|
|
253
|
+
const envelope_od = tlds.get_organizational_domain(ed)
|
|
254
|
+
|
|
255
|
+
if (auth_od === envelope_od) return next()
|
|
256
|
+
|
|
257
|
+
next(DENY, `Envelope domain '${envelope_od}' doesn't match AUTH domain '${auth_od}'`)
|
|
258
|
+
}
|
|
@@ -4,25 +4,36 @@ const net = require('net');
|
|
|
4
4
|
|
|
5
5
|
exports.register = function () {
|
|
6
6
|
this.inherits('auth/auth_base');
|
|
7
|
-
this.
|
|
7
|
+
this.blankout_password=true
|
|
8
|
+
|
|
9
|
+
this.load_vpopmaild_ini();
|
|
10
|
+
|
|
11
|
+
if (this.cfg.main.constrain_sender) {
|
|
12
|
+
this.register_hook('mail', 'constrain_sender')
|
|
13
|
+
}
|
|
8
14
|
}
|
|
9
15
|
|
|
10
|
-
exports.
|
|
11
|
-
this.cfg = this.config.get('auth_vpopmaild.ini',
|
|
12
|
-
|
|
16
|
+
exports.load_vpopmaild_ini = function () {
|
|
17
|
+
this.cfg = this.config.get('auth_vpopmaild.ini', {
|
|
18
|
+
booleans: [
|
|
19
|
+
'+main.constrain_sender',
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
() => {
|
|
23
|
+
this.load_vpopmaild_ini();
|
|
13
24
|
});
|
|
14
25
|
}
|
|
15
26
|
|
|
16
27
|
exports.hook_capabilities = function (next, connection) {
|
|
17
|
-
if (!connection.tls.enabled)
|
|
28
|
+
if (!connection.tls.enabled) return next();
|
|
18
29
|
|
|
19
30
|
const methods = [ 'PLAIN', 'LOGIN' ];
|
|
20
|
-
if (this.cfg.main.sysadmin)
|
|
31
|
+
if (this.cfg.main.sysadmin) methods.push('CRAM-MD5');
|
|
21
32
|
|
|
22
33
|
connection.capabilities.push(`AUTH ${methods.join(' ')}`);
|
|
23
34
|
connection.notes.allowed_auth_methods = methods;
|
|
24
35
|
|
|
25
|
-
|
|
36
|
+
next();
|
|
26
37
|
}
|
|
27
38
|
|
|
28
39
|
exports.check_plain_passwd = function (connection, user, passwd, cb) {
|
|
@@ -49,11 +60,12 @@ exports.check_plain_passwd = function (connection, user, passwd, cb) {
|
|
|
49
60
|
}
|
|
50
61
|
socket.end(); // disconnect
|
|
51
62
|
}
|
|
52
|
-
})
|
|
63
|
+
})
|
|
64
|
+
|
|
53
65
|
socket.on('end', () => {
|
|
54
66
|
connection.loginfo(this, `AUTH user="${user}" success=${auth_success}`);
|
|
55
|
-
|
|
56
|
-
})
|
|
67
|
+
cb(auth_success);
|
|
68
|
+
})
|
|
57
69
|
}
|
|
58
70
|
|
|
59
71
|
exports.get_sock_opts = function (user) {
|
|
@@ -66,13 +78,11 @@ exports.get_sock_opts = function (user) {
|
|
|
66
78
|
|
|
67
79
|
const domain = (user.split('@'))[1];
|
|
68
80
|
let sect = this.cfg.main;
|
|
69
|
-
if (domain && this.cfg[domain])
|
|
70
|
-
sect = this.cfg[domain];
|
|
71
|
-
}
|
|
81
|
+
if (domain && this.cfg[domain]) sect = this.cfg[domain];
|
|
72
82
|
|
|
73
|
-
if (sect.port)
|
|
74
|
-
if (sect.host)
|
|
75
|
-
if (sect.sysadmin)
|
|
83
|
+
if (sect.port) this.sock_opts.port = sect.port;
|
|
84
|
+
if (sect.host) this.sock_opts.host = sect.host;
|
|
85
|
+
if (sect.sysadmin) this.sock_opts.sysadmin = sect.sysadmin;
|
|
76
86
|
|
|
77
87
|
this.logdebug(`sock: ${this.sock_opts.host}:${this.sock_opts.port}`);
|
|
78
88
|
return this.sock_opts;
|
|
@@ -89,14 +99,14 @@ exports.get_vpopmaild_socket = function (user) {
|
|
|
89
99
|
socket.on('timeout', () => {
|
|
90
100
|
this.logerror("vpopmaild connection timed out");
|
|
91
101
|
socket.end();
|
|
92
|
-
})
|
|
102
|
+
})
|
|
93
103
|
socket.on('error', err => {
|
|
94
104
|
this.logerror(`vpopmaild connection failed: ${err}`);
|
|
95
105
|
socket.end();
|
|
96
|
-
})
|
|
106
|
+
})
|
|
97
107
|
socket.on('connect', () => {
|
|
98
108
|
this.logdebug('vpopmail connected');
|
|
99
|
-
})
|
|
109
|
+
})
|
|
100
110
|
return socket;
|
|
101
111
|
}
|
|
102
112
|
|
|
@@ -3,26 +3,32 @@
|
|
|
3
3
|
exports.register = function () {
|
|
4
4
|
this.inherits('auth/auth_base');
|
|
5
5
|
this.load_flat_ini();
|
|
6
|
+
|
|
7
|
+
if (this.cfg.core.constrain_sender) {
|
|
8
|
+
this.register_hook('mail', 'constrain_sender')
|
|
9
|
+
}
|
|
6
10
|
}
|
|
7
11
|
|
|
8
12
|
exports.load_flat_ini = function () {
|
|
9
|
-
this.cfg = this.config.get('auth_flat_file.ini',
|
|
13
|
+
this.cfg = this.config.get('auth_flat_file.ini', {
|
|
14
|
+
booleans: [
|
|
15
|
+
'+core.constrain_sender',
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
() => {
|
|
10
19
|
this.load_flat_ini();
|
|
11
20
|
});
|
|
21
|
+
|
|
22
|
+
if (this.cfg.users === undefined) this.cfg.users = {}
|
|
12
23
|
}
|
|
13
24
|
|
|
14
25
|
exports.hook_capabilities = function (next, connection) {
|
|
15
|
-
// don't allow AUTH unless private IP or encrypted
|
|
16
26
|
if (!connection.remote.is_private && !connection.tls.enabled) {
|
|
17
|
-
connection.logdebug(this,
|
|
18
|
-
"Auth disabled for insecure public connection");
|
|
27
|
+
connection.logdebug(this, "Auth disabled for insecure public connection");
|
|
19
28
|
return next();
|
|
20
29
|
}
|
|
21
30
|
|
|
22
|
-
|
|
23
|
-
if (this.cfg.core?.methods ) {
|
|
24
|
-
methods = this.cfg.core.methods.split(',');
|
|
25
|
-
}
|
|
31
|
+
const methods = this.cfg.core?.methods ? this.cfg.core.methods.split(',') : null
|
|
26
32
|
if (methods && methods.length > 0) {
|
|
27
33
|
connection.capabilities.push(`AUTH ${methods.join(' ')}`);
|
|
28
34
|
connection.notes.allowed_auth_methods = methods;
|
|
@@ -31,8 +37,7 @@ exports.hook_capabilities = function (next, connection) {
|
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
exports.get_plain_passwd = function (user, connection, cb) {
|
|
34
|
-
if (this.cfg.users[user])
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return cb();
|
|
40
|
+
if (this.cfg.users[user]) return cb(this.cfg.users[user].toString());
|
|
41
|
+
|
|
42
|
+
cb();
|
|
38
43
|
}
|
package/plugins/clamd.js
CHANGED
|
@@ -269,6 +269,7 @@ exports.hook_data_post = function (next, connection) {
|
|
|
269
269
|
if (virus && plugin.rejectRE && // enabled
|
|
270
270
|
plugin.allRE.test(virus) && // has a reject option
|
|
271
271
|
!plugin.rejectRE.test(virus)) { // reject=false set
|
|
272
|
+
txn.add_header('X-Haraka-Virus', virus);
|
|
272
273
|
return next();
|
|
273
274
|
}
|
|
274
275
|
if (!plugin.cfg.reject.virus) { return next(); }
|
package/plugins/helo.checks.js
CHANGED
|
@@ -499,7 +499,7 @@ exports.get_a_records = async function (host) {
|
|
|
499
499
|
err.code = dns.TIMEOUT;
|
|
500
500
|
this.logerror(err);
|
|
501
501
|
throw err;
|
|
502
|
-
}, (this.cfg.main.dns_timeout ||
|
|
502
|
+
}, (this.cfg.main.dns_timeout || 28) * 1000);
|
|
503
503
|
|
|
504
504
|
// fully qualify, to ignore any search options in /etc/resolv.conf
|
|
505
505
|
if (!/\.$/.test(host)) host = `${host}.`;
|
|
@@ -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}`);
|
|
@@ -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 () {
|
package/plugins.js
CHANGED
package/tests/queue/multibyte
CHANGED
|
Binary file
|
package/tests/queue/plain
CHANGED
|
Binary file
|
package/transaction.js
CHANGED
|
@@ -152,7 +152,7 @@ class Transaction {
|
|
|
152
152
|
this.header_lines.push(line.toString(this.encoding).replace(/\r\n$/, '\n'));
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
-
else if (this.
|
|
155
|
+
else if (this.parse_body) {
|
|
156
156
|
let new_line = line;
|
|
157
157
|
if (new_line[0] === 0x2E) new_line = new_line.slice(1); // Strip leading "."
|
|
158
158
|
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
[general]
|
|
2
|
-
nomatch=Please setup matching DNS and rDNS records.
|
|
3
|
-
timeout=60
|
|
4
|
-
timeout_msg=DNS check timed out.
|
|
5
|
-
|
|
6
|
-
[forward]
|
|
7
|
-
nxdomain=Please setup a forward DNS record.
|
|
8
|
-
dnserror=Please setup matching DNS and rDNS records.
|
|
9
|
-
|
|
10
|
-
[reverse]
|
|
11
|
-
nxdomain=Please setup a reverse DNS record.
|
|
12
|
-
dnserror=Please setup matching DNS and rDNS records.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Hostnames and IPs are matched exactly as written on each line.
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# Does the same thing as the whitelist file, but each line is a regex.
|
|
2
|
-
# Each line is also anchored for you, meaning '^' + regex + '$' is added for
|
|
3
|
-
# you. If you need to get around this restriction, you may use a '.*' at
|
|
4
|
-
# either the start or the end of your regex. This should help prevent people
|
|
5
|
-
# from writing overly permissive rules on accident.
|
package/config/rcpt_to.blocklist
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# This is a blocklist for the rcpt_to line. One address per line.
|
|
File without changes
|
package/config/rdns.deny_regexps
DELETED
|
File without changes
|
package/config.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
relay\_acl
|
|
2
|
-
========
|
|
3
|
-
|
|
4
|
-
This plugin makes it possible to relay outbound mails using IP based ACLs
|
|
5
|
-
and relay inbound mails using destination domains.
|
|
6
|
-
|
|
7
|
-
Configuration
|
|
8
|
-
-------------
|
|
9
|
-
|
|
10
|
-
* `config/relay_acl_allow`
|
|
11
|
-
Allowed IP ranges in CIDR notation, one per line.
|
|
12
|
-
IPs listed in here will be allowed to send mails without any furthur
|
|
13
|
-
checks.
|
|
14
|
-
|
|
15
|
-
* `config/relay_dest_domains.ini`
|
|
16
|
-
Allowed destination domains. The format is in ini file, the domain
|
|
17
|
-
is the key and the value is in JSON, all under the [domains] section.
|
|
18
|
-
Currently supported field is "action": where the value can be
|
|
19
|
-
"accept" (accept the mail without further checks), "continue" (mails
|
|
20
|
-
are still subjected to further checks) or "deny" (reject the mails).
|
|
21
|
-
|
|
22
|
-
An example:
|
|
23
|
-
|
|
24
|
-
[domains]
|
|
25
|
-
test.com = { "action": "continue" }
|
|
26
|
-
|
|
27
|
-
Please note that this config/relay\_dest\_domains.ini is shared with
|
|
28
|
-
plugins/relay\_force\_routing.js, which uses additional fields.
|
|
29
|
-
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
relay\_all
|
|
2
|
-
=========
|
|
3
|
-
|
|
4
|
-
This plugin is useful in spamtraps to accept mail to any host, and to allow
|
|
5
|
-
any user from anywhere to send email.
|
|
6
|
-
|
|
7
|
-
Do NOT use this plugin on a real mail server, unless you really know what
|
|
8
|
-
you are doing. If you use this plugin with anything that relays mail (such
|
|
9
|
-
as forwarding to a real mail server, or the `deliver` plugin), your mail
|
|
10
|
-
server is now an open relay.
|
|
11
|
-
|
|
12
|
-
This is BAD. Hence the big letters. In short: DO NOT USE THIS PLUGIN.
|
|
13
|
-
|
|
14
|
-
It is useful for testing, hence why it is here. Also I work with spamtraps
|
|
15
|
-
a lot, so it is useful there.
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
relay\_force\_routing.js
|
|
2
|
-
========
|
|
3
|
-
|
|
4
|
-
This plugin allows you to force the next hop for the configured domains.
|
|
5
|
-
It works a lot like the transport map of Postfix.
|
|
6
|
-
|
|
7
|
-
Configuration
|
|
8
|
-
-------------
|
|
9
|
-
|
|
10
|
-
* `config/relay_dest_domains.ini`
|
|
11
|
-
This config file is shared with relay\_acl.js, for the basics see the
|
|
12
|
-
documentation provided by plugins/relay\_acl.js.
|
|
13
|
-
|
|
14
|
-
relay\_force\_routing.js adds the field "nexthop": in the JSON value
|
|
15
|
-
of the domain. The value of "nexthop": can be hostname or IP optionally
|
|
16
|
-
follow by :port.
|
|
17
|
-
|
|
18
|
-
Example:
|
|
19
|
-
|
|
20
|
-
[domains]
|
|
21
|
-
test.com = { "action": "continue", "nexthop": "127.0.0.1:2525" }
|
|
22
|
-
|
|
23
|
-
You can also define a default relay using the "any" domain, which will be
|
|
24
|
-
used if the message's destination domain doesn't match any of the domains
|
|
25
|
-
already defined.
|
|
26
|
-
|
|
27
|
-
Example:
|
|
28
|
-
```
|
|
29
|
-
[domains]
|
|
30
|
-
test.com = { "action": "continue", "nexthop": "127.0.0.1:2525" }
|
|
31
|
-
my.test.com = { "action": "continue", "nexthop": "127.0.0.1:2527" }
|
|
32
|
-
any = { "action": "continue", "nexthop": "10.10.10.1:2525"}
|
|
33
|
-
```
|
package/plugins/data.headers.js
DELETED
package/plugins/relay_all.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Just relay everything - could be useful for a spamtrap
|
|
2
|
-
|
|
3
|
-
exports.register = function () {
|
|
4
|
-
this.logerror(this, "deprecated. see 'haraka -h relay'");
|
|
5
|
-
this.register_hook('rcpt', 'confirm_all');
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
exports.confirm_all = function (next, connection, params) {
|
|
9
|
-
const recipient = params.shift();
|
|
10
|
-
connection.loginfo(this, `confirming recipient ${recipient}`);
|
|
11
|
-
connection.relaying = true;
|
|
12
|
-
next(OK);
|
|
13
|
-
}
|
|
File without changes
|