mirror of
				https://github.com/traefik/traefik.git
				synced 2025-10-31 00:11:38 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			103 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package ip
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"net/netip"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // Checker allows to check that addresses are in a trusted IPs.
 | |
| type Checker struct {
 | |
| 	authorizedIPs    []*net.IP
 | |
| 	authorizedIPsNet []*net.IPNet
 | |
| }
 | |
| 
 | |
| // NewChecker builds a new Checker given a list of CIDR-Strings to trusted IPs.
 | |
| func NewChecker(trustedIPs []string) (*Checker, error) {
 | |
| 	if len(trustedIPs) == 0 {
 | |
| 		return nil, errors.New("no trusted IPs provided")
 | |
| 	}
 | |
| 
 | |
| 	checker := &Checker{}
 | |
| 
 | |
| 	for _, ipMask := range trustedIPs {
 | |
| 		if ipAddr := net.ParseIP(ipMask); ipAddr != nil {
 | |
| 			checker.authorizedIPs = append(checker.authorizedIPs, &ipAddr)
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		_, ipAddr, err := net.ParseCIDR(ipMask)
 | |
| 		if err != nil {
 | |
| 			return nil, fmt.Errorf("parsing CIDR trusted IPs %s: %w", ipAddr, err)
 | |
| 		}
 | |
| 		checker.authorizedIPsNet = append(checker.authorizedIPsNet, ipAddr)
 | |
| 	}
 | |
| 
 | |
| 	return checker, nil
 | |
| }
 | |
| 
 | |
| // IsAuthorized checks if provided request is authorized by the trusted IPs.
 | |
| func (ip *Checker) IsAuthorized(addr string) error {
 | |
| 	var invalidMatches []string
 | |
| 
 | |
| 	host, _, err := net.SplitHostPort(addr)
 | |
| 	if err != nil {
 | |
| 		host = addr
 | |
| 	}
 | |
| 
 | |
| 	ok, err := ip.Contains(host)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if !ok {
 | |
| 		invalidMatches = append(invalidMatches, addr)
 | |
| 		return fmt.Errorf("%q matched none of the trusted IPs", strings.Join(invalidMatches, ", "))
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // Contains checks if provided address is in the trusted IPs.
 | |
| func (ip *Checker) Contains(addr string) (bool, error) {
 | |
| 	if len(addr) == 0 {
 | |
| 		return false, errors.New("empty IP address")
 | |
| 	}
 | |
| 
 | |
| 	ipAddr, err := parseIP(addr)
 | |
| 	if err != nil {
 | |
| 		return false, fmt.Errorf("unable to parse address: %s: %w", addr, err)
 | |
| 	}
 | |
| 
 | |
| 	return ip.ContainsIP(ipAddr), nil
 | |
| }
 | |
| 
 | |
| // ContainsIP checks if provided address is in the trusted IPs.
 | |
| func (ip *Checker) ContainsIP(addr net.IP) bool {
 | |
| 	for _, authorizedIP := range ip.authorizedIPs {
 | |
| 		if authorizedIP.Equal(addr) {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for _, authorizedNet := range ip.authorizedIPsNet {
 | |
| 		if authorizedNet.Contains(addr) {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func parseIP(addr string) (net.IP, error) {
 | |
| 	parsedAddr, err := netip.ParseAddr(addr)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("can't parse IP from address %s", addr)
 | |
| 	}
 | |
| 
 | |
| 	ip := parsedAddr.As16()
 | |
| 	return ip[:], nil
 | |
| }
 |