diff options
-rw-r--r-- | dhcpv6/modifiers.go | 8 | ||||
-rw-r--r-- | dhcpv6/modifiers_test.go | 10 | ||||
-rw-r--r-- | dhcpv6/option_fqdn.go | 41 | ||||
-rw-r--r-- | dhcpv6/option_fqdn_test.go | 39 | ||||
-rw-r--r-- | dhcpv6/options.go | 2 |
5 files changed, 100 insertions, 0 deletions
diff --git a/dhcpv6/modifiers.go b/dhcpv6/modifiers.go index efd14a5..06eb9d9 100644 --- a/dhcpv6/modifiers.go +++ b/dhcpv6/modifiers.go @@ -43,6 +43,14 @@ func WithNetboot(d DHCPv6) { msg.UpdateOption(oro) } +// WithFQDN adds a fully qualified domain name option to the packet +func WithFQDN(flags uint8, domainname string) Modifier { + return func(d DHCPv6) { + ofqdn := OptFQDN{Flags: flags, DomainName: domainname} + d.AddOption(&ofqdn) + } +} + // WithUserClass adds a user class option to the packet func WithUserClass(uc []byte) Modifier { // TODO let the user specify multiple user classes diff --git a/dhcpv6/modifiers_test.go b/dhcpv6/modifiers_test.go index 324c425..dfef08c 100644 --- a/dhcpv6/modifiers_test.go +++ b/dhcpv6/modifiers_test.go @@ -95,3 +95,13 @@ func TestWithDomainSearchList(t *testing.T) { require.Equal(t, "slackware.it", labels[0]) require.Equal(t, "dhcp.slackware.it", labels[1]) } + +func TestWithFQDN(t *testing.T) { + var d Message + WithFQDN(4, "cnos.localhost")(&d) + require.Equal(t, 1, len(d.Options)) + ofqdn := d.Options[0].(*OptFQDN) + require.Equal(t, OptionFQDN, ofqdn.Code()) + require.Equal(t, uint8(4), ofqdn.Flags) + require.Equal(t, "cnos.localhost", ofqdn.DomainName) +} diff --git a/dhcpv6/option_fqdn.go b/dhcpv6/option_fqdn.go new file mode 100644 index 0000000..82d1254 --- /dev/null +++ b/dhcpv6/option_fqdn.go @@ -0,0 +1,41 @@ +package dhcpv6 + +import ( + "fmt" + + "github.com/u-root/u-root/pkg/uio" +) + +// OptFQDN implements OptionFQDN option. +// +// https://tools.ietf.org/html/rfc4704 +type OptFQDN struct { + Flags uint8 + DomainName string +} + +// Code returns the option code. +func (op *OptFQDN) Code() OptionCode { + return OptionFQDN +} + +// ToBytes serializes the option and returns it as a sequence of bytes +func (op *OptFQDN) ToBytes() []byte { + buf := uio.NewBigEndianBuffer(nil) + buf.Write8(op.Flags) + buf.WriteBytes([]byte(op.DomainName)) + return buf.Data() +} + +func (op *OptFQDN) String() string { + return fmt.Sprintf("OptFQDN{flags=%d, domainname=%s}", op.Flags, op.DomainName) +} + +// ParseOptFQDN deserializes from bytes to build a OptFQDN structure. +func ParseOptFQDN(data []byte) (*OptFQDN, error) { + var opt OptFQDN + buf := uio.NewBigEndianBuffer(data) + opt.Flags = buf.Read8() + opt.DomainName = string(buf.ReadAll()) + return &opt, buf.FinError() +} diff --git a/dhcpv6/option_fqdn_test.go b/dhcpv6/option_fqdn_test.go new file mode 100644 index 0000000..870ed9d --- /dev/null +++ b/dhcpv6/option_fqdn_test.go @@ -0,0 +1,39 @@ +package dhcpv6 + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseOptFQDN(t *testing.T) { + data := []byte{ + 0, // Flags + 'c', 'n', 'o', 's', '.', 'l', 'o', 'c', 'a', 'l', + 'h', 'o', 's', 't', + } + opt, err := ParseOptFQDN(data) + + require.NoError(t, err) + require.Equal(t, OptionFQDN, opt.Code()) + require.Equal(t, uint8(0), opt.Flags) + require.Equal(t, "cnos.localhost", opt.DomainName) + require.Equal(t, "OptFQDN{flags=0, domainname=cnos.localhost}", opt.String()) +} + +func TestOptFQDNToBytes(t *testing.T) { + opt := OptFQDN{ + Flags: 0, + DomainName: "cnos.localhost", + } + want := []byte{ + 0, // Flags + 'c', 'n', 'o', 's', '.', 'l', 'o', 'c', 'a', 'l', + 'h', 'o', 's', 't', + } + b := opt.ToBytes() + if !bytes.Equal(b, want) { + t.Fatalf("opt.ToBytes()=%v, want %v", b, want) + } +} diff --git a/dhcpv6/options.go b/dhcpv6/options.go index fb36a38..e653c01 100644 --- a/dhcpv6/options.go +++ b/dhcpv6/options.go @@ -73,6 +73,8 @@ func ParseOption(code OptionCode, optData []byte) (Option, error) { opt, err = ParseOptIAPrefix(optData) case OptionRemoteID: opt, err = ParseOptRemoteId(optData) + case OptionFQDN: + opt, err = ParseOptFQDN(optData) case OptionBootfileURL: opt, err = ParseOptBootFileURL(optData) case OptionBootfileParam: |