github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/internal/cidr/cidr.go (about)

     1  package cidr
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strings"
     7  )
     8  
     9  var privateIPBlocks []*net.IPNet
    10  
    11  func init() {
    12  	for _, cidr := range []string{
    13  		"127.0.0.0/8",    // IPv4 loopback
    14  		"10.0.0.0/8",     // RFC1918
    15  		"172.16.0.0/12",  // RFC1918
    16  		"192.168.0.0/16", // RFC1918
    17  		"169.254.0.0/16", // RFC3927 link-local
    18  		"::1/128",        // IPv6 loopback
    19  		"fe80::/10",      // IPv6 link-local
    20  		"fc00::/7",       // IPv6 unique local addr
    21  		"100.64.0.0/10",  // IPv4 shared address space
    22  	} {
    23  		_, block, err := net.ParseCIDR(cidr)
    24  		if err != nil {
    25  			panic(fmt.Errorf("parse error on %q: `%w`", cidr, err))
    26  		}
    27  		privateIPBlocks = append(privateIPBlocks, block)
    28  	}
    29  }
    30  
    31  func isPrivate(ip net.IP) bool {
    32  	for _, block := range privateIPBlocks {
    33  		if block.Contains(ip) {
    34  			return true
    35  		}
    36  	}
    37  	return false
    38  }
    39  
    40  // CountAddresses calculates the number of addresses within the given CIDR. If the given
    41  // CIDR is in fact an IP (includes no /), 1 will bne returned. If the number of addresses
    42  // overflows an unsigned 64-bit int, the maximum value of an unsigned 64-bit int will be
    43  // returned.
    44  func CountAddresses(inputCIDR string) uint64 {
    45  	if inputCIDR == "*" || inputCIDR == "internet" || inputCIDR == "any" {
    46  		return 0xffffffffffffffff
    47  	}
    48  	if !strings.Contains(inputCIDR, "/") {
    49  		ip := net.ParseIP(inputCIDR)
    50  		if ip == nil {
    51  			return 0
    52  		}
    53  		return 1
    54  	}
    55  	_, network, err := net.ParseCIDR(inputCIDR)
    56  	if err != nil {
    57  		return 0
    58  	}
    59  	prefixLen, bits := network.Mask.Size()
    60  	power := bits - prefixLen
    61  	if power >= 63 {
    62  		return 0xffffffffffffffff
    63  	}
    64  	return 1 << power
    65  }
    66  
    67  // IsPublic returns true if a provided IP is outside of the designated public ranges, or
    68  // true if either of the min/max addresses of a provided CIDR are outside of these ranges.
    69  func IsPublic(cidr string) bool {
    70  
    71  	// some providers use wildcards etc. instead of "0.0.0.0/0" :/
    72  	if cidr == "*" || cidr == "internet" || cidr == "any" {
    73  		return true
    74  	}
    75  
    76  	// providers also allow "ranges" instead of cidrs :/
    77  	if strings.Contains(cidr, "-") {
    78  		parts := strings.Split(cidr, "-")
    79  		if len(parts) != 2 {
    80  			return false
    81  		}
    82  		if !isPrivate(net.IP(strings.TrimSpace(parts[0]))) {
    83  			return true
    84  		}
    85  		if !isPrivate(net.IP(strings.TrimSpace(parts[1]))) {
    86  			return true
    87  		}
    88  		return false
    89  	}
    90  
    91  	if !strings.Contains(cidr, "/") {
    92  		ip := net.ParseIP(cidr)
    93  		if ip == nil {
    94  			return false
    95  		}
    96  		return !isPrivate(ip)
    97  	}
    98  
    99  	start, network, err := net.ParseCIDR(cidr)
   100  	if err != nil {
   101  		return false
   102  	}
   103  
   104  	if !isPrivate(start) {
   105  		return true
   106  	}
   107  
   108  	end := highestAddress(network)
   109  	return !isPrivate(end)
   110  }
   111  
   112  func highestAddress(network *net.IPNet) net.IP {
   113  	raw := make([]byte, len(network.IP))
   114  	copy(raw, network.IP)
   115  	ones, bits := network.Mask.Size()
   116  	flip := bits - ones
   117  	for i := 0; i < flip; i++ {
   118  		index := len(raw) - 1
   119  		index -= (i / 8)
   120  		raw[index] ^= (1 << (i % 8))
   121  	}
   122  	return net.IP(raw)
   123  }