diff --git a/provider/aws/aws.go b/provider/aws/aws.go index 5593861d8..26ad8112e 100644 --- a/provider/aws/aws.go +++ b/provider/aws/aws.go @@ -64,7 +64,7 @@ const ( sameZoneAlias = "same-zone" ) -// see: https://docs.aws.amazon.com/general/latest/gr/elb.html +// see elb: https://docs.aws.amazon.com/general/latest/gr/elb.html var canonicalHostedZones = map[string]string{ // Application Load Balancers and Classic Load Balancers "us-east-2.elb.amazonaws.com": "Z3AADJGX6KTTL2", @@ -101,7 +101,7 @@ var canonicalHostedZones = map[string]string{ "me-south-1.elb.amazonaws.com": "ZS929ML54UICD", "af-south-1.elb.amazonaws.com": "Z268VQBMOI5EKX", "il-central-1.elb.amazonaws.com": "Z09170902867EHPV2DABU", - // Network Load Balancers + // Network Load Balancers https://docs.aws.amazon.com/general/latest/gr/elb.html#elb_region "elb.us-east-2.amazonaws.com": "ZLMOA37VPKANP", "elb.us-east-1.amazonaws.com": "Z26RNL4JYFTOTI", "elb.us-west-1.amazonaws.com": "Z24FKFUX50B4VW", @@ -140,7 +140,7 @@ var canonicalHostedZones = map[string]string{ "awsglobalaccelerator.com": "Z2BJ6XQ5FK7U4H", // Cloudfront and AWS API Gateway edge-optimized endpoints "cloudfront.net": "Z2FDTNDATAQYW2", - // VPC Endpoint (PrivateLink) + // VPC Endpoint (PrivateLink) https://github.com/kubernetes-sigs/external-dns/issues/3429#issuecomment-1440415806 "eu-west-2.vpce.amazonaws.com": "Z7K1066E3PUKB", "us-east-2.vpce.amazonaws.com": "ZC8PG0KIFKBRI", "af-south-1.vpce.amazonaws.com": "Z09302161J80N9A7UTP7U", @@ -1163,9 +1163,15 @@ func isAWSAlias(ep *endpoint.Endpoint) string { // canonicalHostedZone returns the matching canonical zone for a given hostname. func canonicalHostedZone(hostname string) string { - for suffix, zone := range canonicalHostedZones { - if strings.HasSuffix(hostname, suffix) { - return zone + // strings.HasSuffix is optimized for this specific task and avoids the overhead associated with compiling and executing a regular expression. + if strings.HasSuffix(hostname, "aws.com") || strings.HasSuffix(hostname, "aws.com.cn") || strings.HasSuffix(hostname, "tor.com") || strings.HasSuffix(hostname, "ont.com") || strings.HasSuffix(hostname, "ont.net") { + parts := strings.Split(hostname, ".") + // iterate from the second-last part (zone) towards the beginning + for i := len(parts) - 2; i >= 0; i-- { + suffix := strings.Join(parts[i:], ".") + if zone, exists := canonicalHostedZones[suffix]; exists { + return zone + } } } diff --git a/provider/aws/aws_test.go b/provider/aws/aws_test.go index ef45bf9a4..59ea876f6 100644 --- a/provider/aws/aws_test.go +++ b/provider/aws/aws_test.go @@ -17,6 +17,7 @@ limitations under the License. package aws import ( + "bytes" "context" "fmt" "math" @@ -29,6 +30,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/route53" route53types "github.com/aws/aws-sdk-go-v2/service/route53/types" + log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -1900,13 +1902,37 @@ func TestAWSisAWSAlias(t *testing.T) { func TestAWSCanonicalHostedZone(t *testing.T) { for suffix, id := range canonicalHostedZones { zone := canonicalHostedZone(fmt.Sprintf("foo.%s", suffix)) - assert.Equal(t, id, zone) + assert.Equal(t, id, zone, "zone suffix: %s", suffix) } zone := canonicalHostedZone("foo.example.org") assert.Equal(t, "", zone, "no canonical zone should be returned for a non-aws hostname") } +func TestAWSCanonicalHostedZoneNotExist(t *testing.T) { + var buf bytes.Buffer + log.SetOutput(&buf) + host := "foo.elb.eastwest-1.amazonaws.com" + _ = canonicalHostedZone(host) + assert.Containsf(t, buf.String(), "Could not find canonical hosted zone for domain", host) +} + +func BenchmarkTestAWSCanonicalHostedZone(b *testing.B) { + for i := 0; i < b.N; i++ { + for suffix, _ := range canonicalHostedZones { + _ = canonicalHostedZone(fmt.Sprintf("foo.%s", suffix)) + } + } +} + +func BenchmarkTestAWSNonCanonicalHostedZone(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, _ = range canonicalHostedZones { + _ = canonicalHostedZone("extremely.long.zone-2.ext.dns.test.zone.non.canonical.example.com") + } + } +} + func TestAWSSuitableZones(t *testing.T) { zones := map[string]*profiledZone{ // Public domain