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,381 +0,0 @@
1
- // messagesniffer
2
-
3
- const fs = require('fs');
4
- const net = require('net');
5
- const plugin = exports;
6
-
7
- // Defaults
8
- let port = 9001;
9
-
10
- exports.register = function () {
11
- const cfg = this.config.get('messagesniffer.ini');
12
- if (cfg.main.port) port = parseInt(cfg.main.port);
13
- }
14
-
15
- exports.hook_connect = function (next, connection) {
16
- const cfg = this.config.get('messagesniffer.ini');
17
- // Skip any private IP ranges
18
- // Skip connection.transaction undefined
19
- if (connection?.remote?.is_private || !connection?.transaction) return next();
20
-
21
- // Retrieve GBUdb information for the connecting IP
22
- SNFClient(`<snf><xci><gbudb><test ip='${connection.remote.ip}'/></gbudb></xci></snf>`, (err, result) => {
23
- if (err) {
24
- connection.logerror(this, err.message);
25
- return next();
26
- }
27
- let match;
28
- if ((match = /<result ((?:(?!\/>)[^])+)\/>/.exec(result))) {
29
- // Log result
30
- connection.loginfo(this, match[1]);
31
- // Populate result
32
- const gbudb = {};
33
- const split = match[1].toString().split(/\s+/);
34
- for (const element of split) {
35
- const split2 = element.split(/=/);
36
- gbudb[split2[0]] = split2[1].replace(/(?:^'|'$)/g,'');
37
- }
38
- // Set notes for other plugins
39
- connection.notes.gbudb = gbudb;
40
- // Handle result
41
- switch (gbudb.range) {
42
- case 'new':
43
- case 'normal':
44
- return next();
45
- case 'white':
46
- // Default for white if no configuration
47
- if (!cfg.gbudb || (cfg.gbudb && !cfg.gbudb[gbudb.range])) {
48
- return next(OK);
49
- }
50
- // fall through
51
- case 'caution':
52
- case 'black':
53
- case 'truncate':
54
- if (cfg.gbudb?.[gbudb.range]) {
55
- connection.loginfo(this, `range=${gbudb.range} action=${cfg.gbudb[gbudb.range]}`);
56
- switch (cfg.gbudb[gbudb.range]) {
57
- case 'accept':
58
- // Whitelist
59
- connection.notes.gbudb.action = 'accept';
60
- return next(OK);
61
- case 'allow':
62
- case 'continue':
63
- // Continue to next plugin
64
- connection.notes.gbudb.action = 'allow';
65
- return next();
66
- case 'retry':
67
- case 'tempfail':
68
- return next(DENYSOFT, `Poor GBUdb reputation for [${connection.remote.ip}]`);
69
- case 'reject':
70
- return next(DENY, `Poor GBUdb reputation for [${connection.remote.ip}]`);
71
- case 'quarantine':
72
- connection.notes.gbudb.action = 'quarantine';
73
- connection.notes.quarantine = true;
74
- connection.notes.quarantine_action = [ OK, `Message quarantined (${connection.transaction.uuid})` ];
75
- break;
76
- case 'tag':
77
- connection.notes.gbudb.action = 'tag';
78
- break;
79
- default:
80
- // Unknown action
81
- return next();
82
- }
83
- }
84
- else if (gbudb.range === 'truncate') {
85
- // Default for truncate
86
- return next(DENY, `Poor GBUdb reputation for [${connection.remote.ip}]`);
87
- }
88
- return next();
89
- default:
90
- // Unknown
91
- connection.logerror(this, `Unknown GBUdb range: ${gbudb.range}`);
92
- next();
93
- }
94
- }
95
- else {
96
- next();
97
- }
98
- });
99
- }
100
-
101
- exports.hook_data_post = function (next, connection) {
102
- const cfg = this.config.get('messagesniffer.ini');
103
- const txn = connection?.transaction;
104
- if (!txn) return next();
105
-
106
- function tag_subject (){
107
- const tag = cfg.main.tag_string || '[SPAM]';
108
- const subj = txn.header.get_decoded('Subject');
109
- // Try and prevent any double subject modifications
110
- const subject_re = new RegExp(`^${tag}`);
111
- if (!subject_re.test(subj)) {
112
- txn.remove_header('Subject');
113
- txn.add_header('Subject', `${tag} ${subj}`);
114
- }
115
- // Add spam flag
116
- txn.remove_header('X-Spam-Flag');
117
- txn.add_header('X-Spam-Flag', 'YES');
118
- }
119
-
120
- // Check GBUdb results
121
- if (connection.notes.gbudb?.action) {
122
- switch (connection.notes.gbudb.action) {
123
- case 'accept':
124
- case 'quarantine':
125
- return next(OK);
126
- case 'tag':
127
- // Tag message
128
- tag_subject();
129
- return next();
130
- }
131
- }
132
-
133
- const tmpdir = cfg.main.tmpdir || '/tmp';
134
- const tmpfile = `${tmpdir}/${txn.uuid}.tmp`;
135
- const ws = fs.createWriteStream(tmpfile);
136
-
137
- ws.once('error', err => {
138
- connection.logerror(this, `Error writing temporary file: ${err.message}`);
139
- next();
140
- });
141
-
142
- ws.once('close', () => {
143
- const start_time = Date.now();
144
- SNFClient(`<snf><xci><scanner><scan file='${tmpfile}' xhdr='yes'/></scanner></xci></snf>`, (err, result) => {
145
- const end_time = Date.now();
146
- const elapsed = end_time - start_time;
147
- // Delete the tempfile
148
- fs.unlink(tmpfile, () => {});
149
- let match;
150
- // Make sure we actually got a result
151
- if ((match = /<result code='(\d+)'/.exec(result))) {
152
- const code = parseInt(match[1]);
153
- let group;
154
- let rules;
155
- let gbudb_ip;
156
- // Make a note that we actually ran
157
- connection.notes.snf_run = true;
158
- // Get the returned headers
159
- if ((match = /<xhdr>((?:(?!<\/xhdr>)[^])+)/.exec(result,'m'))) {
160
- // Parse the returned headers and add them to the message
161
- const xhdr = match[1].split('\r\n');
162
- const headers = [];
163
- for (const line of xhdr) {
164
- // Check for continuation
165
- if (/^\s/.test(line)) {
166
- // Continuation; add to previous header value
167
- if (headers[headers.length-1]) {
168
- headers[headers.length-1].value += `${line}\r\n`;
169
- }
170
- }
171
- else {
172
- // Must be a header
173
- match = /^([^: ]+):(?:\s*(.+))?$/.exec(line);
174
- if (match) {
175
- headers.push({ header: match[1], value: (match[2] ? `${match[2]}\r\n` : '\r\n') });
176
- }
177
- }
178
- }
179
- // Add headers to message
180
- for (const header of headers) {
181
- // If present save the group for logging purposes
182
- if (header.header === 'X-MessageSniffer-SNF-Group') {
183
- group = header.value.replace(/\r?\n/gm, '');
184
- }
185
- // Log GBUdb analysis
186
- if (header.header === 'X-GBUdb-Analysis') {
187
- // Retrieve IP address determined by GBUdb
188
- const gbudb_split = header.value.split(/,\s*/);
189
- gbudb_ip = gbudb_split[1];
190
- connection.logdebug(this, `GBUdb: ${header.value.replace(/\r?\n/gm, '')}`);
191
- }
192
- if (header.header === 'X-MessageSniffer-Rules') {
193
- rules = header.value.replace(/\r?\n/gm, '').replace(/\s+/g,' ').trim();
194
- connection.logdebug(this, `rules: ${rules}`);
195
- }
196
- // Remove any existing headers
197
- txn.remove_header(header.header);
198
- txn.add_header(header.header, header.value);
199
- }
200
- }
201
- // Summary log
202
- connection.loginfo(this, `result: time=${elapsed}ms code=${code
203
- }${gbudb_ip ? ` ip="${gbudb_ip}"` : ''
204
- }${group ? ` group="${group}"` : ''
205
- }${rules ? ` rule_count=${rules.split(/\s+/).length}` : ''
206
- }${rules ? ` rules="${rules}"` : ''}`);
207
- // Result code MUST in the 0-63 range otherwise we got an error
208
- // http://www.armresearch.com/support/articles/software/snfServer/errors.jsp
209
- if (code === 0 || (code && code <= 63)) {
210
- // Handle result
211
- let action;
212
- if (cfg.message) {
213
- if (code === 0 && cfg.message.white) {
214
- action = cfg.message.white;
215
- }
216
- else if (code === 1) {
217
- if (cfg.message.local_white) {
218
- action = cfg.message.local_white;
219
- }
220
- else {
221
- return next(OK);
222
- }
223
- }
224
- else if (code === 20) {
225
- if (cfg.message.truncate) {
226
- action = cfg.message.truncate;
227
- }
228
- else {
229
- return next(DENY, `Poor GBUdb reputation for IP [${connection.remote.ip}]`);
230
- }
231
- }
232
- else if (code === 40 && cfg.message.caution) {
233
- action = cfg.message.caution;
234
- }
235
- else if (code === 63 && cfg.message.black) {
236
- action = cfg.message.black;
237
- }
238
- else {
239
- if (cfg.message[`code_${code}`]) {
240
- action = cfg.message[`code_${code}`];
241
- }
242
- else {
243
- if (code > 1 && code !== 40) {
244
- if (cfg.message.nonzero) {
245
- action = cfg.message.nonzero;
246
- }
247
- else {
248
- return next(DENY, `Spam detected by MessageSniffer (code=${code} group=${group})`);
249
- }
250
- }
251
- }
252
- }
253
- }
254
- else {
255
- // Default with no configuration
256
- if (code > 1 && code !== 40) {
257
- return next(DENY, `Spam detected by MessageSniffer (code=${code} group=${group})`);
258
- }
259
- else {
260
- return next();
261
- }
262
- }
263
- switch (action) {
264
- case 'accept':
265
- // Whitelist
266
- return next(OK);
267
- case 'allow':
268
- case 'continue':
269
- // Continue to next plugin
270
- return next();
271
- case 'retry':
272
- case 'tempfail':
273
- return next(DENYSOFT, `Spam detected by MessageSniffer (code=${code} group=${group})`);
274
- case 'reject':
275
- return next(DENY, `Spam detected by MessageSniffer (code=${code} group=${group})`);
276
- case 'quarantine':
277
- // Set flag for queue/quarantine plugin
278
- txn.notes.quarantine = true;
279
- txn.notes.quarantine_action = [ OK, `Message quarantined (${txn.uuid})` ];
280
- break;
281
- case 'tag':
282
- tag_subject();
283
- // fall through
284
- default:
285
- return next();
286
- }
287
- }
288
- else {
289
- // Out-of-band code returned
290
- // Handle Bulk/Noisy special rule by re-writing the Precedence header
291
- if (code === 100) {
292
- let precedence = txn.header.get('precedence');
293
- if (precedence) {
294
- // We already have a precedence header
295
- precedence = precedence.trim().toLowerCase();
296
- switch (precedence) {
297
- case 'bulk':
298
- case 'list':
299
- case 'junk':
300
- // Leave these as they are
301
- break;
302
- default:
303
- // Remove anything else and replace it with 'bulk'
304
- txn.remove_header('precedence');
305
- txn.add_header('Precedence', 'bulk');
306
- }
307
- }
308
- else {
309
- txn.add_header('Precedence', 'bulk');
310
- }
311
- }
312
- return next();
313
- }
314
- }
315
- else {
316
- // Something must have gone wrong
317
- connection.logwarn(this, `unexpected response: ${result}`);
318
- }
319
- return next();
320
- });
321
- });
322
-
323
- // TODO: we only need the first 64Kb of the message
324
- txn.message_stream.pipe(ws, { line_endings: '\r\n' });
325
- }
326
-
327
- exports.hook_disconnect = function (next, connection) {
328
- const cfg = this.config.get('messagesniffer.ini');
329
-
330
- // Train GBUdb on rejected messages and recipients
331
- if (cfg.main.gbudb_report_deny && !connection.notes.snf_run &&
332
- (connection.rcpt_count.reject > 0 || connection.msg_count.reject > 0)) {
333
- const snfreq = `<snf><xci><gbudb><bad ip='${connection.remote.ip}'/></gbudb></xci></snf>`;
334
- SNFClient(snfreq, (err, result) => {
335
- if (err) {
336
- connection.logerror(this, err.message);
337
- }
338
- else {
339
- connection.logdebug(this, `GBUdb bad encounter added for ${connection.remote.ip}`);
340
- }
341
- next();
342
- });
343
- }
344
- else {
345
- next();
346
- }
347
- }
348
-
349
- function SNFClient (req, cb) {
350
- let result;
351
- const sock = new net.Socket();
352
- sock.setTimeout(30 * 1000); // Connection timeout
353
- sock.once('timeout', function () {
354
- this.destroy();
355
- cb(new Error('connection timed out'));
356
- });
357
- sock.once('error', err => cb(err));
358
- sock.once('connect', function () {
359
- // Connected, send request
360
- plugin.logprotocol(`> ${req}`);
361
- this.write(`${req}\n`);
362
- });
363
- sock.on('data', data => {
364
- plugin.logprotocol(`< ${data}`);
365
- // Buffer all the received lines
366
- (result ? result += data : result = data);
367
- });
368
- sock.once('end', () => {
369
- // Check for result
370
- if (/<result /.exec(result)) return cb(null, result);
371
-
372
- let match;
373
- if ((match = /<error message='([^']+)'/.exec(result))) {
374
- return cb(new Error(match[1]));
375
- }
376
-
377
- cb(new Error(`unexpected result: ${result}`));
378
- });
379
- // Start the sequence
380
- sock.connect(port);
381
- }
@@ -1,3 +0,0 @@
1
- exports.register = function () {
2
- this.logerror('This plugin has moved. See https://github.com/haraka/haraka-plugin-rcpt-ldap');
3
- }
@@ -1,24 +0,0 @@
1
- // Implement a maximum number of recipients per mail
2
- // this helps guard against some spammers who send RCPT TO a gazillion times
3
- // as a way of probing for a working address
4
-
5
- // Consider using the karma plugin. It supports limiting the number
6
- // of recipients based on past behavior (good, bad, unknown)
7
-
8
- exports.hook_rcpt = function (next, connection = {}) {
9
- const { notes } = connection.transaction
10
-
11
- if (notes?.rcpt_to_count) {
12
- notes.rcpt_to_count++;
13
- }
14
- else {
15
- notes.rcpt_to_count = 1;
16
- }
17
-
18
- const max_count = this.config.get('rcpt_to.max_count') || 40;
19
-
20
- if (notes.rcpt_to_count > max_count) {
21
- return next(DENYDISCONNECT, "Too many recipient attempts");
22
- }
23
- return next();
24
- }