diff options
| -rw-r--r-- | docs/plans/2026-09-08-parse.md | 104 |
1 files changed, 88 insertions, 16 deletions
diff --git a/docs/plans/2026-09-08-parse.md b/docs/plans/2026-09-08-parse.md index 579ff0e..8d30cae 100644 --- a/docs/plans/2026-09-08-parse.md +++ b/docs/plans/2026-09-08-parse.md @@ -1781,18 +1781,69 @@ from pathlib import Path from abusectl import parse -# Sending ranges the providers publish themselves. Static rather than read -# from SPF at runtime: SPF is a DNS lookup, and while the never-resolve rule -# is about parsing hostile mail rather than setup, a static table keeps the -# boundary unambiguous. Verify against the provider's own documentation -# before adding an entry. +# Sending ranges the providers publish in their own SPF records, transcribed +# on 2026-09-08 from: +# +# gmail dig TXT _spf.google.com +# fastmail dig TXT spf.messagingengine.com +# proton dig TXT _spf.protonmail.ch + _spf2.protonmail.ch +# outlook dig TXT spf.protection.outlook.com +# zoho dig TXT spf.zoho.eu +# +# Static rather than read from SPF at runtime: SPF is a DNS lookup, and while +# the never-resolve rule is about parsing hostile mail rather than setup, a +# static table keeps the boundary unambiguous. +# +# IPv4 only. An IPv6 hop from one of these providers is simply not matched by +# the table, which is the safe direction: the user is asked instead of a hop +# being wrongly trusted. +# +# THESE GO STALE. A range that has been reassigned means a hop is treated as +# the user's own and the real sender is never reported, so re-check the SPF +# records before a release rather than trusting the date above. PROVIDERS: dict[str, list[str]] = { - "gmail": ["35.190.247.0/24", "64.233.160.0/19", "66.102.0.0/20", - "66.249.80.0/20", "72.14.192.0/18", "74.125.0.0/16", - "108.177.8.0/21", "173.194.0.0/16", "209.85.128.0/17", - "216.58.192.0/19", "216.239.32.0/19"], - "fastmail": ["66.111.4.0/24", "103.168.172.0/22"], - "proton": ["185.70.40.0/22", "51.89.119.103/32"], + "gmail": [ + "74.125.0.0/16", + "209.85.128.0/17", + ], + "fastmail": [ + "103.168.172.128/27", + "202.12.124.128/27", + "204.75.18.128/27", + ], + "proton": [ + "185.70.40.0/24", + "185.70.41.0/24", + "185.70.43.0/24", + "79.135.106.0/24", + "79.135.107.0/24", + "109.224.244.0/24", + "85.9.206.169/32", + "85.9.210.45/32", + "37.187.220.204/32", + "51.83.17.38/32", + "57.129.93.249/32", + ], + "outlook": [ + "40.92.0.0/15", + "40.107.0.0/16", + "52.100.0.0/15", + "52.102.0.0/16", + "52.103.0.0/17", + "104.47.0.0/17", + ], + "zoho": [ + "185.20.209.0/24", + "31.186.226.0/24", + "31.186.243.0/24", + "89.36.170.0/24", + "185.20.211.0/24", + "185.172.199.0/24", + "91.135.68.104/29", + "185.230.214.0/23", + "136.143.168.0/22", + "34.241.242.183/32", + ], } @@ -1957,12 +2008,33 @@ def write(path: Path, answers: dict, force: bool = False) -> Path: Run: `python3 -m unittest tests.test_init -v` Expected: PASS, 15 tests -- [ ] **Step 5: Verify the shipped provider ranges before trusting them** +- [ ] **Step 5: Re-verify the shipped provider ranges against SPF** + +The table was transcribed from the providers' own SPF records on 2026-09-08, +which is the authoritative source: these are the addresses each provider +declares it sends from. It still goes stale, and a range that has been +reassigned means a hop is treated as the user's own and the real sender is +never reported. + +Re-check before relying on it: + +```bash +for d in _spf.google.com spf.messagingengine.com _spf.protonmail.ch \ + _spf2.protonmail.ch spf.protection.outlook.com spf.zoho.eu; do + printf '%-32s ' "$d"; dig +short TXT "$d" +done +``` + +Compare each `ip4:` entry against `PROVIDERS`. Anything that has moved gets +corrected in the table and the transcription date updated. -The table is static data and can go stale. Confirm each provider's ranges -against its own published documentation, and record the date checked in a -comment above `PROVIDERS`. A wrong range here means a hop is treated as the -user's own and the real sender is never reported. +Two properties of this table are deliberate. It is **IPv4 only**: an IPv6 hop +from one of these providers simply does not match, so the user is asked rather +than a hop being wrongly trusted. And Google publishes a much broader +`goog.json` of all its infrastructure, which is **not** what belongs here: +`_spf.google.com` is two ranges, `goog.json` is over a hundred, and using the +latter would trust every Google-hosted service as if it were the user's own +mail path. - [ ] **Step 6: Commit** |
