From 56867e96d54982156d349709a2dfaee84616a587 Mon Sep 17 00:00:00 2001 From: Nikolay Tkachenko Date: Mon, 19 Aug 2024 21:29:14 +0700 Subject: [PATCH] Release/0.8.0 (#110) * Update dependencies * Bump up APIFW version to v0.8.0 * Bump up Go version to 1.21.13 * Fix GraphQL configuration issue * Add DNS cache * Add basic test for DNS LB cache --- .github/workflows/binaries.yml | 8 +- Makefile | 8 +- .../internal/handlers/proxy/health.go | 4 +- cmd/api-firewall/main.go | 19 +- cmd/api-firewall/tests/main_dns_test.go | 93 +++++++ .../tests/main_graphql_bench_test.go | 2 +- cmd/api-firewall/tests/main_graphql_test.go | 13 +- cmd/api-firewall/tests/main_json_test.go | 8 +- cmd/api-firewall/tests/main_modsec_test.go | 64 ++--- cmd/api-firewall/tests/main_test.go | 241 +++++++++++------ cmd/api-firewall/tests/wallarm_api2_update.db | Bin 98304 -> 98304 bytes .../OWASP_CoreRuleSet/docker-compose.yml | 2 +- .../docker-compose-api-mode.yml | 2 +- .../docker-compose-graphql-mode.yml | 2 +- demo/docker-compose/docker-compose.yml | 2 +- docs/release-notes.md | 2 +- go.mod | 39 +-- go.sum | 205 +++++++++------ helm/api-firewall/Chart.yaml | 2 +- internal/config/config.go | 15 ++ internal/mid/proxy.go | 2 + internal/platform/proxy/chainpool.go | 246 ++++++++++++++---- .../{httppool_mock.go => chainpool_mock.go} | 29 +-- internal/platform/proxy/dnscache.go | 158 +++++++++++ internal/platform/proxy/dnscache_mock.go | 90 +++++++ internal/platform/proxy/proxy.go | 4 +- internal/platform/storage/storage.go | 19 +- .../platform/validator/validate_response.go | 10 - resources/test/docker-compose-api-mode.yml | 2 +- resources/test/modsec/coraza.conf | 2 +- 30 files changed, 961 insertions(+), 332 deletions(-) create mode 100644 cmd/api-firewall/tests/main_dns_test.go rename internal/platform/proxy/{httppool_mock.go => chainpool_mock.go} (81%) create mode 100644 internal/platform/proxy/dnscache.go create mode 100644 internal/platform/proxy/dnscache_mock.go diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 23d06ffe..3407e720 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -51,7 +51,7 @@ jobs: needs: - draft-release env: - X_GO_DISTRIBUTION: "https://go.dev/dl/go1.21.12.linux-amd64.tar.gz" + X_GO_DISTRIBUTION: "https://go.dev/dl/go1.21.13.linux-amd64.tar.gz" strategy: matrix: include: @@ -160,7 +160,7 @@ jobs: needs: - draft-release env: - X_GO_VERSION: "1.21.12" + X_GO_VERSION: "1.21.13" strategy: matrix: include: @@ -267,11 +267,11 @@ jobs: include: - arch: armv6 distro: bullseye - go_distribution: https://go.dev/dl/go1.21.12.linux-armv6l.tar.gz + go_distribution: https://go.dev/dl/go1.21.13.linux-armv6l.tar.gz artifact: armv6-libc - arch: aarch64 distro: bullseye - go_distribution: https://go.dev/dl/go1.21.12.linux-arm64.tar.gz + go_distribution: https://go.dev/dl/go1.21.13.linux-arm64.tar.gz artifact: arm64-libc - arch: armv6 distro: alpine_latest diff --git a/Makefile b/Makefile index 52fef8ed..b236713c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION := 0.7.4 +VERSION := 0.8.0 .DEFAULT_GOAL := build @@ -13,14 +13,16 @@ tidy: go mod vendor test: - go test ./... -count=1 -race -cover + go test ./... -count=1 -race -cover -run '^Test[^W]' + go test ./cmd/api-firewall/tests/main_dns_test.go bench: GOMAXPROCS=1 go test -v -bench=. -benchtime=1000x -count 5 -benchmem -run BenchmarkWSGraphQL ./cmd/api-firewall/tests GOMAXPROCS=4 go test -v -bench=. -benchtime=1000x -count 5 -benchmem -run BenchmarkWSGraphQL ./cmd/api-firewall/tests genmocks: - mockgen -source ./internal/platform/proxy/chainpool.go -destination ./internal/platform/proxy/httppool_mock.go -package proxy + mockgen -source ./internal/platform/proxy/chainpool.go -destination ./internal/platform/proxy/chainpool_mock.go -package proxy + mockgen -source ./internal/platform/proxy/dnscache.go -destination ./internal/platform/proxy/dnscache_mock.go -package proxy mockgen -source ./internal/platform/storage/storage.go -destination ./internal/platform/storage/storage_mock.go -package storage mockgen -source ./internal/platform/storage/updater/updater.go -destination ./internal/platform/storage/updater/updater_mock.go -package updater mockgen -source ./internal/platform/proxy/ws.go -destination ./internal/platform/proxy/ws_mock.go -package proxy diff --git a/cmd/api-firewall/internal/handlers/proxy/health.go b/cmd/api-firewall/internal/handlers/proxy/health.go index 63342b44..10a29e75 100644 --- a/cmd/api-firewall/internal/handlers/proxy/health.go +++ b/cmd/api-firewall/internal/handlers/proxy/health.go @@ -21,14 +21,14 @@ func (h Health) Readiness(ctx *fasthttp.RequestCtx) error { status := "ok" statusCode := fasthttp.StatusOK - reverseProxy, err := h.Pool.Get() + reverseProxy, ip, err := h.Pool.Get() if err != nil { status = "not ready" statusCode = fasthttp.StatusInternalServerError } if reverseProxy != nil { - if err := h.Pool.Put(reverseProxy); err != nil { + if err := h.Pool.Put(ip, reverseProxy); err != nil { status = "not ready" statusCode = fasthttp.StatusInternalServerError } diff --git a/cmd/api-firewall/main.go b/cmd/api-firewall/main.go index e2da21cf..cde519f6 100644 --- a/cmd/api-firewall/main.go +++ b/cmd/api-firewall/main.go @@ -4,6 +4,7 @@ import ( "expvar" // Register the expvar handlers "fmt" "mime" + "net" "net/url" "os" "os/signal" @@ -467,7 +468,7 @@ func runGraphQLMode(logger *logrus.Logger) error { WriteTimeout: cfg.Server.WriteTimeout, DialTimeout: cfg.Server.DialTimeout, } - pool, err := proxy.NewChanPool(host, &options) + pool, err := proxy.NewChanPool(host, &options, nil) if err != nil { return errors.Wrap(err, "proxy pool init") } @@ -626,6 +627,9 @@ func runGraphQLMode(logger *logrus.Logger) error { return errors.Wrap(err, "could not stop server gracefully") } logger.Infof("%s: %v: Completed shutdown", logPrefix, sig) + + // Close proxy pool + pool.Close() } return nil @@ -773,6 +777,16 @@ func runProxyMode(logger *logrus.Logger) error { initialCap = 1 } + var dnsCacheResolver proxy.DNSCache + + // init DNS resolver + if cfg.DNS.Cache { + dnsCacheResolver, err = proxy.NewDNSResolver(cfg.DNS.FetchTimeout, cfg.DNS.LookupTimeout, &net.Resolver{PreferGo: true}, logger) + if err != nil { + return errors.Wrap(err, "DNS cache resolver init") + } + } + options := proxy.Options{ InitialPoolCapacity: initialCap, ClientPoolCapacity: cfg.Server.ClientPoolCapacity, @@ -782,8 +796,9 @@ func runProxyMode(logger *logrus.Logger) error { ReadTimeout: cfg.Server.ReadTimeout, WriteTimeout: cfg.Server.WriteTimeout, DialTimeout: cfg.Server.DialTimeout, + DNSConfig: cfg.DNS, } - pool, err := proxy.NewChanPool(host, &options) + pool, err := proxy.NewChanPool(host, &options, dnsCacheResolver) if err != nil { return errors.Wrap(err, "proxy pool init") } diff --git a/cmd/api-firewall/tests/main_dns_test.go b/cmd/api-firewall/tests/main_dns_test.go new file mode 100644 index 00000000..868b4bf9 --- /dev/null +++ b/cmd/api-firewall/tests/main_dns_test.go @@ -0,0 +1,93 @@ +package tests + +import ( + "context" + "net" + "testing" + "time" + + "github.com/foxcpp/go-mockdns" + "github.com/sirupsen/logrus" + "github.com/wallarm/api-firewall/internal/config" + "github.com/wallarm/api-firewall/internal/platform/proxy" +) + +func TestWithoutRCCDNSCacheBasic(t *testing.T) { + + logger := logrus.New() + logger.SetLevel(logrus.ErrorLevel) + + var cfg = config.ProxyMode{ + RequestValidation: "BLOCK", + ResponseValidation: "BLOCK", + CustomBlockStatusCode: 403, + AddValidationStatusHeader: false, + ShadowAPI: config.ShadowAPI{ + ExcludeList: []int{404, 401}, + }, + DNS: config.DNS{ + Cache: true, + FetchTimeout: 1000 * time.Millisecond, + LookupTimeout: 400 * time.Millisecond, + }, + } + + srv, _ := mockdns.NewServer(map[string]mockdns.Zone{ + "example.org.": { + A: []string{"1.2.3.4", "5.6.7.8"}, + }, + }, false) + defer srv.Close() + + srUpdatedOrder, _ := mockdns.NewServer(map[string]mockdns.Zone{ + "example.org.": { + A: []string{"5.6.7.8", "1.2.3.4"}, + }, + }, false) + defer srUpdatedOrder.Close() + + r := &net.Resolver{} + srv.PatchNet(r) + + dnsCache, err := proxy.NewDNSResolver(cfg.DNS.FetchTimeout, cfg.DNS.LookupTimeout, r, logger) + if err != nil { + t.Fatal(err) + } + defer dnsCache.Stop() + + addr, err := dnsCache.Fetch(context.Background(), "example.org") + if err != nil { + t.Error(err) + } + + if addr[0].String() != "1.2.3.4" { + t.Errorf("Incorrect response from local DNS server. Expected: 1.2.3.4 and got %s", + addr[0].String()) + } + + srUpdatedOrder.PatchNet(r) + + time.Sleep(600 * time.Millisecond) + + addr, err = dnsCache.Fetch(context.Background(), "example.org") + if err != nil { + t.Error(err) + } + + if addr[0].String() != "1.2.3.4" { + t.Errorf("Incorrect response from local DNS server. Expected: 1.2.3.4 and got %s", + addr[0].String()) + } + + time.Sleep(800 * time.Millisecond) + + addr, err = dnsCache.Fetch(context.Background(), "example.org") + if err != nil { + t.Error(err) + } + + if addr[0].String() != "5.6.7.8" { + t.Errorf("Incorrect response from local DNS server. Expected: 5.6.7.8 and got %s", + addr[0].String()) + } +} diff --git a/cmd/api-firewall/tests/main_graphql_bench_test.go b/cmd/api-firewall/tests/main_graphql_bench_test.go index 772e969d..62f8c4a3 100644 --- a/cmd/api-firewall/tests/main_graphql_bench_test.go +++ b/cmd/api-firewall/tests/main_graphql_bench_test.go @@ -134,7 +134,7 @@ func BenchmarkGraphQL(b *testing.B) { WriteTimeout: 5 * time.Second, DialTimeout: 5 * time.Second, } - pool, err := proxy.NewChanPool(host, &options) + pool, err := proxy.NewChanPool(host, &options, nil) if err != nil { b.Fatalf("proxy pool init: %v", err) } diff --git a/cmd/api-firewall/tests/main_graphql_test.go b/cmd/api-firewall/tests/main_graphql_test.go index 6d90ee11..2fc3b722 100644 --- a/cmd/api-firewall/tests/main_graphql_test.go +++ b/cmd/api-firewall/tests/main_graphql_test.go @@ -18,6 +18,7 @@ import ( "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" "github.com/valyala/fasthttp" + graphqlHandler "github.com/wallarm/api-firewall/cmd/api-firewall/internal/handlers/graphql" "github.com/wallarm/api-firewall/internal/config" "github.com/wallarm/api-firewall/internal/platform/denylist" @@ -211,9 +212,9 @@ func (s *ServiceGraphQLTests) testGQLSuccess(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil).Times(1) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil).Times(1) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp).Times(1) - s.proxy.EXPECT().Put(s.client).Return(nil).Times(1) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil).Times(1) handler(&reqCtx) @@ -384,9 +385,9 @@ func (s *ServiceGraphQLTests) testGQLGETSuccess(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil).Times(1) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil).Times(1) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp).Times(1) - s.proxy.EXPECT().Put(s.client).Return(nil).Times(1) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil).Times(1) handler(&reqCtx) @@ -1715,9 +1716,9 @@ func (s *ServiceGraphQLTests) testGQLDuplicateFields(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil).AnyTimes() + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil).AnyTimes() s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp).AnyTimes() - s.proxy.EXPECT().Put(s.client).Return(nil).AnyTimes() + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil).AnyTimes() handler(&reqCtx) diff --git a/cmd/api-firewall/tests/main_json_test.go b/cmd/api-firewall/tests/main_json_test.go index e2e9686d..10247311 100644 --- a/cmd/api-firewall/tests/main_json_test.go +++ b/cmd/api-firewall/tests/main_json_test.go @@ -172,9 +172,9 @@ func (s *ServiceTests) testBasicObjJSONFieldValidation(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -219,9 +219,9 @@ func (s *ServiceTests) testBasicArrJSONFieldValidation(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) diff --git a/cmd/api-firewall/tests/main_modsec_test.go b/cmd/api-firewall/tests/main_modsec_test.go index dda81dc4..52b018d8 100644 --- a/cmd/api-firewall/tests/main_modsec_test.go +++ b/cmd/api-firewall/tests/main_modsec_test.go @@ -229,9 +229,9 @@ func (s *ModSecIntegrationTests) basicMaliciousRequestBlockMode(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -283,9 +283,9 @@ func (s *ModSecIntegrationTests) basicMaliciousRequestLogOnlyMode(t *testing.T) Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -301,9 +301,9 @@ func (s *ModSecIntegrationTests) basicMaliciousRequestLogOnlyMode(t *testing.T) Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -350,9 +350,9 @@ func (s *ModSecIntegrationTests) basicMaliciousRequestDisableMode(t *testing.T) Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -368,9 +368,9 @@ func (s *ModSecIntegrationTests) basicMaliciousRequestDisableMode(t *testing.T) Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -411,9 +411,9 @@ func (s *ModSecIntegrationTests) basicMaliciousResponseBlockMode(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -433,9 +433,9 @@ func (s *ModSecIntegrationTests) basicMaliciousResponseBlockMode(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -473,9 +473,9 @@ func (s *ModSecIntegrationTests) basicMaliciousResponseLogOnlyMode(t *testing.T) Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -495,9 +495,9 @@ func (s *ModSecIntegrationTests) basicMaliciousResponseLogOnlyMode(t *testing.T) Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -544,9 +544,9 @@ func (s *ModSecIntegrationTests) basicMaliciousResponseDisableMode(t *testing.T) Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -566,9 +566,9 @@ func (s *ModSecIntegrationTests) basicMaliciousResponseDisableMode(t *testing.T) Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -612,9 +612,9 @@ func (s *ModSecIntegrationTests) basicMaliciousRequestBody(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -668,9 +668,9 @@ func (s *ModSecIntegrationTests) basicMaliciousRequestHeader(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -732,9 +732,9 @@ func (s *ModSecIntegrationTests) basicMaliciousRequestCookie(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -796,9 +796,9 @@ func (s *ModSecIntegrationTests) basicMaliciousRequestPath(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -859,9 +859,9 @@ func (s *ModSecIntegrationTests) basicResponseActionRedirect(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) diff --git a/cmd/api-firewall/tests/main_test.go b/cmd/api-firewall/tests/main_test.go index cc678c88..aab9ec16 100644 --- a/cmd/api-firewall/tests/main_test.go +++ b/cmd/api-firewall/tests/main_test.go @@ -7,8 +7,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getkin/kin-openapi/openapi3" - "github.com/savsgio/gotils/strconv" "io" "net" "net/url" @@ -20,8 +18,10 @@ import ( "time" "github.com/andybalholm/brotli" + "github.com/getkin/kin-openapi/openapi3" "github.com/golang/mock/gomock" "github.com/google/uuid" + "github.com/savsgio/gotils/strconv" "github.com/sirupsen/logrus" "github.com/valyala/fasthttp" @@ -33,7 +33,9 @@ import ( "github.com/wallarm/api-firewall/internal/platform/storage" ) -const openAPISpecTest = ` +const ( + resolvedIP = "127.0.0.1" + openAPISpecTest = ` openapi: 3.0.1 info: title: Service @@ -319,6 +321,7 @@ components: read: read write: write ` +) var testSupportedEncodingSchemas = []string{"gzip", "deflate", "br"} @@ -354,6 +357,7 @@ type ServiceTests struct { client *proxy.MockHTTPClient lock *sync.RWMutex dbSpec *storage.MockDBOpenAPILoader + dnsCache *proxy.MockDNSCache } func compressFlate(data []byte) ([]byte, error) { @@ -428,6 +432,7 @@ func TestBasic(t *testing.T) { pool := proxy.NewMockPool(mockCtrl) client := proxy.NewMockHTTPClient(mockCtrl) + dnsCache := proxy.NewMockDNSCache(mockCtrl) swagger, err := openapi3.NewLoader().LoadFromData([]byte(openAPISpecTest)) if err != nil { @@ -451,6 +456,7 @@ func TestBasic(t *testing.T) { client: client, lock: &lock, dbSpec: dbSpec, + dnsCache: dnsCache, } // basic test @@ -498,6 +504,9 @@ func TestBasic(t *testing.T) { t.Run("testCustomHostHeader", apifwTests.testCustomHostHeader) t.Run("testCustomHeaderOASviaURL", apifwTests.testCustomHeaderOASviaURL) + + // dns cache + t.Run("testDNSCacheFetch", apifwTests.testDNSCacheFetch) } func (s *ServiceTests) testCustomBlockStatusCode(t *testing.T) { @@ -652,9 +661,9 @@ func (s *ServiceTests) testPathNotExists(t *testing.T) { handler = proxy2.Handlers(s.lock, &cfg, s.serverUrl, s.shutdown, s.logger, s.proxy, s.dbSpec, nil, nil, nil) - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) reqCtx = fasthttp.RequestCtx{ Request: *req, @@ -680,9 +689,9 @@ func (s *ServiceTests) testPathNotExists(t *testing.T) { handler = proxy2.Handlers(s.lock, &cfg, s.serverUrl, s.shutdown, s.logger, s.proxy, s.dbSpec, nil, nil, nil) - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) reqCtx = fasthttp.RequestCtx{ Request: *req, @@ -738,9 +747,9 @@ func (s *ServiceTests) testBlockMode(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -828,9 +837,9 @@ func (s *ServiceTests) testDenylist(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -939,9 +948,9 @@ func (s *ServiceTests) testAllowlist(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1026,9 +1035,9 @@ func (s *ServiceTests) testAllowlistXForwardedFor(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1044,9 +1053,9 @@ func (s *ServiceTests) testAllowlistXForwardedFor(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1121,9 +1130,9 @@ func (s *ServiceTests) testShadowAPI(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1174,9 +1183,9 @@ func (s *ServiceTests) testLogOnlyMode(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1225,9 +1234,9 @@ func (s *ServiceTests) testDisableMode(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1278,9 +1287,9 @@ func (s *ServiceTests) testBlockLogOnlyMode(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1330,9 +1339,9 @@ func (s *ServiceTests) testLogOnlyBlockMode(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1368,9 +1377,9 @@ func (s *ServiceTests) testCommonParameters(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1500,9 +1509,9 @@ func (s *ServiceTests) testOauthIntrospectionReadSuccess(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1518,9 +1527,9 @@ func (s *ServiceTests) testOauthIntrospectionReadSuccess(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1719,9 +1728,9 @@ func (s *ServiceTests) testOauthIntrospectionReadWriteSuccess(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1790,9 +1799,9 @@ func (s *ServiceTests) testOauthIntrospectionContentTypeRequest(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1853,9 +1862,9 @@ func (s *ServiceTests) testOauthJWTRS256(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1930,9 +1939,9 @@ func (s *ServiceTests) testOauthJWTHS256(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -1987,9 +1996,9 @@ func (s *ServiceTests) testRequestHeaders(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2044,9 +2053,9 @@ func (s *ServiceTests) testResponseHeaders(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2062,9 +2071,9 @@ func (s *ServiceTests) testResponseHeaders(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client) + s.proxy.EXPECT().Put(resolvedIP, s.client) handler(&reqCtx) @@ -2133,9 +2142,9 @@ func (s *ServiceTests) testRequestBodyCompression(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2233,9 +2242,9 @@ func (s *ServiceTests) testResponseBodyCompression(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2257,9 +2266,9 @@ func (s *ServiceTests) testResponseBodyCompression(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client) + s.proxy.EXPECT().Put(resolvedIP, s.client) handler(&reqCtx) @@ -2300,9 +2309,9 @@ func (s *ServiceTests) requestOptionalCookies(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2318,9 +2327,9 @@ func (s *ServiceTests) requestOptionalCookies(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2388,9 +2397,9 @@ func (s *ServiceTests) requestOptionalMinMaxCookies(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2406,9 +2415,9 @@ func (s *ServiceTests) requestOptionalMinMaxCookies(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2487,9 +2496,9 @@ func (s *ServiceTests) unknownParamQuery(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2541,9 +2550,9 @@ func (s *ServiceTests) unknownParamPostBody(t *testing.T) { resp.Header.SetContentType("application/json") resp.SetBody([]byte("{\"status\":\"success\"}")) - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) reqCtx := fasthttp.RequestCtx{ Request: *req, @@ -2609,9 +2618,9 @@ func (s *ServiceTests) unknownParamJSONParam(t *testing.T) { resp.Header.SetContentType("application/json") resp.SetBody([]byte("{\"status\":\"success\"}")) - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) reqCtx := fasthttp.RequestCtx{ Request: *req, @@ -2678,9 +2687,9 @@ func (s *ServiceTests) unknownParamUnsupportedMimeType(t *testing.T) { resp.Header.SetContentType("application/json") resp.SetBody([]byte("{\"status\":\"success\"}")) - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) reqCtx := fasthttp.RequestCtx{ Request: *req, @@ -2699,9 +2708,9 @@ func (s *ServiceTests) unknownParamUnsupportedMimeType(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2739,9 +2748,9 @@ func (s *ServiceTests) testConflictPaths(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2758,9 +2767,9 @@ func (s *ServiceTests) testConflictPaths(t *testing.T) { Request: *req, } - s.proxy.EXPECT().Get().Return(s.client, nil) + s.proxy.EXPECT().Get().Return(s.client, resolvedIP, nil) s.client.EXPECT().Do(gomock.Any(), gomock.Any()).SetArg(1, *resp) - s.proxy.EXPECT().Put(s.client).Return(nil) + s.proxy.EXPECT().Put(resolvedIP, s.client).Return(nil) handler(&reqCtx) @@ -2788,6 +2797,10 @@ func checkCustomHeaderEndpoint(ctx *fasthttp.RequestCtx) { } } +func alwaysSuccessResponse(ctx *fasthttp.RequestCtx) { + ctx.SetStatusCode(fasthttp.StatusOK) +} + func (s *ServiceTests) testCustomHostHeader(t *testing.T) { req := fasthttp.AcquireRequest() @@ -2833,7 +2846,7 @@ func (s *ServiceTests) testCustomHostHeader(t *testing.T) { WriteTimeout: cfg.Server.WriteTimeout, DialTimeout: cfg.Server.DialTimeout, } - pool, err := proxy.NewChanPool("localhost:28290", &options) + pool, err := proxy.NewChanPool("localhost:28290", &options, nil) if err != nil { t.Fatal(err) } @@ -2878,3 +2891,79 @@ func (s *ServiceTests) testCustomHeaderOASviaURL(t *testing.T) { } } + +func (s *ServiceTests) testDNSCacheFetch(t *testing.T) { + + req := fasthttp.AcquireRequest() + req.SetRequestURI("/get/test") + req.Header.SetMethod("GET") + req.Header.SetHost("wrongHost") + + port := 28290 + defer startServerOnPort(t, port, alwaysSuccessResponse).Close() + + serverConf := config.Server{ + Backend: config.Backend{ + URL: "http://localhost:28290", + RequestHostHeader: "testCustomHost", + ClientPoolCapacity: 1, + InsecureConnection: false, + RootCA: "", + MaxConnsPerHost: 512, + ReadTimeout: time.Second * 5, + WriteTimeout: time.Second * 5, + DialTimeout: time.Second * 5, + }, + } + + var cfg = config.ProxyMode{ + RequestValidation: "BLOCK", + ResponseValidation: "BLOCK", + CustomBlockStatusCode: 403, + AddValidationStatusHeader: false, + ShadowAPI: config.ShadowAPI{ + ExcludeList: []int{404, 401}, + }, + Server: serverConf, + DNS: config.DNS{ + Cache: true, + FetchTimeout: 200 * time.Millisecond, + }, + } + + options := proxy.Options{ + InitialPoolCapacity: 1, + ClientPoolCapacity: cfg.Server.ClientPoolCapacity, + InsecureConnection: cfg.Server.InsecureConnection, + RootCA: cfg.Server.RootCA, + MaxConnsPerHost: cfg.Server.MaxConnsPerHost, + ReadTimeout: cfg.Server.ReadTimeout, + WriteTimeout: cfg.Server.WriteTimeout, + DialTimeout: cfg.Server.DialTimeout, + DNSConfig: cfg.DNS, + } + + localIP := net.ParseIP("127.0.0.1") + ips := []net.IP{localIP} + + s.dnsCache.EXPECT().Fetch(gomock.Any(), gomock.Any()).Return(ips, nil).Times(3) + + pool, err := proxy.NewChanPool("localhost:28290", &options, s.dnsCache) + if err != nil { + t.Fatal(err) + } + + reqCtx := fasthttp.RequestCtx{ + Request: *req, + } + + if err := proxy.Perform(&reqCtx, pool, cfg.Server.RequestHostHeader); err != nil { + t.Fatal(err) + } + + if reqCtx.Response.StatusCode() != 200 { + t.Errorf("Incorrect response status code. Expected: 200 and got %d", + reqCtx.Response.StatusCode()) + } + +} diff --git a/cmd/api-firewall/tests/wallarm_api2_update.db b/cmd/api-firewall/tests/wallarm_api2_update.db index 3860563816f25d260ae93ba9ece1af0879f87c61..478046eb3f83a90666e5a461a54d6512fe85ac5b 100644 GIT binary patch delta 36 qcmZo@U~6b#n;^x+t}#)@2}o{Ch>~SY-n?7ZMTjxE$zYiQV*miU)Cv*+ delta 36 qcmZo@U~6b#n;^x+raV!`2}o{Ch>~UG*}PlUMTn87$zYiQV*miMn+aF| diff --git a/demo/docker-compose/OWASP_CoreRuleSet/docker-compose.yml b/demo/docker-compose/OWASP_CoreRuleSet/docker-compose.yml index 705e49e0..6152c35e 100644 --- a/demo/docker-compose/OWASP_CoreRuleSet/docker-compose.yml +++ b/demo/docker-compose/OWASP_CoreRuleSet/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.8" services: api-firewall: container_name: api-firewall - image: wallarm/api-firewall:v0.7.4 + image: wallarm/api-firewall:v0.8.0 restart: on-failure environment: APIFW_URL: "http://0.0.0.0:8080" diff --git a/demo/docker-compose/docker-compose-api-mode.yml b/demo/docker-compose/docker-compose-api-mode.yml index 56cd40e2..2f816b1f 100644 --- a/demo/docker-compose/docker-compose-api-mode.yml +++ b/demo/docker-compose/docker-compose-api-mode.yml @@ -2,7 +2,7 @@ version: '3.8' services: api-firewall: container_name: api-firewall - image: wallarm/api-firewall:v0.7.4 + image: wallarm/api-firewall:v0.8.0 restart: on-failure environment: APIFW_MODE: "api" diff --git a/demo/docker-compose/docker-compose-graphql-mode.yml b/demo/docker-compose/docker-compose-graphql-mode.yml index 0165c881..d4b12410 100644 --- a/demo/docker-compose/docker-compose-graphql-mode.yml +++ b/demo/docker-compose/docker-compose-graphql-mode.yml @@ -2,7 +2,7 @@ version: '3.8' services: api-firewall: container_name: api-firewall - image: wallarm/api-firewall:v0.7.4 + image: wallarm/api-firewall:v0.8.0 restart: on-failure environment: APIFW_MODE: "graphql" diff --git a/demo/docker-compose/docker-compose.yml b/demo/docker-compose/docker-compose.yml index 4c2ee447..121eba1f 100644 --- a/demo/docker-compose/docker-compose.yml +++ b/demo/docker-compose/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.8" services: api-firewall: container_name: api-firewall - image: wallarm/api-firewall:v0.7.4 + image: wallarm/api-firewall:v0.8.0 restart: on-failure environment: APIFW_URL: "http://0.0.0.0:8080" diff --git a/docs/release-notes.md b/docs/release-notes.md index 3e9e4b56..1c0fd1f2 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,7 +2,7 @@ This page describes new releases of Wallarm API Firewall. -## v0.8.0 (2024-08-DD) +## v0.8.0 (2024-08-19) * Added [DNS cache update](configuration-guides/dns-cache-update.md) feature diff --git a/go.mod b/go.mod index 081bb00e..8c07e645 100644 --- a/go.mod +++ b/go.mod @@ -6,9 +6,10 @@ require ( github.com/andybalholm/brotli v1.1.0 github.com/ardanlabs/conf v1.5.0 github.com/clbanning/mxj/v2 v2.7.0 - github.com/corazawaf/coraza/v3 v3.1.0 + github.com/corazawaf/coraza/v3 v3.2.1 github.com/dgraph-io/ristretto v0.1.1 - github.com/fasthttp/websocket v1.5.8 + github.com/fasthttp/websocket v1.5.10 + github.com/foxcpp/go-mockdns v1.1.0 github.com/gabriel-vasile/mimetype v1.4.3 github.com/getkin/kin-openapi v0.124.0 github.com/go-playground/validator v9.31.0+incompatible @@ -16,15 +17,15 @@ require ( github.com/golang/mock v1.6.0 github.com/google/uuid v1.6.0 github.com/karlseguin/ccache/v2 v2.0.8 - github.com/klauspost/compress v1.17.8 + github.com/klauspost/compress v1.17.9 github.com/mattn/go-sqlite3 v1.14.22 github.com/pkg/errors v0.9.1 - github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511 + github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 - github.com/valyala/fasthttp v1.54.0 + github.com/valyala/fasthttp v1.55.0 github.com/valyala/fastjson v1.6.4 - github.com/wundergraph/graphql-go-tools v1.67.2 + github.com/wundergraph/graphql-go-tools v1.67.4 golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 golang.org/x/sync v0.7.0 gopkg.in/yaml.v3 v3.0.1 @@ -35,8 +36,8 @@ require ( github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/buger/jsonparser v1.1.1 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/corazawaf/libinjection-go v0.1.3 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/corazawaf/libinjection-go v0.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/eclipse/paho.mqtt.golang v1.2.0 // indirect @@ -44,8 +45,8 @@ require ( github.com/go-openapi/swag v0.22.8 // indirect github.com/go-playground/locales v0.13.0 // indirect github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect - github.com/golang/protobuf v1.5.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/huandu/xstrings v1.2.1 // indirect @@ -58,31 +59,31 @@ require ( github.com/leodido/go-urn v1.2.0 // indirect github.com/magefile/mage v1.15.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/minio/highwayhash v1.0.2 // indirect + github.com/miekg/dns v1.1.61 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/nats-io/jwt/v2 v2.5.5 // indirect - github.com/nats-io/nats.go v1.19.1 // indirect + github.com/nats-io/nats.go v1.34.1 // indirect github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e // indirect + github.com/petar-dambovaliev/aho-corasick v0.0.0-20240411101913-e07a1f0e8eb4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/r3labs/sse/v2 v2.8.1 // indirect - github.com/santhosh-tekuri/jsonschema/v5 v5.3.0 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/tidwall/gjson v1.17.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect - github.com/tidwall/sjson v1.0.4 // indirect + github.com/tidwall/sjson v1.2.5 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.18.1 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.26.0 // indirect golang.org/x/crypto v0.24.0 // indirect + golang.org/x/mod v0.18.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/sys v0.21.0 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/tools v0.22.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/go-playground/assert.v1 v1.2.1 // indirect diff --git a/go.sum b/go.sum index 887123ec..603c8f07 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/99designs/gqlgen v0.17.22 h1:TOcrF8t0T3I0za9JD3CB6ehq7dDEMjR9Onikf8Lc/04= -github.com/99designs/gqlgen v0.17.22/go.mod h1:BMhYIhe4bp7OlCo5I2PnowSK/Wimpv/YlxfNkqZGwLo= +github.com/99designs/gqlgen v0.17.45 h1:bH0AH67vIJo8JKNKPJP+pOPpQhZeuVRQLf53dKIpDik= +github.com/99designs/gqlgen v0.17.45/go.mod h1:Bas0XQ+Jiu/Xm5E33jC8sES3G+iC2esHBMXcq0fUPs0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -14,19 +14,23 @@ github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/ardanlabs/conf v1.5.0 h1:5TwP6Wu9Xi07eLFEpiCUF3oQXh9UzHMDVnD3u/I5d5c= github.com/ardanlabs/conf v1.5.0/go.mod h1:ILsMo9dMqYzCxDjDXTiwMI0IgxOJd0MOiucbQY2wlJw= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bytedance/sonic v1.10.0-rc h1:3S5HeWxjX08CUqNrXtEittExpJsEKBNzrV5UnrzHxVQ= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= +github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= -github.com/corazawaf/coraza/v3 v3.1.0 h1:CB6YxNXdbZjUJS/0FVFoFvS8eOVFbIvlNuHNC5dh88c= -github.com/corazawaf/coraza/v3 v3.1.0/go.mod h1:S0bhYQfTu1Ew3YKdI37X1WWu6t4En4Tvw28aKyQFJaU= -github.com/corazawaf/libinjection-go v0.1.3 h1:PUplAYho1BBl0tIVbhDsNRuVGIeUYSiCEc9oQpb2rJU= -github.com/corazawaf/libinjection-go v0.1.3/go.mod h1:OP4TM7xdJ2skyXqNX1AN1wN5nNZEmJNuWbNPOItn7aw= +github.com/corazawaf/coraza/v3 v3.2.1 h1:zBIji4ut9FtFe8lXdqFwXMAkUoDJZ7HsOlEUYWERLI8= +github.com/corazawaf/coraza/v3 v3.2.1/go.mod h1:fVndCGdUHJWl9c26VZPcORQRzUYwMPnRkC6TyTkhbUg= +github.com/corazawaf/libinjection-go v0.2.1 h1:vNJ7L6c4xkhRgYU6sIO0Tl54TmeCQv/yfxBma30Dy/Y= +github.com/corazawaf/libinjection-go v0.2.1/go.mod h1:OP4TM7xdJ2skyXqNX1AN1wN5nNZEmJNuWbNPOItn7aw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -40,8 +44,8 @@ github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+SwCLQg= github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/fasthttp/websocket v1.5.8 h1:k5DpirKkftIF/w1R8ZzjSgARJrs54Je9YJK37DL/Ah8= -github.com/fasthttp/websocket v1.5.8/go.mod h1:d08g8WaT6nnyvg9uMm8K9zMYyDjfKyj3170AtPRuVU0= +github.com/fasthttp/websocket v1.5.10 h1:bc7NIGyrg1L6sd5pRzCIbXpro54SZLEluZCu0rOpcN4= +github.com/fasthttp/websocket v1.5.10/go.mod h1:BwHeuXGWzCW1/BIKUKD3+qfCl+cTdsHu/f243NcAI/Q= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= @@ -50,8 +54,9 @@ github.com/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/swag v0.22.8 h1:/9RjDSQ0vbFR+NyjGMkFTsA1IA0fmhKSThmfGZjicbw= @@ -63,17 +68,22 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA= github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= +github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs= -github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU= +github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -82,13 +92,12 @@ github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -97,10 +106,12 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/huandu/xstrings v1.2.1 h1:v6IdmkCnDhJG/S0ivr58PeIfg+tyhqQYy4YsCsQ0Pdc= github.com/huandu/xstrings v1.2.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= @@ -125,8 +136,10 @@ github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003 h1:vJ0Snvo+SLM github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -146,14 +159,13 @@ github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= -github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -166,21 +178,18 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLD github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/nats-io/jwt/v2 v2.5.5 h1:ROfXb50elFq5c9+1ztaUbdlrArNFl2+fQWP6B8HGEq4= -github.com/nats-io/jwt/v2 v2.5.5/go.mod h1:ZdWS1nZa6WMZfFwwgpEaqBV8EPGVgOTDHN/wTbz0Y5A= -github.com/nats-io/nats-server/v2 v2.8.2 h1:5m1VytMEbZx0YINvKY+X2gXdLNwP43uLXnFRwz8j8KE= -github.com/nats-io/nats-server/v2 v2.8.2/go.mod h1:vIdpKz3OG+DCg4q/xVPdXHoztEyKDWRtykQ4N7hd7C4= -github.com/nats-io/nats.go v1.19.1 h1:pDQZthDfxRMSJ0ereExAM9ODf3JyS42Exk7iCMdbpec= -github.com/nats-io/nats.go v1.19.1/go.mod h1:tLqubohF7t4z3du1QDPYJIQQyhb4wl6DhjxEajSI7UA= -github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4= +github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= +github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= -github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e h1:POJco99aNgosh92lGqmx7L1ei+kCymivB/419SD15PQ= -github.com/petar-dambovaliev/aho-corasick v0.0.0-20230725210150-fb29fc3c913e/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw= +github.com/petar-dambovaliev/aho-corasick v0.0.0-20240411101913-e07a1f0e8eb4 h1:1Kw2vDBXmjop+LclnzCb/fFy+sgb3gYARwfmoUcQe6o= +github.com/petar-dambovaliev/aho-corasick v0.0.0-20240411101913-e07a1f0e8eb4/go.mod h1:EHPiTAKtiFmrMldLUNswFwfZ2eJIYBHktdaUTZxYWRw= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -191,17 +200,19 @@ github.com/r3labs/sse/v2 v2.8.1/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEm github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.0 h1:uIkTLo0AGRc8l7h5l9r+GcYi9qfVPt6lD4/bhmzfiKo= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0= -github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511 h1:KanIMPX0QdEdB4R3CiimCAbxFrhB3j7h0/OvpYGVQa8= -github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc= +github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y= github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sosodev/duration v1.2.0 h1:pqK/FLSjsAADWY74SyWDCjOcd5l7H8GSnnOGEB9A1Us= +github.com/sosodev/duration v1.2.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -210,6 +221,7 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -217,8 +229,10 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/sjson v1.0.4 h1:UcdIRXff12Lpnu3OLtZvnc03g4vH2suXDXhBwBqmzYg= -github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= @@ -226,59 +240,76 @@ github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0 github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= 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.54.0 h1:cCL+ZZR3z3HPLMVfEYVUMtJqVaui0+gu7Lx63unHwS0= -github.com/valyala/fasthttp v1.54.0/go.mod h1:6dt4/8olwq9QARP/TDuPmWyWcl4byhpvTJ4AAtcz+QM= +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/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= -github.com/vektah/gqlparser/v2 v2.5.1 h1:ZGu+bquAY23jsxDRcYpWjttRZrUz07LbiY77gUOHcr4= -github.com/vektah/gqlparser/v2 v2.5.1/go.mod h1:mPgqFBu/woKTVYWyNk8cO3kh4S/f4aRFZrvOnp3hmCs= +github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8= +github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ= github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM= -github.com/wundergraph/graphql-go-tools v1.67.2 h1:79cKWyzL6oiYPePORqDgc00eugUK4HI9YuA79rHWMJM= -github.com/wundergraph/graphql-go-tools v1.67.2/go.mod h1:XPiFH1mHduFuQTYiGpQe6ZtNI7/BX4EJQVMXr6oWxw0= +github.com/wundergraph/graphql-go-tools v1.67.4 h1:1QtoftaZz5sScV/J6XLZ/oTfi1lMHp6UmFkYRQfY2/g= +github.com/wundergraph/graphql-go-tools v1.67.4/go.mod h1:UFvflYjB/qnSCdgcHQuE6dTfwZ6viJB7yPnGOtBuibo= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= +golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -286,32 +317,53 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= @@ -328,7 +380,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helm/api-firewall/Chart.yaml b/helm/api-firewall/Chart.yaml index f670de98..99bd539d 100644 --- a/helm/api-firewall/Chart.yaml +++ b/helm/api-firewall/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v1 name: api-firewall version: 0.7.1 -appVersion: 0.7.4 +appVersion: 0.8.0 description: Wallarm OpenAPI-based API Firewall home: https://github.com/wallarm/api-firewall icon: https://static.wallarm.com/wallarm-logo.svg diff --git a/internal/config/config.go b/internal/config/config.go index 6e4d35a0..76cb5d94 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -15,6 +15,12 @@ type CustomHeader struct { Value string } +type Nameserver struct { + Host string `conf:""` + Port string `conf:"default:53"` + Proto string `conf:"default:udp"` +} + type ProxyMode struct { conf.Version APIFWMode @@ -24,6 +30,7 @@ type ProxyMode struct { Denylist Denylist Server Server AllowIP AllowIP + DNS DNS APIHost string `conf:"default:http://0.0.0.0:8282,env:URL" validate:"required,url"` HealthAPIHost string `conf:"default:0.0.0.0:9667,env:HEALTH_HOST" validate:"required"` @@ -103,6 +110,14 @@ type Backend struct { WriteTimeout time.Duration `conf:"default:5s"` DialTimeout time.Duration `conf:"default:200ms"` DeleteAcceptEncoding bool `conf:"default:false"` + DNSLoadBalancing bool `conf:"default:false"` +} + +type DNS struct { + Nameserver Nameserver + Cache bool `conf:"default:false"` + FetchTimeout time.Duration `conf:"default:1m"` + LookupTimeout time.Duration `conf:"default:1s"` } type JWT struct { diff --git a/internal/mid/proxy.go b/internal/mid/proxy.go index c1b25e17..7d389303 100644 --- a/internal/mid/proxy.go +++ b/internal/mid/proxy.go @@ -70,10 +70,12 @@ func Proxy(options *ProxyOptions) web.Middleware { ctx.Request.Header.Add(apifwHeaderName, ctx.UserValue(web.RequestID).(string)) } + // update the request Schema to the server Schema value if !bytes.Equal([]byte(options.ServerURL.Scheme), ctx.Request.URI().Scheme()) { ctx.Request.URI().SetSchemeBytes([]byte(options.ServerURL.Scheme)) } + // update the request Host header to the server Host value if !bytes.Equal([]byte(options.ServerURL.Host), ctx.Request.URI().Host()) { ctx.Request.URI().SetHostBytes([]byte(options.ServerURL.Host)) } diff --git a/internal/platform/proxy/chainpool.go b/internal/platform/proxy/chainpool.go index 3f5b29fe..4e5821e3 100644 --- a/internal/platform/proxy/chainpool.go +++ b/internal/platform/proxy/chainpool.go @@ -5,16 +5,20 @@ package proxy // license that can be found in the LICENSE file. import ( + "context" "crypto/tls" "crypto/x509" "errors" "fmt" "net" "os" + "strings" "sync" "time" "github.com/valyala/fasthttp" + + "github.com/wallarm/api-firewall/internal/config" ) var ( @@ -22,37 +26,81 @@ var ( errClosed = errors.New("err: chan closed") ) +func (p *chanPool) tryResolveAndFetchOneIP(host string) (string, error) { + + var ips []net.IP + var resolvedIP string + var err error + + if p.dnsCacheResolver != nil { + ips, err = p.dnsCacheResolver.Fetch(context.Background(), host) + if err != nil { + return "", err + } + } else { + // resolve host using local resolver + ips, err = p.defaultResolver.LookupIP(context.Background(), "ip", host) + if err != nil { + return "", err + } + } + + for _, ip := range ips { + if ip.To4() != nil { + resolvedIP = ip.String() + return resolvedIP, nil + } + } + + for _, ip := range ips { + if ip.To16() != nil { + resolvedIP = ip.String() + return resolvedIP, nil + } + } + + return resolvedIP, nil +} + type HTTPClient interface { Do(req *fasthttp.Request, resp *fasthttp.Response) error } -func factory(hostAddr string, options *Options, tlsConfig *tls.Config) HTTPClient { +func (p *chanPool) factory(connAddr string) HTTPClient { proxyClient := fasthttp.Client{ + NoDefaultUserAgentHeader: true, + DisableHeaderNamesNormalizing: true, + DisablePathNormalizing: true, Dial: func(addr string) (net.Conn, error) { - return fasthttp.DialTimeout(hostAddr, options.DialTimeout) + return fasthttp.DialTimeout(connAddr, p.options.DialTimeout) }, - TLSConfig: tlsConfig, - MaxConnsPerHost: options.MaxConnsPerHost, - ReadTimeout: options.ReadTimeout, - WriteTimeout: options.WriteTimeout, + TLSConfig: p.tlsConfig, + MaxConnsPerHost: p.options.MaxConnsPerHost, + ReadTimeout: p.options.ReadTimeout, + WriteTimeout: p.options.WriteTimeout, + } + + // use configured NS + if p.options.DNSConfig.Nameserver.Host != "" { + proxyClient.Dial = (&fasthttp.TCPDialer{ + Resolver: p.defaultResolver, + }).Dial } + return &proxyClient } type Pool interface { // Get returns a new ReverseProxy from the pool. - Get() (HTTPClient, error) + Get() (HTTPClient, string, error) // Put the ReverseProxy puts it back to the Pool. - Put(HTTPClient) error + Put(string, HTTPClient) error // Close closes the pool and all its connections. After Close() the pool is // no longer usable. Close() - - // Len returns the current number of connections of the pool. - Len() int } // Pool interface impelement based on channel @@ -63,15 +111,19 @@ type chanPool struct { mutex sync.RWMutex // reverseProxyChan chan of getting the *ReverseProxy and putting it back - reverseProxyChan chan HTTPClient + reverseProxyChanLB map[string]chan HTTPClient // factory is factory method to generate ReverseProxy - // this can be customized - // factory Factory options *Options host string + port string - tlsConfig *tls.Config + initResolvedIP string + initConnAddr string + + tlsConfig *tls.Config + defaultResolver *net.Resolver + dnsCacheResolver DNSCache } type Options struct { @@ -80,13 +132,15 @@ type Options struct { InsecureConnection bool RootCA string MaxConnsPerHost int - ReadTimeout time.Duration - WriteTimeout time.Duration - DialTimeout time.Duration + DNSConfig config.DNS + + ReadTimeout time.Duration + WriteTimeout time.Duration + DialTimeout time.Duration } // NewChanPool to new a pool with some params -func NewChanPool(hostAddr string, options *Options) (Pool, error) { +func NewChanPool(hostAddr string, options *Options, dnsCacheResolver DNSCache) (Pool, error) { if options.InitialPoolCapacity < 0 || options.ClientPoolCapacity <= 0 || options.InitialPoolCapacity > options.ClientPoolCapacity { return nil, errInvalidCapacitySetting } @@ -115,70 +169,152 @@ func NewChanPool(hostAddr string, options *Options) (Pool, error) { RootCAs: rootCAs, } + host, port, err := net.SplitHostPort(hostAddr) + if err != nil { + return nil, err + } + // initialize the chanPool pool := &chanPool{ - mutex: sync.RWMutex{}, - reverseProxyChan: make(chan HTTPClient, options.ClientPoolCapacity), - options: options, - host: hostAddr, - tlsConfig: tlsConfig, + mutex: sync.RWMutex{}, + reverseProxyChanLB: make(map[string]chan HTTPClient), + options: options, + host: host, + port: port, + tlsConfig: tlsConfig, + defaultResolver: &net.Resolver{ + PreferGo: true, + }, + dnsCacheResolver: dnsCacheResolver, + } + + // init NS in the DNS resolver + if options.DNSConfig.Nameserver.Host != "" { + var builder strings.Builder + builder.WriteString(options.DNSConfig.Nameserver.Host) + builder.WriteString(":") + builder.WriteString(options.DNSConfig.Nameserver.Port) + + pool.defaultResolver.Dial = func(ctx context.Context, network, address string) (net.Conn, error) { + d := net.Dialer{} + return d.DialContext(ctx, options.DNSConfig.Nameserver.Proto, builder.String()) + } + } + + ip, err := pool.tryResolveAndFetchOneIP(host) + if err != nil { + return nil, err } + var builder strings.Builder + + builder.WriteString(ip) + builder.WriteString(":") + builder.WriteString(port) + + pool.initConnAddr = builder.String() + // create initial connections, if something goes wrong, // just close the pool error out. for i := 0; i < options.InitialPoolCapacity; i++ { - proxy := factory(hostAddr, options, tlsConfig) - pool.reverseProxyChan <- proxy + + connAddr := pool.initConnAddr + + if pool.dnsCacheResolver != nil { + ip, err = pool.tryResolveAndFetchOneIP(pool.host) + if err != nil { + continue + } + + builder.Reset() + + builder.WriteString(ip) + builder.WriteString(":") + builder.WriteString(port) + + connAddr = builder.String() + } + + proxy := pool.factory(connAddr) + if pool.reverseProxyChanLB[ip] == nil { + pool.reverseProxyChanLB[ip] = make(chan HTTPClient, options.ClientPoolCapacity) + } + pool.reverseProxyChanLB[ip] <- proxy } return pool, nil } -// getConnsAndFactory ... get a copy of chanPool's reverseProxyChan and factory -func (p *chanPool) getConnsAndFactory() chan HTTPClient { - p.mutex.RLock() - reverseProxyChan := p.reverseProxyChan - p.mutex.RUnlock() - return reverseProxyChan -} - // Close close the pool func (p *chanPool) Close() { p.mutex.Lock() - reverseProxyChan := p.reverseProxyChan - p.reverseProxyChan = nil - p.mutex.Unlock() + defer p.mutex.Unlock() - if reverseProxyChan == nil { - return + for ip := range p.reverseProxyChanLB { + reverseProxyChan := p.reverseProxyChanLB[ip] + p.reverseProxyChanLB[ip] = nil + + if reverseProxyChan == nil { + return + } + + close(reverseProxyChan) + } + + if p.dnsCacheResolver != nil { + p.dnsCacheResolver.Stop() } - close(reverseProxyChan) } // Get a *ReverseProxy from pool, it will get an error while // reverseProxyChan is nil or pool has been closed -func (p *chanPool) Get() (HTTPClient, error) { - if p.reverseProxyChan == nil { - return nil, errClosed +func (p *chanPool) Get() (HTTPClient, string, error) { + + var resolvedIP, connAddr string + + connAddr = p.initConnAddr + resolvedIP = p.initResolvedIP + + if p.options.DNSConfig.Cache { + ip, err := p.tryResolveAndFetchOneIP(p.host) + if err != nil { + return nil, "", err + } + resolvedIP = ip + + var builder strings.Builder + + builder.WriteString(ip) + builder.WriteString(":") + builder.WriteString(p.port) + + connAddr = builder.String() + } + + reverseProxyChan := p.reverseProxyChanLB[resolvedIP] + + if reverseProxyChan == nil { + p.reverseProxyChanLB[resolvedIP] = make(chan HTTPClient, p.options.ClientPoolCapacity) + reverseProxyChan = p.reverseProxyChanLB[resolvedIP] } // wrap our connections with out custom net.Conn implementation (wrapConn // method) that puts the connection back to the pool if it's closed. select { - case proxy := <-p.reverseProxyChan: + case proxy := <-reverseProxyChan: if proxy == nil { - return nil, errClosed + return nil, resolvedIP, errClosed } - return proxy, nil + return proxy, resolvedIP, nil default: - proxy := factory(p.host, p.options, p.tlsConfig) - return proxy, nil + proxy := p.factory(connAddr) + return proxy, resolvedIP, nil } } // Put ... put a *ReverseProxy object back into chanPool -func (p *chanPool) Put(proxy HTTPClient) error { +func (p *chanPool) Put(ip string, proxy HTTPClient) error { if proxy == nil { return errors.New("proxy is nil. rejecting") } @@ -186,7 +322,9 @@ func (p *chanPool) Put(proxy HTTPClient) error { p.mutex.RLock() defer p.mutex.RUnlock() - if p.reverseProxyChan == nil { + reverseProxyChan := p.reverseProxyChanLB[ip] + + if reverseProxyChan == nil { // pool is closed, close passed connection return nil } @@ -194,15 +332,9 @@ func (p *chanPool) Put(proxy HTTPClient) error { // put the resource back into the pool. If the pool is full, this will // block and the default case will be executed. select { - case p.reverseProxyChan <- proxy: + case reverseProxyChan <- proxy: return nil default: return nil } } - -// Len get chanPool channel length -func (p *chanPool) Len() int { - reverseProxyChan := p.getConnsAndFactory() - return len(reverseProxyChan) -} diff --git a/internal/platform/proxy/httppool_mock.go b/internal/platform/proxy/chainpool_mock.go similarity index 81% rename from internal/platform/proxy/httppool_mock.go rename to internal/platform/proxy/chainpool_mock.go index d1458a85..fd82bbe0 100644 --- a/internal/platform/proxy/httppool_mock.go +++ b/internal/platform/proxy/chainpool_mock.go @@ -84,12 +84,13 @@ func (mr *MockPoolMockRecorder) Close() *gomock.Call { } // Get mocks base method. -func (m *MockPool) Get() (HTTPClient, error) { +func (m *MockPool) Get() (HTTPClient, string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Get") ret0, _ := ret[0].(HTTPClient) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret1, _ := ret[1].(string) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // Get indicates an expected call of Get. @@ -98,30 +99,16 @@ func (mr *MockPoolMockRecorder) Get() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockPool)(nil).Get)) } -// Len mocks base method. -func (m *MockPool) Len() int { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Len") - ret0, _ := ret[0].(int) - return ret0 -} - -// Len indicates an expected call of Len. -func (mr *MockPoolMockRecorder) Len() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Len", reflect.TypeOf((*MockPool)(nil).Len)) -} - // Put mocks base method. -func (m *MockPool) Put(arg0 HTTPClient) error { +func (m *MockPool) Put(arg0 string, arg1 HTTPClient) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Put", arg0) + ret := m.ctrl.Call(m, "Put", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } // Put indicates an expected call of Put. -func (mr *MockPoolMockRecorder) Put(arg0 interface{}) *gomock.Call { +func (mr *MockPoolMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockPool)(nil).Put), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockPool)(nil).Put), arg0, arg1) } diff --git a/internal/platform/proxy/dnscache.go b/internal/platform/proxy/dnscache.go new file mode 100644 index 00000000..6e9fa57a --- /dev/null +++ b/internal/platform/proxy/dnscache.go @@ -0,0 +1,158 @@ +package proxy + +import ( + "context" + "net" + "sync" + "time" + + "github.com/sirupsen/logrus" +) + +const ( + // cacheSize is initial size of addr and IP list cache map. + cacheSize = 64 +) + +// defaultFreq is default frequency a resolver refreshes DNS cache. +var ( + defaultFreq = 3 * time.Second + defaultLookupTimeout = 10 * time.Second +) + +// onRefreshed is called when DNS are refreshed. +var onRefreshed = func() {} + +type DNSCache interface { + LookupIP(ctx context.Context, addr string) ([]net.IP, error) + Fetch(ctx context.Context, addr string) ([]net.IP, error) + Refresh() + Stop() +} + +// Resolver is DNS cache resolver which cache DNS resolve results in memory. +type Resolver struct { + lookupIPFn func(ctx context.Context, host string) ([]net.IP, error) + lookupTimeout time.Duration + + logger *logrus.Logger + + lock sync.RWMutex + cache map[string][]net.IP + closer func() +} + +// NewDNSResolver initializes DNS cache resolver and starts auto refreshing in a new goroutine. +// To stop refreshing, call `Stop()` function. +func NewDNSResolver(freq time.Duration, lookupTimeout time.Duration, resolver *net.Resolver, logger *logrus.Logger) (DNSCache, error) { + if freq <= 0 { + freq = defaultFreq + } + + if lookupTimeout <= 0 { + lookupTimeout = defaultLookupTimeout + } + + ticker := time.NewTicker(freq) + ch := make(chan struct{}) + closer := func() { + ticker.Stop() + close(ch) + } + + // copy handler function to avoid race + onRefreshedFn := onRefreshed + lookupIPFn := func(ctx context.Context, host string) ([]net.IP, error) { + addrs, err := resolver.LookupIPAddr(ctx, host) + + if err != nil { + return nil, err + } + + ips := make([]net.IP, len(addrs)) + for i, ia := range addrs { + ips[i] = ia.IP + } + + return ips, nil + } + + r := &Resolver{ + lookupIPFn: lookupIPFn, + lookupTimeout: lookupTimeout, + cache: make(map[string][]net.IP, cacheSize), + closer: closer, + logger: logger, + } + + go func() { + for { + select { + case <-ticker.C: + r.Refresh() + onRefreshedFn() + case <-ch: + return + } + } + }() + + return r, nil +} + +// LookupIP lookups IP list from DNS server then it saves result in the cache. +// If you want to get result from the cache use `Fetch` function. +func (r *Resolver) LookupIP(ctx context.Context, addr string) ([]net.IP, error) { + ips, err := r.lookupIPFn(ctx, addr) + if err != nil { + return nil, err + } + + r.lock.Lock() + r.cache[addr] = ips + r.lock.Unlock() + return ips, nil +} + +// Fetch fetches IP list from the cache. If IP list of the given addr is not in the cache, +// then it lookups from DNS server by `Lookup` function. +func (r *Resolver) Fetch(ctx context.Context, addr string) ([]net.IP, error) { + r.lock.RLock() + ips, ok := r.cache[addr] + r.lock.RUnlock() + if ok { + return ips, nil + } + return r.LookupIP(ctx, addr) +} + +// Refresh refreshes IP list cache. +func (r *Resolver) Refresh() { + r.lock.RLock() + addrs := make([]string, 0, len(r.cache)) + for addr := range r.cache { + addrs = append(addrs, addr) + } + r.lock.RUnlock() + + for _, addr := range addrs { + ctx, cancelF := context.WithTimeout(context.Background(), r.lookupTimeout) + if _, err := r.LookupIP(ctx, addr); err != nil { + r.logger.WithFields(logrus.Fields{ + "error": err, + "addr": addr, + }).Error("failed to refresh DNS cache") + } + cancelF() + } +} + +// Stop stops auto refreshing. +func (r *Resolver) Stop() { + r.lock.Lock() + defer r.lock.Unlock() + if r.closer != nil { + r.closer() + r.closer = nil + } +} diff --git a/internal/platform/proxy/dnscache_mock.go b/internal/platform/proxy/dnscache_mock.go new file mode 100644 index 00000000..ae27b7a2 --- /dev/null +++ b/internal/platform/proxy/dnscache_mock.go @@ -0,0 +1,90 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./internal/platform/proxy/dnscache.go + +// Package proxy is a generated GoMock package. +package proxy + +import ( + context "context" + net "net" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockDNSCache is a mock of DNSCache interface. +type MockDNSCache struct { + ctrl *gomock.Controller + recorder *MockDNSCacheMockRecorder +} + +// MockDNSCacheMockRecorder is the mock recorder for MockDNSCache. +type MockDNSCacheMockRecorder struct { + mock *MockDNSCache +} + +// NewMockDNSCache creates a new mock instance. +func NewMockDNSCache(ctrl *gomock.Controller) *MockDNSCache { + mock := &MockDNSCache{ctrl: ctrl} + mock.recorder = &MockDNSCacheMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockDNSCache) EXPECT() *MockDNSCacheMockRecorder { + return m.recorder +} + +// Fetch mocks base method. +func (m *MockDNSCache) Fetch(ctx context.Context, addr string) ([]net.IP, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Fetch", ctx, addr) + ret0, _ := ret[0].([]net.IP) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Fetch indicates an expected call of Fetch. +func (mr *MockDNSCacheMockRecorder) Fetch(ctx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Fetch", reflect.TypeOf((*MockDNSCache)(nil).Fetch), ctx, addr) +} + +// LookupIP mocks base method. +func (m *MockDNSCache) LookupIP(ctx context.Context, addr string) ([]net.IP, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LookupIP", ctx, addr) + ret0, _ := ret[0].([]net.IP) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// LookupIP indicates an expected call of LookupIP. +func (mr *MockDNSCacheMockRecorder) LookupIP(ctx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupIP", reflect.TypeOf((*MockDNSCache)(nil).LookupIP), ctx, addr) +} + +// Refresh mocks base method. +func (m *MockDNSCache) Refresh() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Refresh") +} + +// Refresh indicates an expected call of Refresh. +func (mr *MockDNSCacheMockRecorder) Refresh() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Refresh", reflect.TypeOf((*MockDNSCache)(nil).Refresh)) +} + +// Stop mocks base method. +func (m *MockDNSCache) Stop() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Stop") +} + +// Stop indicates an expected call of Stop. +func (mr *MockDNSCacheMockRecorder) Stop() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stop", reflect.TypeOf((*MockDNSCache)(nil).Stop)) +} diff --git a/internal/platform/proxy/proxy.go b/internal/platform/proxy/proxy.go index 7ace06f0..cb160dae 100644 --- a/internal/platform/proxy/proxy.go +++ b/internal/platform/proxy/proxy.go @@ -8,11 +8,11 @@ import ( // Perform function proxies the request to the backend server func Perform(ctx *fasthttp.RequestCtx, proxyPool Pool, customHostHeader string) error { - client, err := proxyPool.Get() + client, ip, err := proxyPool.Get() if err != nil { return err } - defer proxyPool.Put(client) + defer proxyPool.Put(ip, client) if customHostHeader != "" { ctx.Request.Header.SetHost(customHostHeader) diff --git a/internal/platform/storage/storage.go b/internal/platform/storage/storage.go index 60c62fe3..5fa30ef4 100644 --- a/internal/platform/storage/storage.go +++ b/internal/platform/storage/storage.go @@ -56,19 +56,22 @@ func NewOpenAPIFromFileOrURL(specPath string, header *config.CustomHeader) (DBOp var err error // try to parse path or URL - apiSpecURL, _ := url.ParseRequestURI(specPath) + apiSpecURL, err := url.ParseRequestURI(specPath) - switch apiSpecURL.Scheme { - case "": + // can't parse string as URL. Try to load spec from file + if err != nil || apiSpecURL == nil || apiSpecURL.Scheme == "" { specStorage, err = NewOpenAPIFromFile(specPath) if err != nil { return nil, errors.Wrap(err, "loading OpenAPI specification from file") } - default: - specStorage, err = NewOpenAPIFromURL(specPath, header) - if err != nil { - return nil, errors.Wrap(err, "loading OpenAPI specification from URL") - } + + return specStorage, err + } + + // try to load spec from + specStorage, err = NewOpenAPIFromURL(specPath, header) + if err != nil { + return nil, errors.Wrap(err, "loading OpenAPI specification from URL") } return specStorage, err diff --git a/internal/platform/validator/validate_response.go b/internal/platform/validator/validate_response.go index ec0c1957..50920715 100644 --- a/internal/platform/validator/validate_response.go +++ b/internal/platform/validator/validate_response.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "io" - "net/http" "sort" "strings" @@ -28,15 +27,6 @@ func ValidateResponse(ctx context.Context, input *openapi3filter.ResponseValidat } status := input.Status - // These status codes will never be validated. - // TODO: The list is probably missing some. - switch status { - case http.StatusNotModified, - http.StatusPermanentRedirect, - http.StatusTemporaryRedirect, - http.StatusMovedPermanently: - return nil - } route := input.RequestValidationInput.Route options := input.Options if options == nil { diff --git a/resources/test/docker-compose-api-mode.yml b/resources/test/docker-compose-api-mode.yml index d528f810..fbfb4288 100644 --- a/resources/test/docker-compose-api-mode.yml +++ b/resources/test/docker-compose-api-mode.yml @@ -2,7 +2,7 @@ version: '3.8' services: api-firewall: container_name: api-firewall - image: wallarm/api-firewall:v0.7.4 + image: wallarm/api-firewall:v0.8.0 build: context: ../../ dockerfile: Dockerfile diff --git a/resources/test/modsec/coraza.conf b/resources/test/modsec/coraza.conf index aab770e2..fbc82cad 100755 --- a/resources/test/modsec/coraza.conf +++ b/resources/test/modsec/coraza.conf @@ -182,7 +182,7 @@ SecDataDir /tmp/ # location must be private to Coraza. You don't want other users on # the server to access the files, do you? # -SecUploadDir /opt/coraza/var/upload/ +# SecUploadDir /opt/coraza/var/upload/ # By default, only keep the files that were determined to be unusual # in some way (by an external inspection script). For this to work you