Thinking about it more, you can do this easily enough now with Pi-hole, using dnsmasq's option dns-rr but you need to encode the option yourself.
To be clear, this does not add dot, doq or doh functionality to Pi-hole. This is for use in cases such as described by @a7md0 to direct clients to installed proxies capable of handling that conversion.
The python code at the end of this post can generate the line for you, and the result would need to be entered into the misc.dnsmasq_lines
setting in Pi-Hole. You would also need to make sure that dns.specialDomains.designatedResolver
is disabled in the all settings dns tab.
rob@builder:~/git/svcb-encoder$ ./svcbencoder.py
Domain name : (press enter for pi.hole)
IP address :1.2.3.4
Please select server type:
For each of the following (dot, doh, doq), please enter 'y' or 'n'
DNS over TLS - dot (y/n)y
DNS over QUIC - doq (y/n)n
DNS over HTTPS - doh (y/n)y
DOH path ( press enter for '/dns-query{?dns}' ) :
dnsmasq.conf option:
--dns-rr=_dns.reverse.arpa,64,000102706904686F6C65000001000702683203646F740004000401020304000700102F646E732D71756572797B3F646E737D
Pi-Hole misc.dns.masq_lines value:
Enter into settings, expert, all settings, miscellaneous, misc.dnsmasq_lines
dns-rr=_dns.reverse.arpa,64,000102706904686F6C65000001000702683203646F740004000401020304000700102F646E732D71756572797B3F646E737D
Confirm by running
dig SVCB _dns.resolver.arpa @pi.hole
:
rob@builder:~/git/svcb-encoder$dig SVCB _dns.resolve.arpa @pi.hole
; <<>> DiG 9.18.33-1~deb12u2-Debian <<>> SVCB _dns.resolve.arpa @pi.hole
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15648
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;_dns.resolver.arpa. IN SVCB
;; ANSWER SECTION:
_dns.resolver.arpa. 0 IN SVCB 1 pi.hole. alpn="h2,dot" ipv4hint=1.2.3.4 key7="/dns-query{?dns}"
;; Query time: 31 msec
;; SERVER: 192.168.1.228#53(192.168.1.228) (UDP)
;; WHEN: Tue May 06 14:22:56 AEST 2025
;; MSG SIZE rcvd: 107
Code:
#!/usr/bin/python3
import dns.rdata # pip3 install dnspython
import io
name = str(input("Domain name : (press enter for pi.hole)"))
name = name if name else "pi.hole"
ipaddr = str(input("IP address :"))
print("Please select server type:")
print("For each of the following (dot, doh, doq), please enter 'y' or 'n'")
nalpn = int(0)
dot = str(input("DNS over TLS - dot (y/n)"))
if dot == "y":
nalpn = nalpn + 1
doq = str(input("DNS over QUIC - doq (y/n)"))
if doq == "y":
nalpn = nalpn + 2
doh = str(input("DNS over HTTPS - doh (y/n)"))
if doh == "y":
nalpn = nalpn + 4
match nalpn:
case 1:
alpn = "dot"
case 2:
alpn = "doq"
case 3:
alpn = "doq,dot"
case 4:
alpn = "h2"
case 5:
alpn = "h2,dot"
case 6:
alpn = "h2,doh"
case 7:
alpn = "h2,doq,dot"
case 0:
print("Nothing entered. Exiting...")
quit
rclass = dns.rdataclass.IN
rtype = dns.rdatatype.SVCB
rdata = '1 '+name+'. alpn="'+alpn+'" ipv4hint="'+ipaddr+'"'
if nalpn >= 4:
dohpath = str(input("DOH path ( press enter for '/dns-query{?dns}' ) :"))
dohpath = dohpath if dohpath else "/dns-query{?dns}"
rdata = rdata + 'key7="'+dohpath+'"'
rd = dns.rdata.from_text(rclass, rtype, rdata)
f = io.BytesIO()
rd.to_wire(f)
wire_data = f.getvalue()
print ("dnsmasq.conf option:")
print ("--dns-rr=_dns.resolver.arpa," + str(rtype) + "," + wire_data.hex().upper())
print ("Pi-Hole misc.dns.masq_lines value:")
print ("Enter into settings, expert, all settings, miscellaneous, misc.dnsmasq_lines")
print ("dns-rr=_dns.resolver.arpa," + str(rtype) + "," + wire_data.hex().upper())