mirror of
https://github.com/dcarrillo/whatismyip.git
synced 2025-01-15 15:56:48 +00:00
Make geo database usage optional (#39)
This commit is contained in:
parent
95e7742c56
commit
b5fe362183
@ -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
|
||||||
|
11
Makefile
11
Makefile
@ -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
|
||||||
|
40
README.md
40
README.md
@ -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)
|
||||||
@ -22,7 +23,8 @@
|
|||||||
- [Run a container locally using test databases](#run-a-container-locally-using-test-databases)
|
- [Run a container locally using test databases](#run-a-container-locally-using-test-databases)
|
||||||
- [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 \
|
||||||
|
@ -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
25
go.mod
@ -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
69
go.sum
@ -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=
|
||||||
|
@ -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"))
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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")
|
|
||||||
}
|
}
|
||||||
|
127
models/geo.go
127
models/geo.go
@ -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)
|
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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{}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user