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 )