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 }