238 lines
9.3 KiB
Text
238 lines
9.3 KiB
Text
$OpenBSD$
|
|
|
|
Index: spoofcheck.py
|
|
--- spoofcheck.py.orig
|
|
+++ spoofcheck.py
|
|
@@ -1,4 +1,4 @@
|
|
-#! /usr/bin/env python
|
|
+#! /usr/bin/env python3
|
|
|
|
import sys
|
|
|
|
@@ -18,11 +18,9 @@ logging.basicConfig(level=logging.INFO)
|
|
def check_spf_redirect_mechanisms(spf_record):
|
|
redirect_domain = spf_record.get_redirect_domain()
|
|
|
|
- if redirect_domain is not None:
|
|
- output_info("Processing an SPF redirect domain: %s" % redirect_domain)
|
|
-
|
|
+ if redirect_domain:
|
|
+ output_info(f"Processing an SPF redirect domain: {redirect_domain}")
|
|
return is_spf_record_strong(redirect_domain)
|
|
-
|
|
else:
|
|
return False
|
|
|
|
@@ -31,8 +29,7 @@ def check_spf_include_mechanisms(spf_record):
|
|
include_domain_list = spf_record.get_include_domains()
|
|
|
|
for include_domain in include_domain_list:
|
|
- output_info("Processing an SPF include domain: %s" % include_domain)
|
|
-
|
|
+ output_info(f"Processing an SPF include domain: {include_domain}")
|
|
strong_all_string = is_spf_record_strong(include_domain)
|
|
|
|
if strong_all_string:
|
|
@@ -42,8 +39,9 @@ def check_spf_include_mechanisms(spf_record):
|
|
|
|
|
|
def is_spf_redirect_record_strong(spf_record):
|
|
- output_info("Checking SPF redirect domian: %(domain)s" % {"domain": spf_record.get_redirect_domain})
|
|
+ output_info(f"Checking SPF redirect domain: {spf_record.get_redirect_domain}")
|
|
redirect_strong = spf_record._is_redirect_mechanism_strong()
|
|
+
|
|
if redirect_strong:
|
|
output_bad("Redirect mechanism is strong.")
|
|
else:
|
|
@@ -55,6 +53,7 @@ def is_spf_redirect_record_strong(spf_record):
|
|
def are_spf_include_mechanisms_strong(spf_record):
|
|
output_info("Checking SPF include mechanisms")
|
|
include_strong = spf_record._are_include_mechanisms_strong()
|
|
+
|
|
if include_strong:
|
|
output_bad("Include mechanisms include a strong record")
|
|
else:
|
|
@@ -65,7 +64,8 @@ def are_spf_include_mechanisms_strong(spf_record):
|
|
|
|
def check_spf_include_redirect(spf_record):
|
|
other_records_strong = False
|
|
- if spf_record.get_redirect_domain() is not None:
|
|
+
|
|
+ if spf_record.get_redirect_domain():
|
|
other_records_strong = is_spf_redirect_record_strong(spf_record)
|
|
|
|
if not other_records_strong:
|
|
@@ -76,12 +76,15 @@ def check_spf_include_redirect(spf_record):
|
|
|
|
def check_spf_all_string(spf_record):
|
|
strong_spf_all_string = True
|
|
- if spf_record.all_string is not None:
|
|
+
|
|
+ if spf_record.all_string:
|
|
+
|
|
if spf_record.all_string == "~all" or spf_record.all_string == "-all":
|
|
- output_indifferent("SPF record contains an All item: " + spf_record.all_string)
|
|
+ output_indifferent(f"SPF record contains an All item: {spf_record.all_string}")
|
|
else:
|
|
- output_good("SPF record All item is too weak: " + spf_record.all_string)
|
|
+ output_good(f"SPF record All item is too weak: {spf_record.all_string}")
|
|
strong_spf_all_string = False
|
|
+
|
|
else:
|
|
output_good("SPF record has no All string")
|
|
strong_spf_all_string = False
|
|
@@ -94,26 +97,24 @@ def check_spf_all_string(spf_record):
|
|
|
|
def is_spf_record_strong(domain):
|
|
strong_spf_record = True
|
|
+
|
|
spf_record = spflib.SpfRecord.from_domain(domain)
|
|
- if spf_record is not None and spf_record.record is not None:
|
|
+ if spf_record and spf_record.record:
|
|
output_info("Found SPF record:")
|
|
output_info(str(spf_record.record))
|
|
|
|
strong_all_string = check_spf_all_string(spf_record)
|
|
- if strong_all_string is False:
|
|
+ if not strong_all_string:
|
|
|
|
redirect_strength = check_spf_redirect_mechanisms(spf_record)
|
|
include_strength = check_spf_include_mechanisms(spf_record)
|
|
|
|
strong_spf_record = False
|
|
|
|
- if redirect_strength is True:
|
|
+ if redirect_strength or include_strength:
|
|
strong_spf_record = True
|
|
-
|
|
- if include_strength is True:
|
|
- strong_spf_record = True
|
|
else:
|
|
- output_good(domain + " has no SPF record!")
|
|
+ output_good(f"{domain} has no SPF record!")
|
|
strong_spf_record = False
|
|
|
|
return strong_spf_record
|
|
@@ -121,7 +122,7 @@ def is_spf_record_strong(domain):
|
|
|
|
def get_dmarc_record(domain):
|
|
dmarc = dmarclib.DmarcRecord.from_domain(domain)
|
|
- if dmarc is not None and dmarc.record is not None:
|
|
+ if dmarc and dmarc.record:
|
|
output_info("Found DMARC record:")
|
|
output_info(str(dmarc.record))
|
|
return dmarc
|
|
@@ -129,31 +130,32 @@ def get_dmarc_record(domain):
|
|
|
|
def get_dmarc_org_record(base_record):
|
|
org_record = base_record.get_org_record()
|
|
- if org_record is not None:
|
|
+ if org_record:
|
|
output_info("Found DMARC Organizational record:")
|
|
output_info(str(org_record.record))
|
|
return org_record
|
|
|
|
|
|
def check_dmarc_extras(dmarc_record):
|
|
- if dmarc_record.pct is not None and dmarc_record.pct != str(100):
|
|
- output_indifferent("DMARC pct is set to " + dmarc_record.pct + "% - might be possible")
|
|
+ if dmarc_record.pct and dmarc_record.pct != str(100):
|
|
+ output_indifferent(f"DMARC pct is set to {dmarc_record.pct}% - might be possible")
|
|
|
|
- if dmarc_record.rua is not None:
|
|
- output_indifferent("Aggregate reports will be sent: " + dmarc_record.rua)
|
|
+ if dmarc_record.rua:
|
|
+ output_indifferent(f"Aggregate reports will be sent: {dmarc_record.rua}")
|
|
|
|
- if dmarc_record.ruf is not None:
|
|
- output_indifferent("Forensics reports will be sent: " + dmarc_record.ruf)
|
|
+ if dmarc_record.ruf:
|
|
+ output_indifferent(f"Forensics reports will be sent: {dmarc_record.ruf}")
|
|
|
|
|
|
def check_dmarc_policy(dmarc_record):
|
|
policy_strength = False
|
|
- if dmarc_record.policy is not None:
|
|
+
|
|
+ if dmarc_record.policy:
|
|
if dmarc_record.policy == "reject" or dmarc_record.policy == "quarantine":
|
|
policy_strength = True
|
|
- output_bad("DMARC policy set to " + dmarc_record.policy)
|
|
+ output_bad(f"DMARC policy set to {dmarc_record.policy}")
|
|
else:
|
|
- output_good("DMARC policy set to " + dmarc_record.policy)
|
|
+ output_good(f"DMARC policy set to {dmarc_record.policy}")
|
|
else:
|
|
output_good("DMARC record has no Policy")
|
|
|
|
@@ -165,18 +167,18 @@ def check_dmarc_org_policy(base_record):
|
|
|
|
try:
|
|
org_record = base_record.get_org_record()
|
|
- if org_record is not None and org_record.record is not None:
|
|
+ if org_record and org_record.record:
|
|
output_info("Found organizational DMARC record:")
|
|
output_info(str(org_record.record))
|
|
|
|
- if org_record.subdomain_policy is not None:
|
|
+ if org_record.subdomain_policy:
|
|
if org_record.subdomain_policy == "none":
|
|
- output_good("Organizational subdomain policy set to %(sp)s" % {"sp": org_record.subdomain_policy})
|
|
+ output_good(f"Organizational subdomain policy set to {org_record.subdomain_policy}")
|
|
elif org_record.subdomain_policy == "quarantine" or org_record.subdomain_policy == "reject":
|
|
- output_bad("Organizational subdomain policy explicitly set to %(sp)s" % {"sp": org_record.subdomain_policy})
|
|
+ output_bad(f"Organizational subdomain policy explicitly set to {org_record.subdomain_policy}")
|
|
policy_strong = True
|
|
else:
|
|
- output_info("No explicit organizational subdomain policy. Defaulting to organizational policy")
|
|
+ output_info("No explicit organizational subdomain policy. Defaulting to organizational policy.")
|
|
policy_strong = check_dmarc_policy(org_record)
|
|
else:
|
|
output_good("No organizational DMARC record")
|
|
@@ -195,15 +197,17 @@ def is_dmarc_record_strong(domain):
|
|
|
|
dmarc = get_dmarc_record(domain)
|
|
|
|
- if dmarc is not None and dmarc.record is not None:
|
|
+ if dmarc and dmarc.record:
|
|
dmarc_record_strong = check_dmarc_policy(dmarc)
|
|
|
|
check_dmarc_extras(dmarc)
|
|
- elif dmarc.get_org_domain() is not None:
|
|
- output_info("No DMARC record found. Looking for organizational record")
|
|
+
|
|
+ elif dmarc.get_org_domain():
|
|
+ output_info("No DMARC record found. Looking for organizational record.")
|
|
dmarc_record_strong = check_dmarc_org_policy(dmarc)
|
|
+
|
|
else:
|
|
- output_good(domain + " has no DMARC record!")
|
|
+ output_good(f"{domain} has no DMARC record!")
|
|
|
|
return dmarc_record_strong
|
|
|
|
@@ -215,18 +219,13 @@ if __name__ == "__main__":
|
|
try:
|
|
domain = sys.argv[1]
|
|
|
|
- spf_record_strength = is_spf_record_strong(domain)
|
|
+ spf_record_strong = is_spf_record_strong(domain)
|
|
+ dmarc_record_strong = is_dmarc_record_strong(domain)
|
|
|
|
- dmarc_record_strength = is_dmarc_record_strong(domain)
|
|
- if dmarc_record_strength is False:
|
|
- spoofable = True
|
|
+ if spf_record_strong and dmarc_record_strong:
|
|
+ output_bad(f"Spoofing not possible for {domain}")
|
|
else:
|
|
- spoofable = False
|
|
+ output_good(f"Spoofing possible for {domain}!")
|
|
|
|
- if spoofable:
|
|
- output_good("Spoofing possible for " + domain + "!")
|
|
- else:
|
|
- output_bad("Spoofing not possible for " + domain)
|
|
-
|
|
except IndexError:
|
|
- output_error("Usage: " + sys.argv[0] + " [DOMAIN]")
|
|
+ output_error(f"Usage: {sys.argv[0]} [DOMAIN]")
|