jedisct1 / dnscrypt-server-docker

A Docker image for a non-censoring, non-logging, DNSSEC-capable, DNSCrypt-enabled DNS resolver
https://dnscrypt.info
ISC License
141 stars 22 forks source link

Dockerized dnscrypt-proxy can't reach dockerized dnscrypt-server via host's public IP #26

Closed kowalcj0 closed 5 years ago

kowalcj0 commented 5 years ago

Sorry for a lengthy ticket, but I tried to figure it out for a while now and I haven't made any progress, so prefer to include all useful info.

ps. I've redacted real domain name, IPs & ports.

Below are instructions how I:

Build & start dnscrypt-server

I want the server to run on a port different than 443 because other service is using it. I followed instructions from this answer https://github.com/DNSCrypt/dnscrypt-server-docker/issues/36#issuecomment-297631915 to change it to an arbitrary port 43956

git clone https://github.com/jedisct1/dnscrypt-server-docker.git
cd dnscrypt-server-docker
# edit `dnscrypt-wrapper.sh`, `watchdog.sh` & `Dockerfile` like described above
docker build -t dnscrypt-server:2019.03.23 .
docker run --name=dnscrypt-server -p 43956:43956/udp -p 43956:43956/tcp --net=host dnscrypt-server:2019.03.23 init -N my.dns.crypt.server.com -E 159.1.1.1:43956
docker start dnscrypt-server
docker update --restart=unless-stopped dnscrypt-server

Here's the server's Stamp:

docker logs -f dnscrypt-server
Provider name: [2.dnscrypt-cert.my.dns.crypt.server.com]
Generate provider key pair... ok.
Stamp for dnscrypt-proxy 2.x:
  sdns://AQcAAAAAAAAADzE1OS4xLjEuMTozNTM2MyAAABERIiIzM0REVVVmZnd3iIiZmQAAEREiIjMzRERVVScyLmRuc2NyeXB0LWNlcnQubXkuZG5zLmNyeXB0LnNlcnZlci5jb20

Parameters for dnscrypt-proxy 1.x:
  dnscrypt-proxy --provider-key=0000:1111:2222:3333:4444:5555:6666:7777:8888:9999:0000:1111:2222:3333:4444:5555
                 --resolver-address=159.1.1.1:43956
                 --provider-name=2.dnscrypt-cert.my.dns.crypt.server.com
Keys are stored in public.key & secret.key.

Build & start dnscrypt-proxy

I want proxy to be accessible via port 5353 as pihole is listening on port 53, thus -p 5353:53/udp.

ps. I also tried this Dockerfile https://github.com/kometchtech/docker-build/blob/master/dnscrypt-proxy/Dockerfile but I got the same error.

git clone git@github.com:kowalcj0/dnscrypt-proxy-2-docker.git
cd dnscrypt-proxy-2-docker
git checkout bump-to-v2.0.21
docker build -t dnscrypt-proxy-2:2.0.21 .
docker run -d --name dnscrypt-proxy-v2 -p 5353:53/udp -v /root/dnscrypt-proxy-config/dnscrypt-proxy.toml:/config/dnscrypt-proxy.toml --restart=always dnscrypt-proxy-2:2.0.21

My dnscrypt-proxy.toml looks like this:

server_names = ['my.dns.crypt.server.com']
listen_addresses = ['0.0.0.0:53']
max_clients = 250
ipv4_servers = true
ipv6_servers = false
dnscrypt_servers = true
doh_servers = false
require_dnssec = false
require_nolog = true
require_nofilter = true
force_tcp = false
timeout = 2500
cert_refresh_delay = 240
fallback_resolver = '1.1.1.1:53'
ignore_system_dns = true
log_files_max_size = 10
log_files_max_age = 7
log_files_max_backups = 1
block_ipv6 = true
cache = true
cache_size = 256
cache_min_ttl = 600
cache_max_ttl = 86400
cache_neg_ttl = 60
[query_log]
[nx_log]
  format = 'tsv'
[blacklist]
[ip_blacklist]
[schedules]
[sources]
  [sources.'public-resolvers']
  urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/public-resolvers.md', 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md']
  cache_file = 'public-resolvers.md'
  minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
  refresh_delay = 72
  prefix = ''

[static]
  [static.'my.dns.crypt.server.com']
  stamp = 'sdns://AQcAAAAAAAAADzE1OS4xLjEuMTozNTM2MyAAABERIiIzM0REVVVmZnd3iIiZmQAAEREiIjMzRERVVScyLmRuc2NyeXB0LWNlcnQubXkuZG5zLmNyeXB0LnNlcnZlci5jb20'

Problem

The problem is when dnscrypt-proxy tries to connect to the dnscrypt-server:

docker logs -f dnscrypt-proxy-v2
[2019-03-23 18:41:29] [NOTICE] Source [public-resolvers.md] loaded
[2019-03-23 18:41:29] [NOTICE] dnscrypt-proxy 2.0.21
[2019-03-23 18:41:29] [NOTICE] Now listening to 0.0.0.0:53 [UDP]
[2019-03-23 18:41:29] [NOTICE] Now listening to 0.0.0.0:53 [TCP]
[2019-03-23 18:41:31] [NOTICE] [my.dns.crypt.server.com] TIMEOUT
[2019-03-23 18:41:31] [ERROR] read udp 172.17.0.4:57249->159.1.1.1:43956: i/o timeout
[2019-03-23 18:41:31] [NOTICE] dnscrypt-proxy is waiting for at least one server to be reachable

Debugging

Funny thing is that when I use netcat to check if that port is reachable from within proxy container, then it works just fine:

docker exec -it dnscrypt-proxy-v2 sh
/ # nc -z -u -v -s 172.17.0.4 -p 57249 159.1.1.1 43956
159.1.1.1 (159.1.1.1:43956) open

I have 2 DNS A records for domain my.dns.crypt.server.com configured on digital ocean:

A my.dns.crypt.server.com  directs to 159.1.1.1
A 2.dnscrypt-cert.my.dns.crypt.server.com  directs to 159.1.1.1

Both domains are reachable from the outside world:

ping my.dns.crypt.server.com
PING my.dns.crypt.server.com (159.1.1.1) 56(84) bytes of data.
64 bytes from FWDR-1.FWDR-1.FWDR-1.FWDR-159 (159.1.1.1): icmp_seq=1 ttl=59 time=8.14 ms
64 bytes from FWDR-1.FWDR-1.FWDR-1.FWDR-159 (159.1.1.1): icmp_seq=2 ttl=59 time=8.48 ms
64 bytes from FWDR-1.FWDR-1.FWDR-1.FWDR-159 (159.1.1.1): icmp_seq=3 ttl=59 time=8.82 ms
...

ping my.dns.crypt.server.com
PING my.dns.crypt.server.com (159.1.1.1) 56(84) bytes of data.
64 bytes from FWDR-1.FWDR-1.FWDR-1.FWDR-159 (159.1.1.1): icmp_seq=1 ttl=59 time=8.14 ms
64 bytes from FWDR-1.FWDR-1.FWDR-1.FWDR-159 (159.1.1.1): icmp_seq=2 ttl=59 time=8.48 ms
64 bytes from FWDR-1.FWDR-1.FWDR-1.FWDR-159 (159.1.1.1): icmp_seq=3 ttl=59 time=8.82 ms
...

There's nothing in iptables that would block traffic to port 43956

iptables -L INPUT -n --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    DROP       all  --  130.158.0.0/16       0.0.0.0/0           
2    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
3    ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           
4    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
5    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:443 state NEW
6   ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:43956 state NEW
7   ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:22 state NEW
... all other entries are just blocked IPs

I'd really appreciate if you could help me to fix this. Thanks

ianbashford commented 5 years ago

I have mine running on digital ocean as well, but on port 443... Did you use a floating IP ? I needed to change the default route to get mine working with the floating IP. Since you say you're running something on 443 already, that might not be helpful I put it into this gist just in case... https://gist.github.com/ianbashford/0f43b2f7e984fe8e3d80866d1fba0b49

kowalcj0 commented 5 years ago

I don't use floating IP.

Dunno if it helps but I also added a SELinux policy for dns:

sudo semanage port -a -t dns_port_t -p tcp 53
EncryptTown commented 5 years ago

I'm having the same issue on Amazon.

EncryptTown commented 5 years ago

@kowalcj0 Did you change --resolver-address=127.0.0.1:443

Since it's not in watchdog.sh (anymore) ?

EncryptTown commented 5 years ago

@kowalcj0 did you get this during build?

WARNING: Ignoring APKINDEX.b89edf6e.tar.gz: No such file or directory WARNING: Ignoring APKINDEX.737f7e01.tar.gz: No such file or directory

https://github.com/gliderlabs/docker-alpine/issues/207

EncryptTown commented 5 years ago

@kowalcj0 I fixed it by removing --net=host

kowalcj0 commented 5 years ago

@EncryptTown re: q1 To what value I should change --resolver-address=127.0.0.1:443?

re: q2 yup I got it but with slightly different values:

...
+ mv /opt/unbound/etc/unbound/unbound.conf /opt/unbound/etc/unbound/unbound.conf.example
+ apk del --purge make gcc musl-dev git libevent-dev expat-dev shadow autoconf file openssl-dev byacc linux-headers
WARNING: Ignoring APKINDEX.70c88391.tar.gz: No such file or directory
WARNING: Ignoring APKINDEX.5022a8a2.tar.gz: No such file or directory
...

re: q3 I also removed --net=host and it didn't work. I'm still getting:

[ERROR] read udp 172.17.0.3:57569->159.1.1.1:43956: i/o timeout
kibner commented 4 years ago

@kowalcj0 Were you ever able to fix this issue? I am running into the same thing.

kowalcj0 commented 4 years ago

@kibner I got fed-up with it and I haven't looked into it since June last year.

kibner commented 4 years ago

@kibner I got fed-up with it and I haven't looked into it since June last year.

Oof. Well, I was eventually able to figure it out. I had to specify my host machine's IP address when opening the ports. Both my external networks are bridge networks with static IPs.

dnscrypt-server docker-compose file:

version: "3"

services:
  dnscrypt-server:
    container_name: dnscrypt-server
    image: jedisct1/dnscrypt-server:latest
    ports:
      - "192.168.7.8:4443:4443/tcp"
      - "192.168.7.8:4443:4443/udp"
      - "9100:9100/tcp"
    volumes:
      - './docker-volumes/opt-etc-dnscrypt-server-keys:/opt/encrypted-dns/etc/keys'
    environment:
      TZ: 'America/Chicago'
    restart: unless-stopped
    command: ["init", "-N", "dnscrypt-server.example.com", "-E", "192.168.7.8:4443", "-M", "0.0.0.0:9100"]

networks:
  default:
    external:
      name: dnscrypt-server

dnscrypt-proxy docker-compose file:

version: "3"

services:
  dnscrypt-proxy:
    container_name: dnscrypt-proxy
    image: klutchell/dnscrypt-proxy:latest
    ports:
      - "192.168.7.8:53000:53000/udp"
      - "192.168.7.8:53000:53000/tcp"
    volumes:
      - ./docker-volumes/dnscrypt-proxy.toml:/config/dnscrypt-proxy.toml
    environment:
      TZ: 'America/Chicago'
    restart: unless-stopped

networks:
  default:
    external:
      name: dnscrypt-proxy
kowalcj0 commented 4 years ago

Thank you @kibner for looking into this. I'll definitely give it another spin :)