-
Notifications
You must be signed in to change notification settings - Fork 1k
Stamps
Server stamps encode all the parameters required to connect to a secure DNS server as a single string. Think about stamps as QR code, but for DNS.
Stamps can be quickly viewed/modified/created using this VueJS component.
An online demo is accessible here: https://stamps.dnscrypt.info
An example list of public secure DNS resolvers, with their DNS stamps.
-
a || b
is the concatenation ofa
andb
-
a | b
is the result of the logicalOR
operation betweena
andb
. -
len(x)
is a single byte representation of the length ofx
, in bytes. Strings don't have to be zero-terminated and do not require invidual encoding. -
vlen(x)
is equal tolen(x)
ifx
is the last element of a set, and0x80 | len(x)
if there are more elements in the set. -
LP(x)
islen(x) || x
, i.ex
prefixed by its length. -
VLP(x1, x2, ...xn)
encodes a set, asvlen(x1) || x1 || vlen(x2) || x2 ... || vlen(xn) || xn
. Sincevlen(xn) == len(xn)
(length of the last element doesn't have the high bit set), for a set with a single element, we haveVLP(x) == LP(x)
. -
[ Q ]
means thatQ
is optional. -
base64url(s)
is the URL-safe base64 encoding ofs
. None of the parameters are individually base64-encoded. Base64-encoding is only applied once, on the entire concatenation of all length-prefixed parameters.
-
LP("10.0.0.1")
is[ 0x08, 0x31, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31 ]
-
VLP("10.0.0.1", "10.0.0.2")
evaluates to[ 0x88, 0x31, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x08, 0x31, 0x30, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x32 ]
-
base64url(VLP("10.0.0.1", "10.0.0.2"))
isiDEwLjAuMC4xCDEwLjAuMC4y
Format:
"sdns://" || base64url(0x01 || props || LP(addr [:port]) || LP(pk) || LP(providerName))
0x01
is the protocol identifier for DNSCrypt.
props
is a little-endian 64 bit value that represents informal properties about the resolver. It is a logical OR
combination of the following values:
-
1
: the server supports DNSSEC -
2
: the server doesn't keep logs -
4
: the server doesn't intentionally block domains
For example, a server that supports DNSSEC, stores logs, but doesn't block anything on its own should set props
as the following 8 bytes sequence: [ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
.
addr
is the IP address, as a string, with a port number if the server is not accessible over the standard port for the protocol (443).
IPv6 strings must be included in square brackets: [fe80::6d6d:f72c:3ad:60b8]
. Scopes are permitted.
pk
is the DNSCrypt provider's Ed25519 public key, as 32 raw bytes.
providerName
is the DNSCrypt provider name.
Format:
"sdns://" || base64url(0x02 || props || LP(addr) || VLP(hash1, hash2, ...hashn) ||
LP(hostname [:port]) || LP(path)
[ || VLP(bootstrap_ip1, bootstrap_ip2, ...bootstrap_ipn) ])
addr
is the IP address of the server.
It can be an empty string. In that case, the host name will be resolved to an IP address using another resolver.
hashi
is the SHA256 digest of one of the TBS certificate found in the validation chain,
typically the certificate used to sign the resolver's certificate. Multiple hashes can
be provided for seamless rotations.
hostname
is the server host name which will also be used as a SNI name. If the host name contains characters outside the URL-permitted range, these characters should be sent as-is, without any extra encoding (neither URL-encoded nor punycode).
The port number is optional, and is assumed to be 443
if missing.
path
is the absolute URI path, such as /dns-query
.
bootstrap_ipi
are IP addresses of recommended resolvers accessible over standard DNS
in order to resolve hostname
. This is optional, and clients can ignore this information.
Format:
"sdns://" || base64url(0x03 || props || LP(addr) || VLP(hash1, hash2, ...hashn) ||
LP(hostname [:port]) ||
[ || VLP(bootstrap_ip1, bootstrap_ip2, ...bootstrap_ipn) ])
addr
is the IP address of the server.
It can be an empty string. In that case, the host name will be resolved to an IP address using another resolver.
IPv6 strings must be included in square brackets: [fe80::6d6d:f72c:3ad:60b8]
. Scopes are permitted.
hashi
is the SHA256 digest of one of the TBS certificate found in the validation chain,
typically the certificate used to sign the resolver's certificate. Multiple hashes can
be provided for seamless rotations.
hostname
is the server host name which will also be used as a SNI name.
The port number is optional, and is assumed to be 443
if missing.
bootstrap_ipi
are IP addresses of recommended resolvers accessible over standard DNS
in order to resolve hostname
. This is optional, and clients can ignore this information.
Format:
"sdns://" || base64url(0x04 || props || LP(addr) || VLP(hash1, hash2, ...hashn) ||
LP(hostname [:port]) ||
[ || VLP(bootstrap_ip1, bootstrap_ip2, ...bootstrap_ipn) ])
addr
is the IP address of the server.
It can be an empty string. In that case, the host name will be resolved to an IP address using another resolver.
IPv6 strings must be included in square brackets: [fe80::6d6d:f72c:3ad:60b8]
. Scopes are permitted.
hashi
is the SHA256 digest of one of the TBS certificate found in the validation chain,
typically the certificate used to sign the resolver's certificate. Multiple hashes can
be provided for seamless rotations.
hostname
is the server host name which will also be used as a SNI name.
The port number is optional, and is assumed to be 443
if missing.
bootstrap_ipi
are IP addresses of recommended resolvers accessible over standard DNS
in order to resolve hostname
. This is optional, and clients can ignore this information.
Format:
"sdns://" || base64url(0x05 || props || LP(hostname [:port]) || LP(path))
hostname
is the server host name which, for relays, will also be used as a SNI name. If the host name contains characters outside the URL-permitted range, these characters should be sent as-is, without any extra encoding (neither URL-encoded nor punycode).
The port number is optional, and is assumed to be 443
if missing.
path
is the absolute URI path, such as /dns-query
.
Format:
"sdns://" || base64url(0x81 || LP(addr))
0x81
is the protocol identifier for a DNSCrypt relay.
addr is the IP address and port, as a string. IPv6 strings must be included in square brackets: [fe80::6d6d:f72c:3ad:60b8]:443
.
Format:
"sdns://" || base64url(0x85 || props || LP(addr) || VLP(hash1, hash2, ...hashn) ||
LP(hostname [:port]) || LP(path)
[ || VLP(bootstrap_ip1, bootstrap_ip2, ...bootstrap_ipn) ])
0x85
is the protocol identifier for an oDoH relay.
addr
is the IP address of the server.
It can be an empty string. In that case, the host name will be resolved to an IP address using another resolver.
hashi
is the SHA256 digest of one of the TBS certificate found in the validation chain,
typically the certificate used to sign the resolver's certificate. Multiple hashes can
be provided for seamless rotations.
hostname
is the server host name which, for relays, will also be used as a SNI name. If the host name contains characters outside the URL-permitted range, these characters should be sent as-is, without any extra encoding (neither URL-encoded nor punycode).
The port number is optional, and is assumed to be 443
if missing.
path
is the absolute URI path, such as /dns-query
.
bootstrap_ipi
are IP addresses of recommended resolvers accessible over standard DNS in order to resolve hostname
and get the oDoH target public key. This is optional, and clients can ignore this information.
Format:
"sdns://" || base64url(0x00 || props || LP(addr [:port]))
addr
is the IP address of the server. IPv6 strings must be included in square brackets: [fe80::6d6d:f72c:3ad:60b8]
.
Scopes are permitted.
- A Go implementation of DNS stamps
- Another Go implementation of DNS stamps
- A .NET implementation of DNS stamps by @bitbeans
- A Rust implementation of DNS stamps
- Another Rust implementation
- A Python implementation of DNS stamps
- A Javascript implementation of DNS stamps
- A Swift implementation of DNS stamps
DNS stamps are known to be used in the following applications:
In somecases if you want to run dnscrypt-proxy as a non-root user you'll get the error "[FATAL] listen udp 0.0.0.0:53: bind: permission denied"
to solve this problem you can run the following command and allow dnscrypt to have access to a low level port :
sudo setcap cap_net_bind_service=+ep $(which dnscrypt-proxy)
- Home
- Installation
- Configuration
- Checking that your DNS traffic is encrypted
- Automatic Updates
- Server sources
- Combining blocklists
- Public Blocklist and other configuration files
- Building from source
- Run your own DNSCrypt server in under 10 minutes
- DNS stamps specifications
- Windows Tips
- dnscrypt-proxy in the media
- Planned Features