Make geo database usage optional (#39)

This commit is contained in:
Daniel Carrillo 2025-01-02 20:13:41 +01:00 committed by GitHub
parent 95e7742c56
commit b5fe362183
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 457 additions and 268 deletions

View File

@ -15,6 +15,8 @@ RUN --mount=type=cache,target=/go/pkg/mod/ apk --no-cache add make && make build
FROM builder AS build-prod-app FROM builder AS build-prod-app
# hadolint ignore=DL3018 # hadolint ignore=DL3018
RUN apk update && apk add --no-cache ca-certificates && update-ca-certificates
# hadolint ignore=DL3018
RUN --mount=type=cache,target=/go/pkg/mod/ apk --no-cache add make upx \ RUN --mount=type=cache,target=/go/pkg/mod/ apk --no-cache add make upx \
&& make build \ && make build \
&& upx --best --lzma whatismyip && upx --best --lzma whatismyip

View File

@ -50,9 +50,10 @@ endif
docker-run: docker-build-dev docker-run: docker-build-dev
docker run --tty --interactive --rm \ docker run --tty --interactive --rm \
-v ${PWD}/test/GeoIP2-City-Test.mmdb:/tmp/GeoIP2-City-Test.mmdb:ro \ --publish 8080:8080 \
-v ${PWD}/test/GeoLite2-ASN-Test.mmdb:/tmp/GeoLite2-ASN-Test.mmdb:ro -p 8080:8080 \ --volume ${PWD}/test/GeoIP2-City-Test.mmdb:/GeoIP2-City-Test.mmdb \
${DOCKER_URL}:${VERSION} \ --volume ${PWD}/test/GeoLite2-ASN-Test.mmdb:/GeoLite2-ASN-Test.mmdb \
-geoip2-city /tmp/GeoIP2-City-Test.mmdb \ ${DOCKER_URL}:${VERSION} \
-geoip2-asn /tmp/GeoLite2-ASN-Test.mmdb \ -geoip2-city /GeoIP2-City-Test.mmdb \
-geoip2-asn /GeoLite2-ASN-Test.mmdb \
-trusted-header X-Real-IP -trusted-header X-Real-IP

View File

@ -14,7 +14,8 @@
- [Usage](#usage) - [Usage](#usage)
- [Examples](#examples) - [Examples](#examples)
- [Run a default TCP server](#run-a-default-tcp-server) - [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-tco-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 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) - [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) - [Download](#download)
@ -23,6 +24,7 @@
- [From Docker Hub](#from-docker-hub) - [From Docker Hub](#from-docker-hub)
> [!NOTE] > [!NOTE]
> Since version 3.0.0, 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) > Since version 2.3.0, the application includes an optional client [DNS discovery](#dns-discovery)
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, 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,
@ -124,42 +126,48 @@ Golang >= 1.22 is required.
```text ```text
Usage of whatismyip: Usage of whatismyip:
-bind string -bind string
Listening address (see https://pkg.go.dev/net?#Listen) (default ":8080") Listening address (see https://pkg.go.dev/net?#Listen) (default ":8080")
-enable-http3 -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 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 -enable-secure-headers
Add sane security-related headers to every response Add sane security-related headers to every response
-geoip2-asn string -geoip2-asn string
Path to GeoIP2 ASN database Path to GeoIP2 ASN database. Enables ASN information. (--geoip2-city becomes mandatory)
-geoip2-city string -geoip2-city string
Path to GeoIP2 city database Path to GeoIP2 city database. Enables geo information (--geoip2-asn becomes mandatory)
-resolver string -resolver string
Path to the resolver configuration. It actually enables the resolver for DNS client discovery. Path to the resolver configuration. It actually enables the resolver for DNS client discovery.
-template string -template string
Path to template file Path to the template file
-tls-bind string -tls-bind string
Listening address for TLS (see https://pkg.go.dev/net?#Listen) Listening address for TLS (see https://pkg.go.dev/net?#Listen)
-tls-crt string -tls-crt string
When using TLS, path to certificate file When using TLS, path to certificate file
-tls-key string -tls-key string
When using TLS, path to private key file When using TLS, path to private key file
-trusted-header string -trusted-header string
Trusted request header for remote IP (e.g. X-Real-IP). When using this feature if -trusted-port-header is not set the client port is shown as 'unknown' Trusted request header for remote IP (e.g. X-Real-IP). When using this feature if -trusted-port-header is not set the client port is shown as 'unknown'
-trusted-port-header string -trusted-port-header string
Trusted request header for remote client port (e.g. X-Real-Port). When this parameter is set -trusted-header becomes mandatory Trusted request header for remote client port (e.g. X-Real-Port). When this parameter is set -trusted-header becomes mandatory
-version -version
Output version information and exit Output version information and exit
``` ```
## Examples ## Examples
### Run a default TCP server ### Run a default TCP server
```bash
./whatismyip
```
### Run a default TCP server with geo information enabled
```bash ```bash
./whatismyip -geoip2-city ./test/GeoIP2-City-Test.mmdb -geoip2-asn ./test/GeoLite2-ASN-Test.mmdb ./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 ```bash
./whatismyip -geoip2-city ./test/GeoIP2-City-Test.mmdb -geoip2-asn ./test/GeoLite2-ASN-Test.mmdb \ ./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/internal/setting"
"github.com/dcarrillo/whatismyip/resolver" "github.com/dcarrillo/whatismyip/resolver"
"github.com/dcarrillo/whatismyip/server" "github.com/dcarrillo/whatismyip/server"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-contrib/secure" "github.com/gin-contrib/secure"
"github.com/patrickmn/go-cache" "github.com/patrickmn/go-cache"
@ -41,11 +42,20 @@ func main() {
engine.Use(router.GetDNSDiscoveryHandler(store, setting.App.Resolver.Domain, setting.App.Resolver.RedirectPort)) 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 != "" {
var err error
geoSvc, err = service.NewGeo(context.Background(), setting.App.GeodbPath.City, setting.App.GeodbPath.ASN)
if err != nil {
panic(err)
}
}
router.SetupTemplate(engine) router.SetupTemplate(engine)
router.Setup(engine) router.Setup(engine, geoSvc)
servers = slices.Concat(servers, setupHTTPServers(context.Background(), engine.Handler())) servers = slices.Concat(servers, setupHTTPServers(context.Background(), engine.Handler()))
whatismyip := server.Setup(servers) whatismyip := server.Setup(servers, geoSvc)
whatismyip.Run() whatismyip.Run()
} }

25
go.mod
View File

@ -4,14 +4,14 @@ go 1.23
require ( require (
github.com/docker/docker v26.1.5+incompatible github.com/docker/docker v26.1.5+incompatible
github.com/gin-contrib/secure v1.1.0 github.com/gin-contrib/secure v1.1.1
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/miekg/dns v1.1.62 github.com/miekg/dns v1.1.62
github.com/oschwald/maxminddb-golang v1.13.1 github.com/oschwald/maxminddb-golang v1.13.1
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/quic-go/quic-go v0.48.2 github.com/quic-go/quic-go v0.48.2
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.10.0
github.com/testcontainers/testcontainers-go v0.31.0 github.com/testcontainers/testcontainers-go v0.31.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
@ -19,11 +19,13 @@ require (
require ( require (
dario.cat/mergo v1.0.0 // indirect dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // 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/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/bytedance/sonic v1.12.6 // indirect github.com/bytedance/sonic v1.12.6 // indirect
github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/bytedance/sonic/loader v0.2.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // 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/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect github.com/cloudwego/iasm v0.2.0 // indirect
github.com/containerd/containerd v1.7.15 // indirect github.com/containerd/containerd v1.7.15 // indirect
@ -33,9 +35,11 @@ require (
github.com/distribution/reference v0.5.0 // indirect github.com/distribution/reference v0.5.0 // indirect
github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/gabriel-vasile/mimetype v1.4.7 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v1.0.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
@ -47,14 +51,20 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.16.0 // indirect github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
github.com/mgechev/revive v1.5.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect
@ -63,7 +73,8 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect github.com/morikuni/aec v1.0.0 // indirect
github.com/onsi/ginkgo/v2 v2.22.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onsi/ginkgo/v2 v2.22.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect
@ -71,9 +82,11 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/shirou/gopsutil/v3 v3.23.12 // indirect github.com/shirou/gopsutil/v3 v3.23.12 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.9.3 // 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/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
@ -96,5 +109,5 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // 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/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/grpc v1.59.0 // indirect google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.36.0 // indirect google.golang.org/protobuf v1.36.1 // indirect
) )

69
go.sum
View File

@ -4,12 +4,12 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= 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 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= 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 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= 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 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w= github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
github.com/bytedance/sonic v1.12.5 h1:hoZxY8uW+mT+OpkcUWw4k0fDINtOcVavEsGfzwzFU/w=
github.com/bytedance/sonic v1.12.5/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk= github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
@ -17,6 +17,8 @@ github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iC
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= 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/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 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= 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 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
@ -41,14 +43,18 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= 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 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
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/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA= github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU= github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
github.com/gin-contrib/secure v1.1.0 h1:wy/psCWbgUBDCLH13KgB/m06NHXb1jczSTRp+H2hK7E= github.com/gin-contrib/secure v1.1.1 h1:q1AGANrYRhJYYHZCF0VH/NVvP0uOSMXmXbsaqWRgIEQ=
github.com/gin-contrib/secure v1.1.0/go.mod h1:LtEfyy326NRwgkUq8ac6npf845L0L9B8yfEaLcxMHIc= github.com/gin-contrib/secure v1.1.1/go.mod h1:4IhY8OTLEAI3R7qZF1ya4y75WowL8MJ09i2Kunl83HE=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= 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/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
@ -66,7 +72,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= 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/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
@ -86,12 +91,14 @@ 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/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 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 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/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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 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.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
@ -106,10 +113,22 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= 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 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 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/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 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-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.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/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.5.1 h1:hE+QPeq0/wIzJwOphdVyUJ82njdd8Khp4fUIHGZHW3M=
github.com/mgechev/revive v1.5.1/go.mod h1:lC9AhkJIBs5zwx8wkudyHrU+IJkrEKmpCmGMnIJPk4o=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ= github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ= github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
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/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= 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/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
@ -127,10 +146,12 @@ 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/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 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 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/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 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
@ -139,7 +160,6 @@ github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5
github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8= 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 h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -152,6 +172,9 @@ 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/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE= github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs= github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
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 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= 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 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4=
@ -162,17 +185,20 @@ 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/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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.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.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.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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.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.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.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.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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.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 h1:W0VwIhcEVhRflwL9as3dhY6jXjVCA27AkmbnZ+UTh3U=
github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI= github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
@ -212,8 +238,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@ -224,8 +248,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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-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.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -240,6 +262,7 @@ 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-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-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-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.6.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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -270,10 +293,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= 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 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@ -200,8 +200,10 @@ func TestContainerIntegration(t *testing.T) {
resp, body, err = doQuicRequest(req) resp, body, err = doQuicRequest(req)
} else { } else {
client := &http.Client{} client := &http.Client{}
resp, _ = client.Do(req) resp, err = client.Do(req)
assert.NoError(t, err)
body, err = io.ReadAll(resp.Body) body, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
if strings.Contains(tt.url, "https://") { if strings.Contains(tt.url, "https://") {
assert.Equal(t, `h3=":8001"; ma=2592000`, resp.Header.Get("Alt-Svc")) assert.Equal(t, `h3=":8001"; ma=2592000`, resp.Header.Get("Alt-Svc"))
} }

View File

@ -12,9 +12,10 @@ import (
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
type geodbPath struct { type geodbConf struct {
City string City string
ASN string ASN string
Token *string
} }
type serverSettings struct { type serverSettings struct {
ReadTimeout time.Duration ReadTimeout time.Duration
@ -30,7 +31,7 @@ type resolver struct {
} }
type settings struct { type settings struct {
GeodbPath geodbPath GeodbPath geodbConf
TemplatePath string TemplatePath string
BindAddress string BindAddress string
TLSAddress string TLSAddress string
@ -63,8 +64,8 @@ func Setup(args []string) (output string, err error) {
var resolverConf string var resolverConf string
flags.SetOutput(&buf) flags.SetOutput(&buf)
flags.StringVar(&App.GeodbPath.City, "geoip2-city", "", "Path to GeoIP2 city 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") 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(&App.TemplatePath, "template", "", "Path to the template file")
flags.StringVar( flags.StringVar(
&resolverConf, &resolverConf,
@ -120,12 +121,12 @@ func Setup(args []string) (output string, err error) {
return fmt.Sprintf("whatismyip version %s", core.Version), ErrVersion return fmt.Sprintf("whatismyip version %s", core.Version), ErrVersion
} }
if App.TrustedPortHeader != "" && App.TrustedHeader == "" { if (App.GeodbPath.City != "" && App.GeodbPath.ASN == "") || (App.GeodbPath.City == "" && App.GeodbPath.ASN != "") {
return "", fmt.Errorf("truster-header is mandatory when truster-port-header is set") return "", fmt.Errorf("both --geoip2-city and --geoip2-asn are mandatory to enable geo information")
} }
if App.GeodbPath.City == "" || App.GeodbPath.ASN == "" { if App.TrustedPortHeader != "" && App.TrustedHeader == "" {
return "", fmt.Errorf("geoip2-city and geoip2-asn parameters are mandatory") return "", fmt.Errorf("truster-header is mandatory when truster-port-header is set")
} }
if (App.TLSAddress != "") && (App.TLSCrtPath == "" || App.TLSKeyPath == "") { if (App.TLSAddress != "") && (App.TLSCrtPath == "" || App.TLSKeyPath == "") {
@ -150,7 +151,7 @@ func Setup(args []string) (output string, err error) {
var err error var err error
App.Resolver, err = readYAML(resolverConf) App.Resolver, err = readYAML(resolverConf)
if err != nil { 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) { func TestParseMandatoryFlags(t *testing.T) {
var mandatoryFlags = []struct { mandatoryFlags := []struct {
args []string args []string
}{ }{
{
[]string{},
},
{
[]string{"-geoip2-city", "/city-path"},
},
{
[]string{"-geoip2-asn", "/asn-path"},
},
{ {
[]string{ []string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000", "-geoip2-city", "my-city-path",
}, },
}, },
{ {
[]string{ []string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000", "-geoip2-asn", "my-asn-path",
"-tls-crt", "/crt-path", },
},
{
[]string{
"-tls-bind", ":9000",
}, },
}, },
{ {
[]string{ []string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000", "-tls-bind", ":9000", "-tls-crt", "/crt-path",
"-tls-key", "/key-path",
}, },
}, },
{ {
[]string{ []string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-enable-http3", "-tls-bind", ":9000", "-tls-key", "/key-path",
}, },
}, },
{ {
[]string{ []string{
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-bind", ":8000", "-enable-http3",
"-trusted-port-header", "port-header", },
},
{
[]string{
"-bind", ":8000", "-trusted-port-header", "port-header",
}, },
}, },
} }
@ -57,24 +56,20 @@ func TestParseMandatoryFlags(t *testing.T) {
for _, tt := range mandatoryFlags { for _, tt := range mandatoryFlags {
t.Run(strings.Join(tt.args, " "), func(t *testing.T) { t.Run(strings.Join(tt.args, " "), func(t *testing.T) {
_, err := Setup(tt.args) _, err := Setup(tt.args)
require.NotNil(t, err) require.Error(t, err)
assert.Contains(t, err.Error(), "mandatory") assert.Contains(t, err.Error(), "mandatory")
}) })
} }
} }
func TestParseFlags(t *testing.T) { func TestParseFlags(t *testing.T) {
var flags = []struct { flags := []struct {
args []string args []string
conf settings conf settings
}{ }{
{ {
[]string{"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path"}, []string{},
settings{ settings{
GeodbPath: geodbPath{
City: "/city-path",
ASN: "/asn-path",
},
BindAddress: ":8080", BindAddress: ":8080",
Server: serverSettings{ Server: serverSettings{
ReadTimeout: 10 * time.Second, ReadTimeout: 10 * time.Second,
@ -85,7 +80,7 @@ func TestParseFlags(t *testing.T) {
{ {
[]string{"-bind", ":8001", "-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path"}, []string{"-bind", ":8001", "-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path"},
settings{ settings{
GeodbPath: geodbPath{ GeodbPath: geodbConf{
City: "/city-path", City: "/city-path",
ASN: "/asn-path", ASN: "/asn-path",
}, },
@ -102,7 +97,7 @@ func TestParseFlags(t *testing.T) {
"-tls-crt", "/crt-path", "-tls-key", "/key-path", "-tls-crt", "/crt-path", "-tls-key", "/key-path",
}, },
settings{ settings{
GeodbPath: geodbPath{ GeodbPath: geodbConf{
City: "/city-path", City: "/city-path",
ASN: "/asn-path", ASN: "/asn-path",
}, },
@ -122,7 +117,7 @@ func TestParseFlags(t *testing.T) {
"-trusted-header", "header", "-trusted-port-header", "port-header", "-trusted-header", "header", "-trusted-port-header", "port-header",
}, },
settings{ settings{
GeodbPath: geodbPath{ GeodbPath: geodbConf{
City: "/city-path", City: "/city-path",
ASN: "/asn-path", ASN: "/asn-path",
}, },
@ -141,7 +136,7 @@ func TestParseFlags(t *testing.T) {
"-trusted-header", "header", "-enable-secure-headers", "-trusted-header", "header", "-enable-secure-headers",
}, },
settings{ settings{
GeodbPath: geodbPath{ GeodbPath: geodbConf{
City: "/city-path", City: "/city-path",
ASN: "/asn-path", ASN: "/asn-path",
}, },
@ -166,7 +161,7 @@ func TestParseFlags(t *testing.T) {
} }
func TestParseFlagsUsage(t *testing.T) { func TestParseFlagsUsage(t *testing.T) {
var usageArgs = []string{"-help", "-h", "--help"} usageArgs := []string{"-help", "-h", "--help"}
for _, arg := range usageArgs { for _, arg := range usageArgs {
t.Run(arg, func(t *testing.T) { t.Run(arg, func(t *testing.T) {
@ -184,19 +179,28 @@ func TestParseFlagVersion(t *testing.T) {
} }
func TestParseFlagTemplate(t *testing.T) { func TestParseFlagTemplate(t *testing.T) {
flags := []string{ testCases := []struct {
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", name string
"-template", "/template-path", 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{ for _, tc := range testCases {
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", t.Run(tc.name, func(t *testing.T) {
"-template", "/", _, err := Setup(tc.flags)
require.Error(t, err)
assert.Contains(t, err.Error(), tc.errMsg)
})
} }
_, err = Setup(flags)
require.Error(t, err)
assert.Contains(t, err.Error(), "must be a file")
} }

View File

@ -1,13 +1,13 @@
package models package models
import ( import (
"fmt"
"log" "log"
"net" "net"
"github.com/oschwald/maxminddb-golang" "github.com/oschwald/maxminddb-golang"
) )
// GeoRecord is the model for City database
type GeoRecord struct { type GeoRecord struct {
Country struct { Country struct {
ISOCode string `maxminddb:"iso_code"` ISOCode string `maxminddb:"iso_code"`
@ -26,52 +26,107 @@ type GeoRecord struct {
} `maxminddb:"postal"` } `maxminddb:"postal"`
} }
// ASNRecord is the model for ASN database
type ASNRecord struct { type ASNRecord struct {
AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"` AutonomousSystemNumber uint `maxminddb:"autonomous_system_number"`
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"` AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
} }
type geodb struct { type GeoDB struct {
city *maxminddb.Reader cityPath string
asn *maxminddb.Reader 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) db, err := maxminddb.Open(path)
if err != nil { if err != nil {
log.Fatal(err) return nil, err
} }
log.Printf("Database %s has been loaded\n", path) log.Printf("Database %s has been loaded\n", path)
return db return db, nil
}
// 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)
} }

View File

@ -1,10 +1,12 @@
package models package models
import ( import (
"fmt"
"net" "net"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestModels(t *testing.T) { func TestModels(t *testing.T) {
@ -59,19 +61,21 @@ func TestModels(t *testing.T) {
AutonomousSystemOrganization: "IP-Only", AutonomousSystemOrganization: "IP-Only",
} }
Setup("../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb") db, err := Setup("../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
defer CloseDBs() 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) cityRecord, err := db.LookupCity(net.ParseIP("81.2.69.192"))
assert.NotNil(t, db.city) require.NoError(t, err, fmt.Sprintf("Error looking up city: %s", err))
cityRecord := &GeoRecord{}
assert.Nil(t, cityRecord.LookUp(net.ParseIP("81.2.69.192")))
assert.Equal(t, expectedCity, cityRecord) 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{} asnRecord, err := db.LookupASN(net.ParseIP("82.99.17.64"))
assert.Nil(t, asnRecord.LookUp(net.ParseIP("82.99.17.64"))) require.NoError(t, err, fmt.Sprintf("Error looking up asn: %s", err))
assert.Equal(t, expectedASN, asnRecord) 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" "strings"
validator "github.com/dcarrillo/whatismyip/internal/validator/uuid" validator "github.com/dcarrillo/whatismyip/internal/validator/uuid"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/patrickmn/go-cache" "github.com/patrickmn/go-cache"
@ -16,10 +15,14 @@ import (
type DNSJSONResponse struct { type DNSJSONResponse struct {
DNS dnsData `json:"dns"` DNS dnsData `json:"dns"`
} }
type dnsGeoData struct {
Country string `json:"country,omitempty"`
AsnOrganization string `json:"provider,omitempty"`
}
type dnsData struct { type dnsData struct {
IP string `json:"ip"` IP string `json:"ip"`
Country string `json:"country"` dnsGeoData
AsnOrganization string `json:"provider"`
} }
// TODO // TODO
@ -67,12 +70,21 @@ func handleDNS(ctx *gin.Context, store *cache.Cache) {
return 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{ j := DNSJSONResponse{
DNS: dnsData{ DNS: dnsData{
IP: ipStr, IP: ipStr,
Country: geo.LookUpCity().Country.Names["en"], dnsGeoData: geoResp,
AsnOrganization: geo.LookUpASN().AutonomousSystemOrganization,
}, },
} }

View File

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

View File

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

View File

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

View File

@ -1,10 +1,11 @@
package router package router
import ( import (
"context"
"os" "os"
"testing" "testing"
"github.com/dcarrillo/whatismyip/models" "github.com/dcarrillo/whatismyip/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -34,9 +35,9 @@ var (
text: "text/plain; charset=utf-8", text: "text/plain; charset=utf-8",
json: "application/json; 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": {}}` 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", "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": {}}` 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","provider":""}}` jsonDNSIPv4 = `{"dns":{"ip":"81.2.69.192","country":"United Kingdom"}}`
plainDNSIPv4 = "81.2.69.192 (United Kingdom / )\n" plainDNSIPv4 = "81.2.69.192 (United Kingdom / )\n"
) )
@ -49,9 +50,8 @@ const (
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
app = gin.Default() app = gin.Default()
app.TrustedPlatform = trustedHeader app.TrustedPlatform = trustedHeader
models.Setup("../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb") svc, _ := service.NewGeo(context.Background(), "../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
Setup(app) Setup(app, svc)
defer models.CloseDBs()
os.Exit(m.Run()) os.Exit(m.Run())
} }

View File

@ -62,20 +62,22 @@ func TestDefaultTemplate(t *testing.T) {
tmpl, _ := template.New("home").Parse(home) tmpl, _ := template.New("home").Parse(home)
response := JSONResponse{ response := JSONResponse{
IP: "127.0.0.1", IP: "127.0.0.1",
IPVersion: 4, IPVersion: 4,
ClientPort: "1000", ClientPort: "1000",
Country: "A Country", Host: "localhost",
CountryCode: "XX", Headers: req.Header,
City: "A City", GeoResponse: GeoResponse{
Latitude: 100, Country: "A Country",
Longitude: -100, CountryCode: "XX",
PostalCode: "00000", City: "A City",
TimeZone: "My/Timezone", Latitude: 100,
ASN: 0, Longitude: -100,
ASNOrganization: "My ISP", PostalCode: "00000",
Host: "localhost", TimeZone: "My/Timezone",
Headers: req.Header, ASN: 0,
ASNOrganization: "My ISP",
},
} }
buf := &bytes.Buffer{} buf := &bytes.Buffer{}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,37 +1,73 @@
package service package service
import ( import (
"context"
"log" "log"
"net" "net"
"sync"
"github.com/dcarrillo/whatismyip/models" "github.com/dcarrillo/whatismyip/models"
) )
// Geo defines a base type for lookups
type Geo struct { 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 NewGeo(ctx context.Context, cityPath string, asnPath string) (*Geo, error) {
func (g *Geo) LookUpCity() *models.GeoRecord { ctx, cancel := context.WithCancel(ctx)
record := &models.GeoRecord{}
err := record.LookUp(g.IP) db, err := models.Setup(cityPath, asnPath)
if err != nil { 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 nil
} }
return record return record
} }
// LookUpASN queries the database for ASN data related to the given IP func (g *Geo) LookUpASN(ip net.IP) *models.ASNRecord {
func (g *Geo) LookUpASN() *models.ASNRecord { record, err := g.db.LookupASN(ip)
record := &models.ASNRecord{}
err := record.LookUp(g.IP)
if err != nil { if err != nil {
log.Println(err) log.Print(err)
return nil return nil
} }
return record 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 package service
import ( import (
"context"
"net" "net"
"os" "os"
"testing" "testing"
"github.com/dcarrillo/whatismyip/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
var geoSvc *Geo
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
models.Setup("../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb") geoSvc, _ = NewGeo(context.Background(), "../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
defer models.CloseDBs()
os.Exit(m.Run()) os.Exit(m.Run())
} }
func TestCityLookup(t *testing.T) { func TestCityLookup(t *testing.T) {
ip := Geo{IP: net.ParseIP("error")} c := geoSvc.LookUpCity(net.ParseIP("error"))
c := ip.LookUpCity()
assert.Nil(t, c) assert.Nil(t, c)
ip = Geo{IP: net.ParseIP("1.1.1.1")} c = geoSvc.LookUpCity(net.ParseIP("1.1.1.1"))
c = ip.LookUpCity()
assert.NotNil(t, c) assert.NotNil(t, c)
} }
func TestASNLookup(t *testing.T) { func TestASNLookup(t *testing.T) {
ip := Geo{IP: net.ParseIP("error")} a := geoSvc.LookUpASN(net.ParseIP("error"))
a := ip.LookUpASN()
assert.Nil(t, a) assert.Nil(t, a)
ip = Geo{IP: net.ParseIP("1.1.1.1")} a = geoSvc.LookUpASN(net.ParseIP("1.1.1.1"))
a = ip.LookUpASN()
assert.NotNil(t, a) assert.NotNil(t, a)
} }