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.
Files changed (50) hide show
  1. package/Changes.md +31 -0
  2. package/Dockerfile +3 -3
  3. package/Plugins.md +5 -4
  4. package/README.md +4 -4
  5. package/TODO +1 -24
  6. package/config/access.domains +1 -1
  7. package/config/auth_flat_file.ini +1 -0
  8. package/config/auth_vpopmaild.ini +4 -2
  9. package/config/helo.checks.ini +1 -1
  10. package/config/rabbitmq_amqplib.ini +8 -1
  11. package/docs/Connection.md +1 -1
  12. package/docs/Outbound.md +6 -15
  13. package/docs/Plugins.md +46 -39
  14. package/docs/Transaction.md +1 -1
  15. package/docs/{plugins → deprecated}/connect.rdns_access.md +1 -1
  16. package/docs/{plugins → deprecated}/mail_from.access.md +1 -1
  17. package/docs/{plugins → deprecated}/rcpt_to.access.md +1 -1
  18. package/docs/plugins/auth/auth_vpopmaild.md +15 -19
  19. package/docs/plugins/auth/flat_file.md +23 -30
  20. package/docs/plugins/queue/rabbitmq_amqplib.md +7 -0
  21. package/docs/plugins/queue/smtp_forward.md +1 -1
  22. package/docs/plugins/relay.md +2 -2
  23. package/outbound/hmail.js +2 -2
  24. package/outbound/queue.js +5 -0
  25. package/package.json +26 -26
  26. package/plugins/auth/auth_base.js +27 -11
  27. package/plugins/auth/auth_vpopmaild.js +29 -19
  28. package/plugins/auth/flat_file.js +17 -12
  29. package/plugins/clamd.js +1 -0
  30. package/plugins/helo.checks.js +1 -1
  31. package/plugins/queue/rabbitmq_amqplib.js +1 -1
  32. package/plugins/queue/smtp_forward.js +3 -3
  33. package/plugins.js +1 -0
  34. package/tests/queue/multibyte +0 -0
  35. package/tests/queue/plain +0 -0
  36. package/transaction.js +1 -1
  37. package/config/lookup_rdns.strict.ini +0 -12
  38. package/config/lookup_rdns.strict.timeout +0 -1
  39. package/config/lookup_rdns.strict.whitelist +0 -1
  40. package/config/lookup_rdns.strict.whitelist_regex +0 -5
  41. package/config/rcpt_to.blocklist +0 -1
  42. package/config/rdns.allow_regexps +0 -0
  43. package/config/rdns.deny_regexps +0 -0
  44. package/config.js +0 -6
  45. package/docs/plugins/relay_acl.md +0 -29
  46. package/docs/plugins/relay_all.md +0 -15
  47. package/docs/plugins/relay_force_routing.md +0 -33
  48. package/plugins/data.headers.js +0 -4
  49. package/plugins/relay_all.js +0 -13
  50. /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:master
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 python-software-properties g++ make git curl
27
- RUN curl -sL https://deb.nodesource.com/setup_10.x | setuser root bash -
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](plugins-doc) section of [the manual](https://haraka.github.io)
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/manual/Plugins.html
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]: https://haraka.github.io/manual/plugins/spamassassin.html
144
- [10]: https://haraka.github.io/manual/plugins/helo.checks.html
145
- [11]: https://haraka.github.io/manual/plugins/dnsbl.html
146
- [12]: https://github.com/haraka/Haraka/tree/master/plugins
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
- - uses the same TLS/SSL certs as smtpd
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
@@ -10,4 +10,4 @@
10
10
  # aol.com
11
11
  # !friend@aol.com
12
12
  #
13
- # See full docs for details: http://haraka.github.io/manual/plugins/access.html
13
+ # See full docs for details: http://haraka.github.io/plugins/access
@@ -1,5 +1,6 @@
1
1
  [core]
2
2
  methods=CRAM-MD5
3
+ ; constrain_sender=true
3
4
 
4
5
  [users]
5
6
  ; matt=test
@@ -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
@@ -1,6 +1,6 @@
1
1
  ; disable checks or reject for each test if you are worried about strictness
2
2
 
3
- ;dns_timeout=30
3
+ ;dns_timeout=28
4
4
 
5
5
  [check]
6
6
  ; match_re=true
@@ -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
@@ -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 [docs/Results](http://haraka.github.io/manual/Results.html)
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 `tls`
42
- plugin uses, along with other values in `tls.ini`. See the [tls plugin
43
- docs](http://haraka.github.io/manual/plugins/tls.html) for information on generating those files.
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 (note do not set this manually,
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 or during the reception of the message
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
- exports.register = function() {
46
- this.register_hook('rcpt', 'my_rcpt_validate');
47
- };
44
+ ```js
45
+ exports.register = function () {
46
+ this.register_hook('rcpt', 'my_rcpt_validate')
47
+ };
48
48
 
49
- exports.my_rcpt_validate = function (next, connection, params) {
50
- // do processing
51
- next();
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
- exports.hook_rcpt = function (next, connection, params) {
57
- // do processing
58
- next();
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
- 1. register a hook multiple times (see below)
64
- 2. a unique function name in stack traces
65
- 3. [a better function name](https://google.com/search?q=programming%20good%20function%20names)
66
- 4. hooks can be registered conditionally (ie, based on a config setting)
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
- exports.register = function() {
73
- this.register_hook('queue', 'try_queue_my_way');
74
- this.register_hook('queue', 'try_queue_highway');
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
- exports.register = function() {
85
- this.register_hook('rcpt', 'my_rcpt');
86
- this.register_hook('rcpt_ok', 'my_rcpt');
87
- };
88
-
89
- exports.my_rcpt = function (next, connection, params) {
90
- var hook_name = connection.hook; // rcpt or rcpt_ok
91
- // email address is in params[0]
92
- // do processing
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
- var plugin = this;
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
- exports.shutdown = function () {
374
- clearInterval(this._interval);
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
@@ -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 [docs/Results](http://haraka.github.io/manual/Results.html)
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,6 +1,6 @@
1
1
  ## DEPRECATION NOTICE
2
2
 
3
- See the [access](http://haraka.github.io/manual/plugins/access.html) plugin
3
+ See [haraka-plugin-access](https://github.com/haraka/haraka-plugin-access)
4
4
  for upgrade instructions.
5
5
 
6
6
 
@@ -1,6 +1,6 @@
1
1
  ## DEPRECATION NOTICE
2
2
 
3
- See the [access](http://haraka.github.io/manual/plugins/access.html) plugin
3
+ See [haraka-plugin-access](https://github.com/haraka/haraka-plugin-access)
4
4
  for upgrade instructions.
5
5
 
6
6
 
@@ -1,6 +1,6 @@
1
1
  ## DEPRECATION NOTICE
2
2
 
3
- See the [access](http://haraka.github.io/manual/plugins/access.html) plugin
3
+ See [haraka-plugin-access](https://github.com/haraka/haraka-plugin-access)
4
4
  for upgrade instructions.
5
5
 
6
6
 
@@ -1,26 +1,20 @@
1
- auth/auth\_vpopmaild
2
- ===============
1
+ # auth/auth\_vpopmaild
3
2
 
4
- The `auth/vpopmaild` plugin allows you to authenticate against a vpopmaild
5
- daemon.
3
+ The `auth/vpopmaild` plugin allows SMTP users to authenticate against a vpopmaild daemon.
6
4
 
7
5
  ## Configuration
8
6
 
9
- Configuration is stored in `config/auth_vpopmaild.ini` and uses INI
10
- style formatting.
7
+ The configuration file is stored in `config/auth_vpopmaild.ini`.
11
8
 
12
- There are three configuration settings:
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
- SYSADMIN privileges (see vpopmail/bin/vmoduser -S). This is **only**
20
- necessary to support CRAM-MD5 which requires access to the clear text
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
- [example.com]
33
- host=192.168.0.1
34
- port=999
26
+ ```ini
27
+ [example.com]
28
+ host=192.168.0.1
29
+ port=999
35
30
 
36
- [example2.com]
37
- host=192.168.0.2
38
- sysadmin=postmaster@example2.com:sekret
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
- before it will advertise AUTH capabilities by the EHLO command. This is to
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` and uses the INI
24
- style formatting.
14
+ Configuration is stored in `config/auth_flat_file.ini`.
25
15
 
26
- Authentication methods are listed in the `[core]` section under `methods`
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
- Example:
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
- [core]
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
- [users]
43
- user1=password1
44
- user@domain.com=password2
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, 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.
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.
@@ -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 [authentication](http://haraka.github.io/manual.html) via the auth plugins. Successful authentication enables relaying during _that_ SMTP connection. To securely offer SMTP AUTH, the [tls](http://haraka.github.io/manual/plugins/tls.html) 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.
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
- I 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/manual/plugins/rcpt_to.in_host_list.html) plugin is that this one also enables relaying.
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.2",
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.0.1",
23
+ "address-rfc2821": "^2.1.1",
24
24
  "address-rfc2822": "^2.1.0",
25
- "async": "^3.2.4",
25
+ "async": "^3.2.5",
26
26
  "daemon": "~1.1.0",
27
27
  "ipaddr.js": "~2.1.0",
28
- "node-gyp": "^9.4.0",
28
+ "node-gyp": "^10.0.1",
29
29
  "nopt": "~7.2.0",
30
30
  "npid": "~0.4.0",
31
- "semver": "~7.5.2",
32
- "sprintf-js": "~1.1.2",
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.0",
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.0",
42
- "haraka-plugin-redis": "^2.0.5",
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.1.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.1",
53
- "haraka-plugin-auth-ldap": "^1.0.2",
54
- "haraka-plugin-dcc": "^1.0.1",
55
- "haraka-plugin-elasticsearch": "^1.0.6",
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.0",
61
- "haraka-plugin-limit": "^1.1.0",
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.8",
65
- "haraka-plugin-rcpt-ldap": "^1.0.0",
66
- "haraka-plugin-recipient-routes": "^1.0.4",
67
- "haraka-plugin-rspamd": "^1.2.0",
68
- "haraka-plugin-syslog": "^1.0.3",
69
- "haraka-plugin-uribl": "^1.0.6",
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": "^4.5.1",
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.0",
77
+ "haraka-test-fixtures": "^1.3.3",
78
78
  "mock-require": "^3.0.3",
79
- "eslint": "^8.42.0",
79
+ "eslint": "^8.56.0",
80
80
  "eslint-plugin-haraka": "^1.0.15",
81
- "nodemailer": "^6.9.3"
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
- const utils = require('haraka-utils');
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) { return next(); }
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
- if (plain_pw === null ) return cb(false);
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
- return cb(false);
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
- return next(OK);
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))}. ${this.hexi(Date.now())}@${connection.local.host}>`;
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.load_vpop_ini();
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.load_vpop_ini = function () {
11
- this.cfg = this.config.get('auth_vpopmaild.ini', () => {
12
- this.load_vpop_ini();
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) { return next(); }
28
+ if (!connection.tls.enabled) return next();
18
29
 
19
30
  const methods = [ 'PLAIN', 'LOGIN' ];
20
- if (this.cfg.main.sysadmin) { methods.push('CRAM-MD5'); }
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
- return next();
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
- return cb(auth_success);
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) { 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; }
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
- let methods = null;
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
- return cb(this.cfg.users[user].toString());
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(); }
@@ -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 || 30) * 1000);
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
@@ -363,6 +363,7 @@ plugins.deprecated = {
363
363
  'rcpt_to.qmail_deliverable' : 'qmail-deliverable',
364
364
  'rdns.regexp' : 'access',
365
365
  'relay_acl' : 'relay',
366
+ 'relay_all' : 'relay',
366
367
  'relay_force_routing' : 'relay',
367
368
  }
368
369
 
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.header_pos && this.parse_body) {
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.
@@ -1 +0,0 @@
1
- # This is a blocklist for the rcpt_to line. One address per line.
File without changes
File without changes
package/config.js DELETED
@@ -1,6 +0,0 @@
1
- 'use strict'
2
-
3
- module.exports = require('haraka-config')
4
-
5
- // use emit is the same way util.deprecate does it, so follow that style
6
- process.emit('warning', 'Loading config via require("./config") is deprecated, please use: require("haraka-config") instead.')
@@ -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
- ```
@@ -1,4 +0,0 @@
1
-
2
- exports.register = function () {
3
- this.logerror(this, "data.headers is deprecated, remove it from config/plugins. See 'haraka -h headers'");
4
- }
@@ -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