# Sendmail access.db and IPv6 prefixes



## scotia (Jan 6, 2020)

Hi all,

I need to specify an IPv6 prefix in /etc/mail/access using CIDR notation and it doesn't seem to work (nor can I find it documented).

My range is similar to: "`2001:DB8:1111:2200::/56`".

My network doesn't fall on a 16 bit boundary so I can't just specify "`2001:DB8:1111:22`" as this is actually "`2001:0DB8:1111:0022::/64`".  Nor can I specify "`2001:DB8:1111:2200`" as this is just the first network of a block of 256 /64 networks.

In the absence of any other information I have it working by having 256 entries in my access file (`2001:DB8:1111:2200` through `2001:DB8:1111:22FF`) but this is less than ideal.

Does anyone know if there's a patch to allow non-16 bit boundaries to be specified in access?

Thanks,
Scott


----------



## SirDice (Jan 6, 2020)

Have you tried `2001:DB8:1111:2200::/56`?


----------



## scotia (Jan 6, 2020)

SirDice said:


> Have you tried `2001:DB8:1111:2200::/56`?



Swing and a miss...

As per my OP:

"I need to specify an IPv6 prefix ... using CIDR notation and it doesn't ... work ..."


----------



## SirDice (Jan 6, 2020)

Look closely, 2001:DB8:1111:2200 is not valid, 2001:DB8:1111:2200:: is (note the two colons at the end), hence the CIDR notation is 2001:DB8:1111:2200::/56.


----------



## scotia (Jan 6, 2020)

SirDice said:


> Look closely, 2001B8:1111:2200 is not valid, 2001B8:1111:2200:: is.



True, well spotted.  That's actually what I tried (I have edited the OP).

Thanks.


----------



## SirDice (Jan 6, 2020)

If I read the documentation correctly you can't use CIDR at all (not even for IPv4): https://www.sendmail.org/~ca/email/doc8.12/cf/m4/anti_spam.html#access_db

But that may have changed, I couldn't find the documentation for the exact same version we have.


----------



## scotia (Jan 7, 2020)

That's my understanding.  Hence the post.  It seems remiss not to be able to specify CIDR formatted addresses.  The current format was fine for classful routing 30 years ago but being restricted to byte (or double-byte) boundaries is frustrating.


----------



## SirDice (Jan 7, 2020)

scotia said:


> The current format was fine for classful routing 30 years ago but being restricted to byte (or double-byte) boundaries is frustrating.


Yeah, depending on your needs you may be better off with Exim or Postfix. I've set up Exim many years ago for my own domain, nothing fancy though, just some spam and malware filtering.


----------



## scotia (Jan 7, 2020)

SirDice said:


> you may be better off with Exim or Postfix



Maybe, but I'm too invested in sendmail (and have been since I started using FreeBSD 4 - since it came with sendmail).

I found this excerpt from a developer (Per Hedeland) in response to a question about why CIDR is not supported:
https://www.proofpoint.com/sites/default/files/sendmail_open_source_faqs_0.pdf

_Because it is in general very expensive to do this. Here's an explanation from Per Hedeland:
And not just more complex, it would have to do many more (comparatively expensive) lookups - there's no way, given (e.g.) the IP address 66.205.192.123, to find the matching "66.205.192.0/19" with a single lookup in a general key/value hashed map. The code would have to look for "66.205.192.123", "66.205.192.122/31", "66.205.192.120/30", "66.205.192.120/29", etc, etc - 14 lookups to find a /19, 32 to establish a non-match.
which is 8 times more than the available octet boundary lookup.
I haven't done any measurements, but I wouldn't be surprised if even in the absolute worst case, that your map is 128 times bigger than it "needs" to be, the time for a single lookup won't even double - i.e. you'll lose already on the second lookup._

I can see the argument, as the CIDR match would need to be done by sendmail, rather than a key/value match in the DB.  I've just been looking at the source code and doing some debugging.  Here's some debug (note that I use LDAP and access.db for my access database):


```
seq_map_lookup(access, IPv6:2001:DB8:1111:2201:0:0:ff01:120)
ldapmap_lookup(ldap, IPv6:2001:DB8:1111:2201:0:0:ff01:120)
db_map_lookup(local, IPv6:2001:DB8:1111:2201:0:0:ff01:120)
seq_map_lookup(access, IPv6:2001:DB8:1111:2201:0:0:ff01)
ldapmap_lookup(ldap, IPv6:2001:DB8:1111:2201:0:0:ff01)
db_map_lookup(local, IPv6:2001:DB8:1111:2201:0:0:ff01)
seq_map_lookup(access, IPv6:2001:DB8:1111:2201:0:0)
ldapmap_lookup(ldap, IPv6:2001:DB8:1111:2201:0:0)
db_map_lookup(local, IPv6:2001:DB8:1111:2201:0:0)
...
```

You can see how it iterates by shortening the IPv6 address at ':' boundaries.

In my case I need 256 entries in LDAP (to cover the 8 bits between my allocated /56 and the next 16-bit boundary /64).  However this means a maximum of 5 lookups (as it goes from /128, /112, /96, /80, /64) where the heavy lifting is done my the DB.  Annoying to set up initially but fairly efficient from a lookup perspective.

To go to CIDR would require significant changes and you'd no longer be able to text match against the databases.  You'd need to load all of the maps into memory at startup (and when a map changed) and do the CIDR match in sendmail.  Not fun.

I'll live with what I have 

Thanks


----------



## SirDice (Jan 7, 2020)

scotia said:


> In my case I need 256 entries in LDAP (to cover the 8 bits between my allocated /56 and the next 16-bit boundary /64). However this means a maximum of 5 lookups (as it goes from /128, /112, /96, /80, /64) where the heavy lifting is done my the DB. Annoying to set up initially but fairly efficient from a lookup perspective.


I thought about doing the reverse, allow a large range and reject a bunch of the smaller ranges. But in your case that would probably result in a much longer list.


----------



## scotia (Jan 7, 2020)

If I understand you correctly, that won't work for me as I am allowing RELAY for internal hosts, but want other hosts (on the Internet) to submit mail.  I therefore can't do a wide REJECT with a smaller RELAY.


----------



## SirDice (Jan 7, 2020)

scotia said:


> that won't work for me as I am allowing RELAY for internal hosts, but want other hosts (on the Internet) to submit mail.


You often find larger setups that split this up, one mail host handles egress mail (outgoing) and another mail host handles ingress mail (incoming) with everything getting passed  to/from a central (internal) mail server. This is often done because ingress and egress mail is handled differently and splitting them up makes this a lot easier to do.


----------

