mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-12 06:24:10 +01:00
79 lines
1.9 KiB
Go
79 lines
1.9 KiB
Go
// SPDX-FileCopyrightText: 2023 Free Mobile
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
package geoip
|
|
|
|
import (
|
|
"fmt"
|
|
"net/netip"
|
|
"strings"
|
|
|
|
"github.com/oschwald/maxminddb-golang/v2"
|
|
)
|
|
|
|
// GeoIterFunc is the required signature to iter a geo database.
|
|
type GeoIterFunc func(netip.Prefix, GeoInfo) error
|
|
|
|
// AsnIterFunc is the required signature to iter an asn database;
|
|
type AsnIterFunc func(netip.Prefix, ASNInfo) error
|
|
|
|
type geoDatabase interface {
|
|
Close()
|
|
IterASNDatabase(AsnIterFunc) error
|
|
IterGeoDatabase(GeoIterFunc) error
|
|
}
|
|
|
|
// openDatabase opens the provided database and closes the current
|
|
// one. Do nothing if the path is empty.
|
|
func (c *Component) openDatabase(which string, path string, notifySubscribers bool) error {
|
|
if path == "" {
|
|
return nil
|
|
}
|
|
c.r.Debug().Str("database", path).Msgf("opening %s database", which)
|
|
db, err := maxminddb.Open(path)
|
|
if err != nil {
|
|
c.r.Err(err).
|
|
Str("database", path).
|
|
Msgf("cannot open %s database", which)
|
|
return fmt.Errorf("cannot open %s database: %w", which, err)
|
|
}
|
|
newOne, err := getGeoDatabase(db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.db.lock.Lock()
|
|
defer c.db.lock.Unlock()
|
|
var oldOne geoDatabase
|
|
switch which {
|
|
case "asn":
|
|
oldOne = c.db.asn[path]
|
|
c.db.asn[path] = newOne
|
|
case "geo":
|
|
oldOne = c.db.geo[path]
|
|
c.db.geo[path] = newOne
|
|
}
|
|
c.metrics.databaseRefresh.WithLabelValues(which).Inc()
|
|
if oldOne != nil {
|
|
c.r.Debug().
|
|
Str("database", path).
|
|
Msgf("closing previous %s database", which)
|
|
oldOne.Close()
|
|
}
|
|
if notifySubscribers {
|
|
c.notifyDone.Add(1)
|
|
c.onOpenChan <- struct{}{}
|
|
c.notifyDone.Done()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// getGeoDatabase guesses the database format and instantiate the right one.
|
|
func getGeoDatabase(db *maxminddb.Reader) (geoDatabase, error) {
|
|
// We should looks at the fields, but instead we use metadata and default to
|
|
// Maxmind.
|
|
if strings.HasPrefix(db.Metadata.DatabaseType, "ipinfo ") {
|
|
return &ipinfoDB{db: db}, nil
|
|
}
|
|
return &maxmindDB{db: db}, nil
|
|
}
|