MichaIng / DietPi

Lightweight justice for your single-board computer!
https://dietpi.com/
GNU General Public License v2.0
4.69k stars 492 forks source link

DietPi-Software | DNSCrypt-proxy #4772

Open ss-o opened 2 years ago

ss-o commented 2 years ago

I find DNSCrypt-Proxy secure, efficient, and easy to integrate with other services in relation while in use with Dietpi. Is there any plans for this feature? If yes does it need support?

Sincerely, @ss-o

MichaIng commented 2 years ago

Many thanks for your request.

It was requested somewhere as optional addition to Pi-hole. We could have it as an alternative to Unbound, optionally used by Pi-hole.

ss-o commented 2 years ago

Could advise me what should take into consideration (templates, general preferences, standards, etc.) while working on this?

Joulinar commented 2 years ago

we created a wiki article if you like to participate on adding some software title

https://github.com/MichaIng/DietPi/wiki/How-to-add-a-new-software-title

MichaIng commented 2 years ago

To keep it simply, use the Debian APT package: https://packages.debian.org/dnscrypt-proxy It has the service included, so should just work.

To align with the DietPi default upstream DNS, using Quad9 as default upstream DNS (it supports DNSCrypt of course)?

And then I'd integrate it similarly to Unbound:

Joulinar commented 2 years ago

don't forget about AdGuard Home. It's conflicting installation as well and would need to be adjusted same way. Next to this, installation to be prevented if Unbound is present.

ss-o commented 2 years ago

Overall DNSCrypt-Proxy should have 2 configurations, standalone and Adguard/Pi-hole with Quad9 as the default, installed as an asynchronous alternative for Unbound?

Thank you for your responses, will follow up.

MichaIng commented 2 years ago

Seems like APT is few versions behind, as well further update changes may cause additional issues.

On the other hand, Debian's stability is based on exactly that: The upstream versions of packages are basically frozen to assure no breaking changes happen during APT upgrades and everything stays compatible. Using up-to-date binaries from elsewhere implies the risk that a reinstall/upgrade breaks existing configs etc. But that doesn't mean that I am generally against it. If there are significant features missing on Debian (Bullseye)'s version, than it may be worth use newer sources.

ss-o commented 2 years ago

Changes:

Taking your advice into consideration, APT install makes more sense, for user preferences manual update documentation could be added.

MichaIng commented 2 years ago

DoH is supported by Unbound as well (on Bullseye). But good is that DNSCrypt ships pre-compiled binaries as well for all supported platforms: https://github.com/DNSCrypt/dnscrypt-proxy/releases

ss-o commented 2 years ago

Oblivious DoH DNS is an extension of DoH which has been co-developed by Cloudflare, Apple, and Fastly. It has to go through a relay that aims to address the privacy concerns of DoH to make DNS secure and private. It decouples the DNS queries from the IP addresses (of the user) to prevent the DNS resolver from knowing the sites that a user visits. It's considered as future DNS by many experts. In my personal opinion after trying multiple combinations of ODOH, it will become very popular in a short period, and DNSCrypt-Proxy is currently one of the easiest ways to use it.

odoh

Joulinar commented 2 years ago

Yeah, quite some scripting to be done to cover all cases. But all code sections should be available already and would need to be adjusted "only".

MichaIng commented 2 years ago

Probably it makes sense to merge install and config blocks of Pi-hole, AdGuard Home (if not the case yet) and Unbound first, to simplify the complexity of the logic.

Joulinar commented 2 years ago

Maybe we should do that first before adding another title? Just thinking.

MichaIng commented 2 years ago

In this case it makes sense to simplify the logic, but I don't see a reason to do it for all software titles. It's usually just a code reorder without any logical effect, so can be done just when touching those code lines anyway.

Joulinar commented 2 years ago

I meant to simplify code sections for AGH, Pihole and unbound first before going to include DNS crypt. I don't won't to do it for all.

ss-o commented 2 years ago

I have started to make notes before PR, currently testing DNCP configs before proceeding. If something doesn't make sense, would appreciate it if you let me know. Cheers.

agoldcheidt commented 2 years ago

Hi there, I'm running Dietpi v7.8.2 bullseye under a RockPi-s board which I'm using it as Wi-Fi router, so, I've installed dnscrypt-proxy via apt and it works as expected, quick test on it via SSH show this dig output:

;; ANSWER SECTION:
google.com.             59      IN      A       172.217.2.206

;; Query time: 92 msec
;; SERVER: 127.0.2.1#53(127.0.2.1)
;; WHEN: Fri Nov 19 16:31:15 EST 2021
;; MSG SIZE  rcvd: 55

I'm using cloudflare DNS resolvers on dnscrypt-proxy but it doesn't work on clients connected through Wi-Fi SSID because it push the DNS resolvers located at /etc/dhcp/dhcpd.conf:

ddns-update-style none;
default-lease-time 600;
max-lease-time 7200;
authoritative;
log-facility local7;

subnet 192.168.141.0 netmask 255.255.255.0 {
        range 192.168.141.10 192.168.141.50;
        option broadcast-address 192.168.141.255;
        option routers 192.168.141.1;
        option domain-name "local";
        option domain-name-servers 94.140.14.14;
}

I've tried to change option domain-name-servers 94.140.14.14; to option domain-name-servers 127.0.2.1; but after a reboot, there's not internet in clients connected throught the Wi-Fi SSID. If I change it back, internet comes back.

I'm not sure if I'm missing something or maybe this doesn't make sense. The idea is to push dnscrypt-proxy DNS resolvers through ISC DHCP server as well.

Any thoughts?

Joulinar commented 2 years ago

well I guess you need to set option domain-name-servers 192.168.141.1

agoldcheidt commented 2 years ago

well I guess you need to set option domain-name-servers 192.168.141.1

Thanks for the suggestion, I did that, after reboot, clients connected through Wi-Fi SSID doesn't get internet. Quick question: the package resolvconf must be installed? Also, systemd-resolved service should be enabled?

Joulinar commented 2 years ago

maybe the proxy is not LISTEN to correct interface. Could you share following

ss -tulpn | grep LISTEN
MichaIng commented 2 years ago

Quick question: the package resolvconf must be installed? Also, systemd-resolved service should be enabled?

If at all, only either the one or the other, both are conflicting with each other since they are doing the same thing. But both are not required at all for DNSCrypt-proxy or a DHCP server. The DHCP client resp. network stack will alter /etc/resolv.conf directly if the resolvconf command is not available, and since you run a DHCP server on that machine, it likely has a static IP (or something is pretty badly configured 😄) so that /etc/resolv.conf should never be changed anyway but at best pointing to an upstream DNS directly.

domain-name-servers needs to be set to the LAN IP address of the machine that runs DNSCrypt-proxy. 192.168.141.1 is provided as gateway, but is the ROCK Pi S really the internet gateway or only the DHCP server in that network? 127.0.2.1 cannot work as this is a loopback IP so that all clients would try to use themselves as DNS server.

agoldcheidt commented 2 years ago

Hi there,I understand the point, thanks for the suggestions. I believe the issue is on my end. One last try, ss -tulpn | grep LISTEN output:

root@DietPi:~# ss -tulpn | grep LISTEN
tcp   LISTEN 0      0         127.0.0.53:53        0.0.0.0:*    users:(("systemd-resolve",pid=299,fd=17))
tcp   LISTEN 0      0          127.0.2.1:53        0.0.0.0:*    users:(("dnscrypt-proxy",pid=1110,fd=8),("systemd",pid=1,fd=59))
tcp   LISTEN 0      0            0.0.0.0:22        0.0.0.0:*    users:(("sshd",pid=518,fd=3))
tcp   LISTEN 0      0            0.0.0.0:5355      0.0.0.0:*    users:(("systemd-resolve",pid=299,fd=12))
tcp   LISTEN 0      0            0.0.0.0:111       0.0.0.0:*    users:(("rpcbind",pid=298,fd=4),("systemd",pid=1,fd=32))
tcp   LISTEN 0      0            0.0.0.0:6800      0.0.0.0:*    users:(("aria2c",pid=1040,fd=5))
tcp   LISTEN 0      0            0.0.0.0:80        0.0.0.0:*    users:(("lighttpd",pid=585,fd=4))
tcp   LISTEN 0      0                  *:21              *:*    users:(("proftpd",pid=577,fd=0))
tcp   LISTEN 0      0                  *:22              *:*    users:(("sshd",pid=518,fd=4))
tcp   LISTEN 0      0                  *:5355            *:*    users:(("systemd-resolve",pid=299,fd=14))
tcp   LISTEN 0      0                  *:111             *:*    users:(("rpcbind",pid=298,fd=6),("systemd",pid=1,fd=34))
tcp   LISTEN 0      0                  *:6800            *:*    users:(("aria2c",pid=1040,fd=6))
tcp   LISTEN 0      0                  *:80              *:*    users:(("lighttpd",pid=585,fd=5))

Also, I've noticed that network interfaces file have some custom entries:

root@DietPi:~# cat /etc/network/interfaces
# Location: /etc/network/interfaces
# Please modify network settings via: dietpi-config
# Or create your own drop-ins in: /etc/network/interfaces.d/

# Drop-in configs
source interfaces.d/*

# Ethernet
allow-hotplug eth0
iface eth0 inet dhcp
address 192.168.0.100
netmask 255.255.255.0
gateway 192.168.0.1
dns-nameservers 127.0.2.1

# WiFi
allow-hotplug p2p0
iface p2p0 inet static
address 192.168.141.1
netmask 255.255.255.0
#gateway 192.168.141.1
wireless-power off
dns-nameservers 127.0.2.1

# IP tables
up iptables-restore < /etc/iptables.ipv4.nat

Lastly, the RockPi-s ethernet port is connected to an ADSL modem, I believe RockPi-s board is the internet gateway. This is the resolv.conf file on my end:

root@DietPi:~# cat /etc/resolv.conf
nameserver 127.0.2.1

Also, I've set up 127.0.2.1 in the dhclient.conf as prepend and supersede domain-name-servers

prepend domain-name-servers 127.0.2.1;
supersede domain-name-servers 127.0.2.1;

Any thoughts?

Joulinar commented 2 years ago

As stated above, you would need to set DHCP configuration for DNs server to option domain-name-servers 192.168.141.1. Your issue is, that DNScrypt is Listen to localhost interface only. But it would need to be set to 0.0.0.0. You would need to check your configuration file for DNScrypt.

MichaIng commented 2 years ago

Good find. Indeed it must be bind to the loopback IP. There is a listen_addresses setting in /etc/dnscrypt-proxy/dnscrypt-proxy.toml which should do it:

listen_addresses = ['0.0.0.0:53']

of if you use IPv6 in your network as well:

listen_addresses = ['[::]:53']

Settings are well explained in the example config file here: https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml

agoldcheidt commented 2 years ago

Hi there, thank you so much for the support. I've tried things for couple of hours and it doesn't seems to work. I've changed: listen_addresses = ['0.0.0.0:53'], after reboot, dnscrypt-proxy won't start, in journalctl -xe say: [FATAL] listen udp 0.0.0.0:53: bind: permission denied then I've found this in dnscrypt-proxy issues, tried a couple of things from there but it doesn't work on my end.

Question: it will be more easy to do this with a DNS software like PiHole or Unbound? I've found a lot of information about it like this and this and it seems pretty easy to implement.

Any thoughts?

MichaIng commented 2 years ago

With which user are you trying to start dnscrypt-proxy? This is a "privileged" port, so it needs to be root user or otherwise it needs to get additional capabilities, like CAP_NET_BIND_SERVICE.

it will be more easy to do this with a DNS software like PiHole or Unbound?

You mean in combination with DNSCrypt-proxy? No, it is a trivial permission issue as stated above. Without DNSCrypt-proxy: We have Pi-hole and Unbound implemented in dietpi-software, also in combination so that Pi-hole uses Unbound and the letter can be used as recursive and validating DNS resolver or alternatively configured to use DNS-over-TLS, if you trust an upstream DNS provider more than your ISP. Pi-hole is for ads blocking in your network while it alone does not any DNS encryption, so a very different purpose.

So basically DNSCrypt-proxy is an alternative to Unbound with DoT, for encrypting your DNS traffic. It is simply a different protocol, not sure about the exact downsides and upsides compared to DoT.

Joulinar commented 2 years ago

@MichaIng dnscrypt-proxy is starting as own user according service definition. But it is not needed to adjust a configuration file. Means /etc/dnscrypt-proxy/dnscrypt-proxy.toml as well as /lib/systemd/system/dnscrypt-proxy.service can stay untouched. Why? Because dnscrypt-proxy is using /lib/systemd/system/dnscrypt-proxy.socket to configure. Means this is the one to be adjusted 😉

root@DietPi4:~# systemctl cat dnscrypt-proxy.socket
# /lib/systemd/system/dnscrypt-proxy.socket
[Unit]
Description=dnscrypt-proxy listening socket
Documentation=https://github.com/DNSCrypt/dnscrypt-proxy/wiki
Before=nss-lookup.target
Wants=nss-lookup.target
Wants=dnscrypt-proxy-resolvconf.service

[Socket]
ListenStream=0.0.0.0:53
ListenDatagram=0.0.0.0:53
NoDelay=true
DeferAcceptSec=1

[Install]
WantedBy=sockets.target
root@DietPi4:~#

And now dnscrypt-proxy is LISTEN to all interfaces.

root@DietPi4:~# ss -tulpn | grep LISTEN
tcp   LISTEN 0      4096         0.0.0.0:53        0.0.0.0:*    users:(("dnscrypt-proxy",pid=1401,fd=8),("systemd",pid=1,fd=67))

There is an own wiki section for systemd. Looks like it's recommended to disable systemd socket 🤔 https://github.com/DNSCrypt/dnscrypt-proxy/wiki/systemd


EDIT1 after reading thru the systemd sections, better to remove dnscrypt-proxy.socket if we go for an implementation later on.


EDIT2 not related but out of interesst. Looks like dnscrypt-proxy has a service checking for availability of /sbin/resolvconf

root@DietPi4:~# systemctl status dnscrypt-proxy-resolvconf.service
● dnscrypt-proxy-resolvconf.service - DNSCrypt proxy resolvconf support
     Loaded: loaded (/lib/systemd/system/dnscrypt-proxy-resolvconf.service; enabled; vendor preset: enabled)
     Active: inactive (dead)
  Condition: start condition failed at Mon 2021-11-22 13:08:18 CET; 1min 9s ago
             └─ ConditionFileIsExecutable=/sbin/resolvconf was not met
       Docs: https://github.com/DNSCrypt/dnscrypt-proxy/wiki

Nov 22 13:08:18 DietPi4 systemd[1]: Condition check resulted in DNSCrypt proxy resolvconf support being skipped.
root@DietPi4:~#

Ah found it, service to be removed on 2.0.45

MichaIng commented 2 years ago

Not sure how the systemd socket works compared to the dnscrypt-proxy binary itself listening on that port. Probably the systemd socket is a way to avoid privileged permissions, i.e. systemd listens on that port while all applications can then communicate through the local socket, so that it can be controlled via socket file modes. Sounds actually reasonable, although it also implies some overhead. Generally, when trusting software, I'd also vote for letting dnscrypt-proxy directly listing on that port, granting it the required capabilities, as Pi-hole and AdGuard Home do.

dnscrypt-proxy-resolvconf.service is used to apply the loopback IP as additional DNS nameserver for the system. This however rarely makes sense. Usually you do not run a DNS server for the host system itself, but for the LAN only, so the host keeps using a regular upstream DNS so that it cannot break it's own DNS capabilities during maintenance or when the DNS server crashes for some reason. Not sure whether this service adds or replaces existing nameserver entries? If it replaces them, I'd disable it, as /etc/resolv.conf must be controlled only either by a DHCP client or by the admin and not by whatever other software assumes the admin wants to do.

Joulinar commented 2 years ago

Jap systemd socket should be disabled according the wiki. As well dnscrypt-proxy-resolvconf.service should be deleted completely since 2.0.45.

I continued playing with it and had it running using dnscrypt-proxy.service only.

agoldcheidt commented 2 years ago

Means this is the one to be adjusted # /lib/systemd/system/dnscrypt-proxy.socket

Hi there, yes, that works. Now the DHCP server push dnscrypt-proxy resolvers to all clients connected through Wi-Fi SSID. Thank you so much @Joulinar @MichaIng. Also, since I have v2.0.45, I did those steps from dnscrypt-proxy wiki on my end. These are related files at my end:

/lib/systemd/system/dnscrypt-proxy.service

root@DietPi:~# cat /lib/systemd/system/dnscrypt-proxy.service
[Unit]
Description=DNSCrypt client proxy
Documentation=https://github.com/DNSCrypt/dnscrypt-proxy/wiki
Requires=dnscrypt-proxy.socket
After=network.target
Before=nss-lookup.target
Wants=nss-lookup.target

[Install]
Also=dnscrypt-proxy.socket
WantedBy=multi-user.target

[Service]
NonBlocking=true
ExecStart=/usr/sbin/dnscrypt-proxy -config /etc/dnscrypt-proxy/dnscrypt-proxy.toml
ProtectHome=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
MemoryDenyWriteExecute=true

User=_dnscrypt-proxy
CacheDirectory=dnscrypt-proxy
LogsDirectory=dnscrypt-proxy
RuntimeDirectory=dnscrypt-proxy

/etc/dnscrypt-proxy/dnscrypt-proxy.toml

root@DietPi:~# cat /etc/dnscrypt-proxy/dnscrypt-proxy.toml
# Empty listen_addresses to use systemd socket activation
listen_addresses = []
server_names = ['cloudflare']

[query_log]
  file = '/var/log/dnscrypt-proxy/query.log'

[nx_log]
  file = '/var/log/dnscrypt-proxy/nx.log'

[sources]
  [sources.'public-resolvers']
  url = 'https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md'
  cache_file = '/var/cache/dnscrypt-proxy/public-resolvers.md'
  minisign_key = 'RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3'
  refresh_delay = 72
  prefix = ''

/etc/dhcp/dhcpd.conf

root@DietPi:~# cat /etc/dhcp/dhcpd.conf
ddns-update-style none;
default-lease-time 600;
max-lease-time 7200;
authoritative;
log-facility local7;

subnet 192.168.141.0 netmask 255.255.255.0 {
        range 192.168.141.10 192.168.141.50;
        option broadcast-address 192.168.141.255;
        option routers 192.168.141.1;
        option domain-name "local";
        option domain-name-servers 192.168.141.1;
}

/etc/resolv.conf

root@DietPi:~# cat /etc/resolv.conf
nameserver 0.0.0.0

I would like to see DNScrypt Proxy in DietPi's Software list, in a near future. I will write about this on my blog because this is just amazing. Thanks to all you guys.

MichaIng commented 2 years ago

@Joulinar I just reviewed this issue for another reason and stumbled over: https://github.com/MichaIng/DietPi/issues/4772#issuecomment-925855870 So the proxy we talked about has nothing to do with DNSCrypt, but is part of Oblivious DoH, hence a different protocol (DoH extension) that is also supported by DNSCrypt-proxy. As discussed, a regular intercepting proxy would not increase but decrease privacy, since you only trust another party but involve one more player. If you don't trust the upstream DNS, choose a different one, if you trusted the proxy provider, than this would be the one to send DNS to root directly instead of forwarding it to another party, so that concept wouldn't make sense at all. But the key of Oblivious DoH is:

The proxy has no visibility into the DNS messages, with no ability to identify, read, or modify either the query being sent by the client or the answer being returned by the target.

So the proxy does not terminate encryption but forwards it encrypted to the upstream, like a HTTPS proxy with CONNECT or when you connect to a HTTPS server through a VPN. So the upstream does not know your IP address and the proxy does not know your DNS query, hence you don't need to trust those two, only that they are not exchanging their request logs to reverse associate client IP and DNS query 😄. So yes, an improvement to privacy, but also additional complexity and layer. If encryption is wanted due to mistrust against local ISP, governments or similar, I personal would recommend to use an upstream DNS provider which you trust (if there is one), probably not one of the largest available ones, but a smaller one which still serves good performance on your location, instead of increasing complexity. Otherwise keep using the DNS root directly (Unbound as recursive resolver) instead of passing queries through multiple stations. But as last resort, ODoH is the zero trust solution.