yrutschle / sslh

Applicative Protocol Multiplexer (e.g. share SSH and HTTPS on the same port)

Home Page:https://www.rutschle.net/tech/sslh/README.html

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Docker: Transparent mode not working

Ratfiend opened this issue · comments

Hello,

I am using docker for running sslh. This works without problems.

Working config:
sudo docker create --name=sslh -p 192.168.178.56:443:443 -e TZ=Europe/Berlin --restart=unless-stopped ghcr.io/yrutschle/sslh:master --foreground --listen=0.0.0.0:443 --tls=192.168.178.56:9443 --ssh 192.168.178.55:22
sudo docker container start sslh

Now I want to extend my config and use the transparent mode (as I understand it from the documentation):
sudo docker create --name=sslh --cap-add CAP_NET_RAW -p 192.168.178.56:443:443 -e TZ=Europe/Berlin --restart=unless-stopped ghcr.io/yrutschle/sslh:master --foreground --transparent --listen=0.0.0.0:443 --tls=192.168.178.56:9443 --ssh 192.168.178.55:22
sudo docker container start sslh

But this is not working. When I check the logs with sudo docker logs sslh I got the following output:

--transparent is set
Configuring iptables and routing...
iptables v1.8.9 (legacy): can't initialize iptables table 'raw': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
iptables v1.8.9 (legacy): can't initialize iptables table 'mangle': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
getsockopt failed strangely: Operation not permitted
getsockopt failed strangely: Operation not permitted
ip: RTNETLINK answers: Operation not permitted
ip: RTNETLINK answers: Operation not permitted
ip: RTNETLINK answers: Operation not permitted
ip: RTNETLINK answers: Operation not permitted
executing with user 'sslh': sslh --foreground --transparent --listen=0.0.0.0:443 --tls=192.168.178.56:9443 --ssh 192.168.178.55:22
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
ip6tables v1.8.9 (legacy): can't initialize ip6tables table 'raw': Table does not exist (do you need to insmod?)
Perhaps ip6tables or your kernel needs to be upgraded.
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
ip6tables v1.8.9 (legacy): can't initialize ip6tables table 'mangle': Table does not exist (do you need to insmod?)
Perhaps ip6tables or your kernel needs to be upgraded.
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
ip6tables v1.8.9 (legacy): unknown option "--set-xmark"
Try `ip6tables -h' or 'ip6tables --help' for more information.
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
ip6tables v1.8.9 (legacy): can't initialize ip6tables table 'mangle': Table does not exist (do you need to insmod?)
Perhaps ip6tables or your kernel needs to be upgraded.

I played a little bit with the init script. My guess is, when executing the container-entrypoint.sh the first time with root, everything is fine. In the second itaration when dropping privileges the sslh user is not allowed to do this.
# Drop privileges and run as sslh user
sslh_cmd="${entrypoint:+${bin}} ${@}"
echo "Executing with user 'sslh': ${sslh_cmd}"

Does anybody have an idea what could possibly go wrong here?

Hi, can you see #390 and #392. There some clarification and updates to the documentaion that may help.

In my case the problem seems to be the absence of ipv6 as I only use ipv4. So I need to wait for the merge of #392, I guess.

Edit:
After commenting out the 6 ipv6 lines in init file, the log shrunk a bit:

--transparent is set
Configuring iptables and routing...
iptables v1.8.9 (legacy): can't initialize iptables table 'raw': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
iptables v1.8.9 (legacy): can't initialize iptables table 'mangle': Permission denied (you must be root)
Perhaps iptables or your kernel needs to be upgraded.
getsockopt failed strangely: Operation not permitted
getsockopt failed strangely: Operation not permitted
ip: RTNETLINK answers: Operation not permitted
ip: RTNETLINK answers: Operation not permitted
executing with user 'sslh': sslh --foreground --transparent --listen=0.0.0.0:444 --tls=192.168.178.56:9443 --ssh 192.168.178.55:22

But the sslh user (Permission denied) problem still exists.

you need to add --cap-add CAP_NET_ADMIN to be able to add iptables and routing rules

--tls=192.168.178.56:9443 --ssh 192.168.178.55:22

will likey not work with transparent mode. For the transparent mode to work in docker, sslh must be in the same host as your https service (i.e. reachable by localhost).

So either you will need to use --network="container:sslh" to your other container or set your --network="host" for sslh

After some infrastructure changes the following config without --transparent parameter works:
sudo docker create --name=sslh --net=host --cap-add CAP_NET_RAW --cap-add CAP_NET_ADMIN -e TZ=Europe/Berlin --restart=unless-stopped ghcr.io/yrutschle/sslh:master --foreground --listen=0.0.0.0:4433 --tls=127.0.0.1:443 --ssh 127.0.0.1:22
sslh is working as expected 👍

And I pulled the new docker image with the changes of #392.

(Due to github comment formatting I added ' to the +. '+ means +)

When I add the --transparent parameter the log is now more verbose and showing this:
sudo docker logs sslh

--transparent flag is set
'+ iptables -t raw -A PREROUTING '!' -i lo -d 127.0.0.0/8 -j DROP
Configuring iptables and routing...
'+ iptables -t mangle -A POSTROUTING '!' -o lo -s 127.0.0.0/8 -j DROP
'+ iptables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f
'+ iptables -t mangle -A OUTPUT '!' -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f
'+ ip rule add fwmark 0x1 lookup 100
'+ ip route add local 0.0.0.0/0 dev lo table 100
'+ cat /proc/sys/net/ipv6/conf/all/disable_ipv6
'+ '[' 0 -eq 0 ]
'+ ip6tables -t raw -A PREROUTING '!' -i lo -d ::1/128 -j DROP
modprobe: can't change directory to '/lib/modules': No such file or directory
ip6tables v1.8.9 (legacy): can't initialize ip6tables table 'raw': Table does not exist (do you need to insmod?)
Perhaps ip6tables or your kernel needs to be upgraded.
'+ ip6tables -t mangle -A POSTROUTING '!' -o lo -s ::1/128 -j DROP
modprobe: can't change directory to '/lib/modules': No such file or directory
ip6tables v1.8.9 (legacy): can't initialize ip6tables table 'mangle': Table does not exist (do you need to insmod?)
Perhaps ip6tables or your kernel needs to be upgraded.
'+ ip6tables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
ip6tables v1.8.9 (legacy): unknown option "--set-xmark"
Try 'ip6tables -h' or 'ip6tables --help' for more information.
'+ ip6tables -t mangle -A OUTPUT '!' -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
modprobe: can't change directory to '/lib/modules': No such file or directory
ip6tables v1.8.9 (legacy): can't initialize ip6tables table `mangle': Table does not exist (do you need to insmod?)
Perhaps ip6tables or your kernel needs to be upgraded.
'+ ip -6 rule add fwmark 0x1 lookup 100
'+ ip -6 route add local ::/0 dev lo table 100
'+ set -e
Executing with user 'sslh': sslh --foreground --transparent --listen=0.0.0.0:4433 --tls=127.0.0.1:443 --ssh 127.0.0.1:22

The new adding if [ $(cat /proc/sys/net/ipv6/conf/all/disable_ipv6) -eq 0 ]; then is somehow split ( '+ '[' 0 -eq 0 ] ).
I think this behaviour is not as expected.
Especially as the ipv6 blocks are executed.
I'm not an expert but aren't the " missing here?
Like this: if [ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6)" -eq 0 ]; then

Anyway, when I comment the ipv6 lines out and restart the container, the logs reporting this:

--transparent flag is set
Configuring iptables and routing...
'+ iptables -t raw -A PREROUTING '!' -i lo -d 127.0.0.0/8 -j DROP
'+ iptables -t mangle -A POSTROUTING '!' -o lo -s 127.0.0.0/8 -j DROP
'+ iptables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f
'+ iptables -t mangle -A OUTPUT '!' -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f
'+ ip rule add fwmark 0x1 lookup 100
'+ ip route add local 0.0.0.0/0 dev lo table 100
ip: RTNETLINK answers: File exists
'+ set -e
'+ set +x
Executing with user 'sslh': sslh --foreground --transparent --listen=0.0.0.0:4433 --tls=127.0.0.1:443 --ssh 127.0.0.1:22

Both tls and ssh are not functional. Log says:

tls: lost incoming connection
(ssh not even mentioned)

Is this possible what I am trying to achive? I found this in the documentations (I have overlooked that so far):

The firewalling tables also need to be adjusted as follows. I don't think it is possible to have httpd and sslh both listen to 443 in this scheme -- let me know if you manage that

ip: RTNETLINK answers: File exists

This indicate that the old rules were not properly removed which would also mean that the other iptables rules are not removed properly as well. So most likely, the old rules caused the kernel to not mark the packages properly due to this rule:

iptables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f

and resulted in the 'tls: lost incoming connection ' as each time docker restart it will give a different uid for each internal user in the container. That what I think is happening.

Can you also check if your sysctls are set:

net.ipv4.conf.default.route_localnet=1
net.ipv4.conf.all.route_localnet=1

I'm not an expert but aren't the " missing here?
Like this: if [ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6)" -eq 0 ]; then

This is working as expected. It just check if your system (or docker container) has ipv6 enabled. The error "modprobe: can't change directory to '/lib/modules': No such file or directory" is occurring due to missing kernel modules in container. I haven't really looked in to it yet. But if your not using ipv6 it shouldn't affect things too much. edit: it probably requires ipv6 to be enabled in docker. https://docs.docker.com/config/daemon/ipv6/ for it to automatically set ip6tables rules on the host.

Is this possible what I am trying to achive? I found this in the documentations (I have overlooked that so far):

I think so. But if your using the docker the rules should be automatically set and will more or less just work. (If your using host mode u need to set the sysctl manually)

I tried something similar. This is my logs and config:

system-sslh  | --transparent flag is set
system-sslh  | Configuring iptables and routing...
system-sslh  | + iptables -t raw -A PREROUTING '!' -i lo -d 127.0.0.0/8 -j DROP
system-sslh  | + iptables -t mangle -A POSTROUTING '!' -o lo -s 127.0.0.0/8 -j DROP
system-sslh  | + iptables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f
system-sslh  | + iptables -t mangle -A OUTPUT '!' -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f
system-sslh  | + ip rule add fwmark 0x1 lookup 100
system-sslh  | + ip route add local 0.0.0.0/0 dev lo table 100
system-sslh  | + cat /proc/sys/net/ipv6/conf/all/disable_ipv6
system-sslh  | + '[' 0 -eq 0 ]
system-sslh  | + ip6tables -t raw -A PREROUTING '!' -i lo -d ::1/128 -j DROP
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | ip6tables v1.8.9 (legacy): can't initialize ip6tables table `raw': Table does not exist (do you need to insmod?)
system-sslh  | Perhaps ip6tables or your kernel needs to be upgraded.
system-sslh  | + ip6tables -t mangle -A POSTROUTING '!' -o lo -s ::1/128 -j DROP
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | ip6tables v1.8.9 (legacy): can't initialize ip6tables table `mangle': Table does not exist (do you need to insmod?)
system-sslh  | Perhaps ip6tables or your kernel needs to be upgraded.
system-sslh  | + ip6tables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | ip6tables v1.8.9 (legacy): unknown option "--set-xmark"
system-sslh  | Try `ip6tables -h' or 'ip6tables --help' for more information.
system-sslh  | + ip6tables -t mangle -A OUTPUT '!' -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | modprobe: can't change directory to '/lib/modules': No such file or directory
system-sslh  | ip6tables v1.8.9 (legacy): can't initialize ip6tables table `mangle': Table does not exist (do you need to insmod?)
system-sslh  | Perhaps ip6tables or your kernel needs to be upgraded.
system-sslh  | + ip -6 rule add fwmark 0x1 lookup 100
system-sslh  | + ip -6 route add local ::/0 dev lo table 100
system-sslh  | + set -e
system-sslh  | + set +x
system-sslh  | Executing with user 'sslh': sslh --transparent --config=/config/sslh.conf
system-sslh  | tls:connection from 192.168.0.170:60300 to server.local:8443 forwarded from 192.168.0.170:60300 to localhost:https
system-sslh  | ssh:connection from 192.168.0.170:49254 to server.local:8443 forwarded from 192.168.0.170:49254 to localhost:ssh
system-sslh  | tls:connection from 192.168.0.170:49256 to server.local:8443 forwarded from 192.168.0.170:49256 to localhost:https
system-sslh  | tls:connection from 192.168.0.170:43038 to server.local:8443 forwarded from 192.168.0.170:43038 to localhost:https
system-sslh  | tls:connection from 192.168.0.169:43128 to server.local:8443 forwarded from 192.168.0.169:43128 to localhost:https
system-sslh  | tls:connection from 192.168.0.169:43144 to server.local:8443 forwarded from 192.168.0.169:43144 to localhost:https
system-sslh  | tls:connection from 192.168.0.169:43148 to server.local:8443 forwarded from 192.168.0.169:43148 to localhost:https
system-sslh  | tls:connection from 192.168.0.169:43168 to server.local:8443 forwarded from 192.168.0.169:43168 to localhost:https
system-sslh  | ssh:connection from 192.168.0.170:34102 to server.local:8443 forwarded from 192.168.0.170:34102 to localhost:ssh

Docker compose config:

  sslh:
    build: https://github.com/klementng/sslh.git#docker/transparent-patch
    container_name: system-sslh
    environment:
      - TZ=${TZ}
    cap_add:
      - NET_ADMIN
      - NET_RAW
 #   sysctls:
 #     - net.ipv4.conf.default.route_localnet=1
 #     - net.ipv4.conf.all.route_localnet=1
    volumes:
      - ./sslh:/config
#      - /lib/modules:/lib/modules
    command:
      - '--transparent'
#      - '--foreground'
#      - '--listen=0.0.0.0:8443'
#      - '--openvpn=localhost:1194'
#      - '--http=localhost:80'
#      - '--tls=localhost:443'
#      - '--ssh=localhost:22'
#      - '--verbose-probe-info=7'
#      - '--verbose-probe-error=7'
      - '--config=/config/sslh.conf'
#    networks:
#      default:
#        ipv4_address: 172.20.0.50
    network_mode: host
#    ports:
#      - 0.0.0.0:443:8443 #sslh
#      - 0.0.0.0:80:80 #nginx http
    restart: unless-stopped

sslh config file:

foreground: true;
transparent: true;
timeout: 3;

# Logging configuration
# Value: 1: stdout; 2: syslog; 3: stdout+syslog; 4: logfile; ...; 7: all

verbose-config: 0; #  print configuration at startup
verbose-config-error: 7;  # print configuration errors
verbose-connections: 7; # trace established incoming address to forward address
verbose-connections-error: 7; # connection errors
verbose-connections-try: 0; # connection attempts towards targets
verbose-fd: 0; # file descriptor activity, open/close/whatnot
verbose-packets: 0; # hexdump packets on which probing is done
verbose-probe-info: 0; # what's happening during the probe process
verbose-probe-error: 0; # failures and problems during probing
verbose-system-error: 0; # system call problem, i.e.  malloc, fork, failing
verbose-int-error: 0; # internal errors, the kind that should never happen

#logfile: "/config/sslh.log"
logfile: "/dev/null";

listen:
(
    { host: "0.0.0.0"; port: "8443"; },

#    { host: "0.0.0.0"; port: "443"; is_udp: true; },
);

protocols:
(
     { name: "tls"; host: "localhost"; port: "443";},
     { name: "openvpn"; host: "localhost"; port: "1194";},
     { name: "ssh"; host: "localhost"; port: "22"; keepalive: true;},

     { name: "anyprot"; host: "localhost"; port: "443";},

#     { name: "wireguard"; host: "localbox"; port: "51820"; is_udp: true; transparent:false; fork: false},
#     { name: "anyprot"; host: "localbox"; port: "51820"; is_udp: true; transparent:false; keepalive: true},
);

on-timeout: "tls";

Hmm still no luck I'm afraid.

What I did:
Rebuild my config according to your suggestions.
First tried without --transparent and transparent: false; to prove the config.
This is working.

Then I added --transparent and set transparent: true;

(After container creation and bevor first start I commented the ipv6 blocks out, just in case)

sudo docker create --name=sslh --net=host -e TZ=Europe/Berlin --cap-add CAP_NET_RAW --cap-add CAP_NET_ADMIN -v ./config/:/config --restart=unless-stopped ghcr.io/yrutschle/sslh:master --transparent --config=/config/sslh.conf

sslh.conf

foreground: true;
transparent: true;
timeout: 3;

# Logging configuration
# Value: 1: stdout; 2: syslog; 3: stdout+syslog; 4: logfile; ...; 7: all

verbose-config: 7; #  print configuration at startup
verbose-config-error: 7;  # print configuration errors
verbose-connections: 7; # trace established incoming address to forward address
verbose-connections-error: 7; # connection errors
verbose-connections-try: 7; # connection attempts towards targets
verbose-fd: 0; # file descriptor activity, open/close/whatnot
verbose-packets: 0; # hexdump packets on which probing is done
verbose-probe-info: 0; # what's happening during the probe process
verbose-probe-error: 7; # failures and problems during probing
verbose-system-error: 7; # system call problem, i.e.  malloc, fork, failing
verbose-int-error: 7; # internal errors, the kind that should never happen

logfile: "/config/sslh.log"
#logfile: "/dev/null";

listen:
(
    {
        host: "0.0.0.0";
        port: "4433";
    }
);

protocols:
(
    {
        name: "tls"; 
        host: "127.0.0.1";
        port: "443";
    },
    {
        name: "ssh";
        host: "127.0.0.1";
        port: "22";
        # keep-alive: true; # when this is present, ssh won't connect (booth true or false)
    }
);

on-timeout: "tls";

Log keeps telling me:

--transparent flag is set
+ iptables -t raw -A PREROUTING '!' -i lo -d 127.0.0.0/8 -j DROP
Configuring iptables and routing...
+ iptables -t mangle -A POSTROUTING '!' -o lo -s 127.0.0.0/8 -j DROP
+ iptables -t nat -A OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f
+ iptables -t mangle -A OUTPUT '!' -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f
+ ip rule add fwmark 0x1 lookup 100
+ ip route add local 0.0.0.0/0 dev lo table 100
+ set -e
+ set +x
Executing with user 'sslh': sslh --transparent --config=/config/sslh.conf
ssh addr: localhost:ssh. libwrap service: (null) log_level: 1 family 2 2 [] [] []
timeout: 3
on-timeout: ssh
UDP hash size: 1024
Listening to:
4:      0.0.0.0:4433    [] []
sslh-select head-2023-08-10 started
trying to connect to localhost:ssh family 2 len 16
ssh: lost incoming connection
trying to connect to localhost:ssh family 2 len 16
tls: lost incoming connection

When using --net=host the sysctls:
- net.ipv4.conf.default.route_localnet=1
- net.ipv4.conf.all.route_localnet=1
are not allowed to use.

Is there anything I can do to help investigate this further?

When using --net=host the sysctls:

  • net.ipv4.conf.default.route_localnet=1
  • net.ipv4.conf.all.route_localnet=1
    are not allowed to use.

You need to run on your host:

sysctl -w net.ipv4.conf.default.route_localnet=1
sysctl -w net.ipv4.conf.all.route_localnet=1

Is there anything I can do to help investigate this further?

My last guess on what the issue may be is:

  1. Since your using net=host, your existing firewall rules may be interfering with the packets. You could try disabling it temporarily (default allow INPUT,FORWARD,OUTPUT,etc) and test it
  2. Did you create a user 'sslh' before on your host before? you may need to remove it (my guess it it may possibly conflict with the docker user sslh. idk)
  3. Did you ensure that your services are reachable using localhost?

Otherwise you can try using the examples I gave in #390, using sslh container as the main networking container (i.e. setting --network="container:sslh" for your other docker containers

You need to run on your host:
sysctl -w net.ipv4.conf.default.route_localnet=1
sysctl -w net.ipv4.conf.all.route_localnet=1

This did the trick! 👍
The whole time I was not aware to execute this directly on the docker host machine, sorry for the circumstances.

What I've got now for (future) reference:

On docker host executed:

sysctl -w net.ipv4.conf.default.route_localnet=1
sysctl -w net.ipv4.conf.all.route_localnet=1

Running as docker container:

  • sslh
  • swag (purpose: automated enginx reverse proxy with let's encrpyt)
  • openssh (purpose: ssh jump-server. In a future use-case maybe teleport)

sslh:

sudo docker create --name=sslh --net=host -e TZ=Europe/Berlin --cap-add CAP_NET_RAW --cap-add CAP_NET_ADMIN -v ./config/:/config --restart=unless-stopped ghcr.io/yrutschle/sslh:master --transparent --config=/config/sslh.conf

sslh.conf

foreground: true;
transparent: true;
timeout: 3;

# Logging configuration
# Value: 1: stdout; 2: syslog; 3: stdout+syslog; 4: logfile; ...; 7: all

verbose-config: 1; #  print configuration at startup
verbose-config-error: 1;  # print configuration errors
verbose-connections: 1; # trace established incoming address to forward address
verbose-connections-error: 1; # connection errors
verbose-connections-try: 1; # connection attempts towards targets
verbose-fd: 0; # file descriptor activity, open/close/whatnot
verbose-packets: 0; # hexdump packets on which probing is done
verbose-probe-info: 0; # what's happening during the probe process
verbose-probe-error: 1; # failures and problems during probing
verbose-system-error: 1; # system call problem, i.e.  malloc, fork, failing
verbose-int-error: 1; # internal errors, the kind that should never happen

#logfile: "/config/sslh.log"
logfile: "/dev/null";

listen:
(
    {
        host: "0.0.0.0";
        port: "4433";
    }
);

protocols:
(
    {
        name: "tls"; 
        host: "127.0.0.1";
        port: "443";
    },
    {
        name: "ssh";
        host: "127.0.0.1";
        port: "2222";
    }
);

on-timeout: "tls";

swag:

sudo docker create --name=swag --net=host --cap-add=NET_ADMIN  -v ./config/:/config --env-file ./swag.env.list --restart unless-stopped lscr.io/linuxserver/swag:latest

openssh:

sudo docker create --net=host --name openssh --env-file ./openssh.env.list -v /./config/:/config --restart unless-stopped lscr.io/linuxserver/openssh-server:latest

Conclusion:
Transparent mode is working, now I can geoblock ips and make detailed use of fail2ban.
Thank you very much for your time and assistance @klementng 🥇

Do I now have to worry about any safety issues due to all involved containers are running with --net=host and
sysctl -w net.ipv4.conf.default.route_localnet=1 & sysctl -w net.ipv4.conf.all.route_localnet=1 ?
Can or should I optimize any (other) settings for a more secure approache?

Btw: The documentaion Transparent proxy mentions that

  • sslh runs on a host, and the target servers run on LXC or dockers running on the same host. No known working setup.

Am I not doing this? (Well, with having sslh running in docker, too.) Maybe our findings can help other user with their setup for this particular use case?

Do I now have to worry about any safety issues due to all involved containers are running with --net=host

You don't have to run all the involved container with --net=host. Only sslh needs it. You could just expose the port for the other container using docker port mapping/binding.

Can or should I optimize any (other) settings for a more secure approache?

You could by using the other method of achieving transparent mode which should be more secure but i don't think security should be too much of an issue. Using --net=host is more or less the same as installing sslh directly on the system (with some additional docker isolation) .