Skip to content

Commit

Permalink
Allow adding ip address ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
PascalMinder committed Jan 21, 2023
1 parent a829633 commit f923e4e
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 4 deletions.
26 changes: 23 additions & 3 deletions geoblock.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type GeoBlock struct {
blackListMode bool
countries []string
allowedIPAddresses []net.IP
allowedIPRanges []*net.IPNet
privateIPRanges []*net.IPNet
database *lru.LRUCache
name string
Expand All @@ -88,13 +89,21 @@ func New(_ context.Context, next http.Handler, config *Config, name string) (htt
config.APITimeoutMs = 750
}

allowedIPAddresses := make([]net.IP, len(config.AllowedIPAddresses))
for idx, ipAddressEntry := range config.AllowedIPAddresses {
var allowedIPAddresses []net.IP
var allowedIPRanges []*net.IPNet
for _, ipAddressEntry := range config.AllowedIPAddresses {
ip, ipBlock, err := net.ParseCIDR(ipAddressEntry)
if err == nil {
allowedIPAddresses = append(allowedIPAddresses, ip)
allowedIPRanges = append(allowedIPRanges, ipBlock)
continue
}

ipAddress := net.ParseIP(ipAddressEntry)
if ipAddress == nil {
infoLogger.Fatal("Invalid ip address given!")
}
allowedIPAddresses[idx] = ipAddress
allowedIPAddresses = append(allowedIPAddresses, ipAddress)
}

infoLogger.SetOutput(os.Stdout)
Expand Down Expand Up @@ -131,6 +140,7 @@ func New(_ context.Context, next http.Handler, config *Config, name string) (htt
blackListMode: config.BlackListMode,
countries: config.Countries,
allowedIPAddresses: allowedIPAddresses,
allowedIPRanges: allowedIPRanges,
privateIPRanges: initPrivateIPBlocks(),
database: cache,
name: name,
Expand Down Expand Up @@ -175,6 +185,16 @@ func (a *GeoBlock) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}

for _, ipRange := range a.allowedIPRanges {
if ipRange.Contains(*ipAddress) {
if a.logLocalRequests {
infoLogger.Println("Allow explicitly allowed ip: ", ipAddress)
}
a.next.ServeHTTP(rw, req)
return
}
}

cacheEntry, ok := a.database.Get(ipAddressString)

if !ok {
Expand Down
112 changes: 112 additions & 0 deletions geoblock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,118 @@ func TestExplicitlyAllowedIPNoMatch(t *testing.T) {
assertStatusCode(t, recorder.Result(), http.StatusForbidden)
}

func TestExplicitlyAllowedIPRangeIPV6(t *testing.T) {
cfg := createTesterConfig()
cfg.Countries = append(cfg.Countries, "CA")
cfg.AllowedIPAddresses = append(cfg.AllowedIPAddresses, "2a00:00c0:2:3::567:8001/128")
cfg.AllowedIPAddresses = append(cfg.AllowedIPAddresses, "8.8.8.8")

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

handler, err := geoblock.New(ctx, next, cfg, "GeoBlock")
if err != nil {
t.Fatal(err)
}

recorder := httptest.NewRecorder()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost", nil)
if err != nil {
t.Fatal(err)
}

req.Header.Add(xForwardedFor, "2a00:00c0:2:3::567:8001")

handler.ServeHTTP(recorder, req)

assertStatusCode(t, recorder.Result(), http.StatusOK)
}

func TestExplicitlyAllowedIPRangeIPV6NoMatch(t *testing.T) {
cfg := createTesterConfig()
cfg.Countries = append(cfg.Countries, "CA")
cfg.AllowedIPAddresses = append(cfg.AllowedIPAddresses, "2a00:00c0:2:3::567:8001/128")
cfg.AllowedIPAddresses = append(cfg.AllowedIPAddresses, "8.8.8.8")

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

handler, err := geoblock.New(ctx, next, cfg, "GeoBlock")
if err != nil {
t.Fatal(err)
}

recorder := httptest.NewRecorder()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost", nil)
if err != nil {
t.Fatal(err)
}

req.Header.Add(xForwardedFor, "2a00:00c0:2:3::567:8002")

handler.ServeHTTP(recorder, req)

assertStatusCode(t, recorder.Result(), http.StatusForbidden)
}

func TestExplicitlyAllowedIPRangeIPV4(t *testing.T) {
cfg := createTesterConfig()
cfg.Countries = append(cfg.Countries, "CA")
cfg.AllowedIPAddresses = append(cfg.AllowedIPAddresses, "178.90.234.0/27")
cfg.AllowedIPAddresses = append(cfg.AllowedIPAddresses, "8.8.8.8")

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

handler, err := geoblock.New(ctx, next, cfg, "GeoBlock")
if err != nil {
t.Fatal(err)
}

recorder := httptest.NewRecorder()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost", nil)
if err != nil {
t.Fatal(err)
}

req.Header.Add(xForwardedFor, "178.90.234.30")

handler.ServeHTTP(recorder, req)

assertStatusCode(t, recorder.Result(), http.StatusOK)
}

func TestExplicitlyAllowedIPRangeIPV4NoMatch(t *testing.T) {
cfg := createTesterConfig()
cfg.Countries = append(cfg.Countries, "CA")
cfg.AllowedIPAddresses = append(cfg.AllowedIPAddresses, "178.90.234.0/27")
cfg.AllowedIPAddresses = append(cfg.AllowedIPAddresses, "8.8.8.8")

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

handler, err := geoblock.New(ctx, next, cfg, "GeoBlock")
if err != nil {
t.Fatal(err)
}

recorder := httptest.NewRecorder()

req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost", nil)
if err != nil {
t.Fatal(err)
}

req.Header.Add(xForwardedFor, "178.90.234.55")

handler.ServeHTTP(recorder, req)

assertStatusCode(t, recorder.Result(), http.StatusForbidden)
}

func assertStatusCode(t *testing.T, req *http.Response, expected int) {
t.Helper()

Expand Down
9 changes: 8 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,4 +482,11 @@ A list of country codes from which connections to the service should be allowed.

### Allowed IP addresses `allowedIPAddresses`

A list of explicitly allowed IP addresses. IP addresses added to this list will always be allowed.
A list of explicitly allowed IP addresses or IP address ranges. IP addresses and ranges added to this list will always be allowed.

```yaml
allowedIPAddresses:
- 192.0.2.10 # single IPv4 address
- 203.0.113.0/24 # IPv4 range in CIDR format
- 2001:db8:1234:/48 # IPv6 range in CIDR format
```

0 comments on commit f923e4e

Please sign in to comment.