Support recursive resolution for non authoritative CNAME entries

Currently, there is a note in the CNAME entry page stating the below:

Note:
The target of a CNAME must be a domain that the Pi-hole already has in its cache or is authoritative for. This is a universal limitation of CNAME records.
The reason for this is that Pi-hole will not send additional queries upstream when serving CNAME replies. As consequence, if you set a target that isn't already known, the reply to the client may be incomplete. Pi-hole just returns the information it knows at the time of the query. This results in certain limitations for CNAME targets, for instance, only active DHCP leases work as targets - mere DHCP leases aren't sufficient as they aren't (yet) valid DNS records.
Additionally, you can't CNAME external domains ( bing.com to google.com ) successfully as this could result in invalid SSL certificate errors when the target server does not serve content for the requested domain.

The point of SSL not being valid is true, but support for this is needed for split DNS configurations. The note says it is a universal limitation of CNAME, but my Windows DNS server can clearly recursively resolve non authoritative requests as shown below. Can this be implemented in Pi-hole?

C:\Users\adyan\Desktop>nslookup test.adyanth.lan 10.10.10.4
Server:  windows-server-nuc.adyanth.lan
Address:  10.10.10.4

Name:    one.one.one.one
Addresses:  2606:4700:4700::1111
          2606:4700:4700::1001
          1.1.1.1
          1.0.0.1
Aliases:  test.adyanth.lan

As opposed to Pi-hole doing this:

C:\Users\adyan\Desktop>nslookup test.adyanth.site 10.10.10.3
Server:  ubuntu-nuc.adyanth.lan
Address:  10.10.10.3

Name:    test.adyanth.site


C:\Users\adyan\Desktop>nslookup one.one.one.one 10.10.10.3
Server:  ubuntu-nuc.adyanth.lan
Address:  10.10.10.3

Non-authoritative answer:
Name:    one.one.one.one
Addresses:  2606:4700:4700::1111
          2606:4700:4700::1001
          1.0.0.1
          1.1.1.1


C:\Users\adyan\Desktop>nslookup test.adyanth.site 10.10.10.3
Server:  ubuntu-nuc.adyanth.lan
Address:  10.10.10.3

Non-authoritative answer:
Name:    one.one.one.one
Addresses:  2606:4700:4700::1001
          2606:4700:4700::1111
          1.1.1.1
          1.0.0.1
Aliases:  test.adyanth.site

Background on use case:
I have a local lan domain and a valid DNS domain. Many of the services I host are accessible via the internet using Cloudflare Tunnels. The public DNS entry points to the tunnel. The lan domain has the windows server as the authoritative domain and pihole has a custom override to send all requests to this domain to the windows server. Since cloudflare cannot to AXFR transfers to other DNS servers, I cannot configure windows server as a forwarding DNS and override certain subdomains to the local ones. It has to be done on pihole. Now, pihole has a public subdomain -> local subdomain CNAME, but without me explicitly adding the local subdomain to IP mapping, it just does not work. Meaning I need to maintain DNS records in two places, the windows server and Pi-hole. The DNS entries are added to the Windows server using external-dns over RFC 2136 dynamic DNS updates which the Pi-hole does not support (planning to add this as a new feature request too since Pi-hole can be a one stop replacement for all DNS servers).

Pi-hole embeds and extends the DNS forwarding server dnsmasq (link). It cannot do what you are asking for because it is designed to not be recursive. We wouldn't make such a change using Pi-hole extensions as the necessary massive rewrite of code would inevitably break compatibility with future updates of dnsmasq. The same holds true for your second request (external-dns).

I'd suggest you direct your feature request to the official dnsmasq mailing list (dnsmasq-discuss@lists.thekelleys.org.uk, see also here). Whenever the dnsmasq project implements what you are asking for, it will be contained in the next Pi-hole release.

1 Like

Understood, I thought maybe Pi-hole hooks into dnsmasq somehow to be able to manipulate it. Will raise this with dnsmasq or more probably look into alternative ways once the HTTP JSON API is finally available :slight_smile:

Reference: https://github.com/pi-hole/FTL/pull/659

I managed to get setup working by placing bind9 to split the DNS traffic based on if it is authoritative or not.

Here is the setup for anyone else looking for this:

Docker Compose

docker-compose.yaml:

version: "3"

services:
  pihole:
    image: pihole/pihole:latest
    restart: unless-stopped
    hostname: pihole
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "80:80"
    networks: 
      management-services:
      pihole:
        ipv4_address: 172.31.255.250
    environment:
      PIHOLE_DNS_: 1.1.1.1
    volumes:
      - "./etc-pihole/:/etc/pihole/"
      - "./etc-dnsmasq:/etc/dnsmasq.d/"
      - "./02-dns-server.conf:/etc/dnsmasq.d/02-dns-server.conf"

  bind9:
    image: store/internetsystemsconsortium/bind9:9.11
    volumes:
      - "./db.rpz:/etc/bind/db.rpz"
      - "./named.conf.local:/etc/bind/named.conf.local"
      - "./named.conf.options:/etc/bind/named.conf.options"
    networks:
      pihole:
        ipv4_address: 172.31.255.251

networks:
  pihole:
    name: pihole
    ipam:
      driver: default
      config:
        - subnet: 172.31.255.248/29

Pi-hole

example.com is what you want to have partial authority over. Forward it to bind9

02-dns-server.conf:

server=/example.com/172.31.255.251

Bind9

There are 3 files we bind mount to the bind9 container.

db.rpz: Contains the list of entries to override. Two sample entries provided below. Replace them as needed.

$TTL 60
@            IN    SOA  localhost. root.localhost.  (
                          2015112501   ; serial
                          1h           ; refresh
                          30m          ; retry
                          1w           ; expiry
                          30m)         ; minimum
              IN     NS    localhost.

localhost       A   127.0.0.1

domain.example.com   CNAME    myserver.local
pihole.example.com     A               192.168.1.10

named.conf.local: Load the above zone. Forwarders are used when the requested (sub)domain of example.com are not found in the above file.

zone "rpz" {
  type master;
  file "/etc/bind/db.rpz";
  forward only;
  forwarders { 1.1.1.1 port 53; };
};

named.conf.options: Send the query back to pihole for further resolution. This can happen when the CNAME in the DB is to an unknown domain or a local domain known to pihole. (sub.example.com CNAME google.com or server.lan for example)

options {
    directory "/var/cache/bind";

    forwarders { 172.31.255.250 port 53; };

    listen-on-v6 { any; };
    response-policy { zone "rpz"; };
    allow-query { any; };
};

This made my setup work, and only one place I need to update is the db.rpz which is okay.

Here is a diagram for visualization of the above solution

DNS Architecture

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.