CE
cep-ter/z42
Authoritative DNS Server
The ultimate answer to all dns queries.
z42 is an Authoritative name server that serves zone data from redis database.
table of contents
Configuration
server
dns listening server configuration
{
"server": {
"ip": "127.0.0.1",
"port": 1053,
"protocol": "udp",
"count": 1
}
}ip: ip address to bind, default: 127.0.0.1port: port number to bind, default: 1053protocol: protocol; can be tcp or udp, default: udpcount: number of listeners per address, default: 1
redis
we use two seperate redis connection. one read-only connection to get zone data, and one read-write connection for get/set stats
data
{
"redis_data": {
"zone_cache_size": 10000,
"zone_cache_timeout": 60,
"zone_reload": 60,
"record_cache_size": 1000000,
"record_cache_timeout": 60,
"redis": {
"address": "127.0.0.1:6379",
"net": "tcp",
"db": 0,
"password": "",
"prefix": "",
"suffix": "_dns2",
"connection": {
"max_idle_connections": 10,
"max_active_connections": 10,
"connect_timeout": 500,
"read_timeout": 500,
"idle_keep_alive": 30,
"max_keep_alive": 0,
"wait_for_connection": false
}
}
}
}zone_cache_timeout: time in seconds before cached responses expirezone_reload: time in seconds before zone data is reloaded from redis
stat
{
"redis_stat": {
"redis": {
"address": "127.0.0.1:6379",
"net": "tcp",
"db": 0,
"password": "",
"prefix": "z42_",
"suffix": "_z42",
"connection": {
"max_idle_connections": 10,
"max_active_connections": 10,
"connect_timeout": 500,
"read_timeout": 500,
"idle_keep_alive": 30,
"max_keep_alive": 0,
"wait_for_connection": false
}
}
}
}redis config
redis configurations
{
"redis": {
"address": "127.0.0.1:6379",
"net": "tcp",
"db": 0,
"password": "",
"prefix": "test_",
"suffix": "_test",
"connection": {
"max_idle_connections": 10,
"max_active_connections": 10,
"connect_timeout": 500,
"read_timeout": 500,
"idle_keep_alive": 30,
"max_keep_alive": 0,
"wait_for_connection": false
},
"connect_timeout": 0,
"read_timeout": 0
}
}address: redis address: "ip:port" for "tcp" and "/path/to/unix/socket.sock" for "unix", default: "127.0.0.1:6379"net: connection protocol: "tcp" or "unix", default: "tcp"db: redis database to use, default: 0password: redis AUTH string, default is emptyprefix,suffix: strings to prepend/append to all redis queries, default is emptymax_idle_connections: maximum number of idle connections that pool keeps, default: 10max_active_connections: maximum number of active connections, default: 10connect_timeout: time to wait for connecting to redis server in milliseconds, 0 for no timeout; default: 500read_timeout: time to wait for redis query results in milliseconds, 0 for no timeout; default: 500idle_keep_alive: time to keep idle connections in seconds, 0 for unlimited; default: 30max_keep_alive: maximum time to keep a connection in seconds, 0 for unlimited; default: 0wait_for_connection: whether or not wait for a connection to be available if connection pool is full, default: false
handler
dns query handler configuration
{
"handler": {
"max_ttl": 300,
"log_source_location": false,
"log": {
"enable": true,
"level": "info",
"target": "file",
"format": "json",
"path": "/tmp/z42.log"
},
"geoip": {
"enable": true,
"country_db": "geoCity.mmdb",
"asn_db": "geoIsp.mmdb"
},
"upstream": [{
"ip": "1.1.1.1",
"port": 53,
"protocol": "udp",
"timeout": 400
}]
}
}max_ttl: max ttl in seconds, default: 3600log_source_location: enable logging source location of every requestupstream_fallback: enable using upstream for querying non-authoritative requestslog: log configuration to use for handler
geoip
geoip configuration
{
"geoip": {
"enable": true,
"country_db": "geoCity.mmdb",
"asn_db": "geoIsp.mmdb"
}
}enable: enable/disable geoip calculations, default: disablecountry_db: maxminddb file for country codes to use, default: geoCity.mmdbasn_db: maxminddb file for autonomous system numbers to use, default: geoIsp.mmdb
upstream
{
"upstream": [{
"ip": "1.1.1.1",
"port": 53,
"protocol": "udp",
"timeout": 400
}]
}ip: upstream ip address, default: 1.1.1.1port: upstream port number, deafult: 53protocol: upstream protocol, default : udptimeout: request timeout in milliseconds, default: 400
healthcheck
healthcheck configuration
{
"healthcheck": {
"enable": true,
"max_requests": 10,
"max_pending_requests": 100,
"update_interval": 600,
"check_interval": 600,
"log": {
"enable": true,
"level": "info",
"target": "file",
"format": "json",
"path": "/tmp/healthcheck.log"
}
}
}enable: enable/disable healthcheck, default: disablemax_requests: maximum number of simultanous healthcheck requests, deafult: 10max_pending_requests: maximum number of requests to queue, default: 100update_interval: time between checking for updated data from redis in seconds, default: 300check_interval: time between two healthcheck requests in seconds, default: 600log: log configuration to use for healthcheck logs
log
log configuration
{
"log": {
"enable": true,
"level": "info",
"target": "file",
"format": "json",
"time_format": "2006-01-02T15:04:05.999999-07:00",
"path": "/tmp/z42.log",
"sentry": {
"enable": false,
"dsn": ""
},
"syslog": {
"enable": false,
"protocol": "udp",
"address": "localhost:514"
},
"kafka": {
"enable": false,
"brokers": ["127.0.0.1:9092"],
"topic": "z42",
"format": "capnp_request",
"compression": "none",
"timeout": 3000,
"buffer_size": 1000
}
}
}enable: enable/disable this log resource, default: disablelevel: log level, can be debug, info, warning, error, default: infotarget: log target, can be stdout, stderr, file, udp default: stdoutformat: log format, can be text, json, default: text. an extra log format ("capnp_request") is also available for request logstime_format: timestamp format using example-based layout, reference time is Mon Jan 2 15:04:05 MST 2006path: log output file path, net address if target is udpsentry: sentry hook configurationssyslog: syslog hook configurationskafka: kafka hook configurationsenable: enable/disable kafka hook, default: disablebrokers: list of brokers in "ip:port" format, default : "127.0.0.1:9092"topic: name of kafka topic, default : "z42"format: message format, default: "json"compression: compression format : "snappy", "gzip", "lz4", "zstd", "none", default: "none"timeout: kafka operation timeout (dial, read, write) in milliseconds, default : 3000buffer_size: kafka producer buffer size, default : 1000
rate limit
rate limit connfiguration
{
"ratelimit": {
"enable": true,
"rate": 60,
"burst": 10,
"blacklist": ["10.10.10.1"],
"whitelist": ["127.0.0.1"]
}
}enable: enable/disable rate limitrate: maximum allowed request per minuteburst: number of burst requestsblacklist: list of ips to refuse all requestwhitelist: list of ips to bypass rate limit
example
sample config:
{
"server": [
{
"ip": "127.0.0.1",
"port": 1053,
"protocol": "udp",
"count": 8
}
],
"error_log": {
"enable": true,
"target": "stdout",
"level": "info",
"path": "/tmp/error.log",
"format": "text",
"time_format": "2006-01-02T15:04:05Z07:00"
},
"redis_data": {
"zone_cache_size": 10000,
"zone_cache_timeout": 60,
"zone_reload": 60,
"record_cache_size": 1000000,
"record_cache_timeout": 60,
"redis": {
"address": "127.0.0.1:6379",
"net": "tcp",
"db": 0,
"password": "",
"prefix": "",
"suffix": "_dns2",
"connection": {
"max_idle_connections": 10,
"max_active_connections": 10,
"connect_timeout": 500,
"read_timeout": 500,
"idle_keep_alive": 30,
"max_keep_alive": 0,
"wait_for_connection": false
}
}
},
"redis_stat": {
"redis": {
"address": "127.0.0.1:6379",
"net": "tcp",
"db": 0,
"password": "",
"prefix": "z42_",
"suffix": "_z42",
"connection": {
"max_idle_connections": 10,
"max_active_connections": 10,
"connect_timeout": 500,
"read_timeout": 500,
"idle_keep_alive": 30,
"max_keep_alive": 0,
"wait_for_connection": false
}
}
},
"handler": {
"upstream": [
{
"ip": "1.1.1.1",
"port": 53,
"protocol": "udp",
"timeout": 400
}
],
"geoip": {
"enable": true,
"country_db": "geoCity.mmdb",
"asn_db": "geoIsp.mmdb"
},
"max_ttl": 3600,
"log_source_location": false,
"log": {
"enable": true,
"target": "file",
"level": "info",
"path": "/tmp/z42.log",
"format": "json",
"time_format": "2006-01-02T15:04:05Z07:00"
}
},
"healthcheck": {
"enable": false,
"max_requests": 10,
"max_pending_requests": 100,
"update_interval": 600,
"check_interval": 600,
"log": {
"enable": true,
"target": "file",
"level": "info",
"path": "/tmp/healthcheck.log",
"format": "json",
"time_format": "2006-01-02T15:04:05Z07:00"
}
},
"ratelimit": {
"enable": false,
"burst": 10,
"rate": 60,
"whitelist": [],
"blacklist": []
}
}zone format in redis db
keys
- z42:zones is a set containing all active zones
redis-cli>SMEMBERS z42:zones
1) "example.com."
2) "example.net."
- z42:zones:XXXX.XXX. is a hash map containing dns RRs, @ is used for TLD records.
redis-cli>HKEYS z42:zones:example.com.
1) "@"
2) "www"
3) "ns"
4) "subdomain.www"
@ is a special case used for root data
- z42:zones:XXXX.XXX.:config is a string containing zone specific configurations
redis-cli>GET z42:zones:example.com.:config
"{\"soa\":{\"ttl\":300, \"minttl\":100, \"mbox\":\"hostmaster.example.com.\",\"ns\":\"ns1.example.com.\",\"refresh\":44,\"retry\":55,\"expire\":66, \"serial\":23232}}"
- z42:zones:XXXX.XXX.:pub and z42:zones:XXXX.XXX.:priv contains keypair for dnssec
redis-cli>GET z42:zones:XXXX.XXX.:pub
"dnssec_test.com. IN DNSKEY 256 3 5 AwEAAaKsF5vxBfKuqeUa4+ugW37ftFZOyo+k7r2aeJzZdIbYk//P/dpC HK4uYG8Z1dr/qeo12ECNVcf76j+XAdJD841ELiRVaZteH8TqfPQ+jdHz 10e8Sfkh7OZ4oBwSCXWj+Q=="
zones
dns RRs
dns RRs are stored in redis as json strings inside a hash map using address as field key.
@ is used for TLD records.
redis-cli>HGETALL example.com.
1) "@"
2) "www"
A
{
"a":{
"ttl" : 360,
"records":[
{
"ip" : "1.2.3.4",
"country" : "US",
"asn": 444,
"weight" : 10
},
{
"ip" : "2.2.3.4",
"country" : "US",
"asn": 444,
"weight" : 10
}
],
"filter": {
"count":"single",
"order": "rr",
"geo_filter":"country"
},
"health_check":{
"enable":true,
"uri": "/hc/test.html",
"port": 8080,
"protocol": "https",
"up_count":3,
"down_count":-3,
"timeout":1000
}
}
}AAAA
{
"aaaa":{
"ttl" : 360,
"records":[
{
"ip" : "1.2.3.4",
"country" : "US",
"asn": 444,
"weight" : 10
},
{
"ip" : "1.2.3.4",
"country" : "US",
"asn": 444,
"weight" : 10
}
],
"filter": {
"count":"single",
"order": "rr",
"geo_filter":"country"
},
"health_check":{
"enable":true,
"uri": "/hc/test.html",
"port": 8080,
"protocol": "https",
"up_count":3,
"down_count":-3,
"timeout":1000
}
}
}filter : filtering mode:
count: return single or multiple results. values : "multi", "single"order: order of result. values : "none" - saved order, "weighted" - weighted shuffle, "rr" - uniform shufflegeo_filter: geo filter. values : "country" - same country, "location" - nearest destination, "asn" - same isp, "asn+country" same isp then same country, "none"
health_check : health check configuration
enable: enable/disable healthcheck for this host:ipuri: uri to use in healthcheck requestport: port to use in healthcheck requestprotocol: protocol to use in healthcheck request, can be http or httpsup_count: number of successful healthcheck requests to consider an ip validdown_count: number of unsuccessful healthcheck requests to consider an ip invalidtimeout time: to wait for a healthcheck response
ANAME
{
"aname":{
"location": "x.example.com."
}
}CNAME
{
"cname":{
"host" : "x.example.com.",
"ttl" : 360
}
}TXT
{
"txt":{
"ttl" : 360,
"records":[
{"text" : "this is a text"},
{"text" : "this is another text"}
]
}
}NS
{
"ns":{
"ttl" : 360,
"records":[
{"host" : "ns1.example.com."},
{"host" : "ns2.example.com."}
]
}
}MX
{
"mx":{
"ttl" : 360,
"records":[
{
"host" : "mx1.example.com.",
"preference" : 10
},
{
"host" : "mx2.example.com.",
"preference" : 20
}
]
}
}SRV
{
"srv":{
"ttl" : 360,
"records":[
{
"target" : "sip.example.com.",
"port" : 555,
"priority" : 10,
"weight" : 100
}
]
}
}CAA
{
"caa":{
"ttl": 360,
"records":[
{
"tag": "issuewild;",
"value": "godaddy.com",
"flag": 0
}
]
}
}PTR
{
"ptr":{
"ttl": 300,
"domain": "mail.example.com"
}
}TLSA
{
"tlsa":{
"ttl": 300,
"records":[
{
"usage": 1,
"selector": 1,
"matching_type": 1,
"certificate": "1CFC98A706BCF3683015"
}
]
}
}config
{
"soa":{
"ttl" : 100,
"mbox" : "hostmaster.example.com.",
"ns" : "ns1.example.com.",
"refresh" : 44,
"retry" : 55,
"expire" : 66,
"serial" : 25245235
},
"cname_flattening": true,
"dnssec": true,
"domain_id": "123456789"
}cname_flattening: enable/disable cname flattening, default: falsednssec: enable/disable dnssec, default: falsedomain_id: unique domain id for logging, optional
zone example
$ORIGIN example.net.
example.net. 300 IN SOA <SOA RDATA>
example.net. 300 NS ns1.example.net.
example.net. 300 NS ns2.example.net.
*.example.net. 300 TXT "this is a wildcard"
*.example.net. 300 MX 10 host1.example.net.
sub.*.example.net. 300 TXT "this is not a wildcard"
host1.example.net. 300 A 5.5.5.5
_ssh.tcp.host1.example.net. 300 SRV <SRV RDATA>
_ssh.tcp.host2.example.net. 300 SRV <SRV RDATA>
subdel.example.net. 300 NS ns1.subdel.example.net.
subdel.example.net. 300 NS ns2.subdel.example.net.
above zone data should be stored at redis as follow:
redis-cli> smembers z42:zones
1) "example.net."
redis-cli> hgetall z42:zones:example.net.
1) "_ssh._tcp.host1"
2) "{\"srv\":{\"ttl\":300, \"records\":[{\"target\":\"tcp.example.com.\",\"port\":123,\"priority\":10,\"weight\":100}]}}"
3) "*"
4) "{\"txt\":{\"ttl\":300, \"records\":[{\"text\":\"this is a wildcard\"}]},\"mx\":{\"ttl\":300, \"records\":[{\"host\":\"host1.example.net.\",\"preference\": 10}]}}"
5) "host1"
6) "{\"a\":{\"ttl\":300, \"records\":[{\"ip\":\"5.5.5.5\"}]}}"
7) "sub.*"
8) "{\"txt\":{\"ttl\":300, \"records\":[{\"text\":\"this is not a wildcard\"}]}}"
9) "_ssh._tcp.host2"
10) "{\"srv\":{\"ttl\":300, \"records\":[{\"target\":\"tcp.example.com.\",\"port\":123,\"priority\":10,\"weight\":100}]}}"
11) "subdel"
12) "{\"ns\":{\"ttl\":300, \"records\":[{\"host\":\"ns1.subdel.example.net.\"},{\"host\":\"ns2.subdel.example.net.\"}]}"
13) "@"
14) "{\"ns\":{\"ttl\":300, \"records\":[{\"host\":\"ns1.example.net.\"},{\"host\":\"ns2.example.net.\"}]}"
redis-cli> get z42:zones:example.net.:config
"{\"soa\":{\"ttl\":300, \"minttl\":100, \"mbox\":\"hostmaster.example.net.\",\"ns\":\"ns1.example.net.\",\"refresh\":44,\"retry\":55,\"expire\":66, \"serial\":32343}}"
On this page
Languages
Go99.9%Cap'n Proto0.1%
Contributors
GNU General Public License v3.0
Created September 6, 2020
Updated October 2, 2021
