package whitelist import ( "fmt" "net" "github.com/pkg/errors" ) // IP allows to check that addresses are in a white list type IP struct { whiteListsIPs []*net.IP whiteListsNet []*net.IPNet insecure bool } // NewIP builds a new IP given a list of CIDR-Strings to whitelist func NewIP(whitelistStrings []string, insecure bool) (*IP, error) { if len(whitelistStrings) == 0 && !insecure { return nil, errors.New("no white list provided") } ip := IP{insecure: insecure} if !insecure { for _, whitelistString := range whitelistStrings { ipAddr := net.ParseIP(whitelistString) if ipAddr != nil { ip.whiteListsIPs = append(ip.whiteListsIPs, &ipAddr) } else { _, whitelist, err := net.ParseCIDR(whitelistString) if err != nil { return nil, fmt.Errorf("parsing CIDR whitelist %s: %v", whitelist, err) } ip.whiteListsNet = append(ip.whiteListsNet, whitelist) } } } return &ip, nil } // Contains checks if provided address is in the white list func (ip *IP) Contains(addr string) (bool, net.IP, error) { if ip.insecure { return true, nil, nil } ipAddr, err := ipFromRemoteAddr(addr) if err != nil { return false, nil, fmt.Errorf("unable to parse address: %s: %s", addr, err) } contains, err := ip.ContainsIP(ipAddr) return contains, ipAddr, err } // ContainsIP checks if provided address is in the white list func (ip *IP) ContainsIP(addr net.IP) (bool, error) { if ip.insecure { return true, nil } for _, whiteListIP := range ip.whiteListsIPs { if whiteListIP.Equal(addr) { return true, nil } } for _, whiteListNet := range ip.whiteListsNet { if whiteListNet.Contains(addr) { return true, nil } } return false, nil } func ipFromRemoteAddr(addr string) (net.IP, error) { userIP := net.ParseIP(addr) if userIP == nil { return nil, fmt.Errorf("can't parse IP from address %s", addr) } return userIP, nil }