mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 15:26:40 +00:00
* implement reverse proxy --------- Co-authored-by: Alisdair MacLeod <git@alisdairmacleod.co.uk> Co-authored-by: mlsmaycon <mlsmaycon@gmail.com> Co-authored-by: Eduard Gert <kontakt@eduardgert.de> Co-authored-by: Viktor Liu <viktor@netbird.io> Co-authored-by: Diego Noguês <diego.sure@gmail.com> Co-authored-by: Diego Noguês <49420+diegocn@users.noreply.github.com> Co-authored-by: Bethuel Mmbaga <bethuelmbaga12@gmail.com> Co-authored-by: Zoltan Papp <zoltan.pmail@gmail.com> Co-authored-by: Ashley Mensah <ashleyamo982@gmail.com>
89 lines
2.5 KiB
Go
89 lines
2.5 KiB
Go
package domain
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type resolver interface {
|
|
LookupCNAME(context.Context, string) (string, error)
|
|
}
|
|
|
|
type Validator struct {
|
|
Resolver resolver
|
|
}
|
|
|
|
// NewValidator initializes a validator with a specific DNS Resolver.
|
|
// If a Validator is used without specifying a Resolver, then it will
|
|
// use the net.DefaultResolver.
|
|
func NewValidator(resolver resolver) *Validator {
|
|
return &Validator{
|
|
Resolver: resolver,
|
|
}
|
|
}
|
|
|
|
// IsValid looks up the CNAME record for the passed domain with a prefix
|
|
// and compares it against the acceptable domains.
|
|
// If the returned CNAME matches any accepted domain, it will return true,
|
|
// otherwise, including in the event of a DNS error, it will return false.
|
|
// The comparison is very simple, so wildcards will not match if included
|
|
// in the acceptable domain list.
|
|
func (v *Validator) IsValid(ctx context.Context, domain string, accept []string) bool {
|
|
_, valid := v.ValidateWithCluster(ctx, domain, accept)
|
|
return valid
|
|
}
|
|
|
|
// ValidateWithCluster validates a custom domain and returns the matched cluster address.
|
|
// Returns the cluster address and true if valid, or empty string and false if invalid.
|
|
func (v *Validator) ValidateWithCluster(ctx context.Context, domain string, accept []string) (string, bool) {
|
|
if v.Resolver == nil {
|
|
v.Resolver = net.DefaultResolver
|
|
}
|
|
|
|
lookupDomain := "validation." + domain
|
|
log.WithFields(log.Fields{
|
|
"domain": domain,
|
|
"lookupDomain": lookupDomain,
|
|
"acceptList": accept,
|
|
}).Debug("looking up CNAME for domain validation")
|
|
|
|
cname, err := v.Resolver.LookupCNAME(ctx, lookupDomain)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{
|
|
"domain": domain,
|
|
"lookupDomain": lookupDomain,
|
|
}).WithError(err).Warn("CNAME lookup failed for domain validation")
|
|
return "", false
|
|
}
|
|
|
|
nakedCNAME := strings.TrimSuffix(cname, ".")
|
|
log.WithFields(log.Fields{
|
|
"domain": domain,
|
|
"cname": cname,
|
|
"nakedCNAME": nakedCNAME,
|
|
"acceptList": accept,
|
|
}).Debug("CNAME lookup result for domain validation")
|
|
|
|
for _, acceptDomain := range accept {
|
|
normalizedAccept := strings.TrimSuffix(acceptDomain, ".")
|
|
if nakedCNAME == normalizedAccept {
|
|
log.WithFields(log.Fields{
|
|
"domain": domain,
|
|
"cname": nakedCNAME,
|
|
"cluster": acceptDomain,
|
|
}).Info("domain CNAME matched cluster")
|
|
return acceptDomain, true
|
|
}
|
|
}
|
|
|
|
log.WithFields(log.Fields{
|
|
"domain": domain,
|
|
"cname": nakedCNAME,
|
|
"acceptList": accept,
|
|
}).Warn("domain CNAME does not match any accepted cluster")
|
|
return "", false
|
|
}
|