whitelist

package
v1.6.5 Latest Latest
Warning

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

Go to latest
Published: Mar 5, 2024 License: BSD-2-Clause, ISC Imports: 7 Imported by: 194

README

whitelist

This is a simple whitelisting package that encompasses several common patterns into a reusable package.

The basic type of a whitelist is the ACL type, which provides a single method on a net.IP value:

  • Permitted determines whether the IP address is whitelisted and therefore should be permitted access. It should return true if the address is whitelisted.

Additionally, there are two other types that are built on the ACL type; the HostACL stores individual hosts and the NetACL stores networks. Each of these provides two functions that differ in the types of their arguments.

  • Add whitelists the IP address.
  • Remove drops the IP address from the whitelist.

The HostACL operates on net.IP values, while the NetACL operates on *net.IPNets.

There are currently four implementations of ACL provided in this package; a basic implementation of the two types of ACLs and a stub type for each:

  • Basic is a simple host-based whitelister that converts the IP addresses to strings; the whitelist is implemented as a set of string addresses. The set is implemented as a map[string]bool, and uses a sync.Mutex to coordinate updates to the whitelist.
  • BasicNet is a simple network-based whitelister that similarly uses a mutex and an array to store networks. This has a number of limitations: operations are /O(n)/, and subsets/supersets of existing networks isn't detected. That is, if 192.168.3.0/24 is removed from a whitelist that has 192.168.0.0/16 permitted, that subnet will not actually be removed. Exact networks are required for Add and Remove at this time.
  • HostStub and NetStub are stand-in whitelists that always permits addresses. They are vocal about logging warning messages noting that whitelisting is stubbed. They are designed to be used in cases where whitelisting is desired, but the mechanics of whitelisting (i.e. administration of the whitelist) is not yet implemented, perhaps to keep whitelists in the system's flow.

Two convenience functions are provided here for extracting IP addresses:

  • NetConnLookup accepts a net.Conn value, and returns the net.IP value from the connection.
  • HTTPRequestLookup accepts a *http.Request and returns the net.IP value from the request.

There are also two functions for whitelisting HTTP endpoints:

  • NewHandler returns an http.Handler
  • NewHandlerFunc returns an http.HandlerFunc

These endpoints will work with both HostACL and NetACL.

Example http.Handler

This is a file server that uses a pair of whitelists. The admin whitelist permits modifications to the user whitelist only by the localhost. The user whitelist controls which hosts have access to the file server.

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"

	"github.com/cloudflare/cfssl/whitelist"
)

var wl = whitelist.NewBasic()

func addIP(w http.ResponseWriter, r *http.Request) {
	addr := r.FormValue("ip")

	ip := net.ParseIP(addr)
	wl.Add(ip)
	log.Printf("request to add %s to the whitelist", addr)
	w.Write([]byte(fmt.Sprintf("Added %s to whitelist.\n", addr)))
}

func delIP(w http.ResponseWriter, r *http.Request) {
	addr := r.FormValue("ip")

	ip := net.ParseIP(addr)
	wl.Remove(ip)
	log.Printf("request to remove %s from the whitelist", addr)
	w.Write([]byte(fmt.Sprintf("Removed %s from whitelist.\n", ip)))
}

func dumpWhitelist(w http.ResponseWriter, r *http.Request) {
	out, err := json.Marshal(wl)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	} else {
		w.Write(out)
	}
}

type handler struct {
	h func(http.ResponseWriter, *http.Request)
}

func newHandler(h func(w http.ResponseWriter, r *http.Request)) http.Handler {
	return &handler{h: h}
}

func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.h(w, r)
}

func main() {
	root := flag.String("root", "files/", "file server root")
	flag.Parse()

	fileServer := http.StripPrefix("/files/",
		http.FileServer(http.Dir(*root)))
	wl.Add(net.IP{127, 0, 0, 1})

	adminWL := whitelist.NewBasic()
	adminWL.Add(net.IP{127, 0, 0, 1})
	adminWL.Add(net.ParseIP("::1"))

	protFiles, err := whitelist.NewHandler(fileServer, nil, wl)
	if err != nil {
		log.Fatalf("%v", err)
	}

	addHandler, err := whitelist.NewHandlerFunc(addIP, nil, adminWL)
	if err != nil {
		log.Fatalf("%v", err)
	}

	delHandler, err := whitelist.NewHandlerFunc(delIP, nil, adminWL)
	if err != nil {
		log.Fatalf("%v", err)
	}

	dumpHandler, err := whitelist.NewHandlerFunc(dumpWhitelist, nil, adminWL)
	if err != nil {
		log.Fatalf("%v", err)
	}

	http.Handle("/files/", protFiles)
	http.Handle("/add", addHandler)
	http.Handle("/del", delHandler)
	http.Handle("/dump", dumpHandler)

	log.Println("Serving files on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Documentation

Overview

Package whitelist implements IP whitelisting for various types of connections. Two types of access control lists (ACLs) are supported: host-based and network-based.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DumpBasic

func DumpBasic(wl *Basic) []byte

DumpBasic returns a whitelist as a byte slice where each IP is on its own line.

func HTTPRequestLookup

func HTTPRequestLookup(req *http.Request) (net.IP, error)

HTTPRequestLookup extracts an IP from the remote address in a *http.Request. A single *http.Request should be passed to Address.

func NetConnLookup

func NetConnLookup(conn net.Conn) (net.IP, error)

NetConnLookup extracts an IP from the remote address in the net.Conn. A single net.Conn should be passed to Address.

func NewHandler

func NewHandler(allow, deny http.Handler, acl ACL) (http.Handler, error)

NewHandler returns a new whitelisting-wrapped HTTP handler. The allow handler should contain a handler that will be called if the request is whitelisted; the deny handler should contain a handler that will be called in the request is not whitelisted.

Types

type ACL

type ACL interface {
	// Permitted takes an IP address, and returns true if the
	// IP address is whitelisted (e.g. permitted access).
	Permitted(net.IP) bool
}

An ACL stores a list of permitted IP addresses, and handles concurrency as needed.

type Basic

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

Basic implements a basic map-backed whitelister that uses an RWMutex for conccurency. IPv4 addresses are treated differently than an IPv6 address; namely, the IPv4 localhost will not match the IPv6 localhost.

func LoadBasic

func LoadBasic(in []byte) (*Basic, error)

LoadBasic loads a whitelist from a byteslice.

func NewBasic

func NewBasic() *Basic

NewBasic returns a new initialised basic whitelist.

func (*Basic) Add

func (wl *Basic) Add(ip net.IP)

Add whitelists an IP.

func (*Basic) MarshalJSON

func (wl *Basic) MarshalJSON() ([]byte, error)

MarshalJSON serialises a host whitelist to a comma-separated list of hosts, implementing the json.Marshaler interface.

func (*Basic) Permitted

func (wl *Basic) Permitted(ip net.IP) bool

Permitted returns true if the IP has been whitelisted.

func (*Basic) Remove

func (wl *Basic) Remove(ip net.IP)

Remove clears the IP from the whitelist.

func (*Basic) UnmarshalJSON

func (wl *Basic) UnmarshalJSON(in []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for host whitelists, taking a comma-separated string of hosts.

type BasicNet

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

BasicNet implements a basic map-backed network whitelist using locks for concurrency. It must be initialised with one of the constructor functions. This particular implementation is unoptimised and will not scale.

func NewBasicNet

func NewBasicNet() *BasicNet

NewBasicNet constructs a new basic network-based whitelist.

func (*BasicNet) Add

func (wl *BasicNet) Add(n *net.IPNet)

Add adds a new network to the whitelist. Caveat: overlapping networks won't be detected.

func (*BasicNet) MarshalJSON

func (wl *BasicNet) MarshalJSON() ([]byte, error)

MarshalJSON serialises a network whitelist to a comma-separated list of networks.

func (*BasicNet) Permitted

func (wl *BasicNet) Permitted(ip net.IP) bool

Permitted returns true if the IP has been whitelisted.

func (*BasicNet) Remove

func (wl *BasicNet) Remove(n *net.IPNet)

Remove removes a network from the whitelist.

func (*BasicNet) UnmarshalJSON

func (wl *BasicNet) UnmarshalJSON(in []byte) error

UnmarshalJSON implements the json.Unmarshaler interface for network whitelists, taking a comma-separated string of networks.

type Handler

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

Handler wraps an HTTP handler with IP whitelisting.

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP wraps the request in a whitelist check.

type HandlerFunc

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

A HandlerFunc contains a pair of http.HandleFunc-handler functions that will be called depending on whether a request is allowed or denied.

func NewHandlerFunc

func NewHandlerFunc(allow, deny func(http.ResponseWriter, *http.Request), acl ACL) (*HandlerFunc, error)

NewHandlerFunc returns a new basic whitelisting handler.

func (*HandlerFunc) ServeHTTP

func (h *HandlerFunc) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP checks the incoming request to see whether it is permitted, and calls the appropriate handle function.

type HostACL

type HostACL interface {
	ACL

	// Add takes an IP address and adds it to the whitelist so
	// that it is now permitted.
	Add(net.IP)

	// Remove takes an IP address and drops it from the whitelist
	// so that it is no longer permitted.
	Remove(net.IP)
}

A HostACL stores a list of permitted hosts.

type HostStub

type HostStub struct{}

HostStub allows host whitelisting to be added into a system's flow without doing anything yet. All operations result in warning log messages being printed to stderr. There is no mechanism for squelching these messages short of modifying the log package's default logger.

func NewHostStub

func NewHostStub() HostStub

NewHostStub returns a new stubbed host whitelister.

func (HostStub) Add

func (wl HostStub) Add(ip net.IP)

Add prints a warning message about whitelisting being stubbed.

func (HostStub) Permitted

func (wl HostStub) Permitted(ip net.IP) bool

Permitted always returns true, but prints a warning message alerting that whitelisting is stubbed.

func (HostStub) Remove

func (wl HostStub) Remove(ip net.IP)

Remove prints a warning message about whitelisting being stubbed.

type NetACL

type NetACL interface {
	ACL

	// Add takes an IP network and adds it to the whitelist so
	// that it is now permitted.
	Add(*net.IPNet)

	// Remove takes an IP network and drops it from the whitelist
	// so that it is no longer permitted.
	Remove(*net.IPNet)
}

A NetACL stores a list of permitted IP networks.

type NetStub

type NetStub struct{}

NetStub allows network whitelisting to be added into a system's flow without doing anything yet. All operations result in warning log messages being printed to stderr. There is no mechanism for squelching these messages short of modifying the log package's default logger.

func NewNetStub

func NewNetStub() NetStub

NewNetStub returns a new stubbed network whitelister.

func (NetStub) Add

func (wl NetStub) Add(ip *net.IPNet)

Add prints a warning message about whitelisting being stubbed.

func (NetStub) Permitted

func (wl NetStub) Permitted(ip net.IP) bool

Permitted always returns true, but prints a warning message alerting that whitelisting is stubbed.

func (NetStub) Remove

func (wl NetStub) Remove(ip *net.IPNet)

Remove prints a warning message about whitelisting being stubbed.

Notes

Bugs

  • overlapping networks aren't detected.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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