Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
*.code-workspace
*.mmdb
node_modules/
vendor/
147 changes: 79 additions & 68 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -1,78 +1,89 @@
run:
timeout: 3m
skip-files: []
skip-dirs: []

linters-settings:
govet:
enable-all: true
disable:
- fieldalignment
golint:
min-confidence: 0
gocyclo:
min-complexity: 12
goconst:
min-len: 5
min-occurrences: 4
misspell:
locale: US
funlen:
lines: -1
statements: 50
godox:
keywords:
- FIXME
gofumpt:
extra-rules: true

version: "2"
linters:
enable-all: true
default: all
disable:
- deadcode # deprecated
- exhaustivestruct # deprecated
- golint # deprecated
- ifshort # deprecated
- interfacer # deprecated
- maligned # deprecated
- nosnakecase # deprecated
- scopelint # deprecated
- scopelint # deprecated
- structcheck # deprecated
- varcheck # deprecated
- sqlclosecheck # not relevant (SQL)
- rowserrcheck # not relevant (SQL)
- execinquery # not relevant (SQL)
- cyclop # duplicate of gocyclo
- bodyclose # Too many false positives: https://github.com/timakin/bodyclose/issues/30
- bodyclose
- cyclop
- dupl
- testpackage
- tparallel
- paralleltest
- nlreturn
- wsl
- err113
- exhaustive
- exhaustruct
- goerr113
- wrapcheck
- ifshort
- noctx
- lll
- gomnd
- forbidigo
- lll
- mnd
- nlreturn
- noctx
- paralleltest
- rowserrcheck
- sqlclosecheck
- testpackage
- tparallel
- varnamelen
- wrapcheck
- wsl
settings:
funlen:
lines: -1
statements: 50
goconst:
min-len: 5
min-occurrences: 4
gocyclo:
min-complexity: 15
godox:
keywords:
- FIXME
govet:
disable:
- fieldalignment
enable-all: true
misspell:
locale: US

depguard:
rules:
main:
files:
- $all
- "!$test"
allow:
- $gostd
- github.com/IncSW/geoip2
test:
files:
- "$test"
allow:
- $gostd
- github.com/traefik-plugins/traefikgeoip2
exclusions:
generated: lax
rules:
- linters:
- gochecknoglobals
path: middleware.go
- linters:
- funlen
- goconst
- godot
path: (.+)_test.go
paths:
- third_party$
- builtin$
- examples$
issues:
exclude-use-default: false
max-per-linter: 0
max-same-issues: 0
exclude: []
exclude-rules:
- path: middleware.go
linters:
- gochecknoglobals
- path: (.+)_test.go
linters:
- goconst
- funlen
- godot
formatters:
enable:
- gci
- gofmt
- gofumpt
- goimports
settings:
gofumpt:
extra-rules: true
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
23 changes: 23 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.PHONY: prepare lint test vendor

export GO111MODULE=on

default: prepare lint test

prepare:
tar -zxvf geolite2.tgz

lint:
golangci-lint run

test:
go test -v -cover ./...

vendor:
go mod vendor

yaegi:
yaegi run middleware.go

clean:
rm -rf ./vendor *.mmdb || exit 0
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module github.com/traefik-plugins/traefikgeoip2

go 1.19
go 1.25

require github.com/IncSW/geoip2 v0.1.1
require github.com/IncSW/geoip2 v0.1.4
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github.com/IncSW/geoip2 v0.1.1 h1:afzzYF7n9JbdcPy8aiBSgBJuXi4mTWXZ3z6V3o6Vg34=
github.com/IncSW/geoip2 v0.1.1/go.mod h1:adcasR40vXiUBjtzdaTTKL/6wSf+fgO4M8Gve/XzPUk=
github.com/IncSW/geoip2 v0.1.4 h1:nkZz/E6POGDjnHsOda0CpBzwiH+FoDRQ1LhlAlBxOC8=
github.com/IncSW/geoip2 v0.1.4/go.mod h1:P2giYcBGG9oBqvgkLy2DZGM+thol50fXF5+8j+VIdm8=
11 changes: 9 additions & 2 deletions middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ type TraefikGeoIP2 struct {

// New created a new TraefikGeoIP2 plugin.
func New(_ context.Context, next http.Handler, cfg *Config, name string) (http.Handler, error) {
if _, err := os.Stat(cfg.DBPath); err != nil {
_, err := os.Stat(cfg.DBPath)
if err != nil {
log.Printf("[geoip2] DB not found: db=%s, name=%s, err=%v", cfg.DBPath, name, err)

return &TraefikGeoIP2{
next: next,
name: name,
Expand Down Expand Up @@ -83,14 +85,17 @@ func (mw *TraefikGeoIP2) ServeHTTP(reqWr http.ResponseWriter, req *http.Request)
req.Header.Set(RegionHeader, Unknown)
req.Header.Set(CityHeader, Unknown)
req.Header.Set(IPAddressHeader, Unknown)

mw.next.ServeHTTP(reqWr, req)

return
}

ipStr := getClientIP(req, mw.preferXForwardedForHeader)

res, err := lookup(net.ParseIP(ipStr))
if err != nil {
log.Printf("[geoip2] Unable to find: ip=%s, err=%v", ipStr, err)
// log.Printf("[geoip2] Unable to find: ip=%s, err=%v", ipStr, err)
res = &GeoIPResult{
country: Unknown,
region: Unknown,
Expand Down Expand Up @@ -118,9 +123,11 @@ func getClientIP(req *http.Request, preferXForwardedForHeader bool) string {

// If X-Forwarded-For is not present or retrieval is not enabled, fallback to RemoteAddr
remoteAddr := req.RemoteAddr

tmp, _, err := net.SplitHostPort(remoteAddr)
if err == nil {
remoteAddr = tmp
}

return remoteAddr
}
38 changes: 27 additions & 11 deletions middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package traefikgeoip2_test

import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"testing"
Expand All @@ -23,13 +22,16 @@ func TestGeoIPConfig(t *testing.T) {
}

mwCfg.DBPath = "./non-existing"

mw.ResetLookup()

_, err := mw.New(context.TODO(), nil, mwCfg, "")
if err != nil {
t.Fatalf("Must not fail on missing DB")
}

mwCfg.DBPath = "justfile"

_, err = mw.New(context.TODO(), nil, mwCfg, "")
if err != nil {
t.Fatalf("Must not fail on invalid DB format")
Expand All @@ -41,9 +43,10 @@ func TestGeoIPBasic(t *testing.T) {
mwCfg.DBPath = "./GeoLite2-City.mmdb"

called := false
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { called = true })
next := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { called = true })

mw.ResetLookup()

instance, err := mw.New(context.TODO(), next, mwCfg, "traefik-geoip2")
if err != nil {
t.Fatalf("Error creating %v", err)
Expand All @@ -53,9 +56,11 @@ func TestGeoIPBasic(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)

instance.ServeHTTP(recorder, req)

if recorder.Result().StatusCode != http.StatusOK {
t.Fatalf("Invalid return code")
}

if called != true {
t.Fatalf("next handler was not called")
}
Expand All @@ -66,9 +71,10 @@ func TestMissingGeoIPDB(t *testing.T) {
mwCfg.DBPath = "./missing"

called := false
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { called = true })
next := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { called = true })

mw.ResetLookup()

instance, err := mw.New(context.TODO(), next, mwCfg, "traefik-geoip2")
if err != nil {
t.Fatalf("Error creating %v", err)
Expand All @@ -79,12 +85,15 @@ func TestMissingGeoIPDB(t *testing.T) {
req.RemoteAddr = "1.2.3.4"

instance.ServeHTTP(recorder, req)

if recorder.Result().StatusCode != http.StatusOK {
t.Fatalf("Invalid return code")
}

if called != true {
t.Fatalf("next handler was not called")
}

assertHeader(t, req, mw.CountryHeader, mw.Unknown)
assertHeader(t, req, mw.RegionHeader, mw.Unknown)
assertHeader(t, req, mw.CityHeader, mw.Unknown)
Expand All @@ -95,20 +104,22 @@ func TestGeoIPFromRemoteAddr(t *testing.T) {
mwCfg := mw.CreateConfig()
mwCfg.DBPath = "./GeoLite2-City.mmdb"

next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {})
next := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {})

mw.ResetLookup()

instance, _ := mw.New(context.TODO(), next, mwCfg, "traefik-geoip2")

req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
req.RemoteAddr = fmt.Sprintf("%s:9999", ValidIP)
req.RemoteAddr = ValidIP + ":9999"
instance.ServeHTTP(httptest.NewRecorder(), req)
assertHeader(t, req, mw.CountryHeader, "DE")
assertHeader(t, req, mw.RegionHeader, "BY")
assertHeader(t, req, mw.CityHeader, "Munich")
assertHeader(t, req, mw.IPAddressHeader, ValidIP)

req = httptest.NewRequest(http.MethodGet, "http://localhost", nil)
req.RemoteAddr = fmt.Sprintf("%s:9999", ValidIPNoCity)
req.RemoteAddr = ValidIPNoCity + ":9999"
instance.ServeHTTP(httptest.NewRecorder(), req)
assertHeader(t, req, mw.CountryHeader, "US")
assertHeader(t, req, mw.RegionHeader, mw.Unknown)
Expand All @@ -129,12 +140,14 @@ func TestGeoIPFromXForwardedFor(t *testing.T) {
mwCfg.DBPath = "./GeoLite2-City.mmdb"
mwCfg.PreferXForwardedForHeader = true

next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {})
next := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {})

mw.ResetLookup()

instance, _ := mw.New(context.TODO(), next, mwCfg, "traefik-geoip2")

req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
req.RemoteAddr = fmt.Sprintf("%s:9999", ValidIP)
req.RemoteAddr = ValidIP + ":9999"
req.Header.Set("X-Forwarded-For", ValidAlternateIP)
instance.ServeHTTP(httptest.NewRecorder(), req)
assertHeader(t, req, mw.CountryHeader, "DE")
Expand All @@ -143,7 +156,7 @@ func TestGeoIPFromXForwardedFor(t *testing.T) {
assertHeader(t, req, mw.IPAddressHeader, ValidAlternateIP)

req = httptest.NewRequest(http.MethodGet, "http://localhost", nil)
req.RemoteAddr = fmt.Sprintf("%s:9999", ValidIP)
req.RemoteAddr = ValidIP + ":9999"
req.Header.Set("X-Forwarded-For", ValidAlternateIP+",188.193.88.100")
instance.ServeHTTP(httptest.NewRecorder(), req)
assertHeader(t, req, mw.CountryHeader, "DE")
Expand All @@ -165,12 +178,14 @@ func TestGeoIPCountryDBFromRemoteAddr(t *testing.T) {
mwCfg := mw.CreateConfig()
mwCfg.DBPath = "./GeoLite2-Country.mmdb"

next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {})
next := http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {})

mw.ResetLookup()

instance, _ := mw.New(context.TODO(), next, mwCfg, "traefik-geoip2")

req := httptest.NewRequest(http.MethodGet, "http://localhost", nil)
req.RemoteAddr = fmt.Sprintf("%s:9999", ValidIP)
req.RemoteAddr = ValidIP + ":9999"
instance.ServeHTTP(httptest.NewRecorder(), req)

assertHeader(t, req, mw.CountryHeader, "DE")
Expand All @@ -181,6 +196,7 @@ func TestGeoIPCountryDBFromRemoteAddr(t *testing.T) {

func assertHeader(t *testing.T, req *http.Request, key, expected string) {
t.Helper()

if req.Header.Get(key) != expected {
t.Fatalf("invalid value of header [%s] != %s", key, req.Header.Get(key))
}
Expand Down
Loading