added tests to verify generation of replies when no ip addresses can be assigned

This commit is contained in:
Dmitri Dolguikh 2017-10-27 16:36:20 -07:00 committed by Dave Anderson
parent 2c6281a8fd
commit a3a8cf5188
3 changed files with 93 additions and 33 deletions

View File

@ -49,31 +49,36 @@ type Options map[uint16][]*Option
func MakeOptions(bs []byte) (Options, error) {
to_ret := make(Options)
for len(bs) > 0 {
optionLength := uint16(binary.BigEndian.Uint16(bs[2:4]))
optionId := uint16(binary.BigEndian.Uint16(bs[0:2]))
switch optionId {
// parse client_id
// parse server_id
//parse ipaddr
case OptOro:
if optionLength% 2 != 0 {
return nil, fmt.Errorf("OptionID request for options (6) length should be even number of bytes: %d", optionLength)
}
default:
if len(bs[4:]) < int(optionLength) {
fmt.Printf("option %d claims to have %d bytes of payload, but only has %d bytes", optionId, optionLength, len(bs[4:]))
return nil, fmt.Errorf("option %d claims to have %d bytes of payload, but only has %d bytes", optionId, optionLength, len(bs[4:]))
}
o, err := UnmarshalOption(bs)
if err != nil {
return nil, err
}
_, present := to_ret[optionId]; if !present {
to_ret[optionId] = make([]*Option, 1)
}
to_ret[optionId] = append(to_ret[optionId], &Option{ Id: optionId, Length: optionLength, Value: bs[4 : 4+optionLength]})
bs = bs[4+optionLength:]
to_ret[o.Id] = append(to_ret[o.Id], &Option{ Id: o.Id, Length: o.Length, Value: bs[4 : 4+o.Length]})
bs = bs[4+o.Length:]
}
return to_ret, nil
}
func UnmarshalOption(bs []byte) (*Option, error) {
optionLength := uint16(binary.BigEndian.Uint16(bs[2:4]))
optionId := uint16(binary.BigEndian.Uint16(bs[0:2]))
switch optionId {
// parse client_id
// parse server_id
//parse ipaddr
case OptOro:
if optionLength% 2 != 0 {
return nil, fmt.Errorf("OptionID request for options (6) length should be even number of bytes: %d", optionLength)
}
default:
if len(bs[4:]) < int(optionLength) {
fmt.Printf("option %d claims to have %d bytes of payload, but only has %d bytes", optionId, optionLength, len(bs[4:]))
return nil, fmt.Errorf("option %d claims to have %d bytes of payload, but only has %d bytes", optionId, optionLength, len(bs[4:]))
}
}
return &Option{ Id: optionId, Length: optionLength, Value: bs[4 : 4+optionLength]}, nil
}
func (o Options) HumanReadable() []string {
to_ret := make([]string, 0, len(o))
for _, multipleOptions := range(o) {
@ -128,13 +133,13 @@ func (o Options) AddOption(option *Option) {
o[option.Id] = append(o[option.Id], option)
}
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaAddr *Option) *Option {
serializedIaAddr, _ := iaAddr.Marshal()
value := make([]byte, 12 + len(serializedIaAddr))
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaOption *Option) *Option {
serializedIaOption, _ := iaOption.Marshal()
value := make([]byte, 12 + len(serializedIaOption))
copy(value[0:], iaid[0:4])
binary.BigEndian.PutUint32(value[4:], t1)
binary.BigEndian.PutUint32(value[8:], t2)
copy(value[12:], serializedIaAddr)
copy(value[12:], serializedIaOption)
return MakeOption(OptIaNa, value)
}
@ -201,7 +206,7 @@ func (o Options) UnmarshalOptionRequestOption() map[uint16]bool {
return to_ret
}
func (o Options) RequestedBootFileUrlOption() bool {
func (o Options) HasBootFileUrlOption() bool {
requested_options := o.UnmarshalOptionRequestOption()
_, present := requested_options[OptBootfileUrl]
return present

View File

@ -86,7 +86,7 @@ func (p *Packet) ShouldDiscard(serverDuid []byte) error {
func ShouldDiscardSolicit(p *Packet) error {
options := p.Options
if !options.RequestedBootFileUrlOption() {
if !options.HasBootFileUrlOption() {
return fmt.Errorf("'Solicit' packet doesn't have file url option")
}
if !options.HasClientId() {
@ -100,7 +100,7 @@ func ShouldDiscardSolicit(p *Packet) error {
func ShouldDiscardRequest(p *Packet, serverDuid []byte) error {
options := p.Options
if !options.RequestedBootFileUrlOption() {
if !options.HasBootFileUrlOption() {
return fmt.Errorf("'Request' packet doesn't have file url option")
}
if !options.HasClientId() {
@ -117,7 +117,7 @@ func ShouldDiscardRequest(p *Packet, serverDuid []byte) error {
func ShouldDiscardInformationRequest(p *Packet, serverDuid []byte) error {
options := p.Options
if !options.RequestedBootFileUrlOption() {
if !options.HasBootFileUrlOption() {
return fmt.Errorf("'Information-request' packet doesn't have boot file url option")
}
if options.HasIaNa() || options.HasIaTa() {

View File

@ -10,7 +10,7 @@ import (
func TestMakeMsgAdvertise(t *testing.T) {
expectedClientId := []byte("clientid")
expectedServerId := []byte("serverid")
expectedInterfaceId := []byte("interfaceid")
expectedInterfaceId := []byte("id-1")
transactionId := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl")
@ -65,7 +65,7 @@ func TestMakeMsgAdvertise(t *testing.T) {
}
func TestShouldSetPreferenceOptionWhenSpecified(t *testing.T) {
identityAssociation := &IdentityAssociation{IpAddress: net.ParseIP("2001:db8:f00f:cafe::1"), InterfaceId: []byte("interfaceid")}
identityAssociation := &IdentityAssociation{IpAddress: net.ParseIP("2001:db8:f00f:cafe::1"), InterfaceId: []byte("id-1")}
builder := MakePacketBuilder([]byte("serverid"), 90, 100, nil,
NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, 100))
@ -89,7 +89,7 @@ func TestMakeMsgAdvertiseWithHttpClientArch(t *testing.T) {
transactionId := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("interfaceid")}
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")}
builder := MakePacketBuilder(expectedServerId, 90, 100, nil,
NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, 100))
@ -162,7 +162,7 @@ func TestMakeMsgReply(t *testing.T) {
transactionId := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("interfaceid")}
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")}
builder := MakePacketBuilder(expectedServerId, 90, 100, nil,
NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, 100))
@ -219,7 +219,7 @@ func TestMakeMsgReplyWithHttpClientArch(t *testing.T) {
transactionId := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("interfaceid")}
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")}
builder := MakePacketBuilder(expectedServerId, 90, 100, nil,
NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, 100))
@ -241,6 +241,61 @@ func TestMakeMsgReplyWithHttpClientArch(t *testing.T) {
}
}
func TestMakeMsgReplyWithNoAddrsAvailable(t *testing.T) {
expectedClientId := []byte("clientid")
expectedServerId := []byte("serverid")
transactionId := [3]byte{'1', '2', '3'}
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
expectedBootFileUrl := []byte("http://bootfileurl")
identityAssociation := &IdentityAssociation{IpAddress: expectedIp, InterfaceId: []byte("id-1")}
expectedErrorMessage := "Boom!"
builder := MakePacketBuilder(expectedServerId, 90, 100, nil,
NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, 100))
msg := builder.MakeMsgReplyWithNoAddrsAvailable(transactionId, expectedClientId, 0x10,
[]*IdentityAssociation{identityAssociation}, [][]byte{[]byte("id-2")}, expectedBootFileUrl,
fmt.Errorf(expectedErrorMessage))
iaNaOption := msg.Options[OptIaNa]
if iaNaOption == nil {
t.Fatalf("interface non-temporary association options should be present")
}
if (len(iaNaOption)) != 2 {
t.Fatalf("Expected 2 identity associations, got %d", len(iaNaOption))
}
var okIaNaOption, failedIaNaOption []byte
if string(iaNaOption[0].Value[0:4]) == string("id-1") {
okIaNaOption = iaNaOption[0].Value
failedIaNaOption = iaNaOption[1].Value
} else {
okIaNaOption = iaNaOption[1].Value
failedIaNaOption = iaNaOption[0].Value
}
possiblyIaAddrOption, err := UnmarshalOption(okIaNaOption[12:])
if err != nil {
t.Fatalf("Failed to unmarshal IaNa options: %s", err)
}
if possiblyIaAddrOption.Id != OptIaAddr {
t.Fatalf("Expected option 5 (ia address), got %d", possiblyIaAddrOption.Id)
}
possiblyStatusOption, err := UnmarshalOption(failedIaNaOption[12:])
if err != nil {
t.Fatalf("Failed to unmarshal IaNa options: %s", err)
}
if possiblyStatusOption.Id != OptStatusCode {
t.Fatalf("Expected option 13 (status code), got %d", possiblyStatusOption.Id)
}
if binary.BigEndian.Uint16(possiblyStatusOption.Value[0:2]) != uint16(2) {
t.Fatalf("Expected status code 2, got %d", binary.BigEndian.Uint16(possiblyStatusOption.Value[0:2]))
}
if string(possiblyStatusOption.Value[2:]) != expectedErrorMessage {
t.Fatalf("Expected message %s, got %s", expectedErrorMessage, string(possiblyStatusOption.Value[2:]))
}
}
func TestMakeMsgInformationRequestReply(t *testing.T) {
expectedClientId := []byte("clientid")
expectedServerId := []byte("serverid")