mirror of https://github.com/0xERR0R/blocky.git
170 lines
3.4 KiB
Go
170 lines
3.4 KiB
Go
package resolver
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/0xERR0R/blocky/log"
|
|
"github.com/0xERR0R/blocky/util"
|
|
|
|
"github.com/miekg/dns"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// RequestProtocol represents the server protocol
|
|
type RequestProtocol uint8
|
|
|
|
const (
|
|
// TCP is the TPC protocol
|
|
TCP RequestProtocol = iota
|
|
|
|
// UDP is the UDP protocol
|
|
UDP
|
|
)
|
|
|
|
func (r RequestProtocol) String() string {
|
|
names := [...]string{
|
|
"TCP",
|
|
"UDP"}
|
|
|
|
return names[r]
|
|
}
|
|
|
|
// Request represents client's DNS request
|
|
type Request struct {
|
|
ClientIP net.IP
|
|
Protocol RequestProtocol
|
|
ClientNames []string
|
|
Req *dns.Msg
|
|
Log *logrus.Entry
|
|
RequestTS time.Time
|
|
}
|
|
|
|
func newRequest(question string, rType uint16, logger ...*logrus.Entry) *Request {
|
|
var loggerEntry *logrus.Entry
|
|
if len(logger) == 1 {
|
|
loggerEntry = logger[0]
|
|
} else {
|
|
loggerEntry = logrus.NewEntry(log.Log())
|
|
}
|
|
|
|
return &Request{
|
|
Req: util.NewMsgWithQuestion(question, rType),
|
|
Log: loggerEntry,
|
|
Protocol: UDP,
|
|
}
|
|
}
|
|
|
|
func newRequestWithClient(question string, rType uint16, ip string, clientNames ...string) *Request {
|
|
return &Request{
|
|
ClientIP: net.ParseIP(ip),
|
|
ClientNames: clientNames,
|
|
Req: util.NewMsgWithQuestion(question, rType),
|
|
Log: logrus.NewEntry(log.Log()),
|
|
RequestTS: time.Time{},
|
|
Protocol: UDP,
|
|
}
|
|
}
|
|
|
|
// ResponseType represents the type of the response
|
|
type ResponseType int
|
|
|
|
const (
|
|
// RESOLVED the response was resolved by the external upstream resolver
|
|
RESOLVED ResponseType = iota
|
|
|
|
// CACHED the response was resolved from cache
|
|
CACHED
|
|
|
|
// BLOCKED the query was blocked
|
|
BLOCKED
|
|
|
|
// CONDITIONAL the query was resolved by the conditional upstream resolver
|
|
CONDITIONAL
|
|
|
|
// CUSTOMDNS the query was resolved by a custom rule
|
|
CUSTOMDNS
|
|
)
|
|
|
|
func (r ResponseType) String() string {
|
|
names := [...]string{
|
|
"RESOLVED",
|
|
"CACHED",
|
|
"BLOCKED",
|
|
"CONDITIONAL",
|
|
"CUSTOMDNS"}
|
|
|
|
return names[r]
|
|
}
|
|
|
|
// Response represents the response of a DNS query
|
|
type Response struct {
|
|
Res *dns.Msg
|
|
Reason string
|
|
RType ResponseType
|
|
}
|
|
|
|
// Resolver generic interface for all resolvers
|
|
type Resolver interface {
|
|
|
|
// Resolve performs resolution of a DNS request
|
|
Resolve(req *Request) (*Response, error)
|
|
|
|
// Configuration prints current resolver configuration
|
|
Configuration() []string
|
|
}
|
|
|
|
// ChainedResolver represents a resolver, which can delegate result to the next one
|
|
type ChainedResolver interface {
|
|
Resolver
|
|
|
|
// Next sets the next resolver
|
|
Next(n Resolver)
|
|
|
|
// GetNext returns the next resolver
|
|
GetNext() Resolver
|
|
}
|
|
|
|
// NextResolver is the base implementation of ChainedResolver
|
|
type NextResolver struct {
|
|
next Resolver
|
|
}
|
|
|
|
// Next sets the next resolver
|
|
func (r *NextResolver) Next(n Resolver) {
|
|
r.next = n
|
|
}
|
|
|
|
// GetNext returns the next resolver
|
|
func (r *NextResolver) GetNext() Resolver {
|
|
return r.next
|
|
}
|
|
|
|
func logger(prefix string) *logrus.Entry {
|
|
return log.PrefixedLog(prefix)
|
|
}
|
|
|
|
func withPrefix(logger *logrus.Entry, prefix string) *logrus.Entry {
|
|
return logger.WithField("prefix", prefix)
|
|
}
|
|
|
|
// Chain creates a chain of resolvers
|
|
func Chain(resolvers ...Resolver) Resolver {
|
|
for i, res := range resolvers {
|
|
if i+1 < len(resolvers) {
|
|
if cr, ok := res.(ChainedResolver); ok {
|
|
cr.Next(resolvers[i+1])
|
|
}
|
|
}
|
|
}
|
|
|
|
return resolvers[0]
|
|
}
|
|
|
|
// Name returns a user-friendly name of a resolver
|
|
func Name(resolver Resolver) string {
|
|
return strings.Split(fmt.Sprintf("%T", resolver), ".")[1]
|
|
}
|