From b472d3dbdbff9896b4f695e32884f0362183a92b Mon Sep 17 00:00:00 2001 From: Tomas Boros Date: Tue, 2 Dec 2025 13:39:13 +0100 Subject: [PATCH] plugin/geoip - Support for ISO 3166-2 subdivisions. (#7728) Metadata `geoip/subdivisions/code` now available if geoip plugin is used. Signed-off-by: Tomas Boros --- plugin/geoip/README.md | 1 + plugin/geoip/city.go | 13 +++++++++++++ plugin/geoip/geoip_test.go | 1 + 3 files changed, 15 insertions(+) diff --git a/plugin/geoip/README.md b/plugin/geoip/README.md index 0e2f388a9..f2b38b00a 100644 --- a/plugin/geoip/README.md +++ b/plugin/geoip/README.md @@ -141,6 +141,7 @@ A limited set of fields will be exported as labels, all values are stored using | `geoip/longitude` | `float64` | `0.1315` | Base 10, max available precision. | `geoip/timezone` | `string` | `Europe/London` | The timezone. | `geoip/postalcode` | `string` | `CB4` | The postal code. +| `geoip/subdivisions/code` | `string` | `ENG,TWH` | Comma separated [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-2) subdivision(region) codes, e.g. first level (province), second level (state). | `geoip/asn/number` | `uint` | `396982` | The autonomous system number. | `geoip/asn/org` | `string` | `GOOGLE-CLOUD-PLATFORM` | The autonomous system organization. diff --git a/plugin/geoip/city.go b/plugin/geoip/city.go index 2e5d9f7ea..4ebeaf66c 100644 --- a/plugin/geoip/city.go +++ b/plugin/geoip/city.go @@ -3,6 +3,7 @@ package geoip import ( "context" "strconv" + "strings" "github.com/coredns/coredns/plugin/metadata" @@ -30,6 +31,18 @@ func (g GeoIP) setCityMetadata(ctx context.Context, data *geoip2.City) { metadata.SetValueFunc(ctx, pluginName+"/country/code", func() string { return countryCode }) + + // Subdivisions represent administrative divisions (e.g., provinces, states) and are provided + // by the MaxMind database as a hierarchical list of up to 2 levels, ISO codes are set in metadata as + // a comma separated string, with the exact values provided by the database, even if those were empty strings. + subdivisionCodes := make([]string, 0, len(data.Subdivisions)) + for _, sub := range data.Subdivisions { + subdivisionCodes = append(subdivisionCodes, sub.IsoCode) + } + metadata.SetValueFunc(ctx, pluginName+"/subdivisions/code", func() string { + return strings.Join(subdivisionCodes, ",") + }) + isInEurope := strconv.FormatBool(data.Country.IsInEuropeanUnion) metadata.SetValueFunc(ctx, pluginName+"/country/is_in_european_union", func() string { return isInEurope diff --git a/plugin/geoip/geoip_test.go b/plugin/geoip/geoip_test.go index 7416f4c56..c851b3b7f 100644 --- a/plugin/geoip/geoip_test.go +++ b/plugin/geoip/geoip_test.go @@ -32,6 +32,7 @@ func TestMetadata(t *testing.T) { {"geoip/longitude", "0.1315", cityDBPath, "81.2.69.142"}, {"geoip/timezone", "Europe/London", cityDBPath, "81.2.69.142"}, {"geoip/postalcode", "CB4", cityDBPath, "81.2.69.142"}, + {"geoip/subdivisions/code", "ENG,CAM", cityDBPath, "81.2.69.142"}, // ASN database tests {"geoip/asn/number", "12345", asnDBPath, "81.2.69.142"},