Haraka 3.1.4 → 3.1.6

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 (55) hide show
  1. package/.prettierignore +1 -1
  2. package/{Changes.md → CHANGELOG.md} +34 -0
  3. package/CONTRIBUTORS.md +26 -26
  4. package/README.md +68 -93
  5. package/SECURITY.md +178 -0
  6. package/bin/haraka +7 -14
  7. package/config/plugins +0 -3
  8. package/docs/Connection.md +126 -39
  9. package/docs/CoreConfig.md +92 -74
  10. package/docs/HAProxy.md +41 -25
  11. package/docs/Logging.md +68 -38
  12. package/docs/Outbound.md +124 -179
  13. package/docs/Plugins.md +38 -59
  14. package/docs/Transaction.md +78 -83
  15. package/docs/Tutorial.md +122 -209
  16. package/docs/plugins/aliases.md +1 -141
  17. package/docs/plugins/auth/auth_ldap.md +2 -39
  18. package/docs/plugins/max_unrecognized_commands.md +4 -18
  19. package/docs/plugins/process_title.md +3 -3
  20. package/docs/plugins/reseed_rng.md +11 -13
  21. package/docs/plugins/tls.md +7 -7
  22. package/docs/plugins/toobusy.md +10 -4
  23. package/docs/tutorials/SettingUpOutbound.md +40 -48
  24. package/endpoint.js +32 -2
  25. package/outbound/hmail.js +3 -2
  26. package/outbound/index.js +3 -0
  27. package/package.json +21 -34
  28. package/plugins/queue/smtp_forward.js +4 -4
  29. package/run_tests +3 -15
  30. package/server.js +17 -7
  31. package/smtp_client.js +8 -6
  32. package/test/connection.js +234 -0
  33. package/test/endpoint.js +32 -4
  34. package/test/host_pool.js +57 -31
  35. package/test/logger.js +75 -135
  36. package/test/outbound/bounce_net_errors.js +87 -131
  37. package/test/outbound/bounce_rfc3464.js +177 -254
  38. package/test/outbound/hmail.js +19 -0
  39. package/test/outbound/index.js +189 -0
  40. package/test/outbound/queue.js +92 -0
  41. package/test/plugins/auth/auth_base.js +39 -44
  42. package/test/plugins/auth/auth_vpopmaild.js +8 -9
  43. package/test/plugins/queue/smtp_forward.js +953 -183
  44. package/test/plugins/rcpt_to.host_list_base.js +58 -93
  45. package/test/plugins/rcpt_to.in_host_list.js +126 -175
  46. package/test/plugins/record_envelope_addresses.js +8 -8
  47. package/test/plugins/status.js +10 -10
  48. package/test/plugins/tls.js +9 -19
  49. package/test/plugins/xclient.js +75 -110
  50. package/test/plugins.js +10 -13
  51. package/test/rfc1869.js +50 -70
  52. package/test/server.js +438 -421
  53. package/test/smtp_client.js +1192 -218
  54. package/test/tls_socket.js +242 -0
  55. package/tls_socket.js +18 -22
package/README.md CHANGED
@@ -1,144 +1,119 @@
1
- ## Haraka - a Node.js Mail Server
1
+ # Haraka a Node.js Mail Server
2
2
 
3
3
  ![Tests](https://github.com/haraka/Haraka/actions/workflows/ci.yml/badge.svg)
4
4
  [![Coverage Status][cov-img]][cov-url]
5
5
 
6
- Haraka is a highly scalable [node.js][1] email server with a modular
7
- plugin architecture. Haraka can serve thousands of concurrent connections
8
- and deliver thousands of messages per second. Haraka and plugins are written
9
- in asynchronous JS and are very fast.
6
+ Haraka is a highly scalable [Node.js][1] SMTP server with a modular plugin architecture. It handles thousands of concurrent connections and delivers thousands of messages per second. Haraka and its plugins are written in asynchronous JavaScript, optimised for throughput and low latency.
10
7
 
11
- Haraka has very good spam protection (see [plugins][4]) and works
12
- well as a filtering [MTA][3]. It also works well as a [MSA][5] running on
13
- port 587 with auth and [dkim][6] plugins enabled.
8
+ Haraka offers strong spam protection (see [Plugins.md][plugins]) and is widely deployed as a filtering [MTA][3] or as a [MSA][5] on port 465 (and legacy 587) with the auth and [DKIM][6] plugins enabled.
14
9
 
15
- Haraka makes no attempt to be a mail store (like Exchange or Postfix/Exim/Qmail),
16
- a [LDA][7], nor an IMAP server (like Dovecot or Courier). Haraka is
17
- typically used **with** such systems.
10
+ Haraka is not a mail store, an [LDA][7], or an IMAP server. It is designed to work **alongside** those systems. A scalable outbound delivery engine is built in: mail flagged as `relaying` (for example, by an auth plugin) is queued for
11
+ outbound delivery automatically.
18
12
 
19
- Haraka has a scalable outbound mail delivery engine built in. Mail
20
- marked as `relaying` (such as via an `auth` plugin) is automatically
21
- queued for outbound delivery.
13
+ ## Plugin Architecture
22
14
 
23
- ### Getting Help
15
+ Haraka's defining feature is its plugin system. Every SMTP transaction is a sequence of well-defined hooks — `connect`, `helo`, `mail`, `rcpt`, `data`, `data_post`, `queue`, and more — and each hook can be extended with a few lines of JavaScript. Plugins are asynchronous by default, so a slow lookup against DNS, Redis, or an HTTP API never blocks the server.
24
16
 
25
- - [Join the mailing list][8] (implemented as a Haraka plugin)
26
- - [GitHub Issues][15]
17
+ The result is that behaviours which would require a custom MTA elsewhere are typically a small file in Haraka. For example, accepting qmail-style tagged addresses (`user-anything@domain.com`) and rewriting them to `user@domain.com` before forwarding to an Exchange or IMAP backend looks roughly like this:
27
18
 
28
- ### Screencast
19
+ ```js
20
+ exports.hook_rcpt = (next, connection, params) => {
21
+ const rcpt = params[0]
22
+ const [user] = rcpt.user.split('-')
23
+ rcpt.user = user
24
+ next()
25
+ }
26
+ ```
29
27
 
30
- [Getting started with Haraka][2]
28
+ A comprehensive registry of community and core plugins — auth, DNSBLs, DKIM, SpamAssassin, rspamd, Redis, ClamAV, queue backends, and many others — lives in [Plugins.md][plugins]. To write your own, see the [plugin tutorial][tutorial].
31
29
 
32
- ### Why Use Haraka?
30
+ ## Documentation
33
31
 
34
- Haraka's plugin architecture provides an easily extensible MTA that
35
- complements traditional MTAs that excel at managing mail stores but do
36
- not have sufficient filtering.
32
+ - [Plugins.md][plugins] plugin registry and configuration reference
33
+ - [docs/][docs] core documentation (Connection, Transaction, Outbound, …)
34
+ - [Tutorial][tutorial] step-by-step getting started guide
35
+ - [CHANGELOG.md][changelog] — release notes
36
+ - [SECURITY.md][security] — security policy and reporting
37
37
 
38
- The plugin system makes it easy to code new features. A typical example
39
- is providing qmail-like extended addresses to an Exchange system,
40
- whereby you could receive mail as `user-anyword@domain.com`, and yet
41
- still have it correctly routed to `user@domain.com`. This is a few lines of
42
- code in Haraka.
38
+ ## Getting Help
43
39
 
44
- Plugins are provided for running mail through [SpamAssassin][9], validating
45
- [HELO][10] names, checking [DNS Blocklists][11], and [many others][12].
40
+ - [GitHub Issues][issues]
41
+ - [Mailing list][mailing-list] (implemented as a Haraka plugin)
42
+ - [Screencast: Getting started with Haraka][screencast]
46
43
 
47
- ### Installing Haraka
44
+ ## Installation
48
45
 
49
- Haraka requires [node.js][1] to run. Install Haraka with [npm][2]:
46
+ Haraka requires [Node.js][1]. Install via [npm][npm]:
50
47
 
51
48
  ```sh
52
- # If the second command gives "nobody" errors, uncomment & run the next command
53
- # npm -g config set user root
54
49
  npm install -g Haraka
55
50
  ```
56
51
 
57
- After installation, use the `haraka` binary to set up the service.
58
-
59
- ### Running Haraka
60
-
61
- First, create the service:
52
+ Create a service directory:
62
53
 
63
54
  ```sh
64
55
  haraka -i /path/to/haraka_test
65
56
  ```
66
57
 
67
- That creates the directory `haraka_test` with `config` and `plugin`
68
- directories within. It also sets the host name used by Haraka
69
- to the output of `hostname`.
58
+ This creates `haraka_test` with `config/` and `plugins/` subdirectories and sets the host name from `hostname(1)`. Edit `config/host_list` to add the domains for which Haraka should accept mail.
70
59
 
71
- If `hostname` is not correct, edit `config/host_list`. For example,
72
- to receive mail addressed to `user@domain.com`, add `domain.com` to the
73
- `config/host_list` file.
74
-
75
- Finally, start Haraka using root permissions:
60
+ Start Haraka:
76
61
 
77
62
  ```sh
78
63
  haraka -c /path/to/haraka_test
79
64
  ```
80
65
 
81
- And it will run.
82
-
83
- ### Configure Haraka
66
+ ## Configuration
84
67
 
85
- To choose which plugins run, edit `config/plugins`. Plugins control the
86
- overall behaviour of Haraka. By default, only messages to domains listed
87
- in `config/host_list` will be accepted and then delivered via the
88
- `smtp-forward` plugin. Configure the destination in `config/smtp_forward.ini`.
68
+ Edit `config/plugins` to select active plugins. By default, mail addressed to domains in `config/host_list` is accepted and forwarded via the `smtp-forward` plugin (configured in `config/smtp_forward.ini`).
89
69
 
90
- ### Read the Fine Manual
70
+ Per-plugin documentation is available via:
91
71
 
92
72
  ```sh
93
- haraka -h plugins/$name
73
+ haraka -h plugins/<name>
94
74
  ```
95
75
 
96
- The docs detail how each plugin is configured. After editing
97
- `config/plugins`, restart Haraka and enjoy!
98
-
99
- ### Running from git
76
+ See [Plugins.md][plugins] for the full registry.
100
77
 
101
- If you are unable to use npm to install Haraka, you can run from git by
102
- following these steps:
78
+ ## Running from Source
103
79
 
104
- First clone the repository:
105
-
106
- $ git clone https://github.com/haraka/Haraka.git
107
- $ cd Haraka
108
-
109
- Install Haraka's node.js dependencies locally:
110
-
111
- $ npm install
112
-
113
- Edit `config/plugins` and `config/smtp.ini` to specify the plugins and
114
- config you want.
80
+ ```sh
81
+ git clone https://github.com/haraka/Haraka.git
82
+ cd Haraka
83
+ npm install
84
+ node haraka.js
85
+ ```
115
86
 
116
- Finally run Haraka:
87
+ ## Authorship and Maintenance
117
88
 
118
- $ node haraka.js
89
+ Haraka was created by [Matt Sergeant][matt-sergeant] (`baudehlo`), formerly project leader of [SpamAssassin][spamassassin] and a contributor to [Qpsmtpd][qpsmtpd]. The project is currently maintained by
90
+ [Matt Simerson][msimerson] (`msimerson`).
119
91
 
120
- ### License and Author
92
+ Haraka is the work of many hands. See [CONTRIBUTORS.md][contributors] for the full list of people who have contributed code, documentation, and plugins.
121
93
 
122
- Haraka is MIT licensed - see the [LICENSE][16] file for details.
94
+ ## License
123
95
 
124
- Haraka is a project started by [Matt Sergeant][17], a 10 year veteran of the email and anti-spam world. Previous projects have been the project leader for
125
- SpamAssassin and a hacker on [Qpsmtpd][13].
96
+ Haraka is released under the MIT License. See [LICENSE][license] for details.
126
97
 
127
- [1]: http://nodejs.org/
128
- [2]: http://youtu.be/6twKXMAsPsw
129
- [3]: http://en.wikipedia.org/wiki/Message_transfer_agent
130
- [4]: https://github.com/haraka/Haraka/blob/master/Plugins.md
131
- [5]: http://en.wikipedia.org/wiki/Mail_submission_agent
98
+ [1]: https://nodejs.org/
99
+ [3]: https://en.wikipedia.org/wiki/Message_transfer_agent
100
+ [5]: https://en.wikipedia.org/wiki/Message_submission_agent
132
101
  [6]: https://github.com/haraka/haraka-plugin-dkim
133
102
  [7]: https://en.wikipedia.org/wiki/Mail_delivery_agent
134
- [8]: mailto:haraka-sub@harakamail.com
135
- [9]: https://haraka.github.io/plugins/spamassassin
136
- [10]: https://haraka.github.io/plugins/helo.checks
137
- [11]: https://haraka.github.io/plugins/dnsbl
138
- [12]: https://github.com/haraka/Haraka/blob/master/Plugins.md
139
- [13]: https://github.com/smtpd/qpsmtpd/
140
- [15]: https://github.com/haraka/Haraka/issues
141
- [16]: https://github.com/haraka/Haraka/blob/master/LICENSE
142
- [17]: https://github.com/baudehlo
103
+ [npm]: https://www.npmjs.com/package/Haraka
104
+ [plugins]: https://github.com/haraka/Haraka/blob/master/Plugins.md
105
+ [docs]: https://github.com/haraka/Haraka/tree/master/docs
106
+ [tutorial]: https://github.com/haraka/Haraka/blob/master/docs/Tutorial.md
107
+ [changelog]: https://github.com/haraka/Haraka/blob/master/CHANGELOG.md
108
+ [security]: https://github.com/haraka/Haraka/blob/master/SECURITY.md
109
+ [contributors]: https://github.com/haraka/Haraka/blob/master/CONTRIBUTORS.md
110
+ [license]: https://github.com/haraka/Haraka/blob/master/LICENSE
111
+ [issues]: https://github.com/haraka/Haraka/issues
112
+ [mailing-list]: mailto:haraka-sub@harakamail.com
113
+ [screencast]: https://youtu.be/6twKXMAsPsw
114
+ [matt-sergeant]: https://github.com/baudehlo
115
+ [msimerson]: https://github.com/msimerson
116
+ [spamassassin]: https://spamassassin.apache.org/
117
+ [qpsmtpd]: https://github.com/smtpd/qpsmtpd/
143
118
  [cov-img]: https://codecov.io/github/haraka/Haraka/coverage.svg
144
119
  [cov-url]: https://codecov.io/github/haraka/Haraka?branch=master
package/SECURITY.md ADDED
@@ -0,0 +1,178 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ Security fixes are applied to the **current release** only. We encourage all users to run the latest version.
6
+
7
+ | Version | Supported |
8
+ | -------------- | --------- |
9
+ | 3.1.x (latest) | ✅ |
10
+ | < 3.1 | ❌ |
11
+
12
+ ## Reporting a Vulnerability
13
+
14
+ **Please do not report security vulnerabilities through public GitHub issues.**
15
+
16
+ Use [GitHub Private Vulnerability Reporting](https://github.com/haraka/Haraka/security/advisories/new) to disclose security issues confidentially. This allows the maintainers to assess and patch the issue before public disclosure.
17
+
18
+ Include as much of the following as possible:
19
+
20
+ - A description of the vulnerability and its potential impact
21
+ - Steps to reproduce or a proof-of-concept
22
+ - Affected version(s)
23
+ - Any suggested mitigations or patches
24
+
25
+ ## Response Process
26
+
27
+ 1. **Acknowledgement** — We aim to acknowledge reports within **72 hours**.
28
+ 2. **Assessment** — We will confirm the issue, determine severity, and identify affected versions.
29
+ 3. **Fix & Release** — A patch release will be prepared and coordinated with the reporter.
30
+ 4. **Disclosure** — A GitHub Security Advisory (and CVE if applicable) will be published after the fix is available.
31
+
32
+ We follow [coordinated vulnerability disclosure](https://vuls.cert.org/confluence/display/CVD). Reporters are credited in the advisory unless they prefer otherwise.
33
+
34
+ ## Security Advisories
35
+
36
+ Published advisories are listed at:
37
+ **https://github.com/haraka/Haraka/security/advisories**
38
+
39
+ ## Threat Model
40
+
41
+ Haraka is an SMTP server and plugin host. It accepts inbound network
42
+ connections, parses SMTP commands and message content, and can deliver mail
43
+ outbound when an operator enables relaying or outbound.
44
+
45
+ This threat model assumes the operator controls the host, configuration,
46
+ enabled plugins, credentials, TLS material, and any external services Haraka
47
+ is configured to use.
48
+
49
+ ### Data flow
50
+
51
+ ```mermaid
52
+ flowchart LR
53
+ client["SMTP client<br/>(untrusted)"]
54
+ dns["DNS resolver<br/>(untrusted)"]
55
+ peer["Outbound peer<br/>(untrusted)"]
56
+ operator(["Operator<br/>(trusted)"])
57
+ subgraph haraka["Haraka process — trust boundary"]
58
+ listener["Listener / TLS / Parser"] --> plugins["Plugin pipeline"]
59
+ plugins --> queue[("Queue · FS")]
60
+ queue --> delivery["Delivery"]
61
+ stores[("Config · TLS keys · Logs")]
62
+ end
63
+ client <--> listener
64
+ plugins <--> dns
65
+ delivery --> peer
66
+ operator -.-> stores
67
+ operator -.-> plugins
68
+ ```
69
+
70
+ The trust boundary is the Haraka process. External peers (SMTP clients, DNS
71
+ resolvers, outbound peers) are untrusted; data crossing the boundary inbound
72
+ must be validated before it affects delivery, state, or process behavior.
73
+ Inside the boundary, plugins, the queue, configuration, TLS material, and
74
+ logs share the Haraka process privilege and are the operator's
75
+ responsibility — they are not a security boundary against each other.
76
+
77
+ ### Assets
78
+
79
+ The assets Haraka aims to protect:
80
+
81
+ - **Message content** in transit and queued on disk
82
+ - **AUTH credentials** received via SMTP AUTH, and any upstream credentials
83
+ Haraka holds for outbound or backend services
84
+ - **TLS private keys** and certificates used by the listener and for
85
+ outbound delivery
86
+ - **Queue integrity** — no injection, alteration, or deletion of queued
87
+ messages from outside the trust boundary
88
+ - **Availability** of the SMTP service to legitimate clients
89
+ - **Sender reputation** of the operator's deployment — Haraka must not be
90
+ abusable as an open relay or spam amplifier under documented
91
+ configuration
92
+
93
+ ### Entry points and actors
94
+
95
+ Untrusted data enters Haraka through:
96
+
97
+ - **SMTP listeners** on the operator-configured ports (typically 25, 465,
98
+ 587, and any additional listeners enabled by plugins or configuration)
99
+ - **PROXY protocol or XCLIENT metadata** when the operator has enabled
100
+ trusted-relay forwarding
101
+ - **DNS responses** to lookups performed by Haraka core or plugins
102
+ (rDNS, SPF, DKIM, MX, DNSBL, etc.)
103
+ - **Outbound SMTP responses** received from peers during delivery
104
+
105
+ Haraka distinguishes these actors:
106
+
107
+ - **Anonymous SMTP client** — connecting from the network without
108
+ authentication; trusted only to issue SMTP commands subject to policy
109
+ - **Authenticated submission user** — passed SMTP AUTH; trusted with the
110
+ envelope and policy the operator's auth backend permits, nothing more
111
+ - **Trusted relay peer** — a network source the operator has configured to
112
+ bypass certain checks (e.g. permitted to relay, or whose PROXY/XCLIENT
113
+ metadata is honored)
114
+ - **Operator** — controls the host, configuration, and installed plugins;
115
+ fully trusted
116
+ - **Plugin code** — runs inside the trust boundary with full process
117
+ privilege; treated as trusted-as-installed, and not a security boundary
118
+
119
+ ### Haraka does not trust
120
+
121
+ - SMTP clients and other remote peers, including commands, envelopes, headers,
122
+ bodies, attachments, authentication attempts, HELO/EHLO names, and proxied
123
+ client metadata before validation
124
+ - Data returned by remote services Haraka communicates with, such as DNS
125
+ lookups and outbound SMTP peers
126
+ - Untrusted remote input must not be able to trigger behavior beyond
127
+ documented SMTP and plugin semantics, such as unauthorized relaying,
128
+ unintended command execution, protected-data disclosure, or service
129
+ unavailability
130
+
131
+ ### Haraka trusts
132
+
133
+ - The operating system, filesystem, Node.js runtime, local network, process
134
+ privileges, and local administrators operating the service
135
+ - Haraka configuration and deployment choices, including listener exposure,
136
+ relay and authentication policy, TLS certificates, proxy settings, and
137
+ enabled plugins
138
+ - Code loaded as plugins or dependencies. Plugins run with Haraka's process
139
+ privileges and are not a security boundary
140
+ - Upstream services and dependencies as separate projects; flaws in those
141
+ components are usually reported upstream unless Haraka's integration creates
142
+ a distinct vulnerability
143
+
144
+ ### STRIDE summary
145
+
146
+ In-scope threats are classified using [STRIDE][stride] applied at the
147
+ Haraka trust boundary shown above. A finding that lets a remote peer
148
+ cause any of the following under documented or default-safe configuration
149
+ is generally a vulnerability.
150
+
151
+ | Category | Example threats at the Haraka boundary |
152
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
153
+ | **S**poofing | Forged HELO/EHLO or AUTH, identity bypass, unvalidated XCLIENT or proxy metadata accepted as authoritative |
154
+ | **T**ampering | SMTP smuggling, CRLF or header injection, parser inconsistencies that change how a message is delivered or interpreted |
155
+ | **R**epudiation | Remote input that erases or forges the Received: trail, or otherwise defeats logging under default configuration |
156
+ | **I**nformation disclosure | Leakage of message content, credentials, or internal state through SMTP responses, DSNs, error messages, or logs |
157
+ | **D**enial of service | Deterministic resource exhaustion or crashes triggered by remote input without operator misconfiguration |
158
+ | **E**levation of privilege | Remote code execution, or escape of documented SMTP/plugin semantics into arbitrary behavior inside the Haraka process |
159
+
160
+ Plugins execute inside the trust boundary by design, so a malicious or
161
+ vulnerable plugin can produce any STRIDE category above. Findings that
162
+ require installing such a plugin are not vulnerabilities in Haraka itself.
163
+
164
+ [stride]: https://en.wikipedia.org/wiki/STRIDE_model
165
+
166
+ ## Scope
167
+
168
+ Issues that require control of a trusted element are out of scope, including:
169
+
170
+ - Vulnerabilities requiring control of the host OS, filesystem, Node.js
171
+ runtime, local administrator account, or other trusted infrastructure
172
+ - Malicious or compromised plugins or dependencies intentionally installed or
173
+ enabled by the operator
174
+ - Pure misconfiguration of listeners, relay policy, TLS, proxying, or
175
+ outbound destinations unless Haraka's documented defaults create the
176
+ insecure state
177
+
178
+ Issues in third-party plugins maintained outside this repository should be reported to their respective maintainers.
package/bin/haraka CHANGED
@@ -11,7 +11,6 @@ const os = require('node:os')
11
11
 
12
12
  const nopt = require('nopt')
13
13
  const utils = require('haraka-utils')
14
- const sprintf = require('sprintf-js').sprintf
15
14
  const base = path.join(__dirname, '..')
16
15
  const ver = utils.getVersion(base)
17
16
  const knownOpts = {
@@ -313,15 +312,7 @@ if (parsed.version) {
313
312
  ;(async () => {
314
313
  const qlist = await outbound.list_queue()
315
314
  for (const todo of qlist) {
316
- console.log(
317
- sprintf(
318
- 'Q: %s rcpt:%d from:%s domain:%s',
319
- todo.file,
320
- todo.rcpt_to.length,
321
- todo.mail_from.toString(),
322
- todo.domain,
323
- ),
324
- )
315
+ console.log(`Q: ${todo.file} rcpt:${todo.rcpt_to.length} from:${todo.mail_from} domain:${todo.domain}`)
325
316
  }
326
317
  process.exit()
327
318
  })()
@@ -379,12 +370,14 @@ if (parsed.version) {
379
370
  console.log('')
380
371
  for (const hook of getHooks()) {
381
372
  if (!plugins.registered_hooks[hook]) continue
382
- console.log(sprintf("%'--80s", `Hook: ${hook} `))
383
- console.log(sprintf('%-35s %-35s %-4s %-3s', 'Plugin', 'Method', 'Prio', 'T/O'))
384
- console.log(sprintf("%'-80s", ''))
373
+ console.log(`Hook: ${hook} `.padEnd(80, '-'))
374
+ console.log(`${'Plugin'.padEnd(35)} ${'Method'.padEnd(35)} ${'Prio'.padEnd(4)} T/O`)
375
+ console.log('-'.repeat(80))
385
376
  for (let p = 0; p < plugins.registered_hooks[hook].length; p++) {
386
377
  const item = plugins.registered_hooks[hook][p]
387
- console.log(sprintf('%-35s %-35s %4d %3d', item.plugin, item.method, item.priority, item.timeout))
378
+ console.log(
379
+ `${item.plugin.padEnd(35)} ${item.method.padEnd(35)} ${String(item.priority).padStart(4)} ${String(item.timeout).padStart(3)}`,
380
+ )
388
381
  }
389
382
  console.log('')
390
383
  }
package/config/plugins CHANGED
@@ -12,7 +12,6 @@
12
12
  # status
13
13
  # process_title
14
14
  # syslog
15
- # watch
16
15
 
17
16
  # CONNECT
18
17
  # ----------
@@ -20,7 +19,6 @@
20
19
  # karma
21
20
  # relay
22
21
  # access
23
- # p0f
24
22
  # geoip
25
23
  # asn
26
24
  # fcrdns
@@ -49,7 +47,6 @@ mail_from.is_resolvable
49
47
  # At least one rcpt_to plugin is REQUIRED for inbound email.
50
48
  rcpt_to.in_host_list
51
49
  # qmail-deliverable
52
- # rcpt_to.routes
53
50
 
54
51
  # DATA
55
52
  # ----------
@@ -1,66 +1,153 @@
1
1
  # Connection Object
2
2
 
3
- For each connection to Haraka there is one connection object.
3
+ For each connection to Haraka there is one connection object. It is the first argument passed to almost every plugin hook and is the primary context object plugins use to inspect and act on the SMTP session.
4
4
 
5
- ## API
5
+ ## Properties
6
6
 
7
- - connection.uuid
7
+ ### connection.uuid
8
8
 
9
- A unique UUID for this connection.
9
+ A unique UUID for this connection. Used as the connection identifier in logs and inherited by `transaction.uuid`.
10
10
 
11
- - connection.remote - info about the host that is connecting to Haraka.
11
+ ### connection.remote
12
12
 
13
- - ip - remote IP address
14
- - host - reverse DNS of the remote hosts IP
15
- - is_private - true if the remote IP is from a private (loopback, RFC 1918, link local, etc.) IP address.
16
- - is_local - true if the remote IP is localhost (loopback, link local)
13
+ Information about the host connecting to Haraka.
17
14
 
18
- - connection.local - info about the host that is running Haraka
15
+ - `ip` remote IP address
16
+ - `port` — remote TCP port
17
+ - `host` — reverse DNS of the remote IP (populated by the `connect.rdns_access` / `connect` hooks)
18
+ - `info` — free-form descriptor (e.g. populated by FCrDNS)
19
+ - `closed` — `true` once the remote end has dropped the connection
20
+ - `is_private` — `true` if the remote IP is in a private range (RFC 1918, loopback, link-local, etc.)
21
+ - `is_local` — `true` if the remote IP is localhost / loopback
19
22
 
20
- - ip - the IP of the Haraka server, as reported by the OS
21
- - port - the port number handling the connection.
22
- - host - the rDNS host name of the local IP
23
+ ### connection.local
23
24
 
24
- - connection.proxy - proxy properties set when a proxy is used (like haproxy)
25
+ Information about the Haraka server endpoint handling this connection.
25
26
 
26
- - allowed - if the remote IP has proxy permission
27
- - ip - when proxied, the proxy servers IP address
28
- - type - currently null or 'haproxy'
27
+ - `ip` the IP of the Haraka server, as reported by the OS
28
+ - `port` the port number handling the connection
29
+ - `host` the primary host name of the Haraka server
30
+ - `info` — `Haraka` (with `/<version>` appended when `headers.show_version` is enabled in `connection.ini`)
29
31
 
30
- - connection.hello
32
+ ### connection.hello
31
33
 
32
- - verb - Either 'EHLO' or 'HELO' whichever the remote end used
33
- - host - The hostname given with HELO or EHLO
34
+ The greeting given by the client.
34
35
 
35
- - connection.notes
36
+ - `verb` — `EHLO` or `HELO`, whichever the client used
37
+ - `host` — the hostname argument
36
38
 
37
- An object which persists during the lifetime of the connection. It is used to store connection-specific properties. See also, connection.results and [haraka-notes](https://github.com/haraka/haraka-notes).
39
+ ### connection.tls
38
40
 
39
- - connection.transaction
41
+ State of the TLS layer on this connection.
40
42
 
41
- The current transaction object, valid after MAIL FROM, and destroyed at queue
42
- time, RSET time, or if MAIL FROM was rejected. See the Transaction Object
43
- documentation file.
43
+ - `enabled` `true` once STARTTLS has been negotiated (or the listener is `smtps`)
44
+ - `advertised` `true` if Haraka advertised STARTTLS in the EHLO response
45
+ - `verified` — `true` if the peer certificate validated against the configured CAs
46
+ - `cipher` — the negotiated cipher object (`name`, `version`, …)
47
+ - `verifyError` — the verification error, if any
48
+ - `peerCertificate` — the parsed peer certificate (when client certs are used)
44
49
 
45
- - connection.relaying
50
+ ### connection.proxy
46
51
 
47
- A boolean flag to say whether this connection is allowed to relay mails (i.e.
48
- deliver mails outbound). This is normally set by SMTP AUTH, or sometimes via
49
- an IP address check.
52
+ Proxy-protocol state, set when the connection arrived via HAProxy (see [HAProxy.md](HAProxy.md)).
50
53
 
51
- - connection.current_line
54
+ - `allowed` — `true` if the remote IP is in the `haproxy.hosts` allow-list
55
+ - `ip` — the proxy server's IP (the real client IP appears in `connection.remote.ip` once PROXY is parsed)
56
+ - `type` — currently `null` or `'haproxy'`
52
57
 
53
- For low level use. Contains the current line sent from the remote end,
54
- verbatim as it was sent. Can be useful in certain botnet detection techniques.
58
+ ### connection.notes
55
59
 
56
- - connection.last_response
60
+ A plain object that persists for the lifetime of the connection. Use it to share state between plugin hooks. For structured per-test results prefer `connection.results`. See also [haraka-notes](https://github.com/haraka/haraka-notes).
57
61
 
58
- Contains the last SMTP response sent to the client.
62
+ ### connection.results
59
63
 
60
- - connection.remote_closed
64
+ Structured store for plugin results. See [haraka-results](https://github.com/haraka/haraka-results).
61
65
 
62
- For low level use. This value is set when the remote host drops the connection.
66
+ ### connection.transaction
63
67
 
64
- - connection.results
68
+ The current `Transaction` object. Valid between `MAIL FROM` and the end of `queue` / `RSET` (or until `MAIL FROM` is rejected). See [Transaction.md](Transaction.md).
65
69
 
66
- Store results of processing in a structured format. See [haraka-results](https://github.com/haraka/haraka-results)
70
+ ### connection.relaying
71
+
72
+ Boolean. `true` if this connection is allowed to relay (i.e. deliver mail outbound). Normally set by an auth plugin or an IP allow-list. Reading or writing this property transparently routes through the current transaction when one exists, so the flag survives across multiple messages in a single connection only when set on the connection.
73
+
74
+ ### connection.capabilities
75
+
76
+ Array of ESMTP capabilities advertised in the EHLO response (e.g. `['PIPELINING', '8BITMIME', 'SIZE 0', 'STARTTLS', 'AUTH PLAIN LOGIN']`). Plugins may push additional capability strings during the `capabilities` hook.
77
+
78
+ ### connection.esmtp
79
+
80
+ `true` if the client used `EHLO` (as opposed to `HELO`).
81
+
82
+ ### connection.pipelining
83
+
84
+ `true` once Haraka has advertised, and the client has used, SMTP pipelining.
85
+
86
+ ### connection.early_talker
87
+
88
+ `true` if the client sent data before Haraka issued its banner — a
89
+ common spam-bot signal.
90
+
91
+ ### connection.tran_count
92
+
93
+ Number of transactions completed on this connection.
94
+
95
+ ### connection.rcpt_count / connection.msg_count
96
+
97
+ Per-disposition counters (`accept`, `tempfail`, `reject`) tracking
98
+ recipients and full messages on this connection.
99
+
100
+ ### connection.start_time
101
+
102
+ Connection start time, in epoch milliseconds (`Date.now()`).
103
+
104
+ ### connection.last_response
105
+
106
+ The last SMTP response line Haraka sent to the client.
107
+
108
+ ### connection.last_reject
109
+
110
+ The text of the last rejection issued to this client (used by
111
+ `max_unrecognized_commands` and similar throttling plugins).
112
+
113
+ ### connection.errors
114
+
115
+ Count of protocol errors on this connection.
116
+
117
+ ### connection.current_line
118
+
119
+ Low-level. The current line as sent by the remote end, verbatim. Useful
120
+ for botnet fingerprinting.
121
+
122
+ ### connection.state
123
+
124
+ The connection's protocol state — one of the values in `haraka-constants`'s `connection.state` table (`PAUSE`, `CMD`, `LOOP`, `DATA`, `DISCONNECTING`, `DISCONNECTED`).
125
+
126
+ ## Methods
127
+
128
+ ### connection.respond(code, msg, cb)
129
+
130
+ Send an SMTP response to the client. `code` is the numeric SMTP code, `msg` is the human-readable text (a string or an array of strings for a multi-line response). The callback fires when the response has been written.
131
+
132
+ ### connection.disconnect()
133
+
134
+ Close the connection after running the `disconnect` hook.
135
+
136
+ ### connection.reset_transaction(cb)
137
+
138
+ Tear down the current transaction (equivalent to `RSET`) and invoke `cb` when complete.
139
+
140
+ ### connection.set(path, value)
141
+
142
+ Assign a nested property safely, e.g. `connection.set('remote.host', 'mx.example.com')`. Setting `remote.ip`
143
+ automatically recomputes `remote.is_private` / `remote.is_local`.
144
+
145
+ ### connection.get(path)
146
+
147
+ Read a nested property, returning `undefined` if any segment is missing.
148
+
149
+ ### connection.loginfo / lognotice / logwarn / logerror / logdebug / logcrit / logalert / logemerg / logprotocol / logdata
150
+
151
+ Log at the named level. Each takes either `(msg)` or `(plugin, msg, data)`.
152
+
153
+ See [Logging.md](Logging.md).