Skip to content

Commit

Permalink
api: report, add support for geoip
Browse files Browse the repository at this point in the history
  • Loading branch information
gsanchietti committed Aug 23, 2024
1 parent 34e27a5 commit 7a87eb6
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 6 deletions.
9 changes: 9 additions & 0 deletions api/configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ type Configuration struct {
ValidSubscription bool `json:"valid_subscription"`

ReportDbUri string `json:"report_db_uri"`

GeoIPDbDir string `json:"geoip_db_dir"`
}

var Config = Configuration{}
Expand Down Expand Up @@ -251,4 +253,11 @@ func Init() {
logs.Logs.Println("[CRITICAL][ENV] REPORT_DB_URI variable is empty")
os.Exit(1)
}

// Assuming the file is named GeoLite2-Country.mmdb
if os.Getenv("GEOIP_DB_DIR") != "" {
Config.GeoIPDbDir = os.Getenv("GEOIP_DB_DIR")
} else {
Config.GeoIPDbDir = "."
}
}
9 changes: 9 additions & 0 deletions api/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,13 @@ while [ ! -e "$socket" ]; do
fi
done

if [ -n "$MAXMIND_LICENSE" ]; then
# Download GeoLite database
if [ ! -f GeoLite2-Country.mmdb ]; then
curl -v -L --fail --retry 5 --retry-max-time 120 \
'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key='$MAXMIND_LICENSE'&suffix=tar.gz' \
-o db.tar.gz && tar xvzf db.tar.gz --strip-components=1
fi
fi

exec "$@"
8 changes: 6 additions & 2 deletions api/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module github.com/NethServer/nethsecurity-controller/api

go 1.19
go 1.21

toolchain go1.22.6

require (
github.com/NethServer/nethsecurity-api v0.0.0-20230609091000-bf319035cafc
Expand All @@ -13,6 +15,7 @@ require (
github.com/jackc/pgx/v5 v5.6.0
github.com/mattn/go-sqlite3 v1.14.22
github.com/nqd/flat v0.2.0
github.com/oschwald/geoip2-golang v1.11.0
golang.org/x/crypto v0.17.0
)

Expand All @@ -36,13 +39,14 @@ require (
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/oschwald/maxminddb-golang v1.13.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
11 changes: 8 additions & 3 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISq
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48=
github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w=
github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU=
github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
Expand Down Expand Up @@ -229,8 +233,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI=
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
Expand Down Expand Up @@ -343,8 +348,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
Expand Down
4 changes: 4 additions & 0 deletions api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/NethServer/nethsecurity-controller/api/routines"
"github.com/NethServer/nethsecurity-controller/api/socket"
"github.com/NethServer/nethsecurity-controller/api/storage"
"github.com/NethServer/nethsecurity-controller/api/utils"
)

// @title NethSecurity Controller API Server
Expand Down Expand Up @@ -56,6 +57,9 @@ func main() {
// init socket connection
socket.Init()

// init geoip
utils.InitGeoIP()

// starts remote info loop
go routines.RefreshRemoteInfoLoop()

Expand Down
19 changes: 18 additions & 1 deletion api/methods/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
package methods

import (
"net"
"net/http"
"time"

"github.com/NethServer/nethsecurity-api/response"
"github.com/NethServer/nethsecurity-controller/api/logs"
"github.com/NethServer/nethsecurity-controller/api/models"
"github.com/NethServer/nethsecurity-controller/api/storage"
"github.com/NethServer/nethsecurity-controller/api/utils"
"github.com/fatih/structs"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v5"
Expand Down Expand Up @@ -180,12 +182,27 @@ func UpdateTsMalware(c *gin.Context) {
// CopyFrom can't handle conflict resolution, so use batch insert instead
batch := &pgx.Batch{}
for _, malware := range req.Data {
country := ""
// skip invalid objects
if malware.Timestamp == 0 || malware.Src == "" || malware.Dst == "" || malware.Category == "" || malware.Chain == "" {
logs.Logs.Println("[WARN][TSMALWARE] skipping invalid object")
continue
}
batch.Queue("INSERT INTO ts_malware (time, unit_id, src, dst, category, chain) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT DO NOTHING", time.Unix(malware.Timestamp, 0), unit_id, malware.Src, malware.Dst, malware.Category, malware.Chain)

// GeoIP info
if malware.Chain == "inp-wan" {
// Retrieve GeoIP country code for source when traffic is destined to the WAN
country = utils.GetCountryShort(malware.Src)
} else {
// Retrieve GeoIP country code for non-private IP when traffic is forwarded
if !net.ParseIP(malware.Dst).IsPrivate() {
country = utils.GetCountryShort(malware.Dst)
} else if !net.ParseIP(malware.Src).IsPrivate() {
country = utils.GetCountryShort(malware.Src)
}
}

batch.Queue("INSERT INTO ts_malware (time, unit_id, src, dst, category, chain, country) VALUES ($1, $2, $3, $4, $5, $6, $7) ON CONFLICT DO NOTHING", time.Unix(malware.Timestamp, 0), unit_id, malware.Src, malware.Dst, malware.Category, malware.Chain, country)
}
if batch.Len() != 0 {
err := dbpool.SendBatch(dbctx, batch).Close()
Expand Down
1 change: 1 addition & 0 deletions api/storage/report_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ CREATE TABLE IF NOT EXISTS ts_malware (
dst TEXT NOT NULL,
category TEXT NOT NULL,
chain TEXT NOT NULL,
country VARCHAR(2),
UNIQUE (time, unit_id),
CONSTRAINT fk_unit FOREIGN KEY(unit_id) REFERENCES units(id) ON DELETE CASCADE
);
Expand Down
48 changes: 48 additions & 0 deletions api/utils/geoip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2024 Nethesis S.r.l.
* http://www.nethesis.it - [email protected]
*
* SPDX-License-Identifier: GPL-2.0-only
*
* author: Giacomo Sanchietti <[email protected]>
*/

package utils

import (
"log"
"net"

"github.com/NethServer/nethsecurity-controller/api/configuration"
"github.com/NethServer/nethsecurity-controller/api/logs"
"github.com/oschwald/geoip2-golang"
)

var db *geoip2.Reader

func InitGeoIP() error {
var err error
// open geoip db, path from config, name is always the same: GeoLite2-Country.mmdb
db, err = geoip2.Open(configuration.Config.GeoIPDbDir + "/GeoLite2-Country.mmdb")

if err != nil {
logs.Logs.Println("[ERR][GEOIP] error reading geoip db file :" + err.Error())
return err
}

return nil
}

func GetCountryShort(ip string) string {
if ip == "" || db == nil {
return ""
}

// If you are using strings that may be invalid, check that ip is not nil
record, err := db.City(net.ParseIP(ip))
if err != nil {
log.Fatal(err)
}

return record.Country.IsoCode
}

0 comments on commit 7a87eb6

Please sign in to comment.