blocky/resolver/sudn_resolver.go

185 lines
4.4 KiB
Go

package resolver
import (
"context"
"net"
"strings"
"github.com/0xERR0R/blocky/config"
"github.com/0xERR0R/blocky/model"
"github.com/miekg/dns"
)
type sudnHandler = func(request *model.Request, cfg *config.SUDN) *model.Response
//nolint:gochecknoglobals
var (
loopbackV4 = net.ParseIP("127.0.0.1")
loopbackV6 = net.IPv6loopback
// See Wikipedia for an up-to-date reference:
// https://en.wikipedia.org/wiki/Special-use_domain_name
sudnHandlers = map[string]sudnHandler{
// RFC 6761
// https://www.rfc-editor.org/rfc/rfc6761
//
// Section 6.1
"10.in-addr.arpa.": sudnNXDomain,
"21.172.in-addr.arpa.": sudnNXDomain,
"26.172.in-addr.arpa.": sudnNXDomain,
"16.172.in-addr.arpa.": sudnNXDomain,
"22.172.in-addr.arpa.": sudnNXDomain,
"27.172.in-addr.arpa.": sudnNXDomain,
"17.172.in-addr.arpa.": sudnNXDomain,
"30.172.in-addr.arpa.": sudnNXDomain,
"28.172.in-addr.arpa.": sudnNXDomain,
"18.172.in-addr.arpa.": sudnNXDomain,
"23.172.in-addr.arpa.": sudnNXDomain,
"29.172.in-addr.arpa.": sudnNXDomain,
"19.172.in-addr.arpa.": sudnNXDomain,
"24.172.in-addr.arpa.": sudnNXDomain,
"31.172.in-addr.arpa.": sudnNXDomain,
"20.172.in-addr.arpa.": sudnNXDomain,
"25.172.in-addr.arpa.": sudnNXDomain,
"168.192.in-addr.arpa.": sudnNXDomain,
// Section 6.2
"test.": sudnNXDomain,
// Section 6.3
"localhost.": sudnLocalhost,
// Section 6.4
"invalid.": sudnNXDomain,
// Section 6.5
"example.": nil,
"example.com.": nil,
"example.net.": nil,
"example.org.": nil,
// RFC 6762
// https://www.rfc-editor.org/rfc/rfc6762
//
// mDNS is not implemented, so just return NXDOMAIN
//
// Section 3
"local.": sudnNXDomain,
// Section 12
"254.169.in-addr.arpa.": sudnNXDomain, // also section 4
"8.e.f.ip6.arpa.": sudnNXDomain,
"9.e.f.ip6.arpa.": sudnNXDomain,
"a.e.f.ip6.arpa.": sudnNXDomain,
"b.e.f.ip6.arpa.": sudnNXDomain,
// Appendix G
"intranet.": sudnRFC6762AppendixG,
"internal.": sudnRFC6762AppendixG,
"private.": sudnRFC6762AppendixG,
"corp.": sudnRFC6762AppendixG,
"home.": sudnRFC6762AppendixG,
"lan.": sudnRFC6762AppendixG,
// RFC 7686
// https://www.rfc-editor.org/rfc/rfc7686
"onion.": sudnNXDomain,
// RFC 8375
// https://www.rfc-editor.org/rfc/rfc8375
//
// Section 4
"home.arpa.": sudnHomeArpa,
}
)
type SpecialUseDomainNamesResolver struct {
NextResolver
typed
configurable[*config.SUDN]
}
func NewSpecialUseDomainNamesResolver(cfg config.SUDN) *SpecialUseDomainNamesResolver {
return &SpecialUseDomainNamesResolver{
typed: withType("special_use_domains"),
configurable: withConfig(&cfg),
}
}
func (r *SpecialUseDomainNamesResolver) Resolve(ctx context.Context, request *model.Request) (*model.Response, error) {
handler := r.handler(request)
if handler != nil {
resp := handler(request, r.cfg)
if resp != nil {
return resp, nil
}
}
return r.next.Resolve(ctx, request)
}
func (r *SpecialUseDomainNamesResolver) handler(request *model.Request) sudnHandler {
q := request.Req.Question[0]
domain := q.Name
for {
handler, ok := sudnHandlers[domain]
if ok {
return handler
}
_, after, ok := strings.Cut(domain, ".")
if !ok {
return nil
}
domain = after
}
}
func newSUDNResponse(response *model.Request, rcode int) *model.Response {
return newResponse(response, rcode, model.ResponseTypeSPECIAL, "Special-Use Domain Name")
}
func sudnNXDomain(request *model.Request, _ *config.SUDN) *model.Response {
return newSUDNResponse(request, dns.RcodeNameError)
}
func sudnLocalhost(request *model.Request, cfg *config.SUDN) *model.Response {
q := request.Req.Question[0]
var rr dns.RR
switch q.Qtype {
case dns.TypeA:
rr = &dns.A{A: loopbackV4}
case dns.TypeAAAA:
rr = &dns.AAAA{AAAA: loopbackV6}
default:
return sudnNXDomain(request, cfg)
}
*rr.Header() = dns.RR_Header{
Name: q.Name,
Rrtype: q.Qtype,
Class: dns.ClassINET,
Ttl: 0,
}
response := newSUDNResponse(request, dns.RcodeSuccess)
response.Res.Answer = []dns.RR{rr}
return response
}
func sudnRFC6762AppendixG(request *model.Request, cfg *config.SUDN) *model.Response {
if !cfg.RFC6762AppendixG {
return nil
}
return sudnNXDomain(request, cfg)
}
func sudnHomeArpa(request *model.Request, cfg *config.SUDN) *model.Response {
if request.Req.Question[0].Qtype == dns.TypeDS {
// DS queries must be forwarded
return nil
}
return sudnNXDomain(request, cfg)
}