diff --git a/internal/classify/aws.go b/internal/classify/aws.go index cdaf6f5..568289a 100644 --- a/internal/classify/aws.go +++ b/internal/classify/aws.go @@ -17,6 +17,23 @@ func aws(p model.Provider, s model.Service, sem model.PublicSemantic, resource, } } +// classifyCloudFront matches .cloudfront.net. Custom domains +// almost always CNAME to a CloudFront distribution, so this is how CDN-hosted +// static sites get discovered via DNS enrichment. +func classifyCloudFront(s *scanner) (model.Match, bool) { + n := s.n + if n != 3 || s.label(n-1) != "net" || s.label(n-2) != "cloudfront" { + return model.Match{}, false + } + return model.Match{ + Provider: model.ProviderAWS, + Service: model.ServiceWebApp, + ResourceSpecific: true, + PublicSemantic: model.PublicSemanticPublicEndpoint, + Resource: s.label(0), + }, true +} + func classifyAWS(s *scanner) (model.Match, bool) { n := s.n if n < 4 || s.label(n-1) != "com" || s.label(n-2) != "amazonaws" { diff --git a/internal/classify/classify.go b/internal/classify/classify.go index 4849acf..49839a8 100644 --- a/internal/classify/classify.go +++ b/internal/classify/classify.go @@ -114,6 +114,8 @@ func Classify(host string) (model.Match, bool) { switch { case strings.HasSuffix(host, ".amazonaws.com"): return classifyAWS(&s) + case strings.HasSuffix(host, ".cloudfront.net"): + return classifyCloudFront(&s) case strings.HasSuffix(host, ".core.windows.net"): return classifyAzureCore(&s) case strings.HasSuffix(host, ".database.windows.net"): diff --git a/internal/classify/classify_test.go b/internal/classify/classify_test.go index 74ed021..dbc3782 100644 --- a/internal/classify/classify_test.go +++ b/internal/classify/classify_test.go @@ -94,6 +94,7 @@ func TestClassifyMatches(t *testing.T) { {"project.firebaseio.com", want{model.ProviderGCP, model.ServiceFirebaseDB, "project", "", true, 0}}, {"project.europe-west1.firebasedatabase.app", want{model.ProviderGCP, model.ServiceFirebaseDB, "project", "europe-west1", true, 0}}, {"myproject.appspot.com", want{model.ProviderGCP, model.ServiceWebApp, "myproject", "", true, 0}}, + {"d111111abcdef8.cloudfront.net", want{model.ProviderAWS, model.ServiceWebApp, "d111111abcdef8", "", true, model.PublicSemanticPublicEndpoint}}, // Cloudflare {"acct.r2.cloudflarestorage.com", want{model.ProviderCloudflare, model.ServiceObjectStorage, "acct", "", true, 0}}, {"mybucket.r2.dev", want{model.ProviderCloudflare, model.ServiceObjectStorage, "mybucket", "", true, model.PublicSemanticPublicURL}},