From 7ddcab8e1ccf3db3cc2527db76dbf3faa3c5e0ee Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Sat, 3 Aug 2024 15:43:48 +0000 Subject: [PATCH 01/24] isReady false after kernel signal caught --- internal/geoip/geoip_file.go | 4 ++++ internal/geoip/geoip_http.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/internal/geoip/geoip_file.go b/internal/geoip/geoip_file.go index ec08831..666e7f2 100644 --- a/internal/geoip/geoip_file.go +++ b/internal/geoip/geoip_file.go @@ -59,6 +59,10 @@ func (m *GeoIPFileClient) Bootstrap() { <-m.done() m.log.Info().Msg("internal abort() has been caught; initiate application closing...") + m.mu.Lock() + m.isReady = false + m.mu.Unlock() + m.destroy() } diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 046d736..387b91d 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -83,6 +83,10 @@ func (m *GeoIPHTTPClient) Bootstrap() { <-m.done() m.log.Info().Msg("internal abort() has been caught; initiate application closing...") + m.mu.Lock() + m.isReady = false + m.mu.Unlock() + m.destroy() } From 6c6b169ce22e6af1cbe8bad8cd743201c53f4491 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Sat, 3 Aug 2024 15:45:01 +0000 Subject: [PATCH 02/24] cache summary small fix --- internal/cache/cache.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/cache/cache.go b/internal/cache/cache.go index f0ebe51..7c7a744 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -21,8 +21,8 @@ const ( ) var zoneHumanize = map[cacheZone]string{ - defaultCache: "default cache", - quarantineCache: "quarantine cache", + defaultCache: "default", + quarantineCache: "quarantine", } type Cache struct { @@ -107,7 +107,8 @@ func (m *Cache) Bootstrap() { m.log.Info().Msg("internal abort() has been caught; initiate application closing...") for zone, cache := range m.pools { - m.log.Info().Msgf("Serving SUMMARY: DelHits %d, DelMiss %d, Coll %d, Hit %d, Miss %d", + m.log.Info().Msgf("Cache %s serving SUMMARY: DelHits %d, DelMiss %d, Coll %d, Hit %d, Miss %d", + zoneHumanize[zone], cache.Stats().DelHits, cache.Stats().DelMisses, cache.Stats().Collisions, cache.Stats().Hits, cache.Stats().Misses) From 8e34dc395737e6c5581b7b6b1f48b5ef05744ea4 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Sat, 3 Aug 2024 15:45:42 +0000 Subject: [PATCH 03/24] add cache api zone sorting --- internal/cache/api.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/cache/api.go b/internal/cache/api.go index 486dbd6..5f9151a 100644 --- a/internal/cache/api.go +++ b/internal/cache/api.go @@ -115,6 +115,10 @@ func (m *Cache) ApiStats() io.Reader { tb.Style().Options.SeparateRows = true + tb.SortBy([]table.SortBy{ + {Number: 0, Mode: table.Asc}, + }) + return buf } From ff840b36ae75f301acc5e26e91624344ac4aec67 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Sun, 4 Aug 2024 02:06:22 +0000 Subject: [PATCH 04/24] add maxmind database verification skip; small refatroing --- cmd/alice/flags.go | 4 ++++ internal/geoip/geoip_file.go | 32 ++++++++++++++++++-------------- internal/geoip/geoip_http.go | 31 ++++++++++++++++++------------- 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/cmd/alice/flags.go b/cmd/alice/flags.go index 3294b59..d51fd52 100644 --- a/cmd/alice/flags.go +++ b/cmd/alice/flags.go @@ -261,6 +261,10 @@ func flagsInitialization() []cli.Flag { Name: "geoip-download-sha256-skip", Category: "GeoIP", }, + &cli.BoolFlag{ + Name: "geoip-skip-database-verify", + DisableDefaultText: true, + }, // custom settings &cli.BoolFlag{ diff --git a/internal/geoip/geoip_file.go b/internal/geoip/geoip_file.go index 666e7f2..4350f85 100644 --- a/internal/geoip/geoip_file.go +++ b/internal/geoip/geoip_file.go @@ -15,6 +15,7 @@ type GeoIPFileClient struct { *maxminddb.Reader appname, tempdir string + skipVerify bool mu sync.RWMutex isReady bool @@ -34,8 +35,9 @@ func NewGeoIPFileClient(c context.Context, path string) (_ GeoIPClient, e error) done: c.Done, abort: c.Value(utils.CKAbortFunc).(context.CancelFunc), - appname: cli.App.Name, - tempdir: fmt.Sprintf("%s_%s", cli.App.Name, cli.App.Version), + appname: cli.App.Name, + tempdir: fmt.Sprintf("%s_%s", cli.App.Name, cli.App.Version), + skipVerify: cli.Bool("geoip-skip-database-verify"), } gipc.Reader, e = maxminddb.Open(path) @@ -45,24 +47,20 @@ func NewGeoIPFileClient(c context.Context, path string) (_ GeoIPClient, e error) func (m *GeoIPFileClient) Bootstrap() { m.log.Info().Msg("geoip has been initied") - var e error - if e = m.Reader.Verify(); e != nil { - m.log.Error().Msg("could not verify maxmind DB - " + e.Error()) - m.abort() - return + if !m.skipVerify { + if e := m.Reader.Verify(); e != nil { + m.log.Error().Msg("could not verify maxmind DB - " + e.Error()) + m.abort() + return + } } - m.mu.Lock() - m.isReady = true - m.mu.Unlock() + m.setReady(true) <-m.done() m.log.Info().Msg("internal abort() has been caught; initiate application closing...") - m.mu.Lock() - m.isReady = false - m.mu.Unlock() - + m.setReady(false) m.destroy() } @@ -83,3 +81,9 @@ func (m *GeoIPFileClient) destroy() { m.log.Warn().Msg("could not close maxmind reader - " + e.Error()) } } + +func (m *GeoIPFileClient) setReady(ready bool) { + m.mu.Lock() + m.isReady = ready + m.mu.Unlock() +} diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 387b91d..e457180 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -34,6 +34,7 @@ type GeoIPHTTPClient struct { mmpassword string appname, tempdir string + skipVerify bool mu sync.RWMutex isReady bool @@ -53,8 +54,9 @@ func NewGeoIPHTTPClient(c context.Context) (_ GeoIPClient, e error) { done: c.Done, abort: c.Value(utils.CKAbortFunc).(context.CancelFunc), - appname: cli.App.Name, - tempdir: fmt.Sprintf("%s_%s", cli.App.Name, cli.App.Version), + appname: cli.App.Name, + tempdir: fmt.Sprintf("%s_%s", cli.App.Name, cli.App.Version), + skipVerify: cli.Bool("geoip-skip-database-verify"), } return gipc.configureHTTPClient(cli) @@ -70,23 +72,20 @@ func (m *GeoIPHTTPClient) Bootstrap() { } m.log.Info().Msg("geoip has been initied") - if e = m.Reader.Verify(); e != nil { - m.log.Error().Msg("could not verify maxmind DB - " + e.Error()) - m.abort() - return + if !m.skipVerify { + if e = m.Reader.Verify(); e != nil { + m.log.Error().Msg("could not verify maxmind DB - " + e.Error()) + m.abort() + return + } } - m.mu.Lock() - m.isReady = true - m.mu.Unlock() + m.setReady(true) <-m.done() m.log.Info().Msg("internal abort() has been caught; initiate application closing...") - m.mu.Lock() - m.isReady = false - m.mu.Unlock() - + m.setReady(false) m.destroy() } @@ -116,6 +115,12 @@ func (m *GeoIPHTTPClient) destroy() { } } +func (m *GeoIPHTTPClient) setReady(ready bool) { + m.mu.Lock() + m.isReady = ready + m.mu.Unlock() +} + func (m *GeoIPHTTPClient) configureHTTPClient(c *cli.Context) (_ GeoIPClient, e error) { rrl := fasthttp.AcquireURI() defer fasthttp.ReleaseURI(rrl) From 74410a8740e39cd5553f46ba3d4ca669b7260e54 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Sun, 4 Aug 2024 02:18:54 +0000 Subject: [PATCH 05/24] small comment and logging fixes --- cmd/alice/main.go | 4 ++-- internal/geoip/geoip_file.go | 3 +-- internal/geoip/geoip_http.go | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cmd/alice/main.go b/cmd/alice/main.go index ed22fbc..09003b7 100644 --- a/cmd/alice/main.go +++ b/cmd/alice/main.go @@ -114,8 +114,8 @@ func main() { exitcode = 1 } - // TODO avoid this shit - // fucking diode was no `wait` method, so we need to use this `250` shit + // TODO avoid this + // diode hasn't Wait() method, so we need to use this `250` shit log.Trace().Msg("waiting for diode buf") time.Sleep(250 * time.Millisecond) } diff --git a/internal/geoip/geoip_file.go b/internal/geoip/geoip_file.go index 4350f85..db21d6a 100644 --- a/internal/geoip/geoip_file.go +++ b/internal/geoip/geoip_file.go @@ -45,8 +45,6 @@ func NewGeoIPFileClient(c context.Context, path string) (_ GeoIPClient, e error) } func (m *GeoIPFileClient) Bootstrap() { - m.log.Info().Msg("geoip has been initied") - if !m.skipVerify { if e := m.Reader.Verify(); e != nil { m.log.Error().Msg("could not verify maxmind DB - " + e.Error()) @@ -55,6 +53,7 @@ func (m *GeoIPFileClient) Bootstrap() { } } + m.log.Debug().Msg("geoip has been initied") m.setReady(true) <-m.done() diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index e457180..0f7fc58 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -70,7 +70,6 @@ func (m *GeoIPHTTPClient) Bootstrap() { m.abort() return } - m.log.Info().Msg("geoip has been initied") if !m.skipVerify { if e = m.Reader.Verify(); e != nil { @@ -80,6 +79,7 @@ func (m *GeoIPHTTPClient) Bootstrap() { } } + m.log.Debug().Msg("geoip has been initied") m.setReady(true) <-m.done() From b367d9fa80f09acbf240d3f26a28a962a2f070ec Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Sun, 4 Aug 2024 04:11:54 +0000 Subject: [PATCH 06/24] add maxmind database SHA256 verification --- cmd/alice/flags.go | 2 + internal/geoip/geoip_http.go | 160 +++++++++++++++++++++++++++-------- 2 files changed, 128 insertions(+), 34 deletions(-) diff --git a/cmd/alice/flags.go b/cmd/alice/flags.go index 3294b59..6cf2a72 100644 --- a/cmd/alice/flags.go +++ b/cmd/alice/flags.go @@ -260,6 +260,8 @@ func flagsInitialization() []cli.Flag { &cli.BoolFlag{ Name: "geoip-download-sha256-skip", Category: "GeoIP", + Usage: `sha256 helps to check database contents of the mmdb database + and avoid unnecessary requests to MaxMind CDN`, }, // custom settings diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 046d736..db9f676 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -4,6 +4,7 @@ import ( "archive/tar" "bytes" "context" + "crypto/sha256" "errors" "fmt" "io" @@ -33,6 +34,9 @@ type GeoIPHTTPClient struct { mmusername string mmpassword string + mmSkipHashVerify bool + mmLastHash []byte + appname, tempdir string mu sync.RWMutex @@ -55,6 +59,8 @@ func NewGeoIPHTTPClient(c context.Context) (_ GeoIPClient, e error) { appname: cli.App.Name, tempdir: fmt.Sprintf("%s_%s", cli.App.Name, cli.App.Version), + + mmSkipHashVerify: cli.Bool("geoip-download-sha256-skip"), } return gipc.configureHTTPClient(cli) @@ -169,13 +175,29 @@ func (m *GeoIPHTTPClient) makeTempFile() (_ *os.File, e error) { return fd, e } +func (m *GeoIPHTTPClient) acquireGeoIPRequest(parent *fasthttp.Request) (req *fasthttp.Request) { + req = fasthttp.AcquireRequest() + + if parent != nil { + parent.CopyTo(req) + } + + req.SetRequestURI(m.mmurl) + req.URI().SetUsername(m.mmusername) + req.URI().SetPassword(m.mmpassword) + + req.Header.SetUserAgent(m.hclient.Name) + + return +} + func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { if m.mmfd, e = m.makeTempFile(); e != nil { return } m.log.Debug().Msgf("file %s has been successfully allocated", m.mmfd.Name()) - req := fasthttp.AcquireRequest() + req := m.acquireGeoIPRequest(nil) defer fasthttp.ReleaseRequest(req) req.Header.SetUserAgent(m.hclient.Name) @@ -186,47 +208,41 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { rsp := fasthttp.AcquireResponse() defer fasthttp.ReleaseResponse(rsp) - for maxRedirects := 5; ; maxRedirects-- { - if maxRedirects == 0 { - e = errors.New("maxmind responded with too many redirects, redirects count exceeded") - return - } - - m.log.Trace().Msg(req.String()) - if e = m.hclient.Do(req, rsp); e != nil { + var expectedHash []byte + if !m.mmSkipHashVerify { + if expectedHash, e = m.requestSHA256(req); e != nil { return } - status := rsp.StatusCode() - if fasthttp.StatusCodeIsRedirect(status) { - m.log.Trace().Msg(rsp.String()) - m.log.Debug().Msgf("maxmind responded with redirect %d, go to %s", status, - futils.UnsafeString(rsp.Header.Peek(fasthttp.HeaderLocation))) - - req.Header.Del(fasthttp.HeaderAuthorization) + fmt.Printf("%+v\n", expectedHash) - req.SetRequestURIBytes(rsp.Header.Peek(fasthttp.HeaderLocation)) - req.URI().Parse(nil, rsp.Header.Peek(fasthttp.HeaderLocation)) - continue + if bytes.Compare(expectedHash, m.mmLastHash) == 0 { + m.log.Info().Msg("maxmind responded sha256 is not changed; mmdb download will be skipped") + return m.Reader, e } + } - if status != fasthttp.StatusOK { - m.log.Trace().Msg(rsp.String()) - m.log.Error().Msgf("maxmind responded with %d", status) + if e = m.requestWithRedirects(req, rsp); e != nil { + return + } - e = errors.New("maxmind api returned non 200 response") + if !m.mmSkipHashVerify { + var responseHash []byte + if responseHash = m.databaseSHA256Verify(rsp.Body()); len(responseHash) == 0 { + e = errors.New("databases SHA256 verification returns an empty hash") return } - if len(rsp.Body()) == 0 { - m.log.Trace().Msg(rsp.String()) - m.log.Error().Msg("maxmind responded with empty body") + m.log.Trace().Msgf("response - %x", responseHash) + m.log.Trace().Msgf("expected - %x", expectedHash) - e = errors.New("maxmind responded with empty body") + if bytes.Compare(responseHash, expectedHash) != 0 { + e = errors.New("maxmind databases verification not passed, database could not be updated") return } - break + m.log.Debug().Msg("maxmind database sha256 verification passed") + m.mmLastHash = expectedHash } // GZIP reader @@ -255,7 +271,7 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { m.log.Trace().Msg("found mmdb file, copy to temporary file") var written int64 - if written, e = io.Copy(m.mmfd, tr); e != nil { // skipcq: GO-S2110 decompression bomb isn't important here + if written, e = io.Copy(m.mmfd, tr); e != nil { // skipcq: GO-S2110 decompression bomb isn't possible here return } @@ -263,10 +279,86 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { break } - // !!! --geoip-download-sha256-skip - // !!! --geoip-download-sha256-skip - // !!! --geoip-download-sha256-skip - // !!! --geoip-download-sha256-skip - return maxminddb.Open(m.mmfd.Name()) } + +func (m *GeoIPHTTPClient) databaseSHA256Verify(payload []byte) []byte { + sha := sha256.New() + + sha.Write(payload) + return sha.Sum(nil) +} + +func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (hash []byte, e error) { + shareq := m.acquireGeoIPRequest(req) + defer fasthttp.ReleaseRequest(shareq) + + if !shareq.URI().QueryArgs().Has("suffix") { + e = errors.New("unknown maxmind url format; suffix arg is missing, sha256 verification is not possible") + return + } + shareq.URI().QueryArgs().Set("suffix", "tar.gz.sha256") + + rsp := fasthttp.AcquireResponse() + defer fasthttp.ReleaseResponse(rsp) + + if e = m.requestWithRedirects(shareq, rsp); e != nil { + return + } + + if zerolog.GlobalLevel() <= zerolog.DebugLevel { + m.log.Trace().Msg(rsp.String()) + m.log.Debug().Msgf("maxmind respond with hash - '%s'", futils.UnsafeString(rsp.Body()[:64])) + } + + fmt.Printf("%+v\n", rsp.Body()) + + return append(hash, rsp.Body()[:64]...), e +} + +func (m *GeoIPHTTPClient) requestWithRedirects(req *fasthttp.Request, rsp *fasthttp.Response) (e error) { + for maxRedirects := 5; ; maxRedirects-- { + if maxRedirects == 0 { + e = errors.New("maxmind responded with too many redirects, redirects count exceeded") + return + } + + m.log.Trace().Msg(req.String()) + if e = m.hclient.Do(req, rsp); e != nil { + return + } + + status := rsp.StatusCode() + if fasthttp.StatusCodeIsRedirect(status) { + m.log.Trace().Msg(rsp.String()) + m.log.Debug().Msgf("maxmind responded with redirect %d, go to %s", status, + futils.UnsafeString(rsp.Header.Peek(fasthttp.HeaderLocation))) + + req.Header.Del(fasthttp.HeaderAuthorization) + + req.SetRequestURIBytes(rsp.Header.Peek(fasthttp.HeaderLocation)) + req.URI().Parse(nil, rsp.Header.Peek(fasthttp.HeaderLocation)) + continue + } + + if status != fasthttp.StatusOK { + m.log.Trace().Msg(rsp.String()) + m.log.Error().Msgf("maxmind responded with %d", status) + + e = errors.New("maxmind api returned non 200 response") + return + } + + if len(rsp.Body()) == 0 { + m.log.Trace().Msg(rsp.String()) + m.log.Error().Msg("maxmind responded with empty body") + + e = errors.New("maxmind responded with empty body") + return + } + + break + } + + return +} From ed93e5516f43e7466aa28a644ebd70f37016eca1 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sun, 4 Aug 2024 05:18:37 +0000 Subject: [PATCH 07/24] style: format code with Go fmt This commit fixes the style issues introduced in b367d9f according to the output from Go fmt. Details: https://github.com/anilibria/alice/pull/33 --- cmd/alice/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/alice/flags.go b/cmd/alice/flags.go index 6cf2a72..e977be1 100644 --- a/cmd/alice/flags.go +++ b/cmd/alice/flags.go @@ -260,7 +260,7 @@ func flagsInitialization() []cli.Flag { &cli.BoolFlag{ Name: "geoip-download-sha256-skip", Category: "GeoIP", - Usage: `sha256 helps to check database contents of the mmdb database + Usage: `sha256 helps to check database contents of the mmdb database and avoid unnecessary requests to MaxMind CDN`, }, From 1efae728d42b57726b223ebd0632e41cce47e78c Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Sun, 4 Aug 2024 11:36:23 +0000 Subject: [PATCH 08/24] WIP: test with reponse body copying --- internal/geoip/geoip_http.go | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index db9f676..f6b6726 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -214,9 +214,10 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { return } - fmt.Printf("%+v\n", expectedHash) + m.log.Trace().Msgf("expected - %+v", expectedHash) + m.log.Trace().Msgf("expected - %x", expectedHash) - if bytes.Compare(expectedHash, m.mmLastHash) == 0 { + if len(m.mmLastHash) != 0 && bytes.Compare(expectedHash, m.mmLastHash) == 0 { m.log.Info().Msg("maxmind responded sha256 is not changed; mmdb download will be skipped") return m.Reader, e } @@ -289,7 +290,7 @@ func (m *GeoIPHTTPClient) databaseSHA256Verify(payload []byte) []byte { return sha.Sum(nil) } -func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (hash []byte, e error) { +func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (_ []byte, e error) { shareq := m.acquireGeoIPRequest(req) defer fasthttp.ReleaseRequest(shareq) @@ -308,12 +309,32 @@ func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (hash []byte, e e if zerolog.GlobalLevel() <= zerolog.DebugLevel { m.log.Trace().Msg(rsp.String()) + m.log.Trace().Msgf("maxmind body response %x", rsp.Body()) m.log.Debug().Msgf("maxmind respond with hash - '%s'", futils.UnsafeString(rsp.Body()[:64])) + m.log.Trace().Msgf("maxmind body response %x", rsp.Body()) } - fmt.Printf("%+v\n", rsp.Body()) + rsp.StreamBody = false + + fmt.Printf("body - %x\n", rsp.Body()) + fmt.Printf("body string - %s\n", futils.UnsafeString(rsp.Body())) + + hash := make([]byte, 64) + copy(hash, rsp.Body()[:64]) + + fmt.Printf("appending - %x\n", rsp.Body()[:64]) + fmt.Printf("appending string - %s\n", futils.UnsafeString(rsp.Body()[:64])) + // hash = append(hash, rsp.Body()[:64]...) + fmt.Printf("finished - %x\n", hash) + fmt.Printf("finished string - %s\n", futils.UnsafeString(hash)) - return append(hash, rsp.Body()[:64]...), e + buf := bytes.NewBufferString(futils.UnsafeString(rsp.Body()[:64])) + + fmt.Printf("ss finished - %x\n", buf.Bytes()) + fmt.Printf("ss finished string - %s\n", futils.UnsafeString(buf.Bytes())) + + // return append(hash, rsp.Body()[:64]...), e + return } func (m *GeoIPHTTPClient) requestWithRedirects(req *fasthttp.Request, rsp *fasthttp.Response) (e error) { From 5deaa756e9113e5b9069880ae4522a68e565448f Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Mon, 5 Aug 2024 14:03:24 +0000 Subject: [PATCH 09/24] remove debugs, major bugfixes --- go.mod | 4 ++-- go.sum | 8 ++++---- internal/geoip/geoip_http.go | 34 ++++++++++------------------------ 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 2061882..aaad28b 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/mailru/easyjson v0.7.7 github.com/oschwald/maxminddb-golang v1.13.1 github.com/rs/zerolog v1.33.0 - github.com/urfave/cli/v2 v2.27.2 + github.com/urfave/cli/v2 v2.27.3 github.com/valyala/bytebufferpool v1.0.0 github.com/valyala/fasthttp v1.55.0 ) @@ -30,7 +30,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/tinylib/msgp v1.1.8 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect go.etcd.io/bbolt v1.3.9 // indirect golang.org/x/sys v0.21.0 // indirect ) diff --git a/go.sum b/go.sum index 90ad68c..0a21d27 100644 --- a/go.sum +++ b/go.sum @@ -47,16 +47,16 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/urfave/cli/v2 v2.27.3 h1:/POWahRmdh7uztQ3CYnaDddk0Rm90PyOgIxgW2rr41M= +github.com/urfave/cli/v2 v2.27.3/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index f6b6726..1848504 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -5,6 +5,7 @@ import ( "bytes" "context" "crypto/sha256" + "encoding/hex" "errors" "fmt" "io" @@ -214,10 +215,7 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { return } - m.log.Trace().Msgf("expected - %+v", expectedHash) - m.log.Trace().Msgf("expected - %x", expectedHash) - - if len(m.mmLastHash) != 0 && bytes.Compare(expectedHash, m.mmLastHash) == 0 { + if len(m.mmLastHash) != 0 && bytes.Equal(expectedHash, m.mmLastHash) { m.log.Info().Msg("maxmind responded sha256 is not changed; mmdb download will be skipped") return m.Reader, e } @@ -234,10 +232,7 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { return } - m.log.Trace().Msgf("response - %x", responseHash) - m.log.Trace().Msgf("expected - %x", expectedHash) - - if bytes.Compare(responseHash, expectedHash) != 0 { + if !bytes.Equal(responseHash, expectedHash) { e = errors.New("maxmind databases verification not passed, database could not be updated") return } @@ -283,11 +278,14 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { return maxminddb.Open(m.mmfd.Name()) } -func (m *GeoIPHTTPClient) databaseSHA256Verify(payload []byte) []byte { +func (m *GeoIPHTTPClient) databaseSHA256Verify(payload []byte) (hash []byte) { sha := sha256.New() - sha.Write(payload) - return sha.Sum(nil) + + hash = make([]byte, sha.Size()*2) + hex.Encode(hash, sha.Sum(nil)) + + return } func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (_ []byte, e error) { @@ -322,19 +320,7 @@ func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (_ []byte, e erro hash := make([]byte, 64) copy(hash, rsp.Body()[:64]) - fmt.Printf("appending - %x\n", rsp.Body()[:64]) - fmt.Printf("appending string - %s\n", futils.UnsafeString(rsp.Body()[:64])) - // hash = append(hash, rsp.Body()[:64]...) - fmt.Printf("finished - %x\n", hash) - fmt.Printf("finished string - %s\n", futils.UnsafeString(hash)) - - buf := bytes.NewBufferString(futils.UnsafeString(rsp.Body()[:64])) - - fmt.Printf("ss finished - %x\n", buf.Bytes()) - fmt.Printf("ss finished string - %s\n", futils.UnsafeString(buf.Bytes())) - - // return append(hash, rsp.Body()[:64]...), e - return + return hash, e } func (m *GeoIPHTTPClient) requestWithRedirects(req *fasthttp.Request, rsp *fasthttp.Response) (e error) { From 9fce895be9262e78123d0ea1826b2edfb0b58b27 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Mon, 5 Aug 2024 14:09:21 +0000 Subject: [PATCH 10/24] small refactoring --- internal/geoip/geoip_http.go | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 1848504..2bf8d1c 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -40,8 +40,8 @@ type GeoIPHTTPClient struct { appname, tempdir string - mu sync.RWMutex - isReady bool + mu sync.RWMutex + ready bool log *zerolog.Logger @@ -84,7 +84,7 @@ func (m *GeoIPHTTPClient) Bootstrap() { } m.mu.Lock() - m.isReady = true + m.ready = true m.mu.Unlock() <-m.done() @@ -100,7 +100,7 @@ func (m *GeoIPHTTPClient) LookupCountryISO(ip string) (string, error) { func (m *GeoIPHTTPClient) IsReady() bool { m.mu.RLock() defer m.mu.RUnlock() - return m.isReady + return m.ready } // @@ -201,11 +201,6 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { req := m.acquireGeoIPRequest(nil) defer fasthttp.ReleaseRequest(req) - req.Header.SetUserAgent(m.hclient.Name) - req.SetRequestURI(m.mmurl) - req.URI().SetUsername(m.mmusername) - req.URI().SetPassword(m.mmpassword) - rsp := fasthttp.AcquireResponse() defer fasthttp.ReleaseResponse(rsp) @@ -312,11 +307,6 @@ func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (_ []byte, e erro m.log.Trace().Msgf("maxmind body response %x", rsp.Body()) } - rsp.StreamBody = false - - fmt.Printf("body - %x\n", rsp.Body()) - fmt.Printf("body string - %s\n", futils.UnsafeString(rsp.Body())) - hash := make([]byte, 64) copy(hash, rsp.Body()[:64]) @@ -349,18 +339,14 @@ func (m *GeoIPHTTPClient) requestWithRedirects(req *fasthttp.Request, rsp *fasth } if status != fasthttp.StatusOK { + e = errors.New(fmt.Sprintf("maxmind api returned %d response", status)) m.log.Trace().Msg(rsp.String()) - m.log.Error().Msgf("maxmind responded with %d", status) - - e = errors.New("maxmind api returned non 200 response") return } if len(rsp.Body()) == 0 { - m.log.Trace().Msg(rsp.String()) - m.log.Error().Msg("maxmind responded with empty body") - e = errors.New("maxmind responded with empty body") + m.log.Trace().Msg(rsp.String()) return } From 2c87eedda119f029ccf76b5f22bcce87af072c26 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Mon, 5 Aug 2024 14:10:28 +0000 Subject: [PATCH 11/24] fix RVV-B0013 --- internal/geoip/geoip_http.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 2bf8d1c..bd814b7 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -273,7 +273,7 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { return maxminddb.Open(m.mmfd.Name()) } -func (m *GeoIPHTTPClient) databaseSHA256Verify(payload []byte) (hash []byte) { +func (*GeoIPHTTPClient) databaseSHA256Verify(payload []byte) (hash []byte) { sha := sha256.New() sha.Write(payload) From 1a8930064a6fa08cffffa9fafa136fefdb6674ab Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Mon, 5 Aug 2024 14:23:14 +0000 Subject: [PATCH 12/24] try to fix GO-R1005 --- internal/geoip/geoip_http.go | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index bd814b7..1f7f737 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -236,14 +236,24 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { m.mmLastHash = expectedHash } - // GZIP reader + if e = m.extractTarGzArchive(m.mmfd, bytes.NewBuffer(rsp.Body())); e != nil { + return + } + + return maxminddb.Open(m.mmfd.Name()) +} + +func (m *GeoIPHTTPClient) extractTarGzArchive(dst io.Writer, src io.Reader) (e error) { var rd *gzip.Reader - if rd, e = gzip.NewReader(bytes.NewBuffer(rsp.Body())); e != nil { + if rd, e = gzip.NewReader(src); e != nil { return } - // TAR reader - tr := tar.NewReader(rd) + return m.extractTarArchive(dst, rd) +} + +func (m *GeoIPHTTPClient) extractTarArchive(dst io.Writer, src io.Reader) (e error) { + tr := tar.NewReader(src) for { var hdr *tar.Header hdr, e = tr.Next() @@ -262,7 +272,7 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { m.log.Trace().Msg("found mmdb file, copy to temporary file") var written int64 - if written, e = io.Copy(m.mmfd, tr); e != nil { // skipcq: GO-S2110 decompression bomb isn't possible here + if written, e = io.Copy(dst, tr); e != nil { // skipcq: GO-S2110 decompression bomb isn't possible here return } @@ -270,7 +280,7 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { break } - return maxminddb.Open(m.mmfd.Name()) + return } func (*GeoIPHTTPClient) databaseSHA256Verify(payload []byte) (hash []byte) { From c80ee4145aae86a6f4658526ae481a05b150b66a Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Mon, 5 Aug 2024 14:23:56 +0000 Subject: [PATCH 13/24] small refactoring --- internal/geoip/geoip_http.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 1f7f737..37916ad 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -312,9 +312,7 @@ func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (_ []byte, e erro if zerolog.GlobalLevel() <= zerolog.DebugLevel { m.log.Trace().Msg(rsp.String()) - m.log.Trace().Msgf("maxmind body response %x", rsp.Body()) - m.log.Debug().Msgf("maxmind respond with hash - '%s'", futils.UnsafeString(rsp.Body()[:64])) - m.log.Trace().Msgf("maxmind body response %x", rsp.Body()) + m.log.Debug().Msgf("maxmind respond with hash - '%s' (string)", futils.UnsafeString(rsp.Body()[:64])) } hash := make([]byte, 64) From 62b90c80f6b1299763a4dcd2d7d62746b24f9d15 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Mon, 5 Aug 2024 14:27:07 +0000 Subject: [PATCH 14/24] fix SCC-S1028 --- internal/geoip/geoip_http.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 37916ad..aeca241 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -347,7 +347,7 @@ func (m *GeoIPHTTPClient) requestWithRedirects(req *fasthttp.Request, rsp *fasth } if status != fasthttp.StatusOK { - e = errors.New(fmt.Sprintf("maxmind api returned %d response", status)) + e = fmt.Errorf("maxmind api returned %d response", status) m.log.Trace().Msg(rsp.String()) return } From 6dcdccf27056197a61d8f6e100832f9dc809c775 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Mon, 5 Aug 2024 14:52:37 +0000 Subject: [PATCH 15/24] add skeleton for auto update --- cmd/alice/flags.go | 13 +++++++++ internal/geoip/geoip_http.go | 54 ++++++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/cmd/alice/flags.go b/cmd/alice/flags.go index e977be1..3a10a96 100644 --- a/cmd/alice/flags.go +++ b/cmd/alice/flags.go @@ -263,6 +263,19 @@ func flagsInitialization() []cli.Flag { Usage: `sha256 helps to check database contents of the mmdb database and avoid unnecessary requests to MaxMind CDN`, }, + &cli.DurationFlag{ + Name: "geoip-update-frequency", + Category: "GeoIP", + Usage: `when geoip-maxmind-permalink is selected and geoip-db-path is empty, + once within a certain 'PERIOD' of time app will update the geoip database; + do not forget about maxmind donwload limits; set to 0s if want to disable`, + Value: 24 * time.Hour, + }, + &cli.DurationFlag{ + Name: "geoip-update-retry-frequency", + Category: "GeoIP", + Value: 1 * time.Hour, + }, // custom settings &cli.BoolFlag{ diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index aeca241..55b2f9e 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -13,6 +13,7 @@ import ( "os" "strings" "sync" + "time" "github.com/anilibria/alice/internal/utils" "github.com/klauspost/compress/gzip" @@ -38,6 +39,10 @@ type GeoIPHTTPClient struct { mmSkipHashVerify bool mmLastHash []byte + muUpdate sync.RWMutex + mmUpdateFreq time.Duration + mmRetryFreq time.Duration + appname, tempdir string mu sync.RWMutex @@ -62,6 +67,8 @@ func NewGeoIPHTTPClient(c context.Context) (_ GeoIPClient, e error) { tempdir: fmt.Sprintf("%s_%s", cli.App.Name, cli.App.Version), mmSkipHashVerify: cli.Bool("geoip-download-sha256-skip"), + mmUpdateFreq: cli.Duration("geoip-update-frequency"), + mmRetryFreq: cli.Duration("geoip-update-retry-frequency"), } return gipc.configureHTTPClient(cli) @@ -70,7 +77,7 @@ func NewGeoIPHTTPClient(c context.Context) (_ GeoIPClient, e error) { func (m *GeoIPHTTPClient) Bootstrap() { var e error - if m.Reader, e = m.databaseDownload(); e != nil { + if m.Reader, e = m.databaseDownload(m.mmfd); e != nil { m.log.Error().Msg("could not bootstrap GeoIPHTTPClient - " + e.Error()) m.abort() return @@ -87,9 +94,7 @@ func (m *GeoIPHTTPClient) Bootstrap() { m.ready = true m.mu.Unlock() - <-m.done() - m.log.Info().Msg("internal abort() has been caught; initiate application closing...") - + m.loop() m.destroy() } @@ -105,6 +110,33 @@ func (m *GeoIPHTTPClient) IsReady() bool { // +func (m *GeoIPHTTPClient) loop() { + m.log.Debug().Msg("initiate geoip db update loop...") + defer m.log.Debug().Msg("geoip db update loop has been closed") + + var update *time.Timer + if m.mmUpdateFreq != 0 { + update = time.NewTimer(m.mmUpdateFreq) + } + +LOOP: + for { + select { + case <-update.C: + if !m.IsReady() { + update.Reset(m.mmRetryFreq) + m.log.Error().Msg("could not start the database update, ready flag is false at this moment") + continue + } + + // + case <-m.done(): + m.log.Info().Msg("internal abort() has been caught; initiate application closing...") + break LOOP + } + } +} + func (m *GeoIPHTTPClient) destroy() { if e := m.Close(); e != nil { m.log.Warn().Msg("could not close maxmind reader - " + e.Error()) @@ -192,11 +224,15 @@ func (m *GeoIPHTTPClient) acquireGeoIPRequest(parent *fasthttp.Request) (req *fa return } -func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { - if m.mmfd, e = m.makeTempFile(); e != nil { +func (*GeoIPHTTPClient) rotateActiveDB(mmfile *os.File, mmreader *maxminddb.Reader) { + +} + +func (m *GeoIPHTTPClient) databaseDownload(tmpfile *os.File) (_ *maxminddb.Reader, e error) { + if tmpfile, e = m.makeTempFile(); e != nil { return } - m.log.Debug().Msgf("file %s has been successfully allocated", m.mmfd.Name()) + m.log.Debug().Msgf("file %s has been successfully allocated", tmpfile.Name()) req := m.acquireGeoIPRequest(nil) defer fasthttp.ReleaseRequest(req) @@ -236,11 +272,11 @@ func (m *GeoIPHTTPClient) databaseDownload() (_ *maxminddb.Reader, e error) { m.mmLastHash = expectedHash } - if e = m.extractTarGzArchive(m.mmfd, bytes.NewBuffer(rsp.Body())); e != nil { + if e = m.extractTarGzArchive(tmpfile, bytes.NewBuffer(rsp.Body())); e != nil { return } - return maxminddb.Open(m.mmfd.Name()) + return maxminddb.Open(tmpfile.Name()) } func (m *GeoIPHTTPClient) extractTarGzArchive(dst io.Writer, src io.Reader) (e error) { From 47dc8e54985f0b7a807c26aa91d42ffdf95b5865 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Mon, 5 Aug 2024 15:20:41 +0000 Subject: [PATCH 16/24] updates for geoip autoupdate --- cmd/alice/flags.go | 2 ++ internal/geoip/geoip_http.go | 66 ++++++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/cmd/alice/flags.go b/cmd/alice/flags.go index e920b06..e7093e5 100644 --- a/cmd/alice/flags.go +++ b/cmd/alice/flags.go @@ -278,6 +278,8 @@ func flagsInitialization() []cli.Flag { }, &cli.BoolFlag{ Name: "geoip-skip-database-verify", + Category: "GeoIP", + Usage: "skip mmdb contents validation by vendor function db.Verify()", DisableDefaultText: true, }, diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 459ea43..3387cdc 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -26,12 +26,13 @@ import ( ) type GeoIPHTTPClient struct { + mu sync.RWMutex *maxminddb.Reader + fd *os.File hclient *fasthttp.Client // maxmind - mmfd *os.File mmurl string mmusername string mmpassword string @@ -39,15 +40,15 @@ type GeoIPHTTPClient struct { mmSkipHashVerify bool mmLastHash []byte - muUpdate sync.RWMutex + muUpdate sync.Mutex mmUpdateFreq time.Duration mmRetryFreq time.Duration appname, tempdir string skipVerify bool - mu sync.RWMutex - ready bool + muReady sync.RWMutex + ready bool log *zerolog.Logger @@ -80,7 +81,7 @@ func NewGeoIPHTTPClient(c context.Context) (_ GeoIPClient, e error) { func (m *GeoIPHTTPClient) Bootstrap() { var e error - if m.Reader, e = m.databaseDownload(m.mmfd); e != nil { + if m.Reader, e = m.databaseDownload(m.fd); e != nil { m.log.Error().Msg("could not bootstrap GeoIPHTTPClient - " + e.Error()) m.abort() return @@ -107,8 +108,8 @@ func (m *GeoIPHTTPClient) LookupCountryISO(ip string) (string, error) { } func (m *GeoIPHTTPClient) IsReady() bool { - m.mu.RLock() - defer m.mu.RUnlock() + m.muReady.RLock() + defer m.muReady.RUnlock() return m.ready } @@ -127,13 +128,29 @@ LOOP: for { select { case <-update.C: + if !m.muUpdate.TryLock() { + m.log.Error().Msg("could not start the mmdb update, last proccess is not marked as complete") + update.Reset(m.mmRetryFreq) + continue + } if !m.IsReady() { + m.log.Error().Msg("could not start the mmdb update, ready flag is false at this moment") update.Reset(m.mmRetryFreq) - m.log.Error().Msg("could not start the database update, ready flag is false at this moment") + m.muUpdate.Unlock() continue } - // + var newfd *os.File + newrd, e := m.databaseDownload(newfd) + if e != nil { + m.log.Error().Msg("could not start the mmdb update - " + e.Error()) + update.Reset(m.mmRetryFreq) + m.muUpdate.Unlock() + continue + } + + m.rotateActiveDB(newfd, newrd) + m.muUpdate.Unlock() case <-m.done(): m.log.Info().Msg("internal abort() has been caught; initiate application closing...") break LOOP @@ -146,19 +163,38 @@ func (m *GeoIPHTTPClient) destroy() { m.log.Warn().Msg("could not close maxmind reader - " + e.Error()) } - if e := m.mmfd.Close(); e != nil { + m.destroyDB(m.fd, m.Reader) +} + +func (m *GeoIPHTTPClient) destroyDB(mmfile *os.File, mmreader *maxminddb.Reader) { + if e := mmreader.Close(); e != nil { + m.log.Warn().Msg("could not close maxmind reader - " + e.Error()) + } + + if e := mmfile.Close(); e != nil { m.log.Warn().Msg("could not close temporary geoip file - " + e.Error()) } - if e := os.Remove(m.mmfd.Name()); e != nil { + if e := os.Remove(mmfile.Name()); e != nil { m.log.Warn().Msg("could not remove temporary file - " + e.Error()) } } -func (m *GeoIPHTTPClient) setReady(ready bool) { +func (m *GeoIPHTTPClient) rotateActiveDB(mmfile *os.File, mmreader *maxminddb.Reader) { + m.setReady(false) + defer m.setReady(true) + m.mu.Lock() + defer m.mu.Unlock() + + m.destroyDB(m.fd, m.Reader) + m.Reader, m.fd = mmreader, mmfile +} + +func (m *GeoIPHTTPClient) setReady(ready bool) { + m.muReady.Lock() m.ready = ready - m.mu.Unlock() + m.muReady.Unlock() } func (m *GeoIPHTTPClient) configureHTTPClient(c *cli.Context) (_ GeoIPClient, e error) { @@ -234,10 +270,6 @@ func (m *GeoIPHTTPClient) acquireGeoIPRequest(parent *fasthttp.Request) (req *fa return } -func (*GeoIPHTTPClient) rotateActiveDB(mmfile *os.File, mmreader *maxminddb.Reader) { - -} - func (m *GeoIPHTTPClient) databaseDownload(tmpfile *os.File) (_ *maxminddb.Reader, e error) { if tmpfile, e = m.makeTempFile(); e != nil { return From ba42d19a2f0446e71144a7395a6df45420c40ed2 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Mon, 5 Aug 2024 15:55:48 +0000 Subject: [PATCH 17/24] WIP:some debug and refactoring --- cmd/alice/flags.go | 2 +- internal/geoip/geoip_http.go | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/cmd/alice/flags.go b/cmd/alice/flags.go index e7093e5..307915b 100644 --- a/cmd/alice/flags.go +++ b/cmd/alice/flags.go @@ -269,7 +269,7 @@ func flagsInitialization() []cli.Flag { Usage: `when geoip-maxmind-permalink is selected and geoip-db-path is empty, once within a certain 'PERIOD' of time app will update the geoip database; do not forget about maxmind donwload limits; set to 0s if want to disable`, - Value: 24 * time.Hour, + Value: 30 * time.Second, }, &cli.DurationFlag{ Name: "geoip-update-retry-frequency", diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 3387cdc..55e3793 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -122,6 +122,7 @@ func (m *GeoIPHTTPClient) loop() { var update *time.Timer if m.mmUpdateFreq != 0 { update = time.NewTimer(m.mmUpdateFreq) + m.log.Debug().Msgf("geoip database updater enabled; update period - %s", m.mmUpdateFreq.String()) } LOOP: @@ -139,17 +140,30 @@ LOOP: m.muUpdate.Unlock() continue } + m.log.Info().Msg("starting geoip database update") + m.log.Debug().Msg("geoip database update, downloading...") + defer m.log.Debug().Msg("geoip database update, finished") var newfd *os.File newrd, e := m.databaseDownload(newfd) if e != nil { - m.log.Error().Msg("could not start the mmdb update - " + e.Error()) + m.log.Error().Msg("could update the mmdb - " + e.Error()) update.Reset(m.mmRetryFreq) m.muUpdate.Unlock() continue } + m.log.Trace().Msg("geoip database update, old mmdb - " + m.fd.Name()) + m.log.Trace().Msg("geoip database update, new mmdb - " + newfd.Name()) + + m.log.Debug().Msg("geoip database update, rotating...") m.rotateActiveDB(newfd, newrd) + + if !m.skipVerify { + m.log.Debug().Msg("geoip database update, verifying...") + m.Verify() + } + m.muUpdate.Unlock() case <-m.done(): m.log.Info().Msg("internal abort() has been caught; initiate application closing...") @@ -159,10 +173,6 @@ LOOP: } func (m *GeoIPHTTPClient) destroy() { - if e := m.Close(); e != nil { - m.log.Warn().Msg("could not close maxmind reader - " + e.Error()) - } - m.destroyDB(m.fd, m.Reader) } From beec868419bfb28d1a86efad9b27426e997434e0 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Tue, 6 Aug 2024 10:53:12 +0000 Subject: [PATCH 18/24] panic fix, fix - SCC-SA4009 --- internal/geoip/geoip_http.go | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/internal/geoip/geoip_http.go b/internal/geoip/geoip_http.go index 55e3793..e1cba7d 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/geoip_http.go @@ -81,7 +81,7 @@ func NewGeoIPHTTPClient(c context.Context) (_ GeoIPClient, e error) { func (m *GeoIPHTTPClient) Bootstrap() { var e error - if m.Reader, e = m.databaseDownload(m.fd); e != nil { + if m.fd, m.Reader, e = m.databaseDownload(); e != nil { m.log.Error().Msg("could not bootstrap GeoIPHTTPClient - " + e.Error()) m.abort() return @@ -144,9 +144,12 @@ LOOP: m.log.Debug().Msg("geoip database update, downloading...") defer m.log.Debug().Msg("geoip database update, finished") - var newfd *os.File - newrd, e := m.databaseDownload(newfd) - if e != nil { + newfd, newrd, e := m.databaseDownload() + if e != nil && newfd != nil && newrd != nil { // update is not required + m.log.Info().Msg(e.Error()) + m.muUpdate.Unlock() + continue + } else if e != nil { m.log.Error().Msg("could update the mmdb - " + e.Error()) update.Reset(m.mmRetryFreq) m.muUpdate.Unlock() @@ -177,14 +180,17 @@ func (m *GeoIPHTTPClient) destroy() { } func (m *GeoIPHTTPClient) destroyDB(mmfile *os.File, mmreader *maxminddb.Reader) { + m.log.Trace().Msg("geoip database destroy, maxmind closing...") if e := mmreader.Close(); e != nil { m.log.Warn().Msg("could not close maxmind reader - " + e.Error()) } + m.log.Trace().Msg("geoip database destroy, mmdb closing...") if e := mmfile.Close(); e != nil { m.log.Warn().Msg("could not close temporary geoip file - " + e.Error()) } + m.log.Trace().Msg("geoip database destroy, mmdb removing...") if e := os.Remove(mmfile.Name()); e != nil { m.log.Warn().Msg("could not remove temporary file - " + e.Error()) } @@ -198,7 +204,7 @@ func (m *GeoIPHTTPClient) rotateActiveDB(mmfile *os.File, mmreader *maxminddb.Re defer m.mu.Unlock() m.destroyDB(m.fd, m.Reader) - m.Reader, m.fd = mmreader, mmfile + m.fd, m.Reader = mmfile, mmreader } func (m *GeoIPHTTPClient) setReady(ready bool) { @@ -280,11 +286,11 @@ func (m *GeoIPHTTPClient) acquireGeoIPRequest(parent *fasthttp.Request) (req *fa return } -func (m *GeoIPHTTPClient) databaseDownload(tmpfile *os.File) (_ *maxminddb.Reader, e error) { - if tmpfile, e = m.makeTempFile(); e != nil { +func (m *GeoIPHTTPClient) databaseDownload() (fd *os.File, _ *maxminddb.Reader, e error) { + if fd, e = m.makeTempFile(); e != nil { return } - m.log.Debug().Msgf("file %s has been successfully allocated", tmpfile.Name()) + m.log.Debug().Msgf("file %s has been successfully allocated", fd.Name()) req := m.acquireGeoIPRequest(nil) defer fasthttp.ReleaseRequest(req) @@ -299,8 +305,8 @@ func (m *GeoIPHTTPClient) databaseDownload(tmpfile *os.File) (_ *maxminddb.Reade } if len(m.mmLastHash) != 0 && bytes.Equal(expectedHash, m.mmLastHash) { - m.log.Info().Msg("maxmind responded sha256 is not changed; mmdb download will be skipped") - return m.Reader, e + e = errors.New("maxmind responded sha256 is not changed; mmdb download will be skipped") + return m.fd, m.Reader, e } } @@ -324,11 +330,14 @@ func (m *GeoIPHTTPClient) databaseDownload(tmpfile *os.File) (_ *maxminddb.Reade m.mmLastHash = expectedHash } - if e = m.extractTarGzArchive(tmpfile, bytes.NewBuffer(rsp.Body())); e != nil { + if e = m.extractTarGzArchive(fd, bytes.NewBuffer(rsp.Body())); e != nil { return } - return maxminddb.Open(tmpfile.Name()) + var reader *maxminddb.Reader + reader, e = maxminddb.Open(fd.Name()) + + return fd, reader, e } func (m *GeoIPHTTPClient) extractTarGzArchive(dst io.Writer, src io.Reader) (e error) { From 440b4957744c6ddbc88646d7401b01b342e784f9 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Tue, 6 Aug 2024 10:58:21 +0000 Subject: [PATCH 19/24] small refactoring --- internal/geoip/extract.go | 50 ++++++ internal/geoip/{geoip_file.go => file.go} | 0 internal/geoip/{geoip_http.go => http.go} | 177 ++++++---------------- internal/geoip/verify.go | 49 ++++++ 4 files changed, 144 insertions(+), 132 deletions(-) create mode 100644 internal/geoip/extract.go rename internal/geoip/{geoip_file.go => file.go} (100%) rename internal/geoip/{geoip_http.go => http.go} (81%) create mode 100644 internal/geoip/verify.go diff --git a/internal/geoip/extract.go b/internal/geoip/extract.go new file mode 100644 index 0000000..778a793 --- /dev/null +++ b/internal/geoip/extract.go @@ -0,0 +1,50 @@ +package geoip + +import ( + "archive/tar" + "compress/gzip" + "io" + "strings" + + "github.com/rs/zerolog" +) + +func extractTarGzArchive(log *zerolog.Logger, dst io.Writer, src io.Reader) (e error) { + var rd *gzip.Reader + if rd, e = gzip.NewReader(src); e != nil { + return + } + + return extractTarArchive(log, dst, rd) +} + +func extractTarArchive(log *zerolog.Logger, dst io.Writer, src io.Reader) (e error) { + tr := tar.NewReader(src) + for { + var hdr *tar.Header + hdr, e = tr.Next() + + if e == io.EOF { + break // End of archive + } else if e != nil { + return + } + + m.log.Trace().Msg("found file in maxmind tar archive - " + hdr.Name) + if !strings.HasSuffix(hdr.Name, "mmdb") { + continue + } + + m.log.Trace().Msg("found mmdb file, copy to temporary file") + + var written int64 + if written, e = io.Copy(dst, tr); e != nil { // skipcq: GO-S2110 decompression bomb isn't possible here + return + } + + m.log.Debug().Msgf("parsed response has written in temporary file with %d bytes", written) + break + } + + return +} diff --git a/internal/geoip/geoip_file.go b/internal/geoip/file.go similarity index 100% rename from internal/geoip/geoip_file.go rename to internal/geoip/file.go diff --git a/internal/geoip/geoip_http.go b/internal/geoip/http.go similarity index 81% rename from internal/geoip/geoip_http.go rename to internal/geoip/http.go index e1cba7d..a9e8032 100644 --- a/internal/geoip/geoip_http.go +++ b/internal/geoip/http.go @@ -1,14 +1,10 @@ package geoip import ( - "archive/tar" "bytes" "context" - "crypto/sha256" - "encoding/hex" "errors" "fmt" - "io" "io/fs" "os" "strings" @@ -16,7 +12,6 @@ import ( "time" "github.com/anilibria/alice/internal/utils" - "github.com/klauspost/compress/gzip" "github.com/oschwald/maxminddb-golang" "github.com/rs/zerolog" "github.com/urfave/cli/v2" @@ -100,7 +95,7 @@ func (m *GeoIPHTTPClient) Bootstrap() { m.loop() m.setReady(false) - m.destroy() + m.destroyDB(m.fd, m.Reader) } func (m *GeoIPHTTPClient) LookupCountryISO(ip string) (string, error) { @@ -175,10 +170,6 @@ LOOP: } } -func (m *GeoIPHTTPClient) destroy() { - m.destroyDB(m.fd, m.Reader) -} - func (m *GeoIPHTTPClient) destroyDB(mmfile *os.File, mmreader *maxminddb.Reader) { m.log.Trace().Msg("geoip database destroy, maxmind closing...") if e := mmreader.Close(); e != nil { @@ -286,6 +277,49 @@ func (m *GeoIPHTTPClient) acquireGeoIPRequest(parent *fasthttp.Request) (req *fa return } +func (m *GeoIPHTTPClient) requestWithRedirects(req *fasthttp.Request, rsp *fasthttp.Response) (e error) { + for maxRedirects := 5; ; maxRedirects-- { + if maxRedirects == 0 { + e = errors.New("maxmind responded with too many redirects, redirects count exceeded") + return + } + + m.log.Trace().Msg(req.String()) + if e = m.hclient.Do(req, rsp); e != nil { + return + } + + status := rsp.StatusCode() + if fasthttp.StatusCodeIsRedirect(status) { + m.log.Trace().Msg(rsp.String()) + m.log.Debug().Msgf("maxmind responded with redirect %d, go to %s", status, + futils.UnsafeString(rsp.Header.Peek(fasthttp.HeaderLocation))) + + req.Header.Del(fasthttp.HeaderAuthorization) + + req.SetRequestURIBytes(rsp.Header.Peek(fasthttp.HeaderLocation)) + req.URI().Parse(nil, rsp.Header.Peek(fasthttp.HeaderLocation)) + continue + } + + if status != fasthttp.StatusOK { + e = fmt.Errorf("maxmind api returned %d response", status) + m.log.Trace().Msg(rsp.String()) + return + } + + if len(rsp.Body()) == 0 { + e = errors.New("maxmind responded with empty body") + m.log.Trace().Msg(rsp.String()) + return + } + + break + } + + return +} + func (m *GeoIPHTTPClient) databaseDownload() (fd *os.File, _ *maxminddb.Reader, e error) { if fd, e = m.makeTempFile(); e != nil { return @@ -330,7 +364,7 @@ func (m *GeoIPHTTPClient) databaseDownload() (fd *os.File, _ *maxminddb.Reader, m.mmLastHash = expectedHash } - if e = m.extractTarGzArchive(fd, bytes.NewBuffer(rsp.Body())); e != nil { + if e = extractTarGzArchive(m.log, fd, bytes.NewBuffer(rsp.Body())); e != nil { return } @@ -339,124 +373,3 @@ func (m *GeoIPHTTPClient) databaseDownload() (fd *os.File, _ *maxminddb.Reader, return fd, reader, e } - -func (m *GeoIPHTTPClient) extractTarGzArchive(dst io.Writer, src io.Reader) (e error) { - var rd *gzip.Reader - if rd, e = gzip.NewReader(src); e != nil { - return - } - - return m.extractTarArchive(dst, rd) -} - -func (m *GeoIPHTTPClient) extractTarArchive(dst io.Writer, src io.Reader) (e error) { - tr := tar.NewReader(src) - for { - var hdr *tar.Header - hdr, e = tr.Next() - - if e == io.EOF { - break // End of archive - } else if e != nil { - return - } - - m.log.Trace().Msg("found file in maxmind tar archive - " + hdr.Name) - if !strings.HasSuffix(hdr.Name, "mmdb") { - continue - } - - m.log.Trace().Msg("found mmdb file, copy to temporary file") - - var written int64 - if written, e = io.Copy(dst, tr); e != nil { // skipcq: GO-S2110 decompression bomb isn't possible here - return - } - - m.log.Debug().Msgf("parsed response has written in temporary file with %d bytes", written) - break - } - - return -} - -func (*GeoIPHTTPClient) databaseSHA256Verify(payload []byte) (hash []byte) { - sha := sha256.New() - sha.Write(payload) - - hash = make([]byte, sha.Size()*2) - hex.Encode(hash, sha.Sum(nil)) - - return -} - -func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (_ []byte, e error) { - shareq := m.acquireGeoIPRequest(req) - defer fasthttp.ReleaseRequest(shareq) - - if !shareq.URI().QueryArgs().Has("suffix") { - e = errors.New("unknown maxmind url format; suffix arg is missing, sha256 verification is not possible") - return - } - shareq.URI().QueryArgs().Set("suffix", "tar.gz.sha256") - - rsp := fasthttp.AcquireResponse() - defer fasthttp.ReleaseResponse(rsp) - - if e = m.requestWithRedirects(shareq, rsp); e != nil { - return - } - - if zerolog.GlobalLevel() <= zerolog.DebugLevel { - m.log.Trace().Msg(rsp.String()) - m.log.Debug().Msgf("maxmind respond with hash - '%s' (string)", futils.UnsafeString(rsp.Body()[:64])) - } - - hash := make([]byte, 64) - copy(hash, rsp.Body()[:64]) - - return hash, e -} - -func (m *GeoIPHTTPClient) requestWithRedirects(req *fasthttp.Request, rsp *fasthttp.Response) (e error) { - for maxRedirects := 5; ; maxRedirects-- { - if maxRedirects == 0 { - e = errors.New("maxmind responded with too many redirects, redirects count exceeded") - return - } - - m.log.Trace().Msg(req.String()) - if e = m.hclient.Do(req, rsp); e != nil { - return - } - - status := rsp.StatusCode() - if fasthttp.StatusCodeIsRedirect(status) { - m.log.Trace().Msg(rsp.String()) - m.log.Debug().Msgf("maxmind responded with redirect %d, go to %s", status, - futils.UnsafeString(rsp.Header.Peek(fasthttp.HeaderLocation))) - - req.Header.Del(fasthttp.HeaderAuthorization) - - req.SetRequestURIBytes(rsp.Header.Peek(fasthttp.HeaderLocation)) - req.URI().Parse(nil, rsp.Header.Peek(fasthttp.HeaderLocation)) - continue - } - - if status != fasthttp.StatusOK { - e = fmt.Errorf("maxmind api returned %d response", status) - m.log.Trace().Msg(rsp.String()) - return - } - - if len(rsp.Body()) == 0 { - e = errors.New("maxmind responded with empty body") - m.log.Trace().Msg(rsp.String()) - return - } - - break - } - - return -} diff --git a/internal/geoip/verify.go b/internal/geoip/verify.go new file mode 100644 index 0000000..3aa1765 --- /dev/null +++ b/internal/geoip/verify.go @@ -0,0 +1,49 @@ +package geoip + +import ( + "crypto/sha256" + "encoding/hex" + "errors" + + futils "github.com/gofiber/fiber/v2/utils" + "github.com/rs/zerolog" + "github.com/valyala/fasthttp" +) + +func (*GeoIPHTTPClient) databaseSHA256Verify(payload []byte) (hash []byte) { + sha := sha256.New() + sha.Write(payload) + + hash = make([]byte, sha.Size()*2) + hex.Encode(hash, sha.Sum(nil)) + + return +} + +func (m *GeoIPHTTPClient) requestSHA256(req *fasthttp.Request) (_ []byte, e error) { + shareq := m.acquireGeoIPRequest(req) + defer fasthttp.ReleaseRequest(shareq) + + if !shareq.URI().QueryArgs().Has("suffix") { + e = errors.New("unknown maxmind url format; suffix arg is missing, sha256 verification is not possible") + return + } + shareq.URI().QueryArgs().Set("suffix", "tar.gz.sha256") + + rsp := fasthttp.AcquireResponse() + defer fasthttp.ReleaseResponse(rsp) + + if e = m.requestWithRedirects(shareq, rsp); e != nil { + return + } + + if zerolog.GlobalLevel() <= zerolog.DebugLevel { + m.log.Trace().Msg(rsp.String()) + m.log.Debug().Msgf("maxmind respond with hash - '%s' (string)", futils.UnsafeString(rsp.Body()[:64])) + } + + hash := make([]byte, 64) + copy(hash, rsp.Body()[:64]) + + return hash, e +} From ab0ae3bee9b2fab94fe292070d9235f8f5d17e06 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Tue, 6 Aug 2024 11:01:22 +0000 Subject: [PATCH 20/24] revert flags, small refactoring --- cmd/alice/flags.go | 2 +- internal/geoip/extract.go | 6 +++--- internal/geoip/file.go | 21 ++++++++++++--------- internal/geoip/geoip.go | 5 ++++- internal/geoip/http.go | 2 +- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/cmd/alice/flags.go b/cmd/alice/flags.go index 307915b..e7093e5 100644 --- a/cmd/alice/flags.go +++ b/cmd/alice/flags.go @@ -269,7 +269,7 @@ func flagsInitialization() []cli.Flag { Usage: `when geoip-maxmind-permalink is selected and geoip-db-path is empty, once within a certain 'PERIOD' of time app will update the geoip database; do not forget about maxmind donwload limits; set to 0s if want to disable`, - Value: 30 * time.Second, + Value: 24 * time.Hour, }, &cli.DurationFlag{ Name: "geoip-update-retry-frequency", diff --git a/internal/geoip/extract.go b/internal/geoip/extract.go index 778a793..ada3c66 100644 --- a/internal/geoip/extract.go +++ b/internal/geoip/extract.go @@ -30,19 +30,19 @@ func extractTarArchive(log *zerolog.Logger, dst io.Writer, src io.Reader) (e err return } - m.log.Trace().Msg("found file in maxmind tar archive - " + hdr.Name) + log.Trace().Msg("found file in maxmind tar archive - " + hdr.Name) if !strings.HasSuffix(hdr.Name, "mmdb") { continue } - m.log.Trace().Msg("found mmdb file, copy to temporary file") + log.Trace().Msg("found mmdb file, copy to temporary file") var written int64 if written, e = io.Copy(dst, tr); e != nil { // skipcq: GO-S2110 decompression bomb isn't possible here return } - m.log.Debug().Msgf("parsed response has written in temporary file with %d bytes", written) + log.Debug().Msgf("parsed response has written in temporary file with %d bytes", written) break } diff --git a/internal/geoip/file.go b/internal/geoip/file.go index db21d6a..7e2188f 100644 --- a/internal/geoip/file.go +++ b/internal/geoip/file.go @@ -12,13 +12,14 @@ import ( ) type GeoIPFileClient struct { + mu sync.RWMutex *maxminddb.Reader appname, tempdir string skipVerify bool - mu sync.RWMutex - isReady bool + muReady sync.RWMutex + ready bool log *zerolog.Logger @@ -64,13 +65,14 @@ func (m *GeoIPFileClient) Bootstrap() { } func (m *GeoIPFileClient) LookupCountryISO(ip string) (string, error) { - return lookupISOByIP(m.Reader, ip) + return lookupISOByIP(&m.mu, m.Reader, ip) } func (m *GeoIPFileClient) IsReady() bool { - m.mu.RLock() - defer m.mu.RUnlock() - return m.isReady + m.muReady.RLock() + defer m.muReady.RUnlock() + + return m.ready } // @@ -82,7 +84,8 @@ func (m *GeoIPFileClient) destroy() { } func (m *GeoIPFileClient) setReady(ready bool) { - m.mu.Lock() - m.isReady = ready - m.mu.Unlock() + m.muReady.Lock() + defer m.muReady.Unlock() + + m.ready = ready } diff --git a/internal/geoip/geoip.go b/internal/geoip/geoip.go index 970b037..b7fa038 100644 --- a/internal/geoip/geoip.go +++ b/internal/geoip/geoip.go @@ -37,7 +37,10 @@ func (m *geoIPRecord) reset() { *m = geoIPRecord{} } -func lookupISOByIP(mxrd *maxminddb.Reader, rawip string) (iso string, e error) { +func lookupISOByIP(mu *sync.RWMutex, mxrd *maxminddb.Reader, rawip string) (iso string, e error) { + mu.RLock() + defer mu.RUnlock() + var ip netip.Addr if ip, e = netip.ParseAddr(rawip); e != nil { e = errors.New(fmt.Sprintf("could not parse ip addr with netip library, ip - %+v - ", rawip) + e.Error()) diff --git a/internal/geoip/http.go b/internal/geoip/http.go index a9e8032..2e234b4 100644 --- a/internal/geoip/http.go +++ b/internal/geoip/http.go @@ -99,7 +99,7 @@ func (m *GeoIPHTTPClient) Bootstrap() { } func (m *GeoIPHTTPClient) LookupCountryISO(ip string) (string, error) { - return lookupISOByIP(m.Reader, ip) + return lookupISOByIP(&m.mu, m.Reader, ip) } func (m *GeoIPHTTPClient) IsReady() bool { From 879627ca7020fc8d184780da0b077c7d11750cc1 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Tue, 6 Aug 2024 11:24:44 +0000 Subject: [PATCH 21/24] small improvement --- internal/geoip/http.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/internal/geoip/http.go b/internal/geoip/http.go index 2e234b4..20e1452 100644 --- a/internal/geoip/http.go +++ b/internal/geoip/http.go @@ -81,6 +81,7 @@ func (m *GeoIPHTTPClient) Bootstrap() { m.abort() return } + defer m.destroyDB(m.fd, m.Reader) if !m.skipVerify { if e = m.Reader.Verify(); e != nil { @@ -91,11 +92,9 @@ func (m *GeoIPHTTPClient) Bootstrap() { } m.setReady(true) + defer m.setReady(false) m.loop() - m.setReady(false) - - m.destroyDB(m.fd, m.Reader) } func (m *GeoIPHTTPClient) LookupCountryISO(ip string) (string, error) { From 503c3e560da6a9f9f729889e89358bc51c662c8b Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Tue, 6 Aug 2024 13:29:18 +0000 Subject: [PATCH 22/24] change rlock to tryrlock for block avoid --- internal/geoip/geoip.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/geoip/geoip.go b/internal/geoip/geoip.go index b7fa038..9fe4740 100644 --- a/internal/geoip/geoip.go +++ b/internal/geoip/geoip.go @@ -38,7 +38,10 @@ func (m *geoIPRecord) reset() { } func lookupISOByIP(mu *sync.RWMutex, mxrd *maxminddb.Reader, rawip string) (iso string, e error) { - mu.RLock() + if !mu.TryRLock() { + e = errors.New("could not get lock for geoip lookup()") + return + } defer mu.RUnlock() var ip netip.Addr From 252b3fe80f0f64bbd9f9b20a7e5c5189c4da2555 Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Tue, 6 Aug 2024 13:34:06 +0000 Subject: [PATCH 23/24] add misses rate in cache api --- internal/cache/api.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/cache/api.go b/internal/cache/api.go index 5f9151a..0ed778f 100644 --- a/internal/cache/api.go +++ b/internal/cache/api.go @@ -97,7 +97,7 @@ func (m *Cache) ApiStats() io.Reader { tb.SetOutputMirror(buf) tb.AppendHeader(table.Row{ - "zone", "number of entries", "capacity (mb)", "hits", "misses", "delhits", "delmisses", "collisions", + "zone", "number of entries", "capacity (mb)", "hits", "misses", "delhits", "delmisses", "collisions", "misses %", }) for zone, cache := range m.pools { @@ -110,6 +110,7 @@ func (m *Cache) ApiStats() io.Reader { cache.Stats().DelHits, cache.Stats().DelMisses, cache.Stats().Collisions, + round(float64(cache.Stats().Misses*100/cache.Stats().Hits), 2), }) } From cc41e9c6e55bf20bf71affd730c2f6a27ad20f6f Mon Sep 17 00:00:00 2001 From: Vadimka Komissarov Date: Tue, 6 Aug 2024 13:50:26 +0000 Subject: [PATCH 24/24] add handling of "parse error" production error --- internal/proxy/proxy.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index e20f95a..13709da 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -120,6 +120,7 @@ func (m *Proxy) doRequest(c *fiber.Ctx, req *fasthttp.Request, rsp *fasthttp.Res func (*Proxy) unmarshalApiResponse(c *fiber.Ctx, rsp *fasthttp.Response) (ok bool, e error) { var apirsp *utils.ApiResponseWOData if apirsp, e = utils.UnmarshalApiResponse(rsp.Body()); e != nil || apirsp == nil { + rlog(c).Warn().Msg("could not parse legacy api response - " + futils.UnsafeString(rsp.Body())) return } defer utils.ReleaseApiResponseWOData(apirsp)