@ -1,180 +1,51 @@
{ config , lib , pkgs , . . . }:
{ config , lib , pkgs , . . . }:
with lib ;
let
cfg = config . services . stubby ;
settingsFormat = pkgs . formats . yaml { } ;
confFile = settingsFormat . generate " s t u b b y . y m l " cfg . settings ;
in {
imports = map ( x :
( mkRemovedOptionModule [ " s e r v i c e s " " s t u b b y " x ]
" S t u b b y c o n f i g u r a t i o n m o v e d t o s e r v i c e s . s t u b b y . s e t t i n g s . " ) ) [
" a u t h e n t i c a t i o n M o d e "
" f a l l b a c k P r o t o c o l s "
" i d l e T i m e o u t "
" l i s t e n A d d r e s s e s "
" q u e r y P a d d i n g B l o c k s i z e "
" r o u n d R o b i n U p s t r e a m s "
" s u b n e t P r i v a t e "
" u p s t r e a m S e r v e r s "
] ;
fallbacks = concatMapStringsSep " \n " ( x : " - ${ x } " ) cfg . fallbackProtocols ;
listeners = concatMapStringsSep " \n " ( x : " - ${ x } " ) cfg . listenAddresses ;
# By default, the recursive resolvers maintained by the getdns
# project itself are enabled. More information about both getdns's servers,
# as well as third party options for upstream resolvers, can be found here:
# https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Test+Servers
#
# You can override these values by supplying a yaml-formatted array of your
# preferred upstream resolvers in the following format:
#
# 106 # - address_data: IPv4 or IPv6 address of the upstream
# port: Port for UDP/TCP (default is 53)
# tls_auth_name: Authentication domain name checked against the server
# certificate
# tls_pubkey_pinset: An SPKI pinset verified against the keys in the server
# certificate
# - digest: Only "sha256" is currently supported
# value: Base64 encoded value of the sha256 fingerprint of the public
# key
# tls_port: Port for TLS (default is 853)
defaultUpstream = ''
- address_data : 145 .100 .185 .15
tls_auth_name : " d n s o v e r t l s . s i n o d u n . c o m "
tls_pubkey_pinset :
- digest : " s h a 2 5 6 "
value : 6 2 lKu9HsDVbyiPenApnc4sfmSYTHOVfFgL3pyB + cBL4 =
- address_data : 145 .100 .185 .16
tls_auth_name : " d n s o v e r t l s 1 . s i n o d u n . c o m "
tls_pubkey_pinset :
- digest : " s h a 2 5 6 "
value : cE2ecALeE5B + urJhDrJlVFmf38cJLAvqekONvjvpqUA =
- address_data : 185 .49 .141 .37
tls_auth_name : " g e t d n s a p i . n e t "
tls_pubkey_pinset :
- digest : " s h a 2 5 6 "
value : foxZRnIh9gZpWnl + zEiKa0EJ2rdCGroMWm02gaxSc9Q =
- address_data : 2001 : 610 : 1 : 4 0 ba:145:100:185:15
tls_auth_name : " d n s o v e r t l s . s i n o d u n . c o m "
tls_pubkey_pinset :
- digest : " s h a 2 5 6 "
value : 6 2 lKu9HsDVbyiPenApnc4sfmSYTHOVfFgL3pyB + cBL4 =
- address_data : 2001 : 610 : 1 : 4 0 ba:145:100:185:16
tls_auth_name : " d n s o v e r t l s 1 . s i n o d u n . c o m "
tls_pubkey_pinset :
- digest : " s h a 2 5 6 "
value : cE2ecALeE5B + urJhDrJlVFmf38cJLAvqekONvjvpqUA =
- address_data : 2 a04:b900:0:100::38
tls_auth_name : " g e t d n s a p i . n e t "
tls_pubkey_pinset :
- digest : " s h a 2 5 6 "
value : foxZRnIh9gZpWnl + zEiKa0EJ2rdCGroMWm02gaxSc9Q =
'' ;
# Resolution type is not changeable here because it is required per the
# stubby documentation:
#
# "resolution_type: Work in stub mode only (not recursive mode) - required for Stubby
# operation."
#
# https://dnsprivacy.org/wiki/display/DP/Configuring+Stubby
confFile = pkgs . writeText " s t u b b y . y m l " ''
resolution_type : GETDNS_RESOLUTION_STUB
dns_transport_list :
$ { fallbacks }
appdata_dir : " / v a r / c a c h e / s t u b b y "
tls_authentication : $ { cfg . authenticationMode }
tls_query_padding_blocksize : $ { toString cfg . queryPaddingBlocksize }
edns_client_subnet_private : $ { if cfg . subnetPrivate then " 1 " else " 0 " }
idle_timeout : $ { toString cfg . idleTimeout }
listen_addresses :
$ { listeners }
round_robin_upstreams : $ { if cfg . roundRobinUpstreams then " 1 " else " 0 " }
$ { cfg . extraConfig }
upstream_recursive_servers :
$ { cfg . upstreamServers }
'' ;
in
{
options = {
services . stubby = {
enable = mkEnableOption " S t u b b y D N S r e s o l v e r " ;
fallbackProtocols = mkOption {
default = [ " G E T D N S _ T R A N S P O R T _ T L S " ] ;
type = with types ; listOf ( enum [
" G E T D N S _ T R A N S P O R T _ T L S "
" G E T D N S _ T R A N S P O R T _ T C P "
" G E T D N S _ T R A N S P O R T _ U D P "
] ) ;
description = ''
Ordered list composed of one or more transport protocols .
Strict mode should only use <literal> GETDNS_TRANSPORT_TLS < /literal > .
Other options are <literal> GETDNS_TRANSPORT_UDP < /literal > and
<literal> GETDNS_TRANSPORT_TCP < /literal > .
settings = mkOption {
type = types . attrsOf settingsFormat . type ;
example = lib . literalExpression ''
pkgs . stubby . passthru . settingsExample // {
upstream_recursive_servers = [ {
address_data = " 1 5 8 . 6 4 . 1 . 2 9 " ;
tls_auth_name = " k a i t a i n . r e s t e n a . l u " ;
tls_pubkey_pinset = [ {
digest = " s h a 2 5 6 " ;
value = " 7 f t v I k A + U e N / k t V k o v d / 7 r P Z 6 m b k h V I 7 / 8 H n F J I i L a 4 = " ;
} ] ;
} ] ;
} ;
'' ;
} ;
authenticationMode = mkOption {
default = " G E T D N S _ A U T H E N T I C A T I O N _ R E Q U I R E D " ;
type = types . enum [
" G E T D N S _ A U T H E N T I C A T I O N _ R E Q U I R E D "
" G E T D N S _ A U T H E N T I C A T I O N _ N O N E "
] ;
description = ''
Selects the Strict or Opportunistic usage profile .
For strict , set to <literal> GETDNS_AUTHENTICATION_REQUIRED < /literal > .
for opportunistic , use <literal> GETDNS_AUTHENTICATION_NONE < /literal > .
'' ;
} ;
queryPaddingBlocksize = mkOption {
default = 128 ;
type = types . int ;
description = ''
EDNS0 option to pad the size of the DNS query to the given blocksize .
'' ;
} ;
subnetPrivate = mkOption {
default = true ;
type = types . bool ;
description = ''
EDNS0 option for ECS client privacy . Default is
<literal> true < /literal > . If set , this option prevents the client
subnet from being sent to authoritative nameservers .
'' ;
} ;
idleTimeout = mkOption {
default = 10000 ;
type = types . int ;
description = " E D N S 0 o p t i o n f o r k e e p a l i v e i d l e t i m e o u t e x p r e s s e d i n
milliseconds . " ;
} ;
listenAddresses = mkOption {
default = [ " 1 2 7 . 0 . 0 . 1 " " 0 : : 1 " ] ;
type = with types ; listOf str ;
description = ''
Sets the listen address for the stubby daemon .
Uses port 53 by default .
Ise IP @ port to specify a different port .
'' ;
} ;
roundRobinUpstreams = mkOption {
default = true ;
type = types . bool ;
description = ''
Instructs stubby to distribute queries across all available name
servers . Default is <literal> true < /literal > . Set to
<literal> false < /literal > in order to use the first available .
'' ;
} ;
upstreamServers = mkOption {
default = defaultUpstream ;
type = types . lines ;
description = ''
Replace default upstreams . See <citerefentry> <refentrytitle> stubby
< /refentrytitle > <manvolnum> 1 < /manvolnum > < /citerefentry > for an
example of the entry formatting . In Strict mode , at least one of the
following settings must be supplied for each nameserver :
<literal> tls_auth_name < /literal > or
<literal> tls_pubkey_pinset < /literal > .
Content of the Stubby configuration file . All Stubby settings may be set or queried
here . The default settings are available at
<literal> pkgs . stubby . passthru . settingsExample < /literal > . See
< link xlink:href= " h t t p s : / / d n s p r i v a c y . o r g / w i k i / d i s p l a y / D P / C o n f i g u r i n g + S t u b b y " / > .
A list of the public recursive servers can be found here :
< link xlink:href= " h t t p s : / / d n s p r i v a c y . o r g / w i k i / d i s p l a y / D P / D N S + P r i v a c y + T e s t + S e r v e r s " / > .
'' ;
} ;
@ -184,20 +55,21 @@ in
description = " E n a b l e o r d i s a b l e d e b u g l e v e l l o g g i n g . " ;
} ;
extraConfig = mkOption {
default = " " ;
type = types . lines ;
description = ''
Add additional configuration options . see <citerefentry>
<refentrytitle> stubby < /refentrytitle > <manvolnum> 1 < /manvolnum >
< /citerefentry > for more options .
'' ;
} ;
} ;
} ;
config = mkIf cfg . enable {
environment . systemPackages = [ pkgs . stubby ] ;
assertions = [ {
assertion =
( cfg . settings . resolution_type or " " ) == " G E T D N S _ R E S O L U T I O N _ S T U B " ;
message = ''
services . stubby . settings . resolution_type must be set to " G E T D N S _ R E S O L U T I O N _ S T U B " .
Is services . stubby . settings unset ?
'' ;
} ] ;
services . stubby . settings . appdata_dir = " / v a r / c a c h e / s t u b b y " ;
systemd . services . stubby = {
description = " S t u b b y l o c a l D N S r e s o l v e r " ;
after = [ " n e t w o r k . t a r g e t " ] ;