Skip to content

Commit

Permalink
Release v2.1.2 (#55)
Browse files Browse the repository at this point in the history
- config: update several plugin names
- style(es6): refer to plugin as 'this'
- ci: test on node 18 & 20, drop 14,16
  • Loading branch information
msimerson authored Dec 12, 2023
1 parent 4818667 commit 9209e65
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 76 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest ]
node-version: [ 14, 16, 18 ]
node-version: [ 18, 20 ]
fail-fast: false
steps:
- uses: actions/checkout@v3
Expand All @@ -38,7 +38,7 @@ jobs:
strategy:
matrix:
os: [ windows-latest ]
node-version: [ 14, 16, 18 ]
node-version: [ 18, 20 ]
fail-fast: false
steps:
- uses: actions/checkout@v3
Expand Down
7 changes: 7 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
#### N.N.N - YYYY-MM-DD


### [2.1.2] - 2023-12-11

- config: update several plugin names
- style(es6): refer to plugin as 'this'


### [2.1.1] - 2023-08-22

- fix: check_result unexpected return #50
Expand Down Expand Up @@ -111,3 +117,4 @@
- use redis.merge_redis_ini()
[2.1.0]: https://github.com/haraka/haraka-plugin-karma/releases/tag/2.1.0
[2.1.1]: https://github.com/haraka/haraka-plugin-karma/releases/tag/2.1.1
[2.1.2]: https://github.com/haraka/haraka-plugin-karma/releases/tag/2.1.2
120 changes: 77 additions & 43 deletions config/karma.ini
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ enable=true


[tarpit]
delay=0
delay=1

; If you make the remote wait too long, they drop the connection.
; 'max' limits how long to make remotes wait between responses.
Expand Down Expand Up @@ -57,32 +57,49 @@ hooks=unrecognized_command,data,data_post,queue,queue_outbound
; karma captures and scores deny requests from other plugins, permitting finer
; control over connection handling. For plugins that should be able to reject
; the connection, add their name to the plugin list:
plugins=send_email, tls, access, helo.checks, data.headers, rspamd, spamassassin, avg, clamd, attachment
plugins=send_email, tls, access, helo.checks, data.headers, rspamd, spamassassin, clamd, attachment, limit

; hooks whose DENY rejections should be not be captured.
hooks=rcpt, queue
hooks=rcpt, queue, queue_outbound


[spammy_tlds]
; award negative karma to spammy TLDs
; caution, awarding karma > msg_negative_limit may blacklist that TLD
work=-4
rocks=-3
ninja=-3
info=-2
bid=-3
biz=-2
pw=-2
me=-1
us=-5
bet=-4
bio=-4
buzz=-3
club=-3
company=-4
directory=-4
eu=-4
fun=-5
guru=-4
gury=-3
icu=-6
info=-4
link=-3
science=-6
top=-4
me=-1
monster=-5
mom=-5
na=-6
ninja=-3
one=-4
pics=-5
pw=-2
rocks=-3
ru=-2
club=-3
sbs=-4
science=-6
stream=-3
bid=-3
studio=-5
top=-5
trade=-3
us=-4
work=-4
xyz=-6


[tls]
Expand Down Expand Up @@ -129,11 +146,11 @@ early_talker = -3
; towards spam and vise versa for hammy senders.

[asn_awards]
;55286 = -6
;33182 = -4
;46717 = -4
;13332 = -4
;200002 = -4
55286 = -6
33182 = -4
46717 = -4
13332 = -4
200002 = -4


; RESULT AWARDS
Expand All @@ -157,6 +174,7 @@ early_talker = -3

[result_awards]
;geoip.too_far = -1

001 = geoip | distance | gt | 4000 | -1 | Geographic distance is unusual for ham
002 = geoip | distance | gt | 8000 | -1 | Geographic distance is unusual for ham

Expand All @@ -176,17 +194,23 @@ early_talker = -3
012 = karma | fail | equals | rfc5321.MailFrom | -1 | RFC Ignorant MTA | Use a RFC compliant MTA
013 = karma | fail | equals | rfc5321.RcptTo | -1 | RFC Ignorant MTA | Use a RFC compliant MTA
016 = geoip | country | equals | RU | -3 | Sender from Russia
020 = asn | pass | equals | karma | 1 | ASN reputation is good
021 = asn | fail | equals | karma | -1 | ASN reputation is bad
022 = asn | pass | equals | asn_all_good | 2 | ASN reputation is ham-only
023 = asn | fail | equals | asn_all_bad | -2 | ASN reputation is spam-only
024 = asn | org | match | eonix | -4 | Spammy Hoster
;030 = connect.p0f | os_name | match | freebsd | 1 | FreeBSD
031 = connect.p0f | os_name | match | windows | -1 | Windows OS, likely infected by malware | Don't use Windows as MTA
032 = connect.p0f | os_flavor | equals | XP | -2 | Windows XP, likely infected by malware | Upgrade to a supported OS
;030 = p0f | os_name | match | freebsd | 1 | FreeBSD
031 = p0f | os_name | match | windows | -1 | Windows OS, likely infected by malware | Don't use Windows as MTA
032 = p0f | os_flavor | equals | XP | -2 | Windows XP, likely infected by malware | Upgrade to a supported OS

; give back the point penalized for running windows
080 = fcrdns | fcrdns | match | outlook.com | 1
; 080 = fcrdns | fcrdns | match | outlook.com | 1
; 081 = fcrdns | fcrdns@1 = 1 if length gt 0
; 082 = fcrdns | err@1 = -1 if length gt 0
; 083 = fcrdns | fail@1 = -1 if length gt 0
084 = fcrdns | fail | match | ptr_valid | -4 | FCrDNS has no valid PTR | Set up https://en.wikipedia.org/wiki/Forward-confirmed_reverse_DNS
085 = fcrdns | fail | match | valid_tld | -6 | FCrDNS has no valid TLD | Set up https://en.wikipedia.org/wiki/Forward-confirmed_reverse_DNS
086 = fcrdns | fail | equals | has_rdns | -6 | FCrDNS has no rDNS | Set up https://en.wikipedia.org/wiki/Forward-confirmed_reverse_DNS
Expand All @@ -212,6 +236,7 @@ early_talker = -3
117 = dnsbl | fail | equals | xbl.spamhaus.org | -6 | DNS Blacklist | Disinfect your host/network
118 = dnsbl | fail | equals | cbl.abuseat.org | -5 | DNS Blacklist | Disinfect your host/network
119 = dnsbl | fail | equals | dnsbl.justspam.org | -1 | DNS Blacklist | Disinfect your host/network
120 = dnsbl | fail | equals | dnsbl.sorbs.net | -2 | DNS Blacklist | Clean up DNSBL listing

130 = helo.checks | fail | match | valid_hostname | -1 | HELO host invalid | Use valid HELO hostname
131 = helo.checks | pass | match | forward_dns | 1 | HELO host has forward DNS
Expand Down Expand Up @@ -242,28 +267,30 @@ early_talker = -3
172 = rcpt_to.in_host_list | fail | gt | 0 | -1 | Invalid envelope recipient
;173 = rcpt_to.in_host_list | pass | gt | 0 | 1 | Valid Envelope recipient

181 = data.headers | fail | match | from_match | -1 | Envelope From does not match Message From:
182 = data.headers | pass | match | from_match | 1 | Envelope From matches Message From:
183 = data.headers | fail | equals | UA | -1 | Uncommon MUA
184 = data.headers | fail | match | direct-to-mx | -1 | Not relayed
185 = data.headers | fail | match | missing | -1 | Missing a required header

190 = data.uribl | fail | equals | fresh15.spameatingmonkey.net | -2 | URI blacklist: fresh15.spameatingmonkey.net
191 = data.uribl | fail | equals | dbl.spamhaus.org | -2 | URI blacklist: dbl.spamhaus.org
192 = data.uribl | fail | equals | multi.uribl.com | -2 | URI blacklist: multi.uribl.com
193 = data.uribl | fail | equals | multi.surbl.org | -2 | URI blacklist: multi.surbl.org
194 = data.uribl | fail | match | rdns | -2 | URI Blacklist | Don't send spam
195 = data.uribl | fail | match | helo | -2 | URI Blacklist | Don't send spam
196 = data.uribl | fail | match | ehlo | -2 | URI Blacklist | Don't send spam
197 = data.uribl | fail | match | envfrom | -2 | URI Blacklist | Don't send spam
198 = data.uribl | fail | match | from | -2 | URI Blacklist | Don't send spam
199 = data.uribl | fail | match | replyto | -2 | URI Blacklist | Don't send spam
200 = data.uribl | fail | match | body | -2 | URI Blacklist | Don't send spam
201 = data.uribl | fail | match | msgid | -2 | URI Blacklist | Don't send spam
181 = headers | fail | match | from_match | -1 | Envelope From does not match Message From:
182 = headers | pass | match | from_match | 1 | Envelope From matches Message From:
183 = headers | fail | equals | UA | -1 | Uncommon MUA
184 = headers | fail | match | direct-to-mx | -1 | Not relayed
185 = headers | fail | match | missing | -1 | Missing a required header
186 = headers | fail | match | from_phish | -6 | Phish attempt

190 = uribl | fail | equals | fresh15.spameatingmonkey.net | -2 | URI blacklist: fresh15.spameatingmonkey.net
191 = uribl | fail | equals | dbl.spamhaus.org | -2 | URI blacklist: dbl.spamhaus.org
192 = uribl | fail | equals | multi.uribl.com | -2 | URI blacklist: multi.uribl.com
193 = uribl | fail | equals | multi.surbl.org | -2 | URI blacklist: multi.surbl.org
194 = uribl | fail | match | rdns | -2 | URI Blacklist | Don't send spam
195 = uribl | fail | match | helo | -2 | URI Blacklist | Don't send spam
196 = uribl | fail | match | ehlo | -2 | URI Blacklist | Don't send spam
197 = uribl | fail | match | envfrom | -2 | URI Blacklist | Don't send spam
198 = uribl | fail | match | from | -2 | URI Blacklist | Don't send spam
199 = uribl | fail | match | replyto | -2 | URI Blacklist | Don't send spam
200 = uribl | fail | match | body | -2 | URI Blacklist | Don't send spam
201 = uribl | fail | match | msgid | -2 | URI Blacklist | Don't send spam

205 = bounce | fail | equals | single_recipient | -8 | Invalid bounce
206 = bounce | fail | equals | empty_return_path | -8 | Invalid bounce
207 = bounce | fail | equals | bad_rcpt | -8 | Invalid bounce
208 = bounce | isa | equals | yes | -2 | Bounces are bad

210 = clamd | fail | match | executable | -4 | Clam AntiVirus Executable
211 = clamd | fail | match | structured | -2 | Clam AntiVirus Structured
Expand All @@ -282,6 +309,12 @@ early_talker = -3
233 = rspamd | score | gt | 6 | -1 | rspamd moderate score
234 = rspamd | score | gt | 10 | -1 | rspamd high score
235 = rspamd | is_spam | equals | false | 1 | rspamd detected as ham
236 = rspamd | action | match | reject | -2 | rspamd suggested reject

237 = rspamd | symbols | match | DMARC_POLICY_ALLOW | 1 | DMARC policy allow
238 = rspamd | symbols | match | DMARC_POLICY_REJECT | -6 | DMARC policy reject
239 = rspamd | symbols | match | DMARC_POLICY_QUARANTINE | -4 | DMARC policy reject
240 = rspamd | symbols | match | DMARC_POLICY_SOFTFAIL | -2 | DMARC policy softfail

251 = spamassassin | hits | lt | 0 | 1 |
252 = spamassassin | hits | lt | -2 | 1 |
Expand All @@ -297,5 +330,6 @@ early_talker = -3
264 = spamassassin | hits | gt | 9 | -2 |
265 = spamassassin | hits | gt | 20 | -10 |

280 = known-senders | pass | length | gt 0 | 5 | Known Sender
281 = limit | fail | length | gt 0 | -3 | Exceeding rate limits
280 = known-senders | pass | equals | wks | 5 | Known Sender
281 = known-senders | pass | length | gt 0 | 5 | Known Sender
282 = limit | fail | length | gt 0 | -5 | Exceeding rate limits
55 changes: 28 additions & 27 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,12 @@ exports.hook_queue = function (next, connection) {
this.should_we_deny(next, connection, 'queue')
}

exports.hook_queue_outbound = function (next, connection) {
if (this.should_we_skip(connection)) return next()

this.should_we_deny(next, connection, 'queue_outbound')
}

exports.hook_reset_transaction = function (next, connection) {
if (this.should_we_skip(connection)) return next()

Expand All @@ -544,15 +550,15 @@ exports.hook_unrecognized_command = function (next, connection, params) {
exports.ip_history_from_redis = function (next, connection) {
const plugin = this

if (plugin.should_we_skip(connection)) return next()
if (this.should_we_skip(connection)) return next()

const expire = (plugin.cfg.redis.expire_days || 60) * 86400 // to days
const expire = (this.cfg.redis.expire_days || 60) * 86400 // to days
const dbkey = `karma|${connection.remote.ip}`

// redis plugin is emitting errors, no need to here
if (!plugin.db) return next()
if (!this.db) return next()

plugin.db.hGetAll(dbkey).then(dbr => {
this.db.hGetAll(dbkey).then(dbr => {
if (dbr === null) {
plugin.init_ip(dbkey, connection.remote.ip, expire)
return next()
Expand Down Expand Up @@ -591,7 +597,6 @@ exports.ip_history_from_redis = function (next, connection) {
connection.results.add(plugin, { err })
next()
})

}

exports.hook_mail = function (next, connection, params) {
Expand Down Expand Up @@ -672,42 +677,39 @@ exports.hook_data_post = function (next, connection) {
}

exports.increment = function (connection, key, val) {
const plugin = this
if (!plugin.db) return
if (!this.db) return

plugin.db.hIncrBy(`karma|${connection.remote.ip}`, key, 1)
this.db.hIncrBy(`karma|${connection.remote.ip}`, key, 1)

const asnkey = plugin.get_asn_key(connection)
if (asnkey) plugin.db.hIncrBy(asnkey, key, 1)
const asnkey = this.get_asn_key(connection)
if (asnkey) this.db.hIncrBy(asnkey, key, 1)
}

exports.hook_disconnect = function (next, connection) {
const plugin = this

if (plugin.should_we_skip(connection)) return next()
if (this.should_we_skip(connection)) return next()

plugin.redis_unsubscribe(connection)
this.redis_unsubscribe(connection)

const k = connection.results.get('karma')
if (!k || k.score === undefined) {
connection.results.add(plugin, {err: 'karma results missing'})
connection.results.add(this, {err: 'karma results missing'})
return next()
}

if (!plugin.cfg.thresholds) {
plugin.check_awards(connection)
connection.results.add(plugin, {msg: 'no action', emit: true })
if (!this.cfg.thresholds) {
this.check_awards(connection)
connection.results.add(this, {msg: 'no action', emit: true })
return next()
}

if (k.score > (plugin.cfg.thresholds.positive || 3)) {
plugin.increment(connection, 'good', 1)
if (k.score > (this.cfg.thresholds.positive || 3)) {
this.increment(connection, 'good', 1)
}
if (k.score < 0) {
plugin.increment(connection, 'bad', 1)
this.increment(connection, 'bad', 1)
}

connection.results.add(plugin, {emit: true })
connection.results.add(this, {emit: true })
next()
}

Expand Down Expand Up @@ -739,11 +741,11 @@ exports.get_award_loc_from_results = function (connection, loc_bits) {
let obj
if (connection.transaction) obj = connection.transaction.results.get(pi_name)

// connection.logdebug(plugin, `no txn results: ${pi_name}`);
// connection.logdebug(this, `no txn results: ${pi_name}`);
if (!obj) obj = connection.results.get(pi_name)
if (!obj) return

// connection.logdebug(plugin, `found results for ${pi_name}, ${notekey}`);
// connection.logdebug(this, `found results for ${pi_name}, ${notekey}`);
if (notekey) return obj[notekey]
return obj
}
Expand Down Expand Up @@ -997,9 +999,8 @@ exports.get_asn_key = function (connection) {
}

exports.init_asn = function (asnkey, expire) {
const plugin = this
if (!plugin.db) return
plugin.db.multi()
if (!this.db) return
this.db.multi()
.hmSet(asnkey, {'bad': 0, 'good': 0, 'connections': 1})
.expire(asnkey, expire * 2) // keep ASN longer
.exec()
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "haraka-plugin-karma",
"version": "2.1.1",
"version": "2.1.2",
"description": "A heuristics scoring and reputation engine for SMTP connections",
"main": "index.js",
"scripts": {
Expand All @@ -27,12 +27,12 @@
"haraka-constants": ">=1.0.2",
"haraka-utils": "*",
"haraka-plugin-redis": "2.0.5",
"redis": "4.6.7"
"redis": "4.6.11"
},
"devDependencies": {
"eslint": "8",
"eslint": "8.55.0",
"eslint-plugin-haraka": "*",
"haraka-test-fixtures": "*",
"mocha": "9"
"mocha": "10.2.0"
}
}

0 comments on commit 9209e65

Please sign in to comment.