summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorinsomniac <insomniacslk@users.noreply.github.com>2018-08-01 18:21:18 +0100
committerGitHub <noreply@github.com>2018-08-01 18:21:18 +0100
commit85e86a8adb8f51277e8e9ceb1d423270dd2fffac (patch)
treea5fca3619710467f2ae6ee7a5ef3abd970cbea45
parent1ce17c65bf3f13919fa2fbb1a14ce8306a0eca04 (diff)
parenta606ffc4c7a61ae981450b9dcc5605f78bba7e07 (diff)
add OptDomainSearch (#111)
-rw-r--r--dhcpv4/option_domain_search.go63
-rw-r--r--dhcpv4/option_domain_search_test.go37
-rw-r--r--dhcpv4/options.go2
-rw-r--r--dhcpv6/option_domainsearchlist.go6
-rw-r--r--rfc1035label/label.go (renamed from dhcpv6/option_rfc1035label.go)10
-rw-r--r--rfc1035label/label_test.go (renamed from dhcpv6/option_rfc1035label_test.go)2
6 files changed, 115 insertions, 5 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)
}
diff --git a/dhcpv6/option_domainsearchlist.go b/dhcpv6/option_domainsearchlist.go
index 6e5504c..a3c6f28 100644
--- a/dhcpv6/option_domainsearchlist.go
+++ b/dhcpv6/option_domainsearchlist.go
@@ -6,6 +6,8 @@ package dhcpv6
import (
"encoding/binary"
"fmt"
+
+ "github.com/insomniacslk/dhcp/rfc1035label"
)
// OptDomainSearchList list implements a OptionDomainSearchList option
@@ -21,7 +23,7 @@ func (op *OptDomainSearchList) ToBytes() []byte {
buf := make([]byte, 4)
binary.BigEndian.PutUint16(buf[0:2], uint16(OptionDomainSearchList))
binary.BigEndian.PutUint16(buf[2:4], uint16(op.Length()))
- buf = append(buf, LabelsToBytes(op.DomainSearchList)...)
+ buf = append(buf, rfc1035label.LabelsToBytes(op.DomainSearchList)...)
return buf
}
@@ -42,7 +44,7 @@ func (op *OptDomainSearchList) String() string {
func ParseOptDomainSearchList(data []byte) (*OptDomainSearchList, error) {
opt := OptDomainSearchList{}
var err error
- opt.DomainSearchList, err = LabelsFromBytes(data)
+ opt.DomainSearchList, err = rfc1035label.LabelsFromBytes(data)
if err != nil {
return nil, err
}
diff --git a/dhcpv6/option_rfc1035label.go b/rfc1035label/label.go
index 06870b5..c63b4af 100644
--- a/dhcpv6/option_rfc1035label.go
+++ b/rfc1035label/label.go
@@ -1,10 +1,14 @@
-package dhcpv6
+package rfc1035label
import (
"fmt"
"strings"
)
+// This implements the compression from RFC 1035, section 4.1.4
+// https://tools.ietf.org/html/rfc1035
+
+// LabelsFromBytes decodes a serialized stream and returns a list of labels
func LabelsFromBytes(buf []byte) ([]string, error) {
var (
pos = 0
@@ -30,9 +34,9 @@ func LabelsFromBytes(buf []byte) ([]string, error) {
label += string(buf[pos : pos+length])
pos += length
}
- return domains, nil
}
+// LabelToBytes encodes a label and returns a serialized stream of bytes
func LabelToBytes(label string) []byte {
var encodedLabel []byte
if len(label) == 0 {
@@ -45,6 +49,8 @@ func LabelToBytes(label string) []byte {
return append(encodedLabel, 0)
}
+// LabelsToBytes encodes a list of labels and returns a serialized stream of
+// bytes
func LabelsToBytes(labels []string) []byte {
var encodedLabels []byte
for _, label := range labels {
diff --git a/dhcpv6/option_rfc1035label_test.go b/rfc1035label/label_test.go
index f99c209..f91110b 100644
--- a/dhcpv6/option_rfc1035label_test.go
+++ b/rfc1035label/label_test.go
@@ -1,4 +1,4 @@
-package dhcpv6
+package rfc1035label
import (
"bytes"