dnsxl/server.go

71 lines
1.7 KiB
Go

package dnsxl
import (
"context"
"errors"
"net"
"strings"
)
// Result of a lookup from a single server.
type Result struct {
// Server is the name of the DNSxL server that produced this result.
Server string
// InList is true if the IP address that was lookup up is in the list.
InList bool
// Weight is the server's present/not present weight, as appropriate, or
// 0 on error.
Weight int
// Reason may be set if the IP address is in the server's list, and the
// server has a reason TXT record present for it.
Reason string
// Error is set if there was an error looking up the IP address on this
// server.
Error error
}
// server implements a single DNSxL server. It holds the server's DNS name and
// the configured weights for found / not found results.
type server struct {
Addr string
WeightInList, WeightNotInList int
}
// Lookup performs a (synchronous) DNSxL lookup.
func (s server) Lookup(ctx context.Context, res *net.Resolver, reversed string) Result {
r := Result{
Server: s.Addr,
}
addr := reversed + "." + s.Addr
ips, err := res.LookupIP(ctx, "ip4" /* DNSxL entries are A records */, addr)
switch {
case isNXDOMAIN(err):
r.Weight = s.WeightNotInList
return r
case err != nil:
r.Error = err
return r
case len(ips) == 0:
r.Weight = s.WeightNotInList
return r
}
txts, _ := res.LookupTXT(ctx, addr)
r.InList = true
r.Weight = s.WeightInList
r.Reason = strings.Join(txts, "\n")
return r
}
// isNXDOMAIN catches the error that Go returns when getting an NXDOMAIN
// response. This just means "not on list" in our case.
func isNXDOMAIN(err error) bool {
var d *net.DNSError
return errors.As(err, &d) && d.IsNotFound
}