Email-Abuse-Investigator
view release on metacpan or search on metacpan
lib/Email/Abuse/Investigator.pm view on Meta::CPAN
# Default constructor timeout for network operations (seconds)
Readonly::Scalar my $DEFAULT_TIMEOUT => 10;
# Maximum role string length before truncation
Readonly::Scalar my $ROLE_WRAP_LEN => 66;
# Maximum redirect hops to follow when resolving shortener/redirect-cloaker URLs
Readonly::Scalar my $REDIRECT_MAX_HOPS => 3;
# Brand names checked in lookalike-domain detection.
# Overridable at runtime via Object::Configure.
Readonly::Array my @LOOKALIKE_BRANDS => qw(
paypal apple google amazon microsoft netflix ebay
instagram facebook twitter linkedin bankofamerica
wellsfargo chase barclays hsbc lloyds santander
);
# -----------------------------------------------------------------------
# Private ranges -- IPs that are never actionable abuse targets
# -----------------------------------------------------------------------
# Both IPv4 and IPv6 private/reserved ranges. Each entry is a compiled
# regex; _is_private() iterates over them and returns true on first match.
my @PRIVATE_RANGES = (
# IPv4 ranges
qr/^0\./, # 0.0.0.0/8 this-network (RFC 1122)
qr/^127\./, # 127.0.0.0/8 loopback
qr/^10\./, # 10.0.0.0/8 RFC 1918
qr/^192\.168\./, # 192.168.0.0/16 RFC 1918
qr/^172\.(?:1[6-9]|2\d|3[01])\./, # 172.16.0.0/12 RFC 1918
qr/^169\.254\./, # 169.254.0.0/16 link-local
qr/^100\.(?:6[4-9]|[7-9]\d|1(?:[01]\d|2[0-7]))\./, # 100.64.0.0/10 CGN (RFC 6598)
qr/^192\.0\.0\./, # 192.0.0.0/24 IETF protocol (RFC 6890)
qr/^192\.0\.2\./, # 192.0.2.0/24 TEST-NET-1 (RFC 5737)
qr/^198\.51\.100\./, # 198.51.100.0/24 TEST-NET-2 (RFC 5737)
qr/^203\.0\.113\./, # 203.0.113.0/24 TEST-NET-3 (RFC 5737)
qr/^255\./, # 255.0.0.0/8 broadcast
# IPv6 ranges
qr/^::1$/, # IPv6 loopback
qr/^fe80:/i, # IPv6 link-local (fe80::/10)
qr/^fc/i, # IPv6 ULA fc00::/7
qr/^fd/i, # IPv6 ULA fd00::/8
qr/^2001:db8:/i, # IPv6 documentation range (RFC 3849)
qr/^64:ff9b:/i, # IPv6 NAT64 well-known prefix
);
# Priority-ordered patterns for extracting IPs from Received: headers.
# Covers bracketed IPv4, bracketed IPv6, parenthesised address, and bare dotted-quad.
my @RECEIVED_IP_RE = (
qr/\[\s*([\d.]+)\s*\]/, # [1.2.3.4]
qr/\[\s*([0-9a-fA-F:]+)\s*\]/, # [IPv6 address]
qr/\(\s*[\w.-]*\s*\[?\s*([\d.]+)\s*\]?\s*\)/, # (hostname [1.2.3.4])
qr/from\s+[\w.-]+\s+([\d.]+)/, # from hostname addr
qr/([\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3})/, # bare dotted-quad fallback
);
# -----------------------------------------------------------------------
# Default configuration -- overridable via Object::Configure
# -----------------------------------------------------------------------
# Object::Configure may overlay
# values from a file before new() uses them. Use Readonly for constants
# that should never be overridden at runtime.
# -----------------------------------------------------------------------
# Trusted domains (infrastructure -- never report these as abuse targets)
# Can be overrideen at runtime by Object::Configure
# -----------------------------------------------------------------------
my %TRUSTED_DOMAINS = map { $_ => 1 } qw(
gmail.com googlemail.com yahoo.com outlook.com hotmail.com
google.com microsoft.com apple.com amazon.com
googlegroups.com groups.google.com
fonts.googleapis.com fonts.gstatic.com
ajax.googleapis.com maps.googleapis.com
w3.org
fedex.com ups.com dhl.com usps.com royalmail.com
);
# -----------------------------------------------------------------------
# URL shortener domains (real destination is hidden behind these)
# -----------------------------------------------------------------------
my %URL_SHORTENERS = map { $_ => 1 } qw(
bit.ly bitly.com tinyurl.com t.co ow.ly
goo.gl is.gd buff.ly ift.tt dlvr.it
short.link rebrand.ly tiny.cc cutt.ly rb.gy
shorturl.at bl.ink smarturl.it yourls.org clicky.me
snip.ly adf.ly bc.vc lnkd.in fb.me
youtu.be
);
# Cloud object-stores and CDN hosting paths commonly abused to serve redirect
# pages that hide the real phishing destination (same evasion as a URL shortener
# but using legitimate cloud infrastructure to pass spam filters).
# Exact-match hosts; suffix patterns are in @REDIRECT_HOST_SUFFIXES below.
my %REDIRECT_HOSTS = map { $_ => 1 } qw(
storage.googleapis.com
blob.core.windows.net
pages.dev
firebaseapp.com
web.app
);
# Subdomain-suffix patterns for bucket-style hosting (e.g. mybucket.s3.amazonaws.com).
# Checked by _is_redirect_cloaker() using a suffix match against the bare hostname.
Readonly::Array my @REDIRECT_HOST_SUFFIXES => qw(
.s3.amazonaws.com
.s3-website.amazonaws.com
.cloudfront.net
.github.io
.firebaseapp.com
.web.app
);
# -----------------------------------------------------------------------
# Well-known provider abuse contacts
# Can be overrideen at runtime by Object::Configure
# -----------------------------------------------------------------------
# Curated table of provider abuse contacts. Entries with only a 'form'
( run in 1.630 second using v1.01-cache-2.11-cpan-7fcb06a456a )