Skip to content

Commit

Permalink
New whatismydns feature (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcarrillo authored Apr 12, 2024
1 parent b11f15e commit d13ea29
Show file tree
Hide file tree
Showing 20 changed files with 1,570 additions and 209 deletions.
49 changes: 49 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
run:
timeout: 10m
issues:
max-same-issues: 0
linters:
disable-all: true
enable:
- goimports
- ineffassign
- nakedret
- revive
- staticcheck
- stylecheck
- unconvert
- unparam
- unused
linters-settings:
staticcheck:
checks:
- all
revive:
ignore-generated-header: true
severity: warning
confidence: 0.8
rules:
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-return
- name: error-strings
- name: error-naming
- name: exported
- name: increment-decrement
- name: var-naming
- name: var-declaration
- name: package-comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unused-parameter
- name: unreachable-code
- name: redefines-builtin-id
28 changes: 17 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
FROM golang:1.21-alpine as builder
FROM golang:1.22-alpine as builder

ARG ARG_VERSION
ENV VERSION $ARG_VERSION

WORKDIR /app

COPY go.mod .
COPY go.sum .
RUN --mount=type=cache,target=/go/pkg/mod/ go mod download -x
COPY . .

RUN apk add make git upx && make build VERSION=$VERSION \
&& upx --best --lzma whatismyip

# Build final image
FROM scratch
FROM builder AS build-dev-app
# hadolint ignore=DL3018
RUN --mount=type=cache,target=/go/pkg/mod/ apk --no-cache add make && make build

WORKDIR /app

COPY --from=builder /app/whatismyip /usr/bin/
FROM builder AS build-prod-app
# hadolint ignore=DL3018
RUN --mount=type=cache,target=/go/pkg/mod/ apk --no-cache add make upx \
&& make build \
&& upx --best --lzma whatismyip

EXPOSE 8080
FROM scratch AS dev
COPY --from=build-dev-app /app/whatismyip /usr/bin/
ENTRYPOINT ["whatismyip"]

FROM scratch AS prod
COPY --from=build-prod-app /app/whatismyip /usr/bin/
ENTRYPOINT ["whatismyip"]
24 changes: 12 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,40 @@ DOCKER_URL ?= dcarrillo/whatismyip
.PHONY: test
test: unit-test integration-test

.PHONY: unit-test
unit-test:
go test -count=1 -race -short -cover ./...

.PHONY: integration-test
integration-test:
go test -count=1 -v ./integration-tests

.PHONY: install-tools
install-tools:
@command golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin; \
fi

@command $(GOPATH)/revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/mgechev/revive; \
fi

@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
.PHONY: lint

lint: install-tools
gofmt -l . && test -z $$(gofmt -l .)
golangci-lint run
shadow ./...

.PHONY: build
build:
CGO_ENABLED=0 go build -ldflags="-s -w -X 'github.com/dcarrillo/whatismyip/internal/core.Version=${VERSION}'" -o whatismyip ./cmd

.PHONY: docker-build
docker-build:
docker build --build-arg=ARG_VERSION="${VERSION}" --tag ${DOCKER_URL}:${VERSION} .
docker-build-dev:
docker build --target=dev --build-arg=ARG_VERSION="${VERSION}" --tag ${DOCKER_URL}:${VERSION} .

docker-build-prod:
docker build --target=prod --build-arg=ARG_VERSION="${VERSION}" --tag ${DOCKER_URL}:${VERSION} .

.PHONY: docker-push
docker-push: docker-build
docker-push: docker-build-prod
ifneq (,$(findstring devel-,$(VERSION)))
@echo "VERSION is set to ${VERSION}, I can't push devel builds"
exit 1
Expand All @@ -47,8 +48,7 @@ else
docker push ${DOCKER_URL}:latest
endif

.PHONY: docker-run
docker-run: docker-build
docker-run: docker-build-dev
docker run --tty --interactive --rm \
-v ${PWD}/test/GeoIP2-City-Test.mmdb:/tmp/GeoIP2-City-Test.mmdb:ro \
-v ${PWD}/test/GeoLite2-ASN-Test.mmdb:/tmp/GeoLite2-ASN-Test.mmdb:ro -p 8080:8080 \
Expand Down
57 changes: 51 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,49 @@
- [What is my IP address](#what-is-my-ip-address)
- [Features](#features)
- [Endpoints](#endpoints)
- [DNS discovery](#dns-discovery)
- [Build](#build)
- [Usage](#usage)
- [Examples](#examples)
- [Run a default TCP server](#run-a-default-tcp-server)
- [Run a TLS (HTTP/2) server only](#run-a-tls-http2-server-only)
- [Run a TLS (HTTP/2) and enable What is my DNS](#run-a-tls-http2-and-enable-what-is-my-dns)
- [Run an HTTP/3 server](#run-an-http3-server)
- [Run a default TCP server with a custom template and trust a pair of custom headers set by an upstream proxy](#run-a-default-tcp-server-with-a-custom-template-and-trust-a-pair-of-custom-headers-set-by-an-upstream-proxy)
- [Download](#download)
- [Docker](#docker)
- [Run a container locally using test databases](#run-a-container-locally-using-test-databases)
- [From Docker Hub](#from-docker-hub)

> [!NOTE]
> 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,
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`
Take a look at [ifconfig.es](https://ifconfig.es) a live site using `whatismyip` and the `DNS discovery` enabled.

Get your public IP easily from the command line:

```bash
```text
curl ifconfig.es
127.0.0.1
curl -6 ifconfig.es
::1
```

Get the IP of your DNS provider:

```text
curl -L dns.ifconfig.es
2a04:e4c0:47::67 (Spain / OPENDNS)
```

## Features

- TLS and HTTP/2.
- Experimental HTTP/3 support. HTTP/3 requires a TLS server running (`-tls-bind`), 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.
- Beta DNS discovery: A best-effort approach to discovering the DNS server that is resolving the client's requests.
- 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.
Expand Down Expand Up @@ -69,6 +81,38 @@ curl -6 ifconfig.es
- https://ifconfig.es/headers
- https://ifconfig.es/<header_name>
- https://ifconfig.es/scan/tcp/<port_number>
- https://dns.ifconfig.es

## DNS discovery

The DNS discovery works by forcing the client to make a request to `<uuid>.dns.ifconfig.es` this DNS request is handled by a microdns server
included in the `whatismyip` binary. In order to run the discovery server, a configuration file in the following form has to be created:

```yaml
---
domain: dns.example.com
redirect_port: ":8000"
resource_records:
- "1800 IN SOA xns.example.com. hostmaster.example.com. 1 10000 2400 604800 1800"
- "3600 IN NS xns.example.com."
ipv4:
- "127.0.0.2"
ipv6:
- "aaa:aaa:aaa:aaaa::1"
```
The DNS authority for example.com has delegated the subdomain zone `dns.example.com` to the server running the `whatismyip` service.

The client can request the URL `dns.example.com` by following the redirection `curl -L dns.example.com`.

To avoid the redirection, you can provide a valid URL, for example, for the real [ifconfig.es](https://ifconfig.es):

```bash
curl $(uuidgen).dns.ifconfig.es
curl $(cat /proc/sys/kernel/random/uuid).dns.ifconfig.es
```


## Build

Expand Down Expand Up @@ -114,11 +158,12 @@ Usage of whatismyip:
./whatismyip -geoip2-city ./test/GeoIP2-City-Test.mmdb -geoip2-asn ./test/GeoLite2-ASN-Test.mmdb
```

### Run a TLS (HTTP/2) server only
### Run a TLS (HTTP/2) and enable What is my DNS

```bash
./whatismyip -geoip2-city ./test/GeoIP2-City-Test.mmdb -geoip2-asn ./test/GeoLite2-ASN-Test.mmdb \
-bind "" -tls-bind :8081 -tls-crt ./test/server.pem -tls-key ./test/server.key
-bind "" -tls-bind :8081 -tls-crt ./test/server.pem -tls-key ./test/server.key \
-resolver ./test/resolver.yml
```

### Run an HTTP/3 server
Expand All @@ -137,7 +182,7 @@ Usage of whatismyip:

## Download

Download the latest version from https://github.com/dcarrillo/whatismyip/releases
Download the latest version from [github](https://github.com/dcarrillo/whatismyip/releases)

## Docker

Expand Down
16 changes: 15 additions & 1 deletion cmd/whatismyip.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ import (
"fmt"
"net/http"
"os"
"slices"
"time"

"github.com/dcarrillo/whatismyip/internal/httputils"
"github.com/dcarrillo/whatismyip/internal/setting"
"github.com/dcarrillo/whatismyip/resolver"
"github.com/dcarrillo/whatismyip/server"
"github.com/gin-contrib/secure"
"github.com/patrickmn/go-cache"

"github.com/dcarrillo/whatismyip/router"
"github.com/gin-gonic/gin"
Expand All @@ -26,10 +30,20 @@ func main() {
os.Exit(1)
}

servers := []server.Server{}
engine := setupEngine()

if setting.App.Resolver.Domain != "" {
store := cache.New(1*time.Minute, 10*time.Minute)
dnsEngine := resolver.Setup(store)
nameServer := server.NewDNSServer(context.Background(), dnsEngine.Handler())
servers = append(servers, nameServer)
engine.Use(router.GetDNSDiscoveryHandler(store, setting.App.Resolver.Domain, setting.App.Resolver.RedirectPort))
}

router.SetupTemplate(engine)
router.Setup(engine)
servers := setupHTTPServers(context.Background(), engine.Handler())
servers = slices.Concat(servers, setupHTTPServers(context.Background(), engine.Handler()))

whatismyip := server.Setup(servers)
whatismyip.Run()
Expand Down
Loading

0 comments on commit d13ea29

Please sign in to comment.