github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/lang/funcs/cidr.go (about) 1 package funcs 2 3 import ( 4 "fmt" 5 "math/big" 6 7 "github.com/apparentlymart/go-cidr/cidr" 8 "github.com/hashicorp/terraform/internal/ipaddr" 9 "github.com/zclconf/go-cty/cty" 10 "github.com/zclconf/go-cty/cty/function" 11 "github.com/zclconf/go-cty/cty/gocty" 12 ) 13 14 // CidrHostFunc contructs a function that calculates a full host IP address 15 // within a given IP network address prefix. 16 var CidrHostFunc = function.New(&function.Spec{ 17 Params: []function.Parameter{ 18 { 19 Name: "prefix", 20 Type: cty.String, 21 }, 22 { 23 Name: "hostnum", 24 Type: cty.Number, 25 }, 26 }, 27 Type: function.StaticReturnType(cty.String), 28 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { 29 var hostNum *big.Int 30 if err := gocty.FromCtyValue(args[1], &hostNum); err != nil { 31 return cty.UnknownVal(cty.String), err 32 } 33 _, network, err := ipaddr.ParseCIDR(args[0].AsString()) 34 if err != nil { 35 return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err) 36 } 37 38 ip, err := cidr.HostBig(network, hostNum) 39 if err != nil { 40 return cty.UnknownVal(cty.String), err 41 } 42 43 return cty.StringVal(ip.String()), nil 44 }, 45 }) 46 47 // CidrNetmaskFunc contructs a function that converts an IPv4 address prefix given 48 // in CIDR notation into a subnet mask address. 49 var CidrNetmaskFunc = function.New(&function.Spec{ 50 Params: []function.Parameter{ 51 { 52 Name: "prefix", 53 Type: cty.String, 54 }, 55 }, 56 Type: function.StaticReturnType(cty.String), 57 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { 58 _, network, err := ipaddr.ParseCIDR(args[0].AsString()) 59 if err != nil { 60 return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err) 61 } 62 63 if network.IP.To4() == nil { 64 return cty.UnknownVal(cty.String), fmt.Errorf("IPv6 addresses cannot have a netmask: %s", args[0].AsString()) 65 } 66 67 return cty.StringVal(ipaddr.IP(network.Mask).String()), nil 68 }, 69 }) 70 71 // CidrSubnetFunc contructs a function that calculates a subnet address within 72 // a given IP network address prefix. 73 var CidrSubnetFunc = function.New(&function.Spec{ 74 Params: []function.Parameter{ 75 { 76 Name: "prefix", 77 Type: cty.String, 78 }, 79 { 80 Name: "newbits", 81 Type: cty.Number, 82 }, 83 { 84 Name: "netnum", 85 Type: cty.Number, 86 }, 87 }, 88 Type: function.StaticReturnType(cty.String), 89 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { 90 var newbits int 91 if err := gocty.FromCtyValue(args[1], &newbits); err != nil { 92 return cty.UnknownVal(cty.String), err 93 } 94 var netnum *big.Int 95 if err := gocty.FromCtyValue(args[2], &netnum); err != nil { 96 return cty.UnknownVal(cty.String), err 97 } 98 99 _, network, err := ipaddr.ParseCIDR(args[0].AsString()) 100 if err != nil { 101 return cty.UnknownVal(cty.String), fmt.Errorf("invalid CIDR expression: %s", err) 102 } 103 104 newNetwork, err := cidr.SubnetBig(network, newbits, netnum) 105 if err != nil { 106 return cty.UnknownVal(cty.String), err 107 } 108 109 return cty.StringVal(newNetwork.String()), nil 110 }, 111 }) 112 113 // CidrSubnetsFunc is similar to CidrSubnetFunc but calculates many consecutive 114 // subnet addresses at once, rather than just a single subnet extension. 115 var CidrSubnetsFunc = function.New(&function.Spec{ 116 Params: []function.Parameter{ 117 { 118 Name: "prefix", 119 Type: cty.String, 120 }, 121 }, 122 VarParam: &function.Parameter{ 123 Name: "newbits", 124 Type: cty.Number, 125 }, 126 Type: function.StaticReturnType(cty.List(cty.String)), 127 Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) { 128 _, network, err := ipaddr.ParseCIDR(args[0].AsString()) 129 if err != nil { 130 return cty.UnknownVal(cty.String), function.NewArgErrorf(0, "invalid CIDR expression: %s", err) 131 } 132 startPrefixLen, _ := network.Mask.Size() 133 134 prefixLengthArgs := args[1:] 135 if len(prefixLengthArgs) == 0 { 136 return cty.ListValEmpty(cty.String), nil 137 } 138 139 var firstLength int 140 if err := gocty.FromCtyValue(prefixLengthArgs[0], &firstLength); err != nil { 141 return cty.UnknownVal(cty.String), function.NewArgError(1, err) 142 } 143 firstLength += startPrefixLen 144 145 retVals := make([]cty.Value, len(prefixLengthArgs)) 146 147 current, _ := cidr.PreviousSubnet(network, firstLength) 148 for i, lengthArg := range prefixLengthArgs { 149 var length int 150 if err := gocty.FromCtyValue(lengthArg, &length); err != nil { 151 return cty.UnknownVal(cty.String), function.NewArgError(i+1, err) 152 } 153 154 if length < 1 { 155 return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "must extend prefix by at least one bit") 156 } 157 // For portability with 32-bit systems where the subnet number 158 // will be a 32-bit int, we only allow extension of 32 bits in 159 // one call even if we're running on a 64-bit machine. 160 // (Of course, this is significant only for IPv6.) 161 if length > 32 { 162 return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "may not extend prefix by more than 32 bits") 163 } 164 length += startPrefixLen 165 if length > (len(network.IP) * 8) { 166 protocol := "IP" 167 switch len(network.IP) * 8 { 168 case 32: 169 protocol = "IPv4" 170 case 128: 171 protocol = "IPv6" 172 } 173 return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "would extend prefix to %d bits, which is too long for an %s address", length, protocol) 174 } 175 176 next, rollover := cidr.NextSubnet(current, length) 177 if rollover || !network.Contains(next.IP) { 178 // If we run out of suffix bits in the base CIDR prefix then 179 // NextSubnet will start incrementing the prefix bits, which 180 // we don't allow because it would then allocate addresses 181 // outside of the caller's given prefix. 182 return cty.UnknownVal(cty.String), function.NewArgErrorf(i+1, "not enough remaining address space for a subnet with a prefix of %d bits after %s", length, current.String()) 183 } 184 185 current = next 186 retVals[i] = cty.StringVal(current.String()) 187 } 188 189 return cty.ListVal(retVals), nil 190 }, 191 }) 192 193 // CidrHost calculates a full host IP address within a given IP network address prefix. 194 func CidrHost(prefix, hostnum cty.Value) (cty.Value, error) { 195 return CidrHostFunc.Call([]cty.Value{prefix, hostnum}) 196 } 197 198 // CidrNetmask converts an IPv4 address prefix given in CIDR notation into a subnet mask address. 199 func CidrNetmask(prefix cty.Value) (cty.Value, error) { 200 return CidrNetmaskFunc.Call([]cty.Value{prefix}) 201 } 202 203 // CidrSubnet calculates a subnet address within a given IP network address prefix. 204 func CidrSubnet(prefix, newbits, netnum cty.Value) (cty.Value, error) { 205 return CidrSubnetFunc.Call([]cty.Value{prefix, newbits, netnum}) 206 } 207 208 // CidrSubnets calculates a sequence of consecutive subnet prefixes that may 209 // be of different prefix lengths under a common base prefix. 210 func CidrSubnets(prefix cty.Value, newbits ...cty.Value) (cty.Value, error) { 211 args := make([]cty.Value, len(newbits)+1) 212 args[0] = prefix 213 copy(args[1:], newbits) 214 return CidrSubnetsFunc.Call(args) 215 }