summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--dhcpv4/dhcpv4.go8
-rw-r--r--dhcpv4/option_subnet_mask.go56
-rw-r--r--dhcpv4/option_subnet_mask_test.go44
-rw-r--r--dhcpv4/options.go2
-rw-r--r--dhcpv4/options_test.go8
5 files changed, 114 insertions, 4 deletions
diff --git a/dhcpv4/dhcpv4.go b/dhcpv4/dhcpv4.go
index 2d73003..7965161 100644
--- a/dhcpv4/dhcpv4.go
+++ b/dhcpv4/dhcpv4.go
@@ -690,10 +690,10 @@ func (d *DHCPv4) ToBytes() []byte {
ret = append(ret, u16...)
binary.BigEndian.PutUint16(u16, d.flags)
ret = append(ret, u16...)
- ret = append(ret, d.clientIPAddr[:4]...)
- ret = append(ret, d.yourIPAddr[:4]...)
- ret = append(ret, d.serverIPAddr[:4]...)
- ret = append(ret, d.gatewayIPAddr[:4]...)
+ ret = append(ret, d.clientIPAddr.To4()...)
+ ret = append(ret, d.yourIPAddr.To4()...)
+ ret = append(ret, d.serverIPAddr.To4()...)
+ ret = append(ret, d.gatewayIPAddr.To4()...)
ret = append(ret, d.clientHwAddr[:16]...)
ret = append(ret, d.serverHostName[:64]...)
ret = append(ret, d.bootFileName[:128]...)
diff --git a/dhcpv4/option_subnet_mask.go b/dhcpv4/option_subnet_mask.go
new file mode 100644
index 0000000..f1ff4a4
--- /dev/null
+++ b/dhcpv4/option_subnet_mask.go
@@ -0,0 +1,56 @@
+package dhcpv4
+
+import (
+ "fmt"
+ "net"
+)
+
+// This option implements the subnet mask option
+// https://tools.ietf.org/html/rfc2132
+
+// OptSubnetMask represents an option encapsulating the subnet mask.
+type OptSubnetMask struct {
+ SubnetMask net.IPMask
+}
+
+// ParseOptSubnetMask returns a new OptSubnetMask from a byte
+// stream, or error if any.
+func ParseOptSubnetMask(data []byte) (*OptSubnetMask, error) {
+ if len(data) < 2 {
+ return nil, ErrShortByteStream
+ }
+ code := OptionCode(data[0])
+ if code != OptionSubnetMask {
+ return nil, fmt.Errorf("expected code %v, got %v", OptionSubnetMask, 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 &OptSubnetMask{SubnetMask: net.IPMask(data[2 : 2+length])}, nil
+}
+
+// Code returns the option code.
+func (o *OptSubnetMask) Code() OptionCode {
+ return OptionSubnetMask
+}
+
+// ToBytes returns a serialized stream of bytes for this option.
+func (o *OptSubnetMask) ToBytes() []byte {
+ ret := []byte{byte(o.Code()), byte(o.Length())}
+ return append(ret, o.SubnetMask[:4]...)
+}
+
+// String returns a human-readable string.
+func (o *OptSubnetMask) String() string {
+ return fmt.Sprintf("Subnet Mask -> %v", o.SubnetMask.String())
+}
+
+// Length returns the length of the data portion (excluding option code an byte
+// length).
+func (o *OptSubnetMask) Length() int {
+ return 4
+}
diff --git a/dhcpv4/option_subnet_mask_test.go b/dhcpv4/option_subnet_mask_test.go
new file mode 100644
index 0000000..4cb8819
--- /dev/null
+++ b/dhcpv4/option_subnet_mask_test.go
@@ -0,0 +1,44 @@
+package dhcpv4
+
+import (
+ "net"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestOptSubnetMaskInterfaceMethods(t *testing.T) {
+ mask := net.IPMask{255, 255, 255, 0}
+ o := OptSubnetMask{SubnetMask: mask}
+
+ require.Equal(t, OptionSubnetMask, o.Code(), "Code")
+
+ expectedBytes := []byte{1, 4, 255, 255, 255, 0}
+ require.Equal(t, expectedBytes, o.ToBytes(), "ToBytes")
+
+ require.Equal(t, 4, o.Length(), "Length")
+
+ require.Equal(t, "Subnet Mask -> ffffff00", o.String(), "String")
+}
+
+func TestParseOptSubnetMask(t *testing.T) {
+ var (
+ o *OptSubnetMask
+ err error
+ )
+ o, err = ParseOptSubnetMask([]byte{})
+ require.Error(t, err, "empty byte stream")
+
+ o, err = ParseOptSubnetMask([]byte{1, 4, 255})
+ require.Error(t, err, "short byte stream")
+
+ o, err = ParseOptSubnetMask([]byte{1, 3, 255, 255, 255, 0})
+ require.Error(t, err, "wrong IP length")
+
+ o, err = ParseOptSubnetMask([]byte{2, 4, 255, 255, 255})
+ require.Error(t, err, "wrong option code")
+
+ o, err = ParseOptSubnetMask([]byte{1, 4, 255, 255, 255, 0})
+ require.NoError(t, err)
+ require.Equal(t, net.IPMask{255, 255, 255, 0}, o.SubnetMask)
+}
diff --git a/dhcpv4/options.go b/dhcpv4/options.go
index 5e6da80..198fbb0 100644
--- a/dhcpv4/options.go
+++ b/dhcpv4/options.go
@@ -40,6 +40,8 @@ func ParseOption(data []byte) (Option, error) {
err error
)
switch OptionCode(data[0]) {
+ case OptionSubnetMask:
+ opt, err = ParseOptSubnetMask(data)
case OptionDHCPMessageType:
opt, err = ParseOptMessageType(data)
case OptionParameterRequestList:
diff --git a/dhcpv4/options_test.go b/dhcpv4/options_test.go
index 41ef415..01d7427 100644
--- a/dhcpv4/options_test.go
+++ b/dhcpv4/options_test.go
@@ -17,6 +17,14 @@ func TestParseOption(t *testing.T) {
require.Equal(t, 4, generic.Length())
require.Equal(t, "Name Server -> [192 168 1 254]", generic.String())
+ // Option subnet mask
+ option = []byte{1, 4, 255, 255, 255, 0}
+ opt, err = ParseOption(option)
+ require.NoError(t, err)
+ require.Equal(t, OptionSubnetMask, opt.Code(), "Code")
+ require.Equal(t, 4, opt.Length(), "Length")
+ require.Equal(t, option, opt.ToBytes(), "ToBytes")
+
// Message type
option = []byte{53, 1, 1}
opt, err = ParseOption(option)