haraka / Haraka

A fast, highly extensible, and event driven SMTP server
https://haraka.github.io
MIT License
5.11k stars 660 forks source link

Localhost mail loop problem #2809

Closed analogic closed 3 years ago

analogic commented 4 years ago

I am trying to solve kind of configuration problem - it is not Haraka issue per se

There are multiple servers which returns MX as 0.0.0.0 or 127.0.0.1, or other "problematic" IPs. What happens is that Haraka will deliver to itself and relay via outbound again. It depends on added headers but after ±100 deliveries Haraka will reject mail as looped mail.

Thing is that malicious user can easily induce dos with this kind of behaviour. Only solution I've come up is kind of hacky with abusing metadata in headers. Am I missing something?

analogic commented 4 years ago

It is easily testable with sending email to test@yeah.com

msimerson commented 4 years ago

Well, that's unpleasant. This requires some careful consideration. Here's a quick (probably not completely thought through) idea for blocking those:

  1. when a connection arrives on a public IP address
  2. and the MX for the MAIL FROM resolves to a private IP address
  3. reject
analogic commented 4 years ago

I've end up monkey patching mx_lookup.js with condition to add resolved mx only if it is not "local":

if (addresses[i].exchange !== '0.0.0.0' && addresses[i].exchange !== '::' && !net_utils.is_local_ip(addresses[i].exchange)) {

It works but it is far from ideal solution. What about to add something like filter_mxs hook?

celesteking commented 4 years ago

Yeah, some sort of hook_found_mx. Another idea would be having configurable list of "bad" networks where sending a [relayed] message would trigger a defer, and after some configurable time, a bounce. That way you give external sysadmins time to fix their misconfigs.

msimerson commented 3 years ago

@analogic , how about just adding those two special "any" IPs to the is_local_ip test? See the open PR.

DoobleD commented 3 years ago

Hi @msimerson! The issue is still arising with Haraka latest stable release 2.8.27, using haraka-net-utils 1.3.0 which includes the fix. I made sure my installation did have the changes from 5823e52 and it does.

Or at least I got the same symptoms, I can't 100% be sure the cause is the same. But applying the monkey patch from @analogic solved the issue for me.

msimerson commented 3 years ago

Hi @DoobleD , please include some details, like an example of a message and exactly which IP caused the issue. The PR only added RFC 5735 (test IPs), 0.0.0.0, and '::' to the local test. There might be other IPs that need adding, or perhaps just adding them to that test is insufficient.

DoobleD commented 3 years ago

Thanks for getting back to me @msimerson. Sure! I looked at it more closely and it seems it happened on 0.0.0.0, for domain yeah.com actually, exactly like in the example mentioned by analogic.

Here are the Haraka logs:

[outbound] [INFO] - Attempting to deliver to: 0.0.0.0:25 (0) (0)
...
[outbound] [NOTICE] - delivered file=1620042680562_1620042680562_0_4574_1basJo_1097_<obfuscated> domain=yeah.com host=0.0.0.0 ip=0.0.0.0 port=25 mode=SMTP tls=Y auth=N response="Message Queued (7786A502-1985-4479-976B-602DAB154015.1 )" delay=0.512 fails=0 rcpts=1/0/0

This is just for one cycle but I've got tons of those, as the delivery to itself repeats in a loop. It generates a growing email getting huge after a while (I stopped it at 23MB), coming back in queue again and again. Within the email there are a ton of headers like this one:

Received: from localhost (Unknown [127.0.0.1])
    by <obfuscated> (Haraka/2.8.27) with ESMTPSA id 038A9AF8-F8F2-4B07-924F-006D60D71447.1
    envelope-from <noreply@<obfuscated>> (authenticated bits=0)
    (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256);
    Mon, 03 May 2021 11:51:19 +0000
...

And a ton of:

dkim=fail (body hash did not verify) header.i=@<obfuscated>; dkim=fail (body hash did not verify) header.i=@<obfuscated>; dkim=fail (body hash did not verify) header.i=@<obfuscated>; dkim=fail (body hash did not verify) header.i=@<obfuscated>; dkim=fail (body hash did not verify) header.i=@<obfuscated>; dkim=fail (body hash did not verify) header.i=@<obfuscated>; dkim=fail (body hash did not verify) header.i=@<obfuscated>; dkim=fail (body hash did not verify) header.i=@<obfuscated>;
...

Those are why the email is getting so large. Haraka is also printing a lot of warning logs, taking a large amount of CPU while this happens.

Is this of any help? I'm really not sure why this still happens if the PR took care of the 0.0.0.0 case. But I'm sure I have the PR fix in my Haraka installation, and it happened anyway. When I added analogic's fix, it stopped right away. I'm not familiar with Haraka's code but I'll try to have a closer look at the PR to see if I can find something.

msimerson commented 3 years ago

I think I see the issue. The PR that closed this only did part of the needful–it included the additional IPs from @analogic's monkey patch into net_utils.is_local_ip() so that you could do this:

if (!net_utils.is_local_ip(addresses[i].exchange)) {

instead of:

if (addresses[i].exchange !== '0.0.0.0' && addresses[i].exchange !== '::' && !net_utils.is_local_ip(addresses[i].exchange)) {
DoobleD commented 3 years ago

@msimerson yes that seems to be it. :)