mirror of
https://github.com/danderson/netboot.git
synced 2025-10-18 02:51:22 +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) {
|
func MakeOptions(bs []byte) (Options, error) {
|
||||||
to_ret := make(Options)
|
to_ret := make(Options)
|
||||||
for len(bs) > 0 {
|
for len(bs) > 0 {
|
||||||
optionLength := uint16(binary.BigEndian.Uint16(bs[2:4]))
|
o, err := UnmarshalOption(bs)
|
||||||
optionId := uint16(binary.BigEndian.Uint16(bs[0:2]))
|
if err != nil {
|
||||||
switch optionId {
|
return nil, err
|
||||||
// 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:]))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_, present := to_ret[optionId]; if !present {
|
to_ret[o.Id] = append(to_ret[o.Id], &Option{ Id: o.Id, Length: o.Length, Value: bs[4 : 4+o.Length]})
|
||||||
to_ret[optionId] = make([]*Option, 1)
|
bs = bs[4+o.Length:]
|
||||||
}
|
|
||||||
to_ret[optionId] = append(to_ret[optionId], &Option{ Id: optionId, Length: optionLength, Value: bs[4 : 4+optionLength]})
|
|
||||||
bs = bs[4+optionLength:]
|
|
||||||
}
|
}
|
||||||
return to_ret, nil
|
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 {
|
func (o Options) HumanReadable() []string {
|
||||||
to_ret := make([]string, 0, len(o))
|
to_ret := make([]string, 0, len(o))
|
||||||
for _, multipleOptions := range(o) {
|
for _, multipleOptions := range(o) {
|
||||||
@ -128,13 +133,13 @@ func (o Options) AddOption(option *Option) {
|
|||||||
o[option.Id] = append(o[option.Id], option)
|
o[option.Id] = append(o[option.Id], option)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaAddr *Option) *Option {
|
func MakeIaNaOption(iaid []byte, t1, t2 uint32, iaOption *Option) *Option {
|
||||||
serializedIaAddr, _ := iaAddr.Marshal()
|
serializedIaOption, _ := iaOption.Marshal()
|
||||||
value := make([]byte, 12 + len(serializedIaAddr))
|
value := make([]byte, 12 + len(serializedIaOption))
|
||||||
copy(value[0:], iaid[0:4])
|
copy(value[0:], iaid[0:4])
|
||||||
binary.BigEndian.PutUint32(value[4:], t1)
|
binary.BigEndian.PutUint32(value[4:], t1)
|
||||||
binary.BigEndian.PutUint32(value[8:], t2)
|
binary.BigEndian.PutUint32(value[8:], t2)
|
||||||
copy(value[12:], serializedIaAddr)
|
copy(value[12:], serializedIaOption)
|
||||||
return MakeOption(OptIaNa, value)
|
return MakeOption(OptIaNa, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +206,7 @@ func (o Options) UnmarshalOptionRequestOption() map[uint16]bool {
|
|||||||
return to_ret
|
return to_ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Options) RequestedBootFileUrlOption() bool {
|
func (o Options) HasBootFileUrlOption() bool {
|
||||||
requested_options := o.UnmarshalOptionRequestOption()
|
requested_options := o.UnmarshalOptionRequestOption()
|
||||||
_, present := requested_options[OptBootfileUrl]
|
_, present := requested_options[OptBootfileUrl]
|
||||||
return present
|
return present
|
||||||
|
@ -86,7 +86,7 @@ func (p *Packet) ShouldDiscard(serverDuid []byte) error {
|
|||||||
|
|
||||||
func ShouldDiscardSolicit(p *Packet) error {
|
func ShouldDiscardSolicit(p *Packet) error {
|
||||||
options := p.Options
|
options := p.Options
|
||||||
if !options.RequestedBootFileUrlOption() {
|
if !options.HasBootFileUrlOption() {
|
||||||
return fmt.Errorf("'Solicit' packet doesn't have file url option")
|
return fmt.Errorf("'Solicit' packet doesn't have file url option")
|
||||||
}
|
}
|
||||||
if !options.HasClientId() {
|
if !options.HasClientId() {
|
||||||
@ -100,7 +100,7 @@ func ShouldDiscardSolicit(p *Packet) error {
|
|||||||
|
|
||||||
func ShouldDiscardRequest(p *Packet, serverDuid []byte) error {
|
func ShouldDiscardRequest(p *Packet, serverDuid []byte) error {
|
||||||
options := p.Options
|
options := p.Options
|
||||||
if !options.RequestedBootFileUrlOption() {
|
if !options.HasBootFileUrlOption() {
|
||||||
return fmt.Errorf("'Request' packet doesn't have file url option")
|
return fmt.Errorf("'Request' packet doesn't have file url option")
|
||||||
}
|
}
|
||||||
if !options.HasClientId() {
|
if !options.HasClientId() {
|
||||||
@ -117,7 +117,7 @@ func ShouldDiscardRequest(p *Packet, serverDuid []byte) error {
|
|||||||
|
|
||||||
func ShouldDiscardInformationRequest(p *Packet, serverDuid []byte) error {
|
func ShouldDiscardInformationRequest(p *Packet, serverDuid []byte) error {
|
||||||
options := p.Options
|
options := p.Options
|
||||||
if !options.RequestedBootFileUrlOption() {
|
if !options.HasBootFileUrlOption() {
|
||||||
return fmt.Errorf("'Information-request' packet doesn't have boot file url option")
|
return fmt.Errorf("'Information-request' packet doesn't have boot file url option")
|
||||||
}
|
}
|
||||||
if options.HasIaNa() || options.HasIaTa() {
|
if options.HasIaNa() || options.HasIaTa() {
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
func TestMakeMsgAdvertise(t *testing.T) {
|
func TestMakeMsgAdvertise(t *testing.T) {
|
||||||
expectedClientId := []byte("clientid")
|
expectedClientId := []byte("clientid")
|
||||||
expectedServerId := []byte("serverid")
|
expectedServerId := []byte("serverid")
|
||||||
expectedInterfaceId := []byte("interfaceid")
|
expectedInterfaceId := []byte("id-1")
|
||||||
transactionId := [3]byte{'1', '2', '3'}
|
transactionId := [3]byte{'1', '2', '3'}
|
||||||
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
||||||
expectedBootFileUrl := []byte("http://bootfileurl")
|
expectedBootFileUrl := []byte("http://bootfileurl")
|
||||||
@ -65,7 +65,7 @@ func TestMakeMsgAdvertise(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldSetPreferenceOptionWhenSpecified(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,
|
builder := MakePacketBuilder([]byte("serverid"), 90, 100, nil,
|
||||||
NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, 100))
|
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'}
|
transactionId := [3]byte{'1', '2', '3'}
|
||||||
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
||||||
expectedBootFileUrl := []byte("http://bootfileurl")
|
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,
|
builder := MakePacketBuilder(expectedServerId, 90, 100, nil,
|
||||||
NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, 100))
|
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'}
|
transactionId := [3]byte{'1', '2', '3'}
|
||||||
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
||||||
expectedBootFileUrl := []byte("http://bootfileurl")
|
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,
|
builder := MakePacketBuilder(expectedServerId, 90, 100, nil,
|
||||||
NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, 100))
|
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'}
|
transactionId := [3]byte{'1', '2', '3'}
|
||||||
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
expectedIp := net.ParseIP("2001:db8:f00f:cafe::1")
|
||||||
expectedBootFileUrl := []byte("http://bootfileurl")
|
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,
|
builder := MakePacketBuilder(expectedServerId, 90, 100, nil,
|
||||||
NewRandomAddressPool(net.ParseIP("2001:db8:f00f:cafe::1"), 1, 100))
|
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) {
|
func TestMakeMsgInformationRequestReply(t *testing.T) {
|
||||||
expectedClientId := []byte("clientid")
|
expectedClientId := []byte("clientid")
|
||||||
expectedServerId := []byte("serverid")
|
expectedServerId := []byte("serverid")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user