Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ require (
github.com/moby/moby/client v0.1.1-0.20251116162601-e9ff10bf365a
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/nxadm/tail v1.4.11
github.com/oschwald/geoip2-golang v1.9.0
github.com/oschwald/maxminddb-golang v1.12.0
github.com/oschwald/maxminddb-golang/v2 v2.1.1
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_model v0.6.2
Expand All @@ -85,7 +84,7 @@ require (
golang.org/x/mod v0.28.0
golang.org/x/net v0.44.0
golang.org/x/sync v0.17.0
golang.org/x/sys v0.37.0
golang.org/x/sys v0.38.0
golang.org/x/text v0.29.0
golang.org/x/time v0.13.0
google.golang.org/grpc v1.74.2
Expand Down
10 changes: 4 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -458,10 +458,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/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc=
github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y=
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
github.com/oschwald/maxminddb-golang/v2 v2.1.1 h1:lA8FH0oOrM4u7mLvowq8IT6a3Q/qEnqRzLQn9eH5ojc=
github.com/oschwald/maxminddb-golang/v2 v2.1.1/go.mod h1:PLdx6PR+siSIoXqqy7C7r3SB3KZnhxWr1Dp6g0Hacl8=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/petar-dambovaliev/aho-corasick v0.0.0-20250424160509-463d218d4745 h1:Vpr4VgAizEgEZsaMohpw6JYDP+i9Of9dmdY4ufNP6HI=
Expand Down Expand Up @@ -719,8 +717,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand Down
5 changes: 2 additions & 3 deletions pkg/acquisition/modules/appsec/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"strings"
"time"

"github.com/oschwald/geoip2-golang"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"

Expand Down Expand Up @@ -61,7 +60,7 @@ func AppsecEventGenerationGeoIPEnrich(src *models.Source) error {
if err != nil {
return err
} else if asndata != nil {
record := asndata.(*geoip2.ASN)
record := asndata.(*exprhelpers.GeoIPASN)
src.AsName = record.AutonomousSystemOrganization
src.AsNumber = fmt.Sprintf("%d", record.AutonomousSystemNumber)
}
Expand All @@ -70,7 +69,7 @@ func AppsecEventGenerationGeoIPEnrich(src *models.Source) error {
if err != nil {
return err
} else if cityData != nil {
record := cityData.(*geoip2.City)
record := cityData.(*exprhelpers.GeoIPCity)
src.Cn = record.Country.IsoCode
src.Latitude = float32(record.Location.Latitude)
src.Longitude = float32(record.Location.Longitude)
Expand Down
6 changes: 2 additions & 4 deletions pkg/exprhelpers/expr_lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"net/url"
"time"

"github.com/oschwald/geoip2-golang"

"github.com/crowdsecurity/crowdsec/pkg/cticlient"
"github.com/crowdsecurity/crowdsec/pkg/cticlient/ctiexpr"
)
Expand Down Expand Up @@ -493,14 +491,14 @@ var exprFuncs = []exprCustomFunc{
name: "GeoIPEnrich",
function: GeoIPEnrich,
signature: []any{
new(func(string) *geoip2.City),
new(func(string) *GeoIPCity),
},
},
{
name: "GeoIPASNEnrich",
function: GeoIPASNEnrich,
signature: []any{
new(func(string) *geoip2.ASN),
new(func(string) *GeoIPASN),
},
},
{
Expand Down
96 changes: 84 additions & 12 deletions pkg/exprhelpers/geoip.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,81 @@ package exprhelpers

import (
"net"
"net/netip"
)

// This struct is lifted from geoip2-golang to avoid dependency and have better control over the names of the fields.
type GeoIPCity struct {
City struct {
Names map[string]string `maxminddb:"names"`
GeoNameID uint `maxminddb:"geoname_id"`
} `maxminddb:"city"`
Postal struct {
Code string `maxminddb:"code"`
} `maxminddb:"postal"`
Continent struct {
Names map[string]string `maxminddb:"names"`
Code string `maxminddb:"code"`
GeoNameID uint `maxminddb:"geoname_id"`
} `maxminddb:"continent"`
Subdivisions []struct {
Names map[string]string `maxminddb:"names"`
IsoCode string `maxminddb:"iso_code"`
GeoNameID uint `maxminddb:"geoname_id"`
} `maxminddb:"subdivisions"`
RepresentedCountry struct {
Names map[string]string `maxminddb:"names"`
IsoCode string `maxminddb:"iso_code"`
Type string `maxminddb:"type"`
GeoNameID uint `maxminddb:"geoname_id"`
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
} `maxminddb:"represented_country"`
Country struct {
Names map[string]string `maxminddb:"names"`
IsoCode string `maxminddb:"iso_code"`
GeoNameID uint `maxminddb:"geoname_id"`
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
} `maxminddb:"country"`
RegisteredCountry struct {
Names map[string]string `maxminddb:"names"`
IsoCode string `maxminddb:"iso_code"`
GeoNameID uint `maxminddb:"geoname_id"`
IsInEuropeanUnion bool `maxminddb:"is_in_european_union"`
} `maxminddb:"registered_country"`
Location struct {
TimeZone string `maxminddb:"time_zone"`
Latitude float64 `maxminddb:"latitude"`
Longitude float64 `maxminddb:"longitude"`
MetroCode uint `maxminddb:"metro_code"`
AccuracyRadius uint16 `maxminddb:"accuracy_radius"`
} `maxminddb:"location"`
Traits struct {
IsAnonymousProxy bool `maxminddb:"is_anonymous_proxy"`
IsAnycast bool `maxminddb:"is_anycast"`
IsSatelliteProvider bool `maxminddb:"is_satellite_provider"`
} `maxminddb:"traits"`
}

type GeoIPASN struct {
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
}

func GeoIPEnrich(params ...any) (any, error) {
if geoIPCityReader == nil {
return nil, nil
}

ip := params[0].(string)

parsedIP := net.ParseIP(ip)
parsedIP, err := netip.ParseAddr(ip)
if err != nil {
return nil, err
}

city := &GeoIPCity{}

city, err := geoIPCityReader.City(parsedIP)
err = geoIPCityReader.Lookup(parsedIP).Decode(city)
if err != nil {
return nil, err
}
Expand All @@ -22,14 +85,20 @@ func GeoIPEnrich(params ...any) (any, error) {
}

func GeoIPASNEnrich(params ...any) (any, error) {
if geoIPASNReader == nil {
if geoIPASNRangeReader == nil {
return nil, nil
}

ip := params[0].(string)

parsedIP := net.ParseIP(ip)
asn, err := geoIPASNReader.ASN(parsedIP)
parsedIP, err := netip.ParseAddr(ip)
if err != nil {
return nil, err
}

asn := &GeoIPASN{}

err = geoIPASNRangeReader.Lookup(parsedIP).Decode(asn)
if err != nil {
return nil, err
}
Expand All @@ -38,22 +107,25 @@ func GeoIPASNEnrich(params ...any) (any, error) {
}

func GeoIPRangeEnrich(params ...any) (any, error) {
if geoIPRangeReader == nil {
if geoIPASNRangeReader == nil {
return nil, nil
}

ip := params[0].(string)

var dummy interface{}

parsedIP := net.ParseIP(ip)
rangeIP, ok, err := geoIPRangeReader.LookupNetwork(parsedIP, &dummy)
parsedIP, err := netip.ParseAddr(ip)
if err != nil {
return nil, err
}

if !ok {
return nil, nil
// We need to convert back to net.IPNet for backwards compatibility
prefix := geoIPASNRangeReader.Lookup(parsedIP).Prefix().Masked()
addr := prefix.Addr()
bits, totalBits := prefix.Bits(), addr.BitLen()

rangeIP := &net.IPNet{
IP: addr.AsSlice(),
Mask: net.CIDRMask(bits, totalBits),
}

return rangeIP, nil
Expand Down
26 changes: 7 additions & 19 deletions pkg/exprhelpers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ import (
"github.com/cespare/xxhash/v2"
"github.com/davecgh/go-spew/spew"
"github.com/expr-lang/expr"
"github.com/oschwald/geoip2-golang"
"github.com/oschwald/maxminddb-golang"
"github.com/oschwald/maxminddb-golang/v2"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"github.com/umahmood/haversine"
Expand Down Expand Up @@ -63,9 +62,8 @@ func init() { //nolint:gochecknoinits
var keyValuePattern = regexp.MustCompile(`(?P<key>[^=\s]+)=(?:"(?P<quoted_value>[^"\\]*(?:\\.[^"\\]*)*)"|(?P<value>[^=\s]+)|\s*)`)

var (
geoIPCityReader *geoip2.Reader
geoIPASNReader *geoip2.Reader
geoIPRangeReader *maxminddb.Reader
geoIPCityReader *maxminddb.Reader
geoIPASNRangeReader *maxminddb.Reader
)

func GetExprOptions(ctx map[string]any) []expr.Option {
Expand All @@ -80,19 +78,13 @@ func GetExprOptions(ctx map[string]any) []expr.Option {
func GeoIPInit(datadir string) error {
var err error

geoIPCityReader, err = geoip2.Open(filepath.Join(datadir, "GeoLite2-City.mmdb"))
geoIPCityReader, err = maxminddb.Open(filepath.Join(datadir, "GeoLite2-City.mmdb"))
if err != nil {
log.Errorf("unable to open GeoLite2-City.mmdb : %s", err)
return err
}

geoIPASNReader, err = geoip2.Open(filepath.Join(datadir, "GeoLite2-ASN.mmdb"))
if err != nil {
log.Errorf("unable to open GeoLite2-ASN.mmdb : %s", err)
return err
}

geoIPRangeReader, err = maxminddb.Open(filepath.Join(datadir, "GeoLite2-ASN.mmdb"))
geoIPASNRangeReader, err = maxminddb.Open(filepath.Join(datadir, "GeoLite2-ASN.mmdb"))
if err != nil {
log.Errorf("unable to open GeoLite2-ASN.mmdb : %s", err)
return err
Expand All @@ -106,12 +98,8 @@ func GeoIPClose() {
geoIPCityReader.Close()
}

if geoIPASNReader != nil {
geoIPASNReader.Close()
}

if geoIPRangeReader != nil {
geoIPRangeReader.Close()
if geoIPASNRangeReader != nil {
geoIPASNRangeReader.Close()
}
}

Expand Down
5 changes: 2 additions & 3 deletions pkg/parser/enrich_geoip.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"net"
"strconv"

"github.com/oschwald/geoip2-golang"
log "github.com/sirupsen/logrus"

"github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
Expand Down Expand Up @@ -56,7 +55,7 @@ func GeoIpASN(field string, _ *pipeline.Event, plog *log.Entry) (map[string]stri
return nil, nil
}

record, ok := r.(*geoip2.ASN)
record, ok := r.(*exprhelpers.GeoIPASN)

if !ok {
return nil, nil
Expand Down Expand Up @@ -92,7 +91,7 @@ func GeoIpCity(field string, _ *pipeline.Event, plog *log.Entry) (map[string]str
return nil, nil
}

record, ok := r.(*geoip2.City)
record, ok := r.(*exprhelpers.GeoIPCity)

if !ok {
return nil, nil
Expand Down
Loading