ipfilter

package module
v1.2.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 11, 2023 License: MIT Imports: 7 Imported by: 26

README

ipfilter

A package for IP Filtering in Go (golang)

GoDoc Tests

Install
go get github.com/jpillora/ipfilter
Features
  • Simple
  • Thread-safe
  • IPv4 / IPv6 support
  • Subnet support
  • Location filtering (via phuslu/iploc)
  • Simple HTTP middleware
Usage

Country-block HTTP middleware

h := http.Handler(...)
myProtectedHandler := ipfilter.Wrap(h, ipfilter.Options{
    //block requests from China and Russia by IP
    BlockedCountries: []string{"CN", "RU"},
})
http.ListenAndServe(":8080", myProtectedHandler)

Country-block stand-alone

f := ipfilter.New(ipfilter.Options{
    BlockedCountries: []string{"CN"},
})

f.Blocked("116.31.116.51") //=> true (CN)
f.Allowed("216.58.199.67") //=> true (US)

Async allow LAN hosts middleware

f := ipfilter.New(ipfilter.Options{
    BlockByDefault: true,
})

go func() {
	time.Sleep(15 * time.Second)
	//react to admin change....
	f.AllowIP("192.168.0.23")
}()

h := http.Handler(...)
myProtectedHandler := f.Wrap(h)
http.ListenAndServe(":8080", myProtectedHandler)

Allow your entire LAN only

f := ipfilter.New(ipfilter.Options{
    AllowedIPs: []string{"192.168.0.0/24"},
    BlockByDefault: true,
})
//only allow 192.168.0.X IPs
f.Allowed("192.168.0.42") //=> true
f.Allowed("10.0.0.42") //=> false

... and with dynamic list updates

//and allow 10.X.X.X
f.AllowIP("10.0.0.0/8")
f.Allowed("10.0.0.42") //=> true
f.Allowed("203.25.111.68") //=> false
//and allow everyone in Australia
f.AllowCountry("AU")
f.Allowed("203.25.111.68") //=> true

Check with net.IP

f.NetAllowed(net.IP{203,25,111,68}) //=> true

Low-level single IP to country

f.IPToCountry("203.25.111.68") //=> "AU"
f.NetIPToCountry(net.IP{203,25,111,68}) //=> "AU"

Advanced HTTP middleware

Make your own with:

func (m *myMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	//use remote addr as it cant be spoofed
	ip, _, _ := net.SplitHostPort(r.RemoteAddr)
	//show simple forbidden text
	if !m.IPFilter.Allowed(ip) {
		http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
		return
	}
	//success!
	m.next.ServeHTTP(w, r)
}
Issues
  • Due to the nature of IP address allocation, determining location based of a single IP address is quite difficult (if you're not Google) and is therefore not very reliable. For this reason BlockByDefault is off by default.
Todo
  • Use a good algorithm to perform faster prefix matches
  • Investigate reliability of other detectable attributes
  • Add TOR/anonymizer filter options
  • Add great-circle distance filter options (e.g. Allow 500KM radius from code/lat,lon)
Credits
Change log
  • v1.0.0 Use MaxMindDB IP data
  • v1.1.0 Use IP2Location LITE IP data
  • v1.2.3 Upgrade iploc, requires Go 1.16

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IPToCountry

func IPToCountry(ipstr string) string

IPToCountry is a simple IP-country code lookup. Returns an empty string when cannot determine country.

func NetIPToCountry

func NetIPToCountry(ip net.IP) string

NetIPToCountry is a simple IP-country code lookup. Returns an empty string when cannot determine country.

func Wrap

func Wrap(next http.Handler, opts Options) http.Handler

Wrap is equivalent to NewLazy(opts) then Wrap(next)

Types

type IPFilter

type IPFilter struct {
	// contains filtered or unexported fields
}

func New

func New(opts Options) *IPFilter

New constructs IPFilter instance without downloading DB.

func NewLazy

func NewLazy(opts Options) *IPFilter

NewLazy is the same as New

func NewNoDB

func NewNoDB(opts Options) *IPFilter

NewNoDB is the same as New

func (*IPFilter) AllowCountry

func (f *IPFilter) AllowCountry(code string)

func (*IPFilter) AllowIP

func (f *IPFilter) AllowIP(ip string) bool

func (*IPFilter) Allowed

func (f *IPFilter) Allowed(ipstr string) bool

Allowed returns if a given IP can pass through the filter

func (*IPFilter) BlockCountry

func (f *IPFilter) BlockCountry(code string)

func (*IPFilter) BlockIP

func (f *IPFilter) BlockIP(ip string) bool

func (*IPFilter) Blocked

func (f *IPFilter) Blocked(ip string) bool

Blocked returns if a given IP can NOT pass through the filter

func (*IPFilter) IPToCountry

func (f *IPFilter) IPToCountry(ipstr string) string

func (*IPFilter) NetAllowed

func (f *IPFilter) NetAllowed(ip net.IP) bool

NetAllowed returns if a given net.IP can pass through the filter

func (*IPFilter) NetBlocked

func (f *IPFilter) NetBlocked(ip net.IP) bool

NetBlocked returns if a given net.IP can NOT pass through the filter

func (*IPFilter) NetIPToCountry

func (f *IPFilter) NetIPToCountry(ip net.IP) string

func (*IPFilter) ToggleCountry

func (f *IPFilter) ToggleCountry(code string, allowed bool)

ToggleCountry alters a specific country setting

func (*IPFilter) ToggleDefault

func (f *IPFilter) ToggleDefault(allowed bool)

ToggleDefault alters the default setting

func (*IPFilter) ToggleIP

func (f *IPFilter) ToggleIP(str string, allowed bool) bool

func (*IPFilter) Wrap

func (f *IPFilter) Wrap(next http.Handler) http.Handler

Wrap the provided handler with simple IP blocking middleware using this IP filter and its configuration

type Options

type Options struct {
	//explicity allowed IPs
	AllowedIPs []string
	//explicity blocked IPs
	BlockedIPs []string
	//explicity allowed country ISO codes
	AllowedCountries []string
	//explicity blocked country ISO codes
	BlockedCountries []string
	//block by default (defaults to allow)
	BlockByDefault bool
	// TrustProxy enable check request IP from proxy
	TrustProxy bool
	// Logger enables logging, printing using the provided interface
	Logger interface {
		Printf(format string, v ...interface{})
	}
	// These fields currently have no effect
	IPDB         []byte
	IPDBPath     string
	IPDBNoFetch  bool
	IPDBFetchURL string
}

Options for IPFilter. Allow supercedes Block for IP checks across all matching subnets, whereas country checks use the latest Allow/Block setting. IPs can be IPv4 or IPv6 and can optionally contain subnet masks (e.g. /24). Note however, determining if a given IP is included in a subnet requires a linear scan so is less performant than looking up single IPs.

This could be improved with cidr range prefix tree.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL