summaryrefslogtreecommitdiffhomepage
path: root/dhcpv6/option_4rd.go
diff options
context:
space:
mode:
Diffstat (limited to 'dhcpv6/option_4rd.go')
-rw-r--r--dhcpv6/option_4rd.go178
1 files changed, 178 insertions, 0 deletions
diff --git a/dhcpv6/option_4rd.go b/dhcpv6/option_4rd.go
new file mode 100644
index 0000000..9bac74a
--- /dev/null
+++ b/dhcpv6/option_4rd.go
@@ -0,0 +1,178 @@
+package dhcpv6
+
+import (
+ "fmt"
+ "net"
+
+ "github.com/u-root/u-root/pkg/uio"
+)
+
+// Opt4RD represents a 4RD option. It is only a container for 4RD_*_RULE options
+type Opt4RD Options
+
+// Code returns the Option Code for this option
+func (op *Opt4RD) Code() OptionCode {
+ return Option4RD
+}
+
+// ToBytes serializes this option
+func (op *Opt4RD) ToBytes() []byte {
+ return (*Options)(op).ToBytes()
+}
+
+// String returns a human-readable representation of the option
+func (op *Opt4RD) String() string {
+ return fmt.Sprintf("Opt4RD{%v}", (*Options)(op))
+}
+
+// ParseOpt4RD builds an Opt4RD structure from a sequence of bytes.
+// The input data does not include option code and length bytes
+func ParseOpt4RD(data []byte) (*Opt4RD, error) {
+ var opt Options
+ err := opt.FromBytes(data)
+ return (*Opt4RD)(&opt), err
+}
+
+// Opt4RDMapRule represents a 4RD Mapping Rule option
+// The option is described in https://tools.ietf.org/html/rfc7600#section-4.9
+// The 4RD mapping rules are described in https://tools.ietf.org/html/rfc7600#section-4.2
+type Opt4RDMapRule struct {
+ // Prefix4 is the IPv4 prefix mapped by this rule
+ Prefix4 net.IPNet
+ // Prefix6 is the IPv6 prefix mapped by this rule
+ Prefix6 net.IPNet
+ // EABitsLength is the number of bits of an address used in constructing the mapped address
+ EABitsLength uint8
+ // WKPAuthorized determines if well-known ports are assigned to addresses in an A+P mapping
+ // It can only be set if the length of Prefix4 + EABits > 32
+ WKPAuthorized bool
+}
+
+const (
+ // opt4RDWKPAuthorizedMask is the mask for the WKPAuthorized flag in its
+ // byte in Opt4RDMapRule
+ opt4RDWKPAuthorizedMask = 1 << 7
+ // opt4RDHubAndSpokeMask is the mask for the HubAndSpoke flag in its
+ // byte in Opt4RDNonMapRule
+ opt4RDHubAndSpokeMask = 1 << 7
+ // opt4RDTrafficClassMask is the mask for the TrafficClass flag in its
+ // byte in Opt4RDNonMapRule
+ opt4RDTrafficClassMask = 1 << 0
+)
+
+// Code returns the option code representing this option
+func (op *Opt4RDMapRule) Code() OptionCode { return Option4RDMapRule }
+
+// ToBytes serializes this option
+func (op *Opt4RDMapRule) ToBytes() []byte {
+ buf := uio.NewBigEndianBuffer(nil)
+ p4Len, _ := op.Prefix4.Mask.Size()
+ p6Len, _ := op.Prefix6.Mask.Size()
+ buf.Write8(uint8(p4Len))
+ buf.Write8(uint8(p6Len))
+ buf.Write8(op.EABitsLength)
+ if op.WKPAuthorized {
+ buf.Write8(opt4RDWKPAuthorizedMask)
+ } else {
+ buf.Write8(0)
+ }
+ if op.Prefix4.IP.To4() == nil {
+ // The API prevents us from returning an error here
+ // We just write zeros instead, which is pretty bad behaviour
+ buf.Write32(0)
+ } else {
+ buf.WriteBytes(op.Prefix4.IP.To4())
+ }
+ if op.Prefix6.IP.To16() == nil {
+ buf.Write64(0)
+ buf.Write64(0)
+ } else {
+ buf.WriteBytes(op.Prefix6.IP.To16())
+ }
+ return buf.Data()
+}
+
+// String returns a human-readable description of this option
+func (op *Opt4RDMapRule) String() string {
+ return fmt.Sprintf("Opt4RDMapRule{Prefix4=%s, Prefix6=%s, EA-Bits=%d, WKPAuthorized=%t}",
+ op.Prefix4.String(), op.Prefix6.String(), op.EABitsLength, op.WKPAuthorized)
+}
+
+// ParseOpt4RDMapRule builds an Opt4RDMapRule structure from a sequence of bytes.
+// The input data does not include option code and length bytes.
+func ParseOpt4RDMapRule(data []byte) (*Opt4RDMapRule, error) {
+ var opt Opt4RDMapRule
+ buf := uio.NewBigEndianBuffer(data)
+ opt.Prefix4.Mask = net.CIDRMask(int(buf.Read8()), 32)
+ opt.Prefix6.Mask = net.CIDRMask(int(buf.Read8()), 128)
+ opt.EABitsLength = buf.Read8()
+ opt.WKPAuthorized = (buf.Read8() & opt4RDWKPAuthorizedMask) != 0
+ opt.Prefix4.IP = net.IP(buf.CopyN(net.IPv4len))
+ opt.Prefix6.IP = net.IP(buf.CopyN(net.IPv6len))
+ return &opt, buf.FinError()
+}
+
+// Opt4RDNonMapRule represents 4RD parameters other than mapping rules
+type Opt4RDNonMapRule struct {
+ // HubAndSpoke is whether the network topology is hub-and-spoke or meshed
+ HubAndSpoke bool
+ // TrafficClass is an optional 8-bit tunnel traffic class identifier
+ TrafficClass *uint8
+ // DomainPMTU is the Path MTU for this 4RD domain
+ DomainPMTU uint16
+}
+
+// Code returns the option code for this option
+func (op *Opt4RDNonMapRule) Code() OptionCode {
+ return Option4RDNonMapRule
+}
+
+// ToBytes serializes this option
+func (op *Opt4RDNonMapRule) ToBytes() []byte {
+ buf := uio.NewBigEndianBuffer(nil)
+ var flags uint8
+ var trafficClassValue uint8
+ if op.HubAndSpoke {
+ flags |= opt4RDHubAndSpokeMask
+ }
+ if op.TrafficClass != nil {
+ flags |= opt4RDTrafficClassMask
+ trafficClassValue = *op.TrafficClass
+ }
+
+ buf.Write8(flags)
+ buf.Write8(trafficClassValue)
+ buf.Write16(op.DomainPMTU)
+
+ return buf.Data()
+}
+
+// String returns a human-readable description of this option
+func (op *Opt4RDNonMapRule) String() string {
+ var tClass interface{} = false
+ if op.TrafficClass != nil {
+ tClass = *op.TrafficClass
+ }
+
+ return fmt.Sprintf("Opt4RDNonMapRule{HubAndSpoke=%t, TrafficClass=%v, DomainPMTU=%d}",
+ op.HubAndSpoke, tClass, op.DomainPMTU)
+}
+
+// ParseOpt4RDNonMapRule builds an Opt4RDNonMapRule structure from a sequence of bytes.
+// The input data does not include option code and length bytes
+func ParseOpt4RDNonMapRule(data []byte) (*Opt4RDNonMapRule, error) {
+ var opt Opt4RDNonMapRule
+ buf := uio.NewBigEndianBuffer(data)
+ flags := buf.Read8()
+
+ opt.HubAndSpoke = flags&opt4RDHubAndSpokeMask != 0
+
+ tClass := buf.Read8()
+ if flags&opt4RDTrafficClassMask != 0 {
+ opt.TrafficClass = &tClass
+ }
+
+ opt.DomainPMTU = buf.Read16()
+
+ return &opt, buf.FinError()
+}