mirror of
https://github.com/dcarrillo/whatismyip.git
synced 2024-12-22 17:38:00 +00:00
Add feature to get the right client port when using a trusted proxy
This commit is contained in:
parent
9070e9a2c2
commit
7c70abf07f
2
Makefile
2
Makefile
@ -16,7 +16,7 @@ integration-test:
|
|||||||
.PHONY: install-tools
|
.PHONY: install-tools
|
||||||
install-tools:
|
install-tools:
|
||||||
@command golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
@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 v1.45.0; \
|
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.45.2; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@command $(GOPATH)/shadow > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
@command $(GOPATH)/shadow > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||||
|
19
README.md
19
README.md
@ -13,7 +13,7 @@
|
|||||||
- [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) server only](#run-a-tls-http2-server-only)
|
- [Run a TLS (HTTP/2) server only](#run-a-tls-http2-server-only)
|
||||||
- [Run a default TCP server with a custom template and trust a custom header set by an upstream proxy](#run-a-default-tcp-server-with-a-custom-template-and-trust-a-custom-header-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)
|
||||||
- [Docker](#docker)
|
- [Docker](#docker)
|
||||||
- [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)
|
||||||
@ -36,7 +36,7 @@ curl -6 ifconfig.es
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- TLS and HTTP/2.
|
- TLS and HTTP/2.
|
||||||
- Can run behind a proxy by trusting a custom header (usually `X-Real-IP`) to figure out the source IP address.
|
- 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.
|
- 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.
|
- 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.
|
||||||
- High performance.
|
- High performance.
|
||||||
@ -47,6 +47,7 @@ curl -6 ifconfig.es
|
|||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
- https://ifconfig.es/
|
- https://ifconfig.es/
|
||||||
|
- https://ifconfig.es/client-port
|
||||||
- https://ifconfig.es/json (this is the same as `curl -H "Accept: application/json" https://ifconfig.es/`)
|
- https://ifconfig.es/json (this is the same as `curl -H "Accept: application/json" https://ifconfig.es/`)
|
||||||
- https://ifconfig.es/geo
|
- https://ifconfig.es/geo
|
||||||
- https://ifconfig.es/geo/city
|
- https://ifconfig.es/geo/city
|
||||||
@ -72,9 +73,11 @@ Golang >= 1.17 is required. Previous versions may work.
|
|||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```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-secure-headers
|
||||||
|
Add sane security-related headers to every response
|
||||||
-geoip2-asn string
|
-geoip2-asn string
|
||||||
Path to GeoIP2 ASN database
|
Path to GeoIP2 ASN database
|
||||||
-geoip2-city string
|
-geoip2-city string
|
||||||
@ -88,7 +91,9 @@ Usage of ./whatismyip:
|
|||||||
-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)
|
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 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
|
||||||
```
|
```
|
||||||
@ -108,11 +113,11 @@ Usage of ./whatismyip:
|
|||||||
-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
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run a default TCP server with a custom template and trust a custom header 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
|
||||||
|
|
||||||
```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 \
|
||||||
-trusted-header X-Real-IP -template mytemplate.tmpl
|
-trusted-header X-Real-IP -trusted-port-header X-Real-Port -template mytemplate.tmpl
|
||||||
```
|
```
|
||||||
|
|
||||||
## Download
|
## Download
|
||||||
@ -121,7 +126,7 @@ Download latest version from https://github.com/dcarrillo/whatismyip/releases
|
|||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
|
||||||
An ultra-light (~9MB) image is available.
|
An ultra-light (~10MB) image is available at [docker hub](https://hub.docker.com/r/dcarrillo/whatismyip).
|
||||||
|
|
||||||
### Run a container locally using test databases
|
### Run a container locally using test databases
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ type settings struct {
|
|||||||
TLSCrtPath string
|
TLSCrtPath string
|
||||||
TLSKeyPath string
|
TLSKeyPath string
|
||||||
TrustedHeader string
|
TrustedHeader string
|
||||||
|
TrustedPortHeader string
|
||||||
EnableSecureHeaders bool
|
EnableSecureHeaders bool
|
||||||
Server serverSettings
|
Server serverSettings
|
||||||
version bool
|
version bool
|
||||||
@ -74,6 +75,11 @@ func Setup(args []string) (output string, err error) {
|
|||||||
"",
|
"",
|
||||||
"Trusted request header for remote IP (e.g. X-Real-IP)",
|
"Trusted request header for remote IP (e.g. X-Real-IP)",
|
||||||
)
|
)
|
||||||
|
flags.StringVar(&App.TrustedPortHeader,
|
||||||
|
"trusted-port-header",
|
||||||
|
"",
|
||||||
|
"Trusted request header for remote client port (e.g. X-Real-Port)",
|
||||||
|
)
|
||||||
flags.BoolVar(&App.version, "version", false, "Output version information and exit")
|
flags.BoolVar(&App.version, "version", false, "Output version information and exit")
|
||||||
flags.BoolVar(
|
flags.BoolVar(
|
||||||
&App.EnableSecureHeaders,
|
&App.EnableSecureHeaders,
|
||||||
@ -91,21 +97,25 @@ 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 == "" {
|
||||||
|
return "", fmt.Errorf("truster-header is mandatory when truster-port-header is set\n")
|
||||||
|
}
|
||||||
|
|
||||||
if App.GeodbPath.City == "" || App.GeodbPath.ASN == "" {
|
if App.GeodbPath.City == "" || App.GeodbPath.ASN == "" {
|
||||||
return "", fmt.Errorf("geoip2-city and geoip2-asn parameters are mandatory")
|
return "", fmt.Errorf("geoip2-city and geoip2-asn parameters are mandatory\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (App.TLSAddress != "") && (App.TLSCrtPath == "" || App.TLSKeyPath == "") {
|
if (App.TLSAddress != "") && (App.TLSCrtPath == "" || App.TLSKeyPath == "") {
|
||||||
return "", fmt.Errorf("In order to use TLS -tls-crt and -tls-key flags are mandatory")
|
return "", fmt.Errorf("In order to use TLS -tls-crt and -tls-key flags are mandatory\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if App.TemplatePath != "" {
|
if App.TemplatePath != "" {
|
||||||
info, err := os.Stat(App.TemplatePath)
|
info, err := os.Stat(App.TemplatePath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return "", fmt.Errorf("%s no such file or directory", App.TemplatePath)
|
return "", fmt.Errorf("%s no such file or directory\n", App.TemplatePath)
|
||||||
}
|
}
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
return "", fmt.Errorf("%s must be a file", App.TemplatePath)
|
return "", fmt.Errorf("%s must be a file\n", App.TemplatePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,51 +8,51 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseMandatoryFlags(t *testing.T) {
|
func TestParseMandatoryFlags(t *testing.T) {
|
||||||
var mandatoryFlags = []struct {
|
var mandatoryFlags = []struct {
|
||||||
args []string
|
args []string
|
||||||
conf settings
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
[]string{},
|
[]string{},
|
||||||
settings{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[]string{"-geoip2-city", "/city-path"},
|
[]string{"-geoip2-city", "/city-path"},
|
||||||
settings{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[]string{"-geoip2-asn", "/asn-path"},
|
[]string{"-geoip2-asn", "/asn-path"},
|
||||||
settings{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[]string{
|
[]string{
|
||||||
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000",
|
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000",
|
||||||
},
|
},
|
||||||
settings{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[]string{
|
[]string{
|
||||||
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000",
|
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000",
|
||||||
"-tls-crt", "/crt-path",
|
"-tls-crt", "/crt-path",
|
||||||
},
|
},
|
||||||
settings{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[]string{
|
[]string{
|
||||||
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000",
|
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-tls-bind", ":9000",
|
||||||
"-tls-key", "/key-path",
|
"-tls-key", "/key-path",
|
||||||
},
|
},
|
||||||
settings{},
|
},
|
||||||
|
{
|
||||||
|
[]string{
|
||||||
|
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path", "-bind", ":8000",
|
||||||
|
"-trusted-port-header", "port-header",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
assert.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
assert.Contains(t, err.Error(), "mandatory")
|
assert.Contains(t, err.Error(), "mandatory")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -70,13 +70,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
City: "/city-path",
|
City: "/city-path",
|
||||||
ASN: "/asn-path",
|
ASN: "/asn-path",
|
||||||
},
|
},
|
||||||
TemplatePath: "",
|
|
||||||
BindAddress: ":8080",
|
BindAddress: ":8080",
|
||||||
TLSAddress: "",
|
|
||||||
TLSCrtPath: "",
|
|
||||||
TLSKeyPath: "",
|
|
||||||
TrustedHeader: "",
|
|
||||||
EnableSecureHeaders: false,
|
|
||||||
Server: serverSettings{
|
Server: serverSettings{
|
||||||
ReadTimeout: 10 * time.Second,
|
ReadTimeout: 10 * time.Second,
|
||||||
WriteTimeout: 10 * time.Second,
|
WriteTimeout: 10 * time.Second,
|
||||||
@ -90,13 +84,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
City: "/city-path",
|
City: "/city-path",
|
||||||
ASN: "/asn-path",
|
ASN: "/asn-path",
|
||||||
},
|
},
|
||||||
TemplatePath: "",
|
|
||||||
BindAddress: ":8001",
|
BindAddress: ":8001",
|
||||||
TLSAddress: "",
|
|
||||||
TLSCrtPath: "",
|
|
||||||
TLSKeyPath: "",
|
|
||||||
TrustedHeader: "",
|
|
||||||
EnableSecureHeaders: false,
|
|
||||||
Server: serverSettings{
|
Server: serverSettings{
|
||||||
ReadTimeout: 10 * time.Second,
|
ReadTimeout: 10 * time.Second,
|
||||||
WriteTimeout: 10 * time.Second,
|
WriteTimeout: 10 * time.Second,
|
||||||
@ -113,13 +101,29 @@ func TestParseFlags(t *testing.T) {
|
|||||||
City: "/city-path",
|
City: "/city-path",
|
||||||
ASN: "/asn-path",
|
ASN: "/asn-path",
|
||||||
},
|
},
|
||||||
TemplatePath: "",
|
|
||||||
BindAddress: ":8080",
|
BindAddress: ":8080",
|
||||||
TLSAddress: ":9000",
|
TLSAddress: ":9000",
|
||||||
TLSCrtPath: "/crt-path",
|
TLSCrtPath: "/crt-path",
|
||||||
TLSKeyPath: "/key-path",
|
TLSKeyPath: "/key-path",
|
||||||
TrustedHeader: "",
|
Server: serverSettings{
|
||||||
EnableSecureHeaders: false,
|
ReadTimeout: 10 * time.Second,
|
||||||
|
WriteTimeout: 10 * time.Second,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]string{
|
||||||
|
"-geoip2-city", "/city-path", "-geoip2-asn", "/asn-path",
|
||||||
|
"-trusted-header", "header", "-trusted-port-header", "port-header",
|
||||||
|
},
|
||||||
|
settings{
|
||||||
|
GeodbPath: geodbPath{
|
||||||
|
City: "/city-path",
|
||||||
|
ASN: "/asn-path",
|
||||||
|
},
|
||||||
|
BindAddress: ":8080",
|
||||||
|
TrustedHeader: "header",
|
||||||
|
TrustedPortHeader: "port-header",
|
||||||
Server: serverSettings{
|
Server: serverSettings{
|
||||||
ReadTimeout: 10 * time.Second,
|
ReadTimeout: 10 * time.Second,
|
||||||
WriteTimeout: 10 * time.Second,
|
WriteTimeout: 10 * time.Second,
|
||||||
@ -136,11 +140,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
City: "/city-path",
|
City: "/city-path",
|
||||||
ASN: "/asn-path",
|
ASN: "/asn-path",
|
||||||
},
|
},
|
||||||
TemplatePath: "",
|
|
||||||
BindAddress: ":8080",
|
BindAddress: ":8080",
|
||||||
TLSAddress: "",
|
|
||||||
TLSCrtPath: "",
|
|
||||||
TLSKeyPath: "",
|
|
||||||
TrustedHeader: "header",
|
TrustedHeader: "header",
|
||||||
EnableSecureHeaders: true,
|
EnableSecureHeaders: true,
|
||||||
Server: serverSettings{
|
Server: serverSettings{
|
||||||
@ -154,7 +154,7 @@ func TestParseFlags(t *testing.T) {
|
|||||||
for _, tt := range flags {
|
for _, tt := range flags {
|
||||||
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)
|
||||||
assert.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.True(t, reflect.DeepEqual(App, tt.conf))
|
assert.True(t, reflect.DeepEqual(App, tt.conf))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -192,6 +192,6 @@ func TestParseFlagTemplate(t *testing.T) {
|
|||||||
"-template", "/",
|
"-template", "/",
|
||||||
}
|
}
|
||||||
_, err = Setup(flags)
|
_, err = Setup(flags)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.Contains(t, err.Error(), "must be a file")
|
assert.Contains(t, err.Error(), "must be a file")
|
||||||
}
|
}
|
||||||
|
@ -44,15 +44,31 @@ func getRoot(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getClientPort(ctx *gin.Context) string {
|
||||||
|
var port string
|
||||||
|
if setting.App.TrustedPortHeader == "" {
|
||||||
|
if setting.App.TrustedHeader != "" {
|
||||||
|
port = "unknown"
|
||||||
|
} else {
|
||||||
|
_, port, _ = net.SplitHostPort(ctx.Request.RemoteAddr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port = ctx.GetHeader(setting.App.TrustedPortHeader)
|
||||||
|
if port == "" {
|
||||||
|
port = "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return port
|
||||||
|
}
|
||||||
|
|
||||||
func getClientPortAsString(ctx *gin.Context) {
|
func getClientPortAsString(ctx *gin.Context) {
|
||||||
_, port, _ := net.SplitHostPort(ctx.Request.RemoteAddr)
|
ctx.String(http.StatusOK, getClientPort(ctx)+"\n")
|
||||||
ctx.String(http.StatusOK, port+"\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAllAsString(ctx *gin.Context) {
|
func getAllAsString(ctx *gin.Context) {
|
||||||
output := "IP: " + ctx.ClientIP() + "\n"
|
output := "IP: " + ctx.ClientIP() + "\n"
|
||||||
_, port, _ := net.SplitHostPort(ctx.Request.RemoteAddr)
|
output += "Client Port: " + getClientPort(ctx) + "\n"
|
||||||
output += "Client Port: " + port + "\n"
|
|
||||||
|
|
||||||
r := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
|
r := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
|
||||||
if record := r.LookUpCity(); record != nil {
|
if record := r.LookUpCity(); record != nil {
|
||||||
@ -83,11 +99,10 @@ func jsonOutput(ctx *gin.Context) JSONResponse {
|
|||||||
version = 6
|
version = 6
|
||||||
}
|
}
|
||||||
|
|
||||||
_, port, _ := net.SplitHostPort(ctx.Request.RemoteAddr)
|
|
||||||
return JSONResponse{
|
return JSONResponse{
|
||||||
IP: ctx.ClientIP(),
|
IP: ctx.ClientIP(),
|
||||||
IPVersion: version,
|
IPVersion: version,
|
||||||
ClientPort: port,
|
ClientPort: getClientPort(ctx),
|
||||||
Country: cityRecord.Country.Names["en"],
|
Country: cityRecord.Country.Names["en"],
|
||||||
CountryCode: cityRecord.Country.ISOCode,
|
CountryCode: cityRecord.Country.ISOCode,
|
||||||
City: cityRecord.City.Names["en"],
|
City: cityRecord.City.Names["en"],
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/dcarrillo/whatismyip/internal/setting"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -97,16 +98,78 @@ func TestHost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientPort(t *testing.T) {
|
func TestClientPort(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
params []string
|
||||||
|
headers map[string][]string
|
||||||
|
}
|
||||||
|
type expected struct {
|
||||||
|
body string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "No trusted headers set",
|
||||||
|
expected: "1000\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Trusted header only set",
|
||||||
|
args: args{
|
||||||
|
params: []string{
|
||||||
|
"-geoip2-city", "city",
|
||||||
|
"-geoip2-asn", "asn",
|
||||||
|
"-trusted-header", trustedHeader,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "unknown\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Trusted and port header set but not included in headers",
|
||||||
|
args: args{
|
||||||
|
params: []string{
|
||||||
|
"-geoip2-city", "city",
|
||||||
|
"-geoip2-asn", "asn",
|
||||||
|
"-trusted-header", trustedHeader,
|
||||||
|
"-trusted-port-header", trustedPortHeader,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "unknown\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Trusted and port header set and included in headers",
|
||||||
|
args: args{
|
||||||
|
params: []string{
|
||||||
|
"-geoip2-city", "city",
|
||||||
|
"-geoip2-asn", "asn",
|
||||||
|
"-trusted-header", trustedHeader,
|
||||||
|
"-trusted-port-header", trustedPortHeader,
|
||||||
|
},
|
||||||
|
headers: map[string][]string{
|
||||||
|
trustedHeader: {testIP.ipv4},
|
||||||
|
trustedPortHeader: {"1001"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: "1001\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
_, _ = setting.Setup(tt.args.params)
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
req, _ := http.NewRequest("GET", "/client-port", nil)
|
req, _ := http.NewRequest("GET", "/client-port", nil)
|
||||||
req.RemoteAddr = net.JoinHostPort(testIP.ipv4, "1000")
|
req.RemoteAddr = net.JoinHostPort(testIP.ipv4, "1000")
|
||||||
req.Header.Set(trustedHeader, testIP.ipv4)
|
req.Header = tt.args.headers
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
app.ServeHTTP(w, req)
|
app.ServeHTTP(w, req)
|
||||||
|
|
||||||
assert.Equal(t, 200, w.Code)
|
assert.Equal(t, 200, w.Code)
|
||||||
assert.Equal(t, contentType.text, w.Header().Get("Content-Type"))
|
assert.Equal(t, contentType.text, w.Header().Get("Content-Type"))
|
||||||
assert.Equal(t, "1000\n", w.Body.String())
|
assert.Equal(t, tt.expected, w.Body.String())
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNotFound(t *testing.T) {
|
func TestNotFound(t *testing.T) {
|
||||||
@ -120,6 +183,15 @@ func TestNotFound(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestJSON(t *testing.T) {
|
func TestJSON(t *testing.T) {
|
||||||
|
_, _ = setting.Setup(
|
||||||
|
[]string{
|
||||||
|
"-geoip2-city", "city",
|
||||||
|
"-geoip2-asn", "asn",
|
||||||
|
"-trusted-header", trustedHeader,
|
||||||
|
"-trusted-port-header", trustedPortHeader,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
ip string
|
ip string
|
||||||
}
|
}
|
||||||
@ -149,6 +221,7 @@ func TestJSON(t *testing.T) {
|
|||||||
req.RemoteAddr = net.JoinHostPort(tt.args.ip, "1000")
|
req.RemoteAddr = net.JoinHostPort(tt.args.ip, "1000")
|
||||||
req.Host = "test"
|
req.Host = "test"
|
||||||
req.Header.Set(trustedHeader, tt.args.ip)
|
req.Header.Set(trustedHeader, tt.args.ip)
|
||||||
|
req.Header.Set(trustedPortHeader, "1001")
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
app.ServeHTTP(w, req)
|
app.ServeHTTP(w, req)
|
||||||
@ -162,7 +235,7 @@ func TestJSON(t *testing.T) {
|
|||||||
|
|
||||||
func TestAll(t *testing.T) {
|
func TestAll(t *testing.T) {
|
||||||
expected := `IP: 81.2.69.192
|
expected := `IP: 81.2.69.192
|
||||||
Client Port: 1000
|
Client Port: 1001
|
||||||
City: London
|
City: London
|
||||||
Country: United Kingdom
|
Country: United Kingdom
|
||||||
Country Code: GB
|
Country Code: GB
|
||||||
@ -177,12 +250,22 @@ ASN Organization:
|
|||||||
Header1: one
|
Header1: one
|
||||||
Host: test
|
Host: test
|
||||||
X-Real-Ip: 81.2.69.192
|
X-Real-Ip: 81.2.69.192
|
||||||
|
X-Real-Port: 1001
|
||||||
`
|
`
|
||||||
|
_, _ = setting.Setup(
|
||||||
|
[]string{
|
||||||
|
"-geoip2-city", "city",
|
||||||
|
"-geoip2-asn", "asn",
|
||||||
|
"-trusted-header", trustedHeader,
|
||||||
|
"-trusted-port-header", trustedPortHeader,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
req, _ := http.NewRequest("GET", "/all", nil)
|
req, _ := http.NewRequest("GET", "/all", nil)
|
||||||
req.RemoteAddr = net.JoinHostPort(testIP.ipv4, "1000")
|
req.RemoteAddr = net.JoinHostPort(testIP.ipv4, "1000")
|
||||||
req.Host = "test"
|
req.Host = "test"
|
||||||
req.Header.Set(trustedHeader, testIP.ipv4)
|
req.Header.Set(trustedHeader, testIP.ipv4)
|
||||||
|
req.Header.Set(trustedPortHeader, "1001")
|
||||||
req.Header.Set("Header1", "one")
|
req.Header.Set("Header1", "one")
|
||||||
|
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
@ -34,11 +34,12 @@ 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":"1000","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":{"X-Real-Ip":["81.2.69.192"]}}`
|
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":{"X-Real-Ip":["81.2.69.192"], "X-Real-Port":["1001"]}}`
|
||||||
jsonIPv6 = `{"asn":3352, "asn_organization":"TELEFONICA DE ESPANA", "city":"", "client_port":"1000", "country":"", "country_code":"", "headers":{"X-Real-Ip":["2a02:9000::1"]}, "host":"test", "ip":"2a02:9000::1", "ip_version":6, "latitude":0, "longitude":0, "postal_code":"", "time_zone":""}`
|
jsonIPv6 = `{"asn":3352, "asn_organization":"TELEFONICA DE ESPANA", "city":"", "client_port":"1001", "country":"", "country_code":"", "headers":{"X-Real-Ip":["2a02:9000::1"], "X-Real-Port":["1001"]}, "host":"test", "ip":"2a02:9000::1", "ip_version":6, "latitude":0, "longitude":0, "postal_code":"", "time_zone":""}`
|
||||||
)
|
)
|
||||||
|
|
||||||
const trustedHeader = "X-Real-IP"
|
const trustedHeader = "X-Real-IP"
|
||||||
|
const trustedPortHeader = "X-Real-Port"
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
app = gin.Default()
|
app = gin.Default()
|
||||||
|
Loading…
Reference in New Issue
Block a user