Lesson 09 / 16
Domain Policy Record
Tightening the policy declaration for noncompliant messages in stages: the count of dropped legitimate messages and blocked forged messages at each stage, the report flow's rate of finding unauthorized senders, and the cost of rejecting outright.
Published Updated
In this lesson
- Distinguishes which decision the policy declaration moves, and from whom to whom
- Compares the report-only, quarantine, and reject stages by their counts of dropped legitimate messages and blocked forged messages
- Counts the report flow's rate of finding unauthorized senders and where that rate falls short
Contents
The previous lesson ran both checks and produced two outcomes for every message. The question left open there was what the outcome is for: when a message fails a check, does the receiving side deliver it, separate it, or never accept it at all? By default, the name owner does not make this decision. Each receiver acts on its own criteria; some deliver a failed message as is, some apply their own estimate. The result is that the same forged message reaches an inbox in one place and goes nowhere in another.
The policy declaration moves this decision back to the name owner. It is a record published in the zone, and it says: apply this action to a message that arrives in this name’s name but fails the checks. It has three stages — report only, quarantine, reject — and the difference between them is who gets billed for the gaps in the sending infrastructure.
Jumping between stages is one of the most expensive countable mistakes in this topic. This lesson runs one period and derives two numbers together at each stage: how many legitimate messages get dropped and how many forged messages get blocked.
The Fields the Declaration Carries
The record is written into the zone as text and declares four things: the action to apply to a noncompliant message, what percentage of messages the action applies to, the address reports get sent to, and whether a separate action is defined for subdomains. The first two are the two axes this lesson measures; the third is the source of the measurement.
The declaration’s scope is also a decision. The action applies only to messages that carry this name in the from field; the check looks for the name that passed verification to match the name in the from field. Without this requirement, the declaration would not work: a message properly signed under its own name could carry a different name in the from field and appear to pass the checks. The overlap requirement is the link that ties the surface the two records close to the declaration’s scope.
The reason a separate action can be defined for subdomains is that subdomains mostly do not send messages. In the model’s zone there are fourteen names, and only a few of them send; for the subdomains that do not send, the strictest action can be declared directly, because there is no legitimate message to lose there. This is the first and costless step of tightening, and it stays outside the count below.
One Period, Four Stages
DR13. The period is one month and consists of 414 fictional messages; flow counts are taken as fixed. DR14. The compliance criterion is that at least one of the two checks passes aligned with the sender’s name. DR15. A legitimate message put into quarantine counts as delivered; the probability it gets read is not counted in this model.
// Model: one period's message flow and the policy declaration's stages. Flows, // message counts, and the report rate are fictional; compliance means at // least one of the two checks passes aligned with the sender's name. const SEED = 7311; const REPORT_RATE = 0.65; // the rate at which receivers send reports function prng(seed) { let x = seed % 2147483647; return () => { x = (x * 48271) % 2147483647; return (x - 1) / 2147483646; }; } // sources: [address, message count]; the policy/signature fields are check results const FLOWS = [ { name: 'nightly-summary', kind: 'legit', policy: true, signature: true, sources: [['198.51.100.11', 120]] }, { name: 'deviation-alert', kind: 'legit', policy: true, signature: true, sources: [['198.51.100.12', 60]] }, { name: 'period-close', kind: 'legit', policy: true, signature: false, sources: [['198.51.100.13', 40]] }, { name: 'bulk-announcement', kind: 'legit', policy: true, signature: true, sources: [['203.0.113.40', 50], ['203.0.113.41', 40]] }, { name: 'threshold-alert', kind: 'legit', policy: false, signature: false, sources: [['192.0.2.77', 25]] }, { name: 'redirected-order', kind: 'legit', policy: false, signature: false, sources: [['198.51.100.30', 18]] }, { name: 'billing-impersonation', kind: 'forged', policy: false, signature: false, sources: [['192.0.2.200', 30], ['198.18.0.5', 2]] }, { name: 'workorder-impersonation', kind: 'forged', policy: false, signature: false, sources: [['192.0.2.201', 15], ['198.18.0.9', 1], ['198.18.0.12', 1]] }, { name: 'in-block-impersonation', kind: 'forged', policy: true, signature: false, sources: [['203.0.113.200', 12]] }, ]; const compliant = (a) => a.policy || a.signature; const count = (a) => a.sources.reduce((t, [, n]) => t + n, 0); const sum = (predicate) => FLOWS.filter(predicate).reduce((t, a) => t + count(a), 0); const legit = sum((a) => a.kind === 'legit'); const forged = sum((a) => a.kind === 'forged'); console.log('period total:', legit + forged, '| legit:', legit, '| forged:', forged); console.log('noncompliant legit messages:', sum((a) => a.kind === 'legit' && !compliant(a)), '| compliant forged messages:', sum((a) => a.kind === 'forged' && compliant(a))); console.log('unprepared legit flows:', FLOWS.filter((a) => a.kind === 'legit' && !compliant(a)).map((a) => `${a.name}=${count(a)}`).join(' ')); const STAGES = ['no declaration', 'report only', 'quarantine', 'reject']; console.log('\nstage inbox (legit) separated legit inbox (forged) blocked forged'); for (const stage of STAGES) { const separates = stage === 'quarantine' || stage === 'reject'; const legitSeparated = separates ? sum((a) => a.kind === 'legit' && !compliant(a)) : 0; const forgedSeparated = separates ? sum((a) => a.kind === 'forged' && !compliant(a)) : 0; console.log(stage.padEnd(16) + String(legit - legitSeparated).padEnd(22) + `${legitSeparated}${stage === 'reject' ? ' (lost)' : stage === 'quarantine' ? ' (quarantine)' : ''}`.padEnd(17) + String(forged - forgedSeparated).padEnd(22) + String(forgedSeparated)); } // Report flow: each message independently enters the report with REPORT_RATE odds. // A source counts as found if at least one of its messages was reported. const rand = prng(SEED); const unauthorized = []; for (const a of FLOWS) { if (a.policy) continue; // already in the policy record for (const [address, n] of a.sources) { let reported = 0; for (let i = 0; i < n; i++) if (rand() < REPORT_RATE) reported++; unauthorized.push({ address, flow: a.name, kind: a.kind, n, found: reported > 0 }); } } const detected = unauthorized.filter((k) => k.found); console.log('\nreport rate:', REPORT_RATE, '| seed:', SEED); console.log('unauthorized sources:', unauthorized.length, '| found via reports:', detected.length, `(${Math.round((detected.length / unauthorized.length) * 100)}%)`); for (const k of unauthorized.filter((x) => !x.found)) { console.log(` missed source: ${k.address.padEnd(15)} ${k.flow.padEnd(18)} messages=${k.n}`); } console.log('message share of found sources:', `${detected.reduce((t, k) => t + k.n, 0)}/${unauthorized.reduce((t, k) => t + k.n, 0)}`); // Prep: the new service is added to the policy record, the batch job is signed. FLOWS.find((a) => a.name === 'threshold-alert').policy = true; console.log('\nlegit messages lost in the reject stage after prep:', sum((a) => a.kind === 'legit' && !compliant(a)));
period total: 414 | legit: 353 | forged: 61 noncompliant legit messages: 43 | compliant forged messages: 12 unprepared legit flows: threshold-alert=25 redirected-order=18 stage inbox (legit) separated legit inbox (forged) blocked forged no declaration 353 0 61 0 report only 353 0 61 0 quarantine 310 43 (quarantine) 12 49 reject 310 43 (lost) 12 49 report rate: 0.65 | seed: 7311 unauthorized sources: 7 | found via reports: 6 (86%) missed source: 198.18.0.12 workorder-impersonation messages=1 message share of found sources: 91/92 legit messages lost in the reject stage after prep: 18
Reading the Stages
The first two rows carry the same numbers, and that is not a mistake. The report-only stage blocks no message at all; sixty-one forged messages keep reaching the inbox. The only thing this stage produces is a report, and a report is not a defense but a measurement tool.
Tightening begins at the quarantine row: forty-nine forged messages are separated from the inbox, and in exchange forty-three legitimate messages are separated too. The ratio is almost one to one — meaning that alongside the closed open item, the wrong closure is of the same magnitude. The only difference is that a quarantined legitimate message still sits somewhere; the recipient finds it if they look.
Reject gives the same numbers as quarantine, but the column’s meaning changes: the forty-three legitimate messages are now nowhere at all. Two stages at the same strictness diverge on the legitimate-message side in terms of reversibility. This is why the order matters: quarantine is a rehearsal for rejecting, and it keeps the loss recoverable.
The last column shows the item that never closes. Twelve forged messages reach the inbox at every stage, because they come from inside the network block authorized in the policy record and count as compliant. The policy declaration says what to do with a noncompliant message; it does not see a forgery that looks compliant. The overly broad authorization from the previous lesson comes back here directly as an item: tightening the declaration without narrowing the block does not touch these twelve messages.
The Report’s Value and Its Limit
The report flow is receivers telling the name owner: a message came from this source in this name’s name, and the check resulted in this. Its value is that the drift visible only in the previous lesson’s run becomes visible in production.
DR16. A portion of receivers send reports; each message independently has a 0.65 probability of entering a report. DR17. A report shows the source, not whether the message was legitimate or forged.
The number is good: six of seven unauthorized sources are found, the find rate is 86%, and the found sources cover 91 of the messages. The one source that got away sent only a single message during the period. The rule here is that the report flow finds a high-volume source almost for certain and misses a sparse one. That means it is the right tool for preparation — legitimate flows that would be dropped unprepared are, by definition, regular and high-volume.
The limit is in DR17. The report says 25 noncompliant messages came from 192.0.2.77; it
does not say whether that is a newly set-up threshold-alert service or an impersonation. What
makes that distinction is not the report but the inventory — comparison against the list
of services that actually send. The report flow produces the question, not the answer.
The Cost of Rejecting, and Preparation
The cost of moving straight to rejecting is written by name in the output: threshold-alert, 25 messages; redirected-order, 18 messages. The first is a new service waiting to be added to the record; its loss is a preparation gap. The second is a redirect field teams set up to their own addresses, and it is not under the name owner’s control.
The preparation step turns this distinction into a number: after the new service is added to the policy record, the legitimate messages lost in the reject stage drop from 43 to 18. The remaining 18 messages, however, cannot be closed with a record — the redirect makes the message come from a different machine and changes its body.
How long preparation needs to run also comes from the report. A single-period report shows only the sources that sent during that period; a close-out job that runs at the start of the quarter, or a notification sent once a year, never shows up in a one-period window. The one source that got away having sent a single message during the period is the small-scale example of this. The preparation window must cover the period of the sparsest sending flow; kept short, tightening drops that flow the first day it runs.
This is the justification for staged tightening. In the report stage, sources are found, records are completed, and the magnitude of the remaining loss is measured; only after that does the move go to quarantine, then to rejecting. If the order is skipped, the loss ends up the same size, but it is experienced first and learned about afterward.
Tightening by Percentage
A stage is not a single switch. The declaration can also say the action applies to only a percentage of messages; tightening is thereby graduated within a stage too.
// Model: the declaration can apply to only a percentage of noncompliant // messages. Input is the prior counts: two unprepared legit flows, 49 forged. const SEED = 9013; const LEGIT_FLOWS = [['threshold-alert', 25], ['redirected-order', 18]]; const NONCOMPLIANT_FORGED = 49; const NOTICE_THRESHOLD = 10; // this many losses in a flow per period produce a complaint function prng(seed) { let x = seed % 2147483647; return () => { x = (x * 48271) % 2147483647; return (x - 1) / 2147483646; }; } const countHits = (rand, n, rate) => { let k = 0; for (let i = 0; i < n; i++) if (rand() < rate) k++; return k; }; console.log('seed:', SEED, '| notice threshold:', NOTICE_THRESHOLD, 'messages/period'); console.log('rate threshold-alert redirected-order total legit lost forged blocked flows past threshold'); for (const rate of [0.05, 0.1, 0.25, 0.5, 1.0]) { const rand = prng(SEED); const losses = LEGIT_FLOWS.map(([, n]) => countHits(rand, n, rate)); const forgedBlocked = countHits(rand, NONCOMPLIANT_FORGED, rate); console.log( `${Math.round(rate * 100)}%`.padEnd(7) + String(losses[0]).padEnd(17) + String(losses[1]).padEnd(20) + String(losses[0] + losses[1]).padEnd(20) + String(forgedBlocked).padEnd(18) + String(losses.filter((k) => k >= NOTICE_THRESHOLD).length), ); }
seed: 9013 | notice threshold: 10 messages/period rate threshold-alert redirected-order total legit lost forged blocked flows past threshold 5% 0 2 2 2 0 10% 4 3 7 4 0 25% 9 6 15 12 0 50% 14 12 26 26 2 100% 25 18 43 49 2
Two things read at once in the table. First, a low percentage blocks forged messages at a low rate too; at 10%, only four of the forty-nine forgeries get stopped. The percentage grades risk, not defense.
Second, and the actually useful one, is the last column. Up to 25%, no flow crosses the notice threshold; there is loss, but no one complains. This shows the percentage’s real function: a low rate is not a defense setting but a tool for finding preparation gaps cheaply. A loss of fifteen messages shows up in reports and not with the field team; the same flow, opened to 100%, loses twenty-five messages at once and work stops. The cost of running tightening by percentage is that forged messages also get through at the same rate every period that passes.
The Remaining Item and the New Surface
DR18. In this model, the declaration is applied identically by every receiver.
This assumption overreaches reality and shows the part of this topic that cannot be measured: the declaration is a request, not something enforceable. The receiving side may not apply it, may apply it partially, or may layer its own criteria on top. Here the name owner only declares a decision; someone else applies it, and whether it gets applied is visible, incompletely, only through the report flow.
The new surface closing brings is the report flow itself. An address is written into the zone, and continuous data arrives at that address from outside parties: how many messages came from which source, which check failed. This is a flow that makes the measurement network’s sending structure readable from outside, and the address it goes to is written openly in the zone for anyone. It is also a volume surface: the report address is a data intake that comes from outside and must be processed.
Summary
- The policy declaration moves the decision of what to do with a noncompliant message from the receiver to the name owner; without a declaration, the same forged message reaches an inbox at one receiver and goes nowhere at another.
- The report-only stage blocks no message: 61 forged messages keep getting through; this stage is a measurement tool, not a defense.
- Quarantine and reject give the same numbers (49 forged blocked, 43 legitimate separated); the difference is in the reversibility of the legitimate message.
- 12 forged messages coming from inside the authorized network block reach the inbox at every stage; the declaration separates the noncompliant but does not see a forgery that looks compliant.
- The report flow finds six of seven unauthorized sources (86%) and covers 91 of the messages; the source it misses sent a single message during the period.
- Preparation brings the legitimate loss in the reject stage down from 43 to 18; the remaining 18 messages come from a redirect and cannot be closed with any record.
Next Step
The name now also defines who is permitted to send messages in its own name, and declares what happens to a noncompliant message. All of this is a measure of the sending side. A message can fail to arrive even after passing every check: the receiving side also decides based on the sender’s history — how many of its messages bounced, how many people complained, whether the sending volume spiked suddenly. The next lesson models deliverability as a ratio, counts the factors that degrade it separately, and runs one period: how many messages get delayed when reputation drops, how many never arrive at all, and how many periods recovery takes.
To keep your progress and take notes, Log in
My notes
Log in to take notes.