summaryrefslogtreecommitdiffhomepage
path: root/dhcpv6/option_ntp_server.go
blob: a7aafb76905875d6a825472320a8fb872dc94911 (plain)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package dhcpv6

import (
	"fmt"
	"net"

	"github.com/insomniacslk/dhcp/rfc1035label"
	"github.com/u-root/uio/uio"
)

// NTPSuboptionSrvAddr is NTP_SUBOPTION_SRV_ADDR according to RFC 5908.
type NTPSuboptionSrvAddr net.IP

// Code returns the suboption code.
func (n *NTPSuboptionSrvAddr) Code() OptionCode {
	return NTPSuboptionSrvAddrCode
}

// ToBytes returns the byte serialization of the suboption.
func (n *NTPSuboptionSrvAddr) ToBytes() []byte {
	buf := uio.NewBigEndianBuffer(nil)
	buf.Write16(uint16(NTPSuboptionSrvAddrCode))
	buf.Write16(uint16(net.IPv6len))
	buf.WriteBytes(net.IP(*n).To16())
	return buf.Data()
}

func (n *NTPSuboptionSrvAddr) String() string {
	return fmt.Sprintf("Server Address: %s", net.IP(*n).String())
}

// NTPSuboptionMCAddr is NTP_SUBOPTION_MC_ADDR according to RFC 5908.
type NTPSuboptionMCAddr net.IP

// Code returns the suboption code.
func (n *NTPSuboptionMCAddr) Code() OptionCode {
	return NTPSuboptionMCAddrCode
}

// ToBytes returns the byte serialization of the suboption.
func (n *NTPSuboptionMCAddr) ToBytes() []byte {
	buf := uio.NewBigEndianBuffer(nil)
	buf.Write16(uint16(NTPSuboptionMCAddrCode))
	buf.Write16(uint16(net.IPv6len))
	buf.WriteBytes(net.IP(*n).To16())
	return buf.Data()
}

func (n *NTPSuboptionMCAddr) String() string {
	return fmt.Sprintf("Multicast Address: %s", net.IP(*n).String())
}

// NTPSuboptionSrvFQDN is NTP_SUBOPTION_SRV_FQDN according to RFC 5908.
type NTPSuboptionSrvFQDN rfc1035label.Labels

// Code returns the suboption code.
func (n *NTPSuboptionSrvFQDN) Code() OptionCode {
	return NTPSuboptionSrvFQDNCode
}

// ToBytes returns the byte serialization of the suboption.
func (n *NTPSuboptionSrvFQDN) ToBytes() []byte {
	buf := uio.NewBigEndianBuffer(nil)
	buf.Write16(uint16(NTPSuboptionSrvFQDNCode))
	l := rfc1035label.Labels(*n)
	buf.Write16(uint16(l.Length()))
	buf.WriteBytes(l.ToBytes())
	return buf.Data()
}

func (n *NTPSuboptionSrvFQDN) String() string {
	l := rfc1035label.Labels(*n)
	return fmt.Sprintf("Server FQDN: %s", l.String())
}

// NTPSuboptionSrvAddr is the value of NTP_SUBOPTION_SRV_ADDR according to RFC 5908.
const (
	NTPSuboptionSrvAddrCode = OptionCode(1)
	NTPSuboptionMCAddrCode  = OptionCode(2)
	NTPSuboptionSrvFQDNCode = OptionCode(3)
)

// parseNTPSuboption implements the OptionParser interface.
func parseNTPSuboption(code OptionCode, data []byte) (Option, error) {
	//var o Options
	buf := uio.NewBigEndianBuffer(data)
	length := len(data)
	data, err := buf.ReadN(length)
	if err != nil {
		return nil, fmt.Errorf("failed to read %d bytes for suboption: %w", length, err)
	}
	switch code {
	case NTPSuboptionSrvAddrCode, NTPSuboptionMCAddrCode:
		if length != net.IPv6len {
			return nil, fmt.Errorf("invalid suboption length, want %d, got %d", net.IPv6len, length)
		}
		var so Option
		switch code {
		case NTPSuboptionSrvAddrCode:
			sos := NTPSuboptionSrvAddr(data)
			so = &sos
		case NTPSuboptionMCAddrCode:
			som := NTPSuboptionMCAddr(data)
			so = &som
		}
		return so, nil
	case NTPSuboptionSrvFQDNCode:
		l, err := rfc1035label.FromBytes(data)
		if err != nil {
			return nil, fmt.Errorf("failed to parse rfc1035 labels: %w", err)
		}
		// TODO according to rfc3315, this label must not be compressed.
		// Need to add support for compression detection to the
		// `rfc1035label` package in order to do that.
		so := NTPSuboptionSrvFQDN(*l)
		return &so, nil
	default:
		gopt := OptionGeneric{OptionCode: code, OptionData: data}
		return &gopt, nil
	}
}

// ParseOptNTPServer parses a sequence of bytes into an OptNTPServer object.
func ParseOptNTPServer(data []byte) (*OptNTPServer, error) {
	var so Options
	if err := so.FromBytesWithParser(data, parseNTPSuboption); err != nil {
		return nil, err
	}
	return &OptNTPServer{
		Suboptions: so,
	}, nil
}

// OptNTPServer is an option NTP server as defined by RFC 5908.
type OptNTPServer struct {
	Suboptions Options
}

// Code returns the option code
func (op *OptNTPServer) Code() OptionCode {
	return OptionNTPServer
}

// ToBytes returns the option serialized to bytes.
func (op *OptNTPServer) ToBytes() []byte {
	buf := uio.NewBigEndianBuffer(nil)
	for _, so := range op.Suboptions {
		buf.WriteBytes(so.ToBytes())
	}
	return buf.Data()
}

func (op *OptNTPServer) String() string {
	return fmt.Sprintf("NTP: %v", op.Suboptions)
}