From 1cc89131993b14e10204f15d92c7fd74ef20d3bd Mon Sep 17 00:00:00 2001 From: Andrea Barberio Date: Sat, 17 Mar 2018 12:21:03 -0700 Subject: Added OptionBroadcastAddress --- dhcpv4/option_broadcast_address.go | 56 +++++++++++++++++++++++++++++++++ dhcpv4/option_broadcast_address_test.go | 44 ++++++++++++++++++++++++++ dhcpv4/option_server_identifier_test.go | 8 ++--- dhcpv4/options.go | 2 ++ 4 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 dhcpv4/option_broadcast_address.go create mode 100644 dhcpv4/option_broadcast_address_test.go diff --git a/dhcpv4/option_broadcast_address.go b/dhcpv4/option_broadcast_address.go new file mode 100644 index 0000000..ffa57e3 --- /dev/null +++ b/dhcpv4/option_broadcast_address.go @@ -0,0 +1,56 @@ +package dhcpv4 + +import ( + "fmt" + "net" +) + +// This option implements the server identifier option +// https://tools.ietf.org/html/rfc2132 + +// OptBroadcastAddress represents an option encapsulating the server identifier. +type OptBroadcastAddress struct { + BroadcastAddress net.IP +} + +// ParseOptBroadcastAddress returns a new OptBroadcastAddress from a byte +// stream, or error if any. +func ParseOptBroadcastAddress(data []byte) (*OptBroadcastAddress, error) { + if len(data) < 2 { + return nil, ErrShortByteStream + } + code := OptionCode(data[0]) + if code != OptionBroadcastAddress { + return nil, fmt.Errorf("expected code %v, got %v", OptionBroadcastAddress, code) + } + length := int(data[1]) + if length != 4 { + return nil, fmt.Errorf("unexepcted length: expected 4, got %v", length) + } + if len(data) < 6 { + return nil, ErrShortByteStream + } + return &OptBroadcastAddress{BroadcastAddress: net.IP(data[2 : 2+length])}, nil +} + +// Code returns the option code. +func (o *OptBroadcastAddress) Code() OptionCode { + return OptionBroadcastAddress +} + +// ToBytes returns a serialized stream of bytes for this option. +func (o *OptBroadcastAddress) ToBytes() []byte { + ret := []byte{byte(o.Code()), byte(o.Length())} + return append(ret, o.BroadcastAddress.To4()...) +} + +// String returns a human-readable string. +func (o *OptBroadcastAddress) String() string { + return fmt.Sprintf("Broadcast Address -> %v", o.BroadcastAddress.String()) +} + +// Length returns the length of the data portion (excluding option code an byte +// length). +func (o *OptBroadcastAddress) Length() int { + return len(o.BroadcastAddress.To4()) +} diff --git a/dhcpv4/option_broadcast_address_test.go b/dhcpv4/option_broadcast_address_test.go new file mode 100644 index 0000000..3572dc0 --- /dev/null +++ b/dhcpv4/option_broadcast_address_test.go @@ -0,0 +1,44 @@ +package dhcpv4 + +import ( + "net" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestOptBroadcastAddressInterfaceMethods(t *testing.T) { + ip := net.IP{192, 168, 0, 1} + o := OptBroadcastAddress{BroadcastAddress: ip} + + require.Equal(t, OptionBroadcastAddress, o.Code(), "Code") + + expectedBytes := []byte{byte(OptionBroadcastAddress), 4, 192, 168, 0, 1} + require.Equal(t, expectedBytes, o.ToBytes(), "ToBytes") + + require.Equal(t, 4, o.Length(), "Length") + + require.Equal(t, "Broadcast Address -> 192.168.0.1", o.String(), "String") +} + +func TestParseOptBroadcastAddress(t *testing.T) { + var ( + o *OptBroadcastAddress + err error + ) + o, err = ParseOptBroadcastAddress([]byte{}) + require.Error(t, err, "empty byte stream") + + o, err = ParseOptBroadcastAddress([]byte{byte(OptionBroadcastAddress), 4, 192}) + require.Error(t, err, "short byte stream") + + o, err = ParseOptBroadcastAddress([]byte{byte(OptionBroadcastAddress), 3, 192, 168, 0, 1}) + require.Error(t, err, "wrong IP length") + + o, err = ParseOptBroadcastAddress([]byte{53, 4, 192, 168, 1}) + require.Error(t, err, "wrong option code") + + o, err = ParseOptBroadcastAddress([]byte{byte(OptionBroadcastAddress), 4, 192, 168, 0, 1}) + require.NoError(t, err) + require.Equal(t, net.IP{192, 168, 0, 1}, o.BroadcastAddress) +} diff --git a/dhcpv4/option_server_identifier_test.go b/dhcpv4/option_server_identifier_test.go index 94fb542..efd6299 100644 --- a/dhcpv4/option_server_identifier_test.go +++ b/dhcpv4/option_server_identifier_test.go @@ -13,7 +13,7 @@ func TestOptRequestedIPAddressInterfaceMethods(t *testing.T) { require.Equal(t, OptionRequestedIPAddress, o.Code(), "Code") - expectedBytes := []byte{50, 4, 192, 168, 0, 1} + expectedBytes := []byte{byte(OptionRequestedIPAddress), 4, 192, 168, 0, 1} require.Equal(t, expectedBytes, o.ToBytes(), "ToBytes") require.Equal(t, 4, o.Length(), "Length") @@ -29,16 +29,16 @@ func TestParseOptRequestedIPAddress(t *testing.T) { o, err = ParseOptRequestedIPAddress([]byte{}) require.Error(t, err, "empty byte stream") - o, err = ParseOptRequestedIPAddress([]byte{50, 4, 192}) + o, err = ParseOptRequestedIPAddress([]byte{byte(OptionRequestedIPAddress), 4, 192}) require.Error(t, err, "short byte stream") - o, err = ParseOptRequestedIPAddress([]byte{50, 3, 192, 168, 0, 1}) + o, err = ParseOptRequestedIPAddress([]byte{byte(OptionRequestedIPAddress), 3, 192, 168, 0, 1}) require.Error(t, err, "wrong IP length") o, err = ParseOptRequestedIPAddress([]byte{53, 4, 192, 168, 1}) require.Error(t, err, "wrong option code") - o, err = ParseOptRequestedIPAddress([]byte{50, 4, 192, 168, 0, 1}) + o, err = ParseOptRequestedIPAddress([]byte{byte(OptionRequestedIPAddress), 4, 192, 168, 0, 1}) require.NoError(t, err) require.Equal(t, net.IP{192, 168, 0, 1}, o.RequestedAddr) } diff --git a/dhcpv4/options.go b/dhcpv4/options.go index acc2bf5..efbfb74 100644 --- a/dhcpv4/options.go +++ b/dhcpv4/options.go @@ -48,6 +48,8 @@ func ParseOption(data []byte) (Option, error) { opt, err = ParseOptRequestedIPAddress(data) case OptionServerIdentifier: opt, err = ParseOptServerIdentifier(data) + case OptionBroadcastAddress: + opt, err = ParseOptBroadcastAddress(data) case OptionMaximumDHCPMessageSize: opt, err = ParseOptMaximumDHCPMessageSize(data) case OptionClassIdentifier: -- cgit v1.2.3