Haraka 3.0.3 → 3.0.5

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 (239) hide show
  1. package/.eslintrc.yaml +4 -9
  2. package/CONTRIBUTORS.md +11 -0
  3. package/Changes.md +1397 -1213
  4. package/Plugins.md +117 -105
  5. package/README.md +4 -13
  6. package/bin/haraka +198 -298
  7. package/config/auth_flat_file.ini +1 -0
  8. package/config/dhparams.pem +8 -0
  9. package/config/mail_from.is_resolvable.ini +4 -2
  10. package/config/me +1 -0
  11. package/config/outbound.ini +0 -2
  12. package/config/plugins +35 -36
  13. package/config/smtp.ini +1 -1
  14. package/config/smtp.json +17 -0
  15. package/config/tls.ini +2 -0
  16. package/config/tls_cert.pem +23 -0
  17. package/config/tls_key.pem +28 -0
  18. package/connection.js +46 -73
  19. package/contrib/bsd-rc.d/haraka +3 -1
  20. package/contrib/plugin2npm.sh +6 -36
  21. package/docs/CoreConfig.md +2 -2
  22. package/docs/Logging.md +7 -21
  23. package/docs/Outbound.md +104 -201
  24. package/docs/Plugins.md +2 -2
  25. package/docs/Transaction.md +59 -82
  26. package/docs/plugins/queue/smtp_proxy.md +5 -10
  27. package/docs/plugins/tls.md +37 -9
  28. package/endpoint.js +16 -13
  29. package/haraka.js +10 -14
  30. package/host_pool.js +5 -5
  31. package/http/html/index.html +6 -5
  32. package/line_socket.js +3 -4
  33. package/logger.js +44 -28
  34. package/outbound/client_pool.js +27 -23
  35. package/outbound/config.js +4 -6
  36. package/outbound/fsync_writestream.js +1 -1
  37. package/outbound/hmail.js +178 -218
  38. package/outbound/index.js +86 -99
  39. package/outbound/qfile.js +1 -1
  40. package/outbound/queue.js +51 -44
  41. package/outbound/timer_queue.js +3 -2
  42. package/outbound/tls.js +19 -7
  43. package/package.json +60 -51
  44. package/plugins/.eslintrc.yaml +0 -6
  45. package/plugins/auth/auth_base.js +4 -2
  46. package/plugins/auth/auth_proxy.js +14 -12
  47. package/plugins/auth/auth_vpopmaild.js +1 -1
  48. package/plugins/block_me.js +1 -1
  49. package/plugins/data.signatures.js +2 -4
  50. package/plugins/early_talker.js +2 -1
  51. package/plugins/mail_from.is_resolvable.js +65 -135
  52. package/plugins/queue/deliver.js +4 -5
  53. package/plugins/queue/lmtp.js +11 -12
  54. package/plugins/queue/qmail-queue.js +2 -2
  55. package/plugins/queue/quarantine.js +2 -2
  56. package/plugins/queue/rabbitmq.js +16 -17
  57. package/plugins/queue/smtp_forward.js +3 -3
  58. package/plugins/queue/smtp_proxy.js +10 -1
  59. package/plugins/queue/test.js +2 -2
  60. package/plugins/rcpt_to.host_list_base.js +5 -5
  61. package/plugins/rcpt_to.in_host_list.js +2 -2
  62. package/plugins/relay.js +6 -7
  63. package/plugins/reseed_rng.js +1 -1
  64. package/plugins/status.js +37 -33
  65. package/plugins/tls.js +2 -2
  66. package/plugins/xclient.js +3 -2
  67. package/plugins.js +50 -54
  68. package/run_tests +3 -30
  69. package/server.js +190 -190
  70. package/smtp_client.js +30 -23
  71. package/{tests → test}/config/plugins +0 -2
  72. package/{tests → test}/config/smtp.ini +3 -1
  73. package/test/config/tls/example.com/_.example.com.key +28 -0
  74. package/test/config/tls/example.com/example.com.crt +25 -0
  75. package/{tests/loud → test}/config/tls.ini +4 -2
  76. package/test/connection.js +302 -0
  77. package/test/endpoint.js +94 -0
  78. package/{tests → test}/fixtures/line_socket.js +1 -1
  79. package/{tests → test}/fixtures/util_hmailitem.js +19 -25
  80. package/{tests → test}/host_pool.js +42 -57
  81. package/test/logger.js +258 -0
  82. package/test/outbound/hmail.js +141 -0
  83. package/test/outbound/index.js +220 -0
  84. package/test/outbound/qfile.js +126 -0
  85. package/test/outbound_bounce_net_errors.js +142 -0
  86. package/{tests → test}/outbound_bounce_rfc3464.js +110 -122
  87. package/test/plugins/auth/auth_base.js +484 -0
  88. package/test/plugins/auth/auth_vpopmaild.js +83 -0
  89. package/test/plugins/early_talker.js +104 -0
  90. package/test/plugins/mail_from.is_resolvable.js +35 -0
  91. package/test/plugins/queue/smtp_forward.js +206 -0
  92. package/test/plugins/rcpt_to.host_list_base.js +122 -0
  93. package/test/plugins/rcpt_to.in_host_list.js +193 -0
  94. package/test/plugins/relay.js +303 -0
  95. package/test/plugins/status.js +130 -0
  96. package/test/plugins/tls.js +70 -0
  97. package/test/plugins.js +228 -0
  98. package/test/rfc1869.js +73 -0
  99. package/test/server.js +491 -0
  100. package/test/smtp_client.js +299 -0
  101. package/test/tls_socket.js +277 -0
  102. package/test/transaction.js +270 -0
  103. package/tls_socket.js +202 -252
  104. package/transaction.js +8 -23
  105. package/CONTRIBUTING.md +0 -1
  106. package/bin/dkimverify +0 -40
  107. package/config/access.domains +0 -13
  108. package/config/attachment.ctype.regex +0 -2
  109. package/config/attachment.filename.regex +0 -1
  110. package/config/avg.ini +0 -5
  111. package/config/bounce.ini +0 -15
  112. package/config/data.headers.ini +0 -61
  113. package/config/dkim/dkim_key_gen.sh +0 -78
  114. package/config/dkim_sign.ini +0 -4
  115. package/config/dkim_verify.ini +0 -7
  116. package/config/dnsbl.ini +0 -23
  117. package/config/greylist.ini +0 -43
  118. package/config/helo.checks.ini +0 -52
  119. package/config/messagesniffer.ini +0 -18
  120. package/config/spamassassin.ini +0 -56
  121. package/dkim.js +0 -614
  122. package/docs/plugins/avg.md +0 -35
  123. package/docs/plugins/bounce.md +0 -69
  124. package/docs/plugins/clamd.md +0 -147
  125. package/docs/plugins/esets.md +0 -8
  126. package/docs/plugins/greylist.md +0 -90
  127. package/docs/plugins/helo.checks.md +0 -135
  128. package/docs/plugins/messagesniffer.md +0 -163
  129. package/docs/plugins/spamassassin.md +0 -180
  130. package/outbound/mx_lookup.js +0 -70
  131. package/plugins/auth/auth_ldap.js +0 -3
  132. package/plugins/avg.js +0 -162
  133. package/plugins/backscatterer.js +0 -25
  134. package/plugins/bounce.js +0 -381
  135. package/plugins/clamd.js +0 -382
  136. package/plugins/data.uribl.js +0 -4
  137. package/plugins/dkim_sign.js +0 -395
  138. package/plugins/dkim_verify.js +0 -62
  139. package/plugins/dns_list_base.js +0 -221
  140. package/plugins/dnsbl.js +0 -146
  141. package/plugins/dnswl.js +0 -58
  142. package/plugins/esets.js +0 -71
  143. package/plugins/graph.js +0 -5
  144. package/plugins/greylist.js +0 -645
  145. package/plugins/helo.checks.js +0 -533
  146. package/plugins/messagesniffer.js +0 -381
  147. package/plugins/rcpt_to.ldap.js +0 -3
  148. package/plugins/rcpt_to.max_count.js +0 -24
  149. package/plugins/spamassassin.js +0 -384
  150. package/tests/config/dkim/example.com/dns +0 -29
  151. package/tests/config/dkim/example.com/private +0 -6
  152. package/tests/config/dkim/example.com/public +0 -4
  153. package/tests/config/dkim/example.com/selector +0 -1
  154. package/tests/config/dkim.private.key +0 -6
  155. package/tests/config/dkim_sign.ini +0 -4
  156. package/tests/config/helo.checks.ini +0 -52
  157. package/tests/connection.js +0 -327
  158. package/tests/endpoint.js +0 -128
  159. package/tests/fixtures/vm_harness.js +0 -59
  160. package/tests/logger.js +0 -327
  161. package/tests/outbound/hmail.js +0 -112
  162. package/tests/outbound/index.js +0 -324
  163. package/tests/outbound/qfile.js +0 -67
  164. package/tests/outbound_bounce_net_errors.js +0 -173
  165. package/tests/plugins/auth/auth_base.js +0 -463
  166. package/tests/plugins/auth/auth_vpopmaild.js +0 -91
  167. package/tests/plugins/bounce.js +0 -307
  168. package/tests/plugins/clamd.js +0 -224
  169. package/tests/plugins/deprecated/relay_acl.js +0 -140
  170. package/tests/plugins/deprecated/relay_all.js +0 -59
  171. package/tests/plugins/dkim_sign.js +0 -315
  172. package/tests/plugins/dkim_signer.js +0 -108
  173. package/tests/plugins/dns_list_base.js +0 -259
  174. package/tests/plugins/dnsbl.js +0 -101
  175. package/tests/plugins/early_talker.js +0 -115
  176. package/tests/plugins/greylist.js +0 -58
  177. package/tests/plugins/helo.checks.js +0 -525
  178. package/tests/plugins/mail_from.is_resolvable.js +0 -116
  179. package/tests/plugins/queue/smtp_forward.js +0 -221
  180. package/tests/plugins/rcpt_to.host_list_base.js +0 -132
  181. package/tests/plugins/rcpt_to.in_host_list.js +0 -218
  182. package/tests/plugins/relay.js +0 -339
  183. package/tests/plugins/spamassassin.js +0 -171
  184. package/tests/plugins/status.js +0 -138
  185. package/tests/plugins/tls.js +0 -84
  186. package/tests/plugins.js +0 -247
  187. package/tests/rfc1869.js +0 -61
  188. package/tests/server.js +0 -510
  189. package/tests/smtp_client/auth.js +0 -105
  190. package/tests/smtp_client/basic.js +0 -101
  191. package/tests/smtp_client.js +0 -80
  192. package/tests/tls_socket.js +0 -333
  193. package/tests/transaction.js +0 -284
  194. /package/docs/{plugins → deprecated}/dkim_sign.md +0 -0
  195. /package/docs/{plugins → deprecated}/dkim_verify.md +0 -0
  196. /package/docs/{plugins → deprecated}/dnsbl.md +0 -0
  197. /package/docs/{plugins → deprecated}/dnswl.md +0 -0
  198. /package/{tests → test}/.eslintrc.yaml +0 -0
  199. /package/{tests → test}/config/auth_flat_file.ini +0 -0
  200. /package/{tests → test}/config/dhparams.pem +0 -0
  201. /package/{tests → test}/config/host_list +0 -0
  202. /package/{tests → test}/config/outbound_tls_cert.pem +0 -0
  203. /package/{tests → test}/config/outbound_tls_key.pem +0 -0
  204. /package/{tests → test}/config/smtp_forward.ini +0 -0
  205. /package/{tests → test}/config/tls/ec.pem +0 -0
  206. /package/{tests → test}/config/tls/haraka.local.pem +0 -0
  207. /package/{tests → test}/config/tls/mismatched.pem +0 -0
  208. /package/{tests → test}/config/tls_cert.pem +0 -0
  209. /package/{tests → test}/config/tls_key.pem +0 -0
  210. /package/{tests → test}/fixtures/todo_qfile.txt +0 -0
  211. /package/{tests → test}/installation/config/test-plugin-flat +0 -0
  212. /package/{tests → test}/installation/config/test-plugin.ini +0 -0
  213. /package/{tests → test}/installation/config/tls.ini +0 -0
  214. /package/{tests → test}/installation/node_modules/load_first/index.js +0 -0
  215. /package/{tests → test}/installation/node_modules/load_first/package.json +0 -0
  216. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin-flat +0 -0
  217. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin.ini +0 -0
  218. /package/{tests → test}/installation/node_modules/test-plugin/package.json +0 -0
  219. /package/{tests → test}/installation/node_modules/test-plugin/test-plugin.js +0 -0
  220. /package/{tests → test}/installation/plugins/base_plugin.js +0 -0
  221. /package/{tests → test}/installation/plugins/folder_plugin/index.js +0 -0
  222. /package/{tests → test}/installation/plugins/folder_plugin/package.json +0 -0
  223. /package/{tests → test}/installation/plugins/inherits.js +0 -0
  224. /package/{tests → test}/installation/plugins/load_first.js +0 -0
  225. /package/{tests → test}/installation/plugins/plugin.js +0 -0
  226. /package/{tests → test}/installation/plugins/tls.js +0 -0
  227. /package/{tests → test}/loud/config/dhparams.pem +0 -0
  228. /package/{tests → test}/loud/config/tls/goobered.pem +0 -0
  229. /package/{tests → test/loud}/config/tls.ini +0 -0
  230. /package/{tests → test}/mail_specimen/base64-root-part.txt +0 -0
  231. /package/{tests → test}/mail_specimen/varied-fold-lengths-preserve-data.txt +0 -0
  232. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
  233. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
  234. /package/{tests → test}/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
  235. /package/{tests → test}/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
  236. /package/{tests → test}/queue/multibyte +0 -0
  237. /package/{tests → test}/queue/plain +0 -0
  238. /package/{tests → test}/queue/zero-length +0 -0
  239. /package/{tests → test}/test-queue/delete-me +0 -0
@@ -1,19 +1,16 @@
1
- Transaction Object
2
- ==================
1
+ # Transaction Object
3
2
 
4
3
  An SMTP transaction is valid from MAIL FROM time until RSET or "final-dot".
5
4
 
6
- API
7
- ---
5
+ ## API
8
6
 
9
7
  * transaction.uuid
10
8
 
11
- A unique UUID for this transaction. Is equal to the connection.uuid + '.N'
12
- where N increments for each transaction on this connection.
9
+ A unique UUID for this transaction. Is equal to the connection.uuid + '.N' where N increments for each transaction on this connection.
13
10
 
14
11
  * transaction.mail\_from
15
12
 
16
- The value of the MAIL FROM command as an `Address`[1] object.
13
+ The value of the MAIL FROM command is an `Address`[1] object.
17
14
 
18
15
  * transaction.rcpt\_to
19
16
 
@@ -25,13 +22,13 @@ A node.js Readable Stream object for the message.
25
22
 
26
23
  You use it like this:
27
24
 
28
- transaction.message_stream.pipe(WritableStream, options)
25
+ ```js
26
+ transaction.message_stream.pipe(WritableStream, options)
27
+ ```
29
28
 
30
- Where WritableStream is a node.js Writable Stream object such as a
31
- net.socket, fs.writableStream, process.stdout/stderr or custom stream.
29
+ Where WritableStream is a node.js Writable Stream object such as a net.socket, fs.writableStream, process.stdout/stderr or custom stream.
32
30
 
33
- The options argument should be an object that overrides the following
34
- properties:
31
+ The options argument should be an object that overrides the following properties:
35
32
 
36
33
  * line_endings (default: "\r\n")
37
34
  * dot_stuffing (default: false)
@@ -42,7 +39,9 @@ properties:
42
39
 
43
40
  e.g.
44
41
 
45
- transaction.message_stream.pipe(socket, { dot_stuffing: true, ending_dot: true });
42
+ ```js
43
+ transaction.message_stream.pipe(socket, { dot_stuffing: true, ending_dot: true });
44
+ ```
46
45
 
47
46
  * transaction.data\_bytes
48
47
 
@@ -50,8 +49,7 @@ The number of bytes in the email after DATA.
50
49
 
51
50
  * transaction.add\_data(line)
52
51
 
53
- Adds a line of data to the email. Note this is RAW email - it isn't useful
54
- for adding banners to the email.
52
+ Adds a line of data to the email. Note this is RAW email - it isn't useful for adding banners to the email.
55
53
 
56
54
  * transaction.notes
57
55
 
@@ -59,8 +57,7 @@ A safe place to store transaction specific values. See also [haraka-results](htt
59
57
 
60
58
  * transaction.add\_leading\_header(key, value)
61
59
 
62
- Adds a header to the top of the header list. This should only be used in
63
- very specific cases. Most people will want to use `add_header()` instead.
60
+ Adds a header to the top of the header list. This should only be used in very specific cases. Most cases will use `add_header()` instead.
64
61
 
65
62
  * transaction.add\_header(key, value)
66
63
 
@@ -76,8 +73,7 @@ The header of the email. See `Header Object`.
76
73
 
77
74
  * transaction.parse\_body = true|false [default: false]
78
75
 
79
- Set to `true` to enable parsing of the mail body. Make sure you set this in
80
- hook\_data or before.
76
+ Set to `true` to enable parsing of the mail body. Make sure you set this in hook\_data or before. Storing a transaction hook (with transaction.attachment\_hooks) will set this to true.
81
77
 
82
78
  * transaction.body
83
79
 
@@ -85,81 +81,62 @@ The body of the email if you set `parse_body` above. See `Body Object`.
85
81
 
86
82
  * transaction.attachment\_hooks(start)
87
83
 
88
- Sets a callback for when we see an attachment if `parse_body` has been set.
89
-
90
- The `start` event will receive `(content_type, filename, body, stream)` as
91
- parameters.
92
-
93
- The stream is a `ReadableStream` - see http://nodejs.org/api/stream.html for
94
- details on how this works.
95
-
96
- If you set stream.connection then the stream will apply backpressure to the
97
- connection, allowing you to process attachments before the connection has
98
- ended. Here is an example which stores attachments in temporary files using
99
- the `tmp` library from npm and tells us the size of the file:
100
-
101
- exports.hook_data = function (next, connection) {
102
- // enable mail body parsing
103
- connection.transaction.parse_body = true;
104
- connection.transaction.attachment_hooks(
105
- function (ct, fn, body, stream) {
106
- start_att(connection, ct, fn, body, stream)
107
- }
108
- );
109
- next();
110
- }
111
-
112
- function start_att (connection, ct, fn, body, stream) {
113
- connection.loginfo("Got attachment: " + ct + ", " + fn + " for user id: " + connection.transaction.notes.hubdoc_user.email);
114
- connection.transaction.notes.attachment_count++;
115
-
116
- stream.connection = connection; // Allow backpressure
117
- stream.pause();
118
-
119
- var tmp = require('tmp');
120
-
121
- tmp.file(function (err, path, fd) {
122
- connection.loginfo("Got tempfile: " + path + " (" + fd + ")");
123
- var ws = fs.createWriteStream(path);
124
- stream.pipe(ws);
125
- stream.resume();
126
- ws.on('close', function () {
127
- connection.loginfo("End of stream reached");
128
- fs.fstat(fd, function (err, stats) {
129
- connection.loginfo("Got data of length: " + stats.size);
130
- // Close the tmp file descriptor
131
- fs.close(fd, function(){});
132
- });
84
+ Sets a callback for when we see an attachment.
85
+
86
+ The `start` event will receive `(content_type, filename, body, stream)` as parameters.
87
+
88
+ The stream is a [ReadableStream](http://nodejs.org/api/stream.html)
89
+
90
+ If you set stream.connection then the stream will apply backpressure to the connection, allowing you to process attachments before the connection has ended. Here is an example which stores attachments in temporary files using the `tmp` library from npm and tells us the size of the file:
91
+
92
+ ```js
93
+ exports.hook_data = function (next, connection) {
94
+ // enable mail body parsing
95
+ connection.transaction.attachment_hooks(
96
+ function (ct, fn, body, stream) {
97
+ start_att(connection, ct, fn, body, stream)
98
+ }
99
+ );
100
+ next();
101
+ }
102
+
103
+ function start_att (connection, ct, fn, body, stream) {
104
+ connection.loginfo(`Got attachment: ${ct}, ${fn} for user id: ${connection.transaction.notes.hubdoc_user.email}`)
105
+ connection.transaction.notes.attachment_count++
106
+
107
+ stream.connection = connection; // Allow backpressure
108
+ stream.pause();
109
+
110
+ require('tmp').file((err, path, fd) => {
111
+ connection.loginfo(`Got tempfile: ${path} (${fd})`)
112
+ const ws = fs.createWriteStream(path)
113
+ stream.pipe(ws);
114
+ stream.resume();
115
+ ws.on('close', () => {
116
+ connection.loginfo("End of stream reached");
117
+ fs.fstat(fd, (err, stats) => {
118
+ connection.loginfo(`Got data of length: ${stats.size}`);
119
+ fs.close(fd, () => {}); // Close the tmp file descriptor
133
120
  });
134
121
  });
135
- }
122
+ });
123
+ }
124
+ ```
136
125
 
137
126
  * transaction.discard\_data = true|false [default: false]
138
127
 
139
- Set this flag to true to discard all data as it arrives and not store in
140
- memory or on disk (in the message\_stream property). You can still access
141
- the attachments and body if you set parse\_body to true. This is useful
142
- for systems which do not need the full email, just the attachments or
143
- mail text.
128
+ Set this flag to true to discard all data as it arrives and not store in memory or on disk (in the message\_stream property). You can still access the attachments and body if you set parse\_body to true. This is useful for systems which do not need the full email, just the attachments or mail text.
144
129
 
145
130
  * transaction.set\_banner(text, html)
146
131
 
147
- Sets a banner to be added to the end of the email. If the html part is not
148
- given (optional) then the text part will have each line ending replaced with
149
- `<br/>` when being inserted into HTML parts.
132
+ Sets a banner to be added to the end of the email. If the html part is not given (optional) then the text part will have each line ending replaced with `<br/>` when being inserted into HTML parts.
150
133
 
151
134
  * transaction.add\_body\_filter(ct_match, filter)
152
135
 
153
- Adds a filter to be applied to body parts in the email. ct\_match should be a
154
- regular expression to match against the full content-type line, or a string to
155
- match at the start, e.g. `/^text\/html/` or `'text/plain'`. filter will be
156
- called when each body part matching ct_match is complete. It receives three
157
- parameters, the content-type line, the encoding name, and a buffer with the
158
- full body part. It should return a buffer with the desired contents of the
159
- body in the same encoding.
136
+ Adds a filter to be applied to body parts in the email. ct\_match should be a regular expression to match against the full content-type line, or a string to match at the start, e.g. `/^text\/html/` or `'text/plain'`. filter will be called when each body part matching ct_match is complete. It receives three parameters: the content-type line, the encoding name, and a buffer with the full body part. It should return a buffer with the desired contents of the body in the same encoding.
160
137
 
161
138
  * transaction.results
162
139
 
163
- Store results of processing in a structured format. See [haraka-results](https://github.com/haraka/haraka-results)
140
+ Store [results](https://github.com/haraka/haraka-results) of processing in a structured format.
164
141
 
165
- [1]: `Address` objects are address-rfc2821 objects. See https://github.com/haraka/node-address-rfc2821
142
+ [1]: `Address` objects are [address-rfc2821](https://github.com/haraka/node-address-rfc2821) objects.
@@ -1,16 +1,11 @@
1
1
  # queue/smtp\_proxy
2
2
  ================
3
3
 
4
- This plugin delivers to another mail server. This is a common setup when you
5
- want to have a mail server with a solid pedigree of outbound delivery to
6
- other hosts, and inbound delivery to users.
7
-
8
- In comparison to `queue/smtp_forward`, this plugin makes a connection at
9
- MAIL FROM time to the ongoing SMTP server. This can be a benefit in that
10
- you get any SMTP-time filtering that the ongoing server provides, in
11
- particular one important facility to some setups is recipient filtering.
12
- However be aware that other than connect and HELO-time filtering, you will
13
- have as many connections to your ongoing SMTP server as you have to Haraka.
4
+ This plugin delivers to another mail server. This is a common setup when you want to have a mail server with a solid pedigree of outbound delivery to other hosts, and inbound delivery to users.
5
+
6
+ In comparison to `queue/smtp_forward`, this plugin makes a connection at MAIL FROM time to the ongoing SMTP server. This can be a benefit in that you get any SMTP-time filtering that the ongoing server provides, in particular one important facility to some setups is recipient filtering.
7
+
8
+ Be aware that other than connect and HELO-time filtering, you will have as many connections to your ongoing SMTP server as you have to Haraka.
14
9
 
15
10
  ## Configuration
16
11
  -------------
@@ -4,9 +4,11 @@ This plugin enables the use of TLS (via `STARTTLS`) in Haraka.
4
4
 
5
5
  For this plugin to work you must have SSL certificates installed correctly.
6
6
 
7
+ Haraka has [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) support. When the remote MUA/MTA presents a servername during the TLS handshake and a TLS certificate with that Common Name matches, that certificate will be presented. If no match is found, the default certificate (see Certificate Files) is presented.
8
+
7
9
  ## Certificate Files
8
10
 
9
- Defaults are shown and can be overridden in `config/tls.ini`.
11
+ Defaults settings are shown and can be overridden in `config/tls.ini`.
10
12
 
11
13
  ```ini
12
14
  key=tls_key.pem
@@ -16,20 +18,39 @@ dhparam=dhparams.pem
16
18
 
17
19
  ## Certificate Directory
18
20
 
19
- If the directory `config/tls` exists, each file within the directory is expected to be a PEM encoded TLS bundle. Generate the PEM bundles in The Usual Way[TM] by concatenating the key, certificate, and CA/chain certs in that order. Example:
21
+ If the directory `config/tls` exists, files within the directory are PEM encoded TLS files in one of two formats: bundles or Wild Wild West.
22
+
23
+ ### Certificate bundles
24
+
25
+ Generate PEM bundles in The Usual Way[TM] by concatenating the key, certificate, and CA/chain certs in that order. Example:
20
26
 
21
27
  ```sh
22
- cat example.com.key example.com.crt ca.crt > config/tls/example.com.pem
28
+ cat example.com.key example.com.crt ca-int.crt > haraka/config/tls/example.com.pem
23
29
  ```
24
30
 
25
- An example [acme.sh](https://acme.sh) deployment [script](https://github.com/msimerson/Mail-Toaster-6/blob/master/provision/letsencrypt.sh) demonstrates how to install [Let's Encrypt](https://letsencrypt.org) certificates to the Haraka `config/tls`directory.
31
+ An example [acme.sh](https://acme.sh) deployment [script](https://github.com/msimerson/Mail-Toaster-6/blob/master/provision/letsencrypt.sh) installs [Let's Encrypt](https://letsencrypt.org) certificate bundles to the Haraka `config/tls`directory.
32
+
33
+ ### Wild Wild West
34
+
35
+ PEM encoded TLS certificates and keys can be stored in files in `config/tls`. The certificate loader is recursive, so TLS files can be in subdirs like `config/tls/mx1.example.com`. The certificate names are parsed from the 1st cert in each file and indexed by the certs Common Name(s). Subject Alternate Names are supported. The file name containing the certificates does *not* matter. Additional certificates within each file are presumed to be CA chain (intermediate) certificates.
36
+
37
+ If the TLS key is stored in the same file as the matching certificate, then the name of the file does not matter. If the TLS key is alone in a file, the file MUST be named with the keys Common Name. The file extension does not matter, `.pem` and `.key` are common. If the key is used for multiple CNs, the key must be stored in a file name matching each CN. Examples of working TLS key/cert file pairs for the Common Name mx1.example.com:
26
38
 
27
- Haraka has [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) support. When the remote MUA/MTA presents a servername during the TLS handshake and a TLS certificate with that Common Name matches, that certificate will be presented. If no match is found, the default certificate (see Certificate Files above) is presented.
39
+ 1. certificate bundle (see above), key & cert in same file
40
+ - config/tls/mx1.example.com.pem (recommended)
41
+ - config/tls/any-unique-name.pem (CN is extracted from 1st cert)
42
+ 2. files in TLS dir
43
+ - config/tls/mx1.example.com.crt
44
+ - config/tls/mx1.example.com.key
45
+ 3. files in subdir
46
+ - config/tls/example.com/mx1.cert
47
+ - config/tls/example.com/mx1.example.com.key
48
+ 4. wildcard bundle on Windows platform (* is not allowed in file names)
49
+ - config/tls/_.example.com.pem
28
50
 
29
51
  ## Purchased Certificate
30
52
 
31
- If you have a purchased certificate, append any intermediate/chained/ca-cert
32
- files to the certificate in this order:
53
+ For purchased certificate, append any intermediate/chained/ca-cert files to the certificate in this order:
33
54
 
34
55
  1. The CA signed SSL cert
35
56
  2. Any intermediate certificates
@@ -39,8 +60,7 @@ See also [Setting Up TLS](https://github.com/haraka/Haraka/wiki/Setting-up-TLS-w
39
60
 
40
61
  ## Self Issued (unsigned) Certificate
41
62
 
42
- Create a certificate and key file in the config directory with the following
43
- command:
63
+ Create a certificate and key file in the config directory with the following command:
44
64
 
45
65
  openssl req -x509 -nodes -days 2190 -newkey rsa:2048 \
46
66
  -keyout config/tls_key.pem -out config/tls_cert.pem
@@ -89,6 +109,14 @@ If needed, add this section to the `config/tls.ini` file and list any IP ranges
89
109
  172.16.0.0/16
90
110
  ```
91
111
 
112
+ Note: `[no_tls_hosts]` section applies to inbound only. For outbound mail, this feature is implemented as an array like `force_tls_hosts`:
113
+
114
+ ```ini
115
+ [outbound]
116
+ no_tls_hosts[]=192.168.1.3
117
+ no_tls_hosts[]=172.16.0.0/16
118
+ ```
119
+
92
120
  The [Node.js TLS](http://nodejs.org/api/tls.html) page has additional information about the following options.
93
121
 
94
122
  ### no_starttls_ports
package/endpoint.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
  // Socket address parser/formatter and server binding helper
3
3
 
4
- const fs = require('fs');
4
+ const fs = require('node:fs/promises');
5
5
  const sockaddr = require('sockaddr');
6
6
 
7
7
  module.exports = function endpoint (addr, defaultPort) {
@@ -46,21 +46,24 @@ class Endpoint {
46
46
  }
47
47
 
48
48
  // Make server listen on this endpoint, w/optional options
49
- bind (server, opts) {
50
- let done;
51
- opts = Object.assign({}, opts || {});
49
+ async bind (server, opts) {
50
+ opts = {...opts};
51
+
52
+ const mode = this.mode ? parseInt(this.mode, 8) : false;
52
53
  if (this.path) {
53
- const path = opts.path = this.path;
54
- const mode = this.mode ? parseInt(this.mode, 8) : false;
55
- if (mode) {
56
- done = () => fs.chmodSync(path, mode);
57
- }
58
- if (fs.existsSync(path)) fs.unlinkSync(path);
59
- }
60
- else {
54
+ opts.path = this.path;
55
+ await fs.rm(this.path, { force: true }); // errors are ignored when force is true
56
+ } else {
61
57
  opts.host = this.host;
62
58
  opts.port = this.port;
63
59
  }
64
- server.listen(opts, done);
60
+
61
+ return new Promise((resolve, reject) => {
62
+ server.listen(opts, async (err) => {
63
+ if(err) return reject(err);
64
+ if (mode) await fs.chmod(opts.path, mode);
65
+ resolve()
66
+ });
67
+ });
65
68
  }
66
69
  }
package/haraka.js CHANGED
@@ -20,20 +20,18 @@ catch (e) {
20
20
  require('module')._initPaths(); // Horrible hack
21
21
  }
22
22
 
23
- const fs = require('fs');
23
+ const utils = require('haraka-utils');
24
24
  const logger = require('./logger');
25
25
  const server = require('./server');
26
26
 
27
- exports.version = JSON.parse(
28
- fs.readFileSync(path.join(__dirname, './package.json'), 'utf8')
29
- ).version;
27
+ exports.version = utils.getVersion(__dirname)
30
28
 
31
29
  process.on('uncaughtException', err => {
32
30
  if (err.stack) {
33
- err.stack.split("\n").forEach(line => logger.logcrit(line));
31
+ err.stack.split("\n").forEach(line => logger.crit(line));
34
32
  }
35
33
  else {
36
- logger.logcrit(`Caught exception: ${JSON.stringify(err)}`);
34
+ logger.crit(`Caught exception: ${JSON.stringify(err)}`);
37
35
  }
38
36
  logger.dump_and_exit(1);
39
37
  });
@@ -41,18 +39,16 @@ process.on('uncaughtException', err => {
41
39
  let shutting_down = false;
42
40
  const signals = ['SIGINT'];
43
41
 
44
- if (process.pid === 1) {
45
- signals.push('SIGTERM')
46
- }
42
+ if (process.pid === 1) signals.push('SIGTERM')
47
43
 
48
- signals.forEach((sig) => {
44
+ for (const sig of signals) {
49
45
  process.on(sig, () => {
50
46
  if (shutting_down) return process.exit(1);
51
47
  shutting_down = true;
52
48
  const [, filename] = process.argv;
53
49
  process.title = path.basename(filename, '.js');
54
50
 
55
- logger.lognotice(`${sig} received`);
51
+ logger.notice(`${sig} received`);
56
52
  logger.dump_and_exit(() => {
57
53
  if (server.cluster?.isMaster) {
58
54
  server.performShutdown();
@@ -62,10 +58,10 @@ signals.forEach((sig) => {
62
58
  }
63
59
  });
64
60
  });
65
- });
61
+ }
66
62
 
67
63
  process.on('SIGHUP', () => {
68
- logger.lognotice('Flushing the temp fail queue');
64
+ logger.notice('Flushing the temp fail queue');
69
65
  server.flushQueue();
70
66
  });
71
67
 
@@ -74,7 +70,7 @@ process.on('exit', code => {
74
70
  const [, filename] = process.argv;
75
71
  process.title = path.basename(filename, '.js');
76
72
 
77
- logger.lognotice('Shutting down');
73
+ logger.notice('Shutting down');
78
74
  logger.dump_logs();
79
75
  });
80
76
 
package/host_pool.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const net = require('net');
3
+ const net = require('node:net');
4
4
  const utils = require('haraka-utils');
5
5
 
6
6
  /* HostPool:
@@ -61,7 +61,7 @@ class HostPool {
61
61
  self.dead_hosts[key] = true;
62
62
 
63
63
  function cb_if_still_dead () {
64
- logger.logwarn(`${host} ${key} is still dead, will retry in ${self.retry_secs} secs`);
64
+ logger.warn(`${host} ${key} is still dead, will retry in ${self.retry_secs} secs`);
65
65
  self.dead_hosts[key] = true;
66
66
  // console.log(1);
67
67
  setTimeout(() => {
@@ -71,7 +71,7 @@ class HostPool {
71
71
 
72
72
  function cb_if_alive () {
73
73
  // console.log(2);
74
- logger.loginfo(`${host} ${key} is back! adding back into pool`);
74
+ logger.info(`${host} ${key} is back! adding back into pool`);
75
75
  delete self.dead_hosts[key];
76
76
  }
77
77
 
@@ -90,7 +90,7 @@ class HostPool {
90
90
  probe_dead_host (
91
91
  host, port, cb_if_still_dead, cb_if_alive
92
92
  ){
93
- logger.loginfo(`probing dead host ${host}:${port}`);
93
+ logger.info(`probing dead host ${host}:${port}`);
94
94
 
95
95
  const connect_timeout_ms = 200; // keep it snappy
96
96
  let s;
@@ -162,7 +162,7 @@ class HostPool {
162
162
  return host;
163
163
  }
164
164
  else {
165
- logger.logwarn(
165
+ logger.warn(
166
166
  `no working hosts found, retrying a dead one, config (probably from smtp_forward.forwarding_host_pool) is '${this.hostports_str}'`);
167
167
  this.last_i = first_i;
168
168
  return this.hosts[first_i];
@@ -9,10 +9,13 @@
9
9
 
10
10
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.5.1/css/bootstrap.min.css">
11
11
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.5.1/css/bootstrap-theme.min.css">
12
+
13
+ <script src="https://code.jquery.com/jquery-3.5.1.min.js" async></script>
14
+ <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.5.1/js/bootstrap.min.js" async></script>
12
15
  </head>
13
16
  <body>
14
17
  <!--[if lt IE 7]>
15
- <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
18
+ <p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="https://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
16
19
  <![endif]-->
17
20
 
18
21
  <ul id="tabList" class="nav nav-tabs" role="tablist navigation">
@@ -23,13 +26,11 @@
23
26
  <div class="tab-pane fade in active" id="home">
24
27
  <h1>Haraka, a mail server (MTA).</h1>
25
28
 
26
- <p>You are visiting an installation of <a href="http://haraka.github.io">Haraka</a>.</p>
29
+ <p>You are visiting an installation of <a href="https://haraka.github.io">Haraka</a>.</p>
27
30
 
28
- <p>Haraka is on the <a href="http://haraka.github.io">web</a> and <a href="https://github.com/haraka/Haraka">GitHub</a></p>
31
+ <p>Haraka is on the <a href="https://haraka.github.io">web</a> and <a href="https://github.com/haraka/Haraka">GitHub</a></p>
29
32
  </div>
30
33
  </div>
31
34
 
32
- <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
33
- <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.5.1/js/bootstrap.min.js"></script>
34
35
  </body>
35
36
  </html>
package/line_socket.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
  // A subclass of Socket which reads data by line
3
3
 
4
- const net = require('net');
4
+ const net = require('node:net');
5
5
  const utils = require('haraka-utils');
6
6
 
7
7
  const tls_socket = require('./tls_socket');
@@ -37,17 +37,16 @@ function setup_line_processor (socket) {
37
37
  exports.Socket = Socket;
38
38
 
39
39
  // New interface - uses TLS
40
- exports.connect = (port, host, cb) => {
40
+ exports.connect = (port, host) => {
41
41
  let options = {};
42
42
  if (typeof port === 'object') {
43
43
  options = port;
44
- cb = host;
45
44
  }
46
45
  else {
47
46
  options.port = port;
48
47
  options.host = host;
49
48
  }
50
- const sock = tls_socket.connect(options, cb);
49
+ const sock = tls_socket.connect(options);
51
50
  setup_line_processor(sock);
52
51
  return sock;
53
52
  }