Secure DNS
A DNS client which implemented DoT and DoH, with load balancing, DNS cache, custom ECS and HOSTs.
Table of Content
Config
Example
[config]
listen = [
'[::1]:53',
'127.0.0.1:53',
]
custom_ecs = [
'10.20.30.40',
'50.60.70.80',
]
round_robin = 'swrr'
[[traditional]]
host = ['8.8.4.4', '8.8.8.8']
bootstrap = true
[[https]]
host = ['dns.google']
path = '/resolve'
google = true
[[https]]
host = ['dns.google']
weight = 10
[[https]]
host = ['1.1.1.1', '1.0.0.1']
[[tls]]
host = ['dns.google']
[[traditional]]
# Resolve private domain name using local DNS server
host = ['10.0.0.1']
suffix = [ 'private.network.org' ]
[hosts.'example.com']
A = [ '127.0.0.1' ]
AAAA = [ '::1' ]
TXT = [ 'text' ]
Basic config
Key |
Type |
Required |
Default |
Description |
listen |
string[] |
✔️ |
|
host and port to listen |
timeout |
uint |
|
5 |
timeout in seconds for each DNS request, 0 to disable |
round_robin |
string |
|
'clock' |
upstream select round robin, can only be 'clock' , 'random' , 'wrandom' or 'swrr' |
cache_no_answer |
uint |
|
0 |
Cache response for specified seconds even if query returns with no specified answer or domain was not exists |
no_cache |
boolean |
|
false |
disable global DNS result cache |
custom_ecs |
string[] |
|
|
custom EDNS Subnet to override |
fallback_no_ecs |
boolean |
|
false |
fallback to no_ecs=true when DNS request got no answer |
no_ecs |
boolean |
|
false |
disable EDNS Subnet and remove EDNS Subnet from DNS request |
user_agent |
string |
|
'secure-dns/VERSION https://github.com/jinliming2/secure-dns' |
User-Agent field for DNS over HTTPS |
no_user_agent |
boolean |
|
false |
do not send User-Agent header in DNS over HTTPS |
no_single_inflight |
boolean |
|
false |
do not suppress multiple same outstanding queries |
Example:
[config]
listen = ['[::1]:53', '127.0.0.1:53']
custom_ecs = ['1.2.3.4', '1:2::3:4']
no_user_agent = true
Upstream DNS
Traditional DNS
Key |
Type |
Required |
Default |
Description |
host |
string[] |
✔️ |
|
ip addresses |
port |
uint16 |
|
53 |
port to use |
bootstrap |
boolean |
|
false |
mark this is a bootstrap DNS server, only used to resolve names for DNS over HTTPS and DNS over TLS |
weight |
uint |
|
1 |
weight used for weighted round robin, should > 0 |
domain |
string[] |
|
|
mark this DNS server only used to resolve specified domain names |
suffix |
string[] |
|
|
mark this DNS server only used to resolve domain names with specified suffixes |
custom_ecs |
string[] |
|
|
custom EDNS Subnet to override |
fallback_no_ecs |
boolean |
|
false |
fallback to no_ecs=true when DNS request got no answer |
no_ecs |
boolean |
|
false |
disable EDNS Subnet and remove EDNS Subnet from DNS request |
no_single_inflight |
boolean |
|
false |
do not suppress multiple same outstanding queries |
Example:
[[traditional]]
host = ['8.8.4.4', '8.8.8.8']
[[traditional]]
host = ['1.1.1.1', '1.0.0.1']
bootstrap = true
[[traditional]]
host = ['9.9.9.9']
suffix = [
'example.com',
]
DNS over TLS (DoT)
Key |
Type |
Required |
Default |
Description |
host |
string[] |
✔️ |
|
ip addresses or host names |
port |
uint16 |
|
853 |
port to use |
hostname |
string |
|
|
hostname for ip addresses |
weight |
uint |
|
1 |
weight used for weighted round robin, should > 0 |
domain |
string[] |
|
|
mark this DNS server only used to resolve specified domain names |
suffix |
string[] |
|
|
mark this DNS server only used to resolve domain names with specified suffixes |
custom_ecs |
string[] |
|
|
custom EDNS Subnet to override |
fallback_no_ecs |
boolean |
|
false |
fallback to no_ecs=true when DNS request got no answer |
no_ecs |
boolean |
|
false |
disable EDNS Subnet and remove EDNS Subnet from DNS request |
no_single_inflight |
boolean |
|
false |
do not suppress multiple same outstanding queries |
Example:
[[tls]]
host = ['dns.google']
[[tls]]
host = ['1.1.1.1']
hostname = 'cloudflare-dns.com'
domain = [
'example.com',
]
Note: If you want to specify hostname in host field, you must specify a traditional DNS server that marked with bootstrap = true
.
DNS over HTTPS (DoH)
Key |
Type |
Required |
Default |
Description |
host |
string[] |
✔️ |
|
ip addresses or host names |
port |
uint16 |
|
443 |
port to use |
hostname |
string |
|
|
hostname for ip addresses |
path |
string |
|
'/dns-query' |
HTTP URI path to use |
google |
boolean |
|
false |
use google's DoH query structure |
cookie |
boolean |
|
false |
enable cookie support for this server |
weight |
uint |
|
1 |
weight used for weighted round robin, should > 0 |
domain |
string[] |
|
|
mark this DNS server only used to resolve specified domain names |
suffix |
string[] |
|
|
mark this DNS server only used to resolve domain names with specified suffixes |
custom_ecs |
string[] |
|
|
custom EDNS Subnet to override |
fallback_no_ecs |
boolean |
|
false |
fallback to no_ecs=true when DNS request got no answer |
no_ecs |
boolean |
|
false |
disable EDNS Subnet and remove EDNS Subnet from DNS request |
user_agent |
string |
|
'secure-dns/VERSION https://github.com/jinliming2/secure-dns' |
User-Agent field for DNS over HTTPS |
no_user_agent |
boolean |
|
false |
do not send User-Agent header in DNS over HTTPS |
no_single_inflight |
boolean |
|
false |
do not suppress multiple same outstanding queries |
Example:
[[https]]
host = ['dns.google']
[[https]]
host = ['8.8.4.4', '8.8.8.8']
hostname = 'dns.google'
path = '/resolve'
google = true
[[https]]
host = ['1.1.1.1']
hostname = 'cloudflare-dns.com'
domain = [
'example.com',
]
Note: If you want to specify hostname in host field, you must specify a traditional DNS server that marked with bootstrap = true
.
Custom Hosts
Example:
[hosts.'example.com']
A = [
'127.0.0.1',
'192.168.1.1',
]
AAAA = ['::1']
TXT = ['this matches example.com']
[hosts.'*.example.com']
A = ['0.0.0.0']
TXT = ['this matches example.com a.example.com a.b.example.com a.b.c.example.com ...']
[hosts.'*.blocked.domain']
# Answered with no record
Import domain list from file
When defining hosts, you can use the =#
or $#
prefix followed by a relative or absolute file path to import the domain list from the specified file. The file path is related to the TOML config file path.
The domain list file is a plain text file that contains domains in each line, split by the \n
character. Lines starting with the #
character are ignored.
=#
means to use the domain list to resolve specified domain names.
$#
means to use the domain list to resolve domain names with specified suffixes.
Example:
[hosts.'$#./domains.txt']
A = [ '127.0.0.1' ]
[hosts.'=#./domains.txt']
[hosts.'$#/etc/secure-dns/domains.txt']
[hosts.'=#/mnt/txt']
License