85.1.5. pepsi-stage-srs¶
rewrite the envelope sender with the Sender Rewriting Scheme
- Manual section:
1
85.1.5.1.1. Name¶
pepsi-stage-srs - SRS envelope-sender rewriting stage of the Pepsi pipeline.
85.1.5.1.2. Synopsis¶
pepsi-stage-srs [GLOBAL-OPTIONS] worker
pepsi-stage-srs [GLOBAL-OPTIONS] forward ADDRESS
pepsi-stage-srs [GLOBAL-OPTIONS] reverse ADDRESS
85.1.5.1.3. Description¶
This stage defaults to FUSION = yes: when stage fusion is enabled ([pepsi]
ALLOW_FUSION, the default) and this stage is folded into the unified pepsi
binary, a predecessor may run it in its own worker process instead of
dispatching it separately. See pepsi-dispatch(1) and pepsi.conf(5).
pepsi-stage-srs is a stage program run by pepsi-dispatch(1) as a persistent worker reading message ids on standard input. It implements the Sender Rewriting Scheme (SRS).
When Pepsi forwards a message it keeps the body intact but relays it from its own
IP addresses. The next hop’s SPF check then sees Pepsi sending mail whose
envelope sender is still the original sender’s domain, which does not authorise
Pepsi’s IPs, and the check fails. SRS solves this by rewriting the envelope
sender (MAIL FROM) into a local address of a Pepsi-controlled domain
(SRS_DOMAIN) that encodes — and HMAC-signs — the original sender:
SRS0=HHHH=TT=origin.example=alice@srs.example.org
SPF at the next hop now checks srs.example.org, which legitimately sends from
Pepsi’s IPs. The body and its DKIM signatures are untouched. The stage then
advances the message to its NEXT_STAGE (the delivery stage). It changes only
the envelope sender, leaving the row’s state — including any RFC 3461
state.dsn parameters — untouched for later stages to honour.
The null sender (<>, i.e. a returning bounce) is never rewritten, and a
sender already in SRS_DOMAIN is left unchanged (rewriting is idempotent). A
sender that is already an SRS address — the message reached Pepsi through
another forwarder — is re-signed in the compact SRS1 form rather than being
nested, so a bounce hops back one forwarder at a time.
85.1.5.1.3.1. Reverse direction¶
The other half of SRS — recognising a bounce returned to an SRS address,
verifying its signature and timestamp, decoding the original sender and relaying
the bounce there — is performed by pepsi-ingress(1) at RCPT time, not
by this program. A recipient in SRS_DOMAIN whose local-part is a valid SRS
token is accepted and rewritten back to the original sender (even though that
sender’s domain is not one Pepsi serves — the valid signature authorises the
relay); a forged or expired token is rejected with 550. Both directions read
the same shared [pepsi-srs] configuration, so the secret and domain match.
This half is what makes SRS_DOMAIN a domain that must receive mail, not
merely one this host sends as. Rewriting the envelope sender makes Pepsi the
bounce destination for a message it did not write; if the domain publishes no
MX and no address record, the returning bounce is discarded by the MTA that
tried to send it and the original author is never told. pepsi-setup(1)
checks for this on every run, under its DNS cross-checks, because the domain’s
SPF and DMARC records look complete without it.
85.1.5.1.4. Configuration¶
The stage needs only a NEXT_STAGE in its own [stage-<name>] section
(PROGRAM = pepsi-stage-srs); the SRS parameters (SRS_DOMAIN,
SECRET/SECRET_FILE, MAX_AGE_DAYS) live in the shared [pepsi-srs]
section it shares with pepsi-ingress(1). All are documented in
pepsi.conf(5). Omitting [pepsi-srs] disables SRS: a worker of this
stage then refuses to start (as it does when the secret cannot be read), so the
dispatcher holds the messages queued for it until the configuration is fixed
rather than failing them, and pepsi-ingress(1) treats SRS-looking
recipients as ordinary addresses. The secret is re-read for every message, so a
rotated secret needs no restart; if it becomes unreadable while a worker runs,
the message is retried with back-off (see pepsi-dispatch(1)).
85.1.5.1.5. State¶
Inputs: none — the stage operates on the mail_from column, not on
state.
Outputs: state.srs.original, the envelope sender the rewrite replaced.
Nothing else in state is touched — state.dsn and the rest are preserved
unchanged. The state layout is described in pepsi.state(7).
That one key exists for a DSN Pepsi originates after this stage has run, which is every DSN on a relaying path: this stage necessarily precedes the delivery stage, so pepsi-stage-bounce(1) would otherwise address the report to our own SRS alias and make it take a round trip out to the next hop and back in through our MX to be decoded. The bounce stage reads this instead of reversing the alias, which keeps the SRS secret out of a stage that only composes mail. It is written only when absent, so a message rewritten twice keeps the address that names a real correspondent rather than the intermediate alias.
Transitions: always advances to NEXT_STAGE, whether the envelope sender
was SRS-rewritten or passed through unchanged (a null sender, or one already in
SRS_DOMAIN). There is no branch; the stage never pauses, fails, reroutes or
finishes.
85.1.5.1.6. Commands¶
Run as a worker, the program rewrites each message’s envelope sender and advances it. The subcommands are operator tools:
- forward ADDRESS
Print the SRS rewrite of ADDRESS (the forward direction) and exit. Useful for inspecting what a given sender becomes.
- reverse ADDRESS
Decode and verify ADDRESS (an SRS address or bare local-part) and print the original sender, or fail if it is not a valid SRS address.
85.1.5.1.7. Global Options¶
- -c FILE, –config FILE
Read the configuration from FILE instead of the default search path.
- -L LOGLEVEL, –log LOGLEVEL
Set the logging verbosity (
error,warn,info,debug,trace; defaultinfo).- -h, –help
Print a usage summary and exit.
- -V, –version
Print the version and exit.
85.1.5.1.8. Exit Status¶
The outcome of each message is reported to pepsi-dispatch(1) on the worker’s status line, not as the exit status.
- 0
The worker ran until its standard input was closed, or the forward / reverse subcommand succeeded.
- 1
A fatal error occurred (unreadable configuration, the database could not be opened, standard input/output failed, or reverse was given an address that is not a valid SRS address). The reason is written to the log.
85.1.5.1.9. Examples¶
Show what a sender is rewritten to:
pepsi-stage-srs -c /etc/pepsi/pepsi.conf forward alice@origin.example
Decode a returned bounce address:
pepsi-stage-srs -c /etc/pepsi/pepsi.conf reverse 'SRS0=HHHH=TT=origin.example=alice@srs.example.org'
85.1.5.1.10. See Also¶
pepsi-config(1), pepsi-stage-relay-to-smarthost(1), pepsi-stage-relay-to-internet(1), pepsi-stage-bounce(1), pepsi-stage-dkim-sign(1), pepsi-dispatch(1), pepsi-ingress(1), pepsi.conf(5), pepsi.state(7), pepsi-setup(1)
85.1.5.1.11. Bugs¶
Report bugs to the Pepsi issue tracker.