Add darkstat and stubby : issue libreCMC/#101 Package-feed/#8 LTS
authorRISCi_ATOM <bob@bobcall.me>
Wed, 27 Nov 2019 00:13:39 +0000 (19:13 -0500)
committerRISCi_ATOM <bob@bobcall.me>
Wed, 27 Nov 2019 00:13:39 +0000 (19:13 -0500)
12 files changed:
libs/getdns/Config.in [new file with mode: 0644]
libs/getdns/Makefile [new file with mode: 0644]
libs/yaml/Makefile [new file with mode: 0644]
net/darkstat/Makefile [new file with mode: 0644]
net/darkstat/files/darkstat.config [new file with mode: 0644]
net/darkstat/files/darkstat.init [new file with mode: 0755]
net/darkstat/patches/100-do-not-use-NI_IDN.patch [new file with mode: 0644]
net/stubby/Makefile [new file with mode: 0644]
net/stubby/files/README.md [new file with mode: 0644]
net/stubby/files/stubby.conf [new file with mode: 0644]
net/stubby/files/stubby.init [new file with mode: 0755]
net/stubby/files/stubby.yml [new file with mode: 0644]

diff --git a/libs/getdns/Config.in b/libs/getdns/Config.in
new file mode 100644 (file)
index 0000000..f6658d4
--- /dev/null
@@ -0,0 +1,16 @@
+menu "Configuration"
+       depends on PACKAGE_getdns
+
+config GETDNS_ENABLE_STUB_ONLY
+       bool "GETDNS_ENABLE_STUB_ONLY"
+       help
+               getdns can be configured for stub resolution mode only. (Removes libunbound dependency)
+       default y
+       
+config GETDNS_ENABLE_IDN_LIBIDN2
+       bool "GETDNS_ENABLE_IDN_LIBIDN2"
+       help 
+               getdns can be configured with some IDN Support. (Requires libidn2 dependency)
+       default n
+
+endmenu
diff --git a/libs/getdns/Makefile b/libs/getdns/Makefile
new file mode 100644 (file)
index 0000000..b26be3c
--- /dev/null
@@ -0,0 +1,80 @@
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=getdns
+PKG_VERSION:=1.5.2
+PKG_RELEASE:=2
+
+PKG_LICENSE:=BSD-3-Clause
+PKG_LICENSE_FILES:=LICENSE
+PKG_MAINTAINER:=Jonathan Underwood <jonathan.underwood@gmail.com>
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://getdnsapi.net/dist/
+PKG_HASH:=1826a6a221ea9e9301f2c1f5d25f6f5588e841f08b967645bf50c53b970694c0
+
+PKG_FIXUP:=autoreconf
+
+PKG_INSTALL:=1
+
+PKG_CONFIG_DEPENDS:= \
+       CONFIG_GETDNS_ENABLE_STUB_ONLY \
+       CONFIG_GETDNS_ENABLE_IDN_LIBIDN2
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/getdns/Default
+       TITLE:=getdns
+       URL:=https://getdnsapi.net/
+endef
+
+define Package/getdns
+       $(call Package/getdns/Default)
+       SECTION:=libs
+       CATEGORY:=Libraries
+       TITLE+= (library)
+       DEPENDS+= +libopenssl +!GETDNS_ENABLE_STUB_ONLY:libunbound +GETDNS_ENABLE_IDN_LIBIDN2:libidn2
+       MENU:=1
+endef
+
+define Package/getdns/description
+       This package contains the getdns library (libgetdns).
+       This package also contains the "getdns_query" command line wrapper for getdns exposing the features of this implementation (both in the official API and the additional API functions).
+endef
+
+define Package/getdns/config
+       source "$(SOURCE)/Config.in"
+endef
+
+CONFIGURE_ARGS += \
+               $(if $(CONFIG_GETDNS_ENABLE_STUB_ONLY), --enable-stub-only, ) \
+               --without-libidn \
+               $(if $(CONFIG_GETDNS_ENABLE_IDN_LIBIDN2), , --without-libidn2 ) \
+               --with-ssl="$(STAGING_DIR)/usr" \
+
+# This will make 'configure' think that our libbsd.so is missing the
+# functions inet_pton, inet_ntop, strlcpy and use the builtin. This
+# removes the libbsd dependency
+CONFIGURE_VARS += LIBBSD_LIBS=-lc
+
+define Build/InstallDev
+       $(INSTALL_DIR) $(1)/usr/include/getdns/
+       $(CP) $(PKG_INSTALL_DIR)/usr/include/getdns/getdns*.h $(1)/usr/include/getdns/
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libgetdns*.{a,so*} $(1)/usr/lib/
+       $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/getdns*.pc $(1)/usr/lib/pkgconfig/
+endef
+
+
+define Package/getdns/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libgetdns.so.* $(1)/usr/lib/
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/getdns_query $(1)/usr/sbin/getdns_query
+endef
+
+$(eval $(call BuildPackage,getdns))
diff --git a/libs/yaml/Makefile b/libs/yaml/Makefile
new file mode 100644 (file)
index 0000000..a01109d
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2008-2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=yaml
+PKG_VERSION:=0.2.2
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://pyyaml.org/download/libyaml/
+PKG_HASH:=4a9100ab61047fd9bd395bcef3ce5403365cafd55c1e0d0299cde14958e47be9
+
+PKG_MAINTAINER:=
+PKG_LICENSE:=MIT
+PKG_LICENSE_FILES:=COPYING
+PKG_CPE_ID:=cpe:/a:pyyaml_project:pyyaml
+
+PKG_INSTALL:=1
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/libyaml
+  SUBMENU:=Languages
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Fast YAML 1.1 parser and emitter library
+  URL:=https://pyyaml.org/wiki/LibYAML
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+define Build/InstallDev
+       $(INSTALL_DIR) $(1)/usr/include
+       $(CP) $(PKG_INSTALL_DIR)/usr/include/yaml.h $(1)/usr/include/
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libyaml*.{a,so*} $(1)/usr/lib/
+       $(INSTALL_DIR) $(1)/usr/lib/pkgconfig
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/yaml*.pc $(1)/usr/lib/pkgconfig/
+endef
+
+define Package/libyaml/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(CP) $(PKG_INSTALL_DIR)/usr/lib/libyaml*.so* $(1)/usr/lib/
+endef
+
+$(eval $(call BuildPackage,libyaml))
diff --git a/net/darkstat/Makefile b/net/darkstat/Makefile
new file mode 100644 (file)
index 0000000..f7c8508
--- /dev/null
@@ -0,0 +1,67 @@
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=darkstat
+PKG_VERSION:=3.0.719
+PKG_RELEASE:=4
+
+PKG_MAINTAINER:=Jean-Michel Lacroix <lacroix@lepine-lacroix.info>
+
+PKG_LICENSE:=GPL-2.0 BSD-ISC
+PKG_LICENSE_FILES:=COPYING.GPL LICENSE
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:=http://unix4lyfe.org/darkstat
+PKG_HASH:=aeaf909585f7f43dc032a75328fdb62114e58405b06a92a13c0d3653236dedd7
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/darkstat
+  SECTION:=net
+  CATEGORY:=Network
+  DEPENDS:=+libpcap +zlib
+  TITLE:=Network bandwidth monitor
+  URL:=http://unix4lyfe.org/darkstat/
+endef
+
+define Package/darkstat/description
+darkstat is a packet sniffer that runs as a background process on a cable/DSL
+router, gathers all sorts of statistics about network usage, and serves them
+over HTTP.
+endef
+
+define Package/darkstat/conffiles
+/etc/config/darkstat
+endef
+
+CONFIGURE_ARGS += \
+       --disable-debug \
+       --with-chroot-dir=/var/empty
+
+CONFIGURE_VARS += \
+       ac_cv_search_setproctitle=no \
+       ac_cv_search_strlcpy=no \
+       ac_cv_search_strlcat=no
+
+define Build/Compile
+       $(HOSTCC) $(PKG_BUILD_DIR)/static/c-ify.c \
+               -o $(PKG_BUILD_DIR)/c-ify
+       $(call Build/Compile/Default)
+endef
+
+define Package/darkstat/install
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/darkstat $(1)/usr/sbin/
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN) ./files/darkstat.init $(1)/etc/init.d/darkstat
+       $(INSTALL_DIR) $(1)/etc/config
+       $(INSTALL_CONF) ./files/darkstat.config $(1)/etc/config/darkstat
+endef
+
+$(eval $(call BuildPackage,darkstat))
diff --git a/net/darkstat/files/darkstat.config b/net/darkstat/files/darkstat.config
new file mode 100644 (file)
index 0000000..ebe5718
--- /dev/null
@@ -0,0 +1,21 @@
+config darkstat
+       option interface        'lan'
+       option syslog           false
+       option verbose          false
+       option no_promisc       false
+       option no_dns           false
+       option no_macs          false
+       option no_lastseen      false
+       option httpaddr         '0.0.0.0'
+#      option httpport         '667'
+#      option network_filter   'not (src net 192.168.1 and dst net 192.168.1)'
+#      option network_netmask  '192.168.1.0/255.255.255.0'
+       option local_only       false
+#      option hosts_max        '1000'
+#      option hosts_keep       '500'
+#      option ports_max        '60'
+#      option ports_keep       '30'
+#      option highest_port     '65534'
+#      option export_file      'darkstat_export.log'
+#      option import_file      'darkstat_export.log'
+#      option daylog_file      'darkstat_daylog.log'
diff --git a/net/darkstat/files/darkstat.init b/net/darkstat/files/darkstat.init
new file mode 100755 (executable)
index 0000000..4cd8b3e
--- /dev/null
@@ -0,0 +1,100 @@
+#!/bin/sh /etc/rc.common 
+# Copyright (C) 2018 Jean-Michel Lacroix
+
+USE_PROCD=1
+
+START=60
+
+APP=darkstat
+RUN_D=/var/empty
+PID_F=$RUN_D/$APP.pid
+CONFIGNAME=darkstat
+USER=nobody
+GROUP=nogroup
+
+CONFIGSTR=""
+FILTERSTR=""
+
+export_bool () {
+       local option="$1"
+       local section="$2"
+       local _keystr="$3"
+       local _loctmp
+       config_get_bool _loctmp "$section" "$option"
+       if [ -n "$_loctmp" ]; then
+               if [ 1 -eq "$_loctmp" ]; then
+                       CONFIGSTR="$CONFIGSTR${_keystr} "
+               fi
+       fi
+}
+
+set_config_string(){
+       mkdir -p $RUN_D
+       chown $USER:$GROUP $RUN_D
+       . /lib/functions/network.sh
+       config_load $CONFIGNAME
+       config_foreach build_config_string darkstat
+}
+
+build_config_string() {
+       local cfg="$1"                                 
+       config_get interface $cfg interface
+       network_get_device ifname "$interface"       
+       CONFIGSTR=" -i $ifname "
+       export_bool syslog $cfg "--syslog"
+       export_bool verbose $cfg "--verbose"
+       # We need the --no-daemon parameter as with PROCD the process has to run in the background
+       CONFIGSTR="$CONFIGSTR--no-daemon "
+       export_bool no_promisc $cfg "--no-promisc"
+       export_bool no_dns $cfg "--no-dns"
+       export_bool no_macs $cfg "--no-macs"
+       export_bool no_lastseen $cfg "--no-lastseen"
+       config_get httpaddr $cfg httpaddr
+       CONFIGSTR="$CONFIGSTR${httpaddr:+-b "$httpaddr"} "
+       config_get httpport $cfg httpport
+       CONFIGSTR="$CONFIGSTR${httpport:+-p "$httpport"} "
+       config_get network_netmask $cfg network_netmask
+       CONFIGSTR="$CONFIGSTR${network_netmask:+-l "$network_netmask"} "
+       export_bool local_only $cfg "--local-only"
+       config_get hosts_max $cfg hosts_max
+       CONFIGSTR="$CONFIGSTR${hosts_max:+--hosts-max "$hosts_max"} "
+       config_get hosts_keep $cfg hosts_keep
+       CONFIGSTR="$CONFIGSTR${ports_keep:+--ports-keep "$ports_keep"} "
+       config_get highest_port $cfg highest_port
+       CONFIGSTR="$CONFIGSTR${highest_port:+--highest-port "$highest_port"} "
+       config_get export_file $cfg export_file
+       CONFIGSTR="$CONFIGSTR${export_file:+--export "$export_file"} "
+       config_get import_file $cfg import_file
+       CONFIGSTR="$CONFIGSTR${import_file:+--import "$import_file"} "
+       config_get daylog_file $cfg daylog_file
+       CONFIGSTR="$CONFIGSTR${daylog_file:+--daylog "$daylog_file"} "
+       CONFIGSTR="$CONFIGSTR--chroot $RUN_D --pidfile $PID_F"
+       # Now that we have the configuration string (CONFIGSTR), let us get the filter (FILTERSTR)
+       config_get network_filter $cfg network_filter
+       FILTERSTR="${network_filter:+$network_filter}"
+}
+
+service_triggers() {
+       procd_add_reload_trigger $CONFIGNAME
+}
+
+start_service() {
+       set_config_string
+       procd_open_instance
+       procd_set_param command /usr/sbin/$APP
+       procd_append_param command $CONFIGSTR
+       # Let us check if we have a filter string and apply it if we do
+       if [ "$FILTERSTR" != "" ]; then
+               procd_append_param command "-f" "$FILTERSTR"
+       fi
+       procd_close_instance
+}
+
+stop_service() {
+       rm -f $PID_F
+}
+
+reload_service() {
+       stop
+       start
+}
diff --git a/net/darkstat/patches/100-do-not-use-NI_IDN.patch b/net/darkstat/patches/100-do-not-use-NI_IDN.patch
new file mode 100644 (file)
index 0000000..7f7eecd
--- /dev/null
@@ -0,0 +1,12 @@
+--- a/dns.c
++++ b/dns.c
+@@ -347,9 +347,6 @@ dns_main(void)
+          reply.addr = ip;
+          flags = NI_NAMEREQD;
+-#  ifdef NI_IDN
+-         flags |= NI_IDN;
+-#  endif
+          switch (ip.family) {
+             case IPv4:
+                sin.sin_family = AF_INET;
diff --git a/net/stubby/Makefile b/net/stubby/Makefile
new file mode 100644 (file)
index 0000000..20e60ad
--- /dev/null
@@ -0,0 +1,69 @@
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=stubby
+PKG_VERSION:=0.2.6
+PKG_RELEASE:=1
+
+PKG_LICENSE:=BSD-3-Clause
+PKG_LICENSE_FILES:=COPYING
+PKG_MAINTAINER:=Jonathan Underwood <jonathan.underwood@gmail.com>
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/getdnsapi/$(PKG_NAME)
+PKG_SOURCE_VERSION:=v$(PKG_VERSION)
+PKG_MIRROR_HASH:=af896c471ac67b31c2263d11fcdfcdb32a213621c2f8789f4b0a4ceca4437108
+
+PKG_FIXUP:=autoreconf
+
+PKG_INSTALL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/stubby/Default
+       TITLE:=stubby
+       URL:=https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Daemon+-+Stubby
+endef
+
+define Package/stubby
+       $(call Package/stubby/Default)
+       SECTION:=net
+       CATEGORY:=Network
+       SUBMENU:=IP Addresses and Names
+       TITLE+= - (daemon that uses getdns)
+       USERID:=stubby=410:stubby=410
+       DEPENDS:= +libyaml +getdns +ca-certificates
+endef
+
+define Package/stubby/description
+       This package contains the Stubby daemon (which utilizes the getdns library).
+
+       See https://github.com/openwrt/packages/blob/master/net/stubby/files/README.md for more details.
+endef
+
+define Package/stubby/conffiles
+/etc/stubby/stubby.yml
+endef
+
+define Package/stubby/install
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/stubby $(1)/usr/sbin/stubby
+       $(INSTALL_DIR) $(1)/etc/init.d
+       $(INSTALL_BIN)  ./files/stubby.init $(1)/etc/init.d/stubby
+       $(INSTALL_DIR) $(1)/etc/stubby
+       $(INSTALL_DATA) $(PKG_INSTALL_DIR)/etc/stubby/stubby.yml $(1)/etc/stubby/stubby.yml.default
+       $(INSTALL_DATA) ./files/stubby.yml $(1)/etc/stubby/stubby.yml
+       $(INSTALL_DIR) $(1)/etc/config
+       $(INSTALL_DATA) ./files/stubby.conf $(1)/etc/config/stubby
+endef
+
+
+define Package/stubby/conffiles
+       /etc/stubby/stubby.yml
+       /etc/config/stubby
+endef
+
+$(eval $(call BuildPackage,stubby))
diff --git a/net/stubby/files/README.md b/net/stubby/files/README.md
new file mode 100644 (file)
index 0000000..12fcef3
--- /dev/null
@@ -0,0 +1,454 @@
+
+# Stubby for OpenWRT
+
+## Stubby Description
+
+[Stubby](https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Daemon+-+Stubby) is
+an application that acts as a local DNS Privacy stub resolver (using
+DNS-over-TLS). Stubby encrypts DNS queries sent from a client machine to a DNS
+Privacy resolver increasing end user privacy.
+
+Stubby is useful on an OpenWRT device, because it can sit between the usual DNS
+resolver (dnsmasq by default) and the upstream DNS resolver and be used to
+ensure that DNS traffic is encrypted between the OpenWRT device and the
+resolver.
+
+Stubby is developed by the [getdns](http://getdnsapi.net/) project.
+
+For more background and FAQ see the [About
+Stubby](https://dnsprivacy.org/wiki/display/DP/About+Stubby) page.
+
+
+## Installation
+
+Installation of this package can be achieved at the command line using `opkg
+install stubby`, or via the LUCI Web Interface. Installing the stubby package
+will also install the required dependency packages, including the
+`ca-certificates` package.
+
+## Configuration
+
+The default configuration of the package has been chosen to ensure that stubby
+should work after installation.
+
+By default, configuration of stubby is integrated with the OpenWRT UCI system
+using the file `/etc/config/stubby`. The configuration options available are
+also documented in that file. If for some reason you wish to configure stubby
+using the `/etc/stubby/stubby.yml` file, then you simply need to set `option
+manual '1'` in `/etc/config/stubby` and all other settings in
+`/etc/config/stubby` will be ignored.
+
+### Stubby port and addresses
+
+The default configuration ensures that stubby listens on port 5453 on the
+loopback interfaces for IPv4 and IPv6. As such, by default, stubby will respond
+only to lookups from the OpenWRT device itself.
+
+By setting the listening ports to non-standard values, this allows users to keep
+the main name server daemon in place (dnsmasq/unbound/etc.) and have that name
+server forward to stubby.
+
+### Upstream resolvers
+
+The default package configuration uses the CloudFlare resolvers, configured for
+both IPv4 and IPv6. 
+
+CloudFlare have not published SPKI pinsets, and even though they are available,
+they have made no commitment to maintaining them. Using the currently known SPKI
+pinsets for CloudFlare brings the risk that in the future they may be changed by
+CloudFlare, and DNS would stop working. The default configuration has those SPKI
+entries commented out for this reason.
+
+[CloudFlare's privacy
+statement](https://developers.cloudflare.com/1.1.1.1/commitment-to-privacy/)
+details how they treat data from DNS requests.
+
+More resolvers are available in the [upstream stubby example
+configuration](https://github.com/getdnsapi/stubby/blob/develop/stubby.yml.example)
+and the [DNS Privacy
+list](https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Test+Servers).
+
+## Integration of stubby with dnsmasq
+
+The recommended way to use stubby on an OpenWRT device is to integrate it with a
+caching resolver. The default caching resolver in OpenWRT is dnsmasq.
+
+### Set dnsmasq to send DNS requests to stubby
+
+Since dnsmasq responds to LAN DNS requests on port 53 of the OpenWRT device by
+default, all that is required is to have dnsmasq forward those requests to
+stubby which is listening on port 5453 of the OpenWRT device. To achieve this,
+we need to set the `server` option in the dnsmasq configuration in the
+`/etc/config/dhcp` file to `'127.0.0.1#5453'`. We also need to tell dnsmasq not
+to use resolvers found in `/etc/resolv.conf` by setting the dnsmasq option
+`noresolv` to `1` in the same file. This can be achieved by editing the
+`/etc/config/dhcp` file directly or executing the following commands at the
+command line:
+
+    uci add_list dhcp.@dnsmasq[-1].server='127.0.0.1#5453'
+    uci set dhcp.@dnsmasq[-1].noresolv=1
+    uci commit && reload_config
+
+The same outcome can be achieved in the LUCI web interface as follows:
+
+1. Select the Network->DHCP and DNS menu entry.
+2. In the "General Settings" tab, enter the address `127.0.0.1#5453` as the only
+   entry in the "DNS Forwardings" dialogue.
+3. In the "Resolv and Host files" tab tick the "Ignore resolve file" checkbox.
+
+### Disable sending DNS requests to ISP provided DNS servers
+
+The configuration changes in the previous section ensure that DNS queries are
+sent over TLS encrypted connections *once dnsmasq and stubby are started*. When
+the OpenWRT device is first brought up, there is a possibility that DNS queries
+can go to ISP provided DNS servers ahead of dnsmasq and stubby being active. In
+order to mitigate this leakage, it's necessary to ensure that upstream resolvers
+aren't available, and the only DNS resolver used by the system is
+dnsmasq+stubby. 
+
+This requires setting the option `peerdns` to `0` and the option `dns` to the
+loopback address for both the `wan` and `wan6` interfaces in the
+`/etc/config/network` file. This can be achieved by editing the
+`/etc/config/network` file directly, or by executing the following commands:
+
+    uci set network.wan.peerdns='0'
+    uci set network.wan.dns='127.0.0.1'
+    uci set network.wan6.peerdns='0'
+    uci set network.wan6.dns='0::1'
+    uci commit && reload_config
+
+The same outcome can also be achieved using the LUCI web interface as follows:
+
+1. Select the Network->Interfaces menu entry.
+2. Click on Edit for the WAN interfaces.
+3. Choose the Advanced Settings tab.
+4. Unselect the "Use DNS servers advertised by peer" checkbox
+5. Enter `127.0.0.1` in the "Use custom DNS servers" dialogue box.
+6. Repeat the above steps for the WAN6 interface, but use the address `0::1`
+   instead of `127.0.0.1`.
+   
+### Enabling DNSSEC
+
+The configuration described above ensures that DNS queries are executed over TLS
+encrypted links. However, the responses themselves are not validated; DNSSEC
+provides the ability to validate returned DNS responses, and mitigate against
+DNS poisoning risks.
+
+With the combination of stubby+dnsmasq there are two possible ways to enable
+DNSSEC:
+
+1. Configure stubby to perform DNSSEC validation, and configure dnsmasq to proxy
+   the DNSSEC data to clients.
+2. Configure stubby not to perform DNSSEC validation and configure dnsmasq to
+   require DNSSEC validation.
+
+Either option achieves the same outcome, and there appears to be little reason
+for choosing one over the other other than that the second option is easier to
+configure in the LUCI web interface. Both options are detailed below, and both
+require that the `dnsmasq` package on the OpenWRT device is replaced with the
+`dnsmasq-full` package. That can be achieved by running the following command:
+
+    opkg install dnsmasq-full --download-only && opkg remove dnsmasq && opkg install dnsmasq-full --cache . && rm *.ipk
+
+#### DNSSEC by stubby
+
+Configuring stubby to perform DNSSEC validation requires setting the stubby
+configuration option `dnssec_return_status` to `'1'` in `/etc/config/stubby`,
+which can be done by editing the file directly or by executing the commands:
+
+    uci set stubby.global.dnssec_return_status=1
+    uci commit && reload_config
+    
+With stubby performing DNSSEC validation, dnsmasq needs to be configured to
+proxy the DNSSEC data to clients. This requires setting the option `proxydnssec`
+to 1 in the dnsmasq configuration in `/etc/config/dhcp`. That can be achieved by
+the following commands:
+
+    uci set dhcp.@dnsmasq[-1].proxydnssec=1
+    uci commit && reload_config
+
+#### DNSSEC by dnsmasq
+
+Configuring dnsmasq to perform DNSSEC validation requires setting the dnsmasq
+option `dnssec` to `1` in the `/etc/config/dhcp` file. In addition, it is
+advisable to also set the dnsmasq option `dnsseccheckunsigned` to `1`. this can
+be achieved by editing the file `/etc/config/dhcp` or by executing the following
+commands:
+
+    uci set dhcp.@dnsmasq[-1].dnssec=1
+    uci set dhcp.@dnsmasq[-1].dnsseccheckunsigned=1
+    uci commit && reload_config
+
+The same options can be set in the LUCI web interface as follows:
+
+1. Select the "Network->DHCP and DNS" menu entry.
+2. Select the "Advanced Settings" tab.
+3. Ensure both the "DNSSEC" and "DNSSEC check unsigned" check boxes are ticked.
+
+#### Validating DNSSEC operation
+
+Having configured DNSSEC validation using one of the two approaches above, it's
+important to check it's actually working. The following command can be used:
+
+    dig dnssectest.sidn.nl +dnssec +multi @192.168.1.1
+    
+This command should return output like the following:
+
+    ; <<>> DiG 9.11.4-P1-RedHat-9.11.4-5.P1.fc28 <<>> dnssectest.sidn.nl +dnssec +multi @192.168.1.1
+    ;; global options: +cmd
+    ;; Got answer:
+    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 26579
+    ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
+
+    ;; OPT PSEUDOSECTION:
+    ; EDNS: version: 0, flags: do; udp: 512
+    ;; QUESTION SECTION:
+    ;dnssectest.sidn.nl.       IN A
+
+    ;; ANSWER SECTION:
+    dnssectest.sidn.nl.        14399 IN A 213.136.9.12
+    dnssectest.sidn.nl.        14399 IN RRSIG A 8 3 14400 (
+                               20181104071058 20181005071058 42033 sidn.nl.
+                               YAQl3tef36M9EQUOmCneHKCCkxox3csLpfUOql5i/6ND
+                               zPrQFsNr3g32HPoxOsi+hD2BE5+bEsnARayDSVLyx0qU
+                               6Hpi2rzQ0zGNZZkCJhCsdp3wnM1BWlMgPrCD0iIsJDok
+                               +DH5zu+yYufVUdSLQrMqA3MZDFUIqDUqSZuYDF4= )
+
+    ;; Query time: 77 msec
+    ;; SERVER: 192.168.1.1#53(192.168.1.1)
+    ;; WHEN: Sat Oct 06 20:36:25 BST 2018
+    ;; MSG SIZE  rcvd: 230
+
+The key thing to note is the `flags: qr rd ra ad` part - the `ad` flag signifies
+that DNSSEC validation is working. If that flag is absent DNSSEC validation is
+not working.
+
+## Appendix: stubby configuration options
+
+This section details the options available for use in the `/etc/config/stubby`
+file. The `global` configuration section specifies the configuration parameters
+for the stubby daemon. One or more `resolver` sections are used to configure
+upstream resolvers for the stubby daemon to use.
+
+### `global` section options
+
+#### `option manual`
+
+Specify whether to use this file to configure the stubby service. If this is set
+to `'1'` stubby will be configured using the file `/etc/stubby/stubby.yml`. If this
+is set to `'0'`, configuration options will be taken from this file, and the service
+will be managed through UCI.
+
+#### `option trigger`
+
+This specifies an interface to trigger stubby start up on; stubby startup will
+be triggered by a procd signal associated with this interface being ready. If
+this interface is restarted, stubby will also be restarted. 
+
+This option can also be set to `'timed'`, in which case a time, specified by the
+option `triggerdelay`, will be waited before starting stubby.
+
+
+#### `option triggerdelay`
+
+If the `trigger` option specifies an interface, this option sets the time that
+is waited after the procd signal is received before starting stubby. 
+
+If `trigger` is set to `'timed'` then this is the delay before starting stubby.
+This option is specified in seconds and defaults to the value `'2'`.
+
+#### `list dns_transport`
+
+The `dns_transport` list specifies the allowed transports. Allowed values are:
+`GETDNS_TRANSPORT_UDP`, `GETDNS_TRANSPORT_TCP` and `GETDNS_TRANSPORT_TLS`. The
+transports are tried in the order listed.
+
+#### `option tls_authentication`
+
+This option specifies whether TLS authentication is mandatory. A value of `'1'`
+mandates TLS authentication, and is the default.
+
+If this is set to `'0'`, and `GETDNS_TRANSPORT_TCP` or `GETDNS_TRANSPORT_UDP`
+appears in the `dns_transport` list, stubby is allowed to fall back to non-TLS
+authenticated lookups. You probably don't want this though.
+
+#### `option tls_query_padding_blocksize`
+
+This option specifies the block size to pad DNS queries to. You shouldn't need
+to set this to anything but `'128'` (the default), as recommended by
+https://tools.ietf.org/html/draft-ietf-dprive-padding-policy-03
+
+#### `option tls_connection_retries`
+
+This option specifies the number of connection failures stubby permits before
+Stubby backs-off from using an individual upstream resolver. You shouldn't need
+to change this from the default value of `'2'`.
+
+#### `option tls_backoff_time`
+
+This option specifies the maximum time in seconds Stubby will back-off from
+using an individual upstream after failures. You shouldn't need to change this
+from the default value of `'3600'`.
+
+#### `option timeout`
+
+This option specifies the timeout on getting a response to an individual
+request. This is specified in milliseconds. You shouldn't need to change this
+from the default value of ` '5000'`.
+
+#### `option dnssec_return_status`
+
+This option specifies whether stubby should require DNSSEC validation. Specify
+to `'1'` to turn on validation, and `'0'` to turn it off. By default it is off.
+
+#### `option appdata_dir`
+
+This option specifies the location for storing stubby runtime data. In
+particular, if DNSSEC is turned on, stubby will store its automatically
+retrieved trust anchor data here. The default value is `'/var/lib/stubby'`.
+
+#### `option trust_anchors_backoff_time`
+
+When Zero configuration DNSSEC failed, because of network unavailability or
+failure to write to the appdata directory, stubby will backoff trying to refetch
+the DNSSEC trust-anchor for a specified amount of time expressed in milliseconds
+(which defaults to two and a half seconds).
+
+#### `option dnssec_trust_anchors`
+
+This option sets the location of the file containing the trust anchor data used
+for DNSSEC validation. If this is not specified, stubby will automatically
+retrieve a trust anchor at startup. It's unlikely you'll want to manage the
+trust anchor data manually, so in most cases this is not needed. By default,
+this is unset.
+
+#### `option edns_client_subnet_private`
+
+This option specifies whether to enforce ECS client privacy. The default is
+`'1'`. Set to `'0'` to disable client privacy.
+
+For more details see Section 7.1.2 [here](https://tools.ietf.org/html/rfc7871).
+
+#### `option idle_timeout`
+
+This option specifies the time (in milliseconds) to hold TLS connections open to
+avoid the overhead of opening a new connection for every query. You should not
+normally need to change this from the default value (currently `'10000'`).
+
+See [here](https://tools.ietf.org/html/rfc7828) for more details.
+
+#### `option round_robin_upstreams`
+
+This option specifies how stubby will use the upstream DNS resolvers. Set to
+`'1'` (the default) to instruct stubby to distribute queries across all
+available name servers - this will use multiple simultaneous connections which
+can give better performance in most (but not all) cases. Set to `'0'` to treat
+the upstream resolvers as an ordered list and use a single upstream resolver
+until it becomes unavailable, then use the next one.
+
+#### `list listen_address`
+
+This list sets the addresses and ports for the stubby daemon to listen for
+requests on. the default configuration configures stubby to listen on port 5453
+on the loopback interface for both IPv4 and IPv6.
+
+#### `option log_level`
+
+If set, this option specifies the level of logging from the stubby
+daemon. By default, this option is not set.
+
+The possible levels are:
+
+    '0': EMERG  - System is unusable
+    '1': ALERT  - Action must be taken immediately
+    '2': CRIT   - Critical conditions
+    '3': ERROR  - Error conditions
+    '4': WARN   - Warning conditions
+    '5': NOTICE - Normal, but significant, condition
+    '6': INFO   - Informational message
+    '7': DEBUG  - Debug-level message
+
+#### `option command_line_arguments`
+
+This option specifies additional command line arguments for
+stubby daemon. By default, this is an empty string.
+
+#### `option tls_cipher_list`
+
+If set, this specifies the acceptable ciphers for DNS over TLS. With OpenSSL
+1.1.1 this list is for TLS1.2 and older only. Ciphers for TLS1.3 should be set
+with the `tls_ciphersuites` option. This option can also be given per upstream
+resolver. By default, this option is not set.
+
+#### `option tls_ciphersuites`
+
+If set, this specifies the acceptable cipher for DNS over TLS1.3. OpenSSL
+version 1.1.1 or greater is required for this option. This option can also be
+given per upstream resolver. By default, this option is not set.
+
+#### `option tls_min_version`
+
+If set, this specifies the minimum acceptable TLS version. Works with OpenSSL
+1.1.1 or greater only. This option can also be given per upstream resolver. By
+default, this option is not set.
+
+#### `option tls_max_version`
+
+If set, this specifies the maximum acceptable TLS version. Works with OpenSSL
+1.1.1 or greater only. This option can also be given per upstream resolver. By
+default, this option is not set.
+
+
+### `resolver` section options
+
+#### `option address`
+
+This option specifies the resolver IP address, and can either be an IPv4 or an
+IPv6 address.
+
+#### `option tls_auth_name`
+
+This option specifies the upstream domain name used for TLS authentication with
+the supplied server certificate
+
+#### `option tls_port`
+
+This option specifies the TLS port for the upstream resolver. If not specified,
+this defaults to 853.
+
+#### `option tls_cipher_list`
+
+If set, this specifies the acceptable ciphers for DNS over TLS. With OpenSSL
+1.1.1 this list is for TLS1.2 and older only. Ciphers for TLS1.3 should be set
+with the `tls_ciphersuites` option. By default, this option is not set. If set,
+this overrides the global value.
+
+#### `option tls_ciphersuites`
+
+If set, this specifies the acceptable cipher for DNS over TLS1.3. OpenSSL
+version 1.1.1 or greater is required for this option. By default, this option is
+not set. If set, this overrides the global value.
+
+#### `option tls_min_version`
+
+If set, this specifies the minimum acceptable TLS version. Works with OpenSSL
+1.1.1 or greater only. By default, this option is not set. If set, this
+overrides the global value.
+
+#### `option tls_max_version`
+
+If set, this specifies the maximum acceptable TLS version. Works with OpenSSL
+1.1.1 or greater only. By default, this options is not set. If set, this
+overrides the global value.
+
+#### `list spki`
+
+This list specifies the SPKI pinset which is verified against the keys in the
+server cerrtificate. The value takes the form `'<digest type>/value>'`, where
+the `digest type` is the hashing algorithm used, and the value is the Base64
+encoded hash of the public key. At present, only `sha256` is
+supported for the digest type.
+
+This should ONLY be used if the upstream resolver has committed to maintaining
+the pinset. CloudFlare have made no such commitment, and so we do not specify
+the SPKI values in the default configuration, even though they are available.
diff --git a/net/stubby/files/stubby.conf b/net/stubby/files/stubby.conf
new file mode 100644 (file)
index 0000000..f722a43
--- /dev/null
@@ -0,0 +1,66 @@
+config stubby 'global'
+       option manual '0'
+       option trigger 'wan'
+       # option triggerdelay '2'
+       list dns_transport 'GETDNS_TRANSPORT_TLS'
+       option tls_authentication '1'
+       option tls_query_padding_blocksize '128'
+       # option tls_connection_retries '2'
+       # option tls_backoff_time '3600'
+       # option timeout '5000'
+       # option dnssec_return_status '0'
+       option appdata_dir '/var/lib/stubby'
+       # option trust_anchors_backoff_time 2500
+       # option dnssec_trust_anchors '/var/lib/stubby/getdns-root.key'
+       option edns_client_subnet_private '1'
+       option idle_timeout '10000'
+       option round_robin_upstreams '1'
+       list listen_address '127.0.0.1@5453'
+       list listen_address '0::1@5453'
+       # option log_level '7'
+       # option command_line_arguments ''
+       # option tls_cipher_list 'EECDH+AESGCM:EECDH+CHACHA20'
+       # option tls_ciphersuites 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
+       # option tls_min_version '1.2'
+       # option tls_max_version '1.3'
+
+# Upstream resolvers are specified using 'resolver' sections.
+config resolver
+       option address '2606:4700:4700::1111'
+       option tls_auth_name 'cloudflare-dns.com'
+       # option tls_port 853
+       # list spki 'sha256/yioEpqeR4WtDwE9YxNVnCEkTxIjx6EEIwFSQW+lJsbc='
+       # option tls_cipher_list 'EECDH+AESGCM:EECDH+CHACHA20'
+       # option tls_ciphersuites 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
+       # option tls_min_version '1.2'
+       # option tls_max_version '1.3'
+
+config resolver
+       option address '2606:4700:4700::1001'
+       option tls_auth_name 'cloudflare-dns.com'
+       # option tls_port 853
+       # list spki 'sha256/yioEpqeR4WtDwE9YxNVnCEkTxIjx6EEIwFSQW+lJsbc='
+       # option tls_cipher_list 'EECDH+AESGCM:EECDH+CHACHA20'
+       # option tls_ciphersuites 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
+       # option tls_min_version '1.2'
+       # option tls_max_version '1.3'
+
+config resolver
+       option address '1.1.1.1'
+       option tls_auth_name 'cloudflare-dns.com'
+       # option tls_port 853
+       # list spki 'sha256/yioEpqeR4WtDwE9YxNVnCEkTxIjx6EEIwFSQW+lJsbc='
+       # option tls_cipher_list 'EECDH+AESGCM:EECDH+CHACHA20'
+       # option tls_ciphersuites 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
+       # option tls_min_version '1.2'
+       # option tls_max_version '1.3'
+
+config resolver
+       option address '1.0.0.1'
+       option tls_auth_name 'cloudflare-dns.com'
+       # option tls_port 853
+       # list spki 'sha256/yioEpqeR4WtDwE9YxNVnCEkTxIjx6EEIwFSQW+lJsbc='
+       # option tls_cipher_list 'EECDH+AESGCM:EECDH+CHACHA20'
+       # option tls_ciphersuites 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256'
+       # option tls_min_version '1.2'
+       # option tls_max_version '1.3'
diff --git a/net/stubby/files/stubby.init b/net/stubby/files/stubby.init
new file mode 100755 (executable)
index 0000000..cf051a1
--- /dev/null
@@ -0,0 +1,273 @@
+#!/bin/sh /etc/rc.common
+
+USE_PROCD=1
+
+START=30
+STOP=51
+
+stubby="/usr/sbin/stubby"
+stubby_init="/etc/init.d/stubby"
+stubby_config_dir="/var/etc/stubby"
+stubby_config="$stubby_config_dir/stubby.yml"
+stubby_pid_file="/var/run/stubby.pid"
+stubby_manual_config="/etc/stubby/stubby.yml"
+
+boot()
+{
+    stubby_boot=1
+    rc_procd start_service
+}
+
+generate_config()
+{
+    local config_file="$1"
+    local round_robin
+    local tls_authentication
+    local tls_query_padding_blocksize
+    local edns_client_subnet_private
+    local idle_timeout
+    local appdata_dir
+    local trust_anchors_backoff_time
+    local tls_connection_retries
+    local tls_backoff_time
+    local timeout
+    local dnssec_return_status
+    local dnssec_trust_anchors
+    local listen_addresses_section=0
+    local dns_transport_list_section=0
+    local upstream_recursive_servers_section=0
+    local command_line_arguments
+    local log_level
+    local tls_cipher_list
+    local tls_ciphersuites
+    local tls_min_version
+    local tls_max_version
+
+    # Generate configuration. See: https://github.com/getdnsapi/stubby/blob/develop/stubby.yml.example
+    echo "# Autogenerated configuration from uci data" > "$config_file"
+    echo "resolution_type: GETDNS_RESOLUTION_STUB" >> "$config_file"
+
+    config_get round_robin "global" round_robin_upstreams "1"
+    echo "round_robin_upstreams: $round_robin" >> "$config_file"
+
+    config_get appdata_dir "global" appdata_dir "/var/lib/stubby"
+    echo "appdata_dir: \"$appdata_dir\"" >> "$config_file"
+
+    config_get trust_anchors_backoff_time "global" trust_anchors_backoff_time "2500"
+    echo "trust_anchors_backoff_time: $trust_anchors_backoff_time" >> "$config_file"
+
+    config_get tls_connection_retries "global" tls_connection_retries ""
+    if [ -n "$tls_connection_retries" ]; then
+        echo "tls_connection_retries: $tls_connection_retries" >> "$config_file"
+    fi
+
+    config_get tls_backoff_time "global" tls_backoff_time ""
+    if [ -n "$tls_backoff_time" ]; then
+        echo "tls_backoff_time: $tls_backoff_time" >> "$config_file"
+    fi
+
+    config_get timeout "global" timeout ""
+    if [ -n "$timeout" ]; then
+        echo "timeout: $timeout" >> "$config_file"
+    fi
+
+    config_get_bool tls_authentication "global" tls_authentication "1"
+    if [ "$tls_authentication" = "1" ]; then
+        echo "tls_authentication: GETDNS_AUTHENTICATION_REQUIRED" >> "$config_file"
+    else
+        echo "tls_authentication: GETDNS_AUTHENTICATION_NONE" >> "$config_file"
+    fi
+
+    config_get_bool dnssec_return_status "global" dnssec_return_status "0"
+    if [ "$dnssec_return_status" = "1" ]; then
+        echo "dnssec_return_status: GETDNS_EXTENSION_TRUE" >> "$config_file"
+    fi
+
+    config_get dnssec_trust_anchors "global" dnssec_trust_anchors ""
+    if [ -n "$dnssec_trust_anchors" ]; then
+        echo "dnssec_trust_anchors: \"$dnssec_trust_anchors\"" >> "$config_file"
+    fi
+
+    config_get tls_query_padding_blocksize "global" tls_query_padding_blocksize "128"
+    echo "tls_query_padding_blocksize: $tls_query_padding_blocksize" >> "$config_file"
+
+    config_get_bool edns_client_subnet_private "global" edns_client_subnet_private "1"
+    echo "edns_client_subnet_private: $edns_client_subnet_private" >> "$config_file"
+
+    config_get idle_timeout "global" idle_timeout "10000"
+    echo "idle_timeout: $idle_timeout" >> "$config_file"
+
+    config_get tls_cipher_list "global" tls_cipher_list ""
+    if [ -n "$tls_cipher_list" ]; then
+        echo "tls_cipher_list: \"$tls_cipher_list\"" >> "$config_file"
+    fi
+
+    config_get tls_ciphersuites "global" tls_ciphersuites ""
+    if [ -n "$tls_ciphersuites" ]; then
+        echo "tls_ciphersuites: \"$tls_ciphersuites\"" >> "$config_file"
+    fi
+
+    config_get tls_min_version "global" tls_min_version ""
+    if [ -n "$tls_min_version" ]; then
+        echo "tls_min_version: GETDNS_TLS${tls_min_version/\./_}" >> "$config_file"
+    fi
+
+    config_get tls_max_version "global" tls_max_version ""
+    if [ -n "$tls_max_version" ]; then
+        echo "tls_max_version: GETDNS_TLS${tls_max_version/\./_}" >> "$config_file"
+    fi
+
+    handle_listen_address_value()
+    {
+        local value="$1"
+
+        if [ "$listen_addresses_section" = 0 ]; then
+            echo "listen_addresses:" >> "$config_file"
+            listen_addresses_section=1
+        fi
+        echo "  - $value" >> "$config_file"
+    }
+    config_list_foreach "global" listen_address handle_listen_address_value
+
+    handle_dns_transport_list_value()
+    {
+        local value="$1"
+
+        if [ "$dns_transport_list_section" = 0 ]; then
+            echo "dns_transport_list:" >> "$config_file"
+            dns_transport_list_section=1
+        fi
+        echo "  - $value" >> "$config_file"
+    }
+    config_list_foreach "global" dns_transport handle_dns_transport_list_value
+
+    handle_resolver()
+    {
+        local config=$1
+        local address
+        local tls_auth_name
+        local tls_port
+        local tls_pubkey_pinset_section=0
+        local tls_cipher_list
+        local tls_ciphersuites
+        local tls_min_version
+        local tls_max_version
+
+        if [ "$upstream_recursive_servers_section" = 0 ]; then
+            echo "upstream_recursive_servers:" >> "$config_file"
+            upstream_recursive_servers_section=1
+        fi
+        config_get address "$config" address
+        echo "  - address_data: $address" >> "$config_file"
+
+        config_get tls_auth_name "$config" tls_auth_name
+        echo "    tls_auth_name: \"$tls_auth_name\"" >> "$config_file"
+
+        config_get tls_auth_port "$config" tls_port ""
+        if [ -n "$tls_port" ]; then
+            echo "    tls_port: $tls_port"  >> "$config_file"
+        fi
+
+        config_get tls_cipher_list "$config" tls_cipher_list ""
+        if [ -n "$tls_cipher_list" ]; then
+            echo "    tls_cipher_list: \"$tls_cipher_list\"" >> "$config_file"
+        fi
+
+        config_get tls_ciphersuites "$config" tls_ciphersuites ""
+        if [ -n "$tls_ciphersuites" ]; then
+            echo "    tls_ciphersuites: \"$tls_ciphersuites\"" >> "$config_file"
+        fi
+
+        config_get tls_min_version "$config" tls_min_version ""
+        if [ -n "$tls_min_version" ]; then
+            echo "    tls_min_version: GETDNS_TLS${tls_min_version/\./_}" >> "$config_file"
+        fi
+
+        config_get tls_max_version "$config" tls_max_version ""
+        if [ -n "$tls_max_version" ]; then
+            echo "    tls_max_version: GETDNS_TLS${tls_max_version/\./_}" >> "$config_file"
+        fi
+
+        handle_resolver_spki()
+        {
+            local val="$1"
+            local digest="${val%%/*}"
+            local value="${val#*/}"
+
+            if [ "$tls_pubkey_pinset_section" = 0 ]; then
+                echo "    tls_pubkey_pinset:" >> "$config_file"
+                tls_pubkey_pinset_section=1
+            fi
+            echo "      - digest: \"$digest\"" >> "$config_file"
+            echo "        value: $value" >> "$config_file"
+        }
+        config_list_foreach "$config" spki handle_resolver_spki
+    }
+
+    config_foreach handle_resolver resolver
+}
+
+start_service() {
+    local config_file_tmp
+    local manual
+    local log_level
+    local command_line_arguments
+
+    mkdir -p "$stubby_config_dir"
+
+    config_load "stubby"
+
+    config_get_bool manual "global" manual "0"
+
+    if [ "$manual" = "1" ]; then
+        cp "$stubby_manual_config" "$stubby_config"
+    else
+        config_file_tmp="$stubby_config.$$"
+        generate_config "$config_file_tmp"
+        mv "$config_file_tmp" "$stubby_config"
+    fi
+
+    config_get command_line_arguments "global" command_line_arguments ""
+
+    config_get log_level "global" log_level ""
+
+    if [ "$("$stubby_init" enabled; printf "%u" $?)" -eq 0 ]; then
+        if [ -n "$stubby_boot" ]; then
+            local trigger
+            trigger="$(uci_get stubby global trigger)"
+            if [ "$trigger" != "timed" ]; then
+                return 0
+            fi
+        fi
+        procd_open_instance "stubby"
+        procd_set_param command "$stubby" -C "$stubby_config"
+        if [ -n "$log_level" ]; then
+            procd_append_param command -v "$log_level"
+        fi
+        if [ -n "$command_line_arguments" ]; then
+            procd_append_param command "$command_line_arguments"
+        fi
+        procd_set_param respawn
+        procd_set_param file "$stubby_config"
+        procd_set_param stdout 1
+        procd_set_param stderr 1
+        procd_set_param pidfile "$stubby_pid_file"
+        procd_set_param user stubby
+        procd_close_instance
+    fi
+}
+
+service_triggers()
+{
+    local trigger
+    local delay
+
+    trigger="$(uci_get stubby global trigger)"
+    delay="$(uci_get stubby global triggerdelay "2")"
+
+    if [ "$trigger" != "none" ] && [ "$trigger" != "timed" ]; then
+        PROCD_RELOAD_DELAY=$((${delay:-2} * 1000))
+        procd_add_interface_trigger "interface.*.up" "$trigger" "$stubby_init" start
+    fi
+    procd_add_reload_trigger "stubby"
+}
diff --git a/net/stubby/files/stubby.yml b/net/stubby/files/stubby.yml
new file mode 100644 (file)
index 0000000..b935f31
--- /dev/null
@@ -0,0 +1,25 @@
+# Note: by default on OpenWRT stubby configuration is handled via
+# the UCI system and the file /etc/config/stubby. If you want to
+# use this file to configure stubby, then set "option manual '1'"
+# in /etc/config/stubby.
+resolution_type: GETDNS_RESOLUTION_STUB
+round_robin_upstreams: 1
+appdata_dir: "/var/lib/stubby"
+tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
+tls_query_padding_blocksize: 128
+edns_client_subnet_private: 1
+idle_timeout: 10000
+listen_addresses:
+  - 127.0.0.1@5453
+  - 0::1@5453
+dns_transport_list:
+  - GETDNS_TRANSPORT_TLS
+upstream_recursive_servers:
+  - address_data: 2606:4700:4700::1111
+    tls_auth_name: "cloudflare-dns.com"
+  - address_data: 2606:4700:4700::1001
+    tls_auth_name: "cloudflare-dns.com"
+  - address_data: 1.1.1.1
+    tls_auth_name: "cloudflare-dns.com"
+  - address_data: 1.0.0.1
+    tls_auth_name: "cloudflare-dns.com"