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