Skip to content

Commit

Permalink
Merge pull request nscuro#44 from gauth-fr/add-whitelist-ipblocks
Browse files Browse the repository at this point in the history
Add whitelisting CIDR Blocks
  • Loading branch information
nscuro authored Nov 5, 2022
2 parents abea8b6 + 1edab38 commit 52278e1
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .traefik.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ testData:
# databaseFilePath: IP2LOCATION-LITE-DB1.IPV6.BIN
# allowedCountries: [ "CH", "DE" ]
# allowPrivate: true
# disallowedStatusCode: 403
# disallowedStatusCode: 403
# allowedIPBlocks: ["66.249.64.0/19"]
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,6 @@ http:
allowPrivate: true
# HTTP status code to return for disallowed requests (default: 403)
disallowedStatusCode: 204
# Add CIDR to be whitelisted, even if in a non-allowed country
allowedIPBlocks: ["66.249.64.0/19"]
```
51 changes: 49 additions & 2 deletions plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"log"
"net"
"net/http"
"strings"

Expand All @@ -21,6 +22,7 @@ type Config struct {
AllowedCountries []string // Whitelist of countries to allow (ISO 3166-1 alpha-2)
AllowPrivate bool // Allow requests from private / internal networks?
DisallowedStatusCode int // HTTP status code to return for disallowed requests
AllowedIPBlocks []string // List of whitelist CIDR
}

// CreateConfig creates the default plugin configuration.
Expand All @@ -36,6 +38,7 @@ type Plugin struct {
allowedCountries []string
allowPrivate bool
disallowedStatusCode int
allowedIPBlocks []*net.IPNet
}

// New creates a new plugin instance.
Expand Down Expand Up @@ -70,6 +73,11 @@ func New(_ context.Context, next http.Handler, cfg *Config, name string) (http.H
return nil, fmt.Errorf("%s: failed to open database: %w", name, err)
}

allowedIPBlocks, err := initAllowedIPBlocks(cfg.AllowedIPBlocks)
if err != nil {
return nil, fmt.Errorf("%s: failed loading allowed CIDR blocks: %w", name, err)
}

return &Plugin{
next: next,
name: name,
Expand All @@ -78,6 +86,7 @@ func New(_ context.Context, next http.Handler, cfg *Config, name string) (http.H
allowedCountries: cfg.AllowedCountries,
allowPrivate: cfg.AllowPrivate,
disallowedStatusCode: cfg.DisallowedStatusCode,
allowedIPBlocks: allowedIPBlocks,
}, nil
}

Expand Down Expand Up @@ -154,10 +163,15 @@ func (p Plugin) CheckAllowed(ip string) (bool, string, error) {
var allowed bool
for _, allowedCountry := range p.allowedCountries {
if allowedCountry == country {
allowed = true
break
return true, country, nil
}
}

allowed, err = p.isAllowedIPBlocks(ip)
if err != nil {
return false, "", fmt.Errorf("checking if %s is part of an allowed range failed: %w", ip, err)
}

if !allowed {
return false, country, nil
}
Expand All @@ -179,3 +193,36 @@ func (p Plugin) Lookup(ip string) (string, error) {

return record.Country_short, nil
}

// Create IP Networks using CIDR block array
func initAllowedIPBlocks(allowedIPBlocks []string) ([]*net.IPNet, error) {

var allowedIPBlocksNet []*net.IPNet

for _, cidr := range allowedIPBlocks {
_, block, err := net.ParseCIDR(cidr)
if err != nil {
return nil, fmt.Errorf("parse error on %q: %v", cidr, err)
}
allowedIPBlocksNet = append(allowedIPBlocksNet, block)
}

return allowedIPBlocksNet, nil
}

// isAllowedIPBlocks check if an IP is allowed base on the allowed CIDR blocks
func (p Plugin) isAllowedIPBlocks(ip string) (bool, error) {
var ipAddress net.IP = net.ParseIP(ip)

if ipAddress == nil {
return false, fmt.Errorf("unable parse IP address from address [%s]", ip)
}

for _, block := range p.allowedIPBlocks {
if block.Contains(ipAddress) {
return true, nil
}
}

return false, nil
}

0 comments on commit 52278e1

Please sign in to comment.