blocky/resolver/client_names_resolver.go

168 lines
4.1 KiB
Go
Raw Normal View History

2020-01-12 18:23:35 +01:00
package resolver
import (
"fmt"
"net"
"strings"
"time"
2021-08-25 22:06:34 +02:00
"github.com/0xERR0R/blocky/config"
"github.com/0xERR0R/blocky/util"
"github.com/0xERR0R/go-cache"
2020-01-12 18:23:35 +01:00
"github.com/miekg/dns"
"github.com/sirupsen/logrus"
)
// ClientNamesResolver tries to determine client name by asking responsible DNS server vie rDNS (reverse lookup)
type ClientNamesResolver struct {
cache *cache.Cache
externalResolver Resolver
singleNameOrder []uint
2020-05-17 21:50:40 +02:00
clientIPMapping map[string][]net.IP
2020-01-12 18:23:35 +01:00
NextResolver
}
// NewClientNamesResolver creates new resolver instance
2020-01-12 18:23:35 +01:00
func NewClientNamesResolver(cfg config.ClientLookupConfig) ChainedResolver {
var r Resolver
if (config.Upstream{}) != cfg.Upstream {
r = NewUpstreamResolver(cfg.Upstream)
}
return &ClientNamesResolver{
cache: cache.New(1*time.Hour, 1*time.Hour),
externalResolver: r,
singleNameOrder: cfg.SingleNameOrder,
2020-05-17 21:50:40 +02:00
clientIPMapping: cfg.ClientnameIPMapping,
2020-01-12 18:23:35 +01:00
}
}
// Configuration returns current resolver configuration
2020-01-12 18:23:35 +01:00
func (r *ClientNamesResolver) Configuration() (result []string) {
2020-05-17 21:50:40 +02:00
if r.externalResolver != nil || len(r.clientIPMapping) > 0 {
2020-01-12 18:23:35 +01:00
result = append(result, fmt.Sprintf("singleNameOrder = \"%v\"", r.singleNameOrder))
2020-05-17 21:50:40 +02:00
if r.externalResolver != nil {
result = append(result, fmt.Sprintf("externalResolver = \"%s\"", r.externalResolver))
}
2020-01-12 18:23:35 +01:00
result = append(result, fmt.Sprintf("cache item count = %d", r.cache.ItemCount()))
2020-05-17 21:50:40 +02:00
if len(r.clientIPMapping) > 0 {
result = append(result, "client IP mapping:")
for k, v := range r.clientIPMapping {
result = append(result, fmt.Sprintf("%s -> %s", k, v))
}
}
2020-01-12 18:23:35 +01:00
} else {
result = []string{"deactivated, use only IP address"}
}
return
}
// Resolve tries to resolve the client name from the ip address
2020-01-12 18:23:35 +01:00
func (r *ClientNamesResolver) Resolve(request *Request) (*Response, error) {
clientNames := r.getClientNames(request)
request.ClientNames = clientNames
request.Log = request.Log.WithField("client_names", strings.Join(clientNames, "; "))
return r.next.Resolve(request)
}
// returns names of client
func (r *ClientNamesResolver) getClientNames(request *Request) []string {
ip := request.ClientIP
2020-07-08 21:56:09 +02:00
if ip == nil {
return []string{}
}
2020-07-08 21:56:09 +02:00
2020-01-12 18:23:35 +01:00
c, found := r.cache.Get(ip.String())
if found {
if t, ok := c.([]string); ok {
return t
}
}
names := r.resolveClientNames(ip, withPrefix(request.Log, "client_names_resolver"))
r.cache.Set(ip.String(), names, cache.DefaultExpiration)
return names
}
2020-05-17 21:50:40 +02:00
// tries to resolve client name from mapping, performs reverse DNS lookup otherwise
2020-01-12 18:23:35 +01:00
func (r *ClientNamesResolver) resolveClientNames(ip net.IP, logger *logrus.Entry) (result []string) {
2020-05-17 21:50:40 +02:00
// try client mapping first
result = r.getNameFromIPMapping(ip, result)
if len(result) > 0 {
return
}
2020-01-12 18:23:35 +01:00
if r.externalResolver != nil {
2021-01-19 21:52:24 +01:00
reverse, _ := dns.ReverseAddr(ip.String())
2020-01-12 18:23:35 +01:00
resp, err := r.externalResolver.Resolve(&Request{
Req: util.NewMsgWithQuestion(reverse, dns.TypePTR),
Log: logger,
})
if err != nil {
2020-05-04 22:20:13 +02:00
logger.Error("can't resolve client name: ", err)
2020-03-07 16:52:28 +01:00
return []string{ip.String()}
2020-01-12 18:23:35 +01:00
}
var clientNames []string
for _, answer := range resp.Res.Answer {
if t, ok := answer.(*dns.PTR); ok {
hostName := strings.TrimSuffix(t.Ptr, ".")
clientNames = append(clientNames, hostName)
}
}
if len(clientNames) == 0 {
clientNames = []string{ip.String()}
}
// optional: if singleNameOrder is set, use only one name in the defined order
if len(r.singleNameOrder) > 0 {
for _, i := range r.singleNameOrder {
if i > 0 && int(i) <= len(clientNames) {
result = []string{clientNames[i-1]}
break
}
}
} else {
result = clientNames
}
2020-05-17 21:50:40 +02:00
logger.WithField("client_names", strings.Join(result, "; ")).Debug("resolved client name(s) from external resolver")
2020-01-12 18:23:35 +01:00
} else {
result = []string{ip.String()}
}
return result
}
2020-05-17 21:50:40 +02:00
func (r *ClientNamesResolver) getNameFromIPMapping(ip net.IP, result []string) []string {
for name, ips := range r.clientIPMapping {
for _, i := range ips {
if ip.String() == i.String() {
result = append(result, name)
}
}
}
return result
}
// FlushCache reset client name cache
2020-01-12 18:23:35 +01:00
func (r *ClientNamesResolver) FlushCache() {
r.cache.Flush()
}