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
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "server",
10
10
  "email"
11
11
  ],
12
- "version": "3.0.3",
12
+ "version": "3.0.5",
13
13
  "homepage": "http://haraka.github.io",
14
14
  "repository": {
15
15
  "type": "git",
@@ -17,68 +17,74 @@
17
17
  },
18
18
  "main": "haraka.js",
19
19
  "engines": {
20
- "node": ">=16"
20
+ "node": ">=18"
21
21
  },
22
22
  "dependencies": {
23
- "address-rfc2821": "^2.1.1",
24
- "address-rfc2822": "^2.1.0",
25
- "async": "^3.2.5",
23
+ "address-rfc2821": "^2.1.2",
24
+ "address-rfc2822": "^2.2.2",
25
+ "async": "^3.2.6",
26
26
  "daemon": "~1.1.0",
27
- "ipaddr.js": "~2.1.0",
28
- "node-gyp": "^10.0.1",
29
- "nopt": "~7.2.0",
27
+ "haraka-config": "^1.4.0",
28
+ "haraka-constants": "^1.0.7",
29
+ "haraka-dsn": "^1.1.0",
30
+ "haraka-email-message": "^1.2.4",
31
+ "haraka-message-stream": "^1.2.2",
32
+ "haraka-net-utils": "^1.7.0",
33
+ "haraka-notes": "^1.1.0",
34
+ "haraka-plugin-redis": "^2.0.7",
35
+ "haraka-results": "^2.2.4",
36
+ "haraka-tld": "^1.2.2",
37
+ "haraka-utils": "^1.1.3",
38
+ "ipaddr.js": "~2.2.0",
39
+ "node-gyp": "^10.2.0",
40
+ "nopt": "^8.0.0",
30
41
  "npid": "~0.4.0",
31
- "semver": "~7.6.0",
32
- "sprintf-js": "~1.1.3",
33
- "haraka-config": "^1.1.0",
34
- "haraka-constants": "^1.0.6",
35
- "haraka-dsn": "^1.0.4",
36
- "haraka-email-message": "^1.2.0",
37
- "haraka-message-stream": "^1.2.0",
38
- "haraka-net-utils": "^1.5.3",
39
- "haraka-notes": "^1.0.6",
40
- "haraka-plugin-attachment": "^1.0.7",
41
- "haraka-plugin-spf": "1.2.4",
42
- "haraka-plugin-redis": "^2.0.6",
43
- "haraka-results": "^2.2.3",
44
- "haraka-tld": "^1.2.0",
45
- "haraka-utils": "^1.0.3",
46
- "openssl-wrapper": "^0.3.4",
47
- "sockaddr": "^1.0.1"
42
+ "redis": "~4.7.0",
43
+ "semver": "^7.6.3",
44
+ "sockaddr": "^1.0.1",
45
+ "sprintf-js": "~1.1.3"
48
46
  },
49
47
  "optionalDependencies": {
50
- "haraka-plugin-access": "^1.1.5",
51
- "haraka-plugin-aliases": "^1.0.1",
52
- "haraka-plugin-asn": "^2.0.2",
53
- "haraka-plugin-auth-ldap": "^1.1.0",
48
+ "haraka-plugin-access": "^1.1.6",
49
+ "haraka-plugin-aliases": "^1.0.2",
50
+ "haraka-plugin-asn": "^2.0.3",
51
+ "haraka-plugin-attachment": "^1.1.2",
52
+ "haraka-plugin-avg": "^1.1.0",
53
+ "haraka-plugin-bounce": "1.0.2",
54
+ "haraka-plugin-clamd": "1.0.1",
54
55
  "haraka-plugin-dcc": "^1.0.2",
55
- "haraka-plugin-elasticsearch": "^8.0.2",
56
+ "haraka-plugin-dkim": "^1.0.7",
57
+ "haraka-plugin-dns-list": "^1.2.1",
58
+ "haraka-plugin-elasticsearch": "^8.0.3",
59
+ "haraka-plugin-esets": "^1.0.0",
56
60
  "haraka-plugin-fcrdns": "^1.1.0",
61
+ "haraka-plugin-geoip": "^1.1.0",
57
62
  "haraka-plugin-graph": "^1.0.5",
58
- "haraka-plugin-geoip": "^1.0.17",
59
- "haraka-plugin-headers": "^1.0.3",
60
- "haraka-plugin-karma": "^2.1.2",
61
- "haraka-plugin-limit": "^1.1.1",
63
+ "haraka-plugin-greylist": "^1.0.0",
64
+ "haraka-plugin-headers": "^1.0.4",
65
+ "haraka-plugin-helo.checks": "^1.0.0",
66
+ "haraka-plugin-karma": "^2.1.5",
67
+ "haraka-plugin-known-senders": "^1.1.0",
68
+ "haraka-plugin-limit": "^1.2.5",
69
+ "haraka-plugin-messagesniffer": "^1.0.0",
62
70
  "haraka-plugin-p0f": "^1.0.9",
63
- "haraka-plugin-qmail-deliverable": "^1.2.1",
64
- "haraka-plugin-known-senders": "^1.0.9",
65
- "haraka-plugin-rcpt-ldap": "^1.1.0",
71
+ "haraka-plugin-qmail-deliverable": "^1.2.3",
66
72
  "haraka-plugin-recipient-routes": "^1.2.0",
67
73
  "haraka-plugin-rspamd": "^1.3.1",
68
- "haraka-plugin-syslog": "^1.0.5",
74
+ "haraka-plugin-spamassassin": "^1.0.0",
75
+ "haraka-plugin-spf": "1.2.7",
76
+ "haraka-plugin-syslog": "^1.0.6",
69
77
  "haraka-plugin-uribl": "^1.0.8",
70
- "haraka-plugin-watch": "^2.0.2",
78
+ "haraka-plugin-watch": "^2.0.4",
71
79
  "ocsp": "~1.2.0",
72
- "redis": "~4.6.11",
73
- "tmp": "~0.2.1"
80
+ "tmp": "~0.2.3"
74
81
  },
75
82
  "devDependencies": {
76
- "nodeunit-x": "^0.16.0",
77
- "haraka-test-fixtures": "^1.3.3",
83
+ "@haraka/eslint-config": "^1.1.5",
84
+ "haraka-test-fixtures": "^1.3.8",
85
+ "mocha": "^10.7.3",
78
86
  "mock-require": "^3.0.3",
79
- "eslint": "^8.56.0",
80
- "eslint-plugin-haraka": "^1.0.15",
81
- "nodemailer": "^6.9.9"
87
+ "nodemailer": "^6.9.15"
82
88
  },
83
89
  "bugs": {
84
90
  "mail": "haraka.mail@gmail.com",
@@ -86,13 +92,16 @@
86
92
  },
87
93
  "bin": {
88
94
  "haraka": "./bin/haraka",
89
- "dkimverify": "./bin/dkimverify",
90
95
  "haraka_grep": "./bin/haraka_grep"
91
96
  },
92
97
  "scripts": {
93
- "test": "node run_tests",
94
- "lint": "npx eslint *.js outbound plugins plugins/*/*.js tests tests/*/*.js tests/*/*/*.js bin/haraka bin/dkimverify",
95
- "lintfix": "npx eslint --fix *.js outbound plugins plugins/*/*.js tests tests/*/*.js tests/*/*/*.js bin/haraka bin/dkimverify",
96
- "versions": "npx dependency-version-checker check"
98
+ "format:NYET": "npm run prettier:fix && npm run lint:fix",
99
+ "lint": "npx eslint@^8 *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js bin/haraka",
100
+ "lint:fix": "npx eslint@^8 --fix *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js bin/haraka",
101
+ "prettier": "npx prettier . --check",
102
+ "prettier:fix": "npx prettier . --write --log-level=warn",
103
+ "test": "npx mocha --exit --timeout=4000 test test/outbound test/plugins/auth test/plugins/queue test/plugins",
104
+ "versions": "npx dependency-version-checker check",
105
+ "versions:fix": "npx dependency-version-checker update && npm run prettier:fix"
97
106
  }
98
107
  }
@@ -1,10 +1,4 @@
1
1
 
2
2
  globals:
3
3
  server: true
4
- OK: true
5
- CONT: true
6
- DENY: true
7
- DENYSOFT: true
8
- DENYDISCONNECT: true
9
- DENYSOFTDISCONNECT: true
10
4
  NEXT_HOOK: true
@@ -4,7 +4,7 @@
4
4
 
5
5
  // Note: You can disable setting `connection.notes.auth_passwd` by `plugin.blankout_password = true`
6
6
 
7
- const crypto = require('crypto');
7
+ const crypto = require('node:crypto');
8
8
 
9
9
  const tlds = require('haraka-tld')
10
10
  const utils = require('haraka-utils');
@@ -241,10 +241,12 @@ exports.auth_cram_md5 = function (next, connection, params) {
241
241
  exports.hexi = number => String(Math.abs(parseInt(number)).toString(16))
242
242
 
243
243
  exports.constrain_sender = function (next, connection, params) {
244
+ if (this?.cfg?.main?.constrain_sender === false) return next()
245
+
244
246
  const au = connection.results.get('auth')?.user
245
247
  if (!au) return next()
246
248
 
247
- const ad = /@/.test(au) ? au.split('@').pop() : au
249
+ const ad = /@/.test(au) ? au.split('@').pop() : null
248
250
  const ed = params[0].host
249
251
 
250
252
  if (!ad || !ed) return next()
@@ -1,7 +1,9 @@
1
1
  // Proxy AUTH requests selectively by domain
2
2
 
3
- const sock = require('./line_socket');
3
+ const net = require('node:net')
4
+
4
5
  const utils = require('haraka-utils');
6
+ const net_utils = require('haraka-net-utils')
5
7
 
6
8
  const smtp_regexp = /^(\d{3})([ -])(.*)/;
7
9
 
@@ -16,7 +18,6 @@ exports.load_tls_ini = function () {
16
18
  });
17
19
  }
18
20
 
19
-
20
21
  exports.hook_capabilities = (next, connection) => {
21
22
  if (connection.tls.enabled) {
22
23
  const methods = [ 'PLAIN', 'LOGIN' ];
@@ -54,7 +55,8 @@ exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
54
55
  }
55
56
 
56
57
  const self = this;
57
- const host = hosts.shift();
58
+ let [ host, port ] = hosts.shift().split(':'); /* eslint prefer-const: 0 */
59
+ if (!port) port = 25
58
60
  let methods = [];
59
61
  let auth_complete = false;
60
62
  let auth_success = false;
@@ -62,27 +64,27 @@ exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
62
64
  let response = [];
63
65
  let secure = false;
64
66
 
65
- const hostport = host.split(/:/);
66
- const socket = sock.connect(((hostport[1]) ? hostport[1] : 25), hostport[0]);
67
- connection.logdebug(self, `attempting connection to host=${hostport[0]} port=${(hostport[1]) ? hostport[1] : 25}`);
67
+ const socket = net.connect({ host, port });
68
+ net_utils.add_line_processor(socket)
69
+ connection.logdebug(this, `attempting connection to host=${host} port=${port}`);
68
70
  socket.setTimeout(30 * 1000);
69
71
  socket.on('connect', () => { });
70
72
  socket.on('close', () => {
71
73
  if (!auth_complete) {
72
74
  // Try next host
73
- return self.try_auth_proxy(connection, hosts, user, passwd, cb);
75
+ return this.try_auth_proxy(connection, hosts, user, passwd, cb);
74
76
  }
75
- connection.loginfo(self, `AUTH user="${user}" host="${host}" success=${auth_success}`);
76
- return cb(auth_success);
77
+ connection.loginfo(this, `AUTH user="${user}" host="${host}" success=${auth_success}`);
78
+ cb(auth_success);
77
79
  });
78
80
  socket.on('timeout', () => {
79
- connection.logerror(self, "connection timed out");
81
+ connection.logerror(this, "connection timed out");
80
82
  socket.end();
81
83
  // Try next host
82
- return self.try_auth_proxy(connection, hosts, user, passwd, cb);
84
+ this.try_auth_proxy(connection, hosts, user, passwd, cb);
83
85
  });
84
86
  socket.on('error', err => {
85
- connection.logerror(self, `connection failed to host ${host}: ${err}`);
87
+ connection.logerror(this, `connection failed to host ${host}: ${err}`);
86
88
  socket.end();
87
89
  });
88
90
  socket.send_command = function (cmd, data) {
@@ -1,6 +1,6 @@
1
1
  // Auth against vpopmaild
2
2
 
3
- const net = require('net');
3
+ const net = require('node:net');
4
4
 
5
5
  exports.register = function () {
6
6
  this.inherits('auth/auth_base');
@@ -3,7 +3,7 @@
3
3
  // in the mail_from.blocklist file. You need to be running the
4
4
  // mail_from.blocklist plugin for this to work fully.
5
5
 
6
- const fs = require('fs');
6
+ const fs = require('node:fs');
7
7
  const utils = require('haraka-utils');
8
8
 
9
9
  exports.hook_data = (next, connection) => {
@@ -3,9 +3,7 @@
3
3
 
4
4
  exports.hook_data = (next, connection) => {
5
5
  // enable mail body parsing
6
- if (!connection?.transaction) return next();
7
-
8
- connection.transaction.parse_body = true;
6
+ if (connection?.transaction) connection.transaction.parse_body = true;
9
7
  next();
10
8
  }
11
9
 
@@ -17,7 +15,7 @@ exports.hook_data_post = function (next, connection) {
17
15
  if (check_sigs(sigs, connection.transaction.body)) {
18
16
  return next(DENY, "Mail matches a known spam signature");
19
17
  }
20
- return next();
18
+ next();
21
19
  }
22
20
 
23
21
  function check_sigs (sigs, body) {
@@ -1,7 +1,8 @@
1
1
  // This plugin checks for clients that talk before we sent a response
2
2
 
3
+ const { isIPv6 } = require('node:net');
4
+
3
5
  const ipaddr = require('ipaddr.js');
4
- const { isIPv6 } = require('net');
5
6
 
6
7
  exports.register = function () {
7
8
  this.load_config();
@@ -1,8 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  // Check MAIL FROM domain is resolvable to an MX
4
- const dns = require('dns');
5
- const net = require('net');
4
+ const net = require('node:net');
6
5
 
7
6
  const net_utils = require('haraka-net-utils');
8
7
 
@@ -14,12 +13,17 @@ exports.load_ini = function () {
14
13
  this.cfg = this.config.get('mail_from.is_resolvable.ini', {
15
14
  booleans: [
16
15
  '-main.allow_mx_ip',
17
- '+main.reject_no_mx',
16
+ '+reject.no_mx',
18
17
  ],
19
18
  }, () => {
20
19
  this.load_ini();
21
20
  });
22
21
 
22
+ // compat. Sunset 4.0
23
+ if (this.cfg.main.reject_no_mx) {
24
+ this.cfg.reject.no_mx = this.cfg.main.reject_no_mx
25
+ }
26
+
23
27
  if (isNaN(this.cfg.main.timeout)) {
24
28
  this.cfg.main.timeout = 29;
25
29
  }
@@ -40,163 +44,89 @@ exports.hook_mail = function (next, connection, params) {
40
44
  const mail_from = params[0];
41
45
  const txn = connection?.transaction;
42
46
  if (!txn) return next();
43
- const { results } = txn;
47
+ const { results } = txn;
44
48
 
45
- // Check for MAIL FROM without an @ first - ignore those here
49
+ // ignore MAIL FROM without an @
46
50
  if (!mail_from.host) {
47
51
  results.add(plugin, {skip: 'null host'});
48
52
  return next();
49
53
  }
50
54
 
51
55
  let called_next = 0;
52
- const domain = mail_from.host;
53
- const c = plugin.cfg.main;
54
- const timeout_id = setTimeout(() => {
55
- // DNS answer didn't return (UDP)
56
- connection.loginfo(plugin, `timed out resolving MX for ${domain}`);
56
+ const domain = mail_from.host;
57
+ const timeout_id = setTimeout(() => {
58
+ connection.logdebug(plugin, `DNS timeout resolving MX for ${domain}`);
57
59
  called_next++;
58
60
  if (txn) results.add(plugin, {err: `timeout(${domain})`});
59
61
  next(DENYSOFT, 'Temporary resolver error (timeout)');
60
- }, c.timeout * 1000);
62
+ }, this.cfg.main.timeout * 1000);
61
63
 
62
64
  function mxDone (code, reply) {
63
65
  if (called_next) return;
64
66
  clearTimeout(timeout_id);
65
67
  called_next++;
66
- next(code, reply);
68
+ next(...arguments);
67
69
  }
68
70
 
69
- // IS: IPv6 compatible
70
- net_utils.get_mx(domain, (err, addresses) => {
71
- if (!txn) return;
72
- if (err && plugin.mxErr(connection, domain, 'MX', err, mxDone)) return;
71
+ function mxErr (err) {
72
+ if (!connection.transaction) return;
73
+ results.add(plugin, {err: `${domain}:${err.message}`});
74
+ mxDone(DENYSOFT, `Temp. resolver error (${err.code})`);
75
+ }
73
76
 
74
- if (!addresses || !addresses.length) {
75
- // Check for implicit MX 0 record
76
- return plugin.implicit_mx(connection, domain, mxDone);
77
- }
77
+ connection.logdebug(plugin, `resolving MX for domain ${domain}`)
78
78
 
79
- // Verify that the MX records resolve to valid addresses
80
- let records = {};
81
- let pending_queries = 0;
82
- function check_results () {
83
- if (pending_queries !== 0) return;
84
-
85
- records = Object.keys(records);
86
- if (records?.length) {
87
- connection.logdebug(plugin, `${domain}: ${records}`);
88
- results.add(plugin, {pass: 'has_fwd_dns'});
89
- return mxDone();
90
- }
91
- results.add(plugin, {fail: 'has_fwd_dns'});
92
- return mxDone(((c.reject_no_mx) ? DENY : DENYSOFT),
93
- 'MX without A/AAAA records');
94
- }
79
+ net_utils
80
+ .get_mx(domain)
81
+ .then((exchanges) => {
82
+ if (!txn) return;
95
83
 
96
- addresses.forEach(addr => {
97
- // Handle MX records that are IP addresses
98
- // This is invalid - but a lot of MTAs allow it.
99
- if (net_utils.get_ipany_re('^\\[','\\]$','').test(addr.exchange)) {
100
- connection.logwarn(plugin, `${domain}: invalid MX ${addr.exchange}`);
101
- if (c.allow_mx_ip) {
102
- records[addr.exchange] = 1;
103
- }
104
- return;
84
+ connection.logdebug(plugin, `${domain}: MX => ${JSON.stringify(exchanges)}`)
85
+
86
+ if (!exchanges || !exchanges.length) {
87
+ results.add(this, {fail: 'has_fwd_dns'});
88
+ return mxDone(
89
+ ((this.cfg.reject.no_mx) ? DENY : DENYSOFT),
90
+ 'No MX for your FROM address'
91
+ );
105
92
  }
106
- pending_queries++;
107
- net_utils.get_ips_by_host(addr.exchange, (err2, addresses2) => {
108
- pending_queries--;
109
- if (!txn) return;
110
- if (err2 && err2.length === 2) {
111
- results.add(plugin, {msg: err2[0].message});
112
- connection.logdebug(plugin, `${domain}: MX ${addr.priority} ${addr.exchange} => ${err2[0].message}`);
113
- check_results();
114
- return;
115
- }
116
- connection.logdebug(plugin, `${domain}: MX ${addr.priority} ${addr.exchange} => ${addresses2}`);
117
- for (const element of addresses2) {
118
- // Ignore anything obviously bogus
119
- if (net.isIPv4(element)){
120
- if (plugin.re_bogus_ip.test(element)) {
121
- connection.logdebug(plugin, `${addr.exchange}: discarding ${element}`);
122
- continue;
123
- }
93
+
94
+ if (this.cfg.main.allow_mx_ip) {
95
+ for (const mx of exchanges) {
96
+ if (net.isIPv4(mx.exchange) && !this.re_bogus_ip.test(mx.exchange)) {
97
+ txn.results.add(this, {pass: 'implicit_mx', emit: true});
98
+ return mxDone()
124
99
  }
125
- if (net.isIPv6(element)){
126
- if (net_utils.ipv6_bogus(element)) {
127
- connection.logdebug(plugin, `${addr.exchange}: discarding ${element}`);
128
- continue;
129
- }
100
+ if (net.isIPv6(mx.exchange) && !net_utils.ipv6_bogus(mx.exchange)) {
101
+ txn.results.add(this, {pass: 'implicit_mx', emit: true});
102
+ return mxDone()
130
103
  }
131
- records[element] = 1;
132
- }
133
- check_results();
134
- });
135
- });
136
- // In case we don't run any queries
137
- check_results();
138
- });
139
- }
140
-
141
- exports.mxErr = function (connection, domain, type, err, mxDone) {
142
-
143
- const txn = connection?.transaction;
144
- if (!txn) return;
145
-
146
- txn.results.add(this, {msg: `${domain}:${type}:${err.message}`});
147
- connection.logdebug(this, `${domain}:${type} => ${err.message}`);
148
- switch (err.code) {
149
- case dns.NXDOMAIN:
150
- case dns.NOTFOUND:
151
- case dns.NODATA:
152
- // Ignore
153
- break;
154
- default:
155
- mxDone(DENYSOFT, `Temp. resolver error (${err.code})`);
156
- return true;
157
- }
158
- return false;
159
- }
160
-
161
- // IS: IPv6 compatible
162
- exports.implicit_mx = function (connection, domain, mxDone) {
163
- const txn = connection?.transaction;
164
- if (!txn) return;
165
-
166
- net_utils.get_ips_by_host(domain, (err, addresses) => {
167
- if (!txn) return;
168
- if (!addresses || !addresses.length) {
169
- txn.results.add(this, {fail: 'has_fwd_dns'});
170
- return mxDone(((this.cfg.main.reject_no_mx) ? DENY : DENYSOFT),
171
- 'No MX for your FROM address');
172
- }
173
-
174
- connection.logdebug(this, `${domain}: A/AAAA => ${addresses}`);
175
- let records = {};
176
- for (const addr of addresses) {
177
- // Ignore anything obviously bogus
178
- if (net.isIPv4(addr)) {
179
- if (this.re_bogus_ip.test(addr)) {
180
- connection.logdebug(this, `${domain}: discarding ${addr}`);
181
- continue;
182
- }
183
- }
184
- if (net.isIPv6(addr)) {
185
- if (net_utils.ipv6_bogus(addr)) {
186
- connection.logdebug(this, `${domain}: discarding ${addr}`);
187
- continue;
188
104
  }
189
105
  }
190
- records[addr] = true;
191
- }
192
106
 
193
- records = Object.keys(records);
194
- if (records?.length) {
195
- txn.results.add(this, {pass: 'implicit_mx'});
196
- return mxDone();
197
- }
107
+ // filter out the implicit MX and resolve the MX hostnames
108
+ net_utils
109
+ .resolve_mx_hosts(exchanges.filter(a => !net.isIP(a.exchange)))
110
+ .then(resolved => {
111
+ connection.logdebug(plugin, `resolved MX => ${JSON.stringify(resolved)}`);
198
112
 
199
- txn.results.add(this, {fail: `implicit_mx(${domain})`});
200
- return mxDone();
201
- });
113
+ for (const mx of resolved) {
114
+ if (net.isIPv4(mx.exchange) && !this.re_bogus_ip.test(mx.exchange)) {
115
+ txn.results.add(this, {pass: 'has_fwd_dns', emit: true});
116
+ return mxDone()
117
+ }
118
+ if (net.isIPv6(mx.exchange) && !net_utils.ipv6_bogus(mx.exchange)) {
119
+ txn.results.add(this, {pass: 'has_fwd_dns', emit: true});
120
+ return mxDone()
121
+ }
122
+ }
123
+
124
+ mxDone(
125
+ ((this.cfg.main.reject_no_mx) ? DENY : DENYSOFT),
126
+ 'No valid MX for your FROM address'
127
+ );
128
+ })
129
+ .catch(mxErr)
130
+ })
131
+ .catch(mxErr)
202
132
  }
@@ -1,13 +1,12 @@
1
- // This plugin is now entirely redundant. The core will queue outbound mails
1
+ // This plugin is entirely redundant. The core will queue outbound mails
2
2
  // automatically just like this. It is kept here for backwards compatibility
3
3
  // purposes only.
4
4
 
5
5
  const outbound = require('./outbound');
6
6
 
7
7
  exports.hook_queue_outbound = (next, connection) => {
8
- if (!connection?.relaying) {
9
- return next(); // we're not relaying so don't deliver outbound
10
- }
8
+ // if not relaying, don't deliver outbound
9
+ if (!connection?.relaying) return next();
11
10
 
12
- outbound.send_email(connection?.transaction, next);
11
+ outbound.send_trans_email(connection?.transaction, next);
13
12
  }
@@ -19,20 +19,18 @@ exports.hook_get_mx = function (next, hmail, domain) {
19
19
 
20
20
  if (!hmail.todo.notes.using_lmtp) return next();
21
21
 
22
- const mx = { using_lmtp: true, priority: 0, exchange: '127.0.0.1' };
23
-
24
22
  const section = this.cfg[domain] || this.cfg.main;
25
- if (section.path) {
26
- Object.assign(mx, { path: section.path });
27
- return next(OK, mx);
28
- }
29
23
 
30
- Object.assign(mx, {
31
- exchange: section.host || '127.0.0.1',
32
- port: section.port || 24,
33
- });
24
+ const mx = {
25
+ using_lmtp: true,
26
+ priority: 0,
27
+ exchange: section.host ?? '127.0.0.1',
28
+ port: section.port ?? 24,
29
+ };
30
+
31
+ if (section.path) mx.path = section.path;
34
32
 
35
- return next(OK, mx);
33
+ next(OK, mx);
36
34
  }
37
35
 
38
36
  exports.hook_queue = (next, connection) => {
@@ -40,8 +38,9 @@ exports.hook_queue = (next, connection) => {
40
38
  if (!txn) return next();
41
39
 
42
40
  const q_wants = txn.notes.get('queue.wants');
41
+
43
42
  if (q_wants && q_wants !== 'lmtp') return next();
44
43
 
45
44
  txn.notes.using_lmtp = true;
46
- outbound.send_email(txn, next);
45
+ outbound.send_trans_email(txn, next);
47
46
  }
@@ -1,7 +1,7 @@
1
1
  // Queue to qmail-queue
2
2
 
3
- const childproc = require('child_process');
4
- const fs = require('fs');
3
+ const childproc = require('node:child_process');
4
+ const fs = require('node:fs');
5
5
 
6
6
  exports.register = function () {
7
7
 
@@ -1,7 +1,7 @@
1
1
  // quarantine
2
2
 
3
- const fs = require('fs');
4
- const path = require('path');
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
5
 
6
6
  exports.register = function () {
7
7