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
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.4",
13
13
  "homepage": "http://haraka.github.io",
14
14
  "repository": {
15
15
  "type": "git",
@@ -17,68 +17,76 @@
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.3",
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.1",
37
+ "haraka-utils": "^1.1.3",
38
+ "ipaddr.js": "~2.2.0",
39
+ "node-gyp": "^10.2.0",
40
+ "nopt": "^7.2.1",
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",
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",
53
52
  "haraka-plugin-auth-ldap": "^1.1.0",
53
+ "haraka-plugin-avg": "^1.1.0",
54
+ "haraka-plugin-bounce": "1.0.2",
55
+ "haraka-plugin-clamd": "1.0.1",
54
56
  "haraka-plugin-dcc": "^1.0.2",
57
+ "haraka-plugin-dkim": "^1.0.4",
58
+ "haraka-plugin-dns-list": "^1.2.0",
55
59
  "haraka-plugin-elasticsearch": "^8.0.2",
60
+ "haraka-plugin-esets": "^1.0.0",
56
61
  "haraka-plugin-fcrdns": "^1.1.0",
62
+ "haraka-plugin-geoip": "^1.1.0",
57
63
  "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",
64
+ "haraka-plugin-greylist": "^1.0.0",
65
+ "haraka-plugin-headers": "^1.0.4",
66
+ "haraka-plugin-helo.checks": "^1.0.0",
67
+ "haraka-plugin-karma": "^2.1.5",
68
+ "haraka-plugin-known-senders": "^1.1.0",
69
+ "haraka-plugin-limit": "^1.2.5",
70
+ "haraka-plugin-messagesniffer": "^1.0.0",
62
71
  "haraka-plugin-p0f": "^1.0.9",
63
- "haraka-plugin-qmail-deliverable": "^1.2.1",
64
- "haraka-plugin-known-senders": "^1.0.9",
72
+ "haraka-plugin-qmail-deliverable": "^1.2.3",
65
73
  "haraka-plugin-rcpt-ldap": "^1.1.0",
66
74
  "haraka-plugin-recipient-routes": "^1.2.0",
67
75
  "haraka-plugin-rspamd": "^1.3.1",
68
- "haraka-plugin-syslog": "^1.0.5",
76
+ "haraka-plugin-spamassassin": "^1.0.0",
77
+ "haraka-plugin-spf": "1.2.7",
78
+ "haraka-plugin-syslog": "^1.0.6",
69
79
  "haraka-plugin-uribl": "^1.0.8",
70
- "haraka-plugin-watch": "^2.0.2",
80
+ "haraka-plugin-watch": "^2.0.4",
71
81
  "ocsp": "~1.2.0",
72
- "redis": "~4.6.11",
73
- "tmp": "~0.2.1"
82
+ "tmp": "~0.2.3"
74
83
  },
75
84
  "devDependencies": {
76
- "nodeunit-x": "^0.16.0",
77
- "haraka-test-fixtures": "^1.3.3",
85
+ "@haraka/eslint-config": "^1.1.5",
86
+ "haraka-test-fixtures": "^1.3.7",
87
+ "mocha": "^10.7.3",
78
88
  "mock-require": "^3.0.3",
79
- "eslint": "^8.56.0",
80
- "eslint-plugin-haraka": "^1.0.15",
81
- "nodemailer": "^6.9.9"
89
+ "nodemailer": "^6.9.14"
82
90
  },
83
91
  "bugs": {
84
92
  "mail": "haraka.mail@gmail.com",
@@ -86,13 +94,16 @@
86
94
  },
87
95
  "bin": {
88
96
  "haraka": "./bin/haraka",
89
- "dkimverify": "./bin/dkimverify",
90
97
  "haraka_grep": "./bin/haraka_grep"
91
98
  },
92
99
  "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"
100
+ "format": "npm run prettier:fix && npm run lint:fix",
101
+ "lint": "npx eslint@^8 *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js bin/haraka",
102
+ "lint:fix": "npx eslint@^8 --fix *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js bin/haraka",
103
+ "prettier": "npx prettier . --check",
104
+ "prettier:fix": "npx prettier . --write --log-level=warn",
105
+ "test": "npx mocha --exit --timeout=4000 test test/outbound test/plugins/auth test/plugins/queue test/plugins",
106
+ "versions": "npx dependency-version-checker check",
107
+ "versions:fix": "npx dependency-version-checker update && npm run prettier:fix"
97
108
  }
98
109
  }
@@ -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,29 +19,26 @@ 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) => {
39
37
  const txn = connection?.transaction;
40
38
  if (!txn) return next();
41
39
 
42
- const q_wants = txn.notes.get('queue.wants');
43
- if (q_wants && q_wants !== 'lmtp') return next();
40
+ if (txn.notes.get('queue.wants') !== 'lmtp') return next();
44
41
 
45
42
  txn.notes.using_lmtp = true;
46
- outbound.send_email(txn, next);
43
+ outbound.send_trans_email(txn, next);
47
44
  }
@@ -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