diff options
author | insomniac <insomniacslk@users.noreply.github.com> | 2018-08-01 18:21:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-08-01 18:21:18 +0100 |
commit | 85e86a8adb8f51277e8e9ceb1d423270dd2fffac (patch) | |
tree | a5fca3619710467f2ae6ee7a5ef3abd970cbea45 | |
parent | 1ce17c65bf3f13919fa2fbb1a14ce8306a0eca04 (diff) | |
parent | a606ffc4c7a61ae981450b9dcc5605f78bba7e07 (diff) |
add OptDomainSearch (#111)
-rw-r--r-- | dhcpv4/option_domain_search.go | 63 | ||||
-rw-r--r-- | dhcpv4/option_domain_search_test.go | 37 | ||||
-rw-r--r-- | dhcpv4/options.go | 2 | ||||
-rw-r--r-- | dhcpv6/option_domainsearchlist.go | 6 | ||||
-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" |