summaryrefslogtreecommitdiffhomepage
path: root/dhcpv4
diff options
context:
space:
mode:
Diffstat (limited to 'dhcpv4')
-rw-r--r--dhcpv4/option_domain_search.go63
-rw-r--r--dhcpv4/option_domain_search_test.go37
-rw-r--r--dhcpv4/options.go2
3 files changed, 102 insertions, 0 deletions
diff --git a/dhcpv4/option_domain_search.go b/dhcpv4/option_domain_search.go
new file mode 100644
index 0000000..daade0a
--- /dev/null
+++ b/dhcpv4/option_domain_search.go
@@ -0,0 +1,63 @@
+package dhcpv4
+
+// This module defines the OptDomainSearch structure.
+// https://tools.ietf.org/html/rfc3397
+
+import (
+ "fmt"
+
+ "github.com/insomniacslk/dhcp/rfc1035label"
+)
+
+// OptDomainSearch represents an option encapsulating a domain search list.
+type OptDomainSearch struct {
+ DomainSearch []string
+}
+
+// Code returns the option code.
+func (op *OptDomainSearch) Code() OptionCode {
+ return OptionDNSDomainSearchList
+}
+
+// ToBytes returns a serialized stream of bytes for this option.
+func (op *OptDomainSearch) ToBytes() []byte {
+ buf := []byte{byte(op.Code()), byte(op.Length())}
+ buf = append(buf, rfc1035label.LabelsToBytes(op.DomainSearch)...)
+ return buf
+}
+
+// Length returns the length of the data portion (excluding option code an byte
+// length).
+func (op *OptDomainSearch) Length() int {
+ var length int
+ for _, label := range op.DomainSearch {
+ length += len(label) + 2 // add the first and the last length bytes
+ }
+ return length
+}
+
+// String returns a human-readable string.
+func (op *OptDomainSearch) String() string {
+ return fmt.Sprintf("DNS Domain Search List -> %v", op.DomainSearch)
+}
+
+// ParseOptDomainSearch returns a new OptDomainSearch from a byte stream, or
+// error if any.
+func ParseOptDomainSearch(data []byte) (*OptDomainSearch, error) {
+ if len(data) < 2 {
+ return nil, ErrShortByteStream
+ }
+ code := OptionCode(data[0])
+ if code != OptionDNSDomainSearchList {
+ return nil, fmt.Errorf("expected code %v, got %v", OptionDNSDomainSearchList, code)
+ }
+ length := int(data[1])
+ if len(data) < 2+length {
+ return nil, ErrShortByteStream
+ }
+ domainSearch, err := rfc1035label.LabelsFromBytes(data[2:length+2])
+ if err != nil {
+ return nil, err
+ }
+ return &OptDomainSearch{DomainSearch: domainSearch}, nil
+}
diff --git a/dhcpv4/option_domain_search_test.go b/dhcpv4/option_domain_search_test.go
new file mode 100644
index 0000000..4848a83
--- /dev/null
+++ b/dhcpv4/option_domain_search_test.go
@@ -0,0 +1,37 @@
+package dhcpv4
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestParseOptDomainSearch(t *testing.T) {
+ data := []byte{
+ 119, // OptionDNSDomainSearchList
+ 33, // length
+ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0,
+ 6, 's', 'u', 'b', 'n', 'e', 't', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'o', 'r', 'g', 0,
+ }
+ opt, err := ParseOptDomainSearch(data)
+ require.NoError(t, err)
+ require.Equal(t, len(opt.DomainSearch), 2)
+ require.Equal(t, opt.DomainSearch[0], "example.com")
+ require.Equal(t, opt.DomainSearch[1], "subnet.example.org")
+}
+
+func TestOptDomainSearchToBytes(t *testing.T) {
+ expected := []byte{
+ 119, // OptionDNSDomainSearchList
+ 33, // length
+ 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0,
+ 6, 's', 'u', 'b', 'n', 'e', 't', 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'o', 'r', 'g', 0,
+ }
+ opt := OptDomainSearch{
+ DomainSearch: []string{
+ "example.com",
+ "subnet.example.org",
+ },
+ }
+ require.Equal(t, opt.ToBytes(), expected)
+}
diff --git a/dhcpv4/options.go b/dhcpv4/options.go
index 22e6eee..0be494f 100644
--- a/dhcpv4/options.go
+++ b/dhcpv4/options.go
@@ -76,6 +76,8 @@ func ParseOption(data []byte) (Option, error) {
opt, err = ParseOptBootfileName(data)
case OptionUserClassInformation:
opt, err = ParseOptUserClass(data)
+ case OptionDNSDomainSearchList:
+ opt, err = ParseOptDomainSearch(data)
default:
opt, err = ParseOptionGeneric(data)
}