20 Commits
2.3.3 ... 3.1.0

Author SHA1 Message Date
ec1de1fa81 Update dependencies and bump go version to 1.25 2025-09-26 16:09:18 +02:00
00749ae529 Add tests for new disable-scan flag 2025-09-26 16:07:05 +02:00
AdamB
9b87d28433 Add a flag to disable TCP scanning (#45)
* Add a flag to disable TCP scanning

* Move the option definition
2025-09-26 15:59:39 +02:00
751e5f3885 Improve README.md grammar and formatting (#43) 2025-07-19 12:39:18 +02:00
f3216cdf21 Update dependencies 2025-06-07 19:04:25 +02:00
dependabot[bot]
f70f4c6b65 Bump golang.org/x/net from 0.37.0 to 0.38.0 (#42)
* Bump golang.org/x/net from 0.37.0 to 0.38.0

Bumps [golang.org/x/net](https://github.com/golang/net) from 0.37.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.37.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update packages

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Daniel Carrillo <daniel.carrillo@gmail.com>
2025-04-17 10:53:14 +02:00
d3849cec02 [ci] Migrate golangci conf to v2 2025-04-17 10:30:41 +02:00
00b1661ef9 Update dependencies and fix CVE-2025-22870, CVE-2024-40635 2025-03-18 20:25:24 +01:00
10c199109a Bump go to 1.24 2025-02-21 19:37:35 +01:00
b5fe362183 Make geo database usage optional (#39) 2025-01-02 20:13:41 +01:00
95e7742c56 Fix CVE-2024-45338 in golang.org/x/net 2024-12-19 17:52:04 +01:00
680aeefeab Fix CVE-2024-45337 in golang.org/x/crypto 2024-12-13 09:26:24 +01:00
dependabot[bot]
15136359ae Bump github.com/quic-go/quic-go from 0.47.0 to 0.48.2 (#38)
* Bump github.com/quic-go/quic-go from 0.47.0 to 0.48.2

Bumps [github.com/quic-go/quic-go](https://github.com/quic-go/quic-go) from 0.47.0 to 0.48.2.
- [Release notes](https://github.com/quic-go/quic-go/releases)
- [Changelog](https://github.com/quic-go/quic-go/blob/master/Changelog.md)
- [Commits](https://github.com/quic-go/quic-go/compare/v0.47.0...v0.48.2)

---
updated-dependencies:
- dependency-name: github.com/quic-go/quic-go
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fix linter errors

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Daniel Carrillo <daniel.carrillo@gmail.com>
2024-12-02 19:14:32 +01:00
64011f9e99 Update dependencies 2024-09-15 20:01:33 +02:00
f020abc228 Update dependencies and bump Go version to 1.23 2024-08-26 19:51:37 +02:00
dependabot[bot]
24b05c0015 Bump github.com/docker/docker (#36)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 26.1.4+incompatible to 26.1.5+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v26.1.4...v26.1.5)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-10 12:08:29 +02:00
f2da841307 Update dependencies 2024-07-30 12:50:27 +02:00
dependabot[bot]
5bb5c974dd Bump github.com/docker/docker (#35)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 26.1.3+incompatible to 26.1.4+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v26.1.3...v26.1.4)

---
updated-dependencies:
- dependency-name: github.com/docker/docker
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-30 12:50:27 +02:00
159c30f2f0 Update dependecies 2024-07-30 12:50:27 +02:00
1539ba1987 Update dependencies 2024-07-30 12:50:11 +02:00
26 changed files with 732 additions and 542 deletions

View File

@@ -1,28 +1,18 @@
---
run:
timeout: 10m
issues:
max-same-issues: 0
version: "2"
linters:
disable-all: true
default: none
enable:
- goimports
- ineffassign
- nakedret
- revive
- staticcheck
- stylecheck
- unconvert
- unparam
- unused
linters-settings:
staticcheck:
checks:
- all
settings:
revive:
ignore-generated-header: true
severity: warning
confidence: 0.8
severity: warning
rules:
- name: blank-imports
- name: context-as-argument
@@ -47,3 +37,28 @@ linters-settings:
- name: unused-parameter
- name: unreachable-code
- name: redefines-builtin-id
staticcheck:
checks:
- all
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- third_party$
- builtin$
- examples$
issues:
max-same-issues: 0
formatters:
enable:
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

View File

@@ -1,7 +1,7 @@
FROM golang:1.22-alpine as builder
FROM golang:1.25-alpine AS builder
ARG ARG_VERSION
ENV VERSION $ARG_VERSION
ENV VERSION=$ARG_VERSION
WORKDIR /app
COPY go.mod .
@@ -15,7 +15,8 @@ RUN --mount=type=cache,target=/go/pkg/mod/ apk --no-cache add make && make build
FROM builder AS build-prod-app
# hadolint ignore=DL3018
RUN --mount=type=cache,target=/go/pkg/mod/ apk --no-cache add make upx \
RUN apk --no-cache update && apk add --no-cache ca-certificates make upx \
&& update-ca-certificates \
&& make build \
&& upx --best --lzma whatismyip

View File

@@ -50,9 +50,15 @@ endif
docker-run: docker-build-dev
docker run --tty --interactive --rm \
-v ${PWD}/test/GeoIP2-City-Test.mmdb:/tmp/GeoIP2-City-Test.mmdb:ro \
-v ${PWD}/test/GeoLite2-ASN-Test.mmdb:/tmp/GeoLite2-ASN-Test.mmdb:ro -p 8080:8080 \
--publish 8080:8080/tcp \
--publish 8081:8081/tcp \
--publish 8081:8081/udp \
--volume ${PWD}/test:/test \
${DOCKER_URL}:${VERSION} \
-geoip2-city /tmp/GeoIP2-City-Test.mmdb \
-geoip2-asn /tmp/GeoLite2-ASN-Test.mmdb \
-trusted-header X-Real-IP
-geoip2-city /test/GeoIP2-City-Test.mmdb \
-geoip2-asn /test/GeoLite2-ASN-Test.mmdb \
-trusted-header X-Real-PortReal-IP \
-tls-bind :8081 \
-tls-crt /test/server.pem \
-tls-key /test/server.key \
-enable-http3

View File

@@ -14,7 +14,8 @@
- [Usage](#usage)
- [Examples](#examples)
- [Run a default TCP server](#run-a-default-tcp-server)
- [Run a TLS (HTTP/2) and enable What is my DNS](#run-a-tls-http2-and-enable-what-is-my-dns)
- [Run a default TCP server with geo information enabled](#run-a-default-tcp-server-with-geo-information-enabled)
- [Run a TLS (HTTP/2) and enable "what is my DNS" with geo information](#run-a-tls-http2-and-enable-what-is-my-dns-with-geo-information)
- [Run an HTTP/3 server](#run-an-http3-server)
- [Run a default TCP server with a custom template and trust a pair of custom headers set by an upstream proxy](#run-a-default-tcp-server-with-a-custom-template-and-trust-a-pair-of-custom-headers-set-by-an-upstream-proxy)
- [Download](#download)
@@ -23,12 +24,13 @@
- [From Docker Hub](#from-docker-hub)
> [!NOTE]
> Since version 2.3.0, the application includes an optional client [DNS discovery](#dns-discovery)
> Since version 3.0.0, the geodb database is not mandatory; not adding the flags will disable the geo feature.
> Since version 2.3.0, the application includes an optional client [DNS discovery](#dns-discovery) feature.
Just another "what is my IP address" service, including geolocation, TCP open port checking, and headers information. Written in go with high performance in mind,
it uses [gin](https://github.com/gin-gonic/gin) which uses [httprouter](https://github.com/julienschmidt/httprouter) a lightweight high performance HTTP multiplexer.
Just another "what is my IP address" service, including geolocation, TCP open port checking, and headers information. Written in Go with high performance in mind,
it uses [gin](https://github.com/gin-gonic/gin) which uses [httprouter](https://github.com/julienschmidt/httprouter), a lightweight high-performance HTTP multiplexer.
Take a look at [ifconfig.es](https://ifconfig.es) a live site using `whatismyip` and the `DNS discovery` enabled.
Take a look at [ifconfig.es](https://ifconfig.es), a live site using `whatismyip` with the `DNS discovery` feature enabled.
Get your public IP easily from the command line:
@@ -85,7 +87,7 @@ curl -L dns.ifconfig.es
## DNS discovery
The DNS discovery works by forcing the client to make a request to `<uuid>.dns.ifconfig.es` this DNS request is handled by a microdns server
The DNS discovery works by forcing the client to make a request to `<uuid>.dns.ifconfig.es`. This DNS request is handled by a microdns server
included in the `whatismyip` binary. In order to run the discovery server, a configuration file in the following form has to be created:
```yaml
@@ -125,18 +127,20 @@ Golang >= 1.22 is required.
Usage of whatismyip:
-bind string
Listening address (see https://pkg.go.dev/net?#Listen) (default ":8080")
-disable-scan
Disable TCP port scanning functionality
-enable-http3
Enable HTTP/3 protocol. HTTP/3 requires --tls-bind set, as HTTP/3 starts as a TLS connection that then gets upgraded to UDP. The UDP port is the same as the one used for the TLS server.
-enable-secure-headers
Add sane security-related headers to every response
-geoip2-asn string
Path to GeoIP2 ASN database
Path to GeoIP2 ASN database. Enables ASN information. (--geoip2-city becomes mandatory)
-geoip2-city string
Path to GeoIP2 city database
Path to GeoIP2 city database. Enables geo information (--geoip2-asn becomes mandatory)
-resolver string
Path to the resolver configuration. It actually enables the resolver for DNS client discovery.
-template string
Path to template file
Path to the template file
-tls-bind string
Listening address for TLS (see https://pkg.go.dev/net?#Listen)
-tls-crt string
@@ -155,11 +159,17 @@ Usage of whatismyip:
### Run a default TCP server
```bash
./whatismyip
```
### Run a default TCP server with geo information enabled
```bash
./whatismyip -geoip2-city ./test/GeoIP2-City-Test.mmdb -geoip2-asn ./test/GeoLite2-ASN-Test.mmdb
```
### Run a TLS (HTTP/2) and enable What is my DNS
### Run a TLS (HTTP/2) and enable "what is my DNS" with geo information
```bash
./whatismyip -geoip2-city ./test/GeoIP2-City-Test.mmdb -geoip2-asn ./test/GeoLite2-ASN-Test.mmdb \

View File

@@ -13,6 +13,7 @@ import (
"github.com/dcarrillo/whatismyip/internal/setting"
"github.com/dcarrillo/whatismyip/resolver"
"github.com/dcarrillo/whatismyip/server"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-contrib/secure"
"github.com/patrickmn/go-cache"
@@ -22,10 +23,11 @@ import (
func main() {
o, err := setting.Setup(os.Args[1:])
if err != nil {
if err == flag.ErrHelp || err == setting.ErrVersion {
fmt.Print(o)
os.Exit(0)
} else if err != nil {
}
fmt.Println(err)
os.Exit(1)
}
@@ -41,11 +43,18 @@ func main() {
engine.Use(router.GetDNSDiscoveryHandler(store, setting.App.Resolver.Domain, setting.App.Resolver.RedirectPort))
}
var geoSvc *service.Geo
if setting.App.GeodbPath.City != "" || setting.App.GeodbPath.ASN != "" {
if geoSvc, err = service.NewGeo(context.Background(), setting.App.GeodbPath.City, setting.App.GeodbPath.ASN); err != nil {
panic(err)
}
}
router.SetupTemplate(engine)
router.Setup(engine)
router.Setup(engine, geoSvc)
servers = slices.Concat(servers, setupHTTPServers(context.Background(), engine.Handler()))
whatismyip := server.Setup(servers)
whatismyip := server.Setup(servers, geoSvc)
whatismyip.Run()
}
@@ -55,8 +64,7 @@ func setupEngine() *gin.Engine {
gin.SetMode(gin.ReleaseMode)
}
engine := gin.New()
engine.Use(gin.LoggerWithFormatter(httputils.GetLogFormatter))
engine.Use(gin.Recovery())
engine.Use(gin.LoggerWithFormatter(httputils.GetLogFormatter), gin.Recovery())
if setting.App.EnableSecureHeaders {
engine.Use(secure.New(secure.Config{
BrowserXssFilter: true,

121
go.mod
View File

@@ -1,112 +1,97 @@
module github.com/dcarrillo/whatismyip
go 1.22
go 1.25
require (
github.com/docker/docker v26.1.3+incompatible
github.com/gin-contrib/secure v1.1.0
github.com/gin-gonic/gin v1.10.0
github.com/docker/docker v28.0.4+incompatible
github.com/gin-contrib/secure v1.1.2
github.com/gin-gonic/gin v1.11.0
github.com/google/uuid v1.6.0
github.com/miekg/dns v1.1.59
github.com/oschwald/maxminddb-golang v1.12.0
github.com/miekg/dns v1.1.68
github.com/oschwald/maxminddb-golang v1.13.1
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/quic-go/quic-go v0.44.0
github.com/stretchr/testify v1.9.0
github.com/testcontainers/testcontainers-go v0.31.0
github.com/quic-go/quic-go v0.54.1
github.com/stretchr/testify v1.11.1
github.com/testcontainers/testcontainers-go v0.36.0
gopkg.in/yaml.v3 v3.0.1
)
require (
dario.cat/mergo v1.0.0 // indirect
dario.cat/mergo v1.0.1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/bytedance/sonic v1.11.8 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/bytedance/gopkg v0.1.3 // indirect
github.com/bytedance/sonic v1.14.1 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/containerd/containerd v1.7.15 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/cpuguy83/dockercfg v0.3.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/distribution/reference v0.5.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/ebitengine/purego v0.8.2 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/gabriel-vasile/mimetype v1.4.4 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.21.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/go-playground/validator/v10 v10.27.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.16.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
github.com/mgechev/revive v1.3.7 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/user v0.1.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo/v2 v2.19.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/shirou/gopsutil/v3 v3.23.12 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/shirou/gopsutil/v4 v4.25.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
github.com/ugorji/go/codec v1.3.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/tools v0.21.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.uber.org/mock v0.6.0 // indirect
golang.org/x/arch v0.21.0 // indirect
golang.org/x/crypto v0.42.0 // indirect
golang.org/x/mod v0.28.0 // indirect
golang.org/x/net v0.44.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/text v0.29.0 // indirect
golang.org/x/tools v0.37.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect
google.golang.org/protobuf v1.36.9 // indirect
)

293
go.sum
View File

@@ -1,64 +1,55 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/bytedance/sonic v1.11.8 h1:Zw/j1KfiS+OYTi9lyB3bb0CFxPJVkM17k1wyDG32LRA=
github.com/bytedance/sonic v1.11.8/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
github.com/bytedance/sonic v1.14.1 h1:FBMC0zVz5XUmE4z9wF4Jey0An5FueFvOsTKKKtwIl7w=
github.com/bytedance/sonic v1.14.1/go.mod h1:gi6uhQLMbTdeP0muCnrjHLeCUPyb70ujhnNlhOylAFc=
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/containerd/containerd v1.7.15 h1:afEHXdil9iAm03BmhjzKyXnnEBtjaLJefdU7DV0IFes=
github.com/containerd/containerd v1.7.15/go.mod h1:ISzRRTMF8EXNpJlTzyr2XMhN+j9K302C21/+cr3kUnY=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
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=
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo=
github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v28.0.4+incompatible h1:JNNkBctYKurkw6FrHfKqY0nKIDf5nrbxjVBtS+cdcok=
github.com/docker/docker v28.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
github.com/gin-contrib/secure v1.1.0 h1:wy/psCWbgUBDCLH13KgB/m06NHXb1jczSTRp+H2hK7E=
github.com/gin-contrib/secure v1.1.0/go.mod h1:LtEfyy326NRwgkUq8ac6npf845L0L9B8yfEaLcxMHIc=
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.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gin-contrib/secure v1.1.2 h1:6G8/NCOTSywWY7TeaH/0Yfaa6bfkE5ukkqtIm7lK11U=
github.com/gin-contrib/secure v1.1.2/go.mod h1:xI3jI5/BpOYMCBtjgmIVrMA3kI7y9LwCFxs+eLf5S3w=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
@@ -69,63 +60,44 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.21.0 h1:4fZA11ovvtkdgaeev9RGWPgc1uj3H8W+rNYyH/ySBb0=
github.com/go-playground/validator/v10 v10.21.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
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/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g=
github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
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-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE=
github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
@@ -134,6 +106,8 @@ github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -143,116 +117,100 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs=
github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE=
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.54.1 h1:4ZAWm0AhCb6+hE+l5Q1NAL0iRn/ZrMwqHRGQiFwj2eg=
github.com/quic-go/quic-go v0.54.1/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs=
github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/testcontainers/testcontainers-go v0.31.0 h1:W0VwIhcEVhRflwL9as3dhY6jXjVCA27AkmbnZ+UTh3U=
github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/testcontainers/testcontainers-go v0.36.0 h1:YpffyLuHtdp5EUsI5mT4sRw8GZhO/5ozyDT1xWGXt00=
github.com/testcontainers/testcontainers-go v0.36.0/go.mod h1:yk73GVJ0KUZIHUtFna6MO7QS144qYpoY8lEEtU9Hed0=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
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/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw=
golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
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-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -260,47 +218,42 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA=
google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=

View File

@@ -10,7 +10,6 @@ import (
"net/http"
"strings"
"testing"
"time"
validator "github.com/dcarrillo/whatismyip/internal/validator/uuid"
"github.com/dcarrillo/whatismyip/router"
@@ -135,12 +134,7 @@ func TestContainerIntegration(t *testing.T) {
ContainerFilePath: "/resolver.yml",
},
},
WaitingFor: wait.ForAll(
wait.ForListeningPort("8000/tcp").WithStartupTimeout(5*time.Second),
wait.ForListeningPort("8001/tcp").WithStartupTimeout(5*time.Second),
wait.ForListeningPort("8001/udp").WithStartupTimeout(5*time.Second),
wait.ForListeningPort("53/udp").WithStartupTimeout(5*time.Second),
),
WaitingFor: wait.ForLog("Starting QUIC server"),
AutoRemove: true,
},
Started: true,
@@ -200,8 +194,10 @@ func TestContainerIntegration(t *testing.T) {
resp, body, err = doQuicRequest(req)
} else {
client := &http.Client{}
resp, _ = client.Do(req)
resp, err = client.Do(req)
assert.NoError(t, err)
body, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
if strings.Contains(tt.url, "https://") {
assert.Equal(t, `h3=":8001"; ma=2592000`, resp.Header.Get("Alt-Svc"))
}
@@ -239,8 +235,72 @@ func TestContainerIntegration(t *testing.T) {
testWhatIsMyDNS(t)
}
// TODO If other flags like this one are implemented we should think of a better approach
func TestContainerIntegrationDisableScan(t *testing.T) {
if testing.Short() {
t.Skip("Skiping integration tests")
}
ctx := context.Background()
c, err := tc.GenericContainer(ctx, tc.GenericContainerRequest{
ContainerRequest: tc.ContainerRequest{
FromDockerfile: tc.FromDockerfile{
Context: "../",
Dockerfile: "./test/Dockerfile",
PrintBuildLog: true,
KeepImage: false,
BuildOptionsModifier: func(buildOptions *types.ImageBuildOptions) {
buildOptions.Target = "test"
},
},
ExposedPorts: []string{
"8000:8000",
},
Cmd: []string{
"-geoip2-city", "/GeoIP2-City-Test.mmdb",
"-geoip2-asn", "/GeoLite2-ASN-Test.mmdb",
"-bind", ":8000",
"-trusted-header", "X-Real-IP",
"-enable-secure-headers",
"-disable-scan",
},
Files: []tc.ContainerFile{
{
HostFilePath: "./../test/GeoIP2-City-Test.mmdb",
ContainerFilePath: "/GeoIP2-City-Test.mmdb",
},
{
HostFilePath: "./../test/GeoLite2-ASN-Test.mmdb",
ContainerFilePath: "/GeoLite2-ASN-Test.mmdb",
},
},
WaitingFor: wait.ForLog("Starting TCP server"),
AutoRemove: true,
},
Started: true,
})
require.NoError(t, err)
t.Cleanup(func() { c.Terminate(ctx) })
t.Run("RequestScanEndpointWithDisabledScan", func(t *testing.T) {
req, err := http.NewRequest("GET", "http://localhost:8000/scan/tcp/8000", nil)
assert.NoError(t, err)
req.Header.Set("Accept", "application/json")
req.Header.Set("X-Real-IP", "127.0.0.1")
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
assert.NotEmpty(t, body)
})
}
func doQuicRequest(req *http.Request) (*http.Response, []byte, error) {
roundTripper := &http3.RoundTripper{
roundTripper := &http3.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},

View File

@@ -12,9 +12,10 @@ import (
"gopkg.in/yaml.v3"
)
type geodbPath struct {
type geodbConf struct {
City string
ASN string
Token *string
}
type serverSettings struct {
ReadTimeout time.Duration
@@ -30,7 +31,7 @@ type resolver struct {
}
type settings struct {
GeodbPath geodbPath
GeodbPath geodbConf
TemplatePath string
BindAddress string
TLSAddress string
@@ -40,6 +41,7 @@ type settings struct {
TrustedPortHeader string
EnableSecureHeaders bool
EnableHTTP3 bool
DisableTCPScan bool
Server serverSettings
Resolver resolver
version bool
@@ -63,8 +65,8 @@ func Setup(args []string) (output string, err error) {
var resolverConf string
flags.SetOutput(&buf)
flags.StringVar(&App.GeodbPath.City, "geoip2-city", "", "Path to GeoIP2 city database")
flags.StringVar(&App.GeodbPath.ASN, "geoip2-asn", "", "Path to GeoIP2 ASN database")
flags.StringVar(&App.GeodbPath.City, "geoip2-city", "", "Path to GeoIP2 city database. Enables geo information (--geoip2-asn becomes mandatory)")
flags.StringVar(&App.GeodbPath.ASN, "geoip2-asn", "", "Path to GeoIP2 ASN database. Enables ASN information. (--geoip2-city becomes mandatory)")
flags.StringVar(&App.TemplatePath, "template", "", "Path to the template file")
flags.StringVar(
&resolverConf,
@@ -110,6 +112,12 @@ func Setup(args []string) (output string, err error) {
false,
"Enable HTTP/3 protocol. HTTP/3 requires --tls-bind set, as HTTP/3 starts as a TLS connection that then gets upgraded to UDP. The UDP port is the same as the one used for the TLS server.",
)
flags.BoolVar(
&App.DisableTCPScan,
"disable-scan",
false,
"Disable TCP port scanning functionality",
)
err = flags.Parse(args)
if err != nil {
@@ -120,12 +128,12 @@ func Setup(args []string) (output string, err error) {
return fmt.Sprintf("whatismyip version %s", core.Version), ErrVersion
}
if App.TrustedPortHeader != "" && App.TrustedHeader == "" {
return "", fmt.Errorf("truster-header is mandatory when truster-port-header is set")
if (App.GeodbPath.City != "" && App.GeodbPath.ASN == "") || (App.GeodbPath.City == "" && App.GeodbPath.ASN != "") {
return "", fmt.Errorf("both --geoip2-city and --geoip2-asn are mandatory to enable geo information")
}
if App.GeodbPath.City == "" || App.GeodbPath.ASN == "" {
return "", fmt.Errorf("geoip2-city and geoip2-asn parameters are mandatory")
if App.TrustedPortHeader != "" && App.TrustedHeader == "" {
return "", fmt.Errorf("truster-header is mandatory when truster-port-header is set")
}
if (App.TLSAddress != "") && (App.TLSCrtPath == "" || App.TLSKeyPath == "") {
@@ -150,7 +158,7 @@ func Setup(args []string) (output string, err error) {
var err error
App.Resolver, err = readYAML(resolverConf)
if err != nil {
return "", fmt.Errorf("error reading resolver configuration %s", err)
return "", fmt.Errorf("error reading resolver configuration %w", err)
}
}

View File

@@ -12,44 +12,43 @@ import (
)
func TestParseMandatoryFlags(t *testing.T) {
var mandatoryFlags = []struct {
mandatoryFlags := []struct {
args []string
}{
{
[]string{},
},
{
[]string{"-geoip2-city", "/city-path"},
},
{
[]string{"-geoip2-asn", "/asn-path"},
},
{
[]string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000",
"-geoip2-city", "my-city-path",
},
},
{
[]string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000",
"-tls-crt", "/crt-path",
"-geoip2-asn", "my-asn-path",
},
},
{
[]string{
"-tls-bind", ":9000",
},
},
{
[]string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000",
"-tls-key", "/key-path",
"-tls-bind", ":9000", "-tls-crt", "/crt-path",
},
},
{
[]string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-enable-http3",
"-tls-bind", ":9000", "-tls-key", "/key-path",
},
},
{
[]string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-bind", ":8000",
"-trusted-port-header", "port-header",
"-enable-http3",
},
},
{
[]string{
"-bind", ":8000", "-trusted-port-header", "port-header",
},
},
}
@@ -57,24 +56,20 @@ func TestParseMandatoryFlags(t *testing.T) {
for _, tt := range mandatoryFlags {
t.Run(strings.Join(tt.args, " "), func(t *testing.T) {
_, err := Setup(tt.args)
require.NotNil(t, err)
require.Error(t, err)
assert.Contains(t, err.Error(), "mandatory")
})
}
}
func TestParseFlags(t *testing.T) {
var flags = []struct {
flags := []struct {
args []string
conf settings
}{
{
[]string{"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path"},
[]string{},
settings{
GeodbPath: geodbPath{
City: "/city-path",
ASN: "/asn-path",
},
BindAddress: ":8080",
Server: serverSettings{
ReadTimeout: 10 * time.Second,
@@ -82,10 +77,21 @@ func TestParseFlags(t *testing.T) {
},
},
},
{
[]string{"-disable-scan"},
settings{
BindAddress: ":8080",
Server: serverSettings{
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
},
DisableTCPScan: true,
},
},
{
[]string{"-bind", ":8001", "-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path"},
settings{
GeodbPath: geodbPath{
GeodbPath: geodbConf{
City: "/city-path",
ASN: "/asn-path",
},
@@ -102,7 +108,7 @@ func TestParseFlags(t *testing.T) {
"-tls-crt", "/crt-path", "-tls-key", "/key-path",
},
settings{
GeodbPath: geodbPath{
GeodbPath: geodbConf{
City: "/city-path",
ASN: "/asn-path",
},
@@ -122,7 +128,7 @@ func TestParseFlags(t *testing.T) {
"-trusted-header", "header", "-trusted-port-header", "port-header",
},
settings{
GeodbPath: geodbPath{
GeodbPath: geodbConf{
City: "/city-path",
ASN: "/asn-path",
},
@@ -141,7 +147,7 @@ func TestParseFlags(t *testing.T) {
"-trusted-header", "header", "-enable-secure-headers",
},
settings{
GeodbPath: geodbPath{
GeodbPath: geodbConf{
City: "/city-path",
ASN: "/asn-path",
},
@@ -166,7 +172,7 @@ func TestParseFlags(t *testing.T) {
}
func TestParseFlagsUsage(t *testing.T) {
var usageArgs = []string{"-help", "-h", "--help"}
usageArgs := []string{"-help", "-h", "--help"}
for _, arg := range usageArgs {
t.Run(arg, func(t *testing.T) {
@@ -184,19 +190,28 @@ func TestParseFlagVersion(t *testing.T) {
}
func TestParseFlagTemplate(t *testing.T) {
flags := []string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path",
"-template", "/template-path",
testCases := []struct {
name string
flags []string
errMsg string
}{
{
name: "Invalid template path",
flags: []string{"-template", "/template-path"},
errMsg: "no such file or directory",
},
{
name: "Template path is a directory",
flags: []string{"-template", "/"},
errMsg: "must be a file",
},
}
_, err := Setup(flags)
assert.Error(t, err)
assert.Contains(t, err.Error(), "no such file or directory")
flags = []string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path",
"-template", "/",
}
_, err = Setup(flags)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
_, err := Setup(tc.flags)
require.Error(t, err)
assert.Contains(t, err.Error(), "must be a file")
assert.Contains(t, err.Error(), tc.errMsg)
})
}
}

View File

@@ -1,13 +1,13 @@
package models
import (
"fmt"
"log"
"net"
"github.com/oschwald/maxminddb-golang"
)
// GeoRecord is the model for City database
type GeoRecord struct {
Country struct {
ISOCode string `maxminddb:"iso_code"`
@@ -26,52 +26,107 @@ type GeoRecord struct {
} `maxminddb:"postal"`
}
// ASNRecord is the model for ASN database
type ASNRecord struct {
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
}
type geodb struct {
city *maxminddb.Reader
asn *maxminddb.Reader
type GeoDB struct {
cityPath string
asnPath string
City *maxminddb.Reader
ASN *maxminddb.Reader
}
var db geodb
func Setup(cityPath string, asnPath string) (*GeoDB, error) {
city, asn, err := openDatabases(cityPath, asnPath)
if err != nil {
return nil, err
}
func openMMDB(path string) *maxminddb.Reader {
return &GeoDB{
cityPath: cityPath,
asnPath: asnPath,
City: city,
ASN: asn,
}, nil
}
func (db *GeoDB) CloseDBs() error {
var errs []error
if db.City != nil {
if err := db.City.Close(); err != nil {
errs = append(errs, fmt.Errorf("closing city db: %w", err))
}
}
if db.ASN != nil {
if err := db.ASN.Close(); err != nil {
errs = append(errs, fmt.Errorf("closing ASN db: %w", err))
}
}
if len(errs) > 0 {
return fmt.Errorf("errors closing databases: %s", errs)
}
return nil
}
func (db *GeoDB) Reload() error {
if err := db.CloseDBs(); err != nil {
return fmt.Errorf("closing existing connections: %w", err)
}
city, asn, err := openDatabases(db.cityPath, db.asnPath)
if err != nil {
return fmt.Errorf("opening new connections: %w", err)
}
db.City = city
db.ASN = asn
return nil
}
func (db *GeoDB) LookupCity(ip net.IP) (*GeoRecord, error) {
record := &GeoRecord{}
err := db.City.Lookup(ip, record)
if err != nil {
return nil, err
}
return record, nil
}
func (db *GeoDB) LookupASN(ip net.IP) (*ASNRecord, error) {
record := &ASNRecord{}
err := db.ASN.Lookup(ip, record)
if err != nil {
return nil, err
}
return record, nil
}
func openDatabases(cityPath, asnPath string) (*maxminddb.Reader, *maxminddb.Reader, error) {
city, err := openMMDB(cityPath)
if err != nil {
return nil, nil, err
}
asn, err := openMMDB(asnPath)
if err != nil {
return nil, nil, err
}
return city, asn, nil
}
func openMMDB(path string) (*maxminddb.Reader, error) {
db, err := maxminddb.Open(path)
if err != nil {
log.Fatal(err)
return nil, err
}
log.Printf("Database %s has been loaded\n", path)
return db
}
// Setup opens all Geolite2 databases
func Setup(cityPath string, asnPath string) {
db.city = openMMDB(cityPath)
db.asn = openMMDB(asnPath)
}
// CloseDBs unmaps from memory and frees resources to the filesystem
func CloseDBs() {
log.Printf("Closing dbs...")
if err := db.city.Close(); err != nil {
log.Printf("Error closing city db: %s", err)
}
if err := db.asn.Close(); err != nil {
log.Printf("Error closing ASN db: %s", err)
}
}
// LookUp an IP and get city data
func (record *GeoRecord) LookUp(ip net.IP) error {
return db.city.Lookup(ip, record)
}
// LookUp an IP and get ASN data
func (record *ASNRecord) LookUp(ip net.IP) error {
return db.asn.Lookup(ip, record)
return db, nil
}

View File

@@ -1,10 +1,12 @@
package models
import (
"fmt"
"net"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestModels(t *testing.T) {
@@ -59,19 +61,21 @@ func TestModels(t *testing.T) {
AutonomousSystemOrganization: "IP-Only",
}
Setup("../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
defer CloseDBs()
db, err := Setup("../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
require.NoError(t, err, fmt.Sprintf("Error setting up db: %s", err))
defer db.CloseDBs()
assert.NotNil(t, db.ASN)
assert.NotNil(t, db.City)
assert.NotNil(t, db.asn)
assert.NotNil(t, db.city)
cityRecord := &GeoRecord{}
assert.Nil(t, cityRecord.LookUp(net.ParseIP("81.2.69.192")))
cityRecord, err := db.LookupCity(net.ParseIP("81.2.69.192"))
require.NoError(t, err, fmt.Sprintf("Error looking up city: %s", err))
assert.Equal(t, expectedCity, cityRecord)
assert.Error(t, cityRecord.LookUp(net.ParseIP("error")))
_, err = db.LookupCity(net.ParseIP("error"))
assert.Error(t, err)
asnRecord := &ASNRecord{}
assert.Nil(t, asnRecord.LookUp(net.ParseIP("82.99.17.64")))
asnRecord, err := db.LookupASN(net.ParseIP("82.99.17.64"))
require.NoError(t, err, fmt.Sprintf("Error looking up asn: %s", err))
assert.Equal(t, expectedASN, asnRecord)
assert.Error(t, asnRecord.LookUp(net.ParseIP("error")))
_, err = db.LookupASN(net.ParseIP("error"))
assert.Error(t, err)
}

View File

@@ -7,7 +7,6 @@ import (
"strings"
validator "github.com/dcarrillo/whatismyip/internal/validator/uuid"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/patrickmn/go-cache"
@@ -16,10 +15,14 @@ import (
type DNSJSONResponse struct {
DNS dnsData `json:"dns"`
}
type dnsGeoData struct {
Country string `json:"country,omitempty"`
AsnOrganization string `json:"provider,omitempty"`
}
type dnsData struct {
IP string `json:"ip"`
Country string `json:"country"`
AsnOrganization string `json:"provider"`
dnsGeoData
}
// TODO
@@ -67,12 +70,21 @@ func handleDNS(ctx *gin.Context, store *cache.Cache) {
return
}
geo := service.Geo{IP: ip}
geoResp := dnsGeoData{}
if geoSvc != nil {
cityRecord := geoSvc.LookUpCity(ip)
asnRecord := geoSvc.LookUpASN(ip)
geoResp = dnsGeoData{
Country: cityRecord.Country.Names["en"],
AsnOrganization: asnRecord.AutonomousSystemOrganization,
}
}
j := DNSJSONResponse{
DNS: dnsData{
IP: ipStr,
Country: geo.LookUpCity().Country.Names["en"],
AsnOrganization: geo.LookUpASN().AutonomousSystemOrganization,
dnsGeoData: geoResp,
},
}

View File

@@ -7,25 +7,28 @@ import (
"github.com/dcarrillo/whatismyip/internal/httputils"
"github.com/dcarrillo/whatismyip/internal/setting"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-gonic/gin"
)
type GeoResponse struct {
Country string `json:"country,omitempty"`
CountryCode string `json:"country_code,omitempty"`
City string `json:"city,omitempty"`
Latitude float64 `json:"latitude,omitempty"`
Longitude float64 `json:"longitude,omitempty"`
PostalCode string `json:"postal_code,omitempty"`
TimeZone string `json:"time_zone,omitempty"`
ASN uint `json:"asn,omitempty"`
ASNOrganization string `json:"asn_organization,omitempty"`
}
type JSONResponse struct {
IP string `json:"ip"`
IPVersion byte `json:"ip_version"`
ClientPort string `json:"client_port"`
Country string `json:"country"`
CountryCode string `json:"country_code"`
City string `json:"city"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
PostalCode string `json:"postal_code"`
TimeZone string `json:"time_zone"`
ASN uint `json:"asn"`
ASNOrganization string `json:"asn_organization"`
Host string `json:"host"`
Headers http.Header `json:"headers"`
GeoResponse
}
func getRoot(ctx *gin.Context) {
@@ -66,16 +69,14 @@ func getClientPortAsString(ctx *gin.Context) {
}
func getAllAsString(ctx *gin.Context) {
output := "IP: " + ctx.ClientIP() + "\n"
ip := net.ParseIP(ctx.ClientIP())
output := "IP: " + ip.String() + "\n"
output += "Client Port: " + getClientPort(ctx) + "\n"
r := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
if record := r.LookUpCity(); record != nil {
output += geoCityRecordToString(record) + "\n"
}
if record := r.LookUpASN(); record != nil {
output += geoASNRecordToString(record) + "\n"
if geoSvc != nil {
output += geoCityRecordToString(geoSvc.LookUpCity(ip)) + "\n"
output += geoASNRecordToString(geoSvc.LookUpASN(ip)) + "\n"
}
h := httputils.GetHeadersWithoutTrustedHeaders(ctx)
@@ -90,18 +91,19 @@ func getJSON(ctx *gin.Context) {
}
func jsonOutput(ctx *gin.Context) JSONResponse {
ip := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
asnRecord := ip.LookUpASN()
cityRecord := ip.LookUpCity()
ip := net.ParseIP(ctx.ClientIP())
var version byte = 4
if p := net.ParseIP(ctx.ClientIP()).To4(); p == nil {
if p := ip.To4(); p == nil {
version = 6
}
return JSONResponse{
IP: ctx.ClientIP(),
IPVersion: version,
ClientPort: getClientPort(ctx),
geoResp := GeoResponse{}
if geoSvc != nil {
cityRecord := geoSvc.LookUpCity(ip)
asnRecord := geoSvc.LookUpASN(ip)
geoResp = GeoResponse{
Country: cityRecord.Country.Names["en"],
CountryCode: cityRecord.Country.ISOCode,
City: cityRecord.City.Names["en"],
@@ -111,7 +113,15 @@ func jsonOutput(ctx *gin.Context) JSONResponse {
TimeZone: cityRecord.Location.TimeZone,
ASN: asnRecord.AutonomousSystemNumber,
ASNOrganization: asnRecord.AutonomousSystemOrganization,
}
}
return JSONResponse{
IP: ip.String(),
IPVersion: version,
ClientPort: getClientPort(ctx),
Host: ctx.Request.Host,
Headers: httputils.GetHeadersWithoutTrustedHeaders(ctx),
GeoResponse: geoResp,
}
}

View File

@@ -8,7 +8,6 @@ import (
"strings"
"github.com/dcarrillo/whatismyip/models"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-gonic/gin"
)
@@ -83,10 +82,13 @@ var asnOutput = map[string]asnDataFormatter{
}
func getGeoAsString(ctx *gin.Context) {
field := strings.ToLower(ctx.Params.ByName("field"))
ip := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
record := ip.LookUpCity()
if geoSvc == nil {
ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
return
}
field := strings.ToLower(ctx.Params.ByName("field"))
record := geoSvc.LookUpCity(net.ParseIP(ctx.ClientIP()))
if field == "" {
ctx.String(http.StatusOK, geoCityRecordToString(record))
} else if g, ok := geoOutput[field]; ok {
@@ -97,10 +99,12 @@ func getGeoAsString(ctx *gin.Context) {
}
func getASNAsString(ctx *gin.Context) {
if geoSvc == nil {
ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
return
}
field := strings.ToLower(ctx.Params.ByName("field"))
ip := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
record := ip.LookUpASN()
record := geoSvc.LookUpASN(net.ParseIP(ctx.ClientIP()))
if field == "" {
ctx.String(http.StatusOK, geoASNRecordToString(record))
} else if g, ok := asnOutput[field]; ok {

View File

@@ -5,9 +5,12 @@ import (
"log"
"github.com/dcarrillo/whatismyip/internal/setting"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-gonic/gin"
)
var geoSvc *service.Geo
func SetupTemplate(r *gin.Engine) {
if setting.App.TemplatePath == "" {
t, _ := template.New("home").Parse(home)
@@ -18,9 +21,12 @@ func SetupTemplate(r *gin.Engine) {
}
}
func Setup(r *gin.Engine) {
func Setup(r *gin.Engine, geo *service.Geo) {
geoSvc = geo
r.GET("/", getRoot)
if !setting.App.DisableTCPScan {
r.GET("/scan/tcp/:port", scanTCPPort)
}
r.GET("/client-port", getClientPortAsString)
r.GET("/geo", getGeoAsString)
r.GET("/geo/:field", getGeoAsString)

View File

@@ -1,10 +1,11 @@
package router
import (
"context"
"os"
"testing"
"github.com/dcarrillo/whatismyip/models"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-gonic/gin"
)
@@ -34,9 +35,9 @@ var (
text: "text/plain; charset=utf-8",
json: "application/json; charset=utf-8",
}
jsonIPv4 = `{"client_port":"1001","ip":"81.2.69.192","ip_version":4,"country":"United Kingdom","country_code":"GB","city":"London","latitude":51.5142,"longitude":-0.0931,"postal_code":"","time_zone":"Europe/London","asn":0,"asn_organization":"","host":"test", "headers": {}}`
jsonIPv6 = `{"asn":3352, "asn_organization":"TELEFONICA DE ESPANA", "city":"", "client_port":"1001", "country":"", "country_code":"", "host":"test", "ip":"2a02:9000::1", "ip_version":6, "latitude":0, "longitude":0, "postal_code":"", "time_zone":"", "headers": {}}`
jsonDNSIPv4 = `{"dns":{"ip":"81.2.69.192","country":"United Kingdom","provider":""}}`
jsonIPv4 = `{"client_port":"1001","ip":"81.2.69.192","ip_version":4,"country":"United Kingdom","country_code":"GB","city":"London","latitude":51.5142,"longitude":-0.0931,"time_zone":"Europe/London","host":"test", "headers": {}}`
jsonIPv6 = `{"asn":3352,"asn_organization":"TELEFONICA DE ESPANA","client_port":"1001","host":"test","ip":"2a02:9000::1","ip_version":6,"headers": {}}`
jsonDNSIPv4 = `{"dns":{"ip":"81.2.69.192","country":"United Kingdom"}}`
plainDNSIPv4 = "81.2.69.192 (United Kingdom / )\n"
)
@@ -49,9 +50,8 @@ const (
func TestMain(m *testing.M) {
app = gin.Default()
app.TrustedPlatform = trustedHeader
models.Setup("../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
Setup(app)
defer models.CloseDBs()
svc, _ := service.NewGeo(context.Background(), "../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
Setup(app, svc)
os.Exit(m.Run())
}

View File

@@ -65,6 +65,9 @@ func TestDefaultTemplate(t *testing.T) {
IP: "127.0.0.1",
IPVersion: 4,
ClientPort: "1000",
Host: "localhost",
Headers: req.Header,
GeoResponse: GeoResponse{
Country: "A Country",
CountryCode: "XX",
City: "A City",
@@ -74,8 +77,7 @@ func TestDefaultTemplate(t *testing.T) {
TimeZone: "My/Timezone",
ASN: 0,
ASNOrganization: "My ISP",
Host: "localhost",
Headers: req.Header,
},
}
buf := &bytes.Buffer{}

View File

@@ -41,7 +41,7 @@ func (d *DNS) Start() {
}
func (d *DNS) Stop() {
log.Printf("Stopping DNS server...")
log.Print("Stopping DNS server...")
if err := d.server.Shutdown(); err != nil {
log.Printf("DNS server forced to shutdown: %s", err)
}

View File

@@ -48,8 +48,8 @@ func (q *Quic) Start() {
}
func (q *Quic) Stop() {
log.Printf("Stopping QUIC server...")
log.Print("Stopping QUIC server...")
if err := q.server.Close(); err != nil {
log.Printf("QUIC server forced to shutdown")
log.Print("QUIC server forced to shutdown")
}
}

View File

@@ -6,8 +6,7 @@ import (
"os/signal"
"syscall"
"github.com/dcarrillo/whatismyip/internal/setting"
"github.com/dcarrillo/whatismyip/models"
"github.com/dcarrillo/whatismyip/service"
)
type Server interface {
@@ -17,18 +16,19 @@ type Server interface {
type Manager struct {
servers []Server
geoSvc *service.Geo
}
func Setup(servers []Server) *Manager {
func Setup(servers []Server, geoSvc *service.Geo) *Manager {
return &Manager{
servers: servers,
geoSvc: geoSvc,
}
}
func (m *Manager) Run() {
m.start()
models.Setup(setting.App.GeodbPath.City, setting.App.GeodbPath.ASN)
signalChan := make(chan os.Signal, len(m.servers))
signal.Notify(signalChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
var s os.Signal
@@ -37,13 +37,16 @@ func (m *Manager) Run() {
if s == syscall.SIGHUP {
m.stop()
models.CloseDBs()
models.Setup(setting.App.GeodbPath.City, setting.App.GeodbPath.ASN)
if m.geoSvc != nil {
m.geoSvc.Reload()
}
m.start()
} else {
log.Printf("Shutting down...")
log.Print("Shutting down...")
if m.geoSvc != nil {
m.geoSvc.Shutdown()
}
m.stop()
models.CloseDBs()
break
}
}

View File

@@ -39,7 +39,7 @@ func (t *TCP) Start() {
}
func (t *TCP) Stop() {
log.Printf("Stopping TCP server...")
log.Print("Stopping TCP server...")
if err := t.server.Shutdown(t.ctx); err != nil {
log.Printf("TCP server forced to shutdown: %s", err)
}

View File

@@ -40,7 +40,7 @@ func (t *TLS) Start() {
}
func (t *TLS) Stop() {
log.Printf("Stopping TLS server...")
log.Print("Stopping TLS server...")
if err := t.server.Shutdown(t.ctx); err != nil {
log.Printf("TLS server forced to shutdown: %s", err)
}

View File

@@ -1,37 +1,73 @@
package service
import (
"context"
"log"
"net"
"sync"
"github.com/dcarrillo/whatismyip/models"
)
// Geo defines a base type for lookups
type Geo struct {
IP net.IP
ctx context.Context
cancel context.CancelFunc
db *models.GeoDB
mu sync.RWMutex
}
// LookUpCity queries the database for city data related to the given IP
func (g *Geo) LookUpCity() *models.GeoRecord {
record := &models.GeoRecord{}
err := record.LookUp(g.IP)
func NewGeo(ctx context.Context, cityPath string, asnPath string) (*Geo, error) {
ctx, cancel := context.WithCancel(ctx)
db, err := models.Setup(cityPath, asnPath)
if err != nil {
log.Println(err)
cancel()
return nil, err
}
geo := &Geo{
ctx: ctx,
cancel: cancel,
db: db,
}
return geo, nil
}
func (g *Geo) LookUpCity(ip net.IP) *models.GeoRecord {
record, err := g.db.LookupCity(ip)
if err != nil {
log.Print(err)
return nil
}
return record
}
// LookUpASN queries the database for ASN data related to the given IP
func (g *Geo) LookUpASN() *models.ASNRecord {
record := &models.ASNRecord{}
err := record.LookUp(g.IP)
func (g *Geo) LookUpASN(ip net.IP) *models.ASNRecord {
record, err := g.db.LookupASN(ip)
if err != nil {
log.Println(err)
log.Print(err)
return nil
}
return record
}
func (g *Geo) Shutdown() {
g.cancel()
g.db.CloseDBs()
}
func (g *Geo) Reload() {
if err := g.ctx.Err(); err != nil {
log.Printf("Skipping reload, service is shutting down: %v", err)
return
}
g.mu.Lock()
defer g.mu.Unlock()
g.db.Reload()
log.Print("Geo database reloaded")
}

View File

@@ -1,36 +1,33 @@
package service
import (
"context"
"net"
"os"
"testing"
"github.com/dcarrillo/whatismyip/models"
"github.com/stretchr/testify/assert"
)
var geoSvc *Geo
func TestMain(m *testing.M) {
models.Setup("../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
defer models.CloseDBs()
geoSvc, _ = NewGeo(context.Background(), "../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
os.Exit(m.Run())
}
func TestCityLookup(t *testing.T) {
ip := Geo{IP: net.ParseIP("error")}
c := ip.LookUpCity()
c := geoSvc.LookUpCity(net.ParseIP("error"))
assert.Nil(t, c)
ip = Geo{IP: net.ParseIP("1.1.1.1")}
c = ip.LookUpCity()
c = geoSvc.LookUpCity(net.ParseIP("1.1.1.1"))
assert.NotNil(t, c)
}
func TestASNLookup(t *testing.T) {
ip := Geo{IP: net.ParseIP("error")}
a := ip.LookUpASN()
a := geoSvc.LookUpASN(net.ParseIP("error"))
assert.Nil(t, a)
ip = Geo{IP: net.ParseIP("1.1.1.1")}
a = ip.LookUpASN()
a = geoSvc.LookUpASN(net.ParseIP("1.1.1.1"))
assert.NotNil(t, a)
}

View File

@@ -1,7 +1,7 @@
FROM golang:1.22-alpine as builder
FROM golang:1.25-alpine AS builder
ARG ARG_VERSION
ENV VERSION $ARG_VERSION
ENV VERSION=$ARG_VERSION
WORKDIR /app
COPY . .