Haraka 3.0.3 → 3.0.4

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 (238) hide show
  1. package/.eslintrc.yaml +5 -9
  2. package/.prettierrc.yml +1 -0
  3. package/CONTRIBUTORS.md +11 -0
  4. package/Changes.md +1365 -1214
  5. package/Plugins.md +117 -105
  6. package/README.md +4 -13
  7. package/bin/haraka +197 -298
  8. package/config/auth_flat_file.ini +1 -0
  9. package/config/dhparams.pem +8 -0
  10. package/config/mail_from.is_resolvable.ini +4 -2
  11. package/config/me +1 -0
  12. package/config/outbound.ini +0 -2
  13. package/config/plugins +36 -35
  14. package/config/smtp.ini +0 -1
  15. package/config/smtp.json +17 -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 +29 -9
  28. package/endpoint.js +16 -13
  29. package/haraka.js +10 -14
  30. package/host_pool.js +5 -5
  31. package/line_socket.js +3 -4
  32. package/logger.js +44 -28
  33. package/outbound/client_pool.js +27 -23
  34. package/outbound/config.js +4 -6
  35. package/outbound/fsync_writestream.js +1 -1
  36. package/outbound/hmail.js +178 -218
  37. package/outbound/index.js +86 -99
  38. package/outbound/qfile.js +1 -1
  39. package/outbound/queue.js +51 -44
  40. package/outbound/timer_queue.js +3 -2
  41. package/outbound/tls.js +19 -7
  42. package/package.json +59 -48
  43. package/plugins/.eslintrc.yaml +0 -6
  44. package/plugins/auth/auth_base.js +4 -2
  45. package/plugins/auth/auth_proxy.js +14 -12
  46. package/plugins/auth/auth_vpopmaild.js +1 -1
  47. package/plugins/block_me.js +1 -1
  48. package/plugins/data.signatures.js +2 -4
  49. package/plugins/early_talker.js +2 -1
  50. package/plugins/mail_from.is_resolvable.js +65 -135
  51. package/plugins/queue/deliver.js +4 -5
  52. package/plugins/queue/lmtp.js +11 -14
  53. package/plugins/queue/qmail-queue.js +2 -2
  54. package/plugins/queue/quarantine.js +2 -2
  55. package/plugins/queue/rabbitmq.js +16 -17
  56. package/plugins/queue/smtp_forward.js +3 -3
  57. package/plugins/queue/smtp_proxy.js +10 -1
  58. package/plugins/queue/test.js +2 -2
  59. package/plugins/rcpt_to.host_list_base.js +5 -5
  60. package/plugins/rcpt_to.in_host_list.js +2 -2
  61. package/plugins/relay.js +6 -7
  62. package/plugins/reseed_rng.js +1 -1
  63. package/plugins/status.js +37 -33
  64. package/plugins/tls.js +2 -2
  65. package/plugins/xclient.js +3 -2
  66. package/plugins.js +50 -54
  67. package/run_tests +3 -30
  68. package/server.js +190 -190
  69. package/smtp_client.js +30 -23
  70. package/{tests → test}/config/plugins +0 -2
  71. package/{tests → test}/config/smtp.ini +1 -1
  72. package/test/config/tls/example.com/_.example.com.key +28 -0
  73. package/test/config/tls/example.com/example.com.crt +25 -0
  74. package/test/connection.js +302 -0
  75. package/test/endpoint.js +94 -0
  76. package/{tests → test}/fixtures/line_socket.js +1 -1
  77. package/{tests → test}/fixtures/util_hmailitem.js +19 -25
  78. package/{tests → test}/host_pool.js +42 -57
  79. package/test/logger.js +258 -0
  80. package/test/outbound/hmail.js +141 -0
  81. package/test/outbound/index.js +220 -0
  82. package/test/outbound/qfile.js +126 -0
  83. package/test/outbound_bounce_net_errors.js +142 -0
  84. package/{tests → test}/outbound_bounce_rfc3464.js +110 -122
  85. package/test/plugins/auth/auth_base.js +484 -0
  86. package/test/plugins/auth/auth_vpopmaild.js +83 -0
  87. package/test/plugins/early_talker.js +104 -0
  88. package/test/plugins/mail_from.is_resolvable.js +35 -0
  89. package/test/plugins/queue/smtp_forward.js +206 -0
  90. package/test/plugins/rcpt_to.host_list_base.js +122 -0
  91. package/test/plugins/rcpt_to.in_host_list.js +193 -0
  92. package/test/plugins/relay.js +303 -0
  93. package/test/plugins/status.js +130 -0
  94. package/test/plugins/tls.js +70 -0
  95. package/test/plugins.js +228 -0
  96. package/test/rfc1869.js +73 -0
  97. package/test/server.js +491 -0
  98. package/test/smtp_client.js +299 -0
  99. package/test/tls_socket.js +273 -0
  100. package/test/transaction.js +270 -0
  101. package/tls_socket.js +202 -252
  102. package/transaction.js +8 -23
  103. package/CONTRIBUTING.md +0 -1
  104. package/bin/dkimverify +0 -40
  105. package/config/access.domains +0 -13
  106. package/config/attachment.ctype.regex +0 -2
  107. package/config/attachment.filename.regex +0 -1
  108. package/config/avg.ini +0 -5
  109. package/config/bounce.ini +0 -15
  110. package/config/data.headers.ini +0 -61
  111. package/config/dkim/dkim_key_gen.sh +0 -78
  112. package/config/dkim_sign.ini +0 -4
  113. package/config/dkim_verify.ini +0 -7
  114. package/config/dnsbl.ini +0 -23
  115. package/config/greylist.ini +0 -43
  116. package/config/helo.checks.ini +0 -52
  117. package/config/messagesniffer.ini +0 -18
  118. package/config/spamassassin.ini +0 -56
  119. package/dkim.js +0 -614
  120. package/docs/plugins/avg.md +0 -35
  121. package/docs/plugins/bounce.md +0 -69
  122. package/docs/plugins/clamd.md +0 -147
  123. package/docs/plugins/esets.md +0 -8
  124. package/docs/plugins/greylist.md +0 -90
  125. package/docs/plugins/helo.checks.md +0 -135
  126. package/docs/plugins/messagesniffer.md +0 -163
  127. package/docs/plugins/spamassassin.md +0 -180
  128. package/outbound/mx_lookup.js +0 -70
  129. package/plugins/auth/auth_ldap.js +0 -3
  130. package/plugins/avg.js +0 -162
  131. package/plugins/backscatterer.js +0 -25
  132. package/plugins/bounce.js +0 -381
  133. package/plugins/clamd.js +0 -382
  134. package/plugins/data.uribl.js +0 -4
  135. package/plugins/dkim_sign.js +0 -395
  136. package/plugins/dkim_verify.js +0 -62
  137. package/plugins/dns_list_base.js +0 -221
  138. package/plugins/dnsbl.js +0 -146
  139. package/plugins/dnswl.js +0 -58
  140. package/plugins/esets.js +0 -71
  141. package/plugins/graph.js +0 -5
  142. package/plugins/greylist.js +0 -645
  143. package/plugins/helo.checks.js +0 -533
  144. package/plugins/messagesniffer.js +0 -381
  145. package/plugins/rcpt_to.ldap.js +0 -3
  146. package/plugins/rcpt_to.max_count.js +0 -24
  147. package/plugins/spamassassin.js +0 -384
  148. package/tests/config/dkim/example.com/dns +0 -29
  149. package/tests/config/dkim/example.com/private +0 -6
  150. package/tests/config/dkim/example.com/public +0 -4
  151. package/tests/config/dkim/example.com/selector +0 -1
  152. package/tests/config/dkim.private.key +0 -6
  153. package/tests/config/dkim_sign.ini +0 -4
  154. package/tests/config/helo.checks.ini +0 -52
  155. package/tests/connection.js +0 -327
  156. package/tests/endpoint.js +0 -128
  157. package/tests/fixtures/vm_harness.js +0 -59
  158. package/tests/logger.js +0 -327
  159. package/tests/outbound/hmail.js +0 -112
  160. package/tests/outbound/index.js +0 -324
  161. package/tests/outbound/qfile.js +0 -67
  162. package/tests/outbound_bounce_net_errors.js +0 -173
  163. package/tests/plugins/auth/auth_base.js +0 -463
  164. package/tests/plugins/auth/auth_vpopmaild.js +0 -91
  165. package/tests/plugins/bounce.js +0 -307
  166. package/tests/plugins/clamd.js +0 -224
  167. package/tests/plugins/deprecated/relay_acl.js +0 -140
  168. package/tests/plugins/deprecated/relay_all.js +0 -59
  169. package/tests/plugins/dkim_sign.js +0 -315
  170. package/tests/plugins/dkim_signer.js +0 -108
  171. package/tests/plugins/dns_list_base.js +0 -259
  172. package/tests/plugins/dnsbl.js +0 -101
  173. package/tests/plugins/early_talker.js +0 -115
  174. package/tests/plugins/greylist.js +0 -58
  175. package/tests/plugins/helo.checks.js +0 -525
  176. package/tests/plugins/mail_from.is_resolvable.js +0 -116
  177. package/tests/plugins/queue/smtp_forward.js +0 -221
  178. package/tests/plugins/rcpt_to.host_list_base.js +0 -132
  179. package/tests/plugins/rcpt_to.in_host_list.js +0 -218
  180. package/tests/plugins/relay.js +0 -339
  181. package/tests/plugins/spamassassin.js +0 -171
  182. package/tests/plugins/status.js +0 -138
  183. package/tests/plugins/tls.js +0 -84
  184. package/tests/plugins.js +0 -247
  185. package/tests/rfc1869.js +0 -61
  186. package/tests/server.js +0 -510
  187. package/tests/smtp_client/auth.js +0 -105
  188. package/tests/smtp_client/basic.js +0 -101
  189. package/tests/smtp_client.js +0 -80
  190. package/tests/tls_socket.js +0 -333
  191. package/tests/transaction.js +0 -284
  192. /package/docs/{plugins → deprecated}/dkim_sign.md +0 -0
  193. /package/docs/{plugins → deprecated}/dkim_verify.md +0 -0
  194. /package/docs/{plugins → deprecated}/dnsbl.md +0 -0
  195. /package/docs/{plugins → deprecated}/dnswl.md +0 -0
  196. /package/{tests → test}/.eslintrc.yaml +0 -0
  197. /package/{tests → test}/config/auth_flat_file.ini +0 -0
  198. /package/{tests → test}/config/dhparams.pem +0 -0
  199. /package/{tests → test}/config/host_list +0 -0
  200. /package/{tests → test}/config/outbound_tls_cert.pem +0 -0
  201. /package/{tests → test}/config/outbound_tls_key.pem +0 -0
  202. /package/{tests → test}/config/smtp_forward.ini +0 -0
  203. /package/{tests → test}/config/tls/ec.pem +0 -0
  204. /package/{tests → test}/config/tls/haraka.local.pem +0 -0
  205. /package/{tests → test}/config/tls/mismatched.pem +0 -0
  206. /package/{tests → test}/config/tls.ini +0 -0
  207. /package/{tests → test}/config/tls_cert.pem +0 -0
  208. /package/{tests → test}/config/tls_key.pem +0 -0
  209. /package/{tests → test}/fixtures/todo_qfile.txt +0 -0
  210. /package/{tests → test}/installation/config/test-plugin-flat +0 -0
  211. /package/{tests → test}/installation/config/test-plugin.ini +0 -0
  212. /package/{tests → test}/installation/config/tls.ini +0 -0
  213. /package/{tests → test}/installation/node_modules/load_first/index.js +0 -0
  214. /package/{tests → test}/installation/node_modules/load_first/package.json +0 -0
  215. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin-flat +0 -0
  216. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin.ini +0 -0
  217. /package/{tests → test}/installation/node_modules/test-plugin/package.json +0 -0
  218. /package/{tests → test}/installation/node_modules/test-plugin/test-plugin.js +0 -0
  219. /package/{tests → test}/installation/plugins/base_plugin.js +0 -0
  220. /package/{tests → test}/installation/plugins/folder_plugin/index.js +0 -0
  221. /package/{tests → test}/installation/plugins/folder_plugin/package.json +0 -0
  222. /package/{tests → test}/installation/plugins/inherits.js +0 -0
  223. /package/{tests → test}/installation/plugins/load_first.js +0 -0
  224. /package/{tests → test}/installation/plugins/plugin.js +0 -0
  225. /package/{tests → test}/installation/plugins/tls.js +0 -0
  226. /package/{tests → test}/loud/config/dhparams.pem +0 -0
  227. /package/{tests → test}/loud/config/tls/goobered.pem +0 -0
  228. /package/{tests → test}/loud/config/tls.ini +0 -0
  229. /package/{tests → test}/mail_specimen/base64-root-part.txt +0 -0
  230. /package/{tests → test}/mail_specimen/varied-fold-lengths-preserve-data.txt +0 -0
  231. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
  232. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
  233. /package/{tests → test}/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
  234. /package/{tests → test}/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
  235. /package/{tests → test}/queue/multibyte +0 -0
  236. /package/{tests → test}/queue/plain +0 -0
  237. /package/{tests → test}/queue/zero-length +0 -0
  238. /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
- }