diff --git a/.github/workflows/docker-publish-dev.yml b/.github/workflows/docker-publish-dev.yml index 4f13c84..15a2a8c 100644 --- a/.github/workflows/docker-publish-dev.yml +++ b/.github/workflows/docker-publish-dev.yml @@ -8,15 +8,11 @@ name: Docker MultiArch Build Dev on: workflow_dispatch: push: - branches: [ dev ] + branches: [ 76-add-doh-and-dot-support ] paths-ignore: - '**/README.md' # Publish semver tags as releases. tags: [ 'v*.*.*' ] - pull_request: - branches: [ main ] - paths-ignore: - - '**/README.md' env: # Use docker.io for Docker Hub if empty @@ -38,19 +34,19 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 # Login against a Docker registry except on PR # https://github.com/docker/login-action - name: Log into registry ${{ env.REGISTRY }} if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -60,7 +56,7 @@ jobs: # https://github.com/docker/metadata-action - name: Extract Docker metadata id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | @@ -77,7 +73,7 @@ jobs: # https://github.com/docker/build-push-action - name: Build and push Docker image id: build-and-push - uses: docker/build-push-action@v3 + uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm/v7,linux/arm64 diff --git a/Dockerfile b/Dockerfile index 651321d..0aaa59b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,16 +6,23 @@ ENV DNSDIST_BIND_IP=0.0.0.0 ENV ALLOWED_CLIENTS=127.0.0.1 ENV ALLOWED_CLIENTS_FILE= ENV EXTERNAL_IP= + +ENV DNSDIST_ENABLE_DOT=false +ENV DNSDIST_DOT_CERT_TYPE=auto-self + ENV DNSDIST_WEBSERVER_PASSWORD= ENV DNSDIST_WEBSERVER_API_KEY= ENV DNSDIST_WEBSERVER_NETWORKS_ACL="127.0.0.1, ::1" + ENV DNSDIST_UPSTREAM_CHECK_INTERVAL=10 ENV DNSDIST_UPSTREAM_POOL_NAME="upstream" + ENV DNSDIST_RATE_LIMIT_DISABLE=false ENV DNSDIST_RATE_LIMIT_WARN=800 ENV DNSDIST_RATE_LIMIT_BLOCK=1000 ENV DNSDIST_RATE_LIMIT_BLOCK_DURATION=360 ENV DNSDIST_RATE_LIMIT_EVAL_WINDOW=60 + ENV SPOOF_ALL_DOMAINS=false ENV DYNDNS_CRON_SCHEDULE="*/2 * * * *" ENV INSTALL_DEFAULT_DOMAINS=true @@ -28,6 +35,7 @@ EXPOSE 5300/udp EXPOSE 8080/tcp EXPOSE 8443/tcp EXPOSE 8083/tcp +EXPOSE 8530/tcp RUN echo "I'm building for $TARGETPLATFORM" @@ -38,10 +46,13 @@ RUN apk update && apk upgrade RUN addgroup snidust && adduser -D -H -G snidust snidust # Install needed packages and clean up -RUN apk add --no-cache jq tini dnsdist curl bash gnupg procps ca-certificates openssl dog lua5.4-filesystem ipcalc libcap nginx nginx-mod-stream supercronic && rm -rf /var/cache/apk/* +RUN apk add --no-cache jq tini dnsdist curl bash gnupg procps ca-certificates openssl dog lua5.4-filesystem ipcalc libcap nginx nginx-mod-stream supercronic step-cli && \ + rm -f /etc/nginx/conf.d/*.conf && \ + rm -rf /var/cache/apk/* # Setup Folder(s) RUN mkdir -p /etc/dnsdist/conf.d && \ + mkdir -p /etc/dnsdist/certs && \ mkdir -p /etc/snidust/domains.d && \ mkdir -p /etc/sniproxy/ && \ mkdir -p /var/lib/snidust/domains.d diff --git a/README.md b/README.md index 80d9e5a..d9553c3 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,10 @@ In case Systemd is already using port 53 you can follow this [Guide](https://www ## Advanced setups +### DoT + +For examples how to use an setup DoT see `docker-compose.dot.yml` and `docker-compose.acme.sh-dot.yml` + ### Disable installtion of repo default domains If do not want use the default domain lists of this repo, you can disable this by setting the environment variable `INSTALL_DEFAULT_DOMAINS` to `false`. diff --git a/configs/dnsdist/conf.d/00-SniDust.conf b/configs/dnsdist/conf.d/00-SniDust.conf index 8904fb5..083dd2d 100644 --- a/configs/dnsdist/conf.d/00-SniDust.conf +++ b/configs/dnsdist/conf.d/00-SniDust.conf @@ -6,6 +6,21 @@ function trim(s) return s:match "^%s*(.*%S)" or "" end +function ReloadCerts(dq) + infolog("[INFO] [SniDust] Reloading certs...") + + -- prevent the query from going upstream + dq.dh:setQR(true) + + -- load + reloadAllCertificates() + + infolog("[INFO] [SniDust] Certs reloaded!") + + -- respond with a local address just in case + return DNSAction.Spoof, "127.0.0.7" +end + -- read all the domains in a set function LoadBlocklists(smn, folder) f = io.popen('/bin/ls ' .. folder .. '*.lst') diff --git a/configs/dnsdist/dnsdist.conf.template b/configs/dnsdist/dnsdist.conf.template index c4e29fb..af1cc33 100644 --- a/configs/dnsdist/dnsdist.conf.template +++ b/configs/dnsdist/dnsdist.conf.template @@ -21,10 +21,18 @@ echo "end" echo "" echo "" -echo "-- Add Bind" +echo "-- Add plain DNS bind" echo "addLocal('${DNSDIST_BIND_IP}:5300')" echo "" +if [ "${DNSDIST_ENABLE_DOT}" == "true" ]; then + echo "-- Add DoT bind" + echo "addTLSLocal('${DNSDIST_BIND_IP}:8530','/etc/dnsdist/certs/tls.pem','/etc/dnsdist/certs/tls.key')" + echo "" +else + echo "-- TLS Endpoints disabled" +fi + echo "-- Include Config" echo "includeDirectory(\"/etc/dnsdist/conf.d\")" echo "" @@ -59,14 +67,18 @@ if [ "${DNSDIST_DEBUG}" == "true" ]; then echo "" fi -echo "-- query reload.blocklist.unblockdock.local to reload Blocklist" +echo "-- query reload.domainlist.snidust.local to reload Blocklist" echo "addAction(AndRule({QNameRule(\"reload.domainlist.snidust.local\"),QTypeRule(\"A\")}),LuaAction(ReloadBlocklist))" echo "" -echo "-- query reload.acl.unblockdock.local to reload Blocklist" +echo "-- query reload.acl.snidust.local to reload Blocklist" echo "addAction(AndRule({QNameRule(\"reload.acl.snidust.local\"),QTypeRule(\"A\")}),LuaAction(ReloadACL))" echo "" +echo "-- query reload.certs.snidust.local to reload certificates used for DoT" +echo "addAction(AndRule({QNameRule(\"reload.certs.snidust.local\"),QTypeRule(\"A\")}),LuaAction(ReloadCerts))" +echo "" + if [ "${SPOOF_ALL_DOMAINS}" == "true" ]; then echo " -- rewrite it for ALL Domains" echo "addAction(AllRule(), SpoofAction(\"${EXTERNAL_IP}\"))" diff --git a/docker-compose.acme.sh-dot.yml b/docker-compose.acme.sh-dot.yml new file mode 100644 index 0000000..8d2c05d --- /dev/null +++ b/docker-compose.acme.sh-dot.yml @@ -0,0 +1,47 @@ +# NOTE: This is just an example (which is also not fully tested yet) how you could use sniDust with DoT and a trusted certificate. +# Is uses acme.sh and the DNS-01 method in conjuntion with cloudflare. For other options using acme.sh please see here: https://github.com/acmesh-official/acme.sh/wiki/ +# +# +# You need run acme.sh ONCE manually. After the container will manually renew certs and call snidust to reload certs +# docker exec \ +# -e CF_Token="TOKEN" \ +# -e CF_Email="abc@example.com" \ +# acme.sh --issue -d dot.example.com --dns dns_cf +# +volumes: + acme_sh: + driver: local + +services: + acme.sh: + container_name: acme.sh + image: neilpang/acme.sh + command: daemon + volumes: + - acme_sh:/acme.sh + - /var/run/docker.sock:/var/run/docker.sock + environment: + - DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=dot.example.com + - DEPLOY_DOCKER_CONTAINER_KEY_FILE=/etc/dnsdist/cert/tls.key + - DEPLOY_DOCKER_CONTAINER_CERT_FILE="/etc/dnsdist/cert/cert.pem" + - DEPLOY_DOCKER_CONTAINER_CA_FILE="/etc/dnsdist/cert/ca.pem" + - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/etc/dnsdist/cert/tls.pem" + - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="/usr/bin/dog @127.0.0.1:5300 --short reload.certs.snidust.local" + sniDust: + container_name: sniDust + labels: + - sh.acme.autoload.domain=dot.example.com + environment: + - 'ALLOWED_CLIENTS=127.0.0.1/32, myDynDNSDomain.no-ip.com' # CHANGE THIS + - 'EXTERNAL_IP=10.111.123.8' # CHANGE THIS TO YOUR VPS PUBLIC IP + - TZ=Europe/Berlin + - DNSDIST_ENABLE_DOT=true + - DNSDIST_DOT_CERT_TYPE=manual + ports: + - '443:8443' + - '80:8080' + - '53:5300/udp' + - '53:5300/tcp' + - '853:8530/tcp' + image: 'ghcr.io/publish3r/snidust-telerising:main' + restart: unless-stopped diff --git a/docker-compose.dot.yml b/docker-compose.dot.yml new file mode 100644 index 0000000..61e62c8 --- /dev/null +++ b/docker-compose.dot.yml @@ -0,0 +1,21 @@ +services: + sniDust: + container_name: sniDust + environment: + - 'ALLOWED_CLIENTS=127.0.0.1/32, myDynDNSDomain.no-ip.com' # CHANGE THIS + - 'EXTERNAL_IP=10.111.123.8' # CHANGE THIS TO YOUR VPS PUBLIC IP + - TZ=Europe/Berlin + - DNSDIST_ENABLE_DOT=true + - DNSDIST_DOT_CERT_TYPE=auto-self # Generate self-signed cert. Can also be set to 'manual' + # Uncomment this if you choose manual. Align paths to match your environment -> Just an example! + # volumes: + # - /etc/letsencrypt/live/dot.example.com/fullchain.pem:/etc/dnsdist/cert/tls.pem:ro + # - /etc/letsencrypt/live/dot.example.com/privkey.pem:/etc/dnsdist/cert/tls.key:ro + ports: + - '443:8443' + - '80:8080' + - '53:5300/udp' + - '53:5300/tcp' + - '853:8530/tcp' + image: 'ghcr.io/publish3r/snidust-telerising:main' + restart: unless-stopped diff --git a/docker-compose.yml b/docker-compose.yml index 74dc849..ce7211c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,5 @@ -version: '3.8' services: - seji64: + sniDust: container_name: sniDust environment: - 'ALLOWED_CLIENTS=127.0.0.1/32, myDynDNSDomain.no-ip.com' # CHANGE THIS @@ -12,4 +11,4 @@ services: - '53:5300/udp' - '53:5300/tcp' image: 'ghcr.io/publish3r/snidust-telerising:main' - restart: always + restart: unless-stopped diff --git a/entrypoint.sh b/entrypoint.sh index f8077ba..5414684 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,4 +1,23 @@ #!/bin/bash -e + +# Validate DoT config +if [ "${DNSDIST_ENABLE_DOT}" == "true" ]; then + VALID_CERT_TYPE_VALUES=("auto-self" "manual") + if [[ -z "$DNSDIST_DOT_CERT_TYPE" ]]; then + echo "The environment variable DNSDIST_DOT_CERT_TYPE is not set." + exit 1 + fi + + if [[ " ${VALID_CERT_TYPE_VALUES[*]} " =~ " ${DNSDIST_DOT_CERT_TYPE} " ]]; then + if [ "${DNSDIST_DOT_CERT_TYPE}" == "auto-self" ]; then + /usr/bin/step certificate create dot.snidust.local /etc/dnsdist/certs/tls.pem /etc/dnsdist/certs/tls.key --profile self-signed --subtle --no-password --insecure + fi + else + echo "[ERROR] Invalid value for DNSDIST_DOT_CERT_TYPE: $DNSDIST_DOT_CERT_TYPE" + exit 1 + fi +fi + if [ -z "${EXTERNAL_IP}" ]; then echo "[INFO] External IP not set - trying to get IP by myself"