orchestrator: switch to github.com/oschwald/maxminddb-golang/v2

Also, remove the AS name, this is not used at all.
This commit is contained in:
Vincent Bernat
2025-08-02 15:54:54 +02:00
parent 3b353ea940
commit 0a10764cc9
8 changed files with 71 additions and 102 deletions

4
go.mod
View File

@@ -33,8 +33,9 @@ require (
github.com/openconfig/gnmi v0.14.0
github.com/openconfig/gnmic/pkg/api v0.1.9
github.com/opencontainers/image-spec v1.1.1
github.com/oschwald/maxminddb-golang v1.13.1
github.com/oschwald/maxminddb-golang/v2 v2.0.0-beta.8
github.com/osrg/gobgp/v3 v3.37.0
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
github.com/prometheus/client_golang v1.22.0
github.com/rs/zerolog v1.34.0
github.com/scrapli/scrapligo v1.3.3
@@ -152,7 +153,6 @@ require (
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/client_model v0.6.1 // indirect

4
go.sum
View File

@@ -332,8 +332,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/oschwald/maxminddb-golang/v2 v2.0.0-beta.8 h1:aM1/rO6p+XV+l+seD7UCtFZgsOefDTrFVLvPoZWjXZs=
github.com/oschwald/maxminddb-golang/v2 v2.0.0-beta.8/go.mod h1:Jts8ztuE0PkUwY7VCJyp6B68ujQfr6G9P5Dn3Yx9u6w=
github.com/osrg/gobgp/v3 v3.37.0 h1:+ObuOdvj7G7nxrT0fKFta+EAupdWf/q1WzbXydr8IOY=
github.com/osrg/gobgp/v3 v3.37.0/go.mod h1:kVHVFy1/fyZHJ8P32+ctvPeJogn9qKwa1YCeMRXXrP0=
github.com/pascaldekloe/name v1.0.1 h1:9lnXOHeqeHHnWLbKfH6X98+4+ETVqFqxN09UXSjcMb0=

View File

@@ -7,7 +7,7 @@ import (
"compress/gzip"
"context"
"encoding/csv"
"net"
"net/netip"
"os"
"path/filepath"
"strconv"
@@ -57,8 +57,8 @@ func (c *Component) networksCSVRefresher() {
networks := helpers.MustNewSubnetMap[NetworkAttributes](nil)
// Add content of all geoip databases
err := c.d.GeoIP.IterASNDatabases(func(subnet *net.IPNet, data geoip.ASNInfo) error {
subV6Str, err := helpers.SubnetMapParseKey(subnet.String())
err := c.d.GeoIP.IterASNDatabases(func(prefix netip.Prefix, data geoip.ASNInfo) error {
subV6Str, err := helpers.SubnetMapParseKey(prefix.String())
if err != nil {
return err
}
@@ -71,8 +71,8 @@ func (c *Component) networksCSVRefresher() {
c.r.Err(err).Msg("unable to iter over ASN databases")
return
}
err = c.d.GeoIP.IterGeoDatabases(func(subnet *net.IPNet, data geoip.GeoInfo) error {
subV6Str, err := helpers.SubnetMapParseKey(subnet.String())
err = c.d.GeoIP.IterGeoDatabases(func(prefix netip.Prefix, data geoip.GeoInfo) error {
subV6Str, err := helpers.SubnetMapParseKey(prefix.String())
if err != nil {
return err
}

View File

@@ -5,17 +5,17 @@ package geoip
import (
"fmt"
"net"
"net/netip"
"strings"
"github.com/oschwald/maxminddb-golang"
"github.com/oschwald/maxminddb-golang/v2"
)
// GeoIterFunc is the required signature to iter a geo database.
type GeoIterFunc func(*net.IPNet, GeoInfo) error
type GeoIterFunc func(netip.Prefix, GeoInfo) error
// AsnIterFunc is the required signature to iter an asn database;
type AsnIterFunc func(*net.IPNet, ASNInfo) error
type AsnIterFunc func(netip.Prefix, ASNInfo) error
type geoDatabase interface {
Close()

View File

@@ -14,10 +14,9 @@ type GeoInfo struct {
State string
}
// ASNInfo describes ASN data of an asn database.
// ASNInfo describes ASN data of an ASN database.
type ASNInfo struct {
ASNumber uint32
ASName string
}
// IterGeoDatabases iter all entries in all geo databases.

View File

@@ -6,41 +6,30 @@ package geoip
import (
"strconv"
"github.com/oschwald/maxminddb-golang"
"github.com/oschwald/maxminddb-golang/v2"
)
type ipinfoDBASN struct {
ASN string `maxminddb:"asn"`
ASName string `maxminddb:"as_name"`
}
type ipinfoDBCountry struct {
Country string `maxminddb:"country"`
Region string `maxminddb:"region"`
City string `maxminddb:"city"`
}
type ipinfoDB struct {
db *maxminddb.Reader
}
func (mmdb *ipinfoDB) IterASNDatabase(f AsnIterFunc) error {
it := mmdb.db.Networks()
maxminddb.SkipAliasedNetworks(it)
for it.Next() {
asnInfo := &ipinfoDBASN{}
subnet, err := it.Network(asnInfo)
for result := range mmdb.db.Networks() {
var asnStr string // They are stored as ASxxxx
if err != nil {
return err
// Get AS number, skip if not found
result.DecodePath(&asnStr, "asn")
if asnStr == "" {
continue
}
n, err := strconv.ParseUint(asnInfo.ASN[2:], 10, 32)
asn, err := strconv.ParseUint(asnStr[2:], 10, 32)
if err != nil {
return err
continue
}
if err := f(subnet, ASNInfo{
ASNumber: uint32(n),
ASName: asnInfo.ASName,
prefix := result.Prefix()
if err := f(prefix, ASNInfo{
ASNumber: uint32(asn),
}); err != nil {
return err
}
@@ -49,19 +38,19 @@ func (mmdb *ipinfoDB) IterASNDatabase(f AsnIterFunc) error {
}
func (mmdb *ipinfoDB) IterGeoDatabase(f GeoIterFunc) error {
it := mmdb.db.Networks()
maxminddb.SkipAliasedNetworks(it)
for it.Next() {
geoInfo := &ipinfoDBCountry{}
subnet, err := it.Network(geoInfo)
for result := range mmdb.db.Networks() {
var country, region, city string
if err != nil {
return err
}
if err := f(subnet, GeoInfo{
Country: geoInfo.Country,
State: geoInfo.Region,
City: geoInfo.City,
// Get country, region, and city
result.DecodePath(&country, "country")
result.DecodePath(&region, "region")
result.DecodePath(&city, "city")
prefix := result.Prefix()
if err := f(prefix, GeoInfo{
Country: country,
State: region,
City: city,
}); err != nil {
return err
}

View File

@@ -4,45 +4,27 @@
package geoip
import (
"github.com/oschwald/maxminddb-golang"
"github.com/oschwald/maxminddb-golang/v2"
)
type maxmindDBASN struct {
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
}
// for a list fields available, see: https://github.com/oschwald/geoip2-golang/blob/main/reader.go
type maxmindDBCountry struct {
Country struct {
IsoCode string `maxminddb:"iso_code"`
} `maxminddb:"country"`
City struct {
Names map[string]string `maxminddb:"names"`
} `maxminddb:"city"`
Subdivisions []struct {
IsoCode string `maxminddb:"iso_code"`
} `maxminddb:"subdivisions"`
}
type maxmindDB struct {
db *maxminddb.Reader
}
func (mmdb *maxmindDB) IterASNDatabase(f AsnIterFunc) error {
it := mmdb.db.Networks()
maxminddb.SkipAliasedNetworks(it)
for result := range mmdb.db.Networks() {
var asn uint32
for it.Next() {
asnInfo := &maxmindDBASN{}
subnet, err := it.Network(asnInfo)
if err != nil {
return err
// Get AS number, skip if not found
result.DecodePath(&asn, "autonomous_system_number")
if asn == 0 {
continue
}
if err := f(subnet, ASNInfo{
ASNumber: uint32(asnInfo.AutonomousSystemNumber),
ASName: asnInfo.AutonomousSystemOrganization,
prefix := result.Prefix()
if err := f(prefix, ASNInfo{
ASNumber: asn,
}); err != nil {
return err
}
@@ -51,25 +33,24 @@ func (mmdb *maxmindDB) IterASNDatabase(f AsnIterFunc) error {
}
func (mmdb *maxmindDB) IterGeoDatabase(f GeoIterFunc) error {
it := mmdb.db.Networks()
maxminddb.SkipAliasedNetworks(it)
for it.Next() {
geoInfo := &maxmindDBCountry{}
subnet, err := it.Network(geoInfo)
if err != nil {
return err
}
for result := range mmdb.db.Networks() {
var country string
var city string
var state string
if len(geoInfo.Subdivisions) > 0 {
state = geoInfo.Subdivisions[0].IsoCode
}
if err := f(subnet, GeoInfo{
Country: geoInfo.Country.IsoCode,
// Get country, city, and state. Skip if no country
result.DecodePath(&country, "country", "iso_code")
if country == "" {
continue
}
result.DecodePath(&city, "city", "names", "en")
result.DecodePath(&state, "subdivisions", "0", "iso_code")
prefix := result.Prefix()
if err := f(prefix, GeoInfo{
Country: country,
State: state,
City: geoInfo.City.Names["en"],
City: city,
}); err != nil {
return err
}

View File

@@ -4,7 +4,7 @@
package geoip
import (
"net"
"net/netip"
"path/filepath"
"testing"
@@ -55,10 +55,10 @@ func TestIterDatabase(t *testing.T) {
},
}
err := c.IterASNDatabases(func(n *net.IPNet, a ASNInfo) error {
err := c.IterASNDatabases(func(prefix netip.Prefix, a ASNInfo) error {
for i, h := range mustHave {
// found the IP
if n.Contains(net.ParseIP(h.IP)) {
if ip, err := netip.ParseAddr(h.IP); err == nil && prefix.Contains(ip) {
if h.ExpectedASN != 0 && a.ASNumber != h.ExpectedASN {
t.Errorf("expected ASN %d, got %d", h.ExpectedASN, a.ASNumber)
}
@@ -72,10 +72,10 @@ func TestIterDatabase(t *testing.T) {
t.Fatalf("IterASNDatabases() error:\n%+v", err)
}
err = c.IterGeoDatabases(func(n *net.IPNet, a GeoInfo) error {
err = c.IterGeoDatabases(func(prefix netip.Prefix, a GeoInfo) error {
for i, h := range mustHave {
// found the IP
if n.Contains(net.ParseIP(h.IP).To16()) {
if ip, err := netip.ParseAddr(h.IP); err == nil && prefix.Contains(ip) {
if h.ExpectedCountry != "" && a.Country != h.ExpectedCountry {
t.Errorf("expected Country %s, got %s", h.ExpectedCountry, a.Country)
}
@@ -112,12 +112,12 @@ func TestIterNonExistingDatabase(t *testing.T) {
t.Fatalf("New() error:\n%+v", err)
}
helpers.StartStop(t, c)
if err := c.IterASNDatabases(func(_ *net.IPNet, _ ASNInfo) error {
if err := c.IterASNDatabases(func(_ netip.Prefix, _ ASNInfo) error {
return nil
}); err != nil {
t.Fatalf("IterASNDatabases() error:\n%+v", err)
}
if err := c.IterGeoDatabases(func(_ *net.IPNet, _ GeoInfo) error {
if err := c.IterGeoDatabases(func(_ netip.Prefix, _ GeoInfo) error {
return nil
}); err != nil {
t.Fatalf("IterGeoDatabases() error:\n%+v", err)