summaryrefslogtreecommitdiff
path: root/internal/funcs/net.go
diff options
context:
space:
mode:
authorDave Henderson <dhenderson@gmail.com>2024-01-25 20:11:31 -0500
committerGitHub <noreply@github.com>2024-01-25 20:11:31 -0500
commitebb97fb7367fb983cffc1935a8fb57e4b80f5249 (patch)
tree43ef6cd01f629f60f59efe1e5b003f7c8e3a1257 /internal/funcs/net.go
parentf1d9158ea99abbe556251c1ff2fe970f3b460ee9 (diff)
Move funcs package to internal (#1977)
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
Diffstat (limited to 'internal/funcs/net.go')
-rw-r--r--internal/funcs/net.go300
1 files changed, 300 insertions, 0 deletions
diff --git a/internal/funcs/net.go b/internal/funcs/net.go
new file mode 100644
index 00000000..3342bd27
--- /dev/null
+++ b/internal/funcs/net.go
@@ -0,0 +1,300 @@
+package funcs
+
+import (
+ "context"
+ "fmt"
+ "math/big"
+ stdnet "net"
+ "net/netip"
+
+ "github.com/hairyhenderson/gomplate/v4/conv"
+ "github.com/hairyhenderson/gomplate/v4/internal/cidr"
+ "github.com/hairyhenderson/gomplate/v4/internal/deprecated"
+ "github.com/hairyhenderson/gomplate/v4/net"
+ "go4.org/netipx"
+ "inet.af/netaddr"
+)
+
+// NetNS - the net namespace
+//
+// Deprecated: don't use
+func NetNS() *NetFuncs {
+ return &NetFuncs{}
+}
+
+// AddNetFuncs -
+//
+// Deprecated: use [CreateNetFuncs] instead
+func AddNetFuncs(f map[string]interface{}) {
+ for k, v := range CreateNetFuncs(context.Background()) {
+ f[k] = v
+ }
+}
+
+// CreateNetFuncs -
+func CreateNetFuncs(ctx context.Context) map[string]interface{} {
+ ns := &NetFuncs{ctx}
+ return map[string]interface{}{
+ "net": func() interface{} { return ns },
+ }
+}
+
+// NetFuncs -
+type NetFuncs struct {
+ ctx context.Context
+}
+
+// LookupIP -
+func (f NetFuncs) LookupIP(name interface{}) (string, error) {
+ return net.LookupIP(conv.ToString(name))
+}
+
+// LookupIPs -
+func (f NetFuncs) LookupIPs(name interface{}) ([]string, error) {
+ return net.LookupIPs(conv.ToString(name))
+}
+
+// LookupCNAME -
+func (f NetFuncs) LookupCNAME(name interface{}) (string, error) {
+ return net.LookupCNAME(conv.ToString(name))
+}
+
+// LookupSRV -
+func (f NetFuncs) LookupSRV(name interface{}) (*stdnet.SRV, error) {
+ return net.LookupSRV(conv.ToString(name))
+}
+
+// LookupSRVs -
+func (f NetFuncs) LookupSRVs(name interface{}) ([]*stdnet.SRV, error) {
+ return net.LookupSRVs(conv.ToString(name))
+}
+
+// LookupTXT -
+func (f NetFuncs) LookupTXT(name interface{}) ([]string, error) {
+ return net.LookupTXT(conv.ToString(name))
+}
+
+// ParseIP -
+//
+// Deprecated: use [ParseAddr] instead
+func (f *NetFuncs) ParseIP(ip interface{}) (netaddr.IP, error) {
+ deprecated.WarnDeprecated(f.ctx, "net.ParseIP is deprecated - use net.ParseAddr instead")
+ return netaddr.ParseIP(conv.ToString(ip))
+}
+
+// ParseIPPrefix -
+//
+// Deprecated: use [ParsePrefix] instead
+func (f *NetFuncs) ParseIPPrefix(ipprefix interface{}) (netaddr.IPPrefix, error) {
+ deprecated.WarnDeprecated(f.ctx, "net.ParseIPPrefix is deprecated - use net.ParsePrefix instead")
+ return netaddr.ParseIPPrefix(conv.ToString(ipprefix))
+}
+
+// ParseIPRange -
+//
+// Deprecated: use [ParseRange] instead
+func (f *NetFuncs) ParseIPRange(iprange interface{}) (netaddr.IPRange, error) {
+ deprecated.WarnDeprecated(f.ctx, "net.ParseIPRange is deprecated - use net.ParseRange instead")
+ return netaddr.ParseIPRange(conv.ToString(iprange))
+}
+
+// ParseAddr -
+func (f NetFuncs) ParseAddr(ip interface{}) (netip.Addr, error) {
+ return netip.ParseAddr(conv.ToString(ip))
+}
+
+// ParsePrefix -
+func (f NetFuncs) ParsePrefix(ipprefix interface{}) (netip.Prefix, error) {
+ return netip.ParsePrefix(conv.ToString(ipprefix))
+}
+
+// ParseRange -
+//
+// Experimental: this API may change in the future
+func (f NetFuncs) ParseRange(iprange interface{}) (netipx.IPRange, error) {
+ return netipx.ParseIPRange(conv.ToString(iprange))
+}
+
+// func (f *NetFuncs) parseStdnetIPNet(prefix interface{}) (*stdnet.IPNet, error) {
+// switch p := prefix.(type) {
+// case *stdnet.IPNet:
+// return p, nil
+// case netaddr.IPPrefix:
+// deprecated.WarnDeprecated(f.ctx,
+// "support for netaddr.IPPrefix is deprecated - use net.ParsePrefix to produce a netip.Prefix instead")
+// return p.Masked().IPNet(), nil
+// case netip.Prefix:
+// net := &stdnet.IPNet{
+// IP: p.Masked().Addr().AsSlice(),
+// Mask: stdnet.CIDRMask(p.Bits(), p.Addr().BitLen()),
+// }
+// return net, nil
+// default:
+// _, network, err := stdnet.ParseCIDR(conv.ToString(prefix))
+// return network, err
+// }
+// }
+
+// TODO: look at using this instead of parseStdnetIPNet
+func (f *NetFuncs) parseNetipPrefix(prefix interface{}) (netip.Prefix, error) {
+ switch p := prefix.(type) {
+ case *stdnet.IPNet:
+ return f.ipPrefixFromIPNet(p), nil
+ case netaddr.IPPrefix:
+ deprecated.WarnDeprecated(f.ctx,
+ "support for netaddr.IPPrefix is deprecated - use net.ParsePrefix to produce a netip.Prefix instead")
+ return f.ipPrefixFromIPNet(p.Masked().IPNet()), nil
+ case netip.Prefix:
+ return p, nil
+ default:
+ return netip.ParsePrefix(conv.ToString(prefix))
+ }
+}
+
+// func (f NetFuncs) ipFromNetIP(n stdnet.IP) netip.Addr {
+// ip, _ := netip.AddrFromSlice(n)
+// return ip
+// }
+
+func (f NetFuncs) ipPrefixFromIPNet(n *stdnet.IPNet) netip.Prefix {
+ ip, _ := netip.AddrFromSlice(n.IP)
+ ones, _ := n.Mask.Size()
+ return netip.PrefixFrom(ip, ones)
+}
+
+// CIDRHost -
+// Experimental!
+func (f *NetFuncs) CIDRHost(hostnum interface{}, prefix interface{}) (netip.Addr, error) {
+ if err := checkExperimental(f.ctx); err != nil {
+ return netip.Addr{}, err
+ }
+
+ network, err := f.parseNetipPrefix(prefix)
+ if err != nil {
+ return netip.Addr{}, err
+ }
+
+ ip, err := cidr.HostBig(network, big.NewInt(conv.ToInt64(hostnum)))
+
+ return ip, err
+}
+
+// CIDRNetmask -
+// Experimental!
+func (f *NetFuncs) CIDRNetmask(prefix interface{}) (netip.Addr, error) {
+ if err := checkExperimental(f.ctx); err != nil {
+ return netip.Addr{}, err
+ }
+
+ p, err := f.parseNetipPrefix(prefix)
+ if err != nil {
+ return netip.Addr{}, err
+ }
+
+ // fill an appropriately sized byte slice with as many 1s as prefix bits
+ b := make([]byte, p.Addr().BitLen()/8)
+ for i := 0; i < p.Bits(); i++ {
+ b[i/8] |= 1 << uint(7-i%8)
+ }
+
+ m, ok := netip.AddrFromSlice(b)
+ if !ok {
+ return netip.Addr{}, fmt.Errorf("invalid netmask")
+ }
+
+ return m, nil
+}
+
+// CIDRSubnets -
+// Experimental!
+func (f *NetFuncs) CIDRSubnets(newbits interface{}, prefix interface{}) ([]netip.Prefix, error) {
+ if err := checkExperimental(f.ctx); err != nil {
+ return nil, err
+ }
+
+ network, err := f.parseNetipPrefix(prefix)
+ if err != nil {
+ return nil, err
+ }
+
+ nBits := conv.ToInt(newbits)
+ if nBits < 1 {
+ return nil, fmt.Errorf("must extend prefix by at least one bit")
+ }
+
+ maxNetNum := int64(1 << uint64(nBits))
+ retValues := make([]netip.Prefix, maxNetNum)
+ for i := int64(0); i < maxNetNum; i++ {
+ subnet, err := cidr.SubnetBig(network, nBits, big.NewInt(i))
+ if err != nil {
+ return nil, err
+ }
+ retValues[i] = subnet
+ }
+
+ return retValues, nil
+}
+
+// CIDRSubnetSizes -
+// Experimental!
+func (f *NetFuncs) CIDRSubnetSizes(args ...interface{}) ([]netip.Prefix, error) {
+ if err := checkExperimental(f.ctx); err != nil {
+ return nil, err
+ }
+
+ if len(args) < 2 {
+ return nil, fmt.Errorf("wrong number of args: want 2 or more, got %d", len(args))
+ }
+
+ network, err := f.parseNetipPrefix(args[len(args)-1])
+ if err != nil {
+ return nil, err
+ }
+ newbits := conv.ToInts(args[:len(args)-1]...)
+
+ startPrefixLen := network.Bits()
+ firstLength := newbits[0]
+
+ firstLength += startPrefixLen
+ retValues := make([]netip.Prefix, len(newbits))
+
+ current, _ := cidr.PreviousSubnet(network, firstLength)
+
+ for i, length := range newbits {
+ if length < 1 {
+ return nil, fmt.Errorf("must extend prefix by at least one bit")
+ }
+ // For portability with 32-bit systems where the subnet number
+ // will be a 32-bit int, we only allow extension of 32 bits in
+ // one call even if we're running on a 64-bit machine.
+ // (Of course, this is significant only for IPv6.)
+ if length > 32 {
+ return nil, fmt.Errorf("may not extend prefix by more than 32 bits")
+ }
+
+ length += startPrefixLen
+ if length > network.Addr().BitLen() {
+ protocol := "IP"
+ switch {
+ case network.Addr().Is4():
+ protocol = "IPv4"
+ case network.Addr().Is6():
+ protocol = "IPv6"
+ }
+ return nil, fmt.Errorf("would extend prefix to %d bits, which is too long for an %s address", length, protocol)
+ }
+
+ next, rollover := cidr.NextSubnet(current, length)
+ if rollover || !network.Contains(next.Addr()) {
+ // If we run out of suffix bits in the base CIDR prefix then
+ // NextSubnet will start incrementing the prefix bits, which
+ // we don't allow because it would then allocate addresses
+ // outside of the caller's given prefix.
+ return nil, fmt.Errorf("not enough remaining address space for a subnet with a prefix of %d bits after %s", length, current.String())
+ }
+ current = next
+ retValues[i] = current
+ }
+
+ return retValues, nil
+}