From a44312d5166a95ceeb62b04662cb49745b0e32eb Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Aug 2023 16:30:56 +0200 Subject: [PATCH 1/9] Expose tunnel options creation and split tunnel options --- firewall/tunnel.go | 74 ++++++++++++++++++++++++++++++---------------- profile/config.go | 6 ++-- 2 files changed, 52 insertions(+), 28 deletions(-) diff --git a/firewall/tunnel.go b/firewall/tunnel.go index ccaf81ff3..0f747e187 100644 --- a/firewall/tunnel.go +++ b/firewall/tunnel.go @@ -5,9 +5,11 @@ import ( "errors" "github.com/safing/portbase/log" + "github.com/safing/portmaster/intel" "github.com/safing/portmaster/netenv" "github.com/safing/portmaster/network" "github.com/safing/portmaster/network/packet" + "github.com/safing/portmaster/process" "github.com/safing/portmaster/profile" "github.com/safing/portmaster/profile/endpoints" "github.com/safing/portmaster/resolver" @@ -124,38 +126,67 @@ func requestTunneling(ctx context.Context, conn *network.Connection) error { return errors.New("no profile set") } + // Get tunnel options. + conn.TunnelOpts = DeriveTunnelOptions(layeredProfile, conn.Process(), conn.Entity, conn.Encrypted) + + // Queue request in sluice. + err := sluice.AwaitRequest(conn, crew.HandleSluiceRequest) + if err != nil { + return err + } + + log.Tracer(ctx).Trace("filter: tunneling requested") + return nil +} + +func init() { + navigator.DeriveTunnelOptions = func(lp *profile.LayeredProfile, destination *intel.Entity, connEncrypted bool) *navigator.Options { + return DeriveTunnelOptions(lp, nil, destination, connEncrypted) + } +} + +// DeriveTunnelOptions derives and returns the tunnel options from the connection and profile. +func DeriveTunnelOptions(lp *profile.LayeredProfile, proc *process.Process, destination *intel.Entity, connEncrypted bool) *navigator.Options { // Set options. - conn.TunnelOpts = &navigator.Options{ - HubPolicies: layeredProfile.StackedExitHubPolicies(), - CheckHubExitPolicyWith: conn.Entity, - RequireTrustedDestinationHubs: !conn.Encrypted, - RoutingProfile: layeredProfile.SPNRoutingAlgorithm(), + tunnelOpts := &navigator.Options{ + Transit: &navigator.TransitHubOptions{ + HubPolicies: lp.StackedTransitHubPolicies(), + }, + Destination: &navigator.DestinationHubOptions{ + HubPolicies: lp.StackedExitHubPolicies(), + CheckHubPolicyWith: destination, + }, + RoutingProfile: lp.SPNRoutingAlgorithm(), + } + if !connEncrypted { + tunnelOpts.Destination.Regard = tunnelOpts.Destination.Regard.Add(navigator.StateTrusted) } // Add required verified owners if community nodes should not be used. if !useCommunityNodes() { - conn.TunnelOpts.RequireVerifiedOwners = captain.NonCommunityVerifiedOwners + tunnelOpts.Transit.RequireVerifiedOwners = captain.NonCommunityVerifiedOwners + tunnelOpts.Destination.RequireVerifiedOwners = captain.NonCommunityVerifiedOwners } // Get routing profile for checking for upgrades. - routingProfile := navigator.GetRoutingProfile(conn.TunnelOpts.RoutingProfile) + routingProfile := navigator.GetRoutingProfile(tunnelOpts.RoutingProfile) // If we have any exit hub policies, we must be able to hop in order to follow the policy. // Switch to single-hop routing to allow for routing with hub selection. - if routingProfile.MaxHops <= 1 && conn.TunnelOpts.HubPoliciesAreSet() { - conn.TunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID + if routingProfile.MaxHops <= 1 && navigator.HubPoliciesAreSet(tunnelOpts.Destination.HubPolicies) { + tunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID } // If the current home node is not trusted, then upgrade at least to two hops. if routingProfile.MinHops < 2 { homeNode, _ := navigator.Main.GetHome() if homeNode != nil && !homeNode.State.Has(navigator.StateTrusted) { - conn.TunnelOpts.RoutingProfile = navigator.RoutingProfileDoubleHopID + tunnelOpts.RoutingProfile = navigator.RoutingProfileDoubleHopID } } // Special handling for the internal DNS resolver. - if conn.Process().Pid == ownPID && resolver.IsResolverAddress(conn.Entity.IP, conn.Entity.Port) { + if proc != nil && proc.Pid == ownPID && resolver.IsResolverAddress(destination.IP, destination.Port) { dnsExitHubPolicy, err := captain.GetDNSExitHubPolicy() if err != nil { log.Errorf("firewall: failed to get dns exit hub policy: %s", err) @@ -163,27 +194,20 @@ func requestTunneling(ctx context.Context, conn *network.Connection) error { if err == nil && dnsExitHubPolicy.IsSet() { // Apply the dns exit hub policy, if set. - conn.TunnelOpts.HubPolicies = []endpoints.Endpoints{dnsExitHubPolicy} + tunnelOpts.Destination.HubPolicies = []endpoints.Endpoints{dnsExitHubPolicy} // Use the routing algorithm from the profile, as the home profile won't work with the policy. - conn.TunnelOpts.RoutingProfile = layeredProfile.SPNRoutingAlgorithm() + tunnelOpts.RoutingProfile = lp.SPNRoutingAlgorithm() // Raise the routing algorithm at least to single-hop. - if conn.TunnelOpts.RoutingProfile == navigator.RoutingProfileHomeID { - conn.TunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID + if tunnelOpts.RoutingProfile == navigator.RoutingProfileHomeID { + tunnelOpts.RoutingProfile = navigator.RoutingProfileSingleHopID } } else { // Disable any policies for the internal DNS resolver. - conn.TunnelOpts.HubPolicies = nil + tunnelOpts.Destination.HubPolicies = nil // Always use the home routing profile for the internal DNS resolver. - conn.TunnelOpts.RoutingProfile = navigator.RoutingProfileHomeID + tunnelOpts.RoutingProfile = navigator.RoutingProfileHomeID } } - // Queue request in sluice. - err := sluice.AwaitRequest(conn, crew.HandleSluiceRequest) - if err != nil { - return err - } - - log.Tracer(ctx).Trace("filter: tunneling requested") - return nil + return tunnelOpts } diff --git a/profile/config.go b/profile/config.go index 45be8ce3e..624605d54 100644 --- a/profile/config.go +++ b/profile/config.go @@ -7,7 +7,6 @@ import ( "github.com/safing/portmaster/profile/endpoints" "github.com/safing/portmaster/status" "github.com/safing/spn/access/account" - "github.com/safing/spn/navigator" ) // Configuration Keys. @@ -129,6 +128,7 @@ var ( CfgOptionRoutingAlgorithmKey = "spn/routingAlgorithm" cfgOptionRoutingAlgorithm config.StringOption cfgOptionRoutingAlgorithmOrder = 144 + DefaultRoutingProfileID = "double-hop" // Copied due to import loop. // Setting "Home Node Rules" at order 145. @@ -754,7 +754,7 @@ By default, the Portmaster tries to choose the node closest to the destination a Key: CfgOptionRoutingAlgorithmKey, Description: "Select the routing algorithm for your connections through the SPN. Configure your preferred balance between speed and privacy. Portmaster may automatically upgrade the routing algorithm if necessary to protect your privacy.", OptType: config.OptTypeString, - DefaultValue: navigator.DefaultRoutingProfileID, + DefaultValue: DefaultRoutingProfileID, Annotations: config.Annotations{ config.DisplayHintAnnotation: config.DisplayHintOneOf, config.DisplayOrderAnnotation: cfgOptionRoutingAlgorithmOrder, @@ -786,7 +786,7 @@ By default, the Portmaster tries to choose the node closest to the destination a if err != nil { return err } - cfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(CfgOptionRoutingAlgorithmKey, navigator.DefaultRoutingProfileID) + cfgOptionRoutingAlgorithm = config.Concurrent.GetAsString(CfgOptionRoutingAlgorithmKey, DefaultRoutingProfileID) cfgStringOptions[CfgOptionRoutingAlgorithmKey] = cfgOptionRoutingAlgorithm return nil From 96a6d6229a06165ae6a4623d5b244e804d1989f2 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Aug 2023 16:31:17 +0200 Subject: [PATCH 2/9] Add setting to specify transit node rules --- profile/config-update.go | 20 ++++++++++++++------ profile/config.go | 36 ++++++++++++++++++++++++++++++++++-- profile/profile-layered.go | 17 +++++++++++++++++ profile/profile.go | 28 +++++++++++++++++++--------- 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/profile/config-update.go b/profile/config-update.go index 1e73d4fee..3a6cd246b 100644 --- a/profile/config-update.go +++ b/profile/config-update.go @@ -14,12 +14,13 @@ import ( var ( cfgLock sync.RWMutex - cfgDefaultAction uint8 - cfgEndpoints endpoints.Endpoints - cfgServiceEndpoints endpoints.Endpoints - cfgSPNUsagePolicy endpoints.Endpoints - cfgSPNExitHubPolicy endpoints.Endpoints - cfgFilterLists []string + cfgDefaultAction uint8 + cfgEndpoints endpoints.Endpoints + cfgServiceEndpoints endpoints.Endpoints + cfgSPNUsagePolicy endpoints.Endpoints + cfgSPNTransitHubPolicy endpoints.Endpoints + cfgSPNExitHubPolicy endpoints.Endpoints + cfgFilterLists []string ) func registerConfigUpdater() error { @@ -83,6 +84,13 @@ func updateGlobalConfigProfile(ctx context.Context, task *modules.Task) error { lastErr = err } + list = cfgOptionTransitHubPolicy() + cfgSPNTransitHubPolicy, err = endpoints.ParseEndpoints(list) + if err != nil { + // TODO: module error? + lastErr = err + } + list = cfgOptionExitHubPolicy() cfgSPNExitHubPolicy, err = endpoints.ParseEndpoints(list) if err != nil { diff --git a/profile/config.go b/profile/config.go index 624605d54..782d46739 100644 --- a/profile/config.go +++ b/profile/config.go @@ -132,11 +132,15 @@ var ( // Setting "Home Node Rules" at order 145. + CfgOptionTransitHubPolicyKey = "spn/transitHubPolicy" + cfgOptionTransitHubPolicy config.StringArrayOption + cfgOptionTransitHubPolicyOrder = 146 + CfgOptionExitHubPolicyKey = "spn/exitHubPolicy" cfgOptionExitHubPolicy config.StringArrayOption - cfgOptionExitHubPolicyOrder = 146 + cfgOptionExitHubPolicyOrder = 147 - // Setting "DNS Exit Node Rules" at order 147. + // Setting "DNS Exit Node Rules" at order 148. ) // A list of all security level settings. @@ -720,6 +724,34 @@ Please note that if you are using the system resolver, bypass attempts might be cfgOptionSPNUsagePolicy = config.Concurrent.GetAsStringArray(CfgOptionSPNUsagePolicyKey, []string{}) cfgStringArrayOptions[CfgOptionSPNUsagePolicyKey] = cfgOptionSPNUsagePolicy + // Transit Node Rules + err = config.Register(&config.Option{ + Name: "Transit Node Rules", + Key: CfgOptionTransitHubPolicyKey, + Description: `Customize which countries should or should not be used as Transit Nodes. Transit Nodes are used to transit the SPN from your Home to your Exit Node.`, + Help: SPNRulesHelp, + Sensitive: true, + OptType: config.OptTypeStringArray, + ExpertiseLevel: config.ExpertiseLevelExpert, + ReleaseLevel: config.ReleaseLevelBeta, + DefaultValue: []string{}, + Annotations: config.Annotations{ + config.StackableAnnotation: true, + config.CategoryAnnotation: "Routing", + config.DisplayOrderAnnotation: cfgOptionTransitHubPolicyOrder, + config.DisplayHintAnnotation: endpoints.DisplayHintEndpointList, + config.QuickSettingsAnnotation: SPNRulesQuickSettings, + endpoints.EndpointListVerdictNamesAnnotation: SPNRulesVerdictNames, + }, + ValidationRegex: endpoints.ListEntryValidationRegex, + ValidationFunc: endpoints.ValidateEndpointListConfigOption, + }) + if err != nil { + return err + } + cfgOptionTransitHubPolicy = config.Concurrent.GetAsStringArray(CfgOptionTransitHubPolicyKey, []string{}) + cfgStringArrayOptions[CfgOptionTransitHubPolicyKey] = cfgOptionTransitHubPolicy + // Exit Node Rules err = config.Register(&config.Option{ Name: "Exit Node Rules", diff --git a/profile/profile-layered.go b/profile/profile-layered.go index 1310f15ce..6ed2ad925 100644 --- a/profile/profile-layered.go +++ b/profile/profile-layered.go @@ -382,6 +382,23 @@ func (lp *LayeredProfile) MatchSPNUsagePolicy(ctx context.Context, entity *intel return cfgSPNUsagePolicy.Match(ctx, entity) } +// StackedTransitHubPolicies returns all transit hub policies of the layered profile, including the global one. +func (lp *LayeredProfile) StackedTransitHubPolicies() []endpoints.Endpoints { + policies := make([]endpoints.Endpoints, 0, len(lp.layers)+3) // +1 for global policy, +2 for intel policies + + for _, layer := range lp.layers { + if layer.spnTransitHubPolicy.IsSet() { + policies = append(policies, layer.spnTransitHubPolicy) + } + } + + cfgLock.RLock() + defer cfgLock.RUnlock() + policies = append(policies, cfgSPNTransitHubPolicy) + + return policies +} + // StackedExitHubPolicies returns all exit hub policies of the layered profile, including the global one. func (lp *LayeredProfile) StackedExitHubPolicies() []endpoints.Endpoints { policies := make([]endpoints.Endpoints, 0, len(lp.layers)+3) // +1 for global policy, +2 for intel policies diff --git a/profile/profile.go b/profile/profile.go index 1fa12ff81..1838e5341 100644 --- a/profile/profile.go +++ b/profile/profile.go @@ -127,15 +127,16 @@ type Profile struct { //nolint:maligned // not worth the effort layeredProfile *LayeredProfile // Interpreted Data - configPerspective *config.Perspective - dataParsed bool - defaultAction uint8 - endpoints endpoints.Endpoints - serviceEndpoints endpoints.Endpoints - filterListsSet bool - filterListIDs []string - spnUsagePolicy endpoints.Endpoints - spnExitHubPolicy endpoints.Endpoints + configPerspective *config.Perspective + dataParsed bool + defaultAction uint8 + endpoints endpoints.Endpoints + serviceEndpoints endpoints.Endpoints + filterListsSet bool + filterListIDs []string + spnUsagePolicy endpoints.Endpoints + spnTransitHubPolicy endpoints.Endpoints + spnExitHubPolicy endpoints.Endpoints // Lifecycle Management outdated *abool.AtomicBool @@ -224,6 +225,15 @@ func (profile *Profile) parseConfig() error { } } + list, ok = profile.configPerspective.GetAsStringArray(CfgOptionTransitHubPolicyKey) + profile.spnTransitHubPolicy = nil + if ok { + profile.spnTransitHubPolicy, err = endpoints.ParseEndpoints(list) + if err != nil { + lastErr = err + } + } + list, ok = profile.configPerspective.GetAsStringArray(CfgOptionExitHubPolicyKey) profile.spnExitHubPolicy = nil if ok { From 6546c3dc5f670b6ed4e279ee85232e3ca33737f9 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Aug 2023 16:31:33 +0200 Subject: [PATCH 3/9] Update DNS resolver config help --- resolver/config.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/resolver/config.go b/resolver/config.go index 227e4864e..44f8280a1 100644 --- a/resolver/config.go +++ b/resolver/config.go @@ -88,23 +88,28 @@ func prepConfig() error { err := config.Register(&config.Option{ Name: "DNS Servers", Key: CfgOptionNameServersKey, - Description: "DNS Servers to use for resolving DNS requests.", - Help: strings.ReplaceAll(`DNS Servers are used in the order as entered. The first one will be used as the primary DNS Server. Only if it fails, will the other servers be used as a fallback - in their respective order. If all fail, or if no DNS Server is configured here, the Portmaster will use the one configured in your system or network. + Description: "DNS servers to use for resolving DNS requests.", + Help: strings.ReplaceAll(`DNS servers are used in the order as entered. The first one will be used as the primary DNS Server. Only if it fails, will the other servers be used as a fallback - in their respective order. If all fail, or if no DNS Server is configured here, the Portmaster will use the one configured in your system or network. -Additionally, if it is more likely that the DNS Server of your system or network has a (better) answer to a request, they will be asked first. This will be the case for special local domains and domain spaces announced on the current network. +Additionally, if it is more likely that the DNS server of your system or network has a (better) answer to a request, they will be asked first. This will be the case for special local domains and domain spaces announced on the current network. -DNS Servers are configured in a URL format. This allows you to specify special settings for a resolver. If you just want to use a resolver at IP 10.2.3.4, please enter: "dns://10.2.3.4" -The format is: "protocol://ip:port?parameter=value¶meter=value" +DNS servers are configured in a URL format. This allows you to specify special settings for a resolver. If you just want to use a resolver at IP 10.2.3.4, please enter: "dns://10.2.3.4" +The format is: "protocol://host:port?parameter=value¶meter=value" + +For DoH servers, you can also just paste the URL given by the DNS provider. +When referring to the DNS server using a domain name, as with DoH, it is highly recommended to also specify the IP address using the "ip" parameter, so Portmaster does not have to resolve it. - Protocol - - "dot": DNS-over-TLS (recommended) + - "dot": DNS-over-TLS (or "tls"; recommended) + - "doh": DNS-over-HTTPS (or "https") - "dns": plain old DNS - "tcp": plain old DNS over TCP -- IP: always use the IP address and _not_ the domain name! +- Host: specify the domain or IP of the resolver - Port: optionally define a custom port - Parameters: - "name": give your DNS Server a name that is used for messages and logs - - "verify": domain name to verify for "dot", required and only valid for protocol "dot" + - "verify": domain name to verify for "dot", only valid for "dot" and "doh" + - "ip": IP address (if using a domain), so Portmaster does not need to resolve it using the system resolver - this is highly recommended - "blockedif": detect if the name server blocks a query, options: - "empty": server replies with NXDomain status, but without any other record in any section - "refused": server replies with Refused status From e107ea168a93f67ea26bba8a12122c3c65e89484 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Aug 2023 16:31:49 +0200 Subject: [PATCH 4/9] Remove unused parameter from resolver URL --- resolver/resolvers.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/resolver/resolvers.go b/resolver/resolvers.go index dedba3b45..962d3a78b 100644 --- a/resolver/resolvers.go +++ b/resolver/resolvers.go @@ -34,7 +34,6 @@ const ( parameterBlockedIf = "blockedif" parameterSearch = "search" parameterSearchOnly = "search-only" - parameterPath = "path" ) var ( @@ -209,8 +208,7 @@ func checkAndSetResolverParamters(u *url.URL, resolver *Resolver) error { parameterIP, parameterBlockedIf, parameterSearch, - parameterSearchOnly, - parameterPath: + parameterSearchOnly: // Known key, continue. default: // Unknown key, abort. From 629b2db49529fea5fa7fa43e965fc3d778252094 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 22 Aug 2023 16:36:49 +0200 Subject: [PATCH 5/9] Update format of default DNS resolvers --- resolver/config.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/resolver/config.go b/resolver/config.go index 44f8280a1..50669bbba 100644 --- a/resolver/config.go +++ b/resolver/config.go @@ -26,20 +26,19 @@ var ( // https://github.com/safing/portmaster/wiki/DNS-Server-Settings // Quad9 (encrypted DNS) - // `dot://9.9.9.9:853?verify=dns.quad9.net&name=Quad9&blockedif=empty`, - // `dot://149.112.112.112:853?verify=dns.quad9.net&name=Quad9&blockedif=empty`, + // "dot://dns.quad9.net?ip=9.9.9.9&name=Quad9&blockedif=empty", + // "dot://dns.quad9.net?ip=149.112.112.112&name=Quad9&blockedif=empty", // Cloudflare (encrypted DNS, with malware protection) - `dot://1.1.1.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip`, - `dot://1.0.0.2:853?verify=cloudflare-dns.com&name=Cloudflare&blockedif=zeroip`, + "dot://cloudflare-dns.com?ip=1.1.1.2&name=Cloudflare&blockedif=zeroip", + "dot://cloudflare-dns.com?ip=1.0.0.2&name=Cloudflare&blockedif=zeroip", // AdGuard (encrypted DNS, default flavor) - // `dot://94.140.14.14:853?verify=dns.adguard.com&name=AdGuard&blockedif=zeroip`, - // `dot://94.140.15.15:853?verify=dns.adguard.com&name=AdGuard&blockedif=zeroip`, + // "dot://dns.adguard.com?ip=94.140.14.14&name=AdGuard&blockedif=zeroip", + // "dot://dns.adguard.com?ip=94.140.15.15&name=AdGuard&blockedif=zeroip", // Foundation for Applied Privacy (encrypted DNS) - // `dot://94.130.106.88:853?verify=dot1.applied-privacy.net&name=AppliedPrivacy`, - // `dot://94.130.106.88:443?verify=dot1.applied-privacy.net&name=AppliedPrivacy`, + // "dot://dot1.applied-privacy.net?ip=146.255.56.98&name=AppliedPrivacy", // Quad9 (plain DNS) // `dns://9.9.9.9:53?name=Quad9&blockedif=empty`, From 593948676793693d93db7c7b39444c7f6ac5ba18 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 23 Aug 2023 13:53:19 +0200 Subject: [PATCH 6/9] Combine geoip country info and add country names --- intel/geoip/country_info.go | 1776 ++++++++++++++++++++++++++++++ intel/geoip/country_info_test.go | 43 + intel/geoip/fill_missing.go | 264 ----- intel/geoip/location.go | 1 + intel/geoip/lookup.go | 3 +- intel/geoip/module.go | 8 +- intel/geoip/regions.go | 259 ----- profile/config.go | 15 +- profile/profile.go | 2 +- 9 files changed, 1828 insertions(+), 543 deletions(-) create mode 100644 intel/geoip/country_info.go create mode 100644 intel/geoip/country_info_test.go delete mode 100644 intel/geoip/fill_missing.go diff --git a/intel/geoip/country_info.go b/intel/geoip/country_info.go new file mode 100644 index 000000000..28a2706aa --- /dev/null +++ b/intel/geoip/country_info.go @@ -0,0 +1,1776 @@ +package geoip + +const defaultCountryBasedAccuracy = 200 + +// AddCountryInfo adds missing country information to the location. +func (l *Location) AddCountryInfo() { + // Check if we have the country code. + if l.Country.ISOCode == "" { + return + } + + // Get country info. + info, ok := countries[l.Country.ISOCode] + if !ok { + return + } + + // Add missing data. + if l.Country.Name == "" { + l.Country.Name = info.Name + } + if l.Coordinates.Latitude == 0 && l.Coordinates.Longitude == 0 { + l.Coordinates = info.Center + l.Coordinates.AccuracyRadius = defaultCountryBasedAccuracy + } + // TODO: We are currently re-using the Continent-Code for the region. Update this and all dependencies. + l.Continent.Code = info.Region +} + +// GetCountryInfo returns the country info of the given country code, or nil +// in case the data does not exist. +func GetCountryInfo(countryCode string) *CountryInfo { + info := countries[countryCode] + return &info +} + +// CountryInfo holds additional information about countries. +type CountryInfo struct { + ID string + Name string + Region string + ContinentCode string + Center Coordinates +} + +var countries = map[string]CountryInfo{ + "MN": { + ID: "MN", + Name: "Mongolia", + Region: "AS-E", + ContinentCode: "AS", + Center: Coordinates{Latitude: 46.000000, Longitude: 103.000000}, + }, + "BN": { + ID: "BN", + Name: "Brunei Darussalam", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 4.000000, Longitude: 114.000000}, + }, + "GI": { + ID: "GI", + Name: "Gibraltar", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 36.000000, Longitude: -5.000000}, + }, + "SO": { + ID: "SO", + Name: "Somalia", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: 5.000000, Longitude: 46.000000}, + }, + "GG": { + ID: "GG", + Name: "Guernsey", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 49.000000, Longitude: -2.000000}, + }, + "CL": { + ID: "CL", + Name: "Chile", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -35.000000, Longitude: -71.000000}, + }, + "LR": { + ID: "LR", + Name: "Liberia", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 6.000000, Longitude: -9.000000}, + }, + "TZ": { + ID: "TZ", + Name: "Tanzania", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -6.000000, Longitude: 34.000000}, + }, + "MU": { + ID: "MU", + Name: "Mauritius", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -20.000000, Longitude: 57.000000}, + }, + "HM": { + ID: "HM", + Name: "Heard Island and McDonald Islands", + Region: "OC-S", + ContinentCode: "OC", + Center: Coordinates{Latitude: -53.000000, Longitude: 73.000000}, + }, + "AR": { + ID: "AR", + Name: "Argentina", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -38.000000, Longitude: -63.000000}, + }, + "BV": { + ID: "BV", + Name: "Bouvet Island", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -54.000000, Longitude: 3.000000}, + }, + "MS": { + ID: "MS", + Name: "Montserrat", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 16.000000, Longitude: -62.000000}, + }, + "PT": { + ID: "PT", + Name: "Portugal", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 39.000000, Longitude: -8.000000}, + }, + "BO": { + ID: "BO", + Name: "Bolivia", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -16.000000, Longitude: -63.000000}, + }, + "VC": { + ID: "VC", + Name: "Saint Vincent and the Grenadines", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 12.000000, Longitude: -61.000000}, + }, + "RO": { + ID: "RO", + Name: "Romania", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 45.000000, Longitude: 24.000000}, + }, + "MK": { + ID: "MK", + Name: "North Macedonia", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 41.000000, Longitude: 21.000000}, + }, + "UG": { + ID: "UG", + Name: "Uganda", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: 1.000000, Longitude: 32.000000}, + }, + "HN": { + ID: "HN", + Name: "Honduras", + Region: "NA-S", + ContinentCode: "NA", + Center: Coordinates{Latitude: 15.000000, Longitude: -86.000000}, + }, + "IS": { + ID: "IS", + Name: "Iceland", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 64.000000, Longitude: -19.000000}, + }, + "HR": { + ID: "HR", + Name: "Croatia", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 45.000000, Longitude: 15.000000}, + }, + "PL": { + ID: "PL", + Name: "Poland", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 51.000000, Longitude: 19.000000}, + }, + "TC": { + ID: "TC", + Name: "Turks and Caicos Islands", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 21.000000, Longitude: -71.000000}, + }, + "LC": { + ID: "LC", + Name: "Saint Lucia", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 13.000000, Longitude: -60.000000}, + }, + "JP": { + ID: "JP", + Name: "Japan", + Region: "AS-E", + ContinentCode: "AS", + Center: Coordinates{Latitude: 36.000000, Longitude: 138.000000}, + }, + "TN": { + ID: "TN", + Name: "Tunisia", + Region: "AF-N", + ContinentCode: "AF", + Center: Coordinates{Latitude: 33.000000, Longitude: 9.000000}, + }, + "GS": { + ID: "GS", + Name: "South Georgia and the South Sandwich Islands", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -54.000000, Longitude: -36.000000}, + }, + "MY": { + ID: "MY", + Name: "Malaysia", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 4.000000, Longitude: 101.000000}, + }, + "TT": { + ID: "TT", + Name: "Trinidad and Tobago", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 10.000000, Longitude: -61.000000}, + }, + "BE": { + ID: "BE", + Name: "Belgium", + Region: "EU-W", + ContinentCode: "EU", + Center: Coordinates{Latitude: 50.000000, Longitude: 4.000000}, + }, + "GU": { + ID: "GU", + Name: "Guam", + Region: "OC-N", + ContinentCode: "OC", + Center: Coordinates{Latitude: 13.000000, Longitude: 144.000000}, + }, + "NL": { + ID: "NL", + Name: "Netherlands", + Region: "EU-W", + ContinentCode: "EU", + Center: Coordinates{Latitude: 52.000000, Longitude: 5.000000}, + }, + "AF": { + ID: "AF", + Name: "Afghanistan", + Region: "AS-S", + ContinentCode: "AS", + Center: Coordinates{Latitude: 33.000000, Longitude: 67.000000}, + }, + "CK": { + ID: "CK", + Name: "Cook Islands", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -21.000000, Longitude: -159.000000}, + }, + "PM": { + ID: "PM", + Name: "Saint Pierre and Miquelon", + Region: "NA-N", + ContinentCode: "NA", + Center: Coordinates{Latitude: 46.000000, Longitude: -56.000000}, + }, + "OM": { + ID: "OM", + Name: "Oman", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 21.000000, Longitude: 55.000000}, + }, + "NP": { + ID: "NP", + Name: "Nepal", + Region: "AS-S", + ContinentCode: "AS", + Center: Coordinates{Latitude: 28.000000, Longitude: 84.000000}, + }, + "RS": { + ID: "RS", + Name: "Serbia", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 44.000000, Longitude: 21.000000}, + }, + "MW": { + ID: "MW", + Name: "Malawi", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -13.000000, Longitude: 34.000000}, + }, + "NE": { + ID: "NE", + Name: "Niger", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 17.000000, Longitude: 8.000000}, + }, + "BY": { + ID: "BY", + Name: "Belarus", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 53.000000, Longitude: 27.000000}, + }, + "TH": { + ID: "TH", + Name: "Thailand", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 15.000000, Longitude: 100.000000}, + }, + "CW": { + ID: "CW", + Name: "Curaçao", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 12.000000, Longitude: -68.000000}, + }, + "AS": { + ID: "AS", + Name: "American Samoa", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -14.000000, Longitude: -170.000000}, + }, + "BF": { + ID: "BF", + Name: "Burkina Faso", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 12.000000, Longitude: -1.000000}, + }, + "BR": { + ID: "BR", + Name: "Brazil", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -14.000000, Longitude: -51.000000}, + }, + "CX": { + ID: "CX", + Name: "Christmas Island", + Region: "OC-S", + ContinentCode: "OC", + Center: Coordinates{Latitude: -10.000000, Longitude: 105.000000}, + }, + "MG": { + ID: "MG", + Name: "Madagascar", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -18.000000, Longitude: 46.000000}, + }, + "CY": { + ID: "CY", + Name: "Cyprus", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 35.000000, Longitude: 33.000000}, + }, + "KW": { + ID: "KW", + Name: "Kuwait", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 29.000000, Longitude: 47.000000}, + }, + "IT": { + ID: "IT", + Name: "Italy", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 41.000000, Longitude: 12.000000}, + }, + "SJ": { + ID: "SJ", + Name: "Svalbard and Jan Mayen", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 77.000000, Longitude: 23.000000}, + }, + "ZM": { + ID: "ZM", + Name: "Zambia", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -13.000000, Longitude: 27.000000}, + }, + "TO": { + ID: "TO", + Name: "Tonga", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -21.000000, Longitude: -175.000000}, + }, + "EE": { + ID: "EE", + Name: "Estonia", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 58.000000, Longitude: 25.000000}, + }, + "LI": { + ID: "LI", + Name: "Liechtenstein", + Region: "EU-W", + ContinentCode: "EU", + Center: Coordinates{Latitude: 47.000000, Longitude: 9.000000}, + }, + "LB": { + ID: "LB", + Name: "Lebanon", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 33.000000, Longitude: 35.000000}, + }, + "DK": { + ID: "DK", + Name: "Denmark", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 56.000000, Longitude: 9.000000}, + }, + "LS": { + ID: "LS", + Name: "Lesotho", + Region: "AF-S", + ContinentCode: "AF", + Center: Coordinates{Latitude: -29.000000, Longitude: 28.000000}, + }, + "CM": { + ID: "CM", + Name: "Cameroon", + Region: "AF-C", + ContinentCode: "AF", + Center: Coordinates{Latitude: 7.000000, Longitude: 12.000000}, + }, + "BH": { + ID: "BH", + Name: "Bahrain", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 25.000000, Longitude: 50.000000}, + }, + "NA": { + ID: "NA", + Name: "Namibia", + Region: "AF-S", + ContinentCode: "AF", + Center: Coordinates{Latitude: -22.000000, Longitude: 18.000000}, + }, + "ZA": { + ID: "ZA", + Name: "South Africa", + Region: "AF-S", + ContinentCode: "AF", + Center: Coordinates{Latitude: -30.000000, Longitude: 22.000000}, + }, + "PH": { + ID: "PH", + Name: "Philippines", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 12.000000, Longitude: 121.000000}, + }, + "JM": { + ID: "JM", + Name: "Jamaica", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 18.000000, Longitude: -77.000000}, + }, + "PS": { + ID: "PS", + Name: "Palestine", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 31.000000, Longitude: 35.000000}, + }, + "TM": { + ID: "TM", + Name: "Turkmenistan", + Region: "AS-C", + ContinentCode: "AS", + Center: Coordinates{Latitude: 38.000000, Longitude: 59.000000}, + }, + "SD": { + ID: "SD", + Name: "Sudan", + Region: "AF-N", + ContinentCode: "AF", + Center: Coordinates{Latitude: 12.000000, Longitude: 30.000000}, + }, + "KN": { + ID: "KN", + Name: "Saint Kitts and Nevis", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 17.000000, Longitude: -62.000000}, + }, + "GF": { + ID: "GF", + Name: "French Guiana", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: 3.000000, Longitude: -53.000000}, + }, + "WS": { + ID: "WS", + Name: "Samoa", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -13.000000, Longitude: -172.000000}, + }, + "KE": { + ID: "KE", + Name: "Kenya", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: 0.000000, Longitude: 37.000000}, + }, + "CG": { + ID: "CG", + Name: "Congo", + Region: "AF-C", + ContinentCode: "AF", + Center: Coordinates{Latitude: 0.000000, Longitude: 15.000000}, + }, + "FJ": { + ID: "FJ", + Name: "Fiji", + Region: "OC-C", + ContinentCode: "OC", + Center: Coordinates{Latitude: -16.000000, Longitude: 179.000000}, + }, + "BL": { + ID: "BL", + Name: "Saint Barthélemy", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 17.000000, Longitude: -62.000000}, + }, + "TD": { + ID: "TD", + Name: "Chad", + Region: "AF-C", + ContinentCode: "AF", + Center: Coordinates{Latitude: 15.000000, Longitude: 18.000000}, + }, + "TW": { + ID: "TW", + Name: "Taiwan", + Region: "AS-E", + ContinentCode: "AS", + Center: Coordinates{Latitude: 23.000000, Longitude: 120.000000}, + }, + "SA": { + ID: "SA", + Name: "Saudi Arabia", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 23.000000, Longitude: 45.000000}, + }, + "CO": { + ID: "CO", + Name: "Colombia", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: 4.000000, Longitude: -74.000000}, + }, + "FR": { + ID: "FR", + Name: "France", + Region: "EU-W", + ContinentCode: "EU", + Center: Coordinates{Latitude: 46.000000, Longitude: 2.000000}, + }, + "WF": { + ID: "WF", + Name: "Wallis and Futuna", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -13.000000, Longitude: -177.000000}, + }, + "QA": { + ID: "QA", + Name: "Qatar", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 25.000000, Longitude: 51.000000}, + }, + "IO": { + ID: "IO", + Name: "British Indian Ocean Territory", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -6.000000, Longitude: 71.000000}, + }, + "LT": { + ID: "LT", + Name: "Lithuania", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 55.000000, Longitude: 23.000000}, + }, + "IE": { + ID: "IE", + Name: "Ireland", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 53.000000, Longitude: -8.000000}, + }, + "GW": { + ID: "GW", + Name: "Guinea-Bissau", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 11.000000, Longitude: -15.000000}, + }, + "PE": { + ID: "PE", + Name: "Peru", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -9.000000, Longitude: -75.000000}, + }, + "MA": { + ID: "MA", + Name: "Morocco", + Region: "AF-N", + ContinentCode: "AF", + Center: Coordinates{Latitude: 31.000000, Longitude: -7.000000}, + }, + "CR": { + ID: "CR", + Name: "Costa Rica", + Region: "NA-S", + ContinentCode: "NA", + Center: Coordinates{Latitude: 9.000000, Longitude: -83.000000}, + }, + "FK": { + ID: "FK", + Name: "Falkland Islands (Malvinas)", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -51.000000, Longitude: -59.000000}, + }, + "PW": { + ID: "PW", + Name: "Palau", + Region: "OC-N", + ContinentCode: "OC", + Center: Coordinates{Latitude: 7.000000, Longitude: 134.000000}, + }, + "NC": { + ID: "NC", + Name: "New Caledonia", + Region: "OC-C", + ContinentCode: "OC", + Center: Coordinates{Latitude: -20.000000, Longitude: 165.000000}, + }, + "AM": { + ID: "AM", + Name: "Armenia", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 40.000000, Longitude: 45.000000}, + }, + "CU": { + ID: "CU", + Name: "Cuba", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 21.000000, Longitude: -77.000000}, + }, + "DE": { + ID: "DE", + Name: "Germany", + Region: "EU-W", + ContinentCode: "EU", + Center: Coordinates{Latitude: 51.000000, Longitude: 10.000000}, + }, + "MT": { + ID: "MT", + Name: "Malta", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 35.000000, Longitude: 14.000000}, + }, + "YE": { + ID: "YE", + Name: "Yemen", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 15.000000, Longitude: 48.000000}, + }, + "BA": { + ID: "BA", + Name: "Bosnia and Herzegovina", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 43.000000, Longitude: 17.000000}, + }, + "MP": { + ID: "MP", + Name: "Northern Mariana Islands", + Region: "OC-N", + ContinentCode: "OC", + Center: Coordinates{Latitude: 17.000000, Longitude: 145.000000}, + }, + "PY": { + ID: "PY", + Name: "Paraguay", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -23.000000, Longitude: -58.000000}, + }, + "MO": { + ID: "MO", + Name: "Macao", + Region: "AS-E", + ContinentCode: "AS", + Center: Coordinates{Latitude: 22.000000, Longitude: 113.000000}, + }, + "SH": { + ID: "SH", + Name: "Saint Helena", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: -24.000000, Longitude: -10.000000}, + }, + "PN": { + ID: "PN", + Name: "Pitcairn", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -24.000000, Longitude: -127.000000}, + }, + "GM": { + ID: "GM", + Name: "Gambia", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 13.000000, Longitude: -15.000000}, + }, + "TG": { + ID: "TG", + Name: "Togo", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 8.000000, Longitude: 0.000000}, + }, + "AT": { + ID: "AT", + Name: "Austria", + Region: "EU-W", + ContinentCode: "EU", + Center: Coordinates{Latitude: 47.000000, Longitude: 14.000000}, + }, + "GT": { + ID: "GT", + Name: "Guatemala", + Region: "NA-S", + ContinentCode: "NA", + Center: Coordinates{Latitude: 15.000000, Longitude: -90.000000}, + }, + "AE": { + ID: "AE", + Name: "United Arab Emirates", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 23.000000, Longitude: 53.000000}, + }, + "KR": { + ID: "KR", + Name: "South Korea", + Region: "AS-E", + ContinentCode: "AS", + Center: Coordinates{Latitude: 35.000000, Longitude: 127.000000}, + }, + "JE": { + ID: "JE", + Name: "Jersey", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 49.000000, Longitude: -2.000000}, + }, + "LV": { + ID: "LV", + Name: "Latvia", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 56.000000, Longitude: 24.000000}, + }, + "AW": { + ID: "AW", + Name: "Aruba", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 12.000000, Longitude: -69.000000}, + }, + "AO": { + ID: "AO", + Name: "Angola", + Region: "AF-C", + ContinentCode: "AF", + Center: Coordinates{Latitude: -11.000000, Longitude: 17.000000}, + }, + "VE": { + ID: "VE", + Name: "Venezuela", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: 6.000000, Longitude: -66.000000}, + }, + "AG": { + ID: "AG", + Name: "Antigua and Barbuda", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 17.000000, Longitude: -61.000000}, + }, + "NU": { + ID: "NU", + Name: "Niue", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -19.000000, Longitude: -169.000000}, + }, + "KY": { + ID: "KY", + Name: "Cayman Islands", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 19.000000, Longitude: -80.000000}, + }, + "IM": { + ID: "IM", + Name: "Isle of Man", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 54.000000, Longitude: -4.000000}, + }, + "FM": { + ID: "FM", + Name: "Micronesia", + Region: "OC-N", + ContinentCode: "OC", + Center: Coordinates{Latitude: 7.000000, Longitude: 150.000000}, + }, + "SB": { + ID: "SB", + Name: "Solomon Islands", + Region: "OC-C", + ContinentCode: "OC", + Center: Coordinates{Latitude: -9.000000, Longitude: 160.000000}, + }, + "LU": { + ID: "LU", + Name: "Luxembourg", + Region: "EU-W", + ContinentCode: "EU", + Center: Coordinates{Latitude: 49.000000, Longitude: 6.000000}, + }, + "MF": { + ID: "MF", + Name: "Saint Martin", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 18.000000, Longitude: -63.000000}, + }, + "AQ": { + ID: "AQ", + Name: "Antarctica", + Region: "AN", + ContinentCode: "AN", + Center: Coordinates{Latitude: -75.000000, Longitude: 0.000000}, + }, + "SC": { + ID: "SC", + Name: "Seychelles", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -4.000000, Longitude: 55.000000}, + }, + "TL": { + ID: "TL", + Name: "Timor-Leste", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: -8.000000, Longitude: 125.000000}, + }, + "CC": { + ID: "CC", + Name: "Cocos (Keeling) Islands", + Region: "OC-S", + ContinentCode: "OC", + Center: Coordinates{Latitude: -12.000000, Longitude: 96.000000}, + }, + "ST": { + ID: "ST", + Name: "Sao Tome and Principe", + Region: "AF-C", + ContinentCode: "AF", + Center: Coordinates{Latitude: 0.000000, Longitude: 6.000000}, + }, + "NO": { + ID: "NO", + Name: "Norway", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 60.000000, Longitude: 8.000000}, + }, + "CF": { + ID: "CF", + Name: "Central African Republic", + Region: "AF-C", + ContinentCode: "AF", + Center: Coordinates{Latitude: 6.000000, Longitude: 20.000000}, + }, + "MR": { + ID: "MR", + Name: "Mauritania", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 21.000000, Longitude: -10.000000}, + }, + "NI": { + ID: "NI", + Name: "Nicaragua", + Region: "NA-S", + ContinentCode: "NA", + Center: Coordinates{Latitude: 12.000000, Longitude: -85.000000}, + }, + "AI": { + ID: "AI", + Name: "Anguilla", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 18.000000, Longitude: -63.000000}, + }, + "AZ": { + ID: "AZ", + Name: "Azerbaijan", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 40.000000, Longitude: 47.000000}, + }, + "US": { + ID: "US", + Name: "United States of America", + Region: "NA-N", + ContinentCode: "NA", + Center: Coordinates{Latitude: 37.000000, Longitude: -95.000000}, + }, + "LA": { + ID: "LA", + Name: "Lao", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 19.000000, Longitude: 102.000000}, + }, + "BB": { + ID: "BB", + Name: "Barbados", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 13.000000, Longitude: -59.000000}, + }, + "CD": { + ID: "CD", + Name: "DR Congo", + Region: "AF-C", + ContinentCode: "AF", + Center: Coordinates{Latitude: -4.000000, Longitude: 21.000000}, + }, + "TK": { + ID: "TK", + Name: "Tokelau", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -8.000000, Longitude: -171.000000}, + }, + "KZ": { + ID: "KZ", + Name: "Kazakhstan", + Region: "AS-C", + ContinentCode: "AS", + Center: Coordinates{Latitude: 48.000000, Longitude: 66.000000}, + }, + "DM": { + ID: "DM", + Name: "Dominica", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 15.000000, Longitude: -61.000000}, + }, + "EG": { + ID: "EG", + Name: "Egypt", + Region: "AF-N", + ContinentCode: "AF", + Center: Coordinates{Latitude: 26.000000, Longitude: 30.000000}, + }, + "GH": { + ID: "GH", + Name: "Ghana", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 7.000000, Longitude: -1.000000}, + }, + "BI": { + ID: "BI", + Name: "Burundi", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -3.000000, Longitude: 29.000000}, + }, + "NZ": { + ID: "NZ", + Name: "New Zealand", + Region: "OC-S", + ContinentCode: "OC", + Center: Coordinates{Latitude: -40.000000, Longitude: 174.000000}, + }, + "BJ": { + ID: "BJ", + Name: "Benin", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 9.000000, Longitude: 2.000000}, + }, + "HU": { + ID: "HU", + Name: "Hungary", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 47.000000, Longitude: 19.000000}, + }, + "BD": { + ID: "BD", + Name: "Bangladesh", + Region: "AS-S", + ContinentCode: "AS", + Center: Coordinates{Latitude: 23.000000, Longitude: 90.000000}, + }, + "NF": { + ID: "NF", + Name: "Norfolk Island", + Region: "OC-S", + ContinentCode: "OC", + Center: Coordinates{Latitude: -29.000000, Longitude: 167.000000}, + }, + "LY": { + ID: "LY", + Name: "Libya", + Region: "AF-N", + ContinentCode: "AF", + Center: Coordinates{Latitude: 26.000000, Longitude: 17.000000}, + }, + "TV": { + ID: "TV", + Name: "Tuvalu", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -7.000000, Longitude: 177.000000}, + }, + "ZW": { + ID: "ZW", + Name: "Zimbabwe", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -19.000000, Longitude: 29.000000}, + }, + "NG": { + ID: "NG", + Name: "Nigeria", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 9.000000, Longitude: 8.000000}, + }, + "GD": { + ID: "GD", + Name: "Grenada", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 12.000000, Longitude: -61.000000}, + }, + "SM": { + ID: "SM", + Name: "San Marino", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 43.000000, Longitude: 12.000000}, + }, + "RU": { + ID: "RU", + Name: "Russian Federation", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 61.000000, Longitude: 105.000000}, + }, + "DZ": { + ID: "DZ", + Name: "Algeria", + Region: "AF-N", + ContinentCode: "AF", + Center: Coordinates{Latitude: 28.000000, Longitude: 1.000000}, + }, + "DO": { + ID: "DO", + Name: "Dominican Republic", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 18.000000, Longitude: -70.000000}, + }, + "SI": { + ID: "SI", + Name: "Slovenia", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 46.000000, Longitude: 14.000000}, + }, + "BZ": { + ID: "BZ", + Name: "Belize", + Region: "NA-S", + ContinentCode: "NA", + Center: Coordinates{Latitude: 17.000000, Longitude: -88.000000}, + }, + "DJ": { + ID: "DJ", + Name: "Djibouti", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: 11.000000, Longitude: 42.000000}, + }, + "GN": { + ID: "GN", + Name: "Guinea", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 9.000000, Longitude: -9.000000}, + }, + "VN": { + ID: "VN", + Name: "Viet Nam", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 14.000000, Longitude: 108.000000}, + }, + "IR": { + ID: "IR", + Name: "Iran", + Region: "AS-S", + ContinentCode: "AS", + Center: Coordinates{Latitude: 32.000000, Longitude: 53.000000}, + }, + "KG": { + ID: "KG", + Name: "Kyrgyzstan", + Region: "AS-C", + ContinentCode: "AS", + Center: Coordinates{Latitude: 41.000000, Longitude: 74.000000}, + }, + "ML": { + ID: "ML", + Name: "Mali", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 17.000000, Longitude: -3.000000}, + }, + "GP": { + ID: "GP", + Name: "Guadeloupe", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 16.000000, Longitude: -62.000000}, + }, + "FI": { + ID: "FI", + Name: "Finland", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 61.000000, Longitude: 25.000000}, + }, + "UA": { + ID: "UA", + Name: "Ukraine", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 48.000000, Longitude: 31.000000}, + }, + "KP": { + ID: "KP", + Name: "North Korea (DPRK)", + Region: "AS-E", + ContinentCode: "AS", + Center: Coordinates{Latitude: 40.000000, Longitude: 127.000000}, + }, + "BT": { + ID: "BT", + Name: "Bhutan", + Region: "AS-S", + ContinentCode: "AS", + Center: Coordinates{Latitude: 27.000000, Longitude: 90.000000}, + }, + "BG": { + ID: "BG", + Name: "Bulgaria", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 42.000000, Longitude: 25.000000}, + }, + "MM": { + ID: "MM", + Name: "Myanmar", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 21.000000, Longitude: 95.000000}, + }, + "PK": { + ID: "PK", + Name: "Pakistan", + Region: "AS-S", + ContinentCode: "AS", + Center: Coordinates{Latitude: 30.000000, Longitude: 69.000000}, + }, + "KI": { + ID: "KI", + Name: "Kiribati", + Region: "OC-N", + ContinentCode: "OC", + Center: Coordinates{Latitude: -3.000000, Longitude: -168.000000}, + }, + "GL": { + ID: "GL", + Name: "Greenland", + Region: "NA-N", + ContinentCode: "NA", + Center: Coordinates{Latitude: 71.000000, Longitude: -42.000000}, + }, + "PG": { + ID: "PG", + Name: "Papua New Guinea", + Region: "OC-C", + ContinentCode: "OC", + Center: Coordinates{Latitude: -6.000000, Longitude: 143.000000}, + }, + "PF": { + ID: "PF", + Name: "French Polynesia", + Region: "OC-E", + ContinentCode: "OC", + Center: Coordinates{Latitude: -17.000000, Longitude: -149.000000}, + }, + "VU": { + ID: "VU", + Name: "Vanuatu", + Region: "OC-C", + ContinentCode: "OC", + Center: Coordinates{Latitude: -15.000000, Longitude: 166.000000}, + }, + "HT": { + ID: "HT", + Name: "Haiti", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 18.000000, Longitude: -72.000000}, + }, + "SV": { + ID: "SV", + Name: "El Salvador", + Region: "NA-S", + ContinentCode: "NA", + Center: Coordinates{Latitude: 13.000000, Longitude: -88.000000}, + }, + "EC": { + ID: "EC", + Name: "Ecuador", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -1.000000, Longitude: -78.000000}, + }, + "KM": { + ID: "KM", + Name: "Comoros", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -11.000000, Longitude: 43.000000}, + }, + "VI": { + ID: "VI", + Name: "Virgin Islands (U.S.)", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 18.000000, Longitude: -64.000000}, + }, + "YT": { + ID: "YT", + Name: "Mayotte", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -12.000000, Longitude: 45.000000}, + }, + "ET": { + ID: "ET", + Name: "Ethiopia", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: 9.000000, Longitude: 40.000000}, + }, + "JO": { + ID: "JO", + Name: "Jordan", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 30.000000, Longitude: 36.000000}, + }, + "RE": { + ID: "RE", + Name: "Réunion", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -21.000000, Longitude: 55.000000}, + }, + "NR": { + ID: "NR", + Name: "Nauru", + Region: "OC-N", + ContinentCode: "OC", + Center: Coordinates{Latitude: 0.000000, Longitude: 166.000000}, + }, + "HK": { + ID: "HK", + Name: "Hong Kong", + Region: "AS-E", + ContinentCode: "AS", + Center: Coordinates{Latitude: 22.000000, Longitude: 114.000000}, + }, + "AU": { + ID: "AU", + Name: "Australia", + Region: "OC-S", + ContinentCode: "OC", + Center: Coordinates{Latitude: -25.000000, Longitude: 133.000000}, + }, + "FO": { + ID: "FO", + Name: "Faroe Islands", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 61.000000, Longitude: -6.000000}, + }, + "IQ": { + ID: "IQ", + Name: "Iraq", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 33.000000, Longitude: 43.000000}, + }, + "GE": { + ID: "GE", + Name: "Georgia", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 42.000000, Longitude: 43.000000}, + }, + "UZ": { + ID: "UZ", + Name: "Uzbekistan", + Region: "AS-C", + ContinentCode: "AS", + Center: Coordinates{Latitude: 41.000000, Longitude: 64.000000}, + }, + "IN": { + ID: "IN", + Name: "India", + Region: "AS-S", + ContinentCode: "AS", + Center: Coordinates{Latitude: 20.000000, Longitude: 78.000000}, + }, + "MX": { + ID: "MX", + Name: "Mexico", + Region: "NA-S", + ContinentCode: "NA", + Center: Coordinates{Latitude: 23.000000, Longitude: -102.000000}, + }, + "ER": { + ID: "ER", + Name: "Eritrea", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: 15.000000, Longitude: 39.000000}, + }, + "AL": { + ID: "AL", + Name: "Albania", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 41.000000, Longitude: 20.000000}, + }, + "GY": { + ID: "GY", + Name: "Guyana", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: 4.000000, Longitude: -58.000000}, + }, + "CA": { + ID: "CA", + Name: "Canada", + Region: "NA-N", + ContinentCode: "NA", + Center: Coordinates{Latitude: 56.000000, Longitude: -106.000000}, + }, + "SY": { + ID: "SY", + Name: "Syrian Arab Republic", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 34.000000, Longitude: 38.000000}, + }, + "SG": { + ID: "SG", + Name: "Singapore", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 1.000000, Longitude: 103.000000}, + }, + "VG": { + ID: "VG", + Name: "Virgin Islands (British)", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 18.000000, Longitude: -64.000000}, + }, + "MC": { + ID: "MC", + Name: "Monaco", + Region: "EU-W", + ContinentCode: "EU", + Center: Coordinates{Latitude: 43.000000, Longitude: 7.000000}, + }, + "BM": { + ID: "BM", + Name: "Bermuda", + Region: "NA-N", + ContinentCode: "NA", + Center: Coordinates{Latitude: 32.000000, Longitude: -64.000000}, + }, + "SX": { + ID: "SX", + Name: "Sint Maarten", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 18.000000, Longitude: -63.000000}, + }, + "SR": { + ID: "SR", + Name: "Suriname", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: 3.000000, Longitude: -56.000000}, + }, + "MD": { + ID: "MD", + Name: "Moldova", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 47.000000, Longitude: 28.000000}, + }, + "CZ": { + ID: "CZ", + Name: "Czechia", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 49.000000, Longitude: 15.000000}, + }, + "GQ": { + ID: "GQ", + Name: "Equatorial Guinea", + Region: "AF-C", + ContinentCode: "AF", + Center: Coordinates{Latitude: 1.000000, Longitude: 10.000000}, + }, + "TF": { + ID: "TF", + Name: "French Southern Territories", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -49.000000, Longitude: 69.000000}, + }, + "CI": { + ID: "CI", + Name: "Côte d'Ivoire", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 7.000000, Longitude: -5.000000}, + }, + "VA": { + ID: "VA", + Name: "Holy See", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 41.000000, Longitude: 12.000000}, + }, + "SN": { + ID: "SN", + Name: "Senegal", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 14.000000, Longitude: -14.000000}, + }, + "PR": { + ID: "PR", + Name: "Puerto Rico", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 18.000000, Longitude: -66.000000}, + }, + "ID": { + ID: "ID", + Name: "Indonesia", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 0.000000, Longitude: 113.000000}, + }, + "BS": { + ID: "BS", + Name: "Bahamas", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 25.000000, Longitude: -77.000000}, + }, + "CV": { + ID: "CV", + Name: "Cabo Verde", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 16.000000, Longitude: -24.000000}, + }, + "AD": { + ID: "AD", + Name: "Andorra", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 42.000000, Longitude: 1.000000}, + }, + "SK": { + ID: "SK", + Name: "Slovakia", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 48.000000, Longitude: 19.000000}, + }, + "MV": { + ID: "MV", + Name: "Maldives", + Region: "AS-S", + ContinentCode: "AS", + Center: Coordinates{Latitude: 3.000000, Longitude: 73.000000}, + }, + "ME": { + ID: "ME", + Name: "Montenegro", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 42.000000, Longitude: 19.000000}, + }, + "LK": { + ID: "LK", + Name: "Sri Lanka", + Region: "AS-S", + ContinentCode: "AS", + Center: Coordinates{Latitude: 7.000000, Longitude: 80.000000}, + }, + "KH": { + ID: "KH", + Name: "Cambodia", + Region: "AS-SE", + ContinentCode: "AS", + Center: Coordinates{Latitude: 12.000000, Longitude: 104.000000}, + }, + "GR": { + ID: "GR", + Name: "Greece", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 39.000000, Longitude: 21.000000}, + }, + "SL": { + ID: "SL", + Name: "Sierra Leone", + Region: "AF-W", + ContinentCode: "AF", + Center: Coordinates{Latitude: 8.000000, Longitude: -11.000000}, + }, + "XK": { + ID: "XK", + Name: "Kosovo", + Region: "EU-E", + ContinentCode: "EU", + Center: Coordinates{Latitude: 42.000000, Longitude: 20.000000}, + }, + "TJ": { + ID: "TJ", + Name: "Tajikistan", + Region: "AS-C", + ContinentCode: "AS", + Center: Coordinates{Latitude: 38.000000, Longitude: 71.000000}, + }, + "SE": { + ID: "SE", + Name: "Sweden", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 60.000000, Longitude: 18.000000}, + }, + "GA": { + ID: "GA", + Name: "Gabon", + Region: "AF-C", + ContinentCode: "AF", + Center: Coordinates{Latitude: 0.000000, Longitude: 11.000000}, + }, + "UY": { + ID: "UY", + Name: "Uruguay", + Region: "SA", + ContinentCode: "SA", + Center: Coordinates{Latitude: -32.000000, Longitude: -55.000000}, + }, + "MZ": { + ID: "MZ", + Name: "Mozambique", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -18.000000, Longitude: 35.000000}, + }, + "PA": { + ID: "PA", + Name: "Panama", + Region: "NA-S", + ContinentCode: "NA", + Center: Coordinates{Latitude: 8.000000, Longitude: -80.000000}, + }, + "SZ": { + ID: "SZ", + Name: "Eswatini", + Region: "AF-S", + ContinentCode: "AF", + Center: Coordinates{Latitude: -26.000000, Longitude: 31.000000}, + }, + "IL": { + ID: "IL", + Name: "Israel", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 31.000000, Longitude: 34.000000}, + }, + "GB": { + ID: "GB", + Name: "United Kingdom", + Region: "EU-N", + ContinentCode: "EU", + Center: Coordinates{Latitude: 55.000000, Longitude: -3.000000}, + }, + "ES": { + ID: "ES", + Name: "Spain", + Region: "EU-S", + ContinentCode: "EU", + Center: Coordinates{Latitude: 40.000000, Longitude: -3.000000}, + }, + "RW": { + ID: "RW", + Name: "Rwanda", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: -1.000000, Longitude: 29.000000}, + }, + "EH": { + ID: "EH", + Name: "Western Sahara", + Region: "AF-N", + ContinentCode: "AF", + Center: Coordinates{Latitude: 24.000000, Longitude: -12.000000}, + }, + "MH": { + ID: "MH", + Name: "Marshall Islands", + Region: "OC-N", + ContinentCode: "OC", + Center: Coordinates{Latitude: 7.000000, Longitude: 171.000000}, + }, + "MQ": { + ID: "MQ", + Name: "Martinique", + Region: "NA-E", + ContinentCode: "NA", + Center: Coordinates{Latitude: 14.000000, Longitude: -61.000000}, + }, + "CH": { + ID: "CH", + Name: "Switzerland", + Region: "EU-W", + ContinentCode: "EU", + Center: Coordinates{Latitude: 46.000000, Longitude: 8.000000}, + }, + "CN": { + ID: "CN", + Name: "China", + Region: "AS-E", + ContinentCode: "AS", + Center: Coordinates{Latitude: 35.000000, Longitude: 104.000000}, + }, + "TR": { + ID: "TR", + Name: "Turkey", + Region: "AS-W", + ContinentCode: "AS", + Center: Coordinates{Latitude: 38.000000, Longitude: 35.000000}, + }, + "BW": { + ID: "BW", + Name: "Botswana", + Region: "AF-S", + ContinentCode: "AF", + Center: Coordinates{Latitude: -22.000000, Longitude: 24.000000}, + }, + "SS": { + ID: "SS", + Name: "South Sudan", + Region: "AF-E", + ContinentCode: "AF", + Center: Coordinates{Latitude: 4.000000, Longitude: 31.000000}, + }, +} diff --git a/intel/geoip/country_info_test.go b/intel/geoip/country_info_test.go new file mode 100644 index 000000000..544ff440b --- /dev/null +++ b/intel/geoip/country_info_test.go @@ -0,0 +1,43 @@ +package geoip + +import ( + "testing" +) + +func TestCountryInfo(t *testing.T) { + t.Parallel() + + for key, country := range countries { + if key != country.ID { + t.Errorf("%s has a wrong ID of %q", key, country.ID) + } + if country.Name == "" { + t.Errorf("%s is missing name", key) + } + if country.Region == "" { + t.Errorf("%s is missing region", key) + } + if country.ContinentCode == "" { + t.Errorf("%s is missing continent", key) + } + if country.Center.Latitude == 0 && country.Center.Longitude == 0 { + t.Errorf("%s is missing coords", key) + } + + // Generate map source from data: + // fmt.Printf( + // `"%s": {Name:%q,Region:%q,ContinentCode:%q,Center:Coordinates{AccuracyRadius:%d,Latitude:%f,Longitude:%f},},`, + // key, + // country.Name, + // country.Region, + // country.ContinentCode, + // country.Center.AccuracyRadius, + // country.Center.Latitude, + // country.Center.Longitude, + // ) + // fmt.Println() + } + if len(countries) < 247 { + t.Errorf("dataset only includes %d countries", len(countries)) + } +} diff --git a/intel/geoip/fill_missing.go b/intel/geoip/fill_missing.go deleted file mode 100644 index 624a2d5e6..000000000 --- a/intel/geoip/fill_missing.go +++ /dev/null @@ -1,264 +0,0 @@ -package geoip - -const defaultCountryBasedAccuracy = 200 - -// FillMissingInfo tries to fill missing location information based on the -// available existing information. -func (l *Location) FillMissingInfo() { - // Get coordinates from country. - if l.Coordinates.Latitude == 0 && - l.Coordinates.Longitude == 0 && - l.Country.ISOCode != "" { - if c, ok := countryCoordinates[l.Country.ISOCode]; ok { - l.Coordinates = c - l.Coordinates.AccuracyRadius = defaultCountryBasedAccuracy - } - } -} - -var countryCoordinates = map[string]Coordinates{ - "AD": {Latitude: 42, Longitude: 1}, - "AE": {Latitude: 23, Longitude: 53}, - "AF": {Latitude: 33, Longitude: 67}, - "AG": {Latitude: 17, Longitude: -61}, - "AI": {Latitude: 18, Longitude: -63}, - "AL": {Latitude: 41, Longitude: 20}, - "AM": {Latitude: 40, Longitude: 45}, - "AN": {Latitude: 12, Longitude: -69}, - "AO": {Latitude: -11, Longitude: 17}, - "AQ": {Latitude: -75, Longitude: -0}, - "AR": {Latitude: -38, Longitude: -63}, - "AS": {Latitude: -14, Longitude: -170}, - "AT": {Latitude: 47, Longitude: 14}, - "AU": {Latitude: -25, Longitude: 133}, - "AW": {Latitude: 12, Longitude: -69}, - "AZ": {Latitude: 40, Longitude: 47}, - "BA": {Latitude: 43, Longitude: 17}, - "BB": {Latitude: 13, Longitude: -59}, - "BD": {Latitude: 23, Longitude: 90}, - "BE": {Latitude: 50, Longitude: 4}, - "BF": {Latitude: 12, Longitude: -1}, - "BG": {Latitude: 42, Longitude: 25}, - "BH": {Latitude: 25, Longitude: 50}, - "BI": {Latitude: -3, Longitude: 29}, - "BJ": {Latitude: 9, Longitude: 2}, - "BM": {Latitude: 32, Longitude: -64}, - "BN": {Latitude: 4, Longitude: 114}, - "BO": {Latitude: -16, Longitude: -63}, - "BR": {Latitude: -14, Longitude: -51}, - "BS": {Latitude: 25, Longitude: -77}, - "BT": {Latitude: 27, Longitude: 90}, - "BV": {Latitude: -54, Longitude: 3}, - "BW": {Latitude: -22, Longitude: 24}, - "BY": {Latitude: 53, Longitude: 27}, - "BZ": {Latitude: 17, Longitude: -88}, - "CA": {Latitude: 56, Longitude: -106}, - "CC": {Latitude: -12, Longitude: 96}, - "CD": {Latitude: -4, Longitude: 21}, - "CF": {Latitude: 6, Longitude: 20}, - "CG": {Latitude: -0, Longitude: 15}, - "CH": {Latitude: 46, Longitude: 8}, - "CI": {Latitude: 7, Longitude: -5}, - "CK": {Latitude: -21, Longitude: -159}, - "CL": {Latitude: -35, Longitude: -71}, - "CM": {Latitude: 7, Longitude: 12}, - "CN": {Latitude: 35, Longitude: 104}, - "CO": {Latitude: 4, Longitude: -74}, - "CR": {Latitude: 9, Longitude: -83}, - "CU": {Latitude: 21, Longitude: -77}, - "CV": {Latitude: 16, Longitude: -24}, - "CX": {Latitude: -10, Longitude: 105}, - "CY": {Latitude: 35, Longitude: 33}, - "CZ": {Latitude: 49, Longitude: 15}, - "DE": {Latitude: 51, Longitude: 10}, - "DJ": {Latitude: 11, Longitude: 42}, - "DK": {Latitude: 56, Longitude: 9}, - "DM": {Latitude: 15, Longitude: -61}, - "DO": {Latitude: 18, Longitude: -70}, - "DZ": {Latitude: 28, Longitude: 1}, - "EC": {Latitude: -1, Longitude: -78}, - "EE": {Latitude: 58, Longitude: 25}, - "EG": {Latitude: 26, Longitude: 30}, - "EH": {Latitude: 24, Longitude: -12}, - "ER": {Latitude: 15, Longitude: 39}, - "ES": {Latitude: 40, Longitude: -3}, - "ET": {Latitude: 9, Longitude: 40}, - "FI": {Latitude: 61, Longitude: 25}, - "FJ": {Latitude: -16, Longitude: 179}, - "FK": {Latitude: -51, Longitude: -59}, - "FM": {Latitude: 7, Longitude: 150}, - "FO": {Latitude: 61, Longitude: -6}, - "FR": {Latitude: 46, Longitude: 2}, - "GA": {Latitude: -0, Longitude: 11}, - "GB": {Latitude: 55, Longitude: -3}, - "GD": {Latitude: 12, Longitude: -61}, - "GE": {Latitude: 42, Longitude: 43}, - "GF": {Latitude: 3, Longitude: -53}, - "GG": {Latitude: 49, Longitude: -2}, - "GH": {Latitude: 7, Longitude: -1}, - "GI": {Latitude: 36, Longitude: -5}, - "GL": {Latitude: 71, Longitude: -42}, - "GM": {Latitude: 13, Longitude: -15}, - "GN": {Latitude: 9, Longitude: -9}, - "GP": {Latitude: 16, Longitude: -62}, - "GQ": {Latitude: 1, Longitude: 10}, - "GR": {Latitude: 39, Longitude: 21}, - "GS": {Latitude: -54, Longitude: -36}, - "GT": {Latitude: 15, Longitude: -90}, - "GU": {Latitude: 13, Longitude: 144}, - "GW": {Latitude: 11, Longitude: -15}, - "GY": {Latitude: 4, Longitude: -58}, - "GZ": {Latitude: 31, Longitude: 34}, - "HK": {Latitude: 22, Longitude: 114}, - "HM": {Latitude: -53, Longitude: 73}, - "HN": {Latitude: 15, Longitude: -86}, - "HR": {Latitude: 45, Longitude: 15}, - "HT": {Latitude: 18, Longitude: -72}, - "HU": {Latitude: 47, Longitude: 19}, - "ID": {Latitude: -0, Longitude: 113}, - "IE": {Latitude: 53, Longitude: -8}, - "IL": {Latitude: 31, Longitude: 34}, - "IM": {Latitude: 54, Longitude: -4}, - "IN": {Latitude: 20, Longitude: 78}, - "IO": {Latitude: -6, Longitude: 71}, - "IQ": {Latitude: 33, Longitude: 43}, - "IR": {Latitude: 32, Longitude: 53}, - "IS": {Latitude: 64, Longitude: -19}, - "IT": {Latitude: 41, Longitude: 12}, - "JE": {Latitude: 49, Longitude: -2}, - "JM": {Latitude: 18, Longitude: -77}, - "JO": {Latitude: 30, Longitude: 36}, - "JP": {Latitude: 36, Longitude: 138}, - "KE": {Latitude: -0, Longitude: 37}, - "KG": {Latitude: 41, Longitude: 74}, - "KH": {Latitude: 12, Longitude: 104}, - "KI": {Latitude: -3, Longitude: -168}, - "KM": {Latitude: -11, Longitude: 43}, - "KN": {Latitude: 17, Longitude: -62}, - "KP": {Latitude: 40, Longitude: 127}, - "KR": {Latitude: 35, Longitude: 127}, - "KW": {Latitude: 29, Longitude: 47}, - "KY": {Latitude: 19, Longitude: -80}, - "KZ": {Latitude: 48, Longitude: 66}, - "LA": {Latitude: 19, Longitude: 102}, - "LB": {Latitude: 33, Longitude: 35}, - "LC": {Latitude: 13, Longitude: -60}, - "LI": {Latitude: 47, Longitude: 9}, - "LK": {Latitude: 7, Longitude: 80}, - "LR": {Latitude: 6, Longitude: -9}, - "LS": {Latitude: -29, Longitude: 28}, - "LT": {Latitude: 55, Longitude: 23}, - "LU": {Latitude: 49, Longitude: 6}, - "LV": {Latitude: 56, Longitude: 24}, - "LY": {Latitude: 26, Longitude: 17}, - "MA": {Latitude: 31, Longitude: -7}, - "MC": {Latitude: 43, Longitude: 7}, - "MD": {Latitude: 47, Longitude: 28}, - "ME": {Latitude: 42, Longitude: 19}, - "MG": {Latitude: -18, Longitude: 46}, - "MH": {Latitude: 7, Longitude: 171}, - "MK": {Latitude: 41, Longitude: 21}, - "ML": {Latitude: 17, Longitude: -3}, - "MM": {Latitude: 21, Longitude: 95}, - "MN": {Latitude: 46, Longitude: 103}, - "MO": {Latitude: 22, Longitude: 113}, - "MP": {Latitude: 17, Longitude: 145}, - "MQ": {Latitude: 14, Longitude: -61}, - "MR": {Latitude: 21, Longitude: -10}, - "MS": {Latitude: 16, Longitude: -62}, - "MT": {Latitude: 35, Longitude: 14}, - "MU": {Latitude: -20, Longitude: 57}, - "MV": {Latitude: 3, Longitude: 73}, - "MW": {Latitude: -13, Longitude: 34}, - "MX": {Latitude: 23, Longitude: -102}, - "MY": {Latitude: 4, Longitude: 101}, - "MZ": {Latitude: -18, Longitude: 35}, - "NA": {Latitude: -22, Longitude: 18}, - "NC": {Latitude: -20, Longitude: 165}, - "NE": {Latitude: 17, Longitude: 8}, - "NF": {Latitude: -29, Longitude: 167}, - "NG": {Latitude: 9, Longitude: 8}, - "NI": {Latitude: 12, Longitude: -85}, - "NL": {Latitude: 52, Longitude: 5}, - "NO": {Latitude: 60, Longitude: 8}, - "NP": {Latitude: 28, Longitude: 84}, - "NR": {Latitude: -0, Longitude: 166}, - "NU": {Latitude: -19, Longitude: -169}, - "NZ": {Latitude: -40, Longitude: 174}, - "OM": {Latitude: 21, Longitude: 55}, - "PA": {Latitude: 8, Longitude: -80}, - "PE": {Latitude: -9, Longitude: -75}, - "PF": {Latitude: -17, Longitude: -149}, - "PG": {Latitude: -6, Longitude: 143}, - "PH": {Latitude: 12, Longitude: 121}, - "PK": {Latitude: 30, Longitude: 69}, - "PL": {Latitude: 51, Longitude: 19}, - "PM": {Latitude: 46, Longitude: -56}, - "PN": {Latitude: -24, Longitude: -127}, - "PR": {Latitude: 18, Longitude: -66}, - "PS": {Latitude: 31, Longitude: 35}, - "PT": {Latitude: 39, Longitude: -8}, - "PW": {Latitude: 7, Longitude: 134}, - "PY": {Latitude: -23, Longitude: -58}, - "QA": {Latitude: 25, Longitude: 51}, - "RE": {Latitude: -21, Longitude: 55}, - "RO": {Latitude: 45, Longitude: 24}, - "RS": {Latitude: 44, Longitude: 21}, - "RU": {Latitude: 61, Longitude: 105}, - "RW": {Latitude: -1, Longitude: 29}, - "SA": {Latitude: 23, Longitude: 45}, - "SB": {Latitude: -9, Longitude: 160}, - "SC": {Latitude: -4, Longitude: 55}, - "SD": {Latitude: 12, Longitude: 30}, - "SE": {Latitude: 60, Longitude: 18}, - "SG": {Latitude: 1, Longitude: 103}, - "SH": {Latitude: -24, Longitude: -10}, - "SI": {Latitude: 46, Longitude: 14}, - "SJ": {Latitude: 77, Longitude: 23}, - "SK": {Latitude: 48, Longitude: 19}, - "SL": {Latitude: 8, Longitude: -11}, - "SM": {Latitude: 43, Longitude: 12}, - "SN": {Latitude: 14, Longitude: -14}, - "SO": {Latitude: 5, Longitude: 46}, - "SR": {Latitude: 3, Longitude: -56}, - "ST": {Latitude: 0, Longitude: 6}, - "SV": {Latitude: 13, Longitude: -88}, - "SY": {Latitude: 34, Longitude: 38}, - "SZ": {Latitude: -26, Longitude: 31}, - "TC": {Latitude: 21, Longitude: -71}, - "TD": {Latitude: 15, Longitude: 18}, - "TF": {Latitude: -49, Longitude: 69}, - "TG": {Latitude: 8, Longitude: 0}, - "TH": {Latitude: 15, Longitude: 100}, - "TJ": {Latitude: 38, Longitude: 71}, - "TK": {Latitude: -8, Longitude: -171}, - "TL": {Latitude: -8, Longitude: 125}, - "TM": {Latitude: 38, Longitude: 59}, - "TN": {Latitude: 33, Longitude: 9}, - "TO": {Latitude: -21, Longitude: -175}, - "TR": {Latitude: 38, Longitude: 35}, - "TT": {Latitude: 10, Longitude: -61}, - "TV": {Latitude: -7, Longitude: 177}, - "TW": {Latitude: 23, Longitude: 120}, - "TZ": {Latitude: -6, Longitude: 34}, - "UA": {Latitude: 48, Longitude: 31}, - "UG": {Latitude: 1, Longitude: 32}, - "US": {Latitude: 37, Longitude: -95}, - "UY": {Latitude: -32, Longitude: -55}, - "UZ": {Latitude: 41, Longitude: 64}, - "VA": {Latitude: 41, Longitude: 12}, - "VC": {Latitude: 12, Longitude: -61}, - "VE": {Latitude: 6, Longitude: -66}, - "VG": {Latitude: 18, Longitude: -64}, - "VI": {Latitude: 18, Longitude: -64}, - "VN": {Latitude: 14, Longitude: 108}, - "VU": {Latitude: -15, Longitude: 166}, - "WF": {Latitude: -13, Longitude: -177}, - "WS": {Latitude: -13, Longitude: -172}, - "XK": {Latitude: 42, Longitude: 20}, - "YE": {Latitude: 15, Longitude: 48}, - "YT": {Latitude: -12, Longitude: 45}, - "ZA": {Latitude: -30, Longitude: 22}, - "ZM": {Latitude: -13, Longitude: 27}, - "ZW": {Latitude: -19, Longitude: 29}, -} diff --git a/intel/geoip/location.go b/intel/geoip/location.go index 585f3e0d5..281a32622 100644 --- a/intel/geoip/location.go +++ b/intel/geoip/location.go @@ -22,6 +22,7 @@ type Location struct { Code string `maxminddb:"code"` } `maxminddb:"continent"` Country struct { + Name string ISOCode string `maxminddb:"iso_code"` } `maxminddb:"country"` Coordinates Coordinates `maxminddb:"location"` diff --git a/intel/geoip/lookup.go b/intel/geoip/lookup.go index d6f76f87a..da69fa26f 100644 --- a/intel/geoip/lookup.go +++ b/intel/geoip/lookup.go @@ -23,8 +23,7 @@ func GetLocation(ip net.IP) (*Location, error) { return nil, err } - record.FillMissingInfo() - record.AddRegion() + record.AddCountryInfo() return record, nil } diff --git a/intel/geoip/module.go b/intel/geoip/module.go index 0c15769a7..0c65f1af8 100644 --- a/intel/geoip/module.go +++ b/intel/geoip/module.go @@ -16,14 +16,14 @@ func init() { func prep() error { if err := api.RegisterEndpoint(api.Endpoint{ - Path: "intel/geoip/country-centers", + Path: "intel/geoip/countries", Read: api.PermitUser, // Do not attach to module, as the data is always available anyway. StructFunc: func(ar *api.Request) (i interface{}, err error) { - return countryCoordinates, nil + return countries, nil }, - Name: "Get Geographic Country Centers", - Description: "Returns a map of country centers indexed by ISO-A2 country code", + Name: "Get Country Information", + Description: "Returns a map of country information centers indexed by ISO-A2 country code", }); err != nil { return err } diff --git a/intel/geoip/regions.go b/intel/geoip/regions.go index cbaa3ee09..53d608ede 100644 --- a/intel/geoip/regions.go +++ b/intel/geoip/regions.go @@ -4,13 +4,6 @@ import ( "github.com/safing/portbase/utils" ) -// AddRegion adds the region based on the country. -func (l *Location) AddRegion() { - if regionID, ok := countryRegions[l.Country.ISOCode]; ok { - l.Continent.Code = regionID - } -} - // IsRegionalNeighbor returns whether the supplied location is a regional neighbor. func (l *Location) IsRegionalNeighbor(other *Location) bool { if l.Continent.Code == "" || other.Continent.Code == "" { @@ -250,255 +243,3 @@ var regions = map[string]*Region{ }, }, } - -var countryRegions = map[string]string{ - "AF": "AS-S", - "AX": "EU-N", - "AL": "EU-S", - "DZ": "AF-N", - "AS": "OC-E", - "AD": "EU-S", - "AO": "AF-C", - "AI": "NA-E", - "AQ": "AN", - "AG": "NA-E", - "AR": "SA", - "AM": "AS-W", - "AW": "NA-E", - "AU": "OC-S", - "AT": "EU-W", - "AZ": "AS-W", - "BS": "NA-E", - "BH": "AS-W", - "BD": "AS-S", - "BB": "NA-E", - "BY": "EU-E", - "BE": "EU-W", - "BZ": "NA-S", - "BJ": "AF-W", - "BM": "NA-N", - "BT": "AS-S", - "BO": "SA", - "BQ": "NA-E", - "BA": "EU-S", - "BW": "AF-S", - "BV": "SA", - "BR": "SA", - "IO": "AF-E", - "BN": "AS-SE", - "BG": "EU-E", - "BF": "AF-W", - "BI": "AF-E", - "CV": "AF-W", - "KH": "AS-SE", - "CM": "AF-C", - "CA": "NA-N", - "KY": "NA-E", - "CF": "AF-C", - "TD": "AF-C", - "CL": "SA", - "CN": "AS-E", - "CX": "OC-S", - "CC": "OC-S", - "CO": "SA", - "KM": "AF-E", - "CG": "AF-C", - "CD": "AF-C", - "CK": "OC-E", - "CR": "NA-S", - "CI": "AF-W", - "HR": "EU-S", - "CU": "NA-E", - "CW": "NA-E", - "CY": "AS-W", - "CZ": "EU-E", - "DK": "EU-N", - "DJ": "AF-E", - "DM": "NA-E", - "DO": "NA-E", - "EC": "SA", - "EG": "AF-N", - "SV": "NA-S", - "GQ": "AF-C", - "ER": "AF-E", - "EE": "EU-N", - "SZ": "AF-S", - "ET": "AF-E", - "FK": "SA", - "FO": "EU-N", - "FJ": "OC-C", - "FI": "EU-N", - "FR": "EU-W", - "GF": "SA", - "PF": "OC-E", - "TF": "AF-E", - "GA": "AF-C", - "GM": "AF-W", - "GE": "AS-W", - "DE": "EU-W", - "GH": "AF-W", - "GI": "EU-S", - "GR": "EU-S", - "GL": "NA-N", - "GD": "NA-E", - "GP": "NA-E", - "GU": "OC-N", - "GT": "NA-S", - "GG": "EU-N", - "GN": "AF-W", - "GW": "AF-W", - "GY": "SA", - "HT": "NA-E", - "HM": "OC-S", - "VA": "EU-S", - "HN": "NA-S", - "HK": "AS-E", - "HU": "EU-E", - "IS": "EU-N", - "IN": "AS-S", - "ID": "AS-SE", - "IR": "AS-S", - "IQ": "AS-W", - "IE": "EU-N", - "IM": "EU-N", - "IL": "AS-W", - "IT": "EU-S", - "JM": "NA-E", - "JP": "AS-E", - "JE": "EU-N", - "JO": "AS-W", - "KZ": "AS-C", - "KE": "AF-E", - "KI": "OC-N", - "KP": "AS-E", - "KR": "AS-E", - "KW": "AS-W", - "KG": "AS-C", - "LA": "AS-SE", - "LV": "EU-N", - "LB": "AS-W", - "LS": "AF-S", - "LR": "AF-W", - "LY": "AF-N", - "LI": "EU-W", - "LT": "EU-N", - "LU": "EU-W", - "MO": "AS-E", - "MG": "AF-E", - "MW": "AF-E", - "MY": "AS-SE", - "MV": "AS-S", - "ML": "AF-W", - "MT": "EU-S", - "MH": "OC-N", - "MQ": "NA-E", - "MR": "AF-W", - "MU": "AF-E", - "YT": "AF-E", - "MX": "NA-S", - "FM": "OC-N", - "MD": "EU-E", - "MC": "EU-W", - "MN": "AS-E", - "ME": "EU-S", - "MS": "NA-E", - "MA": "AF-N", - "MZ": "AF-E", - "MM": "AS-SE", - "NA": "AF-S", - "NR": "OC-N", - "NP": "AS-S", - "NL": "EU-W", - "NC": "OC-C", - "NZ": "OC-S", - "NI": "NA-S", - "NE": "AF-W", - "NG": "AF-W", - "NU": "OC-E", - "NF": "OC-S", - "MK": "EU-S", - "MP": "OC-N", - "NO": "EU-N", - "OM": "AS-W", - "PK": "AS-S", - "PW": "OC-N", - "PS": "AS-W", - "PA": "NA-S", - "PG": "OC-C", - "PY": "SA", - "PE": "SA", - "PH": "AS-SE", - "PN": "OC-E", - "PL": "EU-E", - "PT": "EU-S", - "PR": "NA-E", - "QA": "AS-W", - "RE": "AF-E", - "RO": "EU-E", - "RU": "EU-E", - "RW": "AF-E", - "BL": "NA-E", - "SH": "AF-W", - "KN": "NA-E", - "LC": "NA-E", - "MF": "NA-E", - "PM": "NA-N", - "VC": "NA-E", - "WS": "OC-E", - "SM": "EU-S", - "ST": "AF-C", - "SA": "AS-W", - "SN": "AF-W", - "RS": "EU-S", - "SC": "AF-E", - "SL": "AF-W", - "SG": "AS-SE", - "SX": "NA-E", - "SK": "EU-E", - "SI": "EU-S", - "SB": "OC-C", - "SO": "AF-E", - "ZA": "AF-S", - "GS": "SA", - "SS": "AF-E", - "ES": "EU-S", - "LK": "AS-S", - "SD": "AF-N", - "SR": "SA", - "SJ": "EU-N", - "SE": "EU-N", - "CH": "EU-W", - "SY": "AS-W", - "TW": "AS-E", - "TJ": "AS-C", - "TZ": "AF-E", - "TH": "AS-SE", - "TL": "AS-SE", - "TG": "AF-W", - "TK": "OC-E", - "TO": "OC-E", - "TT": "NA-E", - "TN": "AF-N", - "TR": "AS-W", - "TM": "AS-C", - "TC": "NA-E", - "TV": "OC-E", - "UG": "AF-E", - "UA": "EU-E", - "AE": "AS-W", - "GB": "EU-N", - "US": "NA-N", - "UM": "OC-N", - "UY": "SA", - "UZ": "AS-C", - "VU": "OC-C", - "VE": "SA", - "VN": "AS-SE", - "VG": "NA-E", - "VI": "NA-E", - "WF": "OC-E", - "EH": "AF-N", - "YE": "AS-W", - "ZM": "AF-E", - "ZW": "AF-E", -} diff --git a/profile/config.go b/profile/config.go index 782d46739..eaaf3ea57 100644 --- a/profile/config.go +++ b/profile/config.go @@ -160,19 +160,9 @@ var securityLevelSettings = []string{ } var ( - // SPNRulesQuickSettings is a list of countries the SPN currently is present in - // as quick settings in order to help users with SPN related policy settings. - // This is a quick win to make the MVP easier to use, but will be replaced by - // a better solution in the future. + // SPNRulesQuickSettings are now generated automatically shorty after start. SPNRulesQuickSettings = []config.QuickSetting{ - {Name: "Exclude Canada (CA)", Action: config.QuickMergeTop, Value: []string{"- CA"}}, - {Name: "Exclude Finland (FI)", Action: config.QuickMergeTop, Value: []string{"- FI"}}, - {Name: "Exclude France (FR)", Action: config.QuickMergeTop, Value: []string{"- FR"}}, - {Name: "Exclude Germany (DE)", Action: config.QuickMergeTop, Value: []string{"- DE"}}, - {Name: "Exclude Israel (IL)", Action: config.QuickMergeTop, Value: []string{"- IL"}}, - {Name: "Exclude Poland (PL)", Action: config.QuickMergeTop, Value: []string{"- PL"}}, - {Name: "Exclude United Kingdom (GB)", Action: config.QuickMergeTop, Value: []string{"- GB"}}, - {Name: "Exclude United States of America (US)", Action: config.QuickMergeTop, Value: []string{"- US"}}, + {Name: "Loading...", Action: config.QuickMergeTop, Value: []string{""}}, } // SPNRulesVerdictNames defines the verdicts names to be used for SPN Rules. @@ -733,7 +723,6 @@ Please note that if you are using the system resolver, bypass attempts might be Sensitive: true, OptType: config.OptTypeStringArray, ExpertiseLevel: config.ExpertiseLevelExpert, - ReleaseLevel: config.ReleaseLevelBeta, DefaultValue: []string{}, Annotations: config.Annotations{ config.StackableAnnotation: true, diff --git a/profile/profile.go b/profile/profile.go index 1838e5341..42a39738a 100644 --- a/profile/profile.go +++ b/profile/profile.go @@ -461,7 +461,7 @@ func (profile *Profile) updateMetadata(binaryPath string) (changed bool) { changed = true } - // Migrato to Fingerprints. + // Migrate to Fingerprints. // TODO: Remove in v1.5 if len(profile.Fingerprints) == 0 && profile.LinkedPath != "" { profile.Fingerprints = []Fingerprint{ From e5baae9bd07181f9e640eac87acf6cf6117f576f Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 23 Aug 2023 14:50:04 +0200 Subject: [PATCH 7/9] Implement review suggestions --- network/dns.go | 2 +- process/process.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/network/dns.go b/network/dns.go index b1f729c75..4f481b320 100644 --- a/network/dns.go +++ b/network/dns.go @@ -87,7 +87,7 @@ func GetDNSRequestConnection(packetInfo *packet.Info) (conn *Connection, ok bool defer dnsRequestConnectionsLock.RUnlock() conn, ok = dnsRequestConnections[key] - return + return conn, ok } // deleteDNSRequestConnection removes a connection from the dns request connections. diff --git a/process/process.go b/process/process.go index 934c195c3..cb34ae325 100644 --- a/process/process.go +++ b/process/process.go @@ -112,8 +112,8 @@ func (p *Process) IsIdentified() bool { } } -// IsLocal returns whether the process has been identified as a local process. -func (p *Process) IsLocal() bool { +// HasValidPID returns whether the process has valid PID of an actual process. +func (p *Process) HasValidPID() bool { // Check if process exists. if p == nil { return false From 07995b7a4fe11b24ae7fc49228c065ce6ae7d66c Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 24 Aug 2023 09:45:53 +0200 Subject: [PATCH 8/9] Remove config option from privacy filter subsystem --- firewall/config.go | 20 ++++++++++++++++++-- firewall/module.go | 14 +------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/firewall/config.go b/firewall/config.go index ea1785b3b..4e3ca653c 100644 --- a/firewall/config.go +++ b/firewall/config.go @@ -13,6 +13,7 @@ import ( // Configuration Keys. var ( CfgOptionEnableFilterKey = "filter/enable" + filterEnabled config.BoolOption CfgOptionAskWithSystemNotificationsKey = "filter/askWithSystemNotifications" cfgOptionAskWithSystemNotificationsOrder = 2 @@ -33,6 +34,23 @@ var ( func registerConfig() error { err := config.Register(&config.Option{ + Name: "Enable Privacy Filter", + Key: CfgOptionEnableFilterKey, + Description: "Enable the Privacy Filter. If turned off, all privacy filter protections are fully disabled on this device. Not meant to be disabled in production - only turn off for testing.", + OptType: config.OptTypeBool, + ExpertiseLevel: config.ExpertiseLevelDeveloper, + ReleaseLevel: config.ReleaseLevelExperimental, + DefaultValue: true, + Annotations: config.Annotations{ + config.CategoryAnnotation: "General", + }, + }) + if err != nil { + return err + } + filterEnabled = config.Concurrent.GetAsBool(CfgOptionEnableFilterKey, true) + + err = config.Register(&config.Option{ Name: "Permanent Verdicts", Key: CfgOptionPermanentVerdictsKey, Description: "The Portmaster's system integration intercepts every single packet. Usually the first packet is enough for the Portmaster to set the verdict for a connection - ie. to allow or deny it. Making these verdicts permanent means that the Portmaster will tell the system integration that is does not want to see any more packets of that single connection. This brings a major performance increase.", @@ -118,7 +136,6 @@ var ( devMode config.BoolOption apiListenAddress config.StringOption - filterEnabled config.BoolOption tunnelEnabled config.BoolOption useCommunityNodes config.BoolOption @@ -129,7 +146,6 @@ func getConfig() { devMode = config.Concurrent.GetAsBool(core.CfgDevModeKey, false) apiListenAddress = config.GetAsString(api.CfgDefaultListenAddressKey, "") - filterEnabled = config.Concurrent.GetAsBool(CfgOptionEnableFilterKey, true) tunnelEnabled = config.Concurrent.GetAsBool(captain.CfgOptionEnableSPNKey, false) useCommunityNodes = config.Concurrent.GetAsBool(captain.CfgOptionUseCommunityNodesKey, true) diff --git a/firewall/module.go b/firewall/module.go index 1e9925b5f..999c3888d 100644 --- a/firewall/module.go +++ b/firewall/module.go @@ -3,7 +3,6 @@ package firewall import ( "context" - "github.com/safing/portbase/config" "github.com/safing/portbase/log" "github.com/safing/portbase/modules" "github.com/safing/portbase/modules/subsystems" @@ -22,18 +21,7 @@ func init() { "DNS and Network Filter", module, "config:filter/", - &config.Option{ - Name: "Privacy Filter Module", - Key: CfgOptionEnableFilterKey, - Description: "Start the Privacy Filter module. If turned off, all privacy filter protections are fully disabled on this device.", - OptType: config.OptTypeBool, - ExpertiseLevel: config.ExpertiseLevelDeveloper, - ReleaseLevel: config.ReleaseLevelStable, - DefaultValue: true, - Annotations: config.Annotations{ - config.CategoryAnnotation: "General", - }, - }, + nil, ) } From 3657470e789d778d708f51b805d082649e527428 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 24 Aug 2023 09:46:57 +0200 Subject: [PATCH 9/9] Update deps --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index e612f5f89..482857a90 100644 --- a/go.mod +++ b/go.mod @@ -18,9 +18,9 @@ require ( github.com/miekg/dns v1.1.55 github.com/oschwald/maxminddb-golang v1.12.0 github.com/safing/jess v0.3.1 - github.com/safing/portbase v0.17.1 + github.com/safing/portbase v0.17.2 github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626 - github.com/safing/spn v0.6.15 + github.com/safing/spn v0.6.16 github.com/shirou/gopsutil v3.21.11+incompatible github.com/spf13/cobra v1.7.0 github.com/spkg/zipfs v0.7.1 @@ -52,7 +52,7 @@ require ( github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index 2bedc52f6..c373ec710 100644 --- a/go.sum +++ b/go.sum @@ -105,8 +105,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= @@ -208,12 +208,12 @@ github.com/safing/jess v0.3.1 h1:cMZVhi2whW/YdD98MPLeLIWJndQ7o2QVt2HefQ/ByFA= github.com/safing/jess v0.3.1/go.mod h1:aj73Eot1zm2ETkJuw9hJlIO8bRom52uBbsCHemvlZmA= github.com/safing/portbase v0.15.2/go.mod h1:5bHi99fz7Hh/wOsZUOI631WF9ePSHk57c4fdlOMS91Y= github.com/safing/portbase v0.16.2/go.mod h1:mzNCWqPbO7vIYbbK5PElGbudwd2vx4YPNawymL8Aro8= -github.com/safing/portbase v0.17.1 h1:q2aNHjJw4aoqTqKOxZpxRhYCciHw1exZ7lfGuB78i1E= -github.com/safing/portbase v0.17.1/go.mod h1:1cVgDZIsPiqM5b+K88Kshir5PGIvsftYkx7y1x925+8= +github.com/safing/portbase v0.17.2 h1:HzJkURMmXkv30wMHB7xJ+Z5U5aTMe+EzvlHavKoKkos= +github.com/safing/portbase v0.17.2/go.mod h1:1cVgDZIsPiqM5b+K88Kshir5PGIvsftYkx7y1x925+8= github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626 h1:olc/REnUdpJN/Gmz8B030OxLpMYxyPDTrDILNEw0eKs= github.com/safing/portmaster-android/go v0.0.0-20230605085256-6abf4c495626/go.mod h1:abwyAQrZGemWbSh/aCD9nnkp0SvFFf/mGWkAbOwPnFE= -github.com/safing/spn v0.6.15 h1:NbjXjZNy6dgYjd36wa/teip9dHtjjzKKYWwsWaok9y4= -github.com/safing/spn v0.6.15/go.mod h1:Mh9bmkqFhO/dHNi9RWXzoXjQij893I4Lj8Wn4tQ0KZA= +github.com/safing/spn v0.6.16 h1:z80H3X6wjsmizjWgichqYRyw3hSVB7rJpsDUDL2EWo0= +github.com/safing/spn v0.6.16/go.mod h1:2CuZfJJazIYyMDrhiwX2eFal0urQyLiX8rXLvJiCTcw= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/seehuhn/fortuna v1.0.1 h1:lu9+CHsmR0bZnx5Ay646XvCSRJ8PJTi5UYJwDBX68H0=