Mail HELO
RFC 5321 §4.1.1.1 HELO / EHLO hostname validation primitive + forward-confirmed-reverse-DNS (FCrDNS, RFC 8601 §2.7.6) verifier. Composes b.network.dns.resolver (v0.9.31) for the rDNS + forward lookup pair; pairs with b.guardSmtpCommand (v0.9.32) which gates the command-line SHAPE — this primitive evaluates the SEMANTIC identity claim.
The MX listener (v0.9.36) calls b.mail.helo.evaluate({ ip, claimedName, resolver }) at the EHLO boundary and feeds the verdict into the per-connection policy decision (reject / greylist-anyway / score-tag for downstream SpamAssassin / accept).
## Shape gate (RFC 5321 §4.1.1.1 + §4.1.2)
- **Domain form**: LDH labels per RFC 5321 §2.3.5, FQDN with at least one . (operator can demand multi-label via profile). Bare hostname (no dots) refused under strict; localhost-class claims (localhost, localdomain) always refused regardless of profile. - **Address-literal**: [1.2.3.4] IPv4 or [IPv6:2001:db8::1] IPv6 per RFC 5321 §4.1.3 — accepted when matches the connection IP, refused otherwise (RFC 5321 §4.1.1.1 implies the literal should be the actual host). - **Empty / too-long**: refused under all profiles.
## FCrDNS check (RFC 8601 §2.7.6 / RFC 1912 §2.1)
With resolver provided, evaluate() issues:
1. PTR for (IPv4) or .ip6.arpa (IPv6) — reverse name. 2. A / AAAA for each PTR result — forward name. 3. Match: at least one forward IP must equal the connection IP (the FCrDNS contract).
The returned verdict carries the rDNS name(s) + the per-name forward-match outcome so operator audit pipelines see exactly why FCrDNS passed or failed.
## "Generic rDNS" heuristic (operator-configurable)
Many spam sources have FCrDNS-valid rDNS that's CLEARLY a consumer ISP dynamic pool (pool-xx-xx.dialup.example.com, dsl-1234.foo.example.net, etc.). Operators opt-in via { genericRdnsPatterns: [ and the verdict flags genericRdns: true. Pre-shipped pattern list lives in b.mail.helo.GENERIC_RDNS_PATTERNS for the common consumer-ISP shapes; operator extends per-deployment.
## Verdict shape
{
action: "accept" | "reject-shape" | "soft-fail-fcrdns" |
"match-self-refused" | "literal-mismatch",
shape: "domain" | "address-literal-v4" |
"address-literal-v6" | "bare-host" | "invalid",
fcrdns: {
checked: boolean,
passed: boolean,
rdnsNames: string[],
forwardIps: string[],
matchedIp: string | null,
} | null,
genericRdns: boolean,
reason: string,
}
## CVE / threat model
- **HELO spoofing** — RFC 5321 §4.1.1.1 doesn't require HELO accuracy, but a peer claiming our-mx-cluster.example.com when its FCrDNS resolves elsewhere is suspect. Operator's selfNames list blocks the self-claim spoof. - **Botnet residential-IP class** — generic-rDNS detection + RBL composition catches consumer-ISP dynamic-pool sources before they reach the DATA phase. - **DNS poisoning of PTR** — composed via b.network.dns.resolver, so PTR queries inherit the resolver's safeDns caps, AD-bit surface, and CVE coverage (CVE-2008-1447 / 2022-3204 / 2023-50387 / 50868 / 2024-1737).
## When NOT to enforce FCrDNS strict
IPv6 PTR records are spotty across consumer ISPs; FCrDNS-strict on IPv6 traffic over-rejects. Operator opts to { fcrdnsRequiredFor: ["v4"] } under balanced profile when they need to accept v6 senders without PTR records (common with legitimate cloud / VPS providers that don't auto-publish rDNS).
b.mail.helo.evaluate(ctx, opts?) #
{
profile: "strict" | "balanced" | "permissive",
posture: "hipaa" | "pci-dss" | "gdpr" | "soc2",
selfNames: string[], // operator's MX hostnames; claim of these by a peer refused
genericRdnsPatterns: RegExp[], // additional patterns layered onto built-ins
fcrdnsRequiredFor: ("v4" | "v6")[], // overrides profile's FCrDNS list
audit: b.audit namespace,
}
Evaluate a peer's HELO / EHLO identity claim. Returns a verdict shape the MX listener consumes to drive accept / reject / score-tag policy.
var resolver = b.network.dns.resolver.create();
var v = await b.mail.helo.evaluate({
ip: "203.0.113.42",
claimedName: "mail.example.com",
resolver: resolver,
}, { profile: "strict" });
if (v.action === "reject-shape") return reply(550, v.reason);
b.mail.helo.compliancePosture(posture) #
Return the effective profile name for a compliance posture, or null for unknown posture names.
b.mail.helo.compliancePosture("hipaa"); // → "strict"
Last updated 2026-08-08T16:39:49.652Z by seeder.