├── .dockerfilelintrc ├── .dockerignore ├── .editorconfig ├── .env.example ├── .github ├── FUNDING.yml └── workflows │ ├── dnscrypt-server.yml │ ├── doh-proxy.yml │ ├── haproxy.yml │ ├── m13253-doh.yml │ ├── nsd.yml │ └── unbound.yml ├── .gitignore ├── LICENSE ├── Readme.md ├── acme-cron-job.yml ├── acme-init-job.yml ├── build.sh ├── daemon.json ├── deploy.sh ├── dns-infra.afdesign ├── dns-infra.png ├── dnscrypt-server ├── Dockerfile ├── Readme.md ├── encrypted-dns.toml.in ├── entrypoint.sh └── undelegated.txt ├── docker-compose.yml ├── docker-stack.yml ├── docker.md ├── doh-proxy ├── Dockerfile ├── doh-proxy-deployment.yml ├── doh-proxy-srv.yml └── entrypoint.sh ├── haproxy ├── Dockerfile ├── entrypoint.sh ├── ffdhe2048.txt ├── haproxy-deployment.yml ├── haproxy-srv.yml ├── haproxy.conf ├── haproxy.sh └── ocsp-updater.sh ├── kube.md ├── lint.sh ├── logo ├── horizonal.png ├── horizontal.svg ├── icon-transparent.png ├── icon-transparent.svg ├── icon.png ├── icon.svg ├── monochrome_horizontal.png ├── monochrome_horizontal.svg ├── monochrome_icon.png ├── monochrome_icon.svg ├── monochrome_vertical.png ├── monochrome_vertical.svg ├── verical.svg └── vertical.png ├── m13253-doh ├── Dockerfile ├── doh-proxy-deployment.yml ├── doh-proxy-srv.yml ├── doh-server.conf └── entrypoint.sh ├── namespace.yml ├── nsd ├── Dockerfile ├── entrypoint.sh ├── nsd-deployment.yml ├── nsd-srv.yml ├── nsd.conf └── opennic.conf ├── package-lock.json ├── package.json ├── test-dog.sh ├── test-doggo.sh ├── test-infra.sh ├── test.sh ├── tests ├── dnscrypt.bats.old ├── doh.bats ├── dot.bats ├── opennic.bats ├── publicarray-au-doh.toml ├── publicarray-au.toml ├── publicarray-au2-doh.toml ├── publicarray-au2.toml └── tls.bats ├── unbound ├── Dockerfile ├── entrypoint.sh ├── unbound-deployment.yml ├── unbound-srv.yml ├── unbound.conf └── unbound.sh └── yarn.lock /.dockerfilelintrc: -------------------------------------------------------------------------------- 1 | rules: 2 | invalid_command: off 3 | latest_tag: off 4 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.* 2 | **/*.md 3 | **/*.yml 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.{yml,yaml}] 12 | indent_size = 2 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Global API 2 | CF_KEY= 3 | CF_EMAIL= 4 | # API v4 https://github.com/acmesh-official/acme.sh/wiki/dnsapi#1-cloudflare-option 5 | CF_TOKEN= 6 | CF_ACCOUNT_ID= 7 | CF_ZONE_ID= 8 | HEALTHCHECK= -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [publicarray] 4 | -------------------------------------------------------------------------------- /.github/workflows/dnscrypt-server.yml: -------------------------------------------------------------------------------- 1 | name: dnscrypt-server 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths: 6 | - 'dnscrypt-server/*' 7 | jobs: 8 | build: 9 | name: Build & Push dnscrypt-server Container 10 | runs-on: ubuntu-latest 11 | env: 12 | APP: dnscrypt-server 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | persist-credentials: false 17 | 18 | - name: Set up QEMU 19 | uses: docker/setup-qemu-action@v2 20 | - name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v2 22 | 23 | - name: Login to DockerHub 24 | uses: docker/login-action@v2 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | 29 | - name: Login to GitHub Packages 30 | uses: docker/login-action@v2 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.repository_owner }} 34 | password: ${{ secrets.GH_PACKAGE_TOKEN }} 35 | 36 | - name: Build and push 37 | uses: docker/build-push-action@v4 38 | with: 39 | context: ${{ env.APP }} 40 | file: ${{ env.APP }}/Dockerfile 41 | platforms: linux/amd64 42 | push: true 43 | tags: | 44 | ghcr.io/${{ github.repository }}/${{ env.APP }}:latest 45 | ${{ github.repository_owner }}/${{ env.APP }}:latest 46 | -------------------------------------------------------------------------------- /.github/workflows/doh-proxy.yml: -------------------------------------------------------------------------------- 1 | name: doh-proxy 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths: 6 | - 'doh-proxy/*' 7 | jobs: 8 | build: 9 | name: Build & Push doh-proxy Container 10 | runs-on: ubuntu-latest 11 | env: 12 | APP: doh-proxy 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | persist-credentials: false 17 | 18 | - name: Set up QEMU 19 | uses: docker/setup-qemu-action@v2 20 | - name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v2 22 | 23 | - name: Login to DockerHub 24 | uses: docker/login-action@v2 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | 29 | - name: Login to GitHub Packages 30 | uses: docker/login-action@v2 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.repository_owner }} 34 | password: ${{ secrets.GH_PACKAGE_TOKEN }} 35 | 36 | - name: Build and push 37 | uses: docker/build-push-action@v4 38 | with: 39 | context: ${{ env.APP }} 40 | file: ${{ env.APP }}/Dockerfile 41 | platforms: linux/amd64 42 | push: true 43 | tags: | 44 | ghcr.io/${{ github.repository }}/${{ env.APP }}:latest 45 | ${{ github.repository_owner }}/${{ env.APP }}:latest 46 | -------------------------------------------------------------------------------- /.github/workflows/haproxy.yml: -------------------------------------------------------------------------------- 1 | name: haproxy 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths: 6 | - 'haproxy/*' 7 | jobs: 8 | build: 9 | name: Build & Push haproxy Container 10 | runs-on: ubuntu-latest 11 | env: 12 | APP: haproxy 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | persist-credentials: false 17 | 18 | - name: Set up QEMU 19 | uses: docker/setup-qemu-action@v2 20 | - name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v2 22 | 23 | - name: Login to DockerHub 24 | uses: docker/login-action@v2 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | 29 | - name: Login to GitHub Packages 30 | uses: docker/login-action@v2 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.repository_owner }} 34 | password: ${{ secrets.GH_PACKAGE_TOKEN }} 35 | 36 | - name: Build and push 37 | uses: docker/build-push-action@v4 38 | with: 39 | context: ${{ env.APP }} 40 | file: ${{ env.APP }}/Dockerfile 41 | platforms: linux/386,linux/amd64,linux/arm64 42 | push: true 43 | tags: | 44 | ghcr.io/${{ github.repository }}/${{ env.APP }}:latest 45 | ${{ github.repository_owner }}/${{ env.APP }}:latest 46 | -------------------------------------------------------------------------------- /.github/workflows/m13253-doh.yml: -------------------------------------------------------------------------------- 1 | name: m13253-doh 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths: 6 | - 'm13253-doh/*' 7 | jobs: 8 | build: 9 | name: Build & Push m13253-doh Container 10 | runs-on: ubuntu-latest 11 | env: 12 | APP: m13253-doh 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | persist-credentials: false 17 | 18 | - name: Set up QEMU 19 | uses: docker/setup-qemu-action@v2 20 | - name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v2 22 | 23 | - name: Login to DockerHub 24 | uses: docker/login-action@v2 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | 29 | - name: Login to GitHub Packages 30 | uses: docker/login-action@v2 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.repository_owner }} 34 | password: ${{ secrets.GH_PACKAGE_TOKEN }} 35 | 36 | - name: Build and push 37 | uses: docker/build-push-action@v4 38 | with: 39 | context: ${{ env.APP }} 40 | file: ${{ env.APP }}/Dockerfile 41 | platforms: linux/386,linux/amd64,linux/arm64 42 | push: true 43 | tags: | 44 | ghcr.io/${{ github.repository }}/${{ env.APP }}:latest 45 | ${{ github.repository_owner }}/${{ env.APP }}:latest 46 | -------------------------------------------------------------------------------- /.github/workflows/nsd.yml: -------------------------------------------------------------------------------- 1 | name: nsd 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths: 6 | - 'nsd/*' 7 | jobs: 8 | build: 9 | name: Build & Push nsd Container 10 | runs-on: ubuntu-latest 11 | env: 12 | APP: nsd 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | persist-credentials: false 17 | 18 | - name: Set up QEMU 19 | uses: docker/setup-qemu-action@v2 20 | - name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v2 22 | 23 | - name: Login to DockerHub 24 | uses: docker/login-action@v2 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | 29 | - name: Login to GitHub Packages 30 | uses: docker/login-action@v2 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.repository_owner }} 34 | password: ${{ secrets.GH_PACKAGE_TOKEN }} 35 | 36 | - name: Build and push 37 | uses: docker/build-push-action@v4 38 | with: 39 | context: ${{ env.APP }} 40 | file: ${{ env.APP }}/Dockerfile 41 | platforms: linux/386,linux/amd64,linux/arm64 42 | push: true 43 | tags: | 44 | ghcr.io/${{ github.repository }}/${{ env.APP }}:latest 45 | ${{ github.repository_owner }}/${{ env.APP }}:latest 46 | -------------------------------------------------------------------------------- /.github/workflows/unbound.yml: -------------------------------------------------------------------------------- 1 | name: unbound 2 | on: 3 | workflow_dispatch: 4 | push: 5 | paths: 6 | - 'unbound/*' 7 | jobs: 8 | build: 9 | name: Build & Push unbound Container 10 | runs-on: ubuntu-latest 11 | env: 12 | APP: unbound 13 | steps: 14 | - uses: actions/checkout@v3 15 | with: 16 | persist-credentials: false 17 | 18 | - name: Set up QEMU 19 | uses: docker/setup-qemu-action@v2 20 | - name: Set up Docker Buildx 21 | uses: docker/setup-buildx-action@v2 22 | 23 | - name: Login to DockerHub 24 | uses: docker/login-action@v2 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | 29 | - name: Login to GitHub Packages 30 | uses: docker/login-action@v2 31 | with: 32 | registry: ghcr.io 33 | username: ${{ github.repository_owner }} 34 | password: ${{ secrets.GH_PACKAGE_TOKEN }} 35 | 36 | - name: Build and push 37 | uses: docker/build-push-action@v4 38 | with: 39 | context: ${{ env.APP }} 40 | file: ${{ env.APP }}/Dockerfile 41 | platforms: linux/386,linux/amd64,linux/arm64 42 | push: true 43 | tags: | 44 | ghcr.io/${{ github.repository }}/${{ env.APP }}:latest 45 | ${{ github.repository_owner }}/${{ env.APP }}:latest 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *secret* 3 | *backup 4 | *.pcap 5 | *.log 6 | node.yml 7 | .env 8 | data/acme/cron 9 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 |

2 | DNS Resolver Infrastructure 3 |

4 | 5 | # DNS Resolver Infrastructure 6 | 7 | ## Infrastructure Overview 8 | 9 | 10 | [![Actions Status](https://github.com/publicarray/dns-resolver-infra/workflows/dnscrypt-server/badge.svg)](https://github.com/publicarray/dns-resolver-infra/actions?workflow=dnscrypt-server) 11 | [![Actions Status](https://github.com/publicarray/dns-resolver-infra/workflows/doh-proxy/badge.svg)](https://github.com/publicarray/dns-resolver-infra/actions?workflow=doh-proxy) 12 | [![Actions Status](https://github.com/publicarray/dns-resolver-infra/workflows/haproxy/badge.svg)](https://github.com/publicarray/dns-resolver-infra/actions?workflow=haproxy) 13 | [![Actions Status](https://github.com/publicarray/dns-resolver-infra/workflows/m13253-doh/badge.svg)](https://github.com/publicarray/dns-resolver-infra/actions?workflow=m13253-doh) 14 | [![Actions Status](https://github.com/publicarray/dns-resolver-infra/workflows/nsd/badge.svg)](https://github.com/publicarray/dns-resolver-infra/actions?workflow=nsd) 15 | [![Actions Status](https://github.com/publicarray/dns-resolver-infra/workflows/unbound/badge.svg)](https://github.com/publicarray/dns-resolver-infra/actions?workflow=unbound) 16 | 17 |
18 | 19 | * [acme.sh](https://github.com/Neilpang/acme.sh) (TLS certificate generation for haproxy) 20 | * [nsd](https://www.nlnetlabs.nl/projects/nsd/) ([OpenNIC](https://www.opennic.org/)) [![Docker Pulls](https://img.shields.io/docker/pulls/publicarray/nsd.svg?maxAge=86400)](https://hub.docker.com/r/publicarray/nsd/) [![Docker Image Size](https://img.shields.io/docker/image-size/publicarray/nsd/latest)](https://microbadger.com/images/publicarray/nsd) 21 | * [unbound](https://unbound.nlnetlabs.nl/) (DNS Resolver) [![Docker Pulls](https://img.shields.io/docker/pulls/publicarray/unbound.svg?maxAge=86400)](https://hub.docker.com/r/publicarray/unbound/) [![Docker Image Size](https://img.shields.io/docker/image-size/publicarray/unbound/latest)](https://microbadger.com/images/publicarray/unbound) 22 | * [dnscrypt-server](https://github.com/jedisct1/encrypted-dns-server) (dnscrypt) [![Docker Pulls](https://img.shields.io/docker/pulls/publicarray/dnscrypt-server.svg?maxAge=86400)](https://hub.docker.com/r/publicarray/dnscrypt-server/) [![Docker Image Size](https://img.shields.io/docker/image-size/publicarray/dnscrypt-server/latest)](https://microbadger.com/images/publicarray/dnscrypt-server) 23 | * [doh-proxy](https://github.com/jedisct1/rust-doh) [![Docker Pulls](https://img.shields.io/docker/pulls/publicarray/doh-proxy.svg?maxAge=86400)](https://hub.docker.com/r/publicarray/doh-proxy/) [![Docker Image Size](https://img.shields.io/docker/image-size/publicarray/doh-proxy/latest)](https://microbadger.com/images/publicarray/doh-proxy) or [m13253-doh](https://github.com/m13253/dns-over-https) [![Docker Pulls](https://img.shields.io/docker/pulls/publicarray/m13253-doh.svg?maxAge=86400)](https://hub.docker.com/r/publicarray/m13253-doh/) ![Docker Image Size](https://img.shields.io/docker/image-size/publicarray/m13253-doh/latest) 24 | * [haproxy](http://www.haproxy.org/) (DNS-over-HTTPS) [![Docker Pulls](https://img.shields.io/docker/pulls/publicarray/haproxy.svg?maxAge=86400)](https://hub.docker.com/r/publicarray/haproxy/) [![Docker Image Size](https://img.shields.io/docker/image-size/publicarray/haproxy/latest)](https://microbadger.com/images/publicarray/haproxy) 25 | * [haproxy](http://www.haproxy.org/) (DNS-over-TLS) [![Docker Pulls](https://img.shields.io/docker/pulls/publicarray/haproxy.svg?maxAge=86400)](https://hub.docker.com/r/publicarray/haproxy/) [![Docker Image Size](https://img.shields.io/docker/image-size/publicarray/haproxy/latest)](https://microbadger.com/images/publicarray/haproxy) 26 | 27 | ## Getting started 28 | 29 | ### Quick start** 30 | 31 | ```sh 32 | pacman -S docker docker-composer docker-buildx 33 | git clone https://github.com/publicarray/dns-resolver-infra.git && cd dns-resolver-infra 34 | # Add Cloudflare cedentials for acme.sh / TLS certificates 35 | echo 'CF_TOKEN=xxxx' >> .env 36 | echo 'CF_ACCOUNT_ID=xxxx' >> .env 37 | echo 'CF_ZONE_ID=xxxx' >> .env 38 | 39 | ./deploy.sh 40 | ``` 41 | 42 | ### Docker Compose 43 | 44 | ```sh 45 | # Build Images or pull them: 46 | docker-compose pull 47 | 48 | # Add Cloudflare cedentials for acme.sh / TLS certificates 49 | echo 'CF_TOKEN=xxxx' >> .env 50 | echo 'CF_ACCOUNT_ID=xxxx' >> .env 51 | echo 'CF_ZONE_ID=xxxx' >> .env 52 | 53 | # # Setup CA 54 | # docker-compose run acme --register-account -m my@example.com 55 | # # or 56 | # docker-compose run acme.sh --set-default-ca --server letsencrypt 57 | 58 | # Launch 59 | docker-compose up -d 60 | ``` 61 | 62 | * [Usage with Docker-Swarm](docker.md) 63 | * [Usage with Kubernetes](kube.md) 64 | 65 | ### sysctl 66 | 67 | ``` 68 | sysctl net.ipv4.tcp_congestion_control=bbr 69 | ``` 70 | 71 | 72 | ### Tests 73 | 74 | ``` 75 | npm i --legacy-peer-deps 76 | ./lint.sh 77 | npm run bats tests 78 | ./test.sh 79 | ``` 80 | 81 | ### -------------------------------------------------------------------------------- /acme-cron-job.yml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1beta1 2 | kind: CronJob 3 | metadata: 4 | name: acme-cron-job 5 | spec: 6 | schedule: 30 03 01 */3 * 7 | jobTemplate: 8 | spec: 9 | template: 10 | spec: 11 | containers: 12 | - name: acme-init 13 | image: neilpang/acme.sh 14 | env: 15 | # - name: DOMAIN 16 | # value: doh.seby.io 17 | - name: CF_Email 18 | valueFrom: 19 | secretKeyRef: 20 | name: cloudflare 21 | key: username 22 | - name: CF_Key 23 | valueFrom: 24 | secretKeyRef: 25 | name: cloudflare 26 | key: password 27 | command: 28 | - acme.sh 29 | - --issue 30 | - --staging # remember to remove in production 31 | - --dns 32 | - dns_cf 33 | - --dnssleep 34 | - "60" 35 | - -d 36 | # - $(DOMAIN) 37 | - doh.seby.io 38 | # - -d 39 | # - www.$(DOMAIN) 40 | - --fullchain-file 41 | - /opt/ssl/fullchain.pem 42 | - --key-file 43 | - /opt/ssl/key.pem 44 | - --ca-file 45 | - /opt/ssl/ca.pem 46 | - --cert-file 47 | - /opt/ssl/cert.pem 48 | - --reloadcmd 49 | - 'cat /opt/ssl/key.pem > cat /opt/ssl/fullchain.pem > /opt/ssl/fullchain-key.pem' 50 | volumeMounts: 51 | - name: ssl 52 | mountPath: /opt/ssl 53 | restartPolicy: Never # OnFailure 54 | volumes: 55 | - name: ssl 56 | hostPath: 57 | path: /data/ssl 58 | type: DirectoryOrCreate 59 | -------------------------------------------------------------------------------- /acme-init-job.yml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: acme-init 5 | spec: 6 | template: 7 | metadata: 8 | name: acme-init 9 | spec: 10 | # schedule: 30 03 01 */3 * 11 | containers: 12 | - name: acme-init 13 | image: neilpang/acme.sh 14 | env: 15 | # - name: DOMAIN 16 | # value: doh.seby.io 17 | - name: CF_Email 18 | valueFrom: 19 | secretKeyRef: 20 | name: cloudflare 21 | key: username 22 | - name: CF_Key 23 | valueFrom: 24 | secretKeyRef: 25 | name: cloudflare 26 | key: password 27 | command: 28 | - acme.sh 29 | - --issue 30 | - --staging # remember to remove in production 31 | - --dns 32 | - dns_cf 33 | - --dnssleep 34 | - "60" 35 | - -d 36 | # - $(DOMAIN) 37 | - doh.seby.io 38 | # - -d 39 | # - www.$(DOMAIN) 40 | - --fullchain-file 41 | - /opt/ssl/fullchain.pem 42 | - --key-file 43 | - /opt/ssl/key.pem 44 | - --ca-file 45 | - /opt/ssl/ca.pem 46 | - --cert-file 47 | - /opt/ssl/cert.pem 48 | - --reloadcmd 49 | - 'cat /opt/ssl/key.pem > cat /opt/ssl/fullchain.pem > /opt/ssl/fullchain-key.pem' 50 | volumeMounts: 51 | - name: ssl 52 | mountPath: /opt/ssl 53 | restartPolicy: Never # OnFailure 54 | volumes: 55 | - name: ssl 56 | hostPath: 57 | path: /data/ssl 58 | type: DirectoryOrCreate 59 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set +x 4 | 5 | docker compose build 6 | docker compose push 7 | -------------------------------------------------------------------------------- /daemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "userns-remap": "dockerremap", 3 | "experimental": false, 4 | "live-restore": false, 5 | "ipv6": false, 6 | "icc": false, 7 | "no-new-privileges": true, 8 | "storage-driver": "overlay2" 9 | } 10 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set +x 4 | 5 | # docker stack deploy dns --compose-file docker-stack.yml 6 | docker compose pull 7 | docker compose up -d --remove-orphans 8 | -------------------------------------------------------------------------------- /dns-infra.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/publicarray/dns-resolver-infra/c0f32be0b0956088d355361a204df5b1fce990ee/dns-infra.afdesign -------------------------------------------------------------------------------- /dns-infra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/publicarray/dns-resolver-infra/c0f32be0b0956088d355361a204df5b1fce990ee/dns-infra.png -------------------------------------------------------------------------------- /dnscrypt-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rustlang/rust:nightly AS encrypted-dns-build 2 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 3 | ENV REVISION 2 4 | ENV VERSION 0.9.13 5 | SHELL ["/bin/sh", "-x", "-c"] 6 | ENV RUSTFLAGS "-C link-arg=-s" 7 | RUN cargo install encrypted-dns --version $VERSION && \ 8 | strip --strip-all /usr/local/cargo/bin/encrypted-dns 9 | 10 | #------------------------------------------------------------------------------# 11 | FROM ubuntu:22.04 12 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 13 | LABEL maintainer="publicarray" 14 | LABEL name="dnscrypt-server" 15 | LABEL description="https://github.com/jedisct1/encrypted-dns-server - Basically https://github.com/DNSCrypt/dnscrypt-server-docker minus unbound" 16 | SHELL ["/bin/sh", "-x", "-c"] 17 | WORKDIR /tmp 18 | ENV RUN_DEPS bash dnsutils coreutils findutils grep ca-certificates libevent-2.1 libssl3 expat 19 | RUN apt-get update && \ 20 | apt-get install -qy --no-install-recommends $RUN_DEPS && \ 21 | rm -fr /tmp/* /var/tmp/* /var/cache/apt/* /var/lib/apt/lists/* /var/log/apt/* /var/log/*.log 22 | RUN update-ca-certificates 2> /dev/null || true 23 | 24 | COPY --from=encrypted-dns-build /usr/local/cargo/bin/encrypted-dns /opt/encrypted-dns/sbin/encrypted-dns 25 | ENV PATH="/opt/encrypted-dns/sbin/:${PATH}" 26 | 27 | RUN mkdir -p /opt/encrypted-dns/empty && \ 28 | groupadd _encrypted-dns && \ 29 | useradd -g _encrypted-dns -s /etc -d /opt/encrypted-dns/empty _encrypted-dns && \ 30 | mkdir -m 700 -p /opt/encrypted-dns/etc/keys && \ 31 | mkdir -m 700 -p /opt/encrypted-dns/etc/lists && \ 32 | chown _encrypted-dns:_encrypted-dns /opt/encrypted-dns/etc/keys && \ 33 | mkdir -m 700 -p /opt/dnscrypt-wrapper/etc/keys && \ 34 | mkdir -m 700 -p /opt/dnscrypt-wrapper/etc/lists && \ 35 | chown _encrypted-dns:_encrypted-dns /opt/dnscrypt-wrapper/etc/keys 36 | 37 | COPY encrypted-dns.toml.in /opt/encrypted-dns/etc/ 38 | COPY undelegated.txt /opt/encrypted-dns/etc/ 39 | COPY entrypoint.sh / 40 | 41 | VOLUME ["/opt/encrypted-dns/etc/keys"] 42 | 43 | EXPOSE 443/udp 443/tcp 9100/tcp 44 | 45 | RUN /opt/encrypted-dns/sbin/encrypted-dns --version 46 | 47 | CMD ["/entrypoint.sh", "start"] 48 | 49 | ENTRYPOINT ["/entrypoint.sh"] 50 | -------------------------------------------------------------------------------- /dnscrypt-server/Readme.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | ``` 4 | docker run --rm -it -v dns_dnscrypt:/opt/dnscrypt -v dns_dnscrypt-server:/opt/encrypted-dns publicarray/dnscrypt-server shell 5 | ``` 6 | -------------------------------------------------------------------------------- /dnscrypt-server/encrypted-dns.toml.in: -------------------------------------------------------------------------------- 1 | #################################################### 2 | # # 3 | # Encrypted DNS Server configuration # 4 | # # 5 | #################################################### 6 | 7 | 8 | 9 | ################################## 10 | # Global settings # 11 | ################################## 12 | 13 | 14 | ## IP addresses and ports to listen to, as well as their external IP 15 | ## If there is no NAT involved, `local` and `external` can be the same. 16 | ## As many addresses as needed can be configured here, IPv4 and/or IPv6. 17 | ## You should at least change the `external` IP address. 18 | 19 | ### Example with both IPv4 and IPv6 addresses: 20 | # listen_addrs = [ 21 | # { local = "0.0.0.0:443", external = "198.51.100.1:443" }, 22 | # { local = "[::]:443", external = "[2001:db8::1]:443" } 23 | # ] 24 | 25 | listen_addrs = [ 26 | { local = "0.0.0.0:443", external = "@EXTERNAL_IPV4@" } 27 | ] 28 | 29 | 30 | ## Upstream DNS server and port 31 | 32 | upstream_addr = "@UPSTREAM_IPV4@:53" 33 | 34 | 35 | ## File name to save the state to 36 | 37 | state_file = "encrypted-dns.state" 38 | 39 | 40 | ## UDP timeout in seconds 41 | 42 | udp_timeout = 10 43 | 44 | 45 | ## TCP timeout in seconds 46 | 47 | tcp_timeout = 10 48 | 49 | 50 | ## Maximum active UDP sockets 51 | 52 | udp_max_active_connections = 1000 53 | 54 | 55 | ## Maximum active TCP connections 56 | 57 | tcp_max_active_connections = 100 58 | 59 | 60 | ## Optional IP address to connect to upstream servers from. 61 | ## Leave commented/undefined to automatically select it. 62 | 63 | # external_addr = "0.0.0.0" 64 | 65 | 66 | ## Built-in DNS cache capacity 67 | 68 | cache_capacity = 150000 69 | 70 | 71 | ## DNS cache: minimum TTL 72 | 73 | cache_ttl_min = 3600 74 | 75 | 76 | ## DNS cache: max TTL 77 | 78 | cache_ttl_max = 86400 79 | 80 | 81 | ## DNS cache: error TTL 82 | 83 | cache_ttl_error = 600 84 | 85 | 86 | ## DNS cache: to avoid bursts of traffic for popular queries when an 87 | ## RRSET expires, hold a TTL received from an upstream server for 88 | ## `client_ttl_holdon` seconds before decreasing it in client responses. 89 | 90 | client_ttl_holdon = 60 91 | 92 | 93 | ## Run as a background process 94 | 95 | daemonize = false 96 | 97 | 98 | ## Log file, when running as a background process 99 | 100 | # log_file = "/tmp/encrypted-dns.log" 101 | 102 | 103 | ## PID file 104 | 105 | # pid_file = "/tmp/encrypted-dns.pid" 106 | 107 | 108 | ## User name to drop privileges to, when started as root. 109 | 110 | user = "_encrypted-dns" 111 | 112 | 113 | ## Group name to drop privileges to, when started as root. 114 | 115 | group = "_encrypted-dns" 116 | 117 | 118 | ## Path to chroot() to, when started as root. 119 | ## The path to the state file is relative to the chroot base. 120 | 121 | # chroot = "/var/empty" 122 | 123 | 124 | ## Queries sent to that name will return the client IP address. 125 | ## This can be very useful for debugging, or to check that relaying works. 126 | 127 | my_ip = "my.ip" 128 | 129 | 130 | #################################### 131 | # DNSCrypt settings # 132 | #################################### 133 | 134 | [dnscrypt] 135 | 136 | ## Provider name (with or without the `2.dnscrypt-cert.` prefix) 137 | 138 | provider_name = "@PROVIDER_NAME@" 139 | 140 | 141 | ## Does the server support DNSSEC? 142 | 143 | dnssec = true 144 | 145 | 146 | ## Does the server always returns correct answers (no filtering, including ad blocking)? 147 | 148 | no_filters = true 149 | 150 | 151 | ## Set to `true` if the server doesn't keep any information that can be used to identify users 152 | 153 | no_logs = true 154 | 155 | 156 | ## Key cache capacity, per certificate 157 | 158 | key_cache_capacity = 10000 159 | 160 | 161 | 162 | ############################### 163 | # TLS settings # 164 | ############################### 165 | 166 | [tls] 167 | 168 | ## Where to proxy TLS connections to (e.g. DoH server) 169 | 170 | @TLS_PROXY_CONFIGURATION@ 171 | 172 | 173 | 174 | ####################################### 175 | # Server-side filtering # 176 | ####################################### 177 | 178 | [filtering] 179 | 180 | ## List of domains to block, one per line 181 | 182 | # domain_blacklist = "/etc/domain_blacklist.txt" 183 | 184 | 185 | ## List of undelegated TLDs 186 | ## This is the list of nonexistent TLDs that queries are frequently observed for, 187 | ## but will never resolve to anything. The server will immediately return a 188 | ## synthesized NXDOMAIN response instead of hitting root servers. 189 | 190 | # undelegated_list = "/etc/undelegated.txt" 191 | 192 | 193 | ## Ignore A and AAAA queries for unqualified host names. 194 | 195 | # ignore_unqualified_hostnames = true 196 | 197 | 198 | 199 | ######################### 200 | # Metrics # 201 | ######################### 202 | 203 | # [metrics] 204 | 205 | # type = "prometheus" 206 | # listen_addr = "0.0.0.0:9100" 207 | # path = "/metrics" 208 | 209 | 210 | 211 | ################################ 212 | # Anonymized DNS # 213 | ################################ 214 | 215 | [anonymized_dns] 216 | 217 | # Enable relaying support for Anonymized DNS 218 | 219 | enabled = @ANONDNS_ENABLED@ 220 | 221 | 222 | # Allowed upstream ports 223 | # This is a list of commonly used ports for encrypted DNS services 224 | 225 | allowed_ports = [ 443, 553, 853, 1443, 2053, 4343, 4434, 4443, 5353, 5443, 8443, 15353 ] 226 | 227 | 228 | # Allow all ports >= 1024 in addition to the list above 229 | 230 | allow_non_reserved_ports = false 231 | 232 | 233 | # Blacklisted upstream IP addresses 234 | 235 | blacklisted_ips = [ @ANONDNS_BLACKLISTED_IPS@ ] 236 | 237 | 238 | 239 | 240 | ################################ 241 | # Access control # 242 | ################################ 243 | 244 | [access_control] 245 | 246 | # Enable access control 247 | 248 | enabled = false 249 | 250 | # Only allow access to client queries including one of these random tokens 251 | # Tokens can be configured in the `query_meta` section of `dnscrypt-proxy` as 252 | # `query_meta = ["token:..."]` -- Replace ... with the token to use by the client. 253 | # Example: `query_meta = ["token:Y2oHkDJNHz"]` 254 | 255 | tokens = ["Y2oHkDJNHz", "G5zY3J5cHQtY", "C5zZWN1cmUuZG5z"] 256 | -------------------------------------------------------------------------------- /dnscrypt-server/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | set -e 4 | 5 | action="$1" 6 | 7 | LEGACY_KEYS_DIR="/opt/dnscrypt-wrapper/etc/keys" 8 | LEGACY_LISTS_DIR="/opt/dnscrypt-wrapper/etc/lists" 9 | LEGACY_STATE_DIR="${LEGACY_KEYS_DIR}/state" 10 | KEYS_DIR="/opt/encrypted-dns/etc/keys" 11 | STATE_DIR="${KEYS_DIR}/state" 12 | LISTS_DIR="/opt/encrypted-dns/etc/lists" 13 | CONF_DIR="/opt/encrypted-dns/etc" 14 | CONFIG_FILE="${CONF_DIR}/encrypted-dns.toml" 15 | CONFIG_FILE_TEMPLATE="${CONF_DIR}/encrypted-dns.toml.in" 16 | 17 | getServiceIP() { 18 | for arg; do 19 | dig "$arg" +short 20 | done 21 | } 22 | waitOrFail() { 23 | maxTries=24 24 | i=0 25 | while [ $i -lt $maxTries ]; do 26 | outStr="$($@)" 27 | if [ $? -eq 0 ]; then 28 | echo "$outStr" 29 | return 30 | fi 31 | i=$((i + 1)) 32 | echo "==> waiting for a dependent service $i/$maxTries" >&2 33 | sleep 5 34 | done 35 | echo "Too many failed attempts" >&2 36 | exit 1 37 | } 38 | 39 | init() { 40 | if [ "$(is_initialized)" = yes ]; then 41 | start 42 | exit $? 43 | fi 44 | 45 | anondns_enabled="false" 46 | anondns_blacklisted_ips="" 47 | upstream_address="127.0.0.1" 48 | metrics_address="127.0.0.1:9100" 49 | tls_proxy_upstream_port="443" 50 | 51 | while getopts "h?N:E:d:T:P:AM:" opt; do 52 | case "$opt" in 53 | h | \?) usage ;; 54 | N) provider_name=$(echo "$OPTARG" | sed -e 's/^[ \t]*//' | tr A-Z a-z) ;; 55 | E) ext_address=$(echo "$OPTARG" | sed -e 's/^[ \t]*//' | tr A-Z a-z) ;; 56 | d) upstream_address=$(waitOrFail getServiceIP "$(echo "$OPTARG" | sed -e 's/^[ \t]*//' | tr A-Z a-z)") ;; 57 | T) tls_proxy_upstream_address=$(waitOrFail getServiceIP "$(echo "$OPTARG" | sed -e 's/^[ \t]*//' | tr A-Z a-z)") ;; 58 | P) tls_proxy_upstream_port=$(echo "$OPTARG" | sed -e 's/^[ \t]*//' | tr A-Z a-z) ;; 59 | A) anondns_enabled="true" ;; 60 | M) metrics_address=$(echo "$OPTARG" | sed -e 's/^[ \t]*//' | tr A-Z a-z) ;; 61 | esac 62 | done 63 | [ -z "$provider_name" ] && usage 64 | case "$provider_name" in 65 | .*) usage ;; 66 | 2.dnscrypt-cert.*) ;; 67 | *) provider_name="2.dnscrypt-cert.${provider_name}" ;; 68 | esac 69 | 70 | [ -z "$ext_address" ] && usage 71 | case "$ext_address" in 72 | .*) usage ;; 73 | 0.*) 74 | echo "Do not use 0.0.0.0, use an actual external IP address" >&2 75 | exit 1 76 | ;; 77 | esac 78 | 79 | tls_proxy_configuration="" 80 | if [ -n "$tls_proxy_upstream_address" ]; then 81 | tls_proxy_configuration="upstream_addr = \"${tls_proxy_upstream_address}:${tls_proxy_upstream_port}\"" 82 | fi 83 | 84 | domain_blacklist_file="${LISTS_DIR}/blacklist.txt" 85 | domain_blacklist_configuration="" 86 | if [ -s "$domain_blacklist_file" ]; then 87 | chown _encrypted-dns:_encrypted_dns "$domain_blacklist_file" 88 | domain_blacklist_configuration="domain_blacklist = \"${domain_blacklist_file}\"" 89 | fi 90 | 91 | echo "Provider name: [$provider_name]" 92 | 93 | echo "$provider_name" >"${KEYS_DIR}/provider_name" 94 | chmod 644 "${KEYS_DIR}/provider_name" 95 | 96 | sed \ 97 | -e "s#@PROVIDER_NAME@#${provider_name}#" \ 98 | -e "s#@EXTERNAL_IPV4@#${ext_address}#" \ 99 | -e "s#@UPSTREAM_IPV4@#${upstream_address}#" \ 100 | -e "s#@TLS_PROXY_CONFIGURATION@#${tls_proxy_configuration}#" \ 101 | -e "s#@DOMAIN_BLACKLIST_CONFIGURATION@#${domain_blacklist_configuration}#" \ 102 | -e "s#@ANONDNS_ENABLED@#${anondns_enabled}#" \ 103 | -e "s#@ANONDNS_BLACKLISTED_IPS@#${anondns_blacklisted_ips}#" \ 104 | -e "s#@METRICS_ADDRESS@#${metrics_address}#" \ 105 | "$CONFIG_FILE_TEMPLATE" >"$CONFIG_FILE" 106 | 107 | mkdir -p -m 700 "${STATE_DIR}" 108 | chown _encrypted-dns:_encrypted-dns "${STATE_DIR}" 109 | 110 | if [ -f "${KEYS_DIR}/secret.key" ]; then 111 | echo "Importing the previous secret key [${KEYS_DIR}/secret.key]" 112 | /opt/encrypted-dns/sbin/encrypted-dns \ 113 | --config "$CONFIG_FILE" \ 114 | --import-from-dnscrypt-wrapper "${KEYS_DIR}/secret.key" \ 115 | --dry-run >/dev/null || exit 1 116 | mv -f "${KEYS_DIR}/secret.key" "${KEYS_DIR}/secret.key.migrated" 117 | fi 118 | 119 | /opt/encrypted-dns/sbin/encrypted-dns \ 120 | --config "$CONFIG_FILE" --dry-run | 121 | tee "${KEYS_DIR}/provider-info.txt" 122 | 123 | echo 124 | echo ----------------------------------------------------------------------- 125 | echo 126 | echo "Congratulations! The container has been properly initialized." 127 | echo "Take a look up above at the way dnscrypt-proxy has to be configured in order" 128 | echo "to connect to your resolver. Then, start the container with the default command." 129 | } 130 | 131 | provider_info() { 132 | ensure_initialized 133 | echo 134 | cat "${KEYS_DIR}/provider-info.txt" 135 | echo 136 | } 137 | 138 | legacy_compat() { 139 | if [ -f "${KEYS_DIR}/provider-info.txt" ] && [ -f "${KEYS_DIR}/provider_name" ]; then 140 | return 0 141 | fi 142 | if [ -f "${LEGACY_KEYS_DIR}/provider-info.txt" ] && [ -f "${LEGACY_KEYS_DIR}/provider_name" ]; then 143 | echo "Using [${LEGACY_KEYS_DIR}] for keys" >&2 144 | mkdir -p "${KEYS_DIR}" 145 | mv -f "${KEYS_DIR}/provider-info.txt" "${KEYS_DIR}/provider-info.txt.migrated" 2>/dev/null || : 146 | ln -s "${LEGACY_KEYS_DIR}/provider-info.txt" "${KEYS_DIR}/provider-info.txt" 2>/dev/null || : 147 | mv -f "${KEYS_DIR}/provider_name" "${KEYS_DIR}/provider_name.migrated" 2>/dev/null || : 148 | ln -s "${LEGACY_KEYS_DIR}/provider_name" "${KEYS_DIR}/provider_name" 2>/dev/null || : 149 | mv -f "${KEYS_DIR}/secret.key" "${KEYS_DIR}/secret.key.migrated" 2>/dev/null || : 150 | ln -s "${LEGACY_KEYS_DIR}/secret.key" "${KEYS_DIR}/secret.key" 2>/dev/null || : 151 | mkdir -p -m 700 "${LEGACY_STATE_DIR}" 152 | chown _encrypted-dns:_encrypted-dns "${LEGACY_STATE_DIR}" 153 | mv -f "$STATE_DIR" "${STATE_DIR}.migrated" 2>/dev/null || : 154 | ln -s "$LEGACY_STATE_DIR" "${STATE_DIR}" 2>/dev/null || : 155 | fi 156 | if [ -f "${LEGACY_LISTS_DIR}/blacklist.txt" ]; then 157 | echo "Using [${LEGACY_LISTS_DIR}] for lists" >&2 158 | mkdir -p "${LISTS_DIR}" 159 | mv -f "${LISTS_DIR}/blacklist.txt" "${LISTS_DIR}/blacklist.txt.migrated" 2>/dev/null || : 160 | ln -s "${LEGACY_LISTS_DIR}/blacklist.txt" "${LISTS_DIR}/blacklist.txt" 2>/dev/null || : 161 | chown _encrypted-dns:_encrypted-dns "${LEGACY_LISTS_DIR}/blacklist.txt" 162 | fi 163 | } 164 | 165 | is_initialized() { 166 | if [ -f "$CONFIG_FILE" ] && [ -f "${STATE_DIR}/encrypted-dns.state" ] && [ -f "${KEYS_DIR}/provider-info.txt" ] && [ -f "${KEYS_DIR}/provider_name" ]; then 167 | echo yes 168 | else 169 | legacy_compat 170 | if [ -f "$CONFIG_FILE" ] && [ -f "${STATE_DIR}/encrypted-dns.state" ] && [ -f "${KEYS_DIR}/provider-info.txt" ] && [ -f "${KEYS_DIR}/provider_name" ]; then 171 | echo yes 172 | else 173 | echo no 174 | fi 175 | fi 176 | } 177 | 178 | ensure_initialized() { 179 | if [ "$(is_initialized)" = no ]; then 180 | if [ -d "$LEGACY_KEYS_DIR" ]; then 181 | echo "Please provide an initial configuration (init -N -E )" >&2 182 | fi 183 | exit 1 184 | fi 185 | } 186 | 187 | start() { 188 | ensure_initialized 189 | if [ -f "${KEYS_DIR}/secret.key" ]; then 190 | echo "Importing the previous secret key [${KEYS_DIR}/secret.key]" 191 | /opt/encrypted-dns/sbin/encrypted-dns \ 192 | --config "$CONFIG_FILE" \ 193 | --import-from-dnscrypt-wrapper "${KEYS_DIR}/secret.key" \ 194 | --dry-run >/dev/null || exit 1 195 | mv -f "${KEYS_DIR}/secret.key" "${KEYS_DIR}/secret.key.migrated" 196 | fi 197 | /opt/encrypted-dns/sbin/encrypted-dns \ 198 | --config "$CONFIG_FILE" --dry-run | 199 | tee "${KEYS_DIR}/provider-info.txt" 200 | 201 | if [ ! -f "${KEYS_DIR}/provider_name" ]; then 202 | exit 1 203 | fi 204 | exec /opt/encrypted-dns/sbin/encrypted-dns --config "$CONFIG_FILE" 205 | } 206 | 207 | shell() { 208 | exec /bin/bash 209 | } 210 | 211 | bin() { 212 | shift 213 | exec /opt/encrypted-dns/sbin/encrypted-dns "$@" 214 | } 215 | 216 | usage() { 217 | cat < -E : 222 | initialize the container for a server accessible at ip on port 223 | , for a provider named . This is required only once. 224 | 225 | If TLS connections to the same port have to be redirected to a HTTPS server 226 | (e.g. for DoH), add -T : 227 | 228 | To enable Anonymized DNS relaying, add -A. 229 | 230 | To use dns service discovery use -d of a resolver on port 53 231 | 232 | * start (default command): start the resolver and the dnscrypt server proxy. 233 | Ports 443/udp and 443/tcp have to be publicly exposed. 234 | 235 | * provider-info: prints the provider name and provider public key. 236 | 237 | * shell: run a shell. 238 | 239 | * bin: run the binary with custom arguments 240 | 241 | This container has a single volume that you might want to securely keep a 242 | backup of: /opt/encrypted-dns/etc/keys 243 | EOT 244 | exit 1 245 | } 246 | 247 | case "$action" in 248 | start) start ;; 249 | init) 250 | shift 251 | init "$@" 252 | ;; 253 | provider-info) provider_info ;; 254 | shell) shell ;; 255 | bin) bin "$@";; 256 | *) usage ;; 257 | esac 258 | -------------------------------------------------------------------------------- /dnscrypt-server/undelegated.txt: -------------------------------------------------------------------------------- 1 | 0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa 2 | 0.in-addr.arpa 3 | 1 4 | 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa 5 | 10.in-addr.arpa 6 | 100.100.in-addr.arpa 7 | 100.51.198.in-addr.arpa 8 | 101.100.in-addr.arpa 9 | 102.100.in-addr.arpa 10 | 103.100.in-addr.arpa 11 | 104.100.in-addr.arpa 12 | 105.100.in-addr.arpa 13 | 106.100.in-addr.arpa 14 | 107.100.in-addr.arpa 15 | 108.100.in-addr.arpa 16 | 109.100.in-addr.arpa 17 | 110.100.in-addr.arpa 18 | 111.100.in-addr.arpa 19 | 112.100.in-addr.arpa 20 | 113.0.203.in-addr.arpa 21 | 113.100.in-addr.arpa 22 | 114.100.in-addr.arpa 23 | 115.100.in-addr.arpa 24 | 116.100.in-addr.arpa 25 | 117.100.in-addr.arpa 26 | 118.100.in-addr.arpa 27 | 119.100.in-addr.arpa 28 | 120.100.in-addr.arpa 29 | 121.100.in-addr.arpa 30 | 122.100.in-addr.arpa 31 | 123.100.in-addr.arpa 32 | 124.100.in-addr.arpa 33 | 125.100.in-addr.arpa 34 | 126.100.in-addr.arpa 35 | 127.100.in-addr.arpa 36 | 127.in-addr.arpa 37 | 16.172.in-addr.arpa 38 | 168.192.in-addr.arpa 39 | 17.172.in-addr.arpa 40 | 18.172.in-addr.arpa 41 | 19.172.in-addr.arpa 42 | 2.0.192.in-addr.arpa 43 | 20.172.in-addr.arpa 44 | 21.172.in-addr.arpa 45 | 22.172.in-addr.arpa 46 | 23.172.in-addr.arpa 47 | 24.172.in-addr.arpa 48 | 25.172.in-addr.arpa 49 | 254.169.in-addr.arpa 50 | 255.255.255.255.in-addr.arpa 51 | 26.172.in-addr.arpa 52 | 27.172.in-addr.arpa 53 | 28.172.in-addr.arpa 54 | 29.172.in-addr.arpa 55 | 30.172.in-addr.arpa 56 | 31.172.in-addr.arpa 57 | 64.100.in-addr.arpa 58 | 65.100.in-addr.arpa 59 | 66.100.in-addr.arpa 60 | 67.100.in-addr.arpa 61 | 68.100.in-addr.arpa 62 | 69.100.in-addr.arpa 63 | 70.100.in-addr.arpa 64 | 71.100.in-addr.arpa 65 | 72.100.in-addr.arpa 66 | 73.100.in-addr.arpa 67 | 74.100.in-addr.arpa 68 | 75.100.in-addr.arpa 69 | 76.100.in-addr.arpa 70 | 77.100.in-addr.arpa 71 | 78.100.in-addr.arpa 72 | 79.100.in-addr.arpa 73 | 8.b.d.0.1.0.0.2.ip6.arpa 74 | 8.e.f.ip6.arpa 75 | 80.100.in-addr.arpa 76 | 81.100.in-addr.arpa 77 | 82.100.in-addr.arpa 78 | 83.100.in-addr.arpa 79 | 84.100.in-addr.arpa 80 | 85.100.in-addr.arpa 81 | 86.100.in-addr.arpa 82 | 87.100.in-addr.arpa 83 | 88.100.in-addr.arpa 84 | 89.100.in-addr.arpa 85 | 9.e.f.ip6.arpa 86 | 90.100.in-addr.arpa 87 | 91.100.in-addr.arpa 88 | 92.100.in-addr.arpa 89 | 93.100.in-addr.arpa 90 | 94.100.in-addr.arpa 91 | 95.100.in-addr.arpa 92 | 96.100.in-addr.arpa 93 | 97.100.in-addr.arpa 94 | 98.100.in-addr.arpa 95 | 99.100.in-addr.arpa 96 | a.e.f.ip6.arpa 97 | airdream 98 | api 99 | b.e.f.ip6.arpa 100 | bbrouter 101 | belkin 102 | blinkap 103 | corp 104 | d.f.ip6.arpa 105 | davolink 106 | dearmyrouter 107 | dhcp 108 | dlink 109 | domain 110 | envoy 111 | example 112 | f.f.ip6.arpa 113 | grp 114 | gw== 115 | home 116 | hub 117 | internal 118 | intra 119 | intranet 120 | invalid 121 | ksyun 122 | lan 123 | loc 124 | local 125 | localdomain 126 | localhost 127 | localnet 128 | modem 129 | mynet 130 | myrouter 131 | novalocal 132 | onion 133 | openstacklocal 134 | priv 135 | private 136 | prv 137 | router 138 | telus 139 | test 140 | totolink 141 | wlan_ap 142 | workgroup 143 | zghjccbob3n0 144 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | volumes: 3 | dnscrypt: 4 | dnscrypt-server: 5 | ssl: 6 | nsd: 7 | acme-sh: 8 | acme-acc: 9 | services: 10 | acme: 11 | image: docker.io/neilpang/acme.sh 12 | container_name: acme 13 | command: > 14 | /bin/sh -c "echo \"#!/bin/sh 15 | 16 | set -e 17 | 18 | acme.sh --set-default-ca --server letsencrypt 19 | 20 | if [ -n ${HEALTHCHECK} ]; then 21 | 22 | acme.sh --issue --dns dns_cf --dnssleep 60 --domain '${DOMAIN}' --keylength ec-384 --fullchain-file /opt/ssl/fullchain-ecc.pem --key-file /opt/ssl/key-ecc.pem --ca-file /opt/ssl/ca-ecc.pem --cert-file /opt/ssl/cert-ecc.pem --pre-hook 'curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/${HEALTHCHECK}' 23 | 24 | else 25 | 26 | acme.sh --issue --dns dns_cf --dnssleep 60 --domain '${DOMAIN}' --keylength ec-384 --fullchain-file /opt/ssl/fullchain-ecc.pem --key-file /opt/ssl/key-ecc.pem --ca-file /opt/ssl/ca-ecc.pem --cert-file /opt/ssl/cert-ecc.pem 27 | 28 | fi 29 | 30 | acme.sh --deploy -d '${DOMAIN}' --ecc --deploy-hook docker 31 | 32 | \" > start.sh 33 | && chmod +x start.sh 34 | && ./start.sh" 35 | logging: 36 | driver: "json-file" 37 | options: 38 | max-size: "200k" 39 | max-file: "10" 40 | environment: 41 | - HEALTHCHECK=${HEALTHCHECK} 42 | - CF_Email=${CF_EMAIL} 43 | - CF_Key=${CF_KEY} 44 | - CF_Token=${CF_TOKEN} 45 | - CF_Account_ID=${CF_ACCOUNT_ID} 46 | - CF_Zone_ID=${CF_ZONE_ID} 47 | - DOMAIN=${DOMAIN} 48 | - DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=${DOMAIN} 49 | - DEPLOY_DOCKER_CONTAINER_KEY_FILE=/opt/ssl/key-ecc.pem 50 | - DEPLOY_DOCKER_CONTAINER_CERT_FILE="/opt/ssl/cert-ecc.pem" 51 | - DEPLOY_DOCKER_CONTAINER_CA_FILE="/opt/ssl/ca-ecc.pem" 52 | - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/opt/ssl/fullchain-ecc.pem" 53 | - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="cat /opt/ssl/key-ecc.pem > cat /opt/ssl/fullchain-ecc.pem > /opt/ssl/fullchain-key.pem.ecdsa; sv restart haproxy" 54 | volumes: 55 | - ssl:/opt/ssl 56 | - ./run/acmeout:/acme.sh 57 | - /var/run/docker.sock:/var/run/docker.sock 58 | 59 | acme-daemon: 60 | container_name: acme-daemon 61 | restart: on-failure:2 62 | image: docker.io/neilpang/acme.sh 63 | command: daemon 64 | logging: 65 | driver: "json-file" 66 | options: 67 | max-size: "200k" 68 | max-file: "10" 69 | volumes: 70 | - ssl:/opt/ssl 71 | - ./run/acmeout:/acme.sh 72 | - /var/run/docker.sock:/var/run/docker.sock 73 | environment: 74 | - DOMAIN=${DOMAIN} 75 | - HEALTHCHECK=${HEALTHCHECK} 76 | - DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=${DOMAIN} 77 | - DEPLOY_DOCKER_CONTAINER_KEY_FILE=/opt/ssl/key-ecc.pem 78 | - DEPLOY_DOCKER_CONTAINER_CERT_FILE="/opt/ssl/cert-ecc.pem" 79 | - DEPLOY_DOCKER_CONTAINER_CA_FILE="/opt/ssl/ca-ecc.pem" 80 | - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/opt/ssl/fullchain-ecc.pem" 81 | - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="cat /opt/ssl/key-ecc.pem > cat /opt/ssl/fullchain-ecc.pem > /opt/ssl/fullchain-key.pem.ecdsa; sv restart haproxy" 82 | 83 | nsd: 84 | container_name: nsd 85 | restart: on-failure:5 86 | build: nsd 87 | image: ghcr.io/publicarray/dns-resolver-infra/nsd 88 | logging: 89 | driver: "json-file" 90 | options: 91 | max-size: "200k" 92 | max-file: "10" 93 | volumes: 94 | - nsd:/etc/nsd/run 95 | 96 | unbound: 97 | container_name: unbound 98 | restart: on-failure:5 99 | depends_on: 100 | - nsd 101 | build: unbound 102 | image: ghcr.io/publicarray/dns-resolver-infra/unbound 103 | command: -d nsd 104 | logging: 105 | driver: "json-file" 106 | options: 107 | max-size: "200k" 108 | max-file: "10" 109 | # ports: 110 | # - target: 4949 111 | # published: 4949 112 | # protocol: tcp 113 | # mode: ingress 114 | 115 | m13253-doh: 116 | container_name: doh 117 | restart: on-failure:5 118 | depends_on: 119 | - unbound 120 | build: m13253-doh 121 | image: ghcr.io/publicarray/dns-resolver-infra/m13253-doh 122 | command: -d unbound 123 | logging: 124 | driver: "json-file" 125 | options: 126 | max-size: "200k" 127 | max-file: "10" 128 | 129 | # doh-proxy: 130 | # container_name: doh-proxy 131 | # restart: on-failure:5 132 | # depends_on: 133 | # - unbound 134 | # build: doh-proxy 135 | # image: ghcr.io/publicarray/dns-resolver-infra/doh-proxy 136 | # command: -d 137 | 138 | haproxy: 139 | container_name: haproxy 140 | restart: on-failure:5 141 | depends_on: 142 | - acme 143 | - m13253-doh 144 | - unbound 145 | labels: 146 | - sh.acme.autoload.domain=${DOMAIN} 147 | build: haproxy 148 | image: ghcr.io/publicarray/dns-resolver-infra/haproxy 149 | command: -d -r 150 | logging: 151 | driver: "json-file" 152 | options: 153 | max-size: "200k" 154 | max-file: "10" 155 | ports: 156 | - "443:443/tcp" 157 | - "853:853/tcp" 158 | - "443:443/udp" 159 | - "853:853/udp" 160 | volumes: 161 | - ssl:/opt/ssl 162 | environment: 163 | - DOMAIN=${DOMAIN} 164 | 165 | # dnscrypt-server: 166 | # container_name: dnscrypt-server 167 | # restart: on-failure:5 168 | # depends_on: 169 | # - unbound 170 | # - haproxy 171 | # image: ghcr.io/publicarray/dns-resolver-infra/dnscrypt-server 172 | # command: 173 | # - init 174 | # - -d unbound 175 | # - -N 176 | # - dns.seby.io 177 | # - -T 178 | # - haproxy 179 | # - -E 180 | # - 139.99.222.72:8443 181 | # - -A 182 | # logging: 183 | # driver: "json-file" 184 | # options: 185 | # max-size: "200k" 186 | # max-file: "10" 187 | # ports: 188 | # - "443:8443/tcp" 189 | # - "443:8443/udp" 190 | # volumes: 191 | # - dnscrypt:/opt/dnscrypt-wrapper 192 | # - dnscrypt-server:/opt/encrypted-dns 193 | -------------------------------------------------------------------------------- /docker-stack.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | volumes: 3 | dnscrypt: 4 | dnscrypt-server: 5 | ssl: 6 | nsd: 7 | acme-sh: 8 | acme-acc: 9 | services: 10 | acme: 11 | image: neilpang/acme.sh 12 | command: > 13 | /bin/sh -c "echo \"#!/bin/sh 14 | 15 | set -e 16 | 17 | # Check if certificate is still valid for the next 30 days, if so exit. 18 | 19 | if [ -f /opt/ssl/fullchain.pem ]; then 20 | 21 | if openssl x509 -checkend 2592000 -noout -in /opt/ssl/fullchain.pem; then 22 | 23 | echo 'Certificate is still valid!' 24 | 25 | exit 0 26 | 27 | else 28 | echo 'Certificate has expired or will do so within 30 days!' 29 | 30 | echo 'Renewing...' 31 | 32 | fi 33 | 34 | fi 35 | 36 | # Grab docker secrets 37 | 38 | export CF_Key='$$(cat /run/secrets/CF_Key)' 39 | 40 | export CF_Email='$$(cat /run/secrets/CF_Email)' 41 | 42 | # Issue Certificates 43 | #### Remember to remove '--staging' in production! #### 44 | 45 | # acme.sh 46 | # --issue 47 | # --dns dns_cf 48 | # --dnssleep 60 49 | # --domain '*.seby.io' 50 | # --keylength 4096 51 | # --fullchain-file /opt/ssl/fullchain.pem 52 | # --key-file /opt/ssl/key.pem 53 | # --ca-file /opt/ssl/ca.pem 54 | # --cert-file /opt/ssl/cert.pem 55 | # --reloadcmd 'cat /opt/ssl/key.pem > cat /opt/ssl/fullchain.pem > /opt/ssl/fullchain-key.pem.rsa' 56 | 57 | acme.sh 58 | --issue 59 | --dns dns_cf 60 | --dnssleep 60 61 | --domain '*.seby.io' 62 | --keylength ec-384 63 | --fullchain-file /opt/ssl/fullchain-ecc.pem 64 | --key-file /opt/ssl/key-ecc.pem 65 | --ca-file /opt/ssl/ca-ecc.pem 66 | --cert-file /opt/ssl/cert-ecc.pem 67 | --reloadcmd 'cat /opt/ssl/key-ecc.pem > cat /opt/ssl/fullchain-ecc.pem > /opt/ssl/fullchain-key.pem.ecdsa' 68 | \" > start.sh 69 | && chmod +x start.sh 70 | && ./start.sh" 71 | deploy: 72 | restart_policy: 73 | condition: on-failure 74 | max_attempts: 2 75 | logging: 76 | driver: "json-file" 77 | options: 78 | max-size: "200k" 79 | max-file: "10" 80 | secrets: 81 | - CF_Email 82 | - CF_Key 83 | volumes: 84 | - ssl:/opt/ssl 85 | - acme-sh:/root/.acme.sh 86 | - acme-acc:/acme.sh 87 | acme-daemon: 88 | container_name: acme 89 | image: neilpang/acme.sh 90 | command: daemon 91 | deploy: 92 | replicas: 1 93 | restart_policy: 94 | condition: on-failure 95 | max_attempts: 20 96 | logging: 97 | driver: "json-file" 98 | options: 99 | max-size: "200k" 100 | max-file: "10" 101 | secrets: 102 | - CF_Email 103 | - CF_Key 104 | volumes: 105 | - ssl:/opt/ssl 106 | - acme-sh:/root/.acme.sh 107 | - acme-acc:/acme.sh 108 | - /var/run/docker.sock:/var/run/docker.sock 109 | environment: 110 | - DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=*.seby.io 111 | - DEPLOY_DOCKER_CONTAINER_KEY_FILE=/opt/ssl/key-ecc.pem 112 | - DEPLOY_DOCKER_CONTAINER_CERT_FILE="/opt/ssl/cert-ecc.pem" 113 | - DEPLOY_DOCKER_CONTAINER_CA_FILE="/opt/ssl/ca-ecc.pem" 114 | - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/opt/ssl/fullchain-ecc.pem" 115 | - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="cat /opt/ssl/key-ecc.pem > cat /opt/ssl/fullchain-ecc.pem > /opt/ssl/fullchain-key.pem.ecdsa; sv restart haproxy" 116 | 117 | nsd: 118 | container_name: nsd 119 | build: nsd 120 | image: publicarray/nsd 121 | deploy: 122 | replicas: 1 123 | restart_policy: 124 | condition: any 125 | delay: 5s 126 | max_attempts: 20 127 | logging: 128 | driver: "json-file" 129 | options: 130 | max-size: "200k" 131 | max-file: "10" 132 | volumes: 133 | - nsd:/etc/nsd/run 134 | networks: 135 | - nsd-net 136 | 137 | unbound: 138 | container_name: unbound 139 | depends_on: 140 | - nsd 141 | build: unbound 142 | image: publicarray/unbound 143 | command: -m -d nsd 144 | deploy: 145 | replicas: 1 146 | resources: 147 | limits: 148 | memory: 260M 149 | restart_policy: 150 | condition: any 151 | delay: 5s 152 | max_attempts: 4 153 | logging: 154 | driver: "json-file" 155 | options: 156 | max-size: "200k" 157 | max-file: "10" 158 | ports: 159 | - target: 4949 160 | published: 4949 161 | protocol: tcp 162 | mode: ingress 163 | networks: 164 | - nsd-net 165 | - unbound-net 166 | 167 | m13253-doh: 168 | container_name: doh 169 | depends_on: 170 | - unbound 171 | build: m13253-doh 172 | image: publicarray/m13253-doh 173 | command: -d unbound 174 | deploy: 175 | replicas: 1 176 | restart_policy: 177 | condition: any 178 | delay: 5s 179 | logging: 180 | driver: "json-file" 181 | options: 182 | max-size: "200k" 183 | max-file: "10" 184 | networks: 185 | - unbound-net 186 | 187 | # doh-proxy: 188 | # depends_on: 189 | # - unbound 190 | # build: doh-proxy 191 | # image: publicarray/doh-proxy 192 | # command: -d 193 | # deploy: 194 | # replicas: 1 195 | # restart_policy: 196 | # condition: any 197 | # delay: 5s 198 | # networks: 199 | # - unbound-net 200 | 201 | haproxy: 202 | container_name: haproxy 203 | depends_on: 204 | - acme 205 | - m13253-doh 206 | - unbound 207 | labels: 208 | - sh.acme.autoload.domain=*.seby.io 209 | build: haproxy 210 | image: publicarray/haproxy 211 | command: -d -r 212 | deploy: 213 | replicas: 1 214 | restart_policy: 215 | condition: any 216 | delay: 5s 217 | max_attempts: 20 218 | logging: 219 | driver: "json-file" 220 | options: 221 | max-size: "200k" 222 | max-file: "10" 223 | ports: 224 | - target: 443 225 | published: 443 226 | protocol: tcp 227 | mode: ingress 228 | - target: 853 229 | published: 853 230 | protocol: tcp 231 | mode: ingress 232 | volumes: 233 | - ssl:/opt/ssl 234 | networks: 235 | - haproxy-net 236 | - unbound-net 237 | 238 | dnscrypt-server: 239 | depends_on: 240 | - unbound 241 | image: publicarray/dnscrypt-server 242 | command: 243 | - init 244 | - -d unbound 245 | - -N 246 | - dns.seby.io 247 | - -E 248 | - 139.99.222.72:8443 249 | - -A 250 | deploy: 251 | replicas: 1 252 | restart_policy: 253 | condition: any 254 | delay: 5s 255 | max_attempts: 20 256 | logging: 257 | driver: "json-file" 258 | options: 259 | max-size: "200k" 260 | max-file: "10" 261 | ports: 262 | - target: 443 263 | published: 8443 264 | protocol: tcp 265 | mode: ingress 266 | - target: 443 267 | published: 8443 268 | protocol: udp 269 | mode: ingress 270 | volumes: 271 | - dnscrypt:/opt/dnscrypt-wrapper 272 | - dnscrypt-server:/opt/encrypted-dns 273 | networks: 274 | - dnscrypt-net 275 | - unbound-net 276 | 277 | secrets: 278 | CF_Email: 279 | external: true 280 | CF_Key: 281 | external: true 282 | 283 | networks: 284 | dnscrypt-net: 285 | driver: overlay 286 | haproxy-net: 287 | driver: overlay 288 | nsd-net: 289 | driver: overlay 290 | unbound-net: 291 | driver: overlay 292 | -------------------------------------------------------------------------------- /docker.md: -------------------------------------------------------------------------------- 1 | # [Docker Machine](https://docs.docker.com/machine/overview/) 2 | 3 | https://docs.docker.com/machine/drivers/ 4 | 5 | https://github.com/docker/docker.github.io/blob/master/machine/AVAILABLE_DRIVER_PLUGINS.md 6 | 7 | ## Vultr / Digital Ocean 8 | 9 | ```sh 10 | brew install docker docker-machine docker-machine-driver-vultr # https://github.com/janeczku/docker-machine-vultr 11 | 12 | # Vultr 13 | docker-machine create -d vultr --vultr-region-id 19 --vultr-plan-id 201 --vultr-api-key "$VTOKEN" --vultr-ssh-key-id xxxxxxxxxxxxxx --vultr-ipv6 --vultr-ros-version v1.3.0 rancher-node 14 | # Digital Ocean 15 | docker-machine create -d digitalocean --digitalocean-region sfo1 --digitalocean-size 1gb --digitalocean-ssh-user rancher --digitalocean-image rancheros --digitalocean-access-token $DOTOKEN rancher-node 16 | 17 | docker-machine ssh rancher-node 18 | eval "$(docker-machine env rancher-node)" # for fish: eval (docker-machine env rancher-node) 19 | docker ps 20 | ``` 21 | 22 | ## Google Cloud Platform 23 | 24 | ```sh 25 | brew install docker docker-machine 26 | brew cask intall google-cloud-sdk 27 | 28 | gcloud auth login 29 | gcloud auth application-default login # (should only be used temporarily) 30 | gcloud compute images list --uri # for machine-image 31 | 32 | docker-machine create -d google --google-project dns-infra-xxxxxxx --google-zone australia-southeast1-a --google-machine-type f1-micro --google-tags doh,dnscrypt,g-node --google-machine-image https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-7-v20180507 g-node 33 | # use "--google-preemptible" for testing 34 | 35 | # https://rancher.com/docs/os/v1.1/en/running-rancheros/cloud/gce/ 36 | # https://cloud.google.com/sdk/gcloud/reference/compute/instances/create 37 | #gcloud compute instances create g-node --zone australia-southeast1-a --machine-type f1-micro --image xxxxxxxxxxxxxx 38 | 39 | gcloud compute ssh g-node 40 | docker-machine ssh g-node 41 | 42 | eval "$(docker-machine env g-node)" # for fish: eval (docker-machine env g-node) 43 | ``` 44 | For logging I suggest you follow: https://cloud.google.com/community/tutorials/docker-gcplogs-driver 45 | 46 | # [Docker Swarm](https://docs.docker.com/engine/swarm/) Setup 47 | 48 | ```sh 49 | eval "$(docker-machine env rancher-node)" # for fish: eval (docker-machine env rancher-node) 50 | docker-machine ls 51 | 52 | docker swarm init --advertise-addr node_ip_address_from_docker-machine_ls 53 | # docker swarm join --token your_swarm_token manager_node_ip_address:2377 54 | docker node ls 55 | 56 | # Add Cloudflare API key for acme.sh to do domain validation via DNS 57 | echo "email@example.com" | docker secret create CF_Email - 58 | echo "xxxxxxxxxxxxxx" | docker secret create CF_Key - 59 | 60 | # You need to modify docker-compose.yml to your needs: 61 | # - Change the domain name for certificate generation (TLS) 62 | # - Change the acme.sh script if you are not using Cloudflare 63 | # - Change dnscrypt-wrapper external IP address and provider name 64 | # - Change memory allocations / limits 65 | # - Change any port allocations if you desire 66 | docker stack deploy --compose-file=docker-compose.yml dns-server 67 | docker ps -a 68 | 69 | # Some useful commands 70 | docker-machine ssh rancher-node 71 | docker-machine ip rancher-node 72 | docker logs xxxxxxxxxxxxxx 73 | docker exec -it xxxxxxxxxxxxxx sh 74 | docker exec -it xxxxxxxxxxxxxx /entrypoint.sh provider-info # for dnscrypt-wrapper 75 | docker stack rm dns-server # when things go wrong and you need to start form a blank slate 76 | docker run --rm -it sh # debug a docker build 77 | ``` 78 | 79 | ## Local development with virtualbox 80 | 81 | ```sh 82 | docker-machine create -d virtualbox local 83 | # docker-machine create -d virtualbox --virtualbox-boot2docker-url https://releases.rancher.com/os/latest/rancheros.iso 84 | eval "$(docker-machine env local)" # for fish: eval (docker-machine env local) 85 | ``` 86 | -------------------------------------------------------------------------------- /doh-proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest as doh-proxy-build 2 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 3 | ENV REVISION 1 4 | ARG VERSION=0.9.9 5 | 6 | ENV RUSTFLAGS "-C link-arg=-s" 7 | RUN cargo install doh-proxy --version $VERSION --target=x86_64-unknown-linux-gnu && \ 8 | strip --strip-all /usr/local/cargo/bin/doh-proxy 9 | 10 | #------------------------------------------------------------------------------# 11 | FROM ubuntu:22.04 12 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 13 | LABEL maintainer="publicarray" 14 | LABEL description="A DNS-over-HTTP server proxy in Rust. https://github.com/DNSCrypt/doh-server" 15 | 16 | RUN apt-get update && \ 17 | apt-get install -qy --no-install-recommends bash libc6 curl ca-certificates dnsutils libssl3 && \ 18 | rm -fr /tmp/* /var/tmp/* /var/cache/apt/* /var/lib/apt/lists/* /var/log/apt/* /var/log/*.log 19 | RUN update-ca-certificates 2> /dev/null || true 20 | COPY --from=doh-proxy-build /usr/local/cargo/bin/doh-proxy /usr/local/bin/doh-proxy 21 | 22 | RUN set -x && \ 23 | groupadd _doh_proxy && \ 24 | useradd -g _doh_proxy -s /dev/null -d /dev/null _doh_proxy 25 | 26 | USER _doh_proxy 27 | 28 | COPY entrypoint.sh / 29 | 30 | EXPOSE 3000/udp 3000/tcp 31 | 32 | RUN doh-proxy --version 33 | 34 | HEALTHCHECK --start-period=5s --interval=2m \ 35 | CMD curl -f -H 'accept: application/dns-message' 'http://127.0.0.1:3000/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' >/dev/null || exit 1 36 | 37 | ENTRYPOINT ["/entrypoint.sh"] 38 | -------------------------------------------------------------------------------- /doh-proxy/doh-proxy-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: doh-proxy 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: dns-server 9 | component: doh-proxy 10 | strategy: 11 | type: Recreate 12 | replicas: 1 13 | template: 14 | metadata: 15 | labels: 16 | app: dns-server 17 | component: doh-proxy 18 | spec: 19 | containers: 20 | - name: doh-proxy 21 | image: publicarray/doh-proxy 22 | # command: ["/entrypoint.sh"] 23 | ports: 24 | - name: dns 25 | containerPort: 3000 26 | # resources: 27 | # requests: 28 | # cpu: 100m 29 | # memory: 50Mi 30 | restartPolicy: Always 31 | -------------------------------------------------------------------------------- /doh-proxy/doh-proxy-srv.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: doh-proxy 5 | labels: 6 | app: dns-server 7 | component: doh-proxy 8 | spec: 9 | selector: 10 | app: dns-server 11 | component: doh-proxy 12 | ports: 13 | - name: doh-tcp 14 | protocol: TCP 15 | port: 3000 16 | targetPort: 3000 17 | # type: ClusterIP 18 | -------------------------------------------------------------------------------- /doh-proxy/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | getServiceIP () { 5 | dig "$1" +short 6 | } 7 | 8 | waitOrFail () { 9 | maxTries=24 10 | i=0 11 | while [ $i -lt $maxTries ]; do 12 | outStr="$($@)" 13 | if [ $? -eq 0 ];then 14 | echo "$outStr" 15 | return 16 | fi 17 | i=$((i+1)) 18 | echo "==> waiting for a dependent service $i/$maxTries" >&2 19 | sleep 5 20 | done 21 | echo "Too many failed attempts" >&2 22 | exit 1 23 | } 24 | 25 | UNBOUND_SERVICE_HOST=${UNBOUND_SERVICE_HOST-"1.1.1.1"} 26 | UNBOUND_SERVICE_PORT=${UNBOUND_SERVICE_PORT-"53"} 27 | while getopts "h?d" opt; do 28 | case "$opt" in 29 | h|\?) echo "-d domain lookup for service discovery"; exit 0;; 30 | d) UNBOUND_SERVICE_HOST="$(waitOrFail getServiceIP unbound)" 31 | ;; 32 | esac 33 | done 34 | shift $((OPTIND-1)) 35 | export RESOLVER="$UNBOUND_SERVICE_HOST:$UNBOUND_SERVICE_PORT" 36 | 37 | if [ $# -eq 0 ]; then 38 | echo "doh-proxy - resolver: $RESOLVER" 39 | exec /usr/local/bin/doh-proxy --server-address "${RESOLVER}" --listen-address 0.0.0.0:3000 40 | fi 41 | 42 | [ "$1" = '--' ] && shift 43 | 44 | exec /usr/local/bin/doh-proxy "$@" 45 | -------------------------------------------------------------------------------- /haproxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.19 as build 2 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 3 | LABEL maintainer="publicarray" 4 | LABEL description="The Reliable, High Performance TCP/HTTP Load Balancer" 5 | # https://github.com/docker-library/haproxy/tree/master 6 | 7 | ENV HAPROXY_BUILD_DEPS gcc ca-certificates libc-dev linux-headers make openssl-dev pcre2-dev readline-dev tar zlib-dev 8 | RUN apk add --no-cache $HAPROXY_BUILD_DEPS 9 | 10 | ENV HAPROXY_VERSION_SHORT 2.9 11 | ENV HAPROXY_VERSION 2.9.7 12 | ENV HAPROXY_SHA256 d1a0a56f008a8d2f007bc0c37df6b2952520d1f4dde33b8d3802710e5158c131 13 | ENV HAPROXY_DOWNLOAD_URL "https://www.haproxy.org/download/${HAPROXY_VERSION_SHORT}/src/haproxy-${HAPROXY_VERSION}.tar.gz" 14 | 15 | RUN set -x && \ 16 | mkdir -p /tmp/src/haproxy && \ 17 | cd /tmp/src/haproxy && \ 18 | wget -O haproxy.tar.gz $HAPROXY_DOWNLOAD_URL && \ 19 | echo "${HAPROXY_SHA256} *haproxy.tar.gz" | sha256sum -c - && \ 20 | tar xzf haproxy.tar.gz -C /tmp/src/haproxy --strip-components=1 && \ 21 | nproc="$(getconf _NPROCESSORS_ONLN)" && \ 22 | makeOpts=' \ 23 | TARGET=linux-musl \ 24 | USE_GETADDRINFO=1 \ 25 | USE_OPENSSL=1 \ 26 | USE_QUIC=1 \ 27 | USE_QUIC_OPENSSL_COMPAT=1 \ 28 | USE_PCRE2=1 \ 29 | USE_PCRE2_JIT=1 \ 30 | USE_ZLIB=1 \ 31 | ' && \ 32 | eval "make $makeOpts -j '$nproc' all" && \ 33 | eval "make $makeOpts install-bin" 34 | 35 | #------------------------------------------------------------------------------# 36 | FROM alpine:3.19 37 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 38 | 39 | ENV HAPROXY_RUN_DEPS curl shadow zlib pcre2 openssl socat runit coreutils bind-tools 40 | 41 | RUN apk add --no-cache $HAPROXY_RUN_DEPS 42 | 43 | COPY --from=build /usr/local/sbin/haproxy /usr/local/sbin/haproxy 44 | COPY --from=build /tmp/src/haproxy/examples/errorfiles /usr/local/etc/haproxy/errors 45 | 46 | RUN set -x && \ 47 | groupadd _haproxy && \ 48 | useradd -g _haproxy -s /dev/null -d /dev/null _haproxy && \ 49 | mkdir -p \ 50 | /etc/service/haproxy/ \ 51 | /run/haproxy/ \ 52 | update-ca-certificates 2> /dev/null || true 53 | 54 | COPY entrypoint.sh / 55 | COPY haproxy.conf /etc/haproxy.conf 56 | COPY haproxy.sh /etc/service/haproxy/run 57 | # wget https://ssl-config.mozilla.org/ffdhe2048.txt -O /opt/ssl/dhparam.pem 58 | COPY ffdhe2048.txt /opt/ssl/dhparam.pem 59 | 60 | VOLUME ["/opt/ssl"] 61 | 62 | EXPOSE 853/udp 853/tcp 443/udp 443/tcp 63 | 64 | RUN haproxy -vv 65 | RUN haproxy -f /etc/haproxy.conf -c || true 66 | 67 | # Gracefully exit 68 | # All services are then put into soft-stop state, 69 | # which means that they will refuse to accept new connections 70 | STOPSIGNAL SIGUSR1 71 | 72 | # HEALTHCHECK --start-period=5s --interval=3m \ 73 | # CMD curl -f -H 'accept: application/dns-message' -k 'https://127.0.0.1/dns-query?ct&dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB'>/dev/null || exit 1 74 | 75 | ENTRYPOINT ["/entrypoint.sh"] 76 | -------------------------------------------------------------------------------- /haproxy/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -x 4 | 5 | getServiceIP () { 6 | for arg 7 | do dig "$arg" +short 8 | done 9 | } 10 | 11 | waitOrFail () { 12 | maxTries=24 13 | i=0 14 | while [ $i -lt $maxTries ]; do 15 | outStr="$($@)" 16 | if [ $? -eq 0 ];then 17 | echo "$outStr" 18 | return 19 | fi 20 | i=$((i+1)) 21 | echo "==> waiting for a dependent service $i/$maxTries" >&2 22 | sleep 5 23 | done 24 | echo "Too many failed attempts" >&2 25 | exit 1 26 | } 27 | 28 | UNBOUND_SERVICE_HOST=${UNBOUND_SERVICE_HOST-"1.1.1.1"} 29 | UNBOUND_SERVICE_PORT=${UNBOUND_SERVICE_PORT-"53"} 30 | DOH_PROXY_SERVICE_HOST=${DOH_PROXY_SERVICE_HOST-"127.0.0.1"} 31 | DOH_PROXY_SERVICE_PORT=${DOH_PROXY_SERVICE_PORT-"3000"} 32 | 33 | if [ ! -f /opt/ssl/dhparam.pem ]; then 34 | openssl dhparam -out /opt/ssl/dhparam.pem 4096 35 | fi 36 | 37 | while getopts "h?dr" opt; do 38 | case "$opt" in 39 | h|\?) 40 | echo "-d domain lookup for service discovery"; 41 | echo "-r uncomment lines in haproxy.conf with the word 'redirect' in them"; 42 | exit 0 43 | ;; 44 | d) 45 | UNBOUND_SERVICE_HOST="$(waitOrFail getServiceIP unbound)" 46 | DOH_PROXY_SERVICE_HOST="$(waitOrFail getServiceIP doh-proxy m13253-doh)" 47 | ;; 48 | r) 49 | sed -i '/^#.* redirect /s/^#//' /etc/haproxy.conf 50 | ;; 51 | esac 52 | done 53 | shift $((OPTIND-1)) 54 | export RESOLVER="$UNBOUND_SERVICE_HOST:$UNBOUND_SERVICE_PORT" 55 | export DOH_SERVER="$DOH_PROXY_SERVICE_HOST:$DOH_PROXY_SERVICE_PORT" 56 | 57 | sed -i -e "s/server doh-proxy .*/server doh-proxy ${DOH_SERVER}/" \ 58 | -e "s/server dns .*/server dns ${RESOLVER}/" \ 59 | /etc/haproxy.conf 60 | 61 | if [ $# -eq 0 ]; then 62 | exec /sbin/runsvdir -P /etc/service 63 | fi 64 | 65 | [ "$1" = '--' ] && shift 66 | /sbin/runsvdir -P /etc/service 67 | exec "$@" 68 | -------------------------------------------------------------------------------- /haproxy/ffdhe2048.txt: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz 3 | +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a 4 | 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 5 | YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi 6 | 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD 7 | ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== 8 | -----END DH PARAMETERS----- -------------------------------------------------------------------------------- /haproxy/haproxy-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | namespace: default 5 | labels: 6 | service: haproxy 7 | name: haproxy 8 | spec: 9 | strategy: 10 | type: Recreate 11 | replicas: 1 12 | template: 13 | metadata: 14 | labels: 15 | app: dns-server 16 | component: haproxy 17 | spec: 18 | containers: 19 | - env: 20 | image: publicarray/haproxy 21 | name: haproxy 22 | ports: 23 | - name: dns-over-tls 24 | containerPort: 853 25 | - name: doh 26 | containerPort: 443 27 | volumeMounts: 28 | - name: ssl 29 | mountPath: /opt/ssl 30 | # command: ["/usr/local/sbin/haproxy", "-f", "/etc/haproxy.conf"] 31 | # resources: 32 | # requests: 33 | # memory: "1Gi" 34 | restartPolicy: Always 35 | volumes: 36 | - name: ssl 37 | hostPath: 38 | path: /data/ssl 39 | type: DirectoryOrCreate 40 | -------------------------------------------------------------------------------- /haproxy/haproxy-srv.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: haproxy 5 | labels: 6 | app: dns-server 7 | component: haproxy 8 | spec: 9 | selector: 10 | app: dns-server 11 | component: haproxy 12 | ports: 13 | - name: dns-over-tls-tcp 14 | protocol: TCP 15 | port: 853 16 | targetPort: 853 17 | - name: dns-over-tls-udp 18 | protocol: UDP 19 | port: 853 20 | targetPort: 853 21 | - name: doh-tcp 22 | protocol: TCP 23 | port: 443 24 | targetPort: 443 25 | - name: doh-udp 26 | protocol: UDP 27 | port: 443 28 | targetPort: 443 29 | type: NodePort 30 | -------------------------------------------------------------------------------- /haproxy/haproxy.conf: -------------------------------------------------------------------------------- 1 | global 2 | log stdout format raw local0 3 | stats socket /run/haproxy/admin.sock mode 660 level admin 4 | stats socket ipv4@127.0.0.1:9000 level admin 5 | stats timeout 2m 6 | hard-stop-after 30s 7 | #maxconn 4000 8 | # chroot /var/haproxy 9 | user _haproxy 10 | group _haproxy 11 | # daemon 12 | pidfile /var/run/haproxy.pid 13 | ## SSL/TLS config 14 | # generated 2019-09-08, https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.4&config=intermediate 15 | ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 16 | ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 17 | ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets 18 | # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam.pem 19 | ssl-dh-param-file /opt/ssl/dhparam.pem 20 | defaults 21 | log global 22 | mode http 23 | option dontlognull 24 | option redispatch 25 | option splice-auto 26 | retries 1 27 | # https://delta.blue/blog/haproxy-timeouts 28 | timeout connect 5s 29 | timeout check 5s 30 | timeout queue 10s 31 | timeout client 30s 32 | timeout client-fin 3s 33 | timeout server-fin 3s 34 | timeout server 30s 35 | timeout tunnel 20m 36 | timeout http-request 10s 37 | 38 | frontend dns-over-tls-in 39 | mode tcp 40 | option tcplog 41 | bind 0.0.0.0:853 ssl crt /opt/ssl/fullchain-key.pem.ecdsa 42 | bind :::853 v6only ssl crt /opt/ssl/fullchain-key.pem.ecdsa 43 | default_backend dns-servers 44 | 45 | frontend doh-in 46 | http-response set-header Strict-Transport-Security "max-age=63072000" 47 | bind 0.0.0.0:443 ssl crt /opt/ssl/fullchain-key.pem.ecdsa alpn h2 48 | bind :::443 v6only ssl crt /opt/ssl/fullchain-key.pem.ecdsa alpn h2 49 | 50 | acl dns_url path /dns-query 51 | redirect location https://dns.seby.io code 301 if !dns_url { hdr(host) -i dns.seby.io } 52 | redirect location https://dns.seby.io code 301 if !dns_url { hdr(host) -i www.dns.seby.io } 53 | redirect location https://dns.seby.io code 301 if !dns_url { hdr(host) -i dot.seby.io } 54 | redirect location https://dns.seby.io code 301 if !dns_url { hdr(host) -i www.dot.seby.io } 55 | redirect location https://dns.seby.io code 301 if !dns_url { hdr(host) -i doh.seby.io } 56 | redirect location https://dns.seby.io code 301 if !dns_url { hdr(host) -i www.doh.seby.io } 57 | redirect location https://www.ntppool.org/en/ code 301 if !dns_url { hdr(host) -i ntppool.org } 58 | 59 | use_backend doh-servers if dns_url 60 | default_backend no-match 61 | 62 | backend no-match 63 | http-request deny deny_status 400 64 | 65 | backend dns-servers 66 | mode tcp 67 | server dns 127.0.0.1:53 maxconn 20 68 | 69 | backend doh-servers 70 | #option forwardfor 71 | http-response del-header server 72 | http-response del-header x-powered-by 73 | server doh-proxy 127.0.0.1:3000 maxconn 20 74 | -------------------------------------------------------------------------------- /haproxy/haproxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | exec /usr/local/sbin/haproxy -V -f /etc/haproxy.conf 5 | -------------------------------------------------------------------------------- /haproxy/ocsp-updater.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -x 4 | set -e 5 | 6 | # https://www.haproxy.com/blog/haproxy-1-9-has-arrived/ 7 | # https://icicimov.github.io/blog/server/HAProxy-OCSP-stapling/ 8 | 9 | # Certificates path and names 10 | DIR="/opt/ssl" 11 | CERT="fullchain-key.pem" 12 | CERT_RSA="fullchain-key.pem.rsa" 13 | CERT_ECC="fullchain-key.pem.ecdsa" 14 | RUNTIME_API=/run/haproxy/admin.sock 15 | 16 | create_ocsp () { 17 | CERT=$1 18 | 19 | # Get the issuer URI, download it's certificate and convert into PEM format 20 | ISSUER_URI=$(openssl x509 -in ${DIR}/${CERT} -text -noout | grep 'CA Issuers' | cut -d: -f2,3) 21 | ISSUER_NAME=letsencrypt 22 | if [ -z "$ISSUER_URI" ]; then 23 | return 24 | fi 25 | 26 | wget -q -O- "$ISSUER_URI" | openssl x509 -inform DER -outform PEM -out ${DIR}/${ISSUER_NAME}.pem 27 | 28 | # Get the OCSP URL from the certificate 29 | ocsp_url=$(openssl x509 -noout -ocsp_uri -in ${DIR}/${CERT}) 30 | 31 | # Extract the hostname from the OCSP URL 32 | ocsp_host=$(echo "$ocsp_url" | cut -d/ -f3) 33 | 34 | # Create/update the ocsp response file and update HAProxy 35 | openssl ocsp -noverify -no_nonce -issuer ${DIR}/${ISSUER_NAME}.pem -cert ${DIR}/${CERT} -url "$ocsp_url" -header Host="$ocsp_host" -respout ${DIR}/${CERT}.ocsp 36 | [ $? -eq 0 ] && [ "$(pidof haproxy)" ] && [ -s ${DIR}/${CERT}.ocsp ] && echo "set ssl ocsp-response $(base64 -w 0 ${DIR}/${CERT}.ocsp)" | socat $RUNTIME_API stdio 37 | } 38 | 39 | create_ocsp $CERT 40 | create_ocsp $CERT_RSA 41 | create_ocsp $CERT_ECC 42 | 43 | sleep 259200 # 3 days 44 | exit 0 45 | -------------------------------------------------------------------------------- /kube.md: -------------------------------------------------------------------------------- 1 | ## Getting Started with [Kubernetes](https://kubernetes.io) 2 | 3 | ```sh 4 | minikube delete 5 | minikube start 6 | kubectl create -f cloudflare-secret.yml 7 | # kubectl get secrets 8 | # kubectl get secret cloudflare -o yaml 9 | 10 | kubectl create -f acme-init-job.yml 11 | kubectl create -f dnscrypt-wrapper/dnscrypt-init-job.yml 12 | 13 | kubectl create -f nsd/nsd-srv.yml 14 | kubectl create -f unbound/unbound-srv.yml 15 | kubectl create -f doh-proxy/doh-proxy-srv.yml 16 | kubectl create -f haproxy/haproxy-srv.yml 17 | kubectl create -f dnscrypt-wrapper/dnscrypt-srv.yml 18 | 19 | kubectl create -f nsd/nsd-deployment.yml 20 | kubectl create -f unbound/unbound-deployment.yml 21 | kubectl create -f doh-proxy/doh-proxy-deployment.yml 22 | kubectl create -f haproxy/haproxy-deployment.yml 23 | kubectl create -f dnscrypt-wrapper/dnscrypt-deployment.yml 24 | ``` 25 | 26 | Workflow 27 | 28 | ```sh 29 | kubectl delete job/acme-init 30 | kubectl create -f acme-init-job.yml 31 | kubectl logs job/acme-init 32 | kubectl get jobs 33 | kubectl describe job/acme-init 34 | ``` 35 | 36 | Dashboard 37 | 38 | ```sh 39 | kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml 40 | # or 41 | minikube dashboard 42 | ``` 43 | 44 | Debugging 45 | 46 | ```sh 47 | kubectl get nodes 48 | kubectl get jobs 49 | kubectl get deployments 50 | kubectl get services 51 | kubectl get pods -o wide 52 | kubectl get all -l app=dns-server 53 | 54 | ## SSH into the container/pod 55 | #export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') 56 | kubectl get pods 57 | kubectl logs job/dnscrypt-init 58 | kubectl exec -ti $POD_NAME sh 59 | kubectl exec -ti $(kubectl get pods | grep 'unbound' | awk '{print $1}') sh 60 | 61 | ## SSH into a new neighbouring container/pod 62 | kubectl run busybox -it --image=busybox --restart=Never --rm 63 | kubectl run alpine -it --image=alpine --restart=Never --rm 64 | 65 | minikube ssh 66 | 67 | kubectl logs deployment/nsd 68 | kubectl describe deployment/nsd 69 | ``` 70 | 71 | Build docker images 72 | 73 | ```sh 74 | docker build -t publicarray/nsd nsd/ 75 | docker build -t publicarray/unbound unbound/ 76 | docker build -t publicarray/doh-proxy doh-proxy/ 77 | docker build -t publicarray/haproxy haproxy/ 78 | docker build -t publicarray/dnscrypt-wrapper dnscrypt-wrapper/ 79 | docker images 80 | docker push publicarray/unbound 81 | 82 | docker run --rm --name myunbound -it publicarray/unbound sh 83 | docker run -p 5300:53/udp -v (pwd)/unbound/unbound.conf:/etc/unbound/unbound.conf:ro --name myunbound publicarray/unbound 84 | docker run -p 4430:443/udp -p 4430:443/tcp --name=dnscrypt-server dnscrypt init -N example.com -E 127.0.0.1:4430 85 | docker start dnscrypt-server 86 | 87 | docker rm dnscrypt-server --force 88 | ``` 89 | -------------------------------------------------------------------------------- /lint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # yarn 4 | find . -not -path "./node_modules/*" -type f -name Dockerfile | xargs -L1 node_modules/.bin/dockerlint 5 | # find . -not -path "./node_modules/*" -type f -name Dockerfile | xargs -L1 node_modules/.bin/dockerfile_lint -f 6 | find . -not -path "./node_modules/*" -type f -name Dockerfile | xargs -L1 node_modules/.bin/dockerfilelint -c . 7 | 8 | if command -v hadolint >/dev/null; then 9 | find . -not -path "./node_modules/*" -type f -name Dockerfile | xargs -L1 hadolint 10 | else 11 | echo "For more linting install hadolint 'brew install hadolint'" 12 | fi 13 | -------------------------------------------------------------------------------- /logo/horizonal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/publicarray/dns-resolver-infra/c0f32be0b0956088d355361a204df5b1fce990ee/logo/horizonal.png -------------------------------------------------------------------------------- /logo/icon-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/publicarray/dns-resolver-infra/c0f32be0b0956088d355361a204df5b1fce990ee/logo/icon-transparent.png -------------------------------------------------------------------------------- /logo/icon-transparent.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /logo/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/publicarray/dns-resolver-infra/c0f32be0b0956088d355361a204df5b1fce990ee/logo/icon.png -------------------------------------------------------------------------------- /logo/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 8 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 43 | 47 | 50 | 51 | 56 | 60 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /logo/monochrome_horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/publicarray/dns-resolver-infra/c0f32be0b0956088d355361a204df5b1fce990ee/logo/monochrome_horizontal.png -------------------------------------------------------------------------------- /logo/monochrome_horizontal.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 18 | 22 | 35 | 36 | 37 | 39 | 43 | 47 | 51 | 61 | 62 | 63 | 67 | 78 | 91 | 103 | 104 | 106 | 117 | 121 | 122 | 123 | 124 | 126 | 127 | 130 | 133 | 136 | 139 | 142 | 145 | 148 | 151 | 154 | 157 | 162 | 166 | 169 | 170 | 175 | 179 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /logo/monochrome_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/publicarray/dns-resolver-infra/c0f32be0b0956088d355361a204df5b1fce990ee/logo/monochrome_icon.png -------------------------------------------------------------------------------- /logo/monochrome_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 13 | 16 | 19 | 22 | 25 | 28 | 31 | 34 | 37 | 40 | 45 | 49 | 52 | 53 | 58 | 62 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /logo/monochrome_vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/publicarray/dns-resolver-infra/c0f32be0b0956088d355361a204df5b1fce990ee/logo/monochrome_vertical.png -------------------------------------------------------------------------------- /logo/monochrome_vertical.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 10 | 11 | 14 | 17 | 20 | 23 | 26 | 29 | 32 | 35 | 38 | 41 | 46 | 50 | 53 | 54 | 59 | 63 | 69 | 70 | 71 | 72 | 73 | 82 | 85 | 98 | 99 | 103 | 114 | 127 | 139 | 140 | 142 | 153 | 157 | 158 | 160 | 164 | 168 | 172 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /logo/vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/publicarray/dns-resolver-infra/c0f32be0b0956088d355361a204df5b1fce990ee/logo/vertical.png -------------------------------------------------------------------------------- /m13253-doh/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine3.19 as doh-build 2 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 3 | LABEL maintainer="publicarray" 4 | LABEL description="High performance DNS over HTTPS server in golang. https://github.com/m13253/dns-over-https" 5 | ENV REVISION 2 6 | 7 | ENV DOH_BUILD_DEPS git make 8 | ENV COMMIT a2b984f816f858aa5d53ef59395b9ccabf20ae2f 9 | RUN apk add --no-cache $DOH_BUILD_DEPS 10 | 11 | RUN set -x && \ 12 | mkdir ~/gopath && \ 13 | export GOPATH=~/gopath && \ 14 | git clone https://github.com/m13253/dns-over-https.git && \ 15 | cd dns-over-https && \ 16 | git checkout ${COMMIT} && \ 17 | make && \ 18 | make install 19 | #------------------------------------------------------------------------------# 20 | FROM alpine:3.19 21 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 22 | 23 | ENV DOH_RUN_DEPS curl bind-tools 24 | 25 | RUN apk add --no-cache $DOH_RUN_DEPS 26 | 27 | COPY --from=0 /usr/local/bin/doh-server /usr/local/bin/doh-server 28 | 29 | COPY entrypoint.sh / 30 | COPY doh-server.conf /etc/dns-over-https/doh-server.conf 31 | 32 | EXPOSE 3000/udp 3000/tcp 33 | 34 | RUN /usr/local/bin/doh-server -version 35 | 36 | HEALTHCHECK --start-period=5s --interval=60s \ 37 | CMD curl -H 'accept: application/dns-message' 'http://127.0.0.1:3000/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' >/dev/null || exit 1 38 | 39 | ENTRYPOINT ["/entrypoint.sh"] 40 | -------------------------------------------------------------------------------- /m13253-doh/doh-proxy-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: m13253-doh 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: dns-server 9 | component: m13253-doh 10 | strategy: 11 | type: Recreate 12 | replicas: 1 13 | template: 14 | metadata: 15 | labels: 16 | app: dns-server 17 | component: m13253-doh 18 | spec: 19 | containers: 20 | - name: m13253-doh 21 | image: publicarray/m13253-doh 22 | # command: ["/entrypoint.sh"] 23 | ports: 24 | - name: dns 25 | containerPort: 3000 26 | # resources: 27 | # requests: 28 | # cpu: 100m 29 | # memory: 50Mi 30 | restartPolicy: Always 31 | -------------------------------------------------------------------------------- /m13253-doh/doh-proxy-srv.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: m13253-doh 5 | labels: 6 | app: dns-server 7 | component: m13253-doh 8 | spec: 9 | selector: 10 | app: dns-server 11 | component: m13253-doh 12 | ports: 13 | - name: doh-tcp 14 | protocol: TCP 15 | port: 3000 16 | targetPort: 3000 17 | # type: ClusterIP 18 | -------------------------------------------------------------------------------- /m13253-doh/doh-server.conf: -------------------------------------------------------------------------------- 1 | # HTTP listen port 2 | listen = [ 3 | "0.0.0.0:3000", 4 | ] 5 | 6 | # TLS certification file 7 | # If left empty, plain-text HTTP will be used. 8 | # You are recommended to leave empty and to use a server load balancer (e.g. 9 | # Caddy, Nginx) and set up TLS there, because this program does not do OCSP 10 | # Stapling, which is necessary for client bootstrapping in a network 11 | # environment with completely no traditional DNS service. 12 | cert = "" 13 | 14 | # TLS private key file 15 | key = "" 16 | 17 | # HTTP path for resolve application 18 | path = "/dns-query" 19 | 20 | # Upstream DNS resolver 21 | # If multiple servers are specified, a random one will be chosen each time. 22 | upstream = [ 23 | "udp:127.0.0.1:53", 24 | ] 25 | 26 | # Upstream timeout 27 | timeout = 12 28 | 29 | # Number of tries if upstream DNS fails 30 | tries = 2 31 | 32 | # Enable logging 33 | verbose = false 34 | 35 | # Enable log IP from HTTPS-reverse proxy header: X-Forwarded-For or X-Real-IP 36 | # Note: http uri/useragent log cannot be controlled by this config 37 | log_guessed_client_ip = false 38 | -------------------------------------------------------------------------------- /m13253-doh/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | getServiceIP () { 5 | dig "$1" +short 6 | } 7 | 8 | waitOrFail () { 9 | maxTries=24 10 | i=0 11 | while [ $i -lt $maxTries ]; do 12 | outStr="$($@)" 13 | if [ $? -eq 0 ];then 14 | echo "$outStr" 15 | return 16 | fi 17 | i=$((i+1)) 18 | echo "==> waiting for a dependent service $i/$maxTries" >&2 19 | sleep 5 20 | done 21 | echo "Too many failed attempts" >&2 22 | exit 1 23 | } 24 | 25 | UNBOUND_SERVICE_HOST=${UNBOUND_SERVICE_HOST-"1.1.1.1"} 26 | UNBOUND_SERVICE_PORT=${UNBOUND_SERVICE_PORT-"53"} 27 | while getopts "h?d:" opt; do 28 | case "$opt" in 29 | h|\?) echo "-d domain lookup for service discovery"; exit 0;; 30 | d) UNBOUND_SERVICE_HOST="$(waitOrFail getServiceIP "$OPTARG")" 31 | ;; 32 | esac 33 | done 34 | shift $((OPTIND-1)) 35 | export RESOLVER="$UNBOUND_SERVICE_HOST:$UNBOUND_SERVICE_PORT" 36 | echo "==> Configuring doh" 37 | sed \ 38 | -e "s/\"udp:127.0.0.1:53\"/\"udp:${RESOLVER}\"/g" \ 39 | -i "/etc/dns-over-https/doh-server.conf" 40 | 41 | if [ $# -eq 0 ]; then 42 | echo "doh - resolver: $RESOLVER" 43 | exec /usr/local/bin/doh-server -conf /etc/dns-over-https/doh-server.conf 44 | fi 45 | 46 | [ "$1" = '--' ] && shift 47 | 48 | exec /usr/local/bin/doh-server "$@" 49 | -------------------------------------------------------------------------------- /namespace.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespce 3 | metadata: 4 | name: dns 5 | -------------------------------------------------------------------------------- /nsd/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.19 as build 2 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 3 | LABEL maintainer="publicarray" 4 | LABEL description="NSD is an authoritative only, high performance, simple and open source name server. https://www.nlnetlabs.nl/projects/nsd/" 5 | ENV REVISION 2 6 | 7 | ENV NSD_BUILD_DEPS make tar gcc musl-dev libevent-dev openssl-dev 8 | 9 | RUN apk add --no-cache $NSD_BUILD_DEPS 10 | 11 | ARG NSD_VERSION=4.8.0 12 | ARG NSD_SHA256=820da4e384721915f4bcaf7f2bed98519da563c6e4c130c742c724760ec02a0a 13 | ARG NSD_DOWNLOAD_URL=https://www.nlnetlabs.nl/downloads/nsd/nsd-${NSD_VERSION}.tar.gz 14 | 15 | RUN set -x && \ 16 | mkdir -p /tmp/src && \ 17 | cd /tmp/src && \ 18 | wget -O nsd.tar.gz $NSD_DOWNLOAD_URL && \ 19 | echo "${NSD_SHA256} *nsd.tar.gz" | sha256sum -c - && \ 20 | tar xzf nsd.tar.gz && \ 21 | rm -f nsd.tar.gz && \ 22 | cd nsd-${NSD_VERSION} && \ 23 | ./configure --enable-root-server --with-configdir=/etc/nsd \ 24 | --with-user=_nsd --with-libevent \ 25 | CFLAGS="-O2 -flto -fPIE -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-strong -Wformat -Werror=format-security" \ 26 | LDFLAGS="-Wl,-z,now -Wl,-z,relro" && \ 27 | make install 28 | 29 | #------------------------------------------------------------------------------# 30 | FROM alpine:3.19 31 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 32 | 33 | ENV NSD_RUN_DEPS openssl libevent shadow drill 34 | RUN apk add --no-cache $NSD_RUN_DEPS 35 | 36 | COPY --from=build /usr/local/sbin/nsd /usr/local/sbin/nsd 37 | COPY --from=build /usr/local/sbin/nsd-control-setup /usr/local/sbin/nsd-control-setup 38 | COPY --from=build /usr/local/sbin/nsd-checkconf /usr/local/sbin/nsd-checkconf 39 | COPY --from=build /usr/local/sbin/nsd-checkzone /usr/local/sbin/nsd-checkzone 40 | COPY --from=build /usr/local/sbin/nsd-control /usr/local/sbin/nsd-control 41 | 42 | RUN set -x && \ 43 | groupadd _nsd && \ 44 | useradd -g _nsd -s /dev/null -d /dev/null _nsd && \ 45 | mkdir -p /etc/nsd/run/zonefiles /etc/service/nsd && \ 46 | chown _nsd:_nsd /etc/nsd/run/zonefiles && \ 47 | chown _nsd:_nsd /etc/nsd/run 48 | 49 | COPY nsd.conf /etc/nsd/nsd.conf 50 | COPY opennic.conf /etc/nsd/opennic.conf 51 | COPY entrypoint.sh / 52 | 53 | VOLUME ["/etc/nsd/run"] 54 | 55 | EXPOSE 53/udp 53/tcp 56 | 57 | RUN nsd -v 58 | RUN nsd-checkconf /etc/nsd/nsd.conf 59 | 60 | HEALTHCHECK --start-period=5s --interval=2m \ 61 | CMD ["drill", "-Q", "dns.opennic.glue", "@127.0.0.1", "SOA"] 62 | 63 | CMD ["-d"] 64 | 65 | ENTRYPOINT ["/entrypoint.sh"] 66 | -------------------------------------------------------------------------------- /nsd/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ ! -f /etc/nsd/nsd_server.pem ]; then 5 | nsd-control-setup 6 | fi 7 | 8 | [ "$1" = '--' ] && shift 9 | 10 | exec /usr/local/sbin/nsd "$@" 11 | -------------------------------------------------------------------------------- /nsd/nsd-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: nsd 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: dns-server 9 | component: nsd 10 | strategy: 11 | type: Recreate 12 | replicas: 1 13 | template: 14 | metadata: 15 | labels: 16 | app: dns-server 17 | component: nsd 18 | spec: 19 | containers: 20 | - name: nsd 21 | image: publicarray/nsd 22 | # command: ["/entrypoint.sh"] 23 | ports: 24 | - name: nsd 25 | containerPort: 53 26 | resources: 27 | requests: 28 | cpu: 100m 29 | memory: 500Mi 30 | restartPolicy: Always 31 | -------------------------------------------------------------------------------- /nsd/nsd-srv.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: nsd 5 | labels: 6 | app: dns-server 7 | component: nsd 8 | spec: 9 | selector: 10 | app: dns-server 11 | component: nsd 12 | ports: 13 | - name: nsd-tcp 14 | protocol: TCP 15 | port: 53 16 | targetPort: 53 17 | - name: nsd-udp 18 | protocol: UDP 19 | port: 53 20 | targetPort: 53 21 | # type: ClusterIP 22 | -------------------------------------------------------------------------------- /nsd/nsd.conf: -------------------------------------------------------------------------------- 1 | # https://www.nlnetlabs.nl/projects/nsd/nsd.conf.5.html 2 | # nsd.conf -- the NSD(8) configuration file, nsd.conf(5). 3 | # 4 | # Copyright (c) 2001-2011, NLnet Labs. All rights reserved. 5 | # 6 | # See LICENSE for the license. 7 | # 8 | 9 | server: 10 | # Number of NSD servers to fork. Put the number of CPUs to use here. 11 | server-count: 1 12 | 13 | # uncomment to specify specific interfaces to bind (default are the 14 | # wildcard interfaces 0.0.0.0 and ::0). 15 | # For servers with multiple IP addresses, list them one by one, 16 | # or the source address of replies could be wrong. 17 | # Use ip-transparent to be able to list addresses that turn on later. 18 | # ip-address: 1.2.3.4 19 | # ip-address: 1.2.3.4@5678 20 | # ip-address: 12fe::8ef0 21 | # ip-address: 127.0.0.1 22 | ip-address: 0.0.0.0 23 | 24 | # listen on IPv4 connections 25 | do-ip4: yes 26 | 27 | # listen on IPv6 connections 28 | do-ip6: yes 29 | 30 | # port to answer queries on. default is 53. 31 | port: 53 32 | 33 | # Verbosity level. 34 | verbosity: 0 35 | 36 | # After binding socket, drop user privileges. 37 | # can be a username, id or id.gid. 38 | username: _nsd 39 | 40 | 41 | # Run NSD in a chroot-jail. 42 | # make sure to have pidfile and database reachable from there. 43 | # by default, no chroot-jail is used. 44 | chroot: "/etc/nsd/run" 45 | 46 | # The directory where zone transfers are stored, in a subdir of it. 47 | xfrdir: "/etc/nsd/run/zonefiles" 48 | 49 | # File to store pid for nsd in. 50 | pidfile: "/etc/nsd/run/nsd.pid" 51 | 52 | # The file where secondary zone refresh and expire timeouts are kept. 53 | # If you delete this file, all secondary zones are forced to be 54 | # 'refreshing' (as if nsd got a notify). Set to "" to disable. 55 | xfrdfile: "/etc/nsd/run/ixfr.state" 56 | 57 | # the database to use 58 | # if set to "" then no disk-database is used, less memory usage. 59 | database: "/etc/nsd/run/nsd.db" 60 | 61 | # The directory for zonefile: files. The daemon chdirs here. 62 | zonesdir: "/etc/nsd/run/zonefiles" 63 | 64 | # the list of dynamically added zones. 65 | zonelistfile: "/etc/nsd/run/zone.list" 66 | 67 | # log messages to file. Default to stderr and syslog (with 68 | # facility LOG_DAEMON). stderr disappears when daemon goes to bg. 69 | # logfile: "/var/log/nsd.log" 70 | 71 | # don't answer VERSION.BIND and VERSION.SERVER CHAOS class queries 72 | hide-version: yes 73 | 74 | # statistics are produced every number of seconds. Prints to log. 75 | # Default is 0, meaning no statistics are produced. 76 | statistics: 0 77 | 78 | # use the reuseport socket option for performance. Default no. 79 | reuseport: yes 80 | 81 | # round robin rotation of records in the answer. 82 | round-robin: yes 83 | 84 | minimal-responses: no 85 | 86 | xfrd-reload-timeout: 1 87 | 88 | # write changed zonefiles to disk, every N seconds. 89 | # default is 0(disabled) or 3600(if database is ""). 90 | zonefiles-write: 3600 91 | 92 | # Optional local server config 93 | # include: "/etc/nsd/server.d/*.conf" 94 | 95 | # Include optional local configs. 96 | include: "/etc/nsd/opennic.conf" 97 | 98 | # Remote control config section. 99 | remote-control: 100 | # Enable remote control with nsd-control(8) here. 101 | # set up the keys and certificates with nsd-control-setup. 102 | control-enable: yes 103 | 104 | # what interfaces are listened to for control, default is on localhost. 105 | control-interface: 127.0.0.1 106 | 107 | # port number for remote control operations (uses TLS over TCP). 108 | control-port: 8952 109 | 110 | # nsd server key file for remote control. 111 | server-key-file: "/etc/nsd/nsd_server.key" 112 | 113 | # nsd server certificate file for remote control. 114 | server-cert-file: "/etc/nsd/nsd_server.pem" 115 | 116 | # nsd-control key file. 117 | control-key-file: "/etc/nsd/nsd_control.key" 118 | 119 | # nsd-control certificate file. 120 | control-cert-file: "/etc/nsd/nsd_control.pem" 121 | -------------------------------------------------------------------------------- /nsd/opennic.conf: -------------------------------------------------------------------------------- 1 | # https://servers.opennicproject.org/ 2 | # http://opennic.glue/ 3 | # https://wiki.opennic.org/opennic/t2slaved 4 | pattern: 5 | name: "opennic" 6 | # allow-notify: 45.56.115.189 NOKEY # ns0.opennic.glue 7 | # allow-notify: 45.56.116.224 NOKEY # ns0.opennic.glue 8 | allow-notify: 161.97.219.84 NOKEY # ns2.opennic.glue 9 | allow-notify: 2001:470:4212:10:0:100:53:10 NOKEY # ns2.opennic.glue 10 | # allow-notify: 104.168.144.17 NOKEY # ns3.opennic.glue 11 | # allow-notify: 2001:470:8269::53 NOKEY # ns3.opennic.glue 12 | allow-notify: 163.172.168.171 NOKEY # ns4.opennic.glue 13 | allow-notify: 2001:bc8:4400:2100::17:213 NOKEY # ns4.opennic.glue 14 | allow-notify: 94.103.153.176 NOKEY # ns5.opennic.glue 15 | allow-notify: 2a02:990:219:1:ba:1337:cafe:3 NOKEY # ns5.opennic.glue 16 | # allow-notify: 207.192.71.13 NOKEY # ns6.opennic.glue 17 | # allow-notify: 2002:cfc0:470d::1 NOKEY # ns6.opennic.glue 18 | allow-notify: 178.63.116.152 NOKEY # ns8.opennic.glue 19 | allow-notify: 2a01:4f8:141:4281::999 NOKEY # ns8.opennic.glue 20 | # allow-notify: 138.68.128.160 NOKEY # ns9.opennic.glue 21 | # allow-notify: 2a03:b0c0:1:a1::46b:a001 NOKEY # ns9.opennic.glue 22 | allow-notify: 188.226.146.136 NOKEY # ns10.opennic.glue 23 | allow-notify: 2001:470:1f04:ebf::2 NOKEY # ns10.opennic.glue 24 | # allow-notify: 45.55.97.204 NOKEY # ns11.opennic.glue 25 | # allow-notify: 2604:a880:800:a1::14c1:1 NOKEY # ns11.opennic.glue 26 | # allow-notify: 79.124.7.81 NOKEY # ns12.opennic.glue 27 | # allow-notify: 2a01:8740:1:ff13::ae67 NOKEY # ns12.opennic.glue 28 | allow-notify: 144.76.103.143 NOKEY # ns13.opennic.glue 29 | allow-notify: 2a01:4f8:192:43a5::2 NOKEY # ns13.opennic.glue 30 | 31 | # request-xfr: 45.56.115.189 NOKEY # ns0.opennic.glue 32 | # request-xfr: 45.56.116.224 NOKEY # ns0.opennic.glue 33 | request-xfr: 161.97.219.84 NOKEY # ns2.opennic.glue 34 | request-xfr: 2001:470:4212:10:0:100:53:10 NOKEY # ns2.opennic.glue 35 | # request-xfr: 104.168.144.17 NOKEY # ns3.opennic.glue 36 | # request-xfr: 2001:470:8269::53 NOKEY # ns3.opennic.glue 37 | request-xfr: 163.172.168.171 NOKEY # ns4.opennic.glue 38 | request-xfr: 2001:bc8:4400:2100::17:213 NOKEY # ns4.opennic.glue 39 | request-xfr: 94.103.153.176 NOKEY # ns5.opennic.glue 40 | request-xfr: 2a02:990:219:1:ba:1337:cafe:3 NOKEY # ns5.opennic.glue 41 | # request-xfr: 207.192.71.13 NOKEY # ns6.opennic.glue 42 | # request-xfr: 2002:cfc0:470d::1 NOKEY # ns6.opennic.glue 43 | request-xfr: 178.63.116.152 NOKEY # ns8.opennic.glue 44 | request-xfr: 2a01:4f8:141:4281::999 NOKEY # ns8.opennic.glue 45 | # request-xfr: 138.68.128.160 NOKEY # ns9.opennic.glue 46 | # request-xfr: 2a03:b0c0:1:a1::46b:a001 NOKEY # ns9.opennic.glue 47 | request-xfr: 188.226.146.136 NOKEY # ns10.opennic.glue 48 | request-xfr: 2001:470:1f04:ebf::2 NOKEY # ns10.opennic.glue 49 | # request-xfr: 45.55.97.204 NOKEY # ns11.opennic.glue 50 | # request-xfr: 2604:a880:800:a1::14c1:1 NOKEY # ns11.opennic.glue 51 | # request-xfr: 79.124.7.81 NOKEY # ns12.opennic.glue 52 | # request-xfr: 2a01:8740:1:ff13::ae67 NOKEY # ns12.opennic.glue 53 | request-xfr: 144.76.103.143 NOKEY # ns13.opennic.glue 54 | request-xfr: 2a01:4f8:192:43a5::2 NOKEY # ns13.opennic.glue 55 | 56 | pattern: 57 | name: "new-nations" # ns2.opennic.glue knows about ku -> dig @161.97.219.84 ns1.new-nations.ku | dig ku NS @161.97.219.84 58 | allow-notify: 5.45.96.220 NOKEY # ns1.new-nations.ku 59 | request-xfr: 5.45.96.220 NOKEY # ns1.new-nations.ku 60 | allow-notify: 185.82.22.133 NOKEY # ns2.new-nations.ku 61 | request-xfr: 185.82.22.133 NOKEY # ns2.new-nations.ku 62 | 63 | pattern: # nic.fur 64 | name: "fur" # dig nic.fur NS @188.40.132.212 65 | allow-notify: 188.40.132.212 NOKEY # ns8.nic.fur 66 | request-xfr: 188.40.132.212 NOKEY # ns8.nic.fur 67 | allow-notify: 178.63.26.172 NOKEY # ns10.nic.fur 68 | request-xfr: 178.63.26.172 NOKEY # ns10.nic.fur 69 | allow-notify: 2a01:4f8:141:4281::150 NOKEY # ns10.nic.fur 70 | request-xfr: 2a01:4f8:141:4281::150 NOKEY # ns10.nic.fur 71 | allow-notify: 178.63.145.230 NOKEY # ns12.nic.fur 72 | request-xfr: 178.63.145.230 NOKEY # ns12.nic.fur 73 | allow-notify: 2a01:4f8:101:3062::5:2 NOKEY # ns12.nic.fur 74 | request-xfr: 2a01:4f8:101:3062::5:2 NOKEY # ns12.nic.fur 75 | allow-notify: 151.236.24.112 NOKEY # ns13.nic.fur 76 | request-xfr: 151.236.24.112 NOKEY # ns13.nic.fur 77 | allow-notify: 178.63.145.236 NOKEY # ns15.nic.fur 78 | request-xfr: 178.63.145.236 NOKEY # ns15.nic.fur 79 | allow-notify: 2a01:4f8:221:1e01::1f:12 NOKEY # ns15.nic.fur 80 | request-xfr: 2a01:4f8:221:1e01::1f:12 NOKEY # ns15.nic.fur 81 | 82 | # dig txt tlds.opennic.glue @161.97.219.84 +short 83 | # https://wiki.opennic.org/opennic/dot 84 | zone: 85 | name: "dns.opennic.glue" 86 | zonefile: "%s.zone" 87 | include-pattern: opennic 88 | zone: 89 | name: "." 90 | zonefile: "%s.zone" 91 | include-pattern: opennic 92 | zone: 93 | name: "bbs" 94 | zonefile: "%s.zone" 95 | include-pattern: opennic 96 | zone: 97 | name: "bit" 98 | zonefile: "%s.zone" 99 | include-pattern: opennic 100 | zone: 101 | name: "chan" 102 | zonefile: "%s.zone" 103 | include-pattern: opennic 104 | zone: 105 | name: "cyb" 106 | zonefile: "%s.zone" 107 | include-pattern: opennic 108 | zone: 109 | name: "dyn" 110 | zonefile: "%s.zone" 111 | include-pattern: opennic 112 | zone: 113 | name: "epic" 114 | zonefile: "%s.zone" 115 | include-pattern: opennic 116 | # zone: 117 | # name: "free" 118 | # zonefile: "%s.zone" 119 | # include-pattern: opennic 120 | zone: 121 | name: "fur" 122 | zonefile: "%s.zone" 123 | include-pattern: fur 124 | zone: 125 | name: "geek" 126 | zonefile: "%s.zone" 127 | include-pattern: opennic 128 | zone: 129 | name: "gopher" 130 | zonefile: "%s.zone" 131 | include-pattern: opennic 132 | zone: 133 | name: "indy" 134 | zonefile: "%s.zone" 135 | include-pattern: opennic 136 | zone: 137 | name: "libre" 138 | zonefile: "%s.zone" 139 | include-pattern: opennic 140 | zone: 141 | name: "neo" 142 | zonefile: "%s.zone" 143 | include-pattern: opennic 144 | zone: 145 | name: "null" 146 | zonefile: "%s.zone" 147 | include-pattern: opennic 148 | zone: 149 | name: "o" 150 | zonefile: "%s.zone" 151 | include-pattern: opennic 152 | zone: 153 | name: "opennic.glue" 154 | zonefile: "%s.zone" 155 | include-pattern: opennic 156 | zone: 157 | name: "oss" 158 | zonefile: "%s.zone" 159 | include-pattern: opennic 160 | zone: 161 | name: "oz" 162 | zonefile: "%s.zone" 163 | include-pattern: opennic 164 | zone: 165 | name: "parody" 166 | zonefile: "%s.zone" 167 | include-pattern: opennic 168 | zone: 169 | name: "pirate" 170 | zonefile: "%s.zone" 171 | include-pattern: opennic 172 | zone: 173 | name: "ku" 174 | zonefile: "%s.zone" 175 | include-pattern: new-nations 176 | zone: 177 | name: "te" 178 | zonefile: "%s.zone" 179 | include-pattern: new-nations 180 | zone: 181 | name: "ti" 182 | zonefile: "%s.zone" 183 | include-pattern: new-nations 184 | zone: 185 | name: "uu" 186 | zonefile: "%s.zone" 187 | include-pattern: new-nations 188 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "bats": "^1.9.0", 4 | "bats-assert": "^2.0.0", 5 | "bats-support": "^0.3.0", 6 | "dockerfilelint": "^1.8.0", 7 | "dockerlint": "^0.3.9" 8 | }, 9 | "scripts": { 10 | "bats": "bats" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test-dog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set +x 4 | set -e 5 | 6 | if ! command -v dog; then 7 | echo "Please install dog first:" 8 | echo "https://github.com/ogham/dog/" 9 | exit 10 | fi 11 | 12 | step() { 13 | echo "=====> $@ <=====" 14 | } 15 | 16 | step 'test DNS -over-TLS:' 17 | dog -S @dot.seby.io example.com 18 | # dog -S @139.99.222.72 example.com 19 | # dog -S @45.76.113.31 example.com 20 | 21 | step 'test opennic:' 22 | 23 | # domains="opennic.glue grep.geek nic.fur be.libre register.null opennic.oz www.opennic.chan" 24 | for domain in $domains; do 25 | dog -S @dot.seby.io $domain 26 | # dog -S @139.99.222.72 $domain 27 | # dog -S @45.76.113.31 $domain 28 | done 29 | 30 | step 'test DNS-over-HTTPS' 31 | dog -H @https://doh.seby.io/dns-query example.com 32 | # dog -H @https://doh-2.seby.io/dns-query example.com 33 | dog -H @https://doh-1.seby.io/dns-query example.com 34 | 35 | step 'test for TLS 1.3' 36 | # echo "Q" | openssl s_client -connect 139.99.222.72:853 | grep TLSv1.3 37 | echo "Q" | openssl s_client -connect 45.76.113.31:853 | grep TLSv1.3 38 | # echo "Q" | openssl s_client -connect 139.99.222.72:443 | grep TLSv1.3 39 | echo "Q" | openssl s_client -connect 45.76.113.31:443 | grep TLSv1.3 40 | 41 | # step 'test dnscrypt-proxy:' 42 | 43 | # # fetch the public-resolvers.md 44 | # dnscrypt-proxy -config tests/publicarray-au.toml -show-certs 45 | 46 | # dnscrypt-proxy -config tests/publicarray-au-doh.toml & 47 | # sleep 1 48 | # dnscrypt-proxy -config tests/publicarray-au-doh.toml -resolve example.com 49 | # kill $(jobs -lp | tail) 50 | # dnscrypt-proxy -config tests/publicarray-au.toml & 51 | # sleep 1 52 | # dnscrypt-proxy -config tests/publicarray-au.toml -resolve example.com 53 | # kill $(jobs -lp | tail) 54 | # dnscrypt-proxy -config tests/publicarray-au2-doh.toml & 55 | # sleep 1 56 | # dnscrypt-proxy -config tests/publicarray-au2-doh.toml -resolve example.com 57 | # kill $(jobs -lp | tail) 58 | # dnscrypt-proxy -config tests/publicarray-au2.toml & 59 | # sleep 1 60 | # dnscrypt-proxy -config tests/publicarray-au2.toml -resolve example.com 61 | # kill $(jobs -lp | tail) 62 | # sleep 1 63 | # jobs -l 64 | # killall dnscrypt-proxy 65 | step 'All Tests Passed!' 66 | -------------------------------------------------------------------------------- /test-doggo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set +x 4 | set -e 5 | 6 | if ! command -v doggo; then 7 | echo "Please install doggo first:" 8 | echo "https://github.com/mr-karan/doggo" 9 | echo "Arch: yay -S doggo-bin" 10 | echo "macOS: brew install doggo" 11 | echo "Windows: scoop install doggo" 12 | echo "source: go install github.com/mr-karan/doggo/cmd/doggo@latest" 13 | exit 14 | fi 15 | 16 | step() { 17 | echo "=====> $@ <=====" 18 | } 19 | 20 | step 'test DNS -over-TLS:' 21 | 22 | doggo @tls://dot.seby.io example.com 23 | # doggo @tls://139.99.222.72 example.com 24 | # doggo @tls://45.76.113.31 example.com 25 | 26 | step 'test opennic:' 27 | 28 | # domains="opennic.glue grep.geek nic.fur be.libre register.null opennic.oz www.opennic.chan" 29 | for domain in $domains; do 30 | doggo @tls://dot.seby.io $domain 31 | # doggo @tls://139.99.222.72 $domain 32 | # doggo @tls://45.76.113.31 $domain 33 | done 34 | 35 | step 'test DNS-over-HTTPS' 36 | doggo @https://doh.seby.io/dns-query example.com 37 | doggo @https://doh-1.seby.io/dns-query example.com 38 | # doggo @https://doh-2.seby.io/dns-query example.com 39 | 40 | step 'test for TLS 1.3' 41 | # echo "Q" | openssl s_client -connect 139.99.222.72:853 | grep TLSv1.3 42 | echo "Q" | openssl s_client -connect 45.76.113.31:853 | grep TLSv1.3 43 | # echo "Q" | openssl s_client -connect 139.99.222.72:443 | grep TLSv1.3 44 | echo "Q" | openssl s_client -connect 45.76.113.31:443 | grep TLSv1.3 45 | 46 | # step 'test dnscrypt-proxy:' 47 | 48 | # fetch the public-resolvers.md 49 | # doggo example.com @sdns://AQcAAAAAAAAADDQ1Ljc2LjExMy4zMSAIVGh4i6eKXqlF6o9Fg92cgD2WcDvKQJ7v_Wq4XrQsVhsyLmRuc2NyeXB0LWNlcnQuZG5zLnNlYnkuaW8 50 | # doggo example.com @sdns://AgcAAAAAAAAADDQ1Ljc2LjExMy4zMaA-GhoPbFPz6XpJLVcIS1uYBwWe4FerFQWHb9g_2j24OCAyhv9lpl-vMghe6hOIw3OLp-N4c8kGzOPEootMwqWJiBBkb2guc2VieS5pbzo4NDQzCi9kbnMtcXVlcnk 51 | # doggo example.com @sdns://AQcAAAAAAAAAEjEzOS45OS4yMjIuNzI6ODQ0MyDR7bj6zoAmbRaE1B8qTkCL_O84QCDMYPUgXZy5FRqUYRsyLmRuc2NyeXB0LWNlcnQuZG5zLnNlYnkuaW8 52 | # doggo example.com @sdns://AgcAAAAAAAAADTEzOS45OS4yMjIuNzKgPhoaD2xT8-l6SS1XCEtbmAcFnuBXqxUFh2_YP9o9uDggMob_ZaZfrzIIXuoTiMNzi6fjeHPJBszjxKKLTMKliYgRZG9oLTIuc2VieS5pbzo0NDMKL2Rucy1xdWVyeQ 53 | 54 | step 'All Tests Passed!' 55 | -------------------------------------------------------------------------------- /test-infra.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -x 4 | 5 | minikube delete 6 | minikube start 7 | # Enable DNS service: https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/ 8 | # kubectl --namespace=kube-system scale deployment kube-dns --replicas=1 9 | 10 | sleep 10 # Wait for API port to open 11 | 12 | kubectl create -f cloudflare-secret.yml 13 | 14 | kubectl create -f acme-init-job.yml 15 | kubectl create -f dnscrypt-wrapper/dnscrypt-init-job.yml 16 | 17 | kubectl create -f acme-cron-job.yml 18 | 19 | sleep 65 # Wait for certificate from Let's Encrypt 20 | 21 | kubectl create -f nsd/nsd-srv.yml 22 | kubectl create -f unbound/unbound-srv.yml 23 | kubectl create -f doh-proxy/doh-proxy-srv.yml 24 | kubectl create -f haproxy/haproxy-srv.yml 25 | kubectl create -f dnscrypt-wrapper/dnscrypt-srv.yml 26 | 27 | kubectl create -f nsd/nsd-deployment.yml 28 | kubectl create -f unbound/unbound-deployment.yml 29 | kubectl create -f doh-proxy/doh-proxy-deployment.yml 30 | kubectl create -f haproxy/haproxy-deployment.yml 31 | kubectl create -f dnscrypt-wrapper/dnscrypt-deployment.yml 32 | 33 | sleep 180 #300# Wait for deployment 34 | 35 | kubectl get nodes 36 | kubectl get jobs 37 | kubectl get deployments 38 | kubectl get services 39 | kubectl get pods -o wide 40 | kubectl get all -l app=dns-server 41 | 42 | minikube ip 43 | kubectl get services 44 | kubectl logs job/dnscrypt-init 45 | minikube service dnscrypt --url 46 | minikube service haproxy --url 47 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # set +x 4 | # set -e 5 | 6 | # docker run -it --rm bats/bats:latest --tap 7 | # docker run -it -v "$PWD":/opt/bats" --workdir /opt/bats bats/bats:latest test 8 | 9 | npm i --legacy-peer-deps 10 | 11 | if ! command -v kdig; then 12 | echo "Please install knot first:" 13 | echo "https://www.knot-dns.cz/" 14 | echo "Arch: pacman -S knot" 15 | echo "macOS: brew install knot" 16 | exit 17 | fi 18 | 19 | npm run bats tests 20 | 21 | exit 22 | 23 | step() { 24 | echo "=====> $@ <=====" 25 | } 26 | # kdig -d @139.99.222.72 +tls-ca +tls-host=dot.seby.io example.com 27 | # kdig -d @45.76.113.31 +tls-ca +tls-host=dot.seby.io example.com 28 | 29 | step 'test DNS -over-TLS:' 30 | # kdig @139.99.222.72 +tls-ca +tls-host=dot.seby.io example.com 31 | kdig @45.76.113.31 +tls-ca +tls-host=dot.seby.io example.com 32 | 33 | step 'test opennic:' 34 | 35 | domains="opennic.glue grep.geek nic.fur be.libre register.null opennic.oz www.opennic.chan" 36 | # step '139.99.222.72' 37 | # for domain in $domains; do 38 | # kdig @139.99.222.72 +short +tls-ca +tls-host=dot.seby.io $domain 39 | # done 40 | step '45.76.113.31' 41 | for domain in $domains; do 42 | kdig @45.76.113.31 +short +tls-ca +tls-host=dot.seby.io $domain 43 | done 44 | # curl -v 'https://doh-2.seby.io/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | hexdump -C 45 | # curl -v 'https://doh.seby.io:8443/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | hexdump -C 46 | 47 | step 'test DNS-over-HTTPS' 48 | # curl -so /dev/null --doh-url https://doh.seby.io:8443/dns-query https://example.com 49 | curl 'https://doh.seby.io/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | hexdump -C 50 | curl 'https://doh-1.seby.io:443/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | hexdump -C 51 | # curl 'https://doh-2.seby.io:443/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | hexdump -C 52 | curl -H 'content-type: application/dns-message' 'https://doh.seby.io/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | hexdump -C 53 | curl -H 'content-type: application/dns-message' 'https://doh-1.seby.io/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | hexdump -C 54 | # curl -H 'content-type: application/dns-message' 'https://doh-2.seby.io/dns-query?dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | hexdump -C 55 | curl --doh-url https://doh.seby.io/dns-query https://ip.seby.io 56 | curl --doh-url https://doh-1.seby.io/dns-query https://ip.seby.io 57 | # curl --doh-url https://doh-2.seby.io/dns-query https://ip.seby.io 58 | 59 | step 'test for TLS 1.3' 60 | # echo "Q" | openssl s_client -connect 139.99.222.72:853 | grep TLSv1.3 61 | echo "Q" | openssl s_client -connect 45.76.113.31:853 | grep TLSv1.3 62 | # echo "Q" | openssl s_client -connect 139.99.222.72:443 | grep TLSv1.3 63 | echo "Q" | openssl s_client -connect 45.76.113.31:8443 | grep TLSv1.3 64 | 65 | # step 'test dnscrypt-proxy:' 66 | 67 | # echo doggo install 68 | 69 | # doggo example.com @sdns://AQcAAAAAAAAADDQ1Ljc2LjExMy4zMSAIVGh4i6eKXqlF6o9Fg92cgD2WcDvKQJ7v_Wq4XrQsVhsyLmRuc2NyeXB0LWNlcnQuZG5zLnNlYnkuaW8 70 | # doggo example.com @sdns://AgcAAAAAAAAADDQ1Ljc2LjExMy4zMaA-GhoPbFPz6XpJLVcIS1uYBwWe4FerFQWHb9g_2j24OCAyhv9lpl-vMghe6hOIw3OLp-N4c8kGzOPEootMwqWJiBBkb2guc2VieS5pbzo4NDQzCi9kbnMtcXVlcnk 71 | # doggo example.com @sdns://AQcAAAAAAAAAEjEzOS45OS4yMjIuNzI6ODQ0MyDR7bj6zoAmbRaE1B8qTkCL_O84QCDMYPUgXZy5FRqUYRsyLmRuc2NyeXB0LWNlcnQuZG5zLnNlYnkuaW8 72 | # doggo example.com @sdns://AgcAAAAAAAAADTEzOS45OS4yMjIuNzKgPhoaD2xT8-l6SS1XCEtbmAcFnuBXqxUFh2_YP9o9uDggMob_ZaZfrzIIXuoTiMNzi6fjeHPJBszjxKKLTMKliYgRZG9oLTIuc2VieS5pbzo0NDMKL2Rucy1xdWVyeQ 73 | 74 | # fetch the public-resolvers.md 75 | # dnscrypt-proxy -config tests/publicarray-au.toml -show-certs 76 | 77 | # dnscrypt-proxy -config tests/publicarray-au-doh.toml & 78 | # sleep 1 79 | # dnscrypt-proxy -config tests/publicarray-au-doh.toml -resolve example.com 80 | # kill $(jobs -lp | tail) 81 | # dnscrypt-proxy -config tests/publicarray-au.toml & 82 | # sleep 1 83 | # dnscrypt-proxy -config tests/publicarray-au.toml -resolve example.com 84 | # kill $(jobs -lp | tail) 85 | # dnscrypt-proxy -config tests/publicarray-au2-doh.toml & 86 | # sleep 1 87 | # dnscrypt-proxy -config tests/publicarray-au2-doh.toml -resolve example.com 88 | # kill $(jobs -lp | tail) 89 | # dnscrypt-proxy -config tests/publicarray-au2.toml & 90 | # sleep 1 91 | # dnscrypt-proxy -config tests/publicarray-au2.toml -resolve example.com 92 | # kill $(jobs -lp | tail) 93 | # sleep 1 94 | # jobs -l 95 | # killall dnscrypt-proxy 96 | step 'All Tests Passed!' 97 | -------------------------------------------------------------------------------- /tests/dnscrypt.bats.old: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | load ../node_modules/bats-support/load.bash 3 | load ../node_modules/bats-assert/load.bash 4 | 5 | # https://dnscrypt.info/stamps/ 6 | 7 | #@test "139.99.222.72 dnscrypt" { 8 | # run doggo example.com @sdns://AQcAAAAAAAAAEjEzOS45OS4yMjIuNzI6ODQ0MyDR7bj6zoAmbRaE1B8qTkCL_O84QCDMYPUgXZy5FRqUYRsyLmRuc2NyeXB0LWNlcnQuZG5zLnNlYnkuaW8 9 | # assert_output -p "example.com." 10 | #} 11 | #@test "139.99.222.72 DNS-over-HTTPS" { 12 | # run doggo example.com @sdns://AgcAAAAAAAAADTEzOS45OS4yMjIuNzKgPhoaD2xT8-l6SS1XCEtbmAcFnuBXqxUFh2_YP9o9uDggMob_ZaZfrzIIXuoTiMNzi6fjeHPJBszjxKKLTMKliYgRZG9oLTIuc2VieS5pbzo0NDMKL2Rucy1xdWVyeQ 13 | # assert_output -p "example.com." 14 | #} 15 | 16 | @test "45.76.113.31 dnscrypt" { 17 | run doggo example.com @sdns://AQcAAAAAAAAADDQ1Ljc2LjExMy4zMSAIVGh4i6eKXqlF6o9Fg92cgD2WcDvKQJ7v_Wq4XrQsVhsyLmRuc2NyeXB0LWNlcnQuZG5zLnNlYnkuaW8 18 | assert_output -p "example.com." 19 | } 20 | @test "45.76.113.31 DNS-over-HTTPS" { 21 | run doggo example.com @sdns://AgcAAAAAAAAADDQ1Ljc2LjExMy4zMaA-GhoPbFPz6XpJLVcIS1uYBwWe4FerFQWHb9g_2j24OCAyhv9lpl-vMghe6hOIw3OLp-N4c8kGzOPEootMwqWJiBBkb2guc2VieS5pbzo4NDQzCi9kbnMtcXVlcnk 22 | assert_output -p "example.com." 23 | } 24 | -------------------------------------------------------------------------------- /tests/doh.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | load ../node_modules/bats-support/load.bash 3 | load ../node_modules/bats-assert/load.bash 4 | 5 | exampledotcom="q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB" 6 | 7 | #@test "139.99.222.72 GET DNS-over-HTTPS" { 8 | # run curl "https://doh-2.seby.io/dns-query?dns=$exampledotcom" 9 | # assert_success 10 | #} 11 | 12 | 13 | #@test "139.99.222.72 GET with content-type DNS-over-HTTPS" { 14 | # run curl -H 'content-type: application/dns-message' "https://doh-2.seby.io/dns-query?dns=$exampledotcom" 15 | # assert_success 16 | #} 17 | 18 | #@test "139.99.222.72 curl-url DNS-over-HTTPS" { 19 | # run curl --doh-url https://doh-2.seby.io/dns-query https://ip.seby.io 20 | # assert_success 21 | #} 22 | 23 | @test "45.76.113.31 GET DNS-over-HTTPS" { 24 | run curl "https://doh-1.seby.io/dns-query?dns=$exampledotcom" 25 | assert_success 26 | } 27 | 28 | @test "45.76.113.31 GET with content-type DNS-over-HTTPS" { 29 | run curl -H 'content-type: application/dns-message' "https://doh-1.seby.io/dns-query?dns=$exampledotcom" 30 | assert_success 31 | } 32 | 33 | @test "45.76.113.31 curl-url DNS-over-HTTPS" { 34 | run curl --doh-url https://doh-1.seby.io/dns-query https://ip.seby.io 35 | assert_success 36 | } 37 | -------------------------------------------------------------------------------- /tests/dot.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | load ../node_modules/bats-support/load.bash 3 | load ../node_modules/bats-assert/load.bash 4 | 5 | #@test "139.99.222.72 DNS-over-TLS online" { 6 | # run kdig @139.99.222.72 +tls-ca +tls-host=dot.seby.io example.com 7 | # assert_success 8 | # assert_output -p "NOERROR;" 9 | #} 10 | 11 | @test "45.76.113.31 DNS-over-TLS online" { 12 | run kdig @45.76.113.31 +tls-ca +tls-host=dot.seby.io example.com 13 | assert_success 14 | assert_output -p "NOERROR;" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /tests/opennic.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | load ../node_modules/bats-support/load.bash 3 | load ../node_modules/bats-assert/load.bash 4 | 5 | domains="opennic.glue grep.geek nic.fur be.libre register.null opennic.oz www.opennic.chan" 6 | 7 | #@test "139.99.222.72 opennic.glue DNS-over-TLS" { 8 | # run kdig @139.99.222.72 +tls-ca +tls-host=dot.seby.io opennic.glue 9 | # assert_success 10 | # assert_output -p "NOERROR;" 11 | #} 12 | @test "45.76.113.31 opennic.glue DNS-over-TLS" { 13 | run kdig @45.76.113.31 +tls-ca +tls-host=dot.seby.io opennic.glue 14 | assert_success 15 | assert_output -p "NOERROR;" 16 | } 17 | 18 | #@test "139.99.222.72 grep.geek DNS-over-TLS" { 19 | # run kdig @139.99.222.72 +tls-ca +tls-host=dot.seby.io grep.geek 20 | # assert_success 21 | # assert_output -p "NOERROR;" 22 | #} 23 | @test "45.76.113.31 grep.geek DNS-over-TLS" { 24 | run kdig @45.76.113.31 +tls-ca +tls-host=dot.seby.io grep.geek 25 | assert_success 26 | assert_output -p "NOERROR;" 27 | } 28 | 29 | 30 | #@test "139.99.222.72 nic.fur DNS-over-TLS" { 31 | # run kdig @139.99.222.72 +tls-ca +tls-host=dot.seby.io nic.fur 32 | # assert_success 33 | # assert_output -p "NOERROR;" 34 | #} 35 | @test "45.76.113.31 nic.fur DNS-over-TLS" { 36 | run kdig @45.76.113.31 +tls-ca +tls-host=dot.seby.io nic.fur 37 | assert_success 38 | assert_output -p "NOERROR;" 39 | } 40 | 41 | #@test "139.99.222.72 be.libre DNS-over-TLS" { 42 | # run kdig @139.99.222.72 +tls-ca +tls-host=dot.seby.io be.libre 43 | # assert_success 44 | # assert_output -p "NOERROR;" 45 | #} 46 | @test "45.76.113.31 be.libre DNS-over-TLS" { 47 | run kdig @45.76.113.31 +tls-ca +tls-host=dot.seby.io be.libre 48 | assert_success 49 | assert_output -p "NOERROR;" 50 | } 51 | 52 | 53 | #@test "139.99.222.72 register.null DNS-over-TLS" { 54 | # run kdig @139.99.222.72 +tls-ca +tls-host=dot.seby.io register.null 55 | # assert_success 56 | # assert_output -p "NOERROR;" 57 | #} 58 | @test "45.76.113.31 register.null DNS-over-TLS" { 59 | run kdig @45.76.113.31 +tls-ca +tls-host=dot.seby.io register.null 60 | assert_success 61 | assert_output -p "NOERROR;" 62 | } 63 | 64 | #@test "139.99.222.72 opennic.oz DNS-over-TLS" { 65 | # run kdig @139.99.222.72 +tls-ca +tls-host=dot.seby.io opennic.oz 66 | # assert_success 67 | # assert_output -p "NOERROR;" 68 | #} 69 | @test "45.76.113.31 opennic.oz DNS-over-TLS" { 70 | run kdig @45.76.113.31 +tls-ca +tls-host=dot.seby.io opennic.oz 71 | assert_success 72 | assert_output -p "NOERROR;" 73 | } 74 | 75 | #@test "139.99.222.72 www.opennic.chan DNS-over-TLS" { 76 | # run kdig @139.99.222.72 +tls-ca +tls-host=dot.seby.io www.opennic.chan 77 | # assert_success 78 | # assert_output -p "NOERROR;" 79 | #} 80 | @test "45.76.113.31 www.opennic.chan DNS-over-TLS" { 81 | run kdig @45.76.113.31 +tls-ca +tls-host=dot.seby.io www.opennic.chan 82 | assert_success 83 | assert_output -p "NOERROR;" 84 | } 85 | -------------------------------------------------------------------------------- /tests/publicarray-au-doh.toml: -------------------------------------------------------------------------------- 1 | server_names = ['publicarray-au2-doh'] 2 | listen_addresses = ['127.0.0.1:4320'] 3 | 4 | [sources] 5 | 6 | ## An example of a remote source from https://github.com/DNSCrypt/dnscrypt-resolvers 7 | 8 | [sources.'public-resolvers'] 9 | urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md'] 10 | cache_file = '/tmp/public-resolvers.md' 11 | minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3' 12 | prefix = '' 13 | 14 | -------------------------------------------------------------------------------- /tests/publicarray-au.toml: -------------------------------------------------------------------------------- 1 | server_names = ['publicarray-au'] 2 | listen_addresses = ['127.0.0.1:4321'] 3 | 4 | [sources] 5 | 6 | ## An example of a remote source from https://github.com/DNSCrypt/dnscrypt-resolvers 7 | 8 | [sources.'public-resolvers'] 9 | urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md'] 10 | cache_file = '/tmp/public-resolvers.md' 11 | minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3' 12 | prefix = '' 13 | 14 | -------------------------------------------------------------------------------- /tests/publicarray-au2-doh.toml: -------------------------------------------------------------------------------- 1 | server_names = ['publicarray-au2-doh'] 2 | listen_addresses = ['127.0.0.1:4322'] 3 | 4 | [sources] 5 | 6 | ## An example of a remote source from https://github.com/DNSCrypt/dnscrypt-resolvers 7 | 8 | [sources.'public-resolvers'] 9 | urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md'] 10 | cache_file = '/tmp/public-resolvers.md' 11 | minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3' 12 | prefix = '' 13 | 14 | -------------------------------------------------------------------------------- /tests/publicarray-au2.toml: -------------------------------------------------------------------------------- 1 | server_names = ['publicarray-au2'] 2 | listen_addresses = ['127.0.0.1:4323'] 3 | 4 | [sources] 5 | 6 | ## An example of a remote source from https://github.com/DNSCrypt/dnscrypt-resolvers 7 | 8 | [sources.'public-resolvers'] 9 | urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md'] 10 | cache_file = '/tmp/public-resolvers.md' 11 | minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3' 12 | prefix = '' 13 | 14 | -------------------------------------------------------------------------------- /tests/tls.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | load ../node_modules/bats-support/load.bash 3 | load ../node_modules/bats-assert/load.bash 4 | 5 | openssl_client() { 6 | echo "Q" | openssl s_client -connect $@ 7 | } 8 | 9 | #@test "139.99.222.72 TLS 1.3 support DNS-over-TLS" { 10 | # run openssl_client 139.99.222.72:853 11 | # assert_output -p "TLSv1.3" 12 | #} 13 | 14 | #@test "139.99.222.72 TLS 1.3 support DNS-over-HTTPS" { 15 | # run openssl_client 139.99.222.72:443 16 | # assert_output -p "TLSv1.3" 17 | #} 18 | 19 | @test "45.76.113.31 TLS 1.3 support DNS-over-TLS" { 20 | run openssl_client 45.76.113.31:853 21 | assert_output -p "TLSv1.3" 22 | } 23 | 24 | @test "45.76.113.31 TLS 1.3 support DNS-over-HTTPS" { 25 | run openssl_client 45.76.113.31:443 26 | assert_output -p "TLSv1.3" 27 | } 28 | -------------------------------------------------------------------------------- /unbound/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.19 as build 2 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 3 | ENV REVISION 9 4 | 5 | ENV UNBOUND_BUILD_DEPS expat-dev file gcc libevent-dev openssl-dev make musl-dev nghttp2-dev 6 | 7 | RUN apk --no-cache add $UNBOUND_BUILD_DEPS 8 | 9 | ARG UNBOUND_VERSION=1.20.0 10 | ARG UNBOUND_SHA256=56b4ceed33639522000fd96775576ddf8782bb3617610715d7f1e777c5ec1dbf 11 | ARG UNBOUND_DOWNLOAD_URL=https://nlnetlabs.nl/downloads/unbound/unbound-${UNBOUND_VERSION}.tar.gz 12 | 13 | RUN set -x && \ 14 | mkdir -p /tmp/src && \ 15 | cd /tmp/src && \ 16 | wget -O unbound.tar.gz $UNBOUND_DOWNLOAD_URL && \ 17 | echo "${UNBOUND_SHA256} *unbound.tar.gz" | sha256sum -c - && \ 18 | tar xzf unbound.tar.gz && \ 19 | rm -f unbound.tar.gz && \ 20 | cd unbound-${UNBOUND_VERSION} && \ 21 | ./configure --with-conf-file=/etc/unbound/unbound.conf --with-run-dir=/etc/unbound \ 22 | --with-pthreads --with-username=_unbound --with-libevent --with-libnghttp2 \ 23 | CFLAGS="-O2 -flto -fPIE -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector-strong -Wformat -Werror=format-security" \ 24 | LDFLAGS="-Wl,-z,now -Wl,-z,relro" && \ 25 | make install && \ 26 | ls /usr/local/lib/ 27 | 28 | #------------------------------------------------------------------------------# 29 | FROM alpine:3.19 30 | LABEL org.opencontainers.image.source https://github.com/publicarray/dns-resolver-infra 31 | 32 | ENV UNBOUND_RUN_DEPS expat libevent openssl runit shadow drill wget bc ca-certificates nghttp2-libs 33 | 34 | # https://github.com/NLnetLabs/unbound/blob/master/configure#L2852 35 | # https://archlinux.pkgs.org/rolling/archlinux-extra-x86_64/unbound-1.20.0-1-x86_64.pkg.tar.zst.html 36 | ARG LIBUNBOUND_CURRENT=8 37 | ARG LIBUNBOUND_AGE=1 38 | ARG LIBUNBOUND_REVISION=27 39 | 40 | # {LIBUNBOUND_CURRENT}.{LIBUNBOUND_AGE}.{LIBUNBOUND_REVISION} 41 | ARG LIBUNBOUND_VERSION=${LIBUNBOUND_CURRENT}.${LIBUNBOUND_AGE}.${LIBUNBOUND_REVISION} 42 | 43 | RUN apk add --no-cache $UNBOUND_RUN_DEPS 44 | 45 | COPY --from=build /usr/local/sbin/unbound /usr/local/sbin/unbound 46 | COPY --from=build /usr/local/sbin/unbound-checkconf /usr/local/sbin/unbound-checkconf 47 | COPY --from=build /usr/local/sbin/unbound-control /usr/local/sbin/unbound-control 48 | COPY --from=build /usr/local/sbin/unbound-host /usr/local/sbin/unbound-host 49 | COPY --from=build /usr/local/sbin/unbound-anchor /usr/local/sbin/unbound-anchor 50 | COPY --from=build /usr/local/sbin/unbound-control-setup /usr/local/sbin/unbound-control-setup 51 | COPY --from=build /usr/local/lib/libunbound.so.${LIBUNBOUND_VERSION} /usr/local/lib/libunbound.so.${LIBUNBOUND_VERSION} 52 | 53 | RUN set -x && \ 54 | cd /usr/local/lib/ && \ 55 | ln -sf libunbound.so.${LIBUNBOUND_VERSION} libunbound.so.${LIBUNBOUND_CURRENT} && \ 56 | ln -sf libunbound.so.${LIBUNBOUND_VERSION} libunbound.so && \ 57 | cd && \ 58 | groupadd _unbound && \ 59 | useradd -g _unbound -s /dev/null -d /dev/null _unbound && \ 60 | mkdir -p /etc/service/unbound /etc/unbound/run && \ 61 | unbound-anchor -a /etc/unbound/run/root.key || true && \ 62 | chown _unbound:_unbound /etc/unbound/run && \ 63 | chown _unbound:_unbound /etc/unbound/run/root.key && \ 64 | wget -O /etc/unbound/root.hints https://www.internic.net/domain/named.root \ 65 | update-ca-certificates 2> /dev/null || true 66 | 67 | COPY unbound.conf /etc/unbound/unbound.conf 68 | COPY unbound.sh /etc/service/unbound/run 69 | COPY entrypoint.sh / 70 | 71 | EXPOSE 53/udp 53/tcp 72 | EXPOSE 4949/tcp 73 | EXPOSE 853/tcp 74 | 75 | RUN unbound -h || true 76 | RUN unbound-checkconf /etc/unbound/unbound.conf || true 77 | 78 | HEALTHCHECK --start-period=1m --interval=2m \ 79 | CMD ["drill", "-D", "-Q", ".", "@127.0.0.1", "SOA"] 80 | 81 | ENTRYPOINT ["/entrypoint.sh"] 82 | 83 | # Metadata 84 | LABEL org.opencontainers.image.title="unbound" \ 85 | org.opencontainers.image.description="Unbound is a validating, recursive, caching DNS resolver." \ 86 | org.opencontainers.image.url="https://nlnetlabs.nl/projects/unbound/about/" \ 87 | org.opencontainers.image.documentation="https://nlnetlabs.nl/documentation/unbound/" \ 88 | org.opencontainers.image.source="https://nlnetlabs.nl/svn/unbound/" \ 89 | org.opencontainers.image.authors="publicarray" \ 90 | org.opencontainers.image.version=${UNBOUND_VERSION} 91 | -------------------------------------------------------------------------------- /unbound/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | getServiceIP () { 5 | drill -4 "$1" | awk '/ANSWER SECTION/ {print;getline;print}' | grep -oE '(([0-9]{1,3})\.){3}(1?[0-9]{1,3})' 6 | } 7 | 8 | waitOrFail () { 9 | maxTries=24 10 | i=0 11 | while [ $i -lt $maxTries ]; do 12 | outStr="$($@)" 13 | if [ $? -eq 0 ];then 14 | echo "$outStr" 15 | return 16 | fi 17 | i=$((i+1)) 18 | echo "==> waiting for a dependent service $i/$maxTries" >&2 19 | sleep 5 20 | done 21 | echo "Too many failed attempts" >&2 22 | exit 1 23 | } 24 | 25 | #------------------------ Optional add munin statistics -----------------------# 26 | munin() { 27 | echo "==> Installing munin-node" 28 | apk update 29 | apk add munin-node 30 | mkdir -p /etc/munin/plugin-state 31 | echo "==> Installing contrib/unbound_munin_" 32 | wget https://raw.githubusercontent.com/NLnetLabs/unbound/master/contrib/unbound_munin_ -O /etc/munin/unbound_munin_ 33 | chmod +x /etc/munin/unbound_munin_ 34 | ln -s /etc/munin/unbound_munin_ /etc/munin/plugins/unbound_munin_by_class 35 | ln -s /etc/munin/unbound_munin_ /etc/munin/plugins/unbound_munin_by_flags 36 | ln -s /etc/munin/unbound_munin_ /etc/munin/plugins/unbound_munin_by_opcode 37 | ln -s /etc/munin/unbound_munin_ /etc/munin/plugins/unbound_munin_by_rcode 38 | ln -s /etc/munin/unbound_munin_ /etc/munin/plugins/unbound_munin_by_type 39 | ln -s /etc/munin/unbound_munin_ /etc/munin/plugins/unbound_munin_histogram 40 | ln -s /etc/munin/unbound_munin_ /etc/munin/plugins/unbound_munin_hits 41 | ln -s /etc/munin/unbound_munin_ /etc/munin/plugins/unbound_munin_memory 42 | ln -s /etc/munin/unbound_munin_ /etc/munin/plugins/unbound_munin_queue 43 | echo "==> Configuring munin-node" 44 | groupadd _munin-node 45 | useradd -g _munin-node -s /dev/null -d /dev/null _munin-node 46 | chown -R _munin-node:_munin-node /etc/munin/ 47 | sed \ 48 | -re "s/user\\s{0,}\\root\\w/user _munin-node/" \ 49 | -re "s/group\\s{0,}\\root\\w/group _munin-node/" \ 50 | -i "/etc/munin/munin-node.conf" 51 | # Allow all connections (we are in a nat environment) 52 | echo "allow .*" >> /etc/munin/munin-node.conf 53 | # enable tls 54 | openssl req -x509 -nodes -sha256 -subj '/CN=localhost' -newkey rsa:4096 \ 55 | -keyout /etc/ssl/munin.key \ 56 | -out /etc/ssl/munin.pem \ 57 | -days 999999 58 | echo "tls enabled" >> /etc/munin/munin-node.conf 59 | echo "tls_verify_certificate no" >> /etc/munin/munin-node.conf 60 | echo "tls_private_key /etc/ssl/munin.key" >> /etc/munin/munin-node.conf 61 | echo "tls_certificate /etc/ssl/munin.pem" >> /etc/munin/munin-node.conf 62 | 63 | cat << EOF > /etc/munin/plugin-conf.d/local.conf 64 | [unbound*] 65 | user root 66 | env.statefile /etc/munin/plugin-state/unbound-state 67 | env.unbound_conf /etc/unbound/unbound.conf 68 | env.unbound_control /usr/local/sbin/unbound-control 69 | env.spoof_warn 1000 70 | env.spoof_crit 100000 71 | EOF 72 | 73 | echo "==> Configuring unbound" 74 | sed \ 75 | -re "s/# statistics-interval:.*/statistics-interval: 0/" \ 76 | -re "s/# extended-statistics:.*/extended-statistics: yes/" \ 77 | -re "s/# statistics-cumulative:.*/statistics-cumulative: no/" \ 78 | -i "/etc/unbound/unbound.conf" 79 | 80 | echo "==> Done munin-node" 81 | /usr/sbin/munin-node & 82 | } 83 | 84 | usage() { 85 | echo "-d [domain name] domain lookup for service discovery" 86 | echo "-m setup munin node" 87 | exit 0 88 | } 89 | 90 | optimise_unbound_memory() { 91 | reserved=25 92 | memoryMB=$(( $( (grep -F MemAvailable /proc/meminfo || grep -F MemTotal /proc/meminfo) | sed 's/[^0-9]//g' ) / 1024 )) 93 | # https://fabiokung.com/2014/03/13/memory-inside-linux-containers/ 94 | dokerMemoryLimitMB=0 95 | if [ -f "/sys/fs/cgroup/memory/memory.limit_in_bytes" ]; then 96 | dokerMemoryLimitMB=$(($(( $(cat /sys/fs/cgroup/memory/memory.limit_in_bytes) / 1024)) / 1024)) 97 | elif [ -f "/sys/fs/cgroup/memory.max" ]; then 98 | dokerMemoryLimitMB=$(($(( $(cat /sys/fs/cgroup/memory.max) / 1024)) / 1024)) 99 | fi 100 | 101 | if [ $dokerMemoryLimitMB -gt 0 ] && [ $dokerMemoryLimitMB -le $memoryMB ]; then 102 | memoryMB=$dokerMemoryLimitMB 103 | fi 104 | 105 | if [ $memoryMB -le $reserved ]; then 106 | echo "Not enough memory" >&2 107 | exit 1 108 | fi 109 | memory=$(($((memoryMB / 4)) - reserved)) 110 | 111 | nproc=$(nproc) 112 | if [ "$nproc" -gt 1 ]; then 113 | threads=$((nproc - 1)) 114 | else 115 | threads=1 116 | fi 117 | 118 | sed \ 119 | -re "s/num-threads:\\s{0,}\\d{1,}\\w/num-threads: ${threads}/" \ 120 | -re "s/msg-cache-slabs:\\s{0,}\\d{1,}\\w/msg-cache-size: ${threads}/" \ 121 | -re "s/rrset-cache-slabs:\\s{0,}\\d{1,}\\w/rrset-cache-slabs: ${threads}/" \ 122 | -re "s/key-cache-slabs:\\s{0,}\\d{1,}\\w/key-cache-slabs: ${threads}/" \ 123 | -re "s/infra-cache-slabs:\\s{0,}\\d{1,}\\w/infra-cache-slabs: ${threads}/" \ 124 | -re "s/msg-cache-size:\\s{0,}\\d{1,}\\w/msg-cache-size: ${memory}m/" \ 125 | -re "s/rrset-cache-size:\\s{0,}\\d{1,}\\w/rrset-cache-size: $((memory * 2))m/" \ 126 | -re "s/key-cache-size:\\s{0,}\\d{1,}\\w/key-cache-size: $((memory / 2))m/" \ 127 | -re "s/neg-cache-size:\\s{0,}\\d{1,}\\w/neg-cache-size: $((memory / 2))m/" \ 128 | -i "/etc/unbound/unbound.conf" 129 | 130 | if [ -n "$NSD_SERVICE_HOST" ]; then 131 | export NSD_SERVICE="${NSD_SERVICE_HOST}@${NSD_SERVICE_PORT}" 132 | echo "==> Info: NSD_SERVICE=$NSD_SERVICE" 133 | sed -e "s/stub-addr: \"127.0.0.1@552\"/stub-addr: \"${NSD_SERVICE}\"/g" \ 134 | -i "/etc/unbound/unbound.conf" 135 | else 136 | echo "==> Info: NSD_SERVICE_HOST is not defined" 137 | fi 138 | } 139 | 140 | while getopts "h?d:m" opt; do 141 | case "$opt" in 142 | h|\?) usage;; 143 | d) NSD_SERVICE_HOST="$(waitOrFail getServiceIP "$OPTARG")" 144 | ;; 145 | m) munin;; 146 | esac 147 | done 148 | 149 | NSD_SERVICE_HOST=${NSD_SERVICE_HOST-""} 150 | NSD_SERVICE_PORT=${NSD_SERVICE_PORT-"53"} 151 | 152 | shift $((OPTIND-1)) 153 | if [ ! -f /etc/unbound/unbound_server.pem ]; then 154 | unbound-control-setup 155 | fi 156 | optimise_unbound_memory 157 | echo "==> Done configuring unbound" 158 | 159 | if [ "$1" = '--' ] && shift; then 160 | /sbin/runsvdir -P /etc/service & 161 | exec "$@" 162 | fi 163 | 164 | exec /sbin/runsvdir -P /etc/service 165 | -------------------------------------------------------------------------------- /unbound/unbound-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: unbound 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: dns-server 9 | component: unbound 10 | strategy: 11 | type: Recreate 12 | replicas: 1 13 | template: 14 | metadata: 15 | labels: 16 | app: dns-server 17 | component: unbound 18 | spec: 19 | containers: 20 | - name: unbound 21 | image: publicarray/unbound 22 | # command: ["/entrypoint.sh"] 23 | ports: 24 | - name: dns 25 | containerPort: 53 26 | resources: 27 | requests: 28 | cpu: 100m 29 | memory: 300Mi 30 | restartPolicy: Always 31 | -------------------------------------------------------------------------------- /unbound/unbound-srv.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: unbound 5 | labels: 6 | app: dns-server 7 | component: unbound 8 | spec: 9 | selector: 10 | app: dns-server 11 | component: unbound 12 | ports: 13 | - name: dns-tcp 14 | protocol: TCP 15 | port: 53 16 | targetPort: 53 17 | - name: dns-udp 18 | protocol: UDP 19 | port: 53 20 | targetPort: 53 21 | type: NodePort 22 | # type: LoadBalancer 23 | -------------------------------------------------------------------------------- /unbound/unbound.conf: -------------------------------------------------------------------------------- 1 | # See unbound.conf(5) man page. 2 | # https://nlnetlabs.nl/documentation/unbound/unbound.conf/ 3 | # https://raw.githubusercontent.com/NLnetLabs/unbound/master/doc/example.conf.in 4 | # 5 | # Use this to include other text into the file. 6 | # include: "otherfile.conf" 7 | 8 | server: 9 | 10 | #### Options already enabled by default: 11 | ## https://tools.ietf.org/html/rfc7816 12 | # qname-minimisation: yes 13 | ### Enabled in v1.8.0 14 | # so-reuseport: yes 15 | # minimal-responses: yes 16 | ## https://tools.ietf.org/html/rfc8020 17 | # harden-below-nxdomain: yes 18 | #### 19 | 20 | ## new option in v1.7.3 21 | # https://tools.ietf.org/html/rfc7828 22 | edns-tcp-keepalive: yes 23 | # edns-tcp-keepalive-timeout: 120000 # 2min 24 | # tcp-idle-timeout: 30000 # 30 sec 25 | edns-buffer-size: 1232 26 | ## New Options in v1.8.0 27 | serve-expired-ttl: 86400 # max 1 day 28 | #serve-expired-ttl-reset: no 29 | #log-servfail: no 30 | 31 | ## new option in v1.8.2 32 | # This responds with an empty message to queries of type ANY. 33 | deny-any: yes 34 | # unknown-server-time-limit: 376 35 | # min-client-subnet-ipv6: 0 36 | # min-client-subnet-ipv4: 0 37 | # max-ecs-tree-size-ipv4: 100 38 | # max-ecs-tree-size-ipv6 : 100 39 | # unknown-server-time-limit: 376 40 | # fast-server-permil: 0 41 | # fast-server-num: 3 42 | 43 | # http://unbound.nlnetlabs.nl/documentation/howto_optimise.html 44 | # https://unbound.net/pipermail/unbound-users/2010-March/001083.html 45 | # https://github.com/jedisct1/dnscrypt-server-docker/blob/master/unbound.sh 46 | num-threads: 1 47 | msg-cache-slabs: 1 48 | rrset-cache-slabs: 1 49 | key-cache-slabs: 1 50 | infra-cache-slabs: 1 51 | # dnscrypt-shared-secret-cache-slabs: 1 52 | # dnscrypt-nonce-cache-slabs:1 53 | 54 | msg-cache-size: 54m # default 4m 55 | rrset-cache-size: 108m # rrset=msg*2 # default 4m 56 | key-cache-size: 54m # default 4m 57 | neg-cache-size: 27m # default 1m 58 | infra-cache-numhosts: 50000 59 | # dnscrypt-shared-secret-cache-size: 13m # default 4m 60 | # dnscrypt-nonce-cache-size: 13m # default 4m 61 | 62 | ## if--with-libevent 63 | # outgoing-range: 8192.0 64 | # num-queries-per-thread: 4096.0 65 | ## else 66 | # outgoing-range: 974.0 67 | # num-queries-per-thread: 487.0 68 | 69 | ## Larger socket buffer. OS may need config. 70 | # so-rcvbuf: 4m 71 | # so-sndbuf: 4m 72 | 73 | domain-insecure: "dns.opennic.glue" 74 | domain-insecure: "bbs" 75 | domain-insecure: "bit" 76 | domain-insecure: "chan" 77 | domain-insecure: "cyb" 78 | domain-insecure: "dyn" 79 | domain-insecure: "epic" 80 | # domain-insecure: "free" 81 | domain-insecure: "fur" 82 | domain-insecure: "geek" 83 | domain-insecure: "gopher" 84 | domain-insecure: "indy" 85 | domain-insecure: "libre" 86 | domain-insecure: "neo" 87 | domain-insecure: "null" 88 | domain-insecure: "o" 89 | domain-insecure: "opennic.glue" 90 | domain-insecure: "oss" 91 | domain-insecure: "oz" 92 | domain-insecure: "parody" 93 | domain-insecure: "pirate" 94 | domain-insecure: "glue" 95 | domain-insecure: "bazar" 96 | domain-insecure: "coin" 97 | domain-insecure: "emc" 98 | domain-insecure: "lib" 99 | domain-insecure: "ku" 100 | domain-insecure: "te" 101 | domain-insecure: "ti" 102 | domain-insecure: "uu" 103 | 104 | verbosity: 0 105 | do-ip6: no 106 | logfile: run/unbound.log 107 | auto-trust-anchor-file: run/root.key 108 | tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt 109 | root-hints: root.hints 110 | pidfile: run/unbound.pid 111 | username: _unbound 112 | directory: /etc/unbound 113 | chroot: /etc/unbound 114 | # use-syslog: yes 115 | log-time-ascii: yes 116 | # val-log-level: 0 117 | # statistics-interval: 0 118 | # extended-statistics: yes 119 | # statistics-cumulative: no 120 | interface: 0.0.0.0 121 | # interface: 127.0.0.1 122 | # interface: ::1 # Docker ipv6 -> can't bind socket: Address not available for ::1 123 | # interface: 10.19.96.4 124 | # interface: 0.0.0.0@853 125 | # interface: ::0@853 126 | port: 53 127 | # ssl-service-key: /etc/unbound/private.key 128 | # ssl-service-pem: /etc/unbound/certificate.pem 129 | # ssl-port: 853 130 | access-control: 0.0.0.0/0 allow 131 | access-control: ::/0 allow 132 | # qname-minimisation-strict : yes 133 | # https://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00 134 | # use-caps-for-id: yes 135 | # caps-whitelist: example.com 136 | # https://tools.ietf.org/html/draft-ietf-dnsop-nsec-aggressiveuse 137 | aggressive-nsec: yes 138 | local-zone: example. static 139 | local-zone: local. static 140 | local-zone: i2p. static 141 | local-zone: home. static 142 | local-zone: zghjccbob3n0. static 143 | local-zone: dhcp. static 144 | local-zone: lan. static 145 | local-zone: localdomain. static 146 | local-zone: ip. static 147 | local-zone: internal. static 148 | local-zone: openstacklocal. static 149 | local-zone: dlink. static 150 | local-zone: gateway. static 151 | local-zone: corp. static 152 | local-zone: workgroup. static 153 | local-zone: belkin. static 154 | local-zone: davolink. static 155 | local-zone: domain. static 156 | local-zone: virtualmin. static 157 | local-zone: invalid. static 158 | local-zone: wlan_ap. static 159 | local-zone: dlinkrouter. static 160 | local-zone: lan1. static 161 | serve-expired: yes 162 | prefetch: yes 163 | prefetch-key: yes 164 | rrset-roundrobin: yes 165 | num-queries-per-thread: 2048 166 | # outgoing-range: 32767 167 | outgoing-range: 4096 168 | incoming-num-tcp: 100 169 | outgoing-num-tcp: 100 170 | jostle-timeout: 325 # average roundtrip time from AU (myserver) to US + a tiny bit extra 171 | neg-cache-size: 25m 172 | cache-min-ttl: 120 173 | cache-max-ttl: 86400 174 | infra-host-ttl: 3600 175 | # cache-max-negative-ttl: 3600 176 | val-bogus-ttl: 120 177 | hide-identity: yes 178 | hide-version: yes 179 | hide-trustanchor: yes 180 | unwanted-reply-threshold: 10000000 181 | ## Simple DNS rebinding protection 182 | ## refer to RFC1918, RFC5735, RFC5156 and https://en.wikipedia.org/wiki/Reserved_IP_addresses 183 | ## IPv4 184 | private-address: 0.0.0.0/32 # Should not be on the Internet (only valid as source address) See https://lwn.net/Articles/791086/ still conflits with https://tools.ietf.org/html/rfc8190 185 | private-address: 10.0.0.0/8 # Private networks 186 | private-address: 127.0.0.0/8 # Loopback, spam-blocklists (RBL) (https://www.dnsbl.info/) e.g. "dig +short 0.0.0.0.zen.spamhaus.org" will stop working (https://www.spamhaus.org/zen/, https://www.spamhaus.org/faq/section/DNSBL%20Usage#202) 187 | private-address: 169.254.0.0/16 # link-local (networks without DHCP) 188 | private-address: 172.16.0.0/12 # Private networks 189 | private-address: 192.168.0.0/16 # Private networks 190 | private-address: 255.255.255.255/32 # Broadcast destination 191 | ## IPv6 192 | private-address: ::/128 # Unspecified addresses (only valid as source address) 193 | private-address: ::1/128 # Loopback 194 | private-address: 2001:db8::/32 # Documentation addresses used for documentation purposes such as user manuals, RFCs, etc. (RFC3849) 195 | # private-address: ::ffff:0:0/96 # IPv4-mapped IPv6 addresses (depreciated and should not be on the public internet) (blocks potentially valid addresses / gives wrong result from DNS Benchmark) 196 | private-address: fe80::/10 # IP address autoconfiguration (link-local unicast, Private network) 197 | private-address: fc00::/7 # Unique Local Addresses (Private network) 198 | # private-address: fec0::/10 # Depreciated site networks 199 | # private-address: 2002::/16 # 6to4 (deprecated) 200 | # private-address: 64:ff9b::/96 # 6to4 "Well-Known" Prefix 201 | # private-address: 2001::/32 # Teredo 202 | private-address: 2001:10::/28 # ORCHID 203 | # private-address: ff00::/8 # Multicast 204 | ## Selected IPv4 mapped addresses from IPv4 above (fixes potentially wrong result from DNS Benchmark if blocking all of ::ffff:0:0/96) 205 | private-address: ::ffff:0.0.0.0/128 # Private IPv4-mapped addresses 206 | private-address: ::ffff:10.0.0.0/120 # Private IPv4-mapped addresses 207 | private-address: ::ffff:127.0.0.1/120 # Loopback IPv4-mapped addresses, spam-blocklists (RBL) 208 | private-address: ::ffff:169.254.0.0/112 # Link-local IPv4-mapped addresses 209 | private-address: ::ffff:172.16.0.0/116 # Private IPv4-mapped addresses 210 | private-address: ::ffff:192.168.0.0/112 # Private IPv4-mapped addresses 211 | private-address: ::ffff:255.255.255.255/128 # Broadcast IPv4-mapped addresses 212 | ## 213 | do-not-query-localhost: yes # ::1 and 127.0.0.1/8 214 | do-not-query-address: 127.0.0.0/8 215 | # do-not-query-address: 10.0.0.0/8 # kube/docker ips, needed for nsd 216 | # do-not-query-address: 172.16.0.0/12 # docker-compose, needed for nsd 217 | do-not-query-address: 192.168.0.0/16 218 | # ratelimit: 500 219 | # ip-ratelimit: 50 220 | ### harden-large-queries: yes 221 | ### harden-short-bufsize: yes 222 | ## harden-algo-downgrade: yes 223 | ### harden-referral-path: yes 224 | ## prefer-ip6: yes 225 | # delay-close: 1500 226 | 227 | # https://support.mozilla.org/en-US/kb/configuring-networks-disable-dns-over-https 228 | local-zone: "use-application-dns.net." always_nxdomain 229 | auth-zone: 230 | name: "." 231 | url: "https://www.internic.net/domain/root.zone" 232 | fallback-enabled: yes 233 | for-downstream: no 234 | for-upstream: yes 235 | zonefile: /run/root.zone 236 | remote-control: 237 | control-enable: yes 238 | control-interface: 127.0.0.1 239 | stub-zone: 240 | name: "dns.opennic.glue" 241 | stub-addr: "127.0.0.1@552" # Authorative Slave DNS server 242 | stub-zone: 243 | name: "bbs" 244 | stub-addr: "127.0.0.1@552" 245 | stub-zone: 246 | name: "bit" 247 | stub-addr: "127.0.0.1@552" 248 | stub-zone: 249 | name: "chan" 250 | stub-addr: "127.0.0.1@552" 251 | stub-zone: 252 | name: "cyb" 253 | stub-addr: "127.0.0.1@552" 254 | stub-zone: 255 | name: "dyn" 256 | stub-addr: "127.0.0.1@552" 257 | stub-zone: 258 | name: "epic" 259 | stub-addr: "127.0.0.1@552" 260 | # stub-zone: 261 | # name: "free" 262 | # stub-addr: "127.0.0.1@552" 263 | stub-zone: 264 | name: "fur" 265 | stub-addr: "127.0.0.1@552" 266 | stub-zone: 267 | name: "geek" 268 | stub-addr: "127.0.0.1@552" 269 | stub-zone: 270 | name: "gopher" 271 | stub-addr: "127.0.0.1@552" 272 | stub-zone: 273 | name: "indy" 274 | stub-addr: "127.0.0.1@552" 275 | stub-zone: 276 | name: "libre" 277 | stub-addr: "127.0.0.1@552" 278 | stub-zone: 279 | name: "neo" 280 | stub-addr: "127.0.0.1@552" 281 | stub-zone: 282 | name: "null" 283 | stub-addr: "127.0.0.1@552" 284 | stub-zone: 285 | name: "o" 286 | stub-addr: "127.0.0.1@552" 287 | stub-zone: 288 | name: "opennic.glue" 289 | stub-addr: "127.0.0.1@552" 290 | stub-zone: 291 | name: "oss" 292 | stub-addr: "127.0.0.1@552" 293 | stub-zone: 294 | name: "oz" 295 | stub-addr: "127.0.0.1@552" 296 | stub-zone: 297 | name: "parody" 298 | stub-addr: "127.0.0.1@552" 299 | stub-zone: 300 | name: "pirate" 301 | stub-addr: "127.0.0.1@552" 302 | # OpenNIC Peers: 303 | stub-zone: 304 | name: "bazar" 305 | stub-host: "seed1.emercoin.com" 306 | stub-host: "seed2.emercoin.com" 307 | stub-zone: 308 | name: "coin" 309 | stub-host: "seed1.emercoin.com" 310 | stub-host: "seed2.emercoin.com" 311 | stub-zone: 312 | name: "emc" 313 | stub-host: "seed1.emercoin.com" 314 | stub-host: "seed2.emercoin.com" 315 | stub-zone: 316 | name: "lib" 317 | stub-host: "seed1.emercoin.com" 318 | stub-host: "seed2.emercoin.com" 319 | stub-zone: 320 | name: "ku" 321 | stub-addr: "127.0.0.1@552" 322 | stub-addr: "5.45.96.220" # ns1.new-nations.ku 323 | stub-addr: "185.82.22.133" # ns2.new-nations.ku 324 | stub-zone: 325 | name: "te" 326 | stub-addr: "127.0.0.1@552" 327 | stub-addr: "5.45.96.220" # ns1.new-nations.te 328 | stub-addr: "185.82.22.133" # ns2.new-nations.te 329 | stub-zone: 330 | name: "ti" 331 | stub-addr: "127.0.0.1@552" 332 | stub-addr: "5.45.96.220" # ns1.new-nations.ti 333 | stub-addr: "185.82.22.133" # ns2.new-nations.ti 334 | stub-zone: 335 | name: "uu" 336 | stub-addr: "127.0.0.1@552" 337 | stub-addr: "5.45.96.220" # ns1.new-nations.uu 338 | stub-addr: "185.82.22.133" # ns2.new-nations.uu 339 | # stub-zone: 340 | # name: "ko" 341 | # stub-addr: "127.0.0.1@552" 342 | # stub-addr: "5.45.96.220" # ns1.new-nations.ko 343 | # stub-addr: "185.82.22.133" # ns2.new-nations.ko 344 | # stub-zone: 345 | # name: "rm" 346 | # stub-addr: "127.0.0.1@552" 347 | # stub-addr: "5.45.96.220" # ns1.new-nations.rm 348 | # stub-addr: "185.82.22.133" # ns2.new-nations.rm 349 | -------------------------------------------------------------------------------- /unbound/unbound.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | exec 2>&1 4 | # . /etc/envvars 5 | exec /usr/local/sbin/unbound -d 6 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ansi-regex@^2.0.0: 6 | version "2.1.1" 7 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" 8 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== 9 | 10 | ansi-regex@^3.0.0: 11 | version "3.0.1" 12 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz" 13 | integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== 14 | 15 | ansi-regex@^4.1.0: 16 | version "4.1.1" 17 | resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz" 18 | integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== 19 | 20 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 21 | version "3.2.1" 22 | resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" 23 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 24 | dependencies: 25 | color-convert "^1.9.0" 26 | 27 | argparse@^1.0.7: 28 | version "1.0.10" 29 | resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" 30 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 31 | dependencies: 32 | sprintf-js "~1.0.2" 33 | 34 | bats-assert@^2.0.0: 35 | version "2.0.0" 36 | resolved "https://registry.npmjs.org/bats-assert/-/bats-assert-2.0.0.tgz" 37 | integrity sha512-qO3kNilWxW8iCONu9NDUfvsCiC6JzL6DPOc/DGq9z3bZ9/A7wURJ+FnFMxGbofOmWbCoy7pVhofn0o47A95qkQ== 38 | 39 | bats-support@^0.3.0: 40 | version "0.3.0" 41 | resolved "https://registry.npmjs.org/bats-support/-/bats-support-0.3.0.tgz" 42 | integrity sha512-z+2WzXbI4OZgLnynydqH8GpI3+DcOtepO66PlK47SfEzTkiuV9hxn9eIQX+uLVFbt2Oqoc7Ky3TJ/N83lqD+cg== 43 | 44 | bats@^1.9.0: 45 | version "1.9.0" 46 | resolved "https://registry.npmjs.org/bats/-/bats-1.9.0.tgz" 47 | integrity sha512-Z5BJaAmmHv/ujj7obhjEzJ//OL+ZtjVq0iRnHu+2fE9OeUaPMbJpBgYiOdNbDrG3E2hqe84/AXNnS/UiXl/UcA== 48 | 49 | camelcase@^5.0.0: 50 | version "5.3.1" 51 | resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" 52 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 53 | 54 | chalk@^2.4.2: 55 | version "2.4.2" 56 | resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" 57 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 58 | dependencies: 59 | ansi-styles "^3.2.1" 60 | escape-string-regexp "^1.0.5" 61 | supports-color "^5.3.0" 62 | 63 | cliui@^4.1.0: 64 | version "4.1.0" 65 | resolved "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz" 66 | integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== 67 | dependencies: 68 | string-width "^2.1.1" 69 | strip-ansi "^4.0.0" 70 | wrap-ansi "^2.0.0" 71 | 72 | cliui@^5.0.0: 73 | version "5.0.0" 74 | resolved "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz" 75 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== 76 | dependencies: 77 | string-width "^3.1.0" 78 | strip-ansi "^5.2.0" 79 | wrap-ansi "^5.1.0" 80 | 81 | code-point-at@^1.0.0: 82 | version "1.1.0" 83 | resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" 84 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== 85 | 86 | color-convert@^1.9.0: 87 | version "1.9.3" 88 | resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" 89 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 90 | dependencies: 91 | color-name "1.1.3" 92 | 93 | color-name@1.1.3: 94 | version "1.1.3" 95 | resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" 96 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== 97 | 98 | decamelize@^1.2.0: 99 | version "1.2.0" 100 | resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" 101 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== 102 | 103 | dockerfilelint@^1.8.0: 104 | version "1.8.0" 105 | resolved "https://registry.npmjs.org/dockerfilelint/-/dockerfilelint-1.8.0.tgz" 106 | integrity sha512-j0tipeP1kpTWfx1XV6QVrrJTtGiP/46+3NT5JuaqXUnYrNlusgvrSP4/ACkqQdglJfmeedIU7c2wztmxEV+JQA== 107 | dependencies: 108 | chalk "^2.4.2" 109 | cliui "^4.1.0" 110 | js-yaml "^3.6.0" 111 | lodash "^4.3.0" 112 | yargs "^13.2.1" 113 | 114 | dockerlint@^0.3.9: 115 | version "0.3.9" 116 | resolved "https://registry.npmjs.org/dockerlint/-/dockerlint-0.3.9.tgz" 117 | integrity sha512-gps1IlRWx0hqhG7qZNYoF/Ae8wpnnPDGV0eYC60FdH2UscS4hZ+NFYX3Pusj/GImjLD/Pxkp/wib7CBb63yzZw== 118 | dependencies: 119 | sty "^0.6.1" 120 | subarg "^1.0.0" 121 | 122 | emoji-regex@^7.0.1: 123 | version "7.0.3" 124 | resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz" 125 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 126 | 127 | escape-string-regexp@^1.0.5: 128 | version "1.0.5" 129 | resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" 130 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== 131 | 132 | esprima@^4.0.0: 133 | version "4.0.1" 134 | resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" 135 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 136 | 137 | find-up@^3.0.0: 138 | version "3.0.0" 139 | resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz" 140 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 141 | dependencies: 142 | locate-path "^3.0.0" 143 | 144 | get-caller-file@^2.0.1: 145 | version "2.0.5" 146 | resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" 147 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 148 | 149 | has-flag@^3.0.0: 150 | version "3.0.0" 151 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" 152 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 153 | 154 | is-fullwidth-code-point@^1.0.0: 155 | version "1.0.0" 156 | resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" 157 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== 158 | dependencies: 159 | number-is-nan "^1.0.0" 160 | 161 | is-fullwidth-code-point@^2.0.0: 162 | version "2.0.0" 163 | resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" 164 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== 165 | 166 | js-yaml@^3.6.0: 167 | version "3.14.1" 168 | resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" 169 | integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== 170 | dependencies: 171 | argparse "^1.0.7" 172 | esprima "^4.0.0" 173 | 174 | locate-path@^3.0.0: 175 | version "3.0.0" 176 | resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz" 177 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== 178 | dependencies: 179 | p-locate "^3.0.0" 180 | path-exists "^3.0.0" 181 | 182 | lodash@^4.3.0: 183 | version "4.17.21" 184 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" 185 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 186 | 187 | minimist@^1.1.0: 188 | version "1.2.6" 189 | resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" 190 | integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== 191 | 192 | number-is-nan@^1.0.0: 193 | version "1.0.1" 194 | resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" 195 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== 196 | 197 | p-limit@^2.0.0: 198 | version "2.3.0" 199 | resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" 200 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 201 | dependencies: 202 | p-try "^2.0.0" 203 | 204 | p-locate@^3.0.0: 205 | version "3.0.0" 206 | resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz" 207 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== 208 | dependencies: 209 | p-limit "^2.0.0" 210 | 211 | p-try@^2.0.0: 212 | version "2.2.0" 213 | resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" 214 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 215 | 216 | path-exists@^3.0.0: 217 | version "3.0.0" 218 | resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" 219 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== 220 | 221 | require-directory@^2.1.1: 222 | version "2.1.1" 223 | resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" 224 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== 225 | 226 | require-main-filename@^2.0.0: 227 | version "2.0.0" 228 | resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" 229 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== 230 | 231 | set-blocking@^2.0.0: 232 | version "2.0.0" 233 | resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" 234 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== 235 | 236 | sprintf-js@~1.0.2: 237 | version "1.0.3" 238 | resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" 239 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== 240 | 241 | string-width@^1.0.1: 242 | version "1.0.2" 243 | resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" 244 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== 245 | dependencies: 246 | code-point-at "^1.0.0" 247 | is-fullwidth-code-point "^1.0.0" 248 | strip-ansi "^3.0.0" 249 | 250 | string-width@^2.1.1: 251 | version "2.1.1" 252 | resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz" 253 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 254 | dependencies: 255 | is-fullwidth-code-point "^2.0.0" 256 | strip-ansi "^4.0.0" 257 | 258 | string-width@^3.0.0, string-width@^3.1.0: 259 | version "3.1.0" 260 | resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz" 261 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 262 | dependencies: 263 | emoji-regex "^7.0.1" 264 | is-fullwidth-code-point "^2.0.0" 265 | strip-ansi "^5.1.0" 266 | 267 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 268 | version "3.0.1" 269 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" 270 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== 271 | dependencies: 272 | ansi-regex "^2.0.0" 273 | 274 | strip-ansi@^4.0.0: 275 | version "4.0.0" 276 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz" 277 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== 278 | dependencies: 279 | ansi-regex "^3.0.0" 280 | 281 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: 282 | version "5.2.0" 283 | resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" 284 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 285 | dependencies: 286 | ansi-regex "^4.1.0" 287 | 288 | sty@^0.6.1: 289 | version "0.6.1" 290 | resolved "https://registry.npmjs.org/sty/-/sty-0.6.1.tgz" 291 | integrity sha1-3j+5rlcLxgp0RyRfDewxIT6i1ag= sha512-Pu/JG9iZxf9n0nS9958Eml71lg5mlKFh7qnq3P10qXff1SP8Kc4dwfnyRaiaI5KEyq2ff4DBucrLW/a8xv+MkA== 292 | 293 | subarg@^1.0.0: 294 | version "1.0.0" 295 | resolved "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz" 296 | integrity sha1-9izxdYHplrSPyWVpn1TAauJouNI= sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg== 297 | dependencies: 298 | minimist "^1.1.0" 299 | 300 | supports-color@^5.3.0: 301 | version "5.5.0" 302 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" 303 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 304 | dependencies: 305 | has-flag "^3.0.0" 306 | 307 | which-module@^2.0.0: 308 | version "2.0.0" 309 | resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" 310 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== 311 | 312 | wrap-ansi@^2.0.0: 313 | version "2.1.0" 314 | resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz" 315 | integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw== 316 | dependencies: 317 | string-width "^1.0.1" 318 | strip-ansi "^3.0.1" 319 | 320 | wrap-ansi@^5.1.0: 321 | version "5.1.0" 322 | resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz" 323 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== 324 | dependencies: 325 | ansi-styles "^3.2.0" 326 | string-width "^3.0.0" 327 | strip-ansi "^5.0.0" 328 | 329 | y18n@^4.0.0: 330 | version "4.0.3" 331 | resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" 332 | integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== 333 | 334 | yargs-parser@^13.1.2: 335 | version "13.1.2" 336 | resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz" 337 | integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== 338 | dependencies: 339 | camelcase "^5.0.0" 340 | decamelize "^1.2.0" 341 | 342 | yargs@^13.2.1: 343 | version "13.3.2" 344 | resolved "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz" 345 | integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== 346 | dependencies: 347 | cliui "^5.0.0" 348 | find-up "^3.0.0" 349 | get-caller-file "^2.0.1" 350 | require-directory "^2.1.1" 351 | require-main-filename "^2.0.0" 352 | set-blocking "^2.0.0" 353 | string-width "^3.0.0" 354 | which-module "^2.0.0" 355 | y18n "^4.0.0" 356 | yargs-parser "^13.1.2" 357 | --------------------------------------------------------------------------------