mirror of
https://github.com/danderson/netboot.git
synced 2025-10-16 18:11:21 +02:00
added tests to verify generation of replies when no ip addresses can be assigned
This commit is contained in:
parent
2c6281a8fd
commit
a3a8cf5188
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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")
|
||||
|
Loading…
x
Reference in New Issue
Block a user