mirror of https://github.com/0xERR0R/blocky.git
185 lines
4.4 KiB
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)
|
|
}
|