diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f306ec5..22f05780 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - Improved compatibilty of built-in DERP server with clients connecting over WebSocket. - Allow nodes to use SSH agent forwarding [#2145](https://github.com/juanfont/headscale/pull/2145) - Fixed processing of fields in post request in MoveNode rpc [#2179](https://github.com/juanfont/headscale/pull/2179) +- Added conversion of 'Hostname' to 'givenName' in a node with FQDN rules applied [#2198](https://github.com/juanfont/headscale/pull/2198) ## 0.23.0 (2024-09-18) diff --git a/hscontrol/db/node.go b/hscontrol/db/node.go index 12eeeff8..1b6e7538 100644 --- a/hscontrol/db/node.go +++ b/hscontrol/db/node.go @@ -607,6 +607,7 @@ func enableRoutes(tx *gorm.DB, } func generateGivenName(suppliedName string, randomSuffix bool) (string, error) { + suppliedName = util.ConvertWithFQDNRules(suppliedName) if len(suppliedName) > util.LabelHostnameLength { return "", types.ErrHostnameTooLong } diff --git a/hscontrol/db/node_test.go b/hscontrol/db/node_test.go index 1edaa06e..888f48db 100644 --- a/hscontrol/db/node_test.go +++ b/hscontrol/db/node_test.go @@ -392,6 +392,15 @@ func TestHeadscale_generateGivenName(t *testing.T) { want: regexp.MustCompile("^testnode$"), wantErr: false, }, + { + name: "UPPERCASE node name generation", + args: args{ + suppliedName: "TestNode", + randomSuffix: false, + }, + want: regexp.MustCompile("^testnode$"), + wantErr: false, + }, { name: "node name with 53 chars", args: args{ diff --git a/hscontrol/util/dns.go b/hscontrol/util/dns.go index 217b1fbc..f57576f4 100644 --- a/hscontrol/util/dns.go +++ b/hscontrol/util/dns.go @@ -50,6 +50,13 @@ func CheckForFQDNRules(name string) error { return nil } +func ConvertWithFQDNRules(name string) string { + name = strings.ToLower(name) + name = invalidCharsInUserRegex.ReplaceAllString(name, "") + + return name +} + // generateMagicDNSRootDomains generates a list of DNS entries to be included in `Routes` in `MapResponse`. // This list of reverse DNS entries instructs the OS on what subnets and domains the Tailscale embedded DNS // server (listening in 100.100.100.100 udp/53) should be used for. diff --git a/hscontrol/util/dns_test.go b/hscontrol/util/dns_test.go index 28a28520..30652e4b 100644 --- a/hscontrol/util/dns_test.go +++ b/hscontrol/util/dns_test.go @@ -53,6 +53,52 @@ func TestCheckForFQDNRules(t *testing.T) { } } +func TestConvertWithFQDNRules(t *testing.T) { + tests := []struct { + name string + hostname string + dnsHostName string + }{ + { + name: "User1.test", + hostname: "User1.Test", + dnsHostName: "user1.test", + }, + { + name: "User'1$2.test", + hostname: "User'1$2.Test", + dnsHostName: "user12.test", + }, + { + name: "User-^_12.local.test", + hostname: "User-^_12.local.Test", + dnsHostName: "user-12.local.test", + }, + { + name: "User-MacBook-Pro", + hostname: "User-MacBook-Pro", + dnsHostName: "user-macbook-pro", + }, + { + name: "User-Linux-Ubuntu/Fedora", + hostname: "User-Linux-Ubuntu/Fedora", + dnsHostName: "user-linux-ubuntufedora", + }, + { + name: "User-[Space]123", + hostname: "User-[ ]123", + dnsHostName: "user-123", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fqdnHostName := ConvertWithFQDNRules(tt.hostname) + assert.Equal(t, tt.dnsHostName, fqdnHostName) + }) + } +} + func TestMagicDNSRootDomains100(t *testing.T) { domains := GenerateIPv4DNSRootDomain(netip.MustParsePrefix("100.64.0.0/10"))