r-raymond / nixos-mailserver

A complete and Simple Nixos Mailserver
GNU General Public License v3.0
181 stars 27 forks source link

Avoid accepting mail to xyz@localhost from remote systems #101

Closed tokudan closed 6 years ago

tokudan commented 6 years ago

This prevents accepting emails addressed to xyz@localhost and thus avoids detecting valid account names from remote systems. This does not affect email that is sent e.g. through the sendmail command, but the target addresses (or the two localhost and $myhostname domain) should be aliased to other users, or they will bounce and the bounce deleted, as it's not deliverable.

r-raymond commented 6 years ago

Thanks for pointing this out. We had this because a user wanted to use the same fqdn as one of the domains. @eqyiel is this still necessary with the new setup where the users are not system users anymore?

phdoerfler commented 6 years ago

Two users, actually. I just never mentioned it and only changed mydestination locally. This being said I am currently using a mail. subdomain for my mail server (hesitantly however for various reasons).

I got two questions about this PR:

  1. Does this still allow local delivery to users? Say I got a cron job which sends mails to root@localhost, hardcoded. I have that aliased to one of my virtual users. Would this be affected by this PR?
  2. (this one is already mentioned) with this PR in place can we still have a fqdn that equals a domain? Meaning can we have our mail server run at example.com instead of mail.example.com?

Also thanks for pointing this out! This (and the backscatter issue recently) just confirms how beneficial it is to have multiple people look at a mail server's config.

tokudan commented 6 years ago

@phdoerfler Postfix has multiple transports, depending of where the domain is configured, postfix puts it into that transport's queue. Roughly it's like this, if I've understood the postfix documentation correctly: domain in mydestination? -> it's for a local system user with that exact name domain in virtual_alias_domains? -> need to use an alias table to figure out the real local system user to deliver the email to domain in virtual_mailbox_domains? -> need to use an arbitrary table to figure out where to store it.

As nixos-mailserver is only using virtual mailboxes, in my opinion it should not accept emails from the outside targeted at anything but the configured domains. Having an empty mydestination causes postfix to not accept emails to its local hostname or localhost. If emails to those accounts are sent from an authorized sender (e.g. cron or other local services), postfix will treat them as email that will leave the system and start to lookup the actual mailserver to send these mails to. Localhost will obviously cause a mail loop and thus cause the email to generate a bounce and the bounce will be discarded, as it's undeliverable as well. E-Mails directed at the hostname of the server (be that myserver or myserver.example.com), will cause a DNS lookup for an MX and then A record to try to deliver the email to the correct server. If there is no MX record, this will very likely be another mail loop that will be handled the same way as localhost. The simple solution is: Create an alias for the domains localhost, myserver and myserver.example.com and point these aliases to the actual virtual mailboxes that should receive the emails. Basically that's what I suggest in #102. The result of that configuration is:

tokudan commented 6 years ago

@phdoerfler So to actually answer your questions:

Does this still allow local delivery to users? Say I got a cron job which sends mails to root@localhost, hardcoded. I have that aliased to one of my virtual users. Would this be affected by this PR?

Since you already have these aliases configured, they should work. What does not happen anymore is that mail is delivered locally to /var/spool/mail/$user.

with this PR in place can we still have a fqdn that equals a domain? Meaning can we have our mail server run at example.com instead of mail.example.com?

Yes, as long as example.com is listed among your receiving domains. With this PR you get the bonus that emails addressed to root@example.com will bounce by default instead of going to /var/spool/mail/root, if you do not have an alias.

phdoerfler commented 6 years ago

@tokudan Very interesting! Thanks for this detailed explanation.

I am a bit puzzled about this part:

Having an empty mydestination causes postfix to not accept emails to its local hostname or localhost. If emails to those accounts are sent from an authorized sender (e.g. cron or other local services), postfix will treat them as email that will leave the system and start to lookup the actual mailserver to send these mails to.

I have observed that the mailserver does differentiate between mails outside and mails that come from the same systen (such as cron jobs) or authorized sources (such as an imap client) respectively. Especially rspamd is very verbose about it and denots in the logs that it's skipping spam checks for a particular email because it is a locally delivered one / authorized one. I am not sure what part postfix plays in this "it's cool, it's a local mail, let it through" mechanism but I would very much like to keep that. If I understand this correctly this change would make postfix treat local mail the same way as remote mail, thus undergoing spam checks and possible rejection and all that jazz. Since the output of say cron jobs does not normally resemble a mail written by a person I am worried rspamd might wrongly classify it as spam or bounce it alltogether. Is that correct? If so, I would much rather accept mail from remote going to localhost than having to give up this differentiation. But that might just be me.

tokudan commented 6 years ago

Here's a test script I use to verify that my mailserver works as expected: https://gist.github.com/tokudan/7a91cdfffd3b792a998d4aaa7337d949 Run from the outside. To create a local mail you could take one of the templates that the script displays and run something like:

$ sendmail -t root@localhost <<EOF
From: <root@localhost>
To: <root@localhost>
Date: Mon, 12 Mar 2018 21:20:42 +0100
Subject: Yet another test

random test email
.
EOF
tokudan commented 6 years ago

I actually just noticed that for some reason an alias root@example.com -> realaccount works. but @example.com -> realaccount does not. So this needs some more thought.

tokudan commented 6 years ago

In the current configuration though, mail that's received locally does not go through spam filtering, as the input does not come from smtpd.

phdoerfler commented 6 years ago

Does it not? My logs indicate otherwise (see https://github.com/r-raymond/nixos-mailserver/issues/65):

Feb 02 15:31:34 nixos postfix/smtpd[24067]: connect from localhost[::1]
tokudan commented 6 years ago

I saw something unexpected in my logs when I ran some tests, but didn't investigate further, as I didn't have time. Quite possible that I misread something in the logs, but double-checking is better than breaking something. I'll have a deeper look today or tomorrow.

r-raymond commented 6 years ago

Let me know when you consider this done, so I can take a look at it again.

tokudan commented 6 years ago

Will do. I haven't forgotten it, this PR. The last couple of days' planning got thrown around a lot...

tokudan commented 6 years ago

Sorry for the delay in working on this. The below points should address the points raised so far. I believe this can be merged.

Two mails sent by the local root account and their logs:

The following tests have been made with
loginAccounts."someone@anotherexample.com".aliases = [ "@freya.example.com" ];

# sendmail -t someone@anotherexample.com
Subject: Test

Test
.

#

Relevant logs for that email:
Apr 02 18:43:35 freya postfix/pickup[28825]: D970C72A0E6: uid=0 from=<root>
Apr 02 18:43:35 freya postfix/cleanup[7854]: D970C72A0E6: message-id=<20180402164335.D970C72A0E6@freya.example.com>
Apr 02 18:43:35 freya postfix/qmgr[13872]: D970C72A0E6: from=<root@freya.example.com>, size=290, nrcpt=1 (queue active)
Apr 02 18:43:35 freya dovecot[12467]: lmtp(7857): Connect from local
Apr 02 18:43:35 freya dovecot[12467]: lmtp(someone@anotherexample.com): qPPlN7ddwlqxHgAA45U+EQ: sieve: msgid=<20180402164335.D970C72A0E6@freya.example.com>: stored mail into mailbox 'INBOX'
Apr 02 18:43:35 freya postfix/lmtp[7856]: D970C72A0E6: to=<someone@anotherexample.com>, relay=freya.example.com[private/dovecot-lmtp], delay=8.4, delays=8.4/0.01/0.01/0.05, dsn=2.0.0, status=sent (250 2.0.0 <someone@anotherexample.com> qPPlN7ddwlqxHgAA45U+EQ Saved)
Apr 02 18:43:35 freya dovecot[12467]: lmtp(7857): Disconnect from local: Successful quit
Apr 02 18:43:35 freya postfix/qmgr[13872]: D970C72A0E6: removed

# sendmail -t root
Subject: Test
Test
.
#

Relevant logs for that email:
Apr 02 18:45:53 freya postfix/pickup[28825]: A20E172A0E6: uid=0 from=<root>
Apr 02 18:45:53 freya postfix/cleanup[8697]: A20E172A0E6: message-id=<20180402164553.A20E172A0E6@freya.example.com>
Apr 02 18:45:53 freya postfix/qmgr[13872]: A20E172A0E6: from=<root@freya.example.com>, size=290, nrcpt=1 (queue active)
Apr 02 18:45:53 freya dovecot[12467]: lmtp(8700): Connect from local
Apr 02 18:45:53 freya dovecot[12467]: lmtp(someone@anotherexample.com): eEdRK0Fewlr8IQAA45U+EQ: sieve: msgid=<20180402164553.A20E172A0E6@freya.example.com>: stored mail into mailbox 'INBOX'
Apr 02 18:45:53 freya postfix/lmtp[8699]: A20E172A0E6: to=<someone@anotherexample.com>, orig_to=<root>, relay=freya.example.com[private/dovecot-lmtp], delay=7.3, delays=7.2/0.01/0.01/0.05, dsn=2.0.0, status=sent (250 2.0.0 <someone@anotherexample.com> eEdRK0Fewlr8IQAA45U+EQ Saved)
Apr 02 18:45:53 freya dovecot[12467]: lmtp(8700): Disconnect from local: Successful quit
Apr 02 18:45:53 freya postfix/qmgr[13872]: A20E172A0E6: removed
r-raymond commented 6 years ago

Sounds great. I vote for merging asap.

@phdoerfler are your concerns addressed?

phdoerfler commented 6 years ago

@r-raymond Yes, I suppose this will do.

r-raymond commented 6 years ago

Thanks again!