diff options
| author | Dave Henderson <dhenderson@gmail.com> | 2023-02-04 16:32:49 -0500 |
|---|---|---|
| committer | Dave Henderson <dhenderson@gmail.com> | 2023-02-04 21:01:14 -0500 |
| commit | edf224ccf7c66498b2d9743fcfb29bf4c0960931 (patch) | |
| tree | 33461cb75f2d63e91be1d8a7ec5a9e72ce962f12 /funcs | |
| parent | af3e81ac52f93f07aea644b6397dbca97e5d30aa (diff) | |
Deprecate netaddr-based funcs
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
Diffstat (limited to 'funcs')
| -rw-r--r-- | funcs/net.go | 144 | ||||
| -rw-r--r-- | funcs/net_test.go | 124 |
2 files changed, 191 insertions, 77 deletions
diff --git a/funcs/net.go b/funcs/net.go index 0d87b98a..ab692cc1 100644 --- a/funcs/net.go +++ b/funcs/net.go @@ -2,14 +2,16 @@ package funcs import ( "context" + "fmt" "math/big" stdnet "net" "net/netip" - "github.com/apparentlymart/go-cidr/cidr" "github.com/hairyhenderson/gomplate/v3/conv" + "github.com/hairyhenderson/gomplate/v3/internal/cidr" + "github.com/hairyhenderson/gomplate/v3/internal/deprecated" "github.com/hairyhenderson/gomplate/v3/net" - "github.com/pkg/errors" + "go4.org/netipx" "inet.af/netaddr" ) @@ -73,46 +75,76 @@ func (f NetFuncs) LookupTXT(name interface{}) ([]string, error) { } // ParseIP - -func (f NetFuncs) ParseIP(ip interface{}) (netaddr.IP, error) { +// +// 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 - -func (f NetFuncs) ParseIPPrefix(ipprefix interface{}) (netaddr.IPPrefix, error) { +// +// 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 - -func (f NetFuncs) ParseIPRange(iprange interface{}) (netaddr.IPRange, error) { +// +// 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)) } -func (f NetFuncs) parseStdnetIPNet(prefix interface{}) (*stdnet.IPNet, error) { - switch p := prefix.(type) { - case *stdnet.IPNet: - return p, nil - case netaddr.IPPrefix: - 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 - } +// 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 // //nolint:unused -func (f NetFuncs) parseNetipPrefix(prefix interface{}) (netip.Prefix, error) { +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 @@ -121,10 +153,10 @@ func (f NetFuncs) parseNetipPrefix(prefix interface{}) (netip.Prefix, error) { } } -func (f NetFuncs) ipFromNetIP(n stdnet.IP) netip.Addr { - ip, _ := netip.AddrFromSlice(n) - return ip -} +// 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) @@ -134,52 +166,62 @@ func (f NetFuncs) ipPrefixFromIPNet(n *stdnet.IPNet) netip.Prefix { // CIDRHost - // Experimental! -func (f NetFuncs) CIDRHost(hostnum interface{}, prefix interface{}) (netip.Addr, error) { +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.parseStdnetIPNet(prefix) + network, err := f.parseNetipPrefix(prefix) if err != nil { return netip.Addr{}, err } ip, err := cidr.HostBig(network, big.NewInt(conv.ToInt64(hostnum))) - return f.ipFromNetIP(ip), err + return ip, err } // CIDRNetmask - // Experimental! -func (f NetFuncs) CIDRNetmask(prefix interface{}) (netip.Addr, error) { +func (f *NetFuncs) CIDRNetmask(prefix interface{}) (netip.Addr, error) { if err := checkExperimental(f.ctx); err != nil { return netip.Addr{}, err } - network, err := f.parseStdnetIPNet(prefix) + p, err := f.parseNetipPrefix(prefix) if err != nil { return netip.Addr{}, err } - netmask := stdnet.IP(network.Mask) - return f.ipFromNetIP(netmask), nil + // 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) { +func (f *NetFuncs) CIDRSubnets(newbits interface{}, prefix interface{}) ([]netip.Prefix, error) { if err := checkExperimental(f.ctx); err != nil { return nil, err } - network, err := f.parseStdnetIPNet(prefix) + network, err := f.parseNetipPrefix(prefix) if err != nil { return nil, err } nBits := conv.ToInt(newbits) if nBits < 1 { - return nil, errors.Errorf("must extend prefix by at least one bit") + return nil, fmt.Errorf("must extend prefix by at least one bit") } maxNetNum := int64(1 << uint64(nBits)) @@ -189,7 +231,7 @@ func (f NetFuncs) CIDRSubnets(newbits interface{}, prefix interface{}) ([]netip. if err != nil { return nil, err } - retValues[i] = f.ipPrefixFromIPNet(subnet) + retValues[i] = subnet } return retValues, nil @@ -197,22 +239,22 @@ func (f NetFuncs) CIDRSubnets(newbits interface{}, prefix interface{}) ([]netip. // CIDRSubnetSizes - // Experimental! -func (f NetFuncs) CIDRSubnetSizes(args ...interface{}) ([]netip.Prefix, error) { +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, errors.Errorf("wrong number of args: want 2 or more, got %d", len(args)) + return nil, fmt.Errorf("wrong number of args: want 2 or more, got %d", len(args)) } - network, err := f.parseStdnetIPNet(args[len(args)-1]) + network, err := f.parseNetipPrefix(args[len(args)-1]) if err != nil { return nil, err } newbits := conv.ToInts(args[:len(args)-1]...) - startPrefixLen, _ := network.Mask.Size() + startPrefixLen := network.Bits() firstLength := newbits[0] firstLength += startPrefixLen @@ -222,38 +264,38 @@ func (f NetFuncs) CIDRSubnetSizes(args ...interface{}) ([]netip.Prefix, error) { for i, length := range newbits { if length < 1 { - return nil, errors.Errorf("must extend prefix by at least one bit") + 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, errors.Errorf("may not extend prefix by more than 32 bits") + return nil, fmt.Errorf("may not extend prefix by more than 32 bits") } length += startPrefixLen - if length > (len(network.IP) * 8) { + if length > network.Addr().BitLen() { protocol := "IP" - switch len(network.IP) { - case stdnet.IPv4len: + switch { + case network.Addr().Is4(): protocol = "IPv4" - case stdnet.IPv6len: + case network.Addr().Is6(): protocol = "IPv6" } - return nil, errors.Errorf("would extend prefix to %d bits, which is too long for an %s address", length, protocol) + 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.IP) { + 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, errors.Errorf("not enough remaining address space for a subnet with a prefix of %d bits after %s", length, current.String()) + 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] = f.ipPrefixFromIPNet(current) + retValues[i] = current } return retValues, nil diff --git a/funcs/net_test.go b/funcs/net_test.go index e8914fa6..642a356c 100644 --- a/funcs/net_test.go +++ b/funcs/net_test.go @@ -9,6 +9,7 @@ import ( "github.com/hairyhenderson/gomplate/v3/internal/config" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "inet.af/netaddr" ) @@ -39,12 +40,12 @@ func TestNetLookupIP(t *testing.T) { func TestParseIP(t *testing.T) { t.Parallel() - n := NetFuncs{} + n := testNetNS() _, err := n.ParseIP("not an IP") assert.Error(t, err) ip, err := n.ParseIP("2001:470:20::2") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, netaddr.IPFrom16([16]byte{ 0x20, 0x01, 0x04, 0x70, 0, 0x20, 0, 0, @@ -56,7 +57,7 @@ func TestParseIP(t *testing.T) { func TestParseIPPrefix(t *testing.T) { t.Parallel() - n := NetFuncs{} + n := testNetNS() _, err := n.ParseIPPrefix("not an IP") assert.Error(t, err) @@ -64,14 +65,14 @@ func TestParseIPPrefix(t *testing.T) { assert.Error(t, err) ipprefix, err := n.ParseIPPrefix("192.168.0.2/28") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "192.168.0.0/28", ipprefix.Masked().String()) } func TestParseIPRange(t *testing.T) { t.Parallel() - n := NetFuncs{} + n := testNetNS() _, err := n.ParseIPRange("not an IP") assert.Error(t, err) @@ -79,10 +80,56 @@ func TestParseIPRange(t *testing.T) { assert.Error(t, err) iprange, err := n.ParseIPRange("192.168.0.2-192.168.23.255") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "192.168.0.2-192.168.23.255", iprange.String()) } +func TestParseAddr(t *testing.T) { + t.Parallel() + + n := testNetNS() + _, err := n.ParseAddr("not an IP") + assert.Error(t, err) + + ip, err := n.ParseAddr("2001:470:20::2") + require.NoError(t, err) + assert.Equal(t, netip.AddrFrom16([16]byte{ + 0x20, 0x01, 0x04, 0x70, + 0, 0x20, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0x02, + }), ip) +} + +func TestParsePrefix(t *testing.T) { + t.Parallel() + + n := testNetNS() + _, err := n.ParsePrefix("not an IP") + assert.Error(t, err) + + _, err = n.ParsePrefix("1.1.1.1") + assert.Error(t, err) + + ipprefix, err := n.ParsePrefix("192.168.0.2/28") + require.NoError(t, err) + assert.Equal(t, "192.168.0.0/28", ipprefix.Masked().String()) +} + +func TestParseRange(t *testing.T) { + t.Parallel() + + n := testNetNS() + _, err := n.ParseRange("not an IP") + assert.Error(t, err) + + _, err = n.ParseRange("1.1.1.1") + assert.Error(t, err) + + iprange, err := n.ParseRange("192.168.0.2-192.168.23.255") + require.NoError(t, err) + assert.Equal(t, "192.168.0.2-192.168.23.255", iprange.String()) +} func testNetNS() *NetFuncs { return &NetFuncs{ctx: config.SetExperimental(context.Background())} } @@ -94,48 +141,48 @@ func TestCIDRHost(t *testing.T) { _, netIP, _ := stdnet.ParseCIDR("10.12.127.0/20") ip, err := n.CIDRHost(16, netIP) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "10.12.112.16", ip.String()) ip, err = n.CIDRHost(268, netIP) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "10.12.113.12", ip.String()) _, netIP, _ = stdnet.ParseCIDR("fd00:fd12:3456:7890:00a2::/72") ip, err = n.CIDRHost(34, netIP) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "fd00:fd12:3456:7890::22", ip.String()) // inet.af/netaddr.IPPrefix ipPrefix, _ := n.ParseIPPrefix("10.12.127.0/20") ip, err = n.CIDRHost(16, ipPrefix) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "10.12.112.16", ip.String()) ip, err = n.CIDRHost(268, ipPrefix) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "10.12.113.12", ip.String()) ipPrefix, _ = n.ParseIPPrefix("fd00:fd12:3456:7890:00a2::/72") ip, err = n.CIDRHost(34, ipPrefix) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "fd00:fd12:3456:7890::22", ip.String()) // net/netip.Prefix prefix := netip.MustParsePrefix("10.12.127.0/20") ip, err = n.CIDRHost(16, prefix) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "10.12.112.16", ip.String()) ip, err = n.CIDRHost(268, prefix) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "10.12.113.12", ip.String()) prefix = netip.MustParsePrefix("fd00:fd12:3456:7890:00a2::/72") ip, err = n.CIDRHost(34, prefix) - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "fd00:fd12:3456:7890::22", ip.String()) } @@ -143,11 +190,11 @@ func TestCIDRNetmask(t *testing.T) { n := testNetNS() ip, err := n.CIDRNetmask("10.0.0.0/12") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "255.240.0.0", ip.String()) ip, err = n.CIDRNetmask("fd00:fd12:3456:7890:00a2::/72") - assert.NoError(t, err) + require.NoError(t, err) assert.Equal(t, "ffff:ffff:ffff:ffff:ff00::", ip.String()) } @@ -156,11 +203,11 @@ func TestCIDRSubnets(t *testing.T) { network := netip.MustParsePrefix("10.0.0.0/16") subnets, err := n.CIDRSubnets(-1, network) - assert.Nil(t, subnets) assert.Error(t, err) + assert.Nil(t, subnets) subnets, err = n.CIDRSubnets(2, network) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, subnets, 4) assert.Equal(t, "10.0.0.0/18", subnets[0].String()) assert.Equal(t, "10.0.64.0/18", subnets[1].String()) @@ -170,25 +217,50 @@ func TestCIDRSubnets(t *testing.T) { func TestCIDRSubnetSizes(t *testing.T) { n := testNetNS() - network := netip.MustParsePrefix("10.1.0.0/16") - subnets, err := n.CIDRSubnetSizes(network) - assert.Nil(t, subnets) + subnets, err := n.CIDRSubnetSizes(netip.MustParsePrefix("10.1.0.0/16")) assert.Error(t, err) - - subnets, err = n.CIDRSubnetSizes(32, network) assert.Nil(t, subnets) + + subnets, err = n.CIDRSubnetSizes(32, netip.MustParsePrefix("10.1.0.0/16")) assert.Error(t, err) + assert.Nil(t, subnets) - subnets, err = n.CIDRSubnetSizes(-1, network) + subnets, err = n.CIDRSubnetSizes(127, netip.MustParsePrefix("ffff::/48")) + assert.Error(t, err) assert.Nil(t, subnets) + + subnets, err = n.CIDRSubnetSizes(-1, netip.MustParsePrefix("10.1.0.0/16")) assert.Error(t, err) + assert.Nil(t, subnets) + + network := netip.MustParsePrefix("8000::/1") + subnets, err = n.CIDRSubnetSizes(1, 2, 2, network) + require.NoError(t, err) + assert.Len(t, subnets, 3) + assert.Equal(t, "8000::/2", subnets[0].String()) + assert.Equal(t, "c000::/3", subnets[1].String()) + assert.Equal(t, "e000::/3", subnets[2].String()) + network = netip.MustParsePrefix("10.1.0.0/16") subnets, err = n.CIDRSubnetSizes(4, 4, 8, 4, network) - assert.NoError(t, err) + require.NoError(t, err) assert.Len(t, subnets, 4) assert.Equal(t, "10.1.0.0/20", subnets[0].String()) assert.Equal(t, "10.1.16.0/20", subnets[1].String()) assert.Equal(t, "10.1.32.0/24", subnets[2].String()) assert.Equal(t, "10.1.48.0/20", subnets[3].String()) + + network = netip.MustParsePrefix("2016:1234:5678:9abc:ffff:ffff:ffff:cafe/64") + subnets, err = n.CIDRSubnetSizes(2, 2, 3, 3, 6, 6, 8, 10, network) + require.NoError(t, err) + assert.Len(t, subnets, 8) + assert.Equal(t, "2016:1234:5678:9abc::/66", subnets[0].String()) + assert.Equal(t, "2016:1234:5678:9abc:4000::/66", subnets[1].String()) + assert.Equal(t, "2016:1234:5678:9abc:8000::/67", subnets[2].String()) + assert.Equal(t, "2016:1234:5678:9abc:a000::/67", subnets[3].String()) + assert.Equal(t, "2016:1234:5678:9abc:c000::/70", subnets[4].String()) + assert.Equal(t, "2016:1234:5678:9abc:c400::/70", subnets[5].String()) + assert.Equal(t, "2016:1234:5678:9abc:c800::/72", subnets[6].String()) + assert.Equal(t, "2016:1234:5678:9abc:c900::/74", subnets[7].String()) } |
