diff --git a/management/server/nameserver.go b/management/server/nameserver.go index 5569172c4..eb2127945 100644 --- a/management/server/nameserver.go +++ b/management/server/nameserver.go @@ -1,14 +1,18 @@ package server import ( + "errors" + "regexp" + "strconv" + "unicode/utf8" + "github.com/miekg/dns" + "github.com/rs/xid" + log "github.com/sirupsen/logrus" + nbdns "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/status" - "github.com/rs/xid" - log "github.com/sirupsen/logrus" - "strconv" - "unicode/utf8" ) const ( @@ -26,6 +30,8 @@ const ( UpdateNameServerGroupPrimary // UpdateNameServerGroupDomains indicates a nameserver group' domains update operation UpdateNameServerGroupDomains + + domainPattern = `^(?i)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$` ) // NameServerGroupUpdateOperationType operation type @@ -364,9 +370,8 @@ func validateDomainInput(primary bool, domains []string) error { " you should set either primary or domain") } for _, domain := range domains { - _, valid := dns.IsDomainName(domain) - if !valid { - return status.Errorf(status.InvalidArgument, "nameserver group got an invalid domain: %s", domain) + if err := validateDomain(domain); err != nil { + return status.Errorf(status.InvalidArgument, "nameserver group got an invalid domain: %s %q", domain, err) } } return nil @@ -417,3 +422,21 @@ func validateGroups(list []string, groups map[string]*Group) error { return nil } + +func validateDomain(domain string) error { + domainMatcher := regexp.MustCompile(domainPattern) + if !domainMatcher.MatchString(domain) { + return errors.New("domain should consists of only letters, numbers, and hyphens with no leading, trailing hyphens, or spaces") + } + + labels, valid := dns.IsDomainName(domain) + if !valid { + return errors.New("invalid domain name") + } + + if labels < 2 { + return errors.New("domain should consists of a minimum of two labels") + } + + return nil +} diff --git a/management/server/nameserver_test.go b/management/server/nameserver_test.go index 3a5c34431..9d4425056 100644 --- a/management/server/nameserver_test.go +++ b/management/server/nameserver_test.go @@ -1160,3 +1160,69 @@ func initTestNSAccount(t *testing.T, am *DefaultAccountManager) (*Account, error return account, nil } + +func TestValidateDomain(t *testing.T) { + testCases := []struct { + name string + domain string + errFunc require.ErrorAssertionFunc + }{ + { + name: "Valid domain name with multiple labels", + domain: "123.example.com", + errFunc: require.NoError, + }, + { + name: "Valid domain name with hyphen", + domain: "test-example.com", + errFunc: require.NoError, + }, + { + name: "Invalid domain name with double hyphen", + domain: "test--example.com", + errFunc: require.Error, + }, + { + name: "Invalid domain name with only one label", + domain: "com", + errFunc: require.Error, + }, + { + name: "Invalid domain name with a label exceeding 63 characters", + domain: "dnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdns.com", + errFunc: require.Error, + }, + { + name: "Invalid domain name starting with a hyphen", + domain: "-example.com", + errFunc: require.Error, + }, + { + name: "Invalid domain name ending with a hyphen", + domain: "example.com-", + errFunc: require.Error, + }, + { + name: "Invalid domain with unicode", + domain: "example?,.com", + errFunc: require.Error, + }, + { + name: "Invalid domain with space before top-level domain", + domain: "space .example.com", + errFunc: require.Error, + }, + { + name: "Invalid domain with trailing space", + domain: "example.com ", + errFunc: require.Error, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + testCase.errFunc(t, validateDomain(testCase.domain)) + }) + } + +}