diff options
author | Anatole Denis <natolumin@unverle.fr> | 2019-11-03 16:46:39 +0100 |
---|---|---|
committer | Anatole Denis <natolumin@unverle.fr> | 2019-11-03 17:00:50 +0100 |
commit | 51aead750bd8a5a9fb757f63d4663ba1b4be9bb6 (patch) | |
tree | 4b7b0a0e634181a8f058dc77f8218f0cf54bdd22 /dhcpv6/option_4rd_test.go | |
parent | 80d8a71da7249766be583e8dd64d3cd566ab86c5 (diff) |
dhcpv6: Add support for 4RD options
IPv4 Residual Deployment (4RD) is a strategy for providing IPv4
connectivity in IPv6-only networks.
The standard includes autoconfiguration via DHCPv6, as described in
RFC7600. This adds support for the 3 options defined in that RFC
Signed-off-by: Anatole Denis <natolumin@unverle.fr>
Diffstat (limited to 'dhcpv6/option_4rd_test.go')
-rw-r--r-- | dhcpv6/option_4rd_test.go | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/dhcpv6/option_4rd_test.go b/dhcpv6/option_4rd_test.go new file mode 100644 index 0000000..1251b13 --- /dev/null +++ b/dhcpv6/option_4rd_test.go @@ -0,0 +1,168 @@ +package dhcpv6 + +import ( + "net" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestOpt4RDNonMapRuleParse(t *testing.T) { + data := []byte{0x81, 0xaa, 0x05, 0xd4} + opt, err := ParseOpt4RDNonMapRule(data) + require.NoError(t, err) + require.True(t, opt.HubAndSpoke) + require.NotNil(t, opt.TrafficClass) + require.EqualValues(t, 0xaa, *opt.TrafficClass) + require.EqualValues(t, 1492, opt.DomainPMTU) + + // Remove the TrafficClass flag and check value is ignored + data[0] = 0x80 + opt, err = ParseOpt4RDNonMapRule(data) + require.NoError(t, err) + require.True(t, opt.HubAndSpoke) + require.Nil(t, opt.TrafficClass) + require.EqualValues(t, 1492, opt.DomainPMTU) +} + +func TestOpt4RDNonMapRuleToBytes(t *testing.T) { + var tClass uint8 = 0xaa + opt := Opt4RDNonMapRule{ + HubAndSpoke: true, + TrafficClass: &tClass, + DomainPMTU: 1492, + } + expected := []byte{0x81, 0xaa, 0x05, 0xd4} + + require.Equal(t, expected, opt.ToBytes()) + + // Unsetting TrafficClass should zero the corresponding bytes in the output + opt.TrafficClass = nil + expected[0], expected[1] = 0x80, 0x00 + + require.Equal(t, expected, opt.ToBytes()) +} + +func TestOpt4RDNonMapRuleString(t *testing.T) { + var tClass uint8 = 120 + opt := Opt4RDNonMapRule{ + HubAndSpoke: true, + TrafficClass: &tClass, + DomainPMTU: 9000, + } + + str := opt.String() + + require.Contains(t, str, "HubAndSpoke=true", + "String() should contain the HubAndSpoke flag value") + require.Contains(t, str, "TrafficClass=120", + "String() should contain the TrafficClass flag value") + require.Contains(t, str, "DomainPMTU=9000", + "String() should contain the domain PMTU") +} + +func TestOpt4RDMapRuleParse(t *testing.T) { + ip6addr, ip6net, err := net.ParseCIDR("2001:db8::1234:5678:0:aabb/64") + ip6net.IP = ip6addr // We want to keep the entire address however, not apply the mask + require.NoError(t, err) + ip4addr, ip4net, err := net.ParseCIDR("100.64.0.234/10") + ip4net.IP = ip4addr.To4() + require.NoError(t, err) + data := append([]byte{ + 10, // IPv4 prefix length + 64, // IPv6 prefix length + 32, // EA-bits + 0x80, // WKPs authorized + }, + append(ip4addr.To4(), ip6addr...)..., + ) + + opt, err := ParseOpt4RDMapRule(data) + require.NoError(t, err) + require.EqualValues(t, *ip6net, opt.Prefix6) + require.EqualValues(t, *ip4net, opt.Prefix4) + require.EqualValues(t, 32, opt.EABitsLength) + require.True(t, opt.WKPAuthorized) +} + +func TestOpt4RDMapRuleToBytes(t *testing.T) { + opt := Opt4RDMapRule{ + Prefix4: net.IPNet{ + IP: net.IPv4(100, 64, 0, 238), + Mask: net.CIDRMask(24, 32), + }, + Prefix6: net.IPNet{ + IP: net.ParseIP("2001:db8::1234:5678:0:aabb"), + Mask: net.CIDRMask(80, 128), + }, + EABitsLength: 32, + WKPAuthorized: true, + } + + expected := append([]byte{ + 24, // v4 prefix length + 80, // v6 prefix length + 32, // EA-bits + 0x80, // WKPs authorized + }, + append(opt.Prefix4.IP.To4(), opt.Prefix6.IP.To16()...)..., + ) + + require.Equal(t, expected, opt.ToBytes()) +} + +// FIXME: Invalid packets are serialized without error + +func TestOpt4RDMapRuleString(t *testing.T) { + opt := Opt4RDMapRule{ + Prefix4: net.IPNet{ + IP: net.IPv4(100, 64, 0, 238), + Mask: net.CIDRMask(24, 32), + }, + Prefix6: net.IPNet{ + IP: net.ParseIP("2001:db8::1234:5678:0:aabb"), + Mask: net.CIDRMask(80, 128), + }, + EABitsLength: 32, + WKPAuthorized: true, + } + + str := opt.String() + require.Contains(t, str, "WKPAuthorized=true", "String() should write the flag values") + require.Contains(t, str, "Prefix6=2001:db8::1234:5678:0:aabb/80", + "String() should include the IPv6 prefix") + require.Contains(t, str, "Prefix4=100.64.0.238/24", + "String() should include the IPv4 prefix") + require.Contains(t, str, "EA-Bits=32", "String() should include the value for EA-Bits") +} + +// This test round-trip serialization/deserialization of both kinds of 4RD +// options, and the container option +func TestOpt4RDRoundTrip(t *testing.T) { + var tClass uint8 = 0xaa + opt := Opt4RD{ + &Opt4RDMapRule{ + Prefix4: net.IPNet{ + IP: net.IPv4(100, 64, 0, 238).To4(), + Mask: net.CIDRMask(24, 32), + }, + Prefix6: net.IPNet{ + IP: net.ParseIP("2001:db8::1234:5678:0:aabb"), + Mask: net.CIDRMask(80, 128), + }, + EABitsLength: 32, + WKPAuthorized: true, + }, + &Opt4RDNonMapRule{ + HubAndSpoke: true, + TrafficClass: &tClass, + DomainPMTU: 9000, + }, + } + + rtOpt, err := ParseOpt4RD(opt.ToBytes()) + + require.NoError(t, err) + require.NotNil(t, rtOpt) + require.Equal(t, opt, *rtOpt) +} |