Using DNSCrypt-Proxy With Forced DNS

Is there no way of encrypting DNS resolving traffic with DNSCrypt and then sending onto to my chosen DNS, in my case OpenDNS that does the filtering? In other words DNSCrypt acts as a middle man.
Client > DNSCrypt > OpenDNS?

DNSCrypt is just software, configure it to use whatever DoH provider you wish.

1 Like

DoH configured in the browser can bypass OpenWrt.

1 Like

Surely if I have a firewall rule that redirects port 53 for DNS quieres to the router's DNS then all traffic should go through DNSCrypt whether or not DoH in Firefox is set?

I found this article which explains blocking DoH.

If I was to block Cloudflare using a firewall rule would that then force the DNS traffic into DNSCrypt?

Depending on the browser DoH fallback settings, it will either stop working, or use the DNS provider from the OS and then become intercepted on the router.

Okay, I'm going to paste all of my configs so you guys and point out what is going wrong. DNS Leak Test Shows my ISP if I keep the 'Use DNS servers advertised by peer' under 'Network > Interfaces > Advanced Settings' checked.

What's interesting is if I uncheck this box and enter 208.67.220.220 & 208.67.222.222 (which is the OpenDNS servers) and re-do the DNS leak test it shows my OpenDNS on the results page.
/etc/config/dhcp

config dnsmasq
        option leasefile '/tmp/dhcp.leases'
        option local '/local/'
        option domain 'local'
        option localuse '1'
        option rebind_protection '0'
        option localservice '0'
        list server '127.0.0.1#5300'
        list server '::1#5300'

config dhcp 'lan'
        option interface 'lan'
        option leasetime '1h'
        option start '1'
        option limit '255'
        option dhcpv6 'server'
        option ra_management '1'
        option ra 'server'
        list dhcp_option '6,208.67.220.220,208.67.222.222'

config dhcp 'wan'
        option interface 'wan'
        option ignore '1'

config dhcp 'guest_lan'
        option interface 'guest_lan'
        option limit '10'
        option leasetime '5m'
        option start '100'
        option ra 'server'
        option dhcpv6 'server'
        option ra_management '1'

/etc/config/network

config interface 'loopback'
        option ifname 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option ula_prefix 'fd45:d0b0:8a3f::/48'

config interface 'lan'
        option type 'bridge'
        option proto 'static'
        option ipaddr '192.168.1.1'
        option netmask '255.255.255.0'
        option ifname 'eth0.1'
        option ip6assign '64'

config interface 'wan'
        option proto 'pppoe'
        option username 'username
        option password 'password'
        option mtu '1492'
        option ifname 'eth1.2'
        option ipv6 'auto'
        option keepalive '0'

For the sake of testing I am using cloudflare as the server choice.

/etc/dnscrypt-proxy2/dnscrypt-proxy.toml

##############################################
#                                            #
#        dnscrypt-proxy configuration        #
#                                            #
##############################################

## This is an example configuration file.
## You should adjust it to your needs, and save it as "dnscrypt-proxy.toml"
##
## Online documentation is available here: https://dnscrypt.info/doc



##################################
#         Global settings        #
##################################

## List of servers to use
##
## Servers from the "public-resolvers" source (see down below) can
## be viewed here: https://dnscrypt.info/public-servers
##
## If this line is commented, all registered servers matching the require_* filters
## will be used.
##
## The proxy will automatically pick the fastest, working servers from the list.
## Remove the leading # first to enable this; lines starting with # are ignored.

server_names = ['cloudflare']


## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6.
## Note: When using systemd socket activation, choose an empty set (i.e. [] ).

listen_addresses = ['127.0.0.1:5300', '[::1]:5300']


## Maximum number of simultaneous client connections to accept

max_clients = 250


## Switch to a different system user after listening sockets have been created.
## Note (1): this feature is currently unsupported on Windows.
## Note (2): this feature is not compatible with systemd socket activation.
## Note (3): when using -pidfile, the PID file directory must be writable by the new user

# user_name = 'nobody'


## Require servers (from static + remote sources) to satisfy specific properties

# Use servers reachable over IPv4
ipv4_servers = true

# Use servers reachable over IPv6 -- Do not enable if you don't have IPv6 connectivity
ipv6_servers = false

# Use servers implementing the DNSCrypt protocol
dnscrypt_servers = true

# Use servers implementing the DNS-over-HTTPS protocol
doh_servers = true


## Require servers defined by remote sources to satisfy specific properties

# Server must support DNS security extensions (DNSSEC)
require_dnssec = false

# Server must not log user queries (declarative)
require_nolog = true

# Server must not enforce its own blacklist (for parental control, ads blocking...)
require_nofilter = true

# Server names to avoid even if they match all criteria
disabled_server_names = []


## Always use TCP to connect to upstream servers.
## This can be useful if you need to route everything through Tor.
## Otherwise, leave this to `false`, as it doesn't improve security
## (dnscrypt-proxy will always encrypt everything even using UDP), and can
## only increase latency.

force_tcp = false


## SOCKS proxy
## Uncomment the following line to route all TCP connections to a local Tor node
## Tor doesn't support UDP, so set `force_tcp` to `true` as well.

# proxy = "socks5://127.0.0.1:9050"


## HTTP/HTTPS proxy
## Only for DoH servers

# http_proxy = "http://127.0.0.1:8888"


## How long a DNS query will wait for a response, in milliseconds

timeout = 2500


## Keepalive for HTTP (HTTPS, HTTP/2) queries, in seconds

keepalive = 30


## Use the REFUSED return code for blocked responses
## Setting this to `false` means that some responses will be lies.
## Unfortunately, `false` appears to be required for Android 8+

refused_code_in_responses = false


## Load-balancing strategy: 'p2' (default), 'ph', 'first' or 'random'

# lb_strategy = 'p2'

## Set to `true` to constantly try to estimate the latency of all the resolvers
## and adjust the load-balancing parameters accordingly, or to `false` to disable.

# lb_estimator = true


## Log level (0-6, default: 2 - 0 is very verbose, 6 only contains fatal errors)

# log_level = 2


## log file for the application

# log_file = 'dnscrypt-proxy.log'


## Use the system logger (syslog on Unix, Event Log on Windows)

# use_syslog = true


## Delay, in minutes, after which certificates are reloaded

cert_refresh_delay = 240


## DNSCrypt: Create a new, unique key for every single DNS query
## This may improve privacy but can also have a significant impact on CPU usage
## Only enable if you don't have a lot of network load

# dnscrypt_ephemeral_keys = false


## DoH: Disable TLS session tickets - increases privacy but also latency

# tls_disable_session_tickets = false


## DoH: Use a specific cipher suite instead of the server preference
## 49199 = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
## 49195 = TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
## 52392 = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
## 52393 = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
##
## On non-Intel CPUs such as MIPS routers and ARM systems (Android, Raspberry Pi...),
## the following suite improves performance.
## This may also help on Intel CPUs running 32-bit operating systems.
##
## Keep tls_cipher_suite empty if you have issues fetching sources or
## connecting to some DoH servers. Google and Cloudflare are fine with it.

# tls_cipher_suite = [52392, 49199]


## Fallback resolver
## This is a normal, non-encrypted DNS resolver, that will be only used
## for one-shot queries when retrieving the initial resolvers list, and
## only if the system DNS configuration doesn't work.
## No user application queries will ever be leaked through this resolver,
## and it will not be used after IP addresses of resolvers URLs have been found.
## It will never be used if lists have already been cached, and if stamps
## don't include host names without IP addresses.
## It will not be used if the configured system DNS works.
## A resolver supporting DNSSEC is recommended. This may become mandatory.
##
## People in China may need to use 114.114.114.114:53 here.
## Other popular options include 8.8.8.8 and 1.1.1.1.

fallback_resolver = '8.8.8.8:53'


## Never let dnscrypt-proxy try to use the system DNS settings;
## unconditionally use the fallback resolver.

ignore_system_dns = false


## Maximum time (in seconds) to wait for network connectivity before
## initializing the proxy.
## Useful if the proxy is automatically started at boot, and network
## connectivity is not guaranteed to be immediately available.
## Use 0 to not test for connectivity at all,
## and -1 to wait as much as possible.

netprobe_timeout = 60

## Address and port to try initializing a connection to, just to check
## if the network is up. It can be any address and any port, even if
## there is nothing answering these on the other side. Just don't use
## a local address, as the goal is to check for Internet connectivity.
## On Windows, a datagram with a single, nul byte will be sent, only
## when the system starts.
## On other operating systems, the connection will be initialized
## but nothing will be sent at all.

netprobe_address = "8.8.8.8:53"


## Offline mode - Do not use any remote encrypted servers.
## The proxy will remain fully functional to respond to queries that
## plugins can handle directly (forwarding, cloaking, ...)

# offline_mode = false


## Automatic log files rotation

# Maximum log files size in MB
log_files_max_size = 10

# How long to keep backup files, in days
log_files_max_age = 7

# Maximum log files backups to keep (or 0 to keep all backups)
log_files_max_backups = 1



#########################
#        Filters        #
#########################

## Immediately respond to IPv6-related queries with an empty response
## This makes things faster when there is no IPv6 connectivity, but can
## also cause reliability issues with some stub resolvers.
## Do not enable if you added a validating resolver such as dnsmasq in front
## of the proxy.

block_ipv6 = false



##################################################################################
#        Route queries for specific domains to a dedicated set of servers        #
##################################################################################

## Example map entries (one entry per line):
## example.com 9.9.9.9
## example.net 9.9.9.9,8.8.8.8,1.1.1.1

forwarding_rules = 'forwarding-rules.txt'



###############################
#        Cloaking rules       #
###############################

## Cloaking returns a predefined address for a specific name.
## In addition to acting as a HOSTS file, it can also return the IP address
## of a different name. It will also do CNAME flattening.
##
## Example map entries (one entry per line)
## example.com     10.1.1.1
## www.google.com  forcesafesearch.google.com

# cloaking_rules = 'cloaking-rules.txt'



###########################
#        DNS cache        #
###########################

## Enable a DNS cache to reduce latency and outgoing traffic

cache = true


## Cache size

cache_size = 512


## Minimum TTL for cached entries

cache_min_ttl = 600


## Maximum TTL for cached entries

cache_max_ttl = 86400


## Minimum TTL for negatively cached entries

cache_neg_min_ttl = 60


## Maximum TTL for negatively cached entries

cache_neg_max_ttl = 600



###############################
#        Query logging        #
###############################

## Log client queries to a file

[query_log]

  ## Path to the query log file (absolute, or relative to the same directory as the executable file)

  # file = 'query.log'


  ## Query log format (currently supported: tsv and ltsv)

  format = 'tsv'


  ## Do not log these query types, to reduce verbosity. Keep empty to log everything.

  # ignored_qtypes = ['DNSKEY', 'NS']



############################################
#        Suspicious queries logging        #
############################################

## Log queries for nonexistent zones
## These queries can reveal the presence of malware, broken/obsolete applications,
## and devices signaling their presence to 3rd parties.

[nx_log]

  ## Path to the query log file (absolute, or relative to the same directory as the executable file)

  # file = 'nx.log'


  ## Query log format (currently supported: tsv and ltsv)

  format = 'tsv'



######################################################
#        Pattern-based blocking (blacklists)        #
######################################################

## Blacklists are made of one pattern per line. Example of valid patterns:
##
##   example.com
##   =example.com
##   *sex*
##   ads.*
##   ads*.example.*
##   ads*.example[0-9]*.com
##
## Example blacklist files can be found at https://download.dnscrypt.info/blacklists/
## A script to build blacklists from public feeds can be found in the
## `utils/generate-domains-blacklists` directory of the dnscrypt-proxy source code.

[blacklist]

  ## Path to the file of blocking rules (absolute, or relative to the same directory as the executable file)

blacklist_file = 'blacklist.txt'


  ## Optional path to a file logging blocked queries

  # log_file = 'blocked.log'


  ## Optional log format: tsv or ltsv (default: tsv)

  # log_format = 'tsv'



###########################################################
#        Pattern-based IP blocking (IP blacklists)        #
###########################################################

## IP blacklists are made of one pattern per line. Example of valid patterns:
##
##   127.*
##   fe80:abcd:*
##   192.168.1.4

[ip_blacklist]

  ## Path to the file of blocking rules (absolute, or relative to the same directory as the executable file)

  # blacklist_file = 'ip-blacklist.txt'


  ## Optional path to a file logging blocked queries

  # log_file = 'ip-blocked.log'


  ## Optional log format: tsv or ltsv (default: tsv)

  # log_format = 'tsv'



######################################################
#   Pattern-based whitelisting (blacklists bypass)   #
######################################################

## Whitelists support the same patterns as blacklists
## If a name matches a whitelist entry, the corresponding session
## will bypass names and IP filters.
##
## Time-based rules are also supported to make some websites only accessible at specific times of the day.

[whitelist]

  ## Path to the file of whitelisting rules (absolute, or relative to the same directory as the executable file)

  # whitelist_file = 'whitelist.txt'


  ## Optional path to a file logging whitelisted queries

  # log_file = 'whitelisted.log'


  ## Optional log format: tsv or ltsv (default: tsv)

  # log_format = 'tsv'



##########################################
#        Time access restrictions        #
##########################################

## One or more weekly schedules can be defined here.
## Patterns in the name-based blocklist can optionally be followed with @schedule_name
## to apply the pattern 'schedule_name' only when it matches a time range of that schedule.
##
## For example, the following rule in a blacklist file:
## *.youtube.* @time-to-sleep
## would block access to YouTube only during the days, and period of the days
## define by the 'time-to-sleep' schedule.
##
## {after='21:00', before= '7:00'} matches 0:00-7:00 and 21:00-0:00
## {after= '9:00', before='18:00'} matches 9:00-18:00

[schedules]

  # [schedules.'time-to-sleep']
  # mon = [{after='21:00', before='7:00'}]
  # tue = [{after='21:00', before='7:00'}]
  # wed = [{after='21:00', before='7:00'}]
  # thu = [{after='21:00', before='7:00'}]
  # fri = [{after='23:00', before='7:00'}]
  # sat = [{after='23:00', before='7:00'}]
  # sun = [{after='21:00', before='7:00'}]

  # [schedules.'work']
  # mon = [{after='9:00', before='18:00'}]
  # tue = [{after='9:00', before='18:00'}]
  # wed = [{after='9:00', before='18:00'}]
  # thu = [{after='9:00', before='18:00'}]
  # fri = [{after='9:00', before='17:00'}]



#########################
#        Servers        #
#########################

## Remote lists of available servers
## Multiple sources can be used simultaneously, but every source
## requires a dedicated cache file.
##
## Refer to the documentation for URLs of public sources.
##
## A prefix can be prepended to server names in order to
## avoid collisions if different sources share the same for
## different servers. In that case, names listed in `server_names`
## must include the prefixes.
##
## If the `urls` property is missing, cache files and valid signatures
## must be already present; This doesn't prevent these cache files from
## expiring after `refresh_delay` hours.

[sources]

  ## An example of a remote source from https://github.com/DNSCrypt/dnscrypt-resolvers

  [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 = ''

  ## Quad9 over DNSCrypt - https://quad9.net/

  # [sources.quad9-resolvers]
  # urls = ["https://www.quad9.net/quad9-resolvers.md"]
  # minisign_key = "RWQBphd2+f6eiAqBsvDZEBXBGHQBJfeG6G+wJPPKxCZMoEQYpmoysKUN"
  # cache_file = "quad9-resolvers.md"
  # refresh_delay = 72
  # prefix = "quad9-"

  ## Another example source, with resolvers censoring some websites not appropriate for children
  ## This is a subset of the `public-resolvers` list, so enabling both is useless

  #  [sources.'parental-control']
  #  urls = ['https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v2/parental-control.md', 'https://download.dnscrypt.info/resolvers-list/v2/parental-control.md']
  #  cache_file = 'parental-control.md'
  #  minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'



## Optional, local, static list of additional servers
## Mostly useful for testing your own servers.

[static]

  # [static.'google']
  # stamp = 'sdns://AgUAAAAAAAAAAAAOZG5zLmdvb2dsZS5jb20NL2V4cGVyaW1lbnRhbA'

dnscrypt-proxy -resolve youtube.com & nslookup youtube.com

root@OpenWrt:/etc/dnscrypt-proxy2# dnscrypt-proxy -resolve youtube.com
Resolving [youtube.com]

Domain exists:  yes, 4 name servers found
Canonical name: youtube.com.
IP addresses:   2a00:1450:4009:808::200e, 216.58.204.238
TXT records:    facebook-domain-verification=64jdes7le4h7e7lfpi22rijygx58j1 google-site-verification=OQz60vR-YapmaVrafWCALpPyA8eKJKssRhfIrzM-DJI v=spf1 include:google.com mx -all
Resolver IP:    81.134.100.125

root@OpenWrt:/etc/dnscrypt-proxy2# nslookup youtube.com
Server:         127.0.0.1
Address:        127.0.0.1#53

Name:      youtube.com
Address 1: 216.58.204.238
Address 2: 2a00:1450:4009:808::200e
root@OpenWrt:/etc/dnscrypt-proxy2# 

You are pushing plain DNS.
This is wrong.

It's obvious, that you need to disable it.

You are mixing plain DNS and encrypted DNS again.
This is also wrong.

It should be like this:

uci -q delete dhcp.lan.dhcp_option
uci commit dhcp
/etc/init.d/dnsmasq restart
uci -q delete network.wan.dns
uci set network.wan.peerdns="0"
uci commit network
/etc/init.d/network restart

Okay they are easy fixes.

After disabling the peer DNS and not entering anything into the box, what is it now pointing to? Do I leave the box blank or can I set an IP address such as localhost (127.0.0.1) so it points to DNSCrypt?

It should be enough as you have already configured the server and localuse options.

You can also enable the noresolv option to avoid DNS leak from Dnsmasq:

uci set dhcp.@dnsmasq[0].noresolv="1"
uci commit dhcp
/etc/init.d/dnsmasq restart

Okay I have DNSCrypt working but now I can't resolve my local domain names which us the .local suffix. It says to create forwarding rules here

Maybe some domain names must be sent to an internal DNS server to be resolved.

Maybe you'd like queries for your local domain to go to your router, and not to an upstream DNS resolver. By doing so, names of your local online devices can be found.

This also prevents internal names from being sent to 3rd party servers.

On this guide is says to add edit /etc/dnsmasq.conf to recognize local requests, so they are not sent to the DNSCrypt server:

# No forward list:
server=/local/
server=/lan/
server=/internal/
server=/intranet/
server=/private/
server=/workgroup/
server=/10.in-addr.arpa/
server=/16.172.in-addr.arpa/
server=/168.192.in-addr.arpa/
server=/254.169.in-addr.arpa/
server=/d.f.ip6.arpa/

Any ideas?

On a side note I still haven't found a way of stopping the overriding over DNSCrypt.

Many thanks

Will

It is already done by default:

You can use something like .lan or .home instead, as .local is reserved for mDNS.

I changed the domain suffix from .local > .lan, rebooted the router and clear the cache from um desktop PC and phone. In have been testing from and I was unable to resolve the local domains.

UPDATE
I partially solved the issue but I can't understand why it's behaving this way.

I downloaded 'Fing' from the Google Play Store and used its device discovery. The suffix was applied to the all of devices it found except for the router. Before I implemented DNSCrypt, the 'local server' and 'local domain' options set under 'DHCP & DNS' would apply the router itself. Now with DNSCrypt in place I use the workaround below.

My workaround is to add '.lan' to the end of the 'hostname' option under 'System > System'`.