22 Commits
2.1.1 ... 2.2.2

Author SHA1 Message Date
901345a337 [chore] Update workflows dependecies 2024-03-23 17:47:39 +01:00
0c14419e7e Server handling refactor (#27) 2024-03-23 17:41:34 +01:00
db111642d2 Bump github.com/docker/docker (#26)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from 24.0.7+incompatible to 24.0.9+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v24.0.7...v24.0.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-20 19:49:19 +01:00
d5b1373e17 Bump google.golang.org/protobuf from 1.32.0 to 1.33.0 (#25)
Bumps google.golang.org/protobuf from 1.32.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-14 15:40:42 +01:00
ba8a2ec494 Bump github.com/opencontainers/runc from 1.1.9 to 1.1.12 (#24)
Bumps [github.com/opencontainers/runc](https://github.com/opencontainers/runc) from 1.1.9 to 1.1.12.
- [Release notes](https://github.com/opencontainers/runc/releases)
- [Changelog](https://github.com/opencontainers/runc/blob/v1.1.12/CHANGELOG.md)
- [Commits](https://github.com/opencontainers/runc/compare/v1.1.9...v1.1.12)

---
updated-dependencies:
- dependency-name: github.com/opencontainers/runc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 17:27:37 +01:00
f8e27bef56 Add endopoint to check is a given port is open on the client (#22) 2023-12-31 12:52:08 +01:00
2bbeeb34c5 Bump github.com/containerd/containerd from 1.7.7 to 1.7.11 (#20)
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.7.7 to 1.7.11.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.7.7...v1.7.11)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-20 20:08:35 +01:00
0090b794ee Bump golang.org/x/crypto from 0.14.0 to 0.17.0 (#19)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.14.0 to 0.17.0.
- [Commits](https://github.com/golang/crypto/compare/v0.14.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 09:10:37 +01:00
93f561d6ef Bump github.com/docker/docker from 20.10.24+incompatible to 24.0.7+incompatible (#18)
* Bump github.com/docker/docker

Bumps [github.com/docker/docker](https://github.com/docker/docker) from 20.10.24+incompatible to 24.0.7+incompatible.
- [Release notes](https://github.com/docker/docker/releases)
- [Commits](https://github.com/docker/docker/compare/v20.10.24...v24.0.7)

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

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

* Update dependencies

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Daniel Carrillo <daniel.carrillo@gmail.com>
2023-10-30 19:17:40 +01:00
9da6d2fec5 Bump google.golang.org/grpc from 1.53.0 to 1.56.3 (#17)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.53.0 to 1.56.3.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.53.0...v1.56.3)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-26 09:25:00 +02:00
8e3d731719 [ci] Remove unused lines from codeql-analysis.yml 2023-10-12 12:52:44 +02:00
d5b244dc5f Bump go version to 1.21.3 (it fix HTTP/2 Stream Resets issue) 2023-10-12 12:14:49 +02:00
d767afd658 Update dependencies 2023-10-11 19:39:33 +02:00
f4fd79737e Bump golang version to 1.21 2023-08-25 18:34:21 +02:00
2ab6b29ed5 Update dependencies 2023-08-12 18:38:01 +02:00
55e6cd4816 Update test to latest quic version 2023-07-22 13:20:17 +02:00
a490d5f10e Update dependencies 2023-07-22 13:14:33 +02:00
994a12da5a Bump google.golang.org/grpc from 1.48.0 to 1.53.0 (#15)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.48.0 to 1.53.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.48.0...v1.53.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-06 08:07:54 +02:00
91deff4a14 chore: bump Go action to v4 (#13) 2023-06-02 17:23:48 +02:00
81c3a4fbb0 Bump github.com/gin-gonic/gin from 1.9.0 to 1.9.1 (#14)
Bumps [github.com/gin-gonic/gin](https://github.com/gin-gonic/gin) from 1.9.0 to 1.9.1.
- [Release notes](https://github.com/gin-gonic/gin/releases)
- [Changelog](https://github.com/gin-gonic/gin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gin-gonic/gin/compare/v1.9.0...v1.9.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-02 17:13:53 +02:00
5b85eef7eb Bump github.com/docker/distribution (#12)
Bumps [github.com/docker/distribution](https://github.com/docker/distribution) from 2.8.1+incompatible to 2.8.2+incompatible.
- [Release notes](https://github.com/docker/distribution/releases)
- [Commits](https://github.com/docker/distribution/compare/v2.8.1...v2.8.2)

---
updated-dependencies:
- dependency-name: github.com/docker/distribution
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-12 17:00:06 +02:00
c54cf5a456 Add upx compression to Dockerfile 2023-04-29 18:49:21 +02:00
17 changed files with 463 additions and 1314 deletions

View File

@ -29,21 +29,18 @@ jobs:
contents: read
security-events: write
strategy:
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: install go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: go
@ -52,4 +49,4 @@ jobs:
make build
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3

View File

@ -15,13 +15,12 @@ jobs:
matrix:
make: ["lint", "test"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: install go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: ${{ matrix.make }}
run: make ${{ matrix.make }}
@ -34,11 +33,11 @@ jobs:
matrix:
goosarch: [linux-amd64]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: install go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

View File

@ -1,4 +1,4 @@
FROM golang:1.20-alpine as builder
FROM golang:1.21-alpine as builder
ARG ARG_VERSION
ENV VERSION $ARG_VERSION
@ -7,7 +7,8 @@ WORKDIR /app
COPY . .
RUN apk add make git && make build VERSION=$VERSION
RUN apk add make git upx && make build VERSION=$VERSION \
&& upx --best --lzma whatismyip
# Build final image
FROM scratch

View File

@ -7,11 +7,11 @@ test: unit-test integration-test
.PHONY: unit-test
unit-test:
go test -race -short -cover ./...
go test -count=1 -race -short -cover ./...
.PHONY: integration-test
integration-test:
go test ./integration-tests -v
go test -count=1 -v ./integration-tests
.PHONY: install-tools
install-tools:
@ -22,14 +22,9 @@ install-tools:
@command $(GOPATH)/shadow > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow@latest; \
fi
@command $(GOPATH)/golines > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install github.com/segmentio/golines@latest; \
fi
.PHONY: lint
lint: install-tools
gofmt -l . && test -z $$(gofmt -l .)
golines -l . && test -z $$(golines -l .)
golangci-lint run
shadow ./...

View File

@ -21,7 +21,8 @@
- [Run a container locally using test databases](#run-a-container-locally-using-test-databases)
- [From Docker Hub](#from-docker-hub)
Just another "what is my IP address" service, including geolocation and headers information, written in go with high performance in mind, it uses [gin](https://github.com/gin-gonic/gin) which uses [httprouter](https://github.com/julienschmidt/httprouter) a lightweight high performance HTTP multiplexer.
Just another "what is my IP address" service, including geolocation, TCP open port checking, and headers information. Written in go with high performance in mind,
it uses [gin](https://github.com/gin-gonic/gin) which uses [httprouter](https://github.com/julienschmidt/httprouter) a lightweight high performance HTTP multiplexer.
Take a look at [ifconfig.es](https://ifconfig.es) a live site using `whatismyip`
@ -42,6 +43,7 @@ curl -6 ifconfig.es
- Can run behind a proxy by trusting a custom header (usually `X-Real-IP`) to figure out the source IP address. It also supports a custom header to resolve the client port, if the proxy can only add a header for the IP (for example a fixed header from CDNs) the client port is shown as unknown.
- IPv4 and IPv6.
- Geolocation info including ASN. This feature is possible thanks to [maxmind](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data?lang=en) GeoLite2 databases. In order to use these databases, a license key is needed. Please visit Maxmind site for further instructions and get a free license.
- Checking TCP open ports.
- High performance.
- Self-contained server that can reload GeoLite2 databases and/or SSL certificates without stop/start. The `hup` signal is honored.
- HTML templates for the landing page.
@ -66,6 +68,7 @@ curl -6 ifconfig.es
- https://ifconfig.es/all
- https://ifconfig.es/headers
- https://ifconfig.es/<header_name>
- https://ifconfig.es/scan/tcp/<port_number>
## Build
@ -138,7 +141,7 @@ Download the latest version from https://github.com/dcarrillo/whatismyip/release
## Docker
An ultra-light (~12MB) image is available at [docker hub](https://hub.docker.com/r/dcarrillo/whatismyip).
An ultra-light (~4MB) image is available on [docker hub](https://hub.docker.com/r/dcarrillo/whatismyip). Since version `2.1.2`, the binary is compressed using [upx](https://github.com/upx/upx).
### Run a container locally using test databases

View File

@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
"net/http"
"os"
"github.com/dcarrillo/whatismyip/internal/httputils"
@ -30,8 +31,9 @@ func main() {
engine := setupEngine()
router.SetupTemplate(engine)
router.Setup(engine)
servers := setupHTTPServers(context.Background(), engine.Handler())
whatismyip := server.Setup(context.Background(), engine.Handler())
whatismyip := server.Setup(servers)
whatismyip.Run()
}
@ -55,3 +57,23 @@ func setupEngine() *gin.Engine {
return engine
}
func setupHTTPServers(ctx context.Context, handler http.Handler) []server.Server {
var servers []server.Server
if setting.App.BindAddress != "" {
tcpServer := server.NewTCPServer(ctx, &handler)
servers = append(servers, tcpServer)
}
if setting.App.TLSAddress != "" {
tlsServer := server.NewTLSServer(ctx, &handler)
servers = append(servers, tlsServer)
if setting.App.EnableHTTP3 {
quicServer := server.NewQuicServer(ctx, tlsServer)
servers = append(servers, quicServer)
}
}
return servers
}

109
go.mod
View File

@ -1,77 +1,90 @@
module github.com/dcarrillo/whatismyip
go 1.20
go 1.21.3
require (
github.com/gin-contrib/secure v0.0.1
github.com/gin-gonic/gin v1.9.0
github.com/oschwald/maxminddb-golang v1.10.0
github.com/quic-go/quic-go v0.34.0
github.com/stretchr/testify v1.8.2
github.com/testcontainers/testcontainers-go v0.13.0
golang.org/x/net v0.9.0
github.com/gin-gonic/gin v1.9.1
github.com/oschwald/maxminddb-golang v1.12.0
github.com/quic-go/quic-go v0.40.1
github.com/stretchr/testify v1.8.4
github.com/testcontainers/testcontainers-go v0.27.0
)
require (
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/Microsoft/hcsshim v0.9.6 // indirect
github.com/bytedance/sonic v1.8.8 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/containerd/cgroups v1.0.4 // indirect
github.com/containerd/containerd v1.6.18 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/bytedance/sonic v1.10.2 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.1 // indirect
github.com/containerd/containerd v1.7.11 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.24+incompatible // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v24.0.9+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.12.0 // indirect
github.com/go-playground/validator/v10 v10.16.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/pprof v0.0.0-20230426061923-93006964c1fc // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/pprof v0.0.0-20231229205709-960ae82b1e42 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/leodido/go-urn v1.2.3 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/moby/sys/mount v0.3.3 // indirect
github.com/moby/sys/mountinfo v0.6.2 // indirect
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
github.com/klauspost/compress v1.16.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/onsi/ginkgo/v2 v2.9.2 // indirect
github.com/onsi/ginkgo/v2 v2.13.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/opencontainers/runc v1.1.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/opencontainers/runc v1.1.12 // indirect
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/shirou/gopsutil/v3 v3.23.11 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.8.0 // indirect
google.golang.org/genproto v0.0.0-20220810155839-1856144b1d9c // indirect
google.golang.org/grpc v1.48.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/arch v0.6.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.17.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
)

1275
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,8 @@ import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"path/filepath"
"runtime"
@ -30,12 +30,12 @@ func buildContainer() testcontainers.ContainerRequest {
Dockerfile: "Dockerfile",
},
Cmd: []string{
"-geoip2-city", "/tmp/GeoIP2-City-Test.mmdb",
"-geoip2-asn", "/tmp/GeoLite2-ASN-Test.mmdb",
"-geoip2-city", "/GeoIP2-City-Test.mmdb",
"-geoip2-asn", "/GeoLite2-ASN-Test.mmdb",
"-bind", ":8000",
"-tls-bind", ":8001",
"-tls-crt", "/tmp/server.pem",
"-tls-key", "/tmp/server.key",
"-tls-crt", "/server.pem",
"-tls-key", "/server.key",
"-trusted-header", "X-Real-IP",
"-enable-secure-headers",
"-enable-http3",
@ -44,45 +44,55 @@ func buildContainer() testcontainers.ContainerRequest {
WaitingFor: wait.ForHTTP("/geo").
WithTLS(true, &tls.Config{InsecureSkipVerify: true}).
WithPort("8001"),
Mounts: testcontainers.Mounts(
testcontainers.BindMount(
filepath.Join(dir, "/../test/GeoIP2-City-Test.mmdb"),
"/tmp/GeoIP2-City-Test.mmdb",
),
testcontainers.BindMount(
filepath.Join(dir, "/../test/GeoLite2-ASN-Test.mmdb"),
"/tmp/GeoLite2-ASN-Test.mmdb",
),
testcontainers.BindMount(filepath.Join(dir, "/../test/server.pem"), "/tmp/server.pem"),
testcontainers.BindMount(filepath.Join(dir, "/../test/server.key"), "/tmp/server.key"),
),
Files: []testcontainers.ContainerFile{
{
HostFilePath: filepath.Join(dir, "/../test/GeoIP2-City-Test.mmdb"),
ContainerFilePath: "/GeoIP2-City-Test.mmdb",
FileMode: 0644,
},
{
HostFilePath: filepath.Join(dir, "/../test/GeoLite2-ASN-Test.mmdb"),
ContainerFilePath: "/GeoLite2-ASN-Test.mmdb",
FileMode: 0644,
},
{
HostFilePath: filepath.Join(dir, "/../test/server.pem"),
ContainerFilePath: "/server.pem",
FileMode: 0644,
},
{
HostFilePath: filepath.Join(dir, "/../test/server.key"),
ContainerFilePath: "/server.key",
FileMode: 0644,
},
},
}
return req
}
func initContainer(t assert.TestingT, request testcontainers.ContainerRequest) func() {
ctx := context.Background()
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: request,
Started: true,
})
assert.NoError(t, err)
return func() {
assert.NoError(t, container.Terminate(ctx))
}
}
func TestContainerIntegration(t *testing.T) {
if testing.Short() {
t.Skip("Skiping integration tests")
}
ctx := context.Background()
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: buildContainer(),
Started: true,
})
if err != nil {
log.Fatal(err)
}
defer func() {
err = container.Terminate(ctx)
if err != nil {
log.Fatal(err)
}
}()
t.Cleanup(initContainer(t, buildContainer()))
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
tests := []struct {
name string
url string
@ -105,9 +115,27 @@ func TestContainerIntegration(t *testing.T) {
},
}
testsPortScan := []struct {
name string
port int
want bool
}{
{
name: "RequestOpenPortScan",
port: 8000,
want: true,
},
{
name: "RequestClosedPortScan",
port: 65533,
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req, _ := http.NewRequest("GET", tt.url, nil)
req, err := http.NewRequest("GET", tt.url, nil)
assert.NoError(t, err)
req.Header.Set("Accept", "application/json")
var resp *http.Response
@ -119,7 +147,7 @@ func TestContainerIntegration(t *testing.T) {
resp, _ = client.Do(req)
body, err = io.ReadAll(resp.Body)
if strings.Contains(tt.url, "https://") {
assert.Equal(t, `h3=":8001"; ma=2592000,h3-29=":8001"; ma=2592000`, resp.Header.Get("Alt-Svc"))
assert.Equal(t, `h3=":8001"; ma=2592000`, resp.Header.Get("Alt-Svc"))
}
}
assert.NoError(t, err)
@ -131,6 +159,27 @@ func TestContainerIntegration(t *testing.T) {
assert.Equal(t, "1; mode=block", resp.Header.Get("X-Xss-Protection"))
})
}
for _, tt := range testsPortScan {
t.Run(tt.name, func(t *testing.T) {
req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:8000/scan/tcp/%d", tt.port), nil)
assert.NoError(t, err)
req.Header.Set("Accept", "application/json")
req.Header.Set("X-Real-IP", "127.0.0.1")
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err)
assert.Equal(t, 200, resp.StatusCode)
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
j := router.JSONScanResponse{}
assert.NoError(t, json.Unmarshal(body, &j))
assert.Equal(t, tt.want, j.Reachable)
})
}
}
func doQuicRequest(req *http.Request) (*http.Response, []byte, error) {

View File

@ -63,7 +63,7 @@ func GetLogFormatter(param gin.LogFormatterParams) string {
)
}
func normalizeLog(log interface{}) interface{} {
func normalizeLog(log any) any {
switch v := log.(type) {
case string:
if v == "" {

54
router/port_scanner.go Normal file
View File

@ -0,0 +1,54 @@
package router
import (
"fmt"
"net"
"net/http"
"strconv"
"github.com/dcarrillo/whatismyip/service"
"github.com/gin-gonic/gin"
)
type JSONScanResponse struct {
IP string `json:"ip"`
Port int `json:"port"`
Reachable bool `json:"reachable"`
Reason string `json:"reason"`
}
func scanTCPPort(ctx *gin.Context) {
port, err := strconv.Atoi(ctx.Params.ByName("port"))
if err == nil && (port < 1 || port > 65535) {
err = fmt.Errorf("%d is not a valid port number", port)
}
if err != nil {
ctx.JSON(http.StatusBadRequest, JSONScanResponse{
Reason: err.Error(),
})
return
}
add := net.TCPAddr{
IP: net.ParseIP(ctx.ClientIP()),
Port: port,
}
scan := service.PortScanner{
Address: &add,
}
isOpen, err := scan.IsPortOpen()
reason := ""
if err != nil {
reason = err.Error()
}
response := JSONScanResponse{
IP: ctx.ClientIP(),
Port: port,
Reachable: isOpen,
Reason: reason,
}
ctx.JSON(http.StatusOK, response)
}

View File

@ -22,6 +22,7 @@ func SetupTemplate(r *gin.Engine) {
// Setup defines the endpoints
func Setup(r *gin.Engine) {
r.GET("/", getRoot)
r.GET("/scan/tcp/:port", scanTCPPort)
r.GET("/client-port", getClientPortAsString)
r.GET("/geo", getGeoAsString)
r.GET("/geo/:field", getGeoAsString)

View File

@ -2,6 +2,7 @@ package server
import (
"context"
"errors"
"log"
"net/http"
@ -9,20 +10,20 @@ import (
"github.com/quic-go/quic-go/http3"
)
type QuicServer struct {
type Quic struct {
server *http3.Server
tlsServer *TLSServer
tlsServer *TLS
ctx context.Context
}
func NewQuicServer(ctx context.Context, tlsServer *TLSServer) *QuicServer {
return &QuicServer{
func NewQuicServer(ctx context.Context, tlsServer *TLS) *Quic {
return &Quic{
tlsServer: tlsServer,
ctx: ctx,
}
}
func (q *QuicServer) Start() {
func (q *Quic) Start() {
q.server = &http3.Server{
Addr: setting.App.TLSAddress,
Handler: q.tlsServer.server.Handler,
@ -40,13 +41,13 @@ func (q *QuicServer) Start() {
log.Printf("Starting QUIC server listening on %s (udp)", setting.App.TLSAddress)
go func() {
if err := q.server.ListenAndServeTLS(setting.App.TLSCrtPath, setting.App.TLSKeyPath); err != nil &&
err.Error() != "quic: Server closed" {
!errors.Is(err, http.ErrServerClosed) {
log.Fatal(err)
}
}()
}
func (q *QuicServer) Stop() {
func (q *Quic) Stop() {
log.Printf("Stopping QUIC server...")
if err := q.server.Close(); err != nil {
log.Printf("QUIC server forced to shutdown")

View File

@ -2,14 +2,12 @@ package server
import (
"log"
"net/http"
"os"
"os/signal"
"syscall"
"github.com/dcarrillo/whatismyip/internal/setting"
"github.com/dcarrillo/whatismyip/models"
"golang.org/x/net/context"
)
type Server interface {
@ -17,80 +15,47 @@ type Server interface {
Stop()
}
type Factory struct {
tcpServer *TCPServer
tlsServer *TLSServer
quicServer *QuicServer
type Manager struct {
servers []Server
}
func Setup(ctx context.Context, handler http.Handler) *Factory {
var tcpServer *TCPServer
var tlsServer *TLSServer
var quicServer *QuicServer
if setting.App.BindAddress != "" {
tcpServer = NewTCPServer(ctx, &handler)
}
if setting.App.TLSAddress != "" {
tlsServer = NewTLSServer(ctx, &handler)
if setting.App.EnableHTTP3 {
quicServer = NewQuicServer(ctx, tlsServer)
}
}
return &Factory{
tcpServer: tcpServer,
tlsServer: tlsServer,
quicServer: quicServer,
func Setup(servers []Server) *Manager {
return &Manager{
servers: servers,
}
}
func (f *Factory) Run() {
f.start()
func (m *Manager) Run() {
m.start()
signalChan := make(chan os.Signal, 3)
signalChan := make(chan os.Signal, len(m.servers))
signal.Notify(signalChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
var s os.Signal
for {
s = <-signalChan
if s == syscall.SIGHUP {
f.stop()
m.stop()
models.CloseDBs()
models.Setup(setting.App.GeodbPath.City, setting.App.GeodbPath.ASN)
f.start()
m.start()
} else {
log.Printf("Shutting down...")
f.stop()
m.stop()
models.CloseDBs()
break
}
}
}
func (f *Factory) start() {
if f.tcpServer != nil {
f.tcpServer.Start()
}
if f.tlsServer != nil {
f.tlsServer.Start()
if f.quicServer != nil {
f.quicServer.Start()
}
func (m *Manager) start() {
for _, s := range m.servers {
s.Start()
}
}
func (f *Factory) stop() {
if f.tcpServer != nil {
f.tcpServer.Stop()
}
if f.tlsServer != nil {
if f.quicServer != nil {
f.quicServer.Stop()
}
f.tlsServer.Stop()
func (m *Manager) stop() {
for _, s := range m.servers {
s.Stop()
}
}

View File

@ -9,20 +9,20 @@ import (
"github.com/dcarrillo/whatismyip/internal/setting"
)
type TCPServer struct {
type TCP struct {
server *http.Server
handler *http.Handler
ctx context.Context
}
func NewTCPServer(ctx context.Context, handler *http.Handler) *TCPServer {
return &TCPServer{
func NewTCPServer(ctx context.Context, handler *http.Handler) *TCP {
return &TCP{
handler: handler,
ctx: ctx,
}
}
func (t *TCPServer) Start() {
func (t *TCP) Start() {
t.server = &http.Server{
Addr: setting.App.BindAddress,
Handler: *t.handler,
@ -38,7 +38,7 @@ func (t *TCPServer) Start() {
}()
}
func (t *TCPServer) Stop() {
func (t *TCP) Stop() {
log.Printf("Stopping TCP server...")
if err := t.server.Shutdown(t.ctx); err != nil {
log.Printf("TCP server forced to shutdown: %s", err)

View File

@ -9,20 +9,20 @@ import (
"github.com/dcarrillo/whatismyip/internal/setting"
)
type TLSServer struct {
type TLS struct {
server *http.Server
handler *http.Handler
ctx context.Context
}
func NewTLSServer(ctx context.Context, handler *http.Handler) *TLSServer {
return &TLSServer{
func NewTLSServer(ctx context.Context, handler *http.Handler) *TLS {
return &TLS{
handler: handler,
ctx: ctx,
}
}
func (t *TLSServer) Start() {
func (t *TLS) Start() {
t.server = &http.Server{
Addr: setting.App.TLSAddress,
Handler: *t.handler,
@ -39,7 +39,7 @@ func (t *TLSServer) Start() {
}()
}
func (t *TLSServer) Stop() {
func (t *TLS) Stop() {
log.Printf("Stopping TLS server...")
if err := t.server.Shutdown(t.ctx); err != nil {
log.Printf("TLS server forced to shutdown: %s", err)

24
service/port_scanner.go Normal file
View File

@ -0,0 +1,24 @@
package service
import (
"net"
"time"
)
const scannerTimeOut = 3 * time.Second
type PortScanner struct {
Address net.Addr
}
func (p *PortScanner) IsPortOpen() (bool, error) {
conn, err := net.DialTimeout(p.Address.Network(), p.Address.String(), scannerTimeOut)
if err != nil {
return false, err
}
if conn != nil {
defer conn.Close()
}
return true, nil
}