diff --git a/Dockerfile b/Dockerfile index f5e08bcf..cb236af4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,25 +2,22 @@ FROM alpine:latest as build WORKDIR /sslh +RUN apk add gcc libconfig-dev make musl-dev pcre2-dev perl + COPY . /sslh -RUN \ - apk add \ - gcc \ - libconfig-dev \ - make \ - musl-dev \ - pcre2-dev \ - perl && \ - make sslh-select && \ - strip sslh-select +RUN make sslh-select && strip sslh-select FROM alpine:latest -COPY --from=build "/sslh/sslh-select" "/usr/local/bin/sslh" +RUN apk --no-cache add libconfig pcre2 iptables ip6tables libcap -RUN apk --no-cache add libconfig pcre2 +RUN adduser sslh --shell /bin/sh --disabled-password + +COPY --from=build "/sslh/sslh-select" "/usr/local/bin/sslh" +RUN setcap cap_net_bind_service,cap_net_raw+ep /usr/local/bin/sslh COPY "./container-entrypoint.sh" "/init" ENTRYPOINT [ "/init" ] -USER nobody:nogroup +# required for updating iptables +USER root:root \ No newline at end of file diff --git a/README.md b/README.md index 8611b9aa..1af4ea8b 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ How to use ```bash docker run \ --cap-add CAP_NET_RAW \ - --cap-add CAP_NET_BIND_SERVICES \ + --cap-add CAP_NET_BIND_SERVICE \ --rm \ -it \ ghcr.io/yrutschle/sslh:latest \ @@ -60,7 +60,7 @@ docker run \ docker-compose example -``` +```yaml version: "3" services: @@ -81,6 +81,72 @@ services: image: openvpn ``` +Transparent mode 1: shared containers + +```yaml +version: "3" + +services: + sslh: + build: https://github.com/yrutschle/sslh.git + container_name: sslh + environment: + - TZ=${TZ} + cap_add: + - NET_ADMIN + - NET_RAW + - NET_BIND_SERVICE + sysctls: + - net.ipv4.conf.default.route_localnet=1 + - net.ipv4.conf.all.route_localnet=1 + command: --transparent --foreground --listen=0.0.0.0:443 --tls=localhost:8443 --openvpn=localhost:1194 --wireguard=localbox:51820 + ports: + - 443:443 #sslh + + - 80:80 #nginx + - 8443:8443 #nginx + + - 1194:1994 #openvpn + extra_hosts: + - localbox:host-gateway + restart: unless-stopped + + nginx: + image: nginx:latest + ..... + network_mode: service:sslh #set nginx container to use sslh networking + + openvpn: + image: openvpn:latest + ..... + network_mode: service:sslh #set openvpn container to use sslh networking +``` + +Transparent mode 2: host networking + +```yaml +version: "3" + +services: + sslh: + build: https://github.com/yrutschle/sslh.git + container_name: sslh + environment: + - TZ=${TZ} + cap_add: + - NET_ADMIN + - NET_RAW + - NET_BIND_SERVICE + # must be set manually + #sysctls: + # - net.ipv4.conf.default.route_localnet=1 + # - net.ipv4.conf.all.route_localnet=1 + command: --transparent --foreground --listen=0.0.0.0:443 --tls=localhost:8443 --openvpn=localhost:1194 --wireguard=localhost:51820 + network_mode: host + restart: unless-stopped +``` + + Comments? Questions? ==================== diff --git a/container-entrypoint.sh b/container-entrypoint.sh index cabc7833..b0641e4d 100755 --- a/container-entrypoint.sh +++ b/container-entrypoint.sh @@ -1,4 +1,5 @@ #!/bin/sh + # SPDX-License-Identifier: GPL2-or-later # # Copyright (C) 2023 Olliver Schinagl @@ -19,6 +20,73 @@ if [ "${#}" -le 0 ] || \ entrypoint='true' fi -exec ${entrypoint:+${bin}} "${@}" +############################################################################ + +unconfigure_iptables() { + set +e # Don't exit + + echo "Received SIG TERM/INT/KILL. Removing iptables / routing changes" + + iptables -t raw -D PREROUTING ! -i lo -d 127.0.0.0/8 -j DROP + iptables -t mangle -D POSTROUTING ! -o lo -s 127.0.0.0/8 -j DROP + + iptables -t nat -D OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f + iptables -t mangle -D OUTPUT ! -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f + + ip rule del fwmark 0x1 lookup 100 + ip route del local 0.0.0.0/0 dev lo table 100 + + + ip6tables -t raw -D PREROUTING ! -i lo -d ::1/128 -j DROP & > /dev/null #silence ipv6 errors + ip6tables -t mangle -D POSTROUTING ! -o lo -s ::1/128 -j DROP & > /dev/null + ip6tables -t nat -D OUTPUT -m owner --uid-owner sslh -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x01/0x0f & > /dev/null + ip6tables -t mangle -D OUTPUT ! -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f & > /dev/null + + ip -6 rule del fwmark 0x1 lookup 100 & > /dev/null + ip -6 route del local ::/0 dev lo table 100 & > /dev/null + + set -e +} + +configure_iptables() { + set +e # Don't exit if rule exist or ipv6 not enabled + + echo "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 + + ip6tables -t raw -A PREROUTING ! -i lo -d ::1/128 -j DROP & > /dev/null #silence ipv6 errors + ip6tables -t mangle -A POSTROUTING ! -o lo -s ::1/128 -j DROP & > /dev/null + 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 & > /dev/null + ip6tables -t mangle -A OUTPUT ! -o lo -p tcp -m connmark --mark 0x01/0x0f -j CONNMARK --restore-mark --mask 0x0f & > /dev/null + + ip -6 rule add fwmark 0x1 lookup 100 & > /dev/null + ip -6 route add local ::/0 dev lo table 100 & > /dev/null + + set -e +} + +for i in "$@" ; do + if [ "${i}" = "--transparent" ] ; then + echo "--transparent is set" + configure_iptables + trap unconfigure_iptables TERM INT KILL + break + fi +done + +#run command as sslh user +command="${entrypoint:+${bin}} ${@}" +echo "executing with user 'sslh': $command" + +exec su - sslh -c "$command" & +wait $! -exit 0 +exit 0 \ No newline at end of file