mirror of
https://git.mills.io/saltyim/saltyim.git
synced 2024-06-16 11:58:24 +00:00
57970ff67f
Co-authored-by: James Mills <1290234+prologic@users.noreply.github.com> Reviewed-on: https://git.mills.io/saltyim/saltyim/pulls/182
82 lines
2.6 KiB
Go
82 lines
2.6 KiB
Go
package saltyim
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/likexian/doh-go"
|
|
"github.com/likexian/doh-go/dns"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// Resolver is an interface for performing DNS lookups and is primarily used by the PWA
|
|
// and possibly other clients where direct DNS queries are not always possible and
|
|
// instead uses DNS over HTTP to eprform the same functionality.
|
|
type Resolver interface {
|
|
LookupSRV(service, proto, domain string) (string, error)
|
|
}
|
|
|
|
var (
|
|
_ Resolver = (*StandardResolver)(nil)
|
|
|
|
// ErrSRVRecordNotFound is an error returned by a resolver when there is no SRV record found for the domain of a Salty Address
|
|
ErrSRVRecordNotFound = errors.New("error: No SRV records found")
|
|
|
|
// DefaultResolver is the default resolver which defaults to the StandardResolver
|
|
DefaultResolver Resolver = &StandardResolver{}
|
|
)
|
|
|
|
// StandardResolver is a standard resolver that performs direct DNS queries over
|
|
// the standard networking protocol using port tcp/53 or udp/53
|
|
type StandardResolver struct{}
|
|
|
|
// LookupSRV implements the Resolver interface
|
|
func (r *StandardResolver) LookupSRV(service, proto, domain string) (string, error) {
|
|
log.Debugf("Using StandardResolver, looking up SRV _%s._%s.%s", service, proto, domain)
|
|
_, records, err := net.LookupSRV(service, proto, domain)
|
|
if err != nil {
|
|
return "", fmt.Errorf("error looking up _%s._%s.%s : %w", service, proto, domain, err)
|
|
}
|
|
if len(records) == 0 {
|
|
return "", ErrSRVRecordNotFound
|
|
}
|
|
return strings.TrimSuffix(records[0].Target, "."), nil
|
|
}
|
|
|
|
// DNSOverHTTPResolver is a resolver that performs DNS queries using a DNS Over HTTP
|
|
// service where direct DNS queries are not possible (standard resolver).
|
|
type DNSOverHTTPResolver struct{}
|
|
|
|
// LookupSRV implements the Resolver interface
|
|
func (r *DNSOverHTTPResolver) LookupSRV(service, proto, domain string) (string, error) {
|
|
name := fmt.Sprintf("_%s._%s.%s", service, proto, domain)
|
|
|
|
log.Debugf("Using DNSOverHTTPResolver, looking up SRV %s", name)
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
c := doh.Use(doh.CloudflareProvider, doh.DNSPodProvider)
|
|
|
|
res, err := c.Query(ctx, dns.Domain(name), dns.Type("SRV"))
|
|
if err != nil {
|
|
return "", fmt.Errorf("error looking up _%s._%s.%s : %w", service, proto, domain, err)
|
|
}
|
|
defer c.Close()
|
|
|
|
if len(res.Answer) == 0 {
|
|
return "", ErrSRVRecordNotFound
|
|
}
|
|
|
|
data := res.Answer[0].Data
|
|
fields := strings.Split(data, " ")
|
|
if len(fields) != 4 {
|
|
return "", fmt.Errorf("invalid SRV records found expected 4 fields got %d: %q", len(fields), data)
|
|
}
|
|
return strings.TrimSuffix(fields[3], "."), nil
|
|
}
|