; karma.ini,  see 'haraka -h karma'

; Redis: karma's high speed key/value store for concurrency, IP history,
;        and AS history
[redis]
 host   = 172.200.0.102
 port   = 6379
 db     = 1

; karma IP history is expired after this many days. This value is refreshed
;       at every connection. Frequent senders may never expire.
expire_days = 60


[asn]
; track karma for AS? (network neighborhood)
enable=true
;report_as=asn


[tarpit]
delay=0

; If you make the remote wait too long, they drop the connection.
; 'max' limits how long to make remotes wait between responses.
max=4

; max_msa: applied for connections to port 587 and 465, when Haraka is acting
; as a Message Submission Agent for roaming users.
; max_msa=1
max_msa=1

[thresholds]
; negative: the threshold below which a connection is denied/rejected
;           Be conservative to avoid false positives!
negative=-8

; score above which connections are considered 'good'
positive=2

; karma history = good - bad connections. A negative score means a sender has
; sent more bad than good messages. IPs are not subject to the penalty box
; until they have made > 5 connections and achieved a score lower than this.
history_negative=-3


[deny]
; hooks to disconnect on. When the score is below [threshholds]negative,
;     deny the connection on these hooks:
;hooks=connect,unrecognized_command,helo,ehlo,mail,rcpt,data,data_post
hooks=unrecognized_command,data,data_post,queue

;message=very bad karma score: {score}
;message=https://example.com/logs/{uuid}

[deny_excludes]
; 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

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


[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
biz=-2
pw=-2
me=-1
us=-5
eu=-4
link=-3
science=-6
top=-4
ru=-2
club=-3
stream=-3
bid=-3
trade=-3


[tls]
; awards based on whether the sender opportunistically encrypted
; spammy senders usually do not. Plenty (~1/4) of ham senders don't either
; use with caution.
set=0
unset=0

;                          CONNECTION / NOTE AWARDS
;
; NOTICE: Generic awards are mostly deprecated in favor of [asn_awards] and
; [result_awards].  These still exist because there are connection properties
; that can't yet be scored any other way.
;
; karma can award points by inspecting connection objects and notes
; saved by other plugins.
;
; syntax: lo.ca.tion = N [if condition VAL]
;
; location: an object or attribute in the connection or transaction object.
;           Use the transaction prefix to check only the transaction note.
; N:      a numeric karma score to award: + to praise, - to smite
; VAL:    the value to use in the conditional match
;
; conditions:
;     if match          // performs a case insensitive regex match on VAL
;     if equals         // performs an === comparison
;     if gt             // performs a greater-than comparison
;     if lt             // performs a less-than comparison
;     if length (gt|lt) // matches against array length
;     if in             // matches in arrays

[awards]
relaying                         =  6
early_talker                     = -3


;                            ASN AWARDS
; Award karma points to specific ASNs. This is much shorter than writing
; result_awards and I score many ASNs. I score an ASN by analyzing the
; past 30 days of traffic. An ASN that sends mostly spam would get an
; award sufficient to "tip the scales" of any indetermine message
; towards spam and vise versa for hammy senders.

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


;                           RESULT AWARDS
; karma subscribes to each connections result store. Any plugin that saves
; results can thus have those results scored by karma.
;
; Example:
; in a plugin named 'example-pi', a result is saved:
;     connection.results.add(plugin, { pass: 'someval' });
;
; in karma.ini, these rules match and assign +1 karma point each:
;    000       = example-pi  | pass     | eq       | someval | 1
;    001       = example-pi  | pass     | match    |  omeva  | 1
;
; result awards have the folowing syntax:
;    unique ID = plugin name | property | operator | value | award | reason | remedy
;
; operators: equal, match, gt, and lt.
; award: any integer (negative values smite, positive values praise)
; reason: an optional human readable reason for the award

[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

003 = karma         | fail     | equals | env_user_match | -2 | Envelope sender doesn't match message sender

004 = karma         | history  | lt     | -1           | -1  | IP reputation is poor
005 = karma         | history  | lt     | -3           | -1  | IP reputation is very poor
006 = karma         | pass     | equals | all_good     |  2  | IP reputation is good
007 = karma         | fail     | equals | all_bad      | -2  | IP reputation is spam-only

; based on ASN history
008 = karma         | pass     | equals | asn          |  1  | ASN reputation is good
009 = karma         | fail     | equals | asn          | -1  | ASN reputation is bad
010 = karma         | pass     | equals | asn_all_good |  2  | ASN reputation is very good
011 = karma         | fail     | equals | asn_all_bad  | -2  | ASN reputation is very bad

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

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

;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

; give back the point penalized for running windows
080 = fcrdns | fcrdns  | match  | outlook.com | 1
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
087 = fcrdns | ip_in_rdns   | equals | true  |  -1  | FCrDNS has IP in rDNS   | Configure proper hostnames for your MTA
088 = fcrdns | generic_rdns | equals | true  |  -1  | FCrDNS host is generic
; well known senders
089 = fcrdns | fcrdns  | match  |  google.com |  2  | FCrDNS Well Known Sender
090 = fcrdns | fcrdns  | match  | twitter.com |  2  | FCrDNS Well Known Sender

100 = access    | whitelist     | equals | true |  9  | Policy Whitelist
101 = access    | blacklist     | equals | true | -7  | Policy Blacklist | Unsubscribe the user, stop spamming them.
102 = access    | pass | equals | connect.rdns_access.whitelist | 8
103 = access    | pass | equals | mail_from.access.whitelist    | 8
104 = access    | pass | equals | rcpt_to.access.whitelist    | 8

; Scores for specific DNSBLs
111 = dnsbl       | fail | equals | b.barracudacentral.org  | -7 | DNS Blacklist | Disinfect your host/network
112 = dnsbl       | fail | equals | truncate.gbudb.net      | -5 | DNS Blacklist | Disinfect your host/network
113 = dnsbl       | fail | equals | psbl.surriel.com        | -6 | DNS Blacklist | Disinfect your host/network
114 = dnsbl       | fail | equals | bl.spamcop.net          | -3 | DNS Blacklist | Disinfect your host/network
115 = dnsbl       | fail | equals | dnsbl-1.uceprotect.net  | -3 | DNS Blacklist | Disinfect your host/network
116 = dnsbl       | fail | equals | zen.spamhaus.org        | -5 | DNS Blacklist | Disinfect your host/network
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

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
132 = helo.checks | skip | match | forward_dns    | -1  | HELO host skipped
133 = helo.checks | fail | match | forward_dns    | -1  | HELO host fails forward DNS | Use valid HELO hostname
134 = helo.checks | fail | match | dynamic        | -1  | HELO host has dynamic name
135 = helo.checks | fail | match | reverse_dns    | -1  | HELO host missing rDNS

; SPF survey in March 2014: over 95% of ham has SPF Pass
;                           over 60% of spam has SPF Pass
; None, Pass, Fail, SoftFail, Neutral, TempError, PermError
150 = spf         | result | equals | Fail      | -4  | SPF fail | Update SPF record
151 = spf         | result | equals | SoftFail  | -3  | SPF soft fail | Maintain DNS properly
152 = spf         | result | equals | Neutral   | -1  | SPF neutral  | Set up SPF records
153 = spf         | result | equals | TempError | -2
154 = spf         | result | equals | PermError | -2

160 = auth                | fail    | match  | auth      | -4  | Authentication failure
161 = auth/auth_base      | fail    | match  | auth      | -4  | Authentication failure
162 = auth                | pass    | match  | auth      |  9  | Authentication success
; 163 = auth/auth_vpopmaild | success | equals | false   | -4  | Authentication failure

168 = mail_from.is_resolvable   | fail   | length | gt 0        | -8  | Mail From host DNS failure
169 = mail_from.is_resolvable   | pass   | equals | implicit_mx | -4  | Envelope From host has no MX

170 = rcpt_to.qmail_deliverable | fail   |    gt  |    0 | -1 | Invalid envelope recipient
;171 = rcpt_to.qmail_deliverable | pass   |    gt  |    0 |  1 | Valid Envelope recipient
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

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

210 = clamd        | fail       | match  | executable   | -4 | Clam AntiVirus Executable
211 = clamd        | fail       | match  | structured   | -2 | Clam AntiVirus Structured
212 = clamd        | fail       | match  | encrypted    | -4 | Clam AntiVirus Encrypted Archive
213 = clamd        | fail       | match  | pua          | -4 | Clam AntiVirus Potentially Unwanted Application
214 = clamd        | fail       | match  | ole2         | -5 | Clam AntiVirus OLE2
215 = clamd        | fail       | match  | safebrows    | -4 | Clam AntiVirus SafeBrowsing
216 = clamd        | fail       | match  | unofficial   | -4 | Clam AntiVirus UNOFFICIAL
217 = clamd        | fail       | match  | phish        | -3 | Clam AntiVirus Phishing
218 = clamd        | fail       | match  | spam         | -2 | Clam AntiVirus Spam
;219 = clamd        | pass       | equals | clean       |  1 | Clam AntiVirus Executable

230 = rspamd       | is_spam    | equals | true         | -2 | rspamd detected as spam
231 = rspamd       | action     | equals | greylist     | -1 | rspamd suggested greylist
232 = rspamd       | score      | lt     | 0            |  1 | rspamd positive score
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

251 = spamassassin | hits       | lt     |  0           |   1 |
252 = spamassassin | hits       | lt     | -2           |   1 |
253 = spamassassin | hits       | lt     | -5           |   1 |
254 = spamassassin | hits       | lt     | -10          |   2 |
255 = spamassassin | hits       | lt     | -20          |   5 |
256 = spamassassin | hits       | gt     |   1          |  -1 |
257 = spamassassin | hits       | gt     |   2          |  -1 |
259 = spamassassin | hits       | gt     |   3          |  -2 |
260 = spamassassin | flag       | equals | Yes          |  -5 | SpamAssassin detected as spam
;261 = spamassassin | hits       | gt     |   6          |  -2 |
;263 = spamassassin | hits       | gt     |   8          |  -2 |
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

