Score:0

Trying to forward SMTP port on strongswan IPsec tunneled docker container?

za flag

I have successfully setup a vpn tunnel with strongswan within a docker container and want to use that tunneled connection to forward specific ports like SMTP to a host on the other side of the tunnel, in my case host 10.0.0.10.

The goal would be to be able to use SMTP in my app directly by connecting to strongswan-container service in the middle like this

(smtp-host)-[IPSec-tunnel]-(strongswan-container [exposes port 25 and forwards everything to tunneled smtp-host])-[some-docker-network]-(my-mail-sending-app-container [calls strongswan-container:25 for smtp])

after reading some docs about this I tried these iptables commands on the strongswan-container but with no success:

iptables -t nat -A PREROUTING  -p tcp --dport 25 -j DNAT --to-destination 10.0.0.10:25
iptables -t nat -A POSTROUTING -p tcp -d 10.0.0.10 --dport 25 -j MASQUERADE

on the my-mail-sending-app-container I tried running

telnet strongswan-container 25

but it would simply wait for a response until timeout.

What is the problem with my iptables command?

iptables-save output after strongswan has connected to the tunnel:

root@14d43f1e2f55:/# iptables-save
# Generated by iptables-save v1.8.4 on Thu Jul 22 16:25:04 2021
*filter
:INPUT ACCEPT [1:112]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1:112]
-A INPUT -s 10.0.0.0/16 -d 192.168.112.2/32 -i eth0 -m policy --dir in --pol ipsec --reqid 1 --proto esp -j ACCEPT
-A OUTPUT -s 192.168.112.2/32 -d 10.0.0.0/16 -o eth0 -m policy --dir out --pol ipsec --reqid 1 --proto esp -j ACCEPT
COMMIT
# Completed on Thu Jul 22 16:25:04 2021
# Generated by iptables-save v1.8.4 on Thu Jul 22 16:25:04 2021
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [2:1600]
:POSTROUTING ACCEPT [2:1600]
:DOCKER_OUTPUT - [0:0]
:DOCKER_POSTROUTING - [0:0]
-A OUTPUT -d 127.0.0.11/32 -j DOCKER_OUTPUT
-A POSTROUTING -d 127.0.0.11/32 -j DOCKER_POSTROUTING
-A DOCKER_OUTPUT -d 127.0.0.11/32 -p tcp -m tcp --dport 53 -j DNAT --to-destination 127.0.0.11:46701
-A DOCKER_OUTPUT -d 127.0.0.11/32 -p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.11:58024
-A DOCKER_POSTROUTING -s 127.0.0.11/32 -p tcp -m tcp --sport 46701 -j SNAT --to-source :53
-A DOCKER_POSTROUTING -s 127.0.0.11/32 -p udp -m udp --sport 58024 -j SNAT --to-source :53
COMMIT
# Completed on Thu Jul 22 16:25:04 2021

my ipsec.conf:

config setup
     strictcrlpolicy=no
     uniqueids=no

# left is local by default, left and right otherwise dynamically detected
conn %default

conn "ezvpn"
    keyexchange=ikev2
    aggressive=yes
    ike=(some-ciphers)     # Phase1 parameters
    esp=(some-ciphers)              # Phase2 parameters
    left=192.168.112.2         # local IP used to connect to IOS
    leftid=12.123.123.1                 # IKEID (group name) used for IOS
    leftfirewall=yes
    leftauth=psk
    rightauth=psk
    fragmentation=yes
    right=12.123.123.2        #gateway (IOS) IP
    rightsubnet=10.0.0.0/16
    rightfirewall=yes
    auto=route
    type=tunnel
    ikelifetime=180m
    keylife=60m
cn flag
Can you actually reach the SMTP host (`10.0.0.10`) from the strongSwan container? Does the container expose port 25 (via `EXPOSE` or `--expose`) or maybe even publish it?
za flag
@ecdsa yes to both, issue is not docker related, just mentioned it because of the extra iptables settings
Score:0
za flag

I solved it by installing traefik into my strongswan container and then using the TCP routing capabilities of traefik to expose the tunneled port internally.

Dockerfile (I am fully aware that this can be achieved using alpine as well):

FROM ubuntu


RUN apt update && apt-get install -yf wget iputils-ping telnet strongswan iptables \
    && ln -sf /conf/ipsec.conf /etc/ipsec.conf \
    && ln -sf /conf/ipsec.secrets /etc/ipsec.secrets \
    && echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf \
    && wget -O /traefik.tar.gz https://github.com/traefik/traefik/releases/download/v2.4.12/traefik_v2.4.12_linux_amd64.tar.gz \
    && tar -zxvf /traefik.tar.gz \
    && ln -s /traefik /usr/bin/traefik


COPY docker-entrypoint.sh /entrypoint.sh
COPY /strongswan /conf
COPY /traefik-conf /traefik-conf

CMD ["/entrypoint.sh"]

My entrypoint.sh:

#!/bin/sh -e

{
    # wait to make sure ipsec is started when upping the tunnel
    sleep 2
    ipsec up ezvpn
    traefik --configfile /traefik-conf/traefik.yml
} &

exec ipsec start --nofork "$@"

traefik-conf/traefik.yml:

# https://doc.traefik.io/traefik/routing/entrypoints/
entryPoints:
  smtp:
    address: ":1025" # the port that listens within the docker network

accessLog: {}

providers:
  file:
    directory: /traefik-conf/dynamic/
    # I use dynamic configurations for local development
    watch: true

api:
  dashboard: true
  insecure: true

/traefik-conf/dynamic/dynamic.yml:

tcp:
  # https://doc.traefik.io/traefik/routing/routers/#rule_1
  routers:
    smtp-router:
      rule: "HostSNI(`*`)"
      entryPoints:
        - smtp
      service: smtp-service

  # https://doc.traefik.io/traefik/routing/routers/#services
  services:
    smtp-service:
      loadBalancer:
        servers:
          - address: 10.0.0.1:25 # replace with your target IP & service port

See here for the full example.

fjch1997 avatar
us flag
I have the same issue but this wouldn't work for UDP
za flag
@fjch1997 you need to take a look at the traefik documentation. My example shows TCP only but it can also be adjusted for UDP .
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.