Created
June 24, 2022 21:12
-
-
Save tklauser/68e341befa2066b6fb5b59a0dda3669f to your computer and use it in GitHub Desktop.
net/netip <-> net conversion helpers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Package netconv provides utilities to convert between types in packages net | |
// and netip. | |
package netconv | |
import ( | |
"net" | |
"net/netip" | |
) | |
// PrefixToIPNet returns p as a *net.IPNet. | |
// TODO: special cases | |
func PrefixToIPNet(p netip.Prefix) *net.IPNet { | |
if !p.IsValid() { | |
return nil | |
} | |
addr := p.Masked().Addr() | |
return &net.IPNet{ | |
IP: addr.AsSlice(), | |
Mask: net.CIDRMask(p.Bits(), addr.BitLen()), | |
} | |
} | |
// IPNetToPrefix return n as a netip.Prefix. | |
// TODO: special cases | |
func IPNetToPrefix(n *net.IPNet) netip.Prefix { | |
if n == nil { | |
return netip.Prefix{} | |
} | |
ones, bits := n.Mask.Size() | |
if bits != net.IPv4len*8 && bits != net.IPv6len*8 { | |
// invalid mask | |
return netip.Prefix{} | |
} | |
ip, ok := netip.AddrFromSlice(n.IP) | |
if !ok { | |
return netip.Prefix{} | |
} | |
return netip.PrefixFrom(ip, ones) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package netconv_test | |
import ( | |
"net" | |
"net/netip" | |
"reflect" | |
"testing" | |
"github.com/tklauser/netconv" | |
) | |
func mustParseCIDR(s string) *net.IPNet { | |
_, net, err := net.ParseCIDR(s) | |
if err != nil { | |
panic(err) | |
} | |
return net | |
} | |
func TestPrefixToIPNet(t *testing.T) { | |
tests := []struct { | |
prefix netip.Prefix | |
net *net.IPNet | |
}{ | |
{ | |
prefix: netip.MustParsePrefix("0.0.0.0/24"), | |
net: &net.IPNet{ | |
IP: net.IPv4(0, 0, 0, 0).To4(), | |
Mask: net.IPv4Mask(255, 255, 255, 0), | |
}, | |
}, | |
{ | |
prefix: netip.MustParsePrefix("0.0.0.0/0"), | |
net: mustParseCIDR("0.0.0.0/0"), | |
}, | |
{ | |
prefix: netip.MustParsePrefix("10.0.0.1/32"), | |
net: &net.IPNet{ | |
IP: net.IPv4(10, 0, 0, 1).To4(), | |
Mask: net.IPv4Mask(255, 255, 255, 255), | |
}, | |
}, | |
{ | |
prefix: netip.MustParsePrefix("10.0.128.0/18"), | |
net: mustParseCIDR("10.0.129.1/18"), | |
}, | |
{ | |
prefix: netip.MustParsePrefix("::1/128"), | |
net: &net.IPNet{ | |
IP: net.ParseIP("::1"), | |
Mask: net.CIDRMask(128, 128), | |
}, | |
}, | |
{ | |
prefix: netip.MustParsePrefix("fd00::1/96"), | |
net: &net.IPNet{ | |
IP: net.ParseIP("fd00::0"), | |
Mask: net.CIDRMask(96, 128), | |
}, | |
}, | |
{ | |
prefix: netip.Prefix{}, | |
net: nil, | |
}, | |
} | |
for _, tc := range tests { | |
net := netconv.PrefixToIPNet(tc.prefix) | |
if !reflect.DeepEqual(net, tc.net) { | |
t.Errorf("PrefixToIPNet(%q)\n"+ | |
" got %#v\n"+ | |
" want %#v", tc.prefix, net, tc.net) | |
} | |
} | |
} | |
func TestIPNetToPrefix(t *testing.T) { | |
tests := []struct { | |
net *net.IPNet | |
prefix netip.Prefix | |
}{ | |
{ | |
net: mustParseCIDR("0.0.0.0/24"), | |
prefix: netip.MustParsePrefix("0.0.0.0/24"), | |
}, | |
{ | |
net: mustParseCIDR("0.0.0.0/0"), | |
prefix: netip.MustParsePrefix("0.0.0.0/0"), | |
}, | |
{ | |
net: mustParseCIDR("10.0.129.1/18"), | |
prefix: netip.MustParsePrefix("10.0.128.0/18"), | |
}, | |
{ | |
net: &net.IPNet{ | |
IP: net.IPv4(0, 0, 0, 0).To4(), | |
Mask: net.IPv4Mask(255, 255, 255, 0), | |
}, | |
prefix: netip.MustParsePrefix("0.0.0.0/24"), | |
}, | |
{ | |
net: &net.IPNet{ | |
IP: net.IPv4(0, 0, 0, 0), | |
Mask: net.IPv4Mask(255, 255, 255, 255), | |
}, | |
prefix: netip.MustParsePrefix("0.0.0.0/32"), | |
}, | |
{ | |
// invalid IP | |
net: &net.IPNet{ | |
IP: net.IP{1, 2}, | |
Mask: net.IPv4Mask(255, 255, 255, 255), | |
}, | |
prefix: netip.Prefix{}, | |
}, | |
{ | |
// invalid mask | |
net: &net.IPNet{ | |
IP: net.IPv4(10, 0, 0, 1), | |
}, | |
prefix: netip.Prefix{}, | |
}, | |
{ | |
// non-contiguous mask | |
net: &net.IPNet{ | |
IP: net.IPv4(10, 0, 0, 1), | |
Mask: net.IPv4Mask(255, 3, 255, 0), | |
}, | |
prefix: netip.Prefix{}, | |
}, | |
{ | |
net: nil, | |
prefix: netip.Prefix{}, | |
}, | |
} | |
for _, tc := range tests { | |
prefix := netconv.IPNetToPrefix(tc.net) | |
if !reflect.DeepEqual(prefix, tc.prefix) { | |
t.Errorf("IPNetToPrefix(%q)\n"+ | |
" got %v\n"+ | |
" want %v", tc.net, prefix, tc.prefix) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment