summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--dhcpv4/option_class_identifier_test.go8
-rw-r--r--dhcpv4/option_domain_name.go49
-rw-r--r--dhcpv4/option_domain_name_test.go41
-rw-r--r--dhcpv4/option_parameter_request_list.go11
-rw-r--r--dhcpv4/option_parameter_request_list_test.go2
-rw-r--r--dhcpv4/options.go2
-rw-r--r--dhcpv6/options.go2
7 files changed, 109 insertions, 6 deletions
diff --git a/dhcpv4/option_class_identifier_test.go b/dhcpv4/option_class_identifier_test.go
index a6a8f21..786ecfb 100644
--- a/dhcpv4/option_class_identifier_test.go
+++ b/dhcpv4/option_class_identifier_test.go
@@ -10,17 +10,17 @@ func TestOptClassIdentifierInterfaceMethods(t *testing.T) {
o := OptClassIdentifier{Identifier: "foo"}
require.Equal(t, OptionClassIdentifier, o.Code(), "Code")
require.Equal(t, 3, o.Length(), "Length")
- require.Equal(t, []byte{60, 3, 'f', 'o', 'o'}, o.ToBytes(), "ToBytes")
+ require.Equal(t, []byte{byte(OptionClassIdentifier), 3, 'f', 'o', 'o'}, o.ToBytes(), "ToBytes")
}
func TestParseOptClassIdentifier(t *testing.T) {
- data := []byte{60, 4, 't', 'e', 's', 't'} // DISCOVER
+ data := []byte{byte(OptionClassIdentifier), 4, 't', 'e', 's', 't'} // DISCOVER
o, err := ParseOptClassIdentifier(data)
require.NoError(t, err)
require.Equal(t, &OptClassIdentifier{Identifier: "test"}, o)
// Short byte stream
- data = []byte{60}
+ data = []byte{byte(OptionClassIdentifier)}
_, err = ParseOptClassIdentifier(data)
require.Error(t, err, "should get error from short byte stream")
@@ -30,7 +30,7 @@ func TestParseOptClassIdentifier(t *testing.T) {
require.Error(t, err, "should get error from wrong code")
// Bad length
- data = []byte{60, 6, 1, 1, 1}
+ data = []byte{byte(OptionClassIdentifier), 6, 1, 1, 1}
_, err = ParseOptClassIdentifier(data)
require.Error(t, err, "should get error from bad length")
}
diff --git a/dhcpv4/option_domain_name.go b/dhcpv4/option_domain_name.go
new file mode 100644
index 0000000..71d7ef1
--- /dev/null
+++ b/dhcpv4/option_domain_name.go
@@ -0,0 +1,49 @@
+package dhcpv4
+
+import "fmt"
+
+// This option implements the server domani name option
+// https://tools.ietf.org/html/rfc2132
+
+// OptDomainName represents an option encapsulating the server identifier.
+type OptDomainName struct {
+ DomainName string
+}
+
+// ParseOptDomainName returns a new OptDomainName from a byte
+// stream, or error if any.
+func ParseOptDomainName(data []byte) (*OptDomainName, error) {
+ if len(data) < 2 {
+ return nil, ErrShortByteStream
+ }
+ code := OptionCode(data[0])
+ if code != OptionDomainName {
+ return nil, fmt.Errorf("expected code %v, got %v", OptionDomainName, code)
+ }
+ length := int(data[1])
+ if len(data) < 2+length {
+ return nil, ErrShortByteStream
+ }
+ return &OptDomainName{DomainName: string(data[2 : 2+length])}, nil
+}
+
+// Code returns the option code.
+func (o *OptDomainName) Code() OptionCode {
+ return OptionDomainName
+}
+
+// ToBytes returns a serialized stream of bytes for this option.
+func (o *OptDomainName) ToBytes() []byte {
+ return append([]byte{byte(o.Code()), byte(o.Length())}, []byte(o.DomainName)...)
+}
+
+// String returns a human-readable string.
+func (o *OptDomainName) String() string {
+ return fmt.Sprintf("Domain Name -> %v", o.DomainName)
+}
+
+// Length returns the length of the data portion (excluding option code an byte
+// length).
+func (o *OptDomainName) Length() int {
+ return len(o.DomainName)
+}
diff --git a/dhcpv4/option_domain_name_test.go b/dhcpv4/option_domain_name_test.go
new file mode 100644
index 0000000..ab66e8b
--- /dev/null
+++ b/dhcpv4/option_domain_name_test.go
@@ -0,0 +1,41 @@
+package dhcpv4
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestOptDomainNameInterfaceMethods(t *testing.T) {
+ o := OptDomainName{DomainName: "foo"}
+ require.Equal(t, OptionDomainName, o.Code(), "Code")
+ require.Equal(t, 3, o.Length(), "Length")
+ require.Equal(t, []byte{byte(OptionDomainName), 3, 'f', 'o', 'o'}, o.ToBytes(), "ToBytes")
+}
+
+func TestParseOptDomainName(t *testing.T) {
+ data := []byte{byte(OptionDomainName), 4, 't', 'e', 's', 't'} // DISCOVER
+ o, err := ParseOptDomainName(data)
+ require.NoError(t, err)
+ require.Equal(t, &OptDomainName{DomainName: "test"}, o)
+
+ // Short byte stream
+ data = []byte{byte(OptionDomainName)}
+ _, err = ParseOptDomainName(data)
+ require.Error(t, err, "should get error from short byte stream")
+
+ // Wrong code
+ data = []byte{54, 2, 1, 1}
+ _, err = ParseOptDomainName(data)
+ require.Error(t, err, "should get error from wrong code")
+
+ // Bad length
+ data = []byte{byte(OptionDomainName), 6, 1, 1, 1}
+ _, err = ParseOptDomainName(data)
+ require.Error(t, err, "should get error from bad length")
+}
+
+func TestOptDomainNameString(t *testing.T) {
+ o := OptDomainName{DomainName: "testy test"}
+ require.Equal(t, "Domain Name -> testy test", o.String())
+}
diff --git a/dhcpv4/option_parameter_request_list.go b/dhcpv4/option_parameter_request_list.go
index f6b0348..324832e 100644
--- a/dhcpv4/option_parameter_request_list.go
+++ b/dhcpv4/option_parameter_request_list.go
@@ -2,6 +2,7 @@ package dhcpv4
import (
"fmt"
+ "strings"
)
// This option implements the parameter request list option
@@ -50,7 +51,15 @@ func (o *OptParameterRequestList) ToBytes() []byte {
// String returns a human-readable string for this option.
func (o *OptParameterRequestList) String() string {
- return fmt.Sprintf("Parameter Request List -> %v", o.RequestedOpts)
+ var optNames []string
+ for _, ro := range o.RequestedOpts {
+ if name, ok := OptionCodeToString[ro]; ok {
+ optNames = append(optNames, name)
+ } else {
+ optNames = append(optNames, fmt.Sprintf("Unknown (%v)", ro))
+ }
+ }
+ return fmt.Sprintf("Parameter Request List -> [%v]", strings.Join(optNames, ", "))
}
// Length returns the length of the data portion (excluding option code and byte
diff --git a/dhcpv4/option_parameter_request_list_test.go b/dhcpv4/option_parameter_request_list_test.go
index 4441b29..f600a70 100644
--- a/dhcpv4/option_parameter_request_list_test.go
+++ b/dhcpv4/option_parameter_request_list_test.go
@@ -14,7 +14,7 @@ func TestOptParameterRequestListInterfaceMethods(t *testing.T) {
expectedBytes := []byte{55, 2, 67, 5}
require.Equal(t, expectedBytes, o.ToBytes(), "ToBytes")
- expectedString := "Parameter Request List -> [67 5]"
+ expectedString := "Parameter Request List -> [Bootfile Name, Name Server]"
require.Equal(t, expectedString, o.String(), "String")
}
diff --git a/dhcpv4/options.go b/dhcpv4/options.go
index a1b5c93..acc2bf5 100644
--- a/dhcpv4/options.go
+++ b/dhcpv4/options.go
@@ -52,6 +52,8 @@ func ParseOption(data []byte) (Option, error) {
opt, err = ParseOptMaximumDHCPMessageSize(data)
case OptionClassIdentifier:
opt, err = ParseOptClassIdentifier(data)
+ case OptionDomainName:
+ opt, err = ParseOptDomainName(data)
default:
opt, err = ParseOptionGeneric(data)
}
diff --git a/dhcpv6/options.go b/dhcpv6/options.go
index fcfed37..ad52998 100644
--- a/dhcpv6/options.go
+++ b/dhcpv6/options.go
@@ -5,8 +5,10 @@ import (
"fmt"
)
+// OptionCode is a single byte representing the code for a given Option.
type OptionCode uint16
+// Option is an interface that all DHCPv6 options adhere to.
type Option interface {
Code() OptionCode
ToBytes() []byte