/
types-values.go
164 lines (137 loc) · 4.75 KB
/
types-values.go
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
156
157
158
159
160
161
162
163
164
package fact
import (
"encoding/binary"
"fmt"
"io"
"net"
"github.com/google/uuid"
"github.com/fastcat/wirelink/util"
)
// IPPortValue represents an IP:port pair as an Attribute of a Subject
type IPPortValue struct {
IP net.IP
Port int
}
// *IPValue must implement Value
// same pointer criteria as for PeerSubject
var _ Value = &IPPortValue{}
// MarshalBinary returns the normalized binary representation
func (ipp *IPPortValue) MarshalBinary() ([]byte, error) {
normalized := util.NormalizeIP(ipp.IP)
ret := make([]byte, len(normalized)+2)
copy(ret, normalized)
binary.BigEndian.PutUint16(ret[len(normalized):], uint16(ipp.Port))
return ret, nil
}
// UnmarshalBinary implements BinaryUnmarshaler
func (ipp *IPPortValue) UnmarshalBinary(data []byte) error {
// IMPORTANT: because we may be parsing from a packet buffer, we MUST NOT
// keep a reference to the data buffer after we return
if len(data) == net.IPv4len+2 {
ipp.IP = net.IP(util.CloneBytes(data[0:net.IPv4len]))
ipp.Port = int(binary.BigEndian.Uint16(data[net.IPv4len:]))
} else if len(data) == net.IPv6len+2 {
ipp.IP = net.IP(util.CloneBytes(data[0:net.IPv6len]))
ipp.Port = int(binary.BigEndian.Uint16(data[net.IPv6len:]))
} else {
return fmt.Errorf("ipv4 + port should be %d bytes, not %d", net.IPv4len+2, len(data))
}
ipp.IP = util.NormalizeIP(ipp.IP)
if len(ipp.IP) != len(data)-2 {
return fmt.Errorf("wrong ip length used (v4 in v6?): %d != %d", len(ipp.IP), len(data)-2)
}
return nil
}
// DecodeFrom implements Decodable
func (ipp *IPPortValue) DecodeFrom(lengthHint int, reader io.Reader) error {
if lengthHint == net.IPv4len+2 {
return util.DecodeFrom(ipp, net.IPv4len+2, reader)
} else if lengthHint == net.IPv6len+2 {
return util.DecodeFrom(ipp, net.IPv6len+2, reader)
} else {
return fmt.Errorf("invalid length hint for for IPPortValue: %v", lengthHint)
}
}
func (ipp *IPPortValue) String() string {
return fmt.Sprintf("%v:%v", ipp.IP, ipp.Port)
}
// IPNetValue represents some IP+Mask as an Attribute of a Subject
type IPNetValue struct {
net.IPNet
}
// *IPNetValue must implement Value
// same pointer criteria as for PeerSubject
var _ Value = &IPNetValue{}
// MarshalBinary gives the binary representation of the ip and cidr prefix
func (ipn IPNetValue) MarshalBinary() ([]byte, error) {
ipNorm := util.NormalizeIP(ipn.IP)
ones, _ := ipn.Mask.Size()
ret := make([]byte, len(ipNorm), len(ipNorm)+1)
copy(ret, ipNorm)
ret = append(ret, uint8(ones))
return ret, nil
}
// UnmarshalBinary implements BinaryUnmarshaler
func (ipn *IPNetValue) UnmarshalBinary(data []byte) error {
// IMPORTANT: because we may be parsing from a packet buffer, we MUST NOT
// keep a reference to the data buffer after we return
if len(data) == net.IPv4len+1 {
ipn.IP = net.IP(util.CloneBytes(data[0:net.IPv4len]))
ipn.Mask = net.CIDRMask(int(data[net.IPv4len]), 8*net.IPv4len)
} else if len(data) == net.IPv6len+1 {
ipn.IP = net.IP(util.CloneBytes(data[0:net.IPv6len]))
ipn.Mask = net.CIDRMask(int(data[net.IPv6len]), 8*net.IPv6len)
} else {
return fmt.Errorf("ipv4 + cidr should be %d bytes, not %d", net.IPv4len+1, len(data))
}
if ipn.Mask == nil {
// decode failed
return fmt.Errorf("bad mask length %d", data[len(data)-1])
}
ipn.IP = util.NormalizeIP(ipn.IP)
if len(ipn.IP) != len(data)-1 {
return fmt.Errorf("wrong ip length used (v4 in v6?): %d != %d", len(ipn.IP), len(data)-1)
}
return nil
}
// DecodeFrom implements Decodable
func (ipn *IPNetValue) DecodeFrom(lengthHint int, reader io.Reader) error {
if lengthHint == net.IPv4len+1 {
return util.DecodeFrom(ipn, net.IPv4len+1, reader)
} else if lengthHint == net.IPv6len+1 {
return util.DecodeFrom(ipn, net.IPv6len+1, reader)
} else {
return fmt.Errorf("invalid length hint for for IPNetValue: %v", lengthHint)
}
}
// IPNetValue inherits Stringer from IPNet
// EmptyValue is currently used as a placeholder in Membership facts
type EmptyValue struct{}
var _ Value = EmptyValue{}
// MarshalBinary always returns an empty slice for EmptyValue
func (v EmptyValue) MarshalBinary() ([]byte, error) {
return []byte{}, nil
}
// DecodeFrom implements Decodable
func (v EmptyValue) DecodeFrom(_ int, _ io.Reader) error {
return nil
}
func (v EmptyValue) String() string {
return "<empty>"
}
// UUIDValue represents a UUID, often used as a random marker or tag
type UUIDValue struct {
uuid.UUID
}
// UUID package doesn't provide this constant for us
const uuidLen = 16
// prove to ourselves it's correct
var _ = uuid.UUID([uuidLen]byte{})
// UUIDValue must implement Value
var _ Value = &UUIDValue{}
// UUIDValue inherits its MarshalBinary from UUID
// DecodeFrom implements Decodable
func (u *UUIDValue) DecodeFrom(_ int, reader io.Reader) error {
return util.DecodeFrom(u, uuidLen, reader)
}
// UUIDValue inherits its String(er) from UUID