diff options
Diffstat (limited to 'dhcpv4')
-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 |
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) } |