aboutsummaryrefslogtreecommitdiffstats
path: root/docs/plans/2026-09-08-parse.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-08 13:24:57 +0200
committerDanilo M. <danix@danix.xyz>2026-09-08 13:24:57 +0200
commit30d2fe0b495405cbecb3b544fd6c49cb6a32eebb (patch)
tree09a8fa835279ebaa8256d8bee5b41adeb9757d62 /docs/plans/2026-09-08-parse.md
parente65e598f4fbdcdfdd0b837abe3c794862f66a3e6 (diff)
downloadabusectl-30d2fe0b495405cbecb3b544fd6c49cb6a32eebb.tar.gz
abusectl-30d2fe0b495405cbecb3b544fd6c49cb6a32eebb.zip
plan: take the provider ranges from SPF, not from memory
Every range in the first draft was wrong. They had been written from memory, and the correct source is each provider's own SPF record, which is the list of addresses it declares it sends from. Gmail is the clearest case: the table claimed eleven IPv4 ranges and _spf.google.com publishes two. Fastmail, Proton and the rest were wrong in the same way. Outlook and Zoho are added since they were queried anyway, and the transcription commands are recorded in a comment so the next check is a copy-paste rather than a search. Google's goog.json is deliberately NOT the source, though it looks like one: it lists all Google infrastructure, over a hundred ranges, and using it would trust every Google-hosted service as part of the user's own mail path. _spf.google.com is the mail-sending answer. The table is IPv4 only. An IPv6 hop from one of these providers does not match and the user is asked instead, which is the safe direction: a hop wrongly trusted means the real sender is never reported. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KphFXTc2QajxXsHWyvGJ4R
Diffstat (limited to 'docs/plans/2026-09-08-parse.md')
-rw-r--r--docs/plans/2026-09-08-parse.md104
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**