71 lines
1.7 KiB
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
|
|
}
|