github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/pkg/scanners/terraform/parser/funcs/cidr.go (about)

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