mirror of https://github.com/0xERR0R/blocky.git
135 lines
3.3 KiB
Go
135 lines
3.3 KiB
Go
package resolver
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
|
|
"github.com/0xERR0R/blocky/config"
|
|
"github.com/0xERR0R/blocky/util"
|
|
|
|
"github.com/miekg/dns"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const customDNSTTL = 60 * 60
|
|
|
|
// CustomDNSResolver resolves passed domain name to ip address defined in domain-IP map
|
|
type CustomDNSResolver struct {
|
|
NextResolver
|
|
mapping map[string][]net.IP
|
|
reverseAddresses map[string][]string
|
|
}
|
|
|
|
// NewCustomDNSResolver creates new resolver instance
|
|
func NewCustomDNSResolver(cfg config.CustomDNSConfig) ChainedResolver {
|
|
m := make(map[string][]net.IP)
|
|
reverse := make(map[string][]string)
|
|
|
|
for url, ips := range cfg.Mapping.HostIPs {
|
|
m[strings.ToLower(url)] = ips
|
|
|
|
for _, ip := range ips {
|
|
r, _ := dns.ReverseAddr(ip.String())
|
|
reverse[r] = append(reverse[r], url)
|
|
}
|
|
}
|
|
|
|
return &CustomDNSResolver{mapping: m, reverseAddresses: reverse}
|
|
}
|
|
|
|
// Configuration returns current resolver configuration
|
|
func (r *CustomDNSResolver) Configuration() (result []string) {
|
|
if len(r.mapping) > 0 {
|
|
for key, val := range r.mapping {
|
|
result = append(result, fmt.Sprintf("%s = \"%s\"", key, val))
|
|
}
|
|
} else {
|
|
result = []string{"deactivated"}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func isSupportedType(ip net.IP, question dns.Question) bool {
|
|
return (ip.To4() != nil && question.Qtype == dns.TypeA) ||
|
|
(strings.Contains(ip.String(), ":") && question.Qtype == dns.TypeAAAA)
|
|
}
|
|
|
|
func (r *CustomDNSResolver) handleReverseDNS(request *Request) *Response {
|
|
question := request.Req.Question[0]
|
|
if question.Qtype == dns.TypePTR {
|
|
urls, found := r.reverseAddresses[question.Name]
|
|
if found {
|
|
response := new(dns.Msg)
|
|
response.SetReply(request.Req)
|
|
|
|
for _, url := range urls {
|
|
h := util.CreateHeader(question, customDNSTTL)
|
|
ptr := new(dns.PTR)
|
|
ptr.Ptr = dns.Fqdn(url)
|
|
ptr.Hdr = h
|
|
response.Answer = append(response.Answer, ptr)
|
|
}
|
|
|
|
return &Response{Res: response, RType: CUSTOMDNS, Reason: "CUSTOM DNS"}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Resolve uses internal mapping to resolve the query
|
|
func (r *CustomDNSResolver) Resolve(request *Request) (*Response, error) {
|
|
logger := withPrefix(request.Log, "custom_dns_resolver")
|
|
|
|
reverseResp := r.handleReverseDNS(request)
|
|
if reverseResp != nil {
|
|
return reverseResp, nil
|
|
}
|
|
|
|
if len(r.mapping) > 0 {
|
|
response := new(dns.Msg)
|
|
response.SetReply(request.Req)
|
|
|
|
question := request.Req.Question[0]
|
|
domain := util.ExtractDomain(question)
|
|
|
|
for len(domain) > 0 {
|
|
ips, found := r.mapping[domain]
|
|
if found {
|
|
for _, ip := range ips {
|
|
if isSupportedType(ip, question) {
|
|
rr, _ := util.CreateAnswerFromQuestion(question, ip, customDNSTTL)
|
|
response.Answer = append(response.Answer, rr)
|
|
}
|
|
}
|
|
|
|
if len(response.Answer) > 0 {
|
|
logger.WithFields(logrus.Fields{
|
|
"answer": util.AnswerToString(response.Answer),
|
|
"domain": domain,
|
|
}).Debugf("returning custom dns entry")
|
|
|
|
return &Response{Res: response, RType: CUSTOMDNS, Reason: "CUSTOM DNS"}, nil
|
|
}
|
|
|
|
// Mapping exists for this domain, but for another type
|
|
// return NOERROR with empty result
|
|
|
|
return &Response{Res: response, RType: CUSTOMDNS, Reason: "CUSTOM DNS"}, nil
|
|
}
|
|
|
|
if i := strings.Index(domain, "."); i >= 0 {
|
|
domain = domain[i+1:]
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
logger.WithField("resolver", Name(r.next)).Trace("go to next resolver")
|
|
|
|
return r.next.Resolve(request)
|
|
}
|