From 43551d9de3015a128c9297e2a753e3f68898c5f8 Mon Sep 17 00:00:00 2001 From: Dmitri Dolguikh Date: Tue, 31 Oct 2017 14:19:55 -0700 Subject: [PATCH] Fixed a bug around setting of server duid --- dhcp6/conn.go | 4 +-- dhcp6/packet_builder.go | 37 ++++++++++---------- dhcp6/packet_builder_test.go | 65 ++++++++++++++++++------------------ pixiecore/cli/bootipv6cmd.go | 2 +- pixiecore/cli/ipv6apicmd.go | 2 +- pixiecorev6/dhcpv6.go | 2 +- 6 files changed, 55 insertions(+), 57 deletions(-) diff --git a/dhcp6/conn.go b/dhcp6/conn.go index c4ee009..ab1386a 100644 --- a/dhcp6/conn.go +++ b/dhcp6/conn.go @@ -25,7 +25,7 @@ type Conn struct { } func NewConn(addr, port string) (*Conn, error) { - ifi, err := InterfaceIndexByAddress(addr) + ifi, err := InterfaceByAddress(addr) if err != nil { return nil, err } @@ -59,7 +59,7 @@ func (c *Conn) Close() error { return c.conn.Close() } -func InterfaceIndexByAddress(ifAddr string) (*net.Interface, error) { +func InterfaceByAddress(ifAddr string) (*net.Interface, error) { allIfis, err := net.Interfaces() if err != nil { return nil, fmt.Errorf("Error getting network interface information: %s", err) diff --git a/dhcp6/packet_builder.go b/dhcp6/packet_builder.go index 0928e2c..044b819 100644 --- a/dhcp6/packet_builder.go +++ b/dhcp6/packet_builder.go @@ -7,16 +7,15 @@ import ( ) type PacketBuilder struct { - ServerDuid []byte PreferredLifetime uint32 ValidLifetime uint32 } -func MakePacketBuilder(serverDuid []byte, preferredLifetime, validLifetime uint32) *PacketBuilder { - return &PacketBuilder{ServerDuid: serverDuid, PreferredLifetime: preferredLifetime, ValidLifetime: validLifetime} +func MakePacketBuilder(preferredLifetime, validLifetime uint32) *PacketBuilder { + return &PacketBuilder{PreferredLifetime: preferredLifetime, ValidLifetime: validLifetime} } -func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguration, addresses AddressPool) (*Packet, error) { +func (b *PacketBuilder) BuildResponse(in *Packet, serverDuid []byte, configuration BootConfiguration, addresses AddressPool) (*Packet, error) { switch in.Type { case MsgSolicit: bootFileUrl, err := configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType()) @@ -25,9 +24,9 @@ func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguratio } associations, err := addresses.ReserveAddresses(in.Options.ClientId(), in.Options.IaNaIds()) if err != nil { - return b.MakeMsgAdvertiseWithNoAddrsAvailable(in.TransactionID, in.Options.ClientId(), err), err + return b.MakeMsgAdvertiseWithNoAddrsAvailable(in.TransactionID, serverDuid, in.Options.ClientId(), err), err } - return b.MakeMsgAdvertise(in.TransactionID, in.Options.ClientId(), + return b.MakeMsgAdvertise(in.TransactionID, serverDuid, in.Options.ClientId(), in.Options.ClientArchType(), associations, bootFileUrl, configuration.GetPreference(), configuration.GetRecursiveDns()), nil case MsgRequest: bootFileUrl, err := configuration.GetBootUrl(b.ExtractLLAddressOrId(in.Options.ClientId()), in.Options.ClientArchType()) @@ -35,7 +34,7 @@ func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguratio return nil, err } associations, err := addresses.ReserveAddresses(in.Options.ClientId(), in.Options.IaNaIds()) - return b.MakeMsgReply(in.TransactionID, in.Options.ClientId(), + return b.MakeMsgReply(in.TransactionID, serverDuid, in.Options.ClientId(), in.Options.ClientArchType(), associations, iasWithoutAddesses(associations, in.Options.IaNaIds()), bootFileUrl, configuration.GetRecursiveDns(), err), err case MsgInformationRequest: @@ -43,17 +42,17 @@ func (b *PacketBuilder) BuildResponse(in *Packet, configuration BootConfiguratio if err != nil { return nil, err } - return b.MakeMsgInformationRequestReply(in.TransactionID, in.Options.ClientId(), + return b.MakeMsgInformationRequestReply(in.TransactionID, serverDuid, in.Options.ClientId(), in.Options.ClientArchType(), bootFileUrl, configuration.GetRecursiveDns()), nil case MsgRelease: addresses.ReleaseAddresses(in.Options.ClientId(), in.Options.IaNaIds()) - return b.MakeMsgReleaseReply(in.TransactionID, in.Options.ClientId()), nil + return b.MakeMsgReleaseReply(in.TransactionID, serverDuid, in.Options.ClientId()), nil default: return nil, nil } } -func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId []byte, clientArchType uint16, +func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, serverDuid, clientId []byte, clientArchType uint16, associations []*IdentityAssociation, bootFileUrl, preference []byte, dnsServers []net.IP) *Packet { ret_options := make(Options) ret_options.AddOption(MakeOption(OptClientId, clientId)) @@ -61,7 +60,7 @@ func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId []byte, ret_options.AddOption(MakeIaNaOption(association.InterfaceId, b.calculateT1(), b.calculateT2(), MakeIaAddrOption(association.IpAddress, b.PreferredLifetime, b.ValidLifetime))) } - ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid)) + ret_options.AddOption(MakeOption(OptServerId, serverDuid)) if 0x10 == clientArchType { // HTTPClient ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient } @@ -72,7 +71,7 @@ func (b *PacketBuilder) MakeMsgAdvertise(transactionId [3]byte, clientId []byte, return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options} } -func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId []byte, clientArchType uint16, +func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, serverDuid, clientId []byte, clientArchType uint16, associations []*IdentityAssociation, iasWithoutAddresses [][]byte, bootFileUrl []byte, dnsServers []net.IP, err error) *Packet { ret_options := make(Options) ret_options.AddOption(MakeOption(OptClientId, clientId)) @@ -84,7 +83,7 @@ func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId []byte, cli ret_options.AddOption(MakeIaNaOption(ia, b.calculateT1(), b.calculateT2(), MakeStatusOption(2, err.Error()))) } - ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid)) + ret_options.AddOption(MakeOption(OptServerId, serverDuid)) if 0x10 == clientArchType { // HTTPClient ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient } @@ -94,11 +93,11 @@ func (b *PacketBuilder) MakeMsgReply(transactionId [3]byte, clientId []byte, cli return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options} } -func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionId [3]byte, clientId []byte, clientArchType uint16, +func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionId [3]byte, serverDuid, clientId []byte, clientArchType uint16, bootFileUrl []byte, dnsServers []net.IP) *Packet { ret_options := make(Options) ret_options.AddOption(MakeOption(OptClientId, clientId)) - ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid)) + ret_options.AddOption(MakeOption(OptServerId, serverDuid)) if 0x10 == clientArchType { // HTTPClient ret_options.AddOption(MakeOption(OptVendorClass, []byte {0, 0, 0, 0, 0, 10, 72, 84, 84, 80, 67, 108, 105, 101, 110, 116})) // HTTPClient } @@ -108,11 +107,11 @@ func (b *PacketBuilder) MakeMsgInformationRequestReply(transactionId [3]byte, cl return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options} } -func (b *PacketBuilder) MakeMsgReleaseReply(transactionId [3]byte, clientId []byte) *Packet { +func (b *PacketBuilder) MakeMsgReleaseReply(transactionId [3]byte, serverDuid, clientId []byte) *Packet { ret_options := make(Options) ret_options.AddOption(MakeOption(OptClientId, clientId)) - ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid)) + ret_options.AddOption(MakeOption(OptServerId, serverDuid)) v := make([]byte, 19, 19) copy(v[2:], []byte("Release received.")) ret_options.AddOption(MakeOption(OptStatusCode, v)) @@ -120,10 +119,10 @@ func (b *PacketBuilder) MakeMsgReleaseReply(transactionId [3]byte, clientId []by return &Packet{Type: MsgReply, TransactionID: transactionId, Options: ret_options} } -func (b *PacketBuilder) MakeMsgAdvertiseWithNoAddrsAvailable(transactionId [3]byte, clientId []byte, err error) *Packet { +func (b *PacketBuilder) MakeMsgAdvertiseWithNoAddrsAvailable(transactionId [3]byte, serverDuid, clientId []byte, err error) *Packet { ret_options := make(Options) ret_options.AddOption(MakeOption(OptClientId, clientId)) - ret_options.AddOption(MakeOption(OptServerId, b.ServerDuid)) + ret_options.AddOption(MakeOption(OptServerId, serverDuid)) ret_options.AddOption(MakeStatusOption(2, err.Error())) // NoAddrAvailable return &Packet{Type: MsgAdvertise, TransactionID: transactionId, Options: ret_options} } diff --git a/dhcp6/packet_builder_test.go b/dhcp6/packet_builder_test.go index f1423ab..1f7e6f1 100644 --- a/dhcp6/packet_builder_test.go +++ b/dhcp6/packet_builder_test.go @@ -17,10 +17,10 @@ func TestMakeMsgAdvertise(t *testing.T) { expectedDnsServerIp := net.ParseIP("2001:db8:f00f:cafe::99") identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: expectedInterfaceId} - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgAdvertise(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation}, - expectedBootFileUrl, nil, []net.IP{expectedDnsServerIp}) + msg := builder.MakeMsgAdvertise(transactionId, expectedServerId, expectedClientId, 0x11, + []*IdentityAssociation{identityAssociation}, expectedBootFileUrl, nil, []net.IP{expectedDnsServerIp}) if msg.Type != MsgAdvertise { t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type) @@ -81,10 +81,10 @@ func TestMakeMsgAdvertiseShouldSkipDnsServersIfNoneConfigured(t *testing.T) { expectedBootFileUrl := []byte("http://bootfileurl") identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: expectedInterfaceId} - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgAdvertise(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation}, - expectedBootFileUrl, nil, []net.IP{}) + msg := builder.MakeMsgAdvertise(transactionId, expectedServerId, expectedClientId, 0x11, + []*IdentityAssociation{identityAssociation}, expectedBootFileUrl, nil, []net.IP{}) _, exists := msg.Options[OptRecursiveDns]; if exists { t.Fatalf("DNS servers option should not be set") @@ -94,10 +94,10 @@ func TestMakeMsgAdvertiseShouldSkipDnsServersIfNoneConfigured(t *testing.T) { func TestShouldSetPreferenceOptionWhenSpecified(t *testing.T) { identityAssociation := &IdentityAssociation{IpAddress: net.ParseIP("2001:db8:f00f:cafe::1"), InterfaceId: []byte("id-1")} - builder := MakePacketBuilder([]byte("serverid"), 90, 100) + builder := MakePacketBuilder(90, 100) expectedPreference := []byte{128} - msg := builder.MakeMsgAdvertise([3]byte{'t', 'i', 'd'}, []byte("clientid"), 0x11, + msg := builder.MakeMsgAdvertise([3]byte{'t', 'i', 'd'}, []byte("serverid"), []byte("clientid"), 0x11, []*IdentityAssociation{identityAssociation}, []byte("http://bootfileurl"), expectedPreference, []net.IP{}) preferenceOption := msg.Options[OptPreference] @@ -117,10 +117,10 @@ func TestMakeMsgAdvertiseWithHttpClientArch(t *testing.T) { expectedBootFileUrl := []byte("http://bootfileurl") identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgAdvertise(transactionId, expectedClientId, 0x10, []*IdentityAssociation{identityAssociation}, - expectedBootFileUrl, nil, []net.IP{}) + msg := builder.MakeMsgAdvertise(transactionId, expectedServerId, expectedClientId, 0x10, + []*IdentityAssociation{identityAssociation}, expectedBootFileUrl, nil, []net.IP{}) vendorClassOption := msg.Options[OptVendorClass] if vendorClassOption == nil { @@ -141,9 +141,9 @@ func TestMakeNoAddrsAvailable(t *testing.T) { transactionId := [3]byte{'1', '2', '3'} expectedMessage := "Boom!" - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgAdvertiseWithNoAddrsAvailable(transactionId, expectedClientId, fmt.Errorf(expectedMessage)) + msg := builder.MakeMsgAdvertiseWithNoAddrsAvailable(transactionId, expectedServerId, expectedClientId, fmt.Errorf(expectedMessage)) if msg.Type != MsgAdvertise { t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type) @@ -189,10 +189,10 @@ func TestMakeMsgReply(t *testing.T) { expectedDnsServerIp := net.ParseIP("2001:db8:f00f:cafe::99") identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation}, - make([][]byte, 0), expectedBootFileUrl, []net.IP{expectedDnsServerIp}, nil) + msg := builder.MakeMsgReply(transactionId, expectedServerId, expectedClientId, 0x11, + []*IdentityAssociation{identityAssociation}, make([][]byte, 0), expectedBootFileUrl, []net.IP{expectedDnsServerIp}, nil) if msg.Type != MsgReply { t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type) @@ -253,10 +253,10 @@ func TestMakeMsgReplyShouldSkipDnsServersIfNoneWereConfigured(t *testing.T) { expectedBootFileUrl := []byte("http://bootfileurl") identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x11, []*IdentityAssociation{identityAssociation}, - make([][]byte, 0), expectedBootFileUrl, []net.IP{}, nil) + msg := builder.MakeMsgReply(transactionId, expectedServerId, expectedClientId, 0x11, + []*IdentityAssociation{identityAssociation}, make([][]byte, 0), expectedBootFileUrl, []net.IP{}, nil) _, exists := msg.Options[OptRecursiveDns]; if exists { t.Fatalf("Dns servers option shouldn't be present") @@ -271,11 +271,10 @@ func TestMakeMsgReplyWithHttpClientArch(t *testing.T) { expectedBootFileUrl := []byte("http://bootfileurl") identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x10, - []*IdentityAssociation{identityAssociation}, make([][]byte, 0), - expectedBootFileUrl, []net.IP{}, nil) + msg := builder.MakeMsgReply(transactionId, expectedServerId, expectedClientId, 0x10, + []*IdentityAssociation{identityAssociation}, make([][]byte, 0), expectedBootFileUrl, []net.IP{}, nil) vendorClassOption := msg.Options[OptVendorClass] if vendorClassOption == nil { @@ -300,9 +299,9 @@ func TestMakeMsgReplyWithNoAddrsAvailable(t *testing.T) { identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")} expectedErrorMessage := "Boom!" - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgReply(transactionId, expectedClientId, 0x10, + msg := builder.MakeMsgReply(transactionId, expectedServerId, expectedClientId, 0x10, []*IdentityAssociation{identityAssociation}, [][]byte{[]byte("id-2")}, expectedBootFileUrl, []net.IP{}, fmt.Errorf(expectedErrorMessage)) @@ -352,9 +351,9 @@ func TestMakeMsgInformationRequestReply(t *testing.T) { expectedBootFileUrl := []byte("http://bootfileurl") expectedDnsServerIp := net.ParseIP("2001:db8:f00f:cafe::99") - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x11, + msg := builder.MakeMsgInformationRequestReply(transactionId, expectedServerId, expectedClientId, 0x11, expectedBootFileUrl, []net.IP{expectedDnsServerIp}) if msg.Type != MsgReply { @@ -409,9 +408,9 @@ func TestMakeMsgInformationRequestReplyShouldSkipDnsServersIfNoneWereConfigured( transactionId := [3]byte{'1', '2', '3'} expectedBootFileUrl := []byte("http://bootfileurl") - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x11, + msg := builder.MakeMsgInformationRequestReply(transactionId, expectedServerId, expectedClientId, 0x11, expectedBootFileUrl, []net.IP{}) _, exists := msg.Options[OptRecursiveDns]; if exists { @@ -425,9 +424,9 @@ func TestMakeMsgInformationRequestReplyWithHttpClientArch(t *testing.T) { transactionId := [3]byte{'1', '2', '3'} expectedBootFileUrl := []byte("http://bootfileurl") - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgInformationRequestReply(transactionId, expectedClientId, 0x10, + msg := builder.MakeMsgInformationRequestReply(transactionId, expectedServerId, expectedClientId, 0x10, expectedBootFileUrl, []net.IP{}) vendorClassOption := msg.Options[OptVendorClass] @@ -449,9 +448,9 @@ func TestMakeMsgReleaseReply(t *testing.T) { expectedServerId := []byte("serverid") transactionId := [3]byte{'1', '2', '3'} - builder := MakePacketBuilder(expectedServerId, 90, 100) + builder := MakePacketBuilder(90, 100) - msg := builder.MakeMsgReleaseReply(transactionId, expectedClientId) + msg := builder.MakeMsgReleaseReply(transactionId, expectedServerId, expectedClientId) if msg.Type != MsgReply { t.Fatalf("Expected message type %d, got %d", MsgAdvertise, msg.Type) diff --git a/pixiecore/cli/bootipv6cmd.go b/pixiecore/cli/bootipv6cmd.go index 6cc1803..f87755a 100644 --- a/pixiecore/cli/bootipv6cmd.go +++ b/pixiecore/cli/bootipv6cmd.go @@ -78,7 +78,7 @@ var bootIPv6Cmd = &cobra.Command{ fatalf("Error reading flag: %s", err) } s.AddressPool = dhcp6.NewRandomAddressPool(net.ParseIP(addressPoolStart), addressPoolSize, addressPoolValidLifetime) - s.PacketBuilder = dhcp6.MakePacketBuilder(s.Duid, addressPoolValidLifetime - addressPoolValidLifetime*3/100, addressPoolValidLifetime) + s.PacketBuilder = dhcp6.MakePacketBuilder(addressPoolValidLifetime - addressPoolValidLifetime*3/100, addressPoolValidLifetime) fmt.Println(s.Serve()) }, diff --git a/pixiecore/cli/ipv6apicmd.go b/pixiecore/cli/ipv6apicmd.go index c0370a6..1f1ed84 100644 --- a/pixiecore/cli/ipv6apicmd.go +++ b/pixiecore/cli/ipv6apicmd.go @@ -75,7 +75,7 @@ var ipv6ApiCmd = &cobra.Command{ fatalf("Error reading flag: %s", err) } s.AddressPool = dhcp6.NewRandomAddressPool(net.ParseIP(addressPoolStart), addressPoolSize, addressPoolValidLifetime) - s.PacketBuilder = dhcp6.MakePacketBuilder(s.Duid, addressPoolValidLifetime - addressPoolValidLifetime*3/100, addressPoolValidLifetime) + s.PacketBuilder = dhcp6.MakePacketBuilder(addressPoolValidLifetime - addressPoolValidLifetime*3/100, addressPoolValidLifetime) fmt.Println(s.Serve()) }, diff --git a/pixiecorev6/dhcpv6.go b/pixiecorev6/dhcpv6.go index 5e51e0b..80c939b 100644 --- a/pixiecorev6/dhcpv6.go +++ b/pixiecorev6/dhcpv6.go @@ -19,7 +19,7 @@ func (s *ServerV6) serveDHCP(conn *dhcp6.Conn) error { s.debug("dhcpv6", fmt.Sprintf("Received (%d) packet (%d): %s\n", pkt.Type, pkt.TransactionID, pkt.Options.HumanReadable())) - response, err := s.PacketBuilder.BuildResponse(pkt, s.BootConfig, s.AddressPool) + response, err := s.PacketBuilder.BuildResponse(pkt, s.Duid, s.BootConfig, s.AddressPool) if err != nil { s.log("dhcpv6", fmt.Sprintf("Error creating response for transaction: %d: %s", pkt.TransactionID, err)) if response == nil {