Fake 127.0.0.1 for connections from listening IPs

This commit is contained in:
PJ Eby 2020-04-15 20:24:48 -04:00
parent 333667db8c
commit 4b6a1839fb
4 changed files with 32 additions and 0 deletions

View file

@ -94,6 +94,7 @@ Take note of the following, however:
* The listening IPs must *not* have any other services listening on ports 25, 80, 110, 143, 443, 466, 587, 993, 995, or 4190. (Though you can change or disable some of those ports using poste.io's environment variables.)
* You should be using **host-mode networking** (`network_mode: host` as shown above), since in any other networking mode, this image will behave roughly the same as the original `analogic/poste.io` image, and have the same limitations and caveats. (Specifically, using any other networking mode means putting specific IP addresses into `LISTEN_ON`, `SEND_ON`, or `outbound-hosts.yml` will not do anything useful!)
* By default, outgoing email to other mail servers will be sent via the first IP address found in `LISTEN_ON` or returned by running `hostname -i` in the container. If you need to override this behavior, configure the container with `SEND_ON` set to the specific IP address to be used, OR create a `/data/outbound-hosts.yml` file as described in [Managing Sender IPs](#managing-sender-ips) below.
* Connections *from* a listening IP will be treated as if they are connections from 127.0.0.1 (because they are from the local host) unless you're using `LISTEN_ON=*` mode. This disables certain host-specific spam checks (e.g. asn, fcrdns, karma/history, etc.), that would otherwise apply. This special behavior is *not* enabled for IPs that are used only for outgoing mail transmission; such IPs will be treated as normal unless you explicitly add them to your relay networks list.
Notice, by the way, that there are **no port mappings** used in this example, because the container uses host-mode networking and thus has direct access to all of the server's network interfaces. This means that the IP addresses to be used by the container must be explicitly defined (either by the DNS address(es) of the hostname, or by setting the `LISTEN_ON` variable to the exact IP addresses) so that the container doesn't take over every IP address on the server. (Unless that's what you *want*, in which case you can set `LISTEN_ON` to `*`.)

View file

@ -54,6 +54,8 @@ fi
if [[ $listen != *'*'* ]]; then
sub '^listen=.*:25$' "listen=${listen//,/:25,}:25" /opt/haraka-smtp/config/smtp.ini
sub '^listen=.*:587,.*:465$' "listen=${listen//,/:587,}:587,${listen//,/:465,}:465" /opt/haraka-submission/config/smtp.ini
else
listen=::0
fi
# Our Haraka sender-ip control plugin will validate outgoing IPs against the
@ -62,3 +64,8 @@ fi
echo "$send" >/opt/haraka-submission/config/my-ips
echo "$send" >/opt/haraka-smtp/config/my-ips
# Our inbound IP plugin will translate local connections to 127.0.0.1
echo "$listen" >/opt/haraka-submission/config/listen-ips
echo "$listen" >/opt/haraka-smtp/config/listen-ips

View file

@ -0,0 +1,21 @@
'use strict';
/*****
This plugin detects local connections from listening IPs, and changes the remote
IP to 127.0.0.1, simulating a local connection. Many of poste.io's plugins
have 127.0.0.1 hardcoded for special handling that otherwise might not be applied
when using this image.
*****/
const listening_ips = require("haraka-config").get("listen-ips").trim().split(/\s*,\s*/);
const is_local = listening_ips.reduce((map, addr)=>{map[addr]=true; return map;}, {});
exports.hook_connect_init = function(next, connection) {
if ( is_local[connection.remote.ip] ) {
this.logdebug(`localhost connection from ${connection.remote.ip}`);
connection.remote.ip = '127.0.0.1';
}
return next();
}

View file

@ -66,6 +66,9 @@ shopt -q expand_aliases||{ unalias -a;shopt -s expand_aliases;};builtin alias +=
}}
~ edit /opt/haraka-{smtp,submission}/config/plugins; {{
# Fake remote IP to 127.0.0.1 when connection is from localhost
- after "status_http" \
"inbound_ips"
# Add our outbound IP routing plugin
- append 'outbound_ips'
}}