diff --git a/profile/endpoints/endpoint-continent.go b/profile/endpoints/endpoint-continent.go new file mode 100644 index 00000000..f241cfa2 --- /dev/null +++ b/profile/endpoints/endpoint-continent.go @@ -0,0 +1,63 @@ +package endpoints + +import ( + "context" + "fmt" + "regexp" + "strings" + + "github.com/safing/portmaster/intel" +) + +var ( + continentCodePrefix = "C:" + continentRegex = regexp.MustCompile(`^C:[A-Z]{2}$`) +) + +// EndpointContinent matches countries. +type EndpointContinent struct { + EndpointBase + + ContinentCode string +} + +// Matches checks whether the given entity matches this endpoint definition. +func (ep *EndpointContinent) Matches(ctx context.Context, entity *intel.Entity) (EPResult, Reason) { + if entity.IP == nil { + return NoMatch, nil + } + + if !entity.IPScope.IsGlobal() { + return NoMatch, nil + } + + countryInfo := entity.GetCountryInfo(ctx) + if countryInfo == nil { + return MatchError, ep.makeReason(ep, "", "country data not available to match") + } + + if ep.ContinentCode == countryInfo.Continent.Code { + return ep.match( + ep, entity, + fmt.Sprintf("%s (%s)", countryInfo.Continent.Name, countryInfo.Continent.Code), + "IP is located in", + ) + } + + return NoMatch, nil +} + +func (ep *EndpointContinent) String() string { + return ep.renderPPP(continentCodePrefix + ep.ContinentCode) +} + +func parseTypeContinent(fields []string) (Endpoint, error) { + if continentRegex.MatchString(fields[1]) { + ep := &EndpointContinent{ + ContinentCode: strings.TrimPrefix(strings.ToUpper(fields[1]), continentCodePrefix), + } + return ep.parsePPP(ep, fields) + } + + return nil, nil +} diff --git a/profile/endpoints/endpoint.go b/profile/endpoints/endpoint.go index 63c1e8b3..ad23c074 100644 --- a/profile/endpoints/endpoint.go +++ b/profile/endpoints/endpoint.go @@ -232,6 +232,10 @@ func parseEndpoint(value string) (endpoint Endpoint, err error) { //nolint:gocog if endpoint, err = parseTypeCountry(fields); endpoint != nil || err != nil { return } + // continent + if endpoint, err = parseTypeContinent(fields); endpoint != nil || err != nil { + return + } // asn if endpoint, err = parseTypeASN(fields); endpoint != nil || err != nil { return