Open WKobes opened 2 weeks ago
Ok, I think the RFC is not so clear, I use to think mx
should count as '1 MX lookup' + 1 lookup for each MX record, since this is indeed a lookup, at least that is how I read RFC 7208 - § 4.6.4. DNS Lookup Limits.
In the meantime I found a nice :crab:rust tool spftrace
(output below) that uses viaspf
, which has Issue #3 - Revisit DNS lookup limits with quite some elaborate research on this topic, including links to older RFCs and the IETF mailing list with the author. Most importantly this answer which indeed would say the sub lookups should not be counted in the total (BTW repo moved to codeberg, probably best to fully quote the research instead of linking).
Some nice output for this case, it should indeed be valid according to this count:
$ spftrace eviny.no 0.0.0.0
eviny.no
│ "v=spf1 mx ip4:149.72.90.22/32 include:spf.logicalware.com include:spf.protection.outlook.com
│ include:sendgrid.net include:_spf.anpdm.com include:_spf.atlassian.net include:spf.zoho.eu
│ include:eu.transmail.net -all"
├── mx → eviny.no (lookups: 1/10, nested: 1/10)
│ └── eviny-no.mail.protection.outlook.com
│ ├── 52.101.73.28
│ ├── 52.101.73.1
│ ├── 52.101.73.26
│ └── 52.101.68.21
│ not-match
├── ip4:149.72.90.22/32 not-match
├── include:spf.logicalware.com → spf.logicalware.com (lookups: 2/10)
│ spf.logicalware.com
│ │ "v=spf1 ip4:54.246.247.240/28 ip4:23.251.238.30/31 ip4:23.251.238.32/31
│ │ ip4:54.240.104.177/32 ip4:54.240.104.178/31 ip4:212.89.52.12/32 ip4:212.89.52.11/32
│ │ ip4:212.89.52.46/31 -all"
│ ├── ip4:54.246.247.240/28 not-match
│ ├── ip4:23.251.238.30/31 not-match
│ ├── ip4:23.251.238.32/31 not-match
│ ├── ip4:54.240.104.177/32 not-match
│ ├── ip4:54.240.104.178/31 not-match
│ ├── ip4:212.89.52.12/32 not-match
│ ├── ip4:212.89.52.11/32 not-match
│ ├── ip4:212.89.52.46/31 not-match
│ └── all match result=fail
│ not-match
├── include:spf.protection.outlook.com → spf.protection.outlook.com (lookups: 3/10)
│ spf.protection.outlook.com
│ │ "v=spf1 ip4:40.92.0.0/15 ip4:40.107.0.0/16 ip4:52.100.0.0/15 ip4:52.102.0.0/16
│ │ ip4:52.103.0.0/17 ip4:104.47.0.0/17 ip6:2a01:111:f400::/48 ip6:2a01:111:f403::/49
│ │ ip6:2a01:111:f403:8000::/51 ip6:2a01:111:f403:c000::/51 ip6:2a01:111:f403:f000::/52 -all"
│ ├── ip4:40.92.0.0/15 not-match
│ ├── ip4:40.107.0.0/16 not-match
│ ├── ip4:52.100.0.0/15 not-match
│ ├── ip4:52.102.0.0/16 not-match
│ ├── ip4:52.103.0.0/17 not-match
│ ├── ip4:104.47.0.0/17 not-match
│ ├── ip6:2a01:111:f400::/48 not-match
│ ├── ip6:2a01:111:f403::/49 not-match
│ ├── ip6:2a01:111:f403:8000::/51 not-match
│ ├── ip6:2a01:111:f403:c000::/51 not-match
│ ├── ip6:2a01:111:f403:f000::/52 not-match
│ └── all match result=fail
│ not-match
├── include:sendgrid.net → sendgrid.net (lookups: 4/10)
│ sendgrid.net
│ │ "v=spf1 ip4:167.89.0.0/17 ip4:208.117.48.0/20 ip4:50.31.32.0/19 ip4:198.37.144.0/20
│ │ ip4:198.21.0.0/21 ip4:192.254.112.0/20 ip4:168.245.0.0/17 ip4:149.72.0.0/16
│ │ ip4:159.183.0.0/16 include:ab.sendgrid.net ~all"
│ ├── ip4:167.89.0.0/17 not-match
│ ├── ip4:208.117.48.0/20 not-match
│ ├── ip4:50.31.32.0/19 not-match
│ ├── ip4:198.37.144.0/20 not-match
│ ├── ip4:198.21.0.0/21 not-match
│ ├── ip4:192.254.112.0/20 not-match
│ ├── ip4:168.245.0.0/17 not-match
│ ├── ip4:149.72.0.0/16 not-match
│ ├── ip4:159.183.0.0/16 not-match
│ ├── include:ab.sendgrid.net → ab.sendgrid.net (lookups: 5/10)
│ │ ab.sendgrid.net
│ │ │ "v=spf1 ip4:223.165.113.0/24 ip4:223.165.115.0/24 ip4:223.165.118.0/23
│ │ │ ip4:223.165.120.0/23 ~all"
│ │ ├── ip4:223.165.113.0/24 not-match
│ │ ├── ip4:223.165.115.0/24 not-match
│ │ ├── ip4:223.165.118.0/23 not-match
│ │ ├── ip4:223.165.120.0/23 not-match
│ │ └── all match result=softfail
│ │ not-match
│ └── all match result=softfail
│ not-match
├── include:_spf.anpdm.com → _spf.anpdm.com (lookups: 6/10)
│ _spf.anpdm.com
│ │ "v=spf1 ip4:91.227.208.0/24 ip4:185.64.72.0/24 ip4:185.64.73.0/24 ip4:185.64.74.0/24
│ │ ip4:52.17.51.198 -all"
│ ├── ip4:91.227.208.0/24 not-match
│ ├── ip4:185.64.72.0/24 not-match
│ ├── ip4:185.64.73.0/24 not-match
│ ├── ip4:185.64.74.0/24 not-match
│ ├── ip4:52.17.51.198 not-match
│ └── all match result=fail
│ not-match
├── include:_spf.atlassian.net → _spf.atlassian.net (lookups: 7/10)
│ _spf.atlassian.net
│ │ "v=spf1 ip4:167.89.0.0/17 ip4:168.245.0.0/17 include:amazonses.com -all"
│ ├── ip4:167.89.0.0/17 not-match
│ ├── ip4:168.245.0.0/17 not-match
│ ├── include:amazonses.com → amazonses.com (lookups: 8/10)
│ │ amazonses.com
│ │ │ "v=spf1 ip4:199.255.192.0/22 ip4:199.127.232.0/22 ip4:54.240.0.0/18 ip4:69.169.224.0/20
│ │ │ ip4:23.249.208.0/20 ip4:23.251.224.0/19 ip4:76.223.176.0/20 ip4:54.240.64.0/19
│ │ │ ip4:54.240.96.0/19 ip4:76.223.128.0/19 ip4:216.221.160.0/19 ip4:206.55.144.0/20 -all"
│ │ ├── ip4:199.255.192.0/22 not-match
│ │ ├── ip4:199.127.232.0/22 not-match
│ │ ├── ip4:54.240.0.0/18 not-match
│ │ ├── ip4:69.169.224.0/20 not-match
│ │ ├── ip4:23.249.208.0/20 not-match
│ │ ├── ip4:23.251.224.0/19 not-match
│ │ ├── ip4:76.223.176.0/20 not-match
│ │ ├── ip4:54.240.64.0/19 not-match
│ │ ├── ip4:54.240.96.0/19 not-match
│ │ ├── ip4:76.223.128.0/19 not-match
│ │ ├── ip4:216.221.160.0/19 not-match
│ │ ├── ip4:206.55.144.0/20 not-match
│ │ └── all match result=fail
│ │ not-match
│ └── all match result=fail
│ not-match
├── include:spf.zoho.eu → spf.zoho.eu (lookups: 9/10)
│ spf.zoho.eu
│ │ "v=spf1 ip4:185.20.209.0/24 ip4:31.186.226.0/24 ip4:31.186.243.0/24 ip4:89.36.170.0/24
│ │ ip4:185.20.211.0/24 ip4:185.172.199.0/24 ip4:91.135.68.104/29 ip4:185.230.214.0/23
│ │ ip4:136.143.168.0/22 ~all"
│ ├── ip4:185.20.209.0/24 not-match
│ ├── ip4:31.186.226.0/24 not-match
│ ├── ip4:31.186.243.0/24 not-match
│ ├── ip4:89.36.170.0/24 not-match
│ ├── ip4:185.20.211.0/24 not-match
│ ├── ip4:185.172.199.0/24 not-match
│ ├── ip4:91.135.68.104/29 not-match
│ ├── ip4:185.230.214.0/23 not-match
│ ├── ip4:136.143.168.0/22 not-match
│ └── all match result=softfail
│ not-match
├── include:eu.transmail.net → eu.transmail.net (lookups: 10/10)
│ eu.transmail.net
│ │ "v=spf1 ip4:136.143.168.0/24 ip4:136.143.170.0/24 ip4:185.172.198.0/24 ~all"
│ ├── ip4:136.143.168.0/24 not-match
│ ├── ip4:136.143.170.0/24 not-match
│ ├── ip4:185.172.198.0/24 not-match
│ └── all match result=softfail
│ not-match
└── all match result=fail
fail
Note: a lot of tooling is wrong in this space.
I'll dig into this specific one, but long term, perhaps we should replace our code entirely with viaspf. Why kludge it ourselves when they've already done it? A bit of work to integrate with rust code, but not that hard.
From careful comparison, I think this is actually an off by one error. We are counting the same way as spftrace (great tool!), we just cut it off once we hit include:amazonses.com. #1548 has a fix.
The tricky thing might be integration with our DNS resolver, etc. But indeed looks like a nice tool.
In our case the 'no-match' isn't really a display thing, even all IPs might be truncated.
Then again, we might add a warning for large CIDRs, e.g. 0.0.0.0/0
or mx/0
:
Main has PR #1533 which fixed #1529
On main, domain eviny.no still fails on lookup count
SPF of
eviny.no
is:v=spf1 mx ip4:149.72.90.22/32 include:spf.logicalware.com include:spf.protection.outlook.com include:sendgrid.net include:_spf.anpdm.com include:_spf.atlassian.net include:spf.zoho.eu include:eu.transmail.net -all
Count: 1 (mx) + 7 (includes) = 8
Two SPF's have additional includes:
SPF of
sendgrid.net
is:v=spf1 ip4:167.89.0.0/17 ip4:208.117.48.0/20 ip4:50.31.32.0/19 ip4:198.37.144.0/20 ip4:198.21.0.0/21 ip4:192.254.112.0/20 ip4:168.245.0.0/17 ip4:149.72.0.0/16 ip4:159.183.0.0/16 include:ab.sendgrid.net ~all
SPF of
_spf.atlassian.net
is:v=spf1 ip4:167.89.0.0/17 ip4:168.245.0.0/17 include:amazonses.com -all
This brings the count to 10. No further includes are found.
Our test possibily fails because we might count the mx term as 1 + N where N is the number of MX Resource Records. The RFC is quite unclear on this. External sources seems to disagree whether the count of mx term should be 1, N or N+1. Other online tests seem to count as 1 or N.
Discussed with @baknu we need to know the correct count here before release.