File: iaprefix.go

package info (click to toggle)
golang-github-mdlayher-dhcp6 0.0~git20190311.2a67805-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 400 kB
  • sloc: makefile: 3
file content (134 lines) | stat: -rw-r--r-- 4,372 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package dhcp6opts

import (
	"io"
	"net"
	"time"

	"github.com/mdlayher/dhcp6"
	"github.com/mdlayher/dhcp6/internal/buffer"
)

// IAPrefix represents an Identity Association Prefix, as defined in RFC 3633,
// Section 10.
//
// Routers may use identity association prefixes (IAPrefixes) to request IPv6
// prefixes to assign individual address to IPv6 clients, using the lifetimes
// specified in the preferred lifetime and valid lifetime fields.  Multiple
// IAPrefixes may be present in a single DHCP request, but only enscapsulated
// within an IAPD's options.
type IAPrefix struct {
	// PreferredLifetime specifies the preferred lifetime of an IPv6 prefix.
	// When the preferred lifetime of a prefix expires, the prefix becomes
	// deprecated, and addresses from the prefix should not be used in new
	// communications.
	//
	// The preferred lifetime of a prefix must not be greater than its valid
	// lifetime.
	PreferredLifetime time.Duration

	// ValidLifetime specifies the valid lifetime of an IPv6 prefix.  When the
	// valid lifetime of a prefix expires, addresses from the prefix the address
	// should not be used for any further communication.
	//
	// The valid lifetime of a prefix must be greater than its preferred
	// lifetime.
	ValidLifetime time.Duration

	// PrefixLength specifies the length in bits of an IPv6 address prefix, such
	// as 32, 64, etc.
	PrefixLength uint8

	// Prefix specifies the IPv6 address prefix from which IPv6 addresses can
	// be allocated.
	Prefix net.IP

	// Options specifies a map of DHCP options specific to this IAPrefix.
	// Its methods can be used to retrieve data from an incoming IAPrefix, or
	// send data with an outgoing IAPrefix.
	Options dhcp6.Options
}

// NewIAPrefix creates a new IAPrefix from preferred and valid lifetime
// durations, an IPv6 prefix length, an IPv6 prefix, and an optional Options
// map.
//
// The preferred lifetime duration must be less than the valid lifetime
// duration.  The IPv6 prefix must be exactly 16 bytes, the correct length
// for an IPv6 address.  Failure to meet either of these conditions will result
// in an error.  If an Options map is not specified, a new one will be
// allocated.
func NewIAPrefix(preferred time.Duration, valid time.Duration, prefixLength uint8, prefix net.IP, options dhcp6.Options) (*IAPrefix, error) {
	// Preferred lifetime must always be less than valid lifetime.
	if preferred > valid {
		return nil, ErrInvalidLifetimes
	}

	// From documentation: If ip is not an IPv4 address, To4 returns nil.
	if prefix.To4() != nil {
		return nil, ErrInvalidIP
	}

	// If no options set, make empty map
	if options == nil {
		options = make(dhcp6.Options)
	}

	return &IAPrefix{
		PreferredLifetime: preferred,
		ValidLifetime:     valid,
		PrefixLength:      prefixLength,
		Prefix:            prefix,
		Options:           options,
	}, nil
}

// MarshalBinary allocates a byte slice containing the data from a IAPrefix.
func (i *IAPrefix) MarshalBinary() ([]byte, error) {
	//  4 bytes: preferred lifetime
	//  4 bytes: valid lifetime
	//  1 byte : prefix length
	// 16 bytes: IPv6 prefix
	//  N bytes: options
	b := buffer.New(nil)

	b.Write32(uint32(i.PreferredLifetime / time.Second))
	b.Write32(uint32(i.ValidLifetime / time.Second))
	b.Write8(i.PrefixLength)
	copy(b.WriteN(net.IPv6len), i.Prefix)
	opts, err := i.Options.MarshalBinary()
	if err != nil {
		return nil, err
	}
	b.WriteBytes(opts)

	return b.Data(), nil
}

// UnmarshalBinary unmarshals a raw byte slice into a IAPrefix.
//
// If the byte slice does not contain enough data to form a valid IAPrefix,
// io.ErrUnexpectedEOF is returned.  If the preferred lifetime value in the
// byte slice is less than the valid lifetime, ErrInvalidLifetimes is
// returned.
func (i *IAPrefix) UnmarshalBinary(p []byte) error {
	b := buffer.New(p)
	// IAPrefix must at least contain lifetimes, prefix length, and prefix
	if b.Len() < 25 {
		return io.ErrUnexpectedEOF
	}

	i.PreferredLifetime = time.Duration(b.Read32()) * time.Second
	i.ValidLifetime = time.Duration(b.Read32()) * time.Second

	// Preferred lifetime must always be less than valid lifetime.
	if i.PreferredLifetime > i.ValidLifetime {
		return ErrInvalidLifetimes
	}

	i.PrefixLength = b.Read8()
	i.Prefix = make(net.IP, net.IPv6len)
	copy(i.Prefix, b.Consume(net.IPv6len))

	return (&i.Options).UnmarshalBinary(b.Remaining())
}